blob: cb39b21be89762b8a1461eeb0bb0e584e3da4d34 [file] [log] [blame]
Jian Li5c411232015-12-16 15:29:16 -08001/*
2 * Copyright 2014-2015 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
Jian Li80cfe452016-01-14 16:04:58 -080019import com.eclipsesource.json.Json;
Jian Li5c411232015-12-16 15:29:16 -080020import com.eclipsesource.json.JsonArray;
21import com.eclipsesource.json.JsonObject;
22import com.google.common.collect.ImmutableSet;
23import com.sun.jersey.api.client.ClientResponse;
24import com.sun.jersey.api.client.WebResource;
25import org.hamcrest.Description;
26import org.hamcrest.TypeSafeMatcher;
27import org.junit.After;
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.codec.CodecService;
34import org.onosproject.codec.impl.CodecManager;
35import org.onosproject.codec.impl.MeterCodec;
36import org.onosproject.core.ApplicationId;
37import org.onosproject.core.CoreService;
38import org.onosproject.core.DefaultApplicationId;
39import org.onosproject.net.DefaultDevice;
40import org.onosproject.net.Device;
41import org.onosproject.net.DeviceId;
42import org.onosproject.net.NetTestTools;
43import org.onosproject.net.device.DeviceService;
44import org.onosproject.net.meter.Band;
45import org.onosproject.net.meter.DefaultBand;
46import org.onosproject.net.meter.Meter;
47import org.onosproject.net.meter.MeterId;
48import org.onosproject.net.meter.MeterService;
49import org.onosproject.net.meter.MeterState;
Jian Li5e5734f2016-01-06 00:33:43 -080050import org.onosproject.rest.resources.CoreWebApplication;
Jian Li5c411232015-12-16 15:29:16 -080051
52import javax.ws.rs.core.MediaType;
53import java.io.InputStream;
54import java.net.HttpURLConnection;
55import java.util.ArrayList;
56import java.util.Collection;
57import java.util.HashMap;
58import java.util.HashSet;
59import java.util.List;
60import java.util.Set;
61
62import static org.easymock.EasyMock.anyObject;
63import static org.easymock.EasyMock.anyShort;
64import static org.easymock.EasyMock.createMock;
65import static org.easymock.EasyMock.expect;
66import static org.easymock.EasyMock.expectLastCall;
67import static org.easymock.EasyMock.replay;
68import static org.easymock.EasyMock.verify;
69import static org.hamcrest.Matchers.hasSize;
70import static org.hamcrest.Matchers.is;
Jian Li5e5734f2016-01-06 00:33:43 -080071import static org.junit.Assert.assertEquals;
Jian Li5c411232015-12-16 15:29:16 -080072import static org.junit.Assert.assertThat;
73import static org.hamcrest.Matchers.notNullValue;
74import static org.onosproject.net.NetTestTools.APP_ID;
75
76/**
77 * Unit tests for meters REST APIs.
78 */
79public class MetersResourceTest extends ResourceTest {
80 final MeterService mockMeterService = createMock(MeterService.class);
81 CoreService mockCoreService = createMock(CoreService.class);
82 final DeviceService mockDeviceService = createMock(DeviceService.class);
83
84 final HashMap<DeviceId, Set<Meter>> meters = new HashMap<>();
85
86 final DeviceId deviceId1 = DeviceId.deviceId("1");
87 final DeviceId deviceId2 = DeviceId.deviceId("2");
88 final DeviceId deviceId3 = DeviceId.deviceId("3");
89 final Device device1 = new DefaultDevice(null, deviceId1, Device.Type.OTHER,
90 "", "", "", "", null);
91 final Device device2 = new DefaultDevice(null, deviceId2, Device.Type.OTHER,
92 "", "", "", "", null);
93
94 final MockMeter meter1 = new MockMeter(deviceId1, 1, 111, 1);
95 final MockMeter meter2 = new MockMeter(deviceId1, 2, 222, 2);
96 final MockMeter meter3 = new MockMeter(deviceId2, 3, 333, 3);
97 final MockMeter meter4 = new MockMeter(deviceId2, 4, 444, 4);
98 final MockMeter meter5 = new MockMeter(deviceId3, 5, 555, 5);
99
Jian Li5e5734f2016-01-06 00:33:43 -0800100 public MetersResourceTest() {
101 super(CoreWebApplication.class);
102 }
103
Jian Li5c411232015-12-16 15:29:16 -0800104 /**
105 * Mock class for a meter.
106 */
107 private static class MockMeter implements Meter {
108
109 final DeviceId deviceId;
110 final ApplicationId appId;
111 final MeterId meterId;
112 final long baseValue;
113 final List<Band> bandList;
114
115 public MockMeter(DeviceId deviceId, int appId, long meterId, int id) {
116 this.deviceId = deviceId;
117 this.appId = new DefaultApplicationId(appId, String.valueOf(appId));
118 this.baseValue = id * 200;
119 this.meterId = MeterId.meterId(meterId);
120
121 Band band = DefaultBand.builder()
122 .ofType(Band.Type.REMARK)
123 .withRate(10)
124 .dropPrecedence((short) 20)
125 .burstSize(30).build();
126
127 this.bandList = new ArrayList<>();
128 this.bandList.add(band);
129 }
130
131 @Override
132 public DeviceId deviceId() {
133 return this.deviceId;
134 }
135
136 @Override
137 public MeterId id() {
138 return this.meterId;
139 }
140
141 @Override
142 public ApplicationId appId() {
143 return this.appId;
144 }
145
146 @Override
147 public Unit unit() {
148 return Unit.KB_PER_SEC;
149 }
150
151 @Override
152 public boolean isBurst() {
153 return false;
154 }
155
156 @Override
157 public Collection<Band> bands() {
158 return this.bandList;
159 }
160
161 @Override
162 public MeterState state() {
163 return MeterState.ADDED;
164 }
165
166 @Override
167 public long life() {
168 return baseValue + 11;
169 }
170
171 @Override
172 public long referenceCount() {
173 return baseValue + 22;
174 }
175
176 @Override
177 public long packetsSeen() {
178 return baseValue + 33;
179 }
180
181 @Override
182 public long bytesSeen() {
183 return baseValue + 44;
184 }
185 }
186
187 /**
188 * Populates some meters used as testing data.
189 */
190 private void setupMockMeters() {
191 final Set<Meter> meters1 = new HashSet<>();
192 meters1.add(meter1);
193 meters1.add(meter2);
194
195 final Set<Meter> meters2 = new HashSet<>();
196 meters2.add(meter3);
197 meters2.add(meter4);
198
199 meters.put(deviceId1, meters1);
200 meters.put(deviceId2, meters2);
201
202 Set<Meter> allMeters = new HashSet<>();
203 for (DeviceId deviceId : meters.keySet()) {
204 allMeters.addAll(meters.get(deviceId));
205 }
206
207 expect(mockMeterService.getAllMeters()).andReturn(allMeters).anyTimes();
208 }
209
210 /**
211 * Sets up the global values for all the tests.
212 */
213 @Before
214 public void setUpTest() {
215 // Mock device service
216 expect(mockDeviceService.getDevice(deviceId1))
217 .andReturn(device1);
218 expect(mockDeviceService.getDevice(deviceId2))
219 .andReturn(device2);
220 expect(mockDeviceService.getDevices())
221 .andReturn(ImmutableSet.of(device1, device2));
222
223 // Mock Core Service
224 expect(mockCoreService.getAppId(anyShort()))
225 .andReturn(NetTestTools.APP_ID).anyTimes();
226 expect(mockCoreService.registerApplication(MeterCodec.REST_APP_ID))
227 .andReturn(APP_ID).anyTimes();
228 replay(mockCoreService);
229
230 // Register the services needed for the test
231 final CodecManager codecService = new CodecManager();
232 codecService.activate();
233 ServiceDirectory testDirectory =
234 new TestServiceDirectory()
235 .add(MeterService.class, mockMeterService)
236 .add(DeviceService.class, mockDeviceService)
237 .add(CodecService.class, codecService)
238 .add(CoreService.class, mockCoreService);
239
240 BaseResource.setServiceDirectory(testDirectory);
241 }
242
243 /**
244 * Cleans up and verifies the mocks.
245 */
246 @After
247 public void tearDownTest() {
248 verify(mockMeterService);
249 verify(mockCoreService);
250 }
251
252 /**
253 * Hamcrest matcher to check that a meter representation in JSON matches
254 * the actual meter.
255 */
256 public static class MeterJsonMatcher extends TypeSafeMatcher<JsonObject> {
257 private final Meter meter;
258 private String reason = "";
259
260 public MeterJsonMatcher(Meter meterValue) {
261 this.meter = meterValue;
262 }
263
264 @Override
265 protected boolean matchesSafely(JsonObject jsonMeter) {
266
267 // check application id
268 final String jsonAppId = jsonMeter.get("appId").asString();
269 final String appId = meter.appId().toString();
270 if (!jsonAppId.equals(appId)) {
271 reason = "appId " + meter.appId().toString();
272 return false;
273 }
274
275 // check device id
276 final String jsonDeviceId = jsonMeter.get("deviceId").asString();
277 if (!jsonDeviceId.equals(meter.deviceId().toString())) {
278 reason = "deviceId " + meter.deviceId();
279 return false;
280 }
281
282 // check band array
283 if (meter.bands() != null) {
284 final JsonArray jsonBands = jsonMeter.get("bands").asArray();
285 if (meter.bands().size() != jsonBands.size()) {
286 reason = "bands array size of " +
287 Integer.toString(meter.bands().size());
288 return false;
289 }
290 for (final Band band : meter.bands()) {
291 boolean bandFound = false;
292 for (int bandIndex = 0; bandIndex < jsonBands.size(); bandIndex++) {
293 final String jsonType = jsonBands.get(bandIndex).asObject().get("type").asString();
294 final String bandType = band.type().name();
295 if (jsonType.equals(bandType)) {
296 bandFound = true;
297 }
298 }
299 if (!bandFound) {
300 reason = "meter band " + band.toString();
301 return false;
302 }
303 }
304 }
305
306 return true;
307 }
308
309 @Override
310 public void describeTo(Description description) {
311 description.appendText(reason);
312 }
313 }
314
315 private static MeterJsonMatcher matchesMeter(Meter meter) {
316 return new MeterJsonMatcher(meter);
317 }
318
319 /**
320 * Hamcrest matcher to check that a meter is represented properly in a JSON
321 * array of meters.
322 */
323 public static class MeterJsonArrayMatcher extends TypeSafeMatcher<JsonArray> {
324 private final Meter meter;
325 private String reason = "";
326
327 public MeterJsonArrayMatcher(Meter meterValue) {
328 meter = meterValue;
329 }
330
331 @Override
332 protected boolean matchesSafely(JsonArray json) {
333 boolean meterFound = false;
334 for (int jsonMeterIndex = 0; jsonMeterIndex < json.size(); jsonMeterIndex++) {
335 final JsonObject jsonMeter = json.get(jsonMeterIndex).asObject();
336
337 final String meterId = meter.id().toString();
338 final String jsonMeterId = jsonMeter.get("id").asString();
339 if (jsonMeterId.equals(meterId)) {
340 meterFound = true;
341
342 assertThat(jsonMeter, matchesMeter(meter));
343 }
344 }
345 if (!meterFound) {
346 reason = "Meter with id " + meter.id().toString() + " not found";
347 return false;
348 } else {
349 return true;
350 }
351 }
352
353 @Override
354 public void describeTo(Description description) {
355 description.appendText(reason);
356 }
357 }
358
359 /**
360 * Factory to allocate a meter array matcher.
361 *
362 * @param meter meter object we are looking for
363 * @return matcher
364 */
365 private static MeterJsonArrayMatcher hasMeter(Meter meter) {
366 return new MeterJsonArrayMatcher(meter);
367 }
368
369 @Test
370 public void testMeterEmptyArray() {
371 expect(mockMeterService.getAllMeters()).andReturn(null).anyTimes();
372 replay(mockMeterService);
373 replay(mockDeviceService);
374 final WebResource rs = resource();
375 final String response = rs.path("meters").get(String.class);
376 assertThat(response, is("{\"meters\":[]}"));
377 }
378
379 /**
380 * Tests the result of the rest api GET when there are active meters.
381 */
382 @Test
383 public void testMetersPopulatedArray() {
384 setupMockMeters();
385 replay(mockMeterService);
386 replay(mockDeviceService);
387 final WebResource rs = resource();
388 final String response = rs.path("meters").get(String.class);
Jian Li80cfe452016-01-14 16:04:58 -0800389 final JsonObject result = Json.parse(response).asObject();
Jian Li5c411232015-12-16 15:29:16 -0800390 assertThat(result, notNullValue());
391
392 assertThat(result.names(), hasSize(1));
393 assertThat(result.names().get(0), is("meters"));
394 final JsonArray jsonMeters = result.get("meters").asArray();
395 assertThat(jsonMeters, notNullValue());
396 assertThat(jsonMeters, hasMeter(meter1));
397 assertThat(jsonMeters, hasMeter(meter2));
398 assertThat(jsonMeters, hasMeter(meter3));
399 assertThat(jsonMeters, hasMeter(meter4));
400 }
401
402 /**
Jian Lia4faf4f2016-01-06 00:22:52 -0800403 * Tests the results of a rest api GET for a device.
404 */
405 @Test
406 public void testMeterSingleDevice() {
407 setupMockMeters();
408
409 final Set<Meter> meters1 = new HashSet<>();
410 meters1.add(meter1);
411 meters1.add(meter2);
412
413 expect(mockMeterService.getMeters(anyObject())).andReturn(meters1).anyTimes();
414 replay(mockMeterService);
415 replay(mockDeviceService);
416
417 final WebResource rs = resource();
418 final String response = rs.path("meters/" + deviceId1.toString()).get(String.class);
Jian Li80cfe452016-01-14 16:04:58 -0800419 final JsonObject result = Json.parse(response).asObject();
Jian Lia4faf4f2016-01-06 00:22:52 -0800420 assertThat(result, notNullValue());
421
422 assertThat(result.names(), hasSize(1));
423 assertThat(result.names().get(0), is("meters"));
424 final JsonArray jsonMeters = result.get("meters").asArray();
425 assertThat(jsonMeters, notNullValue());
426 assertThat(jsonMeters, hasMeter(meter1));
427 assertThat(jsonMeters, hasMeter(meter2));
428 }
429
430 /**
431 * Tests the result of a rest api GET for a device with meter id.
Jian Li5c411232015-12-16 15:29:16 -0800432 */
433 @Test
434 public void testMeterSingleDeviceWithId() {
435 setupMockMeters();
436
437 expect(mockMeterService.getMeter(anyObject(), anyObject()))
438 .andReturn(meter5).anyTimes();
439 replay(mockMeterService);
440 replay(mockDeviceService);
441
442 final WebResource rs = resource();
443 final String response = rs.path("meters/" + deviceId3.toString()
444 + "/" + meter5.id().id()).get(String.class);
Jian Li80cfe452016-01-14 16:04:58 -0800445 final JsonObject result = Json.parse(response).asObject();
Jian Li5c411232015-12-16 15:29:16 -0800446 assertThat(result, notNullValue());
447
448 assertThat(result.names(), hasSize(1));
449 assertThat(result.names().get(0), is("meters"));
Jian Li2e02fab2016-02-25 15:45:59 +0900450 final JsonArray jsonMeters = result.get("meters").asArray();
451 assertThat(jsonMeters, notNullValue());
452 assertThat(jsonMeters, hasMeter(meter5));
Jian Li5c411232015-12-16 15:29:16 -0800453 }
454
455 /**
Jian Li5e5734f2016-01-06 00:33:43 -0800456 * Test whether the REST API returns 404 if no entry has been found.
457 */
458 @Test
459 public void testMeterByDeviceIdAndMeterId() {
460 setupMockMeters();
461
462 expect(mockMeterService.getMeter(anyObject(), anyObject()))
463 .andReturn(null).anyTimes();
464 replay(mockMeterService);
465
466 final WebResource rs = resource();
467 final ClientResponse response = rs.path("meters/" + deviceId3.toString()
468 + "/" + "888").get(ClientResponse.class);
469
470 assertEquals(404, response.getStatus());
471 }
472
473 /**
Jian Li5c411232015-12-16 15:29:16 -0800474 * Tests creating a meter with POST.
475 */
476 @Test
477 public void testPost() {
478 mockMeterService.submit(anyObject());
479 expectLastCall().andReturn(meter5).anyTimes();
480 replay(mockMeterService);
481
482 WebResource rs = resource();
483 InputStream jsonStream = MetersResourceTest.class
484 .getResourceAsStream("post-meter.json");
485
486 ClientResponse response = rs.path("meters/of:0000000000000001")
487 .type(MediaType.APPLICATION_JSON_TYPE)
488 .post(ClientResponse.class, jsonStream);
489 assertThat(response.getStatus(), is(HttpURLConnection.HTTP_CREATED));
490 }
491
492 /**
493 * Tests deleting a meter.
494 */
495 @Test
496 public void testDelete() {
497 setupMockMeters();
498 expect(mockMeterService.getMeter(anyObject(), anyObject()))
499 .andReturn(meter5).anyTimes();
500 mockMeterService.withdraw(anyObject(), anyObject());
501 expectLastCall();
502 replay(mockMeterService);
503
504 WebResource rs = resource();
505
506 String location = "/meters/3/555";
507
508 ClientResponse deleteResponse = rs.path(location)
509 .type(MediaType.APPLICATION_JSON_TYPE)
510 .delete(ClientResponse.class);
511 assertThat(deleteResponse.getStatus(),
512 is(HttpURLConnection.HTTP_NO_CONTENT));
513 }
514}