Thursday, July 15, 2010

Initialising Derby Embedded Database before Tests

I am currently messing around with Netbeans Platform and with that has come the need to to run some UI tests and Integration tests against the Derby embedded database used by the application.

Netbeans has a really handy way of hooking into the build script for this stuff. So I modified the build.xml and added the following:




driver="org.apache.derby.jdbc.EmbeddedDriver"
url="jdbc:derby:/home/carl/euctest2.mdb"
userid=""
password=""
classpath="${pathToDerby}derby.jar"
autocommit="true"
caching="true"
onerror="continue">






Now before running my JUnit tests the database would initialised.

With other databases, such as Oracle, I normally use the sql ant task which works great and is simple to set up. However in my JUnit tests I kept getting "Internal Exception: java.sql.SQLException: Failed to start database '/home/carl/euctest2.mdb' with class loader sun.misc.Launcher$AppClassLoader@2bbd86, see the next exception for details.
Error Code: 40000 .... ERROR XSDB6: Another instance of Derby may have already booted the database". So obviously the sql task was not closing its connection with derby correctly. With the Derby embedded database there can only ever be ONE connection and this was still being hogged by the ant task.

So next I googled and found this article. The solution here was to use custom ant tasks to close the connection with derby. But it ended up giving me the same problems. Not sure why. Maybe I did something silly when configuring something.

Anyway my workaround was to use the Ant exec task to run a script that connected to the database and ran my script. So instead of the sql task I had:







And the actual script:


java -cp derbytools.jar:derby.jar -Dij.database=jdbc:derby:/home/carl/euctest2.mdb org.apache.derby.tools.ij /pathToScripts/init.sql


NB: This script would have to be run from the same directory as the derbytools.jar and derby.jar.

And with that I was able to initialise my database before running the tests. And the tests were able to function correctly because the script was closing the connection with Derby correctly. Yay!

Monday, March 8, 2010

Struts2 - StrutsSpringTestCase - Memory Leak

Edit 12/03/2010: This change has been committed to the Struts 2 code base (https://issues.apache.org/jira/browse/WW-3402) and should be available in one of the new versions. I was using version 2.1.8.


I recently ran into some problems while trying to implement JUnit tests for a Struts2 / Spring2.5 project I was doing. The problem was that when running the tests on some machines we were getting OutOfMemory exceptions. At first I thought this was a environment problem as on my machine it was working fine and I had the oldest and crappiest laptop out of everyone. However from what I could see everyone had the same settings and JVM, etc.

Next I fired up JVisualVM and was able to see everyone was having the same problem. The only difference was that my laptop, the only one running Linux, was handling the memory issue better.



Upon further investigation with JVisualVM I was able to see a bunch of instances for my Spring beans via the heap dump (in some cases 50+). This lead me to look further into the code for the org.apache.struts2.StrutsSpringTestCase class and saw that it was loading the applicationContext every single time and not checking whether it had already been set as was the case with my Spring test cases which extended org.springframework.test.AbstractDependencyInjectionSpringContextTests. And because it was static I guess the garbage collector was not removing them.

I am not sure if this behaviour was intended or not. But I overrode the setupBeforeInitDispatcher of the StrutsSpringTestCase with the following. The only difference being the check whether applicationContext is null.


protected void setupBeforeInitDispatcher() throws Exception {
// only load beans from spring once
if (applicationContext == null) {
GenericXmlContextLoader xmlContextLoader = new GenericXmlContextLoader();
applicationContext = xmlContextLoader.loadContext(getContextLocations());
}
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, applicationContext);
}


After that the memory usage issues were resolved, the tests ran a hell of a lot quicker and I did not have a bunch of instances of my spring beans in the heap. I would recommend to anyone using the supplied StrutsSpringTestCase to do the same.



I am aware of other solutions via the Struts 2 documentation that have their own code for the testing of struts action but I prefer to stick with the classes supplied with the Struts 2 code.