blob: 6cb9181b54dd7b6cf12de01dfbd519fedac1beb3 [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
18 port_count : (Optional) Number of ports in dataplane
19 base_of_port : (Optional) Base OpenFlow port number in dataplane
20 base_if_index : (Optional) Base OS network interface for dataplane
Dan Talayco2c0dba32010-03-06 22:47:06 -080021 test_dir : (TBD) Directory to search for test files (default .)
Dan Talayco48370102010-03-03 15:17:33 -080022 test_spec : (TBD) Specification of test(s) to run
23 log_file : Filename for test logging
Dan Talayco2c0dba32010-03-06 22:47:06 -080024 list : Boolean: List all tests and exit
Dan Talayco48370102010-03-03 15:17:33 -080025 debug : String giving debug level (info, warning, error...)
Dan Talayco2c0dba32010-03-06 22:47:06 -080026</pre>
Dan Talayco48370102010-03-03 15:17:33 -080027
28See config_defaults below for the default values.
29
Dan Talayco2c0dba32010-03-06 22:47:06 -080030The following are stored in the config dictionary, but are not currently
31configurable through the command line.
32
33<pre>
34 dbg_level : logging module value of debug level
35 port_map : Map of dataplane OpenFlow port to OS interface names
36 test_mod_map : Dictionary indexed by module names and whose value
37 is the module reference
38 all_tests : Dictionary indexed by module reference and whose
39 value is a list of functions in that module
40</pre>
41
Dan Talaycoc24aaae2010-07-08 14:05:24 -070042Each test may be assigned a priority by setting test_prio["TestName"] in
43the respective module. For now, the only use of this is to avoid
44automatic inclusion of tests into the default list. This is done by
45setting the test_prio value less than 0. Eventually we may add ordering
46of test execution by test priority.
47
Dan Talayco2c0dba32010-03-06 22:47:06 -080048To add a test to the system, either: edit an existing test case file (like
49basic.py) to add a test class which inherits from unittest.TestCase (directly
50or indirectly); or add a new file which includes a function definition
51test_set_init(config). Preferably the file is in the same directory as existing
52tests, though you can specify the directory on the command line. The file
53should not be called "all" as that's reserved for the test-spec.
54
55If you add a new file, the test_set_init function should record the port
56map object from the configuration along with whatever other configuration
57information it may need.
58
59TBD: To add configuration to the system, first add an entry to config_default
Dan Talayco48370102010-03-03 15:17:33 -080060below. If you want this to be a command line parameter, edit config_setup
61to add the option and default value to the parser. Then edit config_get
62to make sure the option value gets copied into the configuration
63structure (which then gets passed to everyone else).
64
65By convention, oft attempts to import the contents of a file by the
66name of $platform.py into the local namespace.
67
68IMPORTANT: That file should define a function platform_config_update which
69takes a configuration dictionary as an argument and updates it for the
70current run. In particular, it should set up config["port_map"] with
71the proper map from OF port numbers to OF interface names.
72
73You can add your own platform, say gp104, by adding a file gp104.py
74that defines the function platform_config_update and then use the
75parameter --platform=gp104 on the command line.
76
77If platform_config_update does not set config["port_map"], an attempt
78is made to generate a default map via the function default_port_map_setup.
79This will use "local" and "remote" for platform names if available
80and generate a sequential map based on the values of base_of_port and
81base_if_index in the configuration structure.
82
Dan Talayco48370102010-03-03 15:17:33 -080083The current model for test sets is basic.py. The current convention is
84that the test set should implement a function test_set_init which takes
85an oft configuration dictionary and returns a unittest.TestSuite object.
86Future test sets should do the same thing.
87
Dan Talayco52f64442010-03-03 15:32:41 -080088Default setup:
89
90The default setup runs locally using veth pairs. To exercise this,
91checkout and build an openflow userspace datapath. Then start it on
92the local host:
Dan Talayco2c0dba32010-03-06 22:47:06 -080093<pre>
Dan Talayco52f64442010-03-03 15:32:41 -080094 sudo ~/openflow/regress/bin/veth_setup.pl
95 sudo ofdatapath -i veth0,veth2,veth4,veth6 punix:/tmp/ofd &
96 sudo ofprotocol unix:/tmp/ofd tcp:127.0.0.1 --fail=closed --max-backoff=1 &
97
98Next, run oft:
99 sudo ./oft --debug=info
Dan Talayco2c0dba32010-03-06 22:47:06 -0800100</pre>
Dan Talayco52f64442010-03-03 15:32:41 -0800101
102Examine oft.log if things don't work.
Dan Talayco2c0dba32010-03-06 22:47:06 -0800103
Dan Talayco1a88c122010-03-07 22:00:20 -0800104@todo Support per-component debug levels (esp controller vs dataplane)
105@todo Consider moving oft up a level
Dan Talayco2c0dba32010-03-06 22:47:06 -0800106
Dan Talayco1a88c122010-03-07 22:00:20 -0800107Current test case setup:
Dan Talayco2c0dba32010-03-06 22:47:06 -0800108 Files in this or sub directories (or later, directory specified on
109command line) that contain a function test_set_init are considered test
110files.
111 The function test_set_init examines the test_spec config variable
112and generates a suite of tests.
113 Support a command line option --test_mod so that all tests in that
114module will be run.
115 Support all to specify all tests from the module.
116
Dan Talayco48370102010-03-03 15:17:33 -0800117"""
118
119import sys
120from optparse import OptionParser
Dan Talayco2c0dba32010-03-06 22:47:06 -0800121from subprocess import Popen,PIPE
Dan Talayco48370102010-03-03 15:17:33 -0800122import logging
123import unittest
Dan Talayco2c0dba32010-03-06 22:47:06 -0800124import time
Brandon Heller446c1432010-04-01 12:43:27 -0700125import os
Dan Talayco48370102010-03-03 15:17:33 -0800126
Rich Lane39878042012-07-09 14:45:35 -0700127pydir = os.path.join(os.path.dirname(__file__), '..', 'src', 'python')
128if os.path.exists(os.path.join(pydir, 'oftest')):
129 # Running from source tree
130 sys.path.insert(0, pydir)
131
Dan Talaycoba3745c2010-07-21 21:51:08 -0700132import testutils
133
Dan Talayco02eca0b2010-04-15 16:09:43 -0700134try:
135 import scapy.all as scapy
136except:
137 try:
138 import scapy as scapy
139 except:
140 sys.exit("Need to install scapy for packet parsing")
141
Dan Talaycod7c80d12012-04-03 15:20:57 -0700142##@var Profile module
143profile_mod = None
144
Dan Talayco48370102010-03-03 15:17:33 -0800145##@var DEBUG_LEVELS
146# Map from strings to debugging levels
147DEBUG_LEVELS = {
148 'debug' : logging.DEBUG,
149 'verbose' : logging.DEBUG,
150 'info' : logging.INFO,
151 'warning' : logging.WARNING,
152 'warn' : logging.WARNING,
153 'error' : logging.ERROR,
154 'critical' : logging.CRITICAL
155}
156
157_debug_default = "warning"
158_debug_level_default = DEBUG_LEVELS[_debug_default]
159
160##@var config_default
161# The default configuration dictionary for OFT
162config_default = {
Dan Talayco551befa2010-07-15 17:05:32 -0700163 "param" : None,
Dan Talayco48370102010-03-03 15:17:33 -0800164 "platform" : "local",
165 "controller_host" : "127.0.0.1",
166 "controller_port" : 6633,
167 "port_count" : 4,
168 "base_of_port" : 1,
169 "base_if_index" : 1,
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700170 "relax" : False,
Dan Talayco2c0dba32010-03-06 22:47:06 -0800171 "test_spec" : "all",
172 "test_dir" : ".",
Dan Talayco48370102010-03-03 15:17:33 -0800173 "log_file" : "oft.log",
Dan Talayco2c0dba32010-03-06 22:47:06 -0800174 "list" : False,
Dan Talayco48370102010-03-03 15:17:33 -0800175 "debug" : _debug_default,
176 "dbg_level" : _debug_level_default,
Dan Talaycoac25cf32010-07-20 14:08:28 -0700177 "port_map" : {},
Dan Talaycod7c80d12012-04-03 15:20:57 -0700178 "test_params" : "None",
179 "profile" : None
Dan Talayco48370102010-03-03 15:17:33 -0800180}
181
Dan Talaycoc24aaae2010-07-08 14:05:24 -0700182# Default test priority
183TEST_PRIO_DEFAULT=100
Dan Talaycod7c80d12012-04-03 15:20:57 -0700184TEST_PRIO_SKIP=-1
Dan Talaycoc24aaae2010-07-08 14:05:24 -0700185
Dan Talayco1a88c122010-03-07 22:00:20 -0800186#@todo Set up a dict of config params so easier to manage:
187# <param> <cmdline flags> <default value> <help> <optional parser>
188
Dan Talayco48370102010-03-03 15:17:33 -0800189# Map options to config structure
190def config_get(opts):
191 "Convert options class to OFT configuration dictionary"
192 cfg = config_default.copy()
Dan Talayco2c0dba32010-03-06 22:47:06 -0800193 for key in cfg.keys():
194 cfg[key] = eval("opts." + key)
195
196 # Special case checks
Dan Talayco48370102010-03-03 15:17:33 -0800197 if opts.debug not in DEBUG_LEVELS.keys():
198 print "Warning: Bad value specified for debug level; using default"
199 opts.debug = _debug_default
Dan Talayco02eca0b2010-04-15 16:09:43 -0700200 if opts.verbose:
201 cfg["debug"] = "verbose"
Dan Talayco48370102010-03-03 15:17:33 -0800202 cfg["dbg_level"] = DEBUG_LEVELS[cfg["debug"]]
Dan Talayco2c0dba32010-03-06 22:47:06 -0800203
Dan Talayco48370102010-03-03 15:17:33 -0800204 return cfg
205
206def config_setup(cfg_dflt):
207 """
208 Set up the configuration including parsing the arguments
209
210 @param cfg_dflt The default configuration dictionary
211 @return A pair (config, args) where config is an config
212 object and args is any additional arguments from the command line
213 """
214
215 parser = OptionParser(version="%prog 0.1")
216
Dan Talayco2c0dba32010-03-06 22:47:06 -0800217 #@todo parse port map as option?
Dan Talayco48370102010-03-03 15:17:33 -0800218 # Set up default values
Dan Talayco2c0dba32010-03-06 22:47:06 -0800219 for key in cfg_dflt.keys():
220 eval("parser.set_defaults("+key+"=cfg_dflt['"+key+"'])")
Dan Talayco48370102010-03-03 15:17:33 -0800221
Dan Talayco2c0dba32010-03-06 22:47:06 -0800222 #@todo Add options via dictionary
Dan Talayco48370102010-03-03 15:17:33 -0800223 plat_help = """Set the platform type. Valid values include:
224 local: User space virtual ethernet pair setup
225 remote: Remote embedded Broadcom based switch
Dan Talayco673e0852010-03-06 23:09:23 -0800226 Create a new_plat.py file and use --platform=new_plat on the command line
Dan Talayco48370102010-03-03 15:17:33 -0800227 """
228 parser.add_option("-P", "--platform", help=plat_help)
229 parser.add_option("-H", "--host", dest="controller_host",
230 help="The IP/name of the test controller host")
231 parser.add_option("-p", "--port", dest="controller_port",
232 type="int", help="Port number of the test controller")
Dan Talayco673e0852010-03-06 23:09:23 -0800233 test_list_help = """Indicate tests to run. Valid entries are "all" (the
Dan Talaycocfa172f2012-03-23 12:03:00 -0700234 default) or a comma separated list of:
235 module Run all tests in the named module
Dan Talayco673e0852010-03-06 23:09:23 -0800236 testcase Run tests in all modules with the name testcase
237 module.testcase Run the specific test case
238 """
239 parser.add_option("--test-spec", "--test-list", help=test_list_help)
Dan Talayco48370102010-03-03 15:17:33 -0800240 parser.add_option("--log-file",
241 help="Name of log file, empty string to log to console")
242 parser.add_option("--debug",
243 help="Debug lvl: debug, info, warning, error, critical")
Dan Talayco02eca0b2010-04-15 16:09:43 -0700244 parser.add_option("--port-count", type="int",
Dan Talayco48370102010-03-03 15:17:33 -0800245 help="Number of ports to use (optional)")
Dan Talayco02eca0b2010-04-15 16:09:43 -0700246 parser.add_option("--base-of-port", type="int",
Dan Talayco48370102010-03-03 15:17:33 -0800247 help="Base OpenFlow port number (optional)")
Dan Talayco02eca0b2010-04-15 16:09:43 -0700248 parser.add_option("--base-if-index", type="int",
Dan Talayco2c0dba32010-03-06 22:47:06 -0800249 help="Base interface index number (optional)")
250 parser.add_option("--list", action="store_true",
Brandon Heller824504e2010-04-01 12:21:37 -0700251 help="List all tests and exit")
Dan Talayco02eca0b2010-04-15 16:09:43 -0700252 parser.add_option("--verbose", action="store_true",
253 help="Short cut for --debug=verbose")
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700254 parser.add_option("--relax", action="store_true",
255 help="Relax packet match checks allowing other packets")
Dan Talayco551befa2010-07-15 17:05:32 -0700256 parser.add_option("--param", type="int",
257 help="Parameter sent to test (for debugging)")
Dan Talaycod7c80d12012-04-03 15:20:57 -0700258 parser.add_option("--profile",
259 help="File listing tests to skip/run")
Dan Talaycoac25cf32010-07-20 14:08:28 -0700260 parser.add_option("-t", "--test-params",
Dan Talaycof6e76c02012-03-23 10:56:12 -0700261 help="""Set test parameters: key=val;...
262 NOTE: key MUST be a valid Python identifier, egr_count not egr-count
263 See --list""")
Dan Talayco48370102010-03-03 15:17:33 -0800264 # Might need this if other parsers want command line
265 # parser.allow_interspersed_args = False
266 (options, args) = parser.parse_args()
267
268 config = config_get(options)
269
270 return (config, args)
271
Dan Talaycod7c80d12012-04-03 15:20:57 -0700272def check_profile(config):
Dan Talaycod15bed52012-04-04 10:39:52 -0700273 """
274 Import a profile from the profiles library
275 """
276
Dan Talaycod7c80d12012-04-03 15:20:57 -0700277 global profile_mod
278 if "profile" in config and config["profile"]:
Dan Talaycod15bed52012-04-04 10:39:52 -0700279 logging.info("Importing profile: %s" % config["profile"])
280 profile_name = "profiles." + config["profile"]
Dan Talaycod7c80d12012-04-03 15:20:57 -0700281 try:
Dan Talaycod15bed52012-04-04 10:39:52 -0700282 top_mod = __import__(profile_name)
283 profile_mod = eval("top_mod." + config["profile"])
284 logging.info("Imported profile %s. Dir: %s" %
285 (config["profile"], str(dir(profile_mod))))
Dan Talaycod7c80d12012-04-03 15:20:57 -0700286 except:
287 logging.info("Could not import profile: %s.py" %
288 config["profile"])
Dan Talaycod15bed52012-04-04 10:39:52 -0700289 print "Failed to import profile: %s" % config["profile"]
Rich Laneef403e52012-07-09 14:59:43 -0700290 raise
Dan Talaycod7c80d12012-04-03 15:20:57 -0700291 else:
292 logging.info("No profile specified")
293
294
Dan Talayco48370102010-03-03 15:17:33 -0800295def logging_setup(config):
296 """
297 Set up logging based on config
298 """
299 _format = "%(asctime)s %(name)-10s: %(levelname)-8s: %(message)s"
300 _datefmt = "%H:%M:%S"
Dan Talayco88fc8802010-03-07 11:37:52 -0800301 logging.basicConfig(filename=config["log_file"],
302 level=config["dbg_level"],
303 format=_format, datefmt=_datefmt)
Dan Talayco48370102010-03-03 15:17:33 -0800304
305def default_port_map_setup(config):
306 """
307 Setup the OF port mapping based on config
308 @param config The OFT configuration structure
309 @return Port map dictionary
310 """
311 if (config["base_of_port"] is None) or not config["port_count"]:
312 return None
313 port_map = {}
314 if config["platform"] == "local":
315 # For local, use every other veth port
316 for idx in range(config["port_count"]):
317 port_map[config["base_of_port"] + idx] = "veth" + \
318 str(config["base_if_index"] + (2 * idx))
319 elif config["platform"] == "remote":
320 # For remote, use eth ports
321 for idx in range(config["port_count"]):
322 port_map[config["base_of_port"] + idx] = "eth" + \
323 str(config["base_if_index"] + idx)
324 else:
325 return None
326
327 logging.info("Built default port map")
328 return port_map
329
Dan Talayco2c0dba32010-03-06 22:47:06 -0800330def test_list_generate(config):
331 """Generate the list of all known tests indexed by module name
332
333 Conventions: Test files must implement the function test_set_init
334
Dan Talayco1a88c122010-03-07 22:00:20 -0800335 Test cases are classes that implement runTest
Dan Talayco2c0dba32010-03-06 22:47:06 -0800336
337 @param config The oft configuration dictionary
338 @returns An array of triples (mod-name, module, [tests]) where
339 mod-name is the string (filename) of the module, module is the
340 value returned from __import__'ing the module and [tests] is an
341 array of strings giving the test cases from the module.
342 """
343
344 # Find and import test files
345 p1 = Popen(["find", config["test_dir"], "-type","f"], stdout = PIPE)
346 p2 = Popen(["xargs", "grep", "-l", "-e", "^def test_set_init"],
347 stdin=p1.stdout, stdout=PIPE)
348
349 all_tests = {}
350 mod_name_map = {}
351 # There's an extra empty entry at the end of the list
352 filelist = p2.communicate()[0].split("\n")[:-1]
353 for file in filelist:
Dan Talaycoac25cf32010-07-20 14:08:28 -0700354 if file[-1:] == '~' or file[0] == '#':
Dan Talaycode2a6392010-03-10 13:56:51 -0800355 continue
Rich Lane1fac1542012-07-09 16:10:45 -0700356 modname = os.path.splitext(os.path.basename(file))[0]
Dan Talayco2c0dba32010-03-06 22:47:06 -0800357
358 try:
Rich Lane1fac1542012-07-09 16:10:45 -0700359 mod = __import__(modname)
Dan Talayco2c0dba32010-03-06 22:47:06 -0800360 except:
361 logging.warning("Could not import file " + file)
Rich Laneef403e52012-07-09 14:59:43 -0700362 raise
Rich Lane520e4152012-07-09 16:18:16 -0700363
364 tests = [k for k in dir(mod) if type(getattr(mod, k)) == type and
365 issubclass(getattr(mod, k), unittest.TestCase)]
366 if tests:
367 mod_name_map[modname] = mod
368 all_tests[mod] = tests
369
Dan Talayco2c0dba32010-03-06 22:47:06 -0800370 config["all_tests"] = all_tests
371 config["mod_name_map"] = mod_name_map
372
373def die(msg, exit_val=1):
374 print msg
375 logging.critical(msg)
376 sys.exit(exit_val)
377
378def add_test(suite, mod, name):
379 logging.info("Adding test " + mod.__name__ + "." + name)
380 suite.addTest(eval("mod." + name)())
381
Dan Talayco79f36082010-03-11 16:53:53 -0800382def _space_to(n, str):
383 """
384 Generate a string of spaces to achieve width n given string str
385 If length of str >= n, return one space
386 """
387 spaces = n - len(str)
388 if spaces > 0:
389 return " " * spaces
390 return " "
391
Dan Talaycoc24aaae2010-07-08 14:05:24 -0700392def test_prio_get(mod, test):
393 """
394 Return the priority of a test
Dan Talaycod7c80d12012-04-03 15:20:57 -0700395
396 If test is in "skip list" from profile, return the skip value
397
Dan Talaycoc24aaae2010-07-08 14:05:24 -0700398 If set in the test_prio variable for the module, return
399 that value. Otherwise return 100 (default)
400 """
Dan Talaycod7c80d12012-04-03 15:20:57 -0700401 if profile_mod:
402 if profile_mod.skip_test_list and test in profile_mod.skip_test_list:
403 logging.info("Skipping test %s due to profile" % test)
404 return TEST_PRIO_SKIP
Dan Talaycoc24aaae2010-07-08 14:05:24 -0700405 if 'test_prio' in dir(mod):
406 if test in mod.test_prio.keys():
407 return mod.test_prio[test]
408 return TEST_PRIO_DEFAULT
409
Dan Talayco48370102010-03-03 15:17:33 -0800410#
411# Main script
412#
413
414# Get configuration, set up logging, import platform from file
415(config, args) = config_setup(config_default)
Dan Talayco48370102010-03-03 15:17:33 -0800416
Dan Talayco2c0dba32010-03-06 22:47:06 -0800417test_list_generate(config)
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700418oft_config = config
Dan Talayco2c0dba32010-03-06 22:47:06 -0800419
420# Check if test list is requested; display and exit if so
421if config["list"]:
Dan Talayco79f36082010-03-11 16:53:53 -0800422 did_print = False
Dan Talayco7f8dba82012-04-12 12:58:52 -0700423 mod_count = 0
424 test_count = 0
Dan Talayco2c0dba32010-03-06 22:47:06 -0800425 print "\nTest List:"
426 for mod in config["all_tests"].keys():
Dan Talayco79f36082010-03-11 16:53:53 -0800427 if config["test_spec"] != "all" and \
428 config["test_spec"] != mod.__name__:
429 continue
Dan Talayco7f8dba82012-04-12 12:58:52 -0700430 mod_count += 1
Dan Talayco79f36082010-03-11 16:53:53 -0800431 did_print = True
432 desc = mod.__doc__.strip()
433 desc = desc.split('\n')[0]
434 start_str = " Module " + mod.__name__ + ": "
435 print start_str + _space_to(22, start_str) + desc
Dan Talayco2c0dba32010-03-06 22:47:06 -0800436 for test in config["all_tests"][mod]:
Dan Talayco551befa2010-07-15 17:05:32 -0700437 try:
438 desc = eval('mod.' + test + '.__doc__.strip()')
439 desc = desc.split('\n')[0]
440 except:
441 desc = "No description"
Dan Talaycoc24aaae2010-07-08 14:05:24 -0700442 if test_prio_get(mod, test) < 0:
443 start_str = " * " + test + ":"
444 else:
445 start_str = " " + test + ":"
Dan Talayco551befa2010-07-15 17:05:32 -0700446 if len(start_str) > 22:
447 desc = "\n" + _space_to(22, "") + desc
Dan Talayco79f36082010-03-11 16:53:53 -0800448 print start_str + _space_to(22, start_str) + desc
Dan Talayco7f8dba82012-04-12 12:58:52 -0700449 test_count += 1
Dan Talayco79f36082010-03-11 16:53:53 -0800450 print
451 if not did_print:
452 print "No tests found for " + config["test_spec"]
Dan Talaycoc24aaae2010-07-08 14:05:24 -0700453 else:
Dan Talayco7f8dba82012-04-12 12:58:52 -0700454 print "%d modules shown with a total of %d tests" % \
455 (mod_count, test_count)
456 print
Dan Talayco7aa0b812010-07-20 14:51:41 -0700457 print "Tests preceded by * are not run by default"
458 print "Tests marked (TP1) after name take --test-params including:"
Dan Talaycoac25cf32010-07-20 14:08:28 -0700459 print " 'vid=N;strip_vlan=bool;add_vlan=bool'"
Dan Talaycod7c80d12012-04-03 15:20:57 -0700460 print "Note that --profile may override which tests are run"
Dan Talayco2c0dba32010-03-06 22:47:06 -0800461 sys.exit(0)
462
463logging_setup(config)
464logging.info("++++++++ " + time.asctime() + " ++++++++")
465
Dan Talaycod7c80d12012-04-03 15:20:57 -0700466check_profile(config)
467
Dan Talayco2c0dba32010-03-06 22:47:06 -0800468# Generate the test suite
469#@todo Decide if multiple suites are ever needed
470suite = unittest.TestSuite()
471
Dan Talaycoc24aaae2010-07-08 14:05:24 -0700472#@todo Allow specification of priority to override prio check
Dan Talayco2c0dba32010-03-06 22:47:06 -0800473if config["test_spec"] == "all":
474 for mod in config["all_tests"].keys():
475 for test in config["all_tests"][mod]:
Dan Talaycoc24aaae2010-07-08 14:05:24 -0700476 # For now, a way to avoid tests
477 if test_prio_get(mod, test) >= 0:
478 add_test(suite, mod, test)
Dan Talayco2c0dba32010-03-06 22:47:06 -0800479
480else:
481 for ts_entry in config["test_spec"].split(","):
482 parts = ts_entry.split(".")
483
484 if len(parts) == 1: # Either a module or test name
485 if ts_entry in config["mod_name_map"].keys():
486 mod = config["mod_name_map"][ts_entry]
487 for test in config["all_tests"][mod]:
Dan Talayco830b4412011-08-23 22:49:21 -0700488 if test_prio_get(mod, test) >= 0:
489 add_test(suite, mod, test)
Dan Talayco2c0dba32010-03-06 22:47:06 -0800490 else: # Search for matching tests
491 test_found = False
492 for mod in config["all_tests"].keys():
493 if ts_entry in config["all_tests"][mod]:
494 add_test(suite, mod, ts_entry)
495 test_found = True
496 if not test_found:
497 die("Could not find module or test: " + ts_entry)
498
499 elif len(parts) == 2: # module.test
500 if parts[0] not in config["mod_name_map"]:
501 die("Unknown module in test spec: " + ts_entry)
502 mod = config["mod_name_map"][parts[0]]
503 if parts[1] in config["all_tests"][mod]:
504 add_test(suite, mod, parts[1])
505 else:
506 die("No known test matches: " + ts_entry)
507
508 else:
509 die("Bad test spec: " + ts_entry)
510
511# Check if platform specified
Dan Talayco48370102010-03-03 15:17:33 -0800512if config["platform"]:
513 _imp_string = "from " + config["platform"] + " import *"
Dan Talayco2c0dba32010-03-06 22:47:06 -0800514 logging.info("Importing platform: " + _imp_string)
Dan Talayco48370102010-03-03 15:17:33 -0800515 try:
516 exec(_imp_string)
517 except:
518 logging.warn("Failed to import " + config["platform"] + " file")
Rich Laneef403e52012-07-09 14:59:43 -0700519 raise
Dan Talayco48370102010-03-03 15:17:33 -0800520
521try:
522 platform_config_update(config)
523except:
524 logging.warn("Could not run platform host configuration")
Rich Laneef403e52012-07-09 14:59:43 -0700525 raise
Dan Talayco48370102010-03-03 15:17:33 -0800526
527if not config["port_map"]:
528 # Try to set up default port mapping if not done by platform
529 config["port_map"] = default_port_map_setup(config)
530
531if not config["port_map"]:
Dan Talayco2c0dba32010-03-06 22:47:06 -0800532 die("Interface port map is not defined. Exiting")
Dan Talayco48370102010-03-03 15:17:33 -0800533
534logging.debug("Configuration: " + str(config))
535logging.info("OF port map: " + str(config["port_map"]))
536
537# Init the test sets
Dan Talayco2c0dba32010-03-06 22:47:06 -0800538for (modname,mod) in config["mod_name_map"].items():
539 try:
540 mod.test_set_init(config)
541 except:
542 logging.warning("Could not run test_set_init for " + modname)
Rich Laneef403e52012-07-09 14:59:43 -0700543 raise
Dan Talayco48370102010-03-03 15:17:33 -0800544
Dan Talayco2c0dba32010-03-06 22:47:06 -0800545if config["dbg_level"] == logging.CRITICAL:
546 _verb = 0
547elif config["dbg_level"] >= logging.WARNING:
548 _verb = 1
549else:
550 _verb = 2
Dan Talayco48370102010-03-03 15:17:33 -0800551
Brandon Heller446c1432010-04-01 12:43:27 -0700552if os.getuid() != 0:
553 print "ERROR: Super-user privileges required. Please re-run with " \
554 "sudo or as root."
555 exit(1)
556
Dan Talaycoac25cf32010-07-20 14:08:28 -0700557
558if __name__ == "__main__":
559 logging.info("*** TEST RUN START: " + time.asctime())
560 unittest.TextTestRunner(verbosity=_verb).run(suite)
Dan Talaycoba3745c2010-07-21 21:51:08 -0700561 if testutils.skipped_test_count > 0:
562 ts = " tests"
563 if testutils.skipped_test_count == 1: ts = " test"
564 logging.info("Skipped " + str(testutils.skipped_test_count) + ts)
565 print("Skipped " + str(testutils.skipped_test_count) + ts)
Dan Talaycoac25cf32010-07-20 14:08:28 -0700566 logging.info("*** TEST RUN END : " + time.asctime())
Dan Talaycoba3745c2010-07-21 21:51:08 -0700567
Dan Talayco48370102010-03-03 15:17:33 -0800568