blob: 9e92a99997688a2a4cfbd0a5234252ac40dbaaeb [file] [log] [blame]
Dan Talayco48370102010-03-03 15:17:33 -08001#!/usr/bin/env python
2"""
3@package oft
4
5OpenFlow test framework top level script
6
7This script is the entry point for running OpenFlow tests
8using the OFT framework.
9
10The global configuration is passed around in a dictionary
Brandon Heller88f709d2010-04-01 12:29:56 -070011generally called config. The keys have the following
Dan Talayco48370102010-03-03 15:17:33 -080012significance.
13
Dan Talayco2c0dba32010-03-06 22:47:06 -080014<pre>
Dan Talayco48370102010-03-03 15:17:33 -080015 platform : String identifying the target platform
16 controller_host : Host on which test controller is running (for sockets)
17 controller_port : Port on which test controller listens for switch cxn
Dan Talayco2c0dba32010-03-06 22:47:06 -080018 test_dir : (TBD) Directory to search for test files (default .)
Dan Talayco48370102010-03-03 15:17:33 -080019 test_spec : (TBD) Specification of test(s) to run
20 log_file : Filename for test logging
Dan Talayco2c0dba32010-03-06 22:47:06 -080021 list : Boolean: List all tests and exit
Dan Talayco48370102010-03-03 15:17:33 -080022 debug : String giving debug level (info, warning, error...)
Dan Talayco2c0dba32010-03-06 22:47:06 -080023</pre>
Dan Talayco48370102010-03-03 15:17:33 -080024
25See config_defaults below for the default values.
26
Dan Talayco2c0dba32010-03-06 22:47:06 -080027The following are stored in the config dictionary, but are not currently
28configurable through the command line.
29
30<pre>
31 dbg_level : logging module value of debug level
32 port_map : Map of dataplane OpenFlow port to OS interface names
Dan Talayco2c0dba32010-03-06 22:47:06 -080033</pre>
34
Rich Laned1d9c282012-10-04 22:07:10 -070035Each test may be assigned a priority by setting the "priority" property
36in the class definition. For now, the only use of this is to avoid
Dan Talaycoc24aaae2010-07-08 14:05:24 -070037automatic inclusion of tests into the default list. This is done by
Rich Laned1d9c282012-10-04 22:07:10 -070038setting the priority value less than 0. Eventually we may add ordering
Dan Talaycoc24aaae2010-07-08 14:05:24 -070039of test execution by test priority.
40
Dan Talayco2c0dba32010-03-06 22:47:06 -080041To add a test to the system, either: edit an existing test case file (like
42basic.py) to add a test class which inherits from unittest.TestCase (directly
Rich Lane477f4812012-10-04 22:49:00 -070043or indirectly); or add a new file with the test case class. Preferably the
44file is in the same directory as existing tests, though you can specify the
45directory on the command line. The file should not be called "all" as that's
46reserved for the test-spec.
Dan Talayco2c0dba32010-03-06 22:47:06 -080047
48TBD: To add configuration to the system, first add an entry to config_default
Dan Talayco48370102010-03-03 15:17:33 -080049below. If you want this to be a command line parameter, edit config_setup
50to add the option and default value to the parser. Then edit config_get
51to make sure the option value gets copied into the configuration
52structure (which then gets passed to everyone else).
53
54By convention, oft attempts to import the contents of a file by the
55name of $platform.py into the local namespace.
56
57IMPORTANT: That file should define a function platform_config_update which
58takes a configuration dictionary as an argument and updates it for the
59current run. In particular, it should set up config["port_map"] with
60the proper map from OF port numbers to OF interface names.
61
Rich Lane8aebc5e2012-09-25 17:57:53 -070062You can add your own platform, say gp104, by adding a file gp104.py to the
63platforms directory that defines the function platform_config_update and then
64use the parameter --platform=gp104 on the command line. You can also use the
65--platform-dir option to change which directory is searched.
Dan Talayco48370102010-03-03 15:17:33 -080066
Rich Lane477f4812012-10-04 22:49:00 -070067The current model for test sets is basic.py.
Dan Talayco48370102010-03-03 15:17:33 -080068
Dan Talayco52f64442010-03-03 15:32:41 -080069Default setup:
70
71The default setup runs locally using veth pairs. To exercise this,
72checkout and build an openflow userspace datapath. Then start it on
73the local host:
Dan Talayco2c0dba32010-03-06 22:47:06 -080074<pre>
Dan Talayco52f64442010-03-03 15:32:41 -080075 sudo ~/openflow/regress/bin/veth_setup.pl
76 sudo ofdatapath -i veth0,veth2,veth4,veth6 punix:/tmp/ofd &
77 sudo ofprotocol unix:/tmp/ofd tcp:127.0.0.1 --fail=closed --max-backoff=1 &
78
79Next, run oft:
80 sudo ./oft --debug=info
Dan Talayco2c0dba32010-03-06 22:47:06 -080081</pre>
Dan Talayco52f64442010-03-03 15:32:41 -080082
83Examine oft.log if things don't work.
Dan Talayco2c0dba32010-03-06 22:47:06 -080084
Dan Talayco1a88c122010-03-07 22:00:20 -080085@todo Support per-component debug levels (esp controller vs dataplane)
Rich Lane15f64de2012-10-04 21:25:57 -070086@todo Allow specification of priority to override prio check
Dan Talayco2c0dba32010-03-06 22:47:06 -080087
Dan Talayco1a88c122010-03-07 22:00:20 -080088Current test case setup:
Rich Lane477f4812012-10-04 22:49:00 -070089 File with the .py extension in the test directory are considered test files.
90 Support a command line option --test-spec to choose the tests to run.
91 Support test-spec "all" to specify all tests.
Dan Talayco48370102010-03-03 15:17:33 -080092"""
93
94import sys
95from optparse import OptionParser
Dan Talayco2c0dba32010-03-06 22:47:06 -080096from subprocess import Popen,PIPE
Dan Talayco48370102010-03-03 15:17:33 -080097import logging
98import unittest
Dan Talayco2c0dba32010-03-06 22:47:06 -080099import time
Brandon Heller446c1432010-04-01 12:43:27 -0700100import os
Rich Lane6b452bc2012-07-09 16:52:21 -0700101import imp
Rich Lane8592bec2012-09-03 09:06:59 -0700102import random
Rich Lane5bd6cf92012-10-04 17:57:24 -0700103import signal
Rich Lane943be672012-10-04 19:20:16 -0700104import fnmatch
Dan Talayco48370102010-03-03 15:17:33 -0800105
Rich Lanefadf3452012-10-03 16:23:37 -0700106root_dir = os.path.dirname(os.path.realpath(__file__))
107
108pydir = os.path.join(root_dir, 'src', 'python')
Rich Lane39878042012-07-09 14:45:35 -0700109if os.path.exists(os.path.join(pydir, 'oftest')):
110 # Running from source tree
111 sys.path.insert(0, pydir)
112
Rich Lane477f4812012-10-04 22:49:00 -0700113import oftest
114from oftest import config
115
Rich Laneb0470142012-10-04 15:50:35 -0700116try:
117 import oftest.message
118except:
119 sys.exit("Missing OpenFlow message classes: please run \"make -C tools/munger\"")
120
Rich Laneda3b5ad2012-10-03 09:05:32 -0700121import oftest.testutils
Rich Lanee55abf72012-07-26 20:11:42 -0700122import oftest.ofutils
Dan Talaycoba3745c2010-07-21 21:51:08 -0700123
Dan Talayco02eca0b2010-04-15 16:09:43 -0700124try:
125 import scapy.all as scapy
126except:
127 try:
128 import scapy as scapy
129 except:
130 sys.exit("Need to install scapy for packet parsing")
131
Dan Talaycod7c80d12012-04-03 15:20:57 -0700132##@var Profile module
133profile_mod = None
134
Dan Talayco48370102010-03-03 15:17:33 -0800135##@var DEBUG_LEVELS
136# Map from strings to debugging levels
137DEBUG_LEVELS = {
138 'debug' : logging.DEBUG,
139 'verbose' : logging.DEBUG,
140 'info' : logging.INFO,
141 'warning' : logging.WARNING,
142 'warn' : logging.WARNING,
143 'error' : logging.ERROR,
144 'critical' : logging.CRITICAL
145}
146
147_debug_default = "warning"
148_debug_level_default = DEBUG_LEVELS[_debug_default]
149
150##@var config_default
151# The default configuration dictionary for OFT
152config_default = {
Dan Talayco551befa2010-07-15 17:05:32 -0700153 "param" : None,
Dan Talayco48370102010-03-03 15:17:33 -0800154 "platform" : "local",
Rich Lane941d1dd2012-07-30 14:27:53 -0700155 "platform_args" : None,
Rich Lane1aeccc42012-07-29 17:58:10 -0700156 "controller_host" : "0.0.0.0",
Dan Talayco48370102010-03-03 15:17:33 -0800157 "controller_port" : 6633,
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700158 "relax" : False,
Dan Talayco2c0dba32010-03-06 22:47:06 -0800159 "test_spec" : "all",
Dan Talayco48370102010-03-03 15:17:33 -0800160 "log_file" : "oft.log",
Dan Talayco2c0dba32010-03-06 22:47:06 -0800161 "list" : False,
Jeffrey Townsend6614f972012-08-16 13:27:18 -0700162 "list_test_names" : False,
Dan Talayco48370102010-03-03 15:17:33 -0800163 "debug" : _debug_default,
164 "dbg_level" : _debug_level_default,
Dan Talaycoac25cf32010-07-20 14:08:28 -0700165 "port_map" : {},
Dan Talaycod7c80d12012-04-03 15:20:57 -0700166 "test_params" : "None",
Rich Lane1673b8f2012-09-25 18:35:18 -0700167 "profile" : "default",
Rich Laneee57ad02012-07-13 15:40:36 -0700168 "allow_user" : False,
Rich Lane9a84a4f2012-07-17 12:27:42 -0700169 "fail_skipped" : False,
Rich Lanee55abf72012-07-26 20:11:42 -0700170 "default_timeout" : 2,
Jeffrey Townsend5cb7ed32012-08-17 18:11:01 +0000171 "minsize" : 0,
Rich Lane8592bec2012-09-03 09:06:59 -0700172 "random_seed" : None,
Rich Lanee284b6b2012-10-03 09:19:58 -0700173 "test_dir" : os.path.join(root_dir, "tests"),
Rich Lane8aebc5e2012-09-25 17:57:53 -0700174 "platform_dir" : os.path.join(root_dir, "platforms"),
Rich Lane1673b8f2012-09-25 18:35:18 -0700175 "profile_dir" : os.path.join(root_dir, "profiles"),
Rich Lane8260a2d2012-10-09 14:58:35 -0700176 "priority" : 0,
Dan Talayco48370102010-03-03 15:17:33 -0800177}
178
Dan Talaycoc24aaae2010-07-08 14:05:24 -0700179# Default test priority
180TEST_PRIO_DEFAULT=100
Dan Talaycod7c80d12012-04-03 15:20:57 -0700181TEST_PRIO_SKIP=-1
Dan Talaycoc24aaae2010-07-08 14:05:24 -0700182
Dan Talayco1a88c122010-03-07 22:00:20 -0800183#@todo Set up a dict of config params so easier to manage:
184# <param> <cmdline flags> <default value> <help> <optional parser>
185
Dan Talayco48370102010-03-03 15:17:33 -0800186# Map options to config structure
187def config_get(opts):
188 "Convert options class to OFT configuration dictionary"
189 cfg = config_default.copy()
Dan Talayco2c0dba32010-03-06 22:47:06 -0800190 for key in cfg.keys():
Rich Lanea92f2522012-10-04 18:11:04 -0700191 cfg[key] = getattr(opts, key)
Dan Talayco2c0dba32010-03-06 22:47:06 -0800192
193 # Special case checks
Dan Talayco48370102010-03-03 15:17:33 -0800194 if opts.debug not in DEBUG_LEVELS.keys():
195 print "Warning: Bad value specified for debug level; using default"
196 opts.debug = _debug_default
Dan Talayco02eca0b2010-04-15 16:09:43 -0700197 if opts.verbose:
198 cfg["debug"] = "verbose"
Dan Talayco48370102010-03-03 15:17:33 -0800199 cfg["dbg_level"] = DEBUG_LEVELS[cfg["debug"]]
Dan Talayco2c0dba32010-03-06 22:47:06 -0800200
Dan Talayco48370102010-03-03 15:17:33 -0800201 return cfg
202
203def config_setup(cfg_dflt):
204 """
205 Set up the configuration including parsing the arguments
206
207 @param cfg_dflt The default configuration dictionary
208 @return A pair (config, args) where config is an config
209 object and args is any additional arguments from the command line
210 """
211
212 parser = OptionParser(version="%prog 0.1")
213
Dan Talayco2c0dba32010-03-06 22:47:06 -0800214 #@todo parse port map as option?
Dan Talayco48370102010-03-03 15:17:33 -0800215 # Set up default values
Rich Lanea92f2522012-10-04 18:11:04 -0700216 parser.set_defaults(**cfg_dflt)
Dan Talayco48370102010-03-03 15:17:33 -0800217
Dan Talayco2c0dba32010-03-06 22:47:06 -0800218 #@todo Add options via dictionary
Dan Talayco48370102010-03-03 15:17:33 -0800219 plat_help = """Set the platform type. Valid values include:
220 local: User space virtual ethernet pair setup
221 remote: Remote embedded Broadcom based switch
Dan Talayco673e0852010-03-06 23:09:23 -0800222 Create a new_plat.py file and use --platform=new_plat on the command line
Dan Talayco48370102010-03-03 15:17:33 -0800223 """
Rich Lane941d1dd2012-07-30 14:27:53 -0700224 parser.add_option("-a", "--platform-args", help="Custom arguments per platform.")
Dan Talayco48370102010-03-03 15:17:33 -0800225 parser.add_option("-P", "--platform", help=plat_help)
226 parser.add_option("-H", "--host", dest="controller_host",
227 help="The IP/name of the test controller host")
228 parser.add_option("-p", "--port", dest="controller_port",
229 type="int", help="Port number of the test controller")
Dan Talayco673e0852010-03-06 23:09:23 -0800230 test_list_help = """Indicate tests to run. Valid entries are "all" (the
Dan Talaycocfa172f2012-03-23 12:03:00 -0700231 default) or a comma separated list of:
232 module Run all tests in the named module
Dan Talayco673e0852010-03-06 23:09:23 -0800233 testcase Run tests in all modules with the name testcase
234 module.testcase Run the specific test case
235 """
Rich Lanef261a102012-07-25 13:41:38 -0700236 parser.add_option("-T", "--test-spec", "--test-list", help=test_list_help)
Dan Talayco48370102010-03-03 15:17:33 -0800237 parser.add_option("--log-file",
238 help="Name of log file, empty string to log to console")
239 parser.add_option("--debug",
240 help="Debug lvl: debug, info, warning, error, critical")
Dan Talayco02eca0b2010-04-15 16:09:43 -0700241 parser.add_option("--port-count", type="int",
Dan Talayco48370102010-03-03 15:17:33 -0800242 help="Number of ports to use (optional)")
Dan Talayco02eca0b2010-04-15 16:09:43 -0700243 parser.add_option("--base-of-port", type="int",
Dan Talayco48370102010-03-03 15:17:33 -0800244 help="Base OpenFlow port number (optional)")
Dan Talayco02eca0b2010-04-15 16:09:43 -0700245 parser.add_option("--base-if-index", type="int",
Dan Talayco2c0dba32010-03-06 22:47:06 -0800246 help="Base interface index number (optional)")
Jeffrey Townsend6614f972012-08-16 13:27:18 -0700247 parser.add_option("--list-test-names", action='store_true',
248 help="List only test names.", default=False)
Dan Talayco2c0dba32010-03-06 22:47:06 -0800249 parser.add_option("--list", action="store_true",
Brandon Heller824504e2010-04-01 12:21:37 -0700250 help="List all tests and exit")
Rich Lanee703c682012-10-08 15:45:24 -0700251 parser.add_option("-v", "--verbose", action="store_true",
Dan Talayco02eca0b2010-04-15 16:09:43 -0700252 help="Short cut for --debug=verbose")
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700253 parser.add_option("--relax", action="store_true",
254 help="Relax packet match checks allowing other packets")
Dan Talayco551befa2010-07-15 17:05:32 -0700255 parser.add_option("--param", type="int",
256 help="Parameter sent to test (for debugging)")
Dan Talaycod7c80d12012-04-03 15:20:57 -0700257 parser.add_option("--profile",
258 help="File listing tests to skip/run")
Dan Talaycoac25cf32010-07-20 14:08:28 -0700259 parser.add_option("-t", "--test-params",
Dan Talaycof6e76c02012-03-23 10:56:12 -0700260 help="""Set test parameters: key=val;...
261 NOTE: key MUST be a valid Python identifier, egr_count not egr-count
262 See --list""")
Rich Laneee57ad02012-07-13 15:40:36 -0700263 parser.add_option("--allow-user", action="store_true",
264 help="Proceed even if oftest is not run as root")
Rich Lane9a84a4f2012-07-17 12:27:42 -0700265 parser.add_option("--fail-skipped", action="store_true",
266 help="Return failure if any test was skipped")
Rich Lanee55abf72012-07-26 20:11:42 -0700267 parser.add_option("--default-timeout", type="int",
268 help="Timeout in seconds for most operations")
Jeffrey Townsend5cb7ed32012-08-17 18:11:01 +0000269 parser.add_option("--minsize", type="int",
270 help="Minimum allowable packet size on the dataplane.",
271 default=0)
Rich Lane8592bec2012-09-03 09:06:59 -0700272 parser.add_option("--random-seed", type="int",
273 help="Random number generator seed",
274 default=None)
Rich Lanebc3d2962012-09-25 09:34:17 -0700275 parser.add_option("--test-dir", type="string",
276 help="Directory containing tests")
Rich Lane8aebc5e2012-09-25 17:57:53 -0700277 parser.add_option("--platform-dir", type="string",
278 help="Directory containing platform modules")
Rich Lane1673b8f2012-09-25 18:35:18 -0700279 parser.add_option("--profile-dir", type="string",
280 help="Directory containing profile modules")
Rich Lane8260a2d2012-10-09 14:58:35 -0700281 parser.add_option("--priority", type="int",
282 help="Minimum test priority",
283 default=0)
Jeffrey Townsend5cb7ed32012-08-17 18:11:01 +0000284
Dan Talayco48370102010-03-03 15:17:33 -0800285 # Might need this if other parsers want command line
286 # parser.allow_interspersed_args = False
287 (options, args) = parser.parse_args()
288
289 config = config_get(options)
290
291 return (config, args)
292
Rich Lane1673b8f2012-09-25 18:35:18 -0700293def load_profile(config):
Dan Talaycod15bed52012-04-04 10:39:52 -0700294 """
295 Import a profile from the profiles library
296 """
297
Dan Talaycod7c80d12012-04-03 15:20:57 -0700298 global profile_mod
Rich Lane1673b8f2012-09-25 18:35:18 -0700299 logging.info("Importing profile: %s" % config["profile"])
300 try:
301 profile_mod = imp.load_module(config["profile"], *imp.find_module(config["profile"], [config["profile_dir"]]))
302 if not "skip_test_list" in dir(profile_mod):
303 die("Profile did not define skip_test_list")
304 except:
305 logging.info("Could not import profile: %s.py" % config["profile"])
306 print "Failed to import profile: %s" % config["profile"]
307 raise
Dan Talaycod7c80d12012-04-03 15:20:57 -0700308
Dan Talayco48370102010-03-03 15:17:33 -0800309def logging_setup(config):
310 """
311 Set up logging based on config
312 """
313 _format = "%(asctime)s %(name)-10s: %(levelname)-8s: %(message)s"
314 _datefmt = "%H:%M:%S"
Dan Talayco88fc8802010-03-07 11:37:52 -0800315 logging.basicConfig(filename=config["log_file"],
316 level=config["dbg_level"],
317 format=_format, datefmt=_datefmt)
Dan Talayco48370102010-03-03 15:17:33 -0800318
Rich Lane943be672012-10-04 19:20:16 -0700319def load_test_modules(config):
320 """
321 Load tests from the test_dir directory.
Dan Talayco2c0dba32010-03-06 22:47:06 -0800322
Rich Lane943be672012-10-04 19:20:16 -0700323 Test cases are subclasses of unittest.TestCase
Dan Talayco2c0dba32010-03-06 22:47:06 -0800324
325 @param config The oft configuration dictionary
Rich Lane943be672012-10-04 19:20:16 -0700326 @returns A dictionary from test module names to tuples of
327 (module, dictionary from test names to test classes).
Dan Talayco2c0dba32010-03-06 22:47:06 -0800328 """
329
Rich Lane943be672012-10-04 19:20:16 -0700330 result = {}
Dan Talayco2c0dba32010-03-06 22:47:06 -0800331
Rich Lane943be672012-10-04 19:20:16 -0700332 for root, dirs, filenames in os.walk(config["test_dir"]):
333 # Iterate over each python file
334 for filename in fnmatch.filter(filenames, '[!.]*.py'):
335 modname = os.path.splitext(os.path.basename(filename))[0]
Dan Talayco2c0dba32010-03-06 22:47:06 -0800336
Rich Lane943be672012-10-04 19:20:16 -0700337 try:
338 if sys.modules.has_key(modname):
339 mod = sys.modules[modname]
340 else:
341 mod = imp.load_module(modname, *imp.find_module(modname, [root]))
342 except:
343 logging.warning("Could not import file " + filename)
344 raise
Rich Lane520e4152012-07-09 16:18:16 -0700345
Rich Lane943be672012-10-04 19:20:16 -0700346 # Find all testcases defined in the module
347 tests = dict((k, v) for (k, v) in mod.__dict__.items() if type(v) == type and
348 issubclass(v, unittest.TestCase))
349 if tests:
350 result[modname] = (mod, tests)
Rich Lane520e4152012-07-09 16:18:16 -0700351
Rich Lane943be672012-10-04 19:20:16 -0700352 return result
Dan Talayco2c0dba32010-03-06 22:47:06 -0800353
Rich Lane15f64de2012-10-04 21:25:57 -0700354def prune_tests(test_spec, test_modules):
355 """
356 Return tests matching a given test-spec.
357 @param test_spec A test-spec string.
358 @param test_modules Same format as the output of load_test_modules.
359 @returns Same format as the output of load_test_modules.
360 """
361 result = {}
362 for (spec_modname, spec_testname) in parse_test_spec(test_spec):
363 matched = False
364 for (modname, (mod, tests)) in test_modules.items():
365 if (spec_modname == None or spec_modname == modname):
366 for (testname, test) in tests.items():
367 if (spec_testname == None or spec_testname == testname):
368 result.setdefault(modname, (mod, {}))
369 result[modname][1][testname] = test
370 matched = True
371 if not matched:
372 if spec_modname and spec_testname:
373 el = "%s.%s" % (spec_modname, spec_testname)
374 else:
375 el = spec_modname or spec_testname or "all"
376 die("test-spec element %s did not match any tests" % el)
377 return result
378
379def parse_test_spec(test_spec):
380 """
381 The input string is split on commas and each element is parsed
382 individually into a module name and test name. Either may be None
383 for a wildcard. The case of the first letter resolves ambiguity
384 of whether a word is a test or module name. The special string
385 "all" results in both fields wildcarded.
386
387 Examples:
388 basic.Echo -> ("basic", "Echo")
389 basic -> ("basic", None)
390 Echo -> (None, "Echo")
391 all -> (None, None)
392 """
393 results = []
394 for ts_entry in test_spec.split(","):
395 parts = ts_entry.split(".")
396 if len(parts) == 1:
397 if ts_entry == "all":
398 results.append((None, None))
399 elif ts_entry[0].isupper():
400 results.append((None, ts_entry))
401 else:
402 results.append((ts_entry, None))
403 elif len(parts) == 2:
404 results.append((parts[0], parts[1]))
405 else:
406 die("Bad test spec: " + ts_entry)
407 return results
408
Dan Talayco2c0dba32010-03-06 22:47:06 -0800409def die(msg, exit_val=1):
410 print msg
411 logging.critical(msg)
412 sys.exit(exit_val)
413
Dan Talayco79f36082010-03-11 16:53:53 -0800414def _space_to(n, str):
415 """
416 Generate a string of spaces to achieve width n given string str
417 If length of str >= n, return one space
418 """
419 spaces = n - len(str)
420 if spaces > 0:
421 return " " * spaces
422 return " "
423
Rich Laned1d9c282012-10-04 22:07:10 -0700424def test_prio_get(test):
Dan Talaycoc24aaae2010-07-08 14:05:24 -0700425 """
426 Return the priority of a test
Dan Talaycod7c80d12012-04-03 15:20:57 -0700427
428 If test is in "skip list" from profile, return the skip value
429
Rich Laned1d9c282012-10-04 22:07:10 -0700430 If the priority property is set in the class, return
Dan Talaycoc24aaae2010-07-08 14:05:24 -0700431 that value. Otherwise return 100 (default)
432 """
Rich Laned1d9c282012-10-04 22:07:10 -0700433 if test.__name__ in profile_mod.skip_test_list:
434 logging.info("Skipping test %s due to profile" % test.__name__)
Rich Lane1673b8f2012-09-25 18:35:18 -0700435 return TEST_PRIO_SKIP
Rich Laned1d9c282012-10-04 22:07:10 -0700436 return getattr(test, "priority", TEST_PRIO_DEFAULT)
Dan Talaycoc24aaae2010-07-08 14:05:24 -0700437
Dan Talayco48370102010-03-03 15:17:33 -0800438#
439# Main script
440#
441
Rich Lane477f4812012-10-04 22:49:00 -0700442# Setup global configuration
443(new_config, args) = config_setup(config_default)
444oftest.config.update(new_config)
Dan Talayco48370102010-03-03 15:17:33 -0800445
Rich Laned7a85c42012-09-28 15:38:45 -0700446logging_setup(config)
447logging.info("++++++++ " + time.asctime() + " ++++++++")
448
Rich Lanee284b6b2012-10-03 09:19:58 -0700449# Allow tests to import each other
450sys.path.append(config["test_dir"])
451
Rich Lane15f64de2012-10-04 21:25:57 -0700452test_modules = prune_tests(config["test_spec"], load_test_modules(config))
Dan Talayco2c0dba32010-03-06 22:47:06 -0800453
Rich Lanec27fa002012-09-28 12:49:12 -0700454load_profile(config)
455
Dan Talayco2c0dba32010-03-06 22:47:06 -0800456# Check if test list is requested; display and exit if so
457if config["list"]:
Dan Talayco7f8dba82012-04-12 12:58:52 -0700458 mod_count = 0
459 test_count = 0
Dan Talayco2c0dba32010-03-06 22:47:06 -0800460 print "\nTest List:"
Rich Lane943be672012-10-04 19:20:16 -0700461 for (modname, (mod, tests)) in test_modules.items():
Dan Talayco7f8dba82012-04-12 12:58:52 -0700462 mod_count += 1
Dan Talayco79f36082010-03-11 16:53:53 -0800463 desc = mod.__doc__.strip()
464 desc = desc.split('\n')[0]
465 start_str = " Module " + mod.__name__ + ": "
466 print start_str + _space_to(22, start_str) + desc
Rich Lane943be672012-10-04 19:20:16 -0700467 for (testname, test) in tests.items():
Dan Talayco551befa2010-07-15 17:05:32 -0700468 try:
Rich Lane943be672012-10-04 19:20:16 -0700469 desc = test.__doc__.strip()
Dan Talayco551befa2010-07-15 17:05:32 -0700470 desc = desc.split('\n')[0]
471 except:
472 desc = "No description"
Rich Lane8260a2d2012-10-09 14:58:35 -0700473 if test_prio_get(test) < config["priority"]:
Rich Lane943be672012-10-04 19:20:16 -0700474 start_str = " * " + testname + ":"
Dan Talaycoc24aaae2010-07-08 14:05:24 -0700475 else:
Rich Lane943be672012-10-04 19:20:16 -0700476 start_str = " " + testname + ":"
Dan Talayco551befa2010-07-15 17:05:32 -0700477 if len(start_str) > 22:
478 desc = "\n" + _space_to(22, "") + desc
Dan Talayco79f36082010-03-11 16:53:53 -0800479 print start_str + _space_to(22, start_str) + desc
Dan Talayco7f8dba82012-04-12 12:58:52 -0700480 test_count += 1
Dan Talayco79f36082010-03-11 16:53:53 -0800481 print
Rich Lane15f64de2012-10-04 21:25:57 -0700482 print "%d modules shown with a total of %d tests" % \
483 (mod_count, test_count)
484 print
485 print "Tests preceded by * are not run by default"
Dan Talayco7aa0b812010-07-20 14:51:41 -0700486 print "Tests marked (TP1) after name take --test-params including:"
Dan Talaycoac25cf32010-07-20 14:08:28 -0700487 print " 'vid=N;strip_vlan=bool;add_vlan=bool'"
Dan Talaycod7c80d12012-04-03 15:20:57 -0700488 print "Note that --profile may override which tests are run"
Dan Talayco2c0dba32010-03-06 22:47:06 -0800489 sys.exit(0)
490
Jeffrey Townsend6614f972012-08-16 13:27:18 -0700491# Check if test list is requested; display and exit if so
492if config["list_test_names"]:
Rich Lane943be672012-10-04 19:20:16 -0700493 for (modname, (mod, tests)) in test_modules.items():
Rich Lane943be672012-10-04 19:20:16 -0700494 for (testname, test) in tests.items():
Rich Lane8260a2d2012-10-09 14:58:35 -0700495 if test_prio_get(test) >= config["priority"]:
Rich Lane943be672012-10-04 19:20:16 -0700496 print "%s.%s" % (modname, testname)
Jeffrey Townsend6614f972012-08-16 13:27:18 -0700497 sys.exit(0)
498
Dan Talayco2c0dba32010-03-06 22:47:06 -0800499# Generate the test suite
500#@todo Decide if multiple suites are ever needed
501suite = unittest.TestSuite()
502
Rich Lane15f64de2012-10-04 21:25:57 -0700503for (modname, (mod, tests)) in test_modules.items():
504 for (testname, test) in tests.items():
Rich Lane8260a2d2012-10-09 14:58:35 -0700505 if test_prio_get(test) >= config["priority"]:
Rich Lane15f64de2012-10-04 21:25:57 -0700506 logging.info("Adding test " + modname + "." + testname)
507 suite.addTest(test())
Dan Talayco2c0dba32010-03-06 22:47:06 -0800508
Rich Lane51590f62012-10-09 15:06:29 -0700509# Allow platforms to import each other
510sys.path.append(config["platform_dir"])
511
Rich Lane8aebc5e2012-09-25 17:57:53 -0700512# Load the platform module
513platform_name = config["platform"]
514logging.info("Importing platform: " + platform_name)
515platform_mod = None
516try:
Rich Lane483e1542012-10-05 09:29:39 -0700517 platform_mod = imp.load_module(platform_name, *imp.find_module(platform_name, [config["platform_dir"]]))
Rich Lane8aebc5e2012-09-25 17:57:53 -0700518except:
519 logging.warn("Failed to import " + platform_name + " platform module")
520 raise
Dan Talayco48370102010-03-03 15:17:33 -0800521
522try:
Rich Lane8aebc5e2012-09-25 17:57:53 -0700523 platform_mod.platform_config_update(config)
Dan Talayco48370102010-03-03 15:17:33 -0800524except:
525 logging.warn("Could not run platform host configuration")
Rich Laneef403e52012-07-09 14:59:43 -0700526 raise
Dan Talayco48370102010-03-03 15:17:33 -0800527
528if not config["port_map"]:
Rich Lane8aebc5e2012-09-25 17:57:53 -0700529 die("Interface port map was not defined by the platform. Exiting.")
Dan Talayco48370102010-03-03 15:17:33 -0800530
531logging.debug("Configuration: " + str(config))
532logging.info("OF port map: " + str(config["port_map"]))
533
Dan Talayco2c0dba32010-03-06 22:47:06 -0800534if config["dbg_level"] == logging.CRITICAL:
535 _verb = 0
536elif config["dbg_level"] >= logging.WARNING:
537 _verb = 1
538else:
539 _verb = 2
Dan Talayco48370102010-03-03 15:17:33 -0800540
Rich Lanee55abf72012-07-26 20:11:42 -0700541oftest.ofutils.default_timeout = config["default_timeout"]
Rich Laneda3b5ad2012-10-03 09:05:32 -0700542oftest.testutils.MINSIZE = config['minsize']
Rich Lanee55abf72012-07-26 20:11:42 -0700543
Rich Laneee57ad02012-07-13 15:40:36 -0700544if os.getuid() != 0 and not config["allow_user"]:
Brandon Heller446c1432010-04-01 12:43:27 -0700545 print "ERROR: Super-user privileges required. Please re-run with " \
546 "sudo or as root."
Rich Laned1d9c282012-10-04 22:07:10 -0700547 sys.exit(1)
Brandon Heller446c1432010-04-01 12:43:27 -0700548
Rich Lane8592bec2012-09-03 09:06:59 -0700549if config["random_seed"] is not None:
550 logging.info("Random seed: %d" % config["random_seed"])
551 random.seed(config["random_seed"])
552
Rich Lane5bd6cf92012-10-04 17:57:24 -0700553# Remove python's signal handler which raises KeyboardError. Exiting from an
554# exception waits for all threads to terminate which might not happen.
555signal.signal(signal.SIGINT, signal.SIG_DFL)
Dan Talaycoac25cf32010-07-20 14:08:28 -0700556
557if __name__ == "__main__":
558 logging.info("*** TEST RUN START: " + time.asctime())
Rich Lane6a1ecb82012-07-10 18:59:44 -0700559 result = unittest.TextTestRunner(verbosity=_verb).run(suite)
Rich Laneda3b5ad2012-10-03 09:05:32 -0700560 if oftest.testutils.skipped_test_count > 0:
Dan Talaycoba3745c2010-07-21 21:51:08 -0700561 ts = " tests"
Rich Laneda3b5ad2012-10-03 09:05:32 -0700562 if oftest.testutils.skipped_test_count == 1: ts = " test"
563 logging.info("Skipped " + str(oftest.testutils.skipped_test_count) + ts)
564 print("Skipped " + str(oftest.testutils.skipped_test_count) + ts)
Dan Talaycoac25cf32010-07-20 14:08:28 -0700565 logging.info("*** TEST RUN END : " + time.asctime())
Rich Lane50d42eb2012-07-16 11:57:03 -0700566 if result.failures or result.errors:
Shudong Zhoud895fcb2012-08-01 19:09:55 -0700567 # exit(1) hangs sometimes
568 os._exit(1)
Rich Laneda3b5ad2012-10-03 09:05:32 -0700569 if oftest.testutils.skipped_test_count > 0 and config["fail_skipped"]:
Shudong Zhoud895fcb2012-08-01 19:09:55 -0700570 os._exit(1)