blob: 235ca0f9a7426f89a19e2cc45e546793eb6a3c66 [file] [log] [blame]
Jian Li5c411232015-12-16 15:29:16 -08001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2016-present Open Networking Foundation
Jian Li5c411232015-12-16 15:29:16 -08003 *
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;
Jian Li5c411232015-12-16 15:29:16 -080018
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;
Jian Li5c411232015-12-16 15:29:16 -080023import org.hamcrest.Description;
Jian Li9d616492016-03-09 10:52:49 -080024import org.hamcrest.Matchers;
Jian Li5c411232015-12-16 15:29:16 -080025import org.hamcrest.TypeSafeMatcher;
26import org.junit.After;
27import org.junit.Before;
28import org.junit.Test;
29import org.onlab.osgi.ServiceDirectory;
30import org.onlab.osgi.TestServiceDirectory;
Jian Li5c411232015-12-16 15:29:16 -080031import org.onosproject.codec.CodecService;
32import org.onosproject.codec.impl.CodecManager;
33import org.onosproject.codec.impl.MeterCodec;
34import org.onosproject.core.ApplicationId;
35import org.onosproject.core.CoreService;
36import org.onosproject.core.DefaultApplicationId;
37import org.onosproject.net.DefaultDevice;
38import org.onosproject.net.Device;
39import org.onosproject.net.DeviceId;
40import org.onosproject.net.NetTestTools;
41import org.onosproject.net.device.DeviceService;
42import org.onosproject.net.meter.Band;
43import org.onosproject.net.meter.DefaultBand;
44import org.onosproject.net.meter.Meter;
45import org.onosproject.net.meter.MeterId;
46import org.onosproject.net.meter.MeterService;
47import org.onosproject.net.meter.MeterState;
48
Jian Li9d616492016-03-09 10:52:49 -080049import javax.ws.rs.client.Entity;
50import javax.ws.rs.client.WebTarget;
Jian Li5c411232015-12-16 15:29:16 -080051import javax.ws.rs.core.MediaType;
Jian Li9d616492016-03-09 10:52:49 -080052import javax.ws.rs.core.Response;
Jian Li5c411232015-12-16 15:29:16 -080053import 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 Li9d616492016-03-09 10:52:49 -080071import static org.hamcrest.Matchers.notNullValue;
Jian Li5e5734f2016-01-06 00:33:43 -080072import static org.junit.Assert.assertEquals;
Jian Li5c411232015-12-16 15:29:16 -080073import static org.junit.Assert.assertThat;
Jian Li5c411232015-12-16 15:29:16 -080074import 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");
Yoonseon Han59ecdf32016-09-28 14:18:59 -070089 final DeviceId deviceId4 = DeviceId.deviceId("of:0000000000000001");
Jian Li5c411232015-12-16 15:29:16 -080090 final Device device1 = new DefaultDevice(null, deviceId1, Device.Type.OTHER,
91 "", "", "", "", null);
92 final Device device2 = new DefaultDevice(null, deviceId2, Device.Type.OTHER,
93 "", "", "", "", null);
Yoonseon Han59ecdf32016-09-28 14:18:59 -070094 final Device device4 = new DefaultDevice(null, deviceId4, Device.Type.OTHER,
95 "", "", "", "", null);
Jian Li5c411232015-12-16 15:29:16 -080096
97 final MockMeter meter1 = new MockMeter(deviceId1, 1, 111, 1);
98 final MockMeter meter2 = new MockMeter(deviceId1, 2, 222, 2);
99 final MockMeter meter3 = new MockMeter(deviceId2, 3, 333, 3);
100 final MockMeter meter4 = new MockMeter(deviceId2, 4, 444, 4);
101 final MockMeter meter5 = new MockMeter(deviceId3, 5, 555, 5);
102
103 /**
104 * Mock class for a meter.
105 */
106 private static class MockMeter implements Meter {
107
108 final DeviceId deviceId;
109 final ApplicationId appId;
110 final MeterId meterId;
111 final long baseValue;
112 final List<Band> bandList;
113
114 public MockMeter(DeviceId deviceId, int appId, long meterId, int id) {
115 this.deviceId = deviceId;
116 this.appId = new DefaultApplicationId(appId, String.valueOf(appId));
rohitc2e77362017-03-27 20:07:25 +0530117 this.baseValue = id * 200L;
Jian Li5c411232015-12-16 15:29:16 -0800118 this.meterId = MeterId.meterId(meterId);
119
120 Band band = DefaultBand.builder()
121 .ofType(Band.Type.REMARK)
122 .withRate(10)
123 .dropPrecedence((short) 20)
124 .burstSize(30).build();
125
126 this.bandList = new ArrayList<>();
127 this.bandList.add(band);
128 }
129
130 @Override
131 public DeviceId deviceId() {
132 return this.deviceId;
133 }
134
135 @Override
136 public MeterId id() {
137 return this.meterId;
138 }
139
140 @Override
141 public ApplicationId appId() {
142 return this.appId;
143 }
144
145 @Override
146 public Unit unit() {
147 return Unit.KB_PER_SEC;
148 }
149
150 @Override
151 public boolean isBurst() {
152 return false;
153 }
154
155 @Override
156 public Collection<Band> bands() {
157 return this.bandList;
158 }
159
160 @Override
161 public MeterState state() {
162 return MeterState.ADDED;
163 }
164
165 @Override
166 public long life() {
167 return baseValue + 11;
168 }
169
170 @Override
171 public long referenceCount() {
172 return baseValue + 22;
173 }
174
175 @Override
176 public long packetsSeen() {
177 return baseValue + 33;
178 }
179
180 @Override
181 public long bytesSeen() {
182 return baseValue + 44;
183 }
184 }
185
186 /**
187 * Populates some meters used as testing data.
188 */
189 private void setupMockMeters() {
190 final Set<Meter> meters1 = new HashSet<>();
191 meters1.add(meter1);
192 meters1.add(meter2);
193
194 final Set<Meter> meters2 = new HashSet<>();
195 meters2.add(meter3);
196 meters2.add(meter4);
197
198 meters.put(deviceId1, meters1);
199 meters.put(deviceId2, meters2);
200
201 Set<Meter> allMeters = new HashSet<>();
202 for (DeviceId deviceId : meters.keySet()) {
203 allMeters.addAll(meters.get(deviceId));
204 }
205
206 expect(mockMeterService.getAllMeters()).andReturn(allMeters).anyTimes();
207 }
208
209 /**
210 * Sets up the global values for all the tests.
211 */
212 @Before
213 public void setUpTest() {
214 // Mock device service
215 expect(mockDeviceService.getDevice(deviceId1))
216 .andReturn(device1);
217 expect(mockDeviceService.getDevice(deviceId2))
218 .andReturn(device2);
Yoonseon Han59ecdf32016-09-28 14:18:59 -0700219 expect(mockDeviceService.getDevice(deviceId4))
220 .andReturn(device4);
Jian Li5c411232015-12-16 15:29:16 -0800221 expect(mockDeviceService.getDevices())
Yoonseon Han59ecdf32016-09-28 14:18:59 -0700222 .andReturn(ImmutableSet.of(device1, device2, device4));
Jian Li5c411232015-12-16 15:29:16 -0800223
224 // Mock Core Service
225 expect(mockCoreService.getAppId(anyShort()))
226 .andReturn(NetTestTools.APP_ID).anyTimes();
227 expect(mockCoreService.registerApplication(MeterCodec.REST_APP_ID))
228 .andReturn(APP_ID).anyTimes();
229 replay(mockCoreService);
230
231 // Register the services needed for the test
232 final CodecManager codecService = new CodecManager();
233 codecService.activate();
234 ServiceDirectory testDirectory =
235 new TestServiceDirectory()
236 .add(MeterService.class, mockMeterService)
237 .add(DeviceService.class, mockDeviceService)
238 .add(CodecService.class, codecService)
239 .add(CoreService.class, mockCoreService);
240
Ray Milkey094a1352018-01-22 14:03:54 -0800241 setServiceDirectory(testDirectory);
Jian Li5c411232015-12-16 15:29:16 -0800242 }
243
244 /**
245 * Cleans up and verifies the mocks.
246 */
247 @After
248 public void tearDownTest() {
249 verify(mockMeterService);
250 verify(mockCoreService);
251 }
252
253 /**
254 * Hamcrest matcher to check that a meter representation in JSON matches
255 * the actual meter.
256 */
257 public static class MeterJsonMatcher extends TypeSafeMatcher<JsonObject> {
258 private final Meter meter;
259 private String reason = "";
260
261 public MeterJsonMatcher(Meter meterValue) {
262 this.meter = meterValue;
263 }
264
265 @Override
266 protected boolean matchesSafely(JsonObject jsonMeter) {
267
268 // check application id
269 final String jsonAppId = jsonMeter.get("appId").asString();
Jayasree Ghoshe7a240c2016-09-10 14:45:15 +0530270 final String appId = meter.appId().name();
Jian Li5c411232015-12-16 15:29:16 -0800271 if (!jsonAppId.equals(appId)) {
Jayasree Ghoshe7a240c2016-09-10 14:45:15 +0530272 reason = "appId " + meter.appId().name();
Jian Li5c411232015-12-16 15:29:16 -0800273 return false;
274 }
275
276 // check device id
277 final String jsonDeviceId = jsonMeter.get("deviceId").asString();
278 if (!jsonDeviceId.equals(meter.deviceId().toString())) {
279 reason = "deviceId " + meter.deviceId();
280 return false;
281 }
282
283 // check band array
284 if (meter.bands() != null) {
285 final JsonArray jsonBands = jsonMeter.get("bands").asArray();
286 if (meter.bands().size() != jsonBands.size()) {
287 reason = "bands array size of " +
288 Integer.toString(meter.bands().size());
289 return false;
290 }
291 for (final Band band : meter.bands()) {
292 boolean bandFound = false;
293 for (int bandIndex = 0; bandIndex < jsonBands.size(); bandIndex++) {
294 final String jsonType = jsonBands.get(bandIndex).asObject().get("type").asString();
295 final String bandType = band.type().name();
296 if (jsonType.equals(bandType)) {
297 bandFound = true;
298 }
299 }
300 if (!bandFound) {
301 reason = "meter band " + band.toString();
302 return false;
303 }
304 }
305 }
306
307 return true;
308 }
309
310 @Override
311 public void describeTo(Description description) {
312 description.appendText(reason);
313 }
314 }
315
316 private static MeterJsonMatcher matchesMeter(Meter meter) {
317 return new MeterJsonMatcher(meter);
318 }
319
320 /**
321 * Hamcrest matcher to check that a meter is represented properly in a JSON
322 * array of meters.
323 */
324 public static class MeterJsonArrayMatcher extends TypeSafeMatcher<JsonArray> {
325 private final Meter meter;
326 private String reason = "";
327
328 public MeterJsonArrayMatcher(Meter meterValue) {
329 meter = meterValue;
330 }
331
332 @Override
333 protected boolean matchesSafely(JsonArray json) {
334 boolean meterFound = false;
335 for (int jsonMeterIndex = 0; jsonMeterIndex < json.size(); jsonMeterIndex++) {
336 final JsonObject jsonMeter = json.get(jsonMeterIndex).asObject();
337
338 final String meterId = meter.id().toString();
339 final String jsonMeterId = jsonMeter.get("id").asString();
340 if (jsonMeterId.equals(meterId)) {
341 meterFound = true;
342
343 assertThat(jsonMeter, matchesMeter(meter));
344 }
345 }
346 if (!meterFound) {
347 reason = "Meter with id " + meter.id().toString() + " not found";
348 return false;
349 } else {
350 return true;
351 }
352 }
353
354 @Override
355 public void describeTo(Description description) {
356 description.appendText(reason);
357 }
358 }
359
360 /**
361 * Factory to allocate a meter array matcher.
362 *
363 * @param meter meter object we are looking for
364 * @return matcher
365 */
366 private static MeterJsonArrayMatcher hasMeter(Meter meter) {
367 return new MeterJsonArrayMatcher(meter);
368 }
369
370 @Test
371 public void testMeterEmptyArray() {
372 expect(mockMeterService.getAllMeters()).andReturn(null).anyTimes();
373 replay(mockMeterService);
374 replay(mockDeviceService);
Jian Li9d616492016-03-09 10:52:49 -0800375 final WebTarget wt = target();
376 final String response = wt.path("meters").request().get(String.class);
Jian Li5c411232015-12-16 15:29:16 -0800377 assertThat(response, is("{\"meters\":[]}"));
378 }
379
380 /**
381 * Tests the result of the rest api GET when there are active meters.
382 */
383 @Test
384 public void testMetersPopulatedArray() {
385 setupMockMeters();
386 replay(mockMeterService);
387 replay(mockDeviceService);
Jian Li9d616492016-03-09 10:52:49 -0800388 final WebTarget wt = target();
389 final String response = wt.path("meters").request().get(String.class);
Jian Li80cfe452016-01-14 16:04:58 -0800390 final JsonObject result = Json.parse(response).asObject();
Jian Li5c411232015-12-16 15:29:16 -0800391 assertThat(result, notNullValue());
392
393 assertThat(result.names(), hasSize(1));
394 assertThat(result.names().get(0), is("meters"));
395 final JsonArray jsonMeters = result.get("meters").asArray();
396 assertThat(jsonMeters, notNullValue());
397 assertThat(jsonMeters, hasMeter(meter1));
398 assertThat(jsonMeters, hasMeter(meter2));
399 assertThat(jsonMeters, hasMeter(meter3));
400 assertThat(jsonMeters, hasMeter(meter4));
401 }
402
403 /**
Jian Lia4faf4f2016-01-06 00:22:52 -0800404 * Tests the results of a rest api GET for a device.
405 */
406 @Test
407 public void testMeterSingleDevice() {
408 setupMockMeters();
409
410 final Set<Meter> meters1 = new HashSet<>();
411 meters1.add(meter1);
412 meters1.add(meter2);
413
414 expect(mockMeterService.getMeters(anyObject())).andReturn(meters1).anyTimes();
415 replay(mockMeterService);
416 replay(mockDeviceService);
417
Jian Li9d616492016-03-09 10:52:49 -0800418 final WebTarget wt = target();
419 final String response = wt.path("meters/" + deviceId1.toString()).request().get(String.class);
Jian Li80cfe452016-01-14 16:04:58 -0800420 final JsonObject result = Json.parse(response).asObject();
Jian Lia4faf4f2016-01-06 00:22:52 -0800421 assertThat(result, notNullValue());
422
423 assertThat(result.names(), hasSize(1));
424 assertThat(result.names().get(0), is("meters"));
425 final JsonArray jsonMeters = result.get("meters").asArray();
426 assertThat(jsonMeters, notNullValue());
427 assertThat(jsonMeters, hasMeter(meter1));
428 assertThat(jsonMeters, hasMeter(meter2));
429 }
430
431 /**
432 * Tests the result of a rest api GET for a device with meter id.
Jian Li5c411232015-12-16 15:29:16 -0800433 */
434 @Test
435 public void testMeterSingleDeviceWithId() {
436 setupMockMeters();
437
438 expect(mockMeterService.getMeter(anyObject(), anyObject()))
439 .andReturn(meter5).anyTimes();
440 replay(mockMeterService);
441 replay(mockDeviceService);
442
Jian Li9d616492016-03-09 10:52:49 -0800443 final WebTarget wt = target();
444 final String response = wt.path("meters/" + deviceId3.toString()
445 + "/" + meter5.id().id()).request().get(String.class);
Jian Li80cfe452016-01-14 16:04:58 -0800446 final JsonObject result = Json.parse(response).asObject();
Jian Li5c411232015-12-16 15:29:16 -0800447 assertThat(result, notNullValue());
448
449 assertThat(result.names(), hasSize(1));
450 assertThat(result.names().get(0), is("meters"));
Jian Li2e02fab2016-02-25 15:45:59 +0900451 final JsonArray jsonMeters = result.get("meters").asArray();
452 assertThat(jsonMeters, notNullValue());
453 assertThat(jsonMeters, hasMeter(meter5));
Jian Li5c411232015-12-16 15:29:16 -0800454 }
455
456 /**
Jian Li5e5734f2016-01-06 00:33:43 -0800457 * Test whether the REST API returns 404 if no entry has been found.
458 */
459 @Test
460 public void testMeterByDeviceIdAndMeterId() {
461 setupMockMeters();
462
463 expect(mockMeterService.getMeter(anyObject(), anyObject()))
464 .andReturn(null).anyTimes();
465 replay(mockMeterService);
466
Jian Li9d616492016-03-09 10:52:49 -0800467 final WebTarget wt = target();
468 final Response response = wt.path("meters/" + deviceId3.toString()
469 + "/" + "888").request().get();
Jian Li5e5734f2016-01-06 00:33:43 -0800470
471 assertEquals(404, response.getStatus());
472 }
473
474 /**
Jian Li5c411232015-12-16 15:29:16 -0800475 * Tests creating a meter with POST.
476 */
477 @Test
478 public void testPost() {
479 mockMeterService.submit(anyObject());
480 expectLastCall().andReturn(meter5).anyTimes();
481 replay(mockMeterService);
Yoonseon Han59ecdf32016-09-28 14:18:59 -0700482 replay(mockDeviceService);
Jian Li5c411232015-12-16 15:29:16 -0800483
Jian Li9d616492016-03-09 10:52:49 -0800484 WebTarget wt = target();
Jian Li5c411232015-12-16 15:29:16 -0800485 InputStream jsonStream = MetersResourceTest.class
486 .getResourceAsStream("post-meter.json");
487
Jian Li9d616492016-03-09 10:52:49 -0800488 Response response = wt.path("meters/of:0000000000000001")
489 .request(MediaType.APPLICATION_JSON_TYPE)
490 .post(Entity.json(jsonStream));
Jian Li5c411232015-12-16 15:29:16 -0800491 assertThat(response.getStatus(), is(HttpURLConnection.HTTP_CREATED));
Jian Li9d616492016-03-09 10:52:49 -0800492 String location = response.getLocation().getPath();
493 assertThat(location, Matchers.startsWith("/meters/of:0000000000000001/"));
Jian Li5c411232015-12-16 15:29:16 -0800494 }
495
496 /**
Yoonseon Han59ecdf32016-09-28 14:18:59 -0700497 * Tests creating a meter with POST, but wrong deviceID.
498 */
499 @Test
500 public void testPostWithWrongDevice() {
501 mockMeterService.submit(anyObject());
502 expectLastCall().andReturn(meter5).anyTimes();
503 replay(mockMeterService);
504 replay(mockDeviceService);
505
506 WebTarget wt = target();
507 InputStream jsonStream = MetersResourceTest.class
508 .getResourceAsStream("post-meter.json");
509
510 Response response = wt.path("meters/of:0000000000000002")
511 .request(MediaType.APPLICATION_JSON_TYPE)
512 .post(Entity.json(jsonStream));
513 assertThat(response.getStatus(), is(HttpURLConnection.HTTP_BAD_REQUEST));
514 }
515
516 /**
Jian Li5c411232015-12-16 15:29:16 -0800517 * Tests deleting a meter.
518 */
519 @Test
520 public void testDelete() {
521 setupMockMeters();
522 expect(mockMeterService.getMeter(anyObject(), anyObject()))
523 .andReturn(meter5).anyTimes();
524 mockMeterService.withdraw(anyObject(), anyObject());
525 expectLastCall();
526 replay(mockMeterService);
527
Jian Li9d616492016-03-09 10:52:49 -0800528 WebTarget wt = target();
Jian Li5c411232015-12-16 15:29:16 -0800529
530 String location = "/meters/3/555";
531
Jian Li9d616492016-03-09 10:52:49 -0800532 Response deleteResponse = wt.path(location)
533 .request(MediaType.APPLICATION_JSON_TYPE)
534 .delete();
Jian Li5c411232015-12-16 15:29:16 -0800535 assertThat(deleteResponse.getStatus(),
536 is(HttpURLConnection.HTTP_NO_CONTENT));
537 }
538}