Upgrading Grails from 2.0 to 2.2

Grails In preparation for my Grails vs. Play Smackdown at Devoxx France next week, I recently upgraded my Grails version of Happy Trails from Grails 2.0.3 to Grails 2.2.1. I ran into a few issues along the way and figured I'd document them here to help others out.

Fixing the source
The first issue I ran into was Spock and Groovy 2 incompatibilities.

| Resolving plugin JAR dependencies
| Error WARNING: Dependencies cannot be resolved for plugin [mail] due to error: startup failed:
Could not instantiate global transform class org.spockframework.compiler.SpockTransform specified at jar:file:/Users/mraible/.grails/ivy-cache/org.spockframework/spock-core/jars/spock-core-0.7-groovy-1.8.jar!/META-INF/services/org.codehaus.groovy.transform.ASTTransformation  because of exception org.spockframework.util.IncompatibleGroovyVersionException: The Spock compiler plugin cannot execute because Spock 0.7.0-groovy-1.8 is not compatible with Groovy 2.0.7. For more information, see http://versioninfo.spockframework.org

I posted the problem to StackOverflow and got a response almost immediately. While this pull request helped me quite a bit, it was ultimately caused by my vision: I had two "geb-spock" dependencies listed in BuildConfig.groovy with different groupIds.

At this point, I also moved all my plugin dependencies from application.properties to BuildConfig.groovy.

The next problem I ran into was a unit test and functional tests failing. The unit testing issue was caused by my Direction model not being in the tests @Mock annotation. After I added it, validation kicked and I recognized my test was invalid. I added @Ignore and continued.

The functional test seemed to be seemed to be caused by Geb and it trying to use the Chrome Driver. One of my tests didn't work with the default HtmlUnitDriver, so I used the ChromeDriver for the one test.

| Running 11 spock tests... 6 of 11
| Failure:  signup as a new user(happytrails.AuthenticatedUserSpec)
|  org.openqa.selenium.WebDriverException: Unable to either launch or connect to Chrome. Please check that ChromeDriver is up-to-date. Using Chrome binary at: /Applications/Google Chrome.app/Contents/MacOS/Google Chrome (WARNING: The server did not provide any stacktrace information)
Command duration or timeout: 45.66 seconds
Build info: version: '2.27.0', revision: '18259', time: '2012-12-05 11:30:53'
System info: os.name: 'Mac OS X', os.arch: 'x86_64', os.version: '10.8.2', java.version: '1.7.0_04'
Driver info: org.openqa.selenium.chrome.ChromeDriver
    at org.openqa.selenium.remote.ErrorHandler.createThrowable(ErrorHandler.java:187)
    at org.openqa.selenium.remote.ErrorHandler.throwIfResponseFailed(ErrorHandler.java:145)
    at org.openqa.selenium.remote.RemoteWebDriver.execute(RemoteWebDriver.java:533)
    at org.openqa.selenium.remote.RemoteWebDriver.startSession(RemoteWebDriver.java:216)
    at org.openqa.selenium.remote.RemoteWebDriver.(RemoteWebDriver.java:111)
    at org.openqa.selenium.remote.RemoteWebDriver.(RemoteWebDriver.java:115)
    at org.openqa.selenium.chrome.ChromeDriver.(ChromeDriver.java:161)
    at org.openqa.selenium.chrome.ChromeDriver.(ChromeDriver.java:107)
    at happytrails.AuthenticatedUserSpec.signup as a new user(AuthenticatedUserSpec.groovy:25)

Even when running "grails -Dgeb.env=chrome test-app", this still happened. This was caused by the fact that I had GebConfig.groovy in test/functional/happytrails. Move it to test/functional solved the problem. I also discovered that I know longer needed Chrome to get this test to pass. Apparently, the HtmlUnitDriver has issues with Grails 2.2, but it seems to work for me.

After getting the Geb configuration fixed, I ran into a functional test failure:

| Running 11 spock tests... 5 of 11
| Failure:  click signup link(happytrails.AuthenticatedUserSpec)
|  org.openqa.selenium.ElementNotVisibleException: Element must be displayed to click (WARNING: The server did not provide any stacktrace information)

Even though I could see the "signup" link when I ran "grails run-app", I could see that it didn't show up when running tests in Chrome. This turned out to be caused by an extraneous <div class="nav-collapse"> I had in my main.gsp. Removing it solved the problem. It's strange that this never showed up with Grails 2.0. My only guess is that Geb someone didn't look at the visibility of the element.

The last testing-related issue I ran into was a InvalidElementStateException:

| Running 11 spock tests... 7 of 11
| Failure:  add new route to region(happytrails.AuthenticatedUserSpec)
|  org.openqa.selenium.InvalidElementStateException: Element must be user-editable in order to clear it. (WARNING: The server did not provide any stacktrace information)

I was able to fix this by changing AddRoutePage.groovy from:

static content = {
    createButton(to: ShowRoutePage) { create() }
    name { value("Name") }
    distance { value("Distance") }
    location { value("Location") }
}

To:

static content = {
    createButton(to: ShowRoutePage) { create() }
    form { $("form") }
}

And then referencing name, distance and location accordingly (form.name, etc.) in AuthenticatedUserSpec.groovy.

CloudBees
After I had everything working locally, I logged into Jenkins on CloudBees. Since I hadn't used it in a while, I had to wait a bit while my Jenkins server was re-commissioned. Once it was up, I tried to select Grails 2.2.1 to build with, but found it wasn't available. After a tweeting this, I learned about Grails Wrapper, found that the latest Grails Jenkins plugin supported it and got everything working. I later discovered that CloudBees does support Grails 2.2.1, I just needed to setup another Grails installation to automatically download and install 2.2.1.

Heroku
The last two issues I ran into were with Heroku. Since I was upgrading everything, I wanted Grails to build/run under Java 7 and use Servlet 3. I changed the appropriate properties in BuildConfig.groovy, configured Heroku and deployed. No dice.

Error Compilation error: startup failed:
Invalid commandline usage for javac.
javac: invalid source release: 1.7
Usage: javac  
use -help for a list of possible options

Sidenote: I tried building with Java 8 on CloudBees, but discovered the searchable plugin doesn't support it.

Compile error during compilation with javac.
/scratch/jenkins/workspace/Happy Trails - Grails 2/work/plugins/searchable-0.6.4/src/java/grails/plugin/searchable/internal/compass/index/DefaultUnindexMethod.java:94: error: reference to delete is ambiguous
                    session.delete(query);
                           ^
  both method delete(CompassQuery) in CompassOperations and method delete(CompassQuery) in CompassIndexSession match

As far as Servlet 3, it was pretty obvious that the Jetty version Heroku uses for Grails doesn't support it. Therefore, I reverted back to Servlet 2.5.

java.lang.NoClassDefFoundError: javax/servlet/AsyncContext
	at org.codehaus.groovy.util.LazyReference.getLocked(LazyReference.java:46)
	at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:59)
	at java.lang.Class.privateGetDeclaredMethods(Class.java:2444)

I sent the Java 7 issue to Heroku Support a few days ago but haven't heard back yet.

Summary
While upgrading Grails from 2.0 to 2.2 wasn't as easy as expected, it is understandable. After all, Grails 2.2 ships with Groovy 2.0, which has a bunch of new features itself. All the issues I ran into were fairly easy to solve, except for Java 7 on Heroku. But hey, what do you expect from a free hosting service?

If you're at Devoxx France next week, I look forward to sharing our research on Grails 2.2.1 vs. Play 2.1.0.

Posted in Java at Mar 22 2013, 09:16:37 AM MDT 2 Comments
Comments:

I am running into a strange issue where I can run these junit tests as standalone just fine. The chrome driver spawns up a new browser and everything works.

However, I am using grails 2.3.5 and when I try to run 'grails test-app functional', no matter what I do I can't get my functional tests to start any of the BrowserDrivers -- firefox, chrome, IE, phantonjs

They all give a timeout exception:

Build info: version: '2.40.0', revision: '4c5c0568b004f67810ee41c459549aa4b09c651e', time: '2014-02-19 11:13:01'
System info: host: 'WA25012L6', ip: '10.67.204.223', os.name: 'Windows 7', os.arch: 'amd64', os.version: '6.1', java.ver
sion: '1.7.0_51'
Driver info: driver.version: BaseTestUtils$getDriver
        at org.openqa.selenium.remote.RemoteWebDriver.execute(RemoteWebDriver.java:567)
        at org.openqa.selenium.remote.RemoteWebDriver.startSession(RemoteWebDriver.java:218)
        at org.openqa.selenium.chrome.ChromeDriver.startSession(ChromeDriver.java:181)
        at org.openqa.selenium.remote.RemoteWebDriver.<init>(RemoteWebDriver.java:113)
        at org.openqa.selenium.remote.RemoteWebDriver.<init>(RemoteWebDriver.java:117)
        at org.openqa.selenium.chrome.ChromeDriver.<init>(ChromeDriver.java:160)
        at org.openqa.selenium.chrome.ChromeDriver.<init>(ChromeDriver.java:149)
        at org.openqa.selenium.chrome.ChromeDriver.<init>(ChromeDriver.java:106)
        at com.jpmorgan.mte.aim.BaseTestUtils.getChromeDriver(BaseTestUtils.groovy:64)
        at com.jpmorgan.mte.aim.BaseTestUtils.getDriver(BaseTestUtils.groovy:36)
        at com.jpmorgan.mte.aim.BaseFunctionalTest.setUp(BaseFunctionalTest.groovy:23)
Caused by: org.openqa.selenium.WebDriverException: Timed out waiting for driver server to start.
Build info: version: '2.40.0', revision: '4c5c0568b004f67810ee41c459549aa4b09c651e', time: '2014-02-19 11:13:01'
System info: host: 'WA25012L6', ip: '10.67.204.223', os.name: 'Windows 7', os.arch: 'amd64', os.version: '6.1', java.ver
sion: '1.7.0_51'
Driver info: driver.version: BaseTestUtils$getDriver
        at org.openqa.selenium.remote.service.DriverService.start(DriverService.java:165)
        at org.openqa.selenium.remote.service.DriverCommandExecutor.execute(DriverCommandExecutor.java:62)
        at org.openqa.selenium.remote.RemoteWebDriver.execute(RemoteWebDriver.java:546)
        ... 10 more
Caused by: org.openqa.selenium.net.UrlChecker$TimeoutException: Timed out waiting for [http://localhost:35364/status] to
 be available after 20004 ms
        at org.openqa.selenium.net.UrlChecker.waitUntilAvailable(UrlChecker.java:104)
        at org.openqa.selenium.remote.service.DriverService.start(DriverService.java:163)
        ... 12 more
Caused by: com.google.common.util.concurrent.UncheckedTimeoutException: java.util.concurrent.TimeoutException
        at com.google.common.util.concurrent.SimpleTimeLimiter.callWithTimeout(SimpleTimeLimiter.java:143)
        at org.openqa.selenium.net.UrlChecker.waitUntilAvailable(UrlChecker.java:79)
        ... 13 more

I am behind a company firewall, not sure if that has anything to do with it.

Posted by Sohel on March 06, 2014 at 03:18 PM MST #

@Sohel: have you tried adjusting your proxy settings to bypass the proxy when using localhost?

Posted by Matt Raible on March 06, 2014 at 03:27 PM MST #

Post a Comment:
  • HTML Syntax: Allowed