Grails 3.1.9 Functional Test Port

With Grails 3.1.9 and above we now get a default port for Functional tests that is randomly assigned. This is a great feature that was added in with this commit.

While this is a nice addition our tests which were not using Geb were left broken this is due to the fact we now need to know what port was selected for a given run of the tests. So our old test:

@Integration
class UserEndpointSpec extends Specification {  
  def "POST new user"() {
    given:
    ResponseEntity<Map> resp
    RestTemplate restTemplate = new RestTemplate()
    def requestBody = [
        email: 'phil@aol.com',
        fullName: 'Phil',
        password: 'password',
        username: 'phil'
    ]

    when:
    resp = restTemplate.postForEntity("http://localhost:8080/users", requestBody, Map)

    then:
    resp.statusCode == HttpStatus.NO_CONTENT
  }
}

Was broken since the app no longer started on 8080, but we can fix that with a new property that the @Integration annotation adds which is serverPort so the test becomes:

@Integration
class UserEndpointSpec extends Specification {  
  def "POST new user"() {
    given:
    ResponseEntity<Map> resp
    RestTemplate restTemplate = new RestTemplate()
    def requestBody = [
        email: 'phil@aol.com',
        fullName: 'Phil',
        password: 'password',
        username: 'phil'
    ]

    when:
    resp = restTemplate.postForEntity("http://localhost:${serverPort}/users", requestBody, Map)

    then:
    resp.statusCode == HttpStatus.NO_CONTENT
  }
}

If you are wondering how serverPort is actually set you can see it happening inside IntegrationTestMixinTransformation. It will add a property to the test class with the port.

Grails 3 Metrics and Path Variables

Grails 3 is built on top of SpringBoot on of the key components of SpringBoot is Actuator. Actuator sets up Metrics and healthchecks all the things modern services are expected to just have. Grails 3 ships with the /metrics endpoint turned on meaning every request gets tracked by default the endpoint will be available to all logged in users assuming you are using some security.

Most of the time this wouldn’t be an issue and would be very nice to have those metrics the problem comes to the fact that currently all requests with Path Variables are treated as different endpoints. So requests to /items/$id of /items/123 and /items/333 will end up listed as two different metrics with the value of the path variable for everyone to see. This exposes more data than intended and doesn’t provide really useful metrics. Its due to an issue in Actuator GH Issue 5875. So until this is fixed I recommend turning off metrics collection all together for Grails 3.

You can do that with the following config in your application.yml

endpoints:
  metrics:
    enabled: false

I just keep the metrics endpoint off since the health-checks are useful and something we depend on others may want to just shut of Actuator fully which can be done with:

endpoints:
   enabled: false

Thanks to Ryan Vanderwerf for help on this issue.

RxJava and Ratpack Testing Gotcha

Ratpack tends to stay out of the way when building out functionality so there are times you may make classes that use RxJava and Guice without anything from Ratpack. But there is one caveat during testing, if you are using RxJava in a unit test without any Ratpack integration that will work just fine. As soon as there is another test in the same execution that uses Ratpacks integration (ratpack.dependency("rx")) with RxJava such as a functional test you will start seeing the following error in the standard out:

java.lang.IllegalStateException: Cannot install RxJava integration because another execution hook (class rx.plugins.RxJavaObservableExecutionHookDefault) is already installed
	at ratpack.rx.RxRatpack.initialize(RxRatpack.java:101) ~[ratpack-rx-1.1.0.jar:na]
	at ratpack.rx.RxRatpack$initialize$0.call(Unknown Source) ~[na:na]
	at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:48) [groovy-all-2.4.4.jar:2.4.4]
	at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:113) [groovy-all-2.4.4.jar:2.4.4]
	at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:117) [groovy-all-2.4.4.jar:2.4.4]

Many of your functional tests will start failing with very unpredictable results. What is happening is any use of RxJava that runs before the Ratpacks integration will set up an execution hook meaning the strong guarantees about execution Ratpack provides will not be available leading to unpredictable behavior. This is an easy fix for the test, we just need Ratpack to setup the hook in these other tests we can simply add the following to a Spock spec:

import ratpack.rx.RxRatpack

def setupSpec() {
  RxRatpack.initialize()
}

The same initialize can be used in your favorite testing tools, it just needs to happen before the tests are run once and thats what setupSpec gives us in Spock.

Grails 3 and JaCoCo

Now that we have Gradle as our build system we have a whole range of plugins we can use directly in Gradle. For code coverage I am using the JaCoCo plugin. To use it with Grails we just apply the plugin to the build. By default you will get a HTML report, in the build/report/jacoco directory.

apply plugin: "jacoco"

But Grails 3 has it’s test phases split up, out of the box you will have test and integrationTest. Starting with the JaCoCo gradle plugin, you will get coverage for just your test phase.

We can easily fix this by letting JaCoCo know about the phases we want reported on so we just adjust the config for the jacocoTestReport task.

jacocoTestReport {
	executionData integrationTest, test
	//...
}

Vertx3 and Gradle Application Plugin

Vertx 3 is a great step forward you can now work with Vertx without having to install a command line tool to run it. Now you can use standard Maven or Gradle to run your application.

With Gradle the samples given all are based on the use of the great Shadow Plugin. While this is good for deployments and most local development I missed a few of the features of the application plugin.

Set up your build.gradle with the following:

//...

apply plugin: 'java'
apply plugin: 'application'
apply plugin: 'com.github.johnrengelman.shadow'

//...

dependencies {
	compile "io.vertx:vertx-core:${project.vertxVersion}"
	compile "io.vertx:vertx-apex:${project.vertxVersion}"
	compile "io.vertx:vertx-auth-service:${project.vertxVersion}"
}

def mainVerticle = "groovy:ex.main.RestVerticle"

mainClassName = "io.vertx.core.Starter"
run {
	args = ["run", mainVerticle]
}

jar {
	manifest {
		attributes 'Main-Verticle': mainVerticle
	}
}

shadowJar {
	classifier = 'fat'

	mergeServiceFiles {
		include 'META-INF/services/io.vertx.core.spi.VerticleFactory'
	}

	dependencies {
		exclude(dependency('io.vertx:codegen'))
		exclude(dependency('junit:junit'))
		exclude(dependency('org.mvel:mvel2'))
		exclude(dependency('log4j:log4j'))
	}
}

In this case we are deploying Vertx with verticles. So we set the main verticle which does our setup. I define that as variable since we will need to use it in two places once as an argument to the Vertx starter and again in the Jar manifest. You will note the main verticle includes the type in our case it is Groovy but if you are doing JavaScript you would change it there.

Now we can take advantage of the application plugin allowing us to use the simple gradle run instead of depending on the Shadow plugin it is also faster then rebuilding the whole fat jar.

But the main reason I wanted to use the application plugin was the ability to debug easily.

$ gradle run --debug-jvm

That command will allow us to attach a debugger to 5005 default. With these changes Vertx 3 development fits in along side my other Grails 3 and Java 8 projects easily.