blob: 9c7318ca137753817850188945a93763818f5d86 [file] [log] [blame]
Ray Milkey4f5de002014-12-17 19:26:11 -08001/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2016-present Open Networking Laboratory
Ray Milkey4f5de002014-12-17 19:26:11 -08003 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
Jian Li8ae91202016-03-24 14:36:16 -070016package org.onosproject.rest.resources;
Ray Milkey4f5de002014-12-17 19:26:11 -080017
Bharath Thiruveedula99849dc2016-11-17 22:04:38 +053018import java.io.InputStream;
19import java.net.HttpURLConnection;
20import java.util.HashMap;
21import java.util.HashSet;
22import java.util.Set;
23import java.util.concurrent.TimeUnit;
24
25import javax.ws.rs.NotFoundException;
26import javax.ws.rs.client.Entity;
27import javax.ws.rs.client.WebTarget;
28import javax.ws.rs.core.MediaType;
29import javax.ws.rs.core.Response;
30
Ray Milkey4f5de002014-12-17 19:26:11 -080031import org.hamcrest.Description;
Ray Milkeyeb5c7172015-06-23 14:59:27 -070032import org.hamcrest.Matchers;
Ray Milkey4f5de002014-12-17 19:26:11 -080033import org.hamcrest.TypeSafeMatcher;
34import org.junit.After;
35import org.junit.Before;
36import org.junit.Test;
37import org.onlab.osgi.ServiceDirectory;
38import org.onlab.osgi.TestServiceDirectory;
39import org.onlab.packet.MacAddress;
40import org.onlab.rest.BaseResource;
Jian Li2907ad22016-05-12 23:08:54 -070041import org.onosproject.app.ApplicationService;
Ray Milkey4f5de002014-12-17 19:26:11 -080042import org.onosproject.codec.CodecService;
43import org.onosproject.codec.impl.CodecManager;
Jonathan Hart9b80da82016-11-10 21:46:15 +000044import org.onosproject.codec.impl.FlowRuleCodec;
Ray Milkeyd43fe452015-05-29 09:35:12 -070045import org.onosproject.core.CoreService;
Ray Milkey4f5de002014-12-17 19:26:11 -080046import org.onosproject.core.DefaultGroupId;
47import org.onosproject.core.GroupId;
48import org.onosproject.net.DefaultDevice;
49import org.onosproject.net.Device;
50import org.onosproject.net.DeviceId;
Ray Milkeyd43fe452015-05-29 09:35:12 -070051import org.onosproject.net.NetTestTools;
Ray Milkey4f5de002014-12-17 19:26:11 -080052import org.onosproject.net.device.DeviceService;
53import org.onosproject.net.flow.DefaultTrafficSelector;
54import org.onosproject.net.flow.DefaultTrafficTreatment;
55import org.onosproject.net.flow.FlowEntry;
56import org.onosproject.net.flow.FlowId;
Jonathan Hartf44e42c2015-08-04 09:58:46 -070057import org.onosproject.net.flow.FlowRule;
jcc3d4e14a2015-04-21 11:32:05 +080058import org.onosproject.net.flow.FlowRuleExtPayLoad;
Ray Milkey4f5de002014-12-17 19:26:11 -080059import org.onosproject.net.flow.FlowRuleService;
60import org.onosproject.net.flow.TrafficSelector;
61import org.onosproject.net.flow.TrafficTreatment;
62import org.onosproject.net.flow.criteria.Criterion;
63import org.onosproject.net.flow.instructions.Instruction;
jcc3d4e14a2015-04-21 11:32:05 +080064
Bharath Thiruveedula99849dc2016-11-17 22:04:38 +053065import com.eclipsesource.json.Json;
66import com.eclipsesource.json.JsonArray;
67import com.eclipsesource.json.JsonObject;
68import com.google.common.collect.ImmutableSet;
Ray Milkey4f5de002014-12-17 19:26:11 -080069
Thiago Santos877914d2016-07-20 18:29:29 -030070import static java.util.concurrent.TimeUnit.SECONDS;
Ray Milkey4f5de002014-12-17 19:26:11 -080071import static org.easymock.EasyMock.anyObject;
Ray Milkeyd43fe452015-05-29 09:35:12 -070072import static org.easymock.EasyMock.anyShort;
Jian Li2907ad22016-05-12 23:08:54 -070073import static org.easymock.EasyMock.anyString;
Ray Milkey4f5de002014-12-17 19:26:11 -080074import static org.easymock.EasyMock.createMock;
75import static org.easymock.EasyMock.expect;
Ray Milkeyd43fe452015-05-29 09:35:12 -070076import static org.easymock.EasyMock.expectLastCall;
Ray Milkey4f5de002014-12-17 19:26:11 -080077import static org.easymock.EasyMock.replay;
78import static org.easymock.EasyMock.verify;
79import static org.hamcrest.Matchers.containsString;
80import static org.hamcrest.Matchers.hasSize;
81import static org.hamcrest.Matchers.is;
82import static org.hamcrest.Matchers.not;
83import static org.hamcrest.Matchers.notNullValue;
84import static org.junit.Assert.assertThat;
85import static org.junit.Assert.fail;
Ray Milkeyeb5c7172015-06-23 14:59:27 -070086import static org.onosproject.net.NetTestTools.APP_ID;
Ray Milkey4f5de002014-12-17 19:26:11 -080087
88/**
89 * Unit tests for Flows REST APIs.
90 */
Ray Milkey9c3d3362015-01-28 10:39:56 -080091public class FlowsResourceTest extends ResourceTest {
Ray Milkey4f5de002014-12-17 19:26:11 -080092 final FlowRuleService mockFlowService = createMock(FlowRuleService.class);
Ray Milkeyd43fe452015-05-29 09:35:12 -070093 CoreService mockCoreService = createMock(CoreService.class);
94
Ray Milkey4f5de002014-12-17 19:26:11 -080095 final HashMap<DeviceId, Set<FlowEntry>> rules = new HashMap<>();
96
97 final DeviceService mockDeviceService = createMock(DeviceService.class);
98
99 final DeviceId deviceId1 = DeviceId.deviceId("1");
100 final DeviceId deviceId2 = DeviceId.deviceId("2");
101 final DeviceId deviceId3 = DeviceId.deviceId("3");
102 final Device device1 = new DefaultDevice(null, deviceId1, Device.Type.OTHER,
103 "", "", "", "", null);
104 final Device device2 = new DefaultDevice(null, deviceId2, Device.Type.OTHER,
105 "", "", "", "", null);
106
Jian Li2907ad22016-05-12 23:08:54 -0700107 final ApplicationService mockApplicationService = createMock(ApplicationService.class);
108
Ray Milkey4f5de002014-12-17 19:26:11 -0800109 final MockFlowEntry flow1 = new MockFlowEntry(deviceId1, 1);
110 final MockFlowEntry flow2 = new MockFlowEntry(deviceId1, 2);
111
112 final MockFlowEntry flow3 = new MockFlowEntry(deviceId2, 3);
113 final MockFlowEntry flow4 = new MockFlowEntry(deviceId2, 4);
114
115 final MockFlowEntry flow5 = new MockFlowEntry(deviceId2, 5);
116 final MockFlowEntry flow6 = new MockFlowEntry(deviceId2, 6);
117
Bharath Thiruveedula99849dc2016-11-17 22:04:38 +0530118 final Set<FlowEntry> flowEntries = ImmutableSet.of(flow1, flow2, flow3, flow4, flow5, flow6);
Jian Li2907ad22016-05-12 23:08:54 -0700119
Ray Milkey4f5de002014-12-17 19:26:11 -0800120 /**
121 * Mock class for a flow entry.
122 */
123 private static class MockFlowEntry implements FlowEntry {
124 final DeviceId deviceId;
125 final long baseValue;
126 TrafficTreatment treatment;
127 TrafficSelector selector;
128
129 public MockFlowEntry(DeviceId deviceId, long id) {
130 this.deviceId = deviceId;
131 this.baseValue = id * 100;
132 }
133
134 @Override
135 public FlowEntryState state() {
136 return FlowEntryState.ADDED;
137 }
138
139 @Override
140 public long life() {
Thiago Santos877914d2016-07-20 18:29:29 -0300141 return life(SECONDS);
142 }
143
144 @Override
145 public long life(TimeUnit timeUnit) {
146 return SECONDS.convert(baseValue + 11, timeUnit);
Ray Milkey4f5de002014-12-17 19:26:11 -0800147 }
148
149 @Override
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900150 public FlowLiveType liveType() {
151 return FlowLiveType.IMMEDIATE;
152 }
153
154 @Override
Ray Milkey4f5de002014-12-17 19:26:11 -0800155 public long packets() {
156 return baseValue + 22;
157 }
158
159 @Override
160 public long bytes() {
161 return baseValue + 33;
162 }
163
164 @Override
165 public long lastSeen() {
166 return baseValue + 44;
167 }
168
169 @Override
170 public int errType() {
171 return 0;
172 }
173
174 @Override
175 public int errCode() {
176 return 0;
177 }
178
179 @Override
180 public FlowId id() {
181 final long id = baseValue + 55;
182 return FlowId.valueOf(id);
183 }
184
185 @Override
alshabib08d98982015-04-21 16:25:50 -0700186 public GroupId groupId() {
187 return new DefaultGroupId(3);
Ray Milkey4f5de002014-12-17 19:26:11 -0800188 }
189
190 @Override
alshabib08d98982015-04-21 16:25:50 -0700191 public short appId() {
192 return 2;
Ray Milkey4f5de002014-12-17 19:26:11 -0800193 }
194
195 @Override
196 public int priority() {
197 return (int) (baseValue + 66);
198 }
199
200 @Override
201 public DeviceId deviceId() {
202 return deviceId;
203 }
204
205 @Override
206 public TrafficSelector selector() {
207 return selector;
208 }
209
210 @Override
211 public TrafficTreatment treatment() {
212 return treatment;
213 }
214
215 @Override
216 public int timeout() {
217 return (int) (baseValue + 77);
218 }
219
220 @Override
Murat Parlakisikc6759e82016-06-29 03:22:22 -0700221 public int hardTimeout() {
222 return 0;
223 }
224
225 @Override
226 public FlowRemoveReason reason() {
227 return FlowRemoveReason.NO_REASON;
228 }
229
230 @Override
Ray Milkey4f5de002014-12-17 19:26:11 -0800231 public boolean isPermanent() {
232 return false;
233 }
sangho11c30ac2015-01-22 14:30:55 -0800234
Yuta HIGUCHI32a53c52015-02-08 01:25:40 -0800235 @Override
alshabibdb774072015-04-20 13:13:51 -0700236 public int tableId() {
237 return 0;
238 }
jcc3d4e14a2015-04-21 11:32:05 +0800239
240 @Override
Jonathan Hartf44e42c2015-08-04 09:58:46 -0700241 public boolean exactMatch(FlowRule rule) {
242 return false;
243 }
244
245 @Override
jcc3d4e14a2015-04-21 11:32:05 +0800246 public FlowRuleExtPayLoad payLoad() {
247 return null;
248 }
Ray Milkey4f5de002014-12-17 19:26:11 -0800249 }
250
Jian Li2907ad22016-05-12 23:08:54 -0700251
252 /**
Ray Milkey4f5de002014-12-17 19:26:11 -0800253 * Populates some flows used as testing data.
254 */
255 private void setupMockFlows() {
256 flow2.treatment = DefaultTrafficTreatment.builder()
Ray Milkey4f5de002014-12-17 19:26:11 -0800257 .setEthDst(MacAddress.BROADCAST)
258 .build();
259 flow2.selector = DefaultTrafficSelector.builder()
260 .matchEthType((short) 3)
261 .matchIPProtocol((byte) 9)
262 .build();
263 flow4.treatment = DefaultTrafficTreatment.builder()
Ray Milkey4f5de002014-12-17 19:26:11 -0800264 .build();
265 final Set<FlowEntry> flows1 = new HashSet<>();
266 flows1.add(flow1);
267 flows1.add(flow2);
268
269 final Set<FlowEntry> flows2 = new HashSet<>();
Ray Milkeyeb5c7172015-06-23 14:59:27 -0700270 flows2.add(flow3);
271 flows2.add(flow4);
Ray Milkey4f5de002014-12-17 19:26:11 -0800272
273 rules.put(deviceId1, flows1);
274 rules.put(deviceId2, flows2);
275
276 expect(mockFlowService.getFlowEntries(deviceId1))
277 .andReturn(rules.get(deviceId1)).anyTimes();
278 expect(mockFlowService.getFlowEntries(deviceId2))
279 .andReturn(rules.get(deviceId2)).anyTimes();
280 }
281
282 /**
283 * Sets up the global values for all the tests.
284 */
285 @Before
Ray Milkeyed0b1662015-02-05 09:34:29 -0800286 public void setUpTest() {
Ray Milkey4f5de002014-12-17 19:26:11 -0800287 // Mock device service
288 expect(mockDeviceService.getDevice(deviceId1))
289 .andReturn(device1);
290 expect(mockDeviceService.getDevice(deviceId2))
291 .andReturn(device2);
292 expect(mockDeviceService.getDevices())
293 .andReturn(ImmutableSet.of(device1, device2));
294
Ray Milkeyd43fe452015-05-29 09:35:12 -0700295 // Mock Core Service
296 expect(mockCoreService.getAppId(anyShort()))
297 .andReturn(NetTestTools.APP_ID).anyTimes();
Jian Li2907ad22016-05-12 23:08:54 -0700298 expect(mockCoreService.getAppId(anyString()))
299 .andReturn(NetTestTools.APP_ID).anyTimes();
Jonathan Hart9b80da82016-11-10 21:46:15 +0000300 expect(mockCoreService.registerApplication(FlowRuleCodec.REST_APP_ID))
Ray Milkeyeb5c7172015-06-23 14:59:27 -0700301 .andReturn(APP_ID).anyTimes();
Ray Milkeyd43fe452015-05-29 09:35:12 -0700302 replay(mockCoreService);
303
Ray Milkey4f5de002014-12-17 19:26:11 -0800304 // Register the services needed for the test
305 final CodecManager codecService = new CodecManager();
306 codecService.activate();
307 ServiceDirectory testDirectory =
308 new TestServiceDirectory()
309 .add(FlowRuleService.class, mockFlowService)
310 .add(DeviceService.class, mockDeviceService)
Ray Milkeyd43fe452015-05-29 09:35:12 -0700311 .add(CodecService.class, codecService)
Jian Li2907ad22016-05-12 23:08:54 -0700312 .add(CoreService.class, mockCoreService)
313 .add(ApplicationService.class, mockApplicationService);
Ray Milkey4f5de002014-12-17 19:26:11 -0800314
315 BaseResource.setServiceDirectory(testDirectory);
316 }
317
318 /**
319 * Cleans up and verifies the mocks.
Ray Milkey4f5de002014-12-17 19:26:11 -0800320 */
321 @After
Ray Milkeyed0b1662015-02-05 09:34:29 -0800322 public void tearDownTest() {
Ray Milkey4f5de002014-12-17 19:26:11 -0800323 verify(mockFlowService);
Ray Milkeyd43fe452015-05-29 09:35:12 -0700324 verify(mockCoreService);
Ray Milkey4f5de002014-12-17 19:26:11 -0800325 }
326
327 /**
328 * Hamcrest matcher to check that a flow representation in JSON matches
329 * the actual flow entry.
330 */
Jian Li2907ad22016-05-12 23:08:54 -0700331 public static class FlowEntryJsonMatcher extends TypeSafeMatcher<JsonObject> {
Ray Milkey4f5de002014-12-17 19:26:11 -0800332 private final FlowEntry flow;
Ray Milkeybe539db2015-09-04 11:00:43 -0700333 private final String expectedAppId;
Ray Milkey4f5de002014-12-17 19:26:11 -0800334 private String reason = "";
335
Jian Li2907ad22016-05-12 23:08:54 -0700336 public FlowEntryJsonMatcher(FlowEntry flowValue, String expectedAppIdValue) {
Ray Milkey4f5de002014-12-17 19:26:11 -0800337 flow = flowValue;
Ray Milkeybe539db2015-09-04 11:00:43 -0700338 expectedAppId = expectedAppIdValue;
Ray Milkey4f5de002014-12-17 19:26:11 -0800339 }
340
341 @Override
342 public boolean matchesSafely(JsonObject jsonFlow) {
343 // check id
344 final String jsonId = jsonFlow.get("id").asString();
345 final String flowId = Long.toString(flow.id().value());
346 if (!jsonId.equals(flowId)) {
347 reason = "id " + flow.id().toString();
348 return false;
349 }
350
351 // check application id
Ray Milkeybe539db2015-09-04 11:00:43 -0700352 final String jsonAppId = jsonFlow.get("appId").asString();
353 if (!jsonAppId.equals(expectedAppId)) {
Ray Milkey4f5de002014-12-17 19:26:11 -0800354 reason = "appId " + Short.toString(flow.appId());
355 return false;
356 }
357
358 // check device id
359 final String jsonDeviceId = jsonFlow.get("deviceId").asString();
360 if (!jsonDeviceId.equals(flow.deviceId().toString())) {
361 reason = "deviceId " + flow.deviceId();
362 return false;
363 }
364
365 // check treatment and instructions array
366 if (flow.treatment() != null) {
367 final JsonObject jsonTreatment = jsonFlow.get("treatment").asObject();
368 final JsonArray jsonInstructions = jsonTreatment.get("instructions").asArray();
Ray Milkey42507352015-03-20 15:16:10 -0700369 if (flow.treatment().immediate().size() != jsonInstructions.size()) {
Ray Milkey4f5de002014-12-17 19:26:11 -0800370 reason = "instructions array size of " +
Ray Milkey42507352015-03-20 15:16:10 -0700371 Integer.toString(flow.treatment().immediate().size());
Ray Milkey4f5de002014-12-17 19:26:11 -0800372 return false;
373 }
Ray Milkey42507352015-03-20 15:16:10 -0700374 for (final Instruction instruction : flow.treatment().immediate()) {
Ray Milkey4f5de002014-12-17 19:26:11 -0800375 boolean instructionFound = false;
Ray Milkey4f5de002014-12-17 19:26:11 -0800376 for (int instructionIndex = 0; instructionIndex < jsonInstructions.size(); instructionIndex++) {
Ray Milkeyc95bb9d2015-01-06 10:28:24 -0800377 final String jsonType =
378 jsonInstructions.get(instructionIndex)
379 .asObject().get("type").asString();
380 final String instructionType = instruction.type().name();
381 if (jsonType.equals(instructionType)) {
Ray Milkey4f5de002014-12-17 19:26:11 -0800382 instructionFound = true;
383 }
384 }
385 if (!instructionFound) {
Ray Milkeyc95bb9d2015-01-06 10:28:24 -0800386 reason = "instruction " + instruction.toString();
Ray Milkey4f5de002014-12-17 19:26:11 -0800387 return false;
388 }
389 }
390 }
391
392 // check selector and criteria array
393 if (flow.selector() != null) {
394 final JsonObject jsonTreatment = jsonFlow.get("selector").asObject();
395 final JsonArray jsonCriteria = jsonTreatment.get("criteria").asArray();
396 if (flow.selector().criteria().size() != jsonCriteria.size()) {
397 reason = "criteria array size of " +
398 Integer.toString(flow.selector().criteria().size());
399 return false;
400 }
401 for (final Criterion criterion : flow.selector().criteria()) {
402 boolean criterionFound = false;
Ray Milkeyc95bb9d2015-01-06 10:28:24 -0800403
Ray Milkey4f5de002014-12-17 19:26:11 -0800404 for (int criterionIndex = 0; criterionIndex < jsonCriteria.size(); criterionIndex++) {
Ray Milkeyc95bb9d2015-01-06 10:28:24 -0800405 final String jsonType =
406 jsonCriteria.get(criterionIndex)
407 .asObject().get("type").asString();
408 final String criterionType = criterion.type().name();
409 if (jsonType.equals(criterionType)) {
Ray Milkey4f5de002014-12-17 19:26:11 -0800410 criterionFound = true;
411 }
412 }
413 if (!criterionFound) {
Ray Milkeyc95bb9d2015-01-06 10:28:24 -0800414 reason = "criterion " + criterion.toString();
Ray Milkey4f5de002014-12-17 19:26:11 -0800415 return false;
416 }
417 }
418 }
419
420 return true;
421 }
422
423 @Override
424 public void describeTo(Description description) {
425 description.appendText(reason);
426 }
427 }
428
429 /**
430 * Factory to allocate a flow matcher.
431 *
432 * @param flow flow object we are looking for
433 * @return matcher
434 */
Jian Li2907ad22016-05-12 23:08:54 -0700435 private static FlowEntryJsonMatcher matchesFlow(FlowEntry flow, String expectedAppName) {
436 return new FlowEntryJsonMatcher(flow, expectedAppName);
Ray Milkey4f5de002014-12-17 19:26:11 -0800437 }
438
439 /**
440 * Hamcrest matcher to check that a flow is represented properly in a JSON
441 * array of flows.
442 */
Jian Li2907ad22016-05-12 23:08:54 -0700443 public static class FlowEntryJsonArrayMatcher extends TypeSafeMatcher<JsonArray> {
Ray Milkey4f5de002014-12-17 19:26:11 -0800444 private final FlowEntry flow;
445 private String reason = "";
446
Jian Li2907ad22016-05-12 23:08:54 -0700447 public FlowEntryJsonArrayMatcher(FlowEntry flowValue) {
Ray Milkey4f5de002014-12-17 19:26:11 -0800448 flow = flowValue;
449 }
450
451 @Override
452 public boolean matchesSafely(JsonArray json) {
453 boolean flowFound = false;
454
455 for (int jsonFlowIndex = 0; jsonFlowIndex < json.size();
456 jsonFlowIndex++) {
457
458 final JsonObject jsonFlow = json.get(jsonFlowIndex).asObject();
459
460 final String flowId = Long.toString(flow.id().value());
461 final String jsonFlowId = jsonFlow.get("id").asString();
462 if (jsonFlowId.equals(flowId)) {
463 flowFound = true;
464
465 // We found the correct flow, check attribute values
Ray Milkeybe539db2015-09-04 11:00:43 -0700466 assertThat(jsonFlow, matchesFlow(flow, APP_ID.name()));
Ray Milkey4f5de002014-12-17 19:26:11 -0800467 }
468 }
469 if (!flowFound) {
470 reason = "Flow with id " + flow.id().toString() + " not found";
471 return false;
472 } else {
473 return true;
474 }
475 }
476
477 @Override
478 public void describeTo(Description description) {
479 description.appendText(reason);
480 }
481 }
482
483 /**
484 * Factory to allocate a flow array matcher.
485 *
486 * @param flow flow object we are looking for
487 * @return matcher
488 */
Jian Li2907ad22016-05-12 23:08:54 -0700489 private static FlowEntryJsonArrayMatcher hasFlow(FlowEntry flow) {
490 return new FlowEntryJsonArrayMatcher(flow);
491 }
492
493 /**
494 * Hamcrest matcher to check that a flow representation in JSON matches
495 * the actual flow rule.
496 */
497 public static class FlowRuleJsonMatcher extends TypeSafeMatcher<JsonObject> {
498 private final FlowRule flow;
499 private final String expectedAppId;
500 private String reason = "";
501
502 public FlowRuleJsonMatcher(FlowRule flowValue, String expectedAppIdValue) {
503 flow = flowValue;
504 expectedAppId = expectedAppIdValue;
505 }
506
507 @Override
508 public boolean matchesSafely(JsonObject jsonFlow) {
509 // check id
510 final String jsonId = jsonFlow.get("id").asString();
511 final String flowId = Long.toString(flow.id().value());
512 if (!jsonId.equals(flowId)) {
513 reason = "id " + flow.id().toString();
514 return false;
515 }
516
517 // check application id
518 final String jsonAppId = jsonFlow.get("appId").asString();
519 if (!jsonAppId.equals(expectedAppId)) {
520 reason = "appId " + Short.toString(flow.appId());
521 return false;
522 }
523
524 // check device id
525 final String jsonDeviceId = jsonFlow.get("deviceId").asString();
526 if (!jsonDeviceId.equals(flow.deviceId().toString())) {
527 reason = "deviceId " + flow.deviceId();
528 return false;
529 }
530
531 // check treatment and instructions array
532 if (flow.treatment() != null) {
533 final JsonObject jsonTreatment = jsonFlow.get("treatment").asObject();
534 final JsonArray jsonInstructions = jsonTreatment.get("instructions").asArray();
535 if (flow.treatment().immediate().size() != jsonInstructions.size()) {
536 reason = "instructions array size of " +
537 Integer.toString(flow.treatment().immediate().size());
538 return false;
539 }
540 for (final Instruction instruction : flow.treatment().immediate()) {
541 boolean instructionFound = false;
542 for (int instructionIndex = 0; instructionIndex < jsonInstructions.size(); instructionIndex++) {
543 final String jsonType =
544 jsonInstructions.get(instructionIndex)
545 .asObject().get("type").asString();
546 final String instructionType = instruction.type().name();
547 if (jsonType.equals(instructionType)) {
548 instructionFound = true;
549 }
550 }
551 if (!instructionFound) {
552 reason = "instruction " + instruction.toString();
553 return false;
554 }
555 }
556 }
557
558 // check selector and criteria array
559 if (flow.selector() != null) {
560 final JsonObject jsonTreatment = jsonFlow.get("selector").asObject();
561 final JsonArray jsonCriteria = jsonTreatment.get("criteria").asArray();
562 if (flow.selector().criteria().size() != jsonCriteria.size()) {
563 reason = "criteria array size of " +
564 Integer.toString(flow.selector().criteria().size());
565 return false;
566 }
567 for (final Criterion criterion : flow.selector().criteria()) {
568 boolean criterionFound = false;
569
570 for (int criterionIndex = 0; criterionIndex < jsonCriteria.size(); criterionIndex++) {
571 final String jsonType =
572 jsonCriteria.get(criterionIndex)
573 .asObject().get("type").asString();
574 final String criterionType = criterion.type().name();
575 if (jsonType.equals(criterionType)) {
576 criterionFound = true;
577 }
578 }
579 if (!criterionFound) {
580 reason = "criterion " + criterion.toString();
581 return false;
582 }
583 }
584 }
585
586 return true;
587 }
588
589 @Override
590 public void describeTo(Description description) {
591 description.appendText(reason);
592 }
593 }
594
595 /**
596 * Factory to allocate a flow matcher.
597 *
598 * @param flow flow rule object we are looking for
599 * @return matcher
600 */
601 private static FlowRuleJsonMatcher matchesFlowRule(FlowRule flow, String expectedAppName) {
602 return new FlowRuleJsonMatcher(flow, expectedAppName);
603 }
604
605 /**
606 * Hamcrest matcher to check that a flow is represented properly in a JSON
607 * array of flow rules.
608 */
609 public static class FlowRuleJsonArrayMatcher extends TypeSafeMatcher<JsonArray> {
610 private final FlowRule flow;
611 private String reason = "";
612
613 public FlowRuleJsonArrayMatcher(FlowRule flowValue) {
614 flow = flowValue;
615 }
616
617 @Override
618 public boolean matchesSafely(JsonArray json) {
619 boolean flowFound = false;
620
621 for (int jsonFlowIndex = 0; jsonFlowIndex < json.size();
622 jsonFlowIndex++) {
623
624 final JsonObject jsonFlow = json.get(jsonFlowIndex).asObject();
625
626 final String flowId = Long.toString(flow.id().value());
627 final String jsonFlowId = jsonFlow.get("id").asString();
628 if (jsonFlowId.equals(flowId)) {
629 flowFound = true;
630
631 // We found the correct flow, check attribute values
632 assertThat(jsonFlow, matchesFlowRule(flow, APP_ID.name()));
633 }
634 }
635 if (!flowFound) {
636 reason = "Flow with id " + flow.id().toString() + " not found";
637 return false;
638 } else {
639 return true;
640 }
641 }
642
643 @Override
644 public void describeTo(Description description) {
645 description.appendText(reason);
646 }
647 }
648
649 /**
650 * Factory to allocate a flow array matcher.
651 *
652 * @param flow flow rule object we are looking for
653 * @return matcher
654 */
655 private static FlowRuleJsonArrayMatcher hasFlowRule(FlowRule flow) {
656 return new FlowRuleJsonArrayMatcher(flow);
Ray Milkey4f5de002014-12-17 19:26:11 -0800657 }
658
659 /**
660 * Tests the result of the rest api GET when there are no flows.
661 */
662 @Test
663 public void testFlowsEmptyArray() {
664 expect(mockFlowService.getFlowEntries(deviceId1))
665 .andReturn(null).anyTimes();
666 expect(mockFlowService.getFlowEntries(deviceId2))
667 .andReturn(null).anyTimes();
668 replay(mockFlowService);
669 replay(mockDeviceService);
Jian Li9d616492016-03-09 10:52:49 -0800670 final WebTarget wt = target();
671 final String response = wt.path("flows").request().get(String.class);
Ray Milkey4f5de002014-12-17 19:26:11 -0800672 assertThat(response, is("{\"flows\":[]}"));
673 }
674
675 /**
676 * Tests the result of the rest api GET when there are active flows.
677 */
678 @Test
679 public void testFlowsPopulatedArray() {
680 setupMockFlows();
681 replay(mockFlowService);
682 replay(mockDeviceService);
Jian Li9d616492016-03-09 10:52:49 -0800683 final WebTarget wt = target();
684 final String response = wt.path("flows").request().get(String.class);
Jian Li80cfe452016-01-14 16:04:58 -0800685 final JsonObject result = Json.parse(response).asObject();
Ray Milkey4f5de002014-12-17 19:26:11 -0800686 assertThat(result, notNullValue());
687
688 assertThat(result.names(), hasSize(1));
689 assertThat(result.names().get(0), is("flows"));
690 final JsonArray jsonFlows = result.get("flows").asArray();
691 assertThat(jsonFlows, notNullValue());
692 assertThat(jsonFlows, hasFlow(flow1));
693 assertThat(jsonFlows, hasFlow(flow2));
694 assertThat(jsonFlows, hasFlow(flow3));
695 assertThat(jsonFlows, hasFlow(flow4));
696 }
697
698 /**
699 * Tests the result of a rest api GET for a device.
700 */
701 @Test
702 public void testFlowsSingleDevice() {
703 setupMockFlows();
704 final Set<FlowEntry> flows = new HashSet<>();
705 flows.add(flow5);
706 flows.add(flow6);
707 expect(mockFlowService.getFlowEntries(anyObject()))
708 .andReturn(flows).anyTimes();
709 replay(mockFlowService);
710 replay(mockDeviceService);
Jian Li9d616492016-03-09 10:52:49 -0800711 final WebTarget wt = target();
712 final String response = wt.path("flows/" + deviceId3).request().get(String.class);
Jian Li80cfe452016-01-14 16:04:58 -0800713 final JsonObject result = Json.parse(response).asObject();
Ray Milkey4f5de002014-12-17 19:26:11 -0800714 assertThat(result, notNullValue());
715
716 assertThat(result.names(), hasSize(1));
717 assertThat(result.names().get(0), is("flows"));
718 final JsonArray jsonFlows = result.get("flows").asArray();
719 assertThat(jsonFlows, notNullValue());
720 assertThat(jsonFlows, hasFlow(flow5));
721 assertThat(jsonFlows, hasFlow(flow6));
722 }
723
724 /**
725 * Tests the result of a rest api GET for a device.
726 */
727 @Test
728 public void testFlowsSingleDeviceWithFlowId() {
729 setupMockFlows();
730 final Set<FlowEntry> flows = new HashSet<>();
731 flows.add(flow5);
732 flows.add(flow6);
733 expect(mockFlowService.getFlowEntries(anyObject()))
734 .andReturn(flows).anyTimes();
735 replay(mockFlowService);
736 replay(mockDeviceService);
Jian Li9d616492016-03-09 10:52:49 -0800737 final WebTarget wt = target();
738 final String response = wt.path("flows/" + deviceId3 + "/"
739 + Long.toString(flow5.id().value())).request().get(String.class);
Jian Li80cfe452016-01-14 16:04:58 -0800740 final JsonObject result = Json.parse(response).asObject();
Ray Milkey4f5de002014-12-17 19:26:11 -0800741 assertThat(result, notNullValue());
742
743 assertThat(result.names(), hasSize(1));
744 assertThat(result.names().get(0), is("flows"));
745 final JsonArray jsonFlows = result.get("flows").asArray();
746 assertThat(jsonFlows, notNullValue());
747 assertThat(jsonFlows, hasFlow(flow5));
748 assertThat(jsonFlows, not(hasFlow(flow6)));
749 }
750
751 /**
752 * Tests that a fetch of a non-existent device object throws an exception.
753 */
754 @Test
755 public void testBadGet() {
Jian Li9d616492016-03-09 10:52:49 -0800756 expect(mockFlowService.getFlowEntries(anyObject()))
Ray Milkey4f5de002014-12-17 19:26:11 -0800757 .andReturn(null).anyTimes();
758 replay(mockFlowService);
759 replay(mockDeviceService);
760
Jian Li9d616492016-03-09 10:52:49 -0800761 WebTarget wt = target();
Ray Milkey4f5de002014-12-17 19:26:11 -0800762 try {
Jian Li9d616492016-03-09 10:52:49 -0800763 wt.path("flows/0").request().get(String.class);
Ray Milkey4f5de002014-12-17 19:26:11 -0800764 fail("Fetch of non-existent device did not throw an exception");
Jian Li9d616492016-03-09 10:52:49 -0800765 } catch (NotFoundException ex) {
Ray Milkey4f5de002014-12-17 19:26:11 -0800766 assertThat(ex.getMessage(),
Jian Li9d616492016-03-09 10:52:49 -0800767 containsString("HTTP 404 Not Found"));
Ray Milkey4f5de002014-12-17 19:26:11 -0800768 }
769 }
Ray Milkeyd43fe452015-05-29 09:35:12 -0700770
771 /**
772 * Tests creating a flow with POST.
773 */
774 @Test
Jian Li2907ad22016-05-12 23:08:54 -0700775 public void testPostWithoutAppId() {
Jonathan Hart9b80da82016-11-10 21:46:15 +0000776 mockFlowService.applyFlowRules(anyObject());
777 expectLastCall();
Ray Milkeyd43fe452015-05-29 09:35:12 -0700778 replay(mockFlowService);
779
Jian Li9d616492016-03-09 10:52:49 -0800780 WebTarget wt = target();
Phaneendra Manda2be2f882015-11-11 15:23:40 +0530781 InputStream jsonStream = FlowsResourceTest.class
Ray Milkeyb82c42b2015-06-30 09:42:20 -0700782 .getResourceAsStream("post-flow.json");
Ray Milkeyd43fe452015-05-29 09:35:12 -0700783
Jian Li9d616492016-03-09 10:52:49 -0800784 Response response = wt.path("flows/of:0000000000000001")
785 .request(MediaType.APPLICATION_JSON_TYPE)
786 .post(Entity.json(jsonStream));
Jonathan Hart9b80da82016-11-10 21:46:15 +0000787 assertThat(response.getStatus(), is(HttpURLConnection.HTTP_CREATED));
788 String location = response.getLocation().getPath();
789 assertThat(location, Matchers.startsWith("/flows/of:0000000000000001/"));
Ray Milkeyeb5c7172015-06-23 14:59:27 -0700790 }
791
792 /**
Jian Li2907ad22016-05-12 23:08:54 -0700793 * Tests creating a flow with POST while specifying application identifier.
794 */
795 @Test
796 public void testPostWithAppId() {
797 mockFlowService.applyFlowRules(anyObject());
798 expectLastCall();
799 replay(mockFlowService);
800
801 WebTarget wt = target();
802 InputStream jsonStream = FlowsResourceTest.class
803 .getResourceAsStream("post-flow.json");
804
805 Response response = wt.path("flows/of:0000000000000001")
806 .queryParam("appId", "org.onosproject.rest")
807 .request(MediaType.APPLICATION_JSON_TYPE)
808 .post(Entity.json(jsonStream));
809 assertThat(response.getStatus(), is(HttpURLConnection.HTTP_CREATED));
810 String location = response.getLocation().getPath();
811 assertThat(location, Matchers.startsWith("/flows/of:0000000000000001/"));
812 }
813
814 /**
Ray Milkeyeb5c7172015-06-23 14:59:27 -0700815 * Tests deleting a flow.
816 */
817 @Test
818 public void testDelete() {
819 setupMockFlows();
820 mockFlowService.removeFlowRules(anyObject());
821 expectLastCall();
822 replay(mockFlowService);
823
Jian Li9d616492016-03-09 10:52:49 -0800824 WebTarget wt = target();
Ray Milkeyeb5c7172015-06-23 14:59:27 -0700825
826 String location = "/flows/1/155";
827
Jian Li9d616492016-03-09 10:52:49 -0800828 Response deleteResponse = wt.path(location)
829 .request(MediaType.APPLICATION_JSON_TYPE)
830 .delete();
Ray Milkeyeb5c7172015-06-23 14:59:27 -0700831 assertThat(deleteResponse.getStatus(),
832 is(HttpURLConnection.HTTP_NO_CONTENT));
Ray Milkeyd43fe452015-05-29 09:35:12 -0700833 }
Jian Li2907ad22016-05-12 23:08:54 -0700834
835 /**
836 * Tests the result of a rest api GET for an application.
837 */
838 @Test
839 public void testGetFlowByAppId() {
Bharath Thiruveedula99849dc2016-11-17 22:04:38 +0530840 setupMockFlows();
Jian Li2907ad22016-05-12 23:08:54 -0700841
842 expect(mockApplicationService.getId(anyObject())).andReturn(APP_ID).anyTimes();
843 replay(mockApplicationService);
844
Bharath Thiruveedula99849dc2016-11-17 22:04:38 +0530845 expect(mockFlowService.getFlowEntriesById(APP_ID)).andReturn(flowEntries).anyTimes();
Jian Li2907ad22016-05-12 23:08:54 -0700846 replay(mockFlowService);
847
848 final WebTarget wt = target();
Bharath Thiruveedula99849dc2016-11-17 22:04:38 +0530849 final String response = wt.path("/flows/application/1").request().get(String.class);
Jian Li2907ad22016-05-12 23:08:54 -0700850 final JsonObject result = Json.parse(response).asObject();
851 assertThat(result, notNullValue());
852
853 assertThat(result.names(), hasSize(1));
854 assertThat(result.names().get(0), is("flows"));
855 final JsonArray jsonFlows = result.get("flows").asArray();
856 assertThat(jsonFlows, notNullValue());
Bharath Thiruveedula99849dc2016-11-17 22:04:38 +0530857 assertThat(jsonFlows, hasFlowRule(flow1));
858 assertThat(jsonFlows, hasFlowRule(flow2));
859 assertThat(jsonFlows, hasFlowRule(flow3));
860 assertThat(jsonFlows, hasFlowRule(flow4));
Jian Li2907ad22016-05-12 23:08:54 -0700861 }
862
863 /**
864 * Tests the result of a rest api DELETE for an application.
865 */
866 @Test
867 public void testRemoveFlowByAppId() {
868 expect(mockApplicationService.getId(anyObject())).andReturn(APP_ID).anyTimes();
869 replay(mockApplicationService);
870
871 mockFlowService.removeFlowRulesById(APP_ID);
872 expectLastCall();
873 replay(mockFlowService);
874
875 WebTarget wt = target();
876
877 String location = "/flows/application/1";
878
879 Response deleteResponse = wt.path(location)
880 .request()
881 .delete();
882 assertThat(deleteResponse.getStatus(),
883 is(HttpURLConnection.HTTP_NO_CONTENT));
884 }
Ray Milkey4f5de002014-12-17 19:26:11 -0800885}