blob: bb626575fb81e898f414670568cc0bd610716cde [file] [log] [blame]
package net.onrc.onos.core.registry;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import net.floodlightcontroller.core.module.FloodlightModuleContext;
import net.onrc.onos.core.registry.IControllerRegistryService.ControlChangeCallback;
import org.junit.After;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.openflow.util.HexString;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Unit test for {@link StandaloneRegistry}.
*
* @author Naoki Shiota
*/
public class StandaloneRegistryTest {
private static final Logger log = LoggerFactory.getLogger(StandaloneRegistryTest.class);
protected static final long TIMEOUT_MSEC = 1000;
protected StandaloneRegistry registry;
/**
* Implementation of {@link ControlChangeCallback} which defines callback interfaces called by Registry.
* This class remembers past callback parameters and provides methods to access them.
* This class also provides CountDownLatch so one can wait until the callback be called
* specific times (specified by constructor parameter). Particularly, the first time callback
* called is supposed for registration, this class has an independent latch to wait for
* the first callback.
*
* @author Naoki Shiota
*/
public static class LoggingCallback implements ControlChangeCallback {
private LinkedList<Long> dpidsCalledback = new LinkedList<Long>();
private LinkedList<Boolean> controlsCalledback = new LinkedList<Boolean>();
private CountDownLatch lock = null, registerLock = null;
/**
* Constructor with number of times callback to be called.
*
* @param numberToCall Number of times expected callback to be called
*/
public LoggingCallback(int numberToCall) {
lock = new CountDownLatch(numberToCall);
registerLock = new CountDownLatch(1);
}
/**
* Wait until registration is finished (callback is called for the first time).
*
* @throws InterruptedException
*/
public void waitForRegistration() throws InterruptedException {
registerLock.await();
}
/**
* Wait for registration specifying timeout.
*
* @param msec Milliseconds to timeout
* @throws InterruptedException
*/
public void waitForRegistration(long msec) throws InterruptedException {
registerLock.await(msec, TimeUnit.MILLISECONDS);
}
/**
* Wait until callback is called specific times.
*
* @throws InterruptedException
*/
public void waitUntilCalled() throws InterruptedException {
lock.await();
}
/**
* Wait until callback is called specific times, specifying timeout.
*
* @param msec Milliseconds to timeout
* @throws InterruptedException
*/
public void waitUntilCalled(long msec) throws InterruptedException {
lock.await(msec, TimeUnit.MILLISECONDS);
}
/**
* Get DPID parameter given by specific callback time.
*
* @param index Specify which time to get parameter
* @return DPID value by number.
*/
public Long getDpid(int index) {
return dpidsCalledback.get(index);
}
/**
* Get hasControl parameter given by specific callback time.
*
* @param index Specify which time to get parameter
* @return hasControl value
*/
public Boolean getControl(int index) {
return controlsCalledback.get(index);
}
/**
* Get DPID parameter given by latest call.
*
* @return DPID value by number
*/
public Long getLatestDpid() {
return dpidsCalledback.peekLast();
}
/**
* Get hasControl parameter given by latest call.
*
* @return hasControl value
*/
public Boolean getLatestControl() {
return controlsCalledback.peekLast();
}
@Override
public void controlChanged(long dpid, boolean hasControl) {
dpidsCalledback.addLast(dpid);
controlsCalledback.addLast(hasControl);
lock.countDown();
registerLock.countDown();
}
}
@Before
public void setUp() throws Exception {
FloodlightModuleContext fmc = new FloodlightModuleContext();
registry = new StandaloneRegistry();
registry.init(fmc);
}
@After
public void tearDown() {
}
/**
* Test if {@link StandaloneRegistry#registerController(String)} can run without error.
*/
@Test
public void testRegisterController() {
String controllerIdToRegister = "test";
try {
registry.registerController(controllerIdToRegister);
} catch (RegistryException e) {
e.printStackTrace();
fail(e.getMessage());
}
// Register Controller ID doubly
try {
registry.registerController(controllerIdToRegister);
fail("Double registration goes through without exception");
} catch (RegistryException e) {
// expected behavior
log.debug("Exception thrown as expected", e);
}
}
/**
* Test if {@link StandaloneRegistry#getControllerId()} can return correct ID.
*
* @throws RegistryException
*/
@Test
public void testGetControllerId() throws RegistryException {
String controllerIdToRegister = "test";
// try before controller is registered
String controllerId = registry.getControllerId();
assertNull(controllerId);
// register
registry.registerController(controllerIdToRegister);
// call getControllerId and verify
controllerId = registry.getControllerId();
assertNotNull(controllerId);
assertEquals(controllerIdToRegister, controllerId);
}
/**
* Test if {@link StandaloneRegistry#getAllControllers()} can return correct list of controllers.
*
* @throws RegistryException
*/
@Test
public void testGetAllControllers() throws RegistryException {
String controllerIdToRegister = "test";
// Test before register controller
try {
Collection<String> ctrls = registry.getAllControllers();
assertFalse(ctrls.contains(controllerIdToRegister));
} catch (RegistryException e) {
e.printStackTrace();
fail(e.getMessage());
}
// register
registry.registerController(controllerIdToRegister);
// Test after register controller
try {
Collection<String> ctrls = registry.getAllControllers();
assertTrue(ctrls.contains(controllerIdToRegister));
} catch (RegistryException e) {
e.printStackTrace();
fail(e.getMessage());
}
}
/**
* Test if {@link StandaloneRegistry#requestControl(long, ControlChangeCallback)}
* can correctly take control for switch so that callback is called.
*
* @throws RegistryException
* @throws InterruptedException
*/
@Test
public void testRequestControl() throws InterruptedException, RegistryException {
String controllerId = "test";
registry.registerController(controllerId);
LoggingCallback callback = new LoggingCallback(1);
long dpidToRequest = 1000L;
try {
registry.requestControl(dpidToRequest, callback);
} catch (RegistryException e) {
e.printStackTrace();
fail(e.getMessage());
}
callback.waitForRegistration();
long dpidCallback = callback.getLatestDpid();
boolean controlCallback = callback.getLatestControl();
assertEquals(dpidToRequest, dpidCallback);
assertTrue(controlCallback);
}
/**
* Test if {@link StandaloneRegistry#releaseControl(long)}
* can correctly release the control so that callback is called.
*
* @throws InterruptedException
* @throws RegistryException
*/
@Test
public void testReleaseControl() throws InterruptedException, RegistryException {
String controllerId = "test";
registry.registerController(controllerId);
long dpidToRequest = 1000L;
LoggingCallback callback = new LoggingCallback(2);
// to request and wait to take control
registry.requestControl(dpidToRequest, callback);
callback.waitForRegistration();
registry.releaseControl(dpidToRequest);
// verify
callback.waitUntilCalled();
assertEquals(dpidToRequest, (long) callback.getLatestDpid());
assertFalse(callback.getLatestControl());
}
/**
* Test if {@link StandaloneRegistry#hasControl(long)} returns correct status.
*
* @throws InterruptedException
* @throws RegistryException
*/
@Test
public void testHasControl() throws InterruptedException, RegistryException {
String controllerId = "test";
registry.registerController(controllerId);
long dpidToRequest = 1000L;
LoggingCallback callback = new LoggingCallback(2);
// Test before request control
assertFalse(registry.hasControl(dpidToRequest));
registry.requestControl(dpidToRequest, callback);
callback.waitForRegistration();
// Test after take control
assertTrue(registry.hasControl(dpidToRequest));
registry.releaseControl(dpidToRequest);
callback.waitUntilCalled();
// Test after release control
assertFalse(registry.hasControl(dpidToRequest));
}
/**
* Test if {@link StandaloneRegistry#getControllerForSwitch(long)} returns correct controller ID.
*
* @throws InterruptedException
* @throws RegistryException
*/
@Test
public void testGetControllerForSwitch() throws InterruptedException, RegistryException {
String controllerId = "test";
registry.registerController(controllerId);
long dpidToRequest = 1000L;
LoggingCallback callback = new LoggingCallback(2);
// Test before request control
try {
String controllerForSw = registry.getControllerForSwitch(dpidToRequest);
assertNotEquals(controllerId, controllerForSw);
} catch (RegistryException e) {
fail("Failed before request control : " + e.getMessage());
e.printStackTrace();
}
registry.requestControl(dpidToRequest, callback);
callback.waitForRegistration();
// Test after take control
try {
String controllerForSw = registry.getControllerForSwitch(dpidToRequest);
assertEquals(controllerId, controllerForSw);
} catch (RegistryException e) {
fail("Failed after take control : " + e.getMessage());
e.printStackTrace();
}
registry.releaseControl(dpidToRequest);
callback.waitUntilCalled();
// Test after release control
try {
String controllerForSw = registry.getControllerForSwitch(dpidToRequest);
assertNotEquals(controllerId, controllerForSw);
} catch (RegistryException e) {
fail("Failed after release control : " + e.getMessage());
e.printStackTrace();
}
}
/**
* Test if {@link StandaloneRegistry#getAllSwitches()} returns correct list of switches.
*
* @throws InterruptedException
* @throws RegistryException
*/
@Test
public void testGetAllSwitches() throws InterruptedException, RegistryException {
String controllerId = "test";
registry.registerController(controllerId);
long dpidToRequest = 1000L;
String dpidToRequestStr = HexString.toHexString(dpidToRequest);
LoggingCallback callback = new LoggingCallback(2);
// Test before request control
Map<String, List<ControllerRegistryEntry>> switches = registry.getAllSwitches();
assertNotNull(switches);
assertFalse(switches.keySet().contains(dpidToRequestStr));
registry.requestControl(dpidToRequest, callback);
callback.waitForRegistration();
// Test after take control
switches = registry.getAllSwitches();
assertNotNull(switches);
assertTrue(switches.keySet().contains(dpidToRequestStr));
int count = 0;
for (ControllerRegistryEntry ctrl : switches.get(dpidToRequestStr)) {
if (ctrl.getControllerId().equals(controllerId)) {
++count;
}
}
assertEquals(1, count);
registry.releaseControl(dpidToRequest);
callback.waitUntilCalled();
// Test after release control
switches = registry.getAllSwitches();
assertNotNull(switches);
assertFalse(switches.keySet().contains(dpidToRequestStr));
}
/**
* Test if {@link StandaloneRegistry#getSwitchesControlledByController(String)} returns correct list of switches.
*
* @throws InterruptedException
* @throws RegistryException
*/
// TODO: remove @Ignore after implement StandaloneRegistry#getSwitchesControlledByController
@Ignore
@Test
public void testGetSwitchesControlledByController() throws InterruptedException, RegistryException {
String controllerId = "test";
registry.registerController(controllerId);
long dpidToRequest = 1000L;
String dpidToRequestStr = HexString.toHexString(dpidToRequest);
LoggingCallback callback = new LoggingCallback(2);
// Test before request control
Collection<Long> switches = registry.getSwitchesControlledByController(controllerId);
assertNotNull(switches);
assertFalse(switches.contains(dpidToRequestStr));
registry.requestControl(dpidToRequest, callback);
callback.waitForRegistration();
// Test after take control
switches = registry.getSwitchesControlledByController(controllerId);
assertNotNull(switches);
assertTrue(switches.contains(dpidToRequestStr));
int count = 0;
for (Long dpid : switches) {
if (dpid == dpidToRequest) {
++count;
}
}
assertEquals(1, count);
registry.releaseControl(dpidToRequest);
callback.waitUntilCalled();
// Test after release control
switches = registry.getSwitchesControlledByController(controllerId);
assertNotNull(switches);
assertFalse(switches.contains(dpidToRequestStr));
}
/**
* Test if {@link StandaloneRegistry#allocateUniqueIdBlock()} returns appropriate object.
* Get bulk of IdBlocks and check if they do have unique range of IDs.
*/
@Test
public void testAllocateUniqueIdBlock() {
// Number of blocks to be verified that any of them has unique block
final int numBlocks = 100;
ArrayList<IdBlock> blocks = new ArrayList<IdBlock>(numBlocks);
for (int i = 0; i < numBlocks; ++i) {
blocks.add(registry.allocateUniqueIdBlock());
}
for (int i = 0; i < numBlocks; ++i) {
IdBlock block1 = blocks.get(i);
for (int j = i + 1; j < numBlocks; ++j) {
IdBlock block2 = blocks.get(j);
IdBlock lower, higher;
if (block1.getStart() < block2.getStart()) {
lower = block1;
higher = block2;
} else {
lower = block2;
higher = block1;
}
assertTrue(lower.getSize() > 0L);
assertTrue(higher.getSize() > 0L);
assertTrue(lower.getEnd() < higher.getStart());
}
}
}
}