diff options
Diffstat (limited to 'framework/src/onos/protocols/openflow/ctl/src/test/java/org/onosproject/openflow/controller/impl')
6 files changed, 973 insertions, 0 deletions
diff --git a/framework/src/onos/protocols/openflow/ctl/src/test/java/org/onosproject/openflow/controller/impl/ControllerTest.java b/framework/src/onos/protocols/openflow/ctl/src/test/java/org/onosproject/openflow/controller/impl/ControllerTest.java new file mode 100644 index 00000000..dddea328 --- /dev/null +++ b/framework/src/onos/protocols/openflow/ctl/src/test/java/org/onosproject/openflow/controller/impl/ControllerTest.java @@ -0,0 +1,219 @@ +/* + * Copyright 2015 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.onosproject.openflow.controller.impl; + +import java.io.File; +import java.io.IOException; +import java.util.Dictionary; +import java.util.Hashtable; +import java.util.Map; +import java.util.stream.IntStream; + +import org.junit.Before; +import org.junit.Test; +import org.onlab.junit.TestTools; +import org.onlab.util.ItemNotFoundException; +import org.onosproject.net.DeviceId; +import org.onosproject.net.driver.Driver; +import org.onosproject.openflow.DriverAdapter; +import org.onosproject.openflow.DriverServiceAdapter; +import org.onosproject.openflow.OFDescStatsReplyAdapter; +import org.onosproject.openflow.controller.driver.OpenFlowSwitchDriver; +import org.projectfloodlight.openflow.protocol.OFDescStatsReply; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.io.Files; + +import static com.google.common.io.ByteStreams.toByteArray; +import static com.google.common.io.Files.write; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.hasItem; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.lessThan; +import static org.hamcrest.Matchers.not; +import static org.hamcrest.Matchers.notNullValue; +import static org.hamcrest.Matchers.nullValue; + +/** + * Unit tests for the OpenFlow controller class. + */ +public class ControllerTest { + + Controller controller; + protected static final Logger log = LoggerFactory.getLogger(ControllerTest.class); + + static final File TEST_DIR = Files.createTempDir(); + + /* + * Writes the necessary file for the tests in the temporary directory + */ + static File stageTestResource(String name) throws IOException { + File file = new File(TEST_DIR, name); + byte[] bytes = toByteArray(ControllerTest.class.getResourceAsStream(name)); + write(bytes, file); + return file; + } + + class MockDriverService extends DriverServiceAdapter { + static final int NO_SUCH_DRIVER_ID = 1; + static final int ITEM_NOT_FOUND_DRIVER_ID = 2; + static final int DRIVER_EXISTS_ID = 3; + + static final String BASE_DRIVER_NAME = "of:000000000000000"; + + static final String NO_SUCH_DRIVER = BASE_DRIVER_NAME + + NO_SUCH_DRIVER_ID; + static final String ITEM_NOT_FOUND_DRIVER = BASE_DRIVER_NAME + + ITEM_NOT_FOUND_DRIVER_ID; + static final String DRIVER_EXISTS = BASE_DRIVER_NAME + + DRIVER_EXISTS_ID; + + @Override + public Driver getDriver(DeviceId deviceId) { + switch (deviceId.toString()) { + case NO_SUCH_DRIVER: + return null; + case ITEM_NOT_FOUND_DRIVER: + throw new ItemNotFoundException(); + case DRIVER_EXISTS: + return new DriverAdapter(); + default: + throw new AssertionError(); + } + } + } + + /** + * Creates and initializes a new controller. + */ + @Before + public void setUp() { + controller = new Controller(); + Dictionary<String, String> properties = new Hashtable<>(); + properties.put("openflowPorts", + Integer.toString(TestTools.findAvailablePort(0))); + controller.setConfigParams(properties); + } + + /** + * Tests fetching a driver that does not exist. + */ + @Test + public void switchInstanceNotFoundTest() { + controller.start(null, new MockDriverService()); + OpenFlowSwitchDriver driver = + controller.getOFSwitchInstance(MockDriverService.NO_SUCH_DRIVER_ID, + null, + null); + assertThat(driver, nullValue()); + controller.stop(); + } + + /** + * Tests fetching a driver that throws an ItemNotFoundException. + */ + @Test + public void switchItemNotFoundTest() { + controller.start(null, new MockDriverService()); + OFDescStatsReply stats = + new OFDescStatsReplyAdapter(); + OpenFlowSwitchDriver driver = + controller.getOFSwitchInstance(MockDriverService.ITEM_NOT_FOUND_DRIVER_ID, + stats, + null); + assertThat(driver, nullValue()); + controller.stop(); + } + + /** + * Tests fetching a driver that throws an ItemNotFoundException. + */ + @Test + public void driverExistsTest() { + controller.start(null, new MockDriverService()); + OFDescStatsReply stats = + new OFDescStatsReplyAdapter(); + OpenFlowSwitchDriver driver = + controller.getOFSwitchInstance(MockDriverService.DRIVER_EXISTS_ID, + stats, + null); + assertThat(driver, notNullValue()); + controller.stop(); + } + + /** + * Tests configuring the controller. + */ + @Test + public void testConfiguration() { + Dictionary<String, String> properties = new Hashtable<>(); + properties.put("openflowPorts", "1,2,3,4,5"); + properties.put("workerThreads", "5"); + + controller.setConfigParams(properties); + IntStream.rangeClosed(1, 5) + .forEach(i -> assertThat(controller.openFlowPorts, hasItem(i))); + assertThat(controller.workerThreads, is(5)); + } + + /** + * Tests the SSL/TLS methods in the controller. + */ + @Test + public void testSsl() throws IOException { + File keystore = stageTestResource("ControllerTestKeystore.jks"); + String keystoreName = keystore.getAbsolutePath(); + + System.setProperty("enableOFTLS", Boolean.toString(Boolean.TRUE)); + System.setProperty("javax.net.ssl.keyStore", keystoreName); + System.setProperty("javax.net.ssl.trustStore", keystoreName); + System.setProperty("javax.net.ssl.keyStorePassword", "password"); + System.setProperty("javax.net.ssl.trustStorePassword", "password"); + Dictionary<String, String> properties = new Hashtable<>(); + properties.put("openflowPorts", + Integer.toString(TestTools.findAvailablePort(0))); + properties.put("workerThreads", "0"); + + controller.setConfigParams(properties); + controller.start(null, new MockDriverService()); + + assertThat(controller.serverSslEngine, notNullValue()); + + controller.stop(); + boolean removed = keystore.delete(); + if (!removed) { + log.warn("Could not remove temporary file"); + } + } + + /** + * Tests controll utility health methods. + */ + @Test + public void testHealth() { + Map<String, Long> memory = controller.getMemory(); + assertThat(memory.size(), is(2)); + assertThat(memory.get("total"), is(not(0))); + assertThat(memory.get("free"), is(not(0))); + + long startTime = controller.getSystemStartTime(); + assertThat(startTime, lessThan(System.currentTimeMillis())); + + long upTime = controller.getSystemUptime(); + assertThat(upTime, lessThan(30L * 1000)); + } +} diff --git a/framework/src/onos/protocols/openflow/ctl/src/test/java/org/onosproject/openflow/controller/impl/OFMessageDecoderTest.java b/framework/src/onos/protocols/openflow/ctl/src/test/java/org/onosproject/openflow/controller/impl/OFMessageDecoderTest.java new file mode 100644 index 00000000..ed1db238 --- /dev/null +++ b/framework/src/onos/protocols/openflow/ctl/src/test/java/org/onosproject/openflow/controller/impl/OFMessageDecoderTest.java @@ -0,0 +1,84 @@ +/* + * Copyright 2015 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.onosproject.openflow.controller.impl; + + +import org.jboss.netty.buffer.ChannelBuffer; +import org.jboss.netty.buffer.ChannelBuffers; +import org.junit.Test; +import org.onosproject.openflow.ChannelAdapter; +import org.onosproject.openflow.ChannelHandlerContextAdapter; +import org.projectfloodlight.openflow.protocol.OFHello; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.instanceOf; +import static org.hamcrest.Matchers.notNullValue; +import static org.hamcrest.Matchers.nullValue; + +/** + * Tests for the OpenFlow message decoder. + */ +public class OFMessageDecoderTest { + + static class ConnectedChannel extends ChannelAdapter { + @Override + public boolean isConnected() { + return true; + } + } + + private ChannelBuffer getHelloMessageBuffer() { + // OFHello, OF version 1, xid of 0, total of 8 bytes + byte[] messageData = {0x1, 0x0, 0x0, 0x8, 0x0, 0x0, 0x0, 0x0}; + ChannelBuffer channelBuffer = ChannelBuffers.dynamicBuffer(); + channelBuffer.writeBytes(messageData); + return channelBuffer; + } + + /** + * Tests decoding a message on a closed channel. + * + * @throws Exception when an exception is thrown from the decoder + */ + @Test + public void testDecodeNoChannel() throws Exception { + OFMessageDecoder decoder = new OFMessageDecoder(); + ChannelBuffer channelBuffer = getHelloMessageBuffer(); + Object message = + decoder.decode(new ChannelHandlerContextAdapter(), + new ChannelAdapter(), + channelBuffer); + assertThat(message, nullValue()); + } + + /** + * Tests decoding a message. + * + * @throws Exception when an exception is thrown from the decoder + */ + @Test + public void testDecode() throws Exception { + OFMessageDecoder decoder = new OFMessageDecoder(); + ChannelBuffer channelBuffer = getHelloMessageBuffer(); + Object message = + decoder.decode(new ChannelHandlerContextAdapter(), + new ConnectedChannel(), + channelBuffer); + assertThat(message, notNullValue()); + assertThat(message, instanceOf(OFHello.class)); + } + +} diff --git a/framework/src/onos/protocols/openflow/ctl/src/test/java/org/onosproject/openflow/controller/impl/OFMessageEncoderTest.java b/framework/src/onos/protocols/openflow/ctl/src/test/java/org/onosproject/openflow/controller/impl/OFMessageEncoderTest.java new file mode 100644 index 00000000..d09e5661 --- /dev/null +++ b/framework/src/onos/protocols/openflow/ctl/src/test/java/org/onosproject/openflow/controller/impl/OFMessageEncoderTest.java @@ -0,0 +1,90 @@ +/* + * Copyright 2015 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.onosproject.openflow.controller.impl; + +import java.nio.charset.StandardCharsets; +import java.util.List; + +import org.jboss.netty.buffer.ChannelBuffer; +import org.junit.Test; +import org.onosproject.openflow.OfMessageAdapter; +import org.projectfloodlight.openflow.protocol.OFMessage; +import org.projectfloodlight.openflow.protocol.OFType; + +import com.google.common.collect.ImmutableList; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; + +/** + * Tests for the OpenFlow message encoder. + */ +public class OFMessageEncoderTest { + + static class MockOfMessage extends OfMessageAdapter { + static int nextId = 1; + final int id; + + MockOfMessage() { + super(OFType.ERROR); + id = nextId++; + } + + @Override + public void writeTo(ChannelBuffer channelBuffer) { + String message = "message" + Integer.toString(id) + " "; + channelBuffer.writeBytes(message.getBytes(StandardCharsets.UTF_8)); + } + } + + /** + * Tests that encoding a non-list returns the object specified. + * + * @throws Exception on exception in the encoder + */ + @Test + public void testNoList() throws Exception { + OFMessageEncoder encoder = new OFMessageEncoder(); + MockOfMessage message = new MockOfMessage(); + OFMessage returnedMessage = + (OFMessage) encoder.encode(null, null, message); + assertThat(message, is(returnedMessage)); + } + + /** + * Tests that encoding a list returns the proper encoded payload. + * + * @throws Exception on exception in the encoder + */ + @Test + public void testList() throws Exception { + OFMessageEncoder encoder = new OFMessageEncoder(); + MockOfMessage message1 = new MockOfMessage(); + MockOfMessage message2 = new MockOfMessage(); + MockOfMessage message3 = new MockOfMessage(); + List<MockOfMessage> messages = ImmutableList.of(message1, message2, message3); + ChannelBuffer returnedChannel = + (ChannelBuffer) encoder.encode(null, null, messages); + assertThat(returnedChannel, notNullValue()); + byte[] channelBytes = returnedChannel.array(); + String expectedListMessage = "message1 message2 message3 "; + String listMessage = + (new String(channelBytes, StandardCharsets.UTF_8)) + .substring(0, expectedListMessage.length()); + assertThat(listMessage, is(expectedListMessage)); + } +} diff --git a/framework/src/onos/protocols/openflow/ctl/src/test/java/org/onosproject/openflow/controller/impl/OpenFlowControllerImplPacketsTest.java b/framework/src/onos/protocols/openflow/ctl/src/test/java/org/onosproject/openflow/controller/impl/OpenFlowControllerImplPacketsTest.java new file mode 100644 index 00000000..13086ca7 --- /dev/null +++ b/framework/src/onos/protocols/openflow/ctl/src/test/java/org/onosproject/openflow/controller/impl/OpenFlowControllerImplPacketsTest.java @@ -0,0 +1,167 @@ +/* + * Copyright 2015 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.onosproject.openflow.controller.impl; + +import java.net.URI; +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.Future; + +import org.junit.Before; +import org.junit.Test; +import org.onosproject.openflow.ExecutorServiceAdapter; +import org.onosproject.openflow.MockOfFeaturesReply; +import org.onosproject.openflow.MockOfPacketIn; +import org.onosproject.openflow.MockOfPortStatus; +import org.onosproject.openflow.OfMessageAdapter; +import org.onosproject.openflow.OpenFlowSwitchListenerAdapter; +import org.onosproject.openflow.OpenflowSwitchDriverAdapter; +import org.onosproject.openflow.controller.Dpid; +import org.onosproject.openflow.controller.OpenFlowPacketContext; +import org.onosproject.openflow.controller.OpenFlowSwitch; +import org.onosproject.openflow.controller.PacketListener; +import org.projectfloodlight.openflow.protocol.OFMessage; +import org.projectfloodlight.openflow.protocol.OFType; + +import static junit.framework.TestCase.fail; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.hasSize; +import static org.hamcrest.Matchers.is; + +/** + * Tests for packet processing in the open flow controller impl class. + */ +public class OpenFlowControllerImplPacketsTest { + OpenFlowControllerImpl controller; + OpenFlowControllerImpl.OpenFlowSwitchAgent agent; + Dpid dpid1; + OpenFlowSwitch switch1; + OpenFlowSwitchListenerAdapter switchListener; + TestPacketListener packetListener; + TestExecutorService executorService; + + /** + * Mock packet listener that accumulates packets. + */ + class TestPacketListener implements PacketListener { + List<OpenFlowPacketContext> contexts = new ArrayList<>(); + + @Override + public void handlePacket(OpenFlowPacketContext pktCtx) { + contexts.add(pktCtx); + } + + List<OpenFlowPacketContext> contexts() { + return contexts; + } + } + + + /** + * Mock executor service that tracks submits. + */ + static class TestExecutorService extends ExecutorServiceAdapter { + private List<OFMessage> submittedMessages = new ArrayList<>(); + + List<OFMessage> submittedMessages() { + return submittedMessages; + } + + @Override + public Future<?> submit(Runnable task) { + OpenFlowControllerImpl.OFMessageHandler handler = + (OpenFlowControllerImpl.OFMessageHandler) task; + submittedMessages.add(handler.msg); + return null; + } + } + + /** + * Sets up switches to use as data, mocks and launches a controller instance. + */ + @Before + public void setUp() { + try { + switch1 = new OpenflowSwitchDriverAdapter(); + dpid1 = Dpid.dpid(new URI("of:0000000000000111")); + } catch (URISyntaxException ex) { + // Does not happen + fail(); + } + + controller = new OpenFlowControllerImpl(); + agent = controller.agent; + switchListener = new OpenFlowSwitchListenerAdapter(); + controller.addListener(switchListener); + + packetListener = new TestPacketListener(); + controller.addPacketListener(100, packetListener); + + executorService = new TestExecutorService(); + controller.executorMsgs = executorService; + } + + /** + * Tests a port status operation. + */ + @Test + public void testPortStatus() { + OFMessage portStatusPacket = new MockOfPortStatus(); + controller.processPacket(dpid1, portStatusPacket); + assertThat(switchListener.portChangedDpids().size(), is(1)); + assertThat(switchListener.portChangedDpids().containsKey(dpid1), + is(true)); + assertThat(switchListener.portChangedDpids().get(dpid1), + equalTo(portStatusPacket)); + } + + /** + * Tests a features reply operation. + */ + @Test + public void testFeaturesReply() { + OFMessage ofFeaturesReplyPacket = new MockOfFeaturesReply(); + controller.processPacket(dpid1, ofFeaturesReplyPacket); + assertThat(switchListener.changedDpids(), hasSize(1)); + assertThat(switchListener.changedDpids().get(0), + equalTo(dpid1)); + } + + /** + * Tests a packet in operation. + */ + @Test + public void testPacketIn() { + agent.addConnectedSwitch(dpid1, switch1); + OFMessage packetInPacket = new MockOfPacketIn(); + controller.processPacket(dpid1, packetInPacket); + assertThat(packetListener.contexts(), hasSize(1)); + } + + /** + * Tests an error operation. + */ + @Test + public void testError() { + agent.addConnectedSwitch(dpid1, switch1); + OfMessageAdapter errorPacket = new OfMessageAdapter(OFType.ERROR); + controller.processPacket(dpid1, errorPacket); + assertThat(executorService.submittedMessages(), hasSize(1)); + assertThat(executorService.submittedMessages().get(0), is(errorPacket)); + } +} diff --git a/framework/src/onos/protocols/openflow/ctl/src/test/java/org/onosproject/openflow/controller/impl/OpenFlowControllerImplTest.java b/framework/src/onos/protocols/openflow/ctl/src/test/java/org/onosproject/openflow/controller/impl/OpenFlowControllerImplTest.java new file mode 100644 index 00000000..e079c590 --- /dev/null +++ b/framework/src/onos/protocols/openflow/ctl/src/test/java/org/onosproject/openflow/controller/impl/OpenFlowControllerImplTest.java @@ -0,0 +1,283 @@ +/* + * Copyright 2015 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.onosproject.openflow.controller.impl; + +import java.net.URI; +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.Dictionary; +import java.util.Hashtable; +import java.util.List; +import java.util.Spliterator; +import java.util.Spliterators; +import java.util.stream.Stream; +import java.util.stream.StreamSupport; + +import org.easymock.EasyMock; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.onlab.junit.TestTools; +import org.onosproject.cfg.ComponentConfigService; +import org.onosproject.openflow.OpenflowSwitchDriverAdapter; +import org.onosproject.openflow.controller.Dpid; +import org.onosproject.openflow.controller.OpenFlowSwitch; +import org.onosproject.openflow.controller.OpenFlowSwitchListener; +import org.onosproject.openflow.controller.RoleState; +import org.osgi.service.component.ComponentContext; +import org.projectfloodlight.openflow.protocol.OFPortStatus; + +import com.google.common.collect.ImmutableSet; + +import static junit.framework.TestCase.fail; +import static org.easymock.EasyMock.anyObject; +import static org.easymock.EasyMock.expect; +import static org.easymock.EasyMock.expectLastCall; +import static org.easymock.EasyMock.replay; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.hasItems; +import static org.hamcrest.Matchers.hasSize; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.nullValue; + +/** + * Unit tests for the open flow controller implementation test. + */ +public class OpenFlowControllerImplTest { + + OpenFlowSwitch switch1; + Dpid dpid1; + OpenFlowSwitch switch2; + Dpid dpid2; + OpenFlowSwitch switch3; + Dpid dpid3; + + OpenFlowControllerImpl controller; + OpenFlowControllerImpl.OpenFlowSwitchAgent agent; + TestSwitchListener switchListener; + + /** + * Test harness for a switch listener. + */ + static class TestSwitchListener implements OpenFlowSwitchListener { + final List<Dpid> removedDpids = new ArrayList<>(); + final List<Dpid> addedDpids = new ArrayList<>(); + final List<Dpid> changedDpids = new ArrayList<>(); + + @Override + public void switchAdded(Dpid dpid) { + addedDpids.add(dpid); + } + + @Override + public void switchRemoved(Dpid dpid) { + removedDpids.add(dpid); + } + + @Override + public void switchChanged(Dpid dpid) { + changedDpids.add(dpid); + } + + @Override + public void portChanged(Dpid dpid, OFPortStatus status) { + // Stub + } + + @Override + public void receivedRoleReply(Dpid dpid, RoleState requested, RoleState response) { + // Stub + } + } + + + /** + * Sets up switches to use as data, mocks and launches a controller instance. + */ + @Before + public void setUp() { + try { + switch1 = new OpenflowSwitchDriverAdapter(); + dpid1 = Dpid.dpid(new URI("of:0000000000000111")); + switch2 = new OpenflowSwitchDriverAdapter(); + dpid2 = Dpid.dpid(new URI("of:0000000000000222")); + switch3 = new OpenflowSwitchDriverAdapter(); + dpid3 = Dpid.dpid(new URI("of:0000000000000333")); + } catch (URISyntaxException ex) { + // Does not happen + fail(); + } + + controller = new OpenFlowControllerImpl(); + agent = controller.agent; + + switchListener = new TestSwitchListener(); + controller.addListener(switchListener); + + ComponentConfigService mockConfigService = + EasyMock.createMock(ComponentConfigService.class); + expect(mockConfigService.getProperties(anyObject())).andReturn(ImmutableSet.of()); + mockConfigService.registerProperties(controller.getClass()); + expectLastCall(); + mockConfigService.unregisterProperties(controller.getClass(), false); + expectLastCall(); + expect(mockConfigService.getProperties(anyObject())).andReturn(ImmutableSet.of()); + controller.cfgService = mockConfigService; + replay(mockConfigService); + + ComponentContext mockContext = EasyMock.createMock(ComponentContext.class); + Dictionary<String, String> properties = new Hashtable<>(); + properties.put("openflowPorts", + Integer.toString(TestTools.findAvailablePort(0))); + expect(mockContext.getProperties()).andReturn(properties); + replay(mockContext); + controller.activate(mockContext); + } + + @After + public void tearDown() { + controller.removeListener(switchListener); + controller.deactivate(); + } + + /** + * Converts an Iterable of some type into a stream of that type. + * + * @param items Iterable of objects + * @param <T> type of the items in the iterable + * @return stream of objects of type T + */ + private <T> Stream<T> makeIntoStream(Iterable<T> items) { + return StreamSupport.stream( + Spliterators.spliteratorUnknownSize( + items.iterator(), Spliterator.ORDERED), false); + } + + + /** + * Tests adding and removing connected switches. + */ + @Test + public void testAddRemoveConnectedSwitch() { + + // test adding connected switches + boolean addSwitch1 = agent.addConnectedSwitch(dpid1, switch1); + assertThat(addSwitch1, is(true)); + boolean addSwitch2 = agent.addConnectedSwitch(dpid2, switch2); + assertThat(addSwitch2, is(true)); + boolean addSwitch3 = agent.addConnectedSwitch(dpid3, switch3); + assertThat(addSwitch3, is(true)); + + // Make sure the listener add callbacks fired + assertThat(switchListener.addedDpids, hasSize(3)); + assertThat(switchListener.addedDpids, hasItems(dpid1, dpid2, dpid3)); + + // Test adding a switch twice - it should fail + boolean addBadSwitch1 = agent.addConnectedSwitch(dpid1, switch1); + assertThat(addBadSwitch1, is(false)); + + assertThat(controller.connectedSwitches.size(), is(3)); + + // test querying the switch list + Stream<OpenFlowSwitch> fetchedSwitches = + makeIntoStream(controller.getSwitches()); + long switchCount = fetchedSwitches.count(); + assertThat(switchCount, is(3L)); + + // test querying the individual switch + OpenFlowSwitch queriedSwitch = controller.getSwitch(dpid1); + assertThat(queriedSwitch, is(switch1)); + + // Remove a switch + agent.removeConnectedSwitch(dpid3); + Stream<OpenFlowSwitch> fetchedSwitchesAfterRemove = + makeIntoStream(controller.getSwitches()); + long switchCountAfterRemove = fetchedSwitchesAfterRemove.count(); + assertThat(switchCountAfterRemove, is(2L)); + + // Make sure the listener delete callbacks fired + assertThat(switchListener.removedDpids, hasSize(1)); + assertThat(switchListener.removedDpids, hasItems(dpid3)); + + // test querying the removed switch + OpenFlowSwitch queriedSwitchAfterRemove = controller.getSwitch(dpid3); + assertThat(queriedSwitchAfterRemove, nullValue()); + } + + /** + * Tests adding master switches. + */ + @Test + public void testMasterSwitch() { + agent.addConnectedSwitch(dpid1, switch1); + agent.transitionToMasterSwitch(dpid1); + + Stream<OpenFlowSwitch> fetchedMasterSwitches = + makeIntoStream(controller.getMasterSwitches()); + assertThat(fetchedMasterSwitches.count(), is(1L)); + Stream<OpenFlowSwitch> fetchedActivatedSwitches = + makeIntoStream(controller.getEqualSwitches()); + assertThat(fetchedActivatedSwitches.count(), is(0L)); + OpenFlowSwitch fetchedSwitch1 = controller.getMasterSwitch(dpid1); + assertThat(fetchedSwitch1, is(switch1)); + + agent.addConnectedSwitch(dpid2, switch2); + boolean addSwitch2 = agent.addActivatedMasterSwitch(dpid2, switch2); + assertThat(addSwitch2, is(true)); + OpenFlowSwitch fetchedSwitch2 = controller.getMasterSwitch(dpid2); + assertThat(fetchedSwitch2, is(switch2)); + } + + /** + * Tests adding equal switches. + */ + @Test + public void testEqualSwitch() { + agent.addConnectedSwitch(dpid1, switch1); + agent.transitionToEqualSwitch(dpid1); + + Stream<OpenFlowSwitch> fetchedEqualSwitches = + makeIntoStream(controller.getEqualSwitches()); + assertThat(fetchedEqualSwitches.count(), is(1L)); + Stream<OpenFlowSwitch> fetchedActivatedSwitches = + makeIntoStream(controller.getMasterSwitches()); + assertThat(fetchedActivatedSwitches.count(), is(0L)); + OpenFlowSwitch fetchedSwitch1 = controller.getEqualSwitch(dpid1); + assertThat(fetchedSwitch1, is(switch1)); + + agent.addConnectedSwitch(dpid2, switch2); + boolean addSwitch2 = agent.addActivatedEqualSwitch(dpid2, switch2); + assertThat(addSwitch2, is(true)); + OpenFlowSwitch fetchedSwitch2 = controller.getEqualSwitch(dpid2); + assertThat(fetchedSwitch2, is(switch2)); + } + + /** + * Tests changing switch role. + */ + @Test + public void testRoleSetting() { + agent.addConnectedSwitch(dpid2, switch2); + + // check that state can be changed for a connected switch + assertThat(switch2.getRole(), is(RoleState.MASTER)); + controller.setRole(dpid2, RoleState.EQUAL); + assertThat(switch2.getRole(), is(RoleState.EQUAL)); + + // check that changing state on an unconnected switch does not crash + controller.setRole(dpid3, RoleState.SLAVE); + } +} diff --git a/framework/src/onos/protocols/openflow/ctl/src/test/java/org/onosproject/openflow/controller/impl/RoleManagerTest.java b/framework/src/onos/protocols/openflow/ctl/src/test/java/org/onosproject/openflow/controller/impl/RoleManagerTest.java new file mode 100644 index 00000000..4b594383 --- /dev/null +++ b/framework/src/onos/protocols/openflow/ctl/src/test/java/org/onosproject/openflow/controller/impl/RoleManagerTest.java @@ -0,0 +1,130 @@ +/* + * Copyright 2014-2015 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.onosproject.openflow.controller.impl; + +import java.io.IOException; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.onosproject.openflow.OpenflowSwitchDriverAdapter; +import org.onosproject.openflow.controller.RoleState; +import org.onosproject.openflow.controller.driver.OpenFlowSwitchDriver; +import org.onosproject.openflow.controller.driver.RoleRecvStatus; +import org.onosproject.openflow.controller.driver.RoleReplyInfo; +import org.onosproject.openflow.controller.driver.SwitchStateException; +import org.projectfloodlight.openflow.protocol.OFDescStatsReply; +import org.projectfloodlight.openflow.protocol.OFFeaturesReply; +import org.projectfloodlight.openflow.types.U64; + +import static org.junit.Assert.assertEquals; +import static org.onosproject.openflow.controller.RoleState.MASTER; +import static org.onosproject.openflow.controller.RoleState.SLAVE; +import static org.onosproject.openflow.controller.driver.RoleRecvStatus.MATCHED_CURRENT_ROLE; +import static org.onosproject.openflow.controller.driver.RoleRecvStatus.OTHER_EXPECTATION; + +public class RoleManagerTest { + + private static final U64 GID = U64.of(10L); + private static final long XID = 1L; + + private OpenFlowSwitchDriver sw; + private RoleManager manager; + + @Before + public void setUp() { + sw = new TestSwitchDriver(); + manager = new RoleManager(sw); + } + + @After + public void tearDown() { + manager = null; + sw = null; + } + + @Test + public void deliverRoleReply() { + RoleRecvStatus status; + + RoleReplyInfo asserted = new RoleReplyInfo(MASTER, GID, XID); + RoleReplyInfo unasserted = new RoleReplyInfo(SLAVE, GID, XID); + + try { + //call without sendRoleReq() for requestPending = false + //first, sw.role == null + status = manager.deliverRoleReply(asserted); + assertEquals("expectation wrong", OTHER_EXPECTATION, status); + + sw.setRole(MASTER); + assertEquals("expectation wrong", OTHER_EXPECTATION, status); + sw.setRole(SLAVE); + + //match to pendingRole = MASTER, requestPending = true + manager.sendRoleRequest(MASTER, MATCHED_CURRENT_ROLE); + status = manager.deliverRoleReply(asserted); + assertEquals("expectation wrong", MATCHED_CURRENT_ROLE, status); + + //requestPending never gets reset -- this might be a bug. + status = manager.deliverRoleReply(unasserted); + assertEquals("expectation wrong", OTHER_EXPECTATION, status); + assertEquals("pending role mismatch", MASTER, ((TestSwitchDriver) sw).failed); + + } catch (IOException | SwitchStateException e) { + assertEquals("unexpected error thrown", + SwitchStateException.class, e.getClass()); + } + } + + private class TestSwitchDriver extends OpenflowSwitchDriverAdapter { + + RoleState failed = null; + RoleState current = null; + + @Override + public void setRole(RoleState role) { + current = role; + } + + @Override + public RoleState getRole() { + return current; + } + + @Override + public void setFeaturesReply(OFFeaturesReply featuresReply) { + } + + @Override + public void setSwitchDescription(OFDescStatsReply desc) { + } + + @Override + public int getNextTransactionId() { + return (int) XID; + } + + @Override + public void returnRoleReply(RoleState requested, RoleState response) { + failed = requested; + } + + @Override + public String channelId() { + return "1.2.3.4:1"; + } + } +} |