blob: 88a11771f270d0f055942180760621dddbcb413f [file] [log] [blame]
Jonathan Hartdeda0ba2014-04-03 11:14:12 -07001package net.onrc.onos.core.registry;
Naoki Shiotad00accf2013-06-25 14:40:37 -07002
Jonathan Harta88fd242014-04-03 11:24:54 -07003import static org.junit.Assert.assertEquals;
4import static org.junit.Assert.assertFalse;
5import static org.junit.Assert.assertNotEquals;
6import static org.junit.Assert.assertNotNull;
7import static org.junit.Assert.assertNull;
8import static org.junit.Assert.assertTrue;
9import static org.junit.Assert.fail;
Naoki Shiotad00accf2013-06-25 14:40:37 -070010
11import java.util.ArrayList;
12import java.util.Collection;
13import java.util.LinkedList;
14import java.util.List;
15import java.util.Map;
16import java.util.concurrent.CountDownLatch;
17import java.util.concurrent.TimeUnit;
18
19import net.floodlightcontroller.core.module.FloodlightModuleContext;
Jonathan Hartdeda0ba2014-04-03 11:14:12 -070020import net.onrc.onos.core.registry.IControllerRegistryService.ControlChangeCallback;
Pavlin Radoslavov53b208a2014-07-28 13:16:11 -070021import net.onrc.onos.core.util.OnosInstanceId;
Naoki Shiotad00accf2013-06-25 14:40:37 -070022
23import org.junit.After;
24import org.junit.Before;
25import org.junit.Ignore;
26import org.junit.Test;
27import org.openflow.util.HexString;
Yuta HIGUCHI44a0b352014-05-14 21:32:48 -070028import org.slf4j.Logger;
29import org.slf4j.LoggerFactory;
Naoki Shiotad00accf2013-06-25 14:40:37 -070030
31/**
Naoki Shiotaa3b2dfa2013-06-27 13:52:24 -070032 * Unit test for {@link StandaloneRegistry}.
Naoki Shiotad00accf2013-06-25 14:40:37 -070033 */
34public class StandaloneRegistryTest {
Yuta HIGUCHI44a0b352014-05-14 21:32:48 -070035
36 private static final Logger log = LoggerFactory.getLogger(StandaloneRegistryTest.class);
37
Ray Milkey269ffb92014-04-03 14:43:30 -070038 protected static final long TIMEOUT_MSEC = 1000;
Naoki Shiotad00accf2013-06-25 14:40:37 -070039
Ray Milkey269ffb92014-04-03 14:43:30 -070040 protected StandaloneRegistry registry;
Naoki Shiotad00accf2013-06-25 14:40:37 -070041
Ray Milkey269ffb92014-04-03 14:43:30 -070042 /**
43 * Implementation of {@link ControlChangeCallback} which defines callback interfaces called by Registry.
44 * This class remembers past callback parameters and provides methods to access them.
45 * This class also provides CountDownLatch so one can wait until the callback be called
46 * specific times (specified by constructor parameter). Particularly, the first time callback
47 * called is supposed for registration, this class has an independent latch to wait for
48 * the first callback.
Ray Milkey269ffb92014-04-03 14:43:30 -070049 */
50 public static class LoggingCallback implements ControlChangeCallback {
51 private LinkedList<Long> dpidsCalledback = new LinkedList<Long>();
52 private LinkedList<Boolean> controlsCalledback = new LinkedList<Boolean>();
53 private CountDownLatch lock = null, registerLock = null;
Yuta HIGUCHI44a0b352014-05-14 21:32:48 -070054
Ray Milkey269ffb92014-04-03 14:43:30 -070055
56 /**
57 * Constructor with number of times callback to be called.
58 *
59 * @param numberToCall Number of times expected callback to be called
60 */
61 public LoggingCallback(int numberToCall) {
62 lock = new CountDownLatch(numberToCall);
63 registerLock = new CountDownLatch(1);
64 }
65
66 /**
67 * Wait until registration is finished (callback is called for the first time).
68 *
69 * @throws InterruptedException
70 */
71 public void waitForRegistration() throws InterruptedException {
72 registerLock.await();
73 }
74
75 /**
76 * Wait for registration specifying timeout.
77 *
78 * @param msec Milliseconds to timeout
79 * @throws InterruptedException
80 */
81 public void waitForRegistration(long msec) throws InterruptedException {
82 registerLock.await(msec, TimeUnit.MILLISECONDS);
83 }
84
85 /**
86 * Wait until callback is called specific times.
87 *
88 * @throws InterruptedException
89 */
90 public void waitUntilCalled() throws InterruptedException {
91 lock.await();
92 }
93
94 /**
95 * Wait until callback is called specific times, specifying timeout.
96 *
97 * @param msec Milliseconds to timeout
98 * @throws InterruptedException
99 */
100 public void waitUntilCalled(long msec) throws InterruptedException {
101 lock.await(msec, TimeUnit.MILLISECONDS);
102 }
103
104 /**
105 * Get DPID parameter given by specific callback time.
106 *
107 * @param index Specify which time to get parameter
108 * @return DPID value by number.
109 */
110 public Long getDpid(int index) {
111 return dpidsCalledback.get(index);
112 }
113
114 /**
115 * Get hasControl parameter given by specific callback time.
116 *
117 * @param index Specify which time to get parameter
118 * @return hasControl value
119 */
120 public Boolean getControl(int index) {
121 return controlsCalledback.get(index);
122 }
123
124 /**
125 * Get DPID parameter given by latest call.
126 *
127 * @return DPID value by number
128 */
129 public Long getLatestDpid() {
130 return dpidsCalledback.peekLast();
131 }
132
133 /**
Yuta HIGUCHI44a0b352014-05-14 21:32:48 -0700134 * Get hasControl parameter given by latest call.
Ray Milkey269ffb92014-04-03 14:43:30 -0700135 *
136 * @return hasControl value
137 */
138 public Boolean getLatestControl() {
139 return controlsCalledback.peekLast();
140 }
141
142 @Override
143 public void controlChanged(long dpid, boolean hasControl) {
144 dpidsCalledback.addLast(dpid);
145 controlsCalledback.addLast(hasControl);
146
147 lock.countDown();
148 registerLock.countDown();
149 }
150 }
151
Yuta HIGUCHI44a0b352014-05-14 21:32:48 -0700152
Ray Milkey269ffb92014-04-03 14:43:30 -0700153
154 @Before
155 public void setUp() throws Exception {
Naoki Shiotad00accf2013-06-25 14:40:37 -0700156 FloodlightModuleContext fmc = new FloodlightModuleContext();
Ray Milkey269ffb92014-04-03 14:43:30 -0700157 registry = new StandaloneRegistry();
158 registry.init(fmc);
159 }
Naoki Shiotad00accf2013-06-25 14:40:37 -0700160
Ray Milkey269ffb92014-04-03 14:43:30 -0700161 @After
162 public void tearDown() {
163 }
Naoki Shiotad00accf2013-06-25 14:40:37 -0700164
Ray Milkey269ffb92014-04-03 14:43:30 -0700165 /**
166 * Test if {@link StandaloneRegistry#registerController(String)} can run without error.
167 */
168 @Test
169 public void testRegisterController() {
170 String controllerIdToRegister = "test";
171 try {
172 registry.registerController(controllerIdToRegister);
173 } catch (RegistryException e) {
174 e.printStackTrace();
175 fail(e.getMessage());
176 }
Naoki Shiotad00accf2013-06-25 14:40:37 -0700177
Ray Milkey269ffb92014-04-03 14:43:30 -0700178 // Register Controller ID doubly
179 try {
180 registry.registerController(controllerIdToRegister);
181 fail("Double registration goes through without exception");
182 } catch (RegistryException e) {
183 // expected behavior
Yuta HIGUCHI44a0b352014-05-14 21:32:48 -0700184 log.debug("Exception thrown as expected", e);
Ray Milkey269ffb92014-04-03 14:43:30 -0700185 }
186 }
Naoki Shiotad00accf2013-06-25 14:40:37 -0700187
Ray Milkey269ffb92014-04-03 14:43:30 -0700188 /**
Pavlin Radoslavov53b208a2014-07-28 13:16:11 -0700189 * Test if {@link StandaloneRegistry#getOnosInstanceId()} can return
190 * correct ID.
Ray Milkey269ffb92014-04-03 14:43:30 -0700191 *
192 * @throws RegistryException
193 */
194 @Test
Pavlin Radoslavov53b208a2014-07-28 13:16:11 -0700195 public void testGetOnosInstanceId() throws RegistryException {
Ray Milkey269ffb92014-04-03 14:43:30 -0700196 String controllerIdToRegister = "test";
Naoki Shiotad00accf2013-06-25 14:40:37 -0700197
Ray Milkey269ffb92014-04-03 14:43:30 -0700198 // try before controller is registered
Pavlin Radoslavov53b208a2014-07-28 13:16:11 -0700199 OnosInstanceId onosInstanceId = registry.getOnosInstanceId();
200 assertNull(onosInstanceId);
Naoki Shiotad00accf2013-06-25 14:40:37 -0700201
Ray Milkey269ffb92014-04-03 14:43:30 -0700202 // register
203 registry.registerController(controllerIdToRegister);
Naoki Shiotad00accf2013-06-25 14:40:37 -0700204
Pavlin Radoslavov53b208a2014-07-28 13:16:11 -0700205 // call getOnosInstanceId and verify
206 onosInstanceId = registry.getOnosInstanceId();
207 assertNotNull(onosInstanceId);
208 assertEquals(controllerIdToRegister, onosInstanceId.toString());
Ray Milkey269ffb92014-04-03 14:43:30 -0700209 }
Naoki Shiotad00accf2013-06-25 14:40:37 -0700210
Ray Milkey269ffb92014-04-03 14:43:30 -0700211 /**
212 * Test if {@link StandaloneRegistry#getAllControllers()} can return correct list of controllers.
213 *
214 * @throws RegistryException
215 */
216 @Test
217 public void testGetAllControllers() throws RegistryException {
218 String controllerIdToRegister = "test";
Naoki Shiotad00accf2013-06-25 14:40:37 -0700219
Ray Milkey269ffb92014-04-03 14:43:30 -0700220 // Test before register controller
221 try {
222 Collection<String> ctrls = registry.getAllControllers();
223 assertFalse(ctrls.contains(controllerIdToRegister));
224 } catch (RegistryException e) {
225 e.printStackTrace();
226 fail(e.getMessage());
227 }
Naoki Shiotad00accf2013-06-25 14:40:37 -0700228
Ray Milkey269ffb92014-04-03 14:43:30 -0700229 // register
230 registry.registerController(controllerIdToRegister);
Naoki Shiotad00accf2013-06-25 14:40:37 -0700231
Ray Milkey269ffb92014-04-03 14:43:30 -0700232 // Test after register controller
233 try {
234 Collection<String> ctrls = registry.getAllControllers();
235 assertTrue(ctrls.contains(controllerIdToRegister));
236 } catch (RegistryException e) {
237 e.printStackTrace();
238 fail(e.getMessage());
239 }
240 }
Naoki Shiotad00accf2013-06-25 14:40:37 -0700241
Ray Milkey269ffb92014-04-03 14:43:30 -0700242 /**
Yuta HIGUCHI91a8f502014-06-17 10:15:29 -0700243 * Test if {@link StandaloneRegistry#requestControl(long, ControlChangeCallback)}
244 * can correctly take control for switch so that callback is called.
Ray Milkey269ffb92014-04-03 14:43:30 -0700245 *
246 * @throws RegistryException
247 * @throws InterruptedException
248 */
249 @Test
250 public void testRequestControl() throws InterruptedException, RegistryException {
251 String controllerId = "test";
252 registry.registerController(controllerId);
Naoki Shiotad00accf2013-06-25 14:40:37 -0700253
Ray Milkey269ffb92014-04-03 14:43:30 -0700254 LoggingCallback callback = new LoggingCallback(1);
255 long dpidToRequest = 1000L;
Naoki Shiotad00accf2013-06-25 14:40:37 -0700256
Ray Milkey269ffb92014-04-03 14:43:30 -0700257 try {
258 registry.requestControl(dpidToRequest, callback);
259 } catch (RegistryException e) {
260 e.printStackTrace();
261 fail(e.getMessage());
262 }
Naoki Shiotad00accf2013-06-25 14:40:37 -0700263
Ray Milkey269ffb92014-04-03 14:43:30 -0700264 callback.waitForRegistration();
Naoki Shiotad00accf2013-06-25 14:40:37 -0700265
Ray Milkey269ffb92014-04-03 14:43:30 -0700266 long dpidCallback = callback.getLatestDpid();
267 boolean controlCallback = callback.getLatestControl();
Naoki Shiotad00accf2013-06-25 14:40:37 -0700268
Ray Milkey269ffb92014-04-03 14:43:30 -0700269 assertEquals(dpidToRequest, dpidCallback);
270 assertTrue(controlCallback);
271 }
Naoki Shiotad00accf2013-06-25 14:40:37 -0700272
Ray Milkey269ffb92014-04-03 14:43:30 -0700273 /**
Yuta HIGUCHI91a8f502014-06-17 10:15:29 -0700274 * Test if {@link StandaloneRegistry#releaseControl(long)}
275 * can correctly release the control so that callback is called.
Ray Milkey269ffb92014-04-03 14:43:30 -0700276 *
277 * @throws InterruptedException
278 * @throws RegistryException
279 */
280 @Test
281 public void testReleaseControl() throws InterruptedException, RegistryException {
282 String controllerId = "test";
283 registry.registerController(controllerId);
Naoki Shiotad00accf2013-06-25 14:40:37 -0700284
Ray Milkey269ffb92014-04-03 14:43:30 -0700285 long dpidToRequest = 1000L;
286 LoggingCallback callback = new LoggingCallback(2);
Naoki Shiotad00accf2013-06-25 14:40:37 -0700287
Ray Milkey269ffb92014-04-03 14:43:30 -0700288 // to request and wait to take control
289 registry.requestControl(dpidToRequest, callback);
290 callback.waitForRegistration();
Naoki Shiotad00accf2013-06-25 14:40:37 -0700291
Ray Milkey269ffb92014-04-03 14:43:30 -0700292 registry.releaseControl(dpidToRequest);
Naoki Shiotad00accf2013-06-25 14:40:37 -0700293
Ray Milkey269ffb92014-04-03 14:43:30 -0700294 // verify
295 callback.waitUntilCalled();
296 assertEquals(dpidToRequest, (long) callback.getLatestDpid());
297 assertFalse(callback.getLatestControl());
298 }
Naoki Shiotad00accf2013-06-25 14:40:37 -0700299
Ray Milkey269ffb92014-04-03 14:43:30 -0700300 /**
301 * Test if {@link StandaloneRegistry#hasControl(long)} returns correct status.
302 *
303 * @throws InterruptedException
304 * @throws RegistryException
305 */
306 @Test
307 public void testHasControl() throws InterruptedException, RegistryException {
308 String controllerId = "test";
309 registry.registerController(controllerId);
Naoki Shiotad00accf2013-06-25 14:40:37 -0700310
Ray Milkey269ffb92014-04-03 14:43:30 -0700311 long dpidToRequest = 1000L;
312 LoggingCallback callback = new LoggingCallback(2);
Naoki Shiotad00accf2013-06-25 14:40:37 -0700313
Ray Milkey269ffb92014-04-03 14:43:30 -0700314 // Test before request control
315 assertFalse(registry.hasControl(dpidToRequest));
Naoki Shiotad00accf2013-06-25 14:40:37 -0700316
Ray Milkey269ffb92014-04-03 14:43:30 -0700317 registry.requestControl(dpidToRequest, callback);
318 callback.waitForRegistration();
Naoki Shiotad00accf2013-06-25 14:40:37 -0700319
Ray Milkey269ffb92014-04-03 14:43:30 -0700320 // Test after take control
321 assertTrue(registry.hasControl(dpidToRequest));
Naoki Shiotad00accf2013-06-25 14:40:37 -0700322
Ray Milkey269ffb92014-04-03 14:43:30 -0700323 registry.releaseControl(dpidToRequest);
324
325 callback.waitUntilCalled();
326
327 // Test after release control
328 assertFalse(registry.hasControl(dpidToRequest));
329 }
330
331 /**
332 * Test if {@link StandaloneRegistry#getControllerForSwitch(long)} returns correct controller ID.
333 *
334 * @throws InterruptedException
335 * @throws RegistryException
336 */
337 @Test
338 public void testGetControllerForSwitch() throws InterruptedException, RegistryException {
339 String controllerId = "test";
340 registry.registerController(controllerId);
341
342 long dpidToRequest = 1000L;
343 LoggingCallback callback = new LoggingCallback(2);
344
345 // Test before request control
346 try {
347 String controllerForSw = registry.getControllerForSwitch(dpidToRequest);
348 assertNotEquals(controllerId, controllerForSw);
349 } catch (RegistryException e) {
350 fail("Failed before request control : " + e.getMessage());
351 e.printStackTrace();
352 }
353
354 registry.requestControl(dpidToRequest, callback);
355 callback.waitForRegistration();
356
357 // Test after take control
358 try {
359 String controllerForSw = registry.getControllerForSwitch(dpidToRequest);
360 assertEquals(controllerId, controllerForSw);
361 } catch (RegistryException e) {
362 fail("Failed after take control : " + e.getMessage());
363 e.printStackTrace();
364 }
365
366 registry.releaseControl(dpidToRequest);
367 callback.waitUntilCalled();
368
369 // Test after release control
370 try {
371 String controllerForSw = registry.getControllerForSwitch(dpidToRequest);
372 assertNotEquals(controllerId, controllerForSw);
373 } catch (RegistryException e) {
374 fail("Failed after release control : " + e.getMessage());
375 e.printStackTrace();
376 }
377 }
378
379 /**
380 * Test if {@link StandaloneRegistry#getAllSwitches()} returns correct list of switches.
381 *
382 * @throws InterruptedException
383 * @throws RegistryException
384 */
385 @Test
386 public void testGetAllSwitches() throws InterruptedException, RegistryException {
387 String controllerId = "test";
388 registry.registerController(controllerId);
389
390 long dpidToRequest = 1000L;
391 String dpidToRequestStr = HexString.toHexString(dpidToRequest);
392 LoggingCallback callback = new LoggingCallback(2);
393
394 // Test before request control
395 Map<String, List<ControllerRegistryEntry>> switches = registry.getAllSwitches();
396 assertNotNull(switches);
397 assertFalse(switches.keySet().contains(dpidToRequestStr));
398
399 registry.requestControl(dpidToRequest, callback);
400 callback.waitForRegistration();
401
402 // Test after take control
403 switches = registry.getAllSwitches();
404 assertNotNull(switches);
405 assertTrue(switches.keySet().contains(dpidToRequestStr));
406 int count = 0;
407 for (ControllerRegistryEntry ctrl : switches.get(dpidToRequestStr)) {
408 if (ctrl.getControllerId().equals(controllerId)) {
409 ++count;
410 }
411 }
412 assertEquals(1, count);
413
414 registry.releaseControl(dpidToRequest);
415 callback.waitUntilCalled();
416
417 // Test after release control
418 switches = registry.getAllSwitches();
419 assertNotNull(switches);
420 assertFalse(switches.keySet().contains(dpidToRequestStr));
421 }
422
423 /**
424 * Test if {@link StandaloneRegistry#getSwitchesControlledByController(String)} returns correct list of switches.
425 *
426 * @throws InterruptedException
427 * @throws RegistryException
428 */
429 // TODO: remove @Ignore after implement StandaloneRegistry#getSwitchesControlledByController
430 @Ignore
431 @Test
432 public void testGetSwitchesControlledByController() throws InterruptedException, RegistryException {
433 String controllerId = "test";
434 registry.registerController(controllerId);
435
436 long dpidToRequest = 1000L;
437 String dpidToRequestStr = HexString.toHexString(dpidToRequest);
438 LoggingCallback callback = new LoggingCallback(2);
439
440 // Test before request control
441 Collection<Long> switches = registry.getSwitchesControlledByController(controllerId);
442 assertNotNull(switches);
443 assertFalse(switches.contains(dpidToRequestStr));
444
445 registry.requestControl(dpidToRequest, callback);
446 callback.waitForRegistration();
447
448 // Test after take control
449 switches = registry.getSwitchesControlledByController(controllerId);
450 assertNotNull(switches);
451 assertTrue(switches.contains(dpidToRequestStr));
452 int count = 0;
453 for (Long dpid : switches) {
Yuta HIGUCHI44a0b352014-05-14 21:32:48 -0700454 if (dpid == dpidToRequest) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700455 ++count;
456 }
457 }
458 assertEquals(1, count);
459
460 registry.releaseControl(dpidToRequest);
461 callback.waitUntilCalled();
462
463 // Test after release control
464 switches = registry.getSwitchesControlledByController(controllerId);
465 assertNotNull(switches);
466 assertFalse(switches.contains(dpidToRequestStr));
467 }
468
469 /**
470 * Test if {@link StandaloneRegistry#allocateUniqueIdBlock()} returns appropriate object.
471 * Get bulk of IdBlocks and check if they do have unique range of IDs.
472 */
473 @Test
474 public void testAllocateUniqueIdBlock() {
475 // Number of blocks to be verified that any of them has unique block
Yuta HIGUCHI91a8f502014-06-17 10:15:29 -0700476 final int numBlocks = 100;
477 ArrayList<IdBlock> blocks = new ArrayList<IdBlock>(numBlocks);
Ray Milkey269ffb92014-04-03 14:43:30 -0700478
Yuta HIGUCHI91a8f502014-06-17 10:15:29 -0700479 for (int i = 0; i < numBlocks; ++i) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700480 blocks.add(registry.allocateUniqueIdBlock());
481 }
482
Yuta HIGUCHI91a8f502014-06-17 10:15:29 -0700483 for (int i = 0; i < numBlocks; ++i) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700484 IdBlock block1 = blocks.get(i);
Yuta HIGUCHI91a8f502014-06-17 10:15:29 -0700485 for (int j = i + 1; j < numBlocks; ++j) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700486 IdBlock block2 = blocks.get(j);
487 IdBlock lower, higher;
488
489 if (block1.getStart() < block2.getStart()) {
490 lower = block1;
491 higher = block2;
492 } else {
493 lower = block2;
494 higher = block1;
495 }
496
497 assertTrue(lower.getSize() > 0L);
498 assertTrue(higher.getSize() > 0L);
499 assertTrue(lower.getEnd() < higher.getStart());
500 }
501 }
502 }
Naoki Shiotad00accf2013-06-25 14:40:37 -0700503}