blob: 7867ab6a41f05d00cdeed282cd17f9b566a13f33 [file] [log] [blame]
Ray Milkey2b217142014-12-15 09:24:24 -08001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2016-present Open Networking Foundation
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;
Rafal Szaleckif97e0ed2017-06-01 13:07:18 +020022import com.fasterxml.jackson.databind.node.ObjectNode;
Ray Milkey2b217142014-12-15 09:24:24 -080023import org.hamcrest.Description;
Ray Milkeyb82c42b2015-06-30 09:42:20 -070024import org.hamcrest.Matchers;
Ray Milkey2b217142014-12-15 09:24:24 -080025import org.hamcrest.TypeSafeMatcher;
26import org.junit.After;
27import org.junit.Before;
28import org.junit.Test;
29import org.onlab.osgi.ServiceDirectory;
30import org.onlab.osgi.TestServiceDirectory;
Author Namee252a002016-09-26 22:42:24 +053031import org.onlab.packet.MacAddress;
Ray Milkey2b217142014-12-15 09:24:24 -080032import org.onosproject.codec.CodecService;
33import org.onosproject.codec.impl.CodecManager;
Rafal Szaleckif97e0ed2017-06-01 13:07:18 +020034import org.onosproject.codec.impl.MockCodecContext;
Ray Milkey2b217142014-12-15 09:24:24 -080035import org.onosproject.core.ApplicationId;
Ayaka Koshibec06c89b2015-02-10 19:25:41 -080036import org.onosproject.core.CoreService;
Ray Milkey2b217142014-12-15 09:24:24 -080037import org.onosproject.core.DefaultApplicationId;
Author Namee252a002016-09-26 22:42:24 +053038import org.onosproject.core.GroupId;
Rafal Szaleckif97e0ed2017-06-01 13:07:18 +020039import org.onosproject.net.ConnectPoint;
40import org.onosproject.net.DefaultLink;
Author Namee252a002016-09-26 22:42:24 +053041import org.onosproject.net.DeviceId;
David Glantzdfb3ceb2021-10-04 09:10:20 -050042import org.onosproject.net.FilteredConnectPoint;
43import org.onosproject.net.HostId;
Rafal Szaleckif97e0ed2017-06-01 13:07:18 +020044import org.onosproject.net.Link;
Ray Milkey2b217142014-12-15 09:24:24 -080045import org.onosproject.net.NetworkResource;
Rafal Szaleckif97e0ed2017-06-01 13:07:18 +020046import org.onosproject.net.PortNumber;
Author Namee252a002016-09-26 22:42:24 +053047import org.onosproject.net.flow.DefaultTrafficSelector;
48import org.onosproject.net.flow.DefaultTrafficTreatment;
49import org.onosproject.net.flow.FlowEntry;
Ray Milkey634eb172017-04-05 14:48:50 -070050import org.onosproject.net.flow.FlowEntryAdapter;
Author Namee252a002016-09-26 22:42:24 +053051import org.onosproject.net.flow.FlowId;
52import org.onosproject.net.flow.FlowRule;
Author Namee252a002016-09-26 22:42:24 +053053import org.onosproject.net.flow.FlowRuleService;
Carmelo Cascone41605742017-06-19 15:46:44 +090054import org.onosproject.net.flow.TableId;
Author Namee252a002016-09-26 22:42:24 +053055import org.onosproject.net.flow.TrafficSelector;
56import org.onosproject.net.flow.TrafficTreatment;
57import org.onosproject.net.flow.criteria.Criterion;
58import org.onosproject.net.flow.instructions.Instruction;
David Glantzdfb3ceb2021-10-04 09:10:20 -050059import org.onosproject.net.intent.ConnectivityIntent;
Ray Milkey7b158512015-07-21 16:32:43 -070060import org.onosproject.net.intent.FakeIntentManager;
Author Namee252a002016-09-26 22:42:24 +053061import org.onosproject.net.intent.FlowRuleIntent;
David Glantzdfb3ceb2021-10-04 09:10:20 -050062import org.onosproject.net.intent.HostToHostIntent;
Ray Milkey2b217142014-12-15 09:24:24 -080063import org.onosproject.net.intent.Intent;
Ray Milkey2b217142014-12-15 09:24:24 -080064import org.onosproject.net.intent.IntentService;
Ray Milkey1534f8d2015-05-13 15:42:50 -070065import org.onosproject.net.intent.IntentState;
Ray Milkeyf9af43c2015-02-09 16:45:48 -080066import org.onosproject.net.intent.Key;
Thomas Vachuska2048c1f2017-05-10 19:32:22 -070067import org.onosproject.net.intent.MockIdGenerator;
Ray Milkey39f78b62018-01-05 15:17:37 -080068import org.onosproject.net.intent.PathIntent;
David Glantzdfb3ceb2021-10-04 09:10:20 -050069import org.onosproject.net.intent.PointToPointIntent;
Rafal Szaleckif97e0ed2017-06-01 13:07:18 +020070import org.onosproject.net.provider.ProviderId;
Ray Milkey2b217142014-12-15 09:24:24 -080071
dvaddire95c84ed2017-06-14 15:42:24 +053072
Author Namee252a002016-09-26 22:42:24 +053073import javax.ws.rs.NotFoundException;
74import javax.ws.rs.client.Entity;
75import javax.ws.rs.client.WebTarget;
76import javax.ws.rs.core.MediaType;
77import javax.ws.rs.core.Response;
Rafal Szaleckif97e0ed2017-06-01 13:07:18 +020078import java.io.IOException;
Author Namee252a002016-09-26 22:42:24 +053079import java.io.InputStream;
80import java.net.HttpURLConnection;
81import java.util.ArrayList;
82import java.util.Collections;
83import java.util.HashSet;
84import java.util.List;
Rafal Szaleckif97e0ed2017-06-01 13:07:18 +020085import java.util.Set;
Author Namee252a002016-09-26 22:42:24 +053086import java.util.concurrent.TimeUnit;
Ray Milkey2b217142014-12-15 09:24:24 -080087
Author Namee252a002016-09-26 22:42:24 +053088import static java.util.concurrent.TimeUnit.SECONDS;
89import static org.easymock.EasyMock.*;
90import static org.hamcrest.Matchers.*;
Ray Milkey2b217142014-12-15 09:24:24 -080091import static org.junit.Assert.assertThat;
92import static org.junit.Assert.fail;
David Glantzdfb3ceb2021-10-04 09:10:20 -050093import static org.onosproject.net.NetTestTools.hid;
Ray Milkey43a28222015-02-23 13:57:58 -080094import static org.onosproject.net.intent.IntentTestsMocks.MockIntent;
Ray Milkey2b217142014-12-15 09:24:24 -080095
96/**
97 * Unit tests for Intents REST APIs.
98 */
Ray Milkey9c3d3362015-01-28 10:39:56 -080099public class IntentsResourceTest extends ResourceTest {
Author Namee252a002016-09-26 22:42:24 +0530100
101
102 private static final String APPID = "appId";
103 private static final String CRITERIA = "criteria";
104 private static final String DEVICE_ID = "deviceId";
105 private static final String ID = "id";
106 private static final String INSTRUCTIONS = "instructions";
107 private static final String PATHS = "paths";
Rafal Szaleckif97e0ed2017-06-01 13:07:18 +0200108 private static final String INSTALLABLES = "installables";
109 private static final String RESOURCES = "resources";
110 private static final String DEVICE = "device";
111 private static final String PORT = "port";
112 private static final String SRC = "src";
113 private static final String DST = "dst";
Author Namee252a002016-09-26 22:42:24 +0530114 private static final String SELECTOR = "selector";
115 private static final String SPACE = " ";
116 private static final String TREATMENT = "treatment";
117 private static final String TYPE = "type";
118
Ray Milkey2b217142014-12-15 09:24:24 -0800119 final IntentService mockIntentService = createMock(IntentService.class);
Ayaka Koshibec06c89b2015-02-10 19:25:41 -0800120 final CoreService mockCoreService = createMock(CoreService.class);
Author Namee252a002016-09-26 22:42:24 +0530121 final FlowRuleService mockFlowService = createMock(FlowRuleService.class);
Ray Milkey2b217142014-12-15 09:24:24 -0800122 final HashSet<Intent> intents = new HashSet<>();
Author Namee252a002016-09-26 22:42:24 +0530123 final List<org.onosproject.net.intent.Intent> installableIntents = new ArrayList<>();
Thomas Vachuska02aeb032015-01-06 22:36:30 -0800124 private static final ApplicationId APP_ID = new DefaultApplicationId(1, "test");
David Glantzdfb3ceb2021-10-04 09:10:20 -0500125 private static final ApplicationId APP_ID_2 = new DefaultApplicationId(2, "test2");
126
127 private final HostId hostId1 = hid("12:34:56:78:91:ab/1");
128 private final HostId hostId2 = hid("12:34:56:78:92:ab/1");
Ray Milkey2b217142014-12-15 09:24:24 -0800129
Author Namee252a002016-09-26 22:42:24 +0530130 final DeviceId deviceId1 = DeviceId.deviceId("1");
Rafal Szaleckif97e0ed2017-06-01 13:07:18 +0200131 final DeviceId deviceId2 = DeviceId.deviceId("2");
132 final DeviceId deviceId3 = DeviceId.deviceId("3");
133
134 final ConnectPoint connectPoint1 = new ConnectPoint(deviceId1, PortNumber.portNumber(1L));
135 final ConnectPoint connectPoint2 = new ConnectPoint(deviceId2, PortNumber.portNumber(1L));
136 final ConnectPoint connectPoint3 = new ConnectPoint(deviceId2, PortNumber.portNumber(2L));
137 final ConnectPoint connectPoint4 = new ConnectPoint(deviceId3, PortNumber.portNumber(1L));
Author Namee252a002016-09-26 22:42:24 +0530138
139 final TrafficTreatment treatment1 = DefaultTrafficTreatment.builder()
140 .setEthDst(MacAddress.BROADCAST)
141 .build();
142 final TrafficTreatment treatment2 = DefaultTrafficTreatment.builder()
143 .setEthDst(MacAddress.IPV4_MULTICAST)
144 .build();
145
146 final TrafficSelector selector1 = DefaultTrafficSelector.builder()
147 .matchEthType((short) 3)
148 .matchIPProtocol((byte) 9)
149 .build();
150 final TrafficSelector selector2 = DefaultTrafficSelector.builder()
151 .matchEthType((short) 4)
152 .matchIPProtocol((byte) 10)
153 .build();
154
155 final MockFlowEntry flow1 = new MockFlowEntry(deviceId1, 1, treatment1, selector1);
156 final MockFlowEntry flow2 = new MockFlowEntry(deviceId1, 2, treatment2, selector2);
157
158 final MockFlowRule flowRule1 = new MockFlowRule(deviceId1, 1, treatment1, selector1);
159 final MockFlowRule flowRule2 = new MockFlowRule(deviceId1, 2, treatment2, selector2);
160
Ray Milkey2b217142014-12-15 09:24:24 -0800161 private class MockResource implements NetworkResource {
162 int id;
163
164 MockResource(int id) {
165 this.id = id;
166 }
167
Ayaka Koshibec06c89b2015-02-10 19:25:41 -0800168 @Override
Ray Milkey2b217142014-12-15 09:24:24 -0800169 public String toString() {
170 return "Resource " + Integer.toString(id);
171 }
172 }
173
Ray Milkey2b217142014-12-15 09:24:24 -0800174 /**
Author Namee252a002016-09-26 22:42:24 +0530175 * Mock class for a flow entry.
176 */
Ray Milkey634eb172017-04-05 14:48:50 -0700177 private static class MockFlowEntry extends FlowEntryAdapter {
Author Namee252a002016-09-26 22:42:24 +0530178 final DeviceId deviceId;
179 final long baseValue;
180 TrafficTreatment treatment;
181 TrafficSelector selector;
182
183 public MockFlowEntry(DeviceId deviceId, long id,
184 TrafficTreatment treatment,
185 TrafficSelector selector) {
186 this.deviceId = deviceId;
187 this.baseValue = id * 100;
188 this.treatment = treatment;
189 this.selector = selector;
190 }
191
192 @Override
Author Namee252a002016-09-26 22:42:24 +0530193 public long life() {
194 return life(SECONDS);
195 }
196
197 @Override
kalagesa42019542017-03-14 18:00:47 +0530198 public FlowLiveType liveType() {
199 return FlowLiveType.IMMEDIATE;
200 }
201
202 @Override
Author Namee252a002016-09-26 22:42:24 +0530203 public long life(TimeUnit timeUnit) {
204 return SECONDS.convert(baseValue + 11, timeUnit);
205 }
206
207 @Override
208 public long packets() {
209 return baseValue + 22;
210 }
211
212 @Override
213 public long bytes() {
214 return baseValue + 33;
215 }
216
217 @Override
218 public long lastSeen() {
219 return baseValue + 44;
220 }
221
222 @Override
Author Namee252a002016-09-26 22:42:24 +0530223 public FlowId id() {
224 final long id = baseValue + 55;
225 return FlowId.valueOf(id);
226 }
227
228 @Override
229 public GroupId groupId() {
Yi Tsengfa394de2017-02-01 11:26:40 -0800230 return new GroupId(3);
Author Namee252a002016-09-26 22:42:24 +0530231 }
232
233 @Override
234 public short appId() {
235 return 1;
236 }
237
238 @Override
239 public int priority() {
240 return (int) (baseValue + 66);
241 }
242
243 @Override
244 public DeviceId deviceId() {
245 return deviceId;
246 }
247
248 @Override
249 public TrafficSelector selector() {
250 return selector;
251 }
252
253 @Override
254 public TrafficTreatment treatment() {
255 return treatment;
256 }
257
258 @Override
259 public int timeout() {
260 return (int) (baseValue + 77);
261 }
262
Author Namee252a002016-09-26 22:42:24 +0530263
264 @Override
265 public boolean exactMatch(FlowRule rule) {
266 return this.appId() == rule.appId() &&
267 this.deviceId().equals(rule.deviceId()) &&
268 this.id().equals(rule.id()) &&
269 this.treatment.equals(rule.treatment()) &&
270 this.selector().equals(rule.selector());
271 }
272
273 @Override
Author Namee252a002016-09-26 22:42:24 +0530274 public String toString() {
275 return id().id().toString();
276 }
277 }
278
279 /**
280 * Mock class for a flow rule.
281 */
282 private static class MockFlowRule implements FlowRule {
283
284 final DeviceId deviceId;
285 final long baseValue;
286 TrafficTreatment treatment;
287 TrafficSelector selector;
288
289 public MockFlowRule(DeviceId deviceId,
290 long id,
291 TrafficTreatment treatment,
292 TrafficSelector selector) {
293 this.deviceId = deviceId;
294 this.baseValue = id * 100;
295 this.treatment = treatment;
296 this.selector = selector;
297 }
298
299 @Override
300 public FlowId id() {
301 long id = baseValue + 55;
302 return FlowId.valueOf(id);
303 }
304
305 @Override
306 public short appId() {
307 return 1;
308 }
309
310 @Override
311 public GroupId groupId() {
Yi Tsengfa394de2017-02-01 11:26:40 -0800312 return new GroupId(3);
Author Namee252a002016-09-26 22:42:24 +0530313 }
314
315 @Override
316 public int priority() {
317 return 0;
318 }
319
320 @Override
321 public DeviceId deviceId() {
322 return deviceId;
323 }
324
325 @Override
326 public TrafficSelector selector() {
327 return selector;
328 }
329
330 @Override
331 public TrafficTreatment treatment() {
332 return treatment;
333 }
334
335 @Override
336 public int timeout() {
337 return (int) (baseValue + 77);
338 }
339
340 @Override
341 public int hardTimeout() {
342 return 0;
343 }
344
345 @Override
346 public FlowRemoveReason reason() {
347 return FlowRemoveReason.NO_REASON;
348 }
349
350 @Override
351 public boolean isPermanent() {
352 return false;
353 }
354
355 @Override
356 public int tableId() {
357 return 0;
358 }
359
360 @Override
Carmelo Cascone41605742017-06-19 15:46:44 +0900361 public TableId table() {
362 return DEFAULT_TABLE;
363 }
364
365 @Override
Author Namee252a002016-09-26 22:42:24 +0530366 public boolean exactMatch(FlowRule rule) {
367 return false;
368 }
Author Namee252a002016-09-26 22:42:24 +0530369 }
370
371 /**
Ray Milkey2b217142014-12-15 09:24:24 -0800372 * Hamcrest matcher to check that an intent representation in JSON matches
373 * the actual intent.
374 */
375 public static class IntentJsonMatcher extends TypeSafeMatcher<JsonObject> {
376 private final Intent intent;
David Glantzdfb3ceb2021-10-04 09:10:20 -0500377 private boolean detail = false;
Ray Milkey2b217142014-12-15 09:24:24 -0800378 private String reason = "";
379
380 public IntentJsonMatcher(Intent intentValue) {
381 intent = intentValue;
382 }
383
David Glantzdfb3ceb2021-10-04 09:10:20 -0500384 public IntentJsonMatcher(Intent intentValue, boolean detailValue) {
385 intent = intentValue;
386 detail = detailValue;
387 }
388
Ray Milkey2b217142014-12-15 09:24:24 -0800389 @Override
390 public boolean matchesSafely(JsonObject jsonIntent) {
391 // check id
392 final String jsonId = jsonIntent.get("id").asString();
393 if (!jsonId.equals(intent.id().toString())) {
394 reason = "id " + intent.id().toString();
395 return false;
396 }
397
398 // check application id
Ray Milkeyf7cb4012015-07-20 13:01:07 -0700399
Ray Milkey2b217142014-12-15 09:24:24 -0800400 final String jsonAppId = jsonIntent.get("appId").asString();
Ray Milkeyf7cb4012015-07-20 13:01:07 -0700401 final String appId = intent.appId().name();
402 if (!jsonAppId.equals(appId)) {
403 reason = "appId was " + jsonAppId;
Ray Milkey2b217142014-12-15 09:24:24 -0800404 return false;
405 }
406
407 // check intent type
408 final String jsonType = jsonIntent.get("type").asString();
Rafal Szaleckif97e0ed2017-06-01 13:07:18 +0200409 if (!intent.getClass().getSimpleName().equals(jsonType)) {
Ray Milkey2b217142014-12-15 09:24:24 -0800410 reason = "type MockIntent";
411 return false;
412 }
413
Ray Milkey1534f8d2015-05-13 15:42:50 -0700414 // check state field
415 final String jsonState = jsonIntent.get("state").asString();
Jon Halla3fcf672017-03-28 16:53:22 -0700416 if (!"INSTALLED".equals(jsonState)) {
Ray Milkey1534f8d2015-05-13 15:42:50 -0700417 reason = "state INSTALLED";
418 return false;
419 }
420
Ray Milkey2b217142014-12-15 09:24:24 -0800421 // check resources array
422 final JsonArray jsonResources = jsonIntent.get("resources").asArray();
423 if (intent.resources() != null) {
424 if (intent.resources().size() != jsonResources.size()) {
425 reason = "resources array size of " + Integer.toString(intent.resources().size());
426 return false;
427 }
428 for (final NetworkResource resource : intent.resources()) {
429 boolean resourceFound = false;
430 final String resourceString = resource.toString();
Rafal Szaleckif97e0ed2017-06-01 13:07:18 +0200431
432 if (resource instanceof Link) {
433 final Link resourceLink = (Link) resource;
434 MockCodecContext codecContext = new MockCodecContext();
435
436 for (int resourceIndex = 0; resourceIndex < jsonResources.size(); resourceIndex++) {
437 final ObjectNode value;
438 try {
439 value = (ObjectNode) codecContext.mapper()
440 .readTree(jsonResources.get(resourceIndex).toString());
441 } catch (IOException e) {
442 reason = "bad json";
443 return false;
444 }
445 final Link link = codecContext.codec(Link.class).decode(value, codecContext);
446 if (resourceLink.equals(link)) {
447 resourceFound = true;
448 }
449 }
450 } else {
451
452 for (int resourceIndex = 0; resourceIndex < jsonResources.size(); resourceIndex++) {
453 final JsonValue value = jsonResources.get(resourceIndex);
454 if (value.asString().equals(resourceString)) {
455 resourceFound = true;
456 }
Ray Milkey2b217142014-12-15 09:24:24 -0800457 }
458 }
459 if (!resourceFound) {
460 reason = "resource " + resourceString;
461 return false;
462 }
463 }
464 } else if (jsonResources.size() != 0) {
465 reason = "resources array empty";
466 return false;
467 }
David Glantzdfb3ceb2021-10-04 09:10:20 -0500468
469 if (intent instanceof ConnectivityIntent && detail) {
470 return matchConnectivityIntent(jsonIntent);
471 }
472
Ray Milkey2b217142014-12-15 09:24:24 -0800473 return true;
474 }
475
David Glantzdfb3ceb2021-10-04 09:10:20 -0500476 public boolean matchesConnectPoint(ConnectPoint connectPoint, JsonObject jsonConnectPoint) {
477 // check device
478 final String jsonDevice = jsonConnectPoint.get("device").asString();
479 final String device = connectPoint.deviceId().toString();
480 if (!jsonDevice.equals(device)) {
481 reason = "device was " + jsonDevice;
482 return false;
483 }
484
485 // check port
486 final String jsonPort = jsonConnectPoint.get("port").asString();
487 final String port = connectPoint.port().toString();
488 if (!jsonPort.equals(port)) {
489 reason = "port was " + jsonPort;
490 return false;
491 }
492
493 return true;
494 }
495
496 private boolean matchHostToHostIntent(JsonObject jsonIntent) {
497 final HostToHostIntent hostToHostIntent = (HostToHostIntent) intent;
498
499 // check host one
500 final String host1 = hostToHostIntent.one().toString();
501 final String jsonHost1 = jsonIntent.get("one").asString();
502 if (!host1.equals(jsonHost1)) {
503 reason = "host one was " + jsonHost1;
504 return false;
505 }
506
507 // check host 2
508 final String host2 = hostToHostIntent.two().toString();
509 final String jsonHost2 = jsonIntent.get("two").asString();
510 if (!host2.equals(jsonHost2)) {
511 reason = "host two was " + jsonHost2;
512 return false;
513 }
514 return true;
515 }
516
517 /**
518 * Matches the JSON representation of a point to point intent.
519 *
520 * @param jsonIntent JSON representation of the intent
521 * @return true if the JSON matches the intent, false otherwise
522 */
523 private boolean matchPointToPointIntent(JsonObject jsonIntent) {
524 final PointToPointIntent pointToPointIntent = (PointToPointIntent) intent;
525
526 // check ingress connection
527 final ConnectPoint ingress = pointToPointIntent.filteredIngressPoint().connectPoint();
528 final JsonObject jsonIngress = jsonIntent.get("ingressPoint").asObject();
529 final boolean ingressMatches = matchesConnectPoint(ingress, jsonIngress);
530
531 if (!ingressMatches) {
532 reason = "ingress was " + jsonIngress;
533 return false;
534 }
535
536 // check egress connection
537 final ConnectPoint egress = pointToPointIntent.filteredEgressPoint().connectPoint();
538 final JsonObject jsonEgress = jsonIntent.get("egressPoint").asObject();
539 final boolean egressMatches = matchesConnectPoint(egress, jsonEgress);
540
541 if (!egressMatches) {
542 reason = "egress was " + jsonEgress;
543 return false;
544 }
545
546 return true;
547 }
548
549 /**
550 * Matches the JSON representation of a connectivity intent. Calls the
551 * matcher for the connectivity intent subtype.
552 *
553 * @param jsonIntent JSON representation of the intent
554 * @return true if the JSON matches the intent, false otherwise
555 */
556 private boolean matchConnectivityIntent(JsonObject jsonIntent) {
557 final ConnectivityIntent connectivityIntent = (ConnectivityIntent) intent;
558
559 // check selector
560 final JsonObject jsonSelector = jsonIntent.get("selector").asObject();
561 final TrafficSelector selector = connectivityIntent.selector();
562 final Set<Criterion> criteria = selector.criteria();
563 final JsonArray jsonCriteria = jsonSelector.get("criteria").asArray();
564 if (jsonCriteria.size() != criteria.size()) {
565 reason = "size of criteria array is " + Integer.toString(jsonCriteria.size());
566 return false;
567 }
568
569 // check treatment
570 final JsonObject jsonTreatment = jsonIntent.get("treatment").asObject();
571 final TrafficTreatment treatment = connectivityIntent.treatment();
572 final List<Instruction> instructions = treatment.immediate();
573 final JsonArray jsonInstructions = jsonTreatment.get("instructions").asArray();
574 if (jsonInstructions.size() != instructions.size()) {
575 reason = "size of instructions array is " + Integer.toString(jsonInstructions.size());
576 return false;
577 }
578
579 // Check constraints
580 final JsonArray jsonConstraints = jsonIntent.get("constraints").asArray();
581 if (connectivityIntent.constraints() != null) {
582 if (connectivityIntent.constraints().size() != jsonConstraints.size()) {
583 reason = "constraints array size was " + Integer.toString(jsonConstraints.size());
584 return false;
585 }
586 } else if (jsonConstraints.size() != 0) {
587 reason = "constraint array not empty";
588 return false;
589 }
590
591 if (connectivityIntent instanceof HostToHostIntent) {
592 return matchHostToHostIntent(jsonIntent);
593 } else if (connectivityIntent instanceof PointToPointIntent) {
594 return matchPointToPointIntent(jsonIntent);
595 } else {
596 reason = "class of connectivity intent is unknown";
597 return false;
598 }
599 }
600
Ray Milkey2b217142014-12-15 09:24:24 -0800601 @Override
602 public void describeTo(Description description) {
603 description.appendText(reason);
604 }
605 }
606
607 /**
608 * Factory to allocate an intent matcher.
609 *
610 * @param intent intent object we are looking for
David Glantzdfb3ceb2021-10-04 09:10:20 -0500611 * @param detail flag to verify if JSON contains detailed attributes for the intent's implementation class.
Ray Milkey2b217142014-12-15 09:24:24 -0800612 * @return matcher
613 */
David Glantzdfb3ceb2021-10-04 09:10:20 -0500614 private static IntentJsonMatcher matchesIntent(Intent intent, boolean detail) {
615 return new IntentJsonMatcher(intent, detail);
Ray Milkey2b217142014-12-15 09:24:24 -0800616 }
617
618 /**
Author Namee252a002016-09-26 22:42:24 +0530619 * Factory to allocate an IntentRelatedFlows matcher.
620 *
dvaddire95c84ed2017-06-14 15:42:24 +0530621 * @param pathEntries list of path conatining flow entries of a particular intent
Author Namee252a002016-09-26 22:42:24 +0530622 * @param expectedAppId expected app id we are looking for
623 * @return matcher
624 */
625 private static IntentStatsJsonMatcher matchesRelatedFlowEntries(
626 List<List<FlowEntry>> pathEntries,
627 final String expectedAppId) {
628 return new IntentStatsJsonMatcher(pathEntries, expectedAppId);
629 }
630
631 /**
632 * Hamcrest matcher to check that an list of flowEntries in JSON matches
633 * the actual list of flow entries.
634 */
635 public static class IntentStatsJsonMatcher extends
636 TypeSafeMatcher<JsonObject> {
637
638 private final List<List<FlowEntry>> pathEntries;
639 private final String expectedAppId;
640 private String reason = "";
641
642 public IntentStatsJsonMatcher(
643 final List<List<FlowEntry>> pathEntries,
644 final String expectedAppId) {
645 this.pathEntries = pathEntries;
646 this.expectedAppId = expectedAppId;
647 }
648
649 @Override
650 public boolean matchesSafely(JsonObject jsonIntent) {
651 int jsonPathIndex = 0;
652 JsonArray jsonPaths = jsonIntent.get(PATHS).asArray();
653
654 if (pathEntries != null) {
655
rohitsharanfd747602017-01-23 21:57:28 +0530656 if (pathEntries.size() == 0) {
657 reason = "pathEntries array empty";
658 return false;
659 }
660
Author Namee252a002016-09-26 22:42:24 +0530661 if (pathEntries.size() != jsonPaths.size()) {
662 reason = "path entries array size of " +
663 Integer.toString(pathEntries.size());
664 return false;
665 }
666
667 for (List<FlowEntry> flowEntries : pathEntries) {
668 JsonArray jsonFlowEntries = jsonPaths.get(
669 jsonPathIndex++).asArray();
670
671 if (flowEntries.size() != jsonFlowEntries.size()) {
672 reason = "flow entries array size of " +
673 Integer.toString(pathEntries.size());
674
675 return false;
676 }
677
678 int jsonFlowEntryIndex = 0;
679 for (FlowEntry flow : flowEntries) {
680
681 JsonObject jsonFlow = jsonFlowEntries.get(
682 jsonFlowEntryIndex++).asObject();
683
684 String jsonId = jsonFlow.get(ID).asString();
685 String flowId = Long.toString(flow.id().value());
686 if (!jsonId.equals(flowId)) {
687 reason = ID + SPACE + flow.id();
688 return false;
689 }
690
691 // check application id
692 String jsonAppId = jsonFlow.get(APPID).asString();
693 if (!jsonAppId.equals(expectedAppId)) {
694 reason = APPID + SPACE + Short.toString(flow.appId());
695 return false;
696 }
697
698 // check device id
699 String jsonDeviceId =
700 jsonFlow.get(DEVICE_ID).asString();
701
702 if (!jsonDeviceId.equals(flow.deviceId().toString())) {
703 reason = DEVICE_ID + SPACE + flow.deviceId();
704 return false;
705 }
706
707 if (!checkFlowTreatment(flow, jsonFlow)) {
708 return false;
709 }
710
711 if (!checkFlowSelector(flow, jsonFlow)) {
712 return false;
713 }
714
715 }
716
717 }
rohitsharanfd747602017-01-23 21:57:28 +0530718 } else {
Author Namee252a002016-09-26 22:42:24 +0530719 reason = "pathEntries array empty";
720 return false;
721 }
722
723 return true;
724 }
725
726 // check treatment and instructions array.
727 private boolean checkFlowTreatment(FlowEntry flow, JsonObject jsonFlow) {
728
729 if (flow.treatment() != null) {
730 JsonObject jsonTreatment =
731 jsonFlow.get(TREATMENT).asObject();
732 JsonArray jsonInstructions =
733 jsonTreatment.get(INSTRUCTIONS).asArray();
734
735 if (flow.treatment().immediate().size() !=
736 jsonInstructions.size()) {
737 reason = "instructions array size of " +
738 flow.treatment().immediate().size();
739
740 return false;
741 }
742 for (Instruction instruction :
743 flow.treatment().immediate()) {
744 boolean instructionFound = false;
745 for (int instructionIndex = 0;
746 instructionIndex < jsonInstructions.size();
747 instructionIndex++) {
748 String jsonType =
749 jsonInstructions.get(instructionIndex)
750 .asObject().get(TYPE).asString();
751
752 String instructionType =
753 instruction.type().name();
754
755 if (jsonType.equals(instructionType)) {
756 instructionFound = true;
757 }
758 }
759 if (!instructionFound) {
760 reason = INSTRUCTIONS + SPACE + instruction;
761 return false;
762 }
763 }
764 }
765 return true;
766 }
767
768 // check selector and criteria array.
769 private boolean checkFlowSelector(FlowEntry flow, JsonObject jsonFlow) {
770
771 if (flow.selector() != null) {
772 JsonObject jsonTreatment =
773 jsonFlow.get(SELECTOR).asObject();
774
775 JsonArray jsonCriteria =
776 jsonTreatment.get(CRITERIA).asArray();
777
778 if (flow.selector().criteria().size() != jsonCriteria.size()) {
779 reason = CRITERIA + " array size of " +
780 Integer.toString(flow.selector().criteria().size());
781 return false;
782 }
783 for (Criterion criterion : flow.selector().criteria()) {
784 boolean criterionFound = false;
785
786 for (int criterionIndex = 0;
787 criterionIndex < jsonCriteria.size();
788 criterionIndex++) {
789 String jsonType =
790 jsonCriteria.get(criterionIndex)
791 .asObject().get(TYPE).asString();
792 String criterionType = criterion.type().name();
793 if (jsonType.equals(criterionType)) {
794 criterionFound = true;
795 }
796 }
797 if (!criterionFound) {
798 reason = "criterion " + criterion;
799 return false;
800 }
801 }
802 }
803 return true;
804 }
805
806 @Override
807 public void describeTo(Description description) {
808 description.appendText(reason);
809 }
810 }
811
812 /**
Ray Milkey2b217142014-12-15 09:24:24 -0800813 * Hamcrest matcher to check that an intent is represented properly in a JSON
814 * array of intents.
815 */
816 public static class IntentJsonArrayMatcher extends TypeSafeMatcher<JsonArray> {
817 private final Intent intent;
David Glantzdfb3ceb2021-10-04 09:10:20 -0500818 private boolean detail = false;
Ray Milkey2b217142014-12-15 09:24:24 -0800819 private String reason = "";
820
David Glantzdfb3ceb2021-10-04 09:10:20 -0500821 public IntentJsonArrayMatcher(Intent intentValue, boolean detailValue) {
Ray Milkey2b217142014-12-15 09:24:24 -0800822 intent = intentValue;
David Glantzdfb3ceb2021-10-04 09:10:20 -0500823 detail = detailValue;
Ray Milkey2b217142014-12-15 09:24:24 -0800824 }
825
826 @Override
827 public boolean matchesSafely(JsonArray json) {
828 boolean intentFound = false;
Antonio Marsico4f68ec92017-03-09 11:16:32 +0100829 final int expectedAttributes = 6;
Ray Milkey2b217142014-12-15 09:24:24 -0800830 for (int jsonIntentIndex = 0; jsonIntentIndex < json.size();
831 jsonIntentIndex++) {
832
833 final JsonObject jsonIntent = json.get(jsonIntentIndex).asObject();
834
David Glantzdfb3ceb2021-10-04 09:10:20 -0500835 if (jsonIntent.names().size() != expectedAttributes && !detail) {
Ray Milkey2b217142014-12-15 09:24:24 -0800836 reason = "Found an intent with the wrong number of attributes";
837 return false;
838 }
839
840 final String jsonIntentId = jsonIntent.get("id").asString();
841 if (jsonIntentId.equals(intent.id().toString())) {
842 intentFound = true;
843
844 // We found the correct intent, check attribute values
David Glantzdfb3ceb2021-10-04 09:10:20 -0500845 assertThat(jsonIntent, matchesIntent(intent, detail));
Ray Milkey2b217142014-12-15 09:24:24 -0800846 }
847 }
848 if (!intentFound) {
849 reason = "Intent with id " + intent.id().toString() + " not found";
850 return false;
851 } else {
852 return true;
853 }
854 }
855
856 @Override
857 public void describeTo(Description description) {
858 description.appendText(reason);
859 }
860 }
861
862 /**
863 * Factory to allocate an intent array matcher.
864 *
865 * @param intent intent object we are looking for
David Glantzdfb3ceb2021-10-04 09:10:20 -0500866 * @param detail flag to verify if JSON contains detailed attributes for the intent's implementation class.
Ray Milkey2b217142014-12-15 09:24:24 -0800867 * @return matcher
868 */
David Glantzdfb3ceb2021-10-04 09:10:20 -0500869 private static IntentJsonArrayMatcher hasIntent(Intent intent, boolean detail) {
870 return new IntentJsonArrayMatcher(intent, detail);
Ray Milkey2b217142014-12-15 09:24:24 -0800871 }
Ray Milkey4f5de002014-12-17 19:26:11 -0800872
Ray Milkeyed0b1662015-02-05 09:34:29 -0800873 /**
874 * Initializes test mocks and environment.
875 */
Ray Milkey2b217142014-12-15 09:24:24 -0800876 @Before
Ray Milkeyed0b1662015-02-05 09:34:29 -0800877 public void setUpTest() {
Ray Milkey2b217142014-12-15 09:24:24 -0800878 expect(mockIntentService.getIntents()).andReturn(intents).anyTimes();
Ray Milkey1534f8d2015-05-13 15:42:50 -0700879 expect(mockIntentService.getIntentState(anyObject()))
880 .andReturn(IntentState.INSTALLED)
881 .anyTimes();
Ray Milkey2b217142014-12-15 09:24:24 -0800882 // Register the services needed for the test
dvaddire95c84ed2017-06-14 15:42:24 +0530883 final CodecManager codecService = new CodecManager();
Ray Milkey2b217142014-12-15 09:24:24 -0800884 codecService.activate();
885 ServiceDirectory testDirectory =
886 new TestServiceDirectory()
887 .add(IntentService.class, mockIntentService)
Author Namee252a002016-09-26 22:42:24 +0530888 .add(FlowRuleService.class, mockFlowService)
Ayaka Koshibec06c89b2015-02-10 19:25:41 -0800889 .add(CodecService.class, codecService)
890 .add(CoreService.class, mockCoreService);
Ray Milkey2b217142014-12-15 09:24:24 -0800891
Ray Milkey094a1352018-01-22 14:03:54 -0800892 setServiceDirectory(testDirectory);
Ray Milkey2b217142014-12-15 09:24:24 -0800893
Thomas Vachuska2048c1f2017-05-10 19:32:22 -0700894 MockIdGenerator.cleanBind();
Ray Milkey2b217142014-12-15 09:24:24 -0800895 }
896
Ray Milkeyed0b1662015-02-05 09:34:29 -0800897 /**
898 * Tears down and verifies test mocks and environment.
899 */
Ray Milkey2b217142014-12-15 09:24:24 -0800900 @After
Ray Milkeyed0b1662015-02-05 09:34:29 -0800901 public void tearDownTest() {
Thomas Vachuska2048c1f2017-05-10 19:32:22 -0700902 MockIdGenerator.unbind();
Ray Milkey2b217142014-12-15 09:24:24 -0800903 verify(mockIntentService);
Ray Milkey2b217142014-12-15 09:24:24 -0800904 }
905
906 /**
907 * Tests the result of the rest api GET when there are no intents.
908 */
909 @Test
910 public void testIntentsEmptyArray() {
911 replay(mockIntentService);
Jian Li9d616492016-03-09 10:52:49 -0800912 final WebTarget wt = target();
913 final String response = wt.path("intents").request().get(String.class);
Ray Milkey2b217142014-12-15 09:24:24 -0800914 assertThat(response, is("{\"intents\":[]}"));
915 }
916
917 /**
918 * Tests the result of the rest api GET when intents are defined.
919 */
920 @Test
921 public void testIntentsArray() {
922 replay(mockIntentService);
923
Ray Milkey43a28222015-02-23 13:57:58 -0800924 final Intent intent1 = new MockIntent(1L, Collections.emptyList());
Ray Milkey2b217142014-12-15 09:24:24 -0800925 final HashSet<NetworkResource> resources = new HashSet<>();
926 resources.add(new MockResource(1));
927 resources.add(new MockResource(2));
928 resources.add(new MockResource(3));
Ray Milkey43a28222015-02-23 13:57:58 -0800929 final Intent intent2 = new MockIntent(2L, resources);
Ray Milkey2b217142014-12-15 09:24:24 -0800930
931 intents.add(intent1);
932 intents.add(intent2);
Jian Li9d616492016-03-09 10:52:49 -0800933 final WebTarget wt = target();
934 final String response = wt.path("intents").request().get(String.class);
Ray Milkey2b217142014-12-15 09:24:24 -0800935 assertThat(response, containsString("{\"intents\":["));
936
Jian Li80cfe452016-01-14 16:04:58 -0800937 final JsonObject result = Json.parse(response).asObject();
Ray Milkey2b217142014-12-15 09:24:24 -0800938 assertThat(result, notNullValue());
939
940 assertThat(result.names(), hasSize(1));
941 assertThat(result.names().get(0), is("intents"));
942
943 final JsonArray jsonIntents = result.get("intents").asArray();
944 assertThat(jsonIntents, notNullValue());
945
David Glantzdfb3ceb2021-10-04 09:10:20 -0500946 assertThat(jsonIntents, hasIntent(intent1, false));
947 assertThat(jsonIntents, hasIntent(intent2, false));
Ray Milkey2b217142014-12-15 09:24:24 -0800948 }
949
950 /**
951 * Tests the result of a rest api GET for a single intent.
952 */
953 @Test
954 public void testIntentsSingle() {
955 final HashSet<NetworkResource> resources = new HashSet<>();
956 resources.add(new MockResource(1));
957 resources.add(new MockResource(2));
958 resources.add(new MockResource(3));
Ray Milkey43a28222015-02-23 13:57:58 -0800959 final Intent intent = new MockIntent(3L, resources);
Ray Milkey2b217142014-12-15 09:24:24 -0800960
961 intents.add(intent);
962
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800963 expect(mockIntentService.getIntent(Key.of(0, APP_ID)))
Ray Milkey2b217142014-12-15 09:24:24 -0800964 .andReturn(intent)
965 .anyTimes();
Ayaka Koshibec06c89b2015-02-10 19:25:41 -0800966 expect(mockIntentService.getIntent(Key.of("0", APP_ID)))
967 .andReturn(intent)
968 .anyTimes();
Ray Milkey05b169d2015-08-13 14:33:33 -0700969 expect(mockIntentService.getIntent(Key.of(0, APP_ID)))
970 .andReturn(intent)
971 .anyTimes();
972 expect(mockIntentService.getIntent(Key.of("0x0", APP_ID)))
973 .andReturn(null)
974 .anyTimes();
Ray Milkey2b217142014-12-15 09:24:24 -0800975 replay(mockIntentService);
Ray Milkeyf7cb4012015-07-20 13:01:07 -0700976 expect(mockCoreService.getAppId(APP_ID.name()))
Ayaka Koshibec06c89b2015-02-10 19:25:41 -0800977 .andReturn(APP_ID).anyTimes();
978 replay(mockCoreService);
Jian Li9d616492016-03-09 10:52:49 -0800979 final WebTarget wt = target();
Ray Milkey05b169d2015-08-13 14:33:33 -0700980
981 // Test get using key string
Jian Li9d616492016-03-09 10:52:49 -0800982 final String response = wt.path("intents/" + APP_ID.name()
983 + "/0").request().get(String.class);
Jian Li80cfe452016-01-14 16:04:58 -0800984 final JsonObject result = Json.parse(response).asObject();
David Glantzdfb3ceb2021-10-04 09:10:20 -0500985 assertThat(result, matchesIntent(intent, true));
Ray Milkey05b169d2015-08-13 14:33:33 -0700986
987 // Test get using numeric value
Jian Li9d616492016-03-09 10:52:49 -0800988 final String responseNumeric = wt.path("intents/" + APP_ID.name()
989 + "/0x0").request().get(String.class);
Jian Li80cfe452016-01-14 16:04:58 -0800990 final JsonObject resultNumeric = Json.parse(responseNumeric).asObject();
David Glantzdfb3ceb2021-10-04 09:10:20 -0500991 assertThat(resultNumeric, matchesIntent(intent, true));
992 }
993
994 /**
995 * Tests the result of the rest api GET when intents are defined and the detail flag is false.
996 */
997 @Test
998 public void testIntentsArrayWithoutDetail() {
999 replay(mockIntentService);
1000
1001 final PointToPointIntent intent1 =
1002 PointToPointIntent.builder()
1003 .appId(APP_ID)
1004 .selector(selector1)
1005 .treatment(treatment1)
1006 .filteredIngressPoint(new FilteredConnectPoint(connectPoint1))
1007 .filteredEgressPoint(new FilteredConnectPoint(connectPoint2))
1008 .build();
1009
1010 final HashSet<NetworkResource> resources = new HashSet<>();
1011 resources.add(new MockResource(1));
1012 resources.add(new MockResource(2));
1013 resources.add(new MockResource(3));
1014
1015 final HostToHostIntent intent2 =
1016 HostToHostIntent.builder()
1017 .appId(APP_ID)
1018 .selector(selector2)
1019 .treatment(treatment2)
1020 .one(hostId1)
1021 .two(hostId2)
1022 .build();
1023
1024 intents.add(intent1);
1025 intents.add(intent2);
1026
1027 final WebTarget wt = target();
1028 final String response = wt.path("intents").queryParam("detail", false).request().get(String.class);
1029 assertThat(response, containsString("{\"intents\":["));
1030
1031 final JsonObject result = Json.parse(response).asObject();
1032 assertThat(result, notNullValue());
1033
1034 assertThat(result.names(), hasSize(1));
1035 assertThat(result.names().get(0), is("intents"));
1036
1037 final JsonArray jsonIntents = result.get("intents").asArray();
1038 assertThat(jsonIntents, notNullValue());
1039
1040 assertThat(jsonIntents, hasIntent(intent1, false));
1041 }
1042
1043 /**
1044 * Tests the result of the rest api GET when intents are defined and the detail flag is true.
1045 */
1046 @Test
1047 public void testIntentsArrayWithDetail() {
1048 replay(mockIntentService);
1049
1050 final PointToPointIntent intent1 =
1051 PointToPointIntent.builder()
1052 .appId(APP_ID)
1053 .selector(selector1)
1054 .treatment(treatment1)
1055 .filteredIngressPoint(new FilteredConnectPoint(connectPoint1))
1056 .filteredEgressPoint(new FilteredConnectPoint(connectPoint2))
1057 .build();
1058
1059 final HashSet<NetworkResource> resources = new HashSet<>();
1060 resources.add(new MockResource(1));
1061 resources.add(new MockResource(2));
1062 resources.add(new MockResource(3));
1063
1064 final HostToHostIntent intent2 =
1065 HostToHostIntent.builder()
1066 .appId(APP_ID)
1067 .selector(selector2)
1068 .treatment(treatment2)
1069 .one(hostId1)
1070 .two(hostId2)
1071 .build();
1072
1073 intents.add(intent1);
1074 intents.add(intent2);
1075
1076 final WebTarget wt = target();
1077 final String response = wt.path("intents").queryParam("detail", true).request().get(String.class);
1078 assertThat(response, containsString("{\"intents\":["));
1079
1080 final JsonObject result = Json.parse(response).asObject();
1081 assertThat(result, notNullValue());
1082
1083 assertThat(result.names(), hasSize(1));
1084 assertThat(result.names().get(0), is("intents"));
1085
1086 final JsonArray jsonIntents = result.get("intents").asArray();
1087 assertThat(jsonIntents, notNullValue());
1088
1089 assertThat(jsonIntents, hasIntent(intent1, true));
1090 }
1091
1092 /**
1093 * Tests the result of the rest api GET when intents are defined.
1094 */
1095 @Test
1096 public void testIntentsForApplicationWithoutDetail() {
1097 final Intent intent1 =
1098 PointToPointIntent.builder()
1099 .key(Key.of(0, APP_ID))
1100 .appId(APP_ID)
1101 .selector(selector1)
1102 .treatment(treatment1)
1103 .filteredIngressPoint(new FilteredConnectPoint(connectPoint1))
1104 .filteredEgressPoint(new FilteredConnectPoint(connectPoint2))
1105 .build();
1106
1107 final HostToHostIntent intent2 =
1108 HostToHostIntent.builder()
1109 .key(Key.of(1, APP_ID_2))
1110 .appId(APP_ID_2)
1111 .selector(selector2)
1112 .treatment(treatment2)
1113 .one(hostId1)
1114 .two(hostId2)
1115 .build();
1116
1117 intents.add(intent1);
1118 List<Intent> appIntents1 = new ArrayList<>();
1119 appIntents1.add(intent1);
1120
1121 intents.add(intent2);
1122 List<Intent> appIntents2 = new ArrayList<>();
1123 appIntents2.add(intent2);
1124
1125 expect(mockIntentService.getIntentsByAppId(APP_ID))
1126 .andReturn(appIntents1)
1127 .anyTimes();
1128 expect(mockIntentService.getIntentsByAppId(APP_ID_2))
1129 .andReturn(appIntents2)
1130 .anyTimes();
1131 replay(mockIntentService);
1132
1133 expect(mockCoreService.getAppId(APP_ID.name()))
1134 .andReturn(APP_ID).anyTimes();
1135 expect(mockCoreService.getAppId(APP_ID_2.name()))
1136 .andReturn(APP_ID_2).anyTimes();
1137 replay(mockCoreService);
1138
1139
1140 final WebTarget wt = target();
1141 // Verify intents for app_id
1142 final String response1 = wt.path("intents/application/" + APP_ID.name()).request().get(String.class);
1143 assertThat(response1, containsString("{\"intents\":["));
1144
1145 final JsonObject result1 = Json.parse(response1).asObject();
1146 assertThat(result1, notNullValue());
1147
1148 assertThat(result1.names(), hasSize(1));
1149 assertThat(result1.names().get(0), is("intents"));
1150
1151 final JsonArray jsonIntents1 = result1.get("intents").asArray();
1152 assertThat(jsonIntents1, notNullValue());
1153 assertThat(jsonIntents1.size(), is(1));
1154
1155 assertThat(jsonIntents1, hasIntent(intent1, false));
1156 assertThat(jsonIntents1, is(not(hasIntent(intent2, false))));
1157
1158 // Verify intents for app_id_2 with detail = false
1159 final String response2 = wt.path("intents/application/" + APP_ID_2.name())
1160 .queryParam("detail", false).request().get(String.class);
1161 assertThat(response2, containsString("{\"intents\":["));
1162
1163 final JsonObject result2 = Json.parse(response2).asObject();
1164 assertThat(result2, notNullValue());
1165
1166 assertThat(result2.names(), hasSize(1));
1167 assertThat(result2.names().get(0), is("intents"));
1168
1169 final JsonArray jsonIntents2 = result2.get("intents").asArray();
1170 assertThat(jsonIntents2, notNullValue());
1171 assertThat(jsonIntents2.size(), is(1));
1172
1173 assertThat(jsonIntents2, hasIntent(intent2, false));
1174 assertThat(jsonIntents2, is(not(hasIntent(intent1, false))));
1175 }
1176
1177 /**
1178 * Tests the result of the rest api GET when intents are defined and the detail flag is true.
1179 */
1180 @Test
1181 public void testIntentsForApplicationWithDetail() {
1182 final Intent intent1 =
1183 PointToPointIntent.builder()
1184 .key(Key.of(0, APP_ID))
1185 .appId(APP_ID)
1186 .selector(selector1)
1187 .treatment(treatment1)
1188 .filteredIngressPoint(new FilteredConnectPoint(connectPoint1))
1189 .filteredEgressPoint(new FilteredConnectPoint(connectPoint2))
1190 .build();
1191
1192 final HostToHostIntent intent2 =
1193 HostToHostIntent.builder()
1194 .key(Key.of(1, APP_ID_2))
1195 .appId(APP_ID_2)
1196 .selector(selector2)
1197 .treatment(treatment2)
1198 .one(hostId1)
1199 .two(hostId2)
1200 .build();
1201
1202 intents.add(intent1);
1203 List<Intent> appIntents1 = new ArrayList<>();
1204 appIntents1.add(intent1);
1205
1206 intents.add(intent2);
1207 List<Intent> appIntents2 = new ArrayList<>();
1208 appIntents2.add(intent2);
1209
1210 expect(mockIntentService.getIntentsByAppId(APP_ID))
1211 .andReturn(appIntents1)
1212 .anyTimes();
1213 expect(mockIntentService.getIntentsByAppId(APP_ID_2))
1214 .andReturn(appIntents2)
1215 .anyTimes();
1216 replay(mockIntentService);
1217
1218 expect(mockCoreService.getAppId(APP_ID.name()))
1219 .andReturn(APP_ID).anyTimes();
1220 expect(mockCoreService.getAppId(APP_ID_2.name()))
1221 .andReturn(APP_ID_2).anyTimes();
1222 replay(mockCoreService);
1223
1224
1225 final WebTarget wt = target();
1226 // Verify intents for app_id
1227 final String response1 = wt.path("intents/application/" + APP_ID.name())
1228 .queryParam("detail", true).request().get(String.class);
1229 assertThat(response1, containsString("{\"intents\":["));
1230
1231 final JsonObject result1 = Json.parse(response1).asObject();
1232 assertThat(result1, notNullValue());
1233
1234 assertThat(result1.names(), hasSize(1));
1235 assertThat(result1.names().get(0), is("intents"));
1236
1237 final JsonArray jsonIntents1 = result1.get("intents").asArray();
1238 assertThat(jsonIntents1, notNullValue());
1239 assertThat(jsonIntents1.size(), is(1));
1240
1241 assertThat(jsonIntents1, hasIntent(intent1, true));
1242 assertThat(jsonIntents1, is(not(hasIntent(intent2, true))));
1243
1244 // Verify intents for app_id_2
1245 final String response2 = wt.path("intents/application/" + APP_ID_2.name())
1246 .queryParam("detail", true).request().get(String.class);
1247 assertThat(response2, containsString("{\"intents\":["));
1248
1249 final JsonObject result2 = Json.parse(response2).asObject();
1250 assertThat(result2, notNullValue());
1251
1252 assertThat(result2.names(), hasSize(1));
1253 assertThat(result2.names().get(0), is("intents"));
1254
1255 final JsonArray jsonIntents2 = result2.get("intents").asArray();
1256 assertThat(jsonIntents2, notNullValue());
1257 assertThat(jsonIntents2.size(), is(1));
1258
1259 assertThat(jsonIntents2, hasIntent(intent2, true));
1260 assertThat(jsonIntents2, is(not(hasIntent(intent1, true))));
Ray Milkey2b217142014-12-15 09:24:24 -08001261 }
1262
1263 /**
Author Namee252a002016-09-26 22:42:24 +05301264 * Tests the result of a rest api GET for related flows for single intent.
1265 */
1266 @Test
1267 public void testRelatedFlowsForIntents() {
1268 List<FlowEntry> flowEntries = new ArrayList<>();
1269 flowEntries.add(flow1);
1270 flowEntries.add(flow2);
1271 List<List<FlowEntry>> paths = new ArrayList<>();
1272 paths.add(flowEntries);
1273 List<FlowRule> flowRules = new ArrayList<>();
1274 flowRules.add(flowRule1);
1275 flowRules.add(flowRule2);
1276 FlowRuleIntent flowRuleIntent = new FlowRuleIntent(
1277 APP_ID,
Ray Milkey39f78b62018-01-05 15:17:37 -08001278 null,
Author Namee252a002016-09-26 22:42:24 +05301279 flowRules,
Ray Milkey39f78b62018-01-05 15:17:37 -08001280 new HashSet<NetworkResource>(),
1281 PathIntent.ProtectionType.PRIMARY,
1282 null);
Author Namee252a002016-09-26 22:42:24 +05301283 Intent intent = new MockIntent(3L);
1284 installableIntents.add(flowRuleIntent);
1285 intents.add(intent);
1286
1287 expect(mockIntentService.getIntent(Key.of(0, APP_ID)))
1288 .andReturn(intent)
1289 .anyTimes();
1290 expect(mockIntentService.getIntent(Key.of("0", APP_ID)))
1291 .andReturn(intent)
1292 .anyTimes();
1293 expect(mockIntentService.getIntent(Key.of(0, APP_ID)))
1294 .andReturn(intent)
1295 .anyTimes();
1296 expect(mockIntentService.getIntent(Key.of("0x0", APP_ID)))
1297 .andReturn(null)
1298 .anyTimes();
1299 expect(mockIntentService.getInstallableIntents(intent.key()))
1300 .andReturn(installableIntents)
1301 .anyTimes();
1302 replay(mockIntentService);
1303
1304 expect(mockFlowService.getFlowEntries(deviceId1))
1305 .andReturn(flowEntries).anyTimes();
1306 replay(mockFlowService);
1307
1308 expect(mockCoreService.getAppId(APP_ID.name()))
1309 .andReturn(APP_ID).anyTimes();
1310 expect(mockCoreService.getAppId(APP_ID.id()))
1311 .andReturn(APP_ID).anyTimes();
1312 replay(mockCoreService);
1313
1314 final WebTarget wt = target();
1315
1316 // Test get using key string
1317 final String response = wt.path("intents/relatedflows/" + APP_ID.name()
1318 + "/0").request().get(String.class);
1319 final JsonObject result = Json.parse(response).asObject();
1320 assertThat(result, matchesRelatedFlowEntries(paths, APP_ID.name()));
1321
1322 // Test get using numeric value
1323 final String responseNumeric = wt.path("intents/relatedflows/" + APP_ID.name()
1324 + "/0x0").request().get(String.class);
1325 final JsonObject resultNumeric = Json.parse(responseNumeric).asObject();
1326 assertThat(resultNumeric, matchesRelatedFlowEntries(paths, APP_ID.name()));
1327 }
1328
1329 /**
Rafal Szaleckif97e0ed2017-06-01 13:07:18 +02001330 * Tests the result of a rest api GET for intent installables.
1331 */
1332 @Test
1333 public void testIntentInstallables() {
1334
1335 Link link1 = DefaultLink.builder()
1336 .type(Link.Type.DIRECT)
1337 .providerId(ProviderId.NONE)
1338 .src(connectPoint1)
1339 .dst(connectPoint2)
1340 .build();
1341
1342 Link link2 = DefaultLink.builder()
1343 .type(Link.Type.DIRECT)
1344 .providerId(ProviderId.NONE)
1345 .src(connectPoint3)
1346 .dst(connectPoint4)
1347 .build();
1348
1349 Set<NetworkResource> resources = new HashSet<>();
1350 resources.add(link1);
1351 resources.add(link2);
1352
1353 FlowRuleIntent flowRuleIntent = new FlowRuleIntent(
1354 APP_ID,
Ray Milkey39f78b62018-01-05 15:17:37 -08001355 null,
Rafal Szaleckif97e0ed2017-06-01 13:07:18 +02001356 new ArrayList<>(),
Ray Milkey39f78b62018-01-05 15:17:37 -08001357 resources,
1358 PathIntent.ProtectionType.PRIMARY,
1359 null);
Rafal Szaleckif97e0ed2017-06-01 13:07:18 +02001360
1361 Intent intent = new MockIntent(MockIntent.nextId());
1362 Long intentId = intent.id().id();
1363 installableIntents.add(flowRuleIntent);
1364 intents.add(intent);
1365
1366 expect(mockIntentService.getIntent(Key.of(intentId, APP_ID)))
1367 .andReturn(intent)
1368 .anyTimes();
1369 expect(mockIntentService.getIntent(Key.of(intentId.toString(), APP_ID)))
1370 .andReturn(intent)
1371 .anyTimes();
1372 expect(mockIntentService.getIntent(Key.of(intentId, APP_ID)))
1373 .andReturn(intent)
1374 .anyTimes();
1375 expect(mockIntentService.getIntent(Key.of(Long.toHexString(intentId), APP_ID)))
1376 .andReturn(null)
1377 .anyTimes();
1378 expect(mockIntentService.getInstallableIntents(intent.key()))
1379 .andReturn(installableIntents)
1380 .anyTimes();
1381 replay(mockIntentService);
1382
1383 replay(mockFlowService);
1384
1385 expect(mockCoreService.getAppId(APP_ID.name()))
1386 .andReturn(APP_ID).anyTimes();
1387 expect(mockCoreService.getAppId(APP_ID.id()))
1388 .andReturn(APP_ID).anyTimes();
1389 replay(mockCoreService);
1390
1391 final WebTarget wt = target();
1392
1393 // Test get using key string
1394 final String response = wt.path("intents/installables/" + APP_ID.name()
1395 + "/" + intentId).request().get(String.class);
1396 final JsonObject result = Json.parse(response).asObject();
David Glantzdfb3ceb2021-10-04 09:10:20 -05001397 assertThat(result.get(INSTALLABLES).asArray(), hasIntent(flowRuleIntent, false));
Rafal Szaleckif97e0ed2017-06-01 13:07:18 +02001398
1399 // Test get using numeric value
1400 final String responseNumeric = wt.path("intents/installables/" + APP_ID.name()
1401 + "/" + Long.toHexString(intentId)).request().get(String.class);
1402 final JsonObject resultNumeric = Json.parse(responseNumeric).asObject();
David Glantzdfb3ceb2021-10-04 09:10:20 -05001403 assertThat(resultNumeric.get(INSTALLABLES).asArray(), hasIntent(flowRuleIntent, false));
Rafal Szaleckif97e0ed2017-06-01 13:07:18 +02001404 }
1405
1406 /**
Ray Milkey2b217142014-12-15 09:24:24 -08001407 * Tests that a fetch of a non-existent intent object throws an exception.
1408 */
1409 @Test
1410 public void testBadGet() {
1411
Ray Milkeyf9af43c2015-02-09 16:45:48 -08001412 expect(mockIntentService.getIntent(Key.of(0, APP_ID)))
Ray Milkey2b217142014-12-15 09:24:24 -08001413 .andReturn(null)
1414 .anyTimes();
1415 replay(mockIntentService);
1416
Jian Li9d616492016-03-09 10:52:49 -08001417 WebTarget wt = target();
Ray Milkey2b217142014-12-15 09:24:24 -08001418 try {
Jian Li9d616492016-03-09 10:52:49 -08001419 wt.path("intents/0").request().get(String.class);
Ray Milkey2b217142014-12-15 09:24:24 -08001420 fail("Fetch of non-existent intent did not throw an exception");
Jian Li9d616492016-03-09 10:52:49 -08001421 } catch (NotFoundException ex) {
Ray Milkey2b217142014-12-15 09:24:24 -08001422 assertThat(ex.getMessage(),
Jian Li9d616492016-03-09 10:52:49 -08001423 containsString("HTTP 404 Not Found"));
Ray Milkey2b217142014-12-15 09:24:24 -08001424 }
1425 }
Ray Milkeyb82c42b2015-06-30 09:42:20 -07001426
1427 /**
1428 * Tests creating an intent with POST.
1429 */
1430 @Test
1431 public void testPost() {
Ray Milkeyf7cb4012015-07-20 13:01:07 -07001432 ApplicationId testId = new DefaultApplicationId(2, "myApp");
1433 expect(mockCoreService.getAppId("myApp"))
1434 .andReturn(testId);
Ray Milkeyb82c42b2015-06-30 09:42:20 -07001435 replay(mockCoreService);
1436
1437 mockIntentService.submit(anyObject());
1438 expectLastCall();
1439 replay(mockIntentService);
1440
1441 InputStream jsonStream = IntentsResourceTest.class
1442 .getResourceAsStream("post-intent.json");
Jian Li9d616492016-03-09 10:52:49 -08001443 WebTarget wt = target();
Ray Milkeyb82c42b2015-06-30 09:42:20 -07001444
Jian Li9d616492016-03-09 10:52:49 -08001445 Response response = wt.path("intents")
1446 .request(MediaType.APPLICATION_JSON_TYPE)
1447 .post(Entity.json(jsonStream));
Ray Milkeyb82c42b2015-06-30 09:42:20 -07001448 assertThat(response.getStatus(), is(HttpURLConnection.HTTP_CREATED));
1449 String location = response.getLocation().getPath();
Ray Milkey8d076402015-08-31 15:43:18 -07001450 assertThat(location, Matchers.startsWith("/intents/myApp/"));
Ray Milkeyb82c42b2015-06-30 09:42:20 -07001451 }
Ray Milkey7b158512015-07-21 16:32:43 -07001452
1453 /**
Ray Milkey05b169d2015-08-13 14:33:33 -07001454 * Tests creating an intent with POST and illegal JSON.
1455 */
1456 @Test
1457 public void testBadPost() {
1458 replay(mockCoreService);
1459 replay(mockIntentService);
1460
1461 String json = "this is invalid!";
Jian Li9d616492016-03-09 10:52:49 -08001462 WebTarget wt = target();
Ray Milkey05b169d2015-08-13 14:33:33 -07001463
Jian Li9d616492016-03-09 10:52:49 -08001464 Response response = wt.path("intents")
1465 .request(MediaType.APPLICATION_JSON_TYPE)
1466 .post(Entity.json(json));
Ray Milkey05b169d2015-08-13 14:33:33 -07001467 assertThat(response.getStatus(), is(HttpURLConnection.HTTP_BAD_REQUEST));
1468 }
1469
1470 /**
Ray Milkey7b158512015-07-21 16:32:43 -07001471 * Tests removing an intent with DELETE.
1472 */
1473 @Test
1474 public void testRemove() {
1475 final HashSet<NetworkResource> resources = new HashSet<>();
1476 resources.add(new MockResource(1));
1477 resources.add(new MockResource(2));
1478 resources.add(new MockResource(3));
1479 final Intent intent = new MockIntent(3L, resources);
1480 final ApplicationId appId = new DefaultApplicationId(2, "app");
1481 IntentService fakeManager = new FakeIntentManager();
1482
1483 expect(mockCoreService.getAppId("app"))
1484 .andReturn(appId).once();
1485 replay(mockCoreService);
1486
1487 mockIntentService.withdraw(anyObject());
1488 expectLastCall().andDelegateTo(fakeManager).once();
1489 expect(mockIntentService.getIntent(Key.of(2, appId)))
1490 .andReturn(intent)
1491 .once();
1492 expect(mockIntentService.getIntent(Key.of("0x2", appId)))
1493 .andReturn(null)
1494 .once();
1495
1496 mockIntentService.addListener(anyObject());
1497 expectLastCall().andDelegateTo(fakeManager).once();
1498 mockIntentService.removeListener(anyObject());
1499 expectLastCall().andDelegateTo(fakeManager).once();
1500
1501 replay(mockIntentService);
1502
Jian Li9d616492016-03-09 10:52:49 -08001503 WebTarget wt = target();
Ray Milkey7b158512015-07-21 16:32:43 -07001504
Jian Li9d616492016-03-09 10:52:49 -08001505 Response response = wt.path("intents/app/0x2")
Ray Milkey7c251822016-04-06 17:38:25 -07001506 .request(MediaType.APPLICATION_JSON, MediaType.TEXT_PLAIN)
Jian Li9d616492016-03-09 10:52:49 -08001507 .delete();
Ray Milkey7b158512015-07-21 16:32:43 -07001508 assertThat(response.getStatus(), is(HttpURLConnection.HTTP_NO_CONTENT));
1509 }
Ray Milkey05b169d2015-08-13 14:33:33 -07001510
1511 /**
1512 * Tests removal of a non existent intent with DELETE.
1513 */
1514 @Test
1515 public void testBadRemove() {
1516 final ApplicationId appId = new DefaultApplicationId(2, "app");
1517
1518 expect(mockCoreService.getAppId("app"))
1519 .andReturn(appId).once();
1520 replay(mockCoreService);
1521
1522 expect(mockIntentService.getIntent(Key.of(2, appId)))
1523 .andReturn(null)
1524 .once();
1525 expect(mockIntentService.getIntent(Key.of("0x2", appId)))
1526 .andReturn(null)
1527 .once();
1528
1529 replay(mockIntentService);
1530
Jian Li9d616492016-03-09 10:52:49 -08001531 WebTarget wt = target();
Ray Milkey05b169d2015-08-13 14:33:33 -07001532
Jian Li9d616492016-03-09 10:52:49 -08001533 Response response = wt.path("intents/app/0x2")
Ray Milkey7c251822016-04-06 17:38:25 -07001534 .request(MediaType.APPLICATION_JSON, MediaType.TEXT_PLAIN)
Jian Li9d616492016-03-09 10:52:49 -08001535 .delete();
Ray Milkey05b169d2015-08-13 14:33:33 -07001536 assertThat(response.getStatus(), is(HttpURLConnection.HTTP_NO_CONTENT));
1537 }
1538
dvaddire95c84ed2017-06-14 15:42:24 +05301539 @Test
1540 public void testIntentsMiniSummary() {
1541 final Intent intent1 = new MockIntent(1L, Collections.emptyList());
1542 final HashSet<NetworkResource> resources = new HashSet<>();
1543 resources.add(new MockResource(1));
1544 resources.add(new MockResource(2));
1545 resources.add(new MockResource(3));
1546 final Intent intent2 = new MockIntent(2L, resources);
1547 intents.add(intent1);
1548 intents.add(intent2);
1549 final WebTarget wt = target();
1550 replay(mockIntentService);
1551 final String response = wt.path("intents/minisummary").request().get(String.class);
1552 assertThat(response, containsString("{\"All\":{"));
1553 final JsonObject result = Json.parse(response).asObject();
1554 assertThat(result, notNullValue());
1555 assertThat(result.names(), hasSize(2));
1556 assertThat(result.names().get(0), containsString("All"));
1557 JsonObject jsonIntents = (JsonObject) result.get("All");
1558 assertThat(jsonIntents, notNullValue());
1559 assertThat(jsonIntents.get("total").toString(), containsString("2"));
1560 jsonIntents = (JsonObject) result.get("Mock");
1561 assertThat(jsonIntents, notNullValue());
1562 assertThat(jsonIntents.get("installed").toString(), containsString("2"));
1563 }
Ray Milkey2b217142014-12-15 09:24:24 -08001564}
dvaddire95c84ed2017-06-14 15:42:24 +05301565