blob: e041962d839d1c08850b2fa87c180500e4736c75 [file] [log] [blame]
Ray Milkey2b217142014-12-15 09:24:24 -08001/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2016-present Open Networking Laboratory
Ray Milkey2b217142014-12-15 09:24:24 -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 Milkey2b217142014-12-15 09:24:24 -080017
Author Namee252a002016-09-26 22:42:24 +053018import com.eclipsesource.json.Json;
19import com.eclipsesource.json.JsonArray;
20import com.eclipsesource.json.JsonObject;
21import com.eclipsesource.json.JsonValue;
Ray Milkey2b217142014-12-15 09:24:24 -080022import org.hamcrest.Description;
Ray Milkeyb82c42b2015-06-30 09:42:20 -070023import org.hamcrest.Matchers;
Ray Milkey2b217142014-12-15 09:24:24 -080024import org.hamcrest.TypeSafeMatcher;
25import org.junit.After;
26import org.junit.Before;
27import org.junit.Test;
28import org.onlab.osgi.ServiceDirectory;
29import org.onlab.osgi.TestServiceDirectory;
Author Namee252a002016-09-26 22:42:24 +053030import org.onlab.packet.MacAddress;
Ray Milkey2b217142014-12-15 09:24:24 -080031import org.onlab.rest.BaseResource;
32import org.onosproject.codec.CodecService;
33import org.onosproject.codec.impl.CodecManager;
34import org.onosproject.core.ApplicationId;
Ayaka Koshibec06c89b2015-02-10 19:25:41 -080035import org.onosproject.core.CoreService;
Ray Milkey2b217142014-12-15 09:24:24 -080036import org.onosproject.core.DefaultApplicationId;
Author Namee252a002016-09-26 22:42:24 +053037import org.onosproject.core.GroupId;
Author Namee252a002016-09-26 22:42:24 +053038import org.onosproject.net.DeviceId;
Ray Milkey2b217142014-12-15 09:24:24 -080039import org.onosproject.net.NetworkResource;
Author Namee252a002016-09-26 22:42:24 +053040import org.onosproject.net.flow.DefaultTrafficSelector;
41import org.onosproject.net.flow.DefaultTrafficTreatment;
42import org.onosproject.net.flow.FlowEntry;
Ray Milkey634eb172017-04-05 14:48:50 -070043import org.onosproject.net.flow.FlowEntryAdapter;
Author Namee252a002016-09-26 22:42:24 +053044import org.onosproject.net.flow.FlowId;
45import org.onosproject.net.flow.FlowRule;
46import org.onosproject.net.flow.FlowRuleExtPayLoad;
47import org.onosproject.net.flow.FlowRuleService;
48import org.onosproject.net.flow.TrafficSelector;
49import org.onosproject.net.flow.TrafficTreatment;
50import org.onosproject.net.flow.criteria.Criterion;
51import org.onosproject.net.flow.instructions.Instruction;
Ray Milkey7b158512015-07-21 16:32:43 -070052import org.onosproject.net.intent.FakeIntentManager;
Author Namee252a002016-09-26 22:42:24 +053053import org.onosproject.net.intent.FlowRuleIntent;
Ray Milkey2b217142014-12-15 09:24:24 -080054import org.onosproject.net.intent.Intent;
Ray Milkey2b217142014-12-15 09:24:24 -080055import org.onosproject.net.intent.IntentService;
Ray Milkey1534f8d2015-05-13 15:42:50 -070056import org.onosproject.net.intent.IntentState;
Ray Milkeyf9af43c2015-02-09 16:45:48 -080057import org.onosproject.net.intent.Key;
Thomas Vachuska2048c1f2017-05-10 19:32:22 -070058import org.onosproject.net.intent.MockIdGenerator;
Ray Milkey2b217142014-12-15 09:24:24 -080059
Author Namee252a002016-09-26 22:42:24 +053060import javax.ws.rs.NotFoundException;
61import javax.ws.rs.client.Entity;
62import javax.ws.rs.client.WebTarget;
63import javax.ws.rs.core.MediaType;
64import javax.ws.rs.core.Response;
65import java.io.InputStream;
66import java.net.HttpURLConnection;
67import java.util.ArrayList;
68import java.util.Collections;
69import java.util.HashSet;
70import java.util.List;
71import java.util.concurrent.TimeUnit;
Ray Milkey2b217142014-12-15 09:24:24 -080072
Author Namee252a002016-09-26 22:42:24 +053073import static java.util.concurrent.TimeUnit.SECONDS;
74import static org.easymock.EasyMock.*;
75import static org.hamcrest.Matchers.*;
Ray Milkey2b217142014-12-15 09:24:24 -080076import static org.junit.Assert.assertThat;
77import static org.junit.Assert.fail;
Ray Milkey43a28222015-02-23 13:57:58 -080078import static org.onosproject.net.intent.IntentTestsMocks.MockIntent;
Ray Milkey2b217142014-12-15 09:24:24 -080079
80/**
81 * Unit tests for Intents REST APIs.
82 */
Ray Milkey9c3d3362015-01-28 10:39:56 -080083public class IntentsResourceTest extends ResourceTest {
Author Namee252a002016-09-26 22:42:24 +053084
85
86 private static final String APPID = "appId";
87 private static final String CRITERIA = "criteria";
88 private static final String DEVICE_ID = "deviceId";
89 private static final String ID = "id";
90 private static final String INSTRUCTIONS = "instructions";
91 private static final String PATHS = "paths";
92 private static final String SELECTOR = "selector";
93 private static final String SPACE = " ";
94 private static final String TREATMENT = "treatment";
95 private static final String TYPE = "type";
96
Ray Milkey2b217142014-12-15 09:24:24 -080097 final IntentService mockIntentService = createMock(IntentService.class);
Ayaka Koshibec06c89b2015-02-10 19:25:41 -080098 final CoreService mockCoreService = createMock(CoreService.class);
Author Namee252a002016-09-26 22:42:24 +053099 final FlowRuleService mockFlowService = createMock(FlowRuleService.class);
Ray Milkey2b217142014-12-15 09:24:24 -0800100 final HashSet<Intent> intents = new HashSet<>();
Author Namee252a002016-09-26 22:42:24 +0530101 final List<org.onosproject.net.intent.Intent> installableIntents = new ArrayList<>();
Thomas Vachuska02aeb032015-01-06 22:36:30 -0800102 private static final ApplicationId APP_ID = new DefaultApplicationId(1, "test");
Ray Milkey2b217142014-12-15 09:24:24 -0800103
Author Namee252a002016-09-26 22:42:24 +0530104 final DeviceId deviceId1 = DeviceId.deviceId("1");
105
106 final TrafficTreatment treatment1 = DefaultTrafficTreatment.builder()
107 .setEthDst(MacAddress.BROADCAST)
108 .build();
109 final TrafficTreatment treatment2 = DefaultTrafficTreatment.builder()
110 .setEthDst(MacAddress.IPV4_MULTICAST)
111 .build();
112
113 final TrafficSelector selector1 = DefaultTrafficSelector.builder()
114 .matchEthType((short) 3)
115 .matchIPProtocol((byte) 9)
116 .build();
117 final TrafficSelector selector2 = DefaultTrafficSelector.builder()
118 .matchEthType((short) 4)
119 .matchIPProtocol((byte) 10)
120 .build();
121
122 final MockFlowEntry flow1 = new MockFlowEntry(deviceId1, 1, treatment1, selector1);
123 final MockFlowEntry flow2 = new MockFlowEntry(deviceId1, 2, treatment2, selector2);
124
125 final MockFlowRule flowRule1 = new MockFlowRule(deviceId1, 1, treatment1, selector1);
126 final MockFlowRule flowRule2 = new MockFlowRule(deviceId1, 2, treatment2, selector2);
127
Ray Milkey2b217142014-12-15 09:24:24 -0800128 private class MockResource implements NetworkResource {
129 int id;
130
131 MockResource(int id) {
132 this.id = id;
133 }
134
Ayaka Koshibec06c89b2015-02-10 19:25:41 -0800135 @Override
Ray Milkey2b217142014-12-15 09:24:24 -0800136 public String toString() {
137 return "Resource " + Integer.toString(id);
138 }
139 }
140
Ray Milkey2b217142014-12-15 09:24:24 -0800141 /**
Author Namee252a002016-09-26 22:42:24 +0530142 * Mock class for a flow entry.
143 */
Ray Milkey634eb172017-04-05 14:48:50 -0700144 private static class MockFlowEntry extends FlowEntryAdapter {
Author Namee252a002016-09-26 22:42:24 +0530145 final DeviceId deviceId;
146 final long baseValue;
147 TrafficTreatment treatment;
148 TrafficSelector selector;
149
150 public MockFlowEntry(DeviceId deviceId, long id,
151 TrafficTreatment treatment,
152 TrafficSelector selector) {
153 this.deviceId = deviceId;
154 this.baseValue = id * 100;
155 this.treatment = treatment;
156 this.selector = selector;
157 }
158
159 @Override
Author Namee252a002016-09-26 22:42:24 +0530160 public long life() {
161 return life(SECONDS);
162 }
163
164 @Override
kalagesa42019542017-03-14 18:00:47 +0530165 public FlowLiveType liveType() {
166 return FlowLiveType.IMMEDIATE;
167 }
168
169 @Override
Author Namee252a002016-09-26 22:42:24 +0530170 public long life(TimeUnit timeUnit) {
171 return SECONDS.convert(baseValue + 11, timeUnit);
172 }
173
174 @Override
175 public long packets() {
176 return baseValue + 22;
177 }
178
179 @Override
180 public long bytes() {
181 return baseValue + 33;
182 }
183
184 @Override
185 public long lastSeen() {
186 return baseValue + 44;
187 }
188
189 @Override
Author Namee252a002016-09-26 22:42:24 +0530190 public FlowId id() {
191 final long id = baseValue + 55;
192 return FlowId.valueOf(id);
193 }
194
195 @Override
196 public GroupId groupId() {
Yi Tsengfa394de2017-02-01 11:26:40 -0800197 return new GroupId(3);
Author Namee252a002016-09-26 22:42:24 +0530198 }
199
200 @Override
201 public short appId() {
202 return 1;
203 }
204
205 @Override
206 public int priority() {
207 return (int) (baseValue + 66);
208 }
209
210 @Override
211 public DeviceId deviceId() {
212 return deviceId;
213 }
214
215 @Override
216 public TrafficSelector selector() {
217 return selector;
218 }
219
220 @Override
221 public TrafficTreatment treatment() {
222 return treatment;
223 }
224
225 @Override
226 public int timeout() {
227 return (int) (baseValue + 77);
228 }
229
Author Namee252a002016-09-26 22:42:24 +0530230
231 @Override
232 public boolean exactMatch(FlowRule rule) {
233 return this.appId() == rule.appId() &&
234 this.deviceId().equals(rule.deviceId()) &&
235 this.id().equals(rule.id()) &&
236 this.treatment.equals(rule.treatment()) &&
237 this.selector().equals(rule.selector());
238 }
239
240 @Override
Author Namee252a002016-09-26 22:42:24 +0530241 public String toString() {
242 return id().id().toString();
243 }
244 }
245
246 /**
247 * Mock class for a flow rule.
248 */
249 private static class MockFlowRule implements FlowRule {
250
251 final DeviceId deviceId;
252 final long baseValue;
253 TrafficTreatment treatment;
254 TrafficSelector selector;
255
256 public MockFlowRule(DeviceId deviceId,
257 long id,
258 TrafficTreatment treatment,
259 TrafficSelector selector) {
260 this.deviceId = deviceId;
261 this.baseValue = id * 100;
262 this.treatment = treatment;
263 this.selector = selector;
264 }
265
266 @Override
267 public FlowId id() {
268 long id = baseValue + 55;
269 return FlowId.valueOf(id);
270 }
271
272 @Override
273 public short appId() {
274 return 1;
275 }
276
277 @Override
278 public GroupId groupId() {
Yi Tsengfa394de2017-02-01 11:26:40 -0800279 return new GroupId(3);
Author Namee252a002016-09-26 22:42:24 +0530280 }
281
282 @Override
283 public int priority() {
284 return 0;
285 }
286
287 @Override
288 public DeviceId deviceId() {
289 return deviceId;
290 }
291
292 @Override
293 public TrafficSelector selector() {
294 return selector;
295 }
296
297 @Override
298 public TrafficTreatment treatment() {
299 return treatment;
300 }
301
302 @Override
303 public int timeout() {
304 return (int) (baseValue + 77);
305 }
306
307 @Override
308 public int hardTimeout() {
309 return 0;
310 }
311
312 @Override
313 public FlowRemoveReason reason() {
314 return FlowRemoveReason.NO_REASON;
315 }
316
317 @Override
318 public boolean isPermanent() {
319 return false;
320 }
321
322 @Override
323 public int tableId() {
324 return 0;
325 }
326
327 @Override
328 public boolean exactMatch(FlowRule rule) {
329 return false;
330 }
331
332 @Override
333 public FlowRuleExtPayLoad payLoad() {
334 return null;
335 }
336 }
337
338 /**
Ray Milkey2b217142014-12-15 09:24:24 -0800339 * Hamcrest matcher to check that an intent representation in JSON matches
340 * the actual intent.
341 */
342 public static class IntentJsonMatcher extends TypeSafeMatcher<JsonObject> {
343 private final Intent intent;
344 private String reason = "";
345
346 public IntentJsonMatcher(Intent intentValue) {
347 intent = intentValue;
348 }
349
350 @Override
351 public boolean matchesSafely(JsonObject jsonIntent) {
352 // check id
353 final String jsonId = jsonIntent.get("id").asString();
354 if (!jsonId.equals(intent.id().toString())) {
355 reason = "id " + intent.id().toString();
356 return false;
357 }
358
359 // check application id
Ray Milkeyf7cb4012015-07-20 13:01:07 -0700360
Ray Milkey2b217142014-12-15 09:24:24 -0800361 final String jsonAppId = jsonIntent.get("appId").asString();
Ray Milkeyf7cb4012015-07-20 13:01:07 -0700362 final String appId = intent.appId().name();
363 if (!jsonAppId.equals(appId)) {
364 reason = "appId was " + jsonAppId;
Ray Milkey2b217142014-12-15 09:24:24 -0800365 return false;
366 }
367
368 // check intent type
369 final String jsonType = jsonIntent.get("type").asString();
Jon Halla3fcf672017-03-28 16:53:22 -0700370 if (!"MockIntent".equals(jsonType)) {
Ray Milkey2b217142014-12-15 09:24:24 -0800371 reason = "type MockIntent";
372 return false;
373 }
374
Ray Milkey1534f8d2015-05-13 15:42:50 -0700375 // check state field
376 final String jsonState = jsonIntent.get("state").asString();
Jon Halla3fcf672017-03-28 16:53:22 -0700377 if (!"INSTALLED".equals(jsonState)) {
Ray Milkey1534f8d2015-05-13 15:42:50 -0700378 reason = "state INSTALLED";
379 return false;
380 }
381
Ray Milkey2b217142014-12-15 09:24:24 -0800382 // check resources array
383 final JsonArray jsonResources = jsonIntent.get("resources").asArray();
384 if (intent.resources() != null) {
385 if (intent.resources().size() != jsonResources.size()) {
386 reason = "resources array size of " + Integer.toString(intent.resources().size());
387 return false;
388 }
389 for (final NetworkResource resource : intent.resources()) {
390 boolean resourceFound = false;
391 final String resourceString = resource.toString();
392 for (int resourceIndex = 0; resourceIndex < jsonResources.size(); resourceIndex++) {
393 final JsonValue value = jsonResources.get(resourceIndex);
394 if (value.asString().equals(resourceString)) {
395 resourceFound = true;
396 }
397 }
398 if (!resourceFound) {
399 reason = "resource " + resourceString;
400 return false;
401 }
402 }
403 } else if (jsonResources.size() != 0) {
404 reason = "resources array empty";
405 return false;
406 }
407 return true;
408 }
409
410 @Override
411 public void describeTo(Description description) {
412 description.appendText(reason);
413 }
414 }
415
416 /**
417 * Factory to allocate an intent matcher.
418 *
419 * @param intent intent object we are looking for
420 * @return matcher
421 */
422 private static IntentJsonMatcher matchesIntent(Intent intent) {
423 return new IntentJsonMatcher(intent);
424 }
425
426 /**
Author Namee252a002016-09-26 22:42:24 +0530427 * Factory to allocate an IntentRelatedFlows matcher.
428 *
429 * @param pathEntries list of path conatining flow entries of a particular intent
430 * @param expectedAppId expected app id we are looking for
431 * @return matcher
432 */
433 private static IntentStatsJsonMatcher matchesRelatedFlowEntries(
434 List<List<FlowEntry>> pathEntries,
435 final String expectedAppId) {
436 return new IntentStatsJsonMatcher(pathEntries, expectedAppId);
437 }
438
439 /**
440 * Hamcrest matcher to check that an list of flowEntries in JSON matches
441 * the actual list of flow entries.
442 */
443 public static class IntentStatsJsonMatcher extends
444 TypeSafeMatcher<JsonObject> {
445
446 private final List<List<FlowEntry>> pathEntries;
447 private final String expectedAppId;
448 private String reason = "";
449
450 public IntentStatsJsonMatcher(
451 final List<List<FlowEntry>> pathEntries,
452 final String expectedAppId) {
453 this.pathEntries = pathEntries;
454 this.expectedAppId = expectedAppId;
455 }
456
457 @Override
458 public boolean matchesSafely(JsonObject jsonIntent) {
459 int jsonPathIndex = 0;
460 JsonArray jsonPaths = jsonIntent.get(PATHS).asArray();
461
462 if (pathEntries != null) {
463
rohitsharanfd747602017-01-23 21:57:28 +0530464 if (pathEntries.size() == 0) {
465 reason = "pathEntries array empty";
466 return false;
467 }
468
Author Namee252a002016-09-26 22:42:24 +0530469 if (pathEntries.size() != jsonPaths.size()) {
470 reason = "path entries array size of " +
471 Integer.toString(pathEntries.size());
472 return false;
473 }
474
475 for (List<FlowEntry> flowEntries : pathEntries) {
476 JsonArray jsonFlowEntries = jsonPaths.get(
477 jsonPathIndex++).asArray();
478
479 if (flowEntries.size() != jsonFlowEntries.size()) {
480 reason = "flow entries array size of " +
481 Integer.toString(pathEntries.size());
482
483 return false;
484 }
485
486 int jsonFlowEntryIndex = 0;
487 for (FlowEntry flow : flowEntries) {
488
489 JsonObject jsonFlow = jsonFlowEntries.get(
490 jsonFlowEntryIndex++).asObject();
491
492 String jsonId = jsonFlow.get(ID).asString();
493 String flowId = Long.toString(flow.id().value());
494 if (!jsonId.equals(flowId)) {
495 reason = ID + SPACE + flow.id();
496 return false;
497 }
498
499 // check application id
500 String jsonAppId = jsonFlow.get(APPID).asString();
501 if (!jsonAppId.equals(expectedAppId)) {
502 reason = APPID + SPACE + Short.toString(flow.appId());
503 return false;
504 }
505
506 // check device id
507 String jsonDeviceId =
508 jsonFlow.get(DEVICE_ID).asString();
509
510 if (!jsonDeviceId.equals(flow.deviceId().toString())) {
511 reason = DEVICE_ID + SPACE + flow.deviceId();
512 return false;
513 }
514
515 if (!checkFlowTreatment(flow, jsonFlow)) {
516 return false;
517 }
518
519 if (!checkFlowSelector(flow, jsonFlow)) {
520 return false;
521 }
522
523 }
524
525 }
rohitsharanfd747602017-01-23 21:57:28 +0530526 } else {
Author Namee252a002016-09-26 22:42:24 +0530527 reason = "pathEntries array empty";
528 return false;
529 }
530
531 return true;
532 }
533
534 // check treatment and instructions array.
535 private boolean checkFlowTreatment(FlowEntry flow, JsonObject jsonFlow) {
536
537 if (flow.treatment() != null) {
538 JsonObject jsonTreatment =
539 jsonFlow.get(TREATMENT).asObject();
540 JsonArray jsonInstructions =
541 jsonTreatment.get(INSTRUCTIONS).asArray();
542
543 if (flow.treatment().immediate().size() !=
544 jsonInstructions.size()) {
545 reason = "instructions array size of " +
546 flow.treatment().immediate().size();
547
548 return false;
549 }
550 for (Instruction instruction :
551 flow.treatment().immediate()) {
552 boolean instructionFound = false;
553 for (int instructionIndex = 0;
554 instructionIndex < jsonInstructions.size();
555 instructionIndex++) {
556 String jsonType =
557 jsonInstructions.get(instructionIndex)
558 .asObject().get(TYPE).asString();
559
560 String instructionType =
561 instruction.type().name();
562
563 if (jsonType.equals(instructionType)) {
564 instructionFound = true;
565 }
566 }
567 if (!instructionFound) {
568 reason = INSTRUCTIONS + SPACE + instruction;
569 return false;
570 }
571 }
572 }
573 return true;
574 }
575
576 // check selector and criteria array.
577 private boolean checkFlowSelector(FlowEntry flow, JsonObject jsonFlow) {
578
579 if (flow.selector() != null) {
580 JsonObject jsonTreatment =
581 jsonFlow.get(SELECTOR).asObject();
582
583 JsonArray jsonCriteria =
584 jsonTreatment.get(CRITERIA).asArray();
585
586 if (flow.selector().criteria().size() != jsonCriteria.size()) {
587 reason = CRITERIA + " array size of " +
588 Integer.toString(flow.selector().criteria().size());
589 return false;
590 }
591 for (Criterion criterion : flow.selector().criteria()) {
592 boolean criterionFound = false;
593
594 for (int criterionIndex = 0;
595 criterionIndex < jsonCriteria.size();
596 criterionIndex++) {
597 String jsonType =
598 jsonCriteria.get(criterionIndex)
599 .asObject().get(TYPE).asString();
600 String criterionType = criterion.type().name();
601 if (jsonType.equals(criterionType)) {
602 criterionFound = true;
603 }
604 }
605 if (!criterionFound) {
606 reason = "criterion " + criterion;
607 return false;
608 }
609 }
610 }
611 return true;
612 }
613
614 @Override
615 public void describeTo(Description description) {
616 description.appendText(reason);
617 }
618 }
619
620 /**
Ray Milkey2b217142014-12-15 09:24:24 -0800621 * Hamcrest matcher to check that an intent is represented properly in a JSON
622 * array of intents.
623 */
624 public static class IntentJsonArrayMatcher extends TypeSafeMatcher<JsonArray> {
625 private final Intent intent;
626 private String reason = "";
627
628 public IntentJsonArrayMatcher(Intent intentValue) {
629 intent = intentValue;
630 }
631
632 @Override
633 public boolean matchesSafely(JsonArray json) {
634 boolean intentFound = false;
Ray Milkeyf7cb4012015-07-20 13:01:07 -0700635 final int expectedAttributes = 5;
Ray Milkey2b217142014-12-15 09:24:24 -0800636 for (int jsonIntentIndex = 0; jsonIntentIndex < json.size();
637 jsonIntentIndex++) {
638
639 final JsonObject jsonIntent = json.get(jsonIntentIndex).asObject();
640
641 if (jsonIntent.names().size() != expectedAttributes) {
642 reason = "Found an intent with the wrong number of attributes";
643 return false;
644 }
645
646 final String jsonIntentId = jsonIntent.get("id").asString();
647 if (jsonIntentId.equals(intent.id().toString())) {
648 intentFound = true;
649
650 // We found the correct intent, check attribute values
651 assertThat(jsonIntent, matchesIntent(intent));
652 }
653 }
654 if (!intentFound) {
655 reason = "Intent with id " + intent.id().toString() + " not found";
656 return false;
657 } else {
658 return true;
659 }
660 }
661
662 @Override
663 public void describeTo(Description description) {
664 description.appendText(reason);
665 }
666 }
667
668 /**
669 * Factory to allocate an intent array matcher.
670 *
671 * @param intent intent object we are looking for
672 * @return matcher
673 */
674 private static IntentJsonArrayMatcher hasIntent(Intent intent) {
675 return new IntentJsonArrayMatcher(intent);
676 }
Ray Milkey4f5de002014-12-17 19:26:11 -0800677
Ray Milkeyed0b1662015-02-05 09:34:29 -0800678 /**
679 * Initializes test mocks and environment.
680 */
Ray Milkey2b217142014-12-15 09:24:24 -0800681 @Before
Ray Milkeyed0b1662015-02-05 09:34:29 -0800682 public void setUpTest() {
Ray Milkey2b217142014-12-15 09:24:24 -0800683 expect(mockIntentService.getIntents()).andReturn(intents).anyTimes();
Ray Milkey1534f8d2015-05-13 15:42:50 -0700684 expect(mockIntentService.getIntentState(anyObject()))
685 .andReturn(IntentState.INSTALLED)
686 .anyTimes();
Ray Milkey2b217142014-12-15 09:24:24 -0800687 // Register the services needed for the test
688 final CodecManager codecService = new CodecManager();
689 codecService.activate();
690 ServiceDirectory testDirectory =
691 new TestServiceDirectory()
692 .add(IntentService.class, mockIntentService)
Author Namee252a002016-09-26 22:42:24 +0530693 .add(FlowRuleService.class, mockFlowService)
Ayaka Koshibec06c89b2015-02-10 19:25:41 -0800694 .add(CodecService.class, codecService)
695 .add(CoreService.class, mockCoreService);
Ray Milkey2b217142014-12-15 09:24:24 -0800696
697 BaseResource.setServiceDirectory(testDirectory);
698
Thomas Vachuska2048c1f2017-05-10 19:32:22 -0700699 MockIdGenerator.cleanBind();
Ray Milkey2b217142014-12-15 09:24:24 -0800700 }
701
Ray Milkeyed0b1662015-02-05 09:34:29 -0800702 /**
703 * Tears down and verifies test mocks and environment.
704 */
Ray Milkey2b217142014-12-15 09:24:24 -0800705 @After
Ray Milkeyed0b1662015-02-05 09:34:29 -0800706 public void tearDownTest() {
Thomas Vachuska2048c1f2017-05-10 19:32:22 -0700707 MockIdGenerator.unbind();
Ray Milkey2b217142014-12-15 09:24:24 -0800708 verify(mockIntentService);
Ray Milkey2b217142014-12-15 09:24:24 -0800709 }
710
711 /**
712 * Tests the result of the rest api GET when there are no intents.
713 */
714 @Test
715 public void testIntentsEmptyArray() {
716 replay(mockIntentService);
Jian Li9d616492016-03-09 10:52:49 -0800717 final WebTarget wt = target();
718 final String response = wt.path("intents").request().get(String.class);
Ray Milkey2b217142014-12-15 09:24:24 -0800719 assertThat(response, is("{\"intents\":[]}"));
720 }
721
722 /**
723 * Tests the result of the rest api GET when intents are defined.
724 */
725 @Test
726 public void testIntentsArray() {
727 replay(mockIntentService);
728
Ray Milkey43a28222015-02-23 13:57:58 -0800729 final Intent intent1 = new MockIntent(1L, Collections.emptyList());
Ray Milkey2b217142014-12-15 09:24:24 -0800730 final HashSet<NetworkResource> resources = new HashSet<>();
731 resources.add(new MockResource(1));
732 resources.add(new MockResource(2));
733 resources.add(new MockResource(3));
Ray Milkey43a28222015-02-23 13:57:58 -0800734 final Intent intent2 = new MockIntent(2L, resources);
Ray Milkey2b217142014-12-15 09:24:24 -0800735
736 intents.add(intent1);
737 intents.add(intent2);
Jian Li9d616492016-03-09 10:52:49 -0800738 final WebTarget wt = target();
739 final String response = wt.path("intents").request().get(String.class);
Ray Milkey2b217142014-12-15 09:24:24 -0800740 assertThat(response, containsString("{\"intents\":["));
741
Jian Li80cfe452016-01-14 16:04:58 -0800742 final JsonObject result = Json.parse(response).asObject();
Ray Milkey2b217142014-12-15 09:24:24 -0800743 assertThat(result, notNullValue());
744
745 assertThat(result.names(), hasSize(1));
746 assertThat(result.names().get(0), is("intents"));
747
748 final JsonArray jsonIntents = result.get("intents").asArray();
749 assertThat(jsonIntents, notNullValue());
750
751 assertThat(jsonIntents, hasIntent(intent1));
752 assertThat(jsonIntents, hasIntent(intent2));
753 }
754
755 /**
756 * Tests the result of a rest api GET for a single intent.
757 */
758 @Test
759 public void testIntentsSingle() {
760 final HashSet<NetworkResource> resources = new HashSet<>();
761 resources.add(new MockResource(1));
762 resources.add(new MockResource(2));
763 resources.add(new MockResource(3));
Ray Milkey43a28222015-02-23 13:57:58 -0800764 final Intent intent = new MockIntent(3L, resources);
Ray Milkey2b217142014-12-15 09:24:24 -0800765
766 intents.add(intent);
767
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800768 expect(mockIntentService.getIntent(Key.of(0, APP_ID)))
Ray Milkey2b217142014-12-15 09:24:24 -0800769 .andReturn(intent)
770 .anyTimes();
Ayaka Koshibec06c89b2015-02-10 19:25:41 -0800771 expect(mockIntentService.getIntent(Key.of("0", APP_ID)))
772 .andReturn(intent)
773 .anyTimes();
Ray Milkey05b169d2015-08-13 14:33:33 -0700774 expect(mockIntentService.getIntent(Key.of(0, APP_ID)))
775 .andReturn(intent)
776 .anyTimes();
777 expect(mockIntentService.getIntent(Key.of("0x0", APP_ID)))
778 .andReturn(null)
779 .anyTimes();
Ray Milkey2b217142014-12-15 09:24:24 -0800780 replay(mockIntentService);
Ray Milkeyf7cb4012015-07-20 13:01:07 -0700781 expect(mockCoreService.getAppId(APP_ID.name()))
Ayaka Koshibec06c89b2015-02-10 19:25:41 -0800782 .andReturn(APP_ID).anyTimes();
783 replay(mockCoreService);
Jian Li9d616492016-03-09 10:52:49 -0800784 final WebTarget wt = target();
Ray Milkey05b169d2015-08-13 14:33:33 -0700785
786 // Test get using key string
Jian Li9d616492016-03-09 10:52:49 -0800787 final String response = wt.path("intents/" + APP_ID.name()
788 + "/0").request().get(String.class);
Jian Li80cfe452016-01-14 16:04:58 -0800789 final JsonObject result = Json.parse(response).asObject();
Ray Milkey2b217142014-12-15 09:24:24 -0800790 assertThat(result, matchesIntent(intent));
Ray Milkey05b169d2015-08-13 14:33:33 -0700791
792 // Test get using numeric value
Jian Li9d616492016-03-09 10:52:49 -0800793 final String responseNumeric = wt.path("intents/" + APP_ID.name()
794 + "/0x0").request().get(String.class);
Jian Li80cfe452016-01-14 16:04:58 -0800795 final JsonObject resultNumeric = Json.parse(responseNumeric).asObject();
Ray Milkey05b169d2015-08-13 14:33:33 -0700796 assertThat(resultNumeric, matchesIntent(intent));
Ray Milkey2b217142014-12-15 09:24:24 -0800797 }
798
799 /**
Author Namee252a002016-09-26 22:42:24 +0530800 * Tests the result of a rest api GET for related flows for single intent.
801 */
802 @Test
803 public void testRelatedFlowsForIntents() {
804 List<FlowEntry> flowEntries = new ArrayList<>();
805 flowEntries.add(flow1);
806 flowEntries.add(flow2);
807 List<List<FlowEntry>> paths = new ArrayList<>();
808 paths.add(flowEntries);
809 List<FlowRule> flowRules = new ArrayList<>();
810 flowRules.add(flowRule1);
811 flowRules.add(flowRule2);
812 FlowRuleIntent flowRuleIntent = new FlowRuleIntent(
813 APP_ID,
814 flowRules,
815 new HashSet<NetworkResource>());
816 Intent intent = new MockIntent(3L);
817 installableIntents.add(flowRuleIntent);
818 intents.add(intent);
819
820 expect(mockIntentService.getIntent(Key.of(0, APP_ID)))
821 .andReturn(intent)
822 .anyTimes();
823 expect(mockIntentService.getIntent(Key.of("0", APP_ID)))
824 .andReturn(intent)
825 .anyTimes();
826 expect(mockIntentService.getIntent(Key.of(0, APP_ID)))
827 .andReturn(intent)
828 .anyTimes();
829 expect(mockIntentService.getIntent(Key.of("0x0", APP_ID)))
830 .andReturn(null)
831 .anyTimes();
832 expect(mockIntentService.getInstallableIntents(intent.key()))
833 .andReturn(installableIntents)
834 .anyTimes();
835 replay(mockIntentService);
836
837 expect(mockFlowService.getFlowEntries(deviceId1))
838 .andReturn(flowEntries).anyTimes();
839 replay(mockFlowService);
840
841 expect(mockCoreService.getAppId(APP_ID.name()))
842 .andReturn(APP_ID).anyTimes();
843 expect(mockCoreService.getAppId(APP_ID.id()))
844 .andReturn(APP_ID).anyTimes();
845 replay(mockCoreService);
846
847 final WebTarget wt = target();
848
849 // Test get using key string
850 final String response = wt.path("intents/relatedflows/" + APP_ID.name()
851 + "/0").request().get(String.class);
852 final JsonObject result = Json.parse(response).asObject();
853 assertThat(result, matchesRelatedFlowEntries(paths, APP_ID.name()));
854
855 // Test get using numeric value
856 final String responseNumeric = wt.path("intents/relatedflows/" + APP_ID.name()
857 + "/0x0").request().get(String.class);
858 final JsonObject resultNumeric = Json.parse(responseNumeric).asObject();
859 assertThat(resultNumeric, matchesRelatedFlowEntries(paths, APP_ID.name()));
860 }
861
862 /**
Ray Milkey2b217142014-12-15 09:24:24 -0800863 * Tests that a fetch of a non-existent intent object throws an exception.
864 */
865 @Test
866 public void testBadGet() {
867
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800868 expect(mockIntentService.getIntent(Key.of(0, APP_ID)))
Ray Milkey2b217142014-12-15 09:24:24 -0800869 .andReturn(null)
870 .anyTimes();
871 replay(mockIntentService);
872
Jian Li9d616492016-03-09 10:52:49 -0800873 WebTarget wt = target();
Ray Milkey2b217142014-12-15 09:24:24 -0800874 try {
Jian Li9d616492016-03-09 10:52:49 -0800875 wt.path("intents/0").request().get(String.class);
Ray Milkey2b217142014-12-15 09:24:24 -0800876 fail("Fetch of non-existent intent did not throw an exception");
Jian Li9d616492016-03-09 10:52:49 -0800877 } catch (NotFoundException ex) {
Ray Milkey2b217142014-12-15 09:24:24 -0800878 assertThat(ex.getMessage(),
Jian Li9d616492016-03-09 10:52:49 -0800879 containsString("HTTP 404 Not Found"));
Ray Milkey2b217142014-12-15 09:24:24 -0800880 }
881 }
Ray Milkeyb82c42b2015-06-30 09:42:20 -0700882
883 /**
884 * Tests creating an intent with POST.
885 */
886 @Test
887 public void testPost() {
Ray Milkeyf7cb4012015-07-20 13:01:07 -0700888 ApplicationId testId = new DefaultApplicationId(2, "myApp");
889 expect(mockCoreService.getAppId("myApp"))
890 .andReturn(testId);
Ray Milkeyb82c42b2015-06-30 09:42:20 -0700891 replay(mockCoreService);
892
893 mockIntentService.submit(anyObject());
894 expectLastCall();
895 replay(mockIntentService);
896
897 InputStream jsonStream = IntentsResourceTest.class
898 .getResourceAsStream("post-intent.json");
Jian Li9d616492016-03-09 10:52:49 -0800899 WebTarget wt = target();
Ray Milkeyb82c42b2015-06-30 09:42:20 -0700900
Jian Li9d616492016-03-09 10:52:49 -0800901 Response response = wt.path("intents")
902 .request(MediaType.APPLICATION_JSON_TYPE)
903 .post(Entity.json(jsonStream));
Ray Milkeyb82c42b2015-06-30 09:42:20 -0700904 assertThat(response.getStatus(), is(HttpURLConnection.HTTP_CREATED));
905 String location = response.getLocation().getPath();
Ray Milkey8d076402015-08-31 15:43:18 -0700906 assertThat(location, Matchers.startsWith("/intents/myApp/"));
Ray Milkeyb82c42b2015-06-30 09:42:20 -0700907 }
Ray Milkey7b158512015-07-21 16:32:43 -0700908
909 /**
Ray Milkey05b169d2015-08-13 14:33:33 -0700910 * Tests creating an intent with POST and illegal JSON.
911 */
912 @Test
913 public void testBadPost() {
914 replay(mockCoreService);
915 replay(mockIntentService);
916
917 String json = "this is invalid!";
Jian Li9d616492016-03-09 10:52:49 -0800918 WebTarget wt = target();
Ray Milkey05b169d2015-08-13 14:33:33 -0700919
Jian Li9d616492016-03-09 10:52:49 -0800920 Response response = wt.path("intents")
921 .request(MediaType.APPLICATION_JSON_TYPE)
922 .post(Entity.json(json));
Ray Milkey05b169d2015-08-13 14:33:33 -0700923 assertThat(response.getStatus(), is(HttpURLConnection.HTTP_BAD_REQUEST));
924 }
925
926 /**
Ray Milkey7b158512015-07-21 16:32:43 -0700927 * Tests removing an intent with DELETE.
928 */
929 @Test
930 public void testRemove() {
931 final HashSet<NetworkResource> resources = new HashSet<>();
932 resources.add(new MockResource(1));
933 resources.add(new MockResource(2));
934 resources.add(new MockResource(3));
935 final Intent intent = new MockIntent(3L, resources);
936 final ApplicationId appId = new DefaultApplicationId(2, "app");
937 IntentService fakeManager = new FakeIntentManager();
938
939 expect(mockCoreService.getAppId("app"))
940 .andReturn(appId).once();
941 replay(mockCoreService);
942
943 mockIntentService.withdraw(anyObject());
944 expectLastCall().andDelegateTo(fakeManager).once();
945 expect(mockIntentService.getIntent(Key.of(2, appId)))
946 .andReturn(intent)
947 .once();
948 expect(mockIntentService.getIntent(Key.of("0x2", appId)))
949 .andReturn(null)
950 .once();
951
952 mockIntentService.addListener(anyObject());
953 expectLastCall().andDelegateTo(fakeManager).once();
954 mockIntentService.removeListener(anyObject());
955 expectLastCall().andDelegateTo(fakeManager).once();
956
957 replay(mockIntentService);
958
Jian Li9d616492016-03-09 10:52:49 -0800959 WebTarget wt = target();
Ray Milkey7b158512015-07-21 16:32:43 -0700960
Jian Li9d616492016-03-09 10:52:49 -0800961 Response response = wt.path("intents/app/0x2")
Ray Milkey7c251822016-04-06 17:38:25 -0700962 .request(MediaType.APPLICATION_JSON, MediaType.TEXT_PLAIN)
Jian Li9d616492016-03-09 10:52:49 -0800963 .delete();
Ray Milkey7b158512015-07-21 16:32:43 -0700964 assertThat(response.getStatus(), is(HttpURLConnection.HTTP_NO_CONTENT));
965 }
Ray Milkey05b169d2015-08-13 14:33:33 -0700966
967 /**
968 * Tests removal of a non existent intent with DELETE.
969 */
970 @Test
971 public void testBadRemove() {
972 final ApplicationId appId = new DefaultApplicationId(2, "app");
973
974 expect(mockCoreService.getAppId("app"))
975 .andReturn(appId).once();
976 replay(mockCoreService);
977
978 expect(mockIntentService.getIntent(Key.of(2, appId)))
979 .andReturn(null)
980 .once();
981 expect(mockIntentService.getIntent(Key.of("0x2", appId)))
982 .andReturn(null)
983 .once();
984
985 replay(mockIntentService);
986
Jian Li9d616492016-03-09 10:52:49 -0800987 WebTarget wt = target();
Ray Milkey05b169d2015-08-13 14:33:33 -0700988
Jian Li9d616492016-03-09 10:52:49 -0800989 Response response = wt.path("intents/app/0x2")
Ray Milkey7c251822016-04-06 17:38:25 -0700990 .request(MediaType.APPLICATION_JSON, MediaType.TEXT_PLAIN)
Jian Li9d616492016-03-09 10:52:49 -0800991 .delete();
Ray Milkey05b169d2015-08-13 14:33:33 -0700992 assertThat(response.getStatus(), is(HttpURLConnection.HTTP_NO_CONTENT));
993 }
994
Ray Milkey2b217142014-12-15 09:24:24 -0800995}