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