Tuesday, September 24, 2013

Rollback Multiple Datasources in Grails Integration Tests

 

Grails GORM has solid support for using multiple datasources in both 1.3.x with the Datasources plugin, and 2.x with built-in multi-datasource support. This feature allows you to partition your Domain classes and Services to attach to two or more databases. One pitfall you'll encounter though, is that Integration Tests of the secondary datasources DO NOT rollback their transactions on versions of Grails < 2.3 (GRAILS-9771). However, we can borrow the approach from the 2.3 patch to fix our pre 2.3 test classes!

The approach is simply to add rollback steps for the autowired transactionManager in the JUnit test setUp() and tearDown() methods (or Spock setup() and cleanup()). In this example I have a datasource named "db2" so the injected name of the bean is transactionManager_db2. The test then gets a reference to the transactionStatus in setUp() and rolls it back in tearDown(). (Note: this code was written for a Grails 1.3 app but should also work in 2.x)

Of course the downfall of this approach is that you must remember to setup each test class for a non-default datasource (or use a base test class hierarchy). But this code is essential for integration testing your secondary databases until the app has been migrated to Grails 2.3!

As a reference, here is the configuration I was using for the Datasources plugin in Grails 1.3:

Cross-published on the Object Partners blog:  https://objectpartners.com/2013/09/24/rollback-multiple-datasources-in-grails-integration-tests/

Tuesday, July 09, 2013

Configuring Quartz 2 with Spring in clustered mode

 

Aligning the stars to configure Quartz 2.1.7 to work with Spring 3.1.3 in a cluster was surprisingly complicated. The main idea is to run jobs to fire only once per cluster, not once per server, while still providing beans from the Spring managed context and using the latest version of Quartz. The documentation consists essentially of a number of blog posts and stackoverflow answers. So here is one final and (hopefully) more comprehensive summary of the process.

For the TL;DR version, just see the full github gist.

In Quartz.properties we'll want to set useProperties=true so that data persisted to the DB is in String form instead of Serialized Java objects. But unfortunately the Spring 3.1.x CronTriggerFactoryBean sets a jobDetails property as a Java object, so Quartz will complain that the data is not a String. We'll need to create our own PersistableCronTriggerFactoryBean to get around this issue (similar to this blog post and forum discussion).

Additionally, in our Spring config the SchedulerFactoryBean will need to set both the triggers and the jobDetails objects. We also setup the scheduler to use Spring's dataSource and transactionManager. And notice that durability=true must be set on each JobDetailFactoryBean.

By default you cannot use Autowired capabilities in the Quartz Jobs, but this can be easily setup with a AutowiringSpringBeanJobFactory.

You'll also notice that we cannot use MethodInvokingJobDetailFactoryBean because it is not serializable, so we need to create our own Job class that extends QuartzJobBean. If your services are secured by Acegi or Spring Security, you will also need to register an authenticated quartzUser object with the security context.

And finally, we'll want to test that the trigger's Cron expression actually fires when we want it to. Here is an example test case that pulls the cronExpression from configuration and tests that it fires correctly on 2 consecutive days:

Hopefully this helps others in configuring an enterprise-ready Quartz + Spring application to run jobs in a clustered server environment.

Cross-published on the Object Partners blog: https://objectpartners.com/2013/07/09/configuring-quartz-2-with-spring-in-clustered-mode/

Wednesday, January 09, 2013

REST Client Testing With MockRestServiceServer

 

Functionally testing a REST Client is simple with the new MockRestServiceServer if you are using Spring’s RestTemplate to power the client. This is a new feature in Spring 3.2.x but was available via the spring-test-mvc project starting with Spring 3.1.x (extra spring-test-mvc.jar required). The documentation is a little light in the spring reference manual so hopefully this example can help you piece it together.

Previously you might have had unit tests that mocked the RestTemplate but didn’t fully test the calls and error handling provided with the framework. Or you created an elaborate fake server environment just to spit back valid and invalid responses. MockRestServiceServer takes the approach of mocking the server and allowing you to specify expected behavior and responses in your junit test class. This allows you to fully test your handling of the RestTemplate client and server exception classes.

This example only shows how the mock server works. In a real environment you’d probably use RestTemplate with Jackson for object to json mapping and possibly Spring @Async for asynchronous calls.

SimpleRestService is a sample REST client that makes a call to a URL and handles successes and errors by returning them in the result string. We'll use this as an example for our junit test cases:

@Service
public class SimpleRestService {
    @Autowired
    private RestTemplate restTemplate;

    public String getMessage() {
        String result;
        try {
            String httpResult = restTemplate.getForObject("http://google.com",
                                      String.class);
            result = "Message SUCCESS result: " + httpResult;
        } catch (HttpStatusCodeException e) {
            result = "Get FAILED with HttpStatusCode: " + e.getStatusCode()
                       + "|" + e.getStatusText();
        } catch (RuntimeException e) {
            result = "Get FAILEDn" + ExceptionUtils.getFullStackTrace(e);
        }
        return result;
    }
}

The only real setup you need for testing is to configure your IDE to find the static imports. In Eclipse this is in Java>Editor>Content Assist>Favorites. Add these to go along with the hamcrest CoreMatchers and junit Assert that you probably already have.
If using Spring 3.2.x:
org.springframework.test.web.client.match.MockRestRequestMatchers
org.springframework.test.web.client.response.MockRestResponseCreators
If using Spring 3.1.x, the static import classes are named differently:
org.springframework.test.web.client.match.RequestMatchers
org.springframework.test.web.client.response.ResponseCreators

Each test will chain expect() and respond() methods. MockRestRequestMatchers offers many hamcrest matchers to check your request URL, headers, HTTP method, and even json and xpath matchers to check body content. MockRestResponseCreators allows you to easily build both success and error responses.

Also, each test must call mockServer.verify() after the RestTemplate call is made to run the Mock Server assertions.

Setup the MockRestServiceServer in the setUp method:

    @Before
    public void setUp() {
        mockServer = MockRestServiceServer.createServer(restTemplate);
    }

testGetMessage() verifies our URL, GET HttpMethod, and returns a 200 Success with a text message of resultSuccess:

    @Test
    public void testGetMessage() {
        mockServer.expect(requestTo("http://google.com"))
                .andExpect(method(HttpMethod.GET))
                .andRespond(withSuccess("resultSuccess", MediaType.TEXT_PLAIN));

        String result = simpleRestService.getMessage();

        mockServer.verify();
        assertThat(result, allOf(containsString("SUCCESS"),
                       containsString("resultSuccess")));
    }

testGetMessage_404() shows a response with the specific 404 Not Found client http status code:

    @Test
    public void testGetMessage_404() {
        mockServer.expect(requestTo("http://google.com"))
                .andExpect(method(HttpMethod.GET))
                .andRespond(withStatus(HttpStatus.NOT_FOUND));

        String result = simpleRestService.getMessage();

        mockServer.verify();
        assertThat(result, allOf(containsString("FAILED"),
                       containsString("404")));
    }

testGetMessage_500() shows usage of the withServerError() convenience method:

    @Test
    public void testGetMessage_500() {
        mockServer.expect(requestTo("http://google.com"))
                .andExpect(method(HttpMethod.GET))
                .andRespond(withServerError());

        String result = simpleRestService.getMessage();

        mockServer.verify();
        assertThat(result, allOf(containsString("FAILED"),
                       containsString("500")));
    }

Additional matcher test examples can be found in the spring-test-mvc section of the spring 3.2.x github repo.

Hopefully the new mock server in Spring helps you as much as it helped me, by cleaning up and reducing the amount of testing code required in both a reusable and standard fashion. The full java code from these examples are on my github page.

Cross-published on the Object Partners blog: https://objectpartners.com/2013/01/09/rest-client-testing-with-mockrestserviceserver/