diff --git a/apps/ofagent/BUCK b/apps/ofagent/BUCK index 1c8ee1e605..fedf257440 100644 --- a/apps/ofagent/BUCK +++ b/apps/ofagent/BUCK @@ -10,12 +10,16 @@ COMPILE_DEPS = [ '//lib:netty-codec', '//lib:netty-handler', '//lib:openflowj-3.0', + '//lib:javax.ws.rs-api', + '//utils/rest:onlab-rest', ] TEST_DEPS = [ '//lib:TEST_ADAPTERS', '//core/api:onos-api-tests', '//core/common:onos-core-common-tests', + '//lib:TEST_REST', + '//lib:jersey-server', ] EXCLUDED_BUNDLES = [ @@ -25,6 +29,7 @@ EXCLUDED_BUNDLES = [ osgi_jar_with_tests ( deps = COMPILE_DEPS, test_deps = TEST_DEPS, + web_context = '/onos/v1/ofagent', ) onos_app ( diff --git a/apps/ofagent/pom.xml b/apps/ofagent/pom.xml index 3c45384d2d..8b66199f5d 100644 --- a/apps/ofagent/pom.xml +++ b/apps/ofagent/pom.xml @@ -73,6 +73,8 @@ org.onosproject onlab-osgi ${project.version} + tests + test org.onosproject @@ -126,6 +128,49 @@ netty-all ${netty4.version} + + + + org.onosproject + onos-rest + ${project.version} + + + org.onosproject + onlab-rest + ${project.version} + + + javax.ws.rs + javax.ws.rs-api + 2.0.1 + + + org.glassfish.jersey.containers + jersey-container-servlet + + + com.fasterxml.jackson.core + jackson-databind + + + org.glassfish.jersey.test-framework + jersey-test-framework-core + test + + + org.glassfish.jersey.test-framework.providers + jersey-test-framework-provider-jetty + test + + + org.onosproject + onos-rest + ${project.version} + tests + test + + @@ -136,9 +181,18 @@ true + <_wab>src/main/webapp/ + + WEB-INF/classes/apidoc/swagger.json=target/swagger.json, + {maven-resources} + openflowj + + *,org.glassfish.jersey.servlet + + ${web.context} diff --git a/apps/ofagent/src/main/java/org/onosproject/ofagent/rest/OFAgentCodec.java b/apps/ofagent/src/main/java/org/onosproject/ofagent/rest/OFAgentCodec.java new file mode 100644 index 0000000000..6e6e772bd2 --- /dev/null +++ b/apps/ofagent/src/main/java/org/onosproject/ofagent/rest/OFAgentCodec.java @@ -0,0 +1,75 @@ +/* + * Copyright 2017-present Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.onosproject.ofagent.rest; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.ObjectNode; +import com.google.common.collect.Sets; +import org.onosproject.codec.CodecContext; +import org.onosproject.codec.JsonCodec; +import org.onosproject.incubator.net.virtual.NetworkId; +import org.onosproject.ofagent.api.OFAgent; +import org.onosproject.ofagent.api.OFController; +import org.onosproject.ofagent.impl.DefaultOFAgent; + +import java.util.Set; + +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Preconditions.checkState; + +/** + * OpenFlow agent JSON codec. + */ +public final class OFAgentCodec extends JsonCodec { + + @Override + public ObjectNode encode(OFAgent ofAgent, CodecContext context) { + checkNotNull(ofAgent, "OFAgent cannot be null"); + + ObjectMapper mapper = context.mapper(); + ObjectNode ofAgentNode = mapper.createObjectNode(); + ofAgentNode + .put("networkId", ofAgent.networkId().toString()) + .put("state", ofAgent.state().toString()); + + ArrayNode controllers = mapper.createArrayNode(); + ofAgent.controllers().forEach(ofController -> controllers.add((new OFControllerCodec()).encode(ofController, + context))); + ofAgentNode.set("controllers", controllers); + + return ofAgentNode; + } + + public OFAgent decode(ObjectNode json, CodecContext context) { + JsonNode networkId = json.get("networkId"); + checkNotNull(networkId); + + checkNotNull(json.get("controllers")); + checkState(json.get("controllers").isArray()); + Set controllers = Sets.newHashSet(); + json.get("controllers").forEach(jsonController -> controllers.add((new + OFControllerCodec()).decode((ObjectNode) jsonController, context))); + + return DefaultOFAgent.builder() + .networkId(NetworkId.networkId(networkId.asLong())) + .controllers(controllers) + .state(OFAgent.State.STOPPED) + .build(); + } + +} diff --git a/apps/ofagent/src/main/java/org/onosproject/ofagent/rest/OFAgentWebApplication.java b/apps/ofagent/src/main/java/org/onosproject/ofagent/rest/OFAgentWebApplication.java new file mode 100644 index 0000000000..173e1cd7b7 --- /dev/null +++ b/apps/ofagent/src/main/java/org/onosproject/ofagent/rest/OFAgentWebApplication.java @@ -0,0 +1,32 @@ +/* + * Copyright 2017-present Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.onosproject.ofagent.rest; + +import org.onlab.rest.AbstractWebApplication; + +import java.util.Set; + + +/** + * OFAgent Web application. + */ +public class OFAgentWebApplication extends AbstractWebApplication { + @Override + public Set> getClasses() { + return getClasses(OFAgentWebResource.class); + } +} diff --git a/apps/ofagent/src/main/java/org/onosproject/ofagent/rest/OFAgentWebResource.java b/apps/ofagent/src/main/java/org/onosproject/ofagent/rest/OFAgentWebResource.java new file mode 100644 index 0000000000..58d22a1e64 --- /dev/null +++ b/apps/ofagent/src/main/java/org/onosproject/ofagent/rest/OFAgentWebResource.java @@ -0,0 +1,241 @@ +/* + * Copyright 2017-present Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.onosproject.ofagent.rest; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.ObjectNode; +import org.onosproject.incubator.net.virtual.NetworkId; +import org.onosproject.ofagent.api.OFAgent; +import org.onosproject.ofagent.api.OFAgentAdminService; +import org.onosproject.ofagent.api.OFAgentService; +import org.onosproject.rest.AbstractWebResource; + +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; + +import java.io.IOException; +import java.io.InputStream; + +import static javax.ws.rs.core.Response.Status.*; + + +/** + * Manage virtual switch and controller mapping. + */ +@Path("service") +public class OFAgentWebResource extends AbstractWebResource { + + private static final String OFAGENT_NOT_FOUND = "OFAgent not found"; + private static final String OFAGENTS_NOT_FOUND = "OFAgent set not found"; + private static final String OFAGENT_CREATED = "OFAgent created"; + private static final String OFAGENT_NOT_CREATED = "OFAgent not created"; + private static final String OFAGENT_STARTED = "OFAgent started"; + private static final String OFAGENT_NOT_STARTED = "OFAgent not started"; + private static final String OFAGENT_UPDATED = "OFAgent updated"; + private static final String OFAGENT_NOT_UPDATED = "OFAgent not updated"; + + /** + * Lists OpenFlow agents. + * Shows OpenFlow agents for all virtual networks. + * + * @return 200 OK if set exists, 500 INTERNAL SERVER ERROR otherwise + */ + @GET + @Path("ofagents") + public Response listOFAgents() { + OFAgentService service = get(OFAgentService.class); + ObjectMapper mapper = new ObjectMapper(); + ObjectNode root = mapper.createObjectNode(); + ArrayNode ofAgentsArray = mapper.createArrayNode(); + if (service.agents() == null) { + return Response.status(INTERNAL_SERVER_ERROR) + .entity(OFAGENTS_NOT_FOUND).build(); + } else { + service.agents().forEach(ofAgent -> ofAgentsArray.add((new OFAgentCodec()).encode(ofAgent, this))); + + root.set("ofAgents", ofAgentsArray); + return Response.ok(root, MediaType.APPLICATION_JSON_TYPE).build(); + } + + } + + /** + * Lists OpenFlow agent. + * Shows OpenFlow agent for given network. + * + * @param networkId OFAgent networkId + * @return 200 OK if OFAgent exists, 404 NOT FOUND otherwise + */ + @GET + @Path("ofagent/{networkId}") + public Response listOFAgent(@PathParam("networkId") long networkId) { + OFAgentService service = get(OFAgentService.class); + OFAgent ofAgent = service.agent(NetworkId.networkId(networkId)); + if (ofAgent == null) { + return Response.status(NOT_FOUND) + .entity(OFAGENT_NOT_FOUND).build(); + } else { + return Response.ok((new OFAgentCodec()).encode(ofAgent, this), MediaType + .APPLICATION_JSON_TYPE) + .build(); + } + } + + /** + * Adds a new OpenFlow agent. + * Creates a new OpenFlow agent and adds it to OpenFlow agent store. + * + * @param stream JSON stream + * @return 201 CREATED , 400 BAD REQUEST if stream cannot be decoded to OFAgent + * @throws IOException if request cannot be parsed + */ + @POST + @Path("ofagent-create") + @Consumes(MediaType.APPLICATION_JSON) + public Response createOFAgent(InputStream stream) throws IOException { + OFAgentAdminService adminService = get(OFAgentAdminService.class); + + OFAgent ofAgent = (new OFAgentCodec()).decode((ObjectNode) mapper().readTree(stream), this); + if (ofAgent == null) { + return Response.status(BAD_REQUEST) + .entity(OFAGENT_NOT_CREATED).build(); + } else { + adminService.createAgent(ofAgent); + return Response.status(CREATED).entity(OFAGENT_CREATED).build(); + } + } + + /** + * Starts OpenFlow agent. + * Starts OpenFlow agent for the given network. + * + * @param stream JSON stream + * @return 200 OK if OFAgent was started, 404 NOT FOUND when OF agent does not exist, 400 BAD REQUEST otherwise + * @throws IOException if request cannot be parsed + */ + @POST + @Path("ofagent-start") + @Consumes(MediaType.APPLICATION_JSON) + public Response startOFAgent(InputStream stream) throws IOException { + OFAgentAdminService adminService = get(OFAgentAdminService.class); + + ObjectNode jsonTree = (ObjectNode) mapper().readTree(stream); + JsonNode networkId = jsonTree.get("networkId"); + + if (networkId == null) { + return Response.status(BAD_REQUEST) + .entity(OFAGENT_NOT_STARTED).build(); + } else if (get(OFAgentService.class).agent(NetworkId.networkId(networkId.asLong())) == null) { + return Response.status(NOT_FOUND) + .entity(OFAGENT_NOT_STARTED).build(); + } else { + adminService.startAgent(NetworkId.networkId(networkId.asLong())); + return Response.status(OK).entity(OFAGENT_STARTED).build(); + } + } + + /** + * Updates OpenFlow agent. + * Updates existing OpenFlow agent for the given network. + * + * @param stream JSON stream + * @return 200 OK if OFAgent was updated, 404 NOT FOUND when OF agent does not exist, 400 BAD REQUEST otherwise + * @throws IOException if request cannot be parsed + */ + @PUT + @Path("ofagent-update") + @Consumes(MediaType.APPLICATION_JSON) + public Response updateOFAgent(InputStream stream) throws IOException { + OFAgentAdminService adminService = get(OFAgentAdminService.class); + + OFAgent ofAgent = (new OFAgentCodec()).decode((ObjectNode) mapper().readTree(stream), this); + + if (ofAgent == null) { + return Response.status(NOT_FOUND) + .entity(OFAGENT_NOT_UPDATED).build(); + } else if (get(OFAgentService.class).agent(ofAgent.networkId()) == null) { + return Response.status(NOT_FOUND) + .entity(OFAGENT_NOT_UPDATED).build(); + } + + adminService.updateAgent(ofAgent); + return Response.status(OK).entity(OFAGENT_UPDATED).build(); + } + + + /** + * Stops OFAgent. + * Stops OFAgent for the given virtual network. + * + * @param stream JSON stream + * @return 204 NO CONTENT if OpenFlow agent was stopped, 404 NOT FOUND otherwise + * @throws IOException if request cannot be parsed + */ + @POST + @Path("ofagent-stop") + @Consumes(MediaType.APPLICATION_JSON) + public Response stopOFAgent(InputStream stream) throws IOException { + + OFAgentAdminService adminService = get(OFAgentAdminService.class); + ObjectNode jsonTree = (ObjectNode) mapper().readTree(stream); + JsonNode networkId = jsonTree.get("networkId"); + + if (get(OFAgentService.class).agent(NetworkId.networkId(networkId.asLong())) == null) { + return Response.status(NOT_FOUND) + .entity(OFAGENT_NOT_FOUND).build(); + } + + adminService.stopAgent(NetworkId.networkId(networkId.asLong())); + return Response.noContent().build(); + } + + + /** + * Deletes OFAgent. + * Removes OFAgent for the given virtual network from repository. + * + * @param networkId OFAgent networkId + * @return 200 OK if OFAgent was removed, 404 NOT FOUND when OF agent does not exist, 400 BAD REQUEST otherwise + */ + @DELETE + @Path("ofagent-remove/{networkId}") + public Response removeOFAgent(@PathParam("networkId") long networkId) { + if (get(OFAgentService.class).agent(NetworkId.networkId(networkId)) == null) { + return Response.status(BAD_REQUEST) + .entity(OFAGENT_NOT_FOUND).build(); + } + + OFAgentAdminService adminService = get(OFAgentAdminService.class); + OFAgent removed = adminService.removeAgent(NetworkId.networkId(networkId)); + if (removed != null) { + return Response.ok((new OFAgentCodec()).encode(removed, this), MediaType + .APPLICATION_JSON_TYPE) + .build(); + } else { + return Response.status(NOT_FOUND) + .entity(OFAGENT_NOT_FOUND).build(); + } + } +} diff --git a/apps/ofagent/src/main/java/org/onosproject/ofagent/rest/OFControllerCodec.java b/apps/ofagent/src/main/java/org/onosproject/ofagent/rest/OFControllerCodec.java new file mode 100644 index 0000000000..e50dcccdb7 --- /dev/null +++ b/apps/ofagent/src/main/java/org/onosproject/ofagent/rest/OFControllerCodec.java @@ -0,0 +1,64 @@ +/* + * Copyright 2017-present Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.onosproject.ofagent.rest; + +import com.fasterxml.jackson.databind.node.ObjectNode; +import org.onlab.packet.IpAddress; +import org.onlab.packet.TpPort; +import org.onosproject.codec.CodecContext; +import org.onosproject.codec.JsonCodec; +import org.onosproject.ofagent.api.OFController; +import org.onosproject.ofagent.impl.DefaultOFController; + +import static com.google.common.base.Preconditions.checkNotNull; +import static org.onlab.util.Tools.nullIsIllegal; + +/** + * OFController JSON codec. + */ +public final class OFControllerCodec extends JsonCodec { + + private static final String IP = "ip"; + private static final String PORT = "port"; + + private static final String MISSING_MEMBER_MESSAGE = " member is required in OFController"; + + @Override + public ObjectNode encode(OFController ofController, CodecContext context) { + checkNotNull(ofController, "OFController cannot be null"); + + return context.mapper().createObjectNode() + .put(IP, String.valueOf(ofController.ip())) + .put(PORT, String.valueOf(ofController.port())); + + } + + @Override + public OFController decode(ObjectNode json, CodecContext context) { + if (json == null || !json.isObject()) { + return null; + } + + // parse ip address + int id = nullIsIllegal(json.get(IP), IP + MISSING_MEMBER_MESSAGE).asInt(); + + // parse port + String name = nullIsIllegal(json.get(PORT), PORT + MISSING_MEMBER_MESSAGE).asText(); + + return DefaultOFController.of(IpAddress.valueOf(id), + TpPort.tpPort(Integer.valueOf(name))); + } +} diff --git a/apps/ofagent/src/main/java/org/onosproject/ofagent/rest/package-info.java b/apps/ofagent/src/main/java/org/onosproject/ofagent/rest/package-info.java new file mode 100644 index 0000000000..36977f93b4 --- /dev/null +++ b/apps/ofagent/src/main/java/org/onosproject/ofagent/rest/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright 2017-present Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * REST API for OFAgent. + */ +package org.onosproject.ofagent.rest; \ No newline at end of file diff --git a/apps/ofagent/src/main/webapp/WEB-INF/web.xml b/apps/ofagent/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 0000000000..5c82b0dd3c --- /dev/null +++ b/apps/ofagent/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,57 @@ + + + + OFAgent REST API v1.0 + + + + Secured + /* + + + admin + + + + + admin + + + + BASIC + karaf + + + + JAX-RS Service + org.glassfish.jersey.servlet.ServletContainer + + javax.ws.rs.Application + org.onosproject.ofagent.rest.OFAgentWebApplication + + 1 + + + + JAX-RS Service + /* + + diff --git a/apps/ofagent/src/test/java/org/onosproject/ofagent/rest/OFAgentWebResourceTest.java b/apps/ofagent/src/test/java/org/onosproject/ofagent/rest/OFAgentWebResourceTest.java new file mode 100644 index 0000000000..026a9bc2cc --- /dev/null +++ b/apps/ofagent/src/test/java/org/onosproject/ofagent/rest/OFAgentWebResourceTest.java @@ -0,0 +1,525 @@ +/* + * Copyright 2017-present Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.onosproject.ofagent.rest; + +import com.eclipsesource.json.Json; +import com.eclipsesource.json.JsonObject; +import com.google.common.collect.Sets; +import org.glassfish.jersey.server.ResourceConfig; +import org.glassfish.jersey.test.JerseyTest; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.onlab.osgi.ServiceDirectory; +import org.onlab.osgi.TestServiceDirectory; +import org.onlab.packet.IpAddress; +import org.onlab.packet.TpPort; +import org.onlab.rest.BaseResource; +import org.onosproject.incubator.net.virtual.NetworkId; +import org.onosproject.ofagent.api.OFAgent; +import org.onosproject.ofagent.api.OFAgentAdminService; +import org.onosproject.ofagent.api.OFAgentService; +import org.onosproject.ofagent.api.OFController; +import org.onosproject.ofagent.impl.DefaultOFAgent; +import org.onosproject.ofagent.impl.DefaultOFController; + +import javax.ws.rs.client.Entity; +import javax.ws.rs.client.WebTarget; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import java.io.IOException; +import java.io.InputStream; +import java.net.HttpURLConnection; +import java.util.Set; + +import static org.easymock.EasyMock.*; +import static org.hamcrest.Matchers.*; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertThat; +import static org.onosproject.ofagent.api.OFAgent.State.STOPPED; + + +/** + * Test class for OFAgent application REST resource. + */ +public class OFAgentWebResourceTest extends JerseyTest { + + + private static final Set CONTROLLER_SET_1 = Sets.newHashSet( + DefaultOFController.of( + IpAddress.valueOf("147.91.1.4"), + TpPort.tpPort(6633))); + + private static final Set CONTROLLER_SET_2 = Sets.newHashSet( + DefaultOFController.of( + IpAddress.valueOf("147.91.4.25"), + TpPort.tpPort(6633)), + DefaultOFController.of( + IpAddress.valueOf("147.91.4.27"), + TpPort.tpPort(6653))); + + private static final Set CONTROLLER_SET = Sets.newHashSet( + DefaultOFController.of( + IpAddress.valueOf("147.91.2.11"), + TpPort.tpPort(6633)), + DefaultOFController.of( + IpAddress.valueOf("147.91.2.9"), + TpPort.tpPort(6633)), + DefaultOFController.of( + IpAddress.valueOf("147.91.2.17"), + TpPort.tpPort(6653))); + + private static final NetworkId NETWORK_1 = NetworkId.networkId(1); + private static final NetworkId NETWORK_2 = NetworkId.networkId(2); + private static final NetworkId NETWORK = NetworkId.networkId(3); + + private static final OFAgent OF_AGENT = DefaultOFAgent.builder() + .networkId(NETWORK) + .controllers(CONTROLLER_SET) + .state(STOPPED) + .build(); + + private Set agents = Sets.newHashSet(DefaultOFAgent.builder() + .networkId(NETWORK_1) + .controllers(CONTROLLER_SET_1) + .state(STOPPED) + .build(), + DefaultOFAgent.builder() + .networkId(NETWORK_2) + .controllers(CONTROLLER_SET_2) + .state(STOPPED) + .build(), + OF_AGENT); + + private Set empty = Sets.newHashSet(); + + private final OFAgentAdminService mockOFAgentAdminService = createMock(OFAgentAdminService.class); + private final OFAgentService mockOFAgentService = createMock(OFAgentService.class); + + /** + * Constructs OFAgent Web application test instance. + */ + public OFAgentWebResourceTest() { + super(ResourceConfig.forApplicationClass(OFAgentWebApplication.class)); + } + + /** + * Sets up the global values for all the tests. + */ + @Before + public void setUpMocks() { + ServiceDirectory testDirectory = new TestServiceDirectory() + .add(OFAgentAdminService.class, mockOFAgentAdminService) + .add(OFAgentService.class, mockOFAgentService); + BaseResource.setServiceDirectory(testDirectory); + } + + /** + * Cleans up. + */ + @After + public void tearDownMocks() { + } + + /** + * Tests the result of the rest api GET when there are OFAgents. + * + * @throws IOException + */ + @Test + public void testNonEmptyOFAgentSet() throws IOException { + expect(mockOFAgentService.agents()).andReturn(agents).anyTimes(); + replay(mockOFAgentService); + + final WebTarget wt = target(); + assertNotNull("WebTarget is null", wt); + assertNotNull("WebTarget request is null", wt.request()); + final String response = wt.path("service/ofagents").request().get(String.class); + final JsonObject result = Json.parse(response).asObject(); + assertThat(result, notNullValue()); + assertThat(result.names(), hasSize(1)); + assertThat(result.names().get(0), is("ofAgents")); + + mockOFAgentService.agents().forEach(ofAgent -> { + + String expectedJsonStringNetworkId = "\"networkId\":\"" + ofAgent.networkId().id() + "\""; + assertThat(response, containsString(expectedJsonStringNetworkId)); + + String expectedJsonStringState = "\"state\":\"" + ofAgent.state() + "\""; + assertThat(response, containsString(expectedJsonStringState)); + + ofAgent.controllers().forEach(ofController -> { + String expectedJsonStringIP = "\"ip\":\"" + ofController.ip() + "\""; + assertThat(response, containsString(expectedJsonStringIP)); + + String expectedJsonStringPort = "\"port\":\"" + ofController.port() + "\""; + assertThat(response, containsString(expectedJsonStringPort)); + }); + }); + + verify(mockOFAgentService); + } + + /** + * Tests the result of the rest api GET when there are no OFAgents. + * + * @throws IOException + */ + @Test + public void testEmptyOFAgentSet() throws IOException { + expect(mockOFAgentService.agents()).andReturn(empty).anyTimes(); + replay(mockOFAgentService); + + final WebTarget wt = target(); + assertNotNull("WebTarget is null", wt); + assertNotNull("WebTarget request is null", wt.request()); + final String response = wt.path("service/ofagents").request().get(String.class); + final JsonObject result = Json.parse(response).asObject(); + assertThat(result, notNullValue()); + assertThat(result.names(), hasSize(1)); + assertThat(response, is("{\"ofAgents\":[]}")); + + verify(mockOFAgentService); + } + + /** + * Tests the result of the rest api GET for OFAgent. + * + * @throws IOException + */ + @Test + public void testOFAgent() throws IOException { + expect(mockOFAgentService.agent(eq(NETWORK))).andReturn(OF_AGENT).anyTimes(); + replay(mockOFAgentService); + + final WebTarget wt = target(); + assertNotNull("WebTarget is null", wt); + assertNotNull("WebTarget request is null", wt.request()); + final Response response = wt.path("service/ofagent/" + NETWORK).request().get(); + final JsonObject result = Json.parse(response.readEntity(String.class)).asObject(); + assertThat(result, notNullValue()); + assertThat(result.names(), hasSize(3)); + assertThat(result.get("networkId").asString(), is(NETWORK.id().toString())); + assertThat(result.get("state").asString(), is(STOPPED.toString())); + + verify(mockOFAgentService); + } + + + /** + * Tests the result of the rest api GET for non-existent OFAgent. + * + * @throws IOException + */ + @Test + public void testNonExistentOFAgent() throws IOException { + expect(mockOFAgentService.agent(anyObject())).andReturn(null).anyTimes(); + replay(mockOFAgentService); + + final WebTarget wt = target(); + assertNotNull("WebTarget is null", wt); + assertNotNull("WebTarget request is null", wt.request()); + final Response response = wt.path("service/ofagent/" + NETWORK_1).request().get(); + assertThat(response.getStatus(), is(HttpURLConnection.HTTP_NOT_FOUND)); + + verify(mockOFAgentService); + } + + + /** + * Tests creating an OFAgent with POST. + */ + @Test + public void testOFAgentCreate() { + mockOFAgentAdminService.createAgent(anyObject()); + expectLastCall().anyTimes(); + replay(mockOFAgentAdminService); + + + InputStream jsonStream = OFAgentWebResourceTest.class + .getResourceAsStream("post-ofagent-create.json"); + assertNotNull("post-ofagent-create.json is null", jsonStream); + WebTarget wt = target(); + + Response response = wt.path("service/ofagent-create") + .request(MediaType.APPLICATION_JSON_TYPE) + .post(Entity.json(jsonStream)); + assertThat(response.getStatus(), is(HttpURLConnection.HTTP_CREATED)); + + verify(mockOFAgentAdminService); + } + + /** + * Tests creating an OFAgent with bad POST request. + */ + @Test + public void testOFAgentCreateBadRequest() { + InputStream jsonStream = OFAgentWebResourceTest.class + .getResourceAsStream("post-bad-request.json"); + assertNotNull("post-bad-request.json is null", jsonStream); + WebTarget wt = target(); + + Response response = wt.path("service/ofagent-create") + .request(MediaType.APPLICATION_JSON_TYPE) + .post(Entity.json(jsonStream)); + assertThat(response.getStatus(), is(HttpURLConnection.HTTP_INTERNAL_ERROR)); + } + + /** + * Tests updating an OFAgent with PUT. + */ + @Test + public void testOFAgentUpdate() { + expect(mockOFAgentService.agent(eq(NETWORK))).andReturn(OF_AGENT).anyTimes(); + replay(mockOFAgentService); + + mockOFAgentAdminService.updateAgent(anyObject()); + expectLastCall().anyTimes(); + replay(mockOFAgentAdminService); + + InputStream jsonStream = OFAgentWebResourceTest.class + .getResourceAsStream("put-ofagent-update.json"); + assertNotNull("put-ofagent-update.json is null", jsonStream); + WebTarget wt = target(); + Response response = wt.path("service/ofagent-update") + .request(MediaType.APPLICATION_JSON_TYPE) + .put(Entity.json(jsonStream)); + assertThat(response.getStatus(), is(HttpURLConnection.HTTP_OK)); + assertThat(response.readEntity(String.class), containsString("OFAgent updated")); + + verify(mockOFAgentService); + verify(mockOFAgentAdminService); + + } + + /** + * Tests non-existent OFAgent updating with PUT. + */ + @Test + public void testNonExistentOFAgentUpdate() { + expect(mockOFAgentService.agent(anyObject())).andReturn(null).anyTimes(); + replay(mockOFAgentService); + + InputStream jsonStream = OFAgentWebResourceTest.class + .getResourceAsStream("put-non-existent-ofagent-update.json"); + assertNotNull("put-non-existent-ofagent-update.json is null", jsonStream); + WebTarget wt = target(); + Response response = wt.path("service/ofagent-update") + .request(MediaType.APPLICATION_JSON_TYPE) + .put(Entity.json(jsonStream)); + assertThat(response.getStatus(), is(HttpURLConnection.HTTP_NOT_FOUND)); + + verify(mockOFAgentService); + + } + + /** + * Tests OFAgent updating with bad PUT request. + */ + @Test + public void testOFAgentUpdateBadRequest() { + expect(mockOFAgentService.agent(anyObject())).andReturn(null).anyTimes(); + replay(mockOFAgentService); + + InputStream jsonStream = OFAgentWebResourceTest.class + .getResourceAsStream("put-bad-request.json"); + assertNotNull("put-bad-request.json is null", jsonStream); + WebTarget wt = target(); + Response response = wt.path("service/ofagent-update") + .request(MediaType.APPLICATION_JSON_TYPE) + .put(Entity.json(jsonStream)); + assertThat(response.getStatus(), is(HttpURLConnection.HTTP_INTERNAL_ERROR)); + + verify(mockOFAgentService); + } + + /** + * Tests starting an OFAgent with POST. + */ + @Test + public void testOFAgentStart() { + expect(mockOFAgentService.agent(eq(NETWORK))).andReturn(OF_AGENT).anyTimes(); + replay(mockOFAgentService); + + mockOFAgentAdminService.startAgent(anyObject()); + expectLastCall().anyTimes(); + replay(mockOFAgentAdminService); + + InputStream jsonStream = OFAgentWebResourceTest.class + .getResourceAsStream("post-ofagent-start.json"); + assertNotNull("post-ofagent-create.json is null", jsonStream); + WebTarget wt = target(); + + Response response = wt.path("service/ofagent-start") + .request(MediaType.APPLICATION_JSON_TYPE) + .post(Entity.json(jsonStream)); + assertThat(response.getStatus(), is(HttpURLConnection.HTTP_OK)); +// assertThat(response.readEntity(String.class), containsString("OFAgent started")); + assertThat(response.readEntity(String.class), is("OFAgent started")); + + verify(mockOFAgentService); + verify(mockOFAgentAdminService); + } + + /** + * Tests non-existent OFAgent starting with POST. + */ + @Test + public void testNonExistentOFAgentStart() { + expect(mockOFAgentService.agent(eq(NETWORK))).andReturn(null).anyTimes(); + replay(mockOFAgentService); + + InputStream jsonStream = OFAgentWebResourceTest.class + .getResourceAsStream("post-non-existent-ofagent-start.json"); + assertNotNull("post-non-existent-ofagent-start.json is null", jsonStream); + WebTarget wt = target(); + + Response response = wt.path("service/ofagent-start") + .request(MediaType.APPLICATION_JSON_TYPE) + .post(Entity.json(jsonStream)); + assertThat(response.getStatus(), is(HttpURLConnection.HTTP_NOT_FOUND)); + + verify(mockOFAgentService); + } + + /** + * Tests OFAgent starting with bad POST request. + */ + @Test + public void testOFAgentStartBadRequest() { + + InputStream jsonStream = OFAgentWebResourceTest.class + .getResourceAsStream("post-bad-request.json"); + assertNotNull("post-bad-request.json is null", jsonStream); + WebTarget wt = target(); + + Response response = wt.path("service/ofagent-start") + .request(MediaType.APPLICATION_JSON_TYPE) + .post(Entity.json(jsonStream)); + assertThat(response.getStatus(), is(HttpURLConnection.HTTP_BAD_REQUEST)); + + } + + /** + * Tests stopping an OFAgent with POST. + */ + @Test + public void testOFAgentStop() { + expect(mockOFAgentService.agent(eq(NETWORK))).andReturn(OF_AGENT).anyTimes(); + replay(mockOFAgentService); + + mockOFAgentAdminService.stopAgent(anyObject()); + expectLastCall().anyTimes(); + replay(mockOFAgentAdminService); + + InputStream jsonStream = OFAgentWebResourceTest.class + .getResourceAsStream("post-ofagent-stop.json"); + assertNotNull("post-ofagent-stop.json is null", jsonStream); + WebTarget wt = target(); + Response response = wt.path("service/ofagent-stop") + .request(MediaType.APPLICATION_JSON_TYPE) + .post(Entity.json(jsonStream)); + assertThat(response.getStatus(), is(HttpURLConnection.HTTP_NO_CONTENT)); + + verify(mockOFAgentService); + verify(mockOFAgentAdminService); + } + + /** + * Tests stopping non-existent OFAgent with POST. + */ + @Test + public void testNonExistentOFAgentStop() { + expect(mockOFAgentService.agent(NETWORK)).andReturn(null).anyTimes(); + replay(mockOFAgentService); + + InputStream jsonStream = OFAgentWebResourceTest.class + .getResourceAsStream("post-non-existent-ofagent-stop.json"); + assertNotNull("post-non-existent-ofagent-stop.json is null", jsonStream); + WebTarget wt = target(); + + Response response = wt.path("service/ofagent-stop") + .request(MediaType.APPLICATION_JSON_TYPE) + .post(Entity.json(jsonStream)); + assertThat(response.getStatus(), is(HttpURLConnection.HTTP_NOT_FOUND)); + + verify(mockOFAgentService); + } + + /** + * Tests stopping FAgent with bad POST request. + */ + @Test + public void testOFAgentStopBadRequest() { + InputStream jsonStream = OFAgentWebResourceTest.class + .getResourceAsStream("post-bad-request.json"); + assertNotNull("post-bad-request.json is null", jsonStream); + WebTarget wt = target(); + + Response response = wt.path("service/ofagent-stop") + .request(MediaType.APPLICATION_JSON_TYPE) + .post(Entity.json(jsonStream)); + assertThat(response.getStatus(), is(HttpURLConnection.HTTP_INTERNAL_ERROR)); + } + + + /** + * Tests deleting an OFAgent with DELETE. + */ + @Test + public void testOFAgentRemove() { + expect(mockOFAgentService.agent(eq(NETWORK))).andReturn(OF_AGENT).anyTimes(); + replay(mockOFAgentService); + + expect(mockOFAgentAdminService.removeAgent(NETWORK)).andReturn(OF_AGENT).anyTimes(); + replay(mockOFAgentAdminService); + + WebTarget wt = target(); + Response response = wt.path("service/ofagent-remove/" + NETWORK.toString()) + .request(MediaType.APPLICATION_JSON_TYPE) + .delete(); + assertThat(response.getStatus(), is(HttpURLConnection.HTTP_OK)); + final JsonObject result = Json.parse(response.readEntity(String.class)).asObject(); + assertThat(result.get("networkId").asString(), is(NETWORK.id().toString())); + assertThat(result.get("state").asString(), is(STOPPED.toString())); + + verify(mockOFAgentService); + verify(mockOFAgentAdminService); + } + + /** + * Tests deleting a non-existent OFAgent with DELETE. + */ + @Test + public void testNonExistentOFAgentRemove() { + expect(mockOFAgentService.agent(eq(NETWORK))).andReturn(null).anyTimes(); + replay(mockOFAgentService); + + expect(mockOFAgentAdminService.removeAgent(NETWORK)).andReturn(null).anyTimes(); + replay(mockOFAgentAdminService); + + WebTarget wt = target(); + Response response = wt.path("service/ofagent-remove/" + NETWORK.toString()) + .request(MediaType.APPLICATION_JSON_TYPE) + .delete(); + assertThat(response.getStatus(), is(HttpURLConnection.HTTP_BAD_REQUEST)); + assertThat(response.readEntity(String.class), containsString("OFAgent not found")); + + verify(mockOFAgentService); + verify(mockOFAgentAdminService); + } +} diff --git a/apps/ofagent/src/test/resources/org/onosproject/ofagent/rest/post-bad-request.json b/apps/ofagent/src/test/resources/org/onosproject/ofagent/rest/post-bad-request.json new file mode 100644 index 0000000000..7a73a41bfd --- /dev/null +++ b/apps/ofagent/src/test/resources/org/onosproject/ofagent/rest/post-bad-request.json @@ -0,0 +1,2 @@ +{ +} \ No newline at end of file diff --git a/apps/ofagent/src/test/resources/org/onosproject/ofagent/rest/post-non-existent-ofagent-start.json b/apps/ofagent/src/test/resources/org/onosproject/ofagent/rest/post-non-existent-ofagent-start.json new file mode 100644 index 0000000000..165e0e2365 --- /dev/null +++ b/apps/ofagent/src/test/resources/org/onosproject/ofagent/rest/post-non-existent-ofagent-start.json @@ -0,0 +1,3 @@ +{ + "networkId": "3" +} \ No newline at end of file diff --git a/apps/ofagent/src/test/resources/org/onosproject/ofagent/rest/post-non-existent-ofagent-stop.json b/apps/ofagent/src/test/resources/org/onosproject/ofagent/rest/post-non-existent-ofagent-stop.json new file mode 100644 index 0000000000..165e0e2365 --- /dev/null +++ b/apps/ofagent/src/test/resources/org/onosproject/ofagent/rest/post-non-existent-ofagent-stop.json @@ -0,0 +1,3 @@ +{ + "networkId": "3" +} \ No newline at end of file diff --git a/apps/ofagent/src/test/resources/org/onosproject/ofagent/rest/post-ofagent-create.json b/apps/ofagent/src/test/resources/org/onosproject/ofagent/rest/post-ofagent-create.json new file mode 100644 index 0000000000..7632bbf3dc --- /dev/null +++ b/apps/ofagent/src/test/resources/org/onosproject/ofagent/rest/post-ofagent-create.json @@ -0,0 +1,9 @@ +{ + "networkId": "3", + "controllers": [ + { + "ip": "147.91.1.27", + "port": "63" + } + ] +} \ No newline at end of file diff --git a/apps/ofagent/src/test/resources/org/onosproject/ofagent/rest/post-ofagent-start.json b/apps/ofagent/src/test/resources/org/onosproject/ofagent/rest/post-ofagent-start.json new file mode 100644 index 0000000000..165e0e2365 --- /dev/null +++ b/apps/ofagent/src/test/resources/org/onosproject/ofagent/rest/post-ofagent-start.json @@ -0,0 +1,3 @@ +{ + "networkId": "3" +} \ No newline at end of file diff --git a/apps/ofagent/src/test/resources/org/onosproject/ofagent/rest/post-ofagent-stop.json b/apps/ofagent/src/test/resources/org/onosproject/ofagent/rest/post-ofagent-stop.json new file mode 100644 index 0000000000..165e0e2365 --- /dev/null +++ b/apps/ofagent/src/test/resources/org/onosproject/ofagent/rest/post-ofagent-stop.json @@ -0,0 +1,3 @@ +{ + "networkId": "3" +} \ No newline at end of file diff --git a/apps/ofagent/src/test/resources/org/onosproject/ofagent/rest/put-bad-request.json b/apps/ofagent/src/test/resources/org/onosproject/ofagent/rest/put-bad-request.json new file mode 100644 index 0000000000..c3c3d924e2 --- /dev/null +++ b/apps/ofagent/src/test/resources/org/onosproject/ofagent/rest/put-bad-request.json @@ -0,0 +1,12 @@ +{ + "controllers": [ + { + "ip": "147.91.1.27", + "port": "6633" + }, + { + "ip": "147.91.1.25", + "port": "6633" + } + ] +} \ No newline at end of file diff --git a/apps/ofagent/src/test/resources/org/onosproject/ofagent/rest/put-non-existent-ofagent-update.json b/apps/ofagent/src/test/resources/org/onosproject/ofagent/rest/put-non-existent-ofagent-update.json new file mode 100644 index 0000000000..86d1b216bd --- /dev/null +++ b/apps/ofagent/src/test/resources/org/onosproject/ofagent/rest/put-non-existent-ofagent-update.json @@ -0,0 +1,13 @@ +{ + "networkId": "3", + "controllers": [ + { + "ip": "147.91.1.27", + "port": "6653" + }, + { + "ip": "147.91.1.4", + "port": "6633" + } + ] +} \ No newline at end of file diff --git a/apps/ofagent/src/test/resources/org/onosproject/ofagent/rest/put-ofagent-update.json b/apps/ofagent/src/test/resources/org/onosproject/ofagent/rest/put-ofagent-update.json new file mode 100644 index 0000000000..1a361506e8 --- /dev/null +++ b/apps/ofagent/src/test/resources/org/onosproject/ofagent/rest/put-ofagent-update.json @@ -0,0 +1,13 @@ +{ + "networkId": "3", + "controllers": [ + { + "ip": "147.91.1.27", + "port": "6633" + }, + { + "ip": "147.91.1.25", + "port": "6633" + } + ] +} \ No newline at end of file