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