Thursday, 2 September 2010

Internet Explorer and the 1 item remaining bug

We've started using Selenium 2 / WebDriver to soak test our application, and were caught once again by a bug in ie7 and ie8 that randomly causes the browser to hang, waiting for some resource to finish loading, even though the page is visible and works fine.

I hit the problem a year or so ago and solved it by hacking something in prototype.js, but can't remember exactly what. Thankfully there's now a more recent version of prototype (we're stuck on grails 1.1.1 which is bundled with prototype 1.6.0), so I upgraded to prototype 1.6.1 and problem solved :)

Saturday, 7 August 2010

Grails and unit#junit;4.8.1: configuration not found in junit#junit;4.8.1:

After upgrading to grails 1.3.x I started getting the following error...


::::::::::::::::::::::::::::::::::::::::::::::

:: UNRESOLVED DEPENDENCIES ::

::::::::::::::::::::::::::::::::::::::::::::::

:: junit#junit;4.8.1: configuration not found in junit#junit;4.8.1: 'master'. It was required from org.grails.internal#Books;0.1 test

::::::::::::::::::::::::::::::::::::::::::::::


A found a few posts suggesting I needed to clear my ivy cache, but that did sfa. Turned out to be something in the jawr 3.3.2 plugin. It went away when I excluded junit from compile scope in the plugins dependencies.groovy


dependencies {
// specify dependencies here under either 'build', 'compile', 'runtime', 'test' or 'provided' scopes eg.
compile ('net.jawr:jawr:3.3.2') {
excludes "mail", "activation", "ejb","jms","jmxri","jmxremote", "junit"
}

Friday, 23 July 2010

IntelliJ v9.0.3 adds support for Grails v1.3.x

JetBrains released IntelliJ IDEA v9.0.3 two days ago, which includes support for Grails v1.3.x, along with nicer SVN merging.

See more details here:

http://www.jetbrains.com/idea/whatsnew/index.html

Sunday, 2 May 2010

AppStatus Plugin 0.1 Released

The AppStatus plugin enables you to easily display useful info about your application.

Install the plugin and navigate to http://yourapp/appStatus to see application.properties, server time and locale.

If you want to see more details you can specify the "providers" in resources.groovy

import uk.co.acuminous.app.status.provider.*
import uk.co.acuminous.app.status.AppStatusConfig

beans = {
appStatusConfig(AppStatusConfig) {
providers = [

// !!!DANGER WILL ROBINSON!!!
// The ApplicationConfigProvider will dump the entire
// contents of Config.groovy including datasource.password
// The SystemPropertiesProvider could also make available
// potentially sensitive system variables

properties: new ApplicationPropertiesProvider(),
config: new ApplicationConfigProvider(),
system: new SystemPropertiesProvider(),
locale: new LocaleProvider()
]
}
}


If you want to add your own providers just write something that implements the Provider interface and add it to the providers map.

Finally if you're already using jQuery and jQuery UI you pick an nicer view

beans = {
appStatusConfig(AppStatusConfig) {
providers = [
// blah
]
view = 'tabs'
}
}

Saturday, 24 April 2010

Pure Genius and mod_jk

I'm currently developing an application for MegaBank which makes heavy use of AJAX. The latest cut was throwing javascript errors in UAT but not in development. A bit of investigation with firebug showed that when an AJAX request returned 404 (which it does if the user supplies a non-existent cost code for example), the next AJAX request would respond with the SSO login page instead of the expected json response. Further investigation showed that the second AJAX response had been served by a different node than the one it was sent to, resulting in the SSO challenge.

Request had a cookie:
jsessionid=ASAD123DFDFS83242SDFASD9234234.node1

Response has a set-cookie header:
jsessionid=SDFSDF234DFSLFSD324234880SDFSDL.node2

i.e. our sticky session was becoming unstuck.

We reported the incident to our support team, who's spanked it straight back over the net with the wonderfully helpful "It's an application config issue". Great. Thanks. Our app doesn't do anything clever with cookies. There is no logout button. We never invalidate the session. We'd already checked that inbound request had the right jsession id, and also that the associated response had a set-cookie header from the wrong node. Furthermore the app server logs show that the second request didn't even hit the right node. Back to web support with an offer to demonstrate the problem and walk through why we believe it's an issue with the load balancer. Even if it turned out to be an issue with the app we would need their help to diagnose it.

Offer accepted. And "Pure Genius" arrives (That's not his real name, but it is what was written on his cuff links). The first words out of his mouth were, "We support 100s of applications and the load balancer works fine. It must be your application". It doesn't mater that this is a bank, where 99% of the applications he supports are legacy and have probably never heard of AJAX. So I walk him through the process, show him the HTTP headers, show him the logs, explain that this only seems to happen after a 404. He goes away and helpfully reports...

"It's an application configuration issue."

Grrrrrrrr. Escalate. Now engineering areinvolved. Helpfully "Pure Genius" has already told them it's a problem with our app, so they've they've prioritised it to the bottom of their queue. Grrrrrrrr. Another round of the escalation game follows and we get someone from engineering who knows what they're doing and isn't wearing blinkers. Guess what? There's a bug in mod_jk which causes it to fail a session over if it gets a non 200 error code with no content, so we added the words "Pure Genius" to the response and we have sticky sessions again. I guess he helped after all.

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