I am trying to figure out the idiom for writing an integration test for an Http4s app that supports two end points.
I'm starting the Main
app class in a ZManaged
by forking it on a new fiber and then doing interruptFork on release of the ZManaged
.
I then convert this to a ZLayer
and pass it via provideCustomLayerShared()
on the whole suite
that has multiple testM
s .
- Am I on the right track here?
- It doesn't behave as I expect it to :
- Although the httpserver managed in the way mentioned is provided to the suite that encloses both the tests, it is released after the first test and thus the second test fails
- The test suite never finishes and just hangs after executing both tests
Apologies for the half baked nature of the code below.
object MainTest extends DefaultRunnableSpec {
def httpServer =
ZManaged
.make(Main.run(List()).fork)(fiber => {
//fiber.join or Fiber.interrupt will not work here, hangs the test
fiber.interruptFork.map(
ex => println(s"stopped with exitCode: $ex")
)
})
.toLayer
val clockDuration = 1.second
//did the httpserver start listening on 8080?
private def isLocalPortInUse(port: Int): ZIO[Clock, Throwable, Unit] = {
IO.effect(new Socket("0.0.0.0", port).close()).retry(Schedule.exponential(clockDuration) && Schedule.recurs(10))
}
override def spec: ZSpec[Environment, Failure] =
suite("MainTest")(
testM("Health check") {
for {
_ <- TestClock.adjust(clockDuration).fork
_ <- isLocalPortInUse(8080)
client <- Task(JavaNetClientBuilder[Task](blocker).create)
response <- client.expect[HealthReplyDTO]("http://localhost:8080/health")
expected = HealthReplyDTO("OK")
} yield assert(response) {
equalTo(expected)
}
},
testM("Distances endpoint check") {
for {
_ <- TestClock.adjust(clockDuration).fork
_ <- isLocalPortInUse(8080)
client <- Task(JavaNetClientBuilder[Task](blocker).create)
response <- client.expect[DistanceReplyDTO](
Request[Task](method = Method.GET, uri = uri"http://localhost:8080/distances")
.withEntity(DistanceRequestDTO(List("JFK", "LHR")))
)
expected = DistanceReplyDTO(5000)
} yield assert(response) {
equalTo(expected)
}
}
).provideCustomLayerShared(httpServer)
}
Output of the test is that the second test fails while the first succeeds. And I debugged enough to see that the HTTPServer is already brought down before the second test.
stopped with exitCode: ()
- MainTest
+ Health check
- Distances endpoint check
Fiber failed.
A checked error was not handled.
org.http4s.client.UnexpectedStatus: unexpected HTTP status: 404 Not Found
And whether I run the tests from Intellij on sbt testOnly, the test process keeps hung after all this and I have to manually terminate it.