/**
* Copyright 2013, Big Switch Networks, Inc.
*
* 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 net.floodlightcontroller.core.internal;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.net.InetSocketAddress;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import org.easymock.EasyMock;
import org.junit.Before;
import org.junit.Test;
import net.floodlightcontroller.core.IOFSwitchBackend;
import net.floodlightcontroller.core.SwitchDriverSubHandshakeAlreadyStarted;
import net.floodlightcontroller.core.SwitchDriverSubHandshakeCompleted;
import net.floodlightcontroller.core.SwitchDriverSubHandshakeNotStarted;
import net.floodlightcontroller.core.util.URIUtil;
import org.projectfloodlight.openflow.protocol.OFBsnControllerConnection;
import org.projectfloodlight.openflow.protocol.OFBsnControllerConnectionState;
import org.projectfloodlight.openflow.protocol.OFBsnControllerConnectionsReply;
import org.projectfloodlight.openflow.protocol.OFControllerRole;
import org.projectfloodlight.openflow.protocol.OFFactories;
import org.projectfloodlight.openflow.protocol.OFFactory;
import org.projectfloodlight.openflow.protocol.OFMessage;
import org.projectfloodlight.openflow.protocol.OFNiciraControllerRole;
import org.projectfloodlight.openflow.protocol.OFVersion;
import org.projectfloodlight.openflow.types.DatapathId;
import org.projectfloodlight.openflow.types.OFAuxId;
public class OFSwitchTest {
protected OFSwitch sw;
protected OFFactory factory = OFFactories.getFactory(OFVersion.OF_13);
@Before
public void setUp() throws Exception {
MockOFConnection mockConnection = new MockOFConnection(DatapathId.of(1), OFAuxId.MAIN);
sw = new OFSwitch(mockConnection, OFFactories.getFactory(OFVersion.OF_10),
EasyMock.createMock(IOFSwitchManager.class), DatapathId.of(1));
}
@Test
public void testSetHARoleReply() {
sw.setControllerRole(OFControllerRole.ROLE_MASTER);
assertEquals(OFControllerRole.ROLE_MASTER, sw.getControllerRole());
sw.setControllerRole(OFControllerRole.ROLE_EQUAL);
assertEquals(OFControllerRole.ROLE_EQUAL, sw.getControllerRole());
sw.setControllerRole(OFControllerRole.ROLE_SLAVE);
assertEquals(OFControllerRole.ROLE_SLAVE, sw.getControllerRole());
}
@Test
public void testSubHandshake() {
OFFactory factory = OFFactories.getFactory(OFVersion.OF_10);
OFMessage m = factory.buildNiciraControllerRoleReply()
.setXid(1)
.setRole(OFNiciraControllerRole.ROLE_MASTER)
.build();
// test exceptions before handshake is started
try {
sw.processDriverHandshakeMessage(m);
fail("expected exception not thrown");
} catch (SwitchDriverSubHandshakeNotStarted e) { /* expected */ }
try {
sw.isDriverHandshakeComplete();
fail("expected exception not thrown");
} catch (SwitchDriverSubHandshakeNotStarted e) { /* expected */ }
// start the handshake -- it should immediately complete
sw.startDriverHandshake();
assertTrue("Handshake should be complete",
sw.isDriverHandshakeComplete());
// test exceptions after handshake is completed
try {
sw.processDriverHandshakeMessage(m);
fail("expected exception not thrown");
} catch (SwitchDriverSubHandshakeCompleted e) { /* expected */ }
try {
sw.startDriverHandshake();
fail("Expected exception not thrown");
} catch (SwitchDriverSubHandshakeAlreadyStarted e) { /* expected */ }
}
/**
* Helper to load controller connection messages into a switch for testing.
* @param sw the switch to insert the message on
* @param role the role for the controller connection message
* @param state the state for the controller connection message
* @param uri the URI for the controller connection message
*/
public void updateControllerConnections(IOFSwitchBackend sw, OFControllerRole role1, OFBsnControllerConnectionState state1, String uri1
, OFControllerRole role2, OFBsnControllerConnectionState state2, String uri2) {
OFBsnControllerConnection connection1 = factory.buildBsnControllerConnection()
.setAuxiliaryId(OFAuxId.MAIN)
.setRole(role1)
.setState(state1)
.setUri(uri1)
.build();
OFBsnControllerConnection connection2 = factory.buildBsnControllerConnection()
.setAuxiliaryId(OFAuxId.MAIN)
.setRole(role2)
.setState(state2)
.setUri(uri2)
.build();
List<OFBsnControllerConnection> connections = new ArrayList<OFBsnControllerConnection>();
connections.add(connection1);
connections.add(connection2);
OFBsnControllerConnectionsReply reply = factory.buildBsnControllerConnectionsReply()
.setConnections(connections)
.build();
sw.updateControllerConnections(reply);
}
/**
* This test ensures that the switch accurately determined if another master
* exists in the cluster by examining the controller connections it has.
*/
@Test
public void testHasAnotherMaster() {
URI cokeUri = URIUtil.createURI("1.2.3.4", 6653);
InetSocketAddress address = (InetSocketAddress) sw.getConnection(OFAuxId.MAIN).getLocalInetAddress();
URI pepsiUri = URIUtil.createURI(address.getHostName(), address.getPort());
updateControllerConnections(sw, OFControllerRole.ROLE_SLAVE, OFBsnControllerConnectionState.BSN_CONTROLLER_CONNECTION_STATE_CONNECTED, cokeUri.toString(),
OFControllerRole.ROLE_MASTER, OFBsnControllerConnectionState.BSN_CONTROLLER_CONNECTION_STATE_CONNECTED, pepsiUri.toString());
// From the perspective of pepsi, the cluster currently does NOT have another master controller
assertFalse(sw.hasAnotherMaster());
// Switch the controller connections so that pepsi is no longer master
updateControllerConnections(sw, OFControllerRole.ROLE_MASTER, OFBsnControllerConnectionState.BSN_CONTROLLER_CONNECTION_STATE_CONNECTED, cokeUri.toString(),
OFControllerRole.ROLE_SLAVE, OFBsnControllerConnectionState.BSN_CONTROLLER_CONNECTION_STATE_CONNECTED, pepsiUri.toString());
// From the perspective of pepsi, the cluster currently has another master controller
assertTrue(sw.hasAnotherMaster());
}
}