Wednesday, October 6, 2010

Grails EasyB and Selenium

Hi there,

having EasyB in your grails project is handy. There's no question about it. However combining it with Selenium RC adds a whole new flavor to the mixture!

Let's examine a step-by-step scenario on how to include both grails-easyb and selenium-rc in a brand new application, then let's create a simple home controller with one action and let's test it using the potent mix of behaviors and remote test execution :)

Step 1: Create a new application

This one is extremely easy:
grails create-app example
Step 2: Install the grails-easyb plugin.

This one is extremely easy to:
grails install-plugin easyb
Step 3: Install selenium rc.

Well, there's 4 things to it.
a) download the Selenium RC package
b) extract the driver (selenium-java-client-driver.jar) into the lib folder of our example application
c) extract the Selenium RC server (the whole folder selenium-server-1.0.3)
d) run Selenium RC server
java -jar selenium-server.jar
Step 4: Create the home controller.

As you might have already guessed:
grails create-controller home
Step 5: Add some meat to the index action.

Let's change the default empty implementation of our index action into
[ message: "Hello, world!" ]
Step 6: Create a functional (yes! functional test at last!) in test/functional (this folder does not exist at first so you have to create it yourself). I'll call it MyFirstFunctional.story
import com.thoughtworks.selenium.*

before "start selenium", {
given "selenium is up and running", {
selenium = new DefaultSelenium(
"localhost", 4444, "*iexplore",
"http://localhost:8080/example/"
)
selenium.start()
}
}

scenario "Will show 'hello, world!' message", {
when "home/index opens", {
selenium.open("home/index")
}

then "the text 'Hello, world! appears on the page", {
selenium.isTextPresent("Hello, world!")
}
}

after "stop selenium", {
then "selenium should be shutdown", {
selenium.stop()
}
}
WARNING: you might naturally want to move the "after" section right below the "before" section. DON'T EVER DO THAT! EasyB test segments are executed in the order they have been declared so if you do that selenium will get stopped before any scenario can be executed!

Step 7: Run the test and see it fail (we have no view just yet)
grails test-app functional:easyb
Step 8: Create the view (/views/home/index.gsp).
Message: ${message}
Step 9: Execute the test and see it pass:
grails test-app functional:easyb

I hope this will cut down the time you spent implementing easyb- and selenium-enabled functional tests clearing any misunderstandings you might have after reading online docs (they suck big time!).

Do I hear "That's a lot of work, man!"??? Well if you're really that lazy grab the ready-to-run package here and enjoy the rest of the evening :)

Have fun!

Tuesday, October 5, 2010

Grails 1.3.5 Released!

Hi there all you Grails geeks!

Yesterday Grails 1.3.5 was released :) With one small addition from me:

class HomeController {

def index = { }

def save = { LoginCommand login ->
println "login.username: ${login.username}"
println "login.password: ${login.password}"
println "comment.text: ${comment.text}"

redirect action: "index"
}
}

class LoginCommand {
String username
String password
}

This is pretty basic stuff, right? We're creating a command object, giving it as the closure parameter and values from the form (named "username" and "password" get deserialized into this object.
What was missing though is the fact that not all of the form parameters need to be bound to the same command object. In fact there are times when more than one object allows for better re-use and/or separation of concerns.
The elements that need to be deserialized into multiple command objects should be prefixed with command type (by convention).

So "LoginCommand" becomes "login.", "CommentCommand" becomes "comment." and for example "VeryLongAndComplexCommand" becomes "very-long-and-complex.".
  <g:form action="save">
<label for="login.username">Username: <g:textField name="login.username"/><br/>
<label for="login.password">Password: </label>
<g:textField name="login.password"/><br/>
<label for="comment.text">Comment</label>
<g:textField name="comment.text"/><br/>
<br/>
<input type="submit"/>
</g:form>
class HomeController {

def index = { }

def save = { LoginCommand login, CommentCommand comment ->
println "login.username: ${login.username}"
println "login.password: ${login.password}"
println "comment.text: ${comment.text}"

redirect action: "index"
}
}

class LoginCommand {
String username
String password
}

class CommentCommand {
String text
}

I know this example is lame, useless and all that but hey - it's just an example :D

The actual prefix for commands is taken from the class name - not the parameter name! Bear that in mind!

I hope you'll like it!

Monday, October 4, 2010

Grails console and LDAP via JNDI

Hi folks!

I've spent over 6 hours today fiddling with LDAP from Grails console and let me tell you it's been a huuuuge disappointment! Let me explain...

I'm using LDAP (it's Active Directory but this is not really relevant) to store users with their attributes. To perform authentication other than usually (having a user that has right to read the password attribute and then query LDAP once a user logs in, verify the password, etc.) I need to login in using credentials provided by user on login page.

With that the use of grails-springsecurity-ldap is pretty much toasted and a new implementation is needed. I don't want to get into any details of spring security plugin, because it makes no sense in this context. What makes a huge difference is the way we interact with LDAP in Java.


import javax.naming.*
import javax.naming.ldap.*

try {
LdapContext context = new InitialLdapContext((Hashtable) [
(Context.INITIAL_CONTEXT_FACTORY): "com.sun.jndi.ldap.LdapCtxFactory",
(Context.PROVIDER_URL) : "ldap://ldap.localdomain.com",
(Context.SECURITY_AUTHENTICATION): "simple",
(Context.SECURITY_PRINCIPAL) : "DOMAIN\\invalid",
(Context.SECURITY_CREDENTIALS) : "invalid",
(Context.REFERRAL) : "follow",
(Context.BATCHSIZE) : "30"
], (Control[]) []);
println "Logged in!"
} catch (AuthenticationException e) {
println "NOT lOGGED IN"
}


The assumption here is of course that "DOMAIN\invalid" either does not exist or has a password other than "invalid" :)

What one would expect from this piece of code is that it tries to create the initial context and since the credentials are wrong an AuthenticationException is being thrown thus the message "NOT LOGGED IN" should appear.

Well, in Groovy console (you know, the one that you get when you install Groovy on your PC) works exactly this way but Grails console works differently. It creates the initial context without problems and presents one with "Logged in!" message.

Why is this happening? Well the CLI support stuff overrides all protocol handlers (and I mean EVERY SINGLE ONE) with Spring's org.springframework.mock.jndi.SimpleNamingContext! Grouse!

What I ended up doing was to use the LdapClient directly (even though it's an implementation detail it gave me all the methods I needed) and life is (sort of) good again...

Check the bug report here.

Wednesday, September 1, 2010

Same name - different projects...

Hi there!

Today I've faced a serious problem: branchy development in Grails. Sounds easy, right? Well... Let's examine this a little bit.

Grails store files in 4 different locations:

  1. The folder where you've unzipped the distro (GRAILS_HOME)

  2. The project's folder

  3. The project's "target" folder

  4. User's home/.grails/{version} folder

The problem is in the last one. What's bad about it while doing branchy development is that there's more than one application with the same name but different version. That causes all kind of issues ranging from random build errors, no auto-reload of artefacts to unexpected application behavior.

As usually with Grails there's an ultra-easy way of fixing this problem :) Here's the content of my grails.bat that does the trick:


@echo off

set GRAILS_HOME=C:/grails-1.3.4
set JAVA_OPTS=%JAVA_OPTS% -Divy.cache.dir=%CD%/target/libraries
set JAVA_OPTS=%JAVA_OPTS% -Dgrails.project.work.dir=target/work

%GRAILS_HOME%\bin\grails.bat %*


As you can see here everything is made project-specific. In "target/libraries" is the ivy cache (instead of home/.ivy2 which causes problems from time to time when working with other technologies such as JSF) and in "target/work" are the project's artifacts.

And live is gooooooooood again :)

Thursday, August 12, 2010

Grails,Teradata and TIME/TIMESTAMP fields

Hi there,

For a long, long time I've been searching for a solution to the incompatibility issue between Teradata server and Teradata JDBC driver in regard to TIME/TIMESTAMP fields. I've finally figured out what's the deal :)

Long story short the database has columns defined as TIME(0) and TIMESTAMP(0) which during updates from Grails (especially the lastUpdated field filled in automagically) causes a number of different errors to come back from the server (5404 for example).

The problem is that java.lang.Date instances are translated using a default precision (which is grater than zero) and the database server is dumb enough to throw an error and not truncate the incoming data.

Solution: update to the latest version of JDBC driver (tested with TeraJDBC 13.10.00.01) and add TSNANO=0,TNANO=0 to connection string and live is good again!

I hope you'll find this solution handy :)

And by all means: have fun!

Tuesday, August 10, 2010

Grails 1.3.4 Released!

Hi there all you Grails geeks!

Yesterday Grails 1.3.4 was released :) Finally some bugs (described in my previous post) were fixed along with one small addition from me.

If you had a domain class that had a generator of type "assigned" and wanted to mockDomain that class then all calls to "save" method were treated as updates. The reason for that was that the distinction was made on the value of "id" field which had to be assigned in case of the "assigned" generator.

So I've proposed a fix for that that'll make the mocked version of save be sensitive to the actual generator type and if it's the "assigned" generator then to act smart instead :)

I hope you'll like it!

Thursday, July 15, 2010

Grails 1.3.3 - testing domain classes FIX

Hi there,

if you're following the TDD principles while using Grails you might be very surprised when upgrading to Grails 1.3.3 because all your unit tests that mocked domain classes and utilized the "save()" instance method all of the sudden fail with some crazy message:

java.lang.NullPointerException
at grails.test.MockUtils.mockDomain(MockUtils.groovy:443)
at grails.test.MockUtils$mockDomain.call(Unknown Source)
at grails.test.GrailsUnitTestCase.mockDomain(GrailsUnitTestCase.groovy:131)
at grails.test.GrailsUnitTestCase.mockDomain(GrailsUnitTestCase.groovy:129)

It's obviously a bug, but don't fear - help is coming!

The bug description in Jira GRAILS-6482 has the answer!

I've allowed myself to go one step further and I've created a base class for those cases where it's needed (DRY - remember?)

package grails.test

import org.codehaus.groovy.grails.plugins.GrailsPluginManager
import org.codehaus.groovy.grails.plugins.PluginManagerHolder

class FixedGrailsUnitTestCase extends GrailsUnitTestCase {

protected void setUp() {
super.setUp();
PluginManagerHolder.pluginManager = [
hasGrailsPlugin: { String name -> true }
] as GrailsPluginManager
}

protected void tearDown() {
super.tearDown();
PluginManagerHolder.pluginManager = null
}
}

Now all my test classes that were touched by this issue inherit from FixedGrailsUnitTestCase and life is good again :)

I hope this will spare you a few minutes :)