Thursday, 18 February 2010

Javassist Enhancement failed

Just spent the last few hours debugging this.

def adoptChild = {
Parent p = Parent.get(params.id)
p.child = Child.findByName(params.name)
assert p.save(flush:true)
redirect(action: 'showParentWithChild', id: p.id)
}

def showParentWithChild() {
Parent p = Parent.get(params.id) // Javassist Enhancement failed stack trace here
render("OK")
}

Turned out that the child class had a private constructor (no idea why). I ditched the constructor and everything was back to normal.

Tuesday, 26 January 2010

Issues with Eclipse 3.5.1 and groovy plug-in

For all you Linuxy peeps.

After installing Eclipse 3.5.1 (SDK version) I installed all the plugins I usually use but when I installed the groovy v2 plugin all my existing plugins disappeared along with the groovy one. Eclipse insisted that they were installed but they weren't there.

It seems that this combination doesn't like "shared installs". My eclipse installation was in /usr/local/eclipse and I was installing the groovy plugin as my regular user. Fail.

There are two solutions.

1 - install a local copy of eclipse.

Simple but it means an eclipse install per user on your machine.

2 - install the groovy plugin as root.

Means that you have to run it as root every time you want to upgrade the plugin.

Choose whichever evil is lesser for you. (I chose #2).

BTW you may also need this magic shell script line

export GDK_NATIVE_WINDOWS=true

if you find that some of the buttons in eclipse don't like being clicked on. Apparently this is due to be fixed in eclipse 3.5.2.

Hope this saves someone a few frustrated hours.


Friday, 8 January 2010

Ham and Chips

Rob Fletcher's blog post on gMock inspired me to try out hamcrest, but I was surprised to find out there's no simple way to match collections in mocked method arguments - the best I could come up with was this...
mock(tagLib).fieldLabel(instanceOf(Map), instanceOf(Closure)).returns("<label></label>")
which doesn't tell me whether I'm calling fieldLabel with the expected attributes. After a bit of searching I found the MapContentMatcher in the Spring Integration library, but didn't want include the whole jar just for that. It also had dependencies other libraries and was heavily typed with generics. Here's the cut down groovy version...
import org.hamcrest.*
import static org.hamcrest.core.AllOf.*
import org.hamcrest.Factory as HamcrestFactory

class MapContentMatcher extends TypeSafeDiagnosingMatcher<Map> {

Object key
Object value

MapContentMatcher(Object key, Object value) {
this.key = key
this.value = value
}

public boolean matchesSafely(Map actual, Description mismatchDescription) {
return actual.containsKey(key) && value == actual[key]
}

public void describeTo(Description description) {
description.appendText("$key:$value")
}

@HamcrestFactory
public static Matcher hasAllEntries(Map expected) {
return allOf(expected.collect { k, v ->
new MapContentMatcher(k, v)
})
}
}

Which can be used thus...
mock(tagLib).fieldLabel(hasAllEntries([id: expectedField, label:expectedHeading]), instanceOf(Closure)).returns("<label></label>")

Thursday, 7 January 2010

Sitemesh layout applied to AJAX response (gotcha)

Grails supports multiple ways to specify a sitemesh layout for your responses. One way I wasn't familiar with is by convention, i.e. if you have a controller 'BookController' and a layout in /views/layouts called book.gsp all the actions in BookController will be rendered with the book layout by default - even if you do render("some text") or render(template: "/sometemplate").

So if you're wondering why all your AJAX responses are getting wrapped up in a sitemesh template this could be the reason. You can stop this by changing the content type to text/plain or by renaming the layout and specifying it explicitly in your gsps using <meta name="layout" content="layoutname"/>.

Wednesday, 7 October 2009

Testing grails scripts

Not sure if everyone caught the new functionality that Peter has put into 1.2M3. It's the ability to test grails scripts. Heres the link to his blog post:
http://www.cacoethes.co.uk/blog/groovyandgrails/testing-your-grails-scripts

Thursday, 17 September 2009

Build Server Woes (mptscsi task abort)

I'm posting this here for two reasons:
  • in the hope that someone out there will find this useful

  • personal therapy
Scenario:

We've got a couple of build servers (x86_64 linux, openVZ) that have been having some disk I/O problems. These boxes (boxen) run various virtual machines related to our product builds - hudson masters & slaves, distribution servers, puppet master, test mail server, munin server... yada yada. You get the idea. They're kinda important.

The problem manifests itself by first reporting errors like the following:

Sep 16 14:28:51 hn3 mptscsih: ioc0: attempting task abort! (sc=ffff880422a348c0)
Sep 16 14:28:51 hn3 sd 0:1:2:0: [sda] CDB: cdb[0]=0x2a: 2a 00 12 b2 fc 9f 00 00 08 00
Sep 16 14:28:51 hn3 mptscsih: ioc0: Issue of TaskMgmt failed!

followed shortly by the volume in question getting offlined into readonly mode:

Sep 16 14:29:41 hn3 mptscsih: ioc0: host reset: SUCCESS (sc=ffff880422a348c0)
Sep 16 14:29:41 hn3 sd 0:1:2:0: Device offlined - not ready after error recovery

This ain't that helpful when you've got a whole load of hungry VMs wanting to write stuff to disk. A closer look at the disk controller yields the following:

>lspci
...
0b:00.0 SCSI storage controller: LSI Logic / Symbios Logic SAS1068E PCI-Express Fusion-MPT SAS (rev 08)
...

A quick search through our messages shows the following related information:

>dmesg | grep -i mpt
Fusion MPT base driver 3.04.07
Fusion MPT SPI Host driver 3.04.07
Fusion MPT FC Host driver 3.04.07
Fusion MPT SAS Host driver 3.04.07
mptsas 0000:0b:00.0: PCI INT A -> GSI 35 (level, low) -> IRQ 35
mptbase: ioc0: Initiating bringup
mptbase: ioc0: PCI-MSI enabled
mptsas 0000:0b:00.0: setting latency timer to 64
Fusion MPT misc device (ioctl) driver 3.04.07
mptctl: Registered with Fusion MPT base driver
mptctl: /dev/mptctl @ (major,minor=10,220)

A quick google turns up quite a few different issues with these controllers but no clear resolution (no surprise).

To cut a (very) long story short we appear to have a solution by using the drivers supplied by LSI rather than those shipped with the latest linux kernel. Patching the kernel (by replacing the drivers/message/fusion folder with the equivalent found in LSI's MPTLINUX_RHEL5_SLES10_PH16-4.18.00.00-1.zip distribution) with version 4.18 of the MPT drivers has yielded an (apparently) stable system, tested under reasonably high load (load average ~20).

Incidentally, for those of you who like acronyms, MPT stands for 'Message passing technology'.

My work here is done.

Monday, 17 August 2009

Dynamic UrlMapping using request parameters

Might be old news to some, but I just found you can assign closures to the action and controller values in URL mappings, e.g.

"/update/$controller/$target" {
action = {
"update" + params.target[0].toUpperCase() + params.target.substring(1);
}
}

Great for mapping restful style urls to meaningful action names, e.g.

"/update/patient/speciality" => PatientController.updateSpeciality

Sunday, 5 July 2009

Selenium IDE 1.0.1

I recently upgraded to Selenium 1.0.1 and found that everything worked fine except that some asserts were failing around stored variables. e.g.

storeText //h2 varname


It turned out that if the text is hidden on the page then all that is stored is ''. In our case it was fixture pages that was returning some data as hidden page elements for reference.

Wednesday, 24 June 2009

Selenium IDE

Just a quick post to say that if any of you out there spend your day resizing and moving Selenium IDE after reopening it (it doesn't remember the previous window state), you can write a little script to do it for you using the handy 'wmctrl' :)

(on linux)
wmctrl -r 'Mozilla Firefox' -e 0,0,25,1330,1125
wmctrl -r "Mozilla Firefox" -b remove,maximized_vert,maximized_horz
wmctrl -a 'Mozilla Firefox'
wmctrl -r 'Selenium IDE' -e 0,1350,25,575,1125
wmctrl -a 'Selenium IDE'



The snippet above moves, unmaximises and raises firefox before moving and activiating the Selenium IDE.

Tuesday, 23 June 2009

Custom constraint

The other day we were doing some refactoring and we started to look into how all our validation is done. We noticed that we have a lot of duplication in our validators and wanted to do something about it. We came across the following blog post that describes how to create a custom validator. This is a great little blog post and allowed us to kill a lot code.

One thing that we did notice was that they suggest that you put the registering of the custom validator in the Config.groovy file. We found this problematic and found that the better solution was to put it in the resources.groovy file. Another problem that we came across was that you needed to register the constraint in the unit test if you wanted to be able to test constraints. This makes sense because resources.groovy isn't called in unit tests.

To register your constraint use the following line of groovy code:
ConstrainedProperty.registerNewConstraint(PhoneNumberConstraint.NAME, PhoneNumberConstraint)

Hopefully this helps with some refactoring.
Glenn