blob: 623db9c1ae1b0e46e71f3cc03310edbfb8491a79 [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;
Ray Milkey2b217142014-12-15 09:24:24 -080038import org.onosproject.core.IdGenerator;
Author Namee252a002016-09-26 22:42:24 +053039import org.onosproject.net.DeviceId;
Ray Milkey2b217142014-12-15 09:24:24 -080040import org.onosproject.net.NetworkResource;
Author Namee252a002016-09-26 22:42:24 +053041import org.onosproject.net.flow.DefaultTrafficSelector;
42import org.onosproject.net.flow.DefaultTrafficTreatment;
43import org.onosproject.net.flow.FlowEntry;
44import 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;
Ray Milkey2b217142014-12-15 09:24:24 -080058
Author Namee252a002016-09-26 22:42:24 +053059import javax.ws.rs.NotFoundException;
60import javax.ws.rs.client.Entity;
61import javax.ws.rs.client.WebTarget;
62import javax.ws.rs.core.MediaType;
63import javax.ws.rs.core.Response;
64import java.io.InputStream;
65import java.net.HttpURLConnection;
66import java.util.ArrayList;
67import java.util.Collections;
68import java.util.HashSet;
69import java.util.List;
70import java.util.concurrent.TimeUnit;
Ray Milkey2b217142014-12-15 09:24:24 -080071
Author Namee252a002016-09-26 22:42:24 +053072import static java.util.concurrent.TimeUnit.SECONDS;
73import static org.easymock.EasyMock.*;
74import static org.hamcrest.Matchers.*;
Ray Milkey2b217142014-12-15 09:24:24 -080075import static org.junit.Assert.assertThat;
76import static org.junit.Assert.fail;
Ray Milkey43a28222015-02-23 13:57:58 -080077import static org.onosproject.net.intent.IntentTestsMocks.MockIntent;
Ray Milkey7c251822016-04-06 17:38:25 -070078import static org.onosproject.net.intent.MockIdGenerator.bindNewGenerator;
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 private IdGenerator mockGenerator;
104
Author Namee252a002016-09-26 22:42:24 +0530105 final DeviceId deviceId1 = DeviceId.deviceId("1");
106
107 final TrafficTreatment treatment1 = DefaultTrafficTreatment.builder()
108 .setEthDst(MacAddress.BROADCAST)
109 .build();
110 final TrafficTreatment treatment2 = DefaultTrafficTreatment.builder()
111 .setEthDst(MacAddress.IPV4_MULTICAST)
112 .build();
113
114 final TrafficSelector selector1 = DefaultTrafficSelector.builder()
115 .matchEthType((short) 3)
116 .matchIPProtocol((byte) 9)
117 .build();
118 final TrafficSelector selector2 = DefaultTrafficSelector.builder()
119 .matchEthType((short) 4)
120 .matchIPProtocol((byte) 10)
121 .build();
122
123 final MockFlowEntry flow1 = new MockFlowEntry(deviceId1, 1, treatment1, selector1);
124 final MockFlowEntry flow2 = new MockFlowEntry(deviceId1, 2, treatment2, selector2);
125
126 final MockFlowRule flowRule1 = new MockFlowRule(deviceId1, 1, treatment1, selector1);
127 final MockFlowRule flowRule2 = new MockFlowRule(deviceId1, 2, treatment2, selector2);
128
Ray Milkey2b217142014-12-15 09:24:24 -0800129 private class MockResource implements NetworkResource {
130 int id;
131
132 MockResource(int id) {
133 this.id = id;
134 }
135
Ayaka Koshibec06c89b2015-02-10 19:25:41 -0800136 @Override
Ray Milkey2b217142014-12-15 09:24:24 -0800137 public String toString() {
138 return "Resource " + Integer.toString(id);
139 }
140 }
141
Ray Milkey2b217142014-12-15 09:24:24 -0800142 /**
Author Namee252a002016-09-26 22:42:24 +0530143 * Mock class for a flow entry.
144 */
145 private static class MockFlowEntry implements FlowEntry {
146 final DeviceId deviceId;
147 final long baseValue;
148 TrafficTreatment treatment;
149 TrafficSelector selector;
150
151 public MockFlowEntry(DeviceId deviceId, long id,
152 TrafficTreatment treatment,
153 TrafficSelector selector) {
154 this.deviceId = deviceId;
155 this.baseValue = id * 100;
156 this.treatment = treatment;
157 this.selector = selector;
158 }
159
160 @Override
161 public FlowEntryState state() {
162 return FlowEntryState.ADDED;
163 }
164
165 @Override
166 public long life() {
167 return life(SECONDS);
168 }
169
170 @Override
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900171 public FlowLiveType liveType() {
172 return null;
173 }
174
175 @Override
Author Namee252a002016-09-26 22:42:24 +0530176 public long life(TimeUnit timeUnit) {
177 return SECONDS.convert(baseValue + 11, timeUnit);
178 }
179
180 @Override
181 public long packets() {
182 return baseValue + 22;
183 }
184
185 @Override
186 public long bytes() {
187 return baseValue + 33;
188 }
189
190 @Override
191 public long lastSeen() {
192 return baseValue + 44;
193 }
194
195 @Override
196 public int errType() {
197 return 0;
198 }
199
200 @Override
201 public int errCode() {
202 return 0;
203 }
204
205 @Override
206 public FlowId id() {
207 final long id = baseValue + 55;
208 return FlowId.valueOf(id);
209 }
210
211 @Override
212 public GroupId groupId() {
Yi Tsengfa394de2017-02-01 11:26:40 -0800213 return new GroupId(3);
Author Namee252a002016-09-26 22:42:24 +0530214 }
215
216 @Override
217 public short appId() {
218 return 1;
219 }
220
221 @Override
222 public int priority() {
223 return (int) (baseValue + 66);
224 }
225
226 @Override
227 public DeviceId deviceId() {
228 return deviceId;
229 }
230
231 @Override
232 public TrafficSelector selector() {
233 return selector;
234 }
235
236 @Override
237 public TrafficTreatment treatment() {
238 return treatment;
239 }
240
241 @Override
242 public int timeout() {
243 return (int) (baseValue + 77);
244 }
245
246 @Override
247 public int hardTimeout() {
248 return 0;
249 }
250
251 @Override
252 public FlowRule.FlowRemoveReason reason() {
253 return FlowRule.FlowRemoveReason.NO_REASON;
254 }
255
256 @Override
257 public boolean isPermanent() {
258 return false;
259 }
260
261 @Override
262 public int tableId() {
263 return 0;
264 }
265
266 @Override
267 public boolean exactMatch(FlowRule rule) {
268 return this.appId() == rule.appId() &&
269 this.deviceId().equals(rule.deviceId()) &&
270 this.id().equals(rule.id()) &&
271 this.treatment.equals(rule.treatment()) &&
272 this.selector().equals(rule.selector());
273 }
274
275 @Override
276 public FlowRuleExtPayLoad payLoad() {
277 return null;
278 }
279
280 @Override
281 public String toString() {
282 return id().id().toString();
283 }
284 }
285
286 /**
287 * Mock class for a flow rule.
288 */
289 private static class MockFlowRule implements FlowRule {
290
291 final DeviceId deviceId;
292 final long baseValue;
293 TrafficTreatment treatment;
294 TrafficSelector selector;
295
296 public MockFlowRule(DeviceId deviceId,
297 long id,
298 TrafficTreatment treatment,
299 TrafficSelector selector) {
300 this.deviceId = deviceId;
301 this.baseValue = id * 100;
302 this.treatment = treatment;
303 this.selector = selector;
304 }
305
306 @Override
307 public FlowId id() {
308 long id = baseValue + 55;
309 return FlowId.valueOf(id);
310 }
311
312 @Override
313 public short appId() {
314 return 1;
315 }
316
317 @Override
318 public GroupId groupId() {
Yi Tsengfa394de2017-02-01 11:26:40 -0800319 return new GroupId(3);
Author Namee252a002016-09-26 22:42:24 +0530320 }
321
322 @Override
323 public int priority() {
324 return 0;
325 }
326
327 @Override
328 public DeviceId deviceId() {
329 return deviceId;
330 }
331
332 @Override
333 public TrafficSelector selector() {
334 return selector;
335 }
336
337 @Override
338 public TrafficTreatment treatment() {
339 return treatment;
340 }
341
342 @Override
343 public int timeout() {
344 return (int) (baseValue + 77);
345 }
346
347 @Override
348 public int hardTimeout() {
349 return 0;
350 }
351
352 @Override
353 public FlowRemoveReason reason() {
354 return FlowRemoveReason.NO_REASON;
355 }
356
357 @Override
358 public boolean isPermanent() {
359 return false;
360 }
361
362 @Override
363 public int tableId() {
364 return 0;
365 }
366
367 @Override
368 public boolean exactMatch(FlowRule rule) {
369 return false;
370 }
371
372 @Override
373 public FlowRuleExtPayLoad payLoad() {
374 return null;
375 }
376 }
377
378 /**
Ray Milkey2b217142014-12-15 09:24:24 -0800379 * Hamcrest matcher to check that an intent representation in JSON matches
380 * the actual intent.
381 */
382 public static class IntentJsonMatcher extends TypeSafeMatcher<JsonObject> {
383 private final Intent intent;
384 private String reason = "";
385
386 public IntentJsonMatcher(Intent intentValue) {
387 intent = intentValue;
388 }
389
390 @Override
391 public boolean matchesSafely(JsonObject jsonIntent) {
392 // check id
393 final String jsonId = jsonIntent.get("id").asString();
394 if (!jsonId.equals(intent.id().toString())) {
395 reason = "id " + intent.id().toString();
396 return false;
397 }
398
399 // check application id
Ray Milkeyf7cb4012015-07-20 13:01:07 -0700400
Ray Milkey2b217142014-12-15 09:24:24 -0800401 final String jsonAppId = jsonIntent.get("appId").asString();
Ray Milkeyf7cb4012015-07-20 13:01:07 -0700402 final String appId = intent.appId().name();
403 if (!jsonAppId.equals(appId)) {
404 reason = "appId was " + jsonAppId;
Ray Milkey2b217142014-12-15 09:24:24 -0800405 return false;
406 }
407
408 // check intent type
409 final String jsonType = jsonIntent.get("type").asString();
410 if (!jsonType.equals("MockIntent")) {
411 reason = "type MockIntent";
412 return false;
413 }
414
Ray Milkey1534f8d2015-05-13 15:42:50 -0700415 // check state field
416 final String jsonState = jsonIntent.get("state").asString();
417 if (!jsonState.equals("INSTALLED")) {
418 reason = "state INSTALLED";
419 return false;
420 }
421
Ray Milkey2b217142014-12-15 09:24:24 -0800422 // check resources array
423 final JsonArray jsonResources = jsonIntent.get("resources").asArray();
424 if (intent.resources() != null) {
425 if (intent.resources().size() != jsonResources.size()) {
426 reason = "resources array size of " + Integer.toString(intent.resources().size());
427 return false;
428 }
429 for (final NetworkResource resource : intent.resources()) {
430 boolean resourceFound = false;
431 final String resourceString = resource.toString();
432 for (int resourceIndex = 0; resourceIndex < jsonResources.size(); resourceIndex++) {
433 final JsonValue value = jsonResources.get(resourceIndex);
434 if (value.asString().equals(resourceString)) {
435 resourceFound = true;
436 }
437 }
438 if (!resourceFound) {
439 reason = "resource " + resourceString;
440 return false;
441 }
442 }
443 } else if (jsonResources.size() != 0) {
444 reason = "resources array empty";
445 return false;
446 }
447 return true;
448 }
449
450 @Override
451 public void describeTo(Description description) {
452 description.appendText(reason);
453 }
454 }
455
456 /**
457 * Factory to allocate an intent matcher.
458 *
459 * @param intent intent object we are looking for
460 * @return matcher
461 */
462 private static IntentJsonMatcher matchesIntent(Intent intent) {
463 return new IntentJsonMatcher(intent);
464 }
465
466 /**
Author Namee252a002016-09-26 22:42:24 +0530467 * Factory to allocate an IntentRelatedFlows matcher.
468 *
469 * @param pathEntries list of path conatining flow entries of a particular intent
470 * @param expectedAppId expected app id we are looking for
471 * @return matcher
472 */
473 private static IntentStatsJsonMatcher matchesRelatedFlowEntries(
474 List<List<FlowEntry>> pathEntries,
475 final String expectedAppId) {
476 return new IntentStatsJsonMatcher(pathEntries, expectedAppId);
477 }
478
479 /**
480 * Hamcrest matcher to check that an list of flowEntries in JSON matches
481 * the actual list of flow entries.
482 */
483 public static class IntentStatsJsonMatcher extends
484 TypeSafeMatcher<JsonObject> {
485
486 private final List<List<FlowEntry>> pathEntries;
487 private final String expectedAppId;
488 private String reason = "";
489
490 public IntentStatsJsonMatcher(
491 final List<List<FlowEntry>> pathEntries,
492 final String expectedAppId) {
493 this.pathEntries = pathEntries;
494 this.expectedAppId = expectedAppId;
495 }
496
497 @Override
498 public boolean matchesSafely(JsonObject jsonIntent) {
499 int jsonPathIndex = 0;
500 JsonArray jsonPaths = jsonIntent.get(PATHS).asArray();
501
502 if (pathEntries != null) {
503
rohitsharanfd747602017-01-23 21:57:28 +0530504 if (pathEntries.size() == 0) {
505 reason = "pathEntries array empty";
506 return false;
507 }
508
Author Namee252a002016-09-26 22:42:24 +0530509 if (pathEntries.size() != jsonPaths.size()) {
510 reason = "path entries array size of " +
511 Integer.toString(pathEntries.size());
512 return false;
513 }
514
515 for (List<FlowEntry> flowEntries : pathEntries) {
516 JsonArray jsonFlowEntries = jsonPaths.get(
517 jsonPathIndex++).asArray();
518
519 if (flowEntries.size() != jsonFlowEntries.size()) {
520 reason = "flow entries array size of " +
521 Integer.toString(pathEntries.size());
522
523 return false;
524 }
525
526 int jsonFlowEntryIndex = 0;
527 for (FlowEntry flow : flowEntries) {
528
529 JsonObject jsonFlow = jsonFlowEntries.get(
530 jsonFlowEntryIndex++).asObject();
531
532 String jsonId = jsonFlow.get(ID).asString();
533 String flowId = Long.toString(flow.id().value());
534 if (!jsonId.equals(flowId)) {
535 reason = ID + SPACE + flow.id();
536 return false;
537 }
538
539 // check application id
540 String jsonAppId = jsonFlow.get(APPID).asString();
541 if (!jsonAppId.equals(expectedAppId)) {
542 reason = APPID + SPACE + Short.toString(flow.appId());
543 return false;
544 }
545
546 // check device id
547 String jsonDeviceId =
548 jsonFlow.get(DEVICE_ID).asString();
549
550 if (!jsonDeviceId.equals(flow.deviceId().toString())) {
551 reason = DEVICE_ID + SPACE + flow.deviceId();
552 return false;
553 }
554
555 if (!checkFlowTreatment(flow, jsonFlow)) {
556 return false;
557 }
558
559 if (!checkFlowSelector(flow, jsonFlow)) {
560 return false;
561 }
562
563 }
564
565 }
rohitsharanfd747602017-01-23 21:57:28 +0530566 } else {
Author Namee252a002016-09-26 22:42:24 +0530567 reason = "pathEntries array empty";
568 return false;
569 }
570
571 return true;
572 }
573
574 // check treatment and instructions array.
575 private boolean checkFlowTreatment(FlowEntry flow, JsonObject jsonFlow) {
576
577 if (flow.treatment() != null) {
578 JsonObject jsonTreatment =
579 jsonFlow.get(TREATMENT).asObject();
580 JsonArray jsonInstructions =
581 jsonTreatment.get(INSTRUCTIONS).asArray();
582
583 if (flow.treatment().immediate().size() !=
584 jsonInstructions.size()) {
585 reason = "instructions array size of " +
586 flow.treatment().immediate().size();
587
588 return false;
589 }
590 for (Instruction instruction :
591 flow.treatment().immediate()) {
592 boolean instructionFound = false;
593 for (int instructionIndex = 0;
594 instructionIndex < jsonInstructions.size();
595 instructionIndex++) {
596 String jsonType =
597 jsonInstructions.get(instructionIndex)
598 .asObject().get(TYPE).asString();
599
600 String instructionType =
601 instruction.type().name();
602
603 if (jsonType.equals(instructionType)) {
604 instructionFound = true;
605 }
606 }
607 if (!instructionFound) {
608 reason = INSTRUCTIONS + SPACE + instruction;
609 return false;
610 }
611 }
612 }
613 return true;
614 }
615
616 // check selector and criteria array.
617 private boolean checkFlowSelector(FlowEntry flow, JsonObject jsonFlow) {
618
619 if (flow.selector() != null) {
620 JsonObject jsonTreatment =
621 jsonFlow.get(SELECTOR).asObject();
622
623 JsonArray jsonCriteria =
624 jsonTreatment.get(CRITERIA).asArray();
625
626 if (flow.selector().criteria().size() != jsonCriteria.size()) {
627 reason = CRITERIA + " array size of " +
628 Integer.toString(flow.selector().criteria().size());
629 return false;
630 }
631 for (Criterion criterion : flow.selector().criteria()) {
632 boolean criterionFound = false;
633
634 for (int criterionIndex = 0;
635 criterionIndex < jsonCriteria.size();
636 criterionIndex++) {
637 String jsonType =
638 jsonCriteria.get(criterionIndex)
639 .asObject().get(TYPE).asString();
640 String criterionType = criterion.type().name();
641 if (jsonType.equals(criterionType)) {
642 criterionFound = true;
643 }
644 }
645 if (!criterionFound) {
646 reason = "criterion " + criterion;
647 return false;
648 }
649 }
650 }
651 return true;
652 }
653
654 @Override
655 public void describeTo(Description description) {
656 description.appendText(reason);
657 }
658 }
659
660 /**
Ray Milkey2b217142014-12-15 09:24:24 -0800661 * Hamcrest matcher to check that an intent is represented properly in a JSON
662 * array of intents.
663 */
664 public static class IntentJsonArrayMatcher extends TypeSafeMatcher<JsonArray> {
665 private final Intent intent;
666 private String reason = "";
667
668 public IntentJsonArrayMatcher(Intent intentValue) {
669 intent = intentValue;
670 }
671
672 @Override
673 public boolean matchesSafely(JsonArray json) {
674 boolean intentFound = false;
Ray Milkeyf7cb4012015-07-20 13:01:07 -0700675 final int expectedAttributes = 5;
Ray Milkey2b217142014-12-15 09:24:24 -0800676 for (int jsonIntentIndex = 0; jsonIntentIndex < json.size();
677 jsonIntentIndex++) {
678
679 final JsonObject jsonIntent = json.get(jsonIntentIndex).asObject();
680
681 if (jsonIntent.names().size() != expectedAttributes) {
682 reason = "Found an intent with the wrong number of attributes";
683 return false;
684 }
685
686 final String jsonIntentId = jsonIntent.get("id").asString();
687 if (jsonIntentId.equals(intent.id().toString())) {
688 intentFound = true;
689
690 // We found the correct intent, check attribute values
691 assertThat(jsonIntent, matchesIntent(intent));
692 }
693 }
694 if (!intentFound) {
695 reason = "Intent with id " + intent.id().toString() + " not found";
696 return false;
697 } else {
698 return true;
699 }
700 }
701
702 @Override
703 public void describeTo(Description description) {
704 description.appendText(reason);
705 }
706 }
707
708 /**
709 * Factory to allocate an intent array matcher.
710 *
711 * @param intent intent object we are looking for
712 * @return matcher
713 */
714 private static IntentJsonArrayMatcher hasIntent(Intent intent) {
715 return new IntentJsonArrayMatcher(intent);
716 }
Ray Milkey4f5de002014-12-17 19:26:11 -0800717
Ray Milkeyed0b1662015-02-05 09:34:29 -0800718 /**
719 * Initializes test mocks and environment.
720 */
Ray Milkey2b217142014-12-15 09:24:24 -0800721 @Before
Ray Milkeyed0b1662015-02-05 09:34:29 -0800722 public void setUpTest() {
Ray Milkey2b217142014-12-15 09:24:24 -0800723 expect(mockIntentService.getIntents()).andReturn(intents).anyTimes();
Ray Milkey1534f8d2015-05-13 15:42:50 -0700724 expect(mockIntentService.getIntentState(anyObject()))
725 .andReturn(IntentState.INSTALLED)
726 .anyTimes();
Ray Milkey2b217142014-12-15 09:24:24 -0800727 // Register the services needed for the test
728 final CodecManager codecService = new CodecManager();
729 codecService.activate();
730 ServiceDirectory testDirectory =
731 new TestServiceDirectory()
732 .add(IntentService.class, mockIntentService)
Author Namee252a002016-09-26 22:42:24 +0530733 .add(FlowRuleService.class, mockFlowService)
Ayaka Koshibec06c89b2015-02-10 19:25:41 -0800734 .add(CodecService.class, codecService)
735 .add(CoreService.class, mockCoreService);
Ray Milkey2b217142014-12-15 09:24:24 -0800736
737 BaseResource.setServiceDirectory(testDirectory);
738
Ray Milkey7c251822016-04-06 17:38:25 -0700739 bindNewGenerator();
Ray Milkey2b217142014-12-15 09:24:24 -0800740 }
741
Ray Milkeyed0b1662015-02-05 09:34:29 -0800742 /**
743 * Tears down and verifies test mocks and environment.
744 */
Ray Milkey2b217142014-12-15 09:24:24 -0800745 @After
Ray Milkeyed0b1662015-02-05 09:34:29 -0800746 public void tearDownTest() {
Ray Milkey2b217142014-12-15 09:24:24 -0800747 verify(mockIntentService);
Ray Milkey2b217142014-12-15 09:24:24 -0800748 }
749
750 /**
751 * Tests the result of the rest api GET when there are no intents.
752 */
753 @Test
754 public void testIntentsEmptyArray() {
755 replay(mockIntentService);
Jian Li9d616492016-03-09 10:52:49 -0800756 final WebTarget wt = target();
757 final String response = wt.path("intents").request().get(String.class);
Ray Milkey2b217142014-12-15 09:24:24 -0800758 assertThat(response, is("{\"intents\":[]}"));
759 }
760
761 /**
762 * Tests the result of the rest api GET when intents are defined.
763 */
764 @Test
765 public void testIntentsArray() {
766 replay(mockIntentService);
767
Ray Milkey43a28222015-02-23 13:57:58 -0800768 final Intent intent1 = new MockIntent(1L, Collections.emptyList());
Ray Milkey2b217142014-12-15 09:24:24 -0800769 final HashSet<NetworkResource> resources = new HashSet<>();
770 resources.add(new MockResource(1));
771 resources.add(new MockResource(2));
772 resources.add(new MockResource(3));
Ray Milkey43a28222015-02-23 13:57:58 -0800773 final Intent intent2 = new MockIntent(2L, resources);
Ray Milkey2b217142014-12-15 09:24:24 -0800774
775 intents.add(intent1);
776 intents.add(intent2);
Jian Li9d616492016-03-09 10:52:49 -0800777 final WebTarget wt = target();
778 final String response = wt.path("intents").request().get(String.class);
Ray Milkey2b217142014-12-15 09:24:24 -0800779 assertThat(response, containsString("{\"intents\":["));
780
Jian Li80cfe452016-01-14 16:04:58 -0800781 final JsonObject result = Json.parse(response).asObject();
Ray Milkey2b217142014-12-15 09:24:24 -0800782 assertThat(result, notNullValue());
783
784 assertThat(result.names(), hasSize(1));
785 assertThat(result.names().get(0), is("intents"));
786
787 final JsonArray jsonIntents = result.get("intents").asArray();
788 assertThat(jsonIntents, notNullValue());
789
790 assertThat(jsonIntents, hasIntent(intent1));
791 assertThat(jsonIntents, hasIntent(intent2));
792 }
793
794 /**
795 * Tests the result of a rest api GET for a single intent.
796 */
797 @Test
798 public void testIntentsSingle() {
799 final HashSet<NetworkResource> resources = new HashSet<>();
800 resources.add(new MockResource(1));
801 resources.add(new MockResource(2));
802 resources.add(new MockResource(3));
Ray Milkey43a28222015-02-23 13:57:58 -0800803 final Intent intent = new MockIntent(3L, resources);
Ray Milkey2b217142014-12-15 09:24:24 -0800804
805 intents.add(intent);
806
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800807 expect(mockIntentService.getIntent(Key.of(0, APP_ID)))
Ray Milkey2b217142014-12-15 09:24:24 -0800808 .andReturn(intent)
809 .anyTimes();
Ayaka Koshibec06c89b2015-02-10 19:25:41 -0800810 expect(mockIntentService.getIntent(Key.of("0", APP_ID)))
811 .andReturn(intent)
812 .anyTimes();
Ray Milkey05b169d2015-08-13 14:33:33 -0700813 expect(mockIntentService.getIntent(Key.of(0, APP_ID)))
814 .andReturn(intent)
815 .anyTimes();
816 expect(mockIntentService.getIntent(Key.of("0x0", APP_ID)))
817 .andReturn(null)
818 .anyTimes();
Ray Milkey2b217142014-12-15 09:24:24 -0800819 replay(mockIntentService);
Ray Milkeyf7cb4012015-07-20 13:01:07 -0700820 expect(mockCoreService.getAppId(APP_ID.name()))
Ayaka Koshibec06c89b2015-02-10 19:25:41 -0800821 .andReturn(APP_ID).anyTimes();
822 replay(mockCoreService);
Jian Li9d616492016-03-09 10:52:49 -0800823 final WebTarget wt = target();
Ray Milkey05b169d2015-08-13 14:33:33 -0700824
825 // Test get using key string
Jian Li9d616492016-03-09 10:52:49 -0800826 final String response = wt.path("intents/" + APP_ID.name()
827 + "/0").request().get(String.class);
Jian Li80cfe452016-01-14 16:04:58 -0800828 final JsonObject result = Json.parse(response).asObject();
Ray Milkey2b217142014-12-15 09:24:24 -0800829 assertThat(result, matchesIntent(intent));
Ray Milkey05b169d2015-08-13 14:33:33 -0700830
831 // Test get using numeric value
Jian Li9d616492016-03-09 10:52:49 -0800832 final String responseNumeric = wt.path("intents/" + APP_ID.name()
833 + "/0x0").request().get(String.class);
Jian Li80cfe452016-01-14 16:04:58 -0800834 final JsonObject resultNumeric = Json.parse(responseNumeric).asObject();
Ray Milkey05b169d2015-08-13 14:33:33 -0700835 assertThat(resultNumeric, matchesIntent(intent));
Ray Milkey2b217142014-12-15 09:24:24 -0800836 }
837
838 /**
Author Namee252a002016-09-26 22:42:24 +0530839 * Tests the result of a rest api GET for related flows for single intent.
840 */
841 @Test
842 public void testRelatedFlowsForIntents() {
843 List<FlowEntry> flowEntries = new ArrayList<>();
844 flowEntries.add(flow1);
845 flowEntries.add(flow2);
846 List<List<FlowEntry>> paths = new ArrayList<>();
847 paths.add(flowEntries);
848 List<FlowRule> flowRules = new ArrayList<>();
849 flowRules.add(flowRule1);
850 flowRules.add(flowRule2);
851 FlowRuleIntent flowRuleIntent = new FlowRuleIntent(
852 APP_ID,
853 flowRules,
854 new HashSet<NetworkResource>());
855 Intent intent = new MockIntent(3L);
856 installableIntents.add(flowRuleIntent);
857 intents.add(intent);
858
859 expect(mockIntentService.getIntent(Key.of(0, APP_ID)))
860 .andReturn(intent)
861 .anyTimes();
862 expect(mockIntentService.getIntent(Key.of("0", APP_ID)))
863 .andReturn(intent)
864 .anyTimes();
865 expect(mockIntentService.getIntent(Key.of(0, APP_ID)))
866 .andReturn(intent)
867 .anyTimes();
868 expect(mockIntentService.getIntent(Key.of("0x0", APP_ID)))
869 .andReturn(null)
870 .anyTimes();
871 expect(mockIntentService.getInstallableIntents(intent.key()))
872 .andReturn(installableIntents)
873 .anyTimes();
874 replay(mockIntentService);
875
876 expect(mockFlowService.getFlowEntries(deviceId1))
877 .andReturn(flowEntries).anyTimes();
878 replay(mockFlowService);
879
880 expect(mockCoreService.getAppId(APP_ID.name()))
881 .andReturn(APP_ID).anyTimes();
882 expect(mockCoreService.getAppId(APP_ID.id()))
883 .andReturn(APP_ID).anyTimes();
884 replay(mockCoreService);
885
886 final WebTarget wt = target();
887
888 // Test get using key string
889 final String response = wt.path("intents/relatedflows/" + APP_ID.name()
890 + "/0").request().get(String.class);
891 final JsonObject result = Json.parse(response).asObject();
892 assertThat(result, matchesRelatedFlowEntries(paths, APP_ID.name()));
893
894 // Test get using numeric value
895 final String responseNumeric = wt.path("intents/relatedflows/" + APP_ID.name()
896 + "/0x0").request().get(String.class);
897 final JsonObject resultNumeric = Json.parse(responseNumeric).asObject();
898 assertThat(resultNumeric, matchesRelatedFlowEntries(paths, APP_ID.name()));
899 }
900
901 /**
Ray Milkey2b217142014-12-15 09:24:24 -0800902 * Tests that a fetch of a non-existent intent object throws an exception.
903 */
904 @Test
905 public void testBadGet() {
906
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800907 expect(mockIntentService.getIntent(Key.of(0, APP_ID)))
Ray Milkey2b217142014-12-15 09:24:24 -0800908 .andReturn(null)
909 .anyTimes();
910 replay(mockIntentService);
911
Jian Li9d616492016-03-09 10:52:49 -0800912 WebTarget wt = target();
Ray Milkey2b217142014-12-15 09:24:24 -0800913 try {
Jian Li9d616492016-03-09 10:52:49 -0800914 wt.path("intents/0").request().get(String.class);
Ray Milkey2b217142014-12-15 09:24:24 -0800915 fail("Fetch of non-existent intent did not throw an exception");
Jian Li9d616492016-03-09 10:52:49 -0800916 } catch (NotFoundException ex) {
Ray Milkey2b217142014-12-15 09:24:24 -0800917 assertThat(ex.getMessage(),
Jian Li9d616492016-03-09 10:52:49 -0800918 containsString("HTTP 404 Not Found"));
Ray Milkey2b217142014-12-15 09:24:24 -0800919 }
920 }
Ray Milkeyb82c42b2015-06-30 09:42:20 -0700921
922 /**
923 * Tests creating an intent with POST.
924 */
925 @Test
926 public void testPost() {
Ray Milkeyf7cb4012015-07-20 13:01:07 -0700927 ApplicationId testId = new DefaultApplicationId(2, "myApp");
928 expect(mockCoreService.getAppId("myApp"))
929 .andReturn(testId);
Ray Milkeyb82c42b2015-06-30 09:42:20 -0700930 replay(mockCoreService);
931
932 mockIntentService.submit(anyObject());
933 expectLastCall();
934 replay(mockIntentService);
935
936 InputStream jsonStream = IntentsResourceTest.class
937 .getResourceAsStream("post-intent.json");
Jian Li9d616492016-03-09 10:52:49 -0800938 WebTarget wt = target();
Ray Milkeyb82c42b2015-06-30 09:42:20 -0700939
Jian Li9d616492016-03-09 10:52:49 -0800940 Response response = wt.path("intents")
941 .request(MediaType.APPLICATION_JSON_TYPE)
942 .post(Entity.json(jsonStream));
Ray Milkeyb82c42b2015-06-30 09:42:20 -0700943 assertThat(response.getStatus(), is(HttpURLConnection.HTTP_CREATED));
944 String location = response.getLocation().getPath();
Ray Milkey8d076402015-08-31 15:43:18 -0700945 assertThat(location, Matchers.startsWith("/intents/myApp/"));
Ray Milkeyb82c42b2015-06-30 09:42:20 -0700946 }
Ray Milkey7b158512015-07-21 16:32:43 -0700947
948 /**
Ray Milkey05b169d2015-08-13 14:33:33 -0700949 * Tests creating an intent with POST and illegal JSON.
950 */
951 @Test
952 public void testBadPost() {
953 replay(mockCoreService);
954 replay(mockIntentService);
955
956 String json = "this is invalid!";
Jian Li9d616492016-03-09 10:52:49 -0800957 WebTarget wt = target();
Ray Milkey05b169d2015-08-13 14:33:33 -0700958
Jian Li9d616492016-03-09 10:52:49 -0800959 Response response = wt.path("intents")
960 .request(MediaType.APPLICATION_JSON_TYPE)
961 .post(Entity.json(json));
Ray Milkey05b169d2015-08-13 14:33:33 -0700962 assertThat(response.getStatus(), is(HttpURLConnection.HTTP_BAD_REQUEST));
963 }
964
965 /**
Ray Milkey7b158512015-07-21 16:32:43 -0700966 * Tests removing an intent with DELETE.
967 */
968 @Test
969 public void testRemove() {
970 final HashSet<NetworkResource> resources = new HashSet<>();
971 resources.add(new MockResource(1));
972 resources.add(new MockResource(2));
973 resources.add(new MockResource(3));
974 final Intent intent = new MockIntent(3L, resources);
975 final ApplicationId appId = new DefaultApplicationId(2, "app");
976 IntentService fakeManager = new FakeIntentManager();
977
978 expect(mockCoreService.getAppId("app"))
979 .andReturn(appId).once();
980 replay(mockCoreService);
981
982 mockIntentService.withdraw(anyObject());
983 expectLastCall().andDelegateTo(fakeManager).once();
984 expect(mockIntentService.getIntent(Key.of(2, appId)))
985 .andReturn(intent)
986 .once();
987 expect(mockIntentService.getIntent(Key.of("0x2", appId)))
988 .andReturn(null)
989 .once();
990
991 mockIntentService.addListener(anyObject());
992 expectLastCall().andDelegateTo(fakeManager).once();
993 mockIntentService.removeListener(anyObject());
994 expectLastCall().andDelegateTo(fakeManager).once();
995
996 replay(mockIntentService);
997
Jian Li9d616492016-03-09 10:52:49 -0800998 WebTarget wt = target();
Ray Milkey7b158512015-07-21 16:32:43 -0700999
Jian Li9d616492016-03-09 10:52:49 -08001000 Response response = wt.path("intents/app/0x2")
Ray Milkey7c251822016-04-06 17:38:25 -07001001 .request(MediaType.APPLICATION_JSON, MediaType.TEXT_PLAIN)
Jian Li9d616492016-03-09 10:52:49 -08001002 .delete();
Ray Milkey7b158512015-07-21 16:32:43 -07001003 assertThat(response.getStatus(), is(HttpURLConnection.HTTP_NO_CONTENT));
1004 }
Ray Milkey05b169d2015-08-13 14:33:33 -07001005
1006 /**
1007 * Tests removal of a non existent intent with DELETE.
1008 */
1009 @Test
1010 public void testBadRemove() {
1011 final ApplicationId appId = new DefaultApplicationId(2, "app");
1012
1013 expect(mockCoreService.getAppId("app"))
1014 .andReturn(appId).once();
1015 replay(mockCoreService);
1016
1017 expect(mockIntentService.getIntent(Key.of(2, appId)))
1018 .andReturn(null)
1019 .once();
1020 expect(mockIntentService.getIntent(Key.of("0x2", appId)))
1021 .andReturn(null)
1022 .once();
1023
1024 replay(mockIntentService);
1025
Jian Li9d616492016-03-09 10:52:49 -08001026 WebTarget wt = target();
Ray Milkey05b169d2015-08-13 14:33:33 -07001027
Jian Li9d616492016-03-09 10:52:49 -08001028 Response response = wt.path("intents/app/0x2")
Ray Milkey7c251822016-04-06 17:38:25 -07001029 .request(MediaType.APPLICATION_JSON, MediaType.TEXT_PLAIN)
Jian Li9d616492016-03-09 10:52:49 -08001030 .delete();
Ray Milkey05b169d2015-08-13 14:33:33 -07001031 assertThat(response.getStatus(), is(HttpURLConnection.HTTP_NO_CONTENT));
1032 }
1033
Ray Milkey2b217142014-12-15 09:24:24 -08001034}