Showing posts with label groovy. Show all posts
Showing posts with label groovy. Show all posts

Thursday, 9 May 2013

Really Grails, Really?

I'm a bit grumpy at Grails today. We're trying to get a Grails app into something like a production-ready state and Grails is repeatedly showing me that it really doesn't want to be there.

 A couple of weeks ago, our Ops guys requested (completely reasonably) that the app be configurable "externally" - i.e. tweak a properties file somewhere on the filesystem, restart the app, and bingo.

Rather than the godawful files-in-classpath mess that results in excessive trawling through unpacked WAR files in Tomcat's webapps directory, followed by nervous vi-ing and praying something doesn't come along and blow away your delicate changes. Nod sagely if you've done that crap about a bazillion times.

So the change was duly made, there are a million "externalise your Grails config" blogs out there, Google away if you care. But they almost all are totally on the Groovy Kool-Aid: the externalised config files are .groovy files - curly brackets and all that. Our guys not only don't like that (don't blame them), but they won't allow it for security reasons - you can put executable "stuff" in such a file and do who-knows-what to a system.

So the Grails Doco on externalised config says .properties files are A-OK. Great! Let's try something then:

In our externalised property file:
config.feature.enabled = false
In a Grails controller, some time later:
if (config.feature.enabled) {
  println "Combobulating the Doodads"
} else {
  println "Enabled I Am Not"
}

Execute.

And get very, very VERY annoyed.


Monday, 22 April 2013

When Grails Attacks

I've been pretty harsh on Grails before but I'm starting to appreciate some of its charms now. Of course I still think Play! 2.1 is even better but must admit there are fewer OMFGWTFBBQ?!?! moments with Groovy compared to Scala. That might just be me and my functional-programming newb-ness, or it might just be that while Groovy is a new front door on Java, Scala is a new top floor, roof and swimming pool out the back...

 Anyway.

Innocently trying to run some unit tests on an existing set of Grails controllers. Everybody else seems to be running them fine, but I get:

| Running 9 unit tests... 1 of 9
| Failure:  testThatAAABBDDD(BrokenAssTests)
|  java.lang.NullPointerException: Cannot set property 'method' on null object
 at BrokenAssTests.setup(BrokenAssTests.groovy:155)
| Running 9 unit tests... 2 of 9
| Failure:  testThatEEEFFGGG(BrokenAssTests)
|  java.lang.NullPointerException: Cannot set property 'method' on null object
 at BrokenAssTests.setup(BrokenAssTests.groovy:155)

The setup() method in question:
  @Before
  public void setup() {
    request.method = 'GET'
  }

 Same Groovy version, same Grails version, very similar Java version (1.7.0_11 vs 1.7.0_21, hardly a biggie), so what's going on?

I'm running Ubuntu 12.04, everyone else is on Macs (a story for another day).

A great deal of digging and Googling later, and here's what's going on:


  • Grails 2.0 introduced the TestFor annotation which automagically mixes in the ControllerUnitTestMixin  
  • As one of its many magic tricks, the ControllerUnitTestMixin adds mocked request and response objects into the test scope
  • This magic is performed in method bindGrailsWebRequest() which if you persue the documentation, has the JUnit 4 @Before annotation applied
  • The only ordering guarantee about @Before evaluation is "superclass comes before subclass"
  • But a mixin is NOT a superclass!
  • And so the order of @Before evaluation when using Grails' test mixins is essentially OS/JVM dependent
In my case, I was the unlucky "canary" on the "different" platform who encountered the bug. The "fix", such as it was, was manually calling the mixin method just-in-time in "our" setup() method:
  @Before
  public void setup() {
    if (!request) {
      bindGrailsWebRequest()  // Make sure request is visible - the ordering of @Befores is not guaranteed :-(
    }
    request.method = 'GET'
  }
I don't like it much, and hopefully the next version of Grails rectifies this, but for me it's just another one of those "too many layers of magic" problems that in my experience seems to afflict the Groovy world more than others.