Play 2.0 Disabling Akka with multiple test cases

I have two controllers that use AKKA actors in Play 2.0. Accordingly, there are two tests that test these two APIs. However, when a “game test” is performed, only one of the test cases will succeed, and the other will fail. If I run them separately, it succeeds. My guess is that the actor system was disabled by the first test. However, I am new to Play 2 and Akka, this is just my guess. Is there a workaround?

@Test public void callPostA() { running(testServer(2222, fakeApplication(inMemoryDatabase())), new Runnable() { @Override public void run() { HttpPost httpPost = new HttpPost("http://localhost:2222/controllera"); .... } }); } @Test public void callPostB() { running(testServer(2222, fakeApplication(inMemoryDatabase())), new Runnable() { @Override public void run() { HttpPost httpPost = new HttpPost("http://localhost:2222/controllerb"); .... } }); } 

Two controllers:

 public class PostA extends Controller { // master actor for workers public static ActorRef masterActorA = Akka.system().actorOf(new Props(new UntypedActorFactory() { public UntypedActor create() { return new PostAActorMaster(Config.NUMBER_OF_WORKER_ACTOR); } }), "PostAActorMaster"); public static Result postA() { Map<String, String[]> dict = body.asFormUrlEncoded(); String paramField1 = dict.get("paramField1"); String paramField2 = dict.get("paramField2"); ProductInfo pInfo = new ProductInfo(paramField1, paramField2); ProductMessage pMessage = new ProductMessage(pInfo); return async( Akka.asPromise(ask(masterActorA, pMessage, 15000)).map( new Function<Object, Result>() { ... } )); } public class PostB extends Controller { // master actor for workers public static ActorRef masterActorB = Akka.system().actorOf(new Props(new UntypedActorFactory() { public UntypedActor create() { return new PostBActorMaster(Config.NUMBER_OF_WORKER_ACTOR); } }), "PostBActorMaster"); public static Result postB() { Map<String, String[]> dict = body.asFormUrlEncoded(); String paramField3 = dict.get("paramField3"); String paramField4 = dict.get("paramField4"); BillInfo bInfo = new BillInfo(paramField3, paramField4); BillMessage pMessage = new BillMessage(bInfo); return async( Akka.asPromise(ask(masterActorB, pMessage, 15000)).map( new Function<Object, Result>() { ... } )); } 

PostA AKKA Master and Worker:

 public class PostAActorMaster extends UntypedActor { private final ActorRef workerRouter; public PostAActorMaster(final int nrOfWorkers) { workerRouter = this.getContext().actorOf(new Props(PostAActorMaster.class).withRouter(new RoundRobinRouter(nrOfWorkers))); } public void onReceive(Object messageObj) { try { if (messageObj instanceof ProductMessage) { // invoke worker to submit channel messaages workerRouter.tell(messageObj, getSender()); } else if (messageObj instanceof ProductMessageResult) { ...... getSender().tell("OK"); } } catch (Exception e) { ...... } } } public class PostAActorWorker extends UntypedActor { public void onReceive(Object messageObj) throws Exception { if (messageObj instanceof ProductMessage) { ProductMessage pMessage = (ProductMessage)messageObj; ProductInfo pInfo = pMessage.getProductInfo(); log.info(pInfo.getProductId()); ProductMessageResult pr = new ProductMessageResult(pInfo); PostA.masterActor.tell(pr, getSender()); } } } 

Managed Object:

 public class ProductInfo extends Model { @Id private String productId; ... } 
+6
source share
2 answers

I no longer see the problem. Here is the structure of my test case. Perhaps you can try and see if this works for you.

Scala:

 object LoginApiTest extends PlaySpecification { "login api quick login" should { "post login data" in new WithCleanTestData { var org1 = new OrgInfo("testorg", "Test Inc"); org1.save(); } } } abstract class WithCleanTestData extends WithApplication(FakeApplication( additionalConfiguration = TestConf.getConf.toMap )) { override def around[T: AsResult](t: => T): Result = super.around { prepareDbWithData() t } def prepareDbWithData() = { OrgInfo.getAllOrgInfo.foreach(_.delete) } } 

Java:

 public class MyHelpers extends Helpers { public static FakeApplication myFakeApplication(Map<String,String> additionalConfiguration) { List<String> withoutPlugins = new ArrayList<String>(); List<String> additionalPlugins = new ArrayList<String>(); return new MyFakeApplication(new java.io.File("."), MyHelpers.class.getClassLoader(), additionalConfiguration, withoutPlugins, additionalPlugins, null); } } public class BaseModelTest extends WithApplication { @Before public void before() { } } public class PostTest extends BaseModelTest { @Test public void test1() { } } 

Alternatively, you can try adding this parameter to your Build.scala file:

 parallelExecution in Test := false 
+1
source

Hey, I used a static ActorSystem and that caused the problem

 [error] sbt.ForkMain$ForkError: Error creating bean with name 'accountServiceController' defined in file [/Users/admin/Development/src/totes/app/target/scala-2.11/classes/controllers/Ac‌​countServiceController.class]: Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [controllers.AccountServiceController]: Constructor threw exception; nested exception is java.lang.IllegalStateException: cannot create children while terminating or terminated 

By creating a dynamic ActorSystem that is created every time the application starts, the problem seems to disappear. I worked on this for a while, so I wanted to post this here as a potential solution.

0
source

Source: https://habr.com/ru/post/918406/


All Articles