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