Refactor REST API Tests for reuse

- Add a base class for Rest API tests
- Add a base class for Intent Rest API tests
- Add a Matcher to use to check ClientResource HTTP statuses
- Add a test for REST DELETE operations on Intents.
  This is currently disabled because DELETE operations
  are not fully implemented.

Change-Id: Idb1b56052e791a8d5c87edac15d10a247607d4e8
diff --git a/src/test/java/net/onrc/onos/api/rest/ClientResourceStatusMatcher.java b/src/test/java/net/onrc/onos/api/rest/ClientResourceStatusMatcher.java
new file mode 100644
index 0000000..c7d03df
--- /dev/null
+++ b/src/test/java/net/onrc/onos/api/rest/ClientResourceStatusMatcher.java
@@ -0,0 +1,82 @@
+package net.onrc.onos.api.rest;
+
+import org.hamcrest.Description;
+import org.hamcrest.Factory;
+import org.hamcrest.Matcher;
+import org.hamcrest.TypeSafeMatcher;
+import org.restlet.data.Status;
+import org.restlet.resource.ClientResource;
+
+/**
+ * Hamcrest Matcher to determine if a Restlet ClientResource object's status
+ * matches a given status.
+ */
+public class ClientResourceStatusMatcher extends TypeSafeMatcher<ClientResource> {
+    private Status status;
+
+    /**
+     * Hide constructor with no arguments.
+     */
+    @SuppressWarnings("unused")
+    private ClientResourceStatusMatcher() { }
+
+    /**
+     * Create a matcher for the given status object.
+     *
+     * @param newStatus status to be matched against
+     */
+    private ClientResourceStatusMatcher(final Status newStatus) {
+        status = newStatus;
+    }
+
+    /**
+     * Match a Client resource.  Compares the status of the given client against
+     * the expected Status that was given when the object was created.
+     *
+     * @param client the client to perform the match against
+     * @return true if the Status of the given client matches the Status that
+     *         was given when the Matcher was created, false otherwise
+     */
+    @Override
+    public boolean matchesSafely(ClientResource client) {
+        return status.equals(client.getStatus());
+    }
+
+    /**
+     * Generate a Hamcrest description for the 'to' object of this Matcher.
+     *
+     * @param description Description object to add the textual description to
+     */
+    @Override
+    public void describeTo(Description description) {
+        description.appendText("status '")
+                   .appendText(status.getDescription())
+                   .appendText("'");
+    }
+
+    /**
+     * Describe why a mismatch was generated for the given client.
+     *
+     * @param client the client that was detected as a mismatch
+     * @param mismatchDescription Description object to add the textual
+     *                            description to
+     */
+    @Override
+    public void describeMismatchSafely(ClientResource client,
+                                       Description mismatchDescription) {
+        mismatchDescription.appendText("   was '")
+                           .appendText(client.getStatus().getDescription())
+                           .appendText("'");
+    }
+
+    /**
+     * Factory method to create a status Matcher for an ClientResource.
+     *
+     * @param status HTTP status code that the client status is matched against.
+     * @return Matcher object
+     */
+    @Factory
+    public static Matcher<ClientResource> hasStatusOf(final Status status) {
+        return new ClientResourceStatusMatcher(status);
+    }
+}
diff --git a/src/test/java/net/onrc/onos/api/rest/TestRest.java b/src/test/java/net/onrc/onos/api/rest/TestRest.java
new file mode 100644
index 0000000..21bc4be
--- /dev/null
+++ b/src/test/java/net/onrc/onos/api/rest/TestRest.java
@@ -0,0 +1,94 @@
+package net.onrc.onos.api.rest;
+
+import net.floodlightcontroller.restserver.RestletRoutable;
+
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Random;
+
+/**
+ * Base class for REST API tests.  This class exposes common code for setting
+ * up REST tests.
+ *
+ * This class maintains the web server and restlets that allow a test to call
+ * REST APIs.  It is intended to be used as a base class for a class that
+ * allows testing of a specific REST API resource (an example is Intents).
+ * See TestRestIntent as an example of an implementation which uses the
+ * TestRest framework.
+ */
+public class TestRest {
+
+    private final List<RestletRoutable> restlets = new LinkedList<>();
+    private TestRestApiServer restApiServer;
+    private int restPort;
+
+    /**
+     * Add a restlet to the web server.  Tests call this to add the specific
+     * REST APIs they are testing.  Call this before starting the server via
+     * setUp().
+     *
+     * @param newRestlet restlet to add to the web server
+     */
+    void addRestlet(final RestletRoutable newRestlet) {
+        restlets.add(newRestlet);
+    }
+
+    /**
+     * Assign the TCP port for the web server.
+     *
+     * @param newPort port number the web server will use
+     */
+    void setRestPort(int newPort) {
+        restPort = newPort;
+    }
+
+    /**
+     * Fetch the REST API Web Server object.
+     *
+     * @return REST API web server
+     */
+    TestRestApiServer getRestApiServer() {
+        return restApiServer;
+    }
+
+    /**
+     * Set up the REST API web server and start it.
+     */
+    public void setUp() {
+        restApiServer = new TestRestApiServer(restPort);
+        restApiServer.startServer(restlets);
+    }
+
+    /**
+     * Remove anything that will interfere with the next test running correctly.
+     * Shuts down the test REST web server.
+     */
+
+    public void tearDown() {
+        getRestApiServer().stopServer();
+    }
+
+    /**
+     * Get the base URL to use for REST requests.
+     *
+     * @return base URL
+     */
+    String getBaseRestUrl() {
+        return "http://localhost:" + Integer.toString(restPort) + "/wm/onos";
+    }
+
+    /**
+     * Generate a random port number for the REST API web server to use.  For
+     * now, a random port between 50000 and 55000 is selected
+     *
+     * @return a port number that the web server can use
+     */
+    int generateRandomPort() {
+        final int portStartRange = 50000;
+        final int portEndRange = 55000;
+
+        final Random random = new Random();
+
+        return portStartRange + (random.nextInt(portEndRange - portStartRange));
+    }
+}
diff --git a/src/test/java/net/onrc/onos/api/rest/TestRestApiServer.java b/src/test/java/net/onrc/onos/api/rest/TestRestApiServer.java
index e5c0634..77ea670 100644
--- a/src/test/java/net/onrc/onos/api/rest/TestRestApiServer.java
+++ b/src/test/java/net/onrc/onos/api/rest/TestRestApiServer.java
@@ -2,7 +2,6 @@
 
 
 import net.floodlightcontroller.restserver.RestletRoutable;
-import net.onrc.onos.core.intent.runtime.web.IntentWebRoutable;
 import org.restlet.Application;
 import org.restlet.Component;
 import org.restlet.Context;
@@ -57,7 +56,7 @@
      * The restlet engine requires an Application as a container.
      */
     private class RestApplication extends Application {
-        private Context context;
+        private final Context context;
 
         /**
          * Initialize the Application along with its Context.
@@ -149,10 +148,8 @@
      * of a JUnit test.
      *
      * @param restletsUnderTest list of Restlets to run as part of the server.
-     * @throws Exception if starting the server fails.
      */
-    public void startServer(final List<RestletRoutable> restletsUnderTest)
-           throws Exception {
+    public void startServer(final List<RestletRoutable> restletsUnderTest) {
         restlets = restletsUnderTest;
 
         restApplication = new RestApplication();
@@ -163,14 +160,18 @@
     /**
      * Stop the REST server.  The container is stopped, and the server will
      * no longer respond to requests.  The usual use of this is in the @After
-     * (tearDown) part of the server.
-     *
-     * @throws Exception if the server cannot be shut down cleanly.
+     * (tearDown) part of the test.
      */
-    public void stopServer() throws Exception {
-        restApplication.stop();
-        server.stop();
-        component.stop();
+    public void stopServer() {
+        try {
+            restApplication.stop();
+            server.stop();
+            component.stop();
+        } catch (Exception ex) {
+            // Stopping the server failed, convert to unchecked exception to
+            // abort the calling test with a failure.
+            throw new IllegalStateException(ex);
+        }
     }
 
 
diff --git a/src/test/java/net/onrc/onos/api/rest/TestRestIntent.java b/src/test/java/net/onrc/onos/api/rest/TestRestIntent.java
new file mode 100644
index 0000000..c47c56a
--- /dev/null
+++ b/src/test/java/net/onrc/onos/api/rest/TestRestIntent.java
@@ -0,0 +1,157 @@
+package net.onrc.onos.api.rest;
+
+import net.floodlightcontroller.core.module.FloodlightModuleContext;
+import net.floodlightcontroller.core.module.FloodlightModuleException;
+import net.onrc.onos.core.intent.runtime.IPathCalcRuntimeService;
+import net.onrc.onos.core.intent.runtime.IntentTestMocks;
+import net.onrc.onos.core.intent.runtime.PathCalcRuntimeModule;
+import net.onrc.onos.core.intent.runtime.web.IntentWebRoutable;
+import org.restlet.resource.ClientResource;
+
+import java.util.Collection;
+import java.util.Map;
+
+/**
+ * Base class for Intents REST API tests.
+ * Maintains the web server and restlets used for the REST calls
+ * Maintains whatever mocks are required to interact with the Intents framework
+ * Provides JSON related utility routines for processing Intents APIs return values
+ */
+public class TestRestIntent extends TestRest {
+
+    private PathCalcRuntimeModule runtime;
+    private IntentTestMocks mocks;
+
+    /**
+     * Fetch the Path Calc Runtime.
+     *
+     * @return path calc runtime.
+     */
+    PathCalcRuntimeModule getRuntime() {
+        return runtime;
+    }
+
+    /**
+     * Fetch the Intent mocking object.
+     *
+     * @return intent mocking object
+     */
+    IntentTestMocks getMocks() {
+        return mocks;
+    }
+
+    /**
+     * Create the web server, PathCalcRuntime, and mocks required for
+     * all of the tests.
+     */
+    @Override
+    public void setUp() {
+        mocks = new IntentTestMocks();
+        mocks.setUpIntentMocks();
+
+        addRestlet(new IntentWebRoutable());
+        super.setUp();
+
+        runtime = new PathCalcRuntimeModule();
+        final FloodlightModuleContext moduleContext = getMocks().getModuleContext();
+        try {
+            runtime.init(moduleContext);
+        } catch (FloodlightModuleException floodlightEx) {
+            throw new IllegalArgumentException(floodlightEx);
+        }
+        runtime.startUp(moduleContext);
+
+        getRestApiServer().addAttribute(IPathCalcRuntimeService.class.getCanonicalName(),
+                                        runtime);
+    }
+
+    /**
+     * Remove anything that will interfere with the next test running correctly.
+     * Shuts down the test REST web server and removes the mocks.
+     */
+    @Override
+    public void tearDown() {
+        getMocks().tearDownIntentMocks();
+        super.tearDown();
+    }
+
+    /**
+     * Fetch the base URL for Intents REST APIs.
+     *
+     * @return base URL
+     */
+    String getBaseRestIntentUrl() {
+        return getBaseRestUrl() + "/intent";
+    }
+
+    /**
+     * Fetch the URL to use for High Level Intents REST API calls.
+     *
+     * @return high level intents REST API URL
+     */
+    String getHighRestIntentUrl() {
+        return getBaseRestIntentUrl() + "/high";
+    }
+
+    /**
+     * Utility function to locate an intent in a JSON collection
+     * that has the given id.
+     * The JSON collection of intents looks like:
+     *  <code>
+     *      MAP =
+     *        [0] =
+     *          MAP =
+     *            id = "1"
+     *            ...
+     *        [1]
+     *          MAP =
+     *            id = "2"
+     *            ...
+     *        [2]
+     *          MAP =
+     *            id = "3"
+     *            ...
+     *        ...
+     *  </code>
+     *
+     * @param intents collection map to search
+     * @param id id of the intent to look for
+     * @return map for the intent if one was found, null otherwise
+     */
+    Map<String, String> findIntentWithId(final Collection<Map<String, String>> intents,
+                                         final String id) {
+        for (final Map<String, String>intentMap : intents) {
+            if (id.equals(intentMap.get("id"))) {
+                return intentMap;
+            }
+        }
+        return null;
+    }
+
+
+    /**
+     * Convenience function to fetch a collection of Intents from the JSON
+     * result of a REST call.  Hides the ugliness of the unchecked conversion
+     * to the proper Collection of Map type.
+     *
+     * @param client ClientResource that was used to make the REST call
+     * @return Collection of Maps that hold the Intent data
+     */
+    @SuppressWarnings("unchecked")
+    Collection<Map<String, String>> getIntentsCollection(final ClientResource client) {
+        return (Collection<Map<String, String>>)client.get(Collection.class);
+    }
+
+    /**
+     * Convenience function to fetch a single Intent from the JSON
+     * result of a REST call.  Hides the ugliness of the unchecked conversion
+     * to the proper Map type.
+     *
+     * @param client ClientResource that was used to make the REST call
+     * @return Map that hold the Intent data
+     */
+    @SuppressWarnings("unchecked")
+    Map<String, String> getIntent(final ClientResource client) {
+        return (Map<String, String>)client.get(Map.class);
+    }
+}
diff --git a/src/test/java/net/onrc/onos/api/rest/TestRestIntentHighDelete.java b/src/test/java/net/onrc/onos/api/rest/TestRestIntentHighDelete.java
new file mode 100644
index 0000000..162957e
--- /dev/null
+++ b/src/test/java/net/onrc/onos/api/rest/TestRestIntentHighDelete.java
@@ -0,0 +1,170 @@
+package net.onrc.onos.api.rest;
+
+import net.onrc.onos.core.intent.IntentOperation;
+import net.onrc.onos.core.intent.IntentOperationList;
+import net.onrc.onos.core.intent.ShortestPathIntent;
+import net.onrc.onos.core.intent.runtime.PathCalcRuntimeModule;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.modules.junit4.PowerMockRunner;
+import org.restlet.data.Status;
+import org.restlet.resource.ClientResource;
+
+import java.util.Collection;
+import java.util.Map;
+
+import static net.onrc.onos.api.rest.ClientResourceStatusMatcher.hasStatusOf;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.hasSize;
+import static org.hamcrest.Matchers.notNullValue;
+
+/**
+ * Unit tests to test the Intents DELETE REST APIs.
+ */
+@RunWith(PowerMockRunner.class)
+@PrepareForTest(PathCalcRuntimeModule.class)
+public class TestRestIntentHighDelete extends TestRestIntent {
+    private static final Long LOCAL_PORT = 0xFFFEL;
+
+
+    /**
+     * Create the web server, PathCalcRuntime, and mocks required for
+     * all of the tests.
+     */
+    @Before
+    public void beforeTest() {
+        setRestPort(generateRandomPort());
+        setUp();
+    }
+
+
+    /**
+     * Remove anything that will interfere with the next test running correctly.
+     * Shuts down the test REST web server and removes the mocks.
+     */
+    @After
+    public void afterTest() {
+        tearDown();
+    }
+
+
+    /**
+     * Make a set of Intents that can be used as test data.
+     */
+    private void makeDefaultIntents() {
+        final String BAD_SWITCH_INTENT_NAME = "No Such Switch Intent";
+
+        // create shortest path intents
+        final IntentOperationList opList = new IntentOperationList();
+        opList.add(IntentOperation.Operator.ADD,
+                new ShortestPathIntent(BAD_SWITCH_INTENT_NAME, 111L, 12L,
+                        LOCAL_PORT, 2L, 21L, LOCAL_PORT));
+        opList.add(IntentOperation.Operator.ADD,
+                new ShortestPathIntent("1:2", 1L, 14L, LOCAL_PORT, 4L, 41L,
+                        LOCAL_PORT));
+        opList.add(IntentOperation.Operator.ADD,
+                new ShortestPathIntent("1:3", 2L, 23L, LOCAL_PORT, 3L, 32L,
+                        LOCAL_PORT));
+
+        // compile high-level intent operations into low-level intent
+        // operations (calculate paths)
+
+        final IntentOperationList pathIntentOpList =
+                getRuntime().executeIntentOperations(opList);
+        assertThat(pathIntentOpList, notNullValue());
+
+    }
+
+    /**
+     * Test that the DELETE of all high level Intents REST call returns the
+     * proper result.
+     * The HTTP status of the delete call should be NO CONTENT
+     * Once the Intents are removed, an empty list should be
+     * returned by the fetch of all high level Intents.
+     */
+    // @Test The delete API does not currently work properly.
+    public void testDeleteOfAllIntents() {
+
+        makeDefaultIntents();
+
+        final ClientResource deleteClient = new ClientResource(getHighRestIntentUrl());
+        deleteClient.delete();
+
+        // HTTP status should be NO CONTENT
+        assertThat(deleteClient, hasStatusOf(Status.SUCCESS_NO_CONTENT));
+
+        //  Now query the intents to make sure they all got deleted
+        final ClientResource client = new ClientResource(getHighRestIntentUrl());
+        final Collection<Map<String, String>> intents = getIntentsCollection(client);
+
+        // HTTP status should be OK
+        assertThat(client, hasStatusOf(Status.SUCCESS_OK));
+
+        // There should be no intents left
+        assertThat(intents, hasSize(0));
+    }
+
+    /**
+     * Test that the DELETE of an existing high level Intents REST call returns the
+     * proper result.
+     * The HTTP status of the delete call should be NO CONTENT
+     * Once the Intent is removed, an empty list should be
+     * returned by the fetch of the Intent.
+     */
+    // @Test Intent delete currently does not work
+    public void testDeleteOfSingleExistingIntent() {
+
+        makeDefaultIntents();
+
+        final String intentUrl = getHighRestIntentUrl() + "/2";
+        final ClientResource deleteClient = new ClientResource(intentUrl);
+        deleteClient.delete();
+
+        // HTTP status should be NO CONTENT
+        assertThat(deleteClient, hasStatusOf(Status.SUCCESS_NO_CONTENT));
+
+        ClientResource client = new ClientResource(intentUrl);
+        try {
+            //  Now query the intent to make sure it got deleted
+            getIntent(client);
+            Assert.fail("Fetch of deleted intent did not throw an exception");
+        } catch (Exception ex) {
+            // HTTP status should be NOT FOUND
+            assertThat(client, hasStatusOf(Status.CLIENT_ERROR_NOT_FOUND));
+        }
+    }
+
+    /**
+     * Test that the DELETE of an existing high level Intents REST call returns the
+     * proper result.
+     * The HTTP status of the delete call should be NO CONTENT
+     * Once the Intent remove API is called, an empty list should be
+     * returned by the fetch of the Intent.
+     */
+    @Test
+    public void testDeleteOfSingleNonExistingIntent() {
+
+        makeDefaultIntents();
+
+        final String intentUrl = getHighRestIntentUrl() + "/2345678";
+        final ClientResource deleteClient = new ClientResource(intentUrl);
+        deleteClient.delete();
+
+        // HTTP status should be NO CONTENT
+        assertThat(deleteClient, hasStatusOf(Status.SUCCESS_NO_CONTENT));
+
+        ClientResource client = new ClientResource(intentUrl);
+        try {
+            //  Now query the intent to make sure its not there
+            getIntent(client);
+            Assert.fail("Fetch of deleted intent did not throw an exception");
+        } catch (Exception ex) {
+            // HTTP status should be NOT FOUND
+            assertThat(client, hasStatusOf(Status.CLIENT_ERROR_NOT_FOUND));
+        }
+    }
+}
diff --git a/src/test/java/net/onrc/onos/api/rest/TestRestIntentHighGet.java b/src/test/java/net/onrc/onos/api/rest/TestRestIntentHighGet.java
index 90bf596..1dde7bb 100644
--- a/src/test/java/net/onrc/onos/api/rest/TestRestIntentHighGet.java
+++ b/src/test/java/net/onrc/onos/api/rest/TestRestIntentHighGet.java
@@ -1,15 +1,10 @@
 package net.onrc.onos.api.rest;
 
 
-import net.floodlightcontroller.core.module.FloodlightModuleContext;
-import net.floodlightcontroller.restserver.RestletRoutable;
 import net.onrc.onos.core.intent.IntentOperation;
 import net.onrc.onos.core.intent.IntentOperationList;
 import net.onrc.onos.core.intent.ShortestPathIntent;
-import net.onrc.onos.core.intent.runtime.IPathCalcRuntimeService;
-import net.onrc.onos.core.intent.runtime.IntentTestMocks;
 import net.onrc.onos.core.intent.runtime.PathCalcRuntimeModule;
-import net.onrc.onos.core.intent.runtime.web.IntentWebRoutable;
 import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
@@ -22,10 +17,9 @@
 import org.restlet.resource.ResourceException;
 
 import java.util.Collection;
-import java.util.LinkedList;
-import java.util.List;
 import java.util.Map;
 
+import static net.onrc.onos.api.rest.ClientResourceStatusMatcher.hasStatusOf;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.equalTo;
 import static org.hamcrest.Matchers.hasKey;
@@ -34,59 +28,33 @@
 import static org.hamcrest.Matchers.notNullValue;
 
 /**
- * Unit tests to test the Intents REST APIs.
+ * Unit tests to test the Intents GET REST APIs.
  */
 @RunWith(PowerMockRunner.class)
 @PrepareForTest(PathCalcRuntimeModule.class)
-public class TestRestIntentHighGet {
+public class TestRestIntentHighGet extends TestRestIntent {
     private static final Long LOCAL_PORT = 0xFFFEL;
-
-    private static int REST_PORT = 7777;
-    private static String HOST_BASE_URL = "http://localhost:" +
-                                          Integer.toString(REST_PORT);
-    private static final String BASE_URL = HOST_BASE_URL + "/wm/onos/intent";
-    private static final String HIGH_URL = BASE_URL + "/high";
-
-    private PathCalcRuntimeModule runtime;
-    private TestRestApiServer restApiServer;
-    private IntentTestMocks mocks;
+    private static final String BAD_SWITCH_INTENT_NAME = "No Such Switch Intent";
 
 
     /**
      * Create the web server, PathCalcRuntime, and mocks required for
      * all of the tests.
-     * @throws Exception if the mocks or webserver cannot be started.
      */
     @Before
-    public void setUp() throws Exception {
-        mocks = new IntentTestMocks();
-        mocks.setUpIntentMocks();
-
-        runtime = new PathCalcRuntimeModule();
-        final FloodlightModuleContext moduleContext = mocks.getModuleContext();
-        runtime.init(moduleContext);
-        runtime.startUp(moduleContext);
-
-        final List<RestletRoutable> restlets = new LinkedList<>();
-        restlets.add(new IntentWebRoutable());
-
-        restApiServer = new TestRestApiServer(REST_PORT);
-        restApiServer.startServer(restlets);
-        restApiServer.addAttribute(IPathCalcRuntimeService.class.getCanonicalName(),
-                                   runtime);
+    public void beforeTest() {
+        setRestPort(generateRandomPort());
+        setUp();
     }
 
 
     /**
      * Remove anything that will interfere with the next test running correctly.
      * Shuts down the test REST web server and removes the mocks.
-     * @throws Exception if the mocks can't be removed or the web server can't
-     *         shut down correctly.
      */
     @After
-    public void tearDown() throws Exception {
-        restApiServer.stopServer();
-        mocks.tearDownIntentMocks();
+    public void afterTest() {
+        tearDown();
     }
 
 
@@ -94,8 +62,6 @@
      * Make a set of Intents that can be used as test data.
      */
     private void makeDefaultIntents() {
-        final String BAD_SWITCH_INTENT_NAME = "No Such Switch Intent";
-
         // create shortest path intents
         final IntentOperationList opList = new IntentOperationList();
         opList.add(IntentOperation.Operator.ADD,
@@ -112,90 +78,26 @@
         // operations (calculate paths)
 
         final IntentOperationList pathIntentOpList =
-                runtime.executeIntentOperations(opList);
+                getRuntime().executeIntentOperations(opList);
         assertThat(pathIntentOpList, notNullValue());
 
     }
 
     /**
-     * Utility function to locate an intent in a JSON collection
-     * that has the given id.
-     * The JSON collection of intents looks like:
-     *  <code>
-     *      MAP =
-     *        [0] =
-     *          MAP =
-     *            id = "1"
-     *            ...
-     *        [1]
-     *          MAP =
-     *            id = "2"
-     *            ...
-     *        [2]
-     *          MAP =
-     *            id = "3"
-     *            ...
-     *        ...
-     *  </code>
-     *
-     * @param intents collection map to search
-     * @param id id of the intent to look for
-     * @return map for the intent if one was found, null otherwise
-     */
-    private Map<String, String> findIntentWithId(final Collection<Map<String, String>> intents,
-                                                 final String id) {
-        for (final Map<String, String>intentMap : intents) {
-            if (id.equals(intentMap.get("id"))) {
-                return intentMap;
-            }
-        }
-        return null;
-    }
-
-
-    /**
-     * Convenience function to fetch a collection of Intents from the JSON
-     * result of a REST call.  Hides the ugliness of the unchecked conversion
-     * to the proper Collection of Map type.
-     *
-     * @param client ClientResource that was used to make the REST call
-     * @return Collection of Maps that hold the Intent data
-     */
-    @SuppressWarnings("unchecked")
-    private Collection<Map<String, String>> getIntentsCollection (final ClientResource client) {
-        return (Collection<Map<String, String>>)client.get(Collection.class);
-    }
-
-    /**
-     * Convenience function to fetch a single Intent from the JSON
-     * result of a REST call.  Hides the ugliness of the unchecked conversion
-     * to the proper Map type.
-     *
-     * @param client ClientResource that was used to make the REST call
-     * @return Map that hold the Intent data
-     */
-    @SuppressWarnings("unchecked")
-    private Map<String, String> getIntent (final ClientResource client) {
-        return (Map<String, String>)client.get(Map.class);
-    }
-
-    /**
      * Test that the GET of all Intents REST call returns the proper result.
      * The call to get all Intents should return 3 items, an HTTP status of OK,
      * and the proper Intent data.
-     *
-     * @throws Exception if any of the set up or tear down operations fail
      */
     @Test
-    public void testFetchOfAllIntents() throws Exception {
+    public void testFetchOfAllIntents() {
 
         makeDefaultIntents();
 
-        final ClientResource client = new ClientResource(HIGH_URL);
+        final ClientResource client = new ClientResource(getHighRestIntentUrl());
         final Collection<Map<String, String>> intents = getIntentsCollection(client);
 
         // HTTP status should be OK
-        assertThat(client.getStatus(), is(equalTo(Status.SUCCESS_OK)));
+        assertThat(client, hasStatusOf(Status.SUCCESS_OK));
 
         // 3 intents should have been fetched
         assertThat(intents, hasSize(3));
@@ -208,21 +110,30 @@
         assertThat(mapForIntent3, hasKey("state"));
         final String state = mapForIntent3.get("state");
         assertThat(state, is(equalTo("INST_REQ")));
+
+        // check that the Intent with the bad switch ID is present, and has the right data
+        final Map<String, String> mapForIntentBadIntent =
+                findIntentWithId(intents, BAD_SWITCH_INTENT_NAME);
+        // Intent must exist
+        assertThat(mapForIntentBadIntent, notNullValue());
+        //  Data must be correct
+        assertThat(mapForIntentBadIntent, hasKey("state"));
+        final String badIntentState = mapForIntentBadIntent.get("state");
+        assertThat(badIntentState, is(equalTo("INST_NACK")));
+
     }
 
     /**
      * Test that the GET of a single Intent REST call returns the proper result
      * when given a bad Intent id. The call to get the Intent should return a
      * status of NOT_FOUND.
-     *
-     * @throws Exception if any of the set up or tear down operations fail
      */
     @Test
-    public void testFetchOfBadIntent() throws Exception {
+    public void testFetchOfBadIntent() {
 
         makeDefaultIntents();
 
-        final ClientResource client = new ClientResource(HIGH_URL + "/2334");
+        final ClientResource client = new ClientResource(getHighRestIntentUrl() + "/2334");
 
         try {
             getIntent(client);
@@ -231,7 +142,7 @@
             Assert.fail("Invalid intent fetch did not cause an exception");
         } catch (ResourceException resourceError) {
             // The HTTP status should be NOT FOUND
-            assertThat(client.getStatus(), is(equalTo(Status.CLIENT_ERROR_NOT_FOUND)));
+            assertThat(client, hasStatusOf(Status.CLIENT_ERROR_NOT_FOUND));
         }
     }
 
@@ -239,20 +150,18 @@
      * Test that the GET of a single Intent REST call returns the proper result
      * for an existing Intent. The call to get the Intent should return a
      * status of OK, and the data for the Intent should be correct.
-     *
-     * @throws Exception if any of the set up or tear down operations fail
      */
     @Test
-    public void testFetchOfGoodIntent() throws Exception {
+    public void testFetchOfGoodIntent() {
 
         makeDefaultIntents();
 
-        final ClientResource client = new ClientResource(HIGH_URL + "/2");
+        final ClientResource client = new ClientResource(getHighRestIntentUrl() + "/2");
         final Map<String, String> intent;
         intent = getIntent(client);
 
         // HTTP status should be OK
-        assertThat(client.getStatus(), is(equalTo(Status.SUCCESS_OK)));
+        assertThat(client, hasStatusOf(Status.SUCCESS_OK));
 
         //  Intent data should be correct
         assertThat(intent, is(notNullValue()));
diff --git a/src/test/java/net/onrc/onos/core/intent/runtime/IntentTestMocks.java b/src/test/java/net/onrc/onos/core/intent/runtime/IntentTestMocks.java
index 51c42a6..aa5223e 100644
--- a/src/test/java/net/onrc/onos/core/intent/runtime/IntentTestMocks.java
+++ b/src/test/java/net/onrc/onos/core/intent/runtime/IntentTestMocks.java
@@ -53,65 +53,69 @@
      * Create whatever mocks are required to access the Intents framework.
      * This method is intended to be called during @Before processing (setUp())
      * of the JUnit test.
-     *
-     * @throws Exception if any of the mocks cannot be created.
      */
     @SuppressWarnings("unchecked")
-    public void setUpIntentMocks() throws Exception {
-        topology = new MockTopology();
-        topology.createSampleTopology1();
+    public void setUpIntentMocks() {
+        try {
+            topology = new MockTopology();
+            topology.createSampleTopology1();
 
-        datagridService = createMock(IDatagridService.class);
-        topologyService = createMock(ITopologyService.class);
-        controllerRegistryService = createMock(IControllerRegistryService.class);
-        moduleContext = createMock(FloodlightModuleContext.class);
-        final IEventChannel<Long, IntentOperationList> intentOperationChannel =
-                createMock(IEventChannel.class);
-        final IEventChannel<Long, IntentStateList>intentStateChannel =
-                createMock(IEventChannel.class);
-        persistIntent = PowerMock.createMock(PersistIntent.class);
-        restApi = createMock(IRestApiService.class);
+            datagridService = createMock(IDatagridService.class);
+            topologyService = createMock(ITopologyService.class);
+            controllerRegistryService = createMock(IControllerRegistryService.class);
+            moduleContext = createMock(FloodlightModuleContext.class);
+            final IEventChannel<Long, IntentOperationList> intentOperationChannel =
+                    createMock(IEventChannel.class);
+            final IEventChannel<Long, IntentStateList>intentStateChannel =
+                    createMock(IEventChannel.class);
+            persistIntent = PowerMock.createMock(PersistIntent.class);
+            restApi = createMock(IRestApiService.class);
 
-        PowerMock.expectNew(PersistIntent.class,
-                anyObject(IControllerRegistryService.class)).andReturn(persistIntent);
+            PowerMock.expectNew(PersistIntent.class,
+                    anyObject(IControllerRegistryService.class)).andReturn(persistIntent);
 
-        expect(moduleContext.getServiceImpl(IDatagridService.class))
-                .andReturn(datagridService).once();
-        expect(moduleContext.getServiceImpl(ITopologyService.class))
-                .andReturn(topologyService).once();
-        expect(moduleContext.getServiceImpl(IControllerRegistryService.class))
-                .andReturn(controllerRegistryService).once();
-        expect(persistIntent.getKey()).andReturn(1L).anyTimes();
-        expect(persistIntent.persistIfLeader(eq(1L),
-                anyObject(IntentOperationList.class))).andReturn(true)
-                .anyTimes();
-        expect(moduleContext.getServiceImpl(IRestApiService.class))
-                .andReturn(restApi).once();
+            expect(moduleContext.getServiceImpl(IDatagridService.class))
+                    .andReturn(datagridService).once();
+            expect(moduleContext.getServiceImpl(ITopologyService.class))
+                    .andReturn(topologyService).once();
+            expect(moduleContext.getServiceImpl(IControllerRegistryService.class))
+                    .andReturn(controllerRegistryService).once();
+            expect(persistIntent.getKey()).andReturn(1L).anyTimes();
+            expect(persistIntent.persistIfLeader(eq(1L),
+                    anyObject(IntentOperationList.class))).andReturn(true)
+                    .anyTimes();
+            expect(moduleContext.getServiceImpl(IRestApiService.class))
+                    .andReturn(restApi).once();
 
-        expect(topologyService.getTopology()).andReturn(topology)
-                .anyTimes();
-        topologyService.registerTopologyListener(
-                anyObject(ITopologyListener.class));
-        expectLastCall();
+            expect(topologyService.getTopology()).andReturn(topology)
+                    .anyTimes();
+            topologyService.registerTopologyListener(
+                    anyObject(ITopologyListener.class));
+            expectLastCall();
 
-        expect(datagridService.createChannel("onos.pathintent",
-                Long.class, IntentOperationList.class))
-                .andReturn(intentOperationChannel).once();
+            expect(datagridService.createChannel("onos.pathintent",
+                    Long.class, IntentOperationList.class))
+                    .andReturn(intentOperationChannel).once();
 
-        expect(datagridService.addListener(
-                eq("onos.pathintent_state"),
-                anyObject(IEventChannelListener.class),
-                eq(Long.class),
-                eq(IntentStateList.class)))
-                .andReturn(intentStateChannel).once();
-        restApi.addRestletRoutable(anyObject(IntentWebRoutable.class));
+            expect(datagridService.addListener(
+                    eq("onos.pathintent_state"),
+                    anyObject(IEventChannelListener.class),
+                    eq(Long.class),
+                    eq(IntentStateList.class)))
+                    .andReturn(intentStateChannel).once();
+            restApi.addRestletRoutable(anyObject(IntentWebRoutable.class));
 
-        replay(datagridService);
-        replay(topologyService);
-        replay(moduleContext);
-        replay(controllerRegistryService);
-        PowerMock.replay(persistIntent, PersistIntent.class);
-        replay(restApi);
+            replay(datagridService);
+            replay(topologyService);
+            replay(moduleContext);
+            replay(controllerRegistryService);
+            PowerMock.replay(persistIntent, PersistIntent.class);
+            replay(restApi);
+        } catch (Exception ex) {
+            // Convert the checked exception into an unchecked exception to
+            // abort the test that called.
+            throw new IllegalStateException(ex);
+        }
     }
 
     /**
@@ -140,6 +144,7 @@
 
     /**
      * Fetch the mocked topology.
+     *
      * @return mocked topology
      */
     public MockTopology getTopology() {