blob: da603cd9810d20d19a45d1f09332304ef76e11ae [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
rohitsharanfd747602017-01-23 21:57:28 +0530505 if (pathEntries.size() == 0) {
506 reason = "pathEntries array empty";
507 return false;
508 }
509
Author Namee252a002016-09-26 22:42:24 +0530510 if (pathEntries.size() != jsonPaths.size()) {
511 reason = "path entries array size of " +
512 Integer.toString(pathEntries.size());
513 return false;
514 }
515
516 for (List<FlowEntry> flowEntries : pathEntries) {
517 JsonArray jsonFlowEntries = jsonPaths.get(
518 jsonPathIndex++).asArray();
519
520 if (flowEntries.size() != jsonFlowEntries.size()) {
521 reason = "flow entries array size of " +
522 Integer.toString(pathEntries.size());
523
524 return false;
525 }
526
527 int jsonFlowEntryIndex = 0;
528 for (FlowEntry flow : flowEntries) {
529
530 JsonObject jsonFlow = jsonFlowEntries.get(
531 jsonFlowEntryIndex++).asObject();
532
533 String jsonId = jsonFlow.get(ID).asString();
534 String flowId = Long.toString(flow.id().value());
535 if (!jsonId.equals(flowId)) {
536 reason = ID + SPACE + flow.id();
537 return false;
538 }
539
540 // check application id
541 String jsonAppId = jsonFlow.get(APPID).asString();
542 if (!jsonAppId.equals(expectedAppId)) {
543 reason = APPID + SPACE + Short.toString(flow.appId());
544 return false;
545 }
546
547 // check device id
548 String jsonDeviceId =
549 jsonFlow.get(DEVICE_ID).asString();
550
551 if (!jsonDeviceId.equals(flow.deviceId().toString())) {
552 reason = DEVICE_ID + SPACE + flow.deviceId();
553 return false;
554 }
555
556 if (!checkFlowTreatment(flow, jsonFlow)) {
557 return false;
558 }
559
560 if (!checkFlowSelector(flow, jsonFlow)) {
561 return false;
562 }
563
564 }
565
566 }
rohitsharanfd747602017-01-23 21:57:28 +0530567 } else {
Author Namee252a002016-09-26 22:42:24 +0530568 reason = "pathEntries array empty";
569 return false;
570 }
571
572 return true;
573 }
574
575 // check treatment and instructions array.
576 private boolean checkFlowTreatment(FlowEntry flow, JsonObject jsonFlow) {
577
578 if (flow.treatment() != null) {
579 JsonObject jsonTreatment =
580 jsonFlow.get(TREATMENT).asObject();
581 JsonArray jsonInstructions =
582 jsonTreatment.get(INSTRUCTIONS).asArray();
583
584 if (flow.treatment().immediate().size() !=
585 jsonInstructions.size()) {
586 reason = "instructions array size of " +
587 flow.treatment().immediate().size();
588
589 return false;
590 }
591 for (Instruction instruction :
592 flow.treatment().immediate()) {
593 boolean instructionFound = false;
594 for (int instructionIndex = 0;
595 instructionIndex < jsonInstructions.size();
596 instructionIndex++) {
597 String jsonType =
598 jsonInstructions.get(instructionIndex)
599 .asObject().get(TYPE).asString();
600
601 String instructionType =
602 instruction.type().name();
603
604 if (jsonType.equals(instructionType)) {
605 instructionFound = true;
606 }
607 }
608 if (!instructionFound) {
609 reason = INSTRUCTIONS + SPACE + instruction;
610 return false;
611 }
612 }
613 }
614 return true;
615 }
616
617 // check selector and criteria array.
618 private boolean checkFlowSelector(FlowEntry flow, JsonObject jsonFlow) {
619
620 if (flow.selector() != null) {
621 JsonObject jsonTreatment =
622 jsonFlow.get(SELECTOR).asObject();
623
624 JsonArray jsonCriteria =
625 jsonTreatment.get(CRITERIA).asArray();
626
627 if (flow.selector().criteria().size() != jsonCriteria.size()) {
628 reason = CRITERIA + " array size of " +
629 Integer.toString(flow.selector().criteria().size());
630 return false;
631 }
632 for (Criterion criterion : flow.selector().criteria()) {
633 boolean criterionFound = false;
634
635 for (int criterionIndex = 0;
636 criterionIndex < jsonCriteria.size();
637 criterionIndex++) {
638 String jsonType =
639 jsonCriteria.get(criterionIndex)
640 .asObject().get(TYPE).asString();
641 String criterionType = criterion.type().name();
642 if (jsonType.equals(criterionType)) {
643 criterionFound = true;
644 }
645 }
646 if (!criterionFound) {
647 reason = "criterion " + criterion;
648 return false;
649 }
650 }
651 }
652 return true;
653 }
654
655 @Override
656 public void describeTo(Description description) {
657 description.appendText(reason);
658 }
659 }
660
661 /**
Ray Milkey2b217142014-12-15 09:24:24 -0800662 * Hamcrest matcher to check that an intent is represented properly in a JSON
663 * array of intents.
664 */
665 public static class IntentJsonArrayMatcher extends TypeSafeMatcher<JsonArray> {
666 private final Intent intent;
667 private String reason = "";
668
669 public IntentJsonArrayMatcher(Intent intentValue) {
670 intent = intentValue;
671 }
672
673 @Override
674 public boolean matchesSafely(JsonArray json) {
675 boolean intentFound = false;
Ray Milkeyf7cb4012015-07-20 13:01:07 -0700676 final int expectedAttributes = 5;
Ray Milkey2b217142014-12-15 09:24:24 -0800677 for (int jsonIntentIndex = 0; jsonIntentIndex < json.size();
678 jsonIntentIndex++) {
679
680 final JsonObject jsonIntent = json.get(jsonIntentIndex).asObject();
681
682 if (jsonIntent.names().size() != expectedAttributes) {
683 reason = "Found an intent with the wrong number of attributes";
684 return false;
685 }
686
687 final String jsonIntentId = jsonIntent.get("id").asString();
688 if (jsonIntentId.equals(intent.id().toString())) {
689 intentFound = true;
690
691 // We found the correct intent, check attribute values
692 assertThat(jsonIntent, matchesIntent(intent));
693 }
694 }
695 if (!intentFound) {
696 reason = "Intent with id " + intent.id().toString() + " not found";
697 return false;
698 } else {
699 return true;
700 }
701 }
702
703 @Override
704 public void describeTo(Description description) {
705 description.appendText(reason);
706 }
707 }
708
709 /**
710 * Factory to allocate an intent array matcher.
711 *
712 * @param intent intent object we are looking for
713 * @return matcher
714 */
715 private static IntentJsonArrayMatcher hasIntent(Intent intent) {
716 return new IntentJsonArrayMatcher(intent);
717 }
Ray Milkey4f5de002014-12-17 19:26:11 -0800718
Ray Milkeyed0b1662015-02-05 09:34:29 -0800719 /**
720 * Initializes test mocks and environment.
721 */
Ray Milkey2b217142014-12-15 09:24:24 -0800722 @Before
Ray Milkeyed0b1662015-02-05 09:34:29 -0800723 public void setUpTest() {
Ray Milkey2b217142014-12-15 09:24:24 -0800724 expect(mockIntentService.getIntents()).andReturn(intents).anyTimes();
Ray Milkey1534f8d2015-05-13 15:42:50 -0700725 expect(mockIntentService.getIntentState(anyObject()))
726 .andReturn(IntentState.INSTALLED)
727 .anyTimes();
Ray Milkey2b217142014-12-15 09:24:24 -0800728 // Register the services needed for the test
729 final CodecManager codecService = new CodecManager();
730 codecService.activate();
731 ServiceDirectory testDirectory =
732 new TestServiceDirectory()
733 .add(IntentService.class, mockIntentService)
Author Namee252a002016-09-26 22:42:24 +0530734 .add(FlowRuleService.class, mockFlowService)
Ayaka Koshibec06c89b2015-02-10 19:25:41 -0800735 .add(CodecService.class, codecService)
736 .add(CoreService.class, mockCoreService);
Ray Milkey2b217142014-12-15 09:24:24 -0800737
738 BaseResource.setServiceDirectory(testDirectory);
739
Ray Milkey7c251822016-04-06 17:38:25 -0700740 bindNewGenerator();
Ray Milkey2b217142014-12-15 09:24:24 -0800741 }
742
Ray Milkeyed0b1662015-02-05 09:34:29 -0800743 /**
744 * Tears down and verifies test mocks and environment.
745 */
Ray Milkey2b217142014-12-15 09:24:24 -0800746 @After
Ray Milkeyed0b1662015-02-05 09:34:29 -0800747 public void tearDownTest() {
Ray Milkey2b217142014-12-15 09:24:24 -0800748 verify(mockIntentService);
Ray Milkey2b217142014-12-15 09:24:24 -0800749 }
750
751 /**
752 * Tests the result of the rest api GET when there are no intents.
753 */
754 @Test
755 public void testIntentsEmptyArray() {
756 replay(mockIntentService);
Jian Li9d616492016-03-09 10:52:49 -0800757 final WebTarget wt = target();
758 final String response = wt.path("intents").request().get(String.class);
Ray Milkey2b217142014-12-15 09:24:24 -0800759 assertThat(response, is("{\"intents\":[]}"));
760 }
761
762 /**
763 * Tests the result of the rest api GET when intents are defined.
764 */
765 @Test
766 public void testIntentsArray() {
767 replay(mockIntentService);
768
Ray Milkey43a28222015-02-23 13:57:58 -0800769 final Intent intent1 = new MockIntent(1L, Collections.emptyList());
Ray Milkey2b217142014-12-15 09:24:24 -0800770 final HashSet<NetworkResource> resources = new HashSet<>();
771 resources.add(new MockResource(1));
772 resources.add(new MockResource(2));
773 resources.add(new MockResource(3));
Ray Milkey43a28222015-02-23 13:57:58 -0800774 final Intent intent2 = new MockIntent(2L, resources);
Ray Milkey2b217142014-12-15 09:24:24 -0800775
776 intents.add(intent1);
777 intents.add(intent2);
Jian Li9d616492016-03-09 10:52:49 -0800778 final WebTarget wt = target();
779 final String response = wt.path("intents").request().get(String.class);
Ray Milkey2b217142014-12-15 09:24:24 -0800780 assertThat(response, containsString("{\"intents\":["));
781
Jian Li80cfe452016-01-14 16:04:58 -0800782 final JsonObject result = Json.parse(response).asObject();
Ray Milkey2b217142014-12-15 09:24:24 -0800783 assertThat(result, notNullValue());
784
785 assertThat(result.names(), hasSize(1));
786 assertThat(result.names().get(0), is("intents"));
787
788 final JsonArray jsonIntents = result.get("intents").asArray();
789 assertThat(jsonIntents, notNullValue());
790
791 assertThat(jsonIntents, hasIntent(intent1));
792 assertThat(jsonIntents, hasIntent(intent2));
793 }
794
795 /**
796 * Tests the result of a rest api GET for a single intent.
797 */
798 @Test
799 public void testIntentsSingle() {
800 final HashSet<NetworkResource> resources = new HashSet<>();
801 resources.add(new MockResource(1));
802 resources.add(new MockResource(2));
803 resources.add(new MockResource(3));
Ray Milkey43a28222015-02-23 13:57:58 -0800804 final Intent intent = new MockIntent(3L, resources);
Ray Milkey2b217142014-12-15 09:24:24 -0800805
806 intents.add(intent);
807
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800808 expect(mockIntentService.getIntent(Key.of(0, APP_ID)))
Ray Milkey2b217142014-12-15 09:24:24 -0800809 .andReturn(intent)
810 .anyTimes();
Ayaka Koshibec06c89b2015-02-10 19:25:41 -0800811 expect(mockIntentService.getIntent(Key.of("0", APP_ID)))
812 .andReturn(intent)
813 .anyTimes();
Ray Milkey05b169d2015-08-13 14:33:33 -0700814 expect(mockIntentService.getIntent(Key.of(0, APP_ID)))
815 .andReturn(intent)
816 .anyTimes();
817 expect(mockIntentService.getIntent(Key.of("0x0", APP_ID)))
818 .andReturn(null)
819 .anyTimes();
Ray Milkey2b217142014-12-15 09:24:24 -0800820 replay(mockIntentService);
Ray Milkeyf7cb4012015-07-20 13:01:07 -0700821 expect(mockCoreService.getAppId(APP_ID.name()))
Ayaka Koshibec06c89b2015-02-10 19:25:41 -0800822 .andReturn(APP_ID).anyTimes();
823 replay(mockCoreService);
Jian Li9d616492016-03-09 10:52:49 -0800824 final WebTarget wt = target();
Ray Milkey05b169d2015-08-13 14:33:33 -0700825
826 // Test get using key string
Jian Li9d616492016-03-09 10:52:49 -0800827 final String response = wt.path("intents/" + APP_ID.name()
828 + "/0").request().get(String.class);
Jian Li80cfe452016-01-14 16:04:58 -0800829 final JsonObject result = Json.parse(response).asObject();
Ray Milkey2b217142014-12-15 09:24:24 -0800830 assertThat(result, matchesIntent(intent));
Ray Milkey05b169d2015-08-13 14:33:33 -0700831
832 // Test get using numeric value
Jian Li9d616492016-03-09 10:52:49 -0800833 final String responseNumeric = wt.path("intents/" + APP_ID.name()
834 + "/0x0").request().get(String.class);
Jian Li80cfe452016-01-14 16:04:58 -0800835 final JsonObject resultNumeric = Json.parse(responseNumeric).asObject();
Ray Milkey05b169d2015-08-13 14:33:33 -0700836 assertThat(resultNumeric, matchesIntent(intent));
Ray Milkey2b217142014-12-15 09:24:24 -0800837 }
838
839 /**
Author Namee252a002016-09-26 22:42:24 +0530840 * Tests the result of a rest api GET for related flows for single intent.
841 */
842 @Test
843 public void testRelatedFlowsForIntents() {
844 List<FlowEntry> flowEntries = new ArrayList<>();
845 flowEntries.add(flow1);
846 flowEntries.add(flow2);
847 List<List<FlowEntry>> paths = new ArrayList<>();
848 paths.add(flowEntries);
849 List<FlowRule> flowRules = new ArrayList<>();
850 flowRules.add(flowRule1);
851 flowRules.add(flowRule2);
852 FlowRuleIntent flowRuleIntent = new FlowRuleIntent(
853 APP_ID,
854 flowRules,
855 new HashSet<NetworkResource>());
856 Intent intent = new MockIntent(3L);
857 installableIntents.add(flowRuleIntent);
858 intents.add(intent);
859
860 expect(mockIntentService.getIntent(Key.of(0, APP_ID)))
861 .andReturn(intent)
862 .anyTimes();
863 expect(mockIntentService.getIntent(Key.of("0", APP_ID)))
864 .andReturn(intent)
865 .anyTimes();
866 expect(mockIntentService.getIntent(Key.of(0, APP_ID)))
867 .andReturn(intent)
868 .anyTimes();
869 expect(mockIntentService.getIntent(Key.of("0x0", APP_ID)))
870 .andReturn(null)
871 .anyTimes();
872 expect(mockIntentService.getInstallableIntents(intent.key()))
873 .andReturn(installableIntents)
874 .anyTimes();
875 replay(mockIntentService);
876
877 expect(mockFlowService.getFlowEntries(deviceId1))
878 .andReturn(flowEntries).anyTimes();
879 replay(mockFlowService);
880
881 expect(mockCoreService.getAppId(APP_ID.name()))
882 .andReturn(APP_ID).anyTimes();
883 expect(mockCoreService.getAppId(APP_ID.id()))
884 .andReturn(APP_ID).anyTimes();
885 replay(mockCoreService);
886
887 final WebTarget wt = target();
888
889 // Test get using key string
890 final String response = wt.path("intents/relatedflows/" + APP_ID.name()
891 + "/0").request().get(String.class);
892 final JsonObject result = Json.parse(response).asObject();
893 assertThat(result, matchesRelatedFlowEntries(paths, APP_ID.name()));
894
895 // Test get using numeric value
896 final String responseNumeric = wt.path("intents/relatedflows/" + APP_ID.name()
897 + "/0x0").request().get(String.class);
898 final JsonObject resultNumeric = Json.parse(responseNumeric).asObject();
899 assertThat(resultNumeric, matchesRelatedFlowEntries(paths, APP_ID.name()));
900 }
901
902 /**
Ray Milkey2b217142014-12-15 09:24:24 -0800903 * Tests that a fetch of a non-existent intent object throws an exception.
904 */
905 @Test
906 public void testBadGet() {
907
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800908 expect(mockIntentService.getIntent(Key.of(0, APP_ID)))
Ray Milkey2b217142014-12-15 09:24:24 -0800909 .andReturn(null)
910 .anyTimes();
911 replay(mockIntentService);
912
Jian Li9d616492016-03-09 10:52:49 -0800913 WebTarget wt = target();
Ray Milkey2b217142014-12-15 09:24:24 -0800914 try {
Jian Li9d616492016-03-09 10:52:49 -0800915 wt.path("intents/0").request().get(String.class);
Ray Milkey2b217142014-12-15 09:24:24 -0800916 fail("Fetch of non-existent intent did not throw an exception");
Jian Li9d616492016-03-09 10:52:49 -0800917 } catch (NotFoundException ex) {
Ray Milkey2b217142014-12-15 09:24:24 -0800918 assertThat(ex.getMessage(),
Jian Li9d616492016-03-09 10:52:49 -0800919 containsString("HTTP 404 Not Found"));
Ray Milkey2b217142014-12-15 09:24:24 -0800920 }
921 }
Ray Milkeyb82c42b2015-06-30 09:42:20 -0700922
923 /**
924 * Tests creating an intent with POST.
925 */
926 @Test
927 public void testPost() {
Ray Milkeyf7cb4012015-07-20 13:01:07 -0700928 ApplicationId testId = new DefaultApplicationId(2, "myApp");
929 expect(mockCoreService.getAppId("myApp"))
930 .andReturn(testId);
Ray Milkeyb82c42b2015-06-30 09:42:20 -0700931 replay(mockCoreService);
932
933 mockIntentService.submit(anyObject());
934 expectLastCall();
935 replay(mockIntentService);
936
937 InputStream jsonStream = IntentsResourceTest.class
938 .getResourceAsStream("post-intent.json");
Jian Li9d616492016-03-09 10:52:49 -0800939 WebTarget wt = target();
Ray Milkeyb82c42b2015-06-30 09:42:20 -0700940
Jian Li9d616492016-03-09 10:52:49 -0800941 Response response = wt.path("intents")
942 .request(MediaType.APPLICATION_JSON_TYPE)
943 .post(Entity.json(jsonStream));
Ray Milkeyb82c42b2015-06-30 09:42:20 -0700944 assertThat(response.getStatus(), is(HttpURLConnection.HTTP_CREATED));
945 String location = response.getLocation().getPath();
Ray Milkey8d076402015-08-31 15:43:18 -0700946 assertThat(location, Matchers.startsWith("/intents/myApp/"));
Ray Milkeyb82c42b2015-06-30 09:42:20 -0700947 }
Ray Milkey7b158512015-07-21 16:32:43 -0700948
949 /**
Ray Milkey05b169d2015-08-13 14:33:33 -0700950 * Tests creating an intent with POST and illegal JSON.
951 */
952 @Test
953 public void testBadPost() {
954 replay(mockCoreService);
955 replay(mockIntentService);
956
957 String json = "this is invalid!";
Jian Li9d616492016-03-09 10:52:49 -0800958 WebTarget wt = target();
Ray Milkey05b169d2015-08-13 14:33:33 -0700959
Jian Li9d616492016-03-09 10:52:49 -0800960 Response response = wt.path("intents")
961 .request(MediaType.APPLICATION_JSON_TYPE)
962 .post(Entity.json(json));
Ray Milkey05b169d2015-08-13 14:33:33 -0700963 assertThat(response.getStatus(), is(HttpURLConnection.HTTP_BAD_REQUEST));
964 }
965
966 /**
Ray Milkey7b158512015-07-21 16:32:43 -0700967 * Tests removing an intent with DELETE.
968 */
969 @Test
970 public void testRemove() {
971 final HashSet<NetworkResource> resources = new HashSet<>();
972 resources.add(new MockResource(1));
973 resources.add(new MockResource(2));
974 resources.add(new MockResource(3));
975 final Intent intent = new MockIntent(3L, resources);
976 final ApplicationId appId = new DefaultApplicationId(2, "app");
977 IntentService fakeManager = new FakeIntentManager();
978
979 expect(mockCoreService.getAppId("app"))
980 .andReturn(appId).once();
981 replay(mockCoreService);
982
983 mockIntentService.withdraw(anyObject());
984 expectLastCall().andDelegateTo(fakeManager).once();
985 expect(mockIntentService.getIntent(Key.of(2, appId)))
986 .andReturn(intent)
987 .once();
988 expect(mockIntentService.getIntent(Key.of("0x2", appId)))
989 .andReturn(null)
990 .once();
991
992 mockIntentService.addListener(anyObject());
993 expectLastCall().andDelegateTo(fakeManager).once();
994 mockIntentService.removeListener(anyObject());
995 expectLastCall().andDelegateTo(fakeManager).once();
996
997 replay(mockIntentService);
998
Jian Li9d616492016-03-09 10:52:49 -0800999 WebTarget wt = target();
Ray Milkey7b158512015-07-21 16:32:43 -07001000
Jian Li9d616492016-03-09 10:52:49 -08001001 Response response = wt.path("intents/app/0x2")
Ray Milkey7c251822016-04-06 17:38:25 -07001002 .request(MediaType.APPLICATION_JSON, MediaType.TEXT_PLAIN)
Jian Li9d616492016-03-09 10:52:49 -08001003 .delete();
Ray Milkey7b158512015-07-21 16:32:43 -07001004 assertThat(response.getStatus(), is(HttpURLConnection.HTTP_NO_CONTENT));
1005 }
Ray Milkey05b169d2015-08-13 14:33:33 -07001006
1007 /**
1008 * Tests removal of a non existent intent with DELETE.
1009 */
1010 @Test
1011 public void testBadRemove() {
1012 final ApplicationId appId = new DefaultApplicationId(2, "app");
1013
1014 expect(mockCoreService.getAppId("app"))
1015 .andReturn(appId).once();
1016 replay(mockCoreService);
1017
1018 expect(mockIntentService.getIntent(Key.of(2, appId)))
1019 .andReturn(null)
1020 .once();
1021 expect(mockIntentService.getIntent(Key.of("0x2", appId)))
1022 .andReturn(null)
1023 .once();
1024
1025 replay(mockIntentService);
1026
Jian Li9d616492016-03-09 10:52:49 -08001027 WebTarget wt = target();
Ray Milkey05b169d2015-08-13 14:33:33 -07001028
Jian Li9d616492016-03-09 10:52:49 -08001029 Response response = wt.path("intents/app/0x2")
Ray Milkey7c251822016-04-06 17:38:25 -07001030 .request(MediaType.APPLICATION_JSON, MediaType.TEXT_PLAIN)
Jian Li9d616492016-03-09 10:52:49 -08001031 .delete();
Ray Milkey05b169d2015-08-13 14:33:33 -07001032 assertThat(response.getStatus(), is(HttpURLConnection.HTTP_NO_CONTENT));
1033 }
1034
Ray Milkey2b217142014-12-15 09:24:24 -08001035}