aboutsummaryrefslogtreecommitdiffstats
path: root/framework/src/onos/protocols/openflow/ctl/src/test/java/org/onosproject/openflow/controller/impl
diff options
context:
space:
mode:
Diffstat (limited to 'framework/src/onos/protocols/openflow/ctl/src/test/java/org/onosproject/openflow/controller/impl')
-rw-r--r--framework/src/onos/protocols/openflow/ctl/src/test/java/org/onosproject/openflow/controller/impl/ControllerTest.java219
-rw-r--r--framework/src/onos/protocols/openflow/ctl/src/test/java/org/onosproject/openflow/controller/impl/OFMessageDecoderTest.java84
-rw-r--r--framework/src/onos/protocols/openflow/ctl/src/test/java/org/onosproject/openflow/controller/impl/OFMessageEncoderTest.java90
-rw-r--r--framework/src/onos/protocols/openflow/ctl/src/test/java/org/onosproject/openflow/controller/impl/OpenFlowControllerImplPacketsTest.java167
-rw-r--r--framework/src/onos/protocols/openflow/ctl/src/test/java/org/onosproject/openflow/controller/impl/OpenFlowControllerImplTest.java283
-rw-r--r--framework/src/onos/protocols/openflow/ctl/src/test/java/org/onosproject/openflow/controller/impl/RoleManagerTest.java130
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";
+ }
+ }
+}