From dcff9b15e70921e1f0931b5b999d9aa7b6ec011d Mon Sep 17 00:00:00 2001 From: Mihail Stoyanov Date: Tue, 14 Jun 2016 01:57:01 +0100 Subject: [PATCH 1/4] Minor update to tools - logging of tests and output --- tools/build_api.py | 2 -- tools/toolchains/__init__.py | 13 +++++++------ 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/tools/build_api.py b/tools/build_api.py index f8b8099162..3904cd3bf3 100644 --- a/tools/build_api.py +++ b/tools/build_api.py @@ -383,8 +383,6 @@ def build_library(src_paths, build_path, target, toolchain_name, if toolchain_output: cur_result["output"] += toolchain_output - cur_result["output"] += str(e) - add_result_to_report(report, cur_result) # Let Exception propagate diff --git a/tools/toolchains/__init__.py b/tools/toolchains/__init__.py index 777a2cd174..464ad5d063 100644 --- a/tools/toolchains/__init__.py +++ b/tools/toolchains/__init__.py @@ -241,8 +241,9 @@ class mbedToolchain: self.mp_pool = None - if 'UVISOR_PRESENT=1' in self.macros: + if 'UVISOR' in self.target.features and 'UVISOR_SUPPORTED' in self.target.extra_labels: self.target.core = re.sub(r"F$", '', self.target.core) + self.flags = deepcopy(self.DEFAULT_FLAGS) def get_output(self): @@ -253,9 +254,12 @@ class mbedToolchain: """ msg = None - if event['type'] in ['info', 'debug']: + if not self.VERBOSE and event['type'] == 'tool_error': msg = event['message'] - + + elif event['type'] in ['info', 'debug']: + msg = event['message'] + elif event['type'] == 'cc': event['severity'] = event['severity'].title() event['file'] = basename(event['file']) @@ -775,9 +779,6 @@ class mbedToolchain: def default_cmd(self, command): self.debug("Command: %s"% ' '.join(command)) _stdout, _stderr, _rc = run_cmd(command) - # Print all warning / erros from stderr to console output - for error_line in _stderr.splitlines(): - print error_line self.debug("Return: %s"% _rc) From 6796025e7826aa0cda3ee3e8bcfcd54ac8481b80 Mon Sep 17 00:00:00 2001 From: Brian Daniels Date: Mon, 13 Jun 2016 22:10:59 +0100 Subject: [PATCH 2/4] Fixes for logs and test logic in tools --- tools/build_api.py | 2 -- tools/test.py | 7 +++++-- tools/test_api.py | 13 +++++++------ 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/tools/build_api.py b/tools/build_api.py index 3904cd3bf3..e34e74d6e6 100644 --- a/tools/build_api.py +++ b/tools/build_api.py @@ -521,8 +521,6 @@ def build_lib(lib_id, target, toolchain_name, options=None, verbose=False, clean if toolchain_output: cur_result["output"] += toolchain_output - cur_result["output"] += str(e) - add_result_to_report(report, cur_result) # Let Exception propagate diff --git a/tools/test.py b/tools/test.py index 1c7fbcd5d2..16e002bee2 100644 --- a/tools/test.py +++ b/tools/test.py @@ -21,6 +21,7 @@ TEST BUILD & RUN import sys import os import json +import fnmatch ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), "..")) sys.path.insert(0, ROOT) @@ -105,8 +106,10 @@ if __name__ == '__main__': all_tests_keys = all_tests.keys() for name in all_names: - if name in all_tests_keys: - tests[name] = all_tests[name] + if any(fnmatch.fnmatch(testname, name) for testname in all_tests): + for testname, test in all_tests.items(): + if fnmatch.fnmatch(testname, name): + tests[testname] = test else: print "[Warning] Test with name '%s' was not found in the available tests" % (name) else: diff --git a/tools/test_api.py b/tools/test_api.py index 9cdedf9dc9..9872d62316 100644 --- a/tools/test_api.py +++ b/tools/test_api.py @@ -2077,12 +2077,13 @@ def build_tests(tests, base_source_paths, build_path, target, toolchain_name, verbose=verbose) except Exception, e: - result = False - - if continue_on_build_fail: - continue - else: - break + if not isinstance(e, NotSupportedException): + result = False + + if continue_on_build_fail: + continue + else: + break # If a clean build was carried out last time, disable it for the next build. # Otherwise the previously built test will be deleted. From f622c591e81703fe0611a6183ab068edb6f7091a Mon Sep 17 00:00:00 2001 From: Brian Daniels Date: Mon, 13 Jun 2016 23:14:34 +0100 Subject: [PATCH 3/4] Handling exceptions throughout test flow --- tools/test.py | 22 ++++++++++++++++------ tools/test_api.py | 25 +++++++++++++------------ tools/test_exporters.py | 19 +++++++++++-------- 3 files changed, 40 insertions(+), 26 deletions(-) diff --git a/tools/test.py b/tools/test.py index 16e002bee2..9c0d5354a6 100644 --- a/tools/test.py +++ b/tools/test.py @@ -30,7 +30,7 @@ from tools.test_api import test_path_to_name, find_tests, print_tests, build_tes from tools.options import get_default_options_parser from tools.build_api import build_project, build_library from tools.targets import TARGET_MAP -from tools.utils import mkdir +from tools.utils import mkdir, ToolException, NotSupportedException from tools.test_exporters import ReportExporter, ResultExporterType if __name__ == '__main__': @@ -137,7 +137,7 @@ if __name__ == '__main__': build_report = {} build_properties = {} - library_build_success = True + library_build_success = False try: # Build sources build_library(base_source_paths, options.build_dir, target, options.tool, @@ -150,11 +150,21 @@ if __name__ == '__main__': macros=options.macros, verbose=options.verbose, archive=False) - except Exception, e: - library_build_success = False - print "Failed to build library" - if library_build_success: + library_build_success = True + except ToolException, e: + # ToolException output is handled by the build log + pass + except NotSupportedException, e: + # NotSupportedException is handled by the build log + pass + except Exception, e: + # Some other exception occurred, print the error message + print e + + if not library_build_success: + print "Failed to build library" + else: # Build all the tests test_build_success, test_build = build_tests(tests, [options.build_dir], options.build_dir, target, options.tool, options=options.options, diff --git a/tools/test_api.py b/tools/test_api.py index 9872d62316..3ebf7fdf7f 100644 --- a/tools/test_api.py +++ b/tools/test_api.py @@ -2064,7 +2064,7 @@ def build_tests(tests, base_source_paths, build_path, target, toolchain_name, for test_name, test_path in tests.iteritems(): test_build_path = os.path.join(build_path, test_path) src_path = base_source_paths + [test_path] - + bin_file = None try: bin_file = build_project(src_path, test_build_path, target, toolchain_name, options=options, @@ -2091,17 +2091,18 @@ def build_tests(tests, base_source_paths, build_path, target, toolchain_name, clean = False # Normalize the path - bin_file = os.path.normpath(bin_file) - - test_build['tests'][test_name] = { - "binaries": [ - { - "path": bin_file - } - ] - } - - print 'Image: %s'% bin_file + if bin_file: + bin_file = os.path.normpath(bin_file) + + test_build['tests'][test_name] = { + "binaries": [ + { + "path": bin_file + } + ] + } + + print 'Image: %s'% bin_file test_builds = {} test_builds["%s-%s" % (target.name, toolchain_name)] = test_build diff --git a/tools/test_exporters.py b/tools/test_exporters.py index 857a6bfcd3..6a5aba466e 100644 --- a/tools/test_exporters.py +++ b/tools/test_exporters.py @@ -324,15 +324,18 @@ class ReportExporter(): for test_runner in test_runs: #test_run = test_result_ext[target][toolchain][test][test_run_number][0] test_run = test_runner[0] - - if test_run["result"] == "FAIL": - failures.append(test_run) - elif test_run["result"] == "SKIP" or test_run["result"] == "NOT_SUPPORTED": - skips.append(test_run) - elif test_run["result"] == "OK": - successes.append(test_run) + + if "result" in test_run: + if test_run["result"] == "FAIL": + failures.append(test_run) + elif test_run["result"] == "SKIP" or test_run["result"] == "NOT_SUPPORTED": + skips.append(test_run) + elif test_run["result"] == "OK": + successes.append(test_run) + else: + raise Exception("Unhandled result type: %s" % (test_run["result"])) else: - raise Exception("Unhandled result type: %s" % (test_run["result"])) + raise Exception("'test_run' did not have a 'result' value") if successes: print "\n\nBuild successes:" From 1bcd64301abcebb7b667abbfa1391378791826f1 Mon Sep 17 00:00:00 2001 From: Brian Daniels Date: Tue, 14 Jun 2016 00:32:22 +0100 Subject: [PATCH 4/4] Lower case test names, blob matching test names, and sort test names for prints --- tools/test.py | 2 +- tools/test_api.py | 80 ++++++++++++++--------------------------------- 2 files changed, 25 insertions(+), 57 deletions(-) diff --git a/tools/test.py b/tools/test.py index 9c0d5354a6..bdc9bb9c9d 100644 --- a/tools/test.py +++ b/tools/test.py @@ -103,8 +103,8 @@ if __name__ == '__main__': # Filter tests by name if specified if options.names: all_names = options.names.split(",") + all_names = [x.lower() for x in all_names] - all_tests_keys = all_tests.keys() for name in all_names: if any(fnmatch.fnmatch(testname, name) for testname in all_tests): for testname, test in all_tests.items(): diff --git a/tools/test_api.py b/tools/test_api.py index 3ebf7fdf7f..745bce563f 100644 --- a/tools/test_api.py +++ b/tools/test_api.py @@ -1961,76 +1961,44 @@ def test_path_to_name(path): name_parts.insert(0, tail) head, tail = os.path.split(head) - return "-".join(name_parts) + return "-".join(name_parts).lower() def find_tests(base_dir): """Given any directory, walk through the subdirectories and find all tests""" - def is_subdir(path, directory): - path = os.path.realpath(path) - directory = os.path.realpath(directory) - relative = os.path.relpath(path, directory) - return not (relative.startswith(os.pardir + os.sep) and relative.startswith(os.pardir)) - - def find_tests_in_tests_directory(directory): + def find_test_in_directory(directory, tests_path): """Given a 'TESTS' directory, return a dictionary of test names and test paths. The formate of the dictionary is {"test-name": "./path/to/test"}""" - tests = {} + test = None + if tests_path in directory: + head, test_case_directory = os.path.split(directory) + if test_case_directory != tests_path and test_case_directory != "host_tests": + head, test_group_directory = os.path.split(head) + if test_group_directory != tests_path and test_case_directory != "host_tests": + test = { + "name": test_path_to_name(directory), + "path": directory + } - for d in os.listdir(directory): - # dir name host_tests is reserved for host python scripts. - if d != "host_tests": - # Loop on test case directories - for td in os.listdir(os.path.join(directory, d)): - # Add test case to the results if it is a directory and not "host_tests" - if td != "host_tests": - test_case_path = os.path.join(directory, d, td) - if os.path.isdir(test_case_path): - tests[test_path_to_name(test_case_path)] = test_case_path - - return tests - + return test + tests_path = 'TESTS' + tests = {} + dirs = scan_for_source_paths(base_dir) - # Determine if "base_dir" is already a "TESTS" directory - _, top_folder = os.path.split(base_dir) + for directory in dirs: + test = find_test_in_directory(directory, tests_path) + if test: + tests[test['name']] = test['path'] - if top_folder == tests_path: - # Already pointing at a "TESTS" directory - return find_tests_in_tests_directory(base_dir) - else: - # Not pointing at a "TESTS" directory, so go find one! - tests = {} - - dirs = scan_for_source_paths(base_dir) - - test_and_sub_dirs = [x for x in dirs if tests_path in x] - test_dirs = [] - for potential_test_dir in test_and_sub_dirs: - good_to_add = True - if test_dirs: - for test_dir in test_dirs: - if is_subdir(potential_test_dir, test_dir): - good_to_add = False - break - - if good_to_add: - test_dirs.append(potential_test_dir) - - # Only look at valid paths - for path in test_dirs: - # Get the tests inside of the "TESTS" directory - new_tests = find_tests_in_tests_directory(path) - if new_tests: - tests.update(new_tests) - - return tests + return tests -def print_tests(tests, format="list"): +def print_tests(tests, format="list", sort=True): """Given a dictionary of tests (as returned from "find_tests"), print them in the specified format""" if format == "list": - for test_name, test_path in tests.iteritems(): + for test_name in sorted(tests.keys()): + test_path = tests[test_name] print "Test Case:" print " Name: %s" % test_name print " Path: %s" % test_path