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