| /* |
| * Copyright 2016-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.rest.resources; |
| |
| import java.io.InputStream; |
| import java.net.HttpURLConnection; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.Set; |
| import java.util.concurrent.TimeUnit; |
| |
| import javax.ws.rs.NotFoundException; |
| 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 org.hamcrest.Description; |
| import org.hamcrest.Matchers; |
| import org.hamcrest.TypeSafeMatcher; |
| 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.MacAddress; |
| import org.onlab.rest.BaseResource; |
| import org.onosproject.app.ApplicationService; |
| import org.onosproject.codec.CodecService; |
| import org.onosproject.codec.impl.CodecManager; |
| import org.onosproject.codec.impl.FlowRuleCodec; |
| import org.onosproject.core.CoreService; |
| import org.onosproject.core.DefaultGroupId; |
| import org.onosproject.core.GroupId; |
| import org.onosproject.net.DefaultDevice; |
| import org.onosproject.net.Device; |
| import org.onosproject.net.DeviceId; |
| import org.onosproject.net.NetTestTools; |
| import org.onosproject.net.device.DeviceService; |
| import org.onosproject.net.flow.DefaultTrafficSelector; |
| import org.onosproject.net.flow.DefaultTrafficTreatment; |
| import org.onosproject.net.flow.FlowEntry; |
| import org.onosproject.net.flow.FlowId; |
| import org.onosproject.net.flow.FlowRule; |
| import org.onosproject.net.flow.FlowRuleExtPayLoad; |
| import org.onosproject.net.flow.FlowRuleService; |
| import org.onosproject.net.flow.TrafficSelector; |
| import org.onosproject.net.flow.TrafficTreatment; |
| import org.onosproject.net.flow.criteria.Criterion; |
| import org.onosproject.net.flow.instructions.Instruction; |
| |
| import com.eclipsesource.json.Json; |
| import com.eclipsesource.json.JsonArray; |
| import com.eclipsesource.json.JsonObject; |
| import com.google.common.collect.ImmutableSet; |
| |
| import static java.util.concurrent.TimeUnit.SECONDS; |
| import static org.easymock.EasyMock.anyObject; |
| import static org.easymock.EasyMock.anyShort; |
| import static org.easymock.EasyMock.anyString; |
| import static org.easymock.EasyMock.createMock; |
| import static org.easymock.EasyMock.expect; |
| import static org.easymock.EasyMock.expectLastCall; |
| import static org.easymock.EasyMock.replay; |
| import static org.easymock.EasyMock.verify; |
| import static org.hamcrest.Matchers.containsString; |
| import static org.hamcrest.Matchers.hasSize; |
| import static org.hamcrest.Matchers.is; |
| import static org.hamcrest.Matchers.not; |
| import static org.hamcrest.Matchers.notNullValue; |
| import static org.junit.Assert.assertThat; |
| import static org.junit.Assert.fail; |
| import static org.onosproject.net.NetTestTools.APP_ID; |
| |
| /** |
| * Unit tests for Flows REST APIs. |
| */ |
| public class FlowsResourceTest extends ResourceTest { |
| final FlowRuleService mockFlowService = createMock(FlowRuleService.class); |
| CoreService mockCoreService = createMock(CoreService.class); |
| |
| final HashMap<DeviceId, Set<FlowEntry>> rules = new HashMap<>(); |
| |
| final DeviceService mockDeviceService = createMock(DeviceService.class); |
| |
| final DeviceId deviceId1 = DeviceId.deviceId("1"); |
| final DeviceId deviceId2 = DeviceId.deviceId("2"); |
| final DeviceId deviceId3 = DeviceId.deviceId("3"); |
| final Device device1 = new DefaultDevice(null, deviceId1, Device.Type.OTHER, |
| "", "", "", "", null); |
| final Device device2 = new DefaultDevice(null, deviceId2, Device.Type.OTHER, |
| "", "", "", "", null); |
| |
| final ApplicationService mockApplicationService = createMock(ApplicationService.class); |
| |
| final MockFlowEntry flow1 = new MockFlowEntry(deviceId1, 1); |
| final MockFlowEntry flow2 = new MockFlowEntry(deviceId1, 2); |
| |
| final MockFlowEntry flow3 = new MockFlowEntry(deviceId2, 3); |
| final MockFlowEntry flow4 = new MockFlowEntry(deviceId2, 4); |
| |
| final MockFlowEntry flow5 = new MockFlowEntry(deviceId2, 5); |
| final MockFlowEntry flow6 = new MockFlowEntry(deviceId2, 6); |
| |
| final Set<FlowEntry> flowEntries = ImmutableSet.of(flow1, flow2, flow3, flow4, flow5, flow6); |
| |
| /** |
| * Mock class for a flow entry. |
| */ |
| private static class MockFlowEntry implements FlowEntry { |
| final DeviceId deviceId; |
| final long baseValue; |
| TrafficTreatment treatment; |
| TrafficSelector selector; |
| |
| public MockFlowEntry(DeviceId deviceId, long id) { |
| this.deviceId = deviceId; |
| this.baseValue = id * 100; |
| } |
| |
| @Override |
| public FlowEntryState state() { |
| return FlowEntryState.ADDED; |
| } |
| |
| @Override |
| public long life() { |
| return life(SECONDS); |
| } |
| |
| @Override |
| public long life(TimeUnit timeUnit) { |
| return SECONDS.convert(baseValue + 11, timeUnit); |
| } |
| |
| @Override |
| public FlowLiveType liveType() { |
| return FlowLiveType.IMMEDIATE; |
| } |
| |
| @Override |
| public long packets() { |
| return baseValue + 22; |
| } |
| |
| @Override |
| public long bytes() { |
| return baseValue + 33; |
| } |
| |
| @Override |
| public long lastSeen() { |
| return baseValue + 44; |
| } |
| |
| @Override |
| public int errType() { |
| return 0; |
| } |
| |
| @Override |
| public int errCode() { |
| return 0; |
| } |
| |
| @Override |
| public FlowId id() { |
| final long id = baseValue + 55; |
| return FlowId.valueOf(id); |
| } |
| |
| @Override |
| public GroupId groupId() { |
| return new DefaultGroupId(3); |
| } |
| |
| @Override |
| public short appId() { |
| return 2; |
| } |
| |
| @Override |
| public int priority() { |
| return (int) (baseValue + 66); |
| } |
| |
| @Override |
| public DeviceId deviceId() { |
| return deviceId; |
| } |
| |
| @Override |
| public TrafficSelector selector() { |
| return selector; |
| } |
| |
| @Override |
| public TrafficTreatment treatment() { |
| return treatment; |
| } |
| |
| @Override |
| public int timeout() { |
| return (int) (baseValue + 77); |
| } |
| |
| @Override |
| public int hardTimeout() { |
| return 0; |
| } |
| |
| @Override |
| public FlowRemoveReason reason() { |
| return FlowRemoveReason.NO_REASON; |
| } |
| |
| @Override |
| public boolean isPermanent() { |
| return false; |
| } |
| |
| @Override |
| public int tableId() { |
| return 0; |
| } |
| |
| @Override |
| public boolean exactMatch(FlowRule rule) { |
| return false; |
| } |
| |
| @Override |
| public FlowRuleExtPayLoad payLoad() { |
| return null; |
| } |
| } |
| |
| |
| /** |
| * Populates some flows used as testing data. |
| */ |
| private void setupMockFlows() { |
| flow2.treatment = DefaultTrafficTreatment.builder() |
| .setEthDst(MacAddress.BROADCAST) |
| .build(); |
| flow2.selector = DefaultTrafficSelector.builder() |
| .matchEthType((short) 3) |
| .matchIPProtocol((byte) 9) |
| .build(); |
| flow4.treatment = DefaultTrafficTreatment.builder() |
| .build(); |
| final Set<FlowEntry> flows1 = new HashSet<>(); |
| flows1.add(flow1); |
| flows1.add(flow2); |
| |
| final Set<FlowEntry> flows2 = new HashSet<>(); |
| flows2.add(flow3); |
| flows2.add(flow4); |
| |
| rules.put(deviceId1, flows1); |
| rules.put(deviceId2, flows2); |
| |
| expect(mockFlowService.getFlowEntries(deviceId1)) |
| .andReturn(rules.get(deviceId1)).anyTimes(); |
| expect(mockFlowService.getFlowEntries(deviceId2)) |
| .andReturn(rules.get(deviceId2)).anyTimes(); |
| } |
| |
| /** |
| * Sets up the global values for all the tests. |
| */ |
| @Before |
| public void setUpTest() { |
| // Mock device service |
| expect(mockDeviceService.getDevice(deviceId1)) |
| .andReturn(device1); |
| expect(mockDeviceService.getDevice(deviceId2)) |
| .andReturn(device2); |
| expect(mockDeviceService.getDevices()) |
| .andReturn(ImmutableSet.of(device1, device2)); |
| |
| // Mock Core Service |
| expect(mockCoreService.getAppId(anyShort())) |
| .andReturn(NetTestTools.APP_ID).anyTimes(); |
| expect(mockCoreService.getAppId(anyString())) |
| .andReturn(NetTestTools.APP_ID).anyTimes(); |
| expect(mockCoreService.registerApplication(FlowRuleCodec.REST_APP_ID)) |
| .andReturn(APP_ID).anyTimes(); |
| replay(mockCoreService); |
| |
| // Register the services needed for the test |
| final CodecManager codecService = new CodecManager(); |
| codecService.activate(); |
| ServiceDirectory testDirectory = |
| new TestServiceDirectory() |
| .add(FlowRuleService.class, mockFlowService) |
| .add(DeviceService.class, mockDeviceService) |
| .add(CodecService.class, codecService) |
| .add(CoreService.class, mockCoreService) |
| .add(ApplicationService.class, mockApplicationService); |
| |
| BaseResource.setServiceDirectory(testDirectory); |
| } |
| |
| /** |
| * Cleans up and verifies the mocks. |
| */ |
| @After |
| public void tearDownTest() { |
| verify(mockFlowService); |
| verify(mockCoreService); |
| } |
| |
| /** |
| * Hamcrest matcher to check that a flow representation in JSON matches |
| * the actual flow entry. |
| */ |
| public static class FlowEntryJsonMatcher extends TypeSafeMatcher<JsonObject> { |
| private final FlowEntry flow; |
| private final String expectedAppId; |
| private String reason = ""; |
| |
| public FlowEntryJsonMatcher(FlowEntry flowValue, String expectedAppIdValue) { |
| flow = flowValue; |
| expectedAppId = expectedAppIdValue; |
| } |
| |
| @Override |
| public boolean matchesSafely(JsonObject jsonFlow) { |
| // check id |
| final String jsonId = jsonFlow.get("id").asString(); |
| final String flowId = Long.toString(flow.id().value()); |
| if (!jsonId.equals(flowId)) { |
| reason = "id " + flow.id().toString(); |
| return false; |
| } |
| |
| // check application id |
| final String jsonAppId = jsonFlow.get("appId").asString(); |
| if (!jsonAppId.equals(expectedAppId)) { |
| reason = "appId " + Short.toString(flow.appId()); |
| return false; |
| } |
| |
| // check device id |
| final String jsonDeviceId = jsonFlow.get("deviceId").asString(); |
| if (!jsonDeviceId.equals(flow.deviceId().toString())) { |
| reason = "deviceId " + flow.deviceId(); |
| return false; |
| } |
| |
| // check treatment and instructions array |
| if (flow.treatment() != null) { |
| final JsonObject jsonTreatment = jsonFlow.get("treatment").asObject(); |
| final JsonArray jsonInstructions = jsonTreatment.get("instructions").asArray(); |
| if (flow.treatment().immediate().size() != jsonInstructions.size()) { |
| reason = "instructions array size of " + |
| Integer.toString(flow.treatment().immediate().size()); |
| return false; |
| } |
| for (final Instruction instruction : flow.treatment().immediate()) { |
| boolean instructionFound = false; |
| for (int instructionIndex = 0; instructionIndex < jsonInstructions.size(); instructionIndex++) { |
| final String jsonType = |
| jsonInstructions.get(instructionIndex) |
| .asObject().get("type").asString(); |
| final String instructionType = instruction.type().name(); |
| if (jsonType.equals(instructionType)) { |
| instructionFound = true; |
| } |
| } |
| if (!instructionFound) { |
| reason = "instruction " + instruction.toString(); |
| return false; |
| } |
| } |
| } |
| |
| // check selector and criteria array |
| if (flow.selector() != null) { |
| final JsonObject jsonTreatment = jsonFlow.get("selector").asObject(); |
| final JsonArray jsonCriteria = jsonTreatment.get("criteria").asArray(); |
| if (flow.selector().criteria().size() != jsonCriteria.size()) { |
| reason = "criteria array size of " + |
| Integer.toString(flow.selector().criteria().size()); |
| return false; |
| } |
| for (final Criterion criterion : flow.selector().criteria()) { |
| boolean criterionFound = false; |
| |
| for (int criterionIndex = 0; criterionIndex < jsonCriteria.size(); criterionIndex++) { |
| final String jsonType = |
| jsonCriteria.get(criterionIndex) |
| .asObject().get("type").asString(); |
| final String criterionType = criterion.type().name(); |
| if (jsonType.equals(criterionType)) { |
| criterionFound = true; |
| } |
| } |
| if (!criterionFound) { |
| reason = "criterion " + criterion.toString(); |
| return false; |
| } |
| } |
| } |
| |
| return true; |
| } |
| |
| @Override |
| public void describeTo(Description description) { |
| description.appendText(reason); |
| } |
| } |
| |
| /** |
| * Factory to allocate a flow matcher. |
| * |
| * @param flow flow object we are looking for |
| * @return matcher |
| */ |
| private static FlowEntryJsonMatcher matchesFlow(FlowEntry flow, String expectedAppName) { |
| return new FlowEntryJsonMatcher(flow, expectedAppName); |
| } |
| |
| /** |
| * Hamcrest matcher to check that a flow is represented properly in a JSON |
| * array of flows. |
| */ |
| public static class FlowEntryJsonArrayMatcher extends TypeSafeMatcher<JsonArray> { |
| private final FlowEntry flow; |
| private String reason = ""; |
| |
| public FlowEntryJsonArrayMatcher(FlowEntry flowValue) { |
| flow = flowValue; |
| } |
| |
| @Override |
| public boolean matchesSafely(JsonArray json) { |
| boolean flowFound = false; |
| |
| for (int jsonFlowIndex = 0; jsonFlowIndex < json.size(); |
| jsonFlowIndex++) { |
| |
| final JsonObject jsonFlow = json.get(jsonFlowIndex).asObject(); |
| |
| final String flowId = Long.toString(flow.id().value()); |
| final String jsonFlowId = jsonFlow.get("id").asString(); |
| if (jsonFlowId.equals(flowId)) { |
| flowFound = true; |
| |
| // We found the correct flow, check attribute values |
| assertThat(jsonFlow, matchesFlow(flow, APP_ID.name())); |
| } |
| } |
| if (!flowFound) { |
| reason = "Flow with id " + flow.id().toString() + " not found"; |
| return false; |
| } else { |
| return true; |
| } |
| } |
| |
| @Override |
| public void describeTo(Description description) { |
| description.appendText(reason); |
| } |
| } |
| |
| /** |
| * Factory to allocate a flow array matcher. |
| * |
| * @param flow flow object we are looking for |
| * @return matcher |
| */ |
| private static FlowEntryJsonArrayMatcher hasFlow(FlowEntry flow) { |
| return new FlowEntryJsonArrayMatcher(flow); |
| } |
| |
| /** |
| * Hamcrest matcher to check that a flow representation in JSON matches |
| * the actual flow rule. |
| */ |
| public static class FlowRuleJsonMatcher extends TypeSafeMatcher<JsonObject> { |
| private final FlowRule flow; |
| private final String expectedAppId; |
| private String reason = ""; |
| |
| public FlowRuleJsonMatcher(FlowRule flowValue, String expectedAppIdValue) { |
| flow = flowValue; |
| expectedAppId = expectedAppIdValue; |
| } |
| |
| @Override |
| public boolean matchesSafely(JsonObject jsonFlow) { |
| // check id |
| final String jsonId = jsonFlow.get("id").asString(); |
| final String flowId = Long.toString(flow.id().value()); |
| if (!jsonId.equals(flowId)) { |
| reason = "id " + flow.id().toString(); |
| return false; |
| } |
| |
| // check application id |
| final String jsonAppId = jsonFlow.get("appId").asString(); |
| if (!jsonAppId.equals(expectedAppId)) { |
| reason = "appId " + Short.toString(flow.appId()); |
| return false; |
| } |
| |
| // check device id |
| final String jsonDeviceId = jsonFlow.get("deviceId").asString(); |
| if (!jsonDeviceId.equals(flow.deviceId().toString())) { |
| reason = "deviceId " + flow.deviceId(); |
| return false; |
| } |
| |
| // check treatment and instructions array |
| if (flow.treatment() != null) { |
| final JsonObject jsonTreatment = jsonFlow.get("treatment").asObject(); |
| final JsonArray jsonInstructions = jsonTreatment.get("instructions").asArray(); |
| if (flow.treatment().immediate().size() != jsonInstructions.size()) { |
| reason = "instructions array size of " + |
| Integer.toString(flow.treatment().immediate().size()); |
| return false; |
| } |
| for (final Instruction instruction : flow.treatment().immediate()) { |
| boolean instructionFound = false; |
| for (int instructionIndex = 0; instructionIndex < jsonInstructions.size(); instructionIndex++) { |
| final String jsonType = |
| jsonInstructions.get(instructionIndex) |
| .asObject().get("type").asString(); |
| final String instructionType = instruction.type().name(); |
| if (jsonType.equals(instructionType)) { |
| instructionFound = true; |
| } |
| } |
| if (!instructionFound) { |
| reason = "instruction " + instruction.toString(); |
| return false; |
| } |
| } |
| } |
| |
| // check selector and criteria array |
| if (flow.selector() != null) { |
| final JsonObject jsonTreatment = jsonFlow.get("selector").asObject(); |
| final JsonArray jsonCriteria = jsonTreatment.get("criteria").asArray(); |
| if (flow.selector().criteria().size() != jsonCriteria.size()) { |
| reason = "criteria array size of " + |
| Integer.toString(flow.selector().criteria().size()); |
| return false; |
| } |
| for (final Criterion criterion : flow.selector().criteria()) { |
| boolean criterionFound = false; |
| |
| for (int criterionIndex = 0; criterionIndex < jsonCriteria.size(); criterionIndex++) { |
| final String jsonType = |
| jsonCriteria.get(criterionIndex) |
| .asObject().get("type").asString(); |
| final String criterionType = criterion.type().name(); |
| if (jsonType.equals(criterionType)) { |
| criterionFound = true; |
| } |
| } |
| if (!criterionFound) { |
| reason = "criterion " + criterion.toString(); |
| return false; |
| } |
| } |
| } |
| |
| return true; |
| } |
| |
| @Override |
| public void describeTo(Description description) { |
| description.appendText(reason); |
| } |
| } |
| |
| /** |
| * Factory to allocate a flow matcher. |
| * |
| * @param flow flow rule object we are looking for |
| * @return matcher |
| */ |
| private static FlowRuleJsonMatcher matchesFlowRule(FlowRule flow, String expectedAppName) { |
| return new FlowRuleJsonMatcher(flow, expectedAppName); |
| } |
| |
| /** |
| * Hamcrest matcher to check that a flow is represented properly in a JSON |
| * array of flow rules. |
| */ |
| public static class FlowRuleJsonArrayMatcher extends TypeSafeMatcher<JsonArray> { |
| private final FlowRule flow; |
| private String reason = ""; |
| |
| public FlowRuleJsonArrayMatcher(FlowRule flowValue) { |
| flow = flowValue; |
| } |
| |
| @Override |
| public boolean matchesSafely(JsonArray json) { |
| boolean flowFound = false; |
| |
| for (int jsonFlowIndex = 0; jsonFlowIndex < json.size(); |
| jsonFlowIndex++) { |
| |
| final JsonObject jsonFlow = json.get(jsonFlowIndex).asObject(); |
| |
| final String flowId = Long.toString(flow.id().value()); |
| final String jsonFlowId = jsonFlow.get("id").asString(); |
| if (jsonFlowId.equals(flowId)) { |
| flowFound = true; |
| |
| // We found the correct flow, check attribute values |
| assertThat(jsonFlow, matchesFlowRule(flow, APP_ID.name())); |
| } |
| } |
| if (!flowFound) { |
| reason = "Flow with id " + flow.id().toString() + " not found"; |
| return false; |
| } else { |
| return true; |
| } |
| } |
| |
| @Override |
| public void describeTo(Description description) { |
| description.appendText(reason); |
| } |
| } |
| |
| /** |
| * Factory to allocate a flow array matcher. |
| * |
| * @param flow flow rule object we are looking for |
| * @return matcher |
| */ |
| private static FlowRuleJsonArrayMatcher hasFlowRule(FlowRule flow) { |
| return new FlowRuleJsonArrayMatcher(flow); |
| } |
| |
| /** |
| * Tests the result of the rest api GET when there are no flows. |
| */ |
| @Test |
| public void testFlowsEmptyArray() { |
| expect(mockFlowService.getFlowEntries(deviceId1)) |
| .andReturn(null).anyTimes(); |
| expect(mockFlowService.getFlowEntries(deviceId2)) |
| .andReturn(null).anyTimes(); |
| replay(mockFlowService); |
| replay(mockDeviceService); |
| final WebTarget wt = target(); |
| final String response = wt.path("flows").request().get(String.class); |
| assertThat(response, is("{\"flows\":[]}")); |
| } |
| |
| /** |
| * Tests the result of the rest api GET when there are active flows. |
| */ |
| @Test |
| public void testFlowsPopulatedArray() { |
| setupMockFlows(); |
| replay(mockFlowService); |
| replay(mockDeviceService); |
| final WebTarget wt = target(); |
| final String response = wt.path("flows").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("flows")); |
| final JsonArray jsonFlows = result.get("flows").asArray(); |
| assertThat(jsonFlows, notNullValue()); |
| assertThat(jsonFlows, hasFlow(flow1)); |
| assertThat(jsonFlows, hasFlow(flow2)); |
| assertThat(jsonFlows, hasFlow(flow3)); |
| assertThat(jsonFlows, hasFlow(flow4)); |
| } |
| |
| /** |
| * Tests the result of a rest api GET for a device. |
| */ |
| @Test |
| public void testFlowsSingleDevice() { |
| setupMockFlows(); |
| final Set<FlowEntry> flows = new HashSet<>(); |
| flows.add(flow5); |
| flows.add(flow6); |
| expect(mockFlowService.getFlowEntries(anyObject())) |
| .andReturn(flows).anyTimes(); |
| replay(mockFlowService); |
| replay(mockDeviceService); |
| final WebTarget wt = target(); |
| final String response = wt.path("flows/" + deviceId3).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("flows")); |
| final JsonArray jsonFlows = result.get("flows").asArray(); |
| assertThat(jsonFlows, notNullValue()); |
| assertThat(jsonFlows, hasFlow(flow5)); |
| assertThat(jsonFlows, hasFlow(flow6)); |
| } |
| |
| /** |
| * Tests the result of a rest api GET for a device. |
| */ |
| @Test |
| public void testFlowsSingleDeviceWithFlowId() { |
| setupMockFlows(); |
| final Set<FlowEntry> flows = new HashSet<>(); |
| flows.add(flow5); |
| flows.add(flow6); |
| expect(mockFlowService.getFlowEntries(anyObject())) |
| .andReturn(flows).anyTimes(); |
| replay(mockFlowService); |
| replay(mockDeviceService); |
| final WebTarget wt = target(); |
| final String response = wt.path("flows/" + deviceId3 + "/" |
| + Long.toString(flow5.id().value())).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("flows")); |
| final JsonArray jsonFlows = result.get("flows").asArray(); |
| assertThat(jsonFlows, notNullValue()); |
| assertThat(jsonFlows, hasFlow(flow5)); |
| assertThat(jsonFlows, not(hasFlow(flow6))); |
| } |
| |
| /** |
| * Tests that a fetch of a non-existent device object throws an exception. |
| */ |
| @Test |
| public void testBadGet() { |
| expect(mockFlowService.getFlowEntries(anyObject())) |
| .andReturn(null).anyTimes(); |
| replay(mockFlowService); |
| replay(mockDeviceService); |
| |
| WebTarget wt = target(); |
| try { |
| wt.path("flows/0").request().get(String.class); |
| fail("Fetch of non-existent device did not throw an exception"); |
| } catch (NotFoundException ex) { |
| assertThat(ex.getMessage(), |
| containsString("HTTP 404 Not Found")); |
| } |
| } |
| |
| /** |
| * Tests creating a flow with POST. |
| */ |
| @Test |
| public void testPostWithoutAppId() { |
| mockFlowService.applyFlowRules(anyObject()); |
| expectLastCall(); |
| replay(mockFlowService); |
| |
| WebTarget wt = target(); |
| InputStream jsonStream = FlowsResourceTest.class |
| .getResourceAsStream("post-flow.json"); |
| |
| Response response = wt.path("flows/of:0000000000000001") |
| .request(MediaType.APPLICATION_JSON_TYPE) |
| .post(Entity.json(jsonStream)); |
| assertThat(response.getStatus(), is(HttpURLConnection.HTTP_CREATED)); |
| String location = response.getLocation().getPath(); |
| assertThat(location, Matchers.startsWith("/flows/of:0000000000000001/")); |
| } |
| |
| /** |
| * Tests creating a flow with POST while specifying application identifier. |
| */ |
| @Test |
| public void testPostWithAppId() { |
| mockFlowService.applyFlowRules(anyObject()); |
| expectLastCall(); |
| replay(mockFlowService); |
| |
| WebTarget wt = target(); |
| InputStream jsonStream = FlowsResourceTest.class |
| .getResourceAsStream("post-flow.json"); |
| |
| Response response = wt.path("flows/of:0000000000000001") |
| .queryParam("appId", "org.onosproject.rest") |
| .request(MediaType.APPLICATION_JSON_TYPE) |
| .post(Entity.json(jsonStream)); |
| assertThat(response.getStatus(), is(HttpURLConnection.HTTP_CREATED)); |
| String location = response.getLocation().getPath(); |
| assertThat(location, Matchers.startsWith("/flows/of:0000000000000001/")); |
| } |
| |
| /** |
| * Tests deleting a flow. |
| */ |
| @Test |
| public void testDelete() { |
| setupMockFlows(); |
| mockFlowService.removeFlowRules(anyObject()); |
| expectLastCall(); |
| replay(mockFlowService); |
| |
| WebTarget wt = target(); |
| |
| String location = "/flows/1/155"; |
| |
| Response deleteResponse = wt.path(location) |
| .request(MediaType.APPLICATION_JSON_TYPE) |
| .delete(); |
| assertThat(deleteResponse.getStatus(), |
| is(HttpURLConnection.HTTP_NO_CONTENT)); |
| } |
| |
| /** |
| * Tests the result of a rest api GET for an application. |
| */ |
| @Test |
| public void testGetFlowByAppId() { |
| setupMockFlows(); |
| |
| expect(mockApplicationService.getId(anyObject())).andReturn(APP_ID).anyTimes(); |
| replay(mockApplicationService); |
| |
| expect(mockFlowService.getFlowEntriesById(APP_ID)).andReturn(flowEntries).anyTimes(); |
| replay(mockFlowService); |
| |
| final WebTarget wt = target(); |
| final String response = wt.path("/flows/application/1").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("flows")); |
| final JsonArray jsonFlows = result.get("flows").asArray(); |
| assertThat(jsonFlows, notNullValue()); |
| assertThat(jsonFlows, hasFlowRule(flow1)); |
| assertThat(jsonFlows, hasFlowRule(flow2)); |
| assertThat(jsonFlows, hasFlowRule(flow3)); |
| assertThat(jsonFlows, hasFlowRule(flow4)); |
| } |
| |
| /** |
| * Tests the result of a rest api DELETE for an application. |
| */ |
| @Test |
| public void testRemoveFlowByAppId() { |
| expect(mockApplicationService.getId(anyObject())).andReturn(APP_ID).anyTimes(); |
| replay(mockApplicationService); |
| |
| mockFlowService.removeFlowRulesById(APP_ID); |
| expectLastCall(); |
| replay(mockFlowService); |
| |
| WebTarget wt = target(); |
| |
| String location = "/flows/application/1"; |
| |
| Response deleteResponse = wt.path(location) |
| .request() |
| .delete(); |
| assertThat(deleteResponse.getStatus(), |
| is(HttpURLConnection.HTTP_NO_CONTENT)); |
| } |
| } |