blob: 7ecaf38504ce230eb249d2e144aeeb24d74bc1c2 [file] [log] [blame]
Brian Stankeb9170d92016-02-19 14:18:42 -05001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2016-present Open Networking Foundation
Brian Stankeb9170d92016-02-19 14:18:42 -05003 *
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
Jian Li8ae91202016-03-24 14:36:16 -070017package org.onosproject.rest.resources;
Brian Stankeb9170d92016-02-19 14:18:42 -050018
19import com.eclipsesource.json.Json;
20import com.eclipsesource.json.JsonArray;
21import com.eclipsesource.json.JsonObject;
Brian Stankeb9170d92016-02-19 14:18:42 -050022import org.hamcrest.Description;
23import org.hamcrest.Matchers;
24import org.hamcrest.TypeSafeMatcher;
Brian Stankeb9170d92016-02-19 14:18:42 -050025import org.junit.Before;
26import org.junit.Test;
27import org.onlab.osgi.ServiceDirectory;
28import org.onlab.osgi.TestServiceDirectory;
Brian Stankeb9170d92016-02-19 14:18:42 -050029import org.onosproject.codec.CodecService;
30import org.onosproject.codec.impl.CodecManager;
31import org.onosproject.net.key.DeviceKey;
32import org.onosproject.net.key.DeviceKeyAdminService;
33import org.onosproject.net.key.DeviceKeyId;
34import org.onosproject.net.key.DeviceKeyService;
35
Jian Li9d616492016-03-09 10:52:49 -080036import javax.ws.rs.BadRequestException;
37import javax.ws.rs.NotFoundException;
38import javax.ws.rs.client.Entity;
39import javax.ws.rs.client.WebTarget;
Brian Stankeb9170d92016-02-19 14:18:42 -050040import javax.ws.rs.core.MediaType;
Jian Li9d616492016-03-09 10:52:49 -080041import javax.ws.rs.core.Response;
Brian Stankeb9170d92016-02-19 14:18:42 -050042import java.io.InputStream;
43import java.net.HttpURLConnection;
44import java.util.HashSet;
45
Jian Li9d616492016-03-09 10:52:49 -080046import static org.easymock.EasyMock.anyObject;
47import static org.easymock.EasyMock.createMock;
48import static org.easymock.EasyMock.expect;
49import static org.easymock.EasyMock.expectLastCall;
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.assertEquals;
57import static org.junit.Assert.assertThat;
58import static org.junit.Assert.fail;
Brian Stankeb9170d92016-02-19 14:18:42 -050059
60/**
61 * Unit tests for device key REST APIs.
62 */
63public class DeviceKeyWebResourceTest extends ResourceTest {
64
65 final DeviceKeyService mockDeviceKeyService = createMock(DeviceKeyService.class);
66 final DeviceKeyAdminService mockDeviceKeyAdminService = createMock(DeviceKeyAdminService.class);
67
68 final HashSet<DeviceKey> deviceKeySet = new HashSet<>();
69
70 private static final String ID = "id";
71 private static final String TYPE = "type";
72 private static final String LABEL = "label";
73 private static final String COMMUNITY_NAME = "community_name";
74 private static final String USERNAME = "username";
75 private static final String PASSWORD = "password";
76
77 private final String deviceKeyId1 = "DeviceKeyId1";
78 private final String deviceKeyId2 = "DeviceKeyId2";
79 private final String deviceKeyId3 = "DeviceKeyId3";
Brian Stankeb8ff6412016-02-25 14:16:19 -050080 private final String deviceKeyId4 = "DeviceKeyId4";
Brian Stankeb9170d92016-02-19 14:18:42 -050081 private final String deviceKeyLabel = "DeviceKeyLabel";
82 private final String deviceKeyCommunityName = "DeviceKeyCommunityName";
83 private final String deviceKeyUsername = "DeviceKeyUsername";
84 private final String deviceKeyPassword = "DeviceKeyPassword";
85
86 private final DeviceKey deviceKey1 = DeviceKey.createDeviceKeyUsingCommunityName(
87 DeviceKeyId.deviceKeyId(deviceKeyId1), deviceKeyLabel, deviceKeyCommunityName);
88 private final DeviceKey deviceKey2 = DeviceKey.createDeviceKeyUsingUsernamePassword(
Brian Stankeb8ff6412016-02-25 14:16:19 -050089 DeviceKeyId.deviceKeyId(deviceKeyId2), null, deviceKeyUsername, deviceKeyPassword);
90 private final DeviceKey deviceKey3 = DeviceKey.createDeviceKeyUsingUsernamePassword(
91 DeviceKeyId.deviceKeyId(deviceKeyId3), null, null, null);
92 private final DeviceKey deviceKey4 = DeviceKey.createDeviceKeyUsingCommunityName(
93 DeviceKeyId.deviceKeyId(deviceKeyId4), null, null);
Brian Stankeb9170d92016-02-19 14:18:42 -050094
95 /**
96 * Initializes test mocks and environment.
97 */
98 @Before
99 public void setUpMocks() {
100 expect(mockDeviceKeyService.getDeviceKeys()).andReturn(deviceKeySet).anyTimes();
101
102 // Register the services needed for the test
103 CodecManager codecService = new CodecManager();
104 codecService.activate();
105 ServiceDirectory testDirectory =
106 new TestServiceDirectory()
107 .add(DeviceKeyService.class, mockDeviceKeyService)
108 .add(DeviceKeyAdminService.class, mockDeviceKeyAdminService)
109 .add(CodecService.class, codecService);
110
Ray Milkey094a1352018-01-22 14:03:54 -0800111 setServiceDirectory(testDirectory);
Brian Stankeb9170d92016-02-19 14:18:42 -0500112 }
113
114 /**
Brian Stankeb9170d92016-02-19 14:18:42 -0500115 * Hamcrest matcher to check that a device key representation in JSON matches
116 * the actual device key.
117 */
118 public static class DeviceKeyJsonMatcher extends TypeSafeMatcher<JsonObject> {
119 private final DeviceKey deviceKey;
120 private String reason = "";
121
122 public DeviceKeyJsonMatcher(DeviceKey deviceKeyValue) {
123 deviceKey = deviceKeyValue;
124 }
125
126 @Override
127 public boolean matchesSafely(JsonObject jsonHost) {
128 // Check the device key id
129 final String jsonId = jsonHost.get(ID).asString();
130 if (!jsonId.equals(deviceKey.deviceKeyId().id().toString())) {
131 reason = ID + " " + deviceKey.deviceKeyId().id().toString();
132 return false;
133 }
134
135 // Check the device key label
Brian Stankeb8ff6412016-02-25 14:16:19 -0500136 final String jsonLabel = (jsonHost.get(LABEL).isNull()) ? null : jsonHost.get(LABEL).asString();
137 if (deviceKey.label() != null) {
138 if ((jsonLabel == null) || !jsonLabel.equals(deviceKey.label())) {
139 reason = LABEL + " " + deviceKey.label();
140 return false;
141 }
Brian Stankeb9170d92016-02-19 14:18:42 -0500142 }
143
144 // Check the device key type
145 final String jsonType = jsonHost.get(TYPE).asString();
146 if (!jsonType.equals(deviceKey.type().toString())) {
147 reason = TYPE + " " + deviceKey.type().toString();
148 return false;
149 }
150
151 if (jsonType.equals(DeviceKey.Type.COMMUNITY_NAME.toString())) {
152 // Check the device key community name
Brian Stankeb8ff6412016-02-25 14:16:19 -0500153 final String jsonCommunityName = jsonHost.get(COMMUNITY_NAME).isNull() ?
154 null : jsonHost.get(COMMUNITY_NAME).asString();
155 if (deviceKey.asCommunityName().name() != null) {
156 if (!jsonCommunityName.equals(deviceKey.asCommunityName().name().toString())) {
157 reason = COMMUNITY_NAME + " " + deviceKey.asCommunityName().name().toString();
158 return false;
159 }
Brian Stankeb9170d92016-02-19 14:18:42 -0500160 }
161 } else if (jsonType.equals(DeviceKey.Type.USERNAME_PASSWORD.toString())) {
162 // Check the device key username
Brian Stankeb8ff6412016-02-25 14:16:19 -0500163 final String jsonUsername = jsonHost.get(USERNAME).isNull() ?
164 null : jsonHost.get(USERNAME).asString();
165 if (deviceKey.asUsernamePassword().username() != null) {
166 if (!jsonUsername.equals(deviceKey.asUsernamePassword().username().toString())) {
167 reason = USERNAME + " " + deviceKey.asUsernamePassword().username().toString();
168 return false;
169 }
Brian Stankeb9170d92016-02-19 14:18:42 -0500170 }
171
172 // Check the device key password
Brian Stankeb8ff6412016-02-25 14:16:19 -0500173 final String jsonPassword = jsonHost.get(PASSWORD).isNull() ?
174 null : jsonHost.get(PASSWORD).asString();
175 if (deviceKey.asUsernamePassword().password() != null) {
176 if (!jsonPassword.equals(deviceKey.asUsernamePassword().password().toString())) {
177 reason = PASSWORD + " " + deviceKey.asUsernamePassword().password().toString();
178 return false;
179 }
Brian Stankeb9170d92016-02-19 14:18:42 -0500180 }
181 } else {
182 reason = "Unknown " + TYPE + " " + deviceKey.type().toString();
183 return false;
184 }
185
186 return true;
187 }
188
189 @Override
190 public void describeTo(Description description) {
191 description.appendText(reason);
192 }
193 }
194
195 /**
196 * Factory to allocate a device key array matcher.
197 *
198 * @param deviceKey device key object we are looking for
199 * @return matcher
200 */
201 private static DeviceKeyJsonMatcher matchesDeviceKey(DeviceKey deviceKey) {
202 return new DeviceKeyJsonMatcher(deviceKey);
203 }
204
205 /**
206 * Hamcrest matcher to check that a device key is represented properly in a JSON
207 * array of device keys.
208 */
209 public static class DeviceKeyJsonArrayMatcher extends TypeSafeMatcher<JsonArray> {
210 private final DeviceKey deviceKey;
211 private String reason = "";
212
213 public DeviceKeyJsonArrayMatcher(DeviceKey deviceKeyValue) {
214 deviceKey = deviceKeyValue;
215 }
216
217 @Override
218 public boolean matchesSafely(JsonArray json) {
219 boolean deviceKeyFound = false;
220 final int expectedAttributes = 5;
221 for (int jsonDeviceKeyIndex = 0; jsonDeviceKeyIndex < json.size();
222 jsonDeviceKeyIndex++) {
223
224 final JsonObject jsonHost = json.get(jsonDeviceKeyIndex).asObject();
225
226 // Device keys can have a variable number of attribute so we check
227 // that there is a minimum number.
228 if (jsonHost.names().size() < expectedAttributes) {
229 reason = "Found a device key with the wrong number of attributes";
230 return false;
231 }
232
233 final String jsonDeviceKeyId = jsonHost.get(ID).asString();
234 if (jsonDeviceKeyId.equals(deviceKey.deviceKeyId().id().toString())) {
235 deviceKeyFound = true;
236
237 // We found the correct device key, check the device key attribute values
238 assertThat(jsonHost, matchesDeviceKey(deviceKey));
239 }
240 }
241 if (!deviceKeyFound) {
242 reason = "Device key with id " + deviceKey.deviceKeyId().id().toString() + " was not found";
243 return false;
244 } else {
245 return true;
246 }
247 }
248
249 @Override
250 public void describeTo(Description description) {
251 description.appendText(reason);
252 }
253 }
254
255 /**
256 * Factory to allocate a device key array matcher.
257 *
258 * @param deviceKey device key object we are looking for
259 * @return matcher
260 */
261 private static DeviceKeyJsonArrayMatcher hasDeviceKey(DeviceKey deviceKey) {
262 return new DeviceKeyJsonArrayMatcher(deviceKey);
263 }
264
265 /**
266 * Tests the result of the REST API GET when there are no device keys.
267 */
268 @Test
269 public void testGetDeviceKeysEmptyArray() {
270 replay(mockDeviceKeyService);
Brian Stankeb9170d92016-02-19 14:18:42 -0500271
Jian Li9d616492016-03-09 10:52:49 -0800272 WebTarget wt = target();
273 String response = wt.path("keys").request().get(String.class);
Brian Stankeb9170d92016-02-19 14:18:42 -0500274 assertThat(response, is("{\"keys\":[]}"));
Brian Stankeb8ff6412016-02-25 14:16:19 -0500275
276 verify(mockDeviceKeyService);
Brian Stankeb9170d92016-02-19 14:18:42 -0500277 }
278
279 /**
280 * Tests the result of the REST API GET when device keys are defined.
281 */
282 @Test
283 public void testGetDeviceKeysArray() {
284 replay(mockDeviceKeyService);
Brian Stankeb9170d92016-02-19 14:18:42 -0500285 deviceKeySet.add(deviceKey1);
286 deviceKeySet.add(deviceKey2);
Brian Stankeb8ff6412016-02-25 14:16:19 -0500287 deviceKeySet.add(deviceKey3);
288 deviceKeySet.add(deviceKey4);
Brian Stankeb9170d92016-02-19 14:18:42 -0500289
Jian Li9d616492016-03-09 10:52:49 -0800290 WebTarget wt = target();
291 String response = wt.path("keys").request().get(String.class);
Brian Stankeb9170d92016-02-19 14:18:42 -0500292 assertThat(response, containsString("{\"keys\":["));
293
294 final JsonObject result = Json.parse(response).asObject();
295 assertThat(result, notNullValue());
296
297 assertThat(result.names(), hasSize(1));
298 assertThat(result.names().get(0), is("keys"));
299
300 final JsonArray deviceKeys = result.get("keys").asArray();
301 assertThat(deviceKeys, notNullValue());
Brian Stankeb8ff6412016-02-25 14:16:19 -0500302 assertEquals("Device keys array is not the correct size.", 4, deviceKeys.size());
Brian Stankeb9170d92016-02-19 14:18:42 -0500303
304 assertThat(deviceKeys, hasDeviceKey(deviceKey1));
305 assertThat(deviceKeys, hasDeviceKey(deviceKey2));
Brian Stankeb8ff6412016-02-25 14:16:19 -0500306 assertThat(deviceKeys, hasDeviceKey(deviceKey3));
307 assertThat(deviceKeys, hasDeviceKey(deviceKey4));
308
309 verify(mockDeviceKeyService);
Brian Stankeb9170d92016-02-19 14:18:42 -0500310 }
311
312 /**
313 * Tests the result of the REST API GET using a device key identifier.
314 */
315 @Test
316 public void testGetDeviceKeyById() {
317 deviceKeySet.add(deviceKey1);
318
319 expect(mockDeviceKeyService.getDeviceKey(DeviceKeyId.deviceKeyId(deviceKeyId1)))
320 .andReturn(deviceKey1)
321 .anyTimes();
322 replay(mockDeviceKeyService);
Brian Stankeb9170d92016-02-19 14:18:42 -0500323
Jian Li9d616492016-03-09 10:52:49 -0800324 WebTarget wt = target();
325 String response = wt.path("keys/" + deviceKeyId1).request().get(String.class);
Brian Stankeb9170d92016-02-19 14:18:42 -0500326 final JsonObject result = Json.parse(response).asObject();
327 assertThat(result, notNullValue());
328
329 assertThat(result, matchesDeviceKey(deviceKey1));
Brian Stankeb8ff6412016-02-25 14:16:19 -0500330
331 verify(mockDeviceKeyService);
Brian Stankeb9170d92016-02-19 14:18:42 -0500332 }
333
334 /**
335 * Tests that a GET of a non-existent object throws an exception.
336 */
337 @Test
338 public void testGetNonExistentDeviceKey() {
339
340 expect(mockDeviceKeyService.getDeviceKey(DeviceKeyId.deviceKeyId(deviceKeyId1)))
341 .andReturn(null)
342 .anyTimes();
343 replay(mockDeviceKeyService);
Brian Stankeb9170d92016-02-19 14:18:42 -0500344
Jian Li9d616492016-03-09 10:52:49 -0800345 WebTarget wt = target();
Brian Stankeb9170d92016-02-19 14:18:42 -0500346 try {
Jian Li9d616492016-03-09 10:52:49 -0800347 wt.path("keys/" + deviceKeyId1).request().get(String.class);
Brian Stankeb9170d92016-02-19 14:18:42 -0500348 fail("GET of a non-existent device key did not throw an exception");
Jian Li9d616492016-03-09 10:52:49 -0800349 } catch (NotFoundException ex) {
350 assertThat(ex.getMessage(), containsString("HTTP 404 Not Found"));
Brian Stankeb9170d92016-02-19 14:18:42 -0500351 }
Brian Stankeb8ff6412016-02-25 14:16:19 -0500352
353 verify(mockDeviceKeyService);
Brian Stankeb9170d92016-02-19 14:18:42 -0500354 }
355
356 /**
357 * Tests adding of new device key using POST via JSON stream.
358 */
359 @Test
360 public void testPost() {
361
362 mockDeviceKeyAdminService.addKey(anyObject());
363 expectLastCall();
364
Brian Stankeb9170d92016-02-19 14:18:42 -0500365 replay(mockDeviceKeyAdminService);
366
Jian Li9d616492016-03-09 10:52:49 -0800367 WebTarget wt = target();
Brian Stankeb9170d92016-02-19 14:18:42 -0500368 InputStream jsonStream = DeviceKeyWebResourceTest.class
369 .getResourceAsStream("post-device-key.json");
370
Jian Li9d616492016-03-09 10:52:49 -0800371 Response response = wt.path("keys").request(MediaType.APPLICATION_JSON_TYPE)
372 .post(Entity.json(jsonStream));
Brian Stankeb9170d92016-02-19 14:18:42 -0500373 assertThat(response.getStatus(), is(HttpURLConnection.HTTP_CREATED));
374
375 String location = response.getLocation().getPath();
376 assertThat(location, Matchers.startsWith("/keys/" + deviceKeyId3));
Brian Stankeb8ff6412016-02-25 14:16:19 -0500377
378 verify(mockDeviceKeyAdminService);
Brian Stankeb9170d92016-02-19 14:18:42 -0500379 }
380
381 /**
382 * Tests adding of a null device key using POST via JSON stream.
383 */
384 @Test
385 public void testPostNullDeviceKey() {
386
Brian Stankeb9170d92016-02-19 14:18:42 -0500387 replay(mockDeviceKeyAdminService);
388
Jian Li9d616492016-03-09 10:52:49 -0800389 WebTarget wt = target();
Brian Stankeb9170d92016-02-19 14:18:42 -0500390 try {
Jian Li9d616492016-03-09 10:52:49 -0800391 wt.path("keys").request(MediaType.APPLICATION_JSON_TYPE)
392 .post(Entity.json(null), String.class);
Brian Stankeb9170d92016-02-19 14:18:42 -0500393 fail("POST of null device key did not throw an exception");
Jian Li9d616492016-03-09 10:52:49 -0800394 } catch (BadRequestException ex) {
395 assertThat(ex.getMessage(), containsString("HTTP 400 Bad Request"));
Brian Stankeb9170d92016-02-19 14:18:42 -0500396 }
Brian Stankeb8ff6412016-02-25 14:16:19 -0500397
398 verify(mockDeviceKeyAdminService);
Brian Stankeb9170d92016-02-19 14:18:42 -0500399 }
400
401 /**
402 * Tests removing a device key with DELETE request.
403 */
404 @Test
405 public void testDelete() {
406 expect(mockDeviceKeyService.getDeviceKey(DeviceKeyId.deviceKeyId(deviceKeyId2)))
407 .andReturn(deviceKey2)
408 .anyTimes();
409 mockDeviceKeyAdminService.removeKey(anyObject());
410 expectLastCall();
411
412 replay(mockDeviceKeyService);
413 replay(mockDeviceKeyAdminService);
414
Jian Li9d616492016-03-09 10:52:49 -0800415 WebTarget wt = target();
Brian Stankeb9170d92016-02-19 14:18:42 -0500416
Jian Li9d616492016-03-09 10:52:49 -0800417 Response response = wt.path("keys/" + deviceKeyId2)
418 .request(MediaType.APPLICATION_JSON_TYPE)
419 .delete();
Brian Stankeb9170d92016-02-19 14:18:42 -0500420 assertThat(response.getStatus(), is(HttpURLConnection.HTTP_OK));
Brian Stankeb8ff6412016-02-25 14:16:19 -0500421
422 verify(mockDeviceKeyService);
423 verify(mockDeviceKeyAdminService);
Brian Stankeb9170d92016-02-19 14:18:42 -0500424 }
425
426 /**
427 * Tests that a DELETE of a non-existent device key throws an exception.
428 */
429 @Test
430 public void testDeleteNonExistentDeviceKey() {
431 expect(mockDeviceKeyService.getDeviceKey(anyObject()))
432 .andReturn(null)
433 .anyTimes();
434
435 expectLastCall();
436
437 replay(mockDeviceKeyService);
438 replay(mockDeviceKeyAdminService);
439
Jian Li9d616492016-03-09 10:52:49 -0800440 WebTarget wt = target();
Brian Stankeb9170d92016-02-19 14:18:42 -0500441
442 try {
Jian Li9d616492016-03-09 10:52:49 -0800443 wt.path("keys/" + "NON_EXISTENT_DEVICE_KEY").request()
Brian Stankeb9170d92016-02-19 14:18:42 -0500444 .delete(String.class);
445 fail("Delete of a non-existent device key did not throw an exception");
Jian Li9d616492016-03-09 10:52:49 -0800446 } catch (NotFoundException ex) {
447 assertThat(ex.getMessage(), containsString("HTTP 404 Not Found"));
Brian Stankeb9170d92016-02-19 14:18:42 -0500448 }
Brian Stankeb8ff6412016-02-25 14:16:19 -0500449
450 verify(mockDeviceKeyService);
451 verify(mockDeviceKeyAdminService);
Brian Stankeb9170d92016-02-19 14:18:42 -0500452 }
453}