blob: a42855bc85783298790db0b39f7d289c405e3111 [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.DefaultGroupId;
38import org.onosproject.core.GroupId;
Ray Milkey2b217142014-12-15 09:24:24 -080039import org.onosproject.core.IdGenerator;
Author Namee252a002016-09-26 22:42:24 +053040import org.onosproject.net.DeviceId;
Ray Milkey2b217142014-12-15 09:24:24 -080041import org.onosproject.net.NetworkResource;
Author Namee252a002016-09-26 22:42:24 +053042import org.onosproject.net.flow.DefaultTrafficSelector;
43import org.onosproject.net.flow.DefaultTrafficTreatment;
44import org.onosproject.net.flow.FlowEntry;
45import org.onosproject.net.flow.FlowId;
46import org.onosproject.net.flow.FlowRule;
47import org.onosproject.net.flow.FlowRuleExtPayLoad;
48import org.onosproject.net.flow.FlowRuleService;
49import org.onosproject.net.flow.TrafficSelector;
50import org.onosproject.net.flow.TrafficTreatment;
51import org.onosproject.net.flow.criteria.Criterion;
52import org.onosproject.net.flow.instructions.Instruction;
Ray Milkey7b158512015-07-21 16:32:43 -070053import org.onosproject.net.intent.FakeIntentManager;
Author Namee252a002016-09-26 22:42:24 +053054import org.onosproject.net.intent.FlowRuleIntent;
Ray Milkey2b217142014-12-15 09:24:24 -080055import org.onosproject.net.intent.Intent;
Ray Milkey2b217142014-12-15 09:24:24 -080056import org.onosproject.net.intent.IntentService;
Ray Milkey1534f8d2015-05-13 15:42:50 -070057import org.onosproject.net.intent.IntentState;
Ray Milkeyf9af43c2015-02-09 16:45:48 -080058import org.onosproject.net.intent.Key;
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 Milkey7c251822016-04-06 17:38:25 -070079import static org.onosproject.net.intent.MockIdGenerator.bindNewGenerator;
Ray Milkey2b217142014-12-15 09:24:24 -080080
81/**
82 * Unit tests for Intents REST APIs.
83 */
Ray Milkey9c3d3362015-01-28 10:39:56 -080084public class IntentsResourceTest extends ResourceTest {
Author Namee252a002016-09-26 22:42:24 +053085
86
87 private static final String APPID = "appId";
88 private static final String CRITERIA = "criteria";
89 private static final String DEVICE_ID = "deviceId";
90 private static final String ID = "id";
91 private static final String INSTRUCTIONS = "instructions";
92 private static final String PATHS = "paths";
93 private static final String SELECTOR = "selector";
94 private static final String SPACE = " ";
95 private static final String TREATMENT = "treatment";
96 private static final String TYPE = "type";
97
Ray Milkey2b217142014-12-15 09:24:24 -080098 final IntentService mockIntentService = createMock(IntentService.class);
Ayaka Koshibec06c89b2015-02-10 19:25:41 -080099 final CoreService mockCoreService = createMock(CoreService.class);
Author Namee252a002016-09-26 22:42:24 +0530100 final FlowRuleService mockFlowService = createMock(FlowRuleService.class);
Ray Milkey2b217142014-12-15 09:24:24 -0800101 final HashSet<Intent> intents = new HashSet<>();
Author Namee252a002016-09-26 22:42:24 +0530102 final List<org.onosproject.net.intent.Intent> installableIntents = new ArrayList<>();
Thomas Vachuska02aeb032015-01-06 22:36:30 -0800103 private static final ApplicationId APP_ID = new DefaultApplicationId(1, "test");
Ray Milkey2b217142014-12-15 09:24:24 -0800104 private IdGenerator mockGenerator;
105
Author Namee252a002016-09-26 22:42:24 +0530106 final DeviceId deviceId1 = DeviceId.deviceId("1");
107
108 final TrafficTreatment treatment1 = DefaultTrafficTreatment.builder()
109 .setEthDst(MacAddress.BROADCAST)
110 .build();
111 final TrafficTreatment treatment2 = DefaultTrafficTreatment.builder()
112 .setEthDst(MacAddress.IPV4_MULTICAST)
113 .build();
114
115 final TrafficSelector selector1 = DefaultTrafficSelector.builder()
116 .matchEthType((short) 3)
117 .matchIPProtocol((byte) 9)
118 .build();
119 final TrafficSelector selector2 = DefaultTrafficSelector.builder()
120 .matchEthType((short) 4)
121 .matchIPProtocol((byte) 10)
122 .build();
123
124 final MockFlowEntry flow1 = new MockFlowEntry(deviceId1, 1, treatment1, selector1);
125 final MockFlowEntry flow2 = new MockFlowEntry(deviceId1, 2, treatment2, selector2);
126
127 final MockFlowRule flowRule1 = new MockFlowRule(deviceId1, 1, treatment1, selector1);
128 final MockFlowRule flowRule2 = new MockFlowRule(deviceId1, 2, treatment2, selector2);
129
Ray Milkey2b217142014-12-15 09:24:24 -0800130 private class MockResource implements NetworkResource {
131 int id;
132
133 MockResource(int id) {
134 this.id = id;
135 }
136
Ayaka Koshibec06c89b2015-02-10 19:25:41 -0800137 @Override
Ray Milkey2b217142014-12-15 09:24:24 -0800138 public String toString() {
139 return "Resource " + Integer.toString(id);
140 }
141 }
142
Ray Milkey2b217142014-12-15 09:24:24 -0800143 /**
Author Namee252a002016-09-26 22:42:24 +0530144 * Mock class for a flow entry.
145 */
146 private static class MockFlowEntry implements FlowEntry {
147 final DeviceId deviceId;
148 final long baseValue;
149 TrafficTreatment treatment;
150 TrafficSelector selector;
151
152 public MockFlowEntry(DeviceId deviceId, long id,
153 TrafficTreatment treatment,
154 TrafficSelector selector) {
155 this.deviceId = deviceId;
156 this.baseValue = id * 100;
157 this.treatment = treatment;
158 this.selector = selector;
159 }
160
161 @Override
162 public FlowEntryState state() {
163 return FlowEntryState.ADDED;
164 }
165
166 @Override
167 public long life() {
168 return life(SECONDS);
169 }
170
171 @Override
172 public long life(TimeUnit timeUnit) {
173 return SECONDS.convert(baseValue + 11, timeUnit);
174 }
175
176 @Override
177 public long packets() {
178 return baseValue + 22;
179 }
180
181 @Override
182 public long bytes() {
183 return baseValue + 33;
184 }
185
186 @Override
187 public long lastSeen() {
188 return baseValue + 44;
189 }
190
191 @Override
192 public int errType() {
193 return 0;
194 }
195
196 @Override
197 public int errCode() {
198 return 0;
199 }
200
201 @Override
202 public FlowId id() {
203 final long id = baseValue + 55;
204 return FlowId.valueOf(id);
205 }
206
207 @Override
208 public GroupId groupId() {
209 return new DefaultGroupId(3);
210 }
211
212 @Override
213 public short appId() {
214 return 1;
215 }
216
217 @Override
218 public int priority() {
219 return (int) (baseValue + 66);
220 }
221
222 @Override
223 public DeviceId deviceId() {
224 return deviceId;
225 }
226
227 @Override
228 public TrafficSelector selector() {
229 return selector;
230 }
231
232 @Override
233 public TrafficTreatment treatment() {
234 return treatment;
235 }
236
237 @Override
238 public int timeout() {
239 return (int) (baseValue + 77);
240 }
241
242 @Override
243 public int hardTimeout() {
244 return 0;
245 }
246
247 @Override
248 public FlowRule.FlowRemoveReason reason() {
249 return FlowRule.FlowRemoveReason.NO_REASON;
250 }
251
252 @Override
253 public boolean isPermanent() {
254 return false;
255 }
256
257 @Override
258 public int tableId() {
259 return 0;
260 }
261
262 @Override
263 public boolean exactMatch(FlowRule rule) {
264 return this.appId() == rule.appId() &&
265 this.deviceId().equals(rule.deviceId()) &&
266 this.id().equals(rule.id()) &&
267 this.treatment.equals(rule.treatment()) &&
268 this.selector().equals(rule.selector());
269 }
270
271 @Override
272 public FlowRuleExtPayLoad payLoad() {
273 return null;
274 }
275
276 @Override
277 public String toString() {
278 return id().id().toString();
279 }
280 }
281
282 /**
283 * Mock class for a flow rule.
284 */
285 private static class MockFlowRule implements FlowRule {
286
287 final DeviceId deviceId;
288 final long baseValue;
289 TrafficTreatment treatment;
290 TrafficSelector selector;
291
292 public MockFlowRule(DeviceId deviceId,
293 long id,
294 TrafficTreatment treatment,
295 TrafficSelector selector) {
296 this.deviceId = deviceId;
297 this.baseValue = id * 100;
298 this.treatment = treatment;
299 this.selector = selector;
300 }
301
302 @Override
303 public FlowId id() {
304 long id = baseValue + 55;
305 return FlowId.valueOf(id);
306 }
307
308 @Override
309 public short appId() {
310 return 1;
311 }
312
313 @Override
314 public GroupId groupId() {
315 return new DefaultGroupId(3);
316 }
317
318 @Override
319 public int priority() {
320 return 0;
321 }
322
323 @Override
324 public DeviceId deviceId() {
325 return deviceId;
326 }
327
328 @Override
329 public TrafficSelector selector() {
330 return selector;
331 }
332
333 @Override
334 public TrafficTreatment treatment() {
335 return treatment;
336 }
337
338 @Override
339 public int timeout() {
340 return (int) (baseValue + 77);
341 }
342
343 @Override
344 public int hardTimeout() {
345 return 0;
346 }
347
348 @Override
349 public FlowRemoveReason reason() {
350 return FlowRemoveReason.NO_REASON;
351 }
352
353 @Override
354 public boolean isPermanent() {
355 return false;
356 }
357
358 @Override
359 public int tableId() {
360 return 0;
361 }
362
363 @Override
364 public boolean exactMatch(FlowRule rule) {
365 return false;
366 }
367
368 @Override
369 public FlowRuleExtPayLoad payLoad() {
370 return null;
371 }
372 }
373
374 /**
Ray Milkey2b217142014-12-15 09:24:24 -0800375 * Hamcrest matcher to check that an intent representation in JSON matches
376 * the actual intent.
377 */
378 public static class IntentJsonMatcher extends TypeSafeMatcher<JsonObject> {
379 private final Intent intent;
380 private String reason = "";
381
382 public IntentJsonMatcher(Intent intentValue) {
383 intent = intentValue;
384 }
385
386 @Override
387 public boolean matchesSafely(JsonObject jsonIntent) {
388 // check id
389 final String jsonId = jsonIntent.get("id").asString();
390 if (!jsonId.equals(intent.id().toString())) {
391 reason = "id " + intent.id().toString();
392 return false;
393 }
394
395 // check application id
Ray Milkeyf7cb4012015-07-20 13:01:07 -0700396
Ray Milkey2b217142014-12-15 09:24:24 -0800397 final String jsonAppId = jsonIntent.get("appId").asString();
Ray Milkeyf7cb4012015-07-20 13:01:07 -0700398 final String appId = intent.appId().name();
399 if (!jsonAppId.equals(appId)) {
400 reason = "appId was " + jsonAppId;
Ray Milkey2b217142014-12-15 09:24:24 -0800401 return false;
402 }
403
404 // check intent type
405 final String jsonType = jsonIntent.get("type").asString();
406 if (!jsonType.equals("MockIntent")) {
407 reason = "type MockIntent";
408 return false;
409 }
410
Ray Milkey1534f8d2015-05-13 15:42:50 -0700411 // check state field
412 final String jsonState = jsonIntent.get("state").asString();
413 if (!jsonState.equals("INSTALLED")) {
414 reason = "state INSTALLED";
415 return false;
416 }
417
Ray Milkey2b217142014-12-15 09:24:24 -0800418 // check resources array
419 final JsonArray jsonResources = jsonIntent.get("resources").asArray();
420 if (intent.resources() != null) {
421 if (intent.resources().size() != jsonResources.size()) {
422 reason = "resources array size of " + Integer.toString(intent.resources().size());
423 return false;
424 }
425 for (final NetworkResource resource : intent.resources()) {
426 boolean resourceFound = false;
427 final String resourceString = resource.toString();
428 for (int resourceIndex = 0; resourceIndex < jsonResources.size(); resourceIndex++) {
429 final JsonValue value = jsonResources.get(resourceIndex);
430 if (value.asString().equals(resourceString)) {
431 resourceFound = true;
432 }
433 }
434 if (!resourceFound) {
435 reason = "resource " + resourceString;
436 return false;
437 }
438 }
439 } else if (jsonResources.size() != 0) {
440 reason = "resources array empty";
441 return false;
442 }
443 return true;
444 }
445
446 @Override
447 public void describeTo(Description description) {
448 description.appendText(reason);
449 }
450 }
451
452 /**
453 * Factory to allocate an intent matcher.
454 *
455 * @param intent intent object we are looking for
456 * @return matcher
457 */
458 private static IntentJsonMatcher matchesIntent(Intent intent) {
459 return new IntentJsonMatcher(intent);
460 }
461
462 /**
Author Namee252a002016-09-26 22:42:24 +0530463 * Factory to allocate an IntentRelatedFlows matcher.
464 *
465 * @param pathEntries list of path conatining flow entries of a particular intent
466 * @param expectedAppId expected app id we are looking for
467 * @return matcher
468 */
469 private static IntentStatsJsonMatcher matchesRelatedFlowEntries(
470 List<List<FlowEntry>> pathEntries,
471 final String expectedAppId) {
472 return new IntentStatsJsonMatcher(pathEntries, expectedAppId);
473 }
474
475 /**
476 * Hamcrest matcher to check that an list of flowEntries in JSON matches
477 * the actual list of flow entries.
478 */
479 public static class IntentStatsJsonMatcher extends
480 TypeSafeMatcher<JsonObject> {
481
482 private final List<List<FlowEntry>> pathEntries;
483 private final String expectedAppId;
484 private String reason = "";
485
486 public IntentStatsJsonMatcher(
487 final List<List<FlowEntry>> pathEntries,
488 final String expectedAppId) {
489 this.pathEntries = pathEntries;
490 this.expectedAppId = expectedAppId;
491 }
492
493 @Override
494 public boolean matchesSafely(JsonObject jsonIntent) {
495 int jsonPathIndex = 0;
496 JsonArray jsonPaths = jsonIntent.get(PATHS).asArray();
497
498 if (pathEntries != null) {
499
500 if (pathEntries.size() != jsonPaths.size()) {
501 reason = "path entries array size of " +
502 Integer.toString(pathEntries.size());
503 return false;
504 }
505
506 for (List<FlowEntry> flowEntries : pathEntries) {
507 JsonArray jsonFlowEntries = jsonPaths.get(
508 jsonPathIndex++).asArray();
509
510 if (flowEntries.size() != jsonFlowEntries.size()) {
511 reason = "flow entries array size of " +
512 Integer.toString(pathEntries.size());
513
514 return false;
515 }
516
517 int jsonFlowEntryIndex = 0;
518 for (FlowEntry flow : flowEntries) {
519
520 JsonObject jsonFlow = jsonFlowEntries.get(
521 jsonFlowEntryIndex++).asObject();
522
523 String jsonId = jsonFlow.get(ID).asString();
524 String flowId = Long.toString(flow.id().value());
525 if (!jsonId.equals(flowId)) {
526 reason = ID + SPACE + flow.id();
527 return false;
528 }
529
530 // check application id
531 String jsonAppId = jsonFlow.get(APPID).asString();
532 if (!jsonAppId.equals(expectedAppId)) {
533 reason = APPID + SPACE + Short.toString(flow.appId());
534 return false;
535 }
536
537 // check device id
538 String jsonDeviceId =
539 jsonFlow.get(DEVICE_ID).asString();
540
541 if (!jsonDeviceId.equals(flow.deviceId().toString())) {
542 reason = DEVICE_ID + SPACE + flow.deviceId();
543 return false;
544 }
545
546 if (!checkFlowTreatment(flow, jsonFlow)) {
547 return false;
548 }
549
550 if (!checkFlowSelector(flow, jsonFlow)) {
551 return false;
552 }
553
554 }
555
556 }
557 } else if (pathEntries.size() != 0) {
558 reason = "pathEntries array empty";
559 return false;
560 }
561
562 return true;
563 }
564
565 // check treatment and instructions array.
566 private boolean checkFlowTreatment(FlowEntry flow, JsonObject jsonFlow) {
567
568 if (flow.treatment() != null) {
569 JsonObject jsonTreatment =
570 jsonFlow.get(TREATMENT).asObject();
571 JsonArray jsonInstructions =
572 jsonTreatment.get(INSTRUCTIONS).asArray();
573
574 if (flow.treatment().immediate().size() !=
575 jsonInstructions.size()) {
576 reason = "instructions array size of " +
577 flow.treatment().immediate().size();
578
579 return false;
580 }
581 for (Instruction instruction :
582 flow.treatment().immediate()) {
583 boolean instructionFound = false;
584 for (int instructionIndex = 0;
585 instructionIndex < jsonInstructions.size();
586 instructionIndex++) {
587 String jsonType =
588 jsonInstructions.get(instructionIndex)
589 .asObject().get(TYPE).asString();
590
591 String instructionType =
592 instruction.type().name();
593
594 if (jsonType.equals(instructionType)) {
595 instructionFound = true;
596 }
597 }
598 if (!instructionFound) {
599 reason = INSTRUCTIONS + SPACE + instruction;
600 return false;
601 }
602 }
603 }
604 return true;
605 }
606
607 // check selector and criteria array.
608 private boolean checkFlowSelector(FlowEntry flow, JsonObject jsonFlow) {
609
610 if (flow.selector() != null) {
611 JsonObject jsonTreatment =
612 jsonFlow.get(SELECTOR).asObject();
613
614 JsonArray jsonCriteria =
615 jsonTreatment.get(CRITERIA).asArray();
616
617 if (flow.selector().criteria().size() != jsonCriteria.size()) {
618 reason = CRITERIA + " array size of " +
619 Integer.toString(flow.selector().criteria().size());
620 return false;
621 }
622 for (Criterion criterion : flow.selector().criteria()) {
623 boolean criterionFound = false;
624
625 for (int criterionIndex = 0;
626 criterionIndex < jsonCriteria.size();
627 criterionIndex++) {
628 String jsonType =
629 jsonCriteria.get(criterionIndex)
630 .asObject().get(TYPE).asString();
631 String criterionType = criterion.type().name();
632 if (jsonType.equals(criterionType)) {
633 criterionFound = true;
634 }
635 }
636 if (!criterionFound) {
637 reason = "criterion " + criterion;
638 return false;
639 }
640 }
641 }
642 return true;
643 }
644
645 @Override
646 public void describeTo(Description description) {
647 description.appendText(reason);
648 }
649 }
650
651 /**
Ray Milkey2b217142014-12-15 09:24:24 -0800652 * Hamcrest matcher to check that an intent is represented properly in a JSON
653 * array of intents.
654 */
655 public static class IntentJsonArrayMatcher extends TypeSafeMatcher<JsonArray> {
656 private final Intent intent;
657 private String reason = "";
658
659 public IntentJsonArrayMatcher(Intent intentValue) {
660 intent = intentValue;
661 }
662
663 @Override
664 public boolean matchesSafely(JsonArray json) {
665 boolean intentFound = false;
Ray Milkeyf7cb4012015-07-20 13:01:07 -0700666 final int expectedAttributes = 5;
Ray Milkey2b217142014-12-15 09:24:24 -0800667 for (int jsonIntentIndex = 0; jsonIntentIndex < json.size();
668 jsonIntentIndex++) {
669
670 final JsonObject jsonIntent = json.get(jsonIntentIndex).asObject();
671
672 if (jsonIntent.names().size() != expectedAttributes) {
673 reason = "Found an intent with the wrong number of attributes";
674 return false;
675 }
676
677 final String jsonIntentId = jsonIntent.get("id").asString();
678 if (jsonIntentId.equals(intent.id().toString())) {
679 intentFound = true;
680
681 // We found the correct intent, check attribute values
682 assertThat(jsonIntent, matchesIntent(intent));
683 }
684 }
685 if (!intentFound) {
686 reason = "Intent with id " + intent.id().toString() + " not found";
687 return false;
688 } else {
689 return true;
690 }
691 }
692
693 @Override
694 public void describeTo(Description description) {
695 description.appendText(reason);
696 }
697 }
698
699 /**
700 * Factory to allocate an intent array matcher.
701 *
702 * @param intent intent object we are looking for
703 * @return matcher
704 */
705 private static IntentJsonArrayMatcher hasIntent(Intent intent) {
706 return new IntentJsonArrayMatcher(intent);
707 }
Ray Milkey4f5de002014-12-17 19:26:11 -0800708
Ray Milkeyed0b1662015-02-05 09:34:29 -0800709 /**
710 * Initializes test mocks and environment.
711 */
Ray Milkey2b217142014-12-15 09:24:24 -0800712 @Before
Ray Milkeyed0b1662015-02-05 09:34:29 -0800713 public void setUpTest() {
Ray Milkey2b217142014-12-15 09:24:24 -0800714 expect(mockIntentService.getIntents()).andReturn(intents).anyTimes();
Ray Milkey1534f8d2015-05-13 15:42:50 -0700715 expect(mockIntentService.getIntentState(anyObject()))
716 .andReturn(IntentState.INSTALLED)
717 .anyTimes();
Ray Milkey2b217142014-12-15 09:24:24 -0800718 // Register the services needed for the test
719 final CodecManager codecService = new CodecManager();
720 codecService.activate();
721 ServiceDirectory testDirectory =
722 new TestServiceDirectory()
723 .add(IntentService.class, mockIntentService)
Author Namee252a002016-09-26 22:42:24 +0530724 .add(FlowRuleService.class, mockFlowService)
Ayaka Koshibec06c89b2015-02-10 19:25:41 -0800725 .add(CodecService.class, codecService)
726 .add(CoreService.class, mockCoreService);
Ray Milkey2b217142014-12-15 09:24:24 -0800727
728 BaseResource.setServiceDirectory(testDirectory);
729
Ray Milkey7c251822016-04-06 17:38:25 -0700730 bindNewGenerator();
Ray Milkey2b217142014-12-15 09:24:24 -0800731 }
732
Ray Milkeyed0b1662015-02-05 09:34:29 -0800733 /**
734 * Tears down and verifies test mocks and environment.
735 */
Ray Milkey2b217142014-12-15 09:24:24 -0800736 @After
Ray Milkeyed0b1662015-02-05 09:34:29 -0800737 public void tearDownTest() {
Ray Milkey2b217142014-12-15 09:24:24 -0800738 verify(mockIntentService);
Ray Milkey2b217142014-12-15 09:24:24 -0800739 }
740
741 /**
742 * Tests the result of the rest api GET when there are no intents.
743 */
744 @Test
745 public void testIntentsEmptyArray() {
746 replay(mockIntentService);
Jian Li9d616492016-03-09 10:52:49 -0800747 final WebTarget wt = target();
748 final String response = wt.path("intents").request().get(String.class);
Ray Milkey2b217142014-12-15 09:24:24 -0800749 assertThat(response, is("{\"intents\":[]}"));
750 }
751
752 /**
753 * Tests the result of the rest api GET when intents are defined.
754 */
755 @Test
756 public void testIntentsArray() {
757 replay(mockIntentService);
758
Ray Milkey43a28222015-02-23 13:57:58 -0800759 final Intent intent1 = new MockIntent(1L, Collections.emptyList());
Ray Milkey2b217142014-12-15 09:24:24 -0800760 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 intent2 = new MockIntent(2L, resources);
Ray Milkey2b217142014-12-15 09:24:24 -0800765
766 intents.add(intent1);
767 intents.add(intent2);
Jian Li9d616492016-03-09 10:52:49 -0800768 final WebTarget wt = target();
769 final String response = wt.path("intents").request().get(String.class);
Ray Milkey2b217142014-12-15 09:24:24 -0800770 assertThat(response, containsString("{\"intents\":["));
771
Jian Li80cfe452016-01-14 16:04:58 -0800772 final JsonObject result = Json.parse(response).asObject();
Ray Milkey2b217142014-12-15 09:24:24 -0800773 assertThat(result, notNullValue());
774
775 assertThat(result.names(), hasSize(1));
776 assertThat(result.names().get(0), is("intents"));
777
778 final JsonArray jsonIntents = result.get("intents").asArray();
779 assertThat(jsonIntents, notNullValue());
780
781 assertThat(jsonIntents, hasIntent(intent1));
782 assertThat(jsonIntents, hasIntent(intent2));
783 }
784
785 /**
786 * Tests the result of a rest api GET for a single intent.
787 */
788 @Test
789 public void testIntentsSingle() {
790 final HashSet<NetworkResource> resources = new HashSet<>();
791 resources.add(new MockResource(1));
792 resources.add(new MockResource(2));
793 resources.add(new MockResource(3));
Ray Milkey43a28222015-02-23 13:57:58 -0800794 final Intent intent = new MockIntent(3L, resources);
Ray Milkey2b217142014-12-15 09:24:24 -0800795
796 intents.add(intent);
797
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800798 expect(mockIntentService.getIntent(Key.of(0, APP_ID)))
Ray Milkey2b217142014-12-15 09:24:24 -0800799 .andReturn(intent)
800 .anyTimes();
Ayaka Koshibec06c89b2015-02-10 19:25:41 -0800801 expect(mockIntentService.getIntent(Key.of("0", APP_ID)))
802 .andReturn(intent)
803 .anyTimes();
Ray Milkey05b169d2015-08-13 14:33:33 -0700804 expect(mockIntentService.getIntent(Key.of(0, APP_ID)))
805 .andReturn(intent)
806 .anyTimes();
807 expect(mockIntentService.getIntent(Key.of("0x0", APP_ID)))
808 .andReturn(null)
809 .anyTimes();
Ray Milkey2b217142014-12-15 09:24:24 -0800810 replay(mockIntentService);
Ray Milkeyf7cb4012015-07-20 13:01:07 -0700811 expect(mockCoreService.getAppId(APP_ID.name()))
Ayaka Koshibec06c89b2015-02-10 19:25:41 -0800812 .andReturn(APP_ID).anyTimes();
813 replay(mockCoreService);
Jian Li9d616492016-03-09 10:52:49 -0800814 final WebTarget wt = target();
Ray Milkey05b169d2015-08-13 14:33:33 -0700815
816 // Test get using key string
Jian Li9d616492016-03-09 10:52:49 -0800817 final String response = wt.path("intents/" + APP_ID.name()
818 + "/0").request().get(String.class);
Jian Li80cfe452016-01-14 16:04:58 -0800819 final JsonObject result = Json.parse(response).asObject();
Ray Milkey2b217142014-12-15 09:24:24 -0800820 assertThat(result, matchesIntent(intent));
Ray Milkey05b169d2015-08-13 14:33:33 -0700821
822 // Test get using numeric value
Jian Li9d616492016-03-09 10:52:49 -0800823 final String responseNumeric = wt.path("intents/" + APP_ID.name()
824 + "/0x0").request().get(String.class);
Jian Li80cfe452016-01-14 16:04:58 -0800825 final JsonObject resultNumeric = Json.parse(responseNumeric).asObject();
Ray Milkey05b169d2015-08-13 14:33:33 -0700826 assertThat(resultNumeric, matchesIntent(intent));
Ray Milkey2b217142014-12-15 09:24:24 -0800827 }
828
829 /**
Author Namee252a002016-09-26 22:42:24 +0530830 * Tests the result of a rest api GET for related flows for single intent.
831 */
832 @Test
833 public void testRelatedFlowsForIntents() {
834 List<FlowEntry> flowEntries = new ArrayList<>();
835 flowEntries.add(flow1);
836 flowEntries.add(flow2);
837 List<List<FlowEntry>> paths = new ArrayList<>();
838 paths.add(flowEntries);
839 List<FlowRule> flowRules = new ArrayList<>();
840 flowRules.add(flowRule1);
841 flowRules.add(flowRule2);
842 FlowRuleIntent flowRuleIntent = new FlowRuleIntent(
843 APP_ID,
844 flowRules,
845 new HashSet<NetworkResource>());
846 Intent intent = new MockIntent(3L);
847 installableIntents.add(flowRuleIntent);
848 intents.add(intent);
849
850 expect(mockIntentService.getIntent(Key.of(0, APP_ID)))
851 .andReturn(intent)
852 .anyTimes();
853 expect(mockIntentService.getIntent(Key.of("0", APP_ID)))
854 .andReturn(intent)
855 .anyTimes();
856 expect(mockIntentService.getIntent(Key.of(0, APP_ID)))
857 .andReturn(intent)
858 .anyTimes();
859 expect(mockIntentService.getIntent(Key.of("0x0", APP_ID)))
860 .andReturn(null)
861 .anyTimes();
862 expect(mockIntentService.getInstallableIntents(intent.key()))
863 .andReturn(installableIntents)
864 .anyTimes();
865 replay(mockIntentService);
866
867 expect(mockFlowService.getFlowEntries(deviceId1))
868 .andReturn(flowEntries).anyTimes();
869 replay(mockFlowService);
870
871 expect(mockCoreService.getAppId(APP_ID.name()))
872 .andReturn(APP_ID).anyTimes();
873 expect(mockCoreService.getAppId(APP_ID.id()))
874 .andReturn(APP_ID).anyTimes();
875 replay(mockCoreService);
876
877 final WebTarget wt = target();
878
879 // Test get using key string
880 final String response = wt.path("intents/relatedflows/" + APP_ID.name()
881 + "/0").request().get(String.class);
882 final JsonObject result = Json.parse(response).asObject();
883 assertThat(result, matchesRelatedFlowEntries(paths, APP_ID.name()));
884
885 // Test get using numeric value
886 final String responseNumeric = wt.path("intents/relatedflows/" + APP_ID.name()
887 + "/0x0").request().get(String.class);
888 final JsonObject resultNumeric = Json.parse(responseNumeric).asObject();
889 assertThat(resultNumeric, matchesRelatedFlowEntries(paths, APP_ID.name()));
890 }
891
892 /**
Ray Milkey2b217142014-12-15 09:24:24 -0800893 * Tests that a fetch of a non-existent intent object throws an exception.
894 */
895 @Test
896 public void testBadGet() {
897
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800898 expect(mockIntentService.getIntent(Key.of(0, APP_ID)))
Ray Milkey2b217142014-12-15 09:24:24 -0800899 .andReturn(null)
900 .anyTimes();
901 replay(mockIntentService);
902
Jian Li9d616492016-03-09 10:52:49 -0800903 WebTarget wt = target();
Ray Milkey2b217142014-12-15 09:24:24 -0800904 try {
Jian Li9d616492016-03-09 10:52:49 -0800905 wt.path("intents/0").request().get(String.class);
Ray Milkey2b217142014-12-15 09:24:24 -0800906 fail("Fetch of non-existent intent did not throw an exception");
Jian Li9d616492016-03-09 10:52:49 -0800907 } catch (NotFoundException ex) {
Ray Milkey2b217142014-12-15 09:24:24 -0800908 assertThat(ex.getMessage(),
Jian Li9d616492016-03-09 10:52:49 -0800909 containsString("HTTP 404 Not Found"));
Ray Milkey2b217142014-12-15 09:24:24 -0800910 }
911 }
Ray Milkeyb82c42b2015-06-30 09:42:20 -0700912
913 /**
914 * Tests creating an intent with POST.
915 */
916 @Test
917 public void testPost() {
Ray Milkeyf7cb4012015-07-20 13:01:07 -0700918 ApplicationId testId = new DefaultApplicationId(2, "myApp");
919 expect(mockCoreService.getAppId("myApp"))
920 .andReturn(testId);
Ray Milkeyb82c42b2015-06-30 09:42:20 -0700921 replay(mockCoreService);
922
923 mockIntentService.submit(anyObject());
924 expectLastCall();
925 replay(mockIntentService);
926
927 InputStream jsonStream = IntentsResourceTest.class
928 .getResourceAsStream("post-intent.json");
Jian Li9d616492016-03-09 10:52:49 -0800929 WebTarget wt = target();
Ray Milkeyb82c42b2015-06-30 09:42:20 -0700930
Jian Li9d616492016-03-09 10:52:49 -0800931 Response response = wt.path("intents")
932 .request(MediaType.APPLICATION_JSON_TYPE)
933 .post(Entity.json(jsonStream));
Ray Milkeyb82c42b2015-06-30 09:42:20 -0700934 assertThat(response.getStatus(), is(HttpURLConnection.HTTP_CREATED));
935 String location = response.getLocation().getPath();
Ray Milkey8d076402015-08-31 15:43:18 -0700936 assertThat(location, Matchers.startsWith("/intents/myApp/"));
Ray Milkeyb82c42b2015-06-30 09:42:20 -0700937 }
Ray Milkey7b158512015-07-21 16:32:43 -0700938
939 /**
Ray Milkey05b169d2015-08-13 14:33:33 -0700940 * Tests creating an intent with POST and illegal JSON.
941 */
942 @Test
943 public void testBadPost() {
944 replay(mockCoreService);
945 replay(mockIntentService);
946
947 String json = "this is invalid!";
Jian Li9d616492016-03-09 10:52:49 -0800948 WebTarget wt = target();
Ray Milkey05b169d2015-08-13 14:33:33 -0700949
Jian Li9d616492016-03-09 10:52:49 -0800950 Response response = wt.path("intents")
951 .request(MediaType.APPLICATION_JSON_TYPE)
952 .post(Entity.json(json));
Ray Milkey05b169d2015-08-13 14:33:33 -0700953 assertThat(response.getStatus(), is(HttpURLConnection.HTTP_BAD_REQUEST));
954 }
955
956 /**
Ray Milkey7b158512015-07-21 16:32:43 -0700957 * Tests removing an intent with DELETE.
958 */
959 @Test
960 public void testRemove() {
961 final HashSet<NetworkResource> resources = new HashSet<>();
962 resources.add(new MockResource(1));
963 resources.add(new MockResource(2));
964 resources.add(new MockResource(3));
965 final Intent intent = new MockIntent(3L, resources);
966 final ApplicationId appId = new DefaultApplicationId(2, "app");
967 IntentService fakeManager = new FakeIntentManager();
968
969 expect(mockCoreService.getAppId("app"))
970 .andReturn(appId).once();
971 replay(mockCoreService);
972
973 mockIntentService.withdraw(anyObject());
974 expectLastCall().andDelegateTo(fakeManager).once();
975 expect(mockIntentService.getIntent(Key.of(2, appId)))
976 .andReturn(intent)
977 .once();
978 expect(mockIntentService.getIntent(Key.of("0x2", appId)))
979 .andReturn(null)
980 .once();
981
982 mockIntentService.addListener(anyObject());
983 expectLastCall().andDelegateTo(fakeManager).once();
984 mockIntentService.removeListener(anyObject());
985 expectLastCall().andDelegateTo(fakeManager).once();
986
987 replay(mockIntentService);
988
Jian Li9d616492016-03-09 10:52:49 -0800989 WebTarget wt = target();
Ray Milkey7b158512015-07-21 16:32:43 -0700990
Jian Li9d616492016-03-09 10:52:49 -0800991 Response response = wt.path("intents/app/0x2")
Ray Milkey7c251822016-04-06 17:38:25 -0700992 .request(MediaType.APPLICATION_JSON, MediaType.TEXT_PLAIN)
Jian Li9d616492016-03-09 10:52:49 -0800993 .delete();
Ray Milkey7b158512015-07-21 16:32:43 -0700994 assertThat(response.getStatus(), is(HttpURLConnection.HTTP_NO_CONTENT));
995 }
Ray Milkey05b169d2015-08-13 14:33:33 -0700996
997 /**
998 * Tests removal of a non existent intent with DELETE.
999 */
1000 @Test
1001 public void testBadRemove() {
1002 final ApplicationId appId = new DefaultApplicationId(2, "app");
1003
1004 expect(mockCoreService.getAppId("app"))
1005 .andReturn(appId).once();
1006 replay(mockCoreService);
1007
1008 expect(mockIntentService.getIntent(Key.of(2, appId)))
1009 .andReturn(null)
1010 .once();
1011 expect(mockIntentService.getIntent(Key.of("0x2", appId)))
1012 .andReturn(null)
1013 .once();
1014
1015 replay(mockIntentService);
1016
Jian Li9d616492016-03-09 10:52:49 -08001017 WebTarget wt = target();
Ray Milkey05b169d2015-08-13 14:33:33 -07001018
Jian Li9d616492016-03-09 10:52:49 -08001019 Response response = wt.path("intents/app/0x2")
Ray Milkey7c251822016-04-06 17:38:25 -07001020 .request(MediaType.APPLICATION_JSON, MediaType.TEXT_PLAIN)
Jian Li9d616492016-03-09 10:52:49 -08001021 .delete();
Ray Milkey05b169d2015-08-13 14:33:33 -07001022 assertThat(response.getStatus(), is(HttpURLConnection.HTTP_NO_CONTENT));
1023 }
1024
Ray Milkey2b217142014-12-15 09:24:24 -08001025}