=typ #24279 Add tests for ActorSystem startup / shutdown scenarios

This commit is contained in:
Johan Andrén 2018-01-12 18:27:03 +01:00 committed by Johannes Rudolph
parent 4af523a012
commit c6965edc21
No known key found for this signature in database
GPG key ID: 4D293A24CCD39E19
8 changed files with 202 additions and 36 deletions

View file

@ -54,7 +54,6 @@ class ActorSystemSpec extends WordSpec with Matchers with BeforeAndAfterAll
// see issue #24172 // see issue #24172
"shutdown if guardian shuts down immediately" in { "shutdown if guardian shuts down immediately" in {
pending
withSystem("shutdown", Behaviors.stopped[String], doTerminate = false) { sys: ActorSystem[String] withSystem("shutdown", Behaviors.stopped[String], doTerminate = false) { sys: ActorSystem[String]
sys.whenTerminated.futureValue sys.whenTerminated.futureValue
} }

View file

@ -5,15 +5,15 @@ package akka.actor.typed.scaladsl.adapter
import scala.concurrent.duration._ import scala.concurrent.duration._
import scala.util.control.NoStackTrace import scala.util.control.NoStackTrace
import akka.actor.typed.ActorRef import akka.actor.typed.{ ActorRef, ActorSystem, Behavior, Terminated }
import akka.actor.{ InvalidMessageException, Props } import akka.actor.{ InvalidMessageException, Props }
import akka.actor.typed.Behavior
import akka.actor.typed.Terminated
import akka.actor.typed.scaladsl.Behaviors import akka.actor.typed.scaladsl.Behaviors
import akka.{ actor untyped } import akka.{ Done, NotUsed, actor untyped }
import akka.testkit._ import akka.testkit._
import akka.actor.typed.Behavior.UntypedBehavior import akka.actor.typed.Behavior.UntypedBehavior
import scala.concurrent.Await
object AdapterSpec { object AdapterSpec {
val untyped1: untyped.Props = untyped.Props(new Untyped1) val untyped1: untyped.Props = untyped.Props(new Untyped1)
@ -157,6 +157,31 @@ class AdapterSpec extends AkkaSpec {
typed1 should be theSameInstanceAs typed2 typed1 should be theSameInstanceAs typed2
} }
"not crash if guardian is stopped" in {
for { _ 0 to 10 } {
var system: akka.actor.typed.ActorSystem[NotUsed] = null
try {
system = ActorSystem.create(Behavior.stopped[NotUsed], "AdapterSpec-stopping-guardian")
} finally if (system != null) shutdown(system.toUntyped)
}
}
"not crash if guardian is stopped very quickly" in {
for { _ 0 to 10 } {
var system: akka.actor.typed.ActorSystem[Done] = null
try {
system = ActorSystem.create(Behaviors.immutable[Done] { (ctx, msg)
ctx.self ! Done
msg match {
case Done Behaviors.stopped
}
}, "AdapterSpec-stopping-guardian-2")
} finally if (system != null) shutdown(system.toUntyped)
}
}
} }
"Adapted actors" must { "Adapted actors" must {

View file

@ -7,16 +7,14 @@ package docs.akka.typed
import java.net.URLEncoder import java.net.URLEncoder
import java.nio.charset.StandardCharsets import java.nio.charset.StandardCharsets
import akka.actor.typed.ActorRef import akka.NotUsed
import akka.actor.typed.ActorSystem
import akka.actor.typed.Behavior
import akka.actor.typed.Terminated
import akka.actor.typed.scaladsl.AskPattern._ import akka.actor.typed.scaladsl.AskPattern._
import akka.actor.typed.scaladsl.Behaviors import akka.actor.typed.scaladsl.Behaviors
import akka.actor.typed.{ ActorRef, ActorSystem, Behavior, Terminated }
import akka.testkit.typed.TestKit import akka.testkit.typed.TestKit
import scala.concurrent.Await
import scala.concurrent.Future
import scala.concurrent.duration._ import scala.concurrent.duration._
import scala.concurrent.{ Await, Future }
//#imports //#imports
import akka.actor.typed.TypedAkkaSpecWithShutdown import akka.actor.typed.TypedAkkaSpecWithShutdown
@ -107,7 +105,7 @@ class IntroSpec extends TestKit with TypedAkkaSpecWithShutdown {
import IntroSpec._ import IntroSpec._
"Hello world" must { "Hello world" must {
"must say hello" in { "say hello" in {
// TODO Implicits.global is not something we would like to encourage in docs // TODO Implicits.global is not something we would like to encourage in docs
//#hello-world //#hello-world
import HelloWorld._ import HelloWorld._
@ -128,7 +126,7 @@ class IntroSpec extends TestKit with TypedAkkaSpecWithShutdown {
//#hello-world //#hello-world
} }
"must chat" in { "chat" in {
//#chatroom-gabbler //#chatroom-gabbler
import ChatRoom._ import ChatRoom._
@ -152,24 +150,20 @@ class IntroSpec extends TestKit with TypedAkkaSpecWithShutdown {
//#chatroom-gabbler //#chatroom-gabbler
//#chatroom-main //#chatroom-main
val main: Behavior[String] = val main: Behavior[NotUsed] =
Behaviors.deferred { ctx Behaviors.deferred { ctx
val chatRoom = ctx.spawn(ChatRoom.behavior, "chatroom") val chatRoom = ctx.spawn(ChatRoom.behavior, "chatroom")
val gabblerRef = ctx.spawn(gabbler, "gabbler") val gabblerRef = ctx.spawn(gabbler, "gabbler")
ctx.watch(gabblerRef) ctx.watch(gabblerRef)
chatRoom ! GetSession("ol Gabbler", gabblerRef)
Behaviors.immutablePartial[String] { Behaviors.onSignal {
case (_, "go")
chatRoom ! GetSession("ol Gabbler", gabblerRef)
Behaviors.same
} onSignal {
case (_, Terminated(ref)) case (_, Terminated(ref))
Behaviors.stopped Behaviors.stopped
} }
} }
val system = ActorSystem(main, "ChatRoomDemo") val system = ActorSystem(main, "ChatRoomDemo")
system ! "go"
Await.result(system.whenTerminated, 3.seconds) Await.result(system.whenTerminated, 3.seconds)
//#chatroom-main //#chatroom-main
} }

View file

@ -24,6 +24,7 @@ import scala.util.control.{ ControlThrowable, NonFatal }
import java.util.Optional import java.util.Optional
import akka.actor.setup.{ ActorSystemSetup, Setup } import akka.actor.setup.{ ActorSystemSetup, Setup }
import akka.annotation.InternalApi
import scala.compat.java8.FutureConverters import scala.compat.java8.FutureConverters
import scala.compat.java8.OptionConverters._ import scala.compat.java8.OptionConverters._
@ -643,6 +644,10 @@ abstract class ExtendedActorSystem extends ActorSystem {
} }
/**
* Internal API
*/
@InternalApi
private[akka] class ActorSystemImpl( private[akka] class ActorSystemImpl(
val name: String, val name: String,
applicationConfig: Config, applicationConfig: Config,

View file

@ -10,11 +10,15 @@ import akka.cluster.typed.*;
import akka.testkit.typed.javadsl.TestProbe; import akka.testkit.typed.javadsl.TestProbe;
import docs.akka.cluster.typed.BasicClusterManualSpec; import docs.akka.cluster.typed.BasicClusterManualSpec;
//FIXME make these tests // FIXME these tests are awaiting typed Java testkit to be able to await cluster forming like in BasicClusterExampleSpec
public class BasicClusterExampleTest { public class BasicClusterExampleTest { // extends JUnitSuite {
// @Test
public void clusterApiExample() { public void clusterApiExample() {
ActorSystem<Object> system = ActorSystem.create(Behaviors.empty(), "ClusterSystem", BasicClusterManualSpec.clusterConfig()); ActorSystem<Object> system = ActorSystem.create(Behaviors.empty(), "ClusterSystem",
ActorSystem<Object> system2 = ActorSystem.create(Behaviors.empty(), "ClusterSystem", BasicClusterManualSpec.clusterConfig()); BasicClusterManualSpec.noPort().withFallback(BasicClusterManualSpec.clusterConfig()));
ActorSystem<Object> system2 = ActorSystem.create(Behaviors.empty(), "ClusterSystem",
BasicClusterManualSpec.noPort().withFallback(BasicClusterManualSpec.clusterConfig()));
try { try {
//#cluster-create //#cluster-create
@ -26,18 +30,28 @@ public class BasicClusterExampleTest {
cluster.manager().tell(Join.create(cluster.selfMember().address())); cluster.manager().tell(Join.create(cluster.selfMember().address()));
//#cluster-join //#cluster-join
cluster2.manager().tell(Join.create(cluster.selfMember().address()));
// TODO wait for/verify cluster to form
//#cluster-leave //#cluster-leave
cluster2.manager().tell(Leave.create(cluster2.selfMember().address())); cluster2.manager().tell(Leave.create(cluster2.selfMember().address()));
//#cluster-leave //#cluster-leave
// TODO wait for/verify node 2 leaving
} finally { } finally {
system.terminate(); system.terminate();
system2.terminate(); system2.terminate();
} }
} }
// @Test
public void clusterLeave() throws Exception { public void clusterLeave() throws Exception {
ActorSystem<Object> system = ActorSystem.create(Behaviors.empty(), "ClusterSystem", BasicClusterManualSpec.clusterConfig()); ActorSystem<Object> system = ActorSystem.create(Behaviors.empty(), "ClusterSystem",
ActorSystem<Object> system2 = ActorSystem.create(Behaviors.empty(), "ClusterSystem", BasicClusterManualSpec.clusterConfig()); BasicClusterManualSpec.noPort().withFallback(BasicClusterManualSpec.clusterConfig()));
ActorSystem<Object> system2 = ActorSystem.create(Behaviors.empty(), "ClusterSystem",
BasicClusterManualSpec.noPort().withFallback(BasicClusterManualSpec.clusterConfig()));
try { try {
Cluster cluster = Cluster.get(system); Cluster cluster = Cluster.get(system);

View file

@ -6,12 +6,14 @@ import akka.actor.typed.Behavior;
import akka.actor.typed.javadsl.Behaviors; import akka.actor.typed.javadsl.Behaviors;
import akka.actor.typed.receptionist.Receptionist; import akka.actor.typed.receptionist.Receptionist;
import akka.actor.typed.receptionist.ServiceKey; import akka.actor.typed.receptionist.ServiceKey;
import org.junit.Test;
import org.scalatest.junit.JUnitSuite;
import scala.concurrent.Await; import scala.concurrent.Await;
import scala.concurrent.duration.Duration; import scala.concurrent.duration.Duration;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
public class ReceptionistExampleTest { public class ReceptionistExampleTest extends JUnitSuite {
public static class PingPongExample { public static class PingPongExample {
//#ping-service //#ping-service
@ -68,6 +70,7 @@ public class ReceptionistExampleTest {
//#pinger-guardian //#pinger-guardian
} }
@Test
public void workPlease() throws Exception { public void workPlease() throws Exception {
ActorSystem<Receptionist.Listing<PingPongExample.Ping>> system = ActorSystem<Receptionist.Listing<PingPongExample.Ping>> system =
ActorSystem.create(PingPongExample.guardian(), "ReceptionistExample"); ActorSystem.create(PingPongExample.guardian(), "ReceptionistExample");

View file

@ -0,0 +1,131 @@
/**
* Copyright (C) 2016-2018 Lightbend Inc. <http://www.lightbend.com/>
*/
package akka.cluster.typed
import akka.actor.InvalidMessageException
import akka.actor.typed.ActorRef
import akka.actor.typed.ActorSystem
import akka.actor.typed.Behavior
import akka.actor.typed.{ PostStop, Terminated }
import akka.actor.typed.scaladsl.Behaviors
import akka.testkit.typed.TestInbox
import com.typesafe.config.ConfigFactory
import org.scalatest._
import org.scalatest.concurrent.Eventually
import org.scalatest.concurrent.ScalaFutures
import scala.concurrent.duration._
import scala.concurrent.Future
import scala.concurrent.Promise
import scala.util.control.NonFatal
class ActorSystemSpec extends WordSpec with Matchers with BeforeAndAfterAll
with ScalaFutures with Eventually {
override implicit val patienceConfig = PatienceConfig(1.second)
val config = ConfigFactory.parseString(
"""
akka.actor.provider = "akka.remote.RemoteActorRefProvider"
""").withFallback(ConfigFactory.load())
def system[T](behavior: Behavior[T], name: String) = ActorSystem(behavior, name, config)
def suite = "adapter"
case class Probe(msg: String, replyTo: ActorRef[String])
def withSystem[T](name: String, behavior: Behavior[T], doTerminate: Boolean = true)(block: ActorSystem[T] Unit): Terminated = {
val sys = system(behavior, s"$suite-$name")
try {
block(sys)
if (doTerminate) sys.terminate().futureValue else sys.whenTerminated.futureValue
} catch {
case NonFatal(ex)
sys.terminate()
throw ex
}
}
"An ActorSystem" must {
"start the guardian actor and terminate when it terminates" in {
val t = withSystem(
"a",
Behaviors.immutable[Probe] { case (_, p) p.replyTo ! p.msg; Behaviors.stopped }, doTerminate = false) { sys
val inbox = TestInbox[String]("a")
sys ! Probe("hello", inbox.ref)
eventually {
inbox.hasMessages should ===(true)
}
inbox.receiveAll() should ===("hello" :: Nil)
}
val p = t.ref.path
p.name should ===("/")
p.address.system should ===(suite + "-a")
}
// see issue #24172
"shutdown if guardian shuts down immediately" in {
pending
withSystem("shutdown", Behaviors.stopped[String], doTerminate = false) { sys: ActorSystem[String]
sys.whenTerminated.futureValue
}
}
"terminate the guardian actor" in {
val inbox = TestInbox[String]("terminate")
val sys = system(
Behaviors.immutable[Probe] {
case (_, _) Behaviors.unhandled
} onSignal {
case (_, PostStop)
inbox.ref ! "done"
Behaviors.same
},
"terminate")
sys.terminate().futureValue
inbox.receiveAll() should ===("done" :: Nil)
}
"log to the event stream" in {
pending
}
"have a name" in {
withSystem("name", Behaviors.empty[String]) { sys
sys.name should ===(suite + "-name")
}
}
"report its uptime" in {
withSystem("uptime", Behaviors.empty[String]) { sys
sys.uptime should be < 1L
Thread.sleep(2000)
sys.uptime should be >= 1L
}
}
"have a working thread factory" in {
withSystem("thread", Behaviors.empty[String]) { sys
val p = Promise[Int]
sys.threadFactory.newThread(new Runnable {
def run(): Unit = p.success(42)
}).start()
p.future.futureValue should ===(42)
}
}
"be able to run Futures" in {
withSystem("futures", Behaviors.empty[String]) { sys
val f = Future(42)(sys.executionContext)
f.futureValue should ===(42)
}
}
"not allow null messages" in {
withSystem("null-messages", Behaviors.empty[String]) { sys
intercept[InvalidMessageException] {
sys ! null
}
}
}
}
}

View file

@ -197,16 +197,11 @@ class ReceptionistExampleSpec extends WordSpec with ScalaFutures {
"A remote basic example" must { "A remote basic example" must {
"show register" in { "show register" in {
// FIXME cannot use guardian as it touches receptionist #24279 val system1 = ActorSystem(guardianJustPingService, "PingPongExample", clusterConfig)
import scaladsl.adapter._ val system2 = ActorSystem(guardianJustPinger, "PingPongExample", clusterConfig)
val system1 = akka.actor.ActorSystem("PingPongExample", clusterConfig)
val system2 = akka.actor.ActorSystem("PingPongExample", clusterConfig)
system1.spawnAnonymous(guardianJustPingService) val cluster1 = Cluster(system1)
system2.spawnAnonymous(guardianJustPinger) val cluster2 = Cluster(system2)
val cluster1 = Cluster(system1.toTyped)
val cluster2 = Cluster(system2.toTyped)
cluster1.manager ! Join(cluster1.selfMember.address) cluster1.manager ! Join(cluster1.selfMember.address)
cluster1.manager ! Join(cluster2.selfMember.address) cluster1.manager ! Join(cluster2.selfMember.address)