blob: 600c50ba0a070e7cfac02a729c9b8697ddceeb27 [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
144 signal.signal(signal.SIGINT, self.sig_handler)
145 serial_failover_logger.info("** START TEST CASE " + str(self))
146
147 self.test_timeout = test_param_get(serial_failover_config,
148 'failover_timeout') or 60
149 self.test_iterations = test_param_get(serial_failover_config,
150 'failover_iterations') or 4
151
152 self.buildControllerList()
153 self.controller_idx = 0
154 controller = self.getController()
155 self.controllerSetup(controller[0], controller[1])
156
157 def inheritSetup(self, parent):
158 """
159 Inherit the setup of a parent
160
161 This allows running at test from within another test. Do the
162 following:
163
164 sub_test = SomeTestClass() # Create an instance of the test class
165 sub_test.inheritSetup(self) # Inherit setup of parent
166 sub_test.runTest() # Run the test
167
168 Normally, only the parent's setUp and tearDown are called and
169 the state after the sub_test is run must be taken into account
170 by subsequent operations.
171 """
172 self.logger = parent.logger
173 self.config = parent.config
174 serial_failover_logger.info("** Setup " + str(self) +
175 " inheriting from " + str(parent))
176 self.controller = parent.controller
177
178 def tearDown(self):
179 serial_failover_logger.info("** END TEST CASE " + str(self))
180 self.controller.shutdown()
181 if self.clean_shutdown:
182 self.controller.join()
183
184 def doFailover(self, killmethod):
185 serial_failover_logger.info("Starting serial failover test")
186 self.assertTrue(self.controller.switch_socket is not None,
187 str(self) + 'No connection to switch')
188 # kill controller connection
189 self.connectionKill(killmethod)
190 # establish new controller connection
191 controller = self.getNextController()
192 serial_failover_logger.debug("** Next controller (%u/%u)%s:%u" %
193 (self.controller_idx,
194 len(self.controller_list),
195 controller[0],
196 controller[1]))
197 self.controllerSetup(controller[0], controller[1])
198
199 def runTest(self):
200 for i in range(0,self.test_iterations):
201 self.doFailover('controller_shutdown')
202
203 def assertTrue(self, cond, msg):
204 if not cond:
205 serial_failover_logger.error("** FAILED ASSERTION: " + msg)
206 unittest.TestCase.assertTrue(self, cond, msg)
207
208test_prio["SerialFailover"] = -1
209
210
211class SerialFailoverNoEcho(SerialFailover):
212
213 def runTest(self):
214 for i in range(0,self.test_iterations):
215 self.doFailover('no_echo')
216
217test_prio["SerialFailoverNoEcho"] = -1
218