Tuesday, July 30, 2013

Non-transactional tests with Spring and H2

The general paradigm for testing Spring based application back-end is to use a sort of unit testing which loads the whole application (the application context) and performs certain tests on it. Spring provides all sort of helper classes among others AbstractTestNGSpringContextTests and AbstractTransactionalTestNGSpringContextTests. I don't know when that decision happened but we always used the transactional one hence every test method run in a separate transaction which was rolled back after each method. It seems to me that such an approach is prevalent in current development yet it is as well flawed.

I bet you encountered cases when the test cannot be transactional, you want to test that your fix for a concurrent race condition works, the locking on the DB does really prevents another user to access something, etc. So you write a non-transactional test class, annotate it with the Spring annotation @DirtiesContext(classMode = ClassMode.AFTER_EACH_TEST_METHOD) and you're done. The context is reloaded several times for the start so it's not a big deal. But then you write tens of non-transactional tests and all of a sudden build with tests takes time.

That happened to us and made us thinking, do we need to recreate application context so often? The only reason we do it is that the DB is polluted by the non-transactional tests data. I started the investigation. We use in-memory H2 for our tests. I found that H2 has a wonderful feature which let's you drop its content easily: All you need is the following method in your test parent class:

So no more context recreation. It sped our test build from 1:30 to 55 seconds, boohoo. But than a heretic thought began to creep in our brains. What if we don't need to wrap each test method in a transaction? What if we don't gain much speed there? What if we actually oversee a bug here and there as our tests don't work the same as when client works with the application?

We gave it a try and made all tests non-transactional. The build takes the same time as before as populating and dropping in-memory DB is apparently not an issue, we would do the same in separate transactions anyway. The tests now mimic exactly use cases we want to test as often many transactions happen before the app is in certain state.

We found three bugs straight away. I hope you find some too.

Thursday, January 3, 2013

Non-blocking server push with Atmosphere, Wicket and Spring Security

Previous blog post described how to make Wicket, Spring Security and Atmosphere work together. However, it covered only one part of the story - the blocking transport technique (e.g. long polling). We tried to enable non-blocking protocol and run instantly into several problems emerging mainly from the necessity to use Spring Security filter chain along with Wicket filter and Atmosphere servlet:

The problems were:
  • Spring Security authentication did not work with NIO (non-blocking) connector on Tomcat. My guess is that the filter was not applied.
  • AtmosphereServlet is configurable via atmosphere.xml where you define AtmosphereHandlers. The problem is that you cannot define multiple filters similarly to web.xml.
  • AtmosphereFramework has a regexp which is used to map request path to AtmosphereHandlers mapped to /*. It does not contain underscore which is part of default form-login processing-url of SpringSecurity (j_spring_security_check).
Let's see how we dealt with these problems.

First of all, install the newest version of Tomcat 7 as non-blocking support was developed rather recently and it may not work properly with older versions. We used Tomcat 7.0.34.

Modify the HTTP connector in server.xml

Atmosphere will initiate non-blocking transport only if you include some context.xml in META-INF or exclude atmosphere-compat-tomcat7 from your classpath. We encountered a problem with SpringSecurity SessionFixationProtectionStrategy as request.getSession(true) did not return new session but this was fixed by using newer version of Atmosphere runtime. Our respective pom.xml part looks like this:
Then we need to define the two filters inside AtmosphereHandler defined in atmosphere.xml. We decided to do it programmatically. Here is our atmosphere.xml

And the CustomAtmosphereHandler looks like this:

CustomAtmosphereHandler was inspired by Atmosphere ReflectorServletProcessor. It creates both SpringSecurity and Wicket filters programmatically. In case of Wicket it loads the application in the same manner as the org.apache.wicket.spring.SpringWebApplicationFactory.
Custom FilterConfig gives us control over init parameters. Interestingly, Wicket-Atmosphere integration uses in the mapping filter mapping path from InitParam instead of the filter path set on the WicketFilter. Thus we need to add the init param FILTER_MAPPING_PARAM. We decided to do it this way because otherwise we will have filter configuration scattered over CustomAtmosphereHandler and web.xml.

Our web.xml is then fairly simple:

Now one last finishing touch:) We need to alter default SpringSecurity path so that it is mapped to our CustomAtmosphereHandler so modify the form-login line in your spring-security.xml:

Here is a link to a sample application: http://dl.dropbox.com/u/71731051/push-test.zip