2012-09-13 10:54:14 +02:00
|
|
|
package sample.cluster.stats
|
|
|
|
|
|
|
|
|
|
import language.postfixOps
|
|
|
|
|
import scala.concurrent.util.duration._
|
|
|
|
|
|
|
|
|
|
import com.typesafe.config.ConfigFactory
|
|
|
|
|
|
|
|
|
|
import StatsSampleSpec.first
|
|
|
|
|
import StatsSampleSpec.third
|
|
|
|
|
import akka.actor.Props
|
|
|
|
|
import akka.actor.RootActorPath
|
|
|
|
|
import akka.cluster.Cluster
|
|
|
|
|
import akka.cluster.Member
|
|
|
|
|
import akka.cluster.MemberStatus
|
|
|
|
|
import akka.cluster.ClusterEvent.CurrentClusterState
|
|
|
|
|
import akka.cluster.ClusterEvent.MemberUp
|
|
|
|
|
import akka.remote.testkit.MultiNodeConfig
|
|
|
|
|
import akka.remote.testkit.MultiNodeSpec
|
2012-09-20 10:40:08 +02:00
|
|
|
import akka.remote.testkit.STMultiNodeSpec
|
2012-09-13 10:54:14 +02:00
|
|
|
import akka.testkit.ImplicitSender
|
|
|
|
|
|
|
|
|
|
object StatsSampleSingleMasterSpec extends MultiNodeConfig {
|
|
|
|
|
// register the named roles (nodes) of the test
|
|
|
|
|
val first = role("first")
|
|
|
|
|
val second = role("second")
|
|
|
|
|
val third = role("thrid")
|
|
|
|
|
|
|
|
|
|
// this configuration will be used for all nodes
|
|
|
|
|
// note that no fixed host names and ports are used
|
|
|
|
|
commonConfig(ConfigFactory.parseString("""
|
|
|
|
|
akka.loglevel = INFO
|
|
|
|
|
akka.actor.provider = "akka.cluster.ClusterActorRefProvider"
|
|
|
|
|
akka.remote.log-remote-lifecycle-events = off
|
|
|
|
|
akka.cluster.auto-join = off
|
|
|
|
|
#//#router-deploy-config
|
|
|
|
|
akka.actor.deployment {
|
|
|
|
|
/statsFacade/statsService/workerRouter {
|
2012-09-20 12:58:51 +02:00
|
|
|
router = consistent-hashing
|
2012-09-13 10:54:14 +02:00
|
|
|
nr-of-instances = 100
|
|
|
|
|
cluster {
|
|
|
|
|
enabled = on
|
|
|
|
|
max-nr-of-instances-per-node = 3
|
|
|
|
|
allow-local-routees = off
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#//#router-deploy-config
|
|
|
|
|
"""))
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// need one concrete test class per node
|
|
|
|
|
class StatsSampleSingleMasterMultiJvmNode1 extends StatsSampleSingleMasterSpec
|
|
|
|
|
class StatsSampleSingleMasterMultiJvmNode2 extends StatsSampleSingleMasterSpec
|
|
|
|
|
class StatsSampleSingleMasterMultiJvmNode3 extends StatsSampleSingleMasterSpec
|
|
|
|
|
|
|
|
|
|
abstract class StatsSampleSingleMasterSpec extends MultiNodeSpec(StatsSampleSingleMasterSpec)
|
2012-09-20 10:40:08 +02:00
|
|
|
with STMultiNodeSpec with ImplicitSender {
|
2012-09-13 10:54:14 +02:00
|
|
|
|
|
|
|
|
import StatsSampleSpec._
|
|
|
|
|
|
|
|
|
|
override def initialParticipants = roles.size
|
|
|
|
|
|
|
|
|
|
"The stats sample with single master" must {
|
|
|
|
|
"illustrate how to startup cluster" in within(10 seconds) {
|
|
|
|
|
Cluster(system).subscribe(testActor, classOf[MemberUp])
|
|
|
|
|
expectMsgClass(classOf[CurrentClusterState])
|
|
|
|
|
|
|
|
|
|
Cluster(system) join node(first).address
|
|
|
|
|
system.actorOf(Props[StatsFacade], "statsFacade")
|
|
|
|
|
|
|
|
|
|
expectMsgAllOf(
|
|
|
|
|
MemberUp(Member(node(first).address, MemberStatus.Up)),
|
|
|
|
|
MemberUp(Member(node(second).address, MemberStatus.Up)),
|
|
|
|
|
MemberUp(Member(node(third).address, MemberStatus.Up)))
|
|
|
|
|
|
|
|
|
|
Cluster(system).unsubscribe(testActor)
|
|
|
|
|
|
|
|
|
|
testConductor.enter("all-up")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
"show usage of the statsFacade" in within(5 seconds) {
|
|
|
|
|
val facade = system.actorFor(RootActorPath(node(third).address) / "user" / "statsFacade")
|
|
|
|
|
|
|
|
|
|
// eventually the service should be ok,
|
|
|
|
|
// worker nodes might not be up yet
|
|
|
|
|
awaitCond {
|
|
|
|
|
facade ! StatsJob("this is the text that will be analyzed")
|
|
|
|
|
expectMsgPF() {
|
|
|
|
|
case unavailble: JobFailed ⇒ false
|
|
|
|
|
case StatsResult(meanWordLength) ⇒
|
|
|
|
|
meanWordLength must be(3.875 plusOrMinus 0.001)
|
|
|
|
|
true
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
testConductor.enter("done")
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|