Ray Milkey
Committed by Gerrit Code Review

Unit tests for open flow controller message handling.

Change-Id: I9cffe4f4585eaf0df48d9fcb6a9f62ddcc0f9403
......@@ -107,7 +107,7 @@ public class OpenFlowControllerImpl implements OpenFlowController {
label = "Number of controller worker threads; default is 16")
private int workerThreads = DEFAULT_WORKER_THREADS;
private final ExecutorService executorMsgs =
protected ExecutorService executorMsgs =
Executors.newFixedThreadPool(32, groupedThreads("onos/of", "event-stats-%d"));
private final ExecutorService executorBarrier =
......@@ -611,10 +611,10 @@ public class OpenFlowControllerImpl implements OpenFlowController {
}
}
private final class OFMessageHandler implements Runnable {
protected final class OFMessageHandler implements Runnable {
private final OFMessage msg;
private final Dpid dpid;
protected final OFMessage msg;
protected final Dpid dpid;
public OFMessageHandler(Dpid dpid, OFMessage msg) {
this.msg = msg;
......
/*
* 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;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
/**
* Test harness adapter for the ExecutorService.
*/
public class ExecutorServiceAdapter implements ExecutorService {
@Override
public void shutdown() {
}
@Override
public List<Runnable> shutdownNow() {
return null;
}
@Override
public boolean isShutdown() {
return false;
}
@Override
public boolean isTerminated() {
return false;
}
@Override
public boolean awaitTermination(long timeout, TimeUnit unit)
throws InterruptedException {
return false;
}
@Override
public <T> Future<T> submit(Callable<T> task) {
return null;
}
@Override
public <T> Future<T> submit(Runnable task, T result) {
return null;
}
@Override
public Future<?> submit(Runnable task) {
return null;
}
@Override
public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
throws InterruptedException {
return null;
}
@Override
public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit)
throws InterruptedException {
return null;
}
@Override
public <T> T invokeAny(Collection<? extends Callable<T>> tasks) throws InterruptedException, ExecutionException {
return null;
}
@Override
public <T> T invokeAny(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException {
return null;
}
@Override
public void execute(Runnable command) {
}
}
/*
* 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;
import java.util.List;
import java.util.Set;
import org.projectfloodlight.openflow.protocol.OFActionType;
import org.projectfloodlight.openflow.protocol.OFCapabilities;
import org.projectfloodlight.openflow.protocol.OFFeaturesReply;
import org.projectfloodlight.openflow.protocol.OFPortDesc;
import org.projectfloodlight.openflow.protocol.OFType;
import org.projectfloodlight.openflow.types.DatapathId;
import org.projectfloodlight.openflow.types.OFAuxId;
/**
* Mock of the Open FLow features reply message.
*/
public class MockOfFeaturesReply extends OfMessageAdapter implements OFFeaturesReply {
public MockOfFeaturesReply() {
super(OFType.FEATURES_REPLY);
}
@Override
public DatapathId getDatapathId() {
return null;
}
@Override
public long getNBuffers() {
return 0;
}
@Override
public short getNTables() {
return 0;
}
@Override
public Set<OFCapabilities> getCapabilities() {
return null;
}
@Override
public long getReserved() {
return 0;
}
@Override
public List<OFPortDesc> getPorts() {
return null;
}
@Override
public Set<OFActionType> getActions() {
return null;
}
@Override
public OFAuxId getAuxiliaryId() {
return null;
}
@Override
public OFFeaturesReply.Builder createBuilder() {
return null;
}
}
/*
* 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;
import org.projectfloodlight.openflow.protocol.OFPacketIn;
import org.projectfloodlight.openflow.protocol.OFPacketInReason;
import org.projectfloodlight.openflow.protocol.OFType;
import org.projectfloodlight.openflow.protocol.match.Match;
import org.projectfloodlight.openflow.types.OFBufferId;
import org.projectfloodlight.openflow.types.OFPort;
import org.projectfloodlight.openflow.types.TableId;
import org.projectfloodlight.openflow.types.U64;
/**
* Mock of the Open Flow packet in message.
*/
public class MockOfPacketIn extends OfMessageAdapter implements OFPacketIn {
public MockOfPacketIn() {
super(OFType.PACKET_IN);
}
@Override
public OFBufferId getBufferId() {
return null;
}
@Override
public int getTotalLen() {
return 0;
}
@Override
public OFPacketInReason getReason() {
return null;
}
@Override
public TableId getTableId() {
return null;
}
@Override
public Match getMatch() {
return null;
}
@Override
public byte[] getData() {
return new byte[0];
}
@Override
public OFPort getInPort() {
return null;
}
@Override
public OFPort getInPhyPort() {
return null;
}
@Override
public U64 getCookie() {
return null;
}
@Override
public OFPacketIn.Builder createBuilder() {
return null;
}
}
/*
* 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;
import org.projectfloodlight.openflow.protocol.OFPortDesc;
import org.projectfloodlight.openflow.protocol.OFPortReason;
import org.projectfloodlight.openflow.protocol.OFPortStatus;
import org.projectfloodlight.openflow.protocol.OFType;
/**
* Mocked open flow port status message.
*/
public class MockOfPortStatus extends OfMessageAdapter implements OFPortStatus {
public MockOfPortStatus() {
super(OFType.PORT_STATUS);
}
@Override
public OFPortReason getReason() {
return null;
}
@Override
public OFPortDesc getDesc() {
return null;
}
@Override
public OFPortStatus.Builder createBuilder() {
return null;
}
}
......@@ -26,13 +26,21 @@ import com.google.common.hash.PrimitiveSink;
* Adapter for testing against an OpenFlow message.
*/
public class OfMessageAdapter implements OFMessage {
@Override
public OFVersion getVersion() {
return null;
OFType type;
private OfMessageAdapter() {}
public OfMessageAdapter(OFType type) {
this.type = type;
}
@Override
public OFType getType() {
return type;
}
@Override
public OFVersion getVersion() {
return null;
}
......
/*
* 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;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.onosproject.openflow.controller.Dpid;
import org.onosproject.openflow.controller.OpenFlowSwitchListener;
import org.onosproject.openflow.controller.RoleState;
import org.projectfloodlight.openflow.protocol.OFPortStatus;
/**
* Test harness for a switch listener.
*/
public class OpenFlowSwitchListenerAdapter implements OpenFlowSwitchListener {
final List<Dpid> removedDpids = new ArrayList<>();
final List<Dpid> addedDpids = new ArrayList<>();
final List<Dpid> changedDpids = new ArrayList<>();
final Map<Dpid, OFPortStatus> portChangedDpids = new HashMap<>();
@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) {
portChangedDpids.put(dpid, status);
}
@Override
public void receivedRoleReply(Dpid dpid, RoleState requested, RoleState response) {
// Stub
}
public List<Dpid> removedDpids() {
return removedDpids;
}
public List<Dpid> addedDpids() {
return addedDpids;
}
public List<Dpid> changedDpids() {
return changedDpids;
}
public Map<Dpid, OFPortStatus> portChangedDpids() {
return portChangedDpids;
}
}
......@@ -22,6 +22,7 @@ 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;
......@@ -39,6 +40,7 @@ public class OFMessageEncoderTest {
final int id;
MockOfMessage() {
super(OFType.ERROR);
id = nextId++;
}
......
/*
* 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));
}
}