blob: 7baeae02a8506e727fe778dac7aabaf161ecd720 [file] [log] [blame]
Ken Chiang20a3da52012-07-11 09:13:57 -07001"""
2Serial failover test cases
3
4"""
5
6import time
Ken Chiang20a3da52012-07-11 09:13:57 -07007import sys
8import logging
9
10import unittest
11import random
12
Rich Lane477f4812012-10-04 22:49:00 -070013from oftest import config
Ken Chiang20a3da52012-07-11 09:13:57 -070014import oftest.controller as controller
15import oftest.cstruct as ofp
16import oftest.message as message
17import oftest.dataplane as dataplane
18import oftest.action as action
19
Rich Laneda3b5ad2012-10-03 09:05:32 -070020from oftest.testutils import *
Ken Chiang20a3da52012-07-11 09:13:57 -070021
Ken Chiang20a3da52012-07-11 09:13:57 -070022class SerialFailover(unittest.TestCase):
23 """
24 Opens a connection that the switch should use as its only controller,
25 as specified by controller_host and controller_port.
26 Then cause the connection to fail [fail method should be configurable].
27 Ultimately, the switch should connect to the next controller port,
28 as specified by
29 --test-params="controller_list=['ip2:port2','ip3:port3']".
30 Multiple test params are specified by
31 --test-params="param1=val1;param2=val2"
32 """
33
Rich Laned1d9c282012-10-04 22:07:10 -070034 priority = -1
35
Ken Chiang20a3da52012-07-11 09:13:57 -070036 # populated by buildControllerList()
37 controller_list = []
38 controller_idx = 0
39 # populated by setUp()
40 test_timeout = 0
41 test_iterations = 0
42
Ken Chiang20a3da52012-07-11 09:13:57 -070043 def controllerSetup(self, host, port):
44 self.controller = controller.Controller(host=host,port=port)
45
46 # clean_shutdown should be set to False to force quit app
47 self.clean_shutdown = True
48
49 self.controller.start()
50 #@todo Add an option to wait for a pkt transaction to ensure version
51 # compatibilty?
Dan Talayco907efa22012-09-19 11:30:06 -070052 self.controller.connect(timeout=10)
Ken Chiang20a3da52012-07-11 09:13:57 -070053 self.assertTrue(self.controller.active,
54 "Controller startup failed, not active")
55 self.assertTrue(self.controller.switch_addr is not None,
56 "Controller startup failed, no switch addr")
Dan Talayco907efa22012-09-19 11:30:06 -070057 request = message.features_request()
Dan Talaycoc689a792012-09-28 14:22:53 -070058 reply, pkt = self.controller.transact(request, timeout=20)
Dan Talayco907efa22012-09-19 11:30:06 -070059 self.assertTrue(reply is not None,
60 "Did not complete features_request for handshake")
Rich Lane9a003812012-10-04 17:17:59 -070061 logging.info("Connected " +
Ken Chiang20a3da52012-07-11 09:13:57 -070062 str(self.controller.switch_addr))
63
64 # send echo request and wait for reply
65 request = message.echo_request()
66 response, pkt = self.controller.transact(request)
67 self.assertEqual(response.header.type, ofp.OFPT_ECHO_REPLY,
68 'response is not echo_reply')
69 self.assertEqual(request.header.xid, response.header.xid,
70 'response xid != request xid')
71 self.assertEqual(len(response.data), 0, 'response data non-empty')
72
73 def connectionKill(self, kill_method):
74 if kill_method == 'controller_shutdown':
Rich Lane9a003812012-10-04 17:17:59 -070075 logging.info("Shutting down controller")
Ken Chiang20a3da52012-07-11 09:13:57 -070076 self.controller.shutdown()
77 elif kill_method == 'no_echo':
Rich Lane9a003812012-10-04 17:17:59 -070078 logging.info("Disabling controller keep alive")
Ken Chiang20a3da52012-07-11 09:13:57 -070079 self.controller.keep_alive = False
80
81 # wait for controller to die
82 count = 0
83 while self.controller.active and count < self.test_timeout:
84 time.sleep(1)
85 count = count + 1
86 else:
87 self.assertTrue(false, "Unknown controller kill method")
88
89 def buildControllerList(self):
90 # controller_list is list of ip/port tuples
Rich Lane477f4812012-10-04 22:49:00 -070091 partial_list = test_param_get(config,
Ken Chiang20a3da52012-07-11 09:13:57 -070092 'controller_list')
Rich Lane9a003812012-10-04 17:17:59 -070093 logging.debug("ctrl list: " + str(partial_list))
Rich Lane477f4812012-10-04 22:49:00 -070094 self.controller_list = [(config["controller_host"],
95 config["controller_port"])]
Ken Chiang20a3da52012-07-11 09:13:57 -070096 if partial_list is not None:
97 for controller in partial_list:
98 ip,portstr = controller.split(':')
99 try:
100 port = int(portstr)
101 except:
102 self.assertTrue(0, "failure converting port " +
103 portstr + " to integer")
104 self.controller_list.append( (ip, int(port)) )
105
106 def getController(self):
107 return self.controller_list[self.controller_idx]
108
109 def getNextController(self):
110 self.controller_idx = (self.controller_idx + 1) \
111 % len(self.controller_list)
112 return self.controller_list[self.controller_idx]
113
114 def setUp(self):
Rich Lane9a003812012-10-04 17:17:59 -0700115 logging.info("** START TEST CASE " + str(self))
Ken Chiang20a3da52012-07-11 09:13:57 -0700116
Rich Lane477f4812012-10-04 22:49:00 -0700117 self.test_timeout = test_param_get(config,
Ken Chiang20a3da52012-07-11 09:13:57 -0700118 'failover_timeout') or 60
Rich Lane477f4812012-10-04 22:49:00 -0700119 self.test_iterations = test_param_get(config,
Ken Chiang20a3da52012-07-11 09:13:57 -0700120 'failover_iterations') or 4
121
122 self.buildControllerList()
123 self.controller_idx = 0
124 controller = self.getController()
125 self.controllerSetup(controller[0], controller[1])
126
127 def inheritSetup(self, parent):
128 """
129 Inherit the setup of a parent
130
131 This allows running at test from within another test. Do the
132 following:
133
134 sub_test = SomeTestClass() # Create an instance of the test class
135 sub_test.inheritSetup(self) # Inherit setup of parent
136 sub_test.runTest() # Run the test
137
138 Normally, only the parent's setUp and tearDown are called and
139 the state after the sub_test is run must be taken into account
140 by subsequent operations.
141 """
Rich Lane9a003812012-10-04 17:17:59 -0700142 logging.info("** Setup " + str(self) +
Ken Chiang20a3da52012-07-11 09:13:57 -0700143 " inheriting from " + str(parent))
144 self.controller = parent.controller
145
146 def tearDown(self):
Rich Lane9a003812012-10-04 17:17:59 -0700147 logging.info("** END TEST CASE " + str(self))
Ken Chiang20a3da52012-07-11 09:13:57 -0700148 self.controller.shutdown()
149 if self.clean_shutdown:
150 self.controller.join()
151
152 def doFailover(self, killmethod):
Rich Lane9a003812012-10-04 17:17:59 -0700153 logging.info("Starting serial failover test")
Ken Chiang20a3da52012-07-11 09:13:57 -0700154 self.assertTrue(self.controller.switch_socket is not None,
155 str(self) + 'No connection to switch')
156 # kill controller connection
157 self.connectionKill(killmethod)
158 # establish new controller connection
159 controller = self.getNextController()
Rich Lane9a003812012-10-04 17:17:59 -0700160 logging.debug("** Next controller (%u/%u)%s:%u" %
Ken Chiang20a3da52012-07-11 09:13:57 -0700161 (self.controller_idx,
162 len(self.controller_list),
163 controller[0],
164 controller[1]))
165 self.controllerSetup(controller[0], controller[1])
166
167 def runTest(self):
168 for i in range(0,self.test_iterations):
169 self.doFailover('controller_shutdown')
170
171 def assertTrue(self, cond, msg):
172 if not cond:
Rich Lane9a003812012-10-04 17:17:59 -0700173 logging.error("** FAILED ASSERTION: " + msg)
Ken Chiang20a3da52012-07-11 09:13:57 -0700174 unittest.TestCase.assertTrue(self, cond, msg)
175
Ken Chiang20a3da52012-07-11 09:13:57 -0700176
177class SerialFailoverNoEcho(SerialFailover):
Rich Laned1d9c282012-10-04 22:07:10 -0700178 priority = -1
Ken Chiang20a3da52012-07-11 09:13:57 -0700179
180 def runTest(self):
181 for i in range(0,self.test_iterations):
182 self.doFailover('no_echo')