blob: 94940c443887014f158561fd6dc1f6764c9a5648 [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
17package org.onosproject.incubator.store.meter.impl;
18
19import com.google.common.collect.Sets;
20import org.junit.After;
21import org.junit.Before;
22import org.junit.Test;
23import org.onlab.junit.TestUtils;
24import org.onlab.packet.IpAddress;
25import org.onosproject.cluster.ClusterServiceAdapter;
26import org.onosproject.cluster.ControllerNode;
27import org.onosproject.cluster.DefaultControllerNode;
28import org.onosproject.cluster.NodeId;
29import org.onosproject.mastership.MastershipServiceAdapter;
30import org.onosproject.net.DeviceId;
31import org.onosproject.net.behaviour.MeterQuery;
32import org.onosproject.net.driver.Behaviour;
33import org.onosproject.net.driver.Driver;
34import org.onosproject.net.driver.DriverData;
35import org.onosproject.net.driver.DriverHandler;
36import org.onosproject.net.driver.DriverServiceAdapter;
37import org.onosproject.net.meter.Band;
38import org.onosproject.net.meter.DefaultBand;
39import org.onosproject.net.meter.DefaultMeter;
40import org.onosproject.net.meter.DefaultMeterFeatures;
41import org.onosproject.net.meter.Meter;
42import org.onosproject.net.meter.MeterFeatures;
43import org.onosproject.net.meter.MeterFeaturesKey;
44import org.onosproject.net.meter.MeterId;
45import org.onosproject.net.meter.MeterKey;
46import org.onosproject.net.meter.MeterState;
47import org.onosproject.store.service.TestStorageService;
48
49import java.util.Collections;
50import java.util.HashSet;
51import java.util.Set;
52import java.util.concurrent.CompletableFuture;
53import java.util.concurrent.ExecutionException;
54
55import static org.hamcrest.Matchers.is;
56import static org.junit.Assert.*;
57import static org.onosproject.net.NetTestTools.APP_ID;
58import static org.onosproject.net.NetTestTools.did;
59
60/**
61 * Meter store tests.
62 */
63public class DistributedMeterStoreTest {
64
65 // Test node id
66 private static final NodeId NID_LOCAL = new NodeId("local");
67
68 // Test ip address
69 private static final IpAddress LOCALHOST = IpAddress.valueOf("127.0.0.1");
70
71 // Store under testing
72 private DistributedMeterStore meterStore;
73
74 // Device ids used during the tests
75 private DeviceId did1 = did("1");
76 private DeviceId did2 = did("2");
77 private DeviceId did3 = did("3");
78 private DeviceId did4 = did("4");
79
80 // Meter ids used during the tests
81 private MeterId mid1 = MeterId.meterId(1);
82 private MeterId mid2 = MeterId.meterId(2);
83
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());
125 TestUtils.setField(meterStore, "clusterService", new TestClusterService());
126 TestUtils.setField(meterStore, "mastershipService", new TestMastershipService());
127 TestUtils.setField(meterStore, "driverService", new TestDriverService());
128 // Activate the store
129 meterStore.activate();
130 }
131
132 @After
133 public void tearDown() {
134 // Deactivate the store
135 meterStore.deactivate();
136 }
137
138 private void initMeterStore() {
139 // Let's store feature for device 1
140 meterStore.storeMeterFeatures(mef1);
141 // Let's store feature for device 2
142 meterStore.storeMeterFeatures(mef2);
143 }
144
145 /**
146 * Test proper store of meter features.
147 */
148 @Test
149 public void testStoreMeterFeatures() {
150 // Let's store feature for device 1
151 meterStore.storeMeterFeatures(mef1);
152 // Verify store meter features
153 assertThat(meterStore.getMaxMeters(MeterFeaturesKey.key(did1)), is(3L));
154 // Let's store feature for device 1
155 meterStore.storeMeterFeatures(mef2);
156 // Verify store meter features
157 assertThat(meterStore.getMaxMeters(MeterFeaturesKey.key(did2)), is(10L));
158 }
159
160 /**
161 * Test proper delete of meter features.
162 */
163 @Test
164 public void testDeleteMeterFeatures() {
165 // Let's store feature for device 1
166 meterStore.storeMeterFeatures(mef1);
167 // Verify store meter features
168 assertThat(meterStore.getMaxMeters(MeterFeaturesKey.key(did1)), is(3L));
169 // Let's delete the features
170 meterStore.deleteMeterFeatures(did1);
171 // Verify delete meter features
172 assertThat(meterStore.getMaxMeters(MeterFeaturesKey.key(did1)), is(0L));
173 }
174
175 /**
176 * Test proper allocation of meter ids.
177 */
178 @Test
179 public void testAllocateId() {
180 // Init the store
181 initMeterStore();
182 // Allocate a meter id and verify is equal to mid1
183 assertThat(mid1, is(meterStore.allocateMeterId(did1)));
184 // Allocate a meter id and verify is equal to mid2
185 assertThat(mid2, is(meterStore.allocateMeterId(did1)));
186 }
187
188 /**
189 * Test proper free of meter ids.
190 */
191 @Test
192 public void testFreeId() {
193 // Init the store
194 initMeterStore();
195 // Allocate a meter id and verify is equal to mid1
196 assertThat(mid1, is(meterStore.allocateMeterId(did1)));
197 // Free the above id
198 meterStore.freeMeterId(did1, mid1);
199 // Allocate a meter id and verify is equal to mid1
200 assertThat(mid1, is(meterStore.allocateMeterId(did1)));
201 }
202
203 /**
204 * Test proper reuse of meter ids.
205 */
206 @Test
207 public void testReuseId() {
208 // Init the store
209 initMeterStore();
210 // Reserve id 1
211 MeterId meterIdOne = meterStore.allocateMeterId(did2);
212 // Free the above id
213 meterStore.freeMeterId(did2, meterIdOne);
214 // Start an async reservation
215 CompletableFuture<MeterId> future = CompletableFuture.supplyAsync(
216 () -> meterStore.allocateMeterId(did2)
217 );
218 // Start another reservation
219 MeterId meterIdTwo = meterStore.allocateMeterId(did2);
220 try {
221 meterIdOne = future.get();
222 } catch (InterruptedException | ExecutionException e) {
223 e.printStackTrace();
224 }
225 // Ids should be different, otherwise we had clash in the store
226 assertNotEquals("Ids should be different", meterIdOne, meterIdTwo);
227
228 // Free the above id
229 meterStore.freeMeterId(did1, meterIdOne);
230 // Free the above id
231 meterStore.freeMeterId(did1, meterIdTwo);
232 // Reserve id 1
233 meterIdOne = meterStore.allocateMeterId(did2);
234 // Reserve id 2
235 meterStore.allocateMeterId(did2);
236 // Reserve id 3
237 MeterId meterIdThree = meterStore.allocateMeterId(did2);
238 // Reserve id 4
239 MeterId meterIdFour = meterStore.allocateMeterId(did2);
240 // Free the above id
241 meterStore.freeMeterId(did1, meterIdOne);
242 // Free the above id
243 meterStore.freeMeterId(did1, meterIdThree);
244 // Free the above id
245 meterStore.freeMeterId(did1, meterIdFour);
246 // Start an async reservation
247 future = CompletableFuture.supplyAsync(
248 () -> meterStore.allocateMeterId(did2)
249 );
250 // Start another reservation
251 MeterId meterAnotherId = meterStore.allocateMeterId(did2);
252 try {
253 meterAnotherId = future.get();
254 } catch (InterruptedException | ExecutionException e) {
255 e.printStackTrace();
256 }
257 // Ids should be different, otherwise we had clash in the store
258 assertNotEquals("Ids should be different", meterAnotherId, meterIdOne);
259 }
260
261 /**
262 * Test query meters mechanism.
263 */
264 @Test
265 public void testQueryMeters() {
266 // Init the store
267 initMeterStore();
268 // Let's test queryMeters
269 assertThat(mid1, is(meterStore.allocateMeterId(did3)));
270 // Let's test queryMeters error
271 assertNull(meterStore.allocateMeterId(did4));
272 }
273
274 /**
275 * Test max meter error.
276 */
277 @Test
278 public void testMaxMeterError() {
279 // Init the store
280 initMeterStore();
281 // Reserve id 1
282 assertThat(mid1, is(meterStore.allocateMeterId(did1)));
283 // Reserve id 2
284 assertThat(mid2, is(meterStore.allocateMeterId(did1)));
285 // Max meter error
286 assertNull(meterStore.allocateMeterId(did1));
287 }
288
289 /**
290 * Test store meter.
291 */
292 @Test
293 public void testStoreMeter() {
294 // Init the store
295 initMeterStore();
296 // Simulate the allocation of an id
297 MeterId idOne = meterStore.allocateMeterId(did1);
298 // Verify the allocation
299 assertThat(mid1, is(idOne));
300 // Let's create a meter
301 Meter meterOne = DefaultMeter.builder()
302 .forDevice(did1)
303 .fromApp(APP_ID)
304 .withId(mid1)
305 .withUnit(Meter.Unit.KB_PER_SEC)
306 .withBands(Collections.singletonList(b1))
307 .build();
308 // Set the state
309 ((DefaultMeter) meterOne).setState(MeterState.PENDING_ADD);
310 // Store the meter
311 meterStore.storeMeter(meterOne);
312 // Let's create meter key
313 MeterKey meterKey = MeterKey.key(did1, mid1);
314 // Verify the store
315 assertThat(1, is(meterStore.getAllMeters().size()));
316 assertThat(1, is(meterStore.getAllMeters(did1).size()));
317 assertThat(m1, is(meterStore.getMeter(meterKey)));
318 }
319
320 /**
321 * Test delete meter.
322 */
323 @Test
324 public void testDeleteMeter() {
325 // Init the store
326 initMeterStore();
327 // Simulate the allocation of an id
328 MeterId idOne = meterStore.allocateMeterId(did1);
329 // Verify the allocation
330 assertThat(mid1, is(idOne));
331 // Let's create a meter
332 Meter meterOne = DefaultMeter.builder()
333 .forDevice(did1)
334 .fromApp(APP_ID)
335 .withId(mid1)
336 .withUnit(Meter.Unit.KB_PER_SEC)
337 .withBands(Collections.singletonList(b1))
338 .build();
339 // Set the state
340 ((DefaultMeter) meterOne).setState(MeterState.PENDING_ADD);
341 // Store the meter
342 meterStore.storeMeter(meterOne);
343 // Set the state
344 ((DefaultMeter) meterOne).setState(MeterState.PENDING_REMOVE);
345 // Let's create meter key
346 MeterKey meterKey = MeterKey.key(did1, mid1);
347 // Delete meter
348 meterStore.deleteMeter(meterOne);
349 // Start an async delete, simulating the operation of the provider
350 CompletableFuture<Void> future = CompletableFuture.runAsync(
351 () -> meterStore.deleteMeterNow(meterOne)
352 );
353 // Let's wait
354 try {
355 future.get();
356 } catch (InterruptedException | ExecutionException e) {
357 e.printStackTrace();
358 }
359 // Verify delete
360 assertThat(0, is(meterStore.getAllMeters().size()));
361 assertThat(0, is(meterStore.getAllMeters(did1).size()));
362 assertNull(meterStore.getMeter(meterKey));
363 assertThat(mid1, is(meterStore.allocateMeterId(did1)));
364 }
365
366 /**
367 * Test no delete meter.
368 */
369 @Test
370 public void testNoDeleteMeter() {
371 // Init the store
372 initMeterStore();
373 // Simulate the allocation of an id
374 MeterId idOne = meterStore.allocateMeterId(did1);
375 // Create the key
376 MeterKey keyOne = MeterKey.key(did1, idOne);
377 // Let's create a meter
378 Meter meterOne = DefaultMeter.builder()
379 .forDevice(did1)
380 .fromApp(APP_ID)
381 .withId(mid1)
382 .withUnit(Meter.Unit.KB_PER_SEC)
383 .withBands(Collections.singletonList(b1))
384 .build();
385 // Set the state
386 ((DefaultMeter) meterOne).setState(MeterState.PENDING_REMOVE);
387 // Delete meter
388 meterStore.deleteMeter(meterOne);
389 // Verify No delete
390 assertThat(0, is(meterStore.getAllMeters().size()));
391 assertThat(0, is(meterStore.getAllMeters(did1).size()));
392 assertNull(meterStore.getMeter(keyOne));
393 }
394
395 // Test cluster service
396 private final class TestClusterService extends ClusterServiceAdapter {
397
398 private ControllerNode local = new DefaultControllerNode(NID_LOCAL, LOCALHOST);
399
400 @Override
401 public ControllerNode getLocalNode() {
402 return local;
403 }
404
405 @Override
406 public Set<ControllerNode> getNodes() {
407 return Sets.newHashSet();
408 }
409
410 }
411
412 // Test mastership service
413 private final class TestMastershipService extends MastershipServiceAdapter {
414 @Override
415 public NodeId getMasterFor(DeviceId deviceId) {
416 return NID_LOCAL;
417 }
418 }
419
420 // Test class for driver service.
421 private class TestDriverService extends DriverServiceAdapter {
422 @Override
423 public DriverHandler createHandler(DeviceId deviceId, String... credentials) {
424 return deviceId.equals(did3) ? new TestDriverHandler() : null;
425 }
426 }
427
428 // Test class for driver handler.
429 private class TestDriverHandler implements DriverHandler {
430
431 @Override
432 public Driver driver() {
433 return null;
434 }
435
436 @Override
437 public DriverData data() {
438 return null;
439 }
440
441 @Override
442 @SuppressWarnings("unchecked")
443 public <T extends Behaviour> T behaviour(Class<T> behaviourClass) {
444 return (T) new TestMeterQuery();
445 }
446
447 @Override
448 public <T> T get(Class<T> serviceClass) {
449 return null;
450 }
451
452 @Override
453 public boolean hasBehaviour(Class<? extends Behaviour> behaviourClass) {
454 return true;
455 }
456 }
457
458 // Test meter query
459 private class TestMeterQuery implements MeterQuery {
460
461 @Override
462 public DriverData data() {
463 return null;
464 }
465
466 @Override
467 public void setData(DriverData data) {
468
469 }
470 @Override
471 public DriverHandler handler() {
472 return null;
473 }
474
475 @Override
476 public void setHandler(DriverHandler handler) {
477
478 }
479
480 @Override
481 public long getMaxMeters() {
482 return 100;
483 }
484 }
485
486}