blob: 97df2f8f9a5ab9dc80151884d8314d1d0e13d806 [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
13import oftest.controller as controller
14import oftest.cstruct as ofp
15import oftest.message as message
16import oftest.dataplane as dataplane
17import oftest.action as action
18
Rich Laneda3b5ad2012-10-03 09:05:32 -070019from oftest.testutils import *
Ken Chiang20a3da52012-07-11 09:13:57 -070020
21#@var serial_failover_port_map Local copy of the configuration map from OF port
22# numbers to OS interfaces
23serial_failover_port_map = None
Ken Chiang20a3da52012-07-11 09:13:57 -070024#@var serial_failover_config Local copy of global configuration data
25serial_failover_config = None
26
Ken Chiang20a3da52012-07-11 09:13:57 -070027def test_set_init(config):
28 """
29 Set up function for serial failover test classes
30
31 @param config The configuration dictionary; see oft
32 """
33
34 global serial_failover_port_map
Ken Chiang20a3da52012-07-11 09:13:57 -070035 global serial_failover_config
36
Ken Chiang20a3da52012-07-11 09:13:57 -070037 serial_failover_port_map = config["port_map"]
38 serial_failover_config = config
39
40class SerialFailover(unittest.TestCase):
41 """
42 Opens a connection that the switch should use as its only controller,
43 as specified by controller_host and controller_port.
44 Then cause the connection to fail [fail method should be configurable].
45 Ultimately, the switch should connect to the next controller port,
46 as specified by
47 --test-params="controller_list=['ip2:port2','ip3:port3']".
48 Multiple test params are specified by
49 --test-params="param1=val1;param2=val2"
50 """
51
Rich Laned1d9c282012-10-04 22:07:10 -070052 priority = -1
53
Ken Chiang20a3da52012-07-11 09:13:57 -070054 # populated by buildControllerList()
55 controller_list = []
56 controller_idx = 0
57 # populated by setUp()
58 test_timeout = 0
59 test_iterations = 0
60
Ken Chiang20a3da52012-07-11 09:13:57 -070061 def controllerSetup(self, host, port):
62 self.controller = controller.Controller(host=host,port=port)
63
64 # clean_shutdown should be set to False to force quit app
65 self.clean_shutdown = True
66
67 self.controller.start()
68 #@todo Add an option to wait for a pkt transaction to ensure version
69 # compatibilty?
Dan Talayco907efa22012-09-19 11:30:06 -070070 self.controller.connect(timeout=10)
Ken Chiang20a3da52012-07-11 09:13:57 -070071 self.assertTrue(self.controller.active,
72 "Controller startup failed, not active")
73 self.assertTrue(self.controller.switch_addr is not None,
74 "Controller startup failed, no switch addr")
Dan Talayco907efa22012-09-19 11:30:06 -070075 request = message.features_request()
Dan Talaycoc689a792012-09-28 14:22:53 -070076 reply, pkt = self.controller.transact(request, timeout=20)
Dan Talayco907efa22012-09-19 11:30:06 -070077 self.assertTrue(reply is not None,
78 "Did not complete features_request for handshake")
Rich Lane9a003812012-10-04 17:17:59 -070079 logging.info("Connected " +
Ken Chiang20a3da52012-07-11 09:13:57 -070080 str(self.controller.switch_addr))
81
82 # send echo request and wait for reply
83 request = message.echo_request()
84 response, pkt = self.controller.transact(request)
85 self.assertEqual(response.header.type, ofp.OFPT_ECHO_REPLY,
86 'response is not echo_reply')
87 self.assertEqual(request.header.xid, response.header.xid,
88 'response xid != request xid')
89 self.assertEqual(len(response.data), 0, 'response data non-empty')
90
91 def connectionKill(self, kill_method):
92 if kill_method == 'controller_shutdown':
Rich Lane9a003812012-10-04 17:17:59 -070093 logging.info("Shutting down controller")
Ken Chiang20a3da52012-07-11 09:13:57 -070094 self.controller.shutdown()
95 elif kill_method == 'no_echo':
Rich Lane9a003812012-10-04 17:17:59 -070096 logging.info("Disabling controller keep alive")
Ken Chiang20a3da52012-07-11 09:13:57 -070097 self.controller.keep_alive = False
98
99 # wait for controller to die
100 count = 0
101 while self.controller.active and count < self.test_timeout:
102 time.sleep(1)
103 count = count + 1
104 else:
105 self.assertTrue(false, "Unknown controller kill method")
106
107 def buildControllerList(self):
108 # controller_list is list of ip/port tuples
109 partial_list = test_param_get(serial_failover_config,
110 'controller_list')
Rich Lane9a003812012-10-04 17:17:59 -0700111 logging.debug("ctrl list: " + str(partial_list))
Ken Chiang20a3da52012-07-11 09:13:57 -0700112 self.controller_list = [(serial_failover_config["controller_host"],
113 serial_failover_config["controller_port"])]
114 if partial_list is not None:
115 for controller in partial_list:
116 ip,portstr = controller.split(':')
117 try:
118 port = int(portstr)
119 except:
120 self.assertTrue(0, "failure converting port " +
121 portstr + " to integer")
122 self.controller_list.append( (ip, int(port)) )
123
124 def getController(self):
125 return self.controller_list[self.controller_idx]
126
127 def getNextController(self):
128 self.controller_idx = (self.controller_idx + 1) \
129 % len(self.controller_list)
130 return self.controller_list[self.controller_idx]
131
132 def setUp(self):
Ken Chiang20a3da52012-07-11 09:13:57 -0700133 self.config = serial_failover_config
Rich Lane9a003812012-10-04 17:17:59 -0700134 logging.info("** START TEST CASE " + str(self))
Ken Chiang20a3da52012-07-11 09:13:57 -0700135
136 self.test_timeout = test_param_get(serial_failover_config,
137 'failover_timeout') or 60
138 self.test_iterations = test_param_get(serial_failover_config,
139 'failover_iterations') or 4
140
141 self.buildControllerList()
142 self.controller_idx = 0
143 controller = self.getController()
144 self.controllerSetup(controller[0], controller[1])
145
146 def inheritSetup(self, parent):
147 """
148 Inherit the setup of a parent
149
150 This allows running at test from within another test. Do the
151 following:
152
153 sub_test = SomeTestClass() # Create an instance of the test class
154 sub_test.inheritSetup(self) # Inherit setup of parent
155 sub_test.runTest() # Run the test
156
157 Normally, only the parent's setUp and tearDown are called and
158 the state after the sub_test is run must be taken into account
159 by subsequent operations.
160 """
Ken Chiang20a3da52012-07-11 09:13:57 -0700161 self.config = parent.config
Rich Lane9a003812012-10-04 17:17:59 -0700162 logging.info("** Setup " + str(self) +
Ken Chiang20a3da52012-07-11 09:13:57 -0700163 " inheriting from " + str(parent))
164 self.controller = parent.controller
165
166 def tearDown(self):
Rich Lane9a003812012-10-04 17:17:59 -0700167 logging.info("** END TEST CASE " + str(self))
Ken Chiang20a3da52012-07-11 09:13:57 -0700168 self.controller.shutdown()
169 if self.clean_shutdown:
170 self.controller.join()
171
172 def doFailover(self, killmethod):
Rich Lane9a003812012-10-04 17:17:59 -0700173 logging.info("Starting serial failover test")
Ken Chiang20a3da52012-07-11 09:13:57 -0700174 self.assertTrue(self.controller.switch_socket is not None,
175 str(self) + 'No connection to switch')
176 # kill controller connection
177 self.connectionKill(killmethod)
178 # establish new controller connection
179 controller = self.getNextController()
Rich Lane9a003812012-10-04 17:17:59 -0700180 logging.debug("** Next controller (%u/%u)%s:%u" %
Ken Chiang20a3da52012-07-11 09:13:57 -0700181 (self.controller_idx,
182 len(self.controller_list),
183 controller[0],
184 controller[1]))
185 self.controllerSetup(controller[0], controller[1])
186
187 def runTest(self):
188 for i in range(0,self.test_iterations):
189 self.doFailover('controller_shutdown')
190
191 def assertTrue(self, cond, msg):
192 if not cond:
Rich Lane9a003812012-10-04 17:17:59 -0700193 logging.error("** FAILED ASSERTION: " + msg)
Ken Chiang20a3da52012-07-11 09:13:57 -0700194 unittest.TestCase.assertTrue(self, cond, msg)
195
Ken Chiang20a3da52012-07-11 09:13:57 -0700196
197class SerialFailoverNoEcho(SerialFailover):
Rich Laned1d9c282012-10-04 22:07:10 -0700198 priority = -1
Ken Chiang20a3da52012-07-11 09:13:57 -0700199
200 def runTest(self):
201 for i in range(0,self.test_iterations):
202 self.doFailover('no_echo')