blob: ee39094d4d2c89769a2742b10597474ea26765cf [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
Ray Milkeyf7cb4012015-07-20 13:01:07 -0700113
Ray Milkey2b217142014-12-15 09:24:24 -0800114 final String jsonAppId = jsonIntent.get("appId").asString();
Ray Milkeyf7cb4012015-07-20 13:01:07 -0700115 final String appId = intent.appId().name();
116 if (!jsonAppId.equals(appId)) {
117 reason = "appId was " + jsonAppId;
Ray Milkey2b217142014-12-15 09:24:24 -0800118 return false;
119 }
120
121 // check intent type
122 final String jsonType = jsonIntent.get("type").asString();
123 if (!jsonType.equals("MockIntent")) {
124 reason = "type MockIntent";
125 return false;
126 }
127
Ray Milkey1534f8d2015-05-13 15:42:50 -0700128 // check state field
129 final String jsonState = jsonIntent.get("state").asString();
130 if (!jsonState.equals("INSTALLED")) {
131 reason = "state INSTALLED";
132 return false;
133 }
134
Ray Milkey2b217142014-12-15 09:24:24 -0800135 // check resources array
136 final JsonArray jsonResources = jsonIntent.get("resources").asArray();
137 if (intent.resources() != null) {
138 if (intent.resources().size() != jsonResources.size()) {
139 reason = "resources array size of " + Integer.toString(intent.resources().size());
140 return false;
141 }
142 for (final NetworkResource resource : intent.resources()) {
143 boolean resourceFound = false;
144 final String resourceString = resource.toString();
145 for (int resourceIndex = 0; resourceIndex < jsonResources.size(); resourceIndex++) {
146 final JsonValue value = jsonResources.get(resourceIndex);
147 if (value.asString().equals(resourceString)) {
148 resourceFound = true;
149 }
150 }
151 if (!resourceFound) {
152 reason = "resource " + resourceString;
153 return false;
154 }
155 }
156 } else if (jsonResources.size() != 0) {
157 reason = "resources array empty";
158 return false;
159 }
160 return true;
161 }
162
163 @Override
164 public void describeTo(Description description) {
165 description.appendText(reason);
166 }
167 }
168
169 /**
170 * Factory to allocate an intent matcher.
171 *
172 * @param intent intent object we are looking for
173 * @return matcher
174 */
175 private static IntentJsonMatcher matchesIntent(Intent intent) {
176 return new IntentJsonMatcher(intent);
177 }
178
179 /**
180 * Hamcrest matcher to check that an intent is represented properly in a JSON
181 * array of intents.
182 */
183 public static class IntentJsonArrayMatcher extends TypeSafeMatcher<JsonArray> {
184 private final Intent intent;
185 private String reason = "";
186
187 public IntentJsonArrayMatcher(Intent intentValue) {
188 intent = intentValue;
189 }
190
191 @Override
192 public boolean matchesSafely(JsonArray json) {
193 boolean intentFound = false;
Ray Milkeyf7cb4012015-07-20 13:01:07 -0700194 final int expectedAttributes = 5;
Ray Milkey2b217142014-12-15 09:24:24 -0800195 for (int jsonIntentIndex = 0; jsonIntentIndex < json.size();
196 jsonIntentIndex++) {
197
198 final JsonObject jsonIntent = json.get(jsonIntentIndex).asObject();
199
200 if (jsonIntent.names().size() != expectedAttributes) {
201 reason = "Found an intent with the wrong number of attributes";
202 return false;
203 }
204
205 final String jsonIntentId = jsonIntent.get("id").asString();
206 if (jsonIntentId.equals(intent.id().toString())) {
207 intentFound = true;
208
209 // We found the correct intent, check attribute values
210 assertThat(jsonIntent, matchesIntent(intent));
211 }
212 }
213 if (!intentFound) {
214 reason = "Intent with id " + intent.id().toString() + " not found";
215 return false;
216 } else {
217 return true;
218 }
219 }
220
221 @Override
222 public void describeTo(Description description) {
223 description.appendText(reason);
224 }
225 }
226
227 /**
228 * Factory to allocate an intent array matcher.
229 *
230 * @param intent intent object we are looking for
231 * @return matcher
232 */
233 private static IntentJsonArrayMatcher hasIntent(Intent intent) {
234 return new IntentJsonArrayMatcher(intent);
235 }
Ray Milkey4f5de002014-12-17 19:26:11 -0800236
Ray Milkeyed0b1662015-02-05 09:34:29 -0800237 /**
238 * Initializes test mocks and environment.
239 */
Ray Milkey2b217142014-12-15 09:24:24 -0800240 @Before
Ray Milkeyed0b1662015-02-05 09:34:29 -0800241 public void setUpTest() {
Ray Milkey2b217142014-12-15 09:24:24 -0800242 expect(mockIntentService.getIntents()).andReturn(intents).anyTimes();
Ray Milkey1534f8d2015-05-13 15:42:50 -0700243 expect(mockIntentService.getIntentState(anyObject()))
244 .andReturn(IntentState.INSTALLED)
245 .anyTimes();
Ray Milkey2b217142014-12-15 09:24:24 -0800246 // Register the services needed for the test
247 final CodecManager codecService = new CodecManager();
248 codecService.activate();
249 ServiceDirectory testDirectory =
250 new TestServiceDirectory()
251 .add(IntentService.class, mockIntentService)
Ayaka Koshibec06c89b2015-02-10 19:25:41 -0800252 .add(CodecService.class, codecService)
253 .add(CoreService.class, mockCoreService);
Ray Milkey2b217142014-12-15 09:24:24 -0800254
255 BaseResource.setServiceDirectory(testDirectory);
256
257 mockGenerator = new MockIdGenerator();
258 Intent.bindIdGenerator(mockGenerator);
259 }
260
Ray Milkeyed0b1662015-02-05 09:34:29 -0800261 /**
262 * Tears down and verifies test mocks and environment.
263 */
Ray Milkey2b217142014-12-15 09:24:24 -0800264 @After
Ray Milkeyed0b1662015-02-05 09:34:29 -0800265 public void tearDownTest() {
Ray Milkey2b217142014-12-15 09:24:24 -0800266 verify(mockIntentService);
267 Intent.unbindIdGenerator(mockGenerator);
268 }
269
270 /**
271 * Tests the result of the rest api GET when there are no intents.
272 */
273 @Test
274 public void testIntentsEmptyArray() {
275 replay(mockIntentService);
276 final WebResource rs = resource();
277 final String response = rs.path("intents").get(String.class);
278 assertThat(response, is("{\"intents\":[]}"));
279 }
280
281 /**
282 * Tests the result of the rest api GET when intents are defined.
283 */
284 @Test
285 public void testIntentsArray() {
286 replay(mockIntentService);
287
Ray Milkey43a28222015-02-23 13:57:58 -0800288 final Intent intent1 = new MockIntent(1L, Collections.emptyList());
Ray Milkey2b217142014-12-15 09:24:24 -0800289 final HashSet<NetworkResource> resources = new HashSet<>();
290 resources.add(new MockResource(1));
291 resources.add(new MockResource(2));
292 resources.add(new MockResource(3));
Ray Milkey43a28222015-02-23 13:57:58 -0800293 final Intent intent2 = new MockIntent(2L, resources);
Ray Milkey2b217142014-12-15 09:24:24 -0800294
295 intents.add(intent1);
296 intents.add(intent2);
297 final WebResource rs = resource();
298 final String response = rs.path("intents").get(String.class);
299 assertThat(response, containsString("{\"intents\":["));
300
301 final JsonObject result = JsonObject.readFrom(response);
302 assertThat(result, notNullValue());
303
304 assertThat(result.names(), hasSize(1));
305 assertThat(result.names().get(0), is("intents"));
306
307 final JsonArray jsonIntents = result.get("intents").asArray();
308 assertThat(jsonIntents, notNullValue());
309
310 assertThat(jsonIntents, hasIntent(intent1));
311 assertThat(jsonIntents, hasIntent(intent2));
312 }
313
314 /**
315 * Tests the result of a rest api GET for a single intent.
316 */
317 @Test
318 public void testIntentsSingle() {
319 final HashSet<NetworkResource> resources = new HashSet<>();
320 resources.add(new MockResource(1));
321 resources.add(new MockResource(2));
322 resources.add(new MockResource(3));
Ray Milkey43a28222015-02-23 13:57:58 -0800323 final Intent intent = new MockIntent(3L, resources);
Ray Milkey2b217142014-12-15 09:24:24 -0800324
325 intents.add(intent);
326
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800327 expect(mockIntentService.getIntent(Key.of(0, APP_ID)))
Ray Milkey2b217142014-12-15 09:24:24 -0800328 .andReturn(intent)
329 .anyTimes();
Ayaka Koshibec06c89b2015-02-10 19:25:41 -0800330 expect(mockIntentService.getIntent(Key.of("0", APP_ID)))
331 .andReturn(intent)
332 .anyTimes();
Ray Milkey2b217142014-12-15 09:24:24 -0800333 replay(mockIntentService);
Ray Milkeyf7cb4012015-07-20 13:01:07 -0700334 expect(mockCoreService.getAppId(APP_ID.name()))
Ayaka Koshibec06c89b2015-02-10 19:25:41 -0800335 .andReturn(APP_ID).anyTimes();
336 replay(mockCoreService);
Ray Milkey2b217142014-12-15 09:24:24 -0800337 final WebResource rs = resource();
Ray Milkeyf7cb4012015-07-20 13:01:07 -0700338 final String response = rs.path("intents/" + APP_ID.name()
339 + "/0").get(String.class);
Ray Milkey2b217142014-12-15 09:24:24 -0800340 final JsonObject result = JsonObject.readFrom(response);
341 assertThat(result, matchesIntent(intent));
342 }
343
344 /**
345 * Tests that a fetch of a non-existent intent object throws an exception.
346 */
347 @Test
348 public void testBadGet() {
349
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800350 expect(mockIntentService.getIntent(Key.of(0, APP_ID)))
Ray Milkey2b217142014-12-15 09:24:24 -0800351 .andReturn(null)
352 .anyTimes();
353 replay(mockIntentService);
354
355 WebResource rs = resource();
356 try {
357 rs.path("intents/0").get(String.class);
358 fail("Fetch of non-existent intent did not throw an exception");
359 } catch (UniformInterfaceException ex) {
360 assertThat(ex.getMessage(),
361 containsString("returned a response status of"));
362 }
363 }
Ray Milkeyb82c42b2015-06-30 09:42:20 -0700364
365 /**
366 * Tests creating an intent with POST.
367 */
368 @Test
369 public void testPost() {
Ray Milkeyf7cb4012015-07-20 13:01:07 -0700370 ApplicationId testId = new DefaultApplicationId(2, "myApp");
371 expect(mockCoreService.getAppId("myApp"))
372 .andReturn(testId);
Ray Milkeyb82c42b2015-06-30 09:42:20 -0700373 replay(mockCoreService);
374
375 mockIntentService.submit(anyObject());
376 expectLastCall();
377 replay(mockIntentService);
378
379 InputStream jsonStream = IntentsResourceTest.class
380 .getResourceAsStream("post-intent.json");
381 WebResource rs = resource();
382
383 ClientResponse response = rs.path("intents")
384 .type(MediaType.APPLICATION_JSON_TYPE)
385 .post(ClientResponse.class, jsonStream);
386 assertThat(response.getStatus(), is(HttpURLConnection.HTTP_CREATED));
387 String location = response.getLocation().getPath();
388 assertThat(location, Matchers.startsWith("/intents/2/"));
389 }
Ray Milkey2b217142014-12-15 09:24:24 -0800390}