blob: 6572b68c61db8001bc8a36b83c877f6a1dcfe437 [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;
41import org.onosproject.net.intent.Intent;
Ray Milkey2b217142014-12-15 09:24:24 -080042import org.onosproject.net.intent.IntentService;
Ray Milkey1534f8d2015-05-13 15:42:50 -070043import org.onosproject.net.intent.IntentState;
Ray Milkeyf9af43c2015-02-09 16:45:48 -080044import org.onosproject.net.intent.Key;
Ray Milkey43a28222015-02-23 13:57:58 -080045import org.onosproject.net.intent.MockIdGenerator;
Ray Milkey2b217142014-12-15 09:24:24 -080046
47import com.eclipsesource.json.JsonArray;
48import com.eclipsesource.json.JsonObject;
49import com.eclipsesource.json.JsonValue;
Ray Milkeyb82c42b2015-06-30 09:42:20 -070050import com.sun.jersey.api.client.ClientResponse;
Ray Milkey2b217142014-12-15 09:24:24 -080051import com.sun.jersey.api.client.UniformInterfaceException;
52import com.sun.jersey.api.client.WebResource;
Ray Milkey2b217142014-12-15 09:24:24 -080053
Ray Milkey1534f8d2015-05-13 15:42:50 -070054import static org.easymock.EasyMock.anyObject;
Ray Milkey2b217142014-12-15 09:24:24 -080055import static org.easymock.EasyMock.createMock;
56import static org.easymock.EasyMock.expect;
Ray Milkeyb82c42b2015-06-30 09:42:20 -070057import static org.easymock.EasyMock.expectLastCall;
Ray Milkey2b217142014-12-15 09:24:24 -080058import static org.easymock.EasyMock.replay;
59import static org.easymock.EasyMock.verify;
60import static org.hamcrest.Matchers.containsString;
61import static org.hamcrest.Matchers.hasSize;
62import static org.hamcrest.Matchers.is;
63import static org.hamcrest.Matchers.notNullValue;
64import static org.junit.Assert.assertThat;
65import static org.junit.Assert.fail;
Ray Milkey43a28222015-02-23 13:57:58 -080066import static org.onosproject.net.intent.IntentTestsMocks.MockIntent;
Ray Milkey2b217142014-12-15 09:24:24 -080067
68/**
69 * Unit tests for Intents REST APIs.
70 */
Ray Milkey9c3d3362015-01-28 10:39:56 -080071public class IntentsResourceTest extends ResourceTest {
Ray Milkey2b217142014-12-15 09:24:24 -080072 final IntentService mockIntentService = createMock(IntentService.class);
Ayaka Koshibec06c89b2015-02-10 19:25:41 -080073 final CoreService mockCoreService = createMock(CoreService.class);
Ray Milkey2b217142014-12-15 09:24:24 -080074 final HashSet<Intent> intents = new HashSet<>();
Thomas Vachuska02aeb032015-01-06 22:36:30 -080075 private static final ApplicationId APP_ID = new DefaultApplicationId(1, "test");
Ray Milkey2b217142014-12-15 09:24:24 -080076 private IdGenerator mockGenerator;
77
Ray Milkey2b217142014-12-15 09:24:24 -080078 private class MockResource implements NetworkResource {
79 int id;
80
81 MockResource(int id) {
82 this.id = id;
83 }
84
Ayaka Koshibec06c89b2015-02-10 19:25:41 -080085 @Override
Ray Milkey2b217142014-12-15 09:24:24 -080086 public String toString() {
87 return "Resource " + Integer.toString(id);
88 }
89 }
90
Ray Milkey2b217142014-12-15 09:24:24 -080091 /**
92 * Hamcrest matcher to check that an intent representation in JSON matches
93 * the actual intent.
94 */
95 public static class IntentJsonMatcher extends TypeSafeMatcher<JsonObject> {
96 private final Intent intent;
97 private String reason = "";
98
99 public IntentJsonMatcher(Intent intentValue) {
100 intent = intentValue;
101 }
102
103 @Override
104 public boolean matchesSafely(JsonObject jsonIntent) {
105 // check id
106 final String jsonId = jsonIntent.get("id").asString();
107 if (!jsonId.equals(intent.id().toString())) {
108 reason = "id " + intent.id().toString();
109 return false;
110 }
111
112 // check application id
113 final String jsonAppId = jsonIntent.get("appId").asString();
114 if (!jsonAppId.equals(intent.appId().toString())) {
115 reason = "appId " + intent.appId().toString();
116 return false;
117 }
118
119 // check intent type
120 final String jsonType = jsonIntent.get("type").asString();
121 if (!jsonType.equals("MockIntent")) {
122 reason = "type MockIntent";
123 return false;
124 }
125
126 // check details field
127 final String jsonDetails = jsonIntent.get("details").asString();
128 if (!jsonDetails.equals(intent.toString())) {
129 reason = "details " + intent.toString();
130 return false;
131 }
132
Ray Milkey1534f8d2015-05-13 15:42:50 -0700133 // check state field
134 final String jsonState = jsonIntent.get("state").asString();
135 if (!jsonState.equals("INSTALLED")) {
136 reason = "state INSTALLED";
137 return false;
138 }
139
Ray Milkey2b217142014-12-15 09:24:24 -0800140 // check resources array
141 final JsonArray jsonResources = jsonIntent.get("resources").asArray();
142 if (intent.resources() != null) {
143 if (intent.resources().size() != jsonResources.size()) {
144 reason = "resources array size of " + Integer.toString(intent.resources().size());
145 return false;
146 }
147 for (final NetworkResource resource : intent.resources()) {
148 boolean resourceFound = false;
149 final String resourceString = resource.toString();
150 for (int resourceIndex = 0; resourceIndex < jsonResources.size(); resourceIndex++) {
151 final JsonValue value = jsonResources.get(resourceIndex);
152 if (value.asString().equals(resourceString)) {
153 resourceFound = true;
154 }
155 }
156 if (!resourceFound) {
157 reason = "resource " + resourceString;
158 return false;
159 }
160 }
161 } else if (jsonResources.size() != 0) {
162 reason = "resources array empty";
163 return false;
164 }
165 return true;
166 }
167
168 @Override
169 public void describeTo(Description description) {
170 description.appendText(reason);
171 }
172 }
173
174 /**
175 * Factory to allocate an intent matcher.
176 *
177 * @param intent intent object we are looking for
178 * @return matcher
179 */
180 private static IntentJsonMatcher matchesIntent(Intent intent) {
181 return new IntentJsonMatcher(intent);
182 }
183
184 /**
185 * Hamcrest matcher to check that an intent is represented properly in a JSON
186 * array of intents.
187 */
188 public static class IntentJsonArrayMatcher extends TypeSafeMatcher<JsonArray> {
189 private final Intent intent;
190 private String reason = "";
191
192 public IntentJsonArrayMatcher(Intent intentValue) {
193 intent = intentValue;
194 }
195
196 @Override
197 public boolean matchesSafely(JsonArray json) {
198 boolean intentFound = false;
Ray Milkey1534f8d2015-05-13 15:42:50 -0700199 final int expectedAttributes = 6;
Ray Milkey2b217142014-12-15 09:24:24 -0800200 for (int jsonIntentIndex = 0; jsonIntentIndex < json.size();
201 jsonIntentIndex++) {
202
203 final JsonObject jsonIntent = json.get(jsonIntentIndex).asObject();
204
205 if (jsonIntent.names().size() != expectedAttributes) {
206 reason = "Found an intent with the wrong number of attributes";
207 return false;
208 }
209
210 final String jsonIntentId = jsonIntent.get("id").asString();
211 if (jsonIntentId.equals(intent.id().toString())) {
212 intentFound = true;
213
214 // We found the correct intent, check attribute values
215 assertThat(jsonIntent, matchesIntent(intent));
216 }
217 }
218 if (!intentFound) {
219 reason = "Intent with id " + intent.id().toString() + " not found";
220 return false;
221 } else {
222 return true;
223 }
224 }
225
226 @Override
227 public void describeTo(Description description) {
228 description.appendText(reason);
229 }
230 }
231
232 /**
233 * Factory to allocate an intent array matcher.
234 *
235 * @param intent intent object we are looking for
236 * @return matcher
237 */
238 private static IntentJsonArrayMatcher hasIntent(Intent intent) {
239 return new IntentJsonArrayMatcher(intent);
240 }
Ray Milkey4f5de002014-12-17 19:26:11 -0800241
Ray Milkeyed0b1662015-02-05 09:34:29 -0800242 /**
243 * Initializes test mocks and environment.
244 */
Ray Milkey2b217142014-12-15 09:24:24 -0800245 @Before
Ray Milkeyed0b1662015-02-05 09:34:29 -0800246 public void setUpTest() {
Ray Milkey2b217142014-12-15 09:24:24 -0800247 expect(mockIntentService.getIntents()).andReturn(intents).anyTimes();
Ray Milkey1534f8d2015-05-13 15:42:50 -0700248 expect(mockIntentService.getIntentState(anyObject()))
249 .andReturn(IntentState.INSTALLED)
250 .anyTimes();
Ray Milkey2b217142014-12-15 09:24:24 -0800251 // Register the services needed for the test
252 final CodecManager codecService = new CodecManager();
253 codecService.activate();
254 ServiceDirectory testDirectory =
255 new TestServiceDirectory()
256 .add(IntentService.class, mockIntentService)
Ayaka Koshibec06c89b2015-02-10 19:25:41 -0800257 .add(CodecService.class, codecService)
258 .add(CoreService.class, mockCoreService);
Ray Milkey2b217142014-12-15 09:24:24 -0800259
260 BaseResource.setServiceDirectory(testDirectory);
261
262 mockGenerator = new MockIdGenerator();
263 Intent.bindIdGenerator(mockGenerator);
264 }
265
Ray Milkeyed0b1662015-02-05 09:34:29 -0800266 /**
267 * Tears down and verifies test mocks and environment.
268 */
Ray Milkey2b217142014-12-15 09:24:24 -0800269 @After
Ray Milkeyed0b1662015-02-05 09:34:29 -0800270 public void tearDownTest() {
Ray Milkey2b217142014-12-15 09:24:24 -0800271 verify(mockIntentService);
272 Intent.unbindIdGenerator(mockGenerator);
273 }
274
275 /**
276 * Tests the result of the rest api GET when there are no intents.
277 */
278 @Test
279 public void testIntentsEmptyArray() {
280 replay(mockIntentService);
281 final WebResource rs = resource();
282 final String response = rs.path("intents").get(String.class);
283 assertThat(response, is("{\"intents\":[]}"));
284 }
285
286 /**
287 * Tests the result of the rest api GET when intents are defined.
288 */
289 @Test
290 public void testIntentsArray() {
291 replay(mockIntentService);
292
Ray Milkey43a28222015-02-23 13:57:58 -0800293 final Intent intent1 = new MockIntent(1L, Collections.emptyList());
Ray Milkey2b217142014-12-15 09:24:24 -0800294 final HashSet<NetworkResource> resources = new HashSet<>();
295 resources.add(new MockResource(1));
296 resources.add(new MockResource(2));
297 resources.add(new MockResource(3));
Ray Milkey43a28222015-02-23 13:57:58 -0800298 final Intent intent2 = new MockIntent(2L, resources);
Ray Milkey2b217142014-12-15 09:24:24 -0800299
300 intents.add(intent1);
301 intents.add(intent2);
302 final WebResource rs = resource();
303 final String response = rs.path("intents").get(String.class);
304 assertThat(response, containsString("{\"intents\":["));
305
306 final JsonObject result = JsonObject.readFrom(response);
307 assertThat(result, notNullValue());
308
309 assertThat(result.names(), hasSize(1));
310 assertThat(result.names().get(0), is("intents"));
311
312 final JsonArray jsonIntents = result.get("intents").asArray();
313 assertThat(jsonIntents, notNullValue());
314
315 assertThat(jsonIntents, hasIntent(intent1));
316 assertThat(jsonIntents, hasIntent(intent2));
317 }
318
319 /**
320 * Tests the result of a rest api GET for a single intent.
321 */
322 @Test
323 public void testIntentsSingle() {
324 final HashSet<NetworkResource> resources = new HashSet<>();
325 resources.add(new MockResource(1));
326 resources.add(new MockResource(2));
327 resources.add(new MockResource(3));
Ray Milkey43a28222015-02-23 13:57:58 -0800328 final Intent intent = new MockIntent(3L, resources);
Ray Milkey2b217142014-12-15 09:24:24 -0800329
330 intents.add(intent);
331
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800332 expect(mockIntentService.getIntent(Key.of(0, APP_ID)))
Ray Milkey2b217142014-12-15 09:24:24 -0800333 .andReturn(intent)
334 .anyTimes();
Ayaka Koshibec06c89b2015-02-10 19:25:41 -0800335 expect(mockIntentService.getIntent(Key.of("0", APP_ID)))
336 .andReturn(intent)
337 .anyTimes();
Ray Milkey2b217142014-12-15 09:24:24 -0800338 replay(mockIntentService);
Ayaka Koshibec06c89b2015-02-10 19:25:41 -0800339 expect(mockCoreService.getAppId(APP_ID.id()))
340 .andReturn(APP_ID).anyTimes();
341 replay(mockCoreService);
Ray Milkey2b217142014-12-15 09:24:24 -0800342 final WebResource rs = resource();
Ayaka Koshibec06c89b2015-02-10 19:25:41 -0800343 final String response = rs.path("intents/1/0").get(String.class);
Ray Milkey2b217142014-12-15 09:24:24 -0800344 final JsonObject result = JsonObject.readFrom(response);
345 assertThat(result, matchesIntent(intent));
346 }
347
348 /**
349 * Tests that a fetch of a non-existent intent object throws an exception.
350 */
351 @Test
352 public void testBadGet() {
353
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800354 expect(mockIntentService.getIntent(Key.of(0, APP_ID)))
Ray Milkey2b217142014-12-15 09:24:24 -0800355 .andReturn(null)
356 .anyTimes();
357 replay(mockIntentService);
358
359 WebResource rs = resource();
360 try {
361 rs.path("intents/0").get(String.class);
362 fail("Fetch of non-existent intent did not throw an exception");
363 } catch (UniformInterfaceException ex) {
364 assertThat(ex.getMessage(),
365 containsString("returned a response status of"));
366 }
367 }
Ray Milkeyb82c42b2015-06-30 09:42:20 -0700368
369 /**
370 * Tests creating an intent with POST.
371 */
372 @Test
373 public void testPost() {
374 expect(mockCoreService.getAppId((short) 2))
375 .andReturn(new DefaultApplicationId(2, "app"));
376 replay(mockCoreService);
377
378 mockIntentService.submit(anyObject());
379 expectLastCall();
380 replay(mockIntentService);
381
382 InputStream jsonStream = IntentsResourceTest.class
383 .getResourceAsStream("post-intent.json");
384 WebResource rs = resource();
385
386 ClientResponse response = rs.path("intents")
387 .type(MediaType.APPLICATION_JSON_TYPE)
388 .post(ClientResponse.class, jsonStream);
389 assertThat(response.getStatus(), is(HttpURLConnection.HTTP_CREATED));
390 String location = response.getLocation().getPath();
391 assertThat(location, Matchers.startsWith("/intents/2/"));
392 }
Ray Milkey2b217142014-12-15 09:24:24 -0800393}