blob: 620251d3fc383e7befb741fcf5dd20de2d514e52 [file] [log] [blame]
Jian Li0c451802016-02-24 22:39:25 +09001/*
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 */
16package org.onosproject.rest;
17
18import com.eclipsesource.json.Json;
19import com.eclipsesource.json.JsonArray;
20import com.eclipsesource.json.JsonObject;
21import com.google.common.collect.ImmutableList;
22import com.google.common.collect.ImmutableSet;
23import com.google.common.collect.Sets;
24import com.sun.jersey.api.client.ClientResponse;
25import com.sun.jersey.api.client.WebResource;
26import org.hamcrest.Description;
27import org.hamcrest.TypeSafeMatcher;
28import org.junit.Before;
29import org.junit.Test;
30import org.onlab.osgi.ServiceDirectory;
31import org.onlab.osgi.TestServiceDirectory;
32import org.onlab.rest.BaseResource;
33import org.onosproject.cluster.NodeId;
34import org.onosproject.codec.CodecService;
35import org.onosproject.codec.impl.CodecManager;
36import org.onosproject.net.DeviceId;
37import org.onosproject.net.region.Region;
38import org.onosproject.net.region.RegionAdminService;
39import org.onosproject.net.region.RegionId;
40import org.onosproject.net.region.RegionService;
41import org.onosproject.rest.resources.CoreWebApplication;
42
43import javax.ws.rs.core.MediaType;
44import java.io.InputStream;
45import java.net.HttpURLConnection;
46import java.util.List;
47import java.util.Set;
48
49import static org.easymock.EasyMock.anyObject;
50import static org.easymock.EasyMock.createMock;
51import static org.easymock.EasyMock.expect;
52import static org.easymock.EasyMock.expectLastCall;
53import static org.easymock.EasyMock.replay;
54import static org.easymock.EasyMock.verify;
55import static org.hamcrest.Matchers.hasSize;
56import static org.hamcrest.Matchers.is;
57import static org.hamcrest.Matchers.notNullValue;
58import static org.junit.Assert.assertThat;
59
60/**
61 * Unit tests for region REST APIs.
62 */
63public class RegionsResourceTest extends ResourceTest {
64
65 final RegionService mockRegionService = createMock(RegionService.class);
66 final RegionAdminService mockRegionAdminService = createMock(RegionAdminService.class);
67
68 final RegionId regionId1 = RegionId.regionId("1");
69 final RegionId regionId2 = RegionId.regionId("2");
70 final RegionId regionId3 = RegionId.regionId("3");
71
72 final MockRegion region1 = new MockRegion(regionId1, "r1", Region.Type.RACK);
73 final MockRegion region2 = new MockRegion(regionId2, "r2", Region.Type.ROOM);
74 final MockRegion region3 = new MockRegion(regionId3, "r3", Region.Type.CAMPUS);
75
76 public RegionsResourceTest() {
77 super(CoreWebApplication.class);
78 }
79
80 /**
81 * Mock class for a region.
82 */
83 private static class MockRegion implements Region {
84
85 private final RegionId id;
86 private final String name;
87 private final Type type;
88 private final List<Set<NodeId>> masters;
89
90 public MockRegion(RegionId id, String name, Type type) {
91 this.id = id;
92 this.name = name;
93 this.type = type;
94
95 final NodeId nodeId1 = NodeId.nodeId("1");
96 final NodeId nodeId2 = NodeId.nodeId("2");
97 final NodeId nodeId3 = NodeId.nodeId("3");
98 final NodeId nodeId4 = NodeId.nodeId("4");
99
100 Set<NodeId> nodeIds1 = ImmutableSet.of(nodeId1);
101 Set<NodeId> nodeIds2 = ImmutableSet.of(nodeId1, nodeId2);
102 Set<NodeId> nodeIds3 = ImmutableSet.of(nodeId1, nodeId2, nodeId3);
103 Set<NodeId> nodeIds4 = ImmutableSet.of(nodeId1, nodeId2, nodeId3, nodeId4);
104
105 this.masters = ImmutableList.of(nodeIds1, nodeIds2, nodeIds3, nodeIds4);
106 }
107
108 @Override
109 public RegionId id() {
110 return this.id;
111 }
112
113 @Override
114 public String name() {
115 return this.name;
116 }
117
118 @Override
119 public Type type() {
120 return this.type;
121 }
122
123 @Override
124 public List<Set<NodeId>> masters() {
125 return this.masters;
126 }
127 }
128
129 /**
130 * Sets up the global values for all the tests.
131 */
132 @Before
133 public void setupTest() {
134 final CodecManager codecService = new CodecManager();
135 codecService.activate();
136 ServiceDirectory testDirectory =
137 new TestServiceDirectory()
138 .add(RegionService.class, mockRegionService)
139 .add(RegionAdminService.class, mockRegionAdminService)
140 .add(CodecService.class, codecService);
141 BaseResource.setServiceDirectory(testDirectory);
142 }
143
144 /**
145 * Hamcrest matcher to check that a meter representation in JSON matches
146 * the actual meter.
147 */
148 public static class RegionJsonMatcher extends TypeSafeMatcher<JsonObject> {
149 private final Region region;
150 private String reason = "";
151
152 public RegionJsonMatcher(Region regionValue) {
153 this.region = regionValue;
154 }
155
156 @Override
157 protected boolean matchesSafely(JsonObject jsonRegion) {
158
159 // check id
160 String jsonRegionId = jsonRegion.get("id").asString();
161 String regionId = region.id().toString();
162 if (!jsonRegionId.equals(regionId)) {
163 reason = "region id was " + jsonRegionId;
164 return false;
165 }
166
167 // check type
168 String jsonType = jsonRegion.get("type").asString();
169 String type = region.type().toString();
170 if (!jsonType.equals(type)) {
171 reason = "type was " + jsonType;
172 return false;
173 }
174
175 // check name
176 String jsonName = jsonRegion.get("name").asString();
177 String name = region.name();
178 if (!jsonName.equals(name)) {
179 reason = "name was " + jsonName;
180 return false;
181 }
182
183 // check size of master array
184 JsonArray jsonMasters = jsonRegion.get("masters").asArray();
185 if (jsonMasters.size() != region.masters().size()) {
186 reason = "masters size was " + jsonMasters.size();
187 return false;
188 }
189
190 // check master
191 for (Set<NodeId> set : region.masters()) {
192 boolean masterFound = false;
193 for (int masterIndex = 0; masterIndex < jsonMasters.size(); masterIndex++) {
194 masterFound = checkEquality(jsonMasters.get(masterIndex).asArray(), set);
195 }
196
197 if (!masterFound) {
198 reason = "master not found " + set.toString();
199 return false;
200 }
201 }
202
203 return true;
204 }
205
206 @Override
207 public void describeTo(Description description) {
208 description.appendText(reason);
209 }
210
211 private Set<NodeId> jsonToSet(JsonArray nodes) {
212 final Set<NodeId> nodeIds = Sets.newHashSet();
213 nodes.forEach(node -> nodeIds.add(NodeId.nodeId(node.asString())));
214 return nodeIds;
215 }
216
217 private boolean checkEquality(JsonArray nodes, Set<NodeId> nodeIds) {
218 Set<NodeId> jsonSet = jsonToSet(nodes);
219 if (jsonSet.size() == nodes.size()) {
220 return jsonSet.containsAll(nodeIds);
221 }
222 return false;
223 }
224 }
225
226 private static RegionJsonMatcher matchesRegion(Region region) {
227 return new RegionJsonMatcher(region);
228 }
229
230 /**
231 * Hamcrest matcher to check that a region is represented properly in a JSON
232 * array of regions.
233 */
234 public static class RegionJsonArrayMatcher extends TypeSafeMatcher<JsonArray> {
235 private final Region region;
236 private String reason = "";
237
238 public RegionJsonArrayMatcher(Region regionValue) {
239 this.region = regionValue;
240 }
241
242 @Override
243 protected boolean matchesSafely(JsonArray json) {
244 boolean regionFound = false;
245 for (int jsonRegionIndex = 0; jsonRegionIndex < json.size(); jsonRegionIndex++) {
246 final JsonObject jsonRegion = json.get(jsonRegionIndex).asObject();
247
248 final String regionId = region.id().toString();
249 final String jsonRegionId = jsonRegion.get("id").asString();
250 if (jsonRegionId.equals(regionId)) {
251 regionFound = true;
252 assertThat(jsonRegion, matchesRegion(region));
253 }
254 }
255
256 if (!regionFound) {
257 reason = "Region with id " + region.id().toString() + " not found";
258 return false;
259 } else {
260 return true;
261 }
262 }
263
264 @Override
265 public void describeTo(Description description) {
266 description.appendText(reason);
267 }
268 }
269
270 /**
271 * Factory to allocate a region array matcher.
272 *
273 * @param region region object we are looking for
274 * @return matcher
275 */
276 private static RegionJsonArrayMatcher hasRegion(Region region) {
277 return new RegionJsonArrayMatcher(region);
278 }
279
280 @Test
281 public void testRegionEmptyArray() {
282 expect(mockRegionService.getRegions()).andReturn(ImmutableSet.of()).anyTimes();
283 replay((mockRegionService));
284 final WebResource rs = resource();
285 final String response = rs.path("regions").get(String.class);
286 assertThat(response, is("{\"regions\":[]}"));
287
288 verify(mockRegionService);
289 }
290
291 /**
292 * Tests the results of the REST API GET when there are active regions.
293 */
294 @Test
295 public void testRegionsPopulatedArray() {
296 final Set<Region> regions = ImmutableSet.of(region1, region2, region3);
297 expect(mockRegionService.getRegions()).andReturn(regions).anyTimes();
298 replay(mockRegionService);
299
300 final WebResource rs = resource();
301 final String response = rs.path("regions").get(String.class);
302 final JsonObject result = Json.parse(response).asObject();
303 assertThat(result, notNullValue());
304
305 assertThat(result.names(), hasSize(1));
306 assertThat(result.names().get(0), is("regions"));
307 final JsonArray jsonRegions = result.get("regions").asArray();
308 assertThat(jsonRegions, notNullValue());
309 assertThat(jsonRegions, hasRegion(region1));
310 assertThat(jsonRegions, hasRegion(region2));
311 assertThat(jsonRegions, hasRegion(region3));
312
313 verify(mockRegionService);
314
315 }
316
317 /**
318 * Tests the result of a REST API GET for a region with region id.
319 */
320 @Test
321 public void testGetRegionById() {
322 expect(mockRegionService.getRegion(anyObject())).andReturn(region1).anyTimes();
323 replay(mockRegionService);
324
325 final WebResource rs = resource();
326 final String response = rs.path("regions/" + regionId1.toString()).get(String.class);
327 final JsonObject result = Json.parse(response).asObject();
328 assertThat(result, notNullValue());
329 assertThat(result, matchesRegion(region1));
330
331 verify(mockRegionService);
332 }
333
334 /**
335 * Tests creating a region with POST.
336 */
337 @Test
338 public void testRegionPost() {
339 mockRegionAdminService.createRegion(anyObject(), anyObject(),
340 anyObject(), anyObject());
341 expectLastCall().andReturn(region2).anyTimes();
342 replay(mockRegionAdminService);
343
344 WebResource rs = resource();
345 InputStream jsonStream = MetersResourceTest.class
346 .getResourceAsStream("post-region.json");
347
348 ClientResponse response = rs.path("regions")
349 .type(MediaType.APPLICATION_JSON_TYPE)
350 .post(ClientResponse.class, jsonStream);
351 assertThat(response.getStatus(), is(HttpURLConnection.HTTP_CREATED));
352
353 verify(mockRegionAdminService);
354 }
355
356 /**
357 * Tests updating a region with PUT.
358 */
359 @Test
360 public void testRegionPut() {
361 mockRegionAdminService.updateRegion(anyObject(), anyObject(),
362 anyObject(), anyObject());
363 expectLastCall().andReturn(region1).anyTimes();
364 replay(mockRegionAdminService);
365
366 WebResource rs = resource();
367 InputStream jsonStream = MetersResourceTest.class
368 .getResourceAsStream("post-region.json");
369
370 ClientResponse response = rs.path("regions/" + region1.id().toString())
371 .type(MediaType.APPLICATION_JSON_TYPE)
372 .put(ClientResponse.class, jsonStream);
373 assertThat(response.getStatus(), is(HttpURLConnection.HTTP_OK));
374
375 verify(mockRegionAdminService);
376 }
377
378 /**
379 * Tests deleting a region with DELETE.
380 */
381 @Test
382 public void testRegionDelete() {
383 mockRegionAdminService.removeRegion(anyObject());
384 expectLastCall();
385 replay(mockRegionAdminService);
386
387 WebResource rs = resource();
388 ClientResponse response = rs.path("regions/" + region1.id().toString())
389 .delete(ClientResponse.class);
390 assertThat(response.getStatus(), is(HttpURLConnection.HTTP_OK));
391
392 verify(mockRegionAdminService);
393 }
394
395 /**
396 * Tests retrieving device ids that are associated with the given region.
397 */
398 @Test
399 public void testGetRegionDevices() {
400 final DeviceId deviceId1 = DeviceId.deviceId("1");
401 final DeviceId deviceId2 = DeviceId.deviceId("2");
402 final DeviceId deviceId3 = DeviceId.deviceId("3");
403
404 final Set<DeviceId> deviceIds = ImmutableSet.of(deviceId1, deviceId2, deviceId3);
405
406 expect(mockRegionService.getRegionDevices(anyObject()))
407 .andReturn(deviceIds).anyTimes();
408 replay(mockRegionService);
409
410 final WebResource rs = resource();
411 final String response = rs.path("regions/" +
412 region1.id().toString() + "/devices").get(String.class);
413 final JsonObject result = Json.parse(response).asObject();
414 assertThat(result, notNullValue());
415
416 assertThat(result.names(), hasSize(1));
417 assertThat(result.names().get(0), is("deviceIds"));
418 final JsonArray jsonDeviceIds = result.get("deviceIds").asArray();
419 assertThat(jsonDeviceIds.size(), is(3));
420 assertThat(jsonDeviceIds.get(0).asString(), is("1"));
421 assertThat(jsonDeviceIds.get(1).asString(), is("2"));
422 assertThat(jsonDeviceIds.get(2).asString(), is("3"));
423
424 verify(mockRegionService);
425 }
426
427 /**
428 * Tests adding a set of devices in region with POST.
429 */
430 @Test
431 public void testAddDevicesPost() {
432 mockRegionAdminService.addDevices(anyObject(), anyObject());
433 expectLastCall();
434 replay(mockRegionAdminService);
435
436 WebResource rs = resource();
437 InputStream jsonStream = MetersResourceTest.class
438 .getResourceAsStream("region-deviceIds.json");
439
440 ClientResponse response = rs.path("regions/" +
441 region1.id().toString() + "/devices")
442 .type(MediaType.APPLICATION_JSON_TYPE)
443 .post(ClientResponse.class, jsonStream);
444 assertThat(response.getStatus(), is(HttpURLConnection.HTTP_CREATED));
445
446 verify(mockRegionAdminService);
447 }
448
449 /**
450 * Tests deleting a set of devices contained in the given region with DELETE.
451 */
452 @Test
453 public void testRemoveDevicesDelete() {
454 mockRegionAdminService.removeDevices(anyObject(), anyObject());
455 expectLastCall();
456 replay(mockRegionAdminService);
457
458 WebResource rs = resource();
459 InputStream jsonStream = MetersResourceTest.class
460 .getResourceAsStream("region-deviceIds.json");
461
462 ClientResponse response = rs.path("regions/" +
463 region1.id().toString() + "/devices")
464 .type(MediaType.APPLICATION_JSON_TYPE)
465 .delete(ClientResponse.class, jsonStream);
466 assertThat(response.getStatus(), is(HttpURLConnection.HTTP_OK));
467
468 verify(mockRegionAdminService);
469 }
470}