Plugin Configurations in Grails

Perhaps, you have a plugin and you would like to configure it instead of hard coding the settings. Lets say, it is a url for REST service that your plugin consumes. In this post, we cover how to incorporate the plugin configurations into part of the default Grails configurations(conf/Config.groovy). In the second part, we cover how to separate the plugins configurations into a separate configurations file while still part of the application

Configurations From App conf/Config.groovy

First, add the configurations setting in the Grails app configuration file(conf/Config.groovy):

// This default value...
yourConfigurationName.url='http://service.com/restapi/'
...
environments {
  development {
    // configurations when in development environment
    yourConfigurationName.url='http://service.com/restapi/'
  }
}

The configuration name may be as you like. From your plugin, this configurations setting can be accessed as follows:

class NodeDriverProxyService {
    def grailsApplication
    def http

    public someMethod(){
        http = new HTTPBuilder(grailsApplication.config.yourConfigurationName.url)
...

As you see, first we inject grailsApplication and then access your setting via grailsApplicaiton.config

This way it is also possible to externalize plugin settings among the other grails configurations as described in post Externalizing Configurations per Grails Application

Configuration from plugins config file

Perhaps, you like to put plugin configurations into separate configuration file instead Grails default Config.groovy
First, create your configuration file and add the configurations. For example grails-app/conf/myPluginName.groovy:

// This default value...
yourConfigurationName.url=http://service.com/restapi/
...
environments {
  development {
    // configurations when in development environment
    yourConfigurationName.url=http://service.com/restapi/
  }
}

This is exact same as part of the Application configurations. Next, here is how to access from plugin:

GroovyClassLoader classLoader = new GroovyClassLoader(getClass().getClassLoader())
ConfigObject config
try {
   config = new ConfigSlurper().parse(classLoader.loadClass('myPluginName'))
}
catch (Exception e) {/*
    if exception, set default settings
*/}

//to access
config.yourConfigurationName.url

Here, we load the file and then use Groovy ConfigSlurper utility to parse and access plugin configurations

To summarize, we covered two ways for plugins configurations being incorporated in the application. One as part of the Grails configuration and another as a separate plugin configurations within the application.

Issues

1. grailsApplication is null
Make sure grailsApplication.config is used within a method. i.e:

class someClass{
def grailsApplication
def url = grailsApplication.config.pluginName.url//this is going to be null

public someMethod(){
   url = grailsApplication.config.pluginName.url//this works!!!
  }
}

Useful Links

  • http://groovy.codehaus.org/ConfigSlurper
  • http://stackoverflow.com/questions/843216/configuration-of-grails-plugin

Parse JSON Request and Build JSON Response in Grails

This is a summary, how to parse JSON type requests and then build a JSON type response in Grails. With JSON type, i mean requests with header of ‘content-type: application/json’

Parse JSON Requests

Please see post ‘Request Automatic Parsing in Grails

Build JSON Response

From String:
Once its done and ready to respond, here is way to build JSON response from string:

  def responseSome = [
                    'status' : "ok"
            ]
  render responseSome as JSON

Here is another way to build JSON resonse:

render(contentType: 'application/json'){
        [
           'status' : "ok"
        ]
}

Both of them do the same thing, build JSON response with header ‘content-type: application/json’

From Collection:
To build JSON response from Collection:

if (!review.save(request.JSON)){
            render(contentType: "text/json"){
                def errors = array{
                    for (e in review.errors.allErrors){
                        error field: e.field
                        error message: e.defaultMessage
                    }
                }
...

Here all of the errors are collected from Domain class instance validation and new JSON response is built.

For building JSON response from Domain class or other type, please, see post ‘LocalDate as JSON and other types to custom serialize in Grails

Mock HTTPBuilder and POST requests in Grails

For some reason, mocking HTTPBuilder become a larger task than initially anticipated. In this post, the details on how to assert params, payload of the HTTPBuilder request as well as success or failure of the response is covered to have a good test

Here is an example of the HTTP POST request:

class NodeDriverProxyService {
   def http = new HTTPBuilder('http://localhost:8080')

    public registerUpdate(Long id, Long version){
        try{
            http.request(Method.POST, JSON){ req ->
                body = [
                        version: version,
                        id: id
                ]

                response.success = {resp, json ->
                    log.warn "cached object id: $id and version: $version; status code: " + resp.statusLine.statusCode
                }
            }
        }catch(Exception e){
            log.warn('Failure Initiate Connection with Node Driver: ' + e.message);
        }
    }
}

Here the httpBuild is initiated in line 2. The request takes ‘id’ and ‘version’. On the response, the message is logged with the response status(line 13). The error message is also logged if exception encountered at any time during request

1. Test Params

Here is the test for ensuring params(method, body, etc.) passed in the request accordingly

@Shared  id = 2, ver = 3
def "ensure params passed in correctly"(){
        setup:
        def httpBuildMock = new MockFor(HTTPBuilder.class)
        def reqPar = []
        def success

        def requestDelegate = [
                response: [:]
        ]

        httpBuildMock.demand.request(1){
            Method met, ContentType type, Closure b ->
            b.delegate = requestDelegate
            b.call()
            reqPar << [method: met, type: type, id: b.body.id, ver: b.body.version ]
        }

        when:
        httpBuildMock.use{
            service.registerUpdate(id,ver)
        }

        then:
        assert reqPar[0].method == Method.POST
        assert reqPar[0].type == ContentType.JSON
        assert reqPar.ver[0] == ver
        assert reqPar.id[0] == id
    }

First, we declare a list – reqPar(line 5) to hold all of the params since its accessible only within the request scope and we prefer to do assertions outside the request scope part of the ‘then’ block(line 23 – 27)

Next, we mock interface(line 8-10) of the RequestConfigDelegate class because it is the owner scope calling the request method. We also assign it in line 13 to the ‘request’ closure before executing it in next line

We need to execute the ‘request’ closure in line 15, because within that scope the body params are assigned, thus, available for us to access that we are doing in line 15. Beside body params, there may also uri.path, uri.query but in our implementation there isn’t.

2. Test Response

Our other test is going to be testing the successful and failure response.

@Shared  id = 2, ver = 3, status_code = 200, msg = 'test message'
 def "ensure response is handled accordingly for success and failure states"(){

        setup:
        def logTo = []
        def success
        def httpBuildMock = new MockFor(HTTPBuilder.class)

        def logService = [
                warn: { String message ->
                    logTo << [warn: message]
                }         
             ] as org.apache.commons.logging.Log
       
        def requestDelegate = [
                            response: [ 
                                 'statusLine': [ 'protocol': 'HTTP/1.1',
                                                 'statusCode': status_code, 
                                                 'status':'OK'
                                               ]
                                 ],
        ]
      
        httpBuildMock.demand.request(1){Method met, ContentType type, Closure b ->
            b.delegate = requestDelegate
            b.call()
            if(success) {
                requestDelegate.response.success(requestDelegate.response,[:])
            }else{
                throw new Exception(msg)
            }
        }
        service.log = logService

        httpBuildMock.use{
            success = state
            service.registerUpdate(id,ver)
        }

        expect:
        assert logTo[0].warn == message

        where:
        state   | message
        false   | 'Failure Initiate Connection with Node Driver: ' + msg
        true    | 'cached object id: ' + id + ' and version: ' + ver + '; status code: ' + status_code

    }

In our case, in both situation for successful and failure response there are messages logged, so we mock the log service as well in the lines 8-12.

Besides mocking the Log service and asserting the messages, we initiate the response in the highlighted line as it would be when our Http POST request would receive the response. For response, the same RequestConfigDelegate interface is also passed into as response, however. We add ‘statusLine’ in this mocked requestConfigDelegate instance since the ‘statusLine’ is being called and we also need it for the assertion in the ‘where’ block

Useful Links:

  • http://cscarioni.blogspot.com/2011/02/is-it-harder-to-unit-test-in-grails.html
  • http://groovy.codehaus.org/Developer+Testing+using+Closures+instead+of+Mocks
  • http://groovy.codehaus.org/Groovy+way+to+implement+interfaces
  • http://stackoverflow.com/questions/13790246/how-to-use-mockfor-to-mock-client-on-httpbuilder
  • http://groovyconsole.appspot.com/script/760001
  • http://jira.grails.org/browse/GRAILS-8617
  • http://groovy.codehaus.org/modules/http-builder/apidocs/groovyx/net/http/HTTPBuilder.html#request(groovyx.net.http.Method, groovy.lang.Closure)

Externalizing Configurations in Drupal, Node.js and Grails

In this post, we cover how configurations can be externalize for platform Drupal and frameworks Node.js, Grails. By externalizing configurations, it becomes easer to deploy and move around applications and libraries.

Drupal

There are two approaches
1. Configurations in file
In the sites/default/settings.php add the configurations as follows:

$conf['global_driver_url'] = 'localhost';
$conf['global_driver_port'] = '3000';

The $conf is Drupals global variable array as described here
Then to access it anywhere as follows:

global $conf;
var driverPort = $conf['global_driver_port'];
var driverUrl = $conf['global_driver_url'];

So, here you reference the global variable $conf and then access any variables you wish

2. Configurations from User
We create a content type that contains the configurations. For example, we have content-type name ‘Interface Configurations’ with machine name ‘interface_configurations’

Then in preprocessor in template.php file, we load it as follows:

$nid_config = db_select('node', 'n')
        ->fields('n', array('nid'))
        ->fields('n', array('type'))
        ->condition('n.type', 'interface_configurations')
        ->execute()
        ->fetchCol();
    //load the configurations
    $configurationNode = node_load($nid_config);
    $interfaceConfig = array();
    $interfaceConfig['driver_url'] = $configurationNode->field_driver_url['und'][0]['value'];
    $interfaceConfig['driver_port'] = $configurationNode->field_driver_port['und'][0]['value'];
    $vars['interfaceConfig'] = $interfaceConfig;

Here, we first retrieve the Id of the configuration node containing the configurations. Afterward, it is loaded and values retrieved. At last, it is put in $vars array, so it is available in the html template

Node.js

There are several ways doing it in Node.js and there are some modules such as nconf for the that purpose. In the following, is one way of externalizing configurations in Node.js framework:
1. we create config.js that contains configurations and place it in root folder as follows:

var config = {}

config.controller_url = process.env.CONTROLLER_URL || '/minnehaha';
config.controller_host = process.env.CONTROLLER_HOST || 'localhost';
config.controller_port = process.env.CONTROLLER_PORT || 8010;

module.exports = config;

Here we first declare variable config that will hold the configurations. Then assign our configurations. The ‘process’ contains the command line Node.js variables. So, if you like to have environment based configurations such as dev, prod, etc, then you will have to if/switch condition on ‘process.env.NODE_env’ variable.

Important to note, that the ‘process.env’ queries all of the command environment variables(i.e. PATH,GRAILS_HOME,etc.), so you have access to all of them.

At last, we make or configurations available anywhere in Node.js applications in the next step

2. To make these configurations available, we import the module and then access the configurations as follows:

var config = require('./../config');
...
   var options = {
        host: config.controller_host,
....

Here, the config module is imported and assigned to ‘config’ variable after which the configurations are accessed

Grails

For external configurations in Grails framework,please, see post Externalizing Configurations Per Grails Application

Useful Links:

  • http://stackoverflow.com/questions/5869216/how-to-store-node-js-deployment-settings-configuration-files
  • http://devincarlson.ca/blog/configuring-drupal-use-proxy-server-when-making-external-http-requests

Hooking into GORM events from plugin in Grails

we are working on Grails plugin that caches Domain objects in Node.js app. The Grails plugin purpose is to keep the cache current. In this plugin, we listen GORM events, so that once insert or update happens, we can tag the particular instance dirty in the cache. There are two ways to accomplish this that i am aware:

1. Via Groovy metaClass method

In the plugin configuration file plugin/nameOfThePluginGrailsPlugin.groovy we overload the GORM events methods – afterUPdate and afterInsert as follows:

import org.codehaus.groovy.grails.commons.GrailsClassUtils as GCU
...
 def doWithDynamicMethods = { ctx ->
        def service = ctx.nodeDriverProxyService
        application.domainClasses.each{ cClass ->
          def isCached = GCU.getStaticPropertyValue(cClass.clazz, "isCached")
          if(isCached){
            cClass.metaClass.afterUpdate = { ->
                service.registerUpdate(delegate.id, delegate.version)
            }
          }
        }
...

This goes throw each of the domain classes in the application and finds those that has property ‘isCached’ set to true. Afterwards, using groovy metaclass overloads the ‘afterUpdate’ method called each time the domain instance updated

Here we also call the service that does the work. Since ‘ctx’ is Spring ApplicationContext, we are able directly access the instance of our service – NodeDriverProxyService

This is probably not recommended approach, because once someone adds the method ‘afterUpdate’ to the Domain class itself, it overwrites our dynamic method. This is reasons why its good to use Custom Event Listeners instead.

2. Custom Event Listener

Instead attaching dynamic method to overwrite Domain callback methods ‘afterUpdate’ and ‘afterInsert’, we create custom event listener in src/Groovy:

class CacheListener extends AbstractPersistenceEventListener{
    def nodeDriverProxyService

    public CacheListener(final Datastore datastore) {
        super (datastore)
    }

    @Override
    protected void onPersistenceEvent(final AbstractPersistenceEvent event) {
        switch(event.eventType) {
            case PostInsert:
                if(event.entityObject?.isCached){
                    nodeDriverProxyService.registerInsert(event.entityObject.id, event.entityObject.version)
                }
                break
            case PostUpdate:
                if(event.entityObject?.isCached){
                    nodeDriverProxyService.registerUpdate(event.entityObject.id, event.entityObject.version)
                }
                break;
        }
    }

    @Override
    public boolean supportsEventType(Class eventType) {
        return true
    }

}

In our custom listener, the method ‘onPersistenceEvent’ is called on all GORM events that we filter to what we interested – PostInsert, PostUpdate
Afterwards, we register the listener to ApplicationContext in pluginNameGrailsPlugin.groovy configuration file as follows:

...
    def doWithApplicationContext = { applicationContext ->
        application.mainContext.eventTriggeringInterceptor.datastores.each { k, datastore ->
            def cacheListener = new CacheListener(datastore)
            cacheListener.nodeDriverProxyService = applicationContext.nodeDriverProxyService 
            applicationContext.addApplicationListener(cacheListener)
        }
    }
...

This registers our listener. Here we also manually inject our custom service NodeDriverProxyService to make it available for our listener to do some work

Summary

Whichever way it was implemented, the new Grails plugin can be installed to any of our Grails applications to cache any domain. Grails make it easy again!

Useful links:

  • http://stackoverflow.com/questions/1956115/hooking-into-grails-domain-object-save
  • http://hartsock.blogspot.com/2008/04/inside-hibernate-events-and-audit.html
  • http://grails.org/doc/latest/guide/GORM.html
  • http://grails.1312388.n4.nabble.com/How-to-enable-dynamic-methods-logging-by-interception-ClassCastException-on-PojoWrapper-td3165109.html

Request Automatic Parsing in Grails

Grails comes with a parser that takes the request and parses it into variables – ‘params’ and ‘request’

Reading Url Params

The URL part is parsed into the ‘params’ variable. This includes the Url query string as well as URL-encoded string(body). Here is GET request initiated from Curl:
curl -G -d "title=Great%20Place" http://localhost:8010/minnehaha/review/update/100
So, at the controller to read Url parameters as follows:

//action in controller
def update() {
     params.id
     params.title
     params.action
     params.controller
...
}

Besides Url parameters, Grails parses also the ‘action’ and ‘controller’ for the given request

Reading Request Body

The body of the request is parsed into ‘request’ variable depending of ‘content-type’ specified in request. By default, the request parser supports two types – XML and JSON. Here is PUT request initiated via Curl:
curl -i -H "Content-Type: application/json" -X PUT -d '{"title":"great place"}' -d '{"content":"coming again soon"}' http://localhost:8010/minnehaha/review/update/100
At the controller, the request parser looks at the content-type, finds ‘json’ and parses into request.JSON:

..
request.JSON.title == 'great place'
request.JSON.content == 'coming again soon'
..

A common mistake is to forget specify ‘content-type’ in request resulting the ‘request.JSON’ variable to be empty because without the type, the parser is unable to parse request

The parser will always try to parse whenever there is a body attached to request even for GET and DELETE requests:
curl -i -H "Content-Type: application/json" -X GET -d '{"title":"great place"}' http://localhost:8010/minnehaha/review/update/100

By convention, the GET and DELETE requests doesn’t have raw/chunked body attached, however. HTTP/1.1 RFC does not forbids it and grails parser will parse it.

What if other than JSON or XML?

There may be situation where the data in body for the request is neither JSON nor XML format. To read the raw data:

request.getReader().text

However, this will give the following error:
getInputStream() has already been called for this request
This is because the default request parser needs to be turned off before reading the body text. Here is one way how to do it in the grails-app/conf/UrlMapping:

class UrlMappings {

    static mappings = {
        "/api/review/$id?"(controller: 'review', parseRequest: false){
            action = [ PUT: "update", POST: "save", GET: "show"]
        }
...
}

By specifying ‘parseRequests:false’ in highlighted line, it will turn off the Grails automatic parsing and make it possible to read the body data (i.e. request.getReader().text)

Content Negotiation

The Content Negotiation is topic in its own and should be separate post. Just to clarify, in the request header the ‘accept’ field is used for content negotiation and the ‘content-type’ is used for request parser to parse the body of request in Grails.

Useful Links:

  • http://grails.1312388.n4.nabble.com/Incoming-JSON-in-Controller-td4495260.html
  • http://grails.org/doc/2.2.x/ref/Controllers/withFormat.html
  • http://grails.org/doc/2.2.x/guide/single.html#contentNegotiation
  • http://jira.grails.org/browse/GRAILS-7099
  • http://grails.org/doc/1.3.9/ref/Servlet%20API/request.html
  • http://stackoverflow.com/questions/5905916/payloads-of-http-request-methods
  • http://sislands.com/coin70/week6/cgi.htm

LocalDate AS JSON and other types to custom serialize in Grails

This post describes how to create custom serializers to marshall custom types such as LocalDate and Domain class objects into JSON response. The challange is that the default JSON converter provided in Grails is unable to marshall custom types. In practice, it also useful to define how the associations is marshalled into the JSON response. For example, if there is Review associated with RentalUnit, perhaps, you wish only marshall rentalUnit Name instead Id and so on.

Quick and Dirty

One way is to add custom serializer in the controller at the time of rendering the response into JSON response as follows:

def show() {
   Review.list()
   ...
   if (result){
   //render result as JSON
            render(contentType: "text/json") {
                def reviews = array {
                    for (b in result) {
                        review title: b.title
                        review dateReceived: b.dateReceived.toString("yyyy-MM-dd")
                    }
                }
   }
   ...
}

This will create JSON response with list of review titles and dates review received as following:

[{"title":"Great Place to Stay!"},{"dateReceived":"2010-08-30"},
{"title":"Great Apartment- Highly Recommend!"},{"dateReceived":"2010-11-03"} ...]

Important to Note that ‘dateReceived’ is custom type of org.joda.time.LocalDate. With that, you can see how groovy provides such easy way to serialize into string while Grails elegant way to build it into JSON response.

Organized To Maintain

It may be a case, you would like to do JSON marshalling per Class(Type) instead at Controller level. In another words, there is custom marshaller for each different custom type in our case Domain class. Its good for Domain class like User where you don’t want JSON response to include email, age or any other personal information.
Step 1: Create Custom Marshaller
In src/groovy/, perhaps, good place to add your custom marshaller as follows:

package reviews

import grails.converters.JSON
import com.minnehahalofts.app.Review

class ReviewMarshaller {

    void register(){
        JSON.registerObjectMarshaller(Review) {Review review ->
            return [
                    title : review?.title,
                    rentalUnitId : review?.rentalUnit?.id,
                    dateReceived : review?.dateReceived.toString("yyyy-MM-dd")
            ]
        }

    }
}

This registers custom marshaller that defines how the JSON response is going to be constructed when ‘as JSON’ called. It also serializes our custom type – LocalDate

NOTE: Make sure to use Safe Navigation operator(?.), otherwise, the marshaller will break

Step 2: Aggregate Marshallers Before Bootstrapping
Next, all of the custom marshallers are kept in one place before bootstrapping each. This makes the Bootstrap.groovy more clean and independent of each custom Marshaller
Perhaps, the src/groovy/util is good locations to add as follows:

package util.marshalling

class CustomObjectMarshallers {

    List marshallers = []

    def register() {
        marshallers.each{ it.register() }
    }
}

CustomObjectMarshallers has a list of all marshallers with an API to register each

Step 3: Define Spring Bean
In the conf/Spring/resource.groovy, we define the spring bean for CustomObjectmarshaller, so its available at the bootstrapping

import util.marshalling.CustomObjectMarshallers
import reviews.ReviewMarshaller

// Place your Spring DSL code here
beans = {
     customObjectMarshallers( CustomObjectMarshallers ) {
         marshallers = [
                 new ReviewMarshaller()
                 new SomeOtherMarshaller()
         ]
     }
}

Here we inject all of our custom marshallers as we keep adding more

Step 4: Bootstrapping to Register
At last, we register each custom marshaller at the application start up as follows:

class BootStrap {

    def loadDomainDataService
    def grailsApplication

    def init = { servletContext ->

        def applicationContext = grailsApplication.mainContext

        //register Custom marshallers
        applicationContext.getBean( "customObjectMarshallers" ).register()
...

As you can see, in Bootstrap.groovy we grab the Spring application context and retrieve our Custom Marshall aggregator – customObjectMarshallers that registers each of our custom marshallers

LocalDate Goes Global

We can follow this way and create custom marshaller just for the custom type – org.joda.time.LocalDate, however. Its already done and available as Joda-Time Plugin

Useful Links:

  • https://github.com/robfletcher/grails-gson
  • https://sites.google.com/site/gson/gson-user-guide#TOC-Custom-Serialization-and-Deserialization
  • http://compiledammit.com/2012/08/16/custom-json-marshalling-in-grails-done-right/
  • http://grails.org/plugin/marshallers
  • http://jwicz.wordpress.com/2011/07/11/grails-custom-xml-marshaller/
  • http://adhockery.blogspot.com/2009/08/json-rendering-your-classes.html
  • http://grails.org/plugin/joda-time

Mocking Log Service and Others in Grails and Groovy

In this post, we cover different ways of mocking Services and other entities when writing tests in Grails. For the examples in this post, we use the Log service to better demonstrate

Environment: Grails 2.1.2, Spock 1.0, Mac 10.7

Using Grails mockFor

In this example, the Grails mockFor mechanism of mocking is used to mock the log service:


    def "mock using grails mockFor"(){
        setup:
        def httpBuildMock = new MockFor(HTTPBuilder.class)
        def logTo = []
        def loggerMock = mockFor(org.apache.commons.logging.Log)
        loggerMock.demand.warn(1..1){ String message ->
            logTo << [msg:message,level: 'warn']
        }
        service.log = loggerMock.createMock()

        when:
        service.methodLogging()

        then:
        assert logTo.msg == 'some message'

First we create global variable ‘logTo’ to store the logged value, so we can assert it later. Then we create mock of Log interface and mock the method ‘log.warn’. At last, the mocked logger is assigned to the logger used by the service

Using Groovy Closure

Since Groovy provides convenient way to implement interfaces, the mocking of logger can be done via closure as following:

def "mock via groovy closure"(){
        setup:
        def logTo = []
        def logInstance = {String message -> logTo << [msg: message]} as org.apache.commons.logging.Log
        service.log = logInstance

        when:
        service.methodLogging()

        then:
        assert logTo.msg == 'some message'

In the highlight line, the closure is created and assigned to a type of org.apache.commons.logging.Log interface. This closure is going to be executed whenever any of the Log methods(warn,error,etc.) is going to be called. Afterwards, the new logger is assigned to the service logger instance

Important to note, for mocking multiple methods the interface is implemented via Groovy Map as following

def "mock via groovy closure"(){
        setup:
        def logTo = []
        def impl = [
                warn:{String message ->
                    logTo << [warn: message]
                },
                error:{String message ->
                    logTo << [error: message]
                }
        ]

        def logInstance = impl as org.apache.commons.logging.Log
        service.log = logInstance

        when:
        service.methodLogging()

        then:
        assert logTo.warn == 'some message'
        assert logTo.error == 'some message'

As you see, here the two closures one for method ‘warn’ and another for ‘error’ are created and put into Map. Afterwards, the interface type assigned and injected into service as the logger instance

Using Groovy MockFor

Another alternative is to use Groovy MockFor mechanism that is very similar to the one in Grails

def "mock via groovy MockFor"(){
        setup:
        def logTo = []
        def logService = new MockFor(org.apache.commons.logging.Log)
        logService.demand.warn(1){ String message ->
            logTo << [msg: message]
        }
        service.log = logService.proxyInstance()

        when:
        service.methodLogging()

        then:
        assert logTo.warn == 'some message'

This is almost identical to Grails mockFor implementation

In summary, there are choices when mocking logger or any other collaborator for that matter. The three different alternatives listed here can be applied to any collaborator in your test of interest

Useful links:

  • http://slf4j.org/faq.html about IlligalAccessError
  • http://blog.springsource.com/2009/12/04/logging-dependencies-in-spring/
  • http://stackoverflow.com/questions/3032654/hibernate-spring-and-slf4j-binding
  • http://groovy.codehaus.org/Groovy+way+to+implement+interfaces

Locally Untracked Files in Git While Making a Grails Plugin In-Place

At my current workplace, the grails application is divided into application and an extra plugin. To avoid package, maven-install every single time new change made in plugin that need to be seen in application, I decided to make this plugin in-place. To make it in-place plugin, i had to update BuildConfig.groovy as follows:

...
grails.plugin.location.nameOfPluginPlugin = '../../pluginLocation'
...
plugins {
    ...
    //uncomment plugin dependency
}
...

At the same time, i don’t want these changes go into others developers local repos, so i wanted to untrack BuildConfig.groovy file. Here are steps to untrack file from git repo.

Ignoring File in Git

To ignore file globally,here are steps

Step-1: Create global git ignore file, not tracked in repository that is user-specific

git config --global core.excludesfile pathTo/.gitignore_global
 

Note: You can find different sample git ignore files per technology here

Step-2: Added BuildConfig.groovy in my local global git ignore file as follows

...
/relative/pathToApp/BuildConfig.groovy
...

This will keep it ignored, but we still need it make it be untracked before it can be ignored

Step-3: Untrack the file itself since it is already tracked

git rm --cached BuildConfig.groovy

This makes the file to be ignored and also untracked, however. By pushing to the shared repo others will make this file to be untracked as well, which we don’t want

Ignoring vs Untracked

Ignore will only apply to untracked files. So, in our case, where we need the file to still be tracked, the solution of ignoring described above will not work. Instead, we set the file to be assumed unchanged by Git:

git update-index --assume-unchanged appname/grails-app/conf/BuildConfig.groovy  

By ‘assume unchanged’, the file is ignored and no changes appear in git repo. This makes the grails plugin in-place only for me since the changes are not tracked anymore and ,thus, pushed into the shared main repository

Useful links:

Revise GEB Functional Tests in Grails

At work, i have been doing enough functional tests to begun note some important aspects that can help boost productativity

Accessing Page Content in Helper Method

In my fellow developer’s code, i noticed in Page objects a lot of repetitive setters for each page content defined. Here is example:

class RentalUnitEditPage extends Page {
...
    static content = {
        nameInput(wait: true) { $("input#name") }
        review(wait: true) { $("select", id: "review.id") }
        someGroupSelect(wait: true) { $("select#someGroup\\.id") }
        paymentMethodSelect(wait: true) { $('select#paymentMethodType') }
        companyTypeSelect(wait: true) { $('select#companyType') }
        groupSizeSelect(wait: true) { $('select#classification') }
...
}

    void setName(String newName) {
        nameInput.value(newName)
    }

    void setSomeGroup(String group) {
        someGroupSelect.value(group)
    }

    void setReview(String rev) {
        review.value(rev)
    }

    void setPaymentMethod(PaymentMethodType paymentMethod) {
        paymentMethodSelect.value(paymentMethod.id)
    }
...
}

As you see, there is setter for each input variable and we need setter because in the test we update fields to validate it updated correctly, however. With so many setters, we certainly are not following DRY(Don’t Repeat Yourself) principle. To do so, instead of the many setters for each field, lets have general setter as follows:

class RentalUnitEditPage extends Page {
...
    void setField(String fieldName, String fieldValue){
        browser.page."$fieldName".value(fieldValue)
    }
...
}

So, this way we can remove the many setters only having one – the general one described above

Upload file widget Module Example

In the ‘Book of GEB‘, it encourages to use Modules for reusing functionality. Here is an example of module for uploading files widget:


class LoadFileModule extends Module {
    String buttonName
    String inputId
    String inputUrl

    static content = {
        fileUploadField(wait: true) { $("input#${inputId}") }
        loadButton(wait: true) { $("input", name: buttonName) }
    }

    void clickLoad(Class toPage){
        fileUploadField.value(inputUrl)
        loadButton.click(toPage)
    }
}

So, for page objects that has the upload file widget, you don’t have to recreate functionality to upload file in test. You could just include the LoadFileModule module and use it as follows:

class SomeLoadPage extends Page {
...
    static content = {
        ...
        loadFile(wait: true) { inId, inUrl, bName -> module  LoadFileModule, inputId: inId, inputUrl: inUrl, buttonName: bName}
    }

    AfterLoadStatusPage loadSomeFile(String filePath) {
        loadFile("fileInputFieldId", filePath, "uploadFileButtonName").clickLoad(AfterLoadStatusPage)
        ...
    }
}

As you can see, first we load the module LoadFileModule(highlighted line) and pass three parameters – inId that is fileInputFieldId, inUrl that is file path and bName that is the button name. Then, in your test to load file all you need is call this method while giving file path.