BBR 1 Ebene

Committer:
borlanic
Date:
Mon May 14 11:29:06 2018 +0000
Revision:
0:fbdae7e6d805
BBR

Who changed what in which revision?

UserRevisionLine numberNew contents of line
borlanic 0:fbdae7e6d805 1 """
borlanic 0:fbdae7e6d805 2 mbed SDK
borlanic 0:fbdae7e6d805 3 Copyright (c) 2011-2014 ARM Limited
borlanic 0:fbdae7e6d805 4
borlanic 0:fbdae7e6d805 5 Licensed under the Apache License, Version 2.0 (the "License");
borlanic 0:fbdae7e6d805 6 you may not use this file except in compliance with the License.
borlanic 0:fbdae7e6d805 7 You may obtain a copy of the License at
borlanic 0:fbdae7e6d805 8
borlanic 0:fbdae7e6d805 9 http://www.apache.org/licenses/LICENSE-2.0
borlanic 0:fbdae7e6d805 10
borlanic 0:fbdae7e6d805 11 Unless required by applicable law or agreed to in writing, software
borlanic 0:fbdae7e6d805 12 distributed under the License is distributed on an "AS IS" BASIS,
borlanic 0:fbdae7e6d805 13 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
borlanic 0:fbdae7e6d805 14 See the License for the specific language governing permissions and
borlanic 0:fbdae7e6d805 15 limitations under the License.
borlanic 0:fbdae7e6d805 16
borlanic 0:fbdae7e6d805 17 Author: Przemyslaw Wirkus <Przemyslaw.wirkus@arm.com>
borlanic 0:fbdae7e6d805 18 """
borlanic 0:fbdae7e6d805 19 from __future__ import print_function
borlanic 0:fbdae7e6d805 20
borlanic 0:fbdae7e6d805 21 import os
borlanic 0:fbdae7e6d805 22 import re
borlanic 0:fbdae7e6d805 23 import sys
borlanic 0:fbdae7e6d805 24 import json
borlanic 0:fbdae7e6d805 25 import uuid
borlanic 0:fbdae7e6d805 26 import pprint
borlanic 0:fbdae7e6d805 27 import random
borlanic 0:fbdae7e6d805 28 import argparse
borlanic 0:fbdae7e6d805 29 import datetime
borlanic 0:fbdae7e6d805 30 import threading
borlanic 0:fbdae7e6d805 31 import ctypes
borlanic 0:fbdae7e6d805 32 import functools
borlanic 0:fbdae7e6d805 33 from colorama import Fore, Back, Style
borlanic 0:fbdae7e6d805 34 from prettytable import PrettyTable
borlanic 0:fbdae7e6d805 35 from copy import copy, deepcopy
borlanic 0:fbdae7e6d805 36
borlanic 0:fbdae7e6d805 37 from time import sleep, time
borlanic 0:fbdae7e6d805 38 try:
borlanic 0:fbdae7e6d805 39 from Queue import Queue, Empty
borlanic 0:fbdae7e6d805 40 except ImportError:
borlanic 0:fbdae7e6d805 41 from queue import Queue, Empty
borlanic 0:fbdae7e6d805 42 from os.path import join, exists, basename, relpath
borlanic 0:fbdae7e6d805 43 from threading import Thread, Lock
borlanic 0:fbdae7e6d805 44 from multiprocessing import Pool, cpu_count
borlanic 0:fbdae7e6d805 45 from subprocess import Popen, PIPE
borlanic 0:fbdae7e6d805 46
borlanic 0:fbdae7e6d805 47 # Imports related to mbed build api
borlanic 0:fbdae7e6d805 48 from tools.tests import TESTS
borlanic 0:fbdae7e6d805 49 from tools.tests import TEST_MAP
borlanic 0:fbdae7e6d805 50 from tools.paths import BUILD_DIR
borlanic 0:fbdae7e6d805 51 from tools.paths import HOST_TESTS
borlanic 0:fbdae7e6d805 52 from tools.utils import ToolException
borlanic 0:fbdae7e6d805 53 from tools.utils import NotSupportedException
borlanic 0:fbdae7e6d805 54 from tools.utils import construct_enum
borlanic 0:fbdae7e6d805 55 from tools.memap import MemapParser
borlanic 0:fbdae7e6d805 56 from tools.targets import TARGET_MAP, Target
borlanic 0:fbdae7e6d805 57 import tools.test_configs as TestConfig
borlanic 0:fbdae7e6d805 58 from tools.test_db import BaseDBAccess
borlanic 0:fbdae7e6d805 59 from tools.build_api import build_project, build_mbed_libs, build_lib
borlanic 0:fbdae7e6d805 60 from tools.build_api import get_target_supported_toolchains
borlanic 0:fbdae7e6d805 61 from tools.build_api import write_build_report
borlanic 0:fbdae7e6d805 62 from tools.build_api import prep_report
borlanic 0:fbdae7e6d805 63 from tools.build_api import prep_properties
borlanic 0:fbdae7e6d805 64 from tools.build_api import create_result
borlanic 0:fbdae7e6d805 65 from tools.build_api import add_result_to_report
borlanic 0:fbdae7e6d805 66 from tools.build_api import prepare_toolchain
borlanic 0:fbdae7e6d805 67 from tools.build_api import scan_resources
borlanic 0:fbdae7e6d805 68 from tools.build_api import get_config
borlanic 0:fbdae7e6d805 69 from tools.libraries import LIBRARIES, LIBRARY_MAP
borlanic 0:fbdae7e6d805 70 from tools.options import extract_profile
borlanic 0:fbdae7e6d805 71 from tools.toolchains import TOOLCHAIN_PATHS
borlanic 0:fbdae7e6d805 72 from tools.toolchains import TOOLCHAINS
borlanic 0:fbdae7e6d805 73 from tools.test_exporters import ReportExporter, ResultExporterType
borlanic 0:fbdae7e6d805 74 from tools.utils import argparse_filestring_type
borlanic 0:fbdae7e6d805 75 from tools.utils import argparse_uppercase_type
borlanic 0:fbdae7e6d805 76 from tools.utils import argparse_lowercase_type
borlanic 0:fbdae7e6d805 77 from tools.utils import argparse_many
borlanic 0:fbdae7e6d805 78 from tools.notifier.mock import MockNotifier
borlanic 0:fbdae7e6d805 79
borlanic 0:fbdae7e6d805 80 import tools.host_tests.host_tests_plugins as host_tests_plugins
borlanic 0:fbdae7e6d805 81
borlanic 0:fbdae7e6d805 82 try:
borlanic 0:fbdae7e6d805 83 import mbed_lstools
borlanic 0:fbdae7e6d805 84 from tools.compliance.ioper_runner import get_available_oper_test_scopes
borlanic 0:fbdae7e6d805 85 except:
borlanic 0:fbdae7e6d805 86 pass
borlanic 0:fbdae7e6d805 87
borlanic 0:fbdae7e6d805 88
borlanic 0:fbdae7e6d805 89 class ProcessObserver(Thread):
borlanic 0:fbdae7e6d805 90 def __init__(self, proc):
borlanic 0:fbdae7e6d805 91 Thread.__init__(self)
borlanic 0:fbdae7e6d805 92 self.proc = proc
borlanic 0:fbdae7e6d805 93 self.queue = Queue()
borlanic 0:fbdae7e6d805 94 self.daemon = True
borlanic 0:fbdae7e6d805 95 self.active = True
borlanic 0:fbdae7e6d805 96 self.start()
borlanic 0:fbdae7e6d805 97
borlanic 0:fbdae7e6d805 98 def run(self):
borlanic 0:fbdae7e6d805 99 while self.active:
borlanic 0:fbdae7e6d805 100 c = self.proc.stdout.read(1)
borlanic 0:fbdae7e6d805 101 self.queue.put(c)
borlanic 0:fbdae7e6d805 102
borlanic 0:fbdae7e6d805 103 def stop(self):
borlanic 0:fbdae7e6d805 104 self.active = False
borlanic 0:fbdae7e6d805 105 try:
borlanic 0:fbdae7e6d805 106 self.proc.terminate()
borlanic 0:fbdae7e6d805 107 except Exception:
borlanic 0:fbdae7e6d805 108 pass
borlanic 0:fbdae7e6d805 109
borlanic 0:fbdae7e6d805 110
borlanic 0:fbdae7e6d805 111 class SingleTestExecutor(threading.Thread):
borlanic 0:fbdae7e6d805 112 """ Example: Single test class in separate thread usage
borlanic 0:fbdae7e6d805 113 """
borlanic 0:fbdae7e6d805 114 def __init__(self, single_test):
borlanic 0:fbdae7e6d805 115 self.single_test = single_test
borlanic 0:fbdae7e6d805 116 threading.Thread.__init__(self)
borlanic 0:fbdae7e6d805 117
borlanic 0:fbdae7e6d805 118 def run(self):
borlanic 0:fbdae7e6d805 119 start = time()
borlanic 0:fbdae7e6d805 120 # Execute tests depending on options and filter applied
borlanic 0:fbdae7e6d805 121 test_summary, shuffle_seed, test_summary_ext, test_suite_properties_ext = self.single_test.execute()
borlanic 0:fbdae7e6d805 122 elapsed_time = time() - start
borlanic 0:fbdae7e6d805 123
borlanic 0:fbdae7e6d805 124 # Human readable summary
borlanic 0:fbdae7e6d805 125 if not self.single_test.opts_suppress_summary:
borlanic 0:fbdae7e6d805 126 # prints well-formed summary with results (SQL table like)
borlanic 0:fbdae7e6d805 127 print(self.single_test.generate_test_summary(test_summary,
borlanic 0:fbdae7e6d805 128 shuffle_seed))
borlanic 0:fbdae7e6d805 129 if self.single_test.opts_test_x_toolchain_summary:
borlanic 0:fbdae7e6d805 130 # prints well-formed summary with results (SQL table like)
borlanic 0:fbdae7e6d805 131 # table shows text x toolchain test result matrix
borlanic 0:fbdae7e6d805 132 print(self.single_test.generate_test_summary_by_target(
borlanic 0:fbdae7e6d805 133 test_summary, shuffle_seed))
borlanic 0:fbdae7e6d805 134 print("Completed in %.2f sec"% (elapsed_time))
borlanic 0:fbdae7e6d805 135
borlanic 0:fbdae7e6d805 136
borlanic 0:fbdae7e6d805 137 class SingleTestRunner(object):
borlanic 0:fbdae7e6d805 138 """ Object wrapper for single test run which may involve multiple MUTs
borlanic 0:fbdae7e6d805 139 """
borlanic 0:fbdae7e6d805 140 RE_DETECT_TESTCASE_RESULT = None
borlanic 0:fbdae7e6d805 141
borlanic 0:fbdae7e6d805 142 # Return codes for test script
borlanic 0:fbdae7e6d805 143 TEST_RESULT_OK = "OK"
borlanic 0:fbdae7e6d805 144 TEST_RESULT_FAIL = "FAIL"
borlanic 0:fbdae7e6d805 145 TEST_RESULT_ERROR = "ERROR"
borlanic 0:fbdae7e6d805 146 TEST_RESULT_UNDEF = "UNDEF"
borlanic 0:fbdae7e6d805 147 TEST_RESULT_IOERR_COPY = "IOERR_COPY"
borlanic 0:fbdae7e6d805 148 TEST_RESULT_IOERR_DISK = "IOERR_DISK"
borlanic 0:fbdae7e6d805 149 TEST_RESULT_IOERR_SERIAL = "IOERR_SERIAL"
borlanic 0:fbdae7e6d805 150 TEST_RESULT_TIMEOUT = "TIMEOUT"
borlanic 0:fbdae7e6d805 151 TEST_RESULT_NO_IMAGE = "NO_IMAGE"
borlanic 0:fbdae7e6d805 152 TEST_RESULT_MBED_ASSERT = "MBED_ASSERT"
borlanic 0:fbdae7e6d805 153 TEST_RESULT_BUILD_FAILED = "BUILD_FAILED"
borlanic 0:fbdae7e6d805 154 TEST_RESULT_NOT_SUPPORTED = "NOT_SUPPORTED"
borlanic 0:fbdae7e6d805 155
borlanic 0:fbdae7e6d805 156 GLOBAL_LOOPS_COUNT = 1 # How many times each test should be repeated
borlanic 0:fbdae7e6d805 157 TEST_LOOPS_LIST = [] # We redefine no.of loops per test_id
borlanic 0:fbdae7e6d805 158 TEST_LOOPS_DICT = {} # TEST_LOOPS_LIST in dict format: { test_id : test_loop_count}
borlanic 0:fbdae7e6d805 159
borlanic 0:fbdae7e6d805 160 muts = {} # MUTs descriptor (from external file)
borlanic 0:fbdae7e6d805 161 test_spec = {} # Test specification (from external file)
borlanic 0:fbdae7e6d805 162
borlanic 0:fbdae7e6d805 163 # mbed test suite -> SingleTestRunner
borlanic 0:fbdae7e6d805 164 TEST_RESULT_MAPPING = {"success" : TEST_RESULT_OK,
borlanic 0:fbdae7e6d805 165 "failure" : TEST_RESULT_FAIL,
borlanic 0:fbdae7e6d805 166 "error" : TEST_RESULT_ERROR,
borlanic 0:fbdae7e6d805 167 "ioerr_copy" : TEST_RESULT_IOERR_COPY,
borlanic 0:fbdae7e6d805 168 "ioerr_disk" : TEST_RESULT_IOERR_DISK,
borlanic 0:fbdae7e6d805 169 "ioerr_serial" : TEST_RESULT_IOERR_SERIAL,
borlanic 0:fbdae7e6d805 170 "timeout" : TEST_RESULT_TIMEOUT,
borlanic 0:fbdae7e6d805 171 "no_image" : TEST_RESULT_NO_IMAGE,
borlanic 0:fbdae7e6d805 172 "end" : TEST_RESULT_UNDEF,
borlanic 0:fbdae7e6d805 173 "mbed_assert" : TEST_RESULT_MBED_ASSERT,
borlanic 0:fbdae7e6d805 174 "build_failed" : TEST_RESULT_BUILD_FAILED,
borlanic 0:fbdae7e6d805 175 "not_supproted" : TEST_RESULT_NOT_SUPPORTED
borlanic 0:fbdae7e6d805 176 }
borlanic 0:fbdae7e6d805 177
borlanic 0:fbdae7e6d805 178 def __init__(self,
borlanic 0:fbdae7e6d805 179 _global_loops_count=1,
borlanic 0:fbdae7e6d805 180 _test_loops_list=None,
borlanic 0:fbdae7e6d805 181 _muts={},
borlanic 0:fbdae7e6d805 182 _clean=False,
borlanic 0:fbdae7e6d805 183 _parser=None,
borlanic 0:fbdae7e6d805 184 _opts=None,
borlanic 0:fbdae7e6d805 185 _opts_db_url=None,
borlanic 0:fbdae7e6d805 186 _opts_log_file_name=None,
borlanic 0:fbdae7e6d805 187 _opts_report_html_file_name=None,
borlanic 0:fbdae7e6d805 188 _opts_report_junit_file_name=None,
borlanic 0:fbdae7e6d805 189 _opts_report_build_file_name=None,
borlanic 0:fbdae7e6d805 190 _opts_report_text_file_name=None,
borlanic 0:fbdae7e6d805 191 _opts_build_report={},
borlanic 0:fbdae7e6d805 192 _opts_build_properties={},
borlanic 0:fbdae7e6d805 193 _test_spec={},
borlanic 0:fbdae7e6d805 194 _opts_goanna_for_mbed_sdk=None,
borlanic 0:fbdae7e6d805 195 _opts_goanna_for_tests=None,
borlanic 0:fbdae7e6d805 196 _opts_shuffle_test_order=False,
borlanic 0:fbdae7e6d805 197 _opts_shuffle_test_seed=None,
borlanic 0:fbdae7e6d805 198 _opts_test_by_names=None,
borlanic 0:fbdae7e6d805 199 _opts_peripheral_by_names=None,
borlanic 0:fbdae7e6d805 200 _opts_test_only_peripheral=False,
borlanic 0:fbdae7e6d805 201 _opts_test_only_common=False,
borlanic 0:fbdae7e6d805 202 _opts_verbose_skipped_tests=False,
borlanic 0:fbdae7e6d805 203 _opts_verbose_test_result_only=False,
borlanic 0:fbdae7e6d805 204 _opts_verbose=False,
borlanic 0:fbdae7e6d805 205 _opts_firmware_global_name=None,
borlanic 0:fbdae7e6d805 206 _opts_only_build_tests=False,
borlanic 0:fbdae7e6d805 207 _opts_parallel_test_exec=False,
borlanic 0:fbdae7e6d805 208 _opts_suppress_summary=False,
borlanic 0:fbdae7e6d805 209 _opts_test_x_toolchain_summary=False,
borlanic 0:fbdae7e6d805 210 _opts_copy_method=None,
borlanic 0:fbdae7e6d805 211 _opts_mut_reset_type=None,
borlanic 0:fbdae7e6d805 212 _opts_jobs=None,
borlanic 0:fbdae7e6d805 213 _opts_waterfall_test=None,
borlanic 0:fbdae7e6d805 214 _opts_consolidate_waterfall_test=None,
borlanic 0:fbdae7e6d805 215 _opts_extend_test_timeout=None,
borlanic 0:fbdae7e6d805 216 _opts_auto_detect=None,
borlanic 0:fbdae7e6d805 217 _opts_include_non_automated=False):
borlanic 0:fbdae7e6d805 218 """ Let's try hard to init this object
borlanic 0:fbdae7e6d805 219 """
borlanic 0:fbdae7e6d805 220 from colorama import init
borlanic 0:fbdae7e6d805 221 init()
borlanic 0:fbdae7e6d805 222
borlanic 0:fbdae7e6d805 223 PATTERN = "\\{(" + "|".join(self.TEST_RESULT_MAPPING.keys()) + ")\\}"
borlanic 0:fbdae7e6d805 224 self.RE_DETECT_TESTCASE_RESULT = re.compile(PATTERN)
borlanic 0:fbdae7e6d805 225 # Settings related to test loops counters
borlanic 0:fbdae7e6d805 226 try:
borlanic 0:fbdae7e6d805 227 _global_loops_count = int(_global_loops_count)
borlanic 0:fbdae7e6d805 228 except:
borlanic 0:fbdae7e6d805 229 _global_loops_count = 1
borlanic 0:fbdae7e6d805 230 if _global_loops_count < 1:
borlanic 0:fbdae7e6d805 231 _global_loops_count = 1
borlanic 0:fbdae7e6d805 232 self.GLOBAL_LOOPS_COUNT = _global_loops_count
borlanic 0:fbdae7e6d805 233 self.TEST_LOOPS_LIST = _test_loops_list if _test_loops_list else []
borlanic 0:fbdae7e6d805 234 self.TEST_LOOPS_DICT = self.test_loop_list_to_dict(_test_loops_list)
borlanic 0:fbdae7e6d805 235
borlanic 0:fbdae7e6d805 236 self.shuffle_random_seed = 0.0
borlanic 0:fbdae7e6d805 237 self.SHUFFLE_SEED_ROUND = 10
borlanic 0:fbdae7e6d805 238
borlanic 0:fbdae7e6d805 239 # MUT list and test specification storage
borlanic 0:fbdae7e6d805 240 self.muts = _muts
borlanic 0:fbdae7e6d805 241 self.test_spec = _test_spec
borlanic 0:fbdae7e6d805 242
borlanic 0:fbdae7e6d805 243 # Settings passed e.g. from command line
borlanic 0:fbdae7e6d805 244 self.opts_db_url = _opts_db_url
borlanic 0:fbdae7e6d805 245 self.opts_log_file_name = _opts_log_file_name
borlanic 0:fbdae7e6d805 246 self.opts_report_html_file_name = _opts_report_html_file_name
borlanic 0:fbdae7e6d805 247 self.opts_report_junit_file_name = _opts_report_junit_file_name
borlanic 0:fbdae7e6d805 248 self.opts_report_build_file_name = _opts_report_build_file_name
borlanic 0:fbdae7e6d805 249 self.opts_report_text_file_name = _opts_report_text_file_name
borlanic 0:fbdae7e6d805 250 self.opts_goanna_for_mbed_sdk = _opts_goanna_for_mbed_sdk
borlanic 0:fbdae7e6d805 251 self.opts_goanna_for_tests = _opts_goanna_for_tests
borlanic 0:fbdae7e6d805 252 self.opts_shuffle_test_order = _opts_shuffle_test_order
borlanic 0:fbdae7e6d805 253 self.opts_shuffle_test_seed = _opts_shuffle_test_seed
borlanic 0:fbdae7e6d805 254 self.opts_test_by_names = _opts_test_by_names
borlanic 0:fbdae7e6d805 255 self.opts_peripheral_by_names = _opts_peripheral_by_names
borlanic 0:fbdae7e6d805 256 self.opts_test_only_peripheral = _opts_test_only_peripheral
borlanic 0:fbdae7e6d805 257 self.opts_test_only_common = _opts_test_only_common
borlanic 0:fbdae7e6d805 258 self.opts_verbose_skipped_tests = _opts_verbose_skipped_tests
borlanic 0:fbdae7e6d805 259 self.opts_verbose_test_result_only = _opts_verbose_test_result_only
borlanic 0:fbdae7e6d805 260 self.opts_verbose = _opts_verbose
borlanic 0:fbdae7e6d805 261 self.opts_firmware_global_name = _opts_firmware_global_name
borlanic 0:fbdae7e6d805 262 self.opts_only_build_tests = _opts_only_build_tests
borlanic 0:fbdae7e6d805 263 self.opts_parallel_test_exec = _opts_parallel_test_exec
borlanic 0:fbdae7e6d805 264 self.opts_suppress_summary = _opts_suppress_summary
borlanic 0:fbdae7e6d805 265 self.opts_test_x_toolchain_summary = _opts_test_x_toolchain_summary
borlanic 0:fbdae7e6d805 266 self.opts_copy_method = _opts_copy_method
borlanic 0:fbdae7e6d805 267 self.opts_mut_reset_type = _opts_mut_reset_type
borlanic 0:fbdae7e6d805 268 self.opts_jobs = _opts_jobs if _opts_jobs is not None else 1
borlanic 0:fbdae7e6d805 269 self.opts_waterfall_test = _opts_waterfall_test
borlanic 0:fbdae7e6d805 270 self.opts_consolidate_waterfall_test = _opts_consolidate_waterfall_test
borlanic 0:fbdae7e6d805 271 self.opts_extend_test_timeout = _opts_extend_test_timeout
borlanic 0:fbdae7e6d805 272 self.opts_clean = _clean
borlanic 0:fbdae7e6d805 273 self.opts_parser = _parser
borlanic 0:fbdae7e6d805 274 self.opts = _opts
borlanic 0:fbdae7e6d805 275 self.opts_auto_detect = _opts_auto_detect
borlanic 0:fbdae7e6d805 276 self.opts_include_non_automated = _opts_include_non_automated
borlanic 0:fbdae7e6d805 277
borlanic 0:fbdae7e6d805 278 self.build_report = _opts_build_report
borlanic 0:fbdae7e6d805 279 self.build_properties = _opts_build_properties
borlanic 0:fbdae7e6d805 280
borlanic 0:fbdae7e6d805 281 # File / screen logger initialization
borlanic 0:fbdae7e6d805 282 self.logger = CLITestLogger(file_name=self.opts_log_file_name) # Default test logger
borlanic 0:fbdae7e6d805 283
borlanic 0:fbdae7e6d805 284 # Database related initializations
borlanic 0:fbdae7e6d805 285 self.db_logger = factory_db_logger(self.opts_db_url)
borlanic 0:fbdae7e6d805 286 self.db_logger_build_id = None # Build ID (database index of build_id table)
borlanic 0:fbdae7e6d805 287 # Let's connect to database to set up credentials and confirm database is ready
borlanic 0:fbdae7e6d805 288 if self.db_logger:
borlanic 0:fbdae7e6d805 289 self.db_logger.connect_url(self.opts_db_url) # Save db access info inside db_logger object
borlanic 0:fbdae7e6d805 290 if self.db_logger.is_connected():
borlanic 0:fbdae7e6d805 291 # Get hostname and uname so we can use it as build description
borlanic 0:fbdae7e6d805 292 # when creating new build_id in external database
borlanic 0:fbdae7e6d805 293 (_hostname, _uname) = self.db_logger.get_hostname()
borlanic 0:fbdae7e6d805 294 _host_location = os.path.dirname(os.path.abspath(__file__))
borlanic 0:fbdae7e6d805 295 build_id_type = None if self.opts_only_build_tests is None else self.db_logger.BUILD_ID_TYPE_BUILD_ONLY
borlanic 0:fbdae7e6d805 296 self.db_logger_build_id = self.db_logger.get_next_build_id(_hostname, desc=_uname, location=_host_location, type=build_id_type)
borlanic 0:fbdae7e6d805 297 self.db_logger.disconnect()
borlanic 0:fbdae7e6d805 298
borlanic 0:fbdae7e6d805 299 def dump_options(self):
borlanic 0:fbdae7e6d805 300 """ Function returns data structure with common settings passed to SingelTestRunner
borlanic 0:fbdae7e6d805 301 It can be used for example to fill _extra fields in database storing test suite single run data
borlanic 0:fbdae7e6d805 302 Example:
borlanic 0:fbdae7e6d805 303 data = self.dump_options()
borlanic 0:fbdae7e6d805 304 or
borlanic 0:fbdae7e6d805 305 data_str = json.dumps(self.dump_options())
borlanic 0:fbdae7e6d805 306 """
borlanic 0:fbdae7e6d805 307 result = {"db_url" : str(self.opts_db_url),
borlanic 0:fbdae7e6d805 308 "log_file_name" : str(self.opts_log_file_name),
borlanic 0:fbdae7e6d805 309 "shuffle_test_order" : str(self.opts_shuffle_test_order),
borlanic 0:fbdae7e6d805 310 "shuffle_test_seed" : str(self.opts_shuffle_test_seed),
borlanic 0:fbdae7e6d805 311 "test_by_names" : str(self.opts_test_by_names),
borlanic 0:fbdae7e6d805 312 "peripheral_by_names" : str(self.opts_peripheral_by_names),
borlanic 0:fbdae7e6d805 313 "test_only_peripheral" : str(self.opts_test_only_peripheral),
borlanic 0:fbdae7e6d805 314 "test_only_common" : str(self.opts_test_only_common),
borlanic 0:fbdae7e6d805 315 "verbose" : str(self.opts_verbose),
borlanic 0:fbdae7e6d805 316 "firmware_global_name" : str(self.opts_firmware_global_name),
borlanic 0:fbdae7e6d805 317 "only_build_tests" : str(self.opts_only_build_tests),
borlanic 0:fbdae7e6d805 318 "copy_method" : str(self.opts_copy_method),
borlanic 0:fbdae7e6d805 319 "mut_reset_type" : str(self.opts_mut_reset_type),
borlanic 0:fbdae7e6d805 320 "jobs" : str(self.opts_jobs),
borlanic 0:fbdae7e6d805 321 "extend_test_timeout" : str(self.opts_extend_test_timeout),
borlanic 0:fbdae7e6d805 322 "_dummy" : ''
borlanic 0:fbdae7e6d805 323 }
borlanic 0:fbdae7e6d805 324 return result
borlanic 0:fbdae7e6d805 325
borlanic 0:fbdae7e6d805 326 def shuffle_random_func(self):
borlanic 0:fbdae7e6d805 327 return self.shuffle_random_seed
borlanic 0:fbdae7e6d805 328
borlanic 0:fbdae7e6d805 329 def is_shuffle_seed_float(self):
borlanic 0:fbdae7e6d805 330 """ return true if function parameter can be converted to float
borlanic 0:fbdae7e6d805 331 """
borlanic 0:fbdae7e6d805 332 result = True
borlanic 0:fbdae7e6d805 333 try:
borlanic 0:fbdae7e6d805 334 float(self.shuffle_random_seed)
borlanic 0:fbdae7e6d805 335 except ValueError:
borlanic 0:fbdae7e6d805 336 result = False
borlanic 0:fbdae7e6d805 337 return result
borlanic 0:fbdae7e6d805 338
borlanic 0:fbdae7e6d805 339 # This will store target / toolchain specific properties
borlanic 0:fbdae7e6d805 340 test_suite_properties_ext = {} # target : toolchain
borlanic 0:fbdae7e6d805 341 # Here we store test results
borlanic 0:fbdae7e6d805 342 test_summary = []
borlanic 0:fbdae7e6d805 343 # Here we store test results in extended data structure
borlanic 0:fbdae7e6d805 344 test_summary_ext = {}
borlanic 0:fbdae7e6d805 345 execute_thread_slice_lock = Lock()
borlanic 0:fbdae7e6d805 346
borlanic 0:fbdae7e6d805 347 def execute_thread_slice(self, q, target, toolchains, clean, test_ids, build_report, build_properties):
borlanic 0:fbdae7e6d805 348 for toolchain in toolchains:
borlanic 0:fbdae7e6d805 349 tt_id = "%s::%s" % (toolchain, target)
borlanic 0:fbdae7e6d805 350
borlanic 0:fbdae7e6d805 351 T = TARGET_MAP[target]
borlanic 0:fbdae7e6d805 352
borlanic 0:fbdae7e6d805 353 # print target, toolchain
borlanic 0:fbdae7e6d805 354 # Test suite properties returned to external tools like CI
borlanic 0:fbdae7e6d805 355 test_suite_properties = {
borlanic 0:fbdae7e6d805 356 'jobs': self.opts_jobs,
borlanic 0:fbdae7e6d805 357 'clean': clean,
borlanic 0:fbdae7e6d805 358 'target': target,
borlanic 0:fbdae7e6d805 359 'vendor': T.extra_labels[0],
borlanic 0:fbdae7e6d805 360 'test_ids': ', '.join(test_ids),
borlanic 0:fbdae7e6d805 361 'toolchain': toolchain,
borlanic 0:fbdae7e6d805 362 'shuffle_random_seed': self.shuffle_random_seed
borlanic 0:fbdae7e6d805 363 }
borlanic 0:fbdae7e6d805 364
borlanic 0:fbdae7e6d805 365
borlanic 0:fbdae7e6d805 366 # print '=== %s::%s ===' % (target, toolchain)
borlanic 0:fbdae7e6d805 367 # Let's build our test
borlanic 0:fbdae7e6d805 368 if target not in TARGET_MAP:
borlanic 0:fbdae7e6d805 369 print(self.logger.log_line(
borlanic 0:fbdae7e6d805 370 self.logger.LogType.NOTIF,
borlanic 0:fbdae7e6d805 371 'Skipped tests for %s target. Target platform not found' %
borlanic 0:fbdae7e6d805 372 (target)))
borlanic 0:fbdae7e6d805 373 continue
borlanic 0:fbdae7e6d805 374
borlanic 0:fbdae7e6d805 375 clean_mbed_libs_options = (self.opts_goanna_for_mbed_sdk or
borlanic 0:fbdae7e6d805 376 self.opts_clean or clean)
borlanic 0:fbdae7e6d805 377
borlanic 0:fbdae7e6d805 378 profile = extract_profile(self.opts_parser, self.opts, toolchain)
borlanic 0:fbdae7e6d805 379 stats_depth = self.opts.stats_depth or 2
borlanic 0:fbdae7e6d805 380
borlanic 0:fbdae7e6d805 381 try:
borlanic 0:fbdae7e6d805 382 build_mbed_libs_result = build_mbed_libs(
borlanic 0:fbdae7e6d805 383 T, toolchain,
borlanic 0:fbdae7e6d805 384 clean=clean_mbed_libs_options,
borlanic 0:fbdae7e6d805 385 verbose=self.opts_verbose,
borlanic 0:fbdae7e6d805 386 jobs=self.opts_jobs,
borlanic 0:fbdae7e6d805 387 report=build_report,
borlanic 0:fbdae7e6d805 388 properties=build_properties,
borlanic 0:fbdae7e6d805 389 build_profile=profile)
borlanic 0:fbdae7e6d805 390
borlanic 0:fbdae7e6d805 391 if not build_mbed_libs_result:
borlanic 0:fbdae7e6d805 392 print(self.logger.log_line(
borlanic 0:fbdae7e6d805 393 self.logger.LogType.NOTIF,
borlanic 0:fbdae7e6d805 394 'Skipped tests for %s target. Toolchain %s is not '
borlanic 0:fbdae7e6d805 395 'supported for this target'% (T.name, toolchain)))
borlanic 0:fbdae7e6d805 396 continue
borlanic 0:fbdae7e6d805 397
borlanic 0:fbdae7e6d805 398 except ToolException:
borlanic 0:fbdae7e6d805 399 print(self.logger.log_line(
borlanic 0:fbdae7e6d805 400 self.logger.LogType.ERROR,
borlanic 0:fbdae7e6d805 401 'There were errors while building MBED libs for %s using %s'
borlanic 0:fbdae7e6d805 402 % (target, toolchain)))
borlanic 0:fbdae7e6d805 403 continue
borlanic 0:fbdae7e6d805 404
borlanic 0:fbdae7e6d805 405 build_dir = join(BUILD_DIR, "test", target, toolchain)
borlanic 0:fbdae7e6d805 406
borlanic 0:fbdae7e6d805 407 test_suite_properties['build_mbed_libs_result'] = build_mbed_libs_result
borlanic 0:fbdae7e6d805 408 test_suite_properties['build_dir'] = build_dir
borlanic 0:fbdae7e6d805 409 test_suite_properties['skipped'] = []
borlanic 0:fbdae7e6d805 410
borlanic 0:fbdae7e6d805 411 # Enumerate through all tests and shuffle test order if requested
borlanic 0:fbdae7e6d805 412 test_map_keys = sorted(TEST_MAP.keys())
borlanic 0:fbdae7e6d805 413
borlanic 0:fbdae7e6d805 414 if self.opts_shuffle_test_order:
borlanic 0:fbdae7e6d805 415 random.shuffle(test_map_keys, self.shuffle_random_func)
borlanic 0:fbdae7e6d805 416 # Update database with shuffle seed f applicable
borlanic 0:fbdae7e6d805 417 if self.db_logger:
borlanic 0:fbdae7e6d805 418 self.db_logger.reconnect();
borlanic 0:fbdae7e6d805 419 if self.db_logger.is_connected():
borlanic 0:fbdae7e6d805 420 self.db_logger.update_build_id_info(
borlanic 0:fbdae7e6d805 421 self.db_logger_build_id,
borlanic 0:fbdae7e6d805 422 _shuffle_seed=self.shuffle_random_func())
borlanic 0:fbdae7e6d805 423 self.db_logger.disconnect();
borlanic 0:fbdae7e6d805 424
borlanic 0:fbdae7e6d805 425 if self.db_logger:
borlanic 0:fbdae7e6d805 426 self.db_logger.reconnect();
borlanic 0:fbdae7e6d805 427 if self.db_logger.is_connected():
borlanic 0:fbdae7e6d805 428 # Update MUTs and Test Specification in database
borlanic 0:fbdae7e6d805 429 self.db_logger.update_build_id_info(
borlanic 0:fbdae7e6d805 430 self.db_logger_build_id,
borlanic 0:fbdae7e6d805 431 _muts=self.muts, _test_spec=self.test_spec)
borlanic 0:fbdae7e6d805 432 # Update Extra information in database (some options passed to test suite)
borlanic 0:fbdae7e6d805 433 self.db_logger.update_build_id_info(
borlanic 0:fbdae7e6d805 434 self.db_logger_build_id,
borlanic 0:fbdae7e6d805 435 _extra=json.dumps(self.dump_options()))
borlanic 0:fbdae7e6d805 436 self.db_logger.disconnect();
borlanic 0:fbdae7e6d805 437
borlanic 0:fbdae7e6d805 438 valid_test_map_keys = self.get_valid_tests(test_map_keys, target, toolchain, test_ids, self.opts_include_non_automated)
borlanic 0:fbdae7e6d805 439 skipped_test_map_keys = self.get_skipped_tests(test_map_keys, valid_test_map_keys)
borlanic 0:fbdae7e6d805 440
borlanic 0:fbdae7e6d805 441 for skipped_test_id in skipped_test_map_keys:
borlanic 0:fbdae7e6d805 442 test_suite_properties['skipped'].append(skipped_test_id)
borlanic 0:fbdae7e6d805 443
borlanic 0:fbdae7e6d805 444
borlanic 0:fbdae7e6d805 445 # First pass through all tests and determine which libraries need to be built
borlanic 0:fbdae7e6d805 446 libraries = []
borlanic 0:fbdae7e6d805 447 for test_id in valid_test_map_keys:
borlanic 0:fbdae7e6d805 448 test = TEST_MAP[test_id]
borlanic 0:fbdae7e6d805 449
borlanic 0:fbdae7e6d805 450 # Detect which lib should be added to test
borlanic 0:fbdae7e6d805 451 # Some libs have to compiled like RTOS or ETH
borlanic 0:fbdae7e6d805 452 for lib in LIBRARIES:
borlanic 0:fbdae7e6d805 453 if lib['build_dir'] in test.dependencies and lib['id'] not in libraries:
borlanic 0:fbdae7e6d805 454 libraries.append(lib['id'])
borlanic 0:fbdae7e6d805 455
borlanic 0:fbdae7e6d805 456
borlanic 0:fbdae7e6d805 457 clean_project_options = True if self.opts_goanna_for_tests or clean or self.opts_clean else None
borlanic 0:fbdae7e6d805 458
borlanic 0:fbdae7e6d805 459 # Build all required libraries
borlanic 0:fbdae7e6d805 460 for lib_id in libraries:
borlanic 0:fbdae7e6d805 461 try:
borlanic 0:fbdae7e6d805 462 build_lib(lib_id,
borlanic 0:fbdae7e6d805 463 T,
borlanic 0:fbdae7e6d805 464 toolchain,
borlanic 0:fbdae7e6d805 465 verbose=self.opts_verbose,
borlanic 0:fbdae7e6d805 466 clean=clean_mbed_libs_options,
borlanic 0:fbdae7e6d805 467 jobs=self.opts_jobs,
borlanic 0:fbdae7e6d805 468 report=build_report,
borlanic 0:fbdae7e6d805 469 properties=build_properties,
borlanic 0:fbdae7e6d805 470 build_profile=profile)
borlanic 0:fbdae7e6d805 471
borlanic 0:fbdae7e6d805 472 except ToolException:
borlanic 0:fbdae7e6d805 473 print(self.logger.log_line(
borlanic 0:fbdae7e6d805 474 self.logger.LogType.ERROR,
borlanic 0:fbdae7e6d805 475 'There were errors while building library %s' % lib_id))
borlanic 0:fbdae7e6d805 476 continue
borlanic 0:fbdae7e6d805 477
borlanic 0:fbdae7e6d805 478
borlanic 0:fbdae7e6d805 479 for test_id in valid_test_map_keys:
borlanic 0:fbdae7e6d805 480 test = TEST_MAP[test_id]
borlanic 0:fbdae7e6d805 481
borlanic 0:fbdae7e6d805 482 test_suite_properties['test.libs.%s.%s.%s'% (target, toolchain, test_id)] = ', '.join(libraries)
borlanic 0:fbdae7e6d805 483
borlanic 0:fbdae7e6d805 484 # TODO: move this 2 below loops to separate function
borlanic 0:fbdae7e6d805 485 INC_DIRS = []
borlanic 0:fbdae7e6d805 486 for lib_id in libraries:
borlanic 0:fbdae7e6d805 487 if 'inc_dirs_ext' in LIBRARY_MAP[lib_id] and LIBRARY_MAP[lib_id]['inc_dirs_ext']:
borlanic 0:fbdae7e6d805 488 INC_DIRS.extend(LIBRARY_MAP[lib_id]['inc_dirs_ext'])
borlanic 0:fbdae7e6d805 489
borlanic 0:fbdae7e6d805 490 MACROS = []
borlanic 0:fbdae7e6d805 491 for lib_id in libraries:
borlanic 0:fbdae7e6d805 492 if 'macros' in LIBRARY_MAP[lib_id] and LIBRARY_MAP[lib_id]['macros']:
borlanic 0:fbdae7e6d805 493 MACROS.extend(LIBRARY_MAP[lib_id]['macros'])
borlanic 0:fbdae7e6d805 494 MACROS.append('TEST_SUITE_TARGET_NAME="%s"'% target)
borlanic 0:fbdae7e6d805 495 MACROS.append('TEST_SUITE_TEST_ID="%s"'% test_id)
borlanic 0:fbdae7e6d805 496 test_uuid = uuid.uuid4()
borlanic 0:fbdae7e6d805 497 MACROS.append('TEST_SUITE_UUID="%s"'% str(test_uuid))
borlanic 0:fbdae7e6d805 498
borlanic 0:fbdae7e6d805 499 # Prepare extended test results data structure (it can be used to generate detailed test report)
borlanic 0:fbdae7e6d805 500 if target not in self.test_summary_ext:
borlanic 0:fbdae7e6d805 501 self.test_summary_ext[target] = {} # test_summary_ext : toolchain
borlanic 0:fbdae7e6d805 502 if toolchain not in self.test_summary_ext[target]:
borlanic 0:fbdae7e6d805 503 self.test_summary_ext[target][toolchain] = {} # test_summary_ext : toolchain : target
borlanic 0:fbdae7e6d805 504
borlanic 0:fbdae7e6d805 505 tt_test_id = "%s::%s::%s" % (toolchain, target, test_id) # For logging only
borlanic 0:fbdae7e6d805 506
borlanic 0:fbdae7e6d805 507 project_name = self.opts_firmware_global_name if self.opts_firmware_global_name else None
borlanic 0:fbdae7e6d805 508 try:
borlanic 0:fbdae7e6d805 509 path = build_project(test.source_dir, join(build_dir, test_id), T,
borlanic 0:fbdae7e6d805 510 toolchain, test.dependencies, clean=clean_project_options,
borlanic 0:fbdae7e6d805 511 verbose=self.opts_verbose, name=project_name, macros=MACROS,
borlanic 0:fbdae7e6d805 512 inc_dirs=INC_DIRS, jobs=self.opts_jobs, report=build_report,
borlanic 0:fbdae7e6d805 513 properties=build_properties, project_id=test_id,
borlanic 0:fbdae7e6d805 514 project_description=test.get_description(),
borlanic 0:fbdae7e6d805 515 build_profile=profile, stats_depth=stats_depth)
borlanic 0:fbdae7e6d805 516
borlanic 0:fbdae7e6d805 517 except Exception as e:
borlanic 0:fbdae7e6d805 518 project_name_str = project_name if project_name is not None else test_id
borlanic 0:fbdae7e6d805 519
borlanic 0:fbdae7e6d805 520
borlanic 0:fbdae7e6d805 521 test_result = self.TEST_RESULT_FAIL
borlanic 0:fbdae7e6d805 522
borlanic 0:fbdae7e6d805 523 if isinstance(e, ToolException):
borlanic 0:fbdae7e6d805 524 print(self.logger.log_line(
borlanic 0:fbdae7e6d805 525 self.logger.LogType.ERROR,
borlanic 0:fbdae7e6d805 526 'There were errors while building project %s' %
borlanic 0:fbdae7e6d805 527 project_name_str))
borlanic 0:fbdae7e6d805 528 test_result = self.TEST_RESULT_BUILD_FAILED
borlanic 0:fbdae7e6d805 529 elif isinstance(e, NotSupportedException):
borlanic 0:fbdae7e6d805 530 print(elf.logger.log_line(
borlanic 0:fbdae7e6d805 531 self.logger.LogType.INFO,
borlanic 0:fbdae7e6d805 532 'Project %s is not supported' % project_name_str))
borlanic 0:fbdae7e6d805 533 test_result = self.TEST_RESULT_NOT_SUPPORTED
borlanic 0:fbdae7e6d805 534
borlanic 0:fbdae7e6d805 535
borlanic 0:fbdae7e6d805 536 # Append test results to global test summary
borlanic 0:fbdae7e6d805 537 self.test_summary.append(
borlanic 0:fbdae7e6d805 538 (test_result, target, toolchain, test_id,
borlanic 0:fbdae7e6d805 539 test.get_description(), 0, 0, '-')
borlanic 0:fbdae7e6d805 540 )
borlanic 0:fbdae7e6d805 541
borlanic 0:fbdae7e6d805 542 # Add detailed test result to test summary structure
borlanic 0:fbdae7e6d805 543 if test_id not in self.test_summary_ext[target][toolchain]:
borlanic 0:fbdae7e6d805 544 self.test_summary_ext[target][toolchain][test_id] = []
borlanic 0:fbdae7e6d805 545
borlanic 0:fbdae7e6d805 546 self.test_summary_ext[target][toolchain][test_id].append({ 0: {
borlanic 0:fbdae7e6d805 547 'result' : test_result,
borlanic 0:fbdae7e6d805 548 'output' : '',
borlanic 0:fbdae7e6d805 549 'target_name' : target,
borlanic 0:fbdae7e6d805 550 'target_name_unique': target,
borlanic 0:fbdae7e6d805 551 'toolchain_name' : toolchain,
borlanic 0:fbdae7e6d805 552 'id' : test_id,
borlanic 0:fbdae7e6d805 553 'description' : test.get_description(),
borlanic 0:fbdae7e6d805 554 'elapsed_time' : 0,
borlanic 0:fbdae7e6d805 555 'duration' : 0,
borlanic 0:fbdae7e6d805 556 'copy_method' : None
borlanic 0:fbdae7e6d805 557 }})
borlanic 0:fbdae7e6d805 558 continue
borlanic 0:fbdae7e6d805 559
borlanic 0:fbdae7e6d805 560 if self.opts_only_build_tests:
borlanic 0:fbdae7e6d805 561 # With this option we are skipping testing phase
borlanic 0:fbdae7e6d805 562 continue
borlanic 0:fbdae7e6d805 563
borlanic 0:fbdae7e6d805 564 # Test duration can be increased by global value
borlanic 0:fbdae7e6d805 565 test_duration = test.duration
borlanic 0:fbdae7e6d805 566 if self.opts_extend_test_timeout is not None:
borlanic 0:fbdae7e6d805 567 test_duration += self.opts_extend_test_timeout
borlanic 0:fbdae7e6d805 568
borlanic 0:fbdae7e6d805 569 # For an automated test the duration act as a timeout after
borlanic 0:fbdae7e6d805 570 # which the test gets interrupted
borlanic 0:fbdae7e6d805 571 test_spec = self.shape_test_request(target, path, test_id, test_duration)
borlanic 0:fbdae7e6d805 572 test_loops = self.get_test_loop_count(test_id)
borlanic 0:fbdae7e6d805 573
borlanic 0:fbdae7e6d805 574 test_suite_properties['test.duration.%s.%s.%s'% (target, toolchain, test_id)] = test_duration
borlanic 0:fbdae7e6d805 575 test_suite_properties['test.loops.%s.%s.%s'% (target, toolchain, test_id)] = test_loops
borlanic 0:fbdae7e6d805 576 test_suite_properties['test.path.%s.%s.%s'% (target, toolchain, test_id)] = path
borlanic 0:fbdae7e6d805 577
borlanic 0:fbdae7e6d805 578 # read MUTs, test specification and perform tests
borlanic 0:fbdae7e6d805 579 handle_results = self.handle(test_spec, target, toolchain, test_loops=test_loops)
borlanic 0:fbdae7e6d805 580
borlanic 0:fbdae7e6d805 581 if handle_results is None:
borlanic 0:fbdae7e6d805 582 continue
borlanic 0:fbdae7e6d805 583
borlanic 0:fbdae7e6d805 584 for handle_result in handle_results:
borlanic 0:fbdae7e6d805 585 if handle_result:
borlanic 0:fbdae7e6d805 586 single_test_result, detailed_test_results = handle_result
borlanic 0:fbdae7e6d805 587 else:
borlanic 0:fbdae7e6d805 588 continue
borlanic 0:fbdae7e6d805 589
borlanic 0:fbdae7e6d805 590 # Append test results to global test summary
borlanic 0:fbdae7e6d805 591 if single_test_result is not None:
borlanic 0:fbdae7e6d805 592 self.test_summary.append(single_test_result)
borlanic 0:fbdae7e6d805 593
borlanic 0:fbdae7e6d805 594 # Add detailed test result to test summary structure
borlanic 0:fbdae7e6d805 595 if target not in self.test_summary_ext[target][toolchain]:
borlanic 0:fbdae7e6d805 596 if test_id not in self.test_summary_ext[target][toolchain]:
borlanic 0:fbdae7e6d805 597 self.test_summary_ext[target][toolchain][test_id] = []
borlanic 0:fbdae7e6d805 598
borlanic 0:fbdae7e6d805 599 append_test_result = detailed_test_results
borlanic 0:fbdae7e6d805 600
borlanic 0:fbdae7e6d805 601 # If waterfall and consolidate-waterfall options are enabled,
borlanic 0:fbdae7e6d805 602 # only include the last test result in the report.
borlanic 0:fbdae7e6d805 603 if self.opts_waterfall_test and self.opts_consolidate_waterfall_test:
borlanic 0:fbdae7e6d805 604 append_test_result = {0: detailed_test_results[len(detailed_test_results) - 1]}
borlanic 0:fbdae7e6d805 605
borlanic 0:fbdae7e6d805 606 self.test_summary_ext[target][toolchain][test_id].append(append_test_result)
borlanic 0:fbdae7e6d805 607
borlanic 0:fbdae7e6d805 608 test_suite_properties['skipped'] = ', '.join(test_suite_properties['skipped'])
borlanic 0:fbdae7e6d805 609 self.test_suite_properties_ext[target][toolchain] = test_suite_properties
borlanic 0:fbdae7e6d805 610
borlanic 0:fbdae7e6d805 611 q.put(target + '_'.join(toolchains))
borlanic 0:fbdae7e6d805 612 return
borlanic 0:fbdae7e6d805 613
borlanic 0:fbdae7e6d805 614 def execute(self):
borlanic 0:fbdae7e6d805 615 clean = self.test_spec.get('clean', False)
borlanic 0:fbdae7e6d805 616 test_ids = self.test_spec.get('test_ids', [])
borlanic 0:fbdae7e6d805 617 q = Queue()
borlanic 0:fbdae7e6d805 618
borlanic 0:fbdae7e6d805 619 # Generate seed for shuffle if seed is not provided in
borlanic 0:fbdae7e6d805 620 self.shuffle_random_seed = round(random.random(), self.SHUFFLE_SEED_ROUND)
borlanic 0:fbdae7e6d805 621 if self.opts_shuffle_test_seed is not None and self.is_shuffle_seed_float():
borlanic 0:fbdae7e6d805 622 self.shuffle_random_seed = round(float(self.opts_shuffle_test_seed), self.SHUFFLE_SEED_ROUND)
borlanic 0:fbdae7e6d805 623
borlanic 0:fbdae7e6d805 624
borlanic 0:fbdae7e6d805 625 if self.opts_parallel_test_exec:
borlanic 0:fbdae7e6d805 626 ###################################################################
borlanic 0:fbdae7e6d805 627 # Experimental, parallel test execution per singletest instance.
borlanic 0:fbdae7e6d805 628 ###################################################################
borlanic 0:fbdae7e6d805 629 execute_threads = [] # Threads used to build mbed SDL, libs, test cases and execute tests
borlanic 0:fbdae7e6d805 630 # Note: We are building here in parallel for each target separately!
borlanic 0:fbdae7e6d805 631 # So we are not building the same thing multiple times and compilers
borlanic 0:fbdae7e6d805 632 # in separate threads do not collide.
borlanic 0:fbdae7e6d805 633 # Inside execute_thread_slice() function function handle() will be called to
borlanic 0:fbdae7e6d805 634 # get information about available MUTs (per target).
borlanic 0:fbdae7e6d805 635 for target, toolchains in self.test_spec['targets'].items():
borlanic 0:fbdae7e6d805 636 self.test_suite_properties_ext[target] = {}
borlanic 0:fbdae7e6d805 637 t = threading.Thread(target=self.execute_thread_slice, args = (q, target, toolchains, clean, test_ids, self.build_report, self.build_properties))
borlanic 0:fbdae7e6d805 638 t.daemon = True
borlanic 0:fbdae7e6d805 639 t.start()
borlanic 0:fbdae7e6d805 640 execute_threads.append(t)
borlanic 0:fbdae7e6d805 641
borlanic 0:fbdae7e6d805 642 for t in execute_threads:
borlanic 0:fbdae7e6d805 643 q.get() # t.join() would block some threads because we should not wait in any order for thread end
borlanic 0:fbdae7e6d805 644 else:
borlanic 0:fbdae7e6d805 645 # Serialized (not parallel) test execution
borlanic 0:fbdae7e6d805 646 for target, toolchains in self.test_spec['targets'].items():
borlanic 0:fbdae7e6d805 647 if target not in self.test_suite_properties_ext:
borlanic 0:fbdae7e6d805 648 self.test_suite_properties_ext[target] = {}
borlanic 0:fbdae7e6d805 649
borlanic 0:fbdae7e6d805 650 self.execute_thread_slice(q, target, toolchains, clean, test_ids, self.build_report, self.build_properties)
borlanic 0:fbdae7e6d805 651 q.get()
borlanic 0:fbdae7e6d805 652
borlanic 0:fbdae7e6d805 653 if self.db_logger:
borlanic 0:fbdae7e6d805 654 self.db_logger.reconnect();
borlanic 0:fbdae7e6d805 655 if self.db_logger.is_connected():
borlanic 0:fbdae7e6d805 656 self.db_logger.update_build_id_info(self.db_logger_build_id, _status_fk=self.db_logger.BUILD_ID_STATUS_COMPLETED)
borlanic 0:fbdae7e6d805 657 self.db_logger.disconnect();
borlanic 0:fbdae7e6d805 658
borlanic 0:fbdae7e6d805 659 return self.test_summary, self.shuffle_random_seed, self.test_summary_ext, self.test_suite_properties_ext, self.build_report, self.build_properties
borlanic 0:fbdae7e6d805 660
borlanic 0:fbdae7e6d805 661 def get_valid_tests(self, test_map_keys, target, toolchain, test_ids, include_non_automated):
borlanic 0:fbdae7e6d805 662 valid_test_map_keys = []
borlanic 0:fbdae7e6d805 663
borlanic 0:fbdae7e6d805 664 for test_id in test_map_keys:
borlanic 0:fbdae7e6d805 665 test = TEST_MAP[test_id]
borlanic 0:fbdae7e6d805 666 if self.opts_test_by_names and test_id not in self.opts_test_by_names:
borlanic 0:fbdae7e6d805 667 continue
borlanic 0:fbdae7e6d805 668
borlanic 0:fbdae7e6d805 669 if test_ids and test_id not in test_ids:
borlanic 0:fbdae7e6d805 670 continue
borlanic 0:fbdae7e6d805 671
borlanic 0:fbdae7e6d805 672 if self.opts_test_only_peripheral and not test.peripherals:
borlanic 0:fbdae7e6d805 673 if self.opts_verbose_skipped_tests:
borlanic 0:fbdae7e6d805 674 print(self.logger.log_line(
borlanic 0:fbdae7e6d805 675 self.logger.LogType.INFO,
borlanic 0:fbdae7e6d805 676 'Common test skipped for target %s' % target))
borlanic 0:fbdae7e6d805 677 continue
borlanic 0:fbdae7e6d805 678
borlanic 0:fbdae7e6d805 679 if (self.opts_peripheral_by_names and test.peripherals and
borlanic 0:fbdae7e6d805 680 not any((i in self.opts_peripheral_by_names)
borlanic 0:fbdae7e6d805 681 for i in test.peripherals)):
borlanic 0:fbdae7e6d805 682 # We will skip tests not forced with -p option
borlanic 0:fbdae7e6d805 683 if self.opts_verbose_skipped_tests:
borlanic 0:fbdae7e6d805 684 print(self.logger.log_line(
borlanic 0:fbdae7e6d805 685 self.logger.LogType.INFO,
borlanic 0:fbdae7e6d805 686 'Common test skipped for target %s' % target))
borlanic 0:fbdae7e6d805 687 continue
borlanic 0:fbdae7e6d805 688
borlanic 0:fbdae7e6d805 689 if self.opts_test_only_common and test.peripherals:
borlanic 0:fbdae7e6d805 690 if self.opts_verbose_skipped_tests:
borlanic 0:fbdae7e6d805 691 print(self.logger.log_line(
borlanic 0:fbdae7e6d805 692 self.logger.LogType.INFO,
borlanic 0:fbdae7e6d805 693 'Peripheral test skipped for target %s' % target))
borlanic 0:fbdae7e6d805 694 continue
borlanic 0:fbdae7e6d805 695
borlanic 0:fbdae7e6d805 696 if not include_non_automated and not test.automated:
borlanic 0:fbdae7e6d805 697 if self.opts_verbose_skipped_tests:
borlanic 0:fbdae7e6d805 698 print(self.logger.log_line(
borlanic 0:fbdae7e6d805 699 self.logger.LogType.INFO,
borlanic 0:fbdae7e6d805 700 'Non automated test skipped for target %s' % target))
borlanic 0:fbdae7e6d805 701 continue
borlanic 0:fbdae7e6d805 702
borlanic 0:fbdae7e6d805 703 if test.is_supported(target, toolchain):
borlanic 0:fbdae7e6d805 704 if test.peripherals is None and self.opts_only_build_tests:
borlanic 0:fbdae7e6d805 705 # When users are using 'build only flag' and test do not have
borlanic 0:fbdae7e6d805 706 # specified peripherals we can allow test building by default
borlanic 0:fbdae7e6d805 707 pass
borlanic 0:fbdae7e6d805 708 elif self.opts_peripheral_by_names and test_id not in self.opts_peripheral_by_names:
borlanic 0:fbdae7e6d805 709 # If we force peripheral with option -p we expect test
borlanic 0:fbdae7e6d805 710 # to pass even if peripheral is not in MUTs file.
borlanic 0:fbdae7e6d805 711 pass
borlanic 0:fbdae7e6d805 712 elif not self.is_peripherals_available(target, test.peripherals):
borlanic 0:fbdae7e6d805 713 if self.opts_verbose_skipped_tests:
borlanic 0:fbdae7e6d805 714 if test.peripherals:
borlanic 0:fbdae7e6d805 715 print(self.logger.log_line(
borlanic 0:fbdae7e6d805 716 self.logger.LogType.INFO,
borlanic 0:fbdae7e6d805 717 'Peripheral %s test skipped for target %s' %
borlanic 0:fbdae7e6d805 718 (",".join(test.peripherals), target)))
borlanic 0:fbdae7e6d805 719 else:
borlanic 0:fbdae7e6d805 720 print(self.logger.log_line(
borlanic 0:fbdae7e6d805 721 self.logger.LogType.INFO,
borlanic 0:fbdae7e6d805 722 'Test %s skipped for target %s' %
borlanic 0:fbdae7e6d805 723 (test_id, target)))
borlanic 0:fbdae7e6d805 724 continue
borlanic 0:fbdae7e6d805 725
borlanic 0:fbdae7e6d805 726 # The test has made it through all the filters, so add it to the valid tests list
borlanic 0:fbdae7e6d805 727 valid_test_map_keys.append(test_id)
borlanic 0:fbdae7e6d805 728
borlanic 0:fbdae7e6d805 729 return valid_test_map_keys
borlanic 0:fbdae7e6d805 730
borlanic 0:fbdae7e6d805 731 def get_skipped_tests(self, all_test_map_keys, valid_test_map_keys):
borlanic 0:fbdae7e6d805 732 # NOTE: This will not preserve order
borlanic 0:fbdae7e6d805 733 return list(set(all_test_map_keys) - set(valid_test_map_keys))
borlanic 0:fbdae7e6d805 734
borlanic 0:fbdae7e6d805 735 def generate_test_summary_by_target(self, test_summary, shuffle_seed=None):
borlanic 0:fbdae7e6d805 736 """ Prints well-formed summary with results (SQL table like)
borlanic 0:fbdae7e6d805 737 table shows text x toolchain test result matrix
borlanic 0:fbdae7e6d805 738 """
borlanic 0:fbdae7e6d805 739 RESULT_INDEX = 0
borlanic 0:fbdae7e6d805 740 TARGET_INDEX = 1
borlanic 0:fbdae7e6d805 741 TOOLCHAIN_INDEX = 2
borlanic 0:fbdae7e6d805 742 TEST_INDEX = 3
borlanic 0:fbdae7e6d805 743 DESC_INDEX = 4
borlanic 0:fbdae7e6d805 744
borlanic 0:fbdae7e6d805 745 unique_targets = get_unique_value_from_summary(test_summary, TARGET_INDEX)
borlanic 0:fbdae7e6d805 746 unique_tests = get_unique_value_from_summary(test_summary, TEST_INDEX)
borlanic 0:fbdae7e6d805 747 unique_test_desc = get_unique_value_from_summary_ext(test_summary, TEST_INDEX, DESC_INDEX)
borlanic 0:fbdae7e6d805 748 unique_toolchains = get_unique_value_from_summary(test_summary, TOOLCHAIN_INDEX)
borlanic 0:fbdae7e6d805 749
borlanic 0:fbdae7e6d805 750 result = "Test summary:\n"
borlanic 0:fbdae7e6d805 751 for target in unique_targets:
borlanic 0:fbdae7e6d805 752 result_dict = {} # test : { toolchain : result }
borlanic 0:fbdae7e6d805 753 unique_target_toolchains = []
borlanic 0:fbdae7e6d805 754 for test in test_summary:
borlanic 0:fbdae7e6d805 755 if test[TARGET_INDEX] == target:
borlanic 0:fbdae7e6d805 756 if test[TOOLCHAIN_INDEX] not in unique_target_toolchains:
borlanic 0:fbdae7e6d805 757 unique_target_toolchains.append(test[TOOLCHAIN_INDEX])
borlanic 0:fbdae7e6d805 758 if test[TEST_INDEX] not in result_dict:
borlanic 0:fbdae7e6d805 759 result_dict[test[TEST_INDEX]] = {}
borlanic 0:fbdae7e6d805 760 result_dict[test[TEST_INDEX]][test[TOOLCHAIN_INDEX]] = test[RESULT_INDEX]
borlanic 0:fbdae7e6d805 761
borlanic 0:fbdae7e6d805 762 pt_cols = ["Target", "Test ID", "Test Description"] + unique_target_toolchains
borlanic 0:fbdae7e6d805 763 pt = PrettyTable(pt_cols)
borlanic 0:fbdae7e6d805 764 for col in pt_cols:
borlanic 0:fbdae7e6d805 765 pt.align[col] = "l"
borlanic 0:fbdae7e6d805 766 pt.padding_width = 1 # One space between column edges and contents (default)
borlanic 0:fbdae7e6d805 767
borlanic 0:fbdae7e6d805 768 for test in unique_tests:
borlanic 0:fbdae7e6d805 769 if test in result_dict:
borlanic 0:fbdae7e6d805 770 test_results = result_dict[test]
borlanic 0:fbdae7e6d805 771 if test in unique_test_desc:
borlanic 0:fbdae7e6d805 772 row = [target, test, unique_test_desc[test]]
borlanic 0:fbdae7e6d805 773 for toolchain in unique_toolchains:
borlanic 0:fbdae7e6d805 774 if toolchain in test_results:
borlanic 0:fbdae7e6d805 775 row.append(test_results[toolchain])
borlanic 0:fbdae7e6d805 776 pt.add_row(row)
borlanic 0:fbdae7e6d805 777 result += pt.get_string()
borlanic 0:fbdae7e6d805 778 shuffle_seed_text = "Shuffle Seed: %.*f"% (self.SHUFFLE_SEED_ROUND,
borlanic 0:fbdae7e6d805 779 shuffle_seed if shuffle_seed else self.shuffle_random_seed)
borlanic 0:fbdae7e6d805 780 result += "\n%s"% (shuffle_seed_text if self.opts_shuffle_test_order else '')
borlanic 0:fbdae7e6d805 781 return result
borlanic 0:fbdae7e6d805 782
borlanic 0:fbdae7e6d805 783 def generate_test_summary(self, test_summary, shuffle_seed=None):
borlanic 0:fbdae7e6d805 784 """ Prints well-formed summary with results (SQL table like)
borlanic 0:fbdae7e6d805 785 table shows target x test results matrix across
borlanic 0:fbdae7e6d805 786 """
borlanic 0:fbdae7e6d805 787 success_code = 0 # Success code that can be leter returned to
borlanic 0:fbdae7e6d805 788 result = "Test summary:\n"
borlanic 0:fbdae7e6d805 789 # Pretty table package is used to print results
borlanic 0:fbdae7e6d805 790 pt = PrettyTable(["Result", "Target", "Toolchain", "Test ID", "Test Description",
borlanic 0:fbdae7e6d805 791 "Elapsed Time (sec)", "Timeout (sec)", "Loops"])
borlanic 0:fbdae7e6d805 792 pt.align["Result"] = "l" # Left align
borlanic 0:fbdae7e6d805 793 pt.align["Target"] = "l" # Left align
borlanic 0:fbdae7e6d805 794 pt.align["Toolchain"] = "l" # Left align
borlanic 0:fbdae7e6d805 795 pt.align["Test ID"] = "l" # Left align
borlanic 0:fbdae7e6d805 796 pt.align["Test Description"] = "l" # Left align
borlanic 0:fbdae7e6d805 797 pt.padding_width = 1 # One space between column edges and contents (default)
borlanic 0:fbdae7e6d805 798
borlanic 0:fbdae7e6d805 799 result_dict = {self.TEST_RESULT_OK : 0,
borlanic 0:fbdae7e6d805 800 self.TEST_RESULT_FAIL : 0,
borlanic 0:fbdae7e6d805 801 self.TEST_RESULT_ERROR : 0,
borlanic 0:fbdae7e6d805 802 self.TEST_RESULT_UNDEF : 0,
borlanic 0:fbdae7e6d805 803 self.TEST_RESULT_IOERR_COPY : 0,
borlanic 0:fbdae7e6d805 804 self.TEST_RESULT_IOERR_DISK : 0,
borlanic 0:fbdae7e6d805 805 self.TEST_RESULT_IOERR_SERIAL : 0,
borlanic 0:fbdae7e6d805 806 self.TEST_RESULT_NO_IMAGE : 0,
borlanic 0:fbdae7e6d805 807 self.TEST_RESULT_TIMEOUT : 0,
borlanic 0:fbdae7e6d805 808 self.TEST_RESULT_MBED_ASSERT : 0,
borlanic 0:fbdae7e6d805 809 self.TEST_RESULT_BUILD_FAILED : 0,
borlanic 0:fbdae7e6d805 810 self.TEST_RESULT_NOT_SUPPORTED : 0
borlanic 0:fbdae7e6d805 811 }
borlanic 0:fbdae7e6d805 812
borlanic 0:fbdae7e6d805 813 for test in test_summary:
borlanic 0:fbdae7e6d805 814 if test[0] in result_dict:
borlanic 0:fbdae7e6d805 815 result_dict[test[0]] += 1
borlanic 0:fbdae7e6d805 816 pt.add_row(test)
borlanic 0:fbdae7e6d805 817 result += pt.get_string()
borlanic 0:fbdae7e6d805 818 result += "\n"
borlanic 0:fbdae7e6d805 819
borlanic 0:fbdae7e6d805 820 # Print result count
borlanic 0:fbdae7e6d805 821 result += "Result: " + ' / '.join(['%s %s' % (value, key) for (key, value) in {k: v for k, v in result_dict.items() if v != 0}.items()])
borlanic 0:fbdae7e6d805 822 shuffle_seed_text = "Shuffle Seed: %.*f\n"% (self.SHUFFLE_SEED_ROUND,
borlanic 0:fbdae7e6d805 823 shuffle_seed if shuffle_seed else self.shuffle_random_seed)
borlanic 0:fbdae7e6d805 824 result += "\n%s"% (shuffle_seed_text if self.opts_shuffle_test_order else '')
borlanic 0:fbdae7e6d805 825 return result
borlanic 0:fbdae7e6d805 826
borlanic 0:fbdae7e6d805 827 def test_loop_list_to_dict(self, test_loops_str):
borlanic 0:fbdae7e6d805 828 """ Transforms test_id=X,test_id=X,test_id=X into dictionary {test_id : test_id_loops_count}
borlanic 0:fbdae7e6d805 829 """
borlanic 0:fbdae7e6d805 830 result = {}
borlanic 0:fbdae7e6d805 831 if test_loops_str:
borlanic 0:fbdae7e6d805 832 test_loops = test_loops_str
borlanic 0:fbdae7e6d805 833 for test_loop in test_loops:
borlanic 0:fbdae7e6d805 834 test_loop_count = test_loop.split('=')
borlanic 0:fbdae7e6d805 835 if len(test_loop_count) == 2:
borlanic 0:fbdae7e6d805 836 _test_id, _test_loops = test_loop_count
borlanic 0:fbdae7e6d805 837 try:
borlanic 0:fbdae7e6d805 838 _test_loops = int(_test_loops)
borlanic 0:fbdae7e6d805 839 except:
borlanic 0:fbdae7e6d805 840 continue
borlanic 0:fbdae7e6d805 841 result[_test_id] = _test_loops
borlanic 0:fbdae7e6d805 842 return result
borlanic 0:fbdae7e6d805 843
borlanic 0:fbdae7e6d805 844 def get_test_loop_count(self, test_id):
borlanic 0:fbdae7e6d805 845 """ This function returns no. of loops per test (deducted by test_id_.
borlanic 0:fbdae7e6d805 846 If test is not in list of redefined loop counts it will use default value.
borlanic 0:fbdae7e6d805 847 """
borlanic 0:fbdae7e6d805 848 result = self.GLOBAL_LOOPS_COUNT
borlanic 0:fbdae7e6d805 849 if test_id in self.TEST_LOOPS_DICT:
borlanic 0:fbdae7e6d805 850 result = self.TEST_LOOPS_DICT[test_id]
borlanic 0:fbdae7e6d805 851 return result
borlanic 0:fbdae7e6d805 852
borlanic 0:fbdae7e6d805 853 def delete_file(self, file_path):
borlanic 0:fbdae7e6d805 854 """ Remove file from the system
borlanic 0:fbdae7e6d805 855 """
borlanic 0:fbdae7e6d805 856 result = True
borlanic 0:fbdae7e6d805 857 resutl_msg = ""
borlanic 0:fbdae7e6d805 858 try:
borlanic 0:fbdae7e6d805 859 os.remove(file_path)
borlanic 0:fbdae7e6d805 860 except Exception as e:
borlanic 0:fbdae7e6d805 861 resutl_msg = e
borlanic 0:fbdae7e6d805 862 result = False
borlanic 0:fbdae7e6d805 863 return result, resutl_msg
borlanic 0:fbdae7e6d805 864
borlanic 0:fbdae7e6d805 865 def handle_mut(self, mut, data, target_name, toolchain_name, test_loops=1):
borlanic 0:fbdae7e6d805 866 """ Test is being invoked for given MUT.
borlanic 0:fbdae7e6d805 867 """
borlanic 0:fbdae7e6d805 868 # Get test information, image and test timeout
borlanic 0:fbdae7e6d805 869 test_id = data['test_id']
borlanic 0:fbdae7e6d805 870 test = TEST_MAP[test_id]
borlanic 0:fbdae7e6d805 871 test_description = TEST_MAP[test_id].get_description()
borlanic 0:fbdae7e6d805 872 image = data["image"]
borlanic 0:fbdae7e6d805 873 duration = data.get("duration", 10)
borlanic 0:fbdae7e6d805 874
borlanic 0:fbdae7e6d805 875 if mut is None:
borlanic 0:fbdae7e6d805 876 print("Error: No Mbed available: MUT[%s]" % data['mcu'])
borlanic 0:fbdae7e6d805 877 return None
borlanic 0:fbdae7e6d805 878
borlanic 0:fbdae7e6d805 879 mcu = mut['mcu']
borlanic 0:fbdae7e6d805 880 copy_method = mut.get('copy_method') # Available board configuration selection e.g. core selection etc.
borlanic 0:fbdae7e6d805 881
borlanic 0:fbdae7e6d805 882 if self.db_logger:
borlanic 0:fbdae7e6d805 883 self.db_logger.reconnect()
borlanic 0:fbdae7e6d805 884
borlanic 0:fbdae7e6d805 885 selected_copy_method = self.opts_copy_method if copy_method is None else copy_method
borlanic 0:fbdae7e6d805 886
borlanic 0:fbdae7e6d805 887 # Tests can be looped so test results must be stored for the same test
borlanic 0:fbdae7e6d805 888 test_all_result = []
borlanic 0:fbdae7e6d805 889 # Test results for one test ran few times
borlanic 0:fbdae7e6d805 890 detailed_test_results = {} # { Loop_number: { results ... } }
borlanic 0:fbdae7e6d805 891
borlanic 0:fbdae7e6d805 892 for test_index in range(test_loops):
borlanic 0:fbdae7e6d805 893
borlanic 0:fbdae7e6d805 894 # If mbedls is available and we are auto detecting MUT info,
borlanic 0:fbdae7e6d805 895 # update MUT info (mounting may changed)
borlanic 0:fbdae7e6d805 896 if get_module_avail('mbed_lstools') and self.opts_auto_detect:
borlanic 0:fbdae7e6d805 897 platform_name_filter = [mcu]
borlanic 0:fbdae7e6d805 898 muts_list = {}
borlanic 0:fbdae7e6d805 899 found = False
borlanic 0:fbdae7e6d805 900
borlanic 0:fbdae7e6d805 901 for i in range(0, 60):
borlanic 0:fbdae7e6d805 902 print('Looking for %s with MBEDLS' % mcu)
borlanic 0:fbdae7e6d805 903 muts_list = get_autodetected_MUTS_list(platform_name_filter=platform_name_filter)
borlanic 0:fbdae7e6d805 904
borlanic 0:fbdae7e6d805 905 if 1 not in muts_list:
borlanic 0:fbdae7e6d805 906 sleep(3)
borlanic 0:fbdae7e6d805 907 else:
borlanic 0:fbdae7e6d805 908 found = True
borlanic 0:fbdae7e6d805 909 break
borlanic 0:fbdae7e6d805 910
borlanic 0:fbdae7e6d805 911 if not found:
borlanic 0:fbdae7e6d805 912 print("Error: mbed not found with MBEDLS: %s" % data['mcu'])
borlanic 0:fbdae7e6d805 913 return None
borlanic 0:fbdae7e6d805 914 else:
borlanic 0:fbdae7e6d805 915 mut = muts_list[1]
borlanic 0:fbdae7e6d805 916
borlanic 0:fbdae7e6d805 917 disk = mut.get('disk')
borlanic 0:fbdae7e6d805 918 port = mut.get('port')
borlanic 0:fbdae7e6d805 919
borlanic 0:fbdae7e6d805 920 if disk is None or port is None:
borlanic 0:fbdae7e6d805 921 return None
borlanic 0:fbdae7e6d805 922
borlanic 0:fbdae7e6d805 923 target_by_mcu = TARGET_MAP[mut['mcu']]
borlanic 0:fbdae7e6d805 924 target_name_unique = mut['mcu_unique'] if 'mcu_unique' in mut else mut['mcu']
borlanic 0:fbdae7e6d805 925 # Some extra stuff can be declared in MUTs structure
borlanic 0:fbdae7e6d805 926 reset_type = mut.get('reset_type') # reboot.txt, reset.txt, shutdown.txt
borlanic 0:fbdae7e6d805 927 reset_tout = mut.get('reset_tout') # COPY_IMAGE -> RESET_PROC -> SLEEP(RESET_TOUT)
borlanic 0:fbdae7e6d805 928
borlanic 0:fbdae7e6d805 929 # When the build and test system were separate, this was relative to a
borlanic 0:fbdae7e6d805 930 # base network folder base path: join(NETWORK_BASE_PATH, )
borlanic 0:fbdae7e6d805 931 image_path = image
borlanic 0:fbdae7e6d805 932
borlanic 0:fbdae7e6d805 933 # Host test execution
borlanic 0:fbdae7e6d805 934 start_host_exec_time = time()
borlanic 0:fbdae7e6d805 935
borlanic 0:fbdae7e6d805 936 single_test_result = self.TEST_RESULT_UNDEF # single test run result
borlanic 0:fbdae7e6d805 937 _copy_method = selected_copy_method
borlanic 0:fbdae7e6d805 938
borlanic 0:fbdae7e6d805 939 if not exists(image_path):
borlanic 0:fbdae7e6d805 940 single_test_result = self.TEST_RESULT_NO_IMAGE
borlanic 0:fbdae7e6d805 941 elapsed_time = 0
borlanic 0:fbdae7e6d805 942 single_test_output = self.logger.log_line(self.logger.LogType.ERROR, 'Image file does not exist: %s'% image_path)
borlanic 0:fbdae7e6d805 943 print(single_test_output)
borlanic 0:fbdae7e6d805 944 else:
borlanic 0:fbdae7e6d805 945 # Host test execution
borlanic 0:fbdae7e6d805 946 start_host_exec_time = time()
borlanic 0:fbdae7e6d805 947
borlanic 0:fbdae7e6d805 948 host_test_verbose = self.opts_verbose_test_result_only or self.opts_verbose
borlanic 0:fbdae7e6d805 949 host_test_reset = self.opts_mut_reset_type if reset_type is None else reset_type
borlanic 0:fbdae7e6d805 950 host_test_result = self.run_host_test(test.host_test,
borlanic 0:fbdae7e6d805 951 image_path, disk, port, duration,
borlanic 0:fbdae7e6d805 952 micro=target_name,
borlanic 0:fbdae7e6d805 953 verbose=host_test_verbose,
borlanic 0:fbdae7e6d805 954 reset=host_test_reset,
borlanic 0:fbdae7e6d805 955 reset_tout=reset_tout,
borlanic 0:fbdae7e6d805 956 copy_method=selected_copy_method,
borlanic 0:fbdae7e6d805 957 program_cycle_s=target_by_mcu.program_cycle_s)
borlanic 0:fbdae7e6d805 958 single_test_result, single_test_output, single_testduration, single_timeout = host_test_result
borlanic 0:fbdae7e6d805 959
borlanic 0:fbdae7e6d805 960 # Store test result
borlanic 0:fbdae7e6d805 961 test_all_result.append(single_test_result)
borlanic 0:fbdae7e6d805 962 total_elapsed_time = time() - start_host_exec_time # Test time with copy (flashing) / reset
borlanic 0:fbdae7e6d805 963 elapsed_time = single_testduration # TIme of single test case execution after reset
borlanic 0:fbdae7e6d805 964
borlanic 0:fbdae7e6d805 965 detailed_test_results[test_index] = {
borlanic 0:fbdae7e6d805 966 'result' : single_test_result,
borlanic 0:fbdae7e6d805 967 'output' : single_test_output,
borlanic 0:fbdae7e6d805 968 'target_name' : target_name,
borlanic 0:fbdae7e6d805 969 'target_name_unique' : target_name_unique,
borlanic 0:fbdae7e6d805 970 'toolchain_name' : toolchain_name,
borlanic 0:fbdae7e6d805 971 'id' : test_id,
borlanic 0:fbdae7e6d805 972 'description' : test_description,
borlanic 0:fbdae7e6d805 973 'elapsed_time' : round(elapsed_time, 2),
borlanic 0:fbdae7e6d805 974 'duration' : single_timeout,
borlanic 0:fbdae7e6d805 975 'copy_method' : _copy_method,
borlanic 0:fbdae7e6d805 976 }
borlanic 0:fbdae7e6d805 977
borlanic 0:fbdae7e6d805 978 print(self.print_test_result(
borlanic 0:fbdae7e6d805 979 single_test_result, target_name_unique, toolchain_name, test_id,
borlanic 0:fbdae7e6d805 980 test_description, elapsed_time, single_timeout))
borlanic 0:fbdae7e6d805 981
borlanic 0:fbdae7e6d805 982 # Update database entries for ongoing test
borlanic 0:fbdae7e6d805 983 if self.db_logger and self.db_logger.is_connected():
borlanic 0:fbdae7e6d805 984 test_type = 'SingleTest'
borlanic 0:fbdae7e6d805 985 self.db_logger.insert_test_entry(self.db_logger_build_id,
borlanic 0:fbdae7e6d805 986 target_name,
borlanic 0:fbdae7e6d805 987 toolchain_name,
borlanic 0:fbdae7e6d805 988 test_type,
borlanic 0:fbdae7e6d805 989 test_id,
borlanic 0:fbdae7e6d805 990 single_test_result,
borlanic 0:fbdae7e6d805 991 single_test_output,
borlanic 0:fbdae7e6d805 992 elapsed_time,
borlanic 0:fbdae7e6d805 993 single_timeout,
borlanic 0:fbdae7e6d805 994 test_index)
borlanic 0:fbdae7e6d805 995
borlanic 0:fbdae7e6d805 996 # If we perform waterfall test we test until we get OK and we stop testing
borlanic 0:fbdae7e6d805 997 if self.opts_waterfall_test and single_test_result == self.TEST_RESULT_OK:
borlanic 0:fbdae7e6d805 998 break
borlanic 0:fbdae7e6d805 999
borlanic 0:fbdae7e6d805 1000 if self.db_logger:
borlanic 0:fbdae7e6d805 1001 self.db_logger.disconnect()
borlanic 0:fbdae7e6d805 1002
borlanic 0:fbdae7e6d805 1003 return (self.shape_global_test_loop_result(test_all_result, self.opts_waterfall_test and self.opts_consolidate_waterfall_test),
borlanic 0:fbdae7e6d805 1004 target_name_unique,
borlanic 0:fbdae7e6d805 1005 toolchain_name,
borlanic 0:fbdae7e6d805 1006 test_id,
borlanic 0:fbdae7e6d805 1007 test_description,
borlanic 0:fbdae7e6d805 1008 round(elapsed_time, 2),
borlanic 0:fbdae7e6d805 1009 single_timeout,
borlanic 0:fbdae7e6d805 1010 self.shape_test_loop_ok_result_count(test_all_result)), detailed_test_results
borlanic 0:fbdae7e6d805 1011
borlanic 0:fbdae7e6d805 1012 def handle(self, test_spec, target_name, toolchain_name, test_loops=1):
borlanic 0:fbdae7e6d805 1013 """ Function determines MUT's mbed disk/port and copies binary to
borlanic 0:fbdae7e6d805 1014 target.
borlanic 0:fbdae7e6d805 1015 """
borlanic 0:fbdae7e6d805 1016 handle_results = []
borlanic 0:fbdae7e6d805 1017 data = json.loads(test_spec)
borlanic 0:fbdae7e6d805 1018
borlanic 0:fbdae7e6d805 1019 # Find a suitable MUT:
borlanic 0:fbdae7e6d805 1020 mut = None
borlanic 0:fbdae7e6d805 1021 for id, m in self.muts.items():
borlanic 0:fbdae7e6d805 1022 if m['mcu'] == data['mcu']:
borlanic 0:fbdae7e6d805 1023 mut = m
borlanic 0:fbdae7e6d805 1024 handle_result = self.handle_mut(mut, data, target_name, toolchain_name, test_loops=test_loops)
borlanic 0:fbdae7e6d805 1025 handle_results.append(handle_result)
borlanic 0:fbdae7e6d805 1026
borlanic 0:fbdae7e6d805 1027 return handle_results
borlanic 0:fbdae7e6d805 1028
borlanic 0:fbdae7e6d805 1029 def print_test_result(self, test_result, target_name, toolchain_name,
borlanic 0:fbdae7e6d805 1030 test_id, test_description, elapsed_time, duration):
borlanic 0:fbdae7e6d805 1031 """ Use specific convention to print test result and related data
borlanic 0:fbdae7e6d805 1032 """
borlanic 0:fbdae7e6d805 1033 tokens = []
borlanic 0:fbdae7e6d805 1034 tokens.append("TargetTest")
borlanic 0:fbdae7e6d805 1035 tokens.append(target_name)
borlanic 0:fbdae7e6d805 1036 tokens.append(toolchain_name)
borlanic 0:fbdae7e6d805 1037 tokens.append(test_id)
borlanic 0:fbdae7e6d805 1038 tokens.append(test_description)
borlanic 0:fbdae7e6d805 1039 separator = "::"
borlanic 0:fbdae7e6d805 1040 time_info = " in %.2f of %d sec" % (round(elapsed_time, 2), duration)
borlanic 0:fbdae7e6d805 1041 result = separator.join(tokens) + " [" + test_result +"]" + time_info
borlanic 0:fbdae7e6d805 1042 return Fore.MAGENTA + result + Fore.RESET
borlanic 0:fbdae7e6d805 1043
borlanic 0:fbdae7e6d805 1044 def shape_test_loop_ok_result_count(self, test_all_result):
borlanic 0:fbdae7e6d805 1045 """ Reformats list of results to simple string
borlanic 0:fbdae7e6d805 1046 """
borlanic 0:fbdae7e6d805 1047 test_loop_count = len(test_all_result)
borlanic 0:fbdae7e6d805 1048 test_loop_ok_result = test_all_result.count(self.TEST_RESULT_OK)
borlanic 0:fbdae7e6d805 1049 return "%d/%d"% (test_loop_ok_result, test_loop_count)
borlanic 0:fbdae7e6d805 1050
borlanic 0:fbdae7e6d805 1051 def shape_global_test_loop_result(self, test_all_result, waterfall_and_consolidate):
borlanic 0:fbdae7e6d805 1052 """ Reformats list of results to simple string
borlanic 0:fbdae7e6d805 1053 """
borlanic 0:fbdae7e6d805 1054 result = self.TEST_RESULT_FAIL
borlanic 0:fbdae7e6d805 1055
borlanic 0:fbdae7e6d805 1056 if all(test_all_result[0] == res for res in test_all_result):
borlanic 0:fbdae7e6d805 1057 result = test_all_result[0]
borlanic 0:fbdae7e6d805 1058 elif waterfall_and_consolidate and any(res == self.TEST_RESULT_OK for res in test_all_result):
borlanic 0:fbdae7e6d805 1059 result = self.TEST_RESULT_OK
borlanic 0:fbdae7e6d805 1060
borlanic 0:fbdae7e6d805 1061 return result
borlanic 0:fbdae7e6d805 1062
borlanic 0:fbdae7e6d805 1063 def run_host_test(self, name, image_path, disk, port, duration,
borlanic 0:fbdae7e6d805 1064 micro=None, reset=None, reset_tout=None,
borlanic 0:fbdae7e6d805 1065 verbose=False, copy_method=None, program_cycle_s=None):
borlanic 0:fbdae7e6d805 1066 """ Function creates new process with host test configured with particular test case.
borlanic 0:fbdae7e6d805 1067 Function also is pooling for serial port activity from process to catch all data
borlanic 0:fbdae7e6d805 1068 printed by test runner and host test during test execution
borlanic 0:fbdae7e6d805 1069 """
borlanic 0:fbdae7e6d805 1070
borlanic 0:fbdae7e6d805 1071 def get_char_from_queue(obs):
borlanic 0:fbdae7e6d805 1072 """ Get character from queue safe way
borlanic 0:fbdae7e6d805 1073 """
borlanic 0:fbdae7e6d805 1074 try:
borlanic 0:fbdae7e6d805 1075 c = obs.queue.get(block=True, timeout=0.5)
borlanic 0:fbdae7e6d805 1076 except Empty:
borlanic 0:fbdae7e6d805 1077 c = None
borlanic 0:fbdae7e6d805 1078 return c
borlanic 0:fbdae7e6d805 1079
borlanic 0:fbdae7e6d805 1080 def filter_queue_char(c):
borlanic 0:fbdae7e6d805 1081 """ Filters out non ASCII characters from serial port
borlanic 0:fbdae7e6d805 1082 """
borlanic 0:fbdae7e6d805 1083 if ord(c) not in range(128):
borlanic 0:fbdae7e6d805 1084 c = ' '
borlanic 0:fbdae7e6d805 1085 return c
borlanic 0:fbdae7e6d805 1086
borlanic 0:fbdae7e6d805 1087 def get_test_result(output):
borlanic 0:fbdae7e6d805 1088 """ Parse test 'output' data
borlanic 0:fbdae7e6d805 1089 """
borlanic 0:fbdae7e6d805 1090 result = self.TEST_RESULT_TIMEOUT
borlanic 0:fbdae7e6d805 1091 for line in "".join(output).splitlines():
borlanic 0:fbdae7e6d805 1092 search_result = self.RE_DETECT_TESTCASE_RESULT.search(line)
borlanic 0:fbdae7e6d805 1093 if search_result and len(search_result.groups()):
borlanic 0:fbdae7e6d805 1094 result = self.TEST_RESULT_MAPPING[search_result.groups(0)[0]]
borlanic 0:fbdae7e6d805 1095 break
borlanic 0:fbdae7e6d805 1096 return result
borlanic 0:fbdae7e6d805 1097
borlanic 0:fbdae7e6d805 1098 def get_auto_property_value(property_name, line):
borlanic 0:fbdae7e6d805 1099 """ Scans auto detection line from MUT and returns scanned parameter 'property_name'
borlanic 0:fbdae7e6d805 1100 Returns string
borlanic 0:fbdae7e6d805 1101 """
borlanic 0:fbdae7e6d805 1102 result = None
borlanic 0:fbdae7e6d805 1103 if re.search("HOST: Property '%s'"% property_name, line) is not None:
borlanic 0:fbdae7e6d805 1104 property = re.search("HOST: Property '%s' = '([\w\d _]+)'"% property_name, line)
borlanic 0:fbdae7e6d805 1105 if property is not None and len(property.groups()) == 1:
borlanic 0:fbdae7e6d805 1106 result = property.groups()[0]
borlanic 0:fbdae7e6d805 1107 return result
borlanic 0:fbdae7e6d805 1108
borlanic 0:fbdae7e6d805 1109 cmd = ["python",
borlanic 0:fbdae7e6d805 1110 '%s.py'% name,
borlanic 0:fbdae7e6d805 1111 '-d', disk,
borlanic 0:fbdae7e6d805 1112 '-f', '"%s"'% image_path,
borlanic 0:fbdae7e6d805 1113 '-p', port,
borlanic 0:fbdae7e6d805 1114 '-t', str(duration),
borlanic 0:fbdae7e6d805 1115 '-C', str(program_cycle_s)]
borlanic 0:fbdae7e6d805 1116
borlanic 0:fbdae7e6d805 1117 if get_module_avail('mbed_lstools') and self.opts_auto_detect:
borlanic 0:fbdae7e6d805 1118 cmd += ['--auto']
borlanic 0:fbdae7e6d805 1119
borlanic 0:fbdae7e6d805 1120 # Add extra parameters to host_test
borlanic 0:fbdae7e6d805 1121 if copy_method is not None:
borlanic 0:fbdae7e6d805 1122 cmd += ["-c", copy_method]
borlanic 0:fbdae7e6d805 1123 if micro is not None:
borlanic 0:fbdae7e6d805 1124 cmd += ["-m", micro]
borlanic 0:fbdae7e6d805 1125 if reset is not None:
borlanic 0:fbdae7e6d805 1126 cmd += ["-r", reset]
borlanic 0:fbdae7e6d805 1127 if reset_tout is not None:
borlanic 0:fbdae7e6d805 1128 cmd += ["-R", str(reset_tout)]
borlanic 0:fbdae7e6d805 1129
borlanic 0:fbdae7e6d805 1130 if verbose:
borlanic 0:fbdae7e6d805 1131 print(Fore.MAGENTA + "Executing '" + " ".join(cmd) + "'" + Fore.RESET)
borlanic 0:fbdae7e6d805 1132 print("Test::Output::Start")
borlanic 0:fbdae7e6d805 1133
borlanic 0:fbdae7e6d805 1134 proc = Popen(cmd, stdout=PIPE, cwd=HOST_TESTS)
borlanic 0:fbdae7e6d805 1135 obs = ProcessObserver(proc)
borlanic 0:fbdae7e6d805 1136 update_once_flag = {} # Stores flags checking if some auto-parameter was already set
borlanic 0:fbdae7e6d805 1137 line = ''
borlanic 0:fbdae7e6d805 1138 output = []
borlanic 0:fbdae7e6d805 1139 start_time = time()
borlanic 0:fbdae7e6d805 1140 while (time() - start_time) < (2 * duration):
borlanic 0:fbdae7e6d805 1141 c = get_char_from_queue(obs)
borlanic 0:fbdae7e6d805 1142 if c:
borlanic 0:fbdae7e6d805 1143 if verbose:
borlanic 0:fbdae7e6d805 1144 sys.stdout.write(c)
borlanic 0:fbdae7e6d805 1145 c = filter_queue_char(c)
borlanic 0:fbdae7e6d805 1146 output.append(c)
borlanic 0:fbdae7e6d805 1147 # Give the mbed under test a way to communicate the end of the test
borlanic 0:fbdae7e6d805 1148 if c in ['\n', '\r']:
borlanic 0:fbdae7e6d805 1149
borlanic 0:fbdae7e6d805 1150 # Checking for auto-detection information from the test about MUT reset moment
borlanic 0:fbdae7e6d805 1151 if 'reset_target' not in update_once_flag and "HOST: Reset target..." in line:
borlanic 0:fbdae7e6d805 1152 # We will update this marker only once to prevent multiple time resets
borlanic 0:fbdae7e6d805 1153 update_once_flag['reset_target'] = True
borlanic 0:fbdae7e6d805 1154 start_time = time()
borlanic 0:fbdae7e6d805 1155
borlanic 0:fbdae7e6d805 1156 # Checking for auto-detection information from the test about timeout
borlanic 0:fbdae7e6d805 1157 auto_timeout_val = get_auto_property_value('timeout', line)
borlanic 0:fbdae7e6d805 1158 if 'timeout' not in update_once_flag and auto_timeout_val is not None:
borlanic 0:fbdae7e6d805 1159 # We will update this marker only once to prevent multiple time resets
borlanic 0:fbdae7e6d805 1160 update_once_flag['timeout'] = True
borlanic 0:fbdae7e6d805 1161 duration = int(auto_timeout_val)
borlanic 0:fbdae7e6d805 1162
borlanic 0:fbdae7e6d805 1163 # Detect mbed assert:
borlanic 0:fbdae7e6d805 1164 if 'mbed assertation failed: ' in line:
borlanic 0:fbdae7e6d805 1165 output.append('{{mbed_assert}}')
borlanic 0:fbdae7e6d805 1166 break
borlanic 0:fbdae7e6d805 1167
borlanic 0:fbdae7e6d805 1168 # Check for test end
borlanic 0:fbdae7e6d805 1169 if '{end}' in line:
borlanic 0:fbdae7e6d805 1170 break
borlanic 0:fbdae7e6d805 1171 line = ''
borlanic 0:fbdae7e6d805 1172 else:
borlanic 0:fbdae7e6d805 1173 line += c
borlanic 0:fbdae7e6d805 1174 end_time = time()
borlanic 0:fbdae7e6d805 1175 testcase_duration = end_time - start_time # Test case duration from reset to {end}
borlanic 0:fbdae7e6d805 1176
borlanic 0:fbdae7e6d805 1177 c = get_char_from_queue(obs)
borlanic 0:fbdae7e6d805 1178
borlanic 0:fbdae7e6d805 1179 if c:
borlanic 0:fbdae7e6d805 1180 if verbose:
borlanic 0:fbdae7e6d805 1181 sys.stdout.write(c)
borlanic 0:fbdae7e6d805 1182 c = filter_queue_char(c)
borlanic 0:fbdae7e6d805 1183 output.append(c)
borlanic 0:fbdae7e6d805 1184
borlanic 0:fbdae7e6d805 1185 if verbose:
borlanic 0:fbdae7e6d805 1186 print("Test::Output::Finish")
borlanic 0:fbdae7e6d805 1187 # Stop test process
borlanic 0:fbdae7e6d805 1188 obs.stop()
borlanic 0:fbdae7e6d805 1189
borlanic 0:fbdae7e6d805 1190 result = get_test_result(output)
borlanic 0:fbdae7e6d805 1191 return (result, "".join(output), testcase_duration, duration)
borlanic 0:fbdae7e6d805 1192
borlanic 0:fbdae7e6d805 1193 def is_peripherals_available(self, target_mcu_name, peripherals=None):
borlanic 0:fbdae7e6d805 1194 """ Checks if specified target should run specific peripheral test case defined in MUTs file
borlanic 0:fbdae7e6d805 1195 """
borlanic 0:fbdae7e6d805 1196 if peripherals is not None:
borlanic 0:fbdae7e6d805 1197 peripherals = set(peripherals)
borlanic 0:fbdae7e6d805 1198 for id, mut in self.muts.items():
borlanic 0:fbdae7e6d805 1199 # Target MCU name check
borlanic 0:fbdae7e6d805 1200 if mut["mcu"] != target_mcu_name:
borlanic 0:fbdae7e6d805 1201 continue
borlanic 0:fbdae7e6d805 1202 # Peripherals check
borlanic 0:fbdae7e6d805 1203 if peripherals is not None:
borlanic 0:fbdae7e6d805 1204 if 'peripherals' not in mut:
borlanic 0:fbdae7e6d805 1205 continue
borlanic 0:fbdae7e6d805 1206 if not peripherals.issubset(set(mut['peripherals'])):
borlanic 0:fbdae7e6d805 1207 continue
borlanic 0:fbdae7e6d805 1208 return True
borlanic 0:fbdae7e6d805 1209 return False
borlanic 0:fbdae7e6d805 1210
borlanic 0:fbdae7e6d805 1211 def shape_test_request(self, mcu, image_path, test_id, duration=10):
borlanic 0:fbdae7e6d805 1212 """ Function prepares JSON structure describing test specification
borlanic 0:fbdae7e6d805 1213 """
borlanic 0:fbdae7e6d805 1214 test_spec = {
borlanic 0:fbdae7e6d805 1215 "mcu": mcu,
borlanic 0:fbdae7e6d805 1216 "image": image_path,
borlanic 0:fbdae7e6d805 1217 "duration": duration,
borlanic 0:fbdae7e6d805 1218 "test_id": test_id,
borlanic 0:fbdae7e6d805 1219 }
borlanic 0:fbdae7e6d805 1220 return json.dumps(test_spec)
borlanic 0:fbdae7e6d805 1221
borlanic 0:fbdae7e6d805 1222
borlanic 0:fbdae7e6d805 1223 def get_unique_value_from_summary(test_summary, index):
borlanic 0:fbdae7e6d805 1224 """ Gets list of unique target names
borlanic 0:fbdae7e6d805 1225 """
borlanic 0:fbdae7e6d805 1226 result = []
borlanic 0:fbdae7e6d805 1227 for test in test_summary:
borlanic 0:fbdae7e6d805 1228 target_name = test[index]
borlanic 0:fbdae7e6d805 1229 if target_name not in result:
borlanic 0:fbdae7e6d805 1230 result.append(target_name)
borlanic 0:fbdae7e6d805 1231 return sorted(result)
borlanic 0:fbdae7e6d805 1232
borlanic 0:fbdae7e6d805 1233
borlanic 0:fbdae7e6d805 1234 def get_unique_value_from_summary_ext(test_summary, index_key, index_val):
borlanic 0:fbdae7e6d805 1235 """ Gets list of unique target names and return dictionary
borlanic 0:fbdae7e6d805 1236 """
borlanic 0:fbdae7e6d805 1237 result = {}
borlanic 0:fbdae7e6d805 1238 for test in test_summary:
borlanic 0:fbdae7e6d805 1239 key = test[index_key]
borlanic 0:fbdae7e6d805 1240 val = test[index_val]
borlanic 0:fbdae7e6d805 1241 if key not in result:
borlanic 0:fbdae7e6d805 1242 result[key] = val
borlanic 0:fbdae7e6d805 1243 return result
borlanic 0:fbdae7e6d805 1244
borlanic 0:fbdae7e6d805 1245
borlanic 0:fbdae7e6d805 1246 def show_json_file_format_error(json_spec_filename, line, column):
borlanic 0:fbdae7e6d805 1247 """ Prints JSON broken content
borlanic 0:fbdae7e6d805 1248 """
borlanic 0:fbdae7e6d805 1249 with open(json_spec_filename) as data_file:
borlanic 0:fbdae7e6d805 1250 line_no = 1
borlanic 0:fbdae7e6d805 1251 for json_line in data_file:
borlanic 0:fbdae7e6d805 1252 if line_no + 5 >= line: # Print last few lines before error
borlanic 0:fbdae7e6d805 1253 print('Line %d:\t'%line_no + json_line)
borlanic 0:fbdae7e6d805 1254 if line_no == line:
borlanic 0:fbdae7e6d805 1255 print('%s\t%s^' (' ' * len('Line %d:' % line_no),
borlanic 0:fbdae7e6d805 1256 '-' * (column - 1)))
borlanic 0:fbdae7e6d805 1257 break
borlanic 0:fbdae7e6d805 1258 line_no += 1
borlanic 0:fbdae7e6d805 1259
borlanic 0:fbdae7e6d805 1260
borlanic 0:fbdae7e6d805 1261 def json_format_error_defect_pos(json_error_msg):
borlanic 0:fbdae7e6d805 1262 """ Gets first error line and column in JSON file format.
borlanic 0:fbdae7e6d805 1263 Parsed from exception thrown by json.loads() string
borlanic 0:fbdae7e6d805 1264 """
borlanic 0:fbdae7e6d805 1265 result = None
borlanic 0:fbdae7e6d805 1266 line, column = 0, 0
borlanic 0:fbdae7e6d805 1267 # Line value search
borlanic 0:fbdae7e6d805 1268 line_search = re.search('line [0-9]+', json_error_msg)
borlanic 0:fbdae7e6d805 1269 if line_search is not None:
borlanic 0:fbdae7e6d805 1270 ls = line_search.group().split(' ')
borlanic 0:fbdae7e6d805 1271 if len(ls) == 2:
borlanic 0:fbdae7e6d805 1272 line = int(ls[1])
borlanic 0:fbdae7e6d805 1273 # Column position search
borlanic 0:fbdae7e6d805 1274 column_search = re.search('column [0-9]+', json_error_msg)
borlanic 0:fbdae7e6d805 1275 if column_search is not None:
borlanic 0:fbdae7e6d805 1276 cs = column_search.group().split(' ')
borlanic 0:fbdae7e6d805 1277 if len(cs) == 2:
borlanic 0:fbdae7e6d805 1278 column = int(cs[1])
borlanic 0:fbdae7e6d805 1279 result = [line, column]
borlanic 0:fbdae7e6d805 1280 return result
borlanic 0:fbdae7e6d805 1281
borlanic 0:fbdae7e6d805 1282
borlanic 0:fbdae7e6d805 1283 def get_json_data_from_file(json_spec_filename, verbose=False):
borlanic 0:fbdae7e6d805 1284 """ Loads from file JSON formatted string to data structure
borlanic 0:fbdae7e6d805 1285 """
borlanic 0:fbdae7e6d805 1286 result = None
borlanic 0:fbdae7e6d805 1287 try:
borlanic 0:fbdae7e6d805 1288 with open(json_spec_filename) as data_file:
borlanic 0:fbdae7e6d805 1289 try:
borlanic 0:fbdae7e6d805 1290 result = json.load(data_file)
borlanic 0:fbdae7e6d805 1291 except ValueError as json_error_msg:
borlanic 0:fbdae7e6d805 1292 result = None
borlanic 0:fbdae7e6d805 1293 print('JSON file %s parsing failed. Reason: %s' %
borlanic 0:fbdae7e6d805 1294 (json_spec_filename, json_error_msg))
borlanic 0:fbdae7e6d805 1295 # We can print where error occurred inside JSON file if we can parse exception msg
borlanic 0:fbdae7e6d805 1296 json_format_defect_pos = json_format_error_defect_pos(str(json_error_msg))
borlanic 0:fbdae7e6d805 1297 if json_format_defect_pos is not None:
borlanic 0:fbdae7e6d805 1298 line = json_format_defect_pos[0]
borlanic 0:fbdae7e6d805 1299 column = json_format_defect_pos[1]
borlanic 0:fbdae7e6d805 1300 print()
borlanic 0:fbdae7e6d805 1301 show_json_file_format_error(json_spec_filename, line, column)
borlanic 0:fbdae7e6d805 1302
borlanic 0:fbdae7e6d805 1303 except IOError as fileopen_error_msg:
borlanic 0:fbdae7e6d805 1304 print('JSON file %s not opened. Reason: %s\n'%
borlanic 0:fbdae7e6d805 1305 (json_spec_filename, fileopen_error_msg))
borlanic 0:fbdae7e6d805 1306 if verbose and result:
borlanic 0:fbdae7e6d805 1307 pp = pprint.PrettyPrinter(indent=4)
borlanic 0:fbdae7e6d805 1308 pp.pprint(result)
borlanic 0:fbdae7e6d805 1309 return result
borlanic 0:fbdae7e6d805 1310
borlanic 0:fbdae7e6d805 1311
borlanic 0:fbdae7e6d805 1312 def print_muts_configuration_from_json(json_data, join_delim=", ", platform_filter=None):
borlanic 0:fbdae7e6d805 1313 """ Prints MUTs configuration passed to test script for verboseness
borlanic 0:fbdae7e6d805 1314 """
borlanic 0:fbdae7e6d805 1315 muts_info_cols = []
borlanic 0:fbdae7e6d805 1316 # We need to check all unique properties for each defined MUT
borlanic 0:fbdae7e6d805 1317 for k in json_data:
borlanic 0:fbdae7e6d805 1318 mut_info = json_data[k]
borlanic 0:fbdae7e6d805 1319 for mut_property in mut_info:
borlanic 0:fbdae7e6d805 1320 if mut_property not in muts_info_cols:
borlanic 0:fbdae7e6d805 1321 muts_info_cols.append(mut_property)
borlanic 0:fbdae7e6d805 1322
borlanic 0:fbdae7e6d805 1323 # Prepare pretty table object to display all MUTs
borlanic 0:fbdae7e6d805 1324 pt_cols = ["index"] + muts_info_cols
borlanic 0:fbdae7e6d805 1325 pt = PrettyTable(pt_cols)
borlanic 0:fbdae7e6d805 1326 for col in pt_cols:
borlanic 0:fbdae7e6d805 1327 pt.align[col] = "l"
borlanic 0:fbdae7e6d805 1328
borlanic 0:fbdae7e6d805 1329 # Add rows to pretty print object
borlanic 0:fbdae7e6d805 1330 for k in json_data:
borlanic 0:fbdae7e6d805 1331 row = [k]
borlanic 0:fbdae7e6d805 1332 mut_info = json_data[k]
borlanic 0:fbdae7e6d805 1333
borlanic 0:fbdae7e6d805 1334 add_row = True
borlanic 0:fbdae7e6d805 1335 if platform_filter and 'mcu' in mut_info:
borlanic 0:fbdae7e6d805 1336 add_row = re.search(platform_filter, mut_info['mcu']) is not None
borlanic 0:fbdae7e6d805 1337 if add_row:
borlanic 0:fbdae7e6d805 1338 for col in muts_info_cols:
borlanic 0:fbdae7e6d805 1339 cell_val = mut_info[col] if col in mut_info else None
borlanic 0:fbdae7e6d805 1340 if isinstance(cell_val, list):
borlanic 0:fbdae7e6d805 1341 cell_val = join_delim.join(cell_val)
borlanic 0:fbdae7e6d805 1342 row.append(cell_val)
borlanic 0:fbdae7e6d805 1343 pt.add_row(row)
borlanic 0:fbdae7e6d805 1344 return pt.get_string()
borlanic 0:fbdae7e6d805 1345
borlanic 0:fbdae7e6d805 1346
borlanic 0:fbdae7e6d805 1347 def print_test_configuration_from_json(json_data, join_delim=", "):
borlanic 0:fbdae7e6d805 1348 """ Prints test specification configuration passed to test script for verboseness
borlanic 0:fbdae7e6d805 1349 """
borlanic 0:fbdae7e6d805 1350 toolchains_info_cols = []
borlanic 0:fbdae7e6d805 1351 # We need to check all toolchains for each device
borlanic 0:fbdae7e6d805 1352 for k in json_data:
borlanic 0:fbdae7e6d805 1353 # k should be 'targets'
borlanic 0:fbdae7e6d805 1354 targets = json_data[k]
borlanic 0:fbdae7e6d805 1355 for target in targets:
borlanic 0:fbdae7e6d805 1356 toolchains = targets[target]
borlanic 0:fbdae7e6d805 1357 for toolchain in toolchains:
borlanic 0:fbdae7e6d805 1358 if toolchain not in toolchains_info_cols:
borlanic 0:fbdae7e6d805 1359 toolchains_info_cols.append(toolchain)
borlanic 0:fbdae7e6d805 1360
borlanic 0:fbdae7e6d805 1361 # Prepare pretty table object to display test specification
borlanic 0:fbdae7e6d805 1362 pt_cols = ["mcu"] + sorted(toolchains_info_cols)
borlanic 0:fbdae7e6d805 1363 pt = PrettyTable(pt_cols)
borlanic 0:fbdae7e6d805 1364 for col in pt_cols:
borlanic 0:fbdae7e6d805 1365 pt.align[col] = "l"
borlanic 0:fbdae7e6d805 1366
borlanic 0:fbdae7e6d805 1367 # { target : [conflicted toolchains] }
borlanic 0:fbdae7e6d805 1368 toolchain_conflicts = {}
borlanic 0:fbdae7e6d805 1369 toolchain_path_conflicts = []
borlanic 0:fbdae7e6d805 1370 for k in json_data:
borlanic 0:fbdae7e6d805 1371 # k should be 'targets'
borlanic 0:fbdae7e6d805 1372 targets = json_data[k]
borlanic 0:fbdae7e6d805 1373 for target in targets:
borlanic 0:fbdae7e6d805 1374 target_supported_toolchains = get_target_supported_toolchains(target)
borlanic 0:fbdae7e6d805 1375 if not target_supported_toolchains:
borlanic 0:fbdae7e6d805 1376 target_supported_toolchains = []
borlanic 0:fbdae7e6d805 1377 target_name = target if target in TARGET_MAP else "%s*"% target
borlanic 0:fbdae7e6d805 1378 row = [target_name]
borlanic 0:fbdae7e6d805 1379 toolchains = targets[target]
borlanic 0:fbdae7e6d805 1380
borlanic 0:fbdae7e6d805 1381 for toolchain in sorted(toolchains_info_cols):
borlanic 0:fbdae7e6d805 1382 # Check for conflicts: target vs toolchain
borlanic 0:fbdae7e6d805 1383 conflict = False
borlanic 0:fbdae7e6d805 1384 conflict_path = False
borlanic 0:fbdae7e6d805 1385 if toolchain in toolchains:
borlanic 0:fbdae7e6d805 1386 if toolchain not in target_supported_toolchains:
borlanic 0:fbdae7e6d805 1387 conflict = True
borlanic 0:fbdae7e6d805 1388 if target not in toolchain_conflicts:
borlanic 0:fbdae7e6d805 1389 toolchain_conflicts[target] = []
borlanic 0:fbdae7e6d805 1390 toolchain_conflicts[target].append(toolchain)
borlanic 0:fbdae7e6d805 1391 # Add marker inside table about target usage / conflict
borlanic 0:fbdae7e6d805 1392 cell_val = 'Yes' if toolchain in toolchains else '-'
borlanic 0:fbdae7e6d805 1393 if conflict:
borlanic 0:fbdae7e6d805 1394 cell_val += '*'
borlanic 0:fbdae7e6d805 1395 # Check for conflicts: toolchain vs toolchain path
borlanic 0:fbdae7e6d805 1396 if toolchain in TOOLCHAIN_PATHS:
borlanic 0:fbdae7e6d805 1397 toolchain_path = TOOLCHAIN_PATHS[toolchain]
borlanic 0:fbdae7e6d805 1398 if not os.path.isdir(toolchain_path):
borlanic 0:fbdae7e6d805 1399 conflict_path = True
borlanic 0:fbdae7e6d805 1400 if toolchain not in toolchain_path_conflicts:
borlanic 0:fbdae7e6d805 1401 toolchain_path_conflicts.append(toolchain)
borlanic 0:fbdae7e6d805 1402 if conflict_path:
borlanic 0:fbdae7e6d805 1403 cell_val += '#'
borlanic 0:fbdae7e6d805 1404 row.append(cell_val)
borlanic 0:fbdae7e6d805 1405 pt.add_row(row)
borlanic 0:fbdae7e6d805 1406
borlanic 0:fbdae7e6d805 1407 # generate result string
borlanic 0:fbdae7e6d805 1408 result = pt.get_string() # Test specification table
borlanic 0:fbdae7e6d805 1409 if toolchain_conflicts or toolchain_path_conflicts:
borlanic 0:fbdae7e6d805 1410 result += "\n"
borlanic 0:fbdae7e6d805 1411 result += "Toolchain conflicts:\n"
borlanic 0:fbdae7e6d805 1412 for target in toolchain_conflicts:
borlanic 0:fbdae7e6d805 1413 if target not in TARGET_MAP:
borlanic 0:fbdae7e6d805 1414 result += "\t* Target %s unknown\n"% (target)
borlanic 0:fbdae7e6d805 1415 conflict_target_list = join_delim.join(toolchain_conflicts[target])
borlanic 0:fbdae7e6d805 1416 sufix = 's' if len(toolchain_conflicts[target]) > 1 else ''
borlanic 0:fbdae7e6d805 1417 result += "\t* Target %s does not support %s toolchain%s\n"% (target, conflict_target_list, sufix)
borlanic 0:fbdae7e6d805 1418
borlanic 0:fbdae7e6d805 1419 for toolchain in toolchain_path_conflicts:
borlanic 0:fbdae7e6d805 1420 # Let's check toolchain configuration
borlanic 0:fbdae7e6d805 1421 if toolchain in TOOLCHAIN_PATHS:
borlanic 0:fbdae7e6d805 1422 toolchain_path = TOOLCHAIN_PATHS[toolchain]
borlanic 0:fbdae7e6d805 1423 if not os.path.isdir(toolchain_path):
borlanic 0:fbdae7e6d805 1424 result += "\t# Toolchain %s path not found: %s\n"% (toolchain, toolchain_path)
borlanic 0:fbdae7e6d805 1425 return result
borlanic 0:fbdae7e6d805 1426
borlanic 0:fbdae7e6d805 1427
borlanic 0:fbdae7e6d805 1428 def get_avail_tests_summary_table(cols=None, result_summary=True, join_delim=',',platform_filter=None):
borlanic 0:fbdae7e6d805 1429 """ Generates table summary with all test cases and additional test cases
borlanic 0:fbdae7e6d805 1430 information using pretty print functionality. Allows test suite user to
borlanic 0:fbdae7e6d805 1431 see test cases
borlanic 0:fbdae7e6d805 1432 """
borlanic 0:fbdae7e6d805 1433 # get all unique test ID prefixes
borlanic 0:fbdae7e6d805 1434 unique_test_id = []
borlanic 0:fbdae7e6d805 1435 for test in TESTS:
borlanic 0:fbdae7e6d805 1436 split = test['id'].split('_')[:-1]
borlanic 0:fbdae7e6d805 1437 test_id_prefix = '_'.join(split)
borlanic 0:fbdae7e6d805 1438 if test_id_prefix not in unique_test_id:
borlanic 0:fbdae7e6d805 1439 unique_test_id.append(test_id_prefix)
borlanic 0:fbdae7e6d805 1440 unique_test_id.sort()
borlanic 0:fbdae7e6d805 1441 counter_dict_test_id_types = dict((t, 0) for t in unique_test_id)
borlanic 0:fbdae7e6d805 1442 counter_dict_test_id_types_all = dict((t, 0) for t in unique_test_id)
borlanic 0:fbdae7e6d805 1443
borlanic 0:fbdae7e6d805 1444 test_properties = ['id',
borlanic 0:fbdae7e6d805 1445 'automated',
borlanic 0:fbdae7e6d805 1446 'description',
borlanic 0:fbdae7e6d805 1447 'peripherals',
borlanic 0:fbdae7e6d805 1448 'host_test',
borlanic 0:fbdae7e6d805 1449 'duration'] if cols is None else cols
borlanic 0:fbdae7e6d805 1450
borlanic 0:fbdae7e6d805 1451 # All tests status table print
borlanic 0:fbdae7e6d805 1452 pt = PrettyTable(test_properties)
borlanic 0:fbdae7e6d805 1453 for col in test_properties:
borlanic 0:fbdae7e6d805 1454 pt.align[col] = "l"
borlanic 0:fbdae7e6d805 1455 pt.align['duration'] = "r"
borlanic 0:fbdae7e6d805 1456
borlanic 0:fbdae7e6d805 1457 counter_all = 0
borlanic 0:fbdae7e6d805 1458 counter_automated = 0
borlanic 0:fbdae7e6d805 1459 pt.padding_width = 1 # One space between column edges and contents (default)
borlanic 0:fbdae7e6d805 1460
borlanic 0:fbdae7e6d805 1461 for test_id in sorted(TEST_MAP.keys()):
borlanic 0:fbdae7e6d805 1462 if platform_filter is not None:
borlanic 0:fbdae7e6d805 1463 # FIlter out platforms using regex
borlanic 0:fbdae7e6d805 1464 if re.search(platform_filter, test_id) is None:
borlanic 0:fbdae7e6d805 1465 continue
borlanic 0:fbdae7e6d805 1466 row = []
borlanic 0:fbdae7e6d805 1467 test = TEST_MAP[test_id]
borlanic 0:fbdae7e6d805 1468 split = test_id.split('_')[:-1]
borlanic 0:fbdae7e6d805 1469 test_id_prefix = '_'.join(split)
borlanic 0:fbdae7e6d805 1470
borlanic 0:fbdae7e6d805 1471 for col in test_properties:
borlanic 0:fbdae7e6d805 1472 col_value = test[col]
borlanic 0:fbdae7e6d805 1473 if isinstance(test[col], list):
borlanic 0:fbdae7e6d805 1474 col_value = join_delim.join(test[col])
borlanic 0:fbdae7e6d805 1475 elif test[col] == None:
borlanic 0:fbdae7e6d805 1476 col_value = "-"
borlanic 0:fbdae7e6d805 1477
borlanic 0:fbdae7e6d805 1478 row.append(col_value)
borlanic 0:fbdae7e6d805 1479 if test['automated'] == True:
borlanic 0:fbdae7e6d805 1480 counter_dict_test_id_types[test_id_prefix] += 1
borlanic 0:fbdae7e6d805 1481 counter_automated += 1
borlanic 0:fbdae7e6d805 1482 pt.add_row(row)
borlanic 0:fbdae7e6d805 1483 # Update counters
borlanic 0:fbdae7e6d805 1484 counter_all += 1
borlanic 0:fbdae7e6d805 1485 counter_dict_test_id_types_all[test_id_prefix] += 1
borlanic 0:fbdae7e6d805 1486 result = pt.get_string()
borlanic 0:fbdae7e6d805 1487 result += "\n\n"
borlanic 0:fbdae7e6d805 1488
borlanic 0:fbdae7e6d805 1489 if result_summary and not platform_filter:
borlanic 0:fbdae7e6d805 1490 # Automation result summary
borlanic 0:fbdae7e6d805 1491 test_id_cols = ['automated', 'all', 'percent [%]', 'progress']
borlanic 0:fbdae7e6d805 1492 pt = PrettyTable(test_id_cols)
borlanic 0:fbdae7e6d805 1493 pt.align['automated'] = "r"
borlanic 0:fbdae7e6d805 1494 pt.align['all'] = "r"
borlanic 0:fbdae7e6d805 1495 pt.align['percent [%]'] = "r"
borlanic 0:fbdae7e6d805 1496
borlanic 0:fbdae7e6d805 1497 percent_progress = round(100.0 * counter_automated / float(counter_all), 1)
borlanic 0:fbdae7e6d805 1498 str_progress = progress_bar(percent_progress, 75)
borlanic 0:fbdae7e6d805 1499 pt.add_row([counter_automated, counter_all, percent_progress, str_progress])
borlanic 0:fbdae7e6d805 1500 result += "Automation coverage:\n"
borlanic 0:fbdae7e6d805 1501 result += pt.get_string()
borlanic 0:fbdae7e6d805 1502 result += "\n\n"
borlanic 0:fbdae7e6d805 1503
borlanic 0:fbdae7e6d805 1504 # Test automation coverage table print
borlanic 0:fbdae7e6d805 1505 test_id_cols = ['id', 'automated', 'all', 'percent [%]', 'progress']
borlanic 0:fbdae7e6d805 1506 pt = PrettyTable(test_id_cols)
borlanic 0:fbdae7e6d805 1507 pt.align['id'] = "l"
borlanic 0:fbdae7e6d805 1508 pt.align['automated'] = "r"
borlanic 0:fbdae7e6d805 1509 pt.align['all'] = "r"
borlanic 0:fbdae7e6d805 1510 pt.align['percent [%]'] = "r"
borlanic 0:fbdae7e6d805 1511 for unique_id in unique_test_id:
borlanic 0:fbdae7e6d805 1512 # print "\t\t%s: %d / %d" % (unique_id, counter_dict_test_id_types[unique_id], counter_dict_test_id_types_all[unique_id])
borlanic 0:fbdae7e6d805 1513 percent_progress = round(100.0 * counter_dict_test_id_types[unique_id] / float(counter_dict_test_id_types_all[unique_id]), 1)
borlanic 0:fbdae7e6d805 1514 str_progress = progress_bar(percent_progress, 75)
borlanic 0:fbdae7e6d805 1515 row = [unique_id,
borlanic 0:fbdae7e6d805 1516 counter_dict_test_id_types[unique_id],
borlanic 0:fbdae7e6d805 1517 counter_dict_test_id_types_all[unique_id],
borlanic 0:fbdae7e6d805 1518 percent_progress,
borlanic 0:fbdae7e6d805 1519 "[" + str_progress + "]"]
borlanic 0:fbdae7e6d805 1520 pt.add_row(row)
borlanic 0:fbdae7e6d805 1521 result += "Test automation coverage:\n"
borlanic 0:fbdae7e6d805 1522 result += pt.get_string()
borlanic 0:fbdae7e6d805 1523 result += "\n\n"
borlanic 0:fbdae7e6d805 1524 return result
borlanic 0:fbdae7e6d805 1525
borlanic 0:fbdae7e6d805 1526
borlanic 0:fbdae7e6d805 1527 def progress_bar(percent_progress, saturation=0):
borlanic 0:fbdae7e6d805 1528 """ This function creates progress bar with optional simple saturation mark
borlanic 0:fbdae7e6d805 1529 """
borlanic 0:fbdae7e6d805 1530 step = int(percent_progress / 2) # Scale by to (scale: 1 - 50)
borlanic 0:fbdae7e6d805 1531 str_progress = '#' * step + '.' * int(50 - step)
borlanic 0:fbdae7e6d805 1532 c = '!' if str_progress[38] == '.' else '|'
borlanic 0:fbdae7e6d805 1533 if saturation > 0:
borlanic 0:fbdae7e6d805 1534 saturation = saturation / 2
borlanic 0:fbdae7e6d805 1535 str_progress = str_progress[:saturation] + c + str_progress[saturation:]
borlanic 0:fbdae7e6d805 1536 return str_progress
borlanic 0:fbdae7e6d805 1537
borlanic 0:fbdae7e6d805 1538
borlanic 0:fbdae7e6d805 1539 def singletest_in_cli_mode(single_test):
borlanic 0:fbdae7e6d805 1540 """ Runs SingleTestRunner object in CLI (Command line interface) mode
borlanic 0:fbdae7e6d805 1541
borlanic 0:fbdae7e6d805 1542 @return returns success code (0 == success) for building and running tests
borlanic 0:fbdae7e6d805 1543 """
borlanic 0:fbdae7e6d805 1544 start = time()
borlanic 0:fbdae7e6d805 1545 # Execute tests depending on options and filter applied
borlanic 0:fbdae7e6d805 1546 test_summary, shuffle_seed, test_summary_ext, test_suite_properties_ext, build_report, build_properties = single_test.execute()
borlanic 0:fbdae7e6d805 1547 elapsed_time = time() - start
borlanic 0:fbdae7e6d805 1548
borlanic 0:fbdae7e6d805 1549 # Human readable summary
borlanic 0:fbdae7e6d805 1550 if not single_test.opts_suppress_summary:
borlanic 0:fbdae7e6d805 1551 # prints well-formed summary with results (SQL table like)
borlanic 0:fbdae7e6d805 1552 print(single_test.generate_test_summary(test_summary, shuffle_seed))
borlanic 0:fbdae7e6d805 1553 if single_test.opts_test_x_toolchain_summary:
borlanic 0:fbdae7e6d805 1554 # prints well-formed summary with results (SQL table like)
borlanic 0:fbdae7e6d805 1555 # table shows text x toolchain test result matrix
borlanic 0:fbdae7e6d805 1556 print(single_test.generate_test_summary_by_target(test_summary,
borlanic 0:fbdae7e6d805 1557 shuffle_seed))
borlanic 0:fbdae7e6d805 1558
borlanic 0:fbdae7e6d805 1559 print("Completed in %.2f sec" % elapsed_time)
borlanic 0:fbdae7e6d805 1560 print
borlanic 0:fbdae7e6d805 1561 # Write summary of the builds
borlanic 0:fbdae7e6d805 1562
borlanic 0:fbdae7e6d805 1563 print_report_exporter = ReportExporter(ResultExporterType.PRINT, package="build")
borlanic 0:fbdae7e6d805 1564 status = print_report_exporter.report(build_report)
borlanic 0:fbdae7e6d805 1565
borlanic 0:fbdae7e6d805 1566 # Store extra reports in files
borlanic 0:fbdae7e6d805 1567 if single_test.opts_report_html_file_name:
borlanic 0:fbdae7e6d805 1568 # Export results in form of HTML report to separate file
borlanic 0:fbdae7e6d805 1569 report_exporter = ReportExporter(ResultExporterType.HTML)
borlanic 0:fbdae7e6d805 1570 report_exporter.report_to_file(test_summary_ext, single_test.opts_report_html_file_name, test_suite_properties=test_suite_properties_ext)
borlanic 0:fbdae7e6d805 1571 if single_test.opts_report_junit_file_name:
borlanic 0:fbdae7e6d805 1572 # Export results in form of JUnit XML report to separate file
borlanic 0:fbdae7e6d805 1573 report_exporter = ReportExporter(ResultExporterType.JUNIT)
borlanic 0:fbdae7e6d805 1574 report_exporter.report_to_file(test_summary_ext, single_test.opts_report_junit_file_name, test_suite_properties=test_suite_properties_ext)
borlanic 0:fbdae7e6d805 1575 if single_test.opts_report_text_file_name:
borlanic 0:fbdae7e6d805 1576 # Export results in form of a text file
borlanic 0:fbdae7e6d805 1577 report_exporter = ReportExporter(ResultExporterType.TEXT)
borlanic 0:fbdae7e6d805 1578 report_exporter.report_to_file(test_summary_ext, single_test.opts_report_text_file_name, test_suite_properties=test_suite_properties_ext)
borlanic 0:fbdae7e6d805 1579 if single_test.opts_report_build_file_name:
borlanic 0:fbdae7e6d805 1580 # Export build results as html report to sparate file
borlanic 0:fbdae7e6d805 1581 report_exporter = ReportExporter(ResultExporterType.JUNIT, package="build")
borlanic 0:fbdae7e6d805 1582 report_exporter.report_to_file(build_report, single_test.opts_report_build_file_name, test_suite_properties=build_properties)
borlanic 0:fbdae7e6d805 1583
borlanic 0:fbdae7e6d805 1584 # Returns True if no build failures of the test projects or their dependencies
borlanic 0:fbdae7e6d805 1585 return status
borlanic 0:fbdae7e6d805 1586
borlanic 0:fbdae7e6d805 1587 class TestLogger():
borlanic 0:fbdae7e6d805 1588 """ Super-class for logging and printing ongoing events for test suite pass
borlanic 0:fbdae7e6d805 1589 """
borlanic 0:fbdae7e6d805 1590 def __init__(self, store_log=True):
borlanic 0:fbdae7e6d805 1591 """ We can control if logger actually stores log in memory
borlanic 0:fbdae7e6d805 1592 or just handled all log entries immediately
borlanic 0:fbdae7e6d805 1593 """
borlanic 0:fbdae7e6d805 1594 self.log = []
borlanic 0:fbdae7e6d805 1595 self.log_to_file = False
borlanic 0:fbdae7e6d805 1596 self.log_file_name = None
borlanic 0:fbdae7e6d805 1597 self.store_log = store_log
borlanic 0:fbdae7e6d805 1598
borlanic 0:fbdae7e6d805 1599 self.LogType = construct_enum(INFO='Info',
borlanic 0:fbdae7e6d805 1600 WARN='Warning',
borlanic 0:fbdae7e6d805 1601 NOTIF='Notification',
borlanic 0:fbdae7e6d805 1602 ERROR='Error',
borlanic 0:fbdae7e6d805 1603 EXCEPT='Exception')
borlanic 0:fbdae7e6d805 1604
borlanic 0:fbdae7e6d805 1605 self.LogToFileAttr = construct_enum(CREATE=1, # Create or overwrite existing log file
borlanic 0:fbdae7e6d805 1606 APPEND=2) # Append to existing log file
borlanic 0:fbdae7e6d805 1607
borlanic 0:fbdae7e6d805 1608 def log_line(self, LogType, log_line, timestamp=True, line_delim='\n'):
borlanic 0:fbdae7e6d805 1609 """ Log one line of text
borlanic 0:fbdae7e6d805 1610 """
borlanic 0:fbdae7e6d805 1611 log_timestamp = time()
borlanic 0:fbdae7e6d805 1612 log_entry = {'log_type' : LogType,
borlanic 0:fbdae7e6d805 1613 'log_timestamp' : log_timestamp,
borlanic 0:fbdae7e6d805 1614 'log_line' : log_line,
borlanic 0:fbdae7e6d805 1615 '_future' : None
borlanic 0:fbdae7e6d805 1616 }
borlanic 0:fbdae7e6d805 1617 # Store log in memory
borlanic 0:fbdae7e6d805 1618 if self.store_log:
borlanic 0:fbdae7e6d805 1619 self.log.append(log_entry)
borlanic 0:fbdae7e6d805 1620 return log_entry
borlanic 0:fbdae7e6d805 1621
borlanic 0:fbdae7e6d805 1622
borlanic 0:fbdae7e6d805 1623 class CLITestLogger(TestLogger):
borlanic 0:fbdae7e6d805 1624 """ Logger used with CLI (Command line interface) test suite. Logs on screen and to file if needed
borlanic 0:fbdae7e6d805 1625 """
borlanic 0:fbdae7e6d805 1626 def __init__(self, store_log=True, file_name=None):
borlanic 0:fbdae7e6d805 1627 TestLogger.__init__(self)
borlanic 0:fbdae7e6d805 1628 self.log_file_name = file_name
borlanic 0:fbdae7e6d805 1629 #self.TIMESTAMP_FORMAT = '%y-%m-%d %H:%M:%S' # Full date and time
borlanic 0:fbdae7e6d805 1630 self.TIMESTAMP_FORMAT = '%H:%M:%S' # Time only
borlanic 0:fbdae7e6d805 1631
borlanic 0:fbdae7e6d805 1632 def log_print(self, log_entry, timestamp=True):
borlanic 0:fbdae7e6d805 1633 """ Prints on screen formatted log entry
borlanic 0:fbdae7e6d805 1634 """
borlanic 0:fbdae7e6d805 1635 ts = log_entry['log_timestamp']
borlanic 0:fbdae7e6d805 1636 timestamp_str = datetime.datetime.fromtimestamp(ts).strftime("[%s] "% self.TIMESTAMP_FORMAT) if timestamp else ''
borlanic 0:fbdae7e6d805 1637 log_line_str = "%(log_type)s: %(log_line)s"% (log_entry)
borlanic 0:fbdae7e6d805 1638 return timestamp_str + log_line_str
borlanic 0:fbdae7e6d805 1639
borlanic 0:fbdae7e6d805 1640 def log_line(self, LogType, log_line, timestamp=True, line_delim='\n'):
borlanic 0:fbdae7e6d805 1641 """ Logs line, if log file output was specified log line will be appended
borlanic 0:fbdae7e6d805 1642 at the end of log file
borlanic 0:fbdae7e6d805 1643 """
borlanic 0:fbdae7e6d805 1644 log_entry = TestLogger.log_line(self, LogType, log_line)
borlanic 0:fbdae7e6d805 1645 log_line_str = self.log_print(log_entry, timestamp)
borlanic 0:fbdae7e6d805 1646 if self.log_file_name is not None:
borlanic 0:fbdae7e6d805 1647 try:
borlanic 0:fbdae7e6d805 1648 with open(self.log_file_name, 'a') as f:
borlanic 0:fbdae7e6d805 1649 f.write(log_line_str + line_delim)
borlanic 0:fbdae7e6d805 1650 except IOError:
borlanic 0:fbdae7e6d805 1651 pass
borlanic 0:fbdae7e6d805 1652 return log_line_str
borlanic 0:fbdae7e6d805 1653
borlanic 0:fbdae7e6d805 1654
borlanic 0:fbdae7e6d805 1655 def factory_db_logger(db_url):
borlanic 0:fbdae7e6d805 1656 """ Factory database driver depending on database type supplied in database connection string db_url
borlanic 0:fbdae7e6d805 1657 """
borlanic 0:fbdae7e6d805 1658 if db_url is not None:
borlanic 0:fbdae7e6d805 1659 from tools.test_mysql import MySQLDBAccess
borlanic 0:fbdae7e6d805 1660 connection_info = BaseDBAccess().parse_db_connection_string(db_url)
borlanic 0:fbdae7e6d805 1661 if connection_info is not None:
borlanic 0:fbdae7e6d805 1662 (db_type, username, password, host, db_name) = BaseDBAccess().parse_db_connection_string(db_url)
borlanic 0:fbdae7e6d805 1663 if db_type == 'mysql':
borlanic 0:fbdae7e6d805 1664 return MySQLDBAccess()
borlanic 0:fbdae7e6d805 1665 return None
borlanic 0:fbdae7e6d805 1666
borlanic 0:fbdae7e6d805 1667
borlanic 0:fbdae7e6d805 1668 def detect_database_verbose(db_url):
borlanic 0:fbdae7e6d805 1669 """ uses verbose mode (prints) database detection sequence to check it database connection string is valid
borlanic 0:fbdae7e6d805 1670 """
borlanic 0:fbdae7e6d805 1671 result = BaseDBAccess().parse_db_connection_string(db_url)
borlanic 0:fbdae7e6d805 1672 if result is not None:
borlanic 0:fbdae7e6d805 1673 # Parsing passed
borlanic 0:fbdae7e6d805 1674 (db_type, username, password, host, db_name) = result
borlanic 0:fbdae7e6d805 1675 #print "DB type '%s', user name '%s', password '%s', host '%s', db name '%s'"% result
borlanic 0:fbdae7e6d805 1676 # Let's try to connect
borlanic 0:fbdae7e6d805 1677 db_ = factory_db_logger(db_url)
borlanic 0:fbdae7e6d805 1678 if db_ is not None:
borlanic 0:fbdae7e6d805 1679 print("Connecting to database '%s'..." % db_url)
borlanic 0:fbdae7e6d805 1680 db_.connect(host, username, password, db_name)
borlanic 0:fbdae7e6d805 1681 if db_.is_connected():
borlanic 0:fbdae7e6d805 1682 print("ok")
borlanic 0:fbdae7e6d805 1683 print("Detecting database...")
borlanic 0:fbdae7e6d805 1684 print(db_.detect_database(verbose=True))
borlanic 0:fbdae7e6d805 1685 print("Disconnecting...")
borlanic 0:fbdae7e6d805 1686 db_.disconnect()
borlanic 0:fbdae7e6d805 1687 print("done")
borlanic 0:fbdae7e6d805 1688 else:
borlanic 0:fbdae7e6d805 1689 print("Database type '%s' unknown" % db_type)
borlanic 0:fbdae7e6d805 1690 else:
borlanic 0:fbdae7e6d805 1691 print("Parse error: '%s' - DB Url error" % db_url)
borlanic 0:fbdae7e6d805 1692
borlanic 0:fbdae7e6d805 1693
borlanic 0:fbdae7e6d805 1694 def get_module_avail(module_name):
borlanic 0:fbdae7e6d805 1695 """ This function returns True if module_name is already imported module
borlanic 0:fbdae7e6d805 1696 """
borlanic 0:fbdae7e6d805 1697 return module_name in sys.modules.keys()
borlanic 0:fbdae7e6d805 1698
borlanic 0:fbdae7e6d805 1699 def get_autodetected_MUTS_list(platform_name_filter=None):
borlanic 0:fbdae7e6d805 1700 oldError = None
borlanic 0:fbdae7e6d805 1701 if os.name == 'nt':
borlanic 0:fbdae7e6d805 1702 # Disable Windows error box temporarily
borlanic 0:fbdae7e6d805 1703 oldError = ctypes.windll.kernel32.SetErrorMode(1) #note that SEM_FAILCRITICALERRORS = 1
borlanic 0:fbdae7e6d805 1704
borlanic 0:fbdae7e6d805 1705 mbeds = mbed_lstools.create()
borlanic 0:fbdae7e6d805 1706 detect_muts_list = mbeds.list_mbeds()
borlanic 0:fbdae7e6d805 1707
borlanic 0:fbdae7e6d805 1708 if os.name == 'nt':
borlanic 0:fbdae7e6d805 1709 ctypes.windll.kernel32.SetErrorMode(oldError)
borlanic 0:fbdae7e6d805 1710
borlanic 0:fbdae7e6d805 1711 return get_autodetected_MUTS(detect_muts_list, platform_name_filter=platform_name_filter)
borlanic 0:fbdae7e6d805 1712
borlanic 0:fbdae7e6d805 1713 def get_autodetected_MUTS(mbeds_list, platform_name_filter=None):
borlanic 0:fbdae7e6d805 1714 """ Function detects all connected to host mbed-enabled devices and generates artificial MUTS file.
borlanic 0:fbdae7e6d805 1715 If function fails to auto-detect devices it will return empty dictionary.
borlanic 0:fbdae7e6d805 1716
borlanic 0:fbdae7e6d805 1717 if get_module_avail('mbed_lstools'):
borlanic 0:fbdae7e6d805 1718 mbeds = mbed_lstools.create()
borlanic 0:fbdae7e6d805 1719 mbeds_list = mbeds.list_mbeds()
borlanic 0:fbdae7e6d805 1720
borlanic 0:fbdae7e6d805 1721 @param mbeds_list list of mbeds captured from mbed_lstools
borlanic 0:fbdae7e6d805 1722 @param platform_name You can filter 'platform_name' with list of filtered targets from 'platform_name_filter'
borlanic 0:fbdae7e6d805 1723 """
borlanic 0:fbdae7e6d805 1724 result = {} # Should be in muts_all.json format
borlanic 0:fbdae7e6d805 1725 # Align mbeds_list from mbed_lstools to MUT file format (JSON dictionary with muts)
borlanic 0:fbdae7e6d805 1726 # mbeds_list = [{'platform_name': 'NUCLEO_F302R8', 'mount_point': 'E:', 'target_id': '07050200623B61125D5EF72A', 'serial_port': u'COM34'}]
borlanic 0:fbdae7e6d805 1727 index = 1
borlanic 0:fbdae7e6d805 1728 for mut in mbeds_list:
borlanic 0:fbdae7e6d805 1729 # Filter the MUTS if a filter is specified
borlanic 0:fbdae7e6d805 1730
borlanic 0:fbdae7e6d805 1731 if platform_name_filter and not mut['platform_name'] in platform_name_filter:
borlanic 0:fbdae7e6d805 1732 continue
borlanic 0:fbdae7e6d805 1733
borlanic 0:fbdae7e6d805 1734 # For mcu_unique - we are assigning 'platform_name_unique' value from mbedls output (if its existing)
borlanic 0:fbdae7e6d805 1735 # if not we are creating our own unique value (last few chars from platform's target_id).
borlanic 0:fbdae7e6d805 1736 m = {'mcu': mut['platform_name'],
borlanic 0:fbdae7e6d805 1737 'mcu_unique' : mut['platform_name_unique'] if 'platform_name_unique' in mut else "%s[%s]" % (mut['platform_name'], mut['target_id'][-4:]),
borlanic 0:fbdae7e6d805 1738 'port': mut['serial_port'],
borlanic 0:fbdae7e6d805 1739 'disk': mut['mount_point'],
borlanic 0:fbdae7e6d805 1740 'peripherals': [] # No peripheral detection
borlanic 0:fbdae7e6d805 1741 }
borlanic 0:fbdae7e6d805 1742 if index not in result:
borlanic 0:fbdae7e6d805 1743 result[index] = {}
borlanic 0:fbdae7e6d805 1744 result[index] = m
borlanic 0:fbdae7e6d805 1745 index += 1
borlanic 0:fbdae7e6d805 1746 return result
borlanic 0:fbdae7e6d805 1747
borlanic 0:fbdae7e6d805 1748
borlanic 0:fbdae7e6d805 1749 def get_autodetected_TEST_SPEC(mbeds_list,
borlanic 0:fbdae7e6d805 1750 use_default_toolchain=True,
borlanic 0:fbdae7e6d805 1751 use_supported_toolchains=False,
borlanic 0:fbdae7e6d805 1752 toolchain_filter=None,
borlanic 0:fbdae7e6d805 1753 platform_name_filter=None):
borlanic 0:fbdae7e6d805 1754 """ Function detects all connected to host mbed-enabled devices and generates artificial test_spec file.
borlanic 0:fbdae7e6d805 1755 If function fails to auto-detect devices it will return empty 'targets' test_spec description.
borlanic 0:fbdae7e6d805 1756
borlanic 0:fbdae7e6d805 1757 use_default_toolchain - if True add default toolchain to test_spec
borlanic 0:fbdae7e6d805 1758 use_supported_toolchains - if True add all supported toolchains to test_spec
borlanic 0:fbdae7e6d805 1759 toolchain_filter - if [...list of toolchains...] add from all toolchains only those in filter to test_spec
borlanic 0:fbdae7e6d805 1760 """
borlanic 0:fbdae7e6d805 1761 result = {'targets': {} }
borlanic 0:fbdae7e6d805 1762
borlanic 0:fbdae7e6d805 1763 for mut in mbeds_list:
borlanic 0:fbdae7e6d805 1764 mcu = mut['mcu']
borlanic 0:fbdae7e6d805 1765 if platform_name_filter is None or (platform_name_filter and mut['mcu'] in platform_name_filter):
borlanic 0:fbdae7e6d805 1766 if mcu in TARGET_MAP:
borlanic 0:fbdae7e6d805 1767 default_toolchain = TARGET_MAP[mcu].default_toolchain
borlanic 0:fbdae7e6d805 1768 supported_toolchains = TARGET_MAP[mcu].supported_toolchains
borlanic 0:fbdae7e6d805 1769
borlanic 0:fbdae7e6d805 1770 # Decide which toolchains should be added to test specification toolchain pool for each target
borlanic 0:fbdae7e6d805 1771 toolchains = []
borlanic 0:fbdae7e6d805 1772 if use_default_toolchain:
borlanic 0:fbdae7e6d805 1773 toolchains.append(default_toolchain)
borlanic 0:fbdae7e6d805 1774 if use_supported_toolchains:
borlanic 0:fbdae7e6d805 1775 toolchains += supported_toolchains
borlanic 0:fbdae7e6d805 1776 if toolchain_filter is not None:
borlanic 0:fbdae7e6d805 1777 all_toolchains = supported_toolchains + [default_toolchain]
borlanic 0:fbdae7e6d805 1778 for toolchain in toolchain_filter:
borlanic 0:fbdae7e6d805 1779 if toolchain in all_toolchains:
borlanic 0:fbdae7e6d805 1780 toolchains.append(toolchain)
borlanic 0:fbdae7e6d805 1781
borlanic 0:fbdae7e6d805 1782 result['targets'][mcu] = list(set(toolchains))
borlanic 0:fbdae7e6d805 1783 return result
borlanic 0:fbdae7e6d805 1784
borlanic 0:fbdae7e6d805 1785
borlanic 0:fbdae7e6d805 1786 def get_default_test_options_parser():
borlanic 0:fbdae7e6d805 1787 """ Get common test script options used by CLI, web services etc.
borlanic 0:fbdae7e6d805 1788 """
borlanic 0:fbdae7e6d805 1789 parser = argparse.ArgumentParser()
borlanic 0:fbdae7e6d805 1790 parser.add_argument('-i', '--tests',
borlanic 0:fbdae7e6d805 1791 dest='test_spec_filename',
borlanic 0:fbdae7e6d805 1792 metavar="FILE",
borlanic 0:fbdae7e6d805 1793 type=argparse_filestring_type,
borlanic 0:fbdae7e6d805 1794 help='Points to file with test specification')
borlanic 0:fbdae7e6d805 1795
borlanic 0:fbdae7e6d805 1796 parser.add_argument('-M', '--MUTS',
borlanic 0:fbdae7e6d805 1797 dest='muts_spec_filename',
borlanic 0:fbdae7e6d805 1798 metavar="FILE",
borlanic 0:fbdae7e6d805 1799 type=argparse_filestring_type,
borlanic 0:fbdae7e6d805 1800 help='Points to file with MUTs specification (overwrites settings.py and private_settings.py)')
borlanic 0:fbdae7e6d805 1801
borlanic 0:fbdae7e6d805 1802 parser.add_argument("-j", "--jobs",
borlanic 0:fbdae7e6d805 1803 dest='jobs',
borlanic 0:fbdae7e6d805 1804 metavar="NUMBER",
borlanic 0:fbdae7e6d805 1805 type=int,
borlanic 0:fbdae7e6d805 1806 help="Define number of compilation jobs. Default value is 1")
borlanic 0:fbdae7e6d805 1807
borlanic 0:fbdae7e6d805 1808 if get_module_avail('mbed_lstools'):
borlanic 0:fbdae7e6d805 1809 # Additional features available when mbed_lstools is installed on host and imported
borlanic 0:fbdae7e6d805 1810 # mbed_lstools allow users to detect connected to host mbed-enabled devices
borlanic 0:fbdae7e6d805 1811 parser.add_argument('--auto',
borlanic 0:fbdae7e6d805 1812 dest='auto_detect',
borlanic 0:fbdae7e6d805 1813 action="store_true",
borlanic 0:fbdae7e6d805 1814 help='Use mbed-ls module to detect all connected mbed devices')
borlanic 0:fbdae7e6d805 1815
borlanic 0:fbdae7e6d805 1816 toolchain_list = list(TOOLCHAINS) + ["DEFAULT", "ALL"]
borlanic 0:fbdae7e6d805 1817 parser.add_argument('--tc',
borlanic 0:fbdae7e6d805 1818 dest='toolchains_filter',
borlanic 0:fbdae7e6d805 1819 type=argparse_many(argparse_uppercase_type(toolchain_list, "toolchains")),
borlanic 0:fbdae7e6d805 1820 help="Toolchain filter for --auto argument. Use toolchains names separated by comma, 'default' or 'all' to select toolchains")
borlanic 0:fbdae7e6d805 1821
borlanic 0:fbdae7e6d805 1822 test_scopes = ','.join(["'%s'" % n for n in get_available_oper_test_scopes()])
borlanic 0:fbdae7e6d805 1823 parser.add_argument('--oper',
borlanic 0:fbdae7e6d805 1824 dest='operability_checks',
borlanic 0:fbdae7e6d805 1825 type=argparse_lowercase_type(get_available_oper_test_scopes(), "scopes"),
borlanic 0:fbdae7e6d805 1826 help='Perform interoperability tests between host and connected mbed devices. Available test scopes are: %s' % test_scopes)
borlanic 0:fbdae7e6d805 1827
borlanic 0:fbdae7e6d805 1828 parser.add_argument('--clean',
borlanic 0:fbdae7e6d805 1829 dest='clean',
borlanic 0:fbdae7e6d805 1830 action="store_true",
borlanic 0:fbdae7e6d805 1831 help='Clean the build directory')
borlanic 0:fbdae7e6d805 1832
borlanic 0:fbdae7e6d805 1833 parser.add_argument('-P', '--only-peripherals',
borlanic 0:fbdae7e6d805 1834 dest='test_only_peripheral',
borlanic 0:fbdae7e6d805 1835 default=False,
borlanic 0:fbdae7e6d805 1836 action="store_true",
borlanic 0:fbdae7e6d805 1837 help='Test only peripheral declared for MUT and skip common tests')
borlanic 0:fbdae7e6d805 1838
borlanic 0:fbdae7e6d805 1839 parser.add_argument("--profile", dest="profile", action="append",
borlanic 0:fbdae7e6d805 1840 type=argparse_filestring_type,
borlanic 0:fbdae7e6d805 1841 default=[])
borlanic 0:fbdae7e6d805 1842
borlanic 0:fbdae7e6d805 1843 parser.add_argument('-C', '--only-commons',
borlanic 0:fbdae7e6d805 1844 dest='test_only_common',
borlanic 0:fbdae7e6d805 1845 default=False,
borlanic 0:fbdae7e6d805 1846 action="store_true",
borlanic 0:fbdae7e6d805 1847 help='Test only board internals. Skip perpherials tests and perform common tests')
borlanic 0:fbdae7e6d805 1848
borlanic 0:fbdae7e6d805 1849 parser.add_argument('-n', '--test-by-names',
borlanic 0:fbdae7e6d805 1850 dest='test_by_names',
borlanic 0:fbdae7e6d805 1851 type=argparse_many(str),
borlanic 0:fbdae7e6d805 1852 help='Runs only test enumerated it this switch. Use comma to separate test case names')
borlanic 0:fbdae7e6d805 1853
borlanic 0:fbdae7e6d805 1854 parser.add_argument('-p', '--peripheral-by-names',
borlanic 0:fbdae7e6d805 1855 dest='peripheral_by_names',
borlanic 0:fbdae7e6d805 1856 type=argparse_many(str),
borlanic 0:fbdae7e6d805 1857 help='Forces discovery of particular peripherals. Use comma to separate peripheral names')
borlanic 0:fbdae7e6d805 1858
borlanic 0:fbdae7e6d805 1859 copy_methods = host_tests_plugins.get_plugin_caps('CopyMethod')
borlanic 0:fbdae7e6d805 1860 copy_methods_str = "Plugin support: " + ', '.join(copy_methods)
borlanic 0:fbdae7e6d805 1861
borlanic 0:fbdae7e6d805 1862 parser.add_argument('-c', '--copy-method',
borlanic 0:fbdae7e6d805 1863 dest='copy_method',
borlanic 0:fbdae7e6d805 1864 type=argparse_uppercase_type(copy_methods, "flash method"),
borlanic 0:fbdae7e6d805 1865 help="Select binary copy (flash) method. Default is Python's shutil.copy() method. %s"% copy_methods_str)
borlanic 0:fbdae7e6d805 1866
borlanic 0:fbdae7e6d805 1867 reset_methods = host_tests_plugins.get_plugin_caps('ResetMethod')
borlanic 0:fbdae7e6d805 1868 reset_methods_str = "Plugin support: " + ', '.join(reset_methods)
borlanic 0:fbdae7e6d805 1869
borlanic 0:fbdae7e6d805 1870 parser.add_argument('-r', '--reset-type',
borlanic 0:fbdae7e6d805 1871 dest='mut_reset_type',
borlanic 0:fbdae7e6d805 1872 default=None,
borlanic 0:fbdae7e6d805 1873 type=argparse_uppercase_type(reset_methods, "reset method"),
borlanic 0:fbdae7e6d805 1874 help='Extra reset method used to reset MUT by host test script. %s'% reset_methods_str)
borlanic 0:fbdae7e6d805 1875
borlanic 0:fbdae7e6d805 1876 parser.add_argument('-g', '--goanna-for-tests',
borlanic 0:fbdae7e6d805 1877 dest='goanna_for_tests',
borlanic 0:fbdae7e6d805 1878 action="store_true",
borlanic 0:fbdae7e6d805 1879 help='Run Goanna static analyse tool for tests. (Project will be rebuilded)')
borlanic 0:fbdae7e6d805 1880
borlanic 0:fbdae7e6d805 1881 parser.add_argument('-G', '--goanna-for-sdk',
borlanic 0:fbdae7e6d805 1882 dest='goanna_for_mbed_sdk',
borlanic 0:fbdae7e6d805 1883 action="store_true",
borlanic 0:fbdae7e6d805 1884 help='Run Goanna static analyse tool for mbed SDK (Project will be rebuilded)')
borlanic 0:fbdae7e6d805 1885
borlanic 0:fbdae7e6d805 1886 parser.add_argument('-s', '--suppress-summary',
borlanic 0:fbdae7e6d805 1887 dest='suppress_summary',
borlanic 0:fbdae7e6d805 1888 default=False,
borlanic 0:fbdae7e6d805 1889 action="store_true",
borlanic 0:fbdae7e6d805 1890 help='Suppresses display of wellformatted table with test results')
borlanic 0:fbdae7e6d805 1891
borlanic 0:fbdae7e6d805 1892 parser.add_argument('-t', '--test-summary',
borlanic 0:fbdae7e6d805 1893 dest='test_x_toolchain_summary',
borlanic 0:fbdae7e6d805 1894 default=False,
borlanic 0:fbdae7e6d805 1895 action="store_true",
borlanic 0:fbdae7e6d805 1896 help='Displays wellformatted table with test x toolchain test result per target')
borlanic 0:fbdae7e6d805 1897
borlanic 0:fbdae7e6d805 1898 parser.add_argument('-A', '--test-automation-report',
borlanic 0:fbdae7e6d805 1899 dest='test_automation_report',
borlanic 0:fbdae7e6d805 1900 default=False,
borlanic 0:fbdae7e6d805 1901 action="store_true",
borlanic 0:fbdae7e6d805 1902 help='Prints information about all tests and exits')
borlanic 0:fbdae7e6d805 1903
borlanic 0:fbdae7e6d805 1904 parser.add_argument('-R', '--test-case-report',
borlanic 0:fbdae7e6d805 1905 dest='test_case_report',
borlanic 0:fbdae7e6d805 1906 default=False,
borlanic 0:fbdae7e6d805 1907 action="store_true",
borlanic 0:fbdae7e6d805 1908 help='Prints information about all test cases and exits')
borlanic 0:fbdae7e6d805 1909
borlanic 0:fbdae7e6d805 1910 parser.add_argument("-S", "--supported-toolchains",
borlanic 0:fbdae7e6d805 1911 action="store_true",
borlanic 0:fbdae7e6d805 1912 dest="supported_toolchains",
borlanic 0:fbdae7e6d805 1913 default=False,
borlanic 0:fbdae7e6d805 1914 help="Displays supported matrix of MCUs and toolchains")
borlanic 0:fbdae7e6d805 1915
borlanic 0:fbdae7e6d805 1916 parser.add_argument("-O", "--only-build",
borlanic 0:fbdae7e6d805 1917 action="store_true",
borlanic 0:fbdae7e6d805 1918 dest="only_build_tests",
borlanic 0:fbdae7e6d805 1919 default=False,
borlanic 0:fbdae7e6d805 1920 help="Only build tests, skips actual test procedures (flashing etc.)")
borlanic 0:fbdae7e6d805 1921
borlanic 0:fbdae7e6d805 1922 parser.add_argument('--parallel',
borlanic 0:fbdae7e6d805 1923 dest='parallel_test_exec',
borlanic 0:fbdae7e6d805 1924 default=False,
borlanic 0:fbdae7e6d805 1925 action="store_true",
borlanic 0:fbdae7e6d805 1926 help='Experimental, you execute test runners for connected to your host MUTs in parallel (speeds up test result collection)')
borlanic 0:fbdae7e6d805 1927
borlanic 0:fbdae7e6d805 1928 parser.add_argument('--config',
borlanic 0:fbdae7e6d805 1929 dest='verbose_test_configuration_only',
borlanic 0:fbdae7e6d805 1930 default=False,
borlanic 0:fbdae7e6d805 1931 action="store_true",
borlanic 0:fbdae7e6d805 1932 help='Displays full test specification and MUTs configration and exits')
borlanic 0:fbdae7e6d805 1933
borlanic 0:fbdae7e6d805 1934 parser.add_argument('--loops',
borlanic 0:fbdae7e6d805 1935 dest='test_loops_list',
borlanic 0:fbdae7e6d805 1936 type=argparse_many(str),
borlanic 0:fbdae7e6d805 1937 help='Set no. of loops per test. Format: TEST_1=1,TEST_2=2,TEST_3=3')
borlanic 0:fbdae7e6d805 1938
borlanic 0:fbdae7e6d805 1939 parser.add_argument('--global-loops',
borlanic 0:fbdae7e6d805 1940 dest='test_global_loops_value',
borlanic 0:fbdae7e6d805 1941 type=int,
borlanic 0:fbdae7e6d805 1942 help='Set global number of test loops per test. Default value is set 1')
borlanic 0:fbdae7e6d805 1943
borlanic 0:fbdae7e6d805 1944 parser.add_argument('--consolidate-waterfall',
borlanic 0:fbdae7e6d805 1945 dest='consolidate_waterfall_test',
borlanic 0:fbdae7e6d805 1946 default=False,
borlanic 0:fbdae7e6d805 1947 action="store_true",
borlanic 0:fbdae7e6d805 1948 help='Used with --waterfall argument. Adds only one test to report reflecting outcome of waterfall test.')
borlanic 0:fbdae7e6d805 1949
borlanic 0:fbdae7e6d805 1950 parser.add_argument('-W', '--waterfall',
borlanic 0:fbdae7e6d805 1951 dest='waterfall_test',
borlanic 0:fbdae7e6d805 1952 default=False,
borlanic 0:fbdae7e6d805 1953 action="store_true",
borlanic 0:fbdae7e6d805 1954 help='Used with --loops or --global-loops arguments. Tests until OK result occurs and assumes test passed')
borlanic 0:fbdae7e6d805 1955
borlanic 0:fbdae7e6d805 1956 parser.add_argument('-N', '--firmware-name',
borlanic 0:fbdae7e6d805 1957 dest='firmware_global_name',
borlanic 0:fbdae7e6d805 1958 help='Set global name for all produced projects. Note, proper file extension will be added by buid scripts')
borlanic 0:fbdae7e6d805 1959
borlanic 0:fbdae7e6d805 1960 parser.add_argument('-u', '--shuffle',
borlanic 0:fbdae7e6d805 1961 dest='shuffle_test_order',
borlanic 0:fbdae7e6d805 1962 default=False,
borlanic 0:fbdae7e6d805 1963 action="store_true",
borlanic 0:fbdae7e6d805 1964 help='Shuffles test execution order')
borlanic 0:fbdae7e6d805 1965
borlanic 0:fbdae7e6d805 1966 parser.add_argument('--shuffle-seed',
borlanic 0:fbdae7e6d805 1967 dest='shuffle_test_seed',
borlanic 0:fbdae7e6d805 1968 default=None,
borlanic 0:fbdae7e6d805 1969 help='Shuffle seed (If you want to reproduce your shuffle order please use seed provided in test summary)')
borlanic 0:fbdae7e6d805 1970
borlanic 0:fbdae7e6d805 1971 parser.add_argument('-f', '--filter',
borlanic 0:fbdae7e6d805 1972 dest='general_filter_regex',
borlanic 0:fbdae7e6d805 1973 type=argparse_many(str),
borlanic 0:fbdae7e6d805 1974 default=None,
borlanic 0:fbdae7e6d805 1975 help='For some commands you can use filter to filter out results')
borlanic 0:fbdae7e6d805 1976
borlanic 0:fbdae7e6d805 1977 parser.add_argument('--inc-timeout',
borlanic 0:fbdae7e6d805 1978 dest='extend_test_timeout',
borlanic 0:fbdae7e6d805 1979 metavar="NUMBER",
borlanic 0:fbdae7e6d805 1980 type=int,
borlanic 0:fbdae7e6d805 1981 help='You can increase global timeout for each test by specifying additional test timeout in seconds')
borlanic 0:fbdae7e6d805 1982
borlanic 0:fbdae7e6d805 1983 parser.add_argument('--db',
borlanic 0:fbdae7e6d805 1984 dest='db_url',
borlanic 0:fbdae7e6d805 1985 help='This specifies what database test suite uses to store its state. To pass DB connection info use database connection string. Example: \'mysql://username:password@127.0.0.1/db_name\'')
borlanic 0:fbdae7e6d805 1986
borlanic 0:fbdae7e6d805 1987 parser.add_argument('-l', '--log',
borlanic 0:fbdae7e6d805 1988 dest='log_file_name',
borlanic 0:fbdae7e6d805 1989 help='Log events to external file (note not all console entries may be visible in log file)')
borlanic 0:fbdae7e6d805 1990
borlanic 0:fbdae7e6d805 1991 parser.add_argument('--report-html',
borlanic 0:fbdae7e6d805 1992 dest='report_html_file_name',
borlanic 0:fbdae7e6d805 1993 help='You can log test suite results in form of HTML report')
borlanic 0:fbdae7e6d805 1994
borlanic 0:fbdae7e6d805 1995 parser.add_argument('--report-junit',
borlanic 0:fbdae7e6d805 1996 dest='report_junit_file_name',
borlanic 0:fbdae7e6d805 1997 help='You can log test suite results in form of JUnit compliant XML report')
borlanic 0:fbdae7e6d805 1998
borlanic 0:fbdae7e6d805 1999 parser.add_argument("--report-build",
borlanic 0:fbdae7e6d805 2000 dest="report_build_file_name",
borlanic 0:fbdae7e6d805 2001 help="Output the build results to a junit xml file")
borlanic 0:fbdae7e6d805 2002
borlanic 0:fbdae7e6d805 2003 parser.add_argument("--report-text",
borlanic 0:fbdae7e6d805 2004 dest="report_text_file_name",
borlanic 0:fbdae7e6d805 2005 help="Output the build results to a text file")
borlanic 0:fbdae7e6d805 2006
borlanic 0:fbdae7e6d805 2007 parser.add_argument('--verbose-skipped',
borlanic 0:fbdae7e6d805 2008 dest='verbose_skipped_tests',
borlanic 0:fbdae7e6d805 2009 default=False,
borlanic 0:fbdae7e6d805 2010 action="store_true",
borlanic 0:fbdae7e6d805 2011 help='Prints some extra information about skipped tests')
borlanic 0:fbdae7e6d805 2012
borlanic 0:fbdae7e6d805 2013 parser.add_argument('-V', '--verbose-test-result',
borlanic 0:fbdae7e6d805 2014 dest='verbose_test_result_only',
borlanic 0:fbdae7e6d805 2015 default=False,
borlanic 0:fbdae7e6d805 2016 action="store_true",
borlanic 0:fbdae7e6d805 2017 help='Prints test serial output')
borlanic 0:fbdae7e6d805 2018
borlanic 0:fbdae7e6d805 2019 parser.add_argument('-v', '--verbose',
borlanic 0:fbdae7e6d805 2020 dest='verbose',
borlanic 0:fbdae7e6d805 2021 default=False,
borlanic 0:fbdae7e6d805 2022 action="store_true",
borlanic 0:fbdae7e6d805 2023 help='Verbose mode (prints some extra information)')
borlanic 0:fbdae7e6d805 2024
borlanic 0:fbdae7e6d805 2025 parser.add_argument('--version',
borlanic 0:fbdae7e6d805 2026 dest='version',
borlanic 0:fbdae7e6d805 2027 default=False,
borlanic 0:fbdae7e6d805 2028 action="store_true",
borlanic 0:fbdae7e6d805 2029 help='Prints script version and exits')
borlanic 0:fbdae7e6d805 2030
borlanic 0:fbdae7e6d805 2031 parser.add_argument('--stats-depth',
borlanic 0:fbdae7e6d805 2032 dest='stats_depth',
borlanic 0:fbdae7e6d805 2033 default=2,
borlanic 0:fbdae7e6d805 2034 type=int,
borlanic 0:fbdae7e6d805 2035 help="Depth level for static memory report")
borlanic 0:fbdae7e6d805 2036 return parser
borlanic 0:fbdae7e6d805 2037
borlanic 0:fbdae7e6d805 2038 def test_path_to_name(path, base):
borlanic 0:fbdae7e6d805 2039 """Change all slashes in a path into hyphens
borlanic 0:fbdae7e6d805 2040 This creates a unique cross-platform test name based on the path
borlanic 0:fbdae7e6d805 2041 This can eventually be overriden by a to-be-determined meta-data mechanism"""
borlanic 0:fbdae7e6d805 2042 name_parts = []
borlanic 0:fbdae7e6d805 2043 head, tail = os.path.split(relpath(path,base))
borlanic 0:fbdae7e6d805 2044 while (tail and tail != "."):
borlanic 0:fbdae7e6d805 2045 name_parts.insert(0, tail)
borlanic 0:fbdae7e6d805 2046 head, tail = os.path.split(head)
borlanic 0:fbdae7e6d805 2047
borlanic 0:fbdae7e6d805 2048 return "-".join(name_parts).lower()
borlanic 0:fbdae7e6d805 2049
borlanic 0:fbdae7e6d805 2050 def get_test_config(config_name, target_name):
borlanic 0:fbdae7e6d805 2051 """Finds the path to a test configuration file
borlanic 0:fbdae7e6d805 2052 config_name: path to a custom configuration file OR mbed OS interface "ethernet, wifi_odin, etc"
borlanic 0:fbdae7e6d805 2053 target_name: name of target to determing if mbed OS interface given is valid
borlanic 0:fbdae7e6d805 2054 returns path to config, will return None if no valid config is found
borlanic 0:fbdae7e6d805 2055 """
borlanic 0:fbdae7e6d805 2056 # If they passed in a full path
borlanic 0:fbdae7e6d805 2057 if exists(config_name):
borlanic 0:fbdae7e6d805 2058 # This is a module config
borlanic 0:fbdae7e6d805 2059 return config_name
borlanic 0:fbdae7e6d805 2060 # Otherwise find the path to configuration file based on mbed OS interface
borlanic 0:fbdae7e6d805 2061 return TestConfig.get_config_path(config_name, target_name)
borlanic 0:fbdae7e6d805 2062
borlanic 0:fbdae7e6d805 2063 def find_tests(base_dir, target_name, toolchain_name, app_config=None):
borlanic 0:fbdae7e6d805 2064 """ Finds all tests in a directory recursively
borlanic 0:fbdae7e6d805 2065 base_dir: path to the directory to scan for tests (ex. 'path/to/project')
borlanic 0:fbdae7e6d805 2066 target_name: name of the target to use for scanning (ex. 'K64F')
borlanic 0:fbdae7e6d805 2067 toolchain_name: name of the toolchain to use for scanning (ex. 'GCC_ARM')
borlanic 0:fbdae7e6d805 2068 options: Compile options to pass to the toolchain (ex. ['debug-info'])
borlanic 0:fbdae7e6d805 2069 app_config - location of a chosen mbed_app.json file
borlanic 0:fbdae7e6d805 2070
borlanic 0:fbdae7e6d805 2071 returns a dictionary where keys are the test name, and the values are
borlanic 0:fbdae7e6d805 2072 lists of paths needed to biuld the test.
borlanic 0:fbdae7e6d805 2073 """
borlanic 0:fbdae7e6d805 2074
borlanic 0:fbdae7e6d805 2075 # Temporary structure: tests referenced by (name, base, group, case) tuple
borlanic 0:fbdae7e6d805 2076 tests = {}
borlanic 0:fbdae7e6d805 2077 # List of common folders: (predicate function, path) tuple
borlanic 0:fbdae7e6d805 2078 commons = []
borlanic 0:fbdae7e6d805 2079
borlanic 0:fbdae7e6d805 2080 # Prepare the toolchain
borlanic 0:fbdae7e6d805 2081 toolchain = prepare_toolchain([base_dir], None, target_name, toolchain_name,
borlanic 0:fbdae7e6d805 2082 app_config=app_config)
borlanic 0:fbdae7e6d805 2083
borlanic 0:fbdae7e6d805 2084 # Scan the directory for paths to probe for 'TESTS' folders
borlanic 0:fbdae7e6d805 2085 base_resources = scan_resources([base_dir], toolchain)
borlanic 0:fbdae7e6d805 2086
borlanic 0:fbdae7e6d805 2087 dirs = base_resources.inc_dirs
borlanic 0:fbdae7e6d805 2088 for directory in dirs:
borlanic 0:fbdae7e6d805 2089 subdirs = os.listdir(directory)
borlanic 0:fbdae7e6d805 2090
borlanic 0:fbdae7e6d805 2091 # If the directory contains a subdirectory called 'TESTS', scan it for test cases
borlanic 0:fbdae7e6d805 2092 if 'TESTS' in subdirs:
borlanic 0:fbdae7e6d805 2093 walk_base_dir = join(directory, 'TESTS')
borlanic 0:fbdae7e6d805 2094 test_resources = toolchain.scan_resources(walk_base_dir, base_path=base_dir)
borlanic 0:fbdae7e6d805 2095
borlanic 0:fbdae7e6d805 2096 # Loop through all subdirectories
borlanic 0:fbdae7e6d805 2097 for d in test_resources.inc_dirs:
borlanic 0:fbdae7e6d805 2098
borlanic 0:fbdae7e6d805 2099 # If the test case folder is not called 'host_tests' or 'COMMON' and it is
borlanic 0:fbdae7e6d805 2100 # located two folders down from the main 'TESTS' folder (ex. TESTS/testgroup/testcase)
borlanic 0:fbdae7e6d805 2101 # then add it to the tests
borlanic 0:fbdae7e6d805 2102 relative_path = relpath(d, walk_base_dir)
borlanic 0:fbdae7e6d805 2103 relative_path_parts = os.path.normpath(relative_path).split(os.sep)
borlanic 0:fbdae7e6d805 2104 if len(relative_path_parts) == 2:
borlanic 0:fbdae7e6d805 2105 test_group_directory_path, test_case_directory = os.path.split(d)
borlanic 0:fbdae7e6d805 2106 test_group_directory = os.path.basename(test_group_directory_path)
borlanic 0:fbdae7e6d805 2107
borlanic 0:fbdae7e6d805 2108 # Check to make sure discoverd folder is not in a host test directory or common directory
borlanic 0:fbdae7e6d805 2109 special_dirs = ['host_tests', 'COMMON']
borlanic 0:fbdae7e6d805 2110 if test_group_directory not in special_dirs and test_case_directory not in special_dirs:
borlanic 0:fbdae7e6d805 2111 test_name = test_path_to_name(d, base_dir)
borlanic 0:fbdae7e6d805 2112 tests[(test_name, walk_base_dir, test_group_directory, test_case_directory)] = [d]
borlanic 0:fbdae7e6d805 2113
borlanic 0:fbdae7e6d805 2114 # Also find any COMMON paths, we'll add these later once we find all the base tests
borlanic 0:fbdae7e6d805 2115 if 'COMMON' in relative_path_parts:
borlanic 0:fbdae7e6d805 2116 if relative_path_parts[0] != 'COMMON':
borlanic 0:fbdae7e6d805 2117 def predicate(base_pred, group_pred, name_base_group_case):
borlanic 0:fbdae7e6d805 2118 (name, base, group, case) = name_base_group_case
borlanic 0:fbdae7e6d805 2119 return base == base_pred and group == group_pred
borlanic 0:fbdae7e6d805 2120 commons.append((functools.partial(predicate, walk_base_dir, relative_path_parts[0]), d))
borlanic 0:fbdae7e6d805 2121 else:
borlanic 0:fbdae7e6d805 2122 def predicate(base_pred, name_base_group_case):
borlanic 0:fbdae7e6d805 2123 (name, base, group, case) = name_base_group_case
borlanic 0:fbdae7e6d805 2124 return base == base_pred
borlanic 0:fbdae7e6d805 2125 commons.append((functools.partial(predicate, walk_base_dir), d))
borlanic 0:fbdae7e6d805 2126
borlanic 0:fbdae7e6d805 2127 # Apply common directories
borlanic 0:fbdae7e6d805 2128 for pred, path in commons:
borlanic 0:fbdae7e6d805 2129 for test_identity, test_paths in tests.iteritems():
borlanic 0:fbdae7e6d805 2130 if pred(test_identity):
borlanic 0:fbdae7e6d805 2131 test_paths.append(path)
borlanic 0:fbdae7e6d805 2132
borlanic 0:fbdae7e6d805 2133 # Drop identity besides name
borlanic 0:fbdae7e6d805 2134 return {name: paths for (name, _, _, _), paths in tests.iteritems()}
borlanic 0:fbdae7e6d805 2135
borlanic 0:fbdae7e6d805 2136 def print_tests(tests, format="list", sort=True):
borlanic 0:fbdae7e6d805 2137 """Given a dictionary of tests (as returned from "find_tests"), print them
borlanic 0:fbdae7e6d805 2138 in the specified format"""
borlanic 0:fbdae7e6d805 2139 if format == "list":
borlanic 0:fbdae7e6d805 2140 for test_name in sorted(tests.keys()):
borlanic 0:fbdae7e6d805 2141 test_path = tests[test_name][0]
borlanic 0:fbdae7e6d805 2142 print("Test Case:")
borlanic 0:fbdae7e6d805 2143 print(" Name: %s" % test_name)
borlanic 0:fbdae7e6d805 2144 print(" Path: %s" % test_path)
borlanic 0:fbdae7e6d805 2145 elif format == "json":
borlanic 0:fbdae7e6d805 2146 print(json.dumps({test_name: test_path[0] for test_name, test_paths
borlanic 0:fbdae7e6d805 2147 in tests}, indent=2))
borlanic 0:fbdae7e6d805 2148 else:
borlanic 0:fbdae7e6d805 2149 print("Unknown format '%s'" % format)
borlanic 0:fbdae7e6d805 2150 sys.exit(1)
borlanic 0:fbdae7e6d805 2151
borlanic 0:fbdae7e6d805 2152 def norm_relative_path(path, start):
borlanic 0:fbdae7e6d805 2153 """This function will create a normalized, relative path. It mimics the
borlanic 0:fbdae7e6d805 2154 python os.path.relpath function, but also normalizes a Windows-syle path
borlanic 0:fbdae7e6d805 2155 that use backslashes to a Unix style path that uses forward slashes."""
borlanic 0:fbdae7e6d805 2156 path = os.path.normpath(path)
borlanic 0:fbdae7e6d805 2157 path = os.path.relpath(path, start)
borlanic 0:fbdae7e6d805 2158 path = path.replace("\\", "/")
borlanic 0:fbdae7e6d805 2159 return path
borlanic 0:fbdae7e6d805 2160
borlanic 0:fbdae7e6d805 2161
borlanic 0:fbdae7e6d805 2162 def build_test_worker(*args, **kwargs):
borlanic 0:fbdae7e6d805 2163 """This is a worker function for the parallel building of tests. The `args`
borlanic 0:fbdae7e6d805 2164 and `kwargs` are passed directly to `build_project`. It returns a dictionary
borlanic 0:fbdae7e6d805 2165 with the following structure:
borlanic 0:fbdae7e6d805 2166
borlanic 0:fbdae7e6d805 2167 {
borlanic 0:fbdae7e6d805 2168 'result': `True` if no exceptions were thrown, `False` otherwise
borlanic 0:fbdae7e6d805 2169 'reason': Instance of exception that was thrown on failure
borlanic 0:fbdae7e6d805 2170 'bin_file': Path to the created binary if `build_project` was
borlanic 0:fbdae7e6d805 2171 successful. Not present otherwise
borlanic 0:fbdae7e6d805 2172 'kwargs': The keyword arguments that were passed to `build_project`.
borlanic 0:fbdae7e6d805 2173 This includes arguments that were modified (ex. report)
borlanic 0:fbdae7e6d805 2174 }
borlanic 0:fbdae7e6d805 2175 """
borlanic 0:fbdae7e6d805 2176 bin_file = None
borlanic 0:fbdae7e6d805 2177 ret = {
borlanic 0:fbdae7e6d805 2178 'result': False,
borlanic 0:fbdae7e6d805 2179 'args': args,
borlanic 0:fbdae7e6d805 2180 'kwargs': kwargs
borlanic 0:fbdae7e6d805 2181 }
borlanic 0:fbdae7e6d805 2182
borlanic 0:fbdae7e6d805 2183 # Use parent TOOLCHAIN_PATHS variable
borlanic 0:fbdae7e6d805 2184 for key, value in kwargs['toolchain_paths'].items():
borlanic 0:fbdae7e6d805 2185 TOOLCHAIN_PATHS[key] = value
borlanic 0:fbdae7e6d805 2186
borlanic 0:fbdae7e6d805 2187 del kwargs['toolchain_paths']
borlanic 0:fbdae7e6d805 2188
borlanic 0:fbdae7e6d805 2189 try:
borlanic 0:fbdae7e6d805 2190 bin_file = build_project(*args, **kwargs)
borlanic 0:fbdae7e6d805 2191 ret['result'] = True
borlanic 0:fbdae7e6d805 2192 ret['bin_file'] = bin_file
borlanic 0:fbdae7e6d805 2193 ret['kwargs'] = kwargs
borlanic 0:fbdae7e6d805 2194
borlanic 0:fbdae7e6d805 2195 except NotSupportedException as e:
borlanic 0:fbdae7e6d805 2196 ret['reason'] = e
borlanic 0:fbdae7e6d805 2197 except ToolException as e:
borlanic 0:fbdae7e6d805 2198 ret['reason'] = e
borlanic 0:fbdae7e6d805 2199 except KeyboardInterrupt as e:
borlanic 0:fbdae7e6d805 2200 ret['reason'] = e
borlanic 0:fbdae7e6d805 2201 except:
borlanic 0:fbdae7e6d805 2202 # Print unhandled exceptions here
borlanic 0:fbdae7e6d805 2203 import traceback
borlanic 0:fbdae7e6d805 2204 traceback.print_exc(file=sys.stdout)
borlanic 0:fbdae7e6d805 2205
borlanic 0:fbdae7e6d805 2206 return ret
borlanic 0:fbdae7e6d805 2207
borlanic 0:fbdae7e6d805 2208
borlanic 0:fbdae7e6d805 2209 def build_tests(tests, base_source_paths, build_path, target, toolchain_name,
borlanic 0:fbdae7e6d805 2210 clean=False, notify=None, jobs=1, macros=None,
borlanic 0:fbdae7e6d805 2211 silent=False, report=None, properties=None,
borlanic 0:fbdae7e6d805 2212 continue_on_build_fail=False, app_config=None,
borlanic 0:fbdae7e6d805 2213 build_profile=None, stats_depth=None):
borlanic 0:fbdae7e6d805 2214 """Given the data structure from 'find_tests' and the typical build parameters,
borlanic 0:fbdae7e6d805 2215 build all the tests
borlanic 0:fbdae7e6d805 2216
borlanic 0:fbdae7e6d805 2217 Returns a tuple of the build result (True or False) followed by the test
borlanic 0:fbdae7e6d805 2218 build data structure"""
borlanic 0:fbdae7e6d805 2219
borlanic 0:fbdae7e6d805 2220 execution_directory = "."
borlanic 0:fbdae7e6d805 2221 base_path = norm_relative_path(build_path, execution_directory)
borlanic 0:fbdae7e6d805 2222
borlanic 0:fbdae7e6d805 2223 target_name = target.name if isinstance(target, Target) else target
borlanic 0:fbdae7e6d805 2224 cfg, _, _ = get_config(base_source_paths, target_name, toolchain_name, app_config=app_config)
borlanic 0:fbdae7e6d805 2225
borlanic 0:fbdae7e6d805 2226 baud_rate = 9600
borlanic 0:fbdae7e6d805 2227 if 'platform.stdio-baud-rate' in cfg:
borlanic 0:fbdae7e6d805 2228 baud_rate = cfg['platform.stdio-baud-rate'].value
borlanic 0:fbdae7e6d805 2229
borlanic 0:fbdae7e6d805 2230 test_build = {
borlanic 0:fbdae7e6d805 2231 "platform": target_name,
borlanic 0:fbdae7e6d805 2232 "toolchain": toolchain_name,
borlanic 0:fbdae7e6d805 2233 "base_path": base_path,
borlanic 0:fbdae7e6d805 2234 "baud_rate": baud_rate,
borlanic 0:fbdae7e6d805 2235 "binary_type": "bootable",
borlanic 0:fbdae7e6d805 2236 "tests": {}
borlanic 0:fbdae7e6d805 2237 }
borlanic 0:fbdae7e6d805 2238
borlanic 0:fbdae7e6d805 2239 result = True
borlanic 0:fbdae7e6d805 2240
borlanic 0:fbdae7e6d805 2241 jobs_count = int(jobs if jobs else cpu_count())
borlanic 0:fbdae7e6d805 2242 p = Pool(processes=jobs_count)
borlanic 0:fbdae7e6d805 2243 results = []
borlanic 0:fbdae7e6d805 2244 for test_name, test_paths in tests.items():
borlanic 0:fbdae7e6d805 2245 if not isinstance(test_paths, list):
borlanic 0:fbdae7e6d805 2246 test_paths = [test_paths]
borlanic 0:fbdae7e6d805 2247
borlanic 0:fbdae7e6d805 2248 test_build_path = os.path.join(build_path, test_paths[0])
borlanic 0:fbdae7e6d805 2249 src_paths = base_source_paths + test_paths
borlanic 0:fbdae7e6d805 2250 bin_file = None
borlanic 0:fbdae7e6d805 2251 test_case_folder_name = os.path.basename(test_paths[0])
borlanic 0:fbdae7e6d805 2252
borlanic 0:fbdae7e6d805 2253 args = (src_paths, test_build_path, target, toolchain_name)
borlanic 0:fbdae7e6d805 2254 kwargs = {
borlanic 0:fbdae7e6d805 2255 'jobs': 1,
borlanic 0:fbdae7e6d805 2256 'clean': clean,
borlanic 0:fbdae7e6d805 2257 'macros': macros,
borlanic 0:fbdae7e6d805 2258 'name': test_case_folder_name,
borlanic 0:fbdae7e6d805 2259 'project_id': test_name,
borlanic 0:fbdae7e6d805 2260 'report': report,
borlanic 0:fbdae7e6d805 2261 'properties': properties,
borlanic 0:fbdae7e6d805 2262 'app_config': app_config,
borlanic 0:fbdae7e6d805 2263 'build_profile': build_profile,
borlanic 0:fbdae7e6d805 2264 'toolchain_paths': TOOLCHAIN_PATHS,
borlanic 0:fbdae7e6d805 2265 'stats_depth': stats_depth,
borlanic 0:fbdae7e6d805 2266 'notify': MockNotifier()
borlanic 0:fbdae7e6d805 2267 }
borlanic 0:fbdae7e6d805 2268
borlanic 0:fbdae7e6d805 2269 results.append(p.apply_async(build_test_worker, args, kwargs))
borlanic 0:fbdae7e6d805 2270
borlanic 0:fbdae7e6d805 2271 p.close()
borlanic 0:fbdae7e6d805 2272 result = True
borlanic 0:fbdae7e6d805 2273 itr = 0
borlanic 0:fbdae7e6d805 2274 while len(results):
borlanic 0:fbdae7e6d805 2275 itr += 1
borlanic 0:fbdae7e6d805 2276 if itr > 360000:
borlanic 0:fbdae7e6d805 2277 p.terminate()
borlanic 0:fbdae7e6d805 2278 p.join()
borlanic 0:fbdae7e6d805 2279 raise ToolException("Compile did not finish in 10 minutes")
borlanic 0:fbdae7e6d805 2280 else:
borlanic 0:fbdae7e6d805 2281 sleep(0.01)
borlanic 0:fbdae7e6d805 2282 pending = 0
borlanic 0:fbdae7e6d805 2283 for r in results:
borlanic 0:fbdae7e6d805 2284 if r.ready() is True:
borlanic 0:fbdae7e6d805 2285 try:
borlanic 0:fbdae7e6d805 2286 worker_result = r.get()
borlanic 0:fbdae7e6d805 2287 results.remove(r)
borlanic 0:fbdae7e6d805 2288
borlanic 0:fbdae7e6d805 2289 # Push all deferred notifications out to the actual notifier
borlanic 0:fbdae7e6d805 2290 new_notify = deepcopy(notify)
borlanic 0:fbdae7e6d805 2291 for message in worker_result['kwargs']['notify'].messages:
borlanic 0:fbdae7e6d805 2292 new_notify.notify(message)
borlanic 0:fbdae7e6d805 2293
borlanic 0:fbdae7e6d805 2294 # Take report from the kwargs and merge it into existing report
borlanic 0:fbdae7e6d805 2295 if report:
borlanic 0:fbdae7e6d805 2296 report_entry = worker_result['kwargs']['report'][target_name][toolchain_name]
borlanic 0:fbdae7e6d805 2297 report_entry[worker_result['kwargs']['project_id'].upper()][0][0]['output'] = new_notify.get_output()
borlanic 0:fbdae7e6d805 2298 for test_key in report_entry.keys():
borlanic 0:fbdae7e6d805 2299 report[target_name][toolchain_name][test_key] = report_entry[test_key]
borlanic 0:fbdae7e6d805 2300
borlanic 0:fbdae7e6d805 2301 # Set the overall result to a failure if a build failure occurred
borlanic 0:fbdae7e6d805 2302 if ('reason' in worker_result and
borlanic 0:fbdae7e6d805 2303 not worker_result['reason'] and
borlanic 0:fbdae7e6d805 2304 not isinstance(worker_result['reason'], NotSupportedException)):
borlanic 0:fbdae7e6d805 2305 result = False
borlanic 0:fbdae7e6d805 2306 break
borlanic 0:fbdae7e6d805 2307
borlanic 0:fbdae7e6d805 2308
borlanic 0:fbdae7e6d805 2309 # Adding binary path to test build result
borlanic 0:fbdae7e6d805 2310 if ('result' in worker_result and
borlanic 0:fbdae7e6d805 2311 worker_result['result'] and
borlanic 0:fbdae7e6d805 2312 'bin_file' in worker_result):
borlanic 0:fbdae7e6d805 2313 bin_file = norm_relative_path(worker_result['bin_file'], execution_directory)
borlanic 0:fbdae7e6d805 2314
borlanic 0:fbdae7e6d805 2315 test_build['tests'][worker_result['kwargs']['project_id']] = {
borlanic 0:fbdae7e6d805 2316 "binaries": [
borlanic 0:fbdae7e6d805 2317 {
borlanic 0:fbdae7e6d805 2318 "path": bin_file
borlanic 0:fbdae7e6d805 2319 }
borlanic 0:fbdae7e6d805 2320 ]
borlanic 0:fbdae7e6d805 2321 }
borlanic 0:fbdae7e6d805 2322
borlanic 0:fbdae7e6d805 2323 test_key = worker_result['kwargs']['project_id'].upper()
borlanic 0:fbdae7e6d805 2324 print('Image: %s\n' % bin_file)
borlanic 0:fbdae7e6d805 2325
borlanic 0:fbdae7e6d805 2326 except:
borlanic 0:fbdae7e6d805 2327 if p._taskqueue.queue:
borlanic 0:fbdae7e6d805 2328 p._taskqueue.queue.clear()
borlanic 0:fbdae7e6d805 2329 sleep(0.5)
borlanic 0:fbdae7e6d805 2330 p.terminate()
borlanic 0:fbdae7e6d805 2331 p.join()
borlanic 0:fbdae7e6d805 2332 raise
borlanic 0:fbdae7e6d805 2333 else:
borlanic 0:fbdae7e6d805 2334 pending += 1
borlanic 0:fbdae7e6d805 2335 if pending >= jobs_count:
borlanic 0:fbdae7e6d805 2336 break
borlanic 0:fbdae7e6d805 2337
borlanic 0:fbdae7e6d805 2338 # Break as soon as possible if there is a failure and we are not
borlanic 0:fbdae7e6d805 2339 # continuing on build failures
borlanic 0:fbdae7e6d805 2340 if not result and not continue_on_build_fail:
borlanic 0:fbdae7e6d805 2341 if p._taskqueue.queue:
borlanic 0:fbdae7e6d805 2342 p._taskqueue.queue.clear()
borlanic 0:fbdae7e6d805 2343 sleep(0.5)
borlanic 0:fbdae7e6d805 2344 p.terminate()
borlanic 0:fbdae7e6d805 2345 break
borlanic 0:fbdae7e6d805 2346
borlanic 0:fbdae7e6d805 2347 p.join()
borlanic 0:fbdae7e6d805 2348
borlanic 0:fbdae7e6d805 2349 test_builds = {}
borlanic 0:fbdae7e6d805 2350 test_builds["%s-%s" % (target_name, toolchain_name)] = test_build
borlanic 0:fbdae7e6d805 2351
borlanic 0:fbdae7e6d805 2352 return result, test_builds
borlanic 0:fbdae7e6d805 2353
borlanic 0:fbdae7e6d805 2354
borlanic 0:fbdae7e6d805 2355 def test_spec_from_test_builds(test_builds):
borlanic 0:fbdae7e6d805 2356 return {
borlanic 0:fbdae7e6d805 2357 "builds": test_builds
borlanic 0:fbdae7e6d805 2358 }