Scalatra异步Post多个单元测试混淆请求

huangapple go评论59阅读模式
英文:

Scalatra asyncPost multiple unit tests mixed up requests

问题

I'm new to Scala, so I may not be clear about the issue I'm facing, and I may not have included all the necessary details to identify the problem. I'll do my best to clarify.

I'm converting a post endpoint in Scalatra to an asyncPost endpoint and changing Await.result calls to use Futures. The unit tests that used to pass are now failing intermittently, with one test being executed with the 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 getting mixed up across unit tests. I'm unsure if this is an issue with the code or the unit test setup.

This is production code, so there's a lot of logic that I can't include here, but I'll try to 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 related to something I have omitted. Please let me know if you need more details before making the sample code too complex.

Extra info:

  • Test framework: specs2 + Mockito
英文:

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(&quot;/endpoint/&quot;, operation(queryGroup)) {
    setTransactionName(&quot;:post /endpoint&quot;)
    
    new AsyncResult { val is = {
      for {
        ...
        out &lt;- doSomethingWithRequest() // implicit request is passed, returns a Future
        ...
        response &lt;- doSomething(out) // returns a Future
      } yield response
    }}
  }
}

Tests:

class EndpointsSpec
  extends MockitoSugar
    with JsonFormats
    with ... {

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

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

I also tried to create a context per unit test

class EndpointsSpec
  extends MockitoSugar
    with JsonFormats
    with ... {

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

    &quot;should work for request B&quot; in {
      val context: HystrixRequestContext = HystrixRequestContext.initializeContext
      try {
        post(&quot;/endpoint/&quot;,
          write(mockRequestB).getBytes(),
          Map(&quot;user-id&quot; -&gt; &quot;12345&quot;)) {
          body must_== &quot;&quot;&quot;something B&quot;&quot;&quot;
          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:

  • Test framework: specs2 + mockito

答案1

得分: 1

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 prefix 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
        // ...
      }
    }
  }
}
英文:

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(&quot;/&quot;){
    new AsyncResult { val is =
      Future {
        // Add async logic here
        // ...
      }
    }
  }
}

huangapple
  • 本文由 发表于 2023年5月13日 09:43:42
  • 转载请务必保留本文链接:https://go.coder-hub.com/76240752.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定