Saturday, February 16, 2013

Continous Integration with Dropwizard, ClassRule, ClassPathSuite, Maven and RestAssured

I recently had a chance to do several projects using dropwizard. I found it to be a great tool. Basically, it's a rest container built using embedded jetty, jersey, guava, logback bundled with it. Details can be seen here . This tool was developed and open sourced by yammer.

DropWizard is started as an executable jar file with java -jar .. command. By default DropWizard's main thread blocks after starting embedded instance of jetty. This causes some issues with continous integration as during build process server has to be started, and stopped so tests can be executed against container. Out of the box this could be achieved by executing jar from inside test code, (using Runtime.exec()) but this is really undesirable solution.

Fortunately, this has been addressed by several people by using ServerCommand (available since release 0.6.1 - I believe).
See links below:
forum
EmbeddableServerCommand
TestableServerCommand

I've created a project to wrap all this together in a bundle which makes it easier to get started. Project is posted on github in dropwizard-ci repository.

Key source classes
Here are key classes in the project

EmbeddableServerCommand -  pretty much copy/paste from the gist listed above.
EmbeddableService  - wraps command ensuring that EmbeddableServerCommand has been added to bootstrap, 
 Services extending it, just have to make sure to call super.initialize(..).

Key test classes
NOTE: Most of the credit for test classes listed below belong to David Drake (who's blog can be found here ), as he was leading development effort of classes below.

TestContext - starts and stops server when needed. 
Notice that TestContext is instantiated with false flag passed into constructor in each test except in the test suite (DWCITestSuite) where it's created with true value. See this piece of code in TestContext class:
    @Override
    protected void starting(Description description) {
        if (forSuite == IN_SUITE) {
            startDropWizardServer();
        }
    }
This avoids starting and stopping container for each test when running within test suite, but makes it happen when runing individual tests

Testing
See HelloResourceIT. Running it as a test from an IDE will start server (because overriden starting method of TestWatcher (TestContext) instantiated in the class ), and verifies whether endpoint returns expected response using restassurred client.

Maven builds.
Maven plugin is configured to only execute DWCITestSuite, which runs all tests.

 maven-surefire-plugin
  
    
      **/DWCITestSuite.class
    
  
 
To test the setup pull project down from the github at: https://github.com/pwyrwa/dropwizard-ci.git and execute following maven command:
mvn clean test
Check standard output from maven build to verify that both integration tests have been executed, but server has been started only once.

Setup shown above blends unit and integration tests (as they're all executed in test phase). I'll fix that in my next post and update project in github.

1 comment:

  1. Thanks for this, I've created a fork of your github repo with the cpsuite dependency removed for anyone who is trying to build and run the code but does not have this jar in their maven repository:

    https://github.com/alexspurling/dropwizard-ci

    ReplyDelete