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() {