Thursday, August 5, 2010

DataOnDemand and Number Fields - Unit tests fail on Short and @Min(1L)

I just opened the following bug (ROO-1176). Though one could look at this and say "what junk", I look at this and marvel at the ease of the work-around. I think this is another positive check for ROO.

This bug covers two separate issues, I have placed them together because they seem to stem from the same code.

FIRST:
Creating an entity with number type fields and applying an @Min constraint greater than zero will fail. It seems that either the getNewTransient_() method or the init() method should take the @Min constraint into account. The init() method sends indexes that are from 0 to 9, but if you have an @Min of 1, the getNewTransient_() will try to populate your field with a zero, which will fail when the object persist() method is called.

SECOND:
Creating an entity with number type fields that are smaller than an int fail when the testPersist() test is called, because it calls getNewTransient__(Integer.MAX_VALUE) which cannot be squeezed into a Short (for example).

WORK AROUND:
Override the getNewTransient__() method and add this to the beginning
if(index == 0){
index = 1;
} else if(index <>
index = index * -1;
}
if(index > Short.MAX_VALUE){
Random rnd = new Random(new Integer(index).longValue());
index = rnd.nextInt(Short.MAX_VALUE);
}

LOG.ROO:
The following is a log.roo for a test.
// Spring Roo 1.1.0.M1 [rev 3a0b8a3] log opened at 2010-08-05 11:46:45
project --topLevelPackage com.things
persistence setup --database HYPERSONIC_IN_MEMORY --provider HIBERNATE
entity --class ~.domain.ShortThings --testAutomatically
field string --fieldName name field number --fieldName thingValue --type java.lang.Short --min 1 --notNull
entity --class ~.domain.LongThings --testAutomatically
field number --fieldName thingValue --type java.lang.Long --min 1 --notNull
perform tests
// Spring Roo 1.1.0.M1 [rev 3a0b8a3] log opened at 2010-08-05 11:54:26


Wednesday, August 4, 2010

Tests randomly fail for simple projects that use MYSQL db but work in HYPERSONIC_IN_MEMORY db

Here is a post I made to the Spring Roo Discussion Forum.

I was noticing that my tests would fail, with "java.lang.AssertionError: Data on demand for 'Thing' failed to initialize correctly" (replace 'Thing' with the name of a random class). My search through the forums found a similar, though not same issue where the reporter said that the tests would eventually pass if you re-ran them often enough. So I started re-running my tests, and noticed that the failing classes would change with each run.

In order to rule out something I may have changed during round-trip engineering, I created a new basic project (embedded below as log.roo-InMemoryTest.txt). To my disappointment, it worked fine. After further attempts with my main project such as re-creating all the integration tests, I decided to go back to my test project and try using the MYSQL database that I was using for my main project (embedded below as log.roo-MySqlTest.txt)... and Voila! My simple little four entity project will fail on random classes and then every now and then pass. (see TestResults.txt embedded below)

In fairness, this might be a bit complex of an example, since the "Thing" entity has a reference to a "Store" and a "Person", and the "Storage" entity has a collection of "Thing"s. However, that's not really that complex of a scenario in real life. Given that the error message in the surefire-report references "failed to initialize correctly", I suspect that the failure may be due to an order of executing the tests... but that's just a guess.

A JIRA Issue has been created: ROO-1127.



log.roo-InMemoryTest.txt


// Spring Roo 1.1.0.M1 [rev 3a0b8a3] log opened at 2010-07-21 10:00:53
hint
project --topLevelPackage eh.inventory
hint
persistence setup --provider HIBERNATE --database HYPERSONIC_IN_MEMORY
hint
entity --class ~domain.Person --testAutomatically
field string --fieldName name --notNull
field string --fieldName address
field string --fieldName phone
entity --class ~domain.Store --testAutomatically
field string --fieldName name --notNull
field string --fieldName address
field string --fieldName phone
entity --class ~domain.Thing --testAutomatically
field string --fieldName name --notNull
field string --fieldName description
field string --fieldName type
field reference --fieldName purchasedAt --type ~.domain.Store
field reference --fieldName purchasedBy --type ~.domain.Person
entity --class ~domain.Storage --testAutomatically
field string --fieldName name --notNull
field string --fieldName location
field string --fieldName type
field set --fieldName things --element ~domain.Thing
controller all --package ~.web
security setup
perform tests
perform tests
perform tests
perform tests
help
exit
// Spring Roo 1.1.0.M1 [rev 3a0b8a3] log closed at 2010-07-21 10:17:13


log.roo-MySqlTest.txt

// Spring Roo 1.1.0.M1 [rev 3a0b8a3] log opened at 2010-07-21 11:09:03
project --topLevelPackage eh.inventory
persistence setup --provider HIBERNATE --database MYSQL --databaseName inventory --userName inventory-admin --password password
entity --class ~domain.Person --testAutomatically
field string --fieldName name --notNull
field string --fieldName address
field string --fieldName phone
entity --class ~domain.Store --testAutomatically
field string --fieldName name --notNull
field string --fieldName address
field string --fieldName phone
entity --class ~domain.Thing --testAutomatically
field string --fieldName name --notNull
field string --fieldName description
field string --fieldName type
field reference --fieldName purchasedAt --type ~.domain.Store
field reference --fieldName purchasedBy --type ~.domain.Person
entity --class ~domain.Storage --testAutomatically
field string --fieldName name --notNull
field string --fieldName location
field string --fieldName type
field set --fieldName things --element ~domain.Thing
controller all --package ~.web
perform tests
// Spring Roo 1.1.0.M1 [rev 3a0b8a3] log opened at 2010-07-21 11:16:23
perform tests
perform tests
perform tests
// Spring Roo 1.1.0.M1 [rev 3a0b8a3] log opened at 2010-07-21 11:35:50


TestResults.txt

==============================
Test One
==============================

roo> perform tests
[Thread-5] [INFO] Scanning for projects...
[Thread-5] [INFO] ------------------------------------------------------------------------
[Thread-5] [INFO] Building inventory
[Thread-5] [INFO] task-segment: [test]
[Thread-5] [INFO] ------------------------------------------------------------------------
[Thread-5] [INFO] [aspectj:compile {execution: default}]
[Thread-5] [WARNING] advice defined in org.springframework.mock.staticmock.AnnotationDrivenStaticEntityMockingControl has not been applied [Xlint:adviceDidNotMatch]
[Thread-5] [WARNING] advice defined in org.springframework.mock.staticmock.AbstractMethodMockingControl has not been applied [Xlint:adviceDidNotMatch]
[Thread-5] [INFO] [resources:resources {execution: default-resources}]
[Thread-5] [WARNING] Using platform encoding (UTF-8 actually) to copy filtered resources, i.e. build is platform dependent!
[Thread-5] [INFO] Copying 4 resources
[Thread-5] [INFO] [compiler:compile {execution: default-compile}]
[Thread-5] [INFO] Nothing to compile - all classes are up to date
[Thread-5] [INFO] [aspectj:test-compile {execution: default}]
[Thread-5] [WARNING] advice defined in org.springframework.orm.jpa.aspectj.JpaExceptionTranslatorAspect has not been applied [Xlint:adviceDidNotMatch]
[Thread-5] [WARNING] advice defined in org.springframework.mock.staticmock.AnnotationDrivenStaticEntityMockingControl has not been applied [Xlint:adviceDidNotMatch]
[Thread-5] [WARNING] advice defined in org.springframework.mock.staticmock.AbstractMethodMockingControl has not been applied [Xlint:adviceDidNotMatch]
[Thread-5] [INFO] [resources:testResources {execution: default-testResources}]
[Thread-5] [WARNING] Using platform encoding (UTF-8 actually) to copy filtered resources, i.e. build is platform dependent!
[Thread-5] [INFO] Copying 0 resource
[Thread-5] [INFO] [compiler:testCompile {execution: default-testCompile}]
[Thread-5] [INFO] Nothing to compile - all classes are up to date
[Thread-5] [INFO] [surefire:test {execution: default-test}]
[Thread-5] [INFO] Surefire report directory: /home/waldo/projects/workspace/inventory/target/surefire-reports
[Thread-5]
[Thread-5] -------------------------------------------------------
[Thread-5] T E S T S
[Thread-5] -------------------------------------------------------
[Thread-5] Running eh.inventory.domain.StoreIntegrationTest
[Thread-5] Tests run: 9, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 4.433 sec
[Thread-5] Running eh.inventory.domain.StorageIntegrationTest
[Thread-5] Tests run: 9, Failures: 1, Errors: 0, Skipped: 0, Time elapsed: 0.153 sec <<<>
[Thread-5] Running eh.inventory.domain.PersonIntegrationTest
[Thread-5] Tests run: 9, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.151 sec
[Thread-5] Running eh.inventory.domain.ThingIntegrationTest
[Thread-5] Tests run: 9, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.142 sec
[Thread-5]
[Thread-5] Results :
[Thread-5]
[Thread-5] Failed tests:
[Thread-5] testFindAllStorages(eh.inventory.domain.StorageIntegrationTest)
[Thread-5]
[Thread-5] Tests run: 36, Failures: 1, Errors: 0, Skipped: 0
[Thread-5]
[Thread-5] [INFO] ------------------------------------------------------------------------
[Thread-5] [ERROR] BUILD FAILURE
[Thread-5] [INFO] ------------------------------------------------------------------------
[Thread-5] [INFO] There are test failures.
[Thread-5]
[Thread-5] Please refer to /home/waldo/projects/workspace/inventory/target/surefire-reports for the individual test results.
[Thread-5] [INFO] ------------------------------------------------------------------------
[Thread-5] [INFO] For more information, run Maven with the -e switch
[Thread-5] [INFO] ------------------------------------------------------------------------
[Thread-5] [INFO] Total time: 14 seconds
[Thread-5] [INFO] Finished at: Wed Jul 21 11:14:44 EDT 2010
[Thread-5] [INFO] Final Memory: 26M/205M
[Thread-5] [INFO] ------------------------------------------------------------------------

==============================
Test two
==============================

roo> perform tests
[Thread-4] [INFO] Scanning for projects...
[Thread-4] [INFO] ------------------------------------------------------------------------
[Thread-4] [INFO] Building inventory
[Thread-4] [INFO] task-segment: [test]
[Thread-4] [INFO] ------------------------------------------------------------------------
[Thread-4] [INFO] [aspectj:compile {execution: default}]
[Thread-4] [INFO] [resources:resources {execution: default-resources}]
[Thread-4] [WARNING] Using platform encoding (UTF-8 actually) to copy filtered resources, i.e. build is platform dependent!
[Thread-4] [INFO] Copying 4 resources
[Thread-4] [INFO] [compiler:compile {execution: default-compile}]
[Thread-4] [INFO] Nothing to compile - all classes are up to date
[Thread-4] [INFO] [aspectj:test-compile {execution: default}]
[Thread-4] [INFO] [resources:testResources {execution: default-testResources}]
[Thread-4] [WARNING] Using platform encoding (UTF-8 actually) to copy filtered resources, i.e. build is platform dependent!
[Thread-4] [INFO] Copying 0 resource
[Thread-4] [INFO] [compiler:testCompile {execution: default-testCompile}]
[Thread-4] [INFO] Nothing to compile - all classes are up to date
[Thread-4] [INFO] [surefire:test {execution: default-test}]
[Thread-4] [INFO] Surefire report directory: /home/waldo/projects/workspace/inventory/target/surefire-reports
[Thread-4]
[Thread-4] -------------------------------------------------------
[Thread-4] T E S T S
[Thread-4] -------------------------------------------------------
[Thread-4] Running eh.inventory.domain.StoreIntegrationTest
[Thread-4] Tests run: 9, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 3.938 sec
[Thread-4] Running eh.inventory.domain.StorageIntegrationTest
[Thread-4] Tests run: 9, Failures: 1, Errors: 0, Skipped: 0, Time elapsed: 0.194 sec <<<>
[Thread-4] Running eh.inventory.domain.PersonIntegrationTest
[Thread-4] Tests run: 9, Failures: 1, Errors: 0, Skipped: 0, Time elapsed: 0.113 sec <<<>
[Thread-4] Running eh.inventory.domain.ThingIntegrationTest
[Thread-4] Tests run: 9, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.181 sec
[Thread-4]
[Thread-4] Results :
[Thread-4]
[Thread-4] Failed tests:
[Thread-4] testFindStorage(eh.inventory.domain.StorageIntegrationTest)
[Thread-4] testFindPersonEntries(eh.inventory.domain.PersonIntegrationTest)
[Thread-4]
[Thread-4] Tests run: 36, Failures: 2, Errors: 0, Skipped: 0
[Thread-4]
[Thread-4] [INFO] ------------------------------------------------------------------------
[Thread-4] [ERROR] BUILD FAILURE
[Thread-4] [INFO] ------------------------------------------------------------------------
[Thread-4] [INFO] There are test failures.
[Thread-4]
[Thread-4] Please refer to /home/waldo/projects/workspace/inventory/target/surefire-reports for the individual test results.
[Thread-4] [INFO] ------------------------------------------------------------------------
[Thread-4] [INFO] For more information, run Maven with the -e switch
[Thread-4] [INFO] ------------------------------------------------------------------------
[Thread-4] [INFO] Total time: 10 seconds
[Thread-4] [INFO] Finished at: Wed Jul 21 11:17:12 EDT 2010
[Thread-4] [INFO] Final Memory: 25M/206M
[Thread-4] [INFO] ------------------------------------------------------------------------

==============================
Test Three
==============================

roo> perform tests
[Thread-6] [INFO] Scanning for projects...
[Thread-6] [INFO] ------------------------------------------------------------------------
[Thread-6] [INFO] Building inventory
[Thread-6] [INFO] task-segment: [test]
[Thread-6] [INFO] ------------------------------------------------------------------------
[Thread-6] [INFO] [aspectj:compile {execution: default}]
[Thread-6] [INFO] [resources:resources {execution: default-resources}]
[Thread-6] [WARNING] Using platform encoding (UTF-8 actually) to copy filtered resources, i.e. build is platform dependent!
[Thread-6] [INFO] Copying 4 resources
[Thread-6] [INFO] [compiler:compile {execution: default-compile}]
[Thread-6] [INFO] Nothing to compile - all classes are up to date
[Thread-6] [INFO] [aspectj:test-compile {execution: default}]
[Thread-6] [INFO] [resources:testResources {execution: default-testResources}]
[Thread-6] [WARNING] Using platform encoding (UTF-8 actually) to copy filtered resources, i.e. build is platform dependent!
[Thread-6] [INFO] Copying 0 resource
[Thread-6] [INFO] [compiler:testCompile {execution: default-testCompile}]
[Thread-6] [INFO] Nothing to compile - all classes are up to date
[Thread-6] [INFO] [surefire:test {execution: default-test}]
[Thread-6] [INFO] Surefire report directory: /home/waldo/projects/workspace/inventory/target/surefire-reports
[Thread-6]
[Thread-6] -------------------------------------------------------
[Thread-6] T E S T S
[Thread-6] -------------------------------------------------------
[Thread-6] Running eh.inventory.domain.StoreIntegrationTest
[Thread-6] Tests run: 9, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 3.931 sec
[Thread-6] Running eh.inventory.domain.StorageIntegrationTest
[Thread-6] Tests run: 9, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.204 sec
[Thread-6] Running eh.inventory.domain.PersonIntegrationTest
[Thread-6] Tests run: 9, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.135 sec
[Thread-6] Running eh.inventory.domain.ThingIntegrationTest
[Thread-6] Tests run: 9, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.126 sec
[Thread-6]
[Thread-6] Results :
[Thread-6]
[Thread-6] Tests run: 36, Failures: 0, Errors: 0, Skipped: 0
[Thread-6]
[Thread-6] [INFO] ------------------------------------------------------------------------
[Thread-6] [INFO] BUILD SUCCESSFUL
[Thread-6] [INFO] ------------------------------------------------------------------------
[Thread-6] [INFO] Total time: 9 seconds
[Thread-6] [INFO] Finished at: Wed Jul 21 11:17:47 EDT 2010
[Thread-6] [INFO] Final Memory: 25M/206M
[Thread-6] [INFO] ------------------------------------------------------------------------

==============================
Test Four
==============================

roo> perform tests
[Thread-8] [INFO] Scanning for projects...
[Thread-8] [INFO] ------------------------------------------------------------------------
[Thread-8] [INFO] Building inventory
[Thread-8] [INFO] task-segment: [test]
[Thread-8] [INFO] ------------------------------------------------------------------------
[Thread-8] [INFO] [aspectj:compile {execution: default}]
[Thread-8] [INFO] [resources:resources {execution: default-resources}]
[Thread-8] [WARNING] Using platform encoding (UTF-8 actually) to copy filtered resources, i.e. build is platform dependent!
[Thread-8] [INFO] Copying 4 resources
[Thread-8] [INFO] [compiler:compile {execution: default-compile}]
[Thread-8] [INFO] Nothing to compile - all classes are up to date
[Thread-8] [INFO] [aspectj:test-compile {execution: default}]
[Thread-8] [INFO] [resources:testResources {execution: default-testResources}]
[Thread-8] [WARNING] Using platform encoding (UTF-8 actually) to copy filtered resources, i.e. build is platform dependent!
[Thread-8] [INFO] Copying 0 resource
[Thread-8] [INFO] [compiler:testCompile {execution: default-testCompile}]
[Thread-8] [INFO] Nothing to compile - all classes are up to date
[Thread-8] [INFO] [surefire:test {execution: default-test}]
[Thread-8] [INFO] Surefire report directory: /home/waldo/projects/workspace/inventory/target/surefire-reports
[Thread-8]
[Thread-8] -------------------------------------------------------
[Thread-8] T E S T S
[Thread-8] -------------------------------------------------------
[Thread-8] Running eh.inventory.domain.StoreIntegrationTest
[Thread-8] Tests run: 9, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 3.928 sec
[Thread-8] Running eh.inventory.domain.StorageIntegrationTest
[Thread-8] Tests run: 9, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.192 sec
[Thread-8] Running eh.inventory.domain.PersonIntegrationTest
[Thread-8] Tests run: 9, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.14 sec
[Thread-8] Running eh.inventory.domain.ThingIntegrationTest
[Thread-8] Tests run: 9, Failures: 1, Errors: 0, Skipped: 0, Time elapsed: 0.141 sec <<<>
[Thread-8]
[Thread-8] Results :
[Thread-8]
[Thread-8] Failed tests:
[Thread-8] testFindAllThings(eh.inventory.domain.ThingIntegrationTest)
[Thread-8]
[Thread-8] Tests run: 36, Failures: 1, Errors: 0, Skipped: 0
[Thread-8]
[Thread-8] [INFO] ------------------------------------------------------------------------
[Thread-8] [ERROR] BUILD FAILURE
[Thread-8] [INFO] ------------------------------------------------------------------------
[Thread-8] [INFO] There are test failures.
[Thread-8]
[Thread-8] Please refer to /home/waldo/projects/workspace/inventory/target/surefire-reports for the individual test results.
[Thread-8] [INFO] ------------------------------------------------------------------------
[Thread-8] [INFO] For more information, run Maven with the -e switch
[Thread-8] [INFO] ------------------------------------------------------------------------
[Thread-8] [INFO] Total time: 9 seconds
[Thread-8] [INFO] Finished at: Wed Jul 21 11:18:27 EDT 2010
[Thread-8] [INFO] Final Memory: 25M/206M
[Thread-8] [INFO] ------------------------------------------------------------------------

Can-Go-ROO Court

Further to my post last year called "It's Easy!" I have started playing around with Spring Roo. Yeah, I know... I may be a sucker for punishment, but I can't resist searching for the holy grail of RAD!

For the un-initiated, ROO is a code generation platform for the Spring Framework. I find it very reminiscent of Ruby on Rails. Do you want to run your unit tests?... Just run the perform tests command. Do you want to change the database you are using?... Just re-run the persistence setup command. Do you want to generate web pages and controllers for your app?... Just run the controller all command. From my perspective, bearing in mind that I have just started using it, some of the best things about ROO are the following:

5 - Command line centric. I find that the command line is often much faster than the IDE. There is something about typing over clicking that just works for me.

4 - Reproducibility. ROO logs all of your commands, so when you want to show someone what you did, or if there is a task that you need to do over and over again, it's easy to pull up a transcript. When I give an example, I will try to include my roo.log in the posting.

3 - Test Driven Development. ROO is very test-aware, and makes testing your work very straight forward.

2 - Aspect Oriented. ROO relies heavily on Aspect Oriented programming. This has many technical reasons for being good, but a beautiful side effect is how clean it leaves the code. There is very little that ROO writes that you can screw up yourself. But if you want to change the way ROO does something, for example take more control in the persistence of an object, just over-ride the persist() method in your code, and ROO will remove it from the aspect code.

1 - No Lock-in. ROO promises an easy transition away from ROO. If you start using ROO and then later decide to "un-Roo" your project, they have a simple set of steps to follow, and voilá, you have a standard Java application.

On the down side, ROO forces you into a Domain Oriented Architecture. If you come from a Service Oriented Architecture background, this can take some getting used to. Now I am not saying here that DOA is worse than SOA, just different. Perhaps at some point in the future, they will find a way to offer both, because in my view they both have strengths and weaknesses.

We'll see how this one fares in the long run, but so far, so good. Part of the exercise this time will be blogging about the journey. This page will serve as an index of sorts. When ever I post an article about Roo, I'll reference it here as well.