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