blob: 33ee9317f6df2fc2396a8528575cbc13a3260037 [file] [log] [blame]
Ray Milkey2b217142014-12-15 09:24:24 -08001/*
Ray Milkey34c95902015-04-15 09:47:53 -07002 * Copyright 2014-2015 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 */
16package org.onosproject.rest;
17
Ray Milkeyb82c42b2015-06-30 09:42:20 -070018import java.io.InputStream;
19import java.net.HttpURLConnection;
Sho SHIMIZUd7d18002015-01-21 14:37:14 -080020import java.util.Collections;
Ray Milkey2b217142014-12-15 09:24:24 -080021import java.util.HashSet;
Ray Milkey2b217142014-12-15 09:24:24 -080022
Ray Milkeyb82c42b2015-06-30 09:42:20 -070023import javax.ws.rs.core.MediaType;
24
Ray Milkey2b217142014-12-15 09:24:24 -080025import org.hamcrest.Description;
Ray Milkeyb82c42b2015-06-30 09:42:20 -070026import org.hamcrest.Matchers;
Ray Milkey2b217142014-12-15 09:24:24 -080027import org.hamcrest.TypeSafeMatcher;
28import org.junit.After;
29import org.junit.Before;
30import org.junit.Test;
31import org.onlab.osgi.ServiceDirectory;
32import org.onlab.osgi.TestServiceDirectory;
33import org.onlab.rest.BaseResource;
34import org.onosproject.codec.CodecService;
35import org.onosproject.codec.impl.CodecManager;
36import org.onosproject.core.ApplicationId;
Ayaka Koshibec06c89b2015-02-10 19:25:41 -080037import org.onosproject.core.CoreService;
Ray Milkey2b217142014-12-15 09:24:24 -080038import org.onosproject.core.DefaultApplicationId;
39import org.onosproject.core.IdGenerator;
40import org.onosproject.net.NetworkResource;
Ray Milkey7b158512015-07-21 16:32:43 -070041import org.onosproject.net.intent.FakeIntentManager;
Ray Milkey2b217142014-12-15 09:24:24 -080042import org.onosproject.net.intent.Intent;
Ray Milkey2b217142014-12-15 09:24:24 -080043import org.onosproject.net.intent.IntentService;
Ray Milkey1534f8d2015-05-13 15:42:50 -070044import org.onosproject.net.intent.IntentState;
Ray Milkeyf9af43c2015-02-09 16:45:48 -080045import org.onosproject.net.intent.Key;
Ray Milkey43a28222015-02-23 13:57:58 -080046import org.onosproject.net.intent.MockIdGenerator;
Ray Milkey2b217142014-12-15 09:24:24 -080047
48import com.eclipsesource.json.JsonArray;
49import com.eclipsesource.json.JsonObject;
50import com.eclipsesource.json.JsonValue;
Ray Milkeyb82c42b2015-06-30 09:42:20 -070051import com.sun.jersey.api.client.ClientResponse;
Ray Milkey2b217142014-12-15 09:24:24 -080052import com.sun.jersey.api.client.UniformInterfaceException;
53import com.sun.jersey.api.client.WebResource;
Ray Milkey2b217142014-12-15 09:24:24 -080054
Ray Milkey1534f8d2015-05-13 15:42:50 -070055import static org.easymock.EasyMock.anyObject;
Ray Milkey2b217142014-12-15 09:24:24 -080056import static org.easymock.EasyMock.createMock;
57import static org.easymock.EasyMock.expect;
Ray Milkeyb82c42b2015-06-30 09:42:20 -070058import static org.easymock.EasyMock.expectLastCall;
Ray Milkey2b217142014-12-15 09:24:24 -080059import static org.easymock.EasyMock.replay;
60import static org.easymock.EasyMock.verify;
61import static org.hamcrest.Matchers.containsString;
62import static org.hamcrest.Matchers.hasSize;
63import static org.hamcrest.Matchers.is;
64import static org.hamcrest.Matchers.notNullValue;
65import static org.junit.Assert.assertThat;
66import static org.junit.Assert.fail;
Ray Milkey43a28222015-02-23 13:57:58 -080067import static org.onosproject.net.intent.IntentTestsMocks.MockIntent;
Ray Milkey2b217142014-12-15 09:24:24 -080068
69/**
70 * Unit tests for Intents REST APIs.
71 */
Ray Milkey9c3d3362015-01-28 10:39:56 -080072public class IntentsResourceTest extends ResourceTest {
Ray Milkey2b217142014-12-15 09:24:24 -080073 final IntentService mockIntentService = createMock(IntentService.class);
Ayaka Koshibec06c89b2015-02-10 19:25:41 -080074 final CoreService mockCoreService = createMock(CoreService.class);
Ray Milkey2b217142014-12-15 09:24:24 -080075 final HashSet<Intent> intents = new HashSet<>();
Thomas Vachuska02aeb032015-01-06 22:36:30 -080076 private static final ApplicationId APP_ID = new DefaultApplicationId(1, "test");
Ray Milkey2b217142014-12-15 09:24:24 -080077 private IdGenerator mockGenerator;
78
Ray Milkey2b217142014-12-15 09:24:24 -080079 private class MockResource implements NetworkResource {
80 int id;
81
82 MockResource(int id) {
83 this.id = id;
84 }
85
Ayaka Koshibec06c89b2015-02-10 19:25:41 -080086 @Override
Ray Milkey2b217142014-12-15 09:24:24 -080087 public String toString() {
88 return "Resource " + Integer.toString(id);
89 }
90 }
91
Ray Milkey2b217142014-12-15 09:24:24 -080092 /**
93 * Hamcrest matcher to check that an intent representation in JSON matches
94 * the actual intent.
95 */
96 public static class IntentJsonMatcher extends TypeSafeMatcher<JsonObject> {
97 private final Intent intent;
98 private String reason = "";
99
100 public IntentJsonMatcher(Intent intentValue) {
101 intent = intentValue;
102 }
103
104 @Override
105 public boolean matchesSafely(JsonObject jsonIntent) {
106 // check id
107 final String jsonId = jsonIntent.get("id").asString();
108 if (!jsonId.equals(intent.id().toString())) {
109 reason = "id " + intent.id().toString();
110 return false;
111 }
112
113 // check application id
Ray Milkeyf7cb4012015-07-20 13:01:07 -0700114
Ray Milkey2b217142014-12-15 09:24:24 -0800115 final String jsonAppId = jsonIntent.get("appId").asString();
Ray Milkeyf7cb4012015-07-20 13:01:07 -0700116 final String appId = intent.appId().name();
117 if (!jsonAppId.equals(appId)) {
118 reason = "appId was " + jsonAppId;
Ray Milkey2b217142014-12-15 09:24:24 -0800119 return false;
120 }
121
122 // check intent type
123 final String jsonType = jsonIntent.get("type").asString();
124 if (!jsonType.equals("MockIntent")) {
125 reason = "type MockIntent";
126 return false;
127 }
128
Ray Milkey1534f8d2015-05-13 15:42:50 -0700129 // check state field
130 final String jsonState = jsonIntent.get("state").asString();
131 if (!jsonState.equals("INSTALLED")) {
132 reason = "state INSTALLED";
133 return false;
134 }
135
Ray Milkey2b217142014-12-15 09:24:24 -0800136 // check resources array
137 final JsonArray jsonResources = jsonIntent.get("resources").asArray();
138 if (intent.resources() != null) {
139 if (intent.resources().size() != jsonResources.size()) {
140 reason = "resources array size of " + Integer.toString(intent.resources().size());
141 return false;
142 }
143 for (final NetworkResource resource : intent.resources()) {
144 boolean resourceFound = false;
145 final String resourceString = resource.toString();
146 for (int resourceIndex = 0; resourceIndex < jsonResources.size(); resourceIndex++) {
147 final JsonValue value = jsonResources.get(resourceIndex);
148 if (value.asString().equals(resourceString)) {
149 resourceFound = true;
150 }
151 }
152 if (!resourceFound) {
153 reason = "resource " + resourceString;
154 return false;
155 }
156 }
157 } else if (jsonResources.size() != 0) {
158 reason = "resources array empty";
159 return false;
160 }
161 return true;
162 }
163
164 @Override
165 public void describeTo(Description description) {
166 description.appendText(reason);
167 }
168 }
169
170 /**
171 * Factory to allocate an intent matcher.
172 *
173 * @param intent intent object we are looking for
174 * @return matcher
175 */
176 private static IntentJsonMatcher matchesIntent(Intent intent) {
177 return new IntentJsonMatcher(intent);
178 }
179
180 /**
181 * Hamcrest matcher to check that an intent is represented properly in a JSON
182 * array of intents.
183 */
184 public static class IntentJsonArrayMatcher extends TypeSafeMatcher<JsonArray> {
185 private final Intent intent;
186 private String reason = "";
187
188 public IntentJsonArrayMatcher(Intent intentValue) {
189 intent = intentValue;
190 }
191
192 @Override
193 public boolean matchesSafely(JsonArray json) {
194 boolean intentFound = false;
Ray Milkeyf7cb4012015-07-20 13:01:07 -0700195 final int expectedAttributes = 5;
Ray Milkey2b217142014-12-15 09:24:24 -0800196 for (int jsonIntentIndex = 0; jsonIntentIndex < json.size();
197 jsonIntentIndex++) {
198
199 final JsonObject jsonIntent = json.get(jsonIntentIndex).asObject();
200
201 if (jsonIntent.names().size() != expectedAttributes) {
202 reason = "Found an intent with the wrong number of attributes";
203 return false;
204 }
205
206 final String jsonIntentId = jsonIntent.get("id").asString();
207 if (jsonIntentId.equals(intent.id().toString())) {
208 intentFound = true;
209
210 // We found the correct intent, check attribute values
211 assertThat(jsonIntent, matchesIntent(intent));
212 }
213 }
214 if (!intentFound) {
215 reason = "Intent with id " + intent.id().toString() + " not found";
216 return false;
217 } else {
218 return true;
219 }
220 }
221
222 @Override
223 public void describeTo(Description description) {
224 description.appendText(reason);
225 }
226 }
227
228 /**
229 * Factory to allocate an intent array matcher.
230 *
231 * @param intent intent object we are looking for
232 * @return matcher
233 */
234 private static IntentJsonArrayMatcher hasIntent(Intent intent) {
235 return new IntentJsonArrayMatcher(intent);
236 }
Ray Milkey4f5de002014-12-17 19:26:11 -0800237
Ray Milkeyed0b1662015-02-05 09:34:29 -0800238 /**
239 * Initializes test mocks and environment.
240 */
Ray Milkey2b217142014-12-15 09:24:24 -0800241 @Before
Ray Milkeyed0b1662015-02-05 09:34:29 -0800242 public void setUpTest() {
Ray Milkey2b217142014-12-15 09:24:24 -0800243 expect(mockIntentService.getIntents()).andReturn(intents).anyTimes();
Ray Milkey1534f8d2015-05-13 15:42:50 -0700244 expect(mockIntentService.getIntentState(anyObject()))
245 .andReturn(IntentState.INSTALLED)
246 .anyTimes();
Ray Milkey2b217142014-12-15 09:24:24 -0800247 // Register the services needed for the test
248 final CodecManager codecService = new CodecManager();
249 codecService.activate();
250 ServiceDirectory testDirectory =
251 new TestServiceDirectory()
252 .add(IntentService.class, mockIntentService)
Ayaka Koshibec06c89b2015-02-10 19:25:41 -0800253 .add(CodecService.class, codecService)
254 .add(CoreService.class, mockCoreService);
Ray Milkey2b217142014-12-15 09:24:24 -0800255
256 BaseResource.setServiceDirectory(testDirectory);
257
258 mockGenerator = new MockIdGenerator();
259 Intent.bindIdGenerator(mockGenerator);
260 }
261
Ray Milkeyed0b1662015-02-05 09:34:29 -0800262 /**
263 * Tears down and verifies test mocks and environment.
264 */
Ray Milkey2b217142014-12-15 09:24:24 -0800265 @After
Ray Milkeyed0b1662015-02-05 09:34:29 -0800266 public void tearDownTest() {
Ray Milkey2b217142014-12-15 09:24:24 -0800267 verify(mockIntentService);
268 Intent.unbindIdGenerator(mockGenerator);
269 }
270
271 /**
272 * Tests the result of the rest api GET when there are no intents.
273 */
274 @Test
275 public void testIntentsEmptyArray() {
276 replay(mockIntentService);
277 final WebResource rs = resource();
278 final String response = rs.path("intents").get(String.class);
279 assertThat(response, is("{\"intents\":[]}"));
280 }
281
282 /**
283 * Tests the result of the rest api GET when intents are defined.
284 */
285 @Test
286 public void testIntentsArray() {
287 replay(mockIntentService);
288
Ray Milkey43a28222015-02-23 13:57:58 -0800289 final Intent intent1 = new MockIntent(1L, Collections.emptyList());
Ray Milkey2b217142014-12-15 09:24:24 -0800290 final HashSet<NetworkResource> resources = new HashSet<>();
291 resources.add(new MockResource(1));
292 resources.add(new MockResource(2));
293 resources.add(new MockResource(3));
Ray Milkey43a28222015-02-23 13:57:58 -0800294 final Intent intent2 = new MockIntent(2L, resources);
Ray Milkey2b217142014-12-15 09:24:24 -0800295
296 intents.add(intent1);
297 intents.add(intent2);
298 final WebResource rs = resource();
299 final String response = rs.path("intents").get(String.class);
300 assertThat(response, containsString("{\"intents\":["));
301
302 final JsonObject result = JsonObject.readFrom(response);
303 assertThat(result, notNullValue());
304
305 assertThat(result.names(), hasSize(1));
306 assertThat(result.names().get(0), is("intents"));
307
308 final JsonArray jsonIntents = result.get("intents").asArray();
309 assertThat(jsonIntents, notNullValue());
310
311 assertThat(jsonIntents, hasIntent(intent1));
312 assertThat(jsonIntents, hasIntent(intent2));
313 }
314
315 /**
316 * Tests the result of a rest api GET for a single intent.
317 */
318 @Test
319 public void testIntentsSingle() {
320 final HashSet<NetworkResource> resources = new HashSet<>();
321 resources.add(new MockResource(1));
322 resources.add(new MockResource(2));
323 resources.add(new MockResource(3));
Ray Milkey43a28222015-02-23 13:57:58 -0800324 final Intent intent = new MockIntent(3L, resources);
Ray Milkey2b217142014-12-15 09:24:24 -0800325
326 intents.add(intent);
327
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800328 expect(mockIntentService.getIntent(Key.of(0, APP_ID)))
Ray Milkey2b217142014-12-15 09:24:24 -0800329 .andReturn(intent)
330 .anyTimes();
Ayaka Koshibec06c89b2015-02-10 19:25:41 -0800331 expect(mockIntentService.getIntent(Key.of("0", APP_ID)))
332 .andReturn(intent)
333 .anyTimes();
Ray Milkey05b169d2015-08-13 14:33:33 -0700334 expect(mockIntentService.getIntent(Key.of(0, APP_ID)))
335 .andReturn(intent)
336 .anyTimes();
337 expect(mockIntentService.getIntent(Key.of("0x0", APP_ID)))
338 .andReturn(null)
339 .anyTimes();
Ray Milkey2b217142014-12-15 09:24:24 -0800340 replay(mockIntentService);
Ray Milkeyf7cb4012015-07-20 13:01:07 -0700341 expect(mockCoreService.getAppId(APP_ID.name()))
Ayaka Koshibec06c89b2015-02-10 19:25:41 -0800342 .andReturn(APP_ID).anyTimes();
343 replay(mockCoreService);
Ray Milkey2b217142014-12-15 09:24:24 -0800344 final WebResource rs = resource();
Ray Milkey05b169d2015-08-13 14:33:33 -0700345
346 // Test get using key string
Ray Milkeyf7cb4012015-07-20 13:01:07 -0700347 final String response = rs.path("intents/" + APP_ID.name()
348 + "/0").get(String.class);
Ray Milkey2b217142014-12-15 09:24:24 -0800349 final JsonObject result = JsonObject.readFrom(response);
350 assertThat(result, matchesIntent(intent));
Ray Milkey05b169d2015-08-13 14:33:33 -0700351
352 // Test get using numeric value
353 final String responseNumeric = rs.path("intents/" + APP_ID.name()
354 + "/0x0").get(String.class);
355 final JsonObject resultNumeric = JsonObject.readFrom(responseNumeric);
356 assertThat(resultNumeric, matchesIntent(intent));
Ray Milkey2b217142014-12-15 09:24:24 -0800357 }
358
359 /**
360 * Tests that a fetch of a non-existent intent object throws an exception.
361 */
362 @Test
363 public void testBadGet() {
364
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800365 expect(mockIntentService.getIntent(Key.of(0, APP_ID)))
Ray Milkey2b217142014-12-15 09:24:24 -0800366 .andReturn(null)
367 .anyTimes();
368 replay(mockIntentService);
369
370 WebResource rs = resource();
371 try {
372 rs.path("intents/0").get(String.class);
373 fail("Fetch of non-existent intent did not throw an exception");
374 } catch (UniformInterfaceException ex) {
375 assertThat(ex.getMessage(),
376 containsString("returned a response status of"));
377 }
378 }
Ray Milkeyb82c42b2015-06-30 09:42:20 -0700379
380 /**
381 * Tests creating an intent with POST.
382 */
383 @Test
384 public void testPost() {
Ray Milkeyf7cb4012015-07-20 13:01:07 -0700385 ApplicationId testId = new DefaultApplicationId(2, "myApp");
386 expect(mockCoreService.getAppId("myApp"))
387 .andReturn(testId);
Ray Milkeyb82c42b2015-06-30 09:42:20 -0700388 replay(mockCoreService);
389
390 mockIntentService.submit(anyObject());
391 expectLastCall();
392 replay(mockIntentService);
393
394 InputStream jsonStream = IntentsResourceTest.class
395 .getResourceAsStream("post-intent.json");
396 WebResource rs = resource();
397
398 ClientResponse response = rs.path("intents")
399 .type(MediaType.APPLICATION_JSON_TYPE)
400 .post(ClientResponse.class, jsonStream);
401 assertThat(response.getStatus(), is(HttpURLConnection.HTTP_CREATED));
402 String location = response.getLocation().getPath();
Ray Milkey8d076402015-08-31 15:43:18 -0700403 assertThat(location, Matchers.startsWith("/intents/myApp/"));
Ray Milkeyb82c42b2015-06-30 09:42:20 -0700404 }
Ray Milkey7b158512015-07-21 16:32:43 -0700405
406 /**
Ray Milkey05b169d2015-08-13 14:33:33 -0700407 * Tests creating an intent with POST and illegal JSON.
408 */
409 @Test
410 public void testBadPost() {
411 replay(mockCoreService);
412 replay(mockIntentService);
413
414 String json = "this is invalid!";
415 WebResource rs = resource();
416
417 ClientResponse response = rs.path("intents")
418 .type(MediaType.APPLICATION_JSON_TYPE)
419 .post(ClientResponse.class, json);
420 assertThat(response.getStatus(), is(HttpURLConnection.HTTP_BAD_REQUEST));
421 }
422
423 /**
Ray Milkey7b158512015-07-21 16:32:43 -0700424 * Tests removing an intent with DELETE.
425 */
426 @Test
427 public void testRemove() {
428 final HashSet<NetworkResource> resources = new HashSet<>();
429 resources.add(new MockResource(1));
430 resources.add(new MockResource(2));
431 resources.add(new MockResource(3));
432 final Intent intent = new MockIntent(3L, resources);
433 final ApplicationId appId = new DefaultApplicationId(2, "app");
434 IntentService fakeManager = new FakeIntentManager();
435
436 expect(mockCoreService.getAppId("app"))
437 .andReturn(appId).once();
438 replay(mockCoreService);
439
440 mockIntentService.withdraw(anyObject());
441 expectLastCall().andDelegateTo(fakeManager).once();
442 expect(mockIntentService.getIntent(Key.of(2, appId)))
443 .andReturn(intent)
444 .once();
445 expect(mockIntentService.getIntent(Key.of("0x2", appId)))
446 .andReturn(null)
447 .once();
448
449 mockIntentService.addListener(anyObject());
450 expectLastCall().andDelegateTo(fakeManager).once();
451 mockIntentService.removeListener(anyObject());
452 expectLastCall().andDelegateTo(fakeManager).once();
453
454 replay(mockIntentService);
455
456 WebResource rs = resource();
457
458 ClientResponse response = rs.path("intents/app/0x2")
459 .type(MediaType.APPLICATION_JSON_TYPE)
460 .delete(ClientResponse.class);
461 assertThat(response.getStatus(), is(HttpURLConnection.HTTP_NO_CONTENT));
462 }
Ray Milkey05b169d2015-08-13 14:33:33 -0700463
464 /**
465 * Tests removal of a non existent intent with DELETE.
466 */
467 @Test
468 public void testBadRemove() {
469 final ApplicationId appId = new DefaultApplicationId(2, "app");
470
471 expect(mockCoreService.getAppId("app"))
472 .andReturn(appId).once();
473 replay(mockCoreService);
474
475 expect(mockIntentService.getIntent(Key.of(2, appId)))
476 .andReturn(null)
477 .once();
478 expect(mockIntentService.getIntent(Key.of("0x2", appId)))
479 .andReturn(null)
480 .once();
481
482 replay(mockIntentService);
483
484 WebResource rs = resource();
485
486 ClientResponse response = rs.path("intents/app/0x2")
487 .type(MediaType.APPLICATION_JSON_TYPE)
488 .delete(ClientResponse.class);
489 assertThat(response.getStatus(), is(HttpURLConnection.HTTP_NO_CONTENT));
490 }
491
Ray Milkey2b217142014-12-15 09:24:24 -0800492}