Wednesday, April 28, 2010

Mock Testing with Grails

For unit testing controllers that make calls to injected spring beans, we can use Grails' mock framework.

Take for example a Controller and Service class defined as follows
class MyService {
boolean transactional = true

def serviceMethod(param1) {
return 'hi'
}
}

class MyDomainController {
def myService

def doSomething = {
def val = myService.serviceMethod('input1')
return val }
}

Our test case for the doSomething closure would look as follows
import grails.test.*

class MyDomainControllerTests extends ControllerUnitTestCase {

protected void setUp() {
super.setUp()
}

protected void tearDown() {
super.tearDown()
}

void testSomething() {
GrailsMock serviceMock = mockFor(MyService)

/*
* Mock the method being called
* the 1..1 specifies the min & max number of times the method is expected to be called
* the closure defines the code executed each time the method is called
*/

serviceMock.demand.serviceMethod(1..1) {param1 ->
assertEquals 'input1', param1
return 'hi'
}

/*
* The service needs to be manually set in the controller
*/

controller.myService = serviceMock.createMock()

assertEquals 'hi', controller.doSomething()

/*
* Verifies that the service was accessed
* in the manner established earlier.
*/

serviceMock.verify()
}
}

Wednesday, April 14, 2010

Bypassing Acegi Security

Acegi Security is rather easy to include in your application, but because our application needs to integrate with a single-sign on system, some method of bypassing Acegi or automatically logging into our application is required.

Since Acegi is built upon a list of filters that intercept HttpServletRequests, we can inject our own filter into the chain that will automatically log a user into our application. For simplicity, we assume the SSO is providing user information in a request header parameter.

The first step is include our filter in the list of filters to be invoked by Acegi. Edit conf\SecurityConfig.groovy, which should have been created during installation of the Acegi plugin, to include the following:
filterNames = ['httpSessionContextIntegrationFilter',
'logoutFilter',
'authenticationProcessingFilter',
'securityContextHolderAwareRequestFilter',
'rememberMeProcessingFilter',
'mySsoFilter',
'anonymousProcessingFilter',
'exceptionTranslationFilter',
'filterInvocationInterceptor']

The filters listed are the common filters invoked by Acegi in the listed order. We've included our filter mySsoFilter.


Since the filters in Acegi are actually Spring beans, the next step is to define the bean representing our filter in conf\spring\resources.groovy
mySsoFilter(MySsoFilter) {
userDetailsService = ref("userDetailsService")
}

The userDetailsService bean passed to our filter is pre-defined by Acegi and Grails. It's purpose is described later.


Finally we create our filter file, MySsoFilter.groovy, in the utils directory. The skeleton is listed below. Note
-- we defined an instance field userDetailsService, the Spring bean injected into our filter bean.
-- the method getOrder() defines the order and priority for the filter during invocation
-- the method doFilterHttp(...) is where the functionality of our filter will be contained.
import org.apache.commons.logging.LogFactory

import org.springframework.beans.factory.InitializingBean
import org.springframework.security.GrantedAuthority
import org.springframework.security.GrantedAuthorityImpl
import org.springframework.security.context.SecurityContextHolder
import org.springframework.security.providers.UsernamePasswordAuthenticationToken
import org.springframework.security.ui.FilterChainOrder
import org.springframework.security.ui.SpringSecurityFilter

import javax.servlet.FilterChain
import javax.servlet.http.HttpServletRequest
import javax.servlet.http.HttpServletResponse


class MySsoFilter extends SpringSecurityFilter implements InitializingBean
{
static final HEADER_ATTRIBUTE_LOGIN = 'x-login'
static final HEADER_ATTRIBUTE_FIRSTNAME = 'x-firstname'
static final HEADER_ATTRIBUTE_LASTNAME = 'x-lastname'
static final HEADER_ATTRIBUTE_EMAIL = 'x-email'

static final log = LogFactory.getLog(MySsoFilter.class)

def userDetailsService

void afterPropertiesSet() {
log.debug '************************ inside afterPropertiesSet'
}


void doFilterHttp(HttpServletRequest request, HttpServletResponse response, FilterChain chain) {
chain.doFilter(request, response)
}

int getOrder() {
return FilterChainOrder.REMEMBER_ME_FILTER
}
}



Now that we have a filter being invoked in the proper order, containing information about the user who has been logged in via SSO, the difficulty now lies in simulating a login in Acegi.

First, we get information about the user we're trying to log in. This is provided by the userDetailsService bean, an instance of the Acegi implementation of the UserDetailsService. The interface's only method returns an instance of UserDetails, which is a wrapper around the loginUserDomainClass and authorityDomainClass defined during Acegi installation (and also defined in SecurityConfig.groovy).
def details = userDetailsService.loadUserByUsername(username) 


Next, we create a security token, by using the concrete class UsernamePasswordAuthenticationToken. The password is obtained during lookup of the user.
def token = new UsernamePasswordAuthenticationToken(
details, passwd, details.authorities)


Finally, we give the token to the SecurityContextHolder, an Acegi object which manages the security token per executing thread.
SecurityContextHolder.context.authentication = token 



Our final implementation for doFilterHttp(...) is as follows
    void doFilterHttp(HttpServletRequest request, HttpServletResponse response, FilterChain chain) {
log.debug '************************ inside doFilterHttp'
log.debug 'req value ' + request.getHeader(HEADER_ATTRIBUTE_LOGIN)

// no SSO header, do not continue
def login = request.getHeader(HEADER_ATTRIBUTE_LOGIN)
if (!login) {
log.debug('no sso header found, continuing')
chain.doFilter(request, response)
return
}

// user not in our system, do not continue
def user = User.findByUsername(login)
if (!user) {
log.info('username ' + login + ' not found')
chain.doFilter(request, response)
return
}

// user does not have admin role, do not continue
def adminRole = Role.findByAuthority('ROLE_ADMINISTRATOR')
if (!user.authorities.contains(adminRole)) {
log.info('user ' + login + ' does not have admin permission')
chain.doFilter(request, response)
return
}

log.info('user ' + login + ' given SSO access')
def details = userDetailsService.loadUserByUsername(user.username)
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(
details, user.passwd, details.authorities)
SecurityContextHolder.context.authentication = token
chain.doFilter(request, response)
}

Tuesday, April 13, 2010

GrailsUI Tab Manipulation

We've been using the Tab Layout available in the GrailsUI plugin in our application, but one minor annoyance we've discovered is that while saving the form resets the active tab.

The javascript library that renders the tabs gives you access to the tab information, through the variable GRAILSUI

For example, the following gsp would always display the first tab on save.

<gui:tabView id="myTabs">
<gui:tab label="Basic" active="true">
</gui:tab>
<gui:tab label="Firms">
</gui:tab>
</gui:tabView>



We can now access the tabs in custom javascript by using
GRAILSUI.myTabs.get('activeIndex')


all that's left is to save a hidden field, and change the tab 'active' definitions

Custom Grails Error Handling

Error handling in your Grails app is especially important, as Groovy is a non-checked language -- methods need not declare a throws clause. While UrlMappings.groovy provides a default page for general 500 errors, in our application, we'd like to display different error pages in different situations.

There are several approaches to this problem. One solution is to separate error handling by exception class. This can be done by modifying Bootstrap.groovy

exceptionHandler is an instance of GrailsExceptionResolver, and can be auto injected. Note the last entry is needed for default handling.

Also, be sure to remove the "500" entry from UrlMappings.groovy, as interferes with the definitions here.

class BootStrap {
def exceptionHandler

def init = {
exceptionHandler.exceptionMappings = [
'SpecialException' : '/myController/someAction',
'java.lang.Exception' : '/error'
]
}
}



Another approach is to modify the handling in UrlMappings.groovy. By default, the "500" entry points to error.gsp in the views directory, but it can be changed to another view, or a controller with optional action specified.
"500"(controller:'myController', action:'handleExceptions')

Monday, March 22, 2010

Calling Stored Procedures in Groovy

As expected, Groovy provides some compact syntax for calling stored procedures. All the magic is contained in the Sql class.

For example, a stored procedure with the following signature:
insert_book(p_title IN VARCHAR2, p_author IN VARCHAR2, p_isbn OUT VARCHAR2, p_id OUT INTEGER)


Can be invoked with the following Groovy code:
public saveBook(book) {
def isbn
def bookId

Sql sql = new Sql(dataSource)
sql.call "{insert_book(?, ?, ?, ?)}",
[book.title, book.author, Sql.VARCHAR, Sql.INTEGER],
{ spIsbn, spId ->
isbn = spIsbn
bookId = spId
}
}

Note:
  • the first parameter is a string containing the stored proc call that also parameterizes the in/out variables.
  • the second parameter are the variables to be passed in or the corresponding type of the out parameter
  • the third parameter is a closure that is given the out parameters of the executed stored procedure in the order they are declared in the sproc.
dataSource is an instance of the data source created in DataSource.groovy. Our snippet assumes the saveBook method is contained in a spring bean, where the dataSource variable can be automatically injected.


More information on Groovy and db objects can be found here.

Thursday, March 4, 2010

Mapping Domain Classes with Hibernate Annotations

Save the following file as grails-app/conf/hibernate/hibernate.cfg.xml. Note that it specifies a single class being mapped, all classes in a package can be specified by using:

<mapping package="com.test.domain" />


<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>

<session-factory>
<mapping class="Firm"/>
</session-factory>

</hibernate-configuration>

Our domain class looks as follows. Note that the table name is a Oracle Database Link.

import javax.persistence.Column
import javax.persistence.Entity
import javax.persistence.Id
import javax.persistence.Table

@Entity()
@Table(name="firm@remote")
class Firm {
@Id
Integer id
@Column(name="name")
String name
@Column(name="status")
String status

@Column(name="key")
String key
@Column(name="short_name")
String shortName
}

Wednesday, March 3, 2010

Grails Unit Testing for Beginners

When you use grails generators for domain classes, controllers, services or portlets, it automatically creates tests for you. Simply running "grails test-app" will run all unit and integration tests and is great for build processes. However, when you're developing you simply want to invoke the tests of the class you're editing. This can be accomplished by passing arguments to test-app like this:

grails test-app MyService -unit

or

grails test-app MyController -integration

Using println for testing is bad form but many times println in the code or tests is helpful for debugging. Grails generates test reports and one of them is the System.out. Open a tail tool (such as Baretail for Windows) on the file and you'll see the new results everytime the test runs (it does delete and replace the file.) These are located in:

my-app-home\target\test-reports\plain\
TEST-unit-unit-MyServiceTests.txt
TEST-unit-unit-MyServiceTests-err.txt
TEST-unit-unit-MyServiceTests-out.txt

You can also view an html report on the results of your tests. This is useful for seeing stacktraces:
my-app-home\target\test-reports\plain\index.html



-Ben Hidalgo