eclipse-vertx / vertx-junit5

Testing Vert.x applications with JUnit 5
Apache License 2.0
42 stars 30 forks source link

Checkpoints are ignored #65

Closed u6f6o closed 4 years ago

u6f6o commented 4 years ago

I wrote a bootstrap class that basically deploys all necessary verticles in the right order:

import io.vertx.core.AbstractVerticle
import io.vertx.core.Future
import io.vertx.core.Promise
import io.vertx.core.Verticle
import mu.KLogging

open class ApplicationBootstrapper(
    private val profiles: List<String>) : AbstractVerticle()
{
    companion object: KLogging()

    override fun start(startFuture: Promise<Void>) {
        deploy(messageCodecs())
            .compose { deploy(applicationConfig()) }
            .compose { deploy(stationAmbassador()) }
            .compose { deploy(restEndpoint()) }.setHandler { chain ->
                if(chain.succeeded()) {
                    startFuture.complete()
                } else {
                    startFuture.fail(chain.cause())
                }
            }
    }

    private fun deploy(verticle: Verticle): Future<String> {
        return Promise.promise<String>().also { p ->
            vertx.deployVerticle(
                verticle,
                p
            )
        }.future()
    }

    internal open fun messageCodecs(): Verticle = MessageCodecRegistry()

    internal open fun applicationConfig(): Verticle = ApplicationConfigVerticle(profiles)

    internal open fun stationAmbassador(): Verticle = StationAmbassadorVerticle()

    internal open fun restEndpoint(): Verticle = RestEndpointVerticle()
}

Seems to work as expected. I also wrote a simple unit test, using vertx-junit5:

import assertk.assertThat
import assertk.assertions.isEqualTo
import io.vertx.core.AbstractVerticle
import io.vertx.core.Promise
import io.vertx.core.Vertx
import io.vertx.junit5.Checkpoint
import io.vertx.junit5.VertxExtension
import io.vertx.junit5.VertxTestContext
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.extension.ExtendWith

@ExtendWith(value = [VertxExtension::class])
class ApplicationBootstrapSpec {

    @Test
    fun allVerticlesStart(
        vertx: Vertx,
        testContext: VertxTestContext)
    {
        val messageCodecCP = testContext.checkpoint()
        val applicationConfigCP = testContext.checkpoint()
        val stationAmbassadorCP = testContext.checkpoint()
        val restEndpointCP = testContext.checkpoint()

        val bootstrapper = object: ApplicationBootstrapper(listOf()) {
            override fun messageCodecs() = succeedingVerticle(messageCodecCP)
            override fun applicationConfig() = succeedingVerticle(applicationConfigCP)
            override fun stationAmbassador() = succeedingVerticle(stationAmbassadorCP)
            override fun restEndpoint() = succeedingVerticle(restEndpointCP)
        }
        vertx.deployVerticle(bootstrapper, testContext.succeeding { testContext.completeNow() })
    }

    @Test
    fun messageCodecsFail(
        vertx: Vertx,
        testContext: VertxTestContext)
    {
        val messageCodecCP = testContext.checkpoint()

        val bootstrapper = object: ApplicationBootstrapper(listOf()) {
            override fun messageCodecs() = failingVerticle(messageCodecCP)
            override fun applicationConfig() = throw AssertionError("Not supposed to get here.")
            override fun stationAmbassador() = throw AssertionError("Not supposed to get here.")
            override fun restEndpoint() = throw AssertionError("Not supposed to get here.")
        }
        vertx.deployVerticle(bootstrapper, testContext.failing {
            testContext.verify {
                assertThat(it.message).isEqualTo("Startup failed!")
                testContext.completeNow()
            }
        })
    }

    private fun failingVerticle(checkpoint: Checkpoint) = object: AbstractVerticle() {
        override fun start(startPromise: Promise<Void>) {
            checkpoint.flag()
            startPromise.fail("Startup failed!")
        }
    }

    private fun succeedingVerticle(checkpoint: Checkpoint) = object: AbstractVerticle() {
        override fun start(startPromise: Promise<Void>) {
            checkpoint.flag()
            startPromise.complete()
        }
    }
}

As it looks like though, the checkpoints I defined do not get evaluated at all. No matter if I set them to an arbitrary high value or if I do not flag them at all.

I wonder if I am doing something wrong or if this is maybe a bug?

Below you can find the library versions I am using:

implementation("io.vertx:vertx-core:3.8.3")
implementation("io.vertx:vertx-lang-kotlin:3.8.3")
implementation("io.vertx:vertx-web:3.8.3")
implementation("io.vertx:vertx-circuit-breaker:3.8.3")
implementation("io.vertx:vertx-web-client:3.8.3")
implementation("io.vertx:vertx-micrometer-metrics:3.8.3")
implementation("io.vertx:vertx-config:3.8.3")
implementation("io.vertx:vertx-config-yaml:3.8.3")
implementation("io.vertx:vertx-web-api-contract:3.8.3")

testImplementation("org.junit.jupiter:junit-jupiter-api:5.3.2")
testImplementation("org.junit.jupiter:junit-jupiter-params:5.3.2")
testImplementation("io.vertx:vertx-junit5:3.8.3")
testImplementation("com.willowtreeapps.assertk:assertk-jvm:0.19")
testImplementation("io.mockk:mockk:1.9.3")
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.3.2")    
u6f6o commented 4 years ago

I realised that I got checkpoints wrong in the way, that you should not call completeNow() on the test context manually as this is done by the checkpoint classes internally.

A minor adaption fixed this problem:

    @Test
    fun allVerticlesStart(
        vertx: Vertx,
        testContext: VertxTestContext)
    {
        val messageCodecCP = testContext.checkpoint()
        val applicationConfigCP = testContext.checkpoint()
        val stationAmbassadorCP = testContext.checkpoint()
        val restEndpointCP = testContext.checkpoint()
        val allSucceededCP = testContext.checkpoint()

        val bootstrapper = object: ApplicationBootstrapper(listOf()) {
            override fun messageCodecs() = succeedingVerticle(messageCodecCP)
            override fun applicationConfig() = succeedingVerticle(applicationConfigCP)
            override fun stationAmbassador() = succeedingVerticle(stationAmbassadorCP)
            override fun restEndpoint() = succeedingVerticle(restEndpointCP)
        }
        vertx.deployVerticle(bootstrapper, testContext.succeeding { allSucceededCP.flag() })
    }