blob: efabf66f878c79a08d3c624b97082d2eaa3ddd5f [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;
Ray Milkey634eb172017-04-05 14:48:50 -070044import org.onosproject.net.flow.FlowEntryAdapter;
Author Namee252a002016-09-26 22:42:24 +053045import 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 */
Ray Milkey634eb172017-04-05 14:48:50 -0700146 private static class MockFlowEntry extends FlowEntryAdapter {
Author Namee252a002016-09-26 22:42:24 +0530147 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
Author Namee252a002016-09-26 22:42:24 +0530162 public long life() {
163 return life(SECONDS);
164 }
165
166 @Override
kalagesa42019542017-03-14 18:00:47 +0530167 public FlowLiveType liveType() {
168 return FlowLiveType.IMMEDIATE;
169 }
170
171 @Override
Author Namee252a002016-09-26 22:42:24 +0530172 public long life(TimeUnit timeUnit) {
173 return SECONDS.convert(baseValue + 11, timeUnit);
174 }
175
176 @Override
177 public long packets() {
178 return baseValue + 22;
179 }
180
181 @Override
182 public long bytes() {
183 return baseValue + 33;
184 }
185
186 @Override
187 public long lastSeen() {
188 return baseValue + 44;
189 }
190
191 @Override
Author Namee252a002016-09-26 22:42:24 +0530192 public FlowId id() {
193 final long id = baseValue + 55;
194 return FlowId.valueOf(id);
195 }
196
197 @Override
198 public GroupId groupId() {
Yi Tsengfa394de2017-02-01 11:26:40 -0800199 return new GroupId(3);
Author Namee252a002016-09-26 22:42:24 +0530200 }
201
202 @Override
203 public short appId() {
204 return 1;
205 }
206
207 @Override
208 public int priority() {
209 return (int) (baseValue + 66);
210 }
211
212 @Override
213 public DeviceId deviceId() {
214 return deviceId;
215 }
216
217 @Override
218 public TrafficSelector selector() {
219 return selector;
220 }
221
222 @Override
223 public TrafficTreatment treatment() {
224 return treatment;
225 }
226
227 @Override
228 public int timeout() {
229 return (int) (baseValue + 77);
230 }
231
Author Namee252a002016-09-26 22:42:24 +0530232
233 @Override
234 public boolean exactMatch(FlowRule rule) {
235 return this.appId() == rule.appId() &&
236 this.deviceId().equals(rule.deviceId()) &&
237 this.id().equals(rule.id()) &&
238 this.treatment.equals(rule.treatment()) &&
239 this.selector().equals(rule.selector());
240 }
241
242 @Override
Author Namee252a002016-09-26 22:42:24 +0530243 public String toString() {
244 return id().id().toString();
245 }
246 }
247
248 /**
249 * Mock class for a flow rule.
250 */
251 private static class MockFlowRule implements FlowRule {
252
253 final DeviceId deviceId;
254 final long baseValue;
255 TrafficTreatment treatment;
256 TrafficSelector selector;
257
258 public MockFlowRule(DeviceId deviceId,
259 long id,
260 TrafficTreatment treatment,
261 TrafficSelector selector) {
262 this.deviceId = deviceId;
263 this.baseValue = id * 100;
264 this.treatment = treatment;
265 this.selector = selector;
266 }
267
268 @Override
269 public FlowId id() {
270 long id = baseValue + 55;
271 return FlowId.valueOf(id);
272 }
273
274 @Override
275 public short appId() {
276 return 1;
277 }
278
279 @Override
280 public GroupId groupId() {
Yi Tsengfa394de2017-02-01 11:26:40 -0800281 return new GroupId(3);
Author Namee252a002016-09-26 22:42:24 +0530282 }
283
284 @Override
285 public int priority() {
286 return 0;
287 }
288
289 @Override
290 public DeviceId deviceId() {
291 return deviceId;
292 }
293
294 @Override
295 public TrafficSelector selector() {
296 return selector;
297 }
298
299 @Override
300 public TrafficTreatment treatment() {
301 return treatment;
302 }
303
304 @Override
305 public int timeout() {
306 return (int) (baseValue + 77);
307 }
308
309 @Override
310 public int hardTimeout() {
311 return 0;
312 }
313
314 @Override
315 public FlowRemoveReason reason() {
316 return FlowRemoveReason.NO_REASON;
317 }
318
319 @Override
320 public boolean isPermanent() {
321 return false;
322 }
323
324 @Override
325 public int tableId() {
326 return 0;
327 }
328
329 @Override
330 public boolean exactMatch(FlowRule rule) {
331 return false;
332 }
333
334 @Override
335 public FlowRuleExtPayLoad payLoad() {
336 return null;
337 }
338 }
339
340 /**
Ray Milkey2b217142014-12-15 09:24:24 -0800341 * Hamcrest matcher to check that an intent representation in JSON matches
342 * the actual intent.
343 */
344 public static class IntentJsonMatcher extends TypeSafeMatcher<JsonObject> {
345 private final Intent intent;
346 private String reason = "";
347
348 public IntentJsonMatcher(Intent intentValue) {
349 intent = intentValue;
350 }
351
352 @Override
353 public boolean matchesSafely(JsonObject jsonIntent) {
354 // check id
355 final String jsonId = jsonIntent.get("id").asString();
356 if (!jsonId.equals(intent.id().toString())) {
357 reason = "id " + intent.id().toString();
358 return false;
359 }
360
361 // check application id
Ray Milkeyf7cb4012015-07-20 13:01:07 -0700362
Ray Milkey2b217142014-12-15 09:24:24 -0800363 final String jsonAppId = jsonIntent.get("appId").asString();
Ray Milkeyf7cb4012015-07-20 13:01:07 -0700364 final String appId = intent.appId().name();
365 if (!jsonAppId.equals(appId)) {
366 reason = "appId was " + jsonAppId;
Ray Milkey2b217142014-12-15 09:24:24 -0800367 return false;
368 }
369
370 // check intent type
371 final String jsonType = jsonIntent.get("type").asString();
Jon Halla3fcf672017-03-28 16:53:22 -0700372 if (!"MockIntent".equals(jsonType)) {
Ray Milkey2b217142014-12-15 09:24:24 -0800373 reason = "type MockIntent";
374 return false;
375 }
376
Ray Milkey1534f8d2015-05-13 15:42:50 -0700377 // check state field
378 final String jsonState = jsonIntent.get("state").asString();
Jon Halla3fcf672017-03-28 16:53:22 -0700379 if (!"INSTALLED".equals(jsonState)) {
Ray Milkey1534f8d2015-05-13 15:42:50 -0700380 reason = "state INSTALLED";
381 return false;
382 }
383
Ray Milkey2b217142014-12-15 09:24:24 -0800384 // check resources array
385 final JsonArray jsonResources = jsonIntent.get("resources").asArray();
386 if (intent.resources() != null) {
387 if (intent.resources().size() != jsonResources.size()) {
388 reason = "resources array size of " + Integer.toString(intent.resources().size());
389 return false;
390 }
391 for (final NetworkResource resource : intent.resources()) {
392 boolean resourceFound = false;
393 final String resourceString = resource.toString();
394 for (int resourceIndex = 0; resourceIndex < jsonResources.size(); resourceIndex++) {
395 final JsonValue value = jsonResources.get(resourceIndex);
396 if (value.asString().equals(resourceString)) {
397 resourceFound = true;
398 }
399 }
400 if (!resourceFound) {
401 reason = "resource " + resourceString;
402 return false;
403 }
404 }
405 } else if (jsonResources.size() != 0) {
406 reason = "resources array empty";
407 return false;
408 }
409 return true;
410 }
411
412 @Override
413 public void describeTo(Description description) {
414 description.appendText(reason);
415 }
416 }
417
418 /**
419 * Factory to allocate an intent matcher.
420 *
421 * @param intent intent object we are looking for
422 * @return matcher
423 */
424 private static IntentJsonMatcher matchesIntent(Intent intent) {
425 return new IntentJsonMatcher(intent);
426 }
427
428 /**
Author Namee252a002016-09-26 22:42:24 +0530429 * Factory to allocate an IntentRelatedFlows matcher.
430 *
431 * @param pathEntries list of path conatining flow entries of a particular intent
432 * @param expectedAppId expected app id we are looking for
433 * @return matcher
434 */
435 private static IntentStatsJsonMatcher matchesRelatedFlowEntries(
436 List<List<FlowEntry>> pathEntries,
437 final String expectedAppId) {
438 return new IntentStatsJsonMatcher(pathEntries, expectedAppId);
439 }
440
441 /**
442 * Hamcrest matcher to check that an list of flowEntries in JSON matches
443 * the actual list of flow entries.
444 */
445 public static class IntentStatsJsonMatcher extends
446 TypeSafeMatcher<JsonObject> {
447
448 private final List<List<FlowEntry>> pathEntries;
449 private final String expectedAppId;
450 private String reason = "";
451
452 public IntentStatsJsonMatcher(
453 final List<List<FlowEntry>> pathEntries,
454 final String expectedAppId) {
455 this.pathEntries = pathEntries;
456 this.expectedAppId = expectedAppId;
457 }
458
459 @Override
460 public boolean matchesSafely(JsonObject jsonIntent) {
461 int jsonPathIndex = 0;
462 JsonArray jsonPaths = jsonIntent.get(PATHS).asArray();
463
464 if (pathEntries != null) {
465
rohitsharanfd747602017-01-23 21:57:28 +0530466 if (pathEntries.size() == 0) {
467 reason = "pathEntries array empty";
468 return false;
469 }
470
Author Namee252a002016-09-26 22:42:24 +0530471 if (pathEntries.size() != jsonPaths.size()) {
472 reason = "path entries array size of " +
473 Integer.toString(pathEntries.size());
474 return false;
475 }
476
477 for (List<FlowEntry> flowEntries : pathEntries) {
478 JsonArray jsonFlowEntries = jsonPaths.get(
479 jsonPathIndex++).asArray();
480
481 if (flowEntries.size() != jsonFlowEntries.size()) {
482 reason = "flow entries array size of " +
483 Integer.toString(pathEntries.size());
484
485 return false;
486 }
487
488 int jsonFlowEntryIndex = 0;
489 for (FlowEntry flow : flowEntries) {
490
491 JsonObject jsonFlow = jsonFlowEntries.get(
492 jsonFlowEntryIndex++).asObject();
493
494 String jsonId = jsonFlow.get(ID).asString();
495 String flowId = Long.toString(flow.id().value());
496 if (!jsonId.equals(flowId)) {
497 reason = ID + SPACE + flow.id();
498 return false;
499 }
500
501 // check application id
502 String jsonAppId = jsonFlow.get(APPID).asString();
503 if (!jsonAppId.equals(expectedAppId)) {
504 reason = APPID + SPACE + Short.toString(flow.appId());
505 return false;
506 }
507
508 // check device id
509 String jsonDeviceId =
510 jsonFlow.get(DEVICE_ID).asString();
511
512 if (!jsonDeviceId.equals(flow.deviceId().toString())) {
513 reason = DEVICE_ID + SPACE + flow.deviceId();
514 return false;
515 }
516
517 if (!checkFlowTreatment(flow, jsonFlow)) {
518 return false;
519 }
520
521 if (!checkFlowSelector(flow, jsonFlow)) {
522 return false;
523 }
524
525 }
526
527 }
rohitsharanfd747602017-01-23 21:57:28 +0530528 } else {
Author Namee252a002016-09-26 22:42:24 +0530529 reason = "pathEntries array empty";
530 return false;
531 }
532
533 return true;
534 }
535
536 // check treatment and instructions array.
537 private boolean checkFlowTreatment(FlowEntry flow, JsonObject jsonFlow) {
538
539 if (flow.treatment() != null) {
540 JsonObject jsonTreatment =
541 jsonFlow.get(TREATMENT).asObject();
542 JsonArray jsonInstructions =
543 jsonTreatment.get(INSTRUCTIONS).asArray();
544
545 if (flow.treatment().immediate().size() !=
546 jsonInstructions.size()) {
547 reason = "instructions array size of " +
548 flow.treatment().immediate().size();
549
550 return false;
551 }
552 for (Instruction instruction :
553 flow.treatment().immediate()) {
554 boolean instructionFound = false;
555 for (int instructionIndex = 0;
556 instructionIndex < jsonInstructions.size();
557 instructionIndex++) {
558 String jsonType =
559 jsonInstructions.get(instructionIndex)
560 .asObject().get(TYPE).asString();
561
562 String instructionType =
563 instruction.type().name();
564
565 if (jsonType.equals(instructionType)) {
566 instructionFound = true;
567 }
568 }
569 if (!instructionFound) {
570 reason = INSTRUCTIONS + SPACE + instruction;
571 return false;
572 }
573 }
574 }
575 return true;
576 }
577
578 // check selector and criteria array.
579 private boolean checkFlowSelector(FlowEntry flow, JsonObject jsonFlow) {
580
581 if (flow.selector() != null) {
582 JsonObject jsonTreatment =
583 jsonFlow.get(SELECTOR).asObject();
584
585 JsonArray jsonCriteria =
586 jsonTreatment.get(CRITERIA).asArray();
587
588 if (flow.selector().criteria().size() != jsonCriteria.size()) {
589 reason = CRITERIA + " array size of " +
590 Integer.toString(flow.selector().criteria().size());
591 return false;
592 }
593 for (Criterion criterion : flow.selector().criteria()) {
594 boolean criterionFound = false;
595
596 for (int criterionIndex = 0;
597 criterionIndex < jsonCriteria.size();
598 criterionIndex++) {
599 String jsonType =
600 jsonCriteria.get(criterionIndex)
601 .asObject().get(TYPE).asString();
602 String criterionType = criterion.type().name();
603 if (jsonType.equals(criterionType)) {
604 criterionFound = true;
605 }
606 }
607 if (!criterionFound) {
608 reason = "criterion " + criterion;
609 return false;
610 }
611 }
612 }
613 return true;
614 }
615
616 @Override
617 public void describeTo(Description description) {
618 description.appendText(reason);
619 }
620 }
621
622 /**
Ray Milkey2b217142014-12-15 09:24:24 -0800623 * Hamcrest matcher to check that an intent is represented properly in a JSON
624 * array of intents.
625 */
626 public static class IntentJsonArrayMatcher extends TypeSafeMatcher<JsonArray> {
627 private final Intent intent;
628 private String reason = "";
629
630 public IntentJsonArrayMatcher(Intent intentValue) {
631 intent = intentValue;
632 }
633
634 @Override
635 public boolean matchesSafely(JsonArray json) {
636 boolean intentFound = false;
Ray Milkeyf7cb4012015-07-20 13:01:07 -0700637 final int expectedAttributes = 5;
Ray Milkey2b217142014-12-15 09:24:24 -0800638 for (int jsonIntentIndex = 0; jsonIntentIndex < json.size();
639 jsonIntentIndex++) {
640
641 final JsonObject jsonIntent = json.get(jsonIntentIndex).asObject();
642
643 if (jsonIntent.names().size() != expectedAttributes) {
644 reason = "Found an intent with the wrong number of attributes";
645 return false;
646 }
647
648 final String jsonIntentId = jsonIntent.get("id").asString();
649 if (jsonIntentId.equals(intent.id().toString())) {
650 intentFound = true;
651
652 // We found the correct intent, check attribute values
653 assertThat(jsonIntent, matchesIntent(intent));
654 }
655 }
656 if (!intentFound) {
657 reason = "Intent with id " + intent.id().toString() + " not found";
658 return false;
659 } else {
660 return true;
661 }
662 }
663
664 @Override
665 public void describeTo(Description description) {
666 description.appendText(reason);
667 }
668 }
669
670 /**
671 * Factory to allocate an intent array matcher.
672 *
673 * @param intent intent object we are looking for
674 * @return matcher
675 */
676 private static IntentJsonArrayMatcher hasIntent(Intent intent) {
677 return new IntentJsonArrayMatcher(intent);
678 }
Ray Milkey4f5de002014-12-17 19:26:11 -0800679
Ray Milkeyed0b1662015-02-05 09:34:29 -0800680 /**
681 * Initializes test mocks and environment.
682 */
Ray Milkey2b217142014-12-15 09:24:24 -0800683 @Before
Ray Milkeyed0b1662015-02-05 09:34:29 -0800684 public void setUpTest() {
Ray Milkey2b217142014-12-15 09:24:24 -0800685 expect(mockIntentService.getIntents()).andReturn(intents).anyTimes();
Ray Milkey1534f8d2015-05-13 15:42:50 -0700686 expect(mockIntentService.getIntentState(anyObject()))
687 .andReturn(IntentState.INSTALLED)
688 .anyTimes();
Ray Milkey2b217142014-12-15 09:24:24 -0800689 // Register the services needed for the test
690 final CodecManager codecService = new CodecManager();
691 codecService.activate();
692 ServiceDirectory testDirectory =
693 new TestServiceDirectory()
694 .add(IntentService.class, mockIntentService)
Author Namee252a002016-09-26 22:42:24 +0530695 .add(FlowRuleService.class, mockFlowService)
Ayaka Koshibec06c89b2015-02-10 19:25:41 -0800696 .add(CodecService.class, codecService)
697 .add(CoreService.class, mockCoreService);
Ray Milkey2b217142014-12-15 09:24:24 -0800698
699 BaseResource.setServiceDirectory(testDirectory);
700
Ray Milkey7c251822016-04-06 17:38:25 -0700701 bindNewGenerator();
Ray Milkey2b217142014-12-15 09:24:24 -0800702 }
703
Ray Milkeyed0b1662015-02-05 09:34:29 -0800704 /**
705 * Tears down and verifies test mocks and environment.
706 */
Ray Milkey2b217142014-12-15 09:24:24 -0800707 @After
Ray Milkeyed0b1662015-02-05 09:34:29 -0800708 public void tearDownTest() {
Ray Milkey2b217142014-12-15 09:24:24 -0800709 verify(mockIntentService);
Ray Milkey2b217142014-12-15 09:24:24 -0800710 }
711
712 /**
713 * Tests the result of the rest api GET when there are no intents.
714 */
715 @Test
716 public void testIntentsEmptyArray() {
717 replay(mockIntentService);
Jian Li9d616492016-03-09 10:52:49 -0800718 final WebTarget wt = target();
719 final String response = wt.path("intents").request().get(String.class);
Ray Milkey2b217142014-12-15 09:24:24 -0800720 assertThat(response, is("{\"intents\":[]}"));
721 }
722
723 /**
724 * Tests the result of the rest api GET when intents are defined.
725 */
726 @Test
727 public void testIntentsArray() {
728 replay(mockIntentService);
729
Ray Milkey43a28222015-02-23 13:57:58 -0800730 final Intent intent1 = new MockIntent(1L, Collections.emptyList());
Ray Milkey2b217142014-12-15 09:24:24 -0800731 final HashSet<NetworkResource> resources = new HashSet<>();
732 resources.add(new MockResource(1));
733 resources.add(new MockResource(2));
734 resources.add(new MockResource(3));
Ray Milkey43a28222015-02-23 13:57:58 -0800735 final Intent intent2 = new MockIntent(2L, resources);
Ray Milkey2b217142014-12-15 09:24:24 -0800736
737 intents.add(intent1);
738 intents.add(intent2);
Jian Li9d616492016-03-09 10:52:49 -0800739 final WebTarget wt = target();
740 final String response = wt.path("intents").request().get(String.class);
Ray Milkey2b217142014-12-15 09:24:24 -0800741 assertThat(response, containsString("{\"intents\":["));
742
Jian Li80cfe452016-01-14 16:04:58 -0800743 final JsonObject result = Json.parse(response).asObject();
Ray Milkey2b217142014-12-15 09:24:24 -0800744 assertThat(result, notNullValue());
745
746 assertThat(result.names(), hasSize(1));
747 assertThat(result.names().get(0), is("intents"));
748
749 final JsonArray jsonIntents = result.get("intents").asArray();
750 assertThat(jsonIntents, notNullValue());
751
752 assertThat(jsonIntents, hasIntent(intent1));
753 assertThat(jsonIntents, hasIntent(intent2));
754 }
755
756 /**
757 * Tests the result of a rest api GET for a single intent.
758 */
759 @Test
760 public void testIntentsSingle() {
761 final HashSet<NetworkResource> resources = new HashSet<>();
762 resources.add(new MockResource(1));
763 resources.add(new MockResource(2));
764 resources.add(new MockResource(3));
Ray Milkey43a28222015-02-23 13:57:58 -0800765 final Intent intent = new MockIntent(3L, resources);
Ray Milkey2b217142014-12-15 09:24:24 -0800766
767 intents.add(intent);
768
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800769 expect(mockIntentService.getIntent(Key.of(0, APP_ID)))
Ray Milkey2b217142014-12-15 09:24:24 -0800770 .andReturn(intent)
771 .anyTimes();
Ayaka Koshibec06c89b2015-02-10 19:25:41 -0800772 expect(mockIntentService.getIntent(Key.of("0", APP_ID)))
773 .andReturn(intent)
774 .anyTimes();
Ray Milkey05b169d2015-08-13 14:33:33 -0700775 expect(mockIntentService.getIntent(Key.of(0, APP_ID)))
776 .andReturn(intent)
777 .anyTimes();
778 expect(mockIntentService.getIntent(Key.of("0x0", APP_ID)))
779 .andReturn(null)
780 .anyTimes();
Ray Milkey2b217142014-12-15 09:24:24 -0800781 replay(mockIntentService);
Ray Milkeyf7cb4012015-07-20 13:01:07 -0700782 expect(mockCoreService.getAppId(APP_ID.name()))
Ayaka Koshibec06c89b2015-02-10 19:25:41 -0800783 .andReturn(APP_ID).anyTimes();
784 replay(mockCoreService);
Jian Li9d616492016-03-09 10:52:49 -0800785 final WebTarget wt = target();
Ray Milkey05b169d2015-08-13 14:33:33 -0700786
787 // Test get using key string
Jian Li9d616492016-03-09 10:52:49 -0800788 final String response = wt.path("intents/" + APP_ID.name()
789 + "/0").request().get(String.class);
Jian Li80cfe452016-01-14 16:04:58 -0800790 final JsonObject result = Json.parse(response).asObject();
Ray Milkey2b217142014-12-15 09:24:24 -0800791 assertThat(result, matchesIntent(intent));
Ray Milkey05b169d2015-08-13 14:33:33 -0700792
793 // Test get using numeric value
Jian Li9d616492016-03-09 10:52:49 -0800794 final String responseNumeric = wt.path("intents/" + APP_ID.name()
795 + "/0x0").request().get(String.class);
Jian Li80cfe452016-01-14 16:04:58 -0800796 final JsonObject resultNumeric = Json.parse(responseNumeric).asObject();
Ray Milkey05b169d2015-08-13 14:33:33 -0700797 assertThat(resultNumeric, matchesIntent(intent));
Ray Milkey2b217142014-12-15 09:24:24 -0800798 }
799
800 /**
Author Namee252a002016-09-26 22:42:24 +0530801 * Tests the result of a rest api GET for related flows for single intent.
802 */
803 @Test
804 public void testRelatedFlowsForIntents() {
805 List<FlowEntry> flowEntries = new ArrayList<>();
806 flowEntries.add(flow1);
807 flowEntries.add(flow2);
808 List<List<FlowEntry>> paths = new ArrayList<>();
809 paths.add(flowEntries);
810 List<FlowRule> flowRules = new ArrayList<>();
811 flowRules.add(flowRule1);
812 flowRules.add(flowRule2);
813 FlowRuleIntent flowRuleIntent = new FlowRuleIntent(
814 APP_ID,
815 flowRules,
816 new HashSet<NetworkResource>());
817 Intent intent = new MockIntent(3L);
818 installableIntents.add(flowRuleIntent);
819 intents.add(intent);
820
821 expect(mockIntentService.getIntent(Key.of(0, APP_ID)))
822 .andReturn(intent)
823 .anyTimes();
824 expect(mockIntentService.getIntent(Key.of("0", APP_ID)))
825 .andReturn(intent)
826 .anyTimes();
827 expect(mockIntentService.getIntent(Key.of(0, APP_ID)))
828 .andReturn(intent)
829 .anyTimes();
830 expect(mockIntentService.getIntent(Key.of("0x0", APP_ID)))
831 .andReturn(null)
832 .anyTimes();
833 expect(mockIntentService.getInstallableIntents(intent.key()))
834 .andReturn(installableIntents)
835 .anyTimes();
836 replay(mockIntentService);
837
838 expect(mockFlowService.getFlowEntries(deviceId1))
839 .andReturn(flowEntries).anyTimes();
840 replay(mockFlowService);
841
842 expect(mockCoreService.getAppId(APP_ID.name()))
843 .andReturn(APP_ID).anyTimes();
844 expect(mockCoreService.getAppId(APP_ID.id()))
845 .andReturn(APP_ID).anyTimes();
846 replay(mockCoreService);
847
848 final WebTarget wt = target();
849
850 // Test get using key string
851 final String response = wt.path("intents/relatedflows/" + APP_ID.name()
852 + "/0").request().get(String.class);
853 final JsonObject result = Json.parse(response).asObject();
854 assertThat(result, matchesRelatedFlowEntries(paths, APP_ID.name()));
855
856 // Test get using numeric value
857 final String responseNumeric = wt.path("intents/relatedflows/" + APP_ID.name()
858 + "/0x0").request().get(String.class);
859 final JsonObject resultNumeric = Json.parse(responseNumeric).asObject();
860 assertThat(resultNumeric, matchesRelatedFlowEntries(paths, APP_ID.name()));
861 }
862
863 /**
Ray Milkey2b217142014-12-15 09:24:24 -0800864 * Tests that a fetch of a non-existent intent object throws an exception.
865 */
866 @Test
867 public void testBadGet() {
868
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800869 expect(mockIntentService.getIntent(Key.of(0, APP_ID)))
Ray Milkey2b217142014-12-15 09:24:24 -0800870 .andReturn(null)
871 .anyTimes();
872 replay(mockIntentService);
873
Jian Li9d616492016-03-09 10:52:49 -0800874 WebTarget wt = target();
Ray Milkey2b217142014-12-15 09:24:24 -0800875 try {
Jian Li9d616492016-03-09 10:52:49 -0800876 wt.path("intents/0").request().get(String.class);
Ray Milkey2b217142014-12-15 09:24:24 -0800877 fail("Fetch of non-existent intent did not throw an exception");
Jian Li9d616492016-03-09 10:52:49 -0800878 } catch (NotFoundException ex) {
Ray Milkey2b217142014-12-15 09:24:24 -0800879 assertThat(ex.getMessage(),
Jian Li9d616492016-03-09 10:52:49 -0800880 containsString("HTTP 404 Not Found"));
Ray Milkey2b217142014-12-15 09:24:24 -0800881 }
882 }
Ray Milkeyb82c42b2015-06-30 09:42:20 -0700883
884 /**
885 * Tests creating an intent with POST.
886 */
887 @Test
888 public void testPost() {
Ray Milkeyf7cb4012015-07-20 13:01:07 -0700889 ApplicationId testId = new DefaultApplicationId(2, "myApp");
890 expect(mockCoreService.getAppId("myApp"))
891 .andReturn(testId);
Ray Milkeyb82c42b2015-06-30 09:42:20 -0700892 replay(mockCoreService);
893
894 mockIntentService.submit(anyObject());
895 expectLastCall();
896 replay(mockIntentService);
897
898 InputStream jsonStream = IntentsResourceTest.class
899 .getResourceAsStream("post-intent.json");
Jian Li9d616492016-03-09 10:52:49 -0800900 WebTarget wt = target();
Ray Milkeyb82c42b2015-06-30 09:42:20 -0700901
Jian Li9d616492016-03-09 10:52:49 -0800902 Response response = wt.path("intents")
903 .request(MediaType.APPLICATION_JSON_TYPE)
904 .post(Entity.json(jsonStream));
Ray Milkeyb82c42b2015-06-30 09:42:20 -0700905 assertThat(response.getStatus(), is(HttpURLConnection.HTTP_CREATED));
906 String location = response.getLocation().getPath();
Ray Milkey8d076402015-08-31 15:43:18 -0700907 assertThat(location, Matchers.startsWith("/intents/myApp/"));
Ray Milkeyb82c42b2015-06-30 09:42:20 -0700908 }
Ray Milkey7b158512015-07-21 16:32:43 -0700909
910 /**
Ray Milkey05b169d2015-08-13 14:33:33 -0700911 * Tests creating an intent with POST and illegal JSON.
912 */
913 @Test
914 public void testBadPost() {
915 replay(mockCoreService);
916 replay(mockIntentService);
917
918 String json = "this is invalid!";
Jian Li9d616492016-03-09 10:52:49 -0800919 WebTarget wt = target();
Ray Milkey05b169d2015-08-13 14:33:33 -0700920
Jian Li9d616492016-03-09 10:52:49 -0800921 Response response = wt.path("intents")
922 .request(MediaType.APPLICATION_JSON_TYPE)
923 .post(Entity.json(json));
Ray Milkey05b169d2015-08-13 14:33:33 -0700924 assertThat(response.getStatus(), is(HttpURLConnection.HTTP_BAD_REQUEST));
925 }
926
927 /**
Ray Milkey7b158512015-07-21 16:32:43 -0700928 * Tests removing an intent with DELETE.
929 */
930 @Test
931 public void testRemove() {
932 final HashSet<NetworkResource> resources = new HashSet<>();
933 resources.add(new MockResource(1));
934 resources.add(new MockResource(2));
935 resources.add(new MockResource(3));
936 final Intent intent = new MockIntent(3L, resources);
937 final ApplicationId appId = new DefaultApplicationId(2, "app");
938 IntentService fakeManager = new FakeIntentManager();
939
940 expect(mockCoreService.getAppId("app"))
941 .andReturn(appId).once();
942 replay(mockCoreService);
943
944 mockIntentService.withdraw(anyObject());
945 expectLastCall().andDelegateTo(fakeManager).once();
946 expect(mockIntentService.getIntent(Key.of(2, appId)))
947 .andReturn(intent)
948 .once();
949 expect(mockIntentService.getIntent(Key.of("0x2", appId)))
950 .andReturn(null)
951 .once();
952
953 mockIntentService.addListener(anyObject());
954 expectLastCall().andDelegateTo(fakeManager).once();
955 mockIntentService.removeListener(anyObject());
956 expectLastCall().andDelegateTo(fakeManager).once();
957
958 replay(mockIntentService);
959
Jian Li9d616492016-03-09 10:52:49 -0800960 WebTarget wt = target();
Ray Milkey7b158512015-07-21 16:32:43 -0700961
Jian Li9d616492016-03-09 10:52:49 -0800962 Response response = wt.path("intents/app/0x2")
Ray Milkey7c251822016-04-06 17:38:25 -0700963 .request(MediaType.APPLICATION_JSON, MediaType.TEXT_PLAIN)
Jian Li9d616492016-03-09 10:52:49 -0800964 .delete();
Ray Milkey7b158512015-07-21 16:32:43 -0700965 assertThat(response.getStatus(), is(HttpURLConnection.HTTP_NO_CONTENT));
966 }
Ray Milkey05b169d2015-08-13 14:33:33 -0700967
968 /**
969 * Tests removal of a non existent intent with DELETE.
970 */
971 @Test
972 public void testBadRemove() {
973 final ApplicationId appId = new DefaultApplicationId(2, "app");
974
975 expect(mockCoreService.getAppId("app"))
976 .andReturn(appId).once();
977 replay(mockCoreService);
978
979 expect(mockIntentService.getIntent(Key.of(2, appId)))
980 .andReturn(null)
981 .once();
982 expect(mockIntentService.getIntent(Key.of("0x2", appId)))
983 .andReturn(null)
984 .once();
985
986 replay(mockIntentService);
987
Jian Li9d616492016-03-09 10:52:49 -0800988 WebTarget wt = target();
Ray Milkey05b169d2015-08-13 14:33:33 -0700989
Jian Li9d616492016-03-09 10:52:49 -0800990 Response response = wt.path("intents/app/0x2")
Ray Milkey7c251822016-04-06 17:38:25 -0700991 .request(MediaType.APPLICATION_JSON, MediaType.TEXT_PLAIN)
Jian Li9d616492016-03-09 10:52:49 -0800992 .delete();
Ray Milkey05b169d2015-08-13 14:33:33 -0700993 assertThat(response.getStatus(), is(HttpURLConnection.HTTP_NO_CONTENT));
994 }
995
Ray Milkey2b217142014-12-15 09:24:24 -0800996}