blob: 38df94317a179c7e0cc8ec07f67c75a061fe0382 [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;
Naoki Shiotad00accf2013-06-25 14:40:37 -070021
22import org.junit.After;
23import org.junit.Before;
24import org.junit.Ignore;
25import org.junit.Test;
26import org.openflow.util.HexString;
27
28/**
Naoki Shiotaa3b2dfa2013-06-27 13:52:24 -070029 * Unit test for {@link StandaloneRegistry}.
Naoki Shiotad00accf2013-06-25 14:40:37 -070030 * @author Naoki Shiota
31 *
32 */
33public class StandaloneRegistryTest {
34 protected static final long TIMEOUT_MSEC = 1000;
35
36 protected StandaloneRegistry registry;
37
38 /**
Naoki Shiotaa3b2dfa2013-06-27 13:52:24 -070039 * Implementation of {@link ControlChangeCallback} which defines callback interfaces called by Registry.
Naoki Shiotad00accf2013-06-25 14:40:37 -070040 * This class remembers past callback parameters and provides methods to access them.
41 * This class also provides CountDownLatch so one can wait until the callback be called
Naoki Shiotaa3b2dfa2013-06-27 13:52:24 -070042 * specific times (specified by constructor parameter). Particularly, the first time callback
Naoki Shiotad00accf2013-06-25 14:40:37 -070043 * called is supposed for registration, this class has an independent latch to wait for
44 * the first callback.
45 * @author Naoki Shiota
Naoki Shiotad00accf2013-06-25 14:40:37 -070046 */
47 public static class LoggingCallback implements ControlChangeCallback {
48 private LinkedList<Long> dpidsCalledback = new LinkedList<Long>();
49 private LinkedList<Boolean> controlsCalledback = new LinkedList<Boolean>();
50 private CountDownLatch lock = null, registerLock = null;;
51
52 /**
53 * Constructor with number of times callback to be called.
54 * @param numberToCall Number of times expected callback to be called
55 */
56 public LoggingCallback(int numberToCall) {
57 lock = new CountDownLatch(numberToCall);
58 registerLock = new CountDownLatch(1);
59 }
60
61 /**
62 * Wait until registration is finished (callback is called for the first time).
63 * @throws InterruptedException
64 */
65 public void waitForRegistration() throws InterruptedException {
66 registerLock.await();
67 }
68
69 /**
70 * Wait for registration specifying timeout.
71 * @param msec Milliseconds to timeout
72 * @throws InterruptedException
73 */
74 public void waitForRegistration(long msec) throws InterruptedException {
75 registerLock.await(msec, TimeUnit.MILLISECONDS);
76 }
77
78 /**
79 * Wait until callback is called specific times.
80 * @throws InterruptedException
81 */
82 public void waitUntilCalled() throws InterruptedException {
83 lock.await();
84 }
85
86 /**
87 * Wait until callback is called specific times, specifying timeout.
88 * @param msec Milliseconds to timeout
89 * @throws InterruptedException
90 */
91 public void waitUntilCalled(long msec) throws InterruptedException {
92 lock.await(msec, TimeUnit.MILLISECONDS);
93 }
94
95 /**
96 * Get DPID parameter given by specific callback time.
97 * @param index Specify which time to get parameter
98 * @return DPID value by number.
99 */
100 public Long getDpid(int index) { return dpidsCalledback.get(index); }
101
102 /**
103 * Get hasControl parameter given by specific callback time.
104 * @param index Specify which time to get parameter
105 * @return hasControl value
106 */
107 public Boolean getControl(int index) { return controlsCalledback.get(index); }
108
109 /**
110 * Get DPID parameter given by latest call.
111 * @return DPID value by number
112 */
113 public Long getLatestDpid() { return dpidsCalledback.peekLast(); }
114
115 /**
116 * Get hasControl parameter given by latest call
117 * @return hasControl value
118 */
119 public Boolean getLatestControl() { return controlsCalledback.peekLast(); }
120
121 @Override
122 public void controlChanged(long dpid, boolean hasControl) {
123 dpidsCalledback.addLast(dpid);
124 controlsCalledback.addLast(hasControl);
125
126 lock.countDown();
127 registerLock.countDown();
128 }
129 };
130
131 @Before
132 public void setUp() throws Exception {
133 FloodlightModuleContext fmc = new FloodlightModuleContext();
134 registry = new StandaloneRegistry();
135 registry.init(fmc);
136 }
137
138 @After
139 public void tearDown() {
140 }
141
142 /**
Naoki Shiotaa3b2dfa2013-06-27 13:52:24 -0700143 * Test if {@link StandaloneRegistry#registerController(String)} can run without error.
Naoki Shiotad00accf2013-06-25 14:40:37 -0700144 */
145 @Test
146 public void testRegisterController() {
147 String controllerIdToRegister = "test";
148 try {
149 registry.registerController(controllerIdToRegister);
150 } catch (RegistryException e) {
151 e.printStackTrace();
152 fail(e.getMessage());
153 }
154
155 // Register Controller ID doubly
156 try {
157 registry.registerController(controllerIdToRegister);
158 fail("Double registration goes through without exception");
159 } catch (RegistryException e) {
160 // expected behavior
161 }
162 }
163
164 /**
Naoki Shiotaa3b2dfa2013-06-27 13:52:24 -0700165 * Test if {@link StandaloneRegistry#getControllerId()} can return correct ID.
Naoki Shiotad00accf2013-06-25 14:40:37 -0700166 * @throws RegistryException
167 */
168 @Test
169 public void testGetControllerId() throws RegistryException {
170 String controllerIdToRegister = "test";
171
172 // try before controller is registered
173 String controllerId = registry.getControllerId();
174 assertNull(controllerId);
175
176 // register
177 registry.registerController(controllerIdToRegister);
178
179 // call getControllerId and verify
180 controllerId = registry.getControllerId();
181 assertNotNull(controllerId);
182 assertEquals(controllerIdToRegister, controllerId);
183 }
184
185 /**
Naoki Shiotaa3b2dfa2013-06-27 13:52:24 -0700186 * Test if {@link StandaloneRegistry#getAllControllers()} can return correct list of controllers.
Naoki Shiotad00accf2013-06-25 14:40:37 -0700187 * @throws RegistryException
188 */
189 @Test
190 public void testGetAllControllers() throws RegistryException {
191 String controllerIdToRegister = "test";
192
193 // Test before register controller
194 try {
195 Collection<String> ctrls = registry.getAllControllers();
196 assertFalse(ctrls.contains(controllerIdToRegister));
197 } catch (RegistryException e) {
198 e.printStackTrace();
199 fail(e.getMessage());
200 }
201
202 // register
203 registry.registerController(controllerIdToRegister);
204
205 // Test after register controller
206 try {
207 Collection<String> ctrls = registry.getAllControllers();
208 assertTrue(ctrls.contains(controllerIdToRegister));
209 } catch (RegistryException e) {
210 e.printStackTrace();
211 fail(e.getMessage());
212 }
213 }
214
215 /**
Naoki Shiotaa3b2dfa2013-06-27 13:52:24 -0700216 * Test if {@link StandaloneRegistry#requestControl(long, ControlChangeCallback)} can correctly take control for switch so that callback is called.
Naoki Shiotad00accf2013-06-25 14:40:37 -0700217 * @throws RegistryException
218 * @throws InterruptedException
219 */
220 @Test
221 public void testRequestControl() throws InterruptedException, RegistryException {
222 String controllerId = "test";
223 registry.registerController(controllerId);
224
225 LoggingCallback callback = new LoggingCallback(1);
226 long dpidToRequest = 1000L;
227
228 try {
229 registry.requestControl(dpidToRequest, callback);
230 } catch (RegistryException e) {
231 e.printStackTrace();
232 fail(e.getMessage());
233 }
234
235 callback.waitForRegistration();
236
237 long dpidCallback = callback.getLatestDpid();
238 boolean controlCallback = callback.getLatestControl();
239
240 assertEquals(dpidToRequest, dpidCallback);
241 assertTrue(controlCallback);
242 }
243
244 /**
Naoki Shiotaa3b2dfa2013-06-27 13:52:24 -0700245 * Test if {@link StandaloneRegistry#releaseControl(long)} can correctly release the control so that callback is called.
Naoki Shiotad00accf2013-06-25 14:40:37 -0700246 * @throws InterruptedException
247 * @throws RegistryException
248 */
249 @Test
250 public void testReleaseControl() throws InterruptedException, RegistryException {
251 String controllerId = "test";
252 registry.registerController(controllerId);
253
254 long dpidToRequest = 1000L;
255 LoggingCallback callback = new LoggingCallback(2);
256
257 // to request and wait to take control
258 registry.requestControl(dpidToRequest, callback);
259 callback.waitForRegistration();
260
261 registry.releaseControl(dpidToRequest);
262
263 // verify
264 callback.waitUntilCalled();
265 assertEquals(dpidToRequest, (long)callback.getLatestDpid());
266 assertFalse(callback.getLatestControl());
267 }
268
269 /**
Naoki Shiotaa3b2dfa2013-06-27 13:52:24 -0700270 * Test if {@link StandaloneRegistry#hasControl(long)} returns correct status.
Naoki Shiotad00accf2013-06-25 14:40:37 -0700271 * @throws InterruptedException
272 * @throws RegistryException
273 */
274 @Test
275 public void testHasControl() throws InterruptedException, RegistryException {
276 String controllerId = "test";
277 registry.registerController(controllerId);
278
279 long dpidToRequest = 1000L;
280 LoggingCallback callback = new LoggingCallback(2);
281
282 // Test before request control
283 assertFalse(registry.hasControl(dpidToRequest));
284
285 registry.requestControl(dpidToRequest, callback);
286 callback.waitForRegistration();
287
288 // Test after take control
289 assertTrue(registry.hasControl(dpidToRequest));
290
291 registry.releaseControl(dpidToRequest);
292
293 callback.waitUntilCalled();
294
295 // Test after release control
296 assertFalse(registry.hasControl(dpidToRequest));
297 }
298
299 /**
Naoki Shiotaa3b2dfa2013-06-27 13:52:24 -0700300 * Test if {@link StandaloneRegistry#getControllerForSwitch(long)} returns correct controller ID.
Naoki Shiotad00accf2013-06-25 14:40:37 -0700301 * @throws InterruptedException
302 * @throws RegistryException
303 */
304 @Test
305 public void testGetControllerForSwitch() throws InterruptedException, RegistryException {
306 String controllerId = "test";
307 registry.registerController(controllerId);
308
309 long dpidToRequest = 1000L;
310 LoggingCallback callback = new LoggingCallback(2);
311
312 // Test before request control
313 try {
314 String controllerForSw = registry.getControllerForSwitch(dpidToRequest);
315 assertNotEquals(controllerId,controllerForSw);
316 } catch (RegistryException e) {
317 fail("Failed before request control : " + e.getMessage());
318 e.printStackTrace();
319 }
320
321 registry.requestControl(dpidToRequest, callback);
322 callback.waitForRegistration();
323
324 // Test after take control
325 try {
326 String controllerForSw = registry.getControllerForSwitch(dpidToRequest);
327 assertEquals(controllerId,controllerForSw);
328 } catch (RegistryException e) {
329 fail("Failed after take control : " + e.getMessage());
330 e.printStackTrace();
331 }
332
333 registry.releaseControl(dpidToRequest);
334 callback.waitUntilCalled();
335
336 // Test after release control
337 try {
338 String controllerForSw = registry.getControllerForSwitch(dpidToRequest);
339 assertNotEquals(controllerId,controllerForSw);
340 } catch (RegistryException e) {
341 fail("Failed after release control : " + e.getMessage());
342 e.printStackTrace();
343 }
344 }
345
346 /**
Naoki Shiotaa3b2dfa2013-06-27 13:52:24 -0700347 * Test if {@link StandaloneRegistry#getAllSwitches()} returns correct list of switches.
Naoki Shiotad00accf2013-06-25 14:40:37 -0700348 * @throws InterruptedException
349 * @throws RegistryException
350 */
351 @Test
352 public void testGetAllSwitches() throws InterruptedException, RegistryException {
353 String controllerId = "test";
354 registry.registerController(controllerId);
355
356 long dpidToRequest = 1000L;
357 String dpidToRequestStr = HexString.toHexString(dpidToRequest);
358 LoggingCallback callback = new LoggingCallback(2);
359
360 // Test before request control
361 Map<String, List<ControllerRegistryEntry>> switches = registry.getAllSwitches();
362 assertNotNull(switches);
363 assertFalse(switches.keySet().contains(dpidToRequestStr));
364
365 registry.requestControl(dpidToRequest, callback);
366 callback.waitForRegistration();
367
368 // Test after take control
369 switches = registry.getAllSwitches();
370 assertNotNull(switches);
371 assertTrue(switches.keySet().contains(dpidToRequestStr));
372 int count = 0;
373 for(ControllerRegistryEntry ctrl : switches.get(dpidToRequestStr)) {
374 if(ctrl.getControllerId().equals(controllerId)) {
375 ++count;
376 }
377 }
378 assertEquals(1,count);
379
380 registry.releaseControl(dpidToRequest);
381 callback.waitUntilCalled();
382
383 // Test after release control
384 switches = registry.getAllSwitches();
385 assertNotNull(switches);
386 assertFalse(switches.keySet().contains(dpidToRequestStr));
387 }
388
389 /**
Naoki Shiotaa3b2dfa2013-06-27 13:52:24 -0700390 * Test if {@link StandaloneRegistry#getSwitchesControlledByController(String)} returns correct list of switches.
Naoki Shiotad00accf2013-06-25 14:40:37 -0700391 * @throws InterruptedException
392 * @throws RegistryException
393 */
394 // TODO: remove @Ignore after implement StandaloneRegistry#getSwitchesControlledByController
395 @Ignore @Test
396 public void testGetSwitchesControlledByController() throws InterruptedException, RegistryException {
397 String controllerId = "test";
398 registry.registerController(controllerId);
399
400 long dpidToRequest = 1000L;
401 String dpidToRequestStr = HexString.toHexString(dpidToRequest);
402 LoggingCallback callback = new LoggingCallback(2);
403
404 // Test before request control
405 Collection<Long> switches = registry.getSwitchesControlledByController(controllerId);
406 assertNotNull(switches);
407 assertFalse(switches.contains(dpidToRequestStr));
408
409 registry.requestControl(dpidToRequest, callback);
410 callback.waitForRegistration();
411
412 // Test after take control
413 switches = registry.getSwitchesControlledByController(controllerId);
414 assertNotNull(switches);
415 assertTrue(switches.contains(dpidToRequestStr));
416 int count = 0;
417 for(Long dpid : switches) {
418 if((long)dpid == dpidToRequest) {
419 ++count;
420 }
421 }
422 assertEquals(1, count);
423
424 registry.releaseControl(dpidToRequest);
425 callback.waitUntilCalled();
426
427 // Test after release control
428 switches = registry.getSwitchesControlledByController(controllerId);
429 assertNotNull(switches);
430 assertFalse(switches.contains(dpidToRequestStr));
431 }
432
433 /**
Naoki Shiotaa3b2dfa2013-06-27 13:52:24 -0700434 * Test if {@link StandaloneRegistry#allocateUniqueIdBlock()} returns appropriate object.
435 * Get bulk of IdBlocks and check if they do have unique range of IDs.
Naoki Shiotad00accf2013-06-25 14:40:37 -0700436 */
437 @Test
438 public void testAllocateUniqueIdBlock() {
439 // Number of blocks to be verified that any of them has unique block
440 final int NUM_BLOCKS = 100;
441 ArrayList<IdBlock> blocks = new ArrayList<IdBlock>(NUM_BLOCKS);
442
443 for(int i = 0; i < NUM_BLOCKS; ++i) {
444 blocks.add(registry.allocateUniqueIdBlock());
445 }
446
447 for(int i = 0; i < NUM_BLOCKS; ++i) {
448 IdBlock block1 = blocks.get(i);
449 for(int j = i + 1; j < NUM_BLOCKS; ++j) {
450 IdBlock block2 = blocks.get(j);
451 IdBlock lower,higher;
452
453 if(block1.getStart() < block2.getStart()) {
454 lower = block1;
455 higher = block2;
456 } else {
457 lower = block2;
458 higher = block1;
459 }
460
461 assertTrue(lower.getSize() > 0L);
462 assertTrue(higher.getSize() > 0L);
Naoki Shiotaa3b2dfa2013-06-27 13:52:24 -0700463 assertTrue(lower.getEnd() < higher.getStart());
Naoki Shiotad00accf2013-06-25 14:40:37 -0700464 }
465 }
466 }
467}