Remove serial failover tests, which only maintain one controller at any point
in time.
Instead, cxn.py-based failover tests can maintain multiple controllers at the
same time.
diff --git a/tests/cxn.py b/tests/cxn.py
index e9059cc..db377be 100644
--- a/tests/cxn.py
+++ b/tests/cxn.py
@@ -100,32 +100,59 @@
self.assertTrue(self.controllers[0].wait_disconnected(timeout=10),
"Not notified of controller disconnect")
-class HandshakeAndKeepalive(BaseHandshake):
+class CompleteHandshake(BaseHandshake):
"""
- Complete handshake and respond to echo request, but otherwise do nothing.
- Good for manual testing.
+ Set up multiple controllers and complete handshake, but otherwise do nothing.
"""
priority = -1
- def runTest(self):
- self.num_controllers = test_param_get('num_controllers', default=1)
- self.controller_timeout = test_param_get('controller_timeout',
- default=-1)
- self.hello_timeout = test_param_get('hello_timeout',
- default=5)
- self.features_req_timeout = test_param_get('features_req_timeout',
- default=5)
+ def buildControllerList(self):
+ # controller_list is a list of IP:port tuples
+ con_list = test_param_get('controller_list')
+ if con_list is not None:
+ self.controller_list = []
+ for controller in con_list:
+ ip,portstr = controller.split(':')
+ try:
+ port = int(portstr)
+ except:
+ self.assertTrue(0, "failure converting port " +
+ portstr + " to integer")
+ self.controller_list.append( (ip, int(port)) )
+ else:
+ self.controller_list = [(config["controller_host"],
+ config["controller_port"])]
- for i in range(self.num_controllers):
- self.controllerSetup(config["controller_host"],
- config["controller_port"]+i)
- for i in range(self.num_controllers):
+ def __init__(self, keep_alive=True, cxn_cycles=5,
+ controller_timeout=-1, hello_timeout=5,
+ features_req_timeout=5, disconnected_timeout=3):
+ BaseHandshake.__init__(self)
+ self.buildControllerList()
+ self.keep_alive = keep_alive
+ self.cxn_cycles = test_param_get('cxn_cycles') \
+ or cxn_cycles
+ self.controller_timeout = test_param_get('controller_timeout') \
+ or controller_timeout
+ self.hello_timeout = test_param_get('hello_timeout') \
+ or hello_timeout
+ self.features_req_timeout = test_param_get('features_req_timeout') \
+ or features_req_timeout
+ self.disconnected_timeout = test_param_get('disconnected_timeout') \
+ or disconnected_timeout
+
+ def runTest(self):
+ for conspec in self.controller_list:
+ self.controllerSetup(conspec[0], conspec[1])
+ for i in range(len(self.controller_list)):
self.controllers[i].cstate = 0
- self.controllers[i].keep_alive = True
+ self.controllers[i].keep_alive = self.keep_alive
tick = 0.1 # time period in seconds at which controllers are handled
+ disconnected_count = 0
+ cycle = 0
while True:
+ states = []
for con in self.controllers:
condesc = con.host + ":" + str(con.port) + ": "
logging.debug("Checking " + condesc)
@@ -168,6 +195,7 @@
str(con.switch_addr))
con.cstate = 4
con.count = 0
+ cycle = cycle + 1
else:
con.count = con.count + 1
# fall back to previous state on timeout
@@ -191,5 +219,56 @@
con.cstate = 0
else:
con.cstate = 0
+
+ states.append(con.cstate)
+ logging.debug("Cycle " + str(cycle) +
+ ", states " + str(states) +
+ ", disconnected_count " + str(disconnected_count))
+ if 4 in states:
+ disconnected_count = 0
+ else:
+ disconnected_count = disconnected_count + 1
+ if cycle != 0:
+ self.assertTrue(disconnected_count < self.disconnected_timeout/tick,
+ "Timeout expired connecting to controller")
+ else:
+ # on first cycle, allow more time for initial connect
+ self.assertTrue(disconnected_count < 2*self.disconnected_timeout/tick,
+ "Timeout expired connecting to controller on init")
+
+ if cycle > self.cxn_cycles:
+ break
time.sleep(tick)
+
+class HandshakeAndKeepalive(CompleteHandshake):
+ """
+ Complete handshake and respond to echo request, but otherwise do nothing.
+ Good for manual testing.
+ """
+
+ priority = -1
+
+ def __init__(self):
+ CompleteHandshake.__init__(self, keep_alive=True)
+
+class HandshakeNoEcho(CompleteHandshake):
+ """
+ Complete handshake, but otherwise do nothing, and do not respond to echo.
+ """
+
+ priority = -1
+
+ def __init__(self):
+ CompleteHandshake.__init__(self, keep_alive=False)
+
+class HandshakeAndDrop(CompleteHandshake):
+ """
+ Complete handshake, but otherwise do nothing, and drop connection after a while.
+ """
+
+ priority = -1
+
+ def __init__(self):
+ CompleteHandshake.__init__(self, keep_alive=True, controller_timeout=10)
+
diff --git a/tests/serial_failover.py b/tests/serial_failover.py
deleted file mode 100644
index ffbbf0a..0000000
--- a/tests/serial_failover.py
+++ /dev/null
@@ -1,179 +0,0 @@
-"""
-Serial failover test cases
-
-"""
-
-import time
-import sys
-import logging
-
-import unittest
-import random
-
-from oftest import config
-import oftest.controller as controller
-import oftest.cstruct as ofp
-import oftest.message as message
-import oftest.dataplane as dataplane
-import oftest.action as action
-
-from oftest.testutils import *
-
-class SerialFailover(unittest.TestCase):
- """
- Opens a connection that the switch should use as its only controller,
- as specified by controller_host and controller_port.
- Then cause the connection to fail [fail method should be configurable].
- Ultimately, the switch should connect to the next controller port,
- as specified by
- --test-params="controller_list=['ip2:port2','ip3:port3']".
- Multiple test params are specified by
- --test-params="param1=val1;param2=val2"
- """
-
- priority = -1
-
- # populated by buildControllerList()
- controller_list = []
- controller_idx = 0
- # populated by setUp()
- test_timeout = 0
- test_iterations = 0
-
- def controllerSetup(self, host, port):
- self.controller = controller.Controller(host=host,port=port)
-
- # clean_shutdown should be set to False to force quit app
- self.clean_shutdown = True
-
- self.controller.start()
- #@todo Add an option to wait for a pkt transaction to ensure version
- # compatibilty?
- self.controller.connect(timeout=10)
- self.assertTrue(self.controller.active,
- "Controller startup failed, not active")
- self.assertTrue(self.controller.switch_addr is not None,
- "Controller startup failed, no switch addr")
- request = message.features_request()
- reply, pkt = self.controller.transact(request, timeout=20)
- self.assertTrue(reply is not None,
- "Did not complete features_request for handshake")
- logging.info("Connected " +
- str(self.controller.switch_addr))
-
- # send echo request and wait for reply
- request = message.echo_request()
- response, pkt = self.controller.transact(request)
- self.assertEqual(response.header.type, ofp.OFPT_ECHO_REPLY,
- 'response is not echo_reply')
- self.assertEqual(request.header.xid, response.header.xid,
- 'response xid != request xid')
- self.assertEqual(len(response.data), 0, 'response data non-empty')
-
- def connectionKill(self, kill_method):
- if kill_method == 'controller_shutdown':
- logging.info("Shutting down controller")
- self.controller.shutdown()
- elif kill_method == 'no_echo':
- logging.info("Disabling controller keep alive")
- self.controller.keep_alive = False
-
- # wait for controller to die
- count = 0
- while self.controller.active and count < self.test_timeout:
- time.sleep(1)
- count = count + 1
- else:
- self.assertTrue(False, "Unknown controller kill method")
-
- def buildControllerList(self):
- # controller_list is list of ip/port tuples
- partial_list = test_param_get('controller_list')
- logging.debug("ctrl list: " + str(partial_list))
- self.controller_list = [(config["controller_host"],
- config["controller_port"])]
- if partial_list is not None:
- for controller in partial_list:
- ip,portstr = controller.split(':')
- try:
- port = int(portstr)
- except:
- self.assertTrue(0, "failure converting port " +
- portstr + " to integer")
- self.controller_list.append( (ip, int(port)) )
-
- def getController(self):
- return self.controller_list[self.controller_idx]
-
- def getNextController(self):
- self.controller_idx = (self.controller_idx + 1) \
- % len(self.controller_list)
- return self.controller_list[self.controller_idx]
-
- def setUp(self):
- logging.info("** START TEST CASE " + str(self))
-
- self.test_timeout = test_param_get('failover_timeout') or 60
- self.test_iterations = test_param_get('failover_iterations') or 4
-
- self.buildControllerList()
- self.controller_idx = 0
- controller = self.getController()
- self.controllerSetup(controller[0], controller[1])
-
- def inheritSetup(self, parent):
- """
- Inherit the setup of a parent
-
- This allows running at test from within another test. Do the
- following:
-
- sub_test = SomeTestClass() # Create an instance of the test class
- sub_test.inheritSetup(self) # Inherit setup of parent
- sub_test.runTest() # Run the test
-
- Normally, only the parent's setUp and tearDown are called and
- the state after the sub_test is run must be taken into account
- by subsequent operations.
- """
- logging.info("** Setup " + str(self) +
- " inheriting from " + str(parent))
- self.controller = parent.controller
-
- def tearDown(self):
- logging.info("** END TEST CASE " + str(self))
- self.controller.shutdown()
- if self.clean_shutdown:
- self.controller.join()
-
- def doFailover(self, killmethod):
- logging.info("Starting serial failover test")
- self.assertTrue(self.controller.switch_socket is not None,
- str(self) + 'No connection to switch')
- # kill controller connection
- self.connectionKill(killmethod)
- # establish new controller connection
- controller = self.getNextController()
- logging.debug("** Next controller (%u/%u)%s:%u" %
- (self.controller_idx,
- len(self.controller_list),
- controller[0],
- controller[1]))
- self.controllerSetup(controller[0], controller[1])
-
- def runTest(self):
- for i in range(0,self.test_iterations):
- self.doFailover('controller_shutdown')
-
- def assertTrue(self, cond, msg):
- if not cond:
- logging.error("** FAILED ASSERTION: " + msg)
- unittest.TestCase.assertTrue(self, cond, msg)
-
-
-class SerialFailoverNoEcho(SerialFailover):
- priority = -1
-
- def runTest(self):
- for i in range(0,self.test_iterations):
- self.doFailover('no_echo')