blob: 21ca646fe49cc40192a834f5e11dde8a82334297 [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
19import com.eclipsesource.json.JsonArray;
20import com.eclipsesource.json.JsonObject;
21import com.google.common.collect.ImmutableSet;
22import com.sun.jersey.api.client.ClientResponse;
23import com.sun.jersey.api.client.WebResource;
24import org.hamcrest.Description;
25import 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;
31import org.onlab.rest.BaseResource;
32import org.onosproject.codec.CodecService;
33import org.onosproject.codec.impl.CodecManager;
34import org.onosproject.codec.impl.MeterCodec;
35import org.onosproject.core.ApplicationId;
36import org.onosproject.core.CoreService;
37import org.onosproject.core.DefaultApplicationId;
38import org.onosproject.net.DefaultDevice;
39import org.onosproject.net.Device;
40import org.onosproject.net.DeviceId;
41import org.onosproject.net.NetTestTools;
42import org.onosproject.net.device.DeviceService;
43import org.onosproject.net.meter.Band;
44import org.onosproject.net.meter.DefaultBand;
45import org.onosproject.net.meter.Meter;
46import org.onosproject.net.meter.MeterId;
47import org.onosproject.net.meter.MeterService;
48import org.onosproject.net.meter.MeterState;
Jian Li5e5734f2016-01-06 00:33:43 -080049import org.onosproject.rest.resources.CoreWebApplication;
Jian Li5c411232015-12-16 15:29:16 -080050
51import javax.ws.rs.core.MediaType;
52import java.io.InputStream;
53import java.net.HttpURLConnection;
54import java.util.ArrayList;
55import java.util.Collection;
56import java.util.HashMap;
57import java.util.HashSet;
58import java.util.List;
59import java.util.Set;
60
61import static org.easymock.EasyMock.anyObject;
62import static org.easymock.EasyMock.anyShort;
63import static org.easymock.EasyMock.createMock;
64import static org.easymock.EasyMock.expect;
65import static org.easymock.EasyMock.expectLastCall;
66import static org.easymock.EasyMock.replay;
67import static org.easymock.EasyMock.verify;
68import static org.hamcrest.Matchers.hasSize;
69import static org.hamcrest.Matchers.is;
Jian Li5e5734f2016-01-06 00:33:43 -080070import static org.junit.Assert.assertEquals;
Jian Li5c411232015-12-16 15:29:16 -080071import static org.junit.Assert.assertThat;
72import static org.hamcrest.Matchers.notNullValue;
73import static org.onosproject.net.NetTestTools.APP_ID;
74
75/**
76 * Unit tests for meters REST APIs.
77 */
78public class MetersResourceTest extends ResourceTest {
79 final MeterService mockMeterService = createMock(MeterService.class);
80 CoreService mockCoreService = createMock(CoreService.class);
81 final DeviceService mockDeviceService = createMock(DeviceService.class);
82
83 final HashMap<DeviceId, Set<Meter>> meters = new HashMap<>();
84
85 final DeviceId deviceId1 = DeviceId.deviceId("1");
86 final DeviceId deviceId2 = DeviceId.deviceId("2");
87 final DeviceId deviceId3 = DeviceId.deviceId("3");
88 final Device device1 = new DefaultDevice(null, deviceId1, Device.Type.OTHER,
89 "", "", "", "", null);
90 final Device device2 = new DefaultDevice(null, deviceId2, Device.Type.OTHER,
91 "", "", "", "", null);
92
93 final MockMeter meter1 = new MockMeter(deviceId1, 1, 111, 1);
94 final MockMeter meter2 = new MockMeter(deviceId1, 2, 222, 2);
95 final MockMeter meter3 = new MockMeter(deviceId2, 3, 333, 3);
96 final MockMeter meter4 = new MockMeter(deviceId2, 4, 444, 4);
97 final MockMeter meter5 = new MockMeter(deviceId3, 5, 555, 5);
98
Jian Li5e5734f2016-01-06 00:33:43 -080099 public MetersResourceTest() {
100 super(CoreWebApplication.class);
101 }
102
Jian Li5c411232015-12-16 15:29:16 -0800103 /**
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));
117 this.baseValue = id * 200;
118 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);
219 expect(mockDeviceService.getDevices())
220 .andReturn(ImmutableSet.of(device1, device2));
221
222 // Mock Core Service
223 expect(mockCoreService.getAppId(anyShort()))
224 .andReturn(NetTestTools.APP_ID).anyTimes();
225 expect(mockCoreService.registerApplication(MeterCodec.REST_APP_ID))
226 .andReturn(APP_ID).anyTimes();
227 replay(mockCoreService);
228
229 // Register the services needed for the test
230 final CodecManager codecService = new CodecManager();
231 codecService.activate();
232 ServiceDirectory testDirectory =
233 new TestServiceDirectory()
234 .add(MeterService.class, mockMeterService)
235 .add(DeviceService.class, mockDeviceService)
236 .add(CodecService.class, codecService)
237 .add(CoreService.class, mockCoreService);
238
239 BaseResource.setServiceDirectory(testDirectory);
240 }
241
242 /**
243 * Cleans up and verifies the mocks.
244 */
245 @After
246 public void tearDownTest() {
247 verify(mockMeterService);
248 verify(mockCoreService);
249 }
250
251 /**
252 * Hamcrest matcher to check that a meter representation in JSON matches
253 * the actual meter.
254 */
255 public static class MeterJsonMatcher extends TypeSafeMatcher<JsonObject> {
256 private final Meter meter;
257 private String reason = "";
258
259 public MeterJsonMatcher(Meter meterValue) {
260 this.meter = meterValue;
261 }
262
263 @Override
264 protected boolean matchesSafely(JsonObject jsonMeter) {
265
266 // check application id
267 final String jsonAppId = jsonMeter.get("appId").asString();
268 final String appId = meter.appId().toString();
269 if (!jsonAppId.equals(appId)) {
270 reason = "appId " + meter.appId().toString();
271 return false;
272 }
273
274 // check device id
275 final String jsonDeviceId = jsonMeter.get("deviceId").asString();
276 if (!jsonDeviceId.equals(meter.deviceId().toString())) {
277 reason = "deviceId " + meter.deviceId();
278 return false;
279 }
280
281 // check band array
282 if (meter.bands() != null) {
283 final JsonArray jsonBands = jsonMeter.get("bands").asArray();
284 if (meter.bands().size() != jsonBands.size()) {
285 reason = "bands array size of " +
286 Integer.toString(meter.bands().size());
287 return false;
288 }
289 for (final Band band : meter.bands()) {
290 boolean bandFound = false;
291 for (int bandIndex = 0; bandIndex < jsonBands.size(); bandIndex++) {
292 final String jsonType = jsonBands.get(bandIndex).asObject().get("type").asString();
293 final String bandType = band.type().name();
294 if (jsonType.equals(bandType)) {
295 bandFound = true;
296 }
297 }
298 if (!bandFound) {
299 reason = "meter band " + band.toString();
300 return false;
301 }
302 }
303 }
304
305 return true;
306 }
307
308 @Override
309 public void describeTo(Description description) {
310 description.appendText(reason);
311 }
312 }
313
314 private static MeterJsonMatcher matchesMeter(Meter meter) {
315 return new MeterJsonMatcher(meter);
316 }
317
318 /**
319 * Hamcrest matcher to check that a meter is represented properly in a JSON
320 * array of meters.
321 */
322 public static class MeterJsonArrayMatcher extends TypeSafeMatcher<JsonArray> {
323 private final Meter meter;
324 private String reason = "";
325
326 public MeterJsonArrayMatcher(Meter meterValue) {
327 meter = meterValue;
328 }
329
330 @Override
331 protected boolean matchesSafely(JsonArray json) {
332 boolean meterFound = false;
333 for (int jsonMeterIndex = 0; jsonMeterIndex < json.size(); jsonMeterIndex++) {
334 final JsonObject jsonMeter = json.get(jsonMeterIndex).asObject();
335
336 final String meterId = meter.id().toString();
337 final String jsonMeterId = jsonMeter.get("id").asString();
338 if (jsonMeterId.equals(meterId)) {
339 meterFound = true;
340
341 assertThat(jsonMeter, matchesMeter(meter));
342 }
343 }
344 if (!meterFound) {
345 reason = "Meter with id " + meter.id().toString() + " not found";
346 return false;
347 } else {
348 return true;
349 }
350 }
351
352 @Override
353 public void describeTo(Description description) {
354 description.appendText(reason);
355 }
356 }
357
358 /**
359 * Factory to allocate a meter array matcher.
360 *
361 * @param meter meter object we are looking for
362 * @return matcher
363 */
364 private static MeterJsonArrayMatcher hasMeter(Meter meter) {
365 return new MeterJsonArrayMatcher(meter);
366 }
367
368 @Test
369 public void testMeterEmptyArray() {
370 expect(mockMeterService.getAllMeters()).andReturn(null).anyTimes();
371 replay(mockMeterService);
372 replay(mockDeviceService);
373 final WebResource rs = resource();
374 final String response = rs.path("meters").get(String.class);
375 assertThat(response, is("{\"meters\":[]}"));
376 }
377
378 /**
379 * Tests the result of the rest api GET when there are active meters.
380 */
381 @Test
382 public void testMetersPopulatedArray() {
383 setupMockMeters();
384 replay(mockMeterService);
385 replay(mockDeviceService);
386 final WebResource rs = resource();
387 final String response = rs.path("meters").get(String.class);
388 final JsonObject result = JsonObject.readFrom(response);
389 assertThat(result, notNullValue());
390
391 assertThat(result.names(), hasSize(1));
392 assertThat(result.names().get(0), is("meters"));
393 final JsonArray jsonMeters = result.get("meters").asArray();
394 assertThat(jsonMeters, notNullValue());
395 assertThat(jsonMeters, hasMeter(meter1));
396 assertThat(jsonMeters, hasMeter(meter2));
397 assertThat(jsonMeters, hasMeter(meter3));
398 assertThat(jsonMeters, hasMeter(meter4));
399 }
400
401 /**
Jian Lia4faf4f2016-01-06 00:22:52 -0800402 * Tests the results of a rest api GET for a device.
403 */
404 @Test
405 public void testMeterSingleDevice() {
406 setupMockMeters();
407
408 final Set<Meter> meters1 = new HashSet<>();
409 meters1.add(meter1);
410 meters1.add(meter2);
411
412 expect(mockMeterService.getMeters(anyObject())).andReturn(meters1).anyTimes();
413 replay(mockMeterService);
414 replay(mockDeviceService);
415
416 final WebResource rs = resource();
417 final String response = rs.path("meters/" + deviceId1.toString()).get(String.class);
418 final JsonObject result = JsonObject.readFrom(response);
419 assertThat(result, notNullValue());
420
421 assertThat(result.names(), hasSize(1));
422 assertThat(result.names().get(0), is("meters"));
423 final JsonArray jsonMeters = result.get("meters").asArray();
424 assertThat(jsonMeters, notNullValue());
425 assertThat(jsonMeters, hasMeter(meter1));
426 assertThat(jsonMeters, hasMeter(meter2));
427 }
428
429 /**
430 * Tests the result of a rest api GET for a device with meter id.
Jian Li5c411232015-12-16 15:29:16 -0800431 */
432 @Test
433 public void testMeterSingleDeviceWithId() {
434 setupMockMeters();
435
436 expect(mockMeterService.getMeter(anyObject(), anyObject()))
437 .andReturn(meter5).anyTimes();
438 replay(mockMeterService);
439 replay(mockDeviceService);
440
441 final WebResource rs = resource();
442 final String response = rs.path("meters/" + deviceId3.toString()
443 + "/" + meter5.id().id()).get(String.class);
444 final JsonObject result = JsonObject.readFrom(response);
445 assertThat(result, notNullValue());
446
447 assertThat(result.names(), hasSize(1));
448 assertThat(result.names().get(0), is("meters"));
449 final JsonArray jsonFlows = result.get("meters").asArray();
450 assertThat(jsonFlows, notNullValue());
451 assertThat(jsonFlows, hasMeter(meter5));
452 }
453
454 /**
Jian Li5e5734f2016-01-06 00:33:43 -0800455 * Test whether the REST API returns 404 if no entry has been found.
456 */
457 @Test
458 public void testMeterByDeviceIdAndMeterId() {
459 setupMockMeters();
460
461 expect(mockMeterService.getMeter(anyObject(), anyObject()))
462 .andReturn(null).anyTimes();
463 replay(mockMeterService);
464
465 final WebResource rs = resource();
466 final ClientResponse response = rs.path("meters/" + deviceId3.toString()
467 + "/" + "888").get(ClientResponse.class);
468
469 assertEquals(404, response.getStatus());
470 }
471
472 /**
Jian Li5c411232015-12-16 15:29:16 -0800473 * Tests creating a meter with POST.
474 */
475 @Test
476 public void testPost() {
477 mockMeterService.submit(anyObject());
478 expectLastCall().andReturn(meter5).anyTimes();
479 replay(mockMeterService);
480
481 WebResource rs = resource();
482 InputStream jsonStream = MetersResourceTest.class
483 .getResourceAsStream("post-meter.json");
484
485 ClientResponse response = rs.path("meters/of:0000000000000001")
486 .type(MediaType.APPLICATION_JSON_TYPE)
487 .post(ClientResponse.class, jsonStream);
488 assertThat(response.getStatus(), is(HttpURLConnection.HTTP_CREATED));
489 }
490
491 /**
492 * Tests deleting a meter.
493 */
494 @Test
495 public void testDelete() {
496 setupMockMeters();
497 expect(mockMeterService.getMeter(anyObject(), anyObject()))
498 .andReturn(meter5).anyTimes();
499 mockMeterService.withdraw(anyObject(), anyObject());
500 expectLastCall();
501 replay(mockMeterService);
502
503 WebResource rs = resource();
504
505 String location = "/meters/3/555";
506
507 ClientResponse deleteResponse = rs.path(location)
508 .type(MediaType.APPLICATION_JSON_TYPE)
509 .delete(ClientResponse.class);
510 assertThat(deleteResponse.getStatus(),
511 is(HttpURLConnection.HTTP_NO_CONTENT));
512 }
513}