blob: 2d650a5692b40121a39c80ad4a6730998b47c2cd [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<>();
65 private static final ApplicationId APP_ID =
66 new DefaultApplicationId((short) 1, "test");
67 private IdGenerator mockGenerator;
68
69 /**
70 * Mock ID generator. This should be refactored to share the one in
71 * the core/api tests.
72 */
73 public class MockIdGenerator implements IdGenerator {
74 private AtomicLong nextId = new AtomicLong(0);
75
76 @Override
77 public long getNewId() {
78 return nextId.getAndIncrement();
79 }
80 }
81
82 /**
83 * Mock compilable intent class.
84 */
85 private static class MockIntent extends Intent {
86
87 public MockIntent(Collection<NetworkResource> resources) {
88 super(APP_ID, resources);
89 }
90
91 @Override
92 public String toString() {
93 return MoreObjects.toStringHelper(getClass())
94 .add("id", id())
95 .add("appId", appId())
96 .toString();
97 }
98 }
99
100 private class MockResource implements NetworkResource {
101 int id;
102
103 MockResource(int id) {
104 this.id = id;
105 }
106
107 public String toString() {
108 return "Resource " + Integer.toString(id);
109 }
110 }
111
Ray Milkey2b217142014-12-15 09:24:24 -0800112 /**
113 * Hamcrest matcher to check that an intent representation in JSON matches
114 * the actual intent.
115 */
116 public static class IntentJsonMatcher extends TypeSafeMatcher<JsonObject> {
117 private final Intent intent;
118 private String reason = "";
119
120 public IntentJsonMatcher(Intent intentValue) {
121 intent = intentValue;
122 }
123
124 @Override
125 public boolean matchesSafely(JsonObject jsonIntent) {
126 // check id
127 final String jsonId = jsonIntent.get("id").asString();
128 if (!jsonId.equals(intent.id().toString())) {
129 reason = "id " + intent.id().toString();
130 return false;
131 }
132
133 // check application id
134 final String jsonAppId = jsonIntent.get("appId").asString();
135 if (!jsonAppId.equals(intent.appId().toString())) {
136 reason = "appId " + intent.appId().toString();
137 return false;
138 }
139
140 // check intent type
141 final String jsonType = jsonIntent.get("type").asString();
142 if (!jsonType.equals("MockIntent")) {
143 reason = "type MockIntent";
144 return false;
145 }
146
147 // check details field
148 final String jsonDetails = jsonIntent.get("details").asString();
149 if (!jsonDetails.equals(intent.toString())) {
150 reason = "details " + intent.toString();
151 return false;
152 }
153
154 // check resources array
155 final JsonArray jsonResources = jsonIntent.get("resources").asArray();
156 if (intent.resources() != null) {
157 if (intent.resources().size() != jsonResources.size()) {
158 reason = "resources array size of " + Integer.toString(intent.resources().size());
159 return false;
160 }
161 for (final NetworkResource resource : intent.resources()) {
162 boolean resourceFound = false;
163 final String resourceString = resource.toString();
164 for (int resourceIndex = 0; resourceIndex < jsonResources.size(); resourceIndex++) {
165 final JsonValue value = jsonResources.get(resourceIndex);
166 if (value.asString().equals(resourceString)) {
167 resourceFound = true;
168 }
169 }
170 if (!resourceFound) {
171 reason = "resource " + resourceString;
172 return false;
173 }
174 }
175 } else if (jsonResources.size() != 0) {
176 reason = "resources array empty";
177 return false;
178 }
179 return true;
180 }
181
182 @Override
183 public void describeTo(Description description) {
184 description.appendText(reason);
185 }
186 }
187
188 /**
189 * Factory to allocate an intent matcher.
190 *
191 * @param intent intent object we are looking for
192 * @return matcher
193 */
194 private static IntentJsonMatcher matchesIntent(Intent intent) {
195 return new IntentJsonMatcher(intent);
196 }
197
198 /**
199 * Hamcrest matcher to check that an intent is represented properly in a JSON
200 * array of intents.
201 */
202 public static class IntentJsonArrayMatcher extends TypeSafeMatcher<JsonArray> {
203 private final Intent intent;
204 private String reason = "";
205
206 public IntentJsonArrayMatcher(Intent intentValue) {
207 intent = intentValue;
208 }
209
210 @Override
211 public boolean matchesSafely(JsonArray json) {
212 boolean intentFound = false;
213 final int expectedAttributes = 5;
214 for (int jsonIntentIndex = 0; jsonIntentIndex < json.size();
215 jsonIntentIndex++) {
216
217 final JsonObject jsonIntent = json.get(jsonIntentIndex).asObject();
218
219 if (jsonIntent.names().size() != expectedAttributes) {
220 reason = "Found an intent with the wrong number of attributes";
221 return false;
222 }
223
224 final String jsonIntentId = jsonIntent.get("id").asString();
225 if (jsonIntentId.equals(intent.id().toString())) {
226 intentFound = true;
227
228 // We found the correct intent, check attribute values
229 assertThat(jsonIntent, matchesIntent(intent));
230 }
231 }
232 if (!intentFound) {
233 reason = "Intent with id " + intent.id().toString() + " not found";
234 return false;
235 } else {
236 return true;
237 }
238 }
239
240 @Override
241 public void describeTo(Description description) {
242 description.appendText(reason);
243 }
244 }
245
246 /**
247 * Factory to allocate an intent array matcher.
248 *
249 * @param intent intent object we are looking for
250 * @return matcher
251 */
252 private static IntentJsonArrayMatcher hasIntent(Intent intent) {
253 return new IntentJsonArrayMatcher(intent);
254 }
Ray Milkey4f5de002014-12-17 19:26:11 -0800255
Ray Milkey2b217142014-12-15 09:24:24 -0800256 @Before
257 public void setUp() {
258 expect(mockIntentService.getIntents()).andReturn(intents).anyTimes();
259
260 // Register the services needed for the test
261 final CodecManager codecService = new CodecManager();
262 codecService.activate();
263 ServiceDirectory testDirectory =
264 new TestServiceDirectory()
265 .add(IntentService.class, mockIntentService)
266 .add(CodecService.class, codecService);
267
268 BaseResource.setServiceDirectory(testDirectory);
269
270 mockGenerator = new MockIdGenerator();
271 Intent.bindIdGenerator(mockGenerator);
272 }
273
274 @After
275 public void tearDown() throws Exception {
276 super.tearDown();
277 verify(mockIntentService);
278 Intent.unbindIdGenerator(mockGenerator);
279 }
280
281 /**
282 * Tests the result of the rest api GET when there are no intents.
283 */
284 @Test
285 public void testIntentsEmptyArray() {
286 replay(mockIntentService);
287 final WebResource rs = resource();
288 final String response = rs.path("intents").get(String.class);
289 assertThat(response, is("{\"intents\":[]}"));
290 }
291
292 /**
293 * Tests the result of the rest api GET when intents are defined.
294 */
295 @Test
296 public void testIntentsArray() {
297 replay(mockIntentService);
298
Sho SHIMIZUd7d18002015-01-21 14:37:14 -0800299 final Intent intent1 = new MockIntent(Collections.emptyList());
Ray Milkey2b217142014-12-15 09:24:24 -0800300 final HashSet<NetworkResource> resources = new HashSet<>();
301 resources.add(new MockResource(1));
302 resources.add(new MockResource(2));
303 resources.add(new MockResource(3));
304 final Intent intent2 = new MockIntent(resources);
305
306 intents.add(intent1);
307 intents.add(intent2);
308 final WebResource rs = resource();
309 final String response = rs.path("intents").get(String.class);
310 assertThat(response, containsString("{\"intents\":["));
311
312 final JsonObject result = JsonObject.readFrom(response);
313 assertThat(result, notNullValue());
314
315 assertThat(result.names(), hasSize(1));
316 assertThat(result.names().get(0), is("intents"));
317
318 final JsonArray jsonIntents = result.get("intents").asArray();
319 assertThat(jsonIntents, notNullValue());
320
321 assertThat(jsonIntents, hasIntent(intent1));
322 assertThat(jsonIntents, hasIntent(intent2));
323 }
324
325 /**
326 * Tests the result of a rest api GET for a single intent.
327 */
328 @Test
329 public void testIntentsSingle() {
330 final HashSet<NetworkResource> resources = new HashSet<>();
331 resources.add(new MockResource(1));
332 resources.add(new MockResource(2));
333 resources.add(new MockResource(3));
334 final Intent intent = new MockIntent(resources);
335
336 intents.add(intent);
337
338 expect(mockIntentService.getIntent(IntentId.valueOf(0)))
339 .andReturn(intent)
340 .anyTimes();
341 replay(mockIntentService);
342
343 final WebResource rs = resource();
344 final String response = rs.path("intents/0").get(String.class);
345 final JsonObject result = JsonObject.readFrom(response);
346 assertThat(result, matchesIntent(intent));
347 }
348
349 /**
350 * Tests that a fetch of a non-existent intent object throws an exception.
351 */
352 @Test
353 public void testBadGet() {
354
355 expect(mockIntentService.getIntent(IntentId.valueOf(0)))
356 .andReturn(null)
357 .anyTimes();
358 replay(mockIntentService);
359
360 WebResource rs = resource();
361 try {
362 rs.path("intents/0").get(String.class);
363 fail("Fetch of non-existent intent did not throw an exception");
364 } catch (UniformInterfaceException ex) {
365 assertThat(ex.getMessage(),
366 containsString("returned a response status of"));
367 }
368 }
369}