Ginkgo4J

Having been an engineer using Java since pretty much version 1 and having practiced TDD for the best part of 10 years one thing that always bothered me was the lack of structure and context that Java testing frameworks like Junit provided.  On larger code bases, with many developers this problem can become quite accute.  When pair programming and working on existing tests I have sometimes even had to say to my pair

“Give me 10/15 minutes to actually figure out what this test is actually doing”

Because the fact of the matter is that the method name is simply not enough to convey the required given, when, then semantics context that are present in all tests.

I recently made a switch in job roles.  Whilst I stayed with EMC, I left the Documentum division (ECD) with whom I had been for 17 years and moved to a new division called the Cloud Platform Team (CPT) whose remit is to help EMC make a transition to the 3rd platform.  As a result I am now based in the Pivotal office in San Francisco and I pair program and I am now working in Golang.

Golang has a testing framework called Ginkgo that was actually created by one of Pivotal’s VPs Onsi Fakhouri.  It mirrors frameworks from other languages like RSpec in Ruby.  All of these framework provide a very simply DSL that the developer can use in his test to build up a described context with closures.  Having practiced this for the last six months I personally find this way of writing tests very useful.  Perhaps the most useful when I pick up an existing test and try to modify it.

Now, since version 8 Java has included it’s version of closures, called Lambda’s.  Whilst there aren’t quite as flexible as some of their equivalents on other languages.  All variable access must be to ‘finals’ for example.  They are sufficient to build an equivalent  testing DSL.  So that’s what I decided to do with Ginkgo4J, pronounced Ginkgo for Java.

So let’s take a quick look at how it works.

In your Java 8 project, add a new test class called BookTests.java as follows:-

package com.github.paulcwarren.ginkgo4j.examples;

import static com.github.paulcwarren.ginkgo4j.Ginkgo4jDSL.*;
 import org.junit.runner.RunWith;
 import com.github.paulcwarren.ginkgo4j.Ginkgo4jRunner;

@RunWith(Ginkgo4jRunner.class)
 public class BookTests {
{
  Describe("A describe", () -> {
  });
 }
 }

Let’s break this down:-

  • The imports Ginkgo4jDSL.* and Ginkgo4jRunner add Ginkgo4J’s DSL and JUnit runner.  The Junit runner allows these style of tests to be run in all IDEs supporting Junit (basically all of them) and also in build tools such as Ant, Maven and Gradle.
  • We add a top-level Describe container using Ginkgo4J’s Describe(String title, ExecutableBlock block) method.  The top-level braces {}trick allows us to evaluate the Describe at the top level without having to wrap it.
  • The 2nd argument to the Describe () -> {}is a lambda expression defining an anonymous class that implements the ExecutableBlock interface.

The 2nd argument lamdba expression to the Describe will contain our specs.  So let’s add some now to test our Book class.

private Book longBook;
private Book shortBook;
{
 Describe("Book", () -> {
   BeforeEach(() -> {
     longBook = new Book("Les Miserables", "Victor Hugo", 1488);
     shortBook = new Book("Fox In Socks", "Dr. Seuss", 24);
   });

   Context("Categorizing book length", () -> {
     Context("With more than 300 pages", () -> {
       It("should be a novel", () -> {
         assertThat(longBook.categoryByLength(), is("NOVEL"));
       });
     });

     Context("With fewer than 300 pages", () -> {
       It("should be a short story", () -> {
         assertThat(shortBook.categoryByLength(), is("NOVELLA"));
       });
     });
   });
   });
 }

Let’s break this down:

  • Ginkgo4J makes extensive use of lambdas to allow you to build descriptive test suites.
  • You should make use of Describe and Context containers to expressively organize the behavior of your code.
  • You can use BeforeEach to set up state for your specs. You use It to specify a single spec.
  • In order to share state between a BeforeEach and an It you must use member variables.
  • In this case we use Hamcrest’s assertThat syntax to make expectations on the categoryByLength() method.

Assuming a Book model with this behavior, running this JUnit test in Eclipse (or Intellij) will yield:

Screen Shot 2016-06-02 at 8.31.35 AM

Success!

Focussed Specs

It is often convenient, when developing to be able to run a subset of specs. Ginkgo4J allows you to focus individual specs or whole containers of specs programatically by adding an F in front of your Describe, Context, andIt:

 FDescribe("some behavior", () -> { ... })
 FContext("some scenario", () -> { ... })
 FIt("some assertion", () -> { ... })

doing so instructs Ginkgo4J to only run those specs. To run all specs, you’ll need to go back and remove all the Fs.

Parallel Specs

Ginkgo4J has support for running specs in parallel.  It does this by spawning separate threads and dividing the specs evenly among these threads.  Parallelism is on by default and will use 4 threads.  If you wish to modify this you can add the additional annotation to your test class:-

@Ginkgo4jConfiguration(threads=1)

which will instruct Ginkgo4J to run a single thread.

Spring Support

Ginkgo4J also offers native support for Spring.  To test a Spring application context simply replace the @RunWith(Ginkgo4jRunner.class) with @RunWith(Ginkgo4jSpringRunner.class) and initialize you test class’ Spring application context in exactly the same way as if you were using Spring’s SpringJUnit4ClassRunner

@RunWith(Ginkgo4jSpringRunner.class)
@SpringApplicationConfiguration(classes = Ginkgo4jSpringApplication.class)

public class Ginkgo4jSpringApplicationTests {
  @Autowired
  HelloService helloService;
  {
  Describe("Spring intergation", () -> {
    It("should be able to use spring beans", () -> {
      assertThat(helloService, is(not(nullValue())));
    });

    Context("hello service", () -> {
      It("should say hello", () -> {
        assertThat(helloService.sayHello("World"), is("Hello World!"));
      });
    });
   });
   }

   @Test
   public void noop() {
   }
 }

The nooptest class is currently required as Spring’s junit runner asserts on at least one test class existing.

Trying it out for yourself

Please feel free to try it out on your Java projects.  For a maven project add:-

<dependency>
    <groupId>com.github.paulcwarren</groupId>
    <artifactId>ginkgo4j</artifactId>
    <version>1.0.0</version>
</dependency>

or for a Gradle project add:-

compile 'com.github.paulcwarren:ginkgo4j:1.0.0'

for others see here.

Advertisements

Role-based SPAs with AngularJS and Spring HATEOAS

Most, if not all, modern enterprise software needs to have a role-based user interface to support common-place use cases like, for example, devolved administration; i.e. User X is an coordinator for Group Y, allowing him or her to perform admin functions for that Group.  This is just an example, of course, there are plenty of others.

Spring provides support for many common authentication and authorization patterns and standards like OAuth2 and user management through LDAP or CAS.  It also supports maturing REST models such as hypermedia through Spring HATEOAS and Spring Data REST.

On the client-side, enterprises usually like to consolidate on a UI technology so that their apps have a similar look and feel.  Obviously, angularjs is right up there (at the time of writing anyways…polymer anyone?) driven largely, I think, by its extensibility.  Seems now-a-days that pretty much any service or directive you can think of is out there in github as a bower component.  One such extension, pertinent to this article, being angular-hal

I wanted to have a look at how one might implement a role-based UI in a modern day SPA by pairing these technologies together.

The complete code for this article can be found in my github repo here.

So, before we begin let’s set some context.  We are operating within a Spring boot-based web application, secured with a handy (for demo purposes) in-memory user database.  To navigate this application it will offer a hypermedia-based REST API for managing these users.  Client-side, we then front this hypermedia API with a role-based UI allowing ADMINs to add or remove users, allowing ADMINS or COORDinators to reset passwords, while USERs can simply just view users and do nothing else.

The type of resource doesn’t really matter, the pattern presented here applies regardless.  I chose user management as it meant the app could be self-demonstrating, and that appealed to me.

The app in github, especially security-wise, is based on Dave Syer’s blog post.  This was part II of a (currently) VI part series.  Excellent, by the way, and I thoroughly recommend checking them out.  Part II was adequate for my purposes.  From a HATEOAS perspective I also used Greg Turnquist’s blog post as a jumping off point.  And from a hypermedia standpoint I am basing my approach on Oliver Gierke’s RESTbucks presentations.

The App

Features and functionality of the app are very simple indeed.  You can log in and out and manage users.  Initially, there is only one user; username wozza, password dotio and this users is an ADMIN so he can create other users and set passwords. 

The idea therefore is to log in as wozza and create other users with different roles, log out and log in as those users to see how it affects the usability of the app.

So, if I log in as wozza:-

image

All functions are available to us and we can create a new user fred_flintstone, who is a COORDinator:-

image

Once created we can then give Fred a password:-

image

And then we can logout and log back in as Fred:-

image

If we do that we can now you can see Fred, who is a COORDinator, can reset passwords but can’t add or remove users.

As wozza we could add a third user, Barnie Rubble for example, with role USER and then we would see that he can view users only but I’ll leave that up to you.  You get the picture.

Server-side

On the server-side I have configured form login-based security that also uses a custom user details service.  This is a really, really simple in-memory user database.  So, note if you reboot the app you are back to the wozza user only.

Hypermedia-wise I have a root SiteController that is the entry-point, offered at /api.  This links (via a linkrel) to the UsersController that manages the collection of users and this in turn links to the UserController for managing individual user resources including setting their password.  Therefore from the single known entry point /api the client can follow the “users” linkrel to get the set of users and potentially follow the “password” linkrel for an indiivdual user to update the their password or follow the “delete” linkrel to remove the user from the system altogether.

Important to this article is that these controllers are role-aware and offer these linkrels IF and only if the current principal has the appropriate authority.  Let’s have a look at an example of this:-

image

Here we can see that in the UsersController.listUsers request handler we have injected (using standard Spring MVC) the security context’s Authentication object.  This then allows us to either add links to the users resource, or not.  In this example we are adding the self linkrel regardless (because users collection is available to everyone) but only adding the create linkrel if the current principal has ADMIN authority; i.e. only admins can create new users.

Likewise, for the user resource we do similar:-

image

Again we can see the self linkrel is added regardless, everyone can see a “user”.  But we only add the password linkrel if the current principal is an ADMIN or a COORDinator.  And only add the delete linkrel if the principal is an ADMIN.

When authenticated as an ADMIN we would then see this sort of response after following the users linkrel:-

{
  "_links" : {
    "self" : {
      "href" : "
http://localhost:8080/users"
    },
    "create" : {
      "href" : "
http://localhost:8080/users"
    }
  },
  "_embedded" : {
    "users" : [ {
      "username" : "rubble_barnie",
      "roles" : [ "USER" ],
      "_links" : {
        "self" : {
          "href" : "
http://localhost:8080/users/rubble_barnie"
        },
        "password" : {
          "href" : "
http://localhost:8080/users/rubble_barnie/password"
        },
        "delete" : {
          "href" : "
http://localhost:8080/users/rubble_barnie"
        }
      }
    }, …

Note, the presence of the create linkrel on the users resource itself and the password and deleted linkrels on the user resource.

Compare that with a response after following the same users linkrel, when authenticated as a COORDinator:-

{
  "_links" : {
    "self" : {
      "href" : "
http://localhost:8080/users"
    }
  },
  "_embedded" : {
    "users" : [ {
      "username" : "rubble_barnie",
      "roles" : [ "USER" ],
      "_links" : {
        "self" : {
          "href" : "
http://localhost:8080/users/rubble_barnie"
        },
        "password" : {
          "href" : "
http://localhost:8080/users/rubble_barnie/password"
        }
      }
    }, …

Where, as you will probably expect by now, we don’t have the create or delete linkrels but do still have the password linkrel.

A note before we move on.  Clearly, this approach wont stop any form of malicious attack which is why we still need “security in depth” in the real-world.  To show this you will see I have also configured security on the actual resources themselves, as follows…

image

…so we aren’t simple relying on the web client, which is inherently weak of course.  Any malicious attempt to call a resource without proper authentication is going to result in a 401 Unauthorized.

Client-side

OK, so the backend programming model is simple.  Hopefully, it is fairly obvious how we can use the presence or absence of these linkrels on the client-side to now show, hide or disable components of the user interface.  So, let’s take a look at that next.

There are several angular modules that support the application/hal+json mediatype.  As mentioned in the opening I chose angular-hal primarily because as it was small, simple and seemed to do what I required as I was initially thinking about this.

To set some context here as well this is just a standard angularjs app BUT important to this article is that the hypermedia approach of linkrel following allows us to consolidate on a single angular-hal service, halClient, for interacting with the REST API regardless of the type of resource.  This is important.  I have found that this replaces the many type-specific services that I have been writing up to this point (I don’t like $resource before any one asks). 

To kick everything off, in the application controller we bootstrap the client by using this halClient service to invoke the REST API entry point /api:-

.controller(‘appController’, [‘$rootScope’, ‘$scope’, ‘halClient’,
        function($rootScope, $scope, halClient) {

            $scope.root = function() {
                halClient.$get(‘/api’, {
                    linksAttribute : "_links"
                }).then(function(resource) {
                    $rootScope.resource = resource;
                });
            };

            $scope.root();

        } ]);

this returns the top-level resource, as follows:-

{
  "_links" : {
    "self" : {
      "href" : "
http://localhost:8080/api"
    },
    "users" : {
      "href" : "
http://localhost:8080/users"
    }
  }
}

and halClient will decorate this object with a bunch of methods:-

image

allowing us to re-use this object to follow these linkrels further into the server’s REST API.  Note, that we save this object to $rootScope.resource so that we can refer to it from anywhere.

As you might expect then, in the “users” route, we use $rootScope.resource.$get to follow the “users” linkrel, as you can see here:-

    $routeProvider.when(‘/users’, {
        templateUrl : ‘/js/users/users.html’,
        controller : ‘usersController’,
        resolve: {
            usersResource: function($rootScope) {
               if ($rootScope.resource)
                 return $rootScope.resource.$get(‘users’, {
                        linksAttribute: "_links",
                        embeddedAttribute: "_embedded"
                    });
               else
                    return {};
                }
        }
    })

that, when authenticated as an ADMIN, gets the following response from the server:-

{
  "_links" : {
    "self" : {
      "href" : "
http://localhost:8080/users"
    },
    "create" : {
      "href" : "
http://localhost:8080/users"
    }
  },
  "_embedded" : {
    "users" : [ {
      "username" : "wozza",
      "roles" : [ "ADMIN" ],
      "_links" : {
        "self" : {
          "href" : "
http://localhost:8080/users/wozza"
        },
        "password" : {
          "href" : "
http://localhost:8080/users/wozza/password"
        },
        "delete" : {
          "href" : "
http://localhost:8080/users/wozza"
        }
      }
    } ]
  }
}

Note the presence of the create linkrel on the users collection itself and the presence of the password and delete linkrels on the “wozza” user resource.

We then use this usersResource response object to bootstrap the users UI:-

app.controller(‘usersController’, [‘$scope’, ‘usersResource’,
        function($scope, usersResource) {

            $scope.resource = usersResource;
           
            usersResource.$get(‘users’)
                .then(function(users) {
                    $scope.users = users;
                });

by storing the usersResource as the local scope variable resource and by storing the embedded users collection in local scope variable users.

An interesting aspects of this, that I havent had time to investigate yet, is how application navigation typically maps to REST API navigation.

I didn’t use it in this simple demo app, but I suspect in a more complex application using the ui-router (and its nested views) it will likely end up that as you navigate deeper into the application, you will also navigate deeper into the REST API, thus this $scope.resource overriding pattern might prove quite natural.

Ultimately, in the HTML template we use this local scope variable resource to show/hide, enable/disable various aspects of the UI:-

<table class="table">

    <tr ng-show="resource.$has(‘create’)">
        <td><input type="text" placeholder="Enter username" ng-model="newUser.username"></td>

        <td><button class="btn" ng-click="onClickAdd(newUser)">Add</button></td>
        <td></td>
    </tr>
    <tr ng-repeat="user in users">
        <td>{{user.username}}</td>
        <td>{{user.roles}}</td>
        <td><button class="btn" ng-disabled="!user.$has(‘delete’)" ng-click="onClickRemove(user)">Remove</button></td>
        <td><button class="btn" ng-disabled="!user.$has(‘password’)" ng-click="onClickSetPassword(user)">Set Password</button></td>
    </tr>
</table>

You can see here that we show the table “create” row only if the create linkrel is present.  Similarly, we disable (rather than hide this time) the Remove and Set Password buttons based on the presence or absence of the delete and password linkrels.  It is important to note here that we are checking the user object here, not the users collection.

In Conclusion

That is about as far as I will go for this article. 

I like this approach as it gives really easy to understand and implement programming paradigm on both the server and the client.  On the server-side Spring, Spring MVC, Spring HATEOAS and Spring Data REST have all made creating role-based controllers super easy.  Likewise, on the client, LuvDaSun has done a great job on angular-hal allowing the server’s hypermedia to be consumed with no effort leading to nice, concise client-code.

Now, with this great power, comes responsibility.  Just because we can do this, doesn’t necessarily make it right?  And that is a more philosophical question where I would like to get some feedback on from my readership please. 

My take on it is that using Spring’s principal to decide whether, or not, to add linkrels to a resource is I think, considering prevailing trends towards micro-services and super-user sessions to backend data sources, well-aligned.  Conversely though, in more traditional on-premise enterprise platforms, like Documentum, authorization decisions are usually provided by the backend data source.  It is more secure.  However, what I have presented here could easily be adapted to defer these decisions to the data source instead.

Where Next?

There is lots I haven’t looked at here. 

I haven’t paid any attention to the excellent Spring Data and Spring Data REST.  Spring Data REST uses ALPS which is an integral part of a proper hypermedia API of course.  So, I would like to investigate adding ALPS.  For example, clients could discover what the password linkrel actually does and whether it is idempotent; i.e. a PUT, or not.

I would also like to look at using ResourceProcessor’s to take a similar approach to that proposed here to add role-aware linkrels to Spring Data REST resources.  I think this combo could be very enabling.

Thanks all.