views:

211

answers:

0

I've been trying to make GORM throw an optimistic locking error in an integration test. It has been said before that it is not possible to test for concurrent update errors without resorting to multiple threads, but even so I find the behaviour of my test case surprising:

void testOptimisticLocking() {

 new Widget(foo:"bar").save(flush:true)

 // Get the widget and change a property
 def widget = Widget.findByFoo("bar")
 assertNotNull widget
 widget.foo = "baz"
 def widgetVersion = widget.version
 println "widget: $widgetVersion"   // >>>  widget: 0

 // Discard the widget without saving; Hibernate now knows nothing about it
 widget.discard()

 // Get a different instance of the same widget from the database,
 // with the old value for foo
 def sameWidget = Widget.findByFoo("bar")
 assertNotNull sameWidget
 assertFalse System.identityHashCode(sameWidget) == System.identityHashCode(widget)

 // Change the foo property and save
 sameWidget.foo = "bat"
 sameWidget.save(flush:true)

 // Check the version has incremented
 println "sameWidget: $sameWidget.version"         // >>>  sameWidget: 1
 assertTrue widgetVersion < sameWidget.version

 // Check the database hold the "bat" widget
 sameWidget.discard()
 assertEquals 0, Widget.countByFoo("bar")
 assertEquals 1, Widget.countByFoo("bat")

 // Reattach the original widget and try to save it
 assertFalse widget.isAttached()
 widget.attach()
 println "widget: $widget.version"            // >>>  widget: 0
 assertEquals widgetVersion, widget.version
 assertEquals "baz", widget.foo

 // TEST FAILS HERE
 // No error is thrown, and the update fails silently!
 shouldFail(org.hibernate.StaleStateException) {
  assertTrue widget.validate()
  widget.save(flush:true)
  println widget.foo              // >>>  baz
  widget.discard()
  println "baz: " + Widget.countByFoo("baz")    // >>>  baz: 0
  println "bat: " + Widget.countByFoo("bat")    // >>>  bat: 1
 }



}

The re-attached instance of Widget is not persisted to the database, but no exception is thrown!

My test case is rather contrived, but still I am surprised by the result.

Can anybody explain this?