blob: a49cafc34a3beca9543e6d91ceb5eceb4ef08fae [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
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900172 public FlowLiveType liveType() {
173 return null;
174 }
175
176 @Override
Author Namee252a002016-09-26 22:42:24 +0530177 public long life(TimeUnit timeUnit) {
178 return SECONDS.convert(baseValue + 11, timeUnit);
179 }
180
181 @Override
182 public long packets() {
183 return baseValue + 22;
184 }
185
186 @Override
187 public long bytes() {
188 return baseValue + 33;
189 }
190
191 @Override
192 public long lastSeen() {
193 return baseValue + 44;
194 }
195
196 @Override
197 public int errType() {
198 return 0;
199 }
200
201 @Override
202 public int errCode() {
203 return 0;
204 }
205
206 @Override
207 public FlowId id() {
208 final long id = baseValue + 55;
209 return FlowId.valueOf(id);
210 }
211
212 @Override
213 public GroupId groupId() {
214 return new DefaultGroupId(3);
215 }
216
217 @Override
218 public short appId() {
219 return 1;
220 }
221
222 @Override
223 public int priority() {
224 return (int) (baseValue + 66);
225 }
226
227 @Override
228 public DeviceId deviceId() {
229 return deviceId;
230 }
231
232 @Override
233 public TrafficSelector selector() {
234 return selector;
235 }
236
237 @Override
238 public TrafficTreatment treatment() {
239 return treatment;
240 }
241
242 @Override
243 public int timeout() {
244 return (int) (baseValue + 77);
245 }
246
247 @Override
248 public int hardTimeout() {
249 return 0;
250 }
251
252 @Override
253 public FlowRule.FlowRemoveReason reason() {
254 return FlowRule.FlowRemoveReason.NO_REASON;
255 }
256
257 @Override
258 public boolean isPermanent() {
259 return false;
260 }
261
262 @Override
263 public int tableId() {
264 return 0;
265 }
266
267 @Override
268 public boolean exactMatch(FlowRule rule) {
269 return this.appId() == rule.appId() &&
270 this.deviceId().equals(rule.deviceId()) &&
271 this.id().equals(rule.id()) &&
272 this.treatment.equals(rule.treatment()) &&
273 this.selector().equals(rule.selector());
274 }
275
276 @Override
277 public FlowRuleExtPayLoad payLoad() {
278 return null;
279 }
280
281 @Override
282 public String toString() {
283 return id().id().toString();
284 }
285 }
286
287 /**
288 * Mock class for a flow rule.
289 */
290 private static class MockFlowRule implements FlowRule {
291
292 final DeviceId deviceId;
293 final long baseValue;
294 TrafficTreatment treatment;
295 TrafficSelector selector;
296
297 public MockFlowRule(DeviceId deviceId,
298 long id,
299 TrafficTreatment treatment,
300 TrafficSelector selector) {
301 this.deviceId = deviceId;
302 this.baseValue = id * 100;
303 this.treatment = treatment;
304 this.selector = selector;
305 }
306
307 @Override
308 public FlowId id() {
309 long id = baseValue + 55;
310 return FlowId.valueOf(id);
311 }
312
313 @Override
314 public short appId() {
315 return 1;
316 }
317
318 @Override
319 public GroupId groupId() {
320 return new DefaultGroupId(3);
321 }
322
323 @Override
324 public int priority() {
325 return 0;
326 }
327
328 @Override
329 public DeviceId deviceId() {
330 return deviceId;
331 }
332
333 @Override
334 public TrafficSelector selector() {
335 return selector;
336 }
337
338 @Override
339 public TrafficTreatment treatment() {
340 return treatment;
341 }
342
343 @Override
344 public int timeout() {
345 return (int) (baseValue + 77);
346 }
347
348 @Override
349 public int hardTimeout() {
350 return 0;
351 }
352
353 @Override
354 public FlowRemoveReason reason() {
355 return FlowRemoveReason.NO_REASON;
356 }
357
358 @Override
359 public boolean isPermanent() {
360 return false;
361 }
362
363 @Override
364 public int tableId() {
365 return 0;
366 }
367
368 @Override
369 public boolean exactMatch(FlowRule rule) {
370 return false;
371 }
372
373 @Override
374 public FlowRuleExtPayLoad payLoad() {
375 return null;
376 }
377 }
378
379 /**
Ray Milkey2b217142014-12-15 09:24:24 -0800380 * Hamcrest matcher to check that an intent representation in JSON matches
381 * the actual intent.
382 */
383 public static class IntentJsonMatcher extends TypeSafeMatcher<JsonObject> {
384 private final Intent intent;
385 private String reason = "";
386
387 public IntentJsonMatcher(Intent intentValue) {
388 intent = intentValue;
389 }
390
391 @Override
392 public boolean matchesSafely(JsonObject jsonIntent) {
393 // check id
394 final String jsonId = jsonIntent.get("id").asString();
395 if (!jsonId.equals(intent.id().toString())) {
396 reason = "id " + intent.id().toString();
397 return false;
398 }
399
400 // check application id
Ray Milkeyf7cb4012015-07-20 13:01:07 -0700401
Ray Milkey2b217142014-12-15 09:24:24 -0800402 final String jsonAppId = jsonIntent.get("appId").asString();
Ray Milkeyf7cb4012015-07-20 13:01:07 -0700403 final String appId = intent.appId().name();
404 if (!jsonAppId.equals(appId)) {
405 reason = "appId was " + jsonAppId;
Ray Milkey2b217142014-12-15 09:24:24 -0800406 return false;
407 }
408
409 // check intent type
410 final String jsonType = jsonIntent.get("type").asString();
411 if (!jsonType.equals("MockIntent")) {
412 reason = "type MockIntent";
413 return false;
414 }
415
Ray Milkey1534f8d2015-05-13 15:42:50 -0700416 // check state field
417 final String jsonState = jsonIntent.get("state").asString();
418 if (!jsonState.equals("INSTALLED")) {
419 reason = "state INSTALLED";
420 return false;
421 }
422
Ray Milkey2b217142014-12-15 09:24:24 -0800423 // check resources array
424 final JsonArray jsonResources = jsonIntent.get("resources").asArray();
425 if (intent.resources() != null) {
426 if (intent.resources().size() != jsonResources.size()) {
427 reason = "resources array size of " + Integer.toString(intent.resources().size());
428 return false;
429 }
430 for (final NetworkResource resource : intent.resources()) {
431 boolean resourceFound = false;
432 final String resourceString = resource.toString();
433 for (int resourceIndex = 0; resourceIndex < jsonResources.size(); resourceIndex++) {
434 final JsonValue value = jsonResources.get(resourceIndex);
435 if (value.asString().equals(resourceString)) {
436 resourceFound = true;
437 }
438 }
439 if (!resourceFound) {
440 reason = "resource " + resourceString;
441 return false;
442 }
443 }
444 } else if (jsonResources.size() != 0) {
445 reason = "resources array empty";
446 return false;
447 }
448 return true;
449 }
450
451 @Override
452 public void describeTo(Description description) {
453 description.appendText(reason);
454 }
455 }
456
457 /**
458 * Factory to allocate an intent matcher.
459 *
460 * @param intent intent object we are looking for
461 * @return matcher
462 */
463 private static IntentJsonMatcher matchesIntent(Intent intent) {
464 return new IntentJsonMatcher(intent);
465 }
466
467 /**
Author Namee252a002016-09-26 22:42:24 +0530468 * Factory to allocate an IntentRelatedFlows matcher.
469 *
470 * @param pathEntries list of path conatining flow entries of a particular intent
471 * @param expectedAppId expected app id we are looking for
472 * @return matcher
473 */
474 private static IntentStatsJsonMatcher matchesRelatedFlowEntries(
475 List<List<FlowEntry>> pathEntries,
476 final String expectedAppId) {
477 return new IntentStatsJsonMatcher(pathEntries, expectedAppId);
478 }
479
480 /**
481 * Hamcrest matcher to check that an list of flowEntries in JSON matches
482 * the actual list of flow entries.
483 */
484 public static class IntentStatsJsonMatcher extends
485 TypeSafeMatcher<JsonObject> {
486
487 private final List<List<FlowEntry>> pathEntries;
488 private final String expectedAppId;
489 private String reason = "";
490
491 public IntentStatsJsonMatcher(
492 final List<List<FlowEntry>> pathEntries,
493 final String expectedAppId) {
494 this.pathEntries = pathEntries;
495 this.expectedAppId = expectedAppId;
496 }
497
498 @Override
499 public boolean matchesSafely(JsonObject jsonIntent) {
500 int jsonPathIndex = 0;
501 JsonArray jsonPaths = jsonIntent.get(PATHS).asArray();
502
503 if (pathEntries != null) {
504
505 if (pathEntries.size() != jsonPaths.size()) {
506 reason = "path entries array size of " +
507 Integer.toString(pathEntries.size());
508 return false;
509 }
510
511 for (List<FlowEntry> flowEntries : pathEntries) {
512 JsonArray jsonFlowEntries = jsonPaths.get(
513 jsonPathIndex++).asArray();
514
515 if (flowEntries.size() != jsonFlowEntries.size()) {
516 reason = "flow entries array size of " +
517 Integer.toString(pathEntries.size());
518
519 return false;
520 }
521
522 int jsonFlowEntryIndex = 0;
523 for (FlowEntry flow : flowEntries) {
524
525 JsonObject jsonFlow = jsonFlowEntries.get(
526 jsonFlowEntryIndex++).asObject();
527
528 String jsonId = jsonFlow.get(ID).asString();
529 String flowId = Long.toString(flow.id().value());
530 if (!jsonId.equals(flowId)) {
531 reason = ID + SPACE + flow.id();
532 return false;
533 }
534
535 // check application id
536 String jsonAppId = jsonFlow.get(APPID).asString();
537 if (!jsonAppId.equals(expectedAppId)) {
538 reason = APPID + SPACE + Short.toString(flow.appId());
539 return false;
540 }
541
542 // check device id
543 String jsonDeviceId =
544 jsonFlow.get(DEVICE_ID).asString();
545
546 if (!jsonDeviceId.equals(flow.deviceId().toString())) {
547 reason = DEVICE_ID + SPACE + flow.deviceId();
548 return false;
549 }
550
551 if (!checkFlowTreatment(flow, jsonFlow)) {
552 return false;
553 }
554
555 if (!checkFlowSelector(flow, jsonFlow)) {
556 return false;
557 }
558
559 }
560
561 }
562 } else if (pathEntries.size() != 0) {
563 reason = "pathEntries array empty";
564 return false;
565 }
566
567 return true;
568 }
569
570 // check treatment and instructions array.
571 private boolean checkFlowTreatment(FlowEntry flow, JsonObject jsonFlow) {
572
573 if (flow.treatment() != null) {
574 JsonObject jsonTreatment =
575 jsonFlow.get(TREATMENT).asObject();
576 JsonArray jsonInstructions =
577 jsonTreatment.get(INSTRUCTIONS).asArray();
578
579 if (flow.treatment().immediate().size() !=
580 jsonInstructions.size()) {
581 reason = "instructions array size of " +
582 flow.treatment().immediate().size();
583
584 return false;
585 }
586 for (Instruction instruction :
587 flow.treatment().immediate()) {
588 boolean instructionFound = false;
589 for (int instructionIndex = 0;
590 instructionIndex < jsonInstructions.size();
591 instructionIndex++) {
592 String jsonType =
593 jsonInstructions.get(instructionIndex)
594 .asObject().get(TYPE).asString();
595
596 String instructionType =
597 instruction.type().name();
598
599 if (jsonType.equals(instructionType)) {
600 instructionFound = true;
601 }
602 }
603 if (!instructionFound) {
604 reason = INSTRUCTIONS + SPACE + instruction;
605 return false;
606 }
607 }
608 }
609 return true;
610 }
611
612 // check selector and criteria array.
613 private boolean checkFlowSelector(FlowEntry flow, JsonObject jsonFlow) {
614
615 if (flow.selector() != null) {
616 JsonObject jsonTreatment =
617 jsonFlow.get(SELECTOR).asObject();
618
619 JsonArray jsonCriteria =
620 jsonTreatment.get(CRITERIA).asArray();
621
622 if (flow.selector().criteria().size() != jsonCriteria.size()) {
623 reason = CRITERIA + " array size of " +
624 Integer.toString(flow.selector().criteria().size());
625 return false;
626 }
627 for (Criterion criterion : flow.selector().criteria()) {
628 boolean criterionFound = false;
629
630 for (int criterionIndex = 0;
631 criterionIndex < jsonCriteria.size();
632 criterionIndex++) {
633 String jsonType =
634 jsonCriteria.get(criterionIndex)
635 .asObject().get(TYPE).asString();
636 String criterionType = criterion.type().name();
637 if (jsonType.equals(criterionType)) {
638 criterionFound = true;
639 }
640 }
641 if (!criterionFound) {
642 reason = "criterion " + criterion;
643 return false;
644 }
645 }
646 }
647 return true;
648 }
649
650 @Override
651 public void describeTo(Description description) {
652 description.appendText(reason);
653 }
654 }
655
656 /**
Ray Milkey2b217142014-12-15 09:24:24 -0800657 * Hamcrest matcher to check that an intent is represented properly in a JSON
658 * array of intents.
659 */
660 public static class IntentJsonArrayMatcher extends TypeSafeMatcher<JsonArray> {
661 private final Intent intent;
662 private String reason = "";
663
664 public IntentJsonArrayMatcher(Intent intentValue) {
665 intent = intentValue;
666 }
667
668 @Override
669 public boolean matchesSafely(JsonArray json) {
670 boolean intentFound = false;
Ray Milkeyf7cb4012015-07-20 13:01:07 -0700671 final int expectedAttributes = 5;
Ray Milkey2b217142014-12-15 09:24:24 -0800672 for (int jsonIntentIndex = 0; jsonIntentIndex < json.size();
673 jsonIntentIndex++) {
674
675 final JsonObject jsonIntent = json.get(jsonIntentIndex).asObject();
676
677 if (jsonIntent.names().size() != expectedAttributes) {
678 reason = "Found an intent with the wrong number of attributes";
679 return false;
680 }
681
682 final String jsonIntentId = jsonIntent.get("id").asString();
683 if (jsonIntentId.equals(intent.id().toString())) {
684 intentFound = true;
685
686 // We found the correct intent, check attribute values
687 assertThat(jsonIntent, matchesIntent(intent));
688 }
689 }
690 if (!intentFound) {
691 reason = "Intent with id " + intent.id().toString() + " not found";
692 return false;
693 } else {
694 return true;
695 }
696 }
697
698 @Override
699 public void describeTo(Description description) {
700 description.appendText(reason);
701 }
702 }
703
704 /**
705 * Factory to allocate an intent array matcher.
706 *
707 * @param intent intent object we are looking for
708 * @return matcher
709 */
710 private static IntentJsonArrayMatcher hasIntent(Intent intent) {
711 return new IntentJsonArrayMatcher(intent);
712 }
Ray Milkey4f5de002014-12-17 19:26:11 -0800713
Ray Milkeyed0b1662015-02-05 09:34:29 -0800714 /**
715 * Initializes test mocks and environment.
716 */
Ray Milkey2b217142014-12-15 09:24:24 -0800717 @Before
Ray Milkeyed0b1662015-02-05 09:34:29 -0800718 public void setUpTest() {
Ray Milkey2b217142014-12-15 09:24:24 -0800719 expect(mockIntentService.getIntents()).andReturn(intents).anyTimes();
Ray Milkey1534f8d2015-05-13 15:42:50 -0700720 expect(mockIntentService.getIntentState(anyObject()))
721 .andReturn(IntentState.INSTALLED)
722 .anyTimes();
Ray Milkey2b217142014-12-15 09:24:24 -0800723 // Register the services needed for the test
724 final CodecManager codecService = new CodecManager();
725 codecService.activate();
726 ServiceDirectory testDirectory =
727 new TestServiceDirectory()
728 .add(IntentService.class, mockIntentService)
Author Namee252a002016-09-26 22:42:24 +0530729 .add(FlowRuleService.class, mockFlowService)
Ayaka Koshibec06c89b2015-02-10 19:25:41 -0800730 .add(CodecService.class, codecService)
731 .add(CoreService.class, mockCoreService);
Ray Milkey2b217142014-12-15 09:24:24 -0800732
733 BaseResource.setServiceDirectory(testDirectory);
734
Ray Milkey7c251822016-04-06 17:38:25 -0700735 bindNewGenerator();
Ray Milkey2b217142014-12-15 09:24:24 -0800736 }
737
Ray Milkeyed0b1662015-02-05 09:34:29 -0800738 /**
739 * Tears down and verifies test mocks and environment.
740 */
Ray Milkey2b217142014-12-15 09:24:24 -0800741 @After
Ray Milkeyed0b1662015-02-05 09:34:29 -0800742 public void tearDownTest() {
Ray Milkey2b217142014-12-15 09:24:24 -0800743 verify(mockIntentService);
Ray Milkey2b217142014-12-15 09:24:24 -0800744 }
745
746 /**
747 * Tests the result of the rest api GET when there are no intents.
748 */
749 @Test
750 public void testIntentsEmptyArray() {
751 replay(mockIntentService);
Jian Li9d616492016-03-09 10:52:49 -0800752 final WebTarget wt = target();
753 final String response = wt.path("intents").request().get(String.class);
Ray Milkey2b217142014-12-15 09:24:24 -0800754 assertThat(response, is("{\"intents\":[]}"));
755 }
756
757 /**
758 * Tests the result of the rest api GET when intents are defined.
759 */
760 @Test
761 public void testIntentsArray() {
762 replay(mockIntentService);
763
Ray Milkey43a28222015-02-23 13:57:58 -0800764 final Intent intent1 = new MockIntent(1L, Collections.emptyList());
Ray Milkey2b217142014-12-15 09:24:24 -0800765 final HashSet<NetworkResource> resources = new HashSet<>();
766 resources.add(new MockResource(1));
767 resources.add(new MockResource(2));
768 resources.add(new MockResource(3));
Ray Milkey43a28222015-02-23 13:57:58 -0800769 final Intent intent2 = new MockIntent(2L, resources);
Ray Milkey2b217142014-12-15 09:24:24 -0800770
771 intents.add(intent1);
772 intents.add(intent2);
Jian Li9d616492016-03-09 10:52:49 -0800773 final WebTarget wt = target();
774 final String response = wt.path("intents").request().get(String.class);
Ray Milkey2b217142014-12-15 09:24:24 -0800775 assertThat(response, containsString("{\"intents\":["));
776
Jian Li80cfe452016-01-14 16:04:58 -0800777 final JsonObject result = Json.parse(response).asObject();
Ray Milkey2b217142014-12-15 09:24:24 -0800778 assertThat(result, notNullValue());
779
780 assertThat(result.names(), hasSize(1));
781 assertThat(result.names().get(0), is("intents"));
782
783 final JsonArray jsonIntents = result.get("intents").asArray();
784 assertThat(jsonIntents, notNullValue());
785
786 assertThat(jsonIntents, hasIntent(intent1));
787 assertThat(jsonIntents, hasIntent(intent2));
788 }
789
790 /**
791 * Tests the result of a rest api GET for a single intent.
792 */
793 @Test
794 public void testIntentsSingle() {
795 final HashSet<NetworkResource> resources = new HashSet<>();
796 resources.add(new MockResource(1));
797 resources.add(new MockResource(2));
798 resources.add(new MockResource(3));
Ray Milkey43a28222015-02-23 13:57:58 -0800799 final Intent intent = new MockIntent(3L, resources);
Ray Milkey2b217142014-12-15 09:24:24 -0800800
801 intents.add(intent);
802
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800803 expect(mockIntentService.getIntent(Key.of(0, APP_ID)))
Ray Milkey2b217142014-12-15 09:24:24 -0800804 .andReturn(intent)
805 .anyTimes();
Ayaka Koshibec06c89b2015-02-10 19:25:41 -0800806 expect(mockIntentService.getIntent(Key.of("0", APP_ID)))
807 .andReturn(intent)
808 .anyTimes();
Ray Milkey05b169d2015-08-13 14:33:33 -0700809 expect(mockIntentService.getIntent(Key.of(0, APP_ID)))
810 .andReturn(intent)
811 .anyTimes();
812 expect(mockIntentService.getIntent(Key.of("0x0", APP_ID)))
813 .andReturn(null)
814 .anyTimes();
Ray Milkey2b217142014-12-15 09:24:24 -0800815 replay(mockIntentService);
Ray Milkeyf7cb4012015-07-20 13:01:07 -0700816 expect(mockCoreService.getAppId(APP_ID.name()))
Ayaka Koshibec06c89b2015-02-10 19:25:41 -0800817 .andReturn(APP_ID).anyTimes();
818 replay(mockCoreService);
Jian Li9d616492016-03-09 10:52:49 -0800819 final WebTarget wt = target();
Ray Milkey05b169d2015-08-13 14:33:33 -0700820
821 // Test get using key string
Jian Li9d616492016-03-09 10:52:49 -0800822 final String response = wt.path("intents/" + APP_ID.name()
823 + "/0").request().get(String.class);
Jian Li80cfe452016-01-14 16:04:58 -0800824 final JsonObject result = Json.parse(response).asObject();
Ray Milkey2b217142014-12-15 09:24:24 -0800825 assertThat(result, matchesIntent(intent));
Ray Milkey05b169d2015-08-13 14:33:33 -0700826
827 // Test get using numeric value
Jian Li9d616492016-03-09 10:52:49 -0800828 final String responseNumeric = wt.path("intents/" + APP_ID.name()
829 + "/0x0").request().get(String.class);
Jian Li80cfe452016-01-14 16:04:58 -0800830 final JsonObject resultNumeric = Json.parse(responseNumeric).asObject();
Ray Milkey05b169d2015-08-13 14:33:33 -0700831 assertThat(resultNumeric, matchesIntent(intent));
Ray Milkey2b217142014-12-15 09:24:24 -0800832 }
833
834 /**
Author Namee252a002016-09-26 22:42:24 +0530835 * Tests the result of a rest api GET for related flows for single intent.
836 */
837 @Test
838 public void testRelatedFlowsForIntents() {
839 List<FlowEntry> flowEntries = new ArrayList<>();
840 flowEntries.add(flow1);
841 flowEntries.add(flow2);
842 List<List<FlowEntry>> paths = new ArrayList<>();
843 paths.add(flowEntries);
844 List<FlowRule> flowRules = new ArrayList<>();
845 flowRules.add(flowRule1);
846 flowRules.add(flowRule2);
847 FlowRuleIntent flowRuleIntent = new FlowRuleIntent(
848 APP_ID,
849 flowRules,
850 new HashSet<NetworkResource>());
851 Intent intent = new MockIntent(3L);
852 installableIntents.add(flowRuleIntent);
853 intents.add(intent);
854
855 expect(mockIntentService.getIntent(Key.of(0, APP_ID)))
856 .andReturn(intent)
857 .anyTimes();
858 expect(mockIntentService.getIntent(Key.of("0", APP_ID)))
859 .andReturn(intent)
860 .anyTimes();
861 expect(mockIntentService.getIntent(Key.of(0, APP_ID)))
862 .andReturn(intent)
863 .anyTimes();
864 expect(mockIntentService.getIntent(Key.of("0x0", APP_ID)))
865 .andReturn(null)
866 .anyTimes();
867 expect(mockIntentService.getInstallableIntents(intent.key()))
868 .andReturn(installableIntents)
869 .anyTimes();
870 replay(mockIntentService);
871
872 expect(mockFlowService.getFlowEntries(deviceId1))
873 .andReturn(flowEntries).anyTimes();
874 replay(mockFlowService);
875
876 expect(mockCoreService.getAppId(APP_ID.name()))
877 .andReturn(APP_ID).anyTimes();
878 expect(mockCoreService.getAppId(APP_ID.id()))
879 .andReturn(APP_ID).anyTimes();
880 replay(mockCoreService);
881
882 final WebTarget wt = target();
883
884 // Test get using key string
885 final String response = wt.path("intents/relatedflows/" + APP_ID.name()
886 + "/0").request().get(String.class);
887 final JsonObject result = Json.parse(response).asObject();
888 assertThat(result, matchesRelatedFlowEntries(paths, APP_ID.name()));
889
890 // Test get using numeric value
891 final String responseNumeric = wt.path("intents/relatedflows/" + APP_ID.name()
892 + "/0x0").request().get(String.class);
893 final JsonObject resultNumeric = Json.parse(responseNumeric).asObject();
894 assertThat(resultNumeric, matchesRelatedFlowEntries(paths, APP_ID.name()));
895 }
896
897 /**
Ray Milkey2b217142014-12-15 09:24:24 -0800898 * Tests that a fetch of a non-existent intent object throws an exception.
899 */
900 @Test
901 public void testBadGet() {
902
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800903 expect(mockIntentService.getIntent(Key.of(0, APP_ID)))
Ray Milkey2b217142014-12-15 09:24:24 -0800904 .andReturn(null)
905 .anyTimes();
906 replay(mockIntentService);
907
Jian Li9d616492016-03-09 10:52:49 -0800908 WebTarget wt = target();
Ray Milkey2b217142014-12-15 09:24:24 -0800909 try {
Jian Li9d616492016-03-09 10:52:49 -0800910 wt.path("intents/0").request().get(String.class);
Ray Milkey2b217142014-12-15 09:24:24 -0800911 fail("Fetch of non-existent intent did not throw an exception");
Jian Li9d616492016-03-09 10:52:49 -0800912 } catch (NotFoundException ex) {
Ray Milkey2b217142014-12-15 09:24:24 -0800913 assertThat(ex.getMessage(),
Jian Li9d616492016-03-09 10:52:49 -0800914 containsString("HTTP 404 Not Found"));
Ray Milkey2b217142014-12-15 09:24:24 -0800915 }
916 }
Ray Milkeyb82c42b2015-06-30 09:42:20 -0700917
918 /**
919 * Tests creating an intent with POST.
920 */
921 @Test
922 public void testPost() {
Ray Milkeyf7cb4012015-07-20 13:01:07 -0700923 ApplicationId testId = new DefaultApplicationId(2, "myApp");
924 expect(mockCoreService.getAppId("myApp"))
925 .andReturn(testId);
Ray Milkeyb82c42b2015-06-30 09:42:20 -0700926 replay(mockCoreService);
927
928 mockIntentService.submit(anyObject());
929 expectLastCall();
930 replay(mockIntentService);
931
932 InputStream jsonStream = IntentsResourceTest.class
933 .getResourceAsStream("post-intent.json");
Jian Li9d616492016-03-09 10:52:49 -0800934 WebTarget wt = target();
Ray Milkeyb82c42b2015-06-30 09:42:20 -0700935
Jian Li9d616492016-03-09 10:52:49 -0800936 Response response = wt.path("intents")
937 .request(MediaType.APPLICATION_JSON_TYPE)
938 .post(Entity.json(jsonStream));
Ray Milkeyb82c42b2015-06-30 09:42:20 -0700939 assertThat(response.getStatus(), is(HttpURLConnection.HTTP_CREATED));
940 String location = response.getLocation().getPath();
Ray Milkey8d076402015-08-31 15:43:18 -0700941 assertThat(location, Matchers.startsWith("/intents/myApp/"));
Ray Milkeyb82c42b2015-06-30 09:42:20 -0700942 }
Ray Milkey7b158512015-07-21 16:32:43 -0700943
944 /**
Ray Milkey05b169d2015-08-13 14:33:33 -0700945 * Tests creating an intent with POST and illegal JSON.
946 */
947 @Test
948 public void testBadPost() {
949 replay(mockCoreService);
950 replay(mockIntentService);
951
952 String json = "this is invalid!";
Jian Li9d616492016-03-09 10:52:49 -0800953 WebTarget wt = target();
Ray Milkey05b169d2015-08-13 14:33:33 -0700954
Jian Li9d616492016-03-09 10:52:49 -0800955 Response response = wt.path("intents")
956 .request(MediaType.APPLICATION_JSON_TYPE)
957 .post(Entity.json(json));
Ray Milkey05b169d2015-08-13 14:33:33 -0700958 assertThat(response.getStatus(), is(HttpURLConnection.HTTP_BAD_REQUEST));
959 }
960
961 /**
Ray Milkey7b158512015-07-21 16:32:43 -0700962 * Tests removing an intent with DELETE.
963 */
964 @Test
965 public void testRemove() {
966 final HashSet<NetworkResource> resources = new HashSet<>();
967 resources.add(new MockResource(1));
968 resources.add(new MockResource(2));
969 resources.add(new MockResource(3));
970 final Intent intent = new MockIntent(3L, resources);
971 final ApplicationId appId = new DefaultApplicationId(2, "app");
972 IntentService fakeManager = new FakeIntentManager();
973
974 expect(mockCoreService.getAppId("app"))
975 .andReturn(appId).once();
976 replay(mockCoreService);
977
978 mockIntentService.withdraw(anyObject());
979 expectLastCall().andDelegateTo(fakeManager).once();
980 expect(mockIntentService.getIntent(Key.of(2, appId)))
981 .andReturn(intent)
982 .once();
983 expect(mockIntentService.getIntent(Key.of("0x2", appId)))
984 .andReturn(null)
985 .once();
986
987 mockIntentService.addListener(anyObject());
988 expectLastCall().andDelegateTo(fakeManager).once();
989 mockIntentService.removeListener(anyObject());
990 expectLastCall().andDelegateTo(fakeManager).once();
991
992 replay(mockIntentService);
993
Jian Li9d616492016-03-09 10:52:49 -0800994 WebTarget wt = target();
Ray Milkey7b158512015-07-21 16:32:43 -0700995
Jian Li9d616492016-03-09 10:52:49 -0800996 Response response = wt.path("intents/app/0x2")
Ray Milkey7c251822016-04-06 17:38:25 -0700997 .request(MediaType.APPLICATION_JSON, MediaType.TEXT_PLAIN)
Jian Li9d616492016-03-09 10:52:49 -0800998 .delete();
Ray Milkey7b158512015-07-21 16:32:43 -0700999 assertThat(response.getStatus(), is(HttpURLConnection.HTTP_NO_CONTENT));
1000 }
Ray Milkey05b169d2015-08-13 14:33:33 -07001001
1002 /**
1003 * Tests removal of a non existent intent with DELETE.
1004 */
1005 @Test
1006 public void testBadRemove() {
1007 final ApplicationId appId = new DefaultApplicationId(2, "app");
1008
1009 expect(mockCoreService.getAppId("app"))
1010 .andReturn(appId).once();
1011 replay(mockCoreService);
1012
1013 expect(mockIntentService.getIntent(Key.of(2, appId)))
1014 .andReturn(null)
1015 .once();
1016 expect(mockIntentService.getIntent(Key.of("0x2", appId)))
1017 .andReturn(null)
1018 .once();
1019
1020 replay(mockIntentService);
1021
Jian Li9d616492016-03-09 10:52:49 -08001022 WebTarget wt = target();
Ray Milkey05b169d2015-08-13 14:33:33 -07001023
Jian Li9d616492016-03-09 10:52:49 -08001024 Response response = wt.path("intents/app/0x2")
Ray Milkey7c251822016-04-06 17:38:25 -07001025 .request(MediaType.APPLICATION_JSON, MediaType.TEXT_PLAIN)
Jian Li9d616492016-03-09 10:52:49 -08001026 .delete();
Ray Milkey05b169d2015-08-13 14:33:33 -07001027 assertThat(response.getStatus(), is(HttpURLConnection.HTTP_NO_CONTENT));
1028 }
1029
Ray Milkey2b217142014-12-15 09:24:24 -08001030}