blob: 4cddf547ac330f703803fd5ba53af98baa649c72 [file] [log] [blame]
Pier Luigif094c612017-10-14 12:15:02 +02001/*
2 * Copyright 2017-present Open Networking Foundation
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
Thomas Vachuska52f2cd12018-11-08 21:20:04 -080017package org.onosproject.store.meter.impl;
Pier Luigif094c612017-10-14 12:15:02 +020018
Charles Chan593acf92017-11-22 13:55:41 -080019import com.google.common.collect.Lists;
Pier Luigif094c612017-10-14 12:15:02 +020020import org.junit.After;
21import org.junit.Before;
22import org.junit.Test;
23import org.onlab.junit.TestUtils;
24import org.onlab.packet.IpAddress;
Charles Chan593acf92017-11-22 13:55:41 -080025import org.onlab.util.KryoNamespace;
26import org.onosproject.TestApplicationId;
Pier Luigif094c612017-10-14 12:15:02 +020027import org.onosproject.cluster.NodeId;
Pier Luigif094c612017-10-14 12:15:02 +020028import org.onosproject.net.DeviceId;
29import org.onosproject.net.behaviour.MeterQuery;
30import org.onosproject.net.driver.Behaviour;
31import org.onosproject.net.driver.Driver;
32import org.onosproject.net.driver.DriverData;
33import org.onosproject.net.driver.DriverHandler;
34import org.onosproject.net.driver.DriverServiceAdapter;
35import org.onosproject.net.meter.Band;
36import org.onosproject.net.meter.DefaultBand;
37import org.onosproject.net.meter.DefaultMeter;
38import org.onosproject.net.meter.DefaultMeterFeatures;
39import org.onosproject.net.meter.Meter;
40import org.onosproject.net.meter.MeterFeatures;
41import org.onosproject.net.meter.MeterFeaturesKey;
42import org.onosproject.net.meter.MeterId;
43import org.onosproject.net.meter.MeterKey;
44import org.onosproject.net.meter.MeterState;
Charles Chan593acf92017-11-22 13:55:41 -080045import org.onosproject.store.service.Serializer;
Pier Luigif094c612017-10-14 12:15:02 +020046import org.onosproject.store.service.TestStorageService;
47
pierventrebb5110d2020-09-22 12:51:06 +020048import java.util.Collection;
Pier Luigif094c612017-10-14 12:15:02 +020049import java.util.Collections;
50import java.util.HashSet;
Pier Luigif094c612017-10-14 12:15:02 +020051import java.util.concurrent.CompletableFuture;
52import java.util.concurrent.ExecutionException;
53
54import static org.hamcrest.Matchers.is;
55import static org.junit.Assert.*;
56import static org.onosproject.net.NetTestTools.APP_ID;
57import static org.onosproject.net.NetTestTools.did;
58
59/**
60 * Meter store tests.
61 */
62public class DistributedMeterStoreTest {
63
64 // Test node id
65 private static final NodeId NID_LOCAL = new NodeId("local");
66
67 // Test ip address
68 private static final IpAddress LOCALHOST = IpAddress.valueOf("127.0.0.1");
69
70 // Store under testing
71 private DistributedMeterStore meterStore;
72
73 // Device ids used during the tests
74 private DeviceId did1 = did("1");
75 private DeviceId did2 = did("2");
76 private DeviceId did3 = did("3");
77 private DeviceId did4 = did("4");
78
79 // Meter ids used during the tests
80 private MeterId mid1 = MeterId.meterId(1);
81 private MeterId mid2 = MeterId.meterId(2);
Pier Luigibdcd9672017-10-13 13:54:48 +020082 private MeterId mid10 = MeterId.meterId(10);
Pier Luigif094c612017-10-14 12:15:02 +020083
84 // Bands used during the tests
85 private Band b1 = DefaultBand.builder()
86 .ofType(Band.Type.DROP)
87 .withRate(500)
88 .build();
89
90 // Meters used during the tests
91 private Meter m1 = DefaultMeter.builder()
92 .forDevice(did1)
93 .fromApp(APP_ID)
94 .withId(mid1)
95 .withUnit(Meter.Unit.KB_PER_SEC)
96 .withBands(Collections.singletonList(b1))
97 .build();
98
99 // Meter features used during the tests
100 private MeterFeatures mef1 = DefaultMeterFeatures.builder().forDevice(did1)
101 .withMaxMeters(3L)
102 .withBandTypes(new HashSet<>())
103 .withUnits(new HashSet<>())
104 .hasStats(false)
105 .hasBurst(false)
106 .withMaxBands((byte) 0)
107 .withMaxColors((byte) 0)
108 .build();
109 private MeterFeatures mef2 = DefaultMeterFeatures.builder().forDevice(did2)
110 .withMaxMeters(10L)
111 .withBandTypes(new HashSet<>())
112 .withUnits(new HashSet<>())
113 .hasStats(false)
114 .hasBurst(false)
115 .withMaxBands((byte) 0)
116 .withMaxColors((byte) 0)
117 .build();
118
119 @Before
120 public void setup() {
121 // Init step
122 meterStore = new DistributedMeterStore();
123 // Let's initialize some internal services
124 TestUtils.setField(meterStore, "storageService", new TestStorageService());
Pier Luigif094c612017-10-14 12:15:02 +0200125 TestUtils.setField(meterStore, "driverService", new TestDriverService());
Charles Chan593acf92017-11-22 13:55:41 -0800126
127 // Inject TestApplicationId into the DistributedMeterStore serializer
128 KryoNamespace.Builder testKryoBuilder = TestUtils.getField(meterStore, "APP_KRYO_BUILDER");
129 testKryoBuilder.register(TestApplicationId.class);
130 Serializer testSerializer = Serializer.using(Lists.newArrayList(testKryoBuilder.build()));
131 TestUtils.setField(meterStore, "serializer", testSerializer);
132
Pier Luigif094c612017-10-14 12:15:02 +0200133 // Activate the store
134 meterStore.activate();
135 }
136
137 @After
138 public void tearDown() {
139 // Deactivate the store
140 meterStore.deactivate();
141 }
142
143 private void initMeterStore() {
144 // Let's store feature for device 1
145 meterStore.storeMeterFeatures(mef1);
146 // Let's store feature for device 2
147 meterStore.storeMeterFeatures(mef2);
148 }
149
150 /**
151 * Test proper store of meter features.
152 */
153 @Test
154 public void testStoreMeterFeatures() {
155 // Let's store feature for device 1
156 meterStore.storeMeterFeatures(mef1);
157 // Verify store meter features
158 assertThat(meterStore.getMaxMeters(MeterFeaturesKey.key(did1)), is(3L));
159 // Let's store feature for device 1
160 meterStore.storeMeterFeatures(mef2);
161 // Verify store meter features
162 assertThat(meterStore.getMaxMeters(MeterFeaturesKey.key(did2)), is(10L));
163 }
164
165 /**
166 * Test proper delete of meter features.
167 */
168 @Test
169 public void testDeleteMeterFeatures() {
170 // Let's store feature for device 1
171 meterStore.storeMeterFeatures(mef1);
172 // Verify store meter features
173 assertThat(meterStore.getMaxMeters(MeterFeaturesKey.key(did1)), is(3L));
174 // Let's delete the features
175 meterStore.deleteMeterFeatures(did1);
176 // Verify delete meter features
177 assertThat(meterStore.getMaxMeters(MeterFeaturesKey.key(did1)), is(0L));
178 }
179
180 /**
181 * Test proper allocation of meter ids.
182 */
183 @Test
184 public void testAllocateId() {
185 // Init the store
186 initMeterStore();
187 // Allocate a meter id and verify is equal to mid1
188 assertThat(mid1, is(meterStore.allocateMeterId(did1)));
189 // Allocate a meter id and verify is equal to mid2
190 assertThat(mid2, is(meterStore.allocateMeterId(did1)));
191 }
192
193 /**
194 * Test proper free of meter ids.
195 */
196 @Test
197 public void testFreeId() {
198 // Init the store
199 initMeterStore();
200 // Allocate a meter id and verify is equal to mid1
201 assertThat(mid1, is(meterStore.allocateMeterId(did1)));
202 // Free the above id
203 meterStore.freeMeterId(did1, mid1);
204 // Allocate a meter id and verify is equal to mid1
205 assertThat(mid1, is(meterStore.allocateMeterId(did1)));
Pier Luigibdcd9672017-10-13 13:54:48 +0200206 // Free an id not allocated
207 meterStore.freeMeterId(did1, mid10);
208 // Allocate a meter id and verify is equal to mid2
209 assertThat(mid2, is(meterStore.allocateMeterId(did1)));
Pier Luigif094c612017-10-14 12:15:02 +0200210 }
211
212 /**
213 * Test proper reuse of meter ids.
214 */
215 @Test
216 public void testReuseId() {
217 // Init the store
218 initMeterStore();
219 // Reserve id 1
220 MeterId meterIdOne = meterStore.allocateMeterId(did2);
221 // Free the above id
222 meterStore.freeMeterId(did2, meterIdOne);
223 // Start an async reservation
224 CompletableFuture<MeterId> future = CompletableFuture.supplyAsync(
225 () -> meterStore.allocateMeterId(did2)
226 );
227 // Start another reservation
228 MeterId meterIdTwo = meterStore.allocateMeterId(did2);
229 try {
230 meterIdOne = future.get();
231 } catch (InterruptedException | ExecutionException e) {
232 e.printStackTrace();
233 }
234 // Ids should be different, otherwise we had clash in the store
235 assertNotEquals("Ids should be different", meterIdOne, meterIdTwo);
236
237 // Free the above id
238 meterStore.freeMeterId(did1, meterIdOne);
239 // Free the above id
240 meterStore.freeMeterId(did1, meterIdTwo);
241 // Reserve id 1
242 meterIdOne = meterStore.allocateMeterId(did2);
243 // Reserve id 2
244 meterStore.allocateMeterId(did2);
245 // Reserve id 3
246 MeterId meterIdThree = meterStore.allocateMeterId(did2);
247 // Reserve id 4
248 MeterId meterIdFour = meterStore.allocateMeterId(did2);
249 // Free the above id
250 meterStore.freeMeterId(did1, meterIdOne);
251 // Free the above id
252 meterStore.freeMeterId(did1, meterIdThree);
253 // Free the above id
254 meterStore.freeMeterId(did1, meterIdFour);
255 // Start an async reservation
256 future = CompletableFuture.supplyAsync(
257 () -> meterStore.allocateMeterId(did2)
258 );
259 // Start another reservation
260 MeterId meterAnotherId = meterStore.allocateMeterId(did2);
261 try {
262 meterAnotherId = future.get();
263 } catch (InterruptedException | ExecutionException e) {
264 e.printStackTrace();
265 }
266 // Ids should be different, otherwise we had clash in the store
267 assertNotEquals("Ids should be different", meterAnotherId, meterIdOne);
268 }
269
270 /**
271 * Test query meters mechanism.
272 */
273 @Test
274 public void testQueryMeters() {
275 // Init the store
276 initMeterStore();
277 // Let's test queryMeters
278 assertThat(mid1, is(meterStore.allocateMeterId(did3)));
279 // Let's test queryMeters error
280 assertNull(meterStore.allocateMeterId(did4));
281 }
282
283 /**
284 * Test max meter error.
285 */
286 @Test
287 public void testMaxMeterError() {
288 // Init the store
289 initMeterStore();
290 // Reserve id 1
291 assertThat(mid1, is(meterStore.allocateMeterId(did1)));
292 // Reserve id 2
293 assertThat(mid2, is(meterStore.allocateMeterId(did1)));
294 // Max meter error
295 assertNull(meterStore.allocateMeterId(did1));
296 }
297
298 /**
299 * Test store meter.
300 */
301 @Test
302 public void testStoreMeter() {
303 // Init the store
304 initMeterStore();
305 // Simulate the allocation of an id
306 MeterId idOne = meterStore.allocateMeterId(did1);
307 // Verify the allocation
308 assertThat(mid1, is(idOne));
309 // Let's create a meter
310 Meter meterOne = DefaultMeter.builder()
311 .forDevice(did1)
312 .fromApp(APP_ID)
313 .withId(mid1)
314 .withUnit(Meter.Unit.KB_PER_SEC)
315 .withBands(Collections.singletonList(b1))
316 .build();
317 // Set the state
318 ((DefaultMeter) meterOne).setState(MeterState.PENDING_ADD);
319 // Store the meter
320 meterStore.storeMeter(meterOne);
321 // Let's create meter key
322 MeterKey meterKey = MeterKey.key(did1, mid1);
323 // Verify the store
324 assertThat(1, is(meterStore.getAllMeters().size()));
325 assertThat(1, is(meterStore.getAllMeters(did1).size()));
326 assertThat(m1, is(meterStore.getMeter(meterKey)));
327 }
328
329 /**
330 * Test delete meter.
331 */
332 @Test
333 public void testDeleteMeter() {
334 // Init the store
335 initMeterStore();
336 // Simulate the allocation of an id
337 MeterId idOne = meterStore.allocateMeterId(did1);
338 // Verify the allocation
339 assertThat(mid1, is(idOne));
340 // Let's create a meter
341 Meter meterOne = DefaultMeter.builder()
342 .forDevice(did1)
343 .fromApp(APP_ID)
344 .withId(mid1)
345 .withUnit(Meter.Unit.KB_PER_SEC)
346 .withBands(Collections.singletonList(b1))
347 .build();
348 // Set the state
349 ((DefaultMeter) meterOne).setState(MeterState.PENDING_ADD);
350 // Store the meter
351 meterStore.storeMeter(meterOne);
352 // Set the state
353 ((DefaultMeter) meterOne).setState(MeterState.PENDING_REMOVE);
354 // Let's create meter key
355 MeterKey meterKey = MeterKey.key(did1, mid1);
356 // Delete meter
357 meterStore.deleteMeter(meterOne);
358 // Start an async delete, simulating the operation of the provider
359 CompletableFuture<Void> future = CompletableFuture.runAsync(
360 () -> meterStore.deleteMeterNow(meterOne)
361 );
362 // Let's wait
363 try {
364 future.get();
365 } catch (InterruptedException | ExecutionException e) {
366 e.printStackTrace();
367 }
368 // Verify delete
369 assertThat(0, is(meterStore.getAllMeters().size()));
370 assertThat(0, is(meterStore.getAllMeters(did1).size()));
371 assertNull(meterStore.getMeter(meterKey));
372 assertThat(mid1, is(meterStore.allocateMeterId(did1)));
373 }
374
375 /**
376 * Test no delete meter.
377 */
378 @Test
379 public void testNoDeleteMeter() {
380 // Init the store
381 initMeterStore();
382 // Simulate the allocation of an id
383 MeterId idOne = meterStore.allocateMeterId(did1);
384 // Create the key
385 MeterKey keyOne = MeterKey.key(did1, idOne);
386 // Let's create a meter
387 Meter meterOne = DefaultMeter.builder()
388 .forDevice(did1)
389 .fromApp(APP_ID)
390 .withId(mid1)
391 .withUnit(Meter.Unit.KB_PER_SEC)
392 .withBands(Collections.singletonList(b1))
393 .build();
394 // Set the state
395 ((DefaultMeter) meterOne).setState(MeterState.PENDING_REMOVE);
396 // Delete meter
397 meterStore.deleteMeter(meterOne);
398 // Verify No delete
399 assertThat(0, is(meterStore.getAllMeters().size()));
400 assertThat(0, is(meterStore.getAllMeters(did1).size()));
401 assertNull(meterStore.getMeter(keyOne));
402 }
403
pierventree97f4832020-07-13 14:07:05 +0200404 /**
405 * Test purge meter.
406 */
407 @Test
408 public void testPurgeMeter() {
409 // add the meter
410 testStoreMeter();
411 meterStore.purgeMeter(did1);
412 // Verify delete
413 MeterKey keyOne = MeterKey.key(did1, mid1);
414 assertThat(0, is(meterStore.getAllMeters().size()));
415 assertThat(0, is(meterStore.getAllMeters(did1).size()));
416 assertNull(meterStore.getMeter(keyOne));
Pier Luigif094c612017-10-14 12:15:02 +0200417 }
418
pierventrebb5110d2020-09-22 12:51:06 +0200419 /**
420 * Test getMeters API immutability.
421 */
422 @Test
423 public void testGetMetersImmutability() {
424 // Init the store
425 initMeterStore();
426
427 // Simulate the allocation of an id
428 MeterId idOne = meterStore.allocateMeterId(did1);
429 // Verify the allocation
430 assertThat(mid1, is(idOne));
431 // Let's create a meter
432 Meter meterOne = DefaultMeter.builder()
433 .forDevice(did1)
434 .fromApp(APP_ID)
435 .withId(mid1)
436 .withUnit(Meter.Unit.KB_PER_SEC)
437 .withBands(Collections.singletonList(b1))
438 .build();
439 // Set the state
440 ((DefaultMeter) meterOne).setState(MeterState.PENDING_ADD);
441 // Store the meter
442 meterStore.storeMeter(meterOne);
443
444 // Verify the immutability
445 Collection<Meter> meters = meterStore.getAllMeters();
446 Collection<Meter> metersDevice = meterStore.getAllMeters(did1);
447 assertThat(1, is(meters.size()));
448 assertThat(1, is(metersDevice.size()));
449
450 MeterId idTwo = meterStore.allocateMeterId(did1);
451 // Verify the allocation
452 assertThat(mid2, is(idTwo));
453 // Let's create a meter
454 Meter meterTwo = DefaultMeter.builder()
455 .forDevice(did1)
456 .fromApp(APP_ID)
457 .withId(mid2)
458 .withUnit(Meter.Unit.KB_PER_SEC)
459 .withBands(Collections.singletonList(b1))
460 .build();
461 // Set the state
462 ((DefaultMeter) meterTwo).setState(MeterState.PENDING_ADD);
463 // Store the meter
464 meterStore.storeMeter(meterTwo);
465
466 assertThat(1, is(meters.size()));
467 assertThat(1, is(metersDevice.size()));
468
469 meters = meterStore.getAllMeters();
470 metersDevice = meterStore.getAllMeters(did1);
471 assertThat(2, is(meters.size()));
472 assertThat(2, is(metersDevice.size()));
473
474
475 }
476
Pier Luigif094c612017-10-14 12:15:02 +0200477 // Test class for driver service.
478 private class TestDriverService extends DriverServiceAdapter {
479 @Override
480 public DriverHandler createHandler(DeviceId deviceId, String... credentials) {
481 return deviceId.equals(did3) ? new TestDriverHandler() : null;
482 }
483 }
484
485 // Test class for driver handler.
486 private class TestDriverHandler implements DriverHandler {
487
488 @Override
489 public Driver driver() {
490 return null;
491 }
492
493 @Override
494 public DriverData data() {
495 return null;
496 }
497
498 @Override
499 @SuppressWarnings("unchecked")
500 public <T extends Behaviour> T behaviour(Class<T> behaviourClass) {
501 return (T) new TestMeterQuery();
502 }
503
504 @Override
505 public <T> T get(Class<T> serviceClass) {
506 return null;
507 }
508
509 @Override
510 public boolean hasBehaviour(Class<? extends Behaviour> behaviourClass) {
511 return true;
512 }
513 }
514
515 // Test meter query
516 private class TestMeterQuery implements MeterQuery {
517
518 @Override
519 public DriverData data() {
520 return null;
521 }
522
523 @Override
524 public void setData(DriverData data) {
525
526 }
527 @Override
528 public DriverHandler handler() {
529 return null;
530 }
531
532 @Override
533 public void setHandler(DriverHandler handler) {
534
535 }
536
537 @Override
538 public long getMaxMeters() {
539 return 100;
540 }
541 }
542
543}