Tag Archives: quick&easy

Functional tests in Play! 2 with REST-assured

In the Play! documentation, several flavours of functional testing are mentioned, including starting a HTTP server for the duration of the test – this is very useful for testing web services. In code, this looks like

import static play.test.Helpers.*;
...
@Test
public void testInServer() {
  running(testServer(3333), new Callback0() {
      public void invoke() {
         assertThat(
           WS.url("http://localhost:3333").get().get().status
         ).isEqualTo(OK);
      }
  });
}

A few days ago, when I was looking for a good way to test applications built on a CXF stack, I came across REST-assured. It was simple, elegant and useful so it’s the one I picked. In that case, I had to build some extra support for handling Jetty start-up and shutdown, application loading, etc.

With the full-stack approach of Play, however, you get this support for free out of the box, so all that is left is to integrate the tool of your choice. To add REST-assured to your project, edit the project/Build.scala file and add the dependency. If you already have Play running, don’t forget to reload the project for the changes to be visible.

val appDependencies = Seq(
    "com.jayway.restassured" % "rest-assured" % "1.7" % "test"
)

The above example re-written to use REST-assured then looks like this:

import static play.test.Helpers.*;
import com.jayway.restassured.RestAssured;
...
@Test
public void testInServer() {
  running(testServer(3333), new Runnable() {
      public void run() {
         RestAssured.expect().statusCode(200).when().get("http://localhost:3333");
      }
  });
}

REST-assured defaults to localhost for requests, so it’s possible to cut down on the boilerplate and use relative URLs by tweaking the configuration a little.

import static play.test.Helpers.*;
import com.jayway.restassured.RestAssured;
...
private static final int PORT = 3333;

@Before
public void setUp()
{
    RestAssured.port = PORT;
}
...
@Test
public void testInServer() {
  running(testServer(PORT), new Runnable() {
      public void run() {
         RestAssured.expect().statusCode(200).when().get("/");
      }
  });
}

I’ve written a small example that’s available on github, and here’s a sample from it which features an entity being persisted, and then retrieved for testing.

@Test
public void testGetBeer_present()
{
    running(testServer(PORT), new Runnable()
    {
        @Override
        public void run()
        {
            // Create the beer
            RestAssured.given()
                       .contentType(ContentType.JSON)
                       .content("{\"name\":\"Westmalle\"}")
                       .expect()
                       .statusCode(200)
                       .when()
                       .post("/");

            // Retrieve it by name, and bind the response body into a Beer instance
            Beer beer = RestAssured.expect()
                                   .statusCode(200)
                                   .when()
                                   .get("/Westmalle")
                                   .andReturn()
                                   .body()
                                   .as(Beer.class);
            Assert.assertEquals("Westmalle",
                                beer.name);
        }
    });
}

To run the tests, just start up Play in on your command line, and use the test command:

[play-rest-assured] $ test
[info] controllers.BeersTest
[info] + controllers.BeersTest.testGetAll_emptyDatabase
[info] + controllers.BeersTest.testGetAll_populatedDatabase
[info] + controllers.BeersTest.testGetBeer_emptyDatabase
[info] + controllers.BeersTest.testGetBeer_present
[info] + controllers.BeersTest.testUpdate
[info] 
[info] 
[info] Total for test controllers.BeersTest
[info] Finished in 6.954 seconds
[info] 5 tests, 0 failures, 0 errors
[info] Passed: : Total 5, Failed 0, Errors 0, Passed 5, Skipped 0
[success] Total time: 7 s, completed Oct 29, 2012 7:37:52 AM

Resources

Using SecureSocial in your local dev environment

Jorge Aliss has asked me (about 3 months ago, mea culpa) to write an example application that integrates the Deadbolt authorization module with his excellent SecureSocial module.

The application is currently in development as I take a five minute break to write this, and I thought I would share a handy shortcut for developing your own SecureSocial apps on your local box.

If you’re using, for example, Twitter to provide your OAuth service then you’ll need to provide a callback URL. Since you’re on your local computer, which doesn’t necessarily have its own external IP address then there are a couple of hacks you can use. One involves changing your hosts file to resolve an external URL to your local server.

Another, far easier – and lazier – method, is to use a URL shortener to provide the same situation. bit.ly doesn’t seem to allow request parameters, but goo.gl does. Simply create a shortened URL for http://localhost:9000/securesocial.securesocial/authenticate?type=twitter (adjust as necessary for port, OAuth provider, etc) and use that as the callback address in the application your register with the OAuth provider.

Deadbolt – wtf was I thinking?

I just re-read my previous post and thought to myself…huh? What’s the point in telling people who’ll probably never even read the blog to make sure they cache in order to improve performance?

The answer came to me in a blaze of comprehension – add a caching feature to Deadbolt, document it and then it’s obvious (to anyone who RTFM of course).

So, Deadbolt 1.4.3 is released tonight with caching. It should also have been the release with FastTags instead of Groovy tags, but that’s a bug for another day. Now it’s just a question of getting time to finish the Scala version – coming soon :)

quick&easy: Automatically add content to play!-generated war files

I needed to add content to the war directory/file that play generates via the “play war” command. The content varied from files added to the top level of the war (alongside WEB-INF) to customising WEB-INF/web.xml. Checking the core documentation, no support for this is mentioned. Checking the python scripts that come with play!, I found a snippet of hope:

    if os.path.exists(os.path.join(app.path, 'war')):
        copy_directory(os.path.join(app.path, 'war'), war_path)

A basic play app has the structure

myapp
    |-app
    |-conf
    |-lib
    |-public
    |-test

If you add a directory called “war” at the same level as app, conf, etc, this will be used as the basis of the generated war. So,

myapp
    |-app
    |-conf
    |-lib
    |-public
    |-test
    |-war
        |-deployment
	|   |-deployment.properties
	|-WEB-INF
	    |-web.xml
	    |-arbitrary.txt

will add the deployment directory alongside the WEB-INF folder, and the default web.xml supplied by play! will be replaced by the one you provide. arbitrary.txt will also be placed in WEB-INF.

Make sure sure that, if you replace web.xml, you keep all content found in $PLAY_HOME/resources/war/web.xml otherwise your webapp will not start properly! So, your custom web.xml might look like

<?xml version="1.0" ?>
    <web-app xmlns="http://java.sun.com/xml/ns/j2ee"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
             version="2.4">
  
        <!-- START: standard play content -->
        <display-name>Play! (%APPLICATION_NAME%)</display-name>
  
        <context-param>
            <param-name>play.id</param-name>
            <param-value>%PLAY_ID%</param-value>
        </context-param>
  
        <listener>
            <listener-class>play.server.ServletWrapper</listener-class>
        </listener>
  
        <servlet>
            <servlet-name>play</servlet-name>
            <servlet-class>play.server.ServletWrapper</servlet-class>
        </servlet>

        <servlet-mapping>
            <servlet-name>play</servlet-name>
            <url-pattern>/</url-pattern>
        </servlet-mapping>
        <!-- END: standard play content -->

	<!-- START: custom content -->
		whatever
	<!-- END: custom content -->
    </web-app>

Note the use of fields denoted by % to enable play to update the content.

(As usual, once this was done I later found a mention in the optional GAE module – http://www.playframework.org/modules/gae-1.1/home)

quick&easy: Add optional configuration to play! template tags

Template tags in the play! framework are a simple, powerful way to share functionality between different pages. They have all the groovy goodness of regular templates, and you can pass variables into them easily.

But, as always, there’s always a but…

The functionality of the tags is determined by their implicit content and any parameters passed into them. Adding further configuration allows tags to have much more use as shared functions, but doing this is not obvious from the documentation.

As you can probably guess from the title, doing this is quick and easy.

The key comes from the play/groovy binding mechanism that allows variables to by dynamically declared.

Take the example of a vanilla tag which has a single argument, in a file called hello.html:

hello ${_name}

Note the use of the play convention that states variables passed into a tag are prefixed with an underscore.

This tag is invoked in the regular way:

{#hello name:'steve' /}

All well and good, but what if we want some default behaviour that can be over-ridden? For example, you may want the tag “hello” in its normal usage, but in 40% of the usages, to say “Good day” because someone in senior management can access the function and it’s felt that “hello” is far too informal. Stranger things have happened.

In this case we can rewrite the tag as:

%{ message = _formal == null ? 'Hello' : (formal ? 'Good day' : 'Hello') }%

${message} ${_name}

_formal will be null if not declared in the calling tag, and so the message will be “Hello”. If it is declared, and it’s a boolean, the message will vary according to the value.

So, the existing tag call of

{#hello name:'steve' /}

will produce

Hello Steve

but

{#hello name:'steve' formal:true/}

will produce

Good day Steve

It should be noted there is another possibility in the example above – giving a value to “formal” which is not a boolean but nonetheless a not-null object will result in “Good day”. Take this into account when setting up your defaults, and rewrite the assignment of “message” if necessary to allow for this!

quick&easy: Deliver a generated file to the browser without writing to the server file system

Another day, another post about play!

When you extend from play.mvc.Controller, you have access to various render methods. One of these is renderBinary(), which allows you to send binary data (captchas, images, etc) to the browser.

renderBinary() is overloaded, and one of the signatures takes an java.io.InputStream as the source of the binary data. This makes it easy to load, for example, a file from the server into the InputStream and deliver it to the browser. However, what about files that don’t exist anywhere?

More than a few places allow you to tailor what you’re downloading so you only get exactly what you need – JQuery UI springs to mind here. However, when I tried to download JQuery UI for a new project a few weeks ago, I received an error message – /tmp/foo.zip could not be written to the file system, or something similar.

Because renderBinary() renders – surprise – binary, what you’re doing is passing a bytestream into the response. Java provides a java.io.ByteArrayInputStream, which can hold all your bytes (within reasonable memory constraints) and so there is the possibility of creating in-memory files and rendering them.

In this example, I’ll take some files from the server, zip them up in memory and dump them into the response.

public class Foo extends Controller 
{
    public static void getZipFile()
    {
        ZipOutputStream zos = null;
        ByteArrayOutputStream bytes = new ByteArrayOutputStream();
        FileInputStream fileInput = null;

        try 
        {
            zipOutput = new  ZipOutputStream(new BufferedOutputStream(bytes));
            String fileNames = { "/tmp/foo.txt", "/tmp/bar.txt" };
            for (String fileName : fileNames)
            {
                ZipEntry entry = new ZipEntry(fileName);
                zipOutput.putNextEntry(entry);

                fileInput = new FileInputStream(fileName);
                byte[] buf = new byte[1024]; 
                int len; while ((len = fileInput.read(buf)) > 0) 
                {
                    zipOutput.write(buf, 0, len);
                }

                zos.closeEntry();
                // IOUtils.close() just closes the stream if it's not null, and swallows 
                // any exceptions - this is just an example!
                IOUtils.close(fileInput);
            }
            // close the output stream, but crucially this has no effect on the content 
            // of bytes (check the ByteArrayOutputStream javadoc for why)
            zipOutput.close();
            
            // at this point, bytes contains the zip "file"
            InputStream zipInput = new ByteArrayInputStream(bytes.toByteArray());
            // give the resulting binary a name in the response
            renderBinary(zipInput, "foobar.zip");
        }
        catch (IOException e)
        {
            // whatever
        }
        finally
        {
            IOUtils.close(fileInput);
            IOUtils.close(zipOutput);
        }
    }
}

There are, of course, pros and cons with any approach…

  • Pros
    • You don’t write to the file system, so you don’t need to clean up the file system
    • Should be faster, due to not writing to the file system
  • Cons
    • More memory intensive – potentially much more memory intensive, depending on your user requirements and what you’re actually assembling in memory
    • As written, there’s nothing on the file system for you to check for correctness (easily corrected, in a dev environment)

quick&easy: Sharing a domain model between two Play! apps

If you have a couple of play! apps that have a common domain model, the easiest way to share that model is to put it into a module.

play new-module my-shared-model

generates an empty module in the current directory. Put your domain model in my-shared-model/apps/models, add some tests and then you have a choice: Either
1. install the module into the play! framework (see official docs here). This can then be referenced in conf/application.conf using

module.my-shared-model=${play.path}/modules/my-shared-model

or 2. Put the module somewhere well-known and logically related to the apps that share it, and give it a relative reference, e.g.

projects
 |- app1
 |- app2
 |- my-shared-model

conf/application.conf of app1 and app2:

module.my-shared-model=../my-shared-model

Note the module is now resolved relative to the application root.

Start up app1 (or app2) and the console should give you this happy message:

06:54:52,148 INFO  ~ Starting /home/steve/projects/app1
06:54:52,158 INFO  ~ Module my-shared-model is available (/home/steve/projects/app1/../my-shared-model)

Done!