blob: 90a423641125caea6842b975abe9384d68382542 [file] [log] [blame]
Ken Chiang20a3da52012-07-11 09:13:57 -07001"""
2Serial failover test cases
3
4"""
5
6import time
7import signal
8import sys
9import logging
10
11import unittest
12import random
13
14import 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
20from testutils import *
21
22#@var serial_failover_port_map Local copy of the configuration map from OF port
23# numbers to OS interfaces
24serial_failover_port_map = None
25#@var serial_failover_logger Local logger object
26serial_failover_logger = None
27#@var serial_failover_config Local copy of global configuration data
28serial_failover_config = None
29
30test_prio = {}
31
32def test_set_init(config):
33 """
34 Set up function for serial failover test classes
35
36 @param config The configuration dictionary; see oft
37 """
38
39 global serial_failover_port_map
40 global serial_failover_logger
41 global serial_failover_config
42
43 serial_failover_logger = logging.getLogger("serial_failover")
44 serial_failover_logger.info("Initializing test set")
45 serial_failover_port_map = config["port_map"]
46 serial_failover_config = config
47
48class SerialFailover(unittest.TestCase):
49 """
50 Opens a connection that the switch should use as its only controller,
51 as specified by controller_host and controller_port.
52 Then cause the connection to fail [fail method should be configurable].
53 Ultimately, the switch should connect to the next controller port,
54 as specified by
55 --test-params="controller_list=['ip2:port2','ip3:port3']".
56 Multiple test params are specified by
57 --test-params="param1=val1;param2=val2"
58 """
59
60 # populated by buildControllerList()
61 controller_list = []
62 controller_idx = 0
63 # populated by setUp()
64 test_timeout = 0
65 test_iterations = 0
66
67 def sig_handler(self, v1, v2):
68 serial_failover_logger.critical("Received interrupt signal; exiting")
69 print "Received interrupt signal; exiting"
70 self.clean_shutdown = False
71 self.tearDown()
72 sys.exit(1)
73
74 def controllerSetup(self, host, port):
75 self.controller = controller.Controller(host=host,port=port)
76
77 # clean_shutdown should be set to False to force quit app
78 self.clean_shutdown = True
79
80 self.controller.start()
81 #@todo Add an option to wait for a pkt transaction to ensure version
82 # compatibilty?
Rich Lanec8aaa3e2012-07-26 19:28:02 -070083 self.controller.connect()
Ken Chiang20a3da52012-07-11 09:13:57 -070084 self.assertTrue(self.controller.active,
85 "Controller startup failed, not active")
86 self.assertTrue(self.controller.switch_addr is not None,
87 "Controller startup failed, no switch addr")
88 serial_failover_logger.info("Connected " +
89 str(self.controller.switch_addr))
90
91 # send echo request and wait for reply
92 request = message.echo_request()
93 response, pkt = self.controller.transact(request)
94 self.assertEqual(response.header.type, ofp.OFPT_ECHO_REPLY,
95 'response is not echo_reply')
96 self.assertEqual(request.header.xid, response.header.xid,
97 'response xid != request xid')
98 self.assertEqual(len(response.data), 0, 'response data non-empty')
99
100 def connectionKill(self, kill_method):
101 if kill_method == 'controller_shutdown':
102 serial_failover_logger.info("Shutting down controller")
103 self.controller.shutdown()
104 elif kill_method == 'no_echo':
105 serial_failover_logger.info("Disabling controller keep alive")
106 self.controller.keep_alive = False
107
108 # wait for controller to die
109 count = 0
110 while self.controller.active and count < self.test_timeout:
111 time.sleep(1)
112 count = count + 1
113 else:
114 self.assertTrue(false, "Unknown controller kill method")
115
116 def buildControllerList(self):
117 # controller_list is list of ip/port tuples
118 partial_list = test_param_get(serial_failover_config,
119 'controller_list')
120 serial_failover_logger.debug(str(partial_list))
121 self.controller_list = [(serial_failover_config["controller_host"],
122 serial_failover_config["controller_port"])]
123 if partial_list is not None:
124 for controller in partial_list:
125 ip,portstr = controller.split(':')
126 try:
127 port = int(portstr)
128 except:
129 self.assertTrue(0, "failure converting port " +
130 portstr + " to integer")
131 self.controller_list.append( (ip, int(port)) )
132
133 def getController(self):
134 return self.controller_list[self.controller_idx]
135
136 def getNextController(self):
137 self.controller_idx = (self.controller_idx + 1) \
138 % len(self.controller_list)
139 return self.controller_list[self.controller_idx]
140
141 def setUp(self):
142 self.logger = serial_failover_logger
143 self.config = serial_failover_config
Ed Swierk022d02e2012-08-22 06:26:36 -0700144 #@todo Test cases shouldn't monkey with signals; move SIGINT handler
145 # to top-level oft
146 try:
147 signal.signal(signal.SIGINT, self.sig_handler)
148 except ValueError, e:
149 serial_failover_logger.info("Could not set SIGINT handler: %s" % e)
Ken Chiang20a3da52012-07-11 09:13:57 -0700150 serial_failover_logger.info("** START TEST CASE " + str(self))
151
152 self.test_timeout = test_param_get(serial_failover_config,
153 'failover_timeout') or 60
154 self.test_iterations = test_param_get(serial_failover_config,
155 'failover_iterations') or 4
156
157 self.buildControllerList()
158 self.controller_idx = 0
159 controller = self.getController()
160 self.controllerSetup(controller[0], controller[1])
161
162 def inheritSetup(self, parent):
163 """
164 Inherit the setup of a parent
165
166 This allows running at test from within another test. Do the
167 following:
168
169 sub_test = SomeTestClass() # Create an instance of the test class
170 sub_test.inheritSetup(self) # Inherit setup of parent
171 sub_test.runTest() # Run the test
172
173 Normally, only the parent's setUp and tearDown are called and
174 the state after the sub_test is run must be taken into account
175 by subsequent operations.
176 """
177 self.logger = parent.logger
178 self.config = parent.config
179 serial_failover_logger.info("** Setup " + str(self) +
180 " inheriting from " + str(parent))
181 self.controller = parent.controller
182
183 def tearDown(self):
184 serial_failover_logger.info("** END TEST CASE " + str(self))
185 self.controller.shutdown()
186 if self.clean_shutdown:
187 self.controller.join()
188
189 def doFailover(self, killmethod):
190 serial_failover_logger.info("Starting serial failover test")
191 self.assertTrue(self.controller.switch_socket is not None,
192 str(self) + 'No connection to switch')
193 # kill controller connection
194 self.connectionKill(killmethod)
195 # establish new controller connection
196 controller = self.getNextController()
197 serial_failover_logger.debug("** Next controller (%u/%u)%s:%u" %
198 (self.controller_idx,
199 len(self.controller_list),
200 controller[0],
201 controller[1]))
202 self.controllerSetup(controller[0], controller[1])
203
204 def runTest(self):
205 for i in range(0,self.test_iterations):
206 self.doFailover('controller_shutdown')
207
208 def assertTrue(self, cond, msg):
209 if not cond:
210 serial_failover_logger.error("** FAILED ASSERTION: " + msg)
211 unittest.TestCase.assertTrue(self, cond, msg)
212
213test_prio["SerialFailover"] = -1
214
215
216class SerialFailoverNoEcho(SerialFailover):
217
218 def runTest(self):
219 for i in range(0,self.test_iterations):
220 self.doFailover('no_echo')
221
222test_prio["SerialFailoverNoEcho"] = -1
223