blob: 886674c61b8db95abd70ab814d51ea76bb224e14 [file] [log] [blame]
Brian Stankeb9170d92016-02-19 14:18:42 -05001/*
2 * Copyright 2016 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 */
16
17package org.onosproject.rest;
18
19import com.eclipsesource.json.Json;
20import com.eclipsesource.json.JsonArray;
21import com.eclipsesource.json.JsonObject;
22import com.sun.jersey.api.client.ClientResponse;
23import com.sun.jersey.api.client.UniformInterfaceException;
24import com.sun.jersey.api.client.WebResource;
25import org.hamcrest.Description;
26import org.hamcrest.Matchers;
27import 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.net.key.DeviceKey;
37import org.onosproject.net.key.DeviceKeyAdminService;
38import org.onosproject.net.key.DeviceKeyId;
39import org.onosproject.net.key.DeviceKeyService;
40
41import javax.ws.rs.core.MediaType;
42import java.io.InputStream;
43import java.net.HttpURLConnection;
44import java.util.HashSet;
45
46import static org.easymock.EasyMock.*;
47import static org.hamcrest.Matchers.*;
48import static org.junit.Assert.*;
49
50/**
51 * Unit tests for device key REST APIs.
52 */
53public class DeviceKeyWebResourceTest extends ResourceTest {
54
55 final DeviceKeyService mockDeviceKeyService = createMock(DeviceKeyService.class);
56 final DeviceKeyAdminService mockDeviceKeyAdminService = createMock(DeviceKeyAdminService.class);
57
58 final HashSet<DeviceKey> deviceKeySet = new HashSet<>();
59
60 private static final String ID = "id";
61 private static final String TYPE = "type";
62 private static final String LABEL = "label";
63 private static final String COMMUNITY_NAME = "community_name";
64 private static final String USERNAME = "username";
65 private static final String PASSWORD = "password";
66
67 private final String deviceKeyId1 = "DeviceKeyId1";
68 private final String deviceKeyId2 = "DeviceKeyId2";
69 private final String deviceKeyId3 = "DeviceKeyId3";
70 private final String deviceKeyLabel = "DeviceKeyLabel";
71 private final String deviceKeyCommunityName = "DeviceKeyCommunityName";
72 private final String deviceKeyUsername = "DeviceKeyUsername";
73 private final String deviceKeyPassword = "DeviceKeyPassword";
74
75 private final DeviceKey deviceKey1 = DeviceKey.createDeviceKeyUsingCommunityName(
76 DeviceKeyId.deviceKeyId(deviceKeyId1), deviceKeyLabel, deviceKeyCommunityName);
77 private final DeviceKey deviceKey2 = DeviceKey.createDeviceKeyUsingUsernamePassword(
78 DeviceKeyId.deviceKeyId(deviceKeyId2), deviceKeyLabel, deviceKeyUsername, deviceKeyPassword);
79
80 /**
81 * Initializes test mocks and environment.
82 */
83 @Before
84 public void setUpMocks() {
85 expect(mockDeviceKeyService.getDeviceKeys()).andReturn(deviceKeySet).anyTimes();
86
87 // Register the services needed for the test
88 CodecManager codecService = new CodecManager();
89 codecService.activate();
90 ServiceDirectory testDirectory =
91 new TestServiceDirectory()
92 .add(DeviceKeyService.class, mockDeviceKeyService)
93 .add(DeviceKeyAdminService.class, mockDeviceKeyAdminService)
94 .add(CodecService.class, codecService);
95
96 BaseResource.setServiceDirectory(testDirectory);
97 }
98
99 /**
100 * Verifies test mocks.
101 */
102 @After
103 public void tearDownMocks() {
104 verify(mockDeviceKeyService);
105 verify(mockDeviceKeyAdminService);
106 }
107
108 /**
109 * Hamcrest matcher to check that a device key representation in JSON matches
110 * the actual device key.
111 */
112 public static class DeviceKeyJsonMatcher extends TypeSafeMatcher<JsonObject> {
113 private final DeviceKey deviceKey;
114 private String reason = "";
115
116 public DeviceKeyJsonMatcher(DeviceKey deviceKeyValue) {
117 deviceKey = deviceKeyValue;
118 }
119
120 @Override
121 public boolean matchesSafely(JsonObject jsonHost) {
122 // Check the device key id
123 final String jsonId = jsonHost.get(ID).asString();
124 if (!jsonId.equals(deviceKey.deviceKeyId().id().toString())) {
125 reason = ID + " " + deviceKey.deviceKeyId().id().toString();
126 return false;
127 }
128
129 // Check the device key label
130 final String jsonLabel = jsonHost.get(LABEL).asString();
131 if (!jsonLabel.equals(deviceKey.label().toString())) {
132 reason = LABEL + " " + deviceKey.label().toString();
133 return false;
134 }
135
136 // Check the device key type
137 final String jsonType = jsonHost.get(TYPE).asString();
138 if (!jsonType.equals(deviceKey.type().toString())) {
139 reason = TYPE + " " + deviceKey.type().toString();
140 return false;
141 }
142
143 if (jsonType.equals(DeviceKey.Type.COMMUNITY_NAME.toString())) {
144 // Check the device key community name
145 final String jsonCommunityName = jsonHost.get(COMMUNITY_NAME).asString();
146 if (!jsonCommunityName.equals(deviceKey.asCommunityName().name().toString())) {
147 reason = COMMUNITY_NAME + " " + deviceKey.asCommunityName().name().toString();
148 return false;
149 }
150 } else if (jsonType.equals(DeviceKey.Type.USERNAME_PASSWORD.toString())) {
151 // Check the device key username
152 final String jsonUsername = jsonHost.get(USERNAME).asString();
153 if (!jsonUsername.equals(deviceKey.asUsernamePassword().username().toString())) {
154 reason = USERNAME + " " + deviceKey.asUsernamePassword().username().toString();
155 return false;
156 }
157
158 // Check the device key password
159 final String jsonPassword = jsonHost.get(PASSWORD).asString();
160 if (!jsonPassword.equals(deviceKey.asUsernamePassword().password().toString())) {
161 reason = PASSWORD + " " + deviceKey.asUsernamePassword().password().toString();
162 return false;
163 }
164 } else {
165 reason = "Unknown " + TYPE + " " + deviceKey.type().toString();
166 return false;
167 }
168
169 return true;
170 }
171
172 @Override
173 public void describeTo(Description description) {
174 description.appendText(reason);
175 }
176 }
177
178 /**
179 * Factory to allocate a device key array matcher.
180 *
181 * @param deviceKey device key object we are looking for
182 * @return matcher
183 */
184 private static DeviceKeyJsonMatcher matchesDeviceKey(DeviceKey deviceKey) {
185 return new DeviceKeyJsonMatcher(deviceKey);
186 }
187
188 /**
189 * Hamcrest matcher to check that a device key is represented properly in a JSON
190 * array of device keys.
191 */
192 public static class DeviceKeyJsonArrayMatcher extends TypeSafeMatcher<JsonArray> {
193 private final DeviceKey deviceKey;
194 private String reason = "";
195
196 public DeviceKeyJsonArrayMatcher(DeviceKey deviceKeyValue) {
197 deviceKey = deviceKeyValue;
198 }
199
200 @Override
201 public boolean matchesSafely(JsonArray json) {
202 boolean deviceKeyFound = false;
203 final int expectedAttributes = 5;
204 for (int jsonDeviceKeyIndex = 0; jsonDeviceKeyIndex < json.size();
205 jsonDeviceKeyIndex++) {
206
207 final JsonObject jsonHost = json.get(jsonDeviceKeyIndex).asObject();
208
209 // Device keys can have a variable number of attribute so we check
210 // that there is a minimum number.
211 if (jsonHost.names().size() < expectedAttributes) {
212 reason = "Found a device key with the wrong number of attributes";
213 return false;
214 }
215
216 final String jsonDeviceKeyId = jsonHost.get(ID).asString();
217 if (jsonDeviceKeyId.equals(deviceKey.deviceKeyId().id().toString())) {
218 deviceKeyFound = true;
219
220 // We found the correct device key, check the device key attribute values
221 assertThat(jsonHost, matchesDeviceKey(deviceKey));
222 }
223 }
224 if (!deviceKeyFound) {
225 reason = "Device key with id " + deviceKey.deviceKeyId().id().toString() + " was not found";
226 return false;
227 } else {
228 return true;
229 }
230 }
231
232 @Override
233 public void describeTo(Description description) {
234 description.appendText(reason);
235 }
236 }
237
238 /**
239 * Factory to allocate a device key array matcher.
240 *
241 * @param deviceKey device key object we are looking for
242 * @return matcher
243 */
244 private static DeviceKeyJsonArrayMatcher hasDeviceKey(DeviceKey deviceKey) {
245 return new DeviceKeyJsonArrayMatcher(deviceKey);
246 }
247
248 /**
249 * Tests the result of the REST API GET when there are no device keys.
250 */
251 @Test
252 public void testGetDeviceKeysEmptyArray() {
253 replay(mockDeviceKeyService);
254 replay(mockDeviceKeyAdminService);
255
256 WebResource rs = resource();
257 String response = rs.path("keys").get(String.class);
258 assertThat(response, is("{\"keys\":[]}"));
259 }
260
261 /**
262 * Tests the result of the REST API GET when device keys are defined.
263 */
264 @Test
265 public void testGetDeviceKeysArray() {
266 replay(mockDeviceKeyService);
267 replay(mockDeviceKeyAdminService);
268 deviceKeySet.add(deviceKey1);
269 deviceKeySet.add(deviceKey2);
270
271 WebResource rs = resource();
272 String response = rs.path("keys").get(String.class);
273 assertThat(response, containsString("{\"keys\":["));
274
275 final JsonObject result = Json.parse(response).asObject();
276 assertThat(result, notNullValue());
277
278 assertThat(result.names(), hasSize(1));
279 assertThat(result.names().get(0), is("keys"));
280
281 final JsonArray deviceKeys = result.get("keys").asArray();
282 assertThat(deviceKeys, notNullValue());
283 assertEquals("Device keys array is not the correct size.", 2, deviceKeys.size());
284
285 assertThat(deviceKeys, hasDeviceKey(deviceKey1));
286 assertThat(deviceKeys, hasDeviceKey(deviceKey2));
287 }
288
289 /**
290 * Tests the result of the REST API GET using a device key identifier.
291 */
292 @Test
293 public void testGetDeviceKeyById() {
294 deviceKeySet.add(deviceKey1);
295
296 expect(mockDeviceKeyService.getDeviceKey(DeviceKeyId.deviceKeyId(deviceKeyId1)))
297 .andReturn(deviceKey1)
298 .anyTimes();
299 replay(mockDeviceKeyService);
300 replay(mockDeviceKeyAdminService);
301
302 WebResource rs = resource();
303 String response = rs.path("keys/" + deviceKeyId1).get(String.class);
304 final JsonObject result = Json.parse(response).asObject();
305 assertThat(result, notNullValue());
306
307 assertThat(result, matchesDeviceKey(deviceKey1));
308 }
309
310 /**
311 * Tests that a GET of a non-existent object throws an exception.
312 */
313 @Test
314 public void testGetNonExistentDeviceKey() {
315
316 expect(mockDeviceKeyService.getDeviceKey(DeviceKeyId.deviceKeyId(deviceKeyId1)))
317 .andReturn(null)
318 .anyTimes();
319 replay(mockDeviceKeyService);
320 replay(mockDeviceKeyAdminService);
321
322 WebResource rs = resource();
323 try {
324 String response = rs.path("keys/" + deviceKeyId1).get(String.class);
325 fail("GET of a non-existent device key did not throw an exception");
326 } catch (UniformInterfaceException ex) {
327 assertThat(ex.getMessage(),
328 containsString("returned a response status of"));
329 }
330 }
331
332 /**
333 * Tests adding of new device key using POST via JSON stream.
334 */
335 @Test
336 public void testPost() {
337
338 mockDeviceKeyAdminService.addKey(anyObject());
339 expectLastCall();
340
341 replay(mockDeviceKeyService);
342 replay(mockDeviceKeyAdminService);
343
344 WebResource rs = resource();
345 InputStream jsonStream = DeviceKeyWebResourceTest.class
346 .getResourceAsStream("post-device-key.json");
347
348 ClientResponse response = rs.path("keys")
349 .type(MediaType.APPLICATION_JSON_TYPE)
350 .post(ClientResponse.class, jsonStream);
351 assertThat(response.getStatus(), is(HttpURLConnection.HTTP_CREATED));
352
353 String location = response.getLocation().getPath();
354 assertThat(location, Matchers.startsWith("/keys/" + deviceKeyId3));
355 }
356
357 /**
358 * Tests adding of a null device key using POST via JSON stream.
359 */
360 @Test
361 public void testPostNullDeviceKey() {
362
363 replay(mockDeviceKeyService);
364 replay(mockDeviceKeyAdminService);
365
366 WebResource rs = resource();
367 try {
368 String response = rs.path("keys")
369 .type(MediaType.APPLICATION_JSON_TYPE)
370 .post(String.class);
371 fail("POST of null device key did not throw an exception");
372 } catch (UniformInterfaceException ex) {
373 assertThat(ex.getMessage(),
374 containsString("returned a response status of"));
375 }
376 }
377
378 /**
379 * Tests removing a device key with DELETE request.
380 */
381 @Test
382 public void testDelete() {
383 expect(mockDeviceKeyService.getDeviceKey(DeviceKeyId.deviceKeyId(deviceKeyId2)))
384 .andReturn(deviceKey2)
385 .anyTimes();
386 mockDeviceKeyAdminService.removeKey(anyObject());
387 expectLastCall();
388
389 replay(mockDeviceKeyService);
390 replay(mockDeviceKeyAdminService);
391
392 WebResource rs = resource();
393
394 ClientResponse response = rs.path("keys/" + deviceKeyId2)
395 .type(MediaType.APPLICATION_JSON_TYPE)
396 .delete(ClientResponse.class);
397 assertThat(response.getStatus(), is(HttpURLConnection.HTTP_OK));
398 }
399
400 /**
401 * Tests that a DELETE of a non-existent device key throws an exception.
402 */
403 @Test
404 public void testDeleteNonExistentDeviceKey() {
405 expect(mockDeviceKeyService.getDeviceKey(anyObject()))
406 .andReturn(null)
407 .anyTimes();
408
409 expectLastCall();
410
411 replay(mockDeviceKeyService);
412 replay(mockDeviceKeyAdminService);
413
414 WebResource rs = resource();
415
416 try {
417 String response = rs.path("keys/" + "NON_EXISTENT_DEVICE_KEY")
418 .delete(String.class);
419 fail("Delete of a non-existent device key did not throw an exception");
420 } catch (UniformInterfaceException ex) {
421 assertThat(ex.getMessage(),
422 containsString("returned a response status of"));
423 }
424 }
425}