Monday, June 14, 2010

Fix "junitvmwatcherXXX.properties could not be found" during grails unit test

Recently, I forked grails-core to fix the GRAILS-5876. But, when I modified and ran "gradlew testSingleMockUtils", I got a java.io.FileNotFoundException:
java.io.FileNotFoundException: D:\grails\grails-core\junitvmwatcher476409304.properties(no such file or directory)
Compile phase (sources compile and tests compile) was ok, the exception was thrown from the Unit Test phase, and the unit test didn't be launched at all. I tried another build approach, "ant -Dtest=MockUtils test", and got the same exception.
This is very confusing, beacause I launched unit tests successfully under grails 1.2. Google could not give me any suggest this time. Taking a close look at the output on the screen, I found some messages which showed the memory was not enough for running unit tests. That is it!
I compared the unit-test.xml in my local git repository with the one in grails 1.2 dist, and found there was some diffrence in the target "run-test" between these two files:
  • my local git repository:
  •   <target name="run-test" depends="defineTestingScope, build-test,-jar-app-files" unless="_skipTests_">
    <delete dir="${grails.test.reports}" />
    <mkdir dir="${grails.test.reports}" />
    <echo>Test being run ${test} from ${grails.test.build}</echo>
    <junit fork="true" forkmode="perBatch" clonevm="true" printsummary="on">
    <!-- only fork VMs as needed -->
    <sysproperty key="grails.cli.testing" value="true"/>
    <jvmarg line="-server -Dgroovy.grails.joint=${groovy.grails.joint} ${args.memory} ${args.debug}"/>
  • grails 1.2 dist:
  •   <target name="run-test" depends="defineTestingScope, build-test,-jar-app-files" unless="_skipTests_">
    <delete dir="${grails.test.reports}" />
    <mkdir dir="${grails.test.reports}" />
    <echo>Test being run ${test} from ${grails.test.build}</echo>
    <junit fork="true" forkmode="perBatch" clonevm="true" printsummary="on">
    <!-- only fork VMs as needed -->
    <sysproperty key="grails.cli.testing" value="true"/>
    <jvmarg value="-server" />
    <jvmarg value="-Xmx1G" />
    <jvmarg value="-Xms256m" />
    <jvmarg value="-XX:MaxPermSize=256m"/>
    <jvmarg value="-Dgroovy.grails.joint=${groovy.grails.joint}" />
    ...
The solution is obvious. Replacing the last statement in the former build script with the last 5 statements in the latter, I could run the unit test successfully again. Now, let's fix the gradle build script. Open the unit-test.gradle, and search the following statement:
options.forkOptions.jvmArgs = ["-server", "-Xmx1500m", "-Xms256m", "-XX:MaxPermSize=256m", "-Dgroovy.grails.joint=true"]
Change "-Xmx1500m" to "-Xmx1G", and save the file. Then you should run "gradlew testSingleMockUtils" successfully.
There are other reasons can cause "junitvmwatcherXXX.properties could not be found", you could get some advices from google using the key works "ant junitvmwatcherXXX.properties".

Saturday, June 12, 2010

Return partial Domain Class

Reading the description of GRAILS-5791, I found this interesting question. The asker expects the JSON returned by "domain as JSON" not including some properties he lists.
There are serval solutions, the comments following that question have list two ones. Here I will give my own one. In my way, I will add one method to the domain classes in the grails app: part, which returns a map including or excluding some properties of a domain class. Then you can render the result map as JSON. The following shows how to use this method:
  def job= Job.get(1)

//include
render job.part(include:['categorys', 'source']) as JSON

//except
render job.part(except:['id', 'version']) as JSON
This sample is very intuitive. The first statement will result in a JSON only including categorys and source; the JSON rendered by second statement will include all the properties of the domain class except id and version.
Using part, you can make your life easier and also make your code more grace.
Now, let's see how to adding the part method to the domain classes:
  • how: In groovy, in order to add a method to an object dynamiclly, we can use mop.
  • when: In grail app, there is a file named BootStrap.groovy, where is a good place to do some initialization works.
When we know how and when to do that job, here is the detail:
import org.codehaus.groovy.grails.orm.hibernate.support.ClosureEventTriggeringInterceptor as Events

class BootStrap {
def grailsApplication

def excludedProps = [Events.ONLOAD_EVENT,
Events.BEFORE_DELETE_EVENT, Events.AFTER_DELETE_EVENT,
Events.BEFORE_INSERT_EVENT, Events.AFTER_INSERT_EVENT,
Events.BEFORE_UPDATE_EVENT, Events.AFTER_UPDATE_EVENT]

def init = { servletContext ->
grailsApplication.domainClasses.each{ domainClass ->
domainClass.metaClass.part= { m ->
def map= [:]
if(m.'include'){
m.'include'.each{
map[it]= delegate."${it}"
}
}else if(m.'except'){
m.'except'.addAll excludedProps
def props= domainClass.persistentProperties.findAll {
!(it.name in m.'except')
}
props.each{
map[it.name]= delegate."${it.name}"
}
}
return map
}
}
}
def destroy = {
}
}
You also can change this to a plugin, then you can use this feature across different grails apps. Hope you enjoy this.