blob: b2eee81e666d9789f8c2eed6bd0a5138b56f5c6f [file] [log] [blame]
Ray Milkey2b217142014-12-15 09:24:24 -08001/*
2 * Copyright 2014 Open Networking Laboratory
3 *
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
18import java.util.Collection;
Sho SHIMIZUd7d18002015-01-21 14:37:14 -080019import java.util.Collections;
Ray Milkey2b217142014-12-15 09:24:24 -080020import java.util.HashSet;
21import java.util.concurrent.atomic.AtomicLong;
22
23import org.hamcrest.Description;
24import org.hamcrest.TypeSafeMatcher;
25import org.junit.After;
26import org.junit.Before;
27import org.junit.Test;
28import org.onlab.osgi.ServiceDirectory;
29import org.onlab.osgi.TestServiceDirectory;
30import org.onlab.rest.BaseResource;
31import org.onosproject.codec.CodecService;
32import org.onosproject.codec.impl.CodecManager;
33import org.onosproject.core.ApplicationId;
34import org.onosproject.core.DefaultApplicationId;
35import org.onosproject.core.IdGenerator;
36import org.onosproject.net.NetworkResource;
37import org.onosproject.net.intent.Intent;
38import org.onosproject.net.intent.IntentId;
39import org.onosproject.net.intent.IntentService;
40
41import com.eclipsesource.json.JsonArray;
42import com.eclipsesource.json.JsonObject;
43import com.eclipsesource.json.JsonValue;
44import com.google.common.base.MoreObjects;
45import com.sun.jersey.api.client.UniformInterfaceException;
46import com.sun.jersey.api.client.WebResource;
Ray Milkey2b217142014-12-15 09:24:24 -080047
48import static org.easymock.EasyMock.createMock;
49import static org.easymock.EasyMock.expect;
50import static org.easymock.EasyMock.replay;
51import static org.easymock.EasyMock.verify;
52import static org.hamcrest.Matchers.containsString;
53import static org.hamcrest.Matchers.hasSize;
54import static org.hamcrest.Matchers.is;
55import static org.hamcrest.Matchers.notNullValue;
56import static org.junit.Assert.assertThat;
57import static org.junit.Assert.fail;
58
59/**
60 * Unit tests for Intents REST APIs.
61 */
Ray Milkey9c3d3362015-01-28 10:39:56 -080062public class IntentsResourceTest extends ResourceTest {
Ray Milkey2b217142014-12-15 09:24:24 -080063 final IntentService mockIntentService = createMock(IntentService.class);
64 final HashSet<Intent> intents = new HashSet<>();
Thomas Vachuska02aeb032015-01-06 22:36:30 -080065 private static final ApplicationId APP_ID = new DefaultApplicationId(1, "test");
Ray Milkey2b217142014-12-15 09:24:24 -080066 private IdGenerator mockGenerator;
67
68 /**
69 * Mock ID generator. This should be refactored to share the one in
70 * the core/api tests.
71 */
72 public class MockIdGenerator implements IdGenerator {
73 private AtomicLong nextId = new AtomicLong(0);
74
75 @Override
76 public long getNewId() {
77 return nextId.getAndIncrement();
78 }
79 }
80
81 /**
82 * Mock compilable intent class.
83 */
84 private static class MockIntent extends Intent {
85
86 public MockIntent(Collection<NetworkResource> resources) {
87 super(APP_ID, resources);
88 }
89
90 @Override
91 public String toString() {
92 return MoreObjects.toStringHelper(getClass())
93 .add("id", id())
94 .add("appId", appId())
95 .toString();
96 }
97 }
98
99 private class MockResource implements NetworkResource {
100 int id;
101
102 MockResource(int id) {
103 this.id = id;
104 }
105
106 public String toString() {
107 return "Resource " + Integer.toString(id);
108 }
109 }
110
Ray Milkey2b217142014-12-15 09:24:24 -0800111 /**
112 * Hamcrest matcher to check that an intent representation in JSON matches
113 * the actual intent.
114 */
115 public static class IntentJsonMatcher extends TypeSafeMatcher<JsonObject> {
116 private final Intent intent;
117 private String reason = "";
118
119 public IntentJsonMatcher(Intent intentValue) {
120 intent = intentValue;
121 }
122
123 @Override
124 public boolean matchesSafely(JsonObject jsonIntent) {
125 // check id
126 final String jsonId = jsonIntent.get("id").asString();
127 if (!jsonId.equals(intent.id().toString())) {
128 reason = "id " + intent.id().toString();
129 return false;
130 }
131
132 // check application id
133 final String jsonAppId = jsonIntent.get("appId").asString();
134 if (!jsonAppId.equals(intent.appId().toString())) {
135 reason = "appId " + intent.appId().toString();
136 return false;
137 }
138
139 // check intent type
140 final String jsonType = jsonIntent.get("type").asString();
141 if (!jsonType.equals("MockIntent")) {
142 reason = "type MockIntent";
143 return false;
144 }
145
146 // check details field
147 final String jsonDetails = jsonIntent.get("details").asString();
148 if (!jsonDetails.equals(intent.toString())) {
149 reason = "details " + intent.toString();
150 return false;
151 }
152
153 // check resources array
154 final JsonArray jsonResources = jsonIntent.get("resources").asArray();
155 if (intent.resources() != null) {
156 if (intent.resources().size() != jsonResources.size()) {
157 reason = "resources array size of " + Integer.toString(intent.resources().size());
158 return false;
159 }
160 for (final NetworkResource resource : intent.resources()) {
161 boolean resourceFound = false;
162 final String resourceString = resource.toString();
163 for (int resourceIndex = 0; resourceIndex < jsonResources.size(); resourceIndex++) {
164 final JsonValue value = jsonResources.get(resourceIndex);
165 if (value.asString().equals(resourceString)) {
166 resourceFound = true;
167 }
168 }
169 if (!resourceFound) {
170 reason = "resource " + resourceString;
171 return false;
172 }
173 }
174 } else if (jsonResources.size() != 0) {
175 reason = "resources array empty";
176 return false;
177 }
178 return true;
179 }
180
181 @Override
182 public void describeTo(Description description) {
183 description.appendText(reason);
184 }
185 }
186
187 /**
188 * Factory to allocate an intent matcher.
189 *
190 * @param intent intent object we are looking for
191 * @return matcher
192 */
193 private static IntentJsonMatcher matchesIntent(Intent intent) {
194 return new IntentJsonMatcher(intent);
195 }
196
197 /**
198 * Hamcrest matcher to check that an intent is represented properly in a JSON
199 * array of intents.
200 */
201 public static class IntentJsonArrayMatcher extends TypeSafeMatcher<JsonArray> {
202 private final Intent intent;
203 private String reason = "";
204
205 public IntentJsonArrayMatcher(Intent intentValue) {
206 intent = intentValue;
207 }
208
209 @Override
210 public boolean matchesSafely(JsonArray json) {
211 boolean intentFound = false;
212 final int expectedAttributes = 5;
213 for (int jsonIntentIndex = 0; jsonIntentIndex < json.size();
214 jsonIntentIndex++) {
215
216 final JsonObject jsonIntent = json.get(jsonIntentIndex).asObject();
217
218 if (jsonIntent.names().size() != expectedAttributes) {
219 reason = "Found an intent with the wrong number of attributes";
220 return false;
221 }
222
223 final String jsonIntentId = jsonIntent.get("id").asString();
224 if (jsonIntentId.equals(intent.id().toString())) {
225 intentFound = true;
226
227 // We found the correct intent, check attribute values
228 assertThat(jsonIntent, matchesIntent(intent));
229 }
230 }
231 if (!intentFound) {
232 reason = "Intent with id " + intent.id().toString() + " not found";
233 return false;
234 } else {
235 return true;
236 }
237 }
238
239 @Override
240 public void describeTo(Description description) {
241 description.appendText(reason);
242 }
243 }
244
245 /**
246 * Factory to allocate an intent array matcher.
247 *
248 * @param intent intent object we are looking for
249 * @return matcher
250 */
251 private static IntentJsonArrayMatcher hasIntent(Intent intent) {
252 return new IntentJsonArrayMatcher(intent);
253 }
Ray Milkey4f5de002014-12-17 19:26:11 -0800254
Ray Milkey2b217142014-12-15 09:24:24 -0800255 @Before
256 public void setUp() {
257 expect(mockIntentService.getIntents()).andReturn(intents).anyTimes();
258
259 // Register the services needed for the test
260 final CodecManager codecService = new CodecManager();
261 codecService.activate();
262 ServiceDirectory testDirectory =
263 new TestServiceDirectory()
264 .add(IntentService.class, mockIntentService)
265 .add(CodecService.class, codecService);
266
267 BaseResource.setServiceDirectory(testDirectory);
268
269 mockGenerator = new MockIdGenerator();
270 Intent.bindIdGenerator(mockGenerator);
271 }
272
273 @After
274 public void tearDown() throws Exception {
275 super.tearDown();
276 verify(mockIntentService);
277 Intent.unbindIdGenerator(mockGenerator);
278 }
279
280 /**
281 * Tests the result of the rest api GET when there are no intents.
282 */
283 @Test
284 public void testIntentsEmptyArray() {
285 replay(mockIntentService);
286 final WebResource rs = resource();
287 final String response = rs.path("intents").get(String.class);
288 assertThat(response, is("{\"intents\":[]}"));
289 }
290
291 /**
292 * Tests the result of the rest api GET when intents are defined.
293 */
294 @Test
295 public void testIntentsArray() {
296 replay(mockIntentService);
297
Sho SHIMIZUd7d18002015-01-21 14:37:14 -0800298 final Intent intent1 = new MockIntent(Collections.emptyList());
Ray Milkey2b217142014-12-15 09:24:24 -0800299 final HashSet<NetworkResource> resources = new HashSet<>();
300 resources.add(new MockResource(1));
301 resources.add(new MockResource(2));
302 resources.add(new MockResource(3));
303 final Intent intent2 = new MockIntent(resources);
304
305 intents.add(intent1);
306 intents.add(intent2);
307 final WebResource rs = resource();
308 final String response = rs.path("intents").get(String.class);
309 assertThat(response, containsString("{\"intents\":["));
310
311 final JsonObject result = JsonObject.readFrom(response);
312 assertThat(result, notNullValue());
313
314 assertThat(result.names(), hasSize(1));
315 assertThat(result.names().get(0), is("intents"));
316
317 final JsonArray jsonIntents = result.get("intents").asArray();
318 assertThat(jsonIntents, notNullValue());
319
320 assertThat(jsonIntents, hasIntent(intent1));
321 assertThat(jsonIntents, hasIntent(intent2));
322 }
323
324 /**
325 * Tests the result of a rest api GET for a single intent.
326 */
327 @Test
328 public void testIntentsSingle() {
329 final HashSet<NetworkResource> resources = new HashSet<>();
330 resources.add(new MockResource(1));
331 resources.add(new MockResource(2));
332 resources.add(new MockResource(3));
333 final Intent intent = new MockIntent(resources);
334
335 intents.add(intent);
336
337 expect(mockIntentService.getIntent(IntentId.valueOf(0)))
338 .andReturn(intent)
339 .anyTimes();
340 replay(mockIntentService);
341
342 final WebResource rs = resource();
343 final String response = rs.path("intents/0").get(String.class);
344 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
354 expect(mockIntentService.getIntent(IntentId.valueOf(0)))
355 .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 }
368}