Greg Steiert / pegasus_dev

Dependents:   blinky_max32630fthr

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers test.py Source File

test.py

00001 #! /usr/bin/env python2
00002 """
00003 mbed SDK
00004 Copyright (c) 2011-2013 ARM Limited
00005 
00006 Licensed under the Apache License, Version 2.0 (the "License");
00007 you may not use this file except in compliance with the License.
00008 You may obtain a copy of the License at
00009 
00010     http://www.apache.org/licenses/LICENSE-2.0
00011 
00012 Unless required by applicable law or agreed to in writing, software
00013 distributed under the License is distributed on an "AS IS" BASIS,
00014 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00015 See the License for the specific language governing permissions and
00016 limitations under the License.
00017 
00018 
00019 TEST BUILD & RUN
00020 """
00021 import sys
00022 import os
00023 import json
00024 import fnmatch
00025 
00026 ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))
00027 sys.path.insert(0, ROOT)
00028 
00029 from tools.config import ConfigException
00030 from tools.test_api import test_path_to_name, find_tests, print_tests, build_tests, test_spec_from_test_builds
00031 from tools.options import get_default_options_parser, extract_profile
00032 from tools.build_api import build_project, build_library
00033 from tools.build_api import print_build_memory_usage
00034 from tools.targets import TARGET_MAP
00035 from tools.utils import mkdir, ToolException, NotSupportedException, args_error
00036 from tools.test_exporters import ReportExporter, ResultExporterType
00037 from utils import argparse_filestring_type, argparse_lowercase_type, argparse_many
00038 from utils import argparse_dir_not_parent
00039 from tools.toolchains import mbedToolchain, TOOLCHAIN_PATHS, TOOLCHAIN_CLASSES
00040 from tools.settings import CLI_COLOR_MAP
00041 
00042 if __name__ == '__main__':
00043     try:
00044         # Parse Options
00045         parser = get_default_options_parser(add_app_config=True)
00046         
00047         parser.add_argument("-D",
00048                           action="append",
00049                           dest="macros",
00050                           help="Add a macro definition")
00051        
00052         parser.add_argument("-j", "--jobs",
00053                           type=int,
00054                           dest="jobs",
00055                           default=0,
00056                           help="Number of concurrent jobs. Default: 0/auto (based on host machine's number of CPUs)")
00057 
00058         parser.add_argument("--source", dest="source_dir",
00059                           type=argparse_filestring_type,
00060                             default=None, help="The source (input) directory (for sources other than tests). Defaults to current directory.", action="append")
00061 
00062         parser.add_argument("--build", dest="build_dir", type=argparse_dir_not_parent(ROOT),
00063                           default=None, help="The build (output) directory")
00064 
00065         parser.add_argument("-l", "--list", action="store_true", dest="list",
00066                           default=False, help="List (recursively) available tests in order and exit")
00067 
00068         parser.add_argument("-p", "--paths", dest="paths",
00069                           type=argparse_many(argparse_filestring_type),
00070                           default=None, help="Limit the tests to those within the specified comma separated list of paths")
00071 
00072         format_choices = ["list", "json"]
00073         format_default_choice = "list"
00074         format_help = "Change the format in which tests are listed. Choices include: %s. Default: %s" % (", ".join(format_choices), format_default_choice)
00075         parser.add_argument("-f", "--format", dest="format",
00076                             type=argparse_lowercase_type(format_choices, "format"),
00077                             default=format_default_choice, help=format_help)
00078         
00079         parser.add_argument("--continue-on-build-fail", action="store_true", dest="continue_on_build_fail",
00080                           default=None, help="Continue trying to build all tests if a build failure occurs")
00081 
00082         #TODO validate the names instead of just passing through str
00083         parser.add_argument("-n", "--names", dest="names", type=argparse_many(str),
00084                           default=None, help="Limit the tests to a comma separated list of names")
00085                           
00086         parser.add_argument("--test-spec", dest="test_spec",
00087                           default=None, help="Destination path for a test spec file that can be used by the Greentea automated test tool")
00088         
00089         parser.add_argument("--build-report-junit", dest="build_report_junit",
00090                           default=None, help="Destination path for a build report in the JUnit xml format")
00091         
00092         parser.add_argument("-v", "--verbose",
00093                           action="store_true",
00094                           dest="verbose",
00095                           default=False,
00096                           help="Verbose diagnostic output")
00097 
00098         options = parser.parse_args()
00099 
00100         # Filter tests by path if specified
00101         if options.paths:
00102             all_paths = options.paths
00103         else:
00104             all_paths = ["."]
00105 
00106         all_tests = {}
00107         tests = {}
00108 
00109         # Target
00110         if options.mcu is None :
00111             args_error(parser, "argument -m/--mcu is required")
00112         mcu = options.mcu[0]
00113 
00114         # Toolchain
00115         if options.tool is None:
00116             args_error(parser, "argument -t/--tool is required")
00117         toolchain = options.tool[0]
00118 
00119         if not TOOLCHAIN_CLASSES[toolchain].check_executable():
00120             search_path = TOOLCHAIN_PATHS[toolchain] or "No path set"
00121             args_error(parser, "Could not find executable for %s.\n"
00122                                "Currently set search path: %s"
00123                        % (toolchain, search_path))
00124 
00125         # Find all tests in the relevant paths
00126         for path in all_paths:
00127             all_tests.update(find_tests(path, mcu, toolchain, 
00128                                         app_config=options.app_config))
00129 
00130         # Filter tests by name if specified
00131         if options.names:
00132             all_names = options.names
00133             all_names = [x.lower() for x in all_names]
00134 
00135             for name in all_names:
00136                 if any(fnmatch.fnmatch(testname, name) for testname in all_tests):
00137                     for testname, test in all_tests.items():
00138                         if fnmatch.fnmatch(testname, name):
00139                             tests[testname] = test
00140                 else:
00141                     print "[Warning] Test with name '%s' was not found in the available tests" % (name)
00142         else:
00143             tests = all_tests
00144 
00145         if options.color:
00146             # This import happens late to prevent initializing colorization when we don't need it
00147             import colorize
00148             if options.verbose:
00149                 notify = mbedToolchain.print_notify_verbose
00150             else:
00151                 notify = mbedToolchain.print_notify
00152             notify = colorize.print_in_color_notifier(CLI_COLOR_MAP, notify)
00153         else:
00154             notify = None
00155 
00156         if options.list:
00157             # Print available tests in order and exit
00158             print_tests(tests, options.format)
00159             sys.exit(0)
00160         else:
00161             # Build all tests
00162             if not options.build_dir:
00163                 args_error(parser, "argument --build is required")
00164 
00165             base_source_paths = options.source_dir
00166 
00167             # Default base source path is the current directory
00168             if not base_source_paths:
00169                 base_source_paths = ['.']
00170             
00171             build_report = {}
00172             build_properties = {}
00173 
00174             library_build_success = False
00175             profile = extract_profile(parser, options, toolchain)
00176             try:
00177                 # Build sources
00178                 build_library(base_source_paths, options.build_dir, mcu, toolchain,
00179                                                 jobs=options.jobs,
00180                                                 clean=options.clean,
00181                                                 report=build_report,
00182                                                 properties=build_properties,
00183                                                 name="mbed-build",
00184                                                 macros=options.macros,
00185                                                 verbose=options.verbose,
00186                                                 notify=notify,
00187                                                 archive=False,
00188                                                 app_config=options.app_config,
00189                               build_profile=profile)
00190 
00191                 library_build_success = True
00192             except ToolException, e:
00193                 # ToolException output is handled by the build log
00194                 pass
00195             except NotSupportedException, e:
00196                 # NotSupportedException is handled by the build log
00197                 pass
00198             except Exception, e:
00199                 # Some other exception occurred, print the error message
00200                 print e
00201 
00202             if not library_build_success:
00203                 print "Failed to build library"
00204             else:
00205                 # Build all the tests
00206 
00207                 test_build_success, test_build = build_tests(tests, [options.build_dir], options.build_dir, mcu, toolchain,
00208                         clean=options.clean,
00209                         report=build_report,
00210                         properties=build_properties,
00211                         macros=options.macros,
00212                         verbose=options.verbose,
00213                         notify=notify,
00214                         jobs=options.jobs,
00215                         continue_on_build_fail=options.continue_on_build_fail,
00216                                                              app_config=options.app_config,
00217                                                              build_profile=profile)
00218 
00219                 # If a path to a test spec is provided, write it to a file
00220                 if options.test_spec:
00221                     test_spec_data = test_spec_from_test_builds(test_build)
00222 
00223                     # Create the target dir for the test spec if necessary
00224                     # mkdir will not create the dir if it already exists
00225                     test_spec_dir = os.path.dirname(options.test_spec)
00226                     if test_spec_dir:
00227                         mkdir(test_spec_dir)
00228 
00229                     try:
00230                         with open(options.test_spec, 'w') as f:
00231                             f.write(json.dumps(test_spec_data, indent=2))
00232                     except IOError, e:
00233                         print "[ERROR] Error writing test spec to file"
00234                         print e
00235 
00236             # If a path to a JUnit build report spec is provided, write it to a file
00237             if options.build_report_junit:
00238                 report_exporter = ReportExporter(ResultExporterType.JUNIT, package="build")
00239                 report_exporter.report_to_file(build_report, options.build_report_junit, test_suite_properties=build_properties)
00240 
00241             # Print memory map summary on screen
00242             if build_report:
00243                 print
00244                 print print_build_memory_usage(build_report)
00245 
00246             print_report_exporter = ReportExporter(ResultExporterType.PRINT, package="build")
00247             status = print_report_exporter.report(build_report)
00248 
00249             if status:
00250                 sys.exit(0)
00251             else:
00252                 sys.exit(1)
00253 
00254     except KeyboardInterrupt, e:
00255         print "\n[CTRL+c] exit"
00256     except ConfigException, e:
00257         # Catching ConfigException here to prevent a traceback
00258         print "[ERROR] %s" % str(e)
00259     except Exception,e:
00260         import traceback
00261         traceback.print_exc(file=sys.stdout)
00262         print "[ERROR] %s" % str(e)
00263         sys.exit(1)