jponge / vertx-gradle-plugin

An opinionated Gradle plugin for Vert.x projects
Apache License 2.0
113 stars 15 forks source link

vertxDebug not working if custom launcher set #36

Closed u6f6o closed 4 years ago

u6f6o commented 4 years ago

I configured both the mainVerticle and the launcher property in my gradle build file. The reason is that I use a custom launcher in order to configure certain vertx options:

override fun beforeStartingVertx(options: VertxOptions) {
    options.metricsOptions = MicrometerMetricsOptions()
            .setEnabled(true)
            .setMicrometerRegistry(configureMeters())
            .setPrometheusOptions(VertxPrometheusOptions().setEnabled(true))
            .setLabels(
                EnumSet.of(
                    Label.HTTP_PATH,
                    Label.HTTP_METHOD,
                    Label.HTTP_CODE
                )
            )
}

When I execute ./gradlew vertxRun, my application starts and everything works as expected. If I execute ./gradlew vertxDebug instead, it fails with the following message:

> Task :vertxDebug
Listening for transport dt_socket at address: 5005
Usage: java foobar.ApplicationLauncher [COMMAND] [OPTIONS]
            [arg...]

Commands:
    bare      Creates a bare instance of vert.x.
    list      List vert.x applications
    run       Runs a verticle called <main-verticle> in its own instance of
              vert.x.
    start     Start a vert.x application in background
    stop      Stop a vert.x application
    version   Displays the version.

Run 'java foobar.ApplicationLauncher COMMAND --help' for
more information on a command.

I had a look at the source code and I think the reason might be that the code of the vertxRun configuration is different to the code of the vertxDebug configuration. If I am not mistaken, this issue could be fixed by using the same code in the vertxDebug method.

u6f6o commented 4 years ago

I applied the proposed solution in my projects local buildSrc directory and can confirm, that ./gradlew vertxDebug works correctly afterwards, having both main verticle and launcher configured.

I could offer to create a pull request but one problem I am struggling with is, that I do not know how to test the gradle tasks vertxRun and vertxDebug directly with the GradleRunner class as these two do not terminate and test execution hangs.

u6f6o commented 4 years ago

I had a look at Spring's bootRun integration test in order to learn how they test the bootRun task without using a separate thread or the like to build the GradleRunner. Turns out, they do not use a fully-fledged spring boot application to test this task, instead they use a fake application class with a main that terminates as entry point for the test.

Furthermore, I asked in the gradle forum but I suppose there is currently no option to use the GradleRunner for tasks that run forever.

I could think about 2 ways how to test the vertxDebug task in the vertx-gradle-plugin project:

  1. Leave the sample projects as they are and execute the gradle runner build in a separate thread and wait for a desired output:

    @Test(timeout = 20_000)
    fun `check that the application does run with custom launcher`() {
    val `in` = PipedInputStream()
    val reader = BufferedReader(InputStreamReader(`in`))
    val out = PipedOutputStream(`in`)
    
    val runnerTask = Thread {
    GradleRunner.create()
      .withProjectDir(File("src/test/gradle/simple-project"))
      .withPluginClasspath()
      .withArguments("clean", "vertxRun")
      .forwardStdOutput(out.writer())
      .build()
    }
    runnerTask.start()
    reader.lineSequence().forEach { line ->
    if (line.startsWith("Starting vert.x application...")) {
      val response = Unirest.get("http://localhost:18080/").asString()
      Unirest.shutdown()
      assertThat(response.status).isEqualTo(200)
      assertThat(response.body).isEqualTo("Yo!")
      return
    }
    }
    fail<String>("Nope!")
    }
  2. Adapt the given sample projects and instead of letting them run forever, start them up, print a message to the console that can be looked up in the unit test.

My personal preference would be 2. as we would only need the GradleRunner class and basic assertions. What do you think?