scalaunit-testingfuturescalatra

Scalatra asyncPost multiple unit tests mixed up requests


I'm new to scala so I might not be clear with the issue I'm facing, I might not be including all the details needed to identify the issue. I'll do my best to clarify.

I'm converting a post scalatra endpoint to asyncPost and converting Await.results to Futures. The unit tests that used to pass are now failing intermittently: a test is executed with request from another test. When I remove all tests and run each test individually they all pass. At this point my hypothesis is that the requests are being mixed up across unit tests. I'm not sure if this is an issue with the code or unit test setup.

This is a production code so there is a lot of logic that I can't fit here, I try to remove everything and keep what I think is relevant.

Actual code:

class Endpoints(...)
  extends ...
    with ABC_ExecutionContext
    with FutureSupport {

  protected implicit def executor = executionContext

  val myEndpoint: Route = asyncPost("/endpoint/", operation(queryGroup)) {
    setTransactionName(":post /endpoint")
    
    new AsyncResult { val is = {
      for {
        ...
        out <- doSomethingWithRequest() // implicit request is passed, returns a Future
        ...
        response <- doSomething(out) // returns a Future
      } yield response
    }}
  }
}

Tests:

class EndpointsSpec
  extends MockitoSugar
    with JsonFormats
    with ... {

  "POST /endpoint on Endpoints" should {
    "should work for request A" in {
      post("/endpoint/",
        write(mockRequestA).getBytes(),
        Map("user-id" -> "12345")) {
        body must_== """something A"""
        status must_== 200
      }
    }

    "should work for request B" in {
      post("/endpoint/",
        write(mockRequestB).getBytes(),
        Map("user-id" -> "12345")) {
        body must_== """something B"""
        status must_== 200
      }
    }
  }
}

I also tried to create a context per unit test

class EndpointsSpec
  extends MockitoSugar
    with JsonFormats
    with ... {

  "POST /endpoint on Endpoints" should {
    "should work for request A" in {
      val context: HystrixRequestContext = HystrixRequestContext.initializeContext
      try {
        post("/endpoint/",
          write(mockRequestA).getBytes(),
          Map("user-id" -> "12345")) {
          body must_== """something A"""
          status must_== 200
        }
      } finally {
        context.shutdown()
      }
    }

    "should work for request B" in {
      val context: HystrixRequestContext = HystrixRequestContext.initializeContext
      try {
        post("/endpoint/",
          write(mockRequestB).getBytes(),
          Map("user-id" -> "12345")) {
          body must_== """something B"""
          status must_== 200
        }
      } finally {
        context.shutdown()
      }
    }
  }
}

The issue might be with something I have omitted, let me know and I can add more details before making sample code too complicate

Extra info:


Solution

  • I don't have experience with Scalatra neither with Specs2. Just giving a quick look to the docs of Scalatra and how to work with async requests, just using get, post or the one you need without the async prefxi should work. From the docs here you have an example

    class MyAppServlet extends ScalatraServlet with FutureSupport {
      get("/"){
        new AsyncResult { val is =
          Future {
            // Add async logic here
            // ...
          }
        }
      }
    }