-
Notifications
You must be signed in to change notification settings - Fork 44
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #78 from ARMmbed/devel_transport
[devel_transport] Async host test execition support Road to version 0.2.0.
- Loading branch information
Showing
12 changed files
with
979 additions
and
504 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
""" | ||
mbed SDK | ||
Copyright (c) 2011-2016 ARM Limited | ||
Licensed under the Apache License, Version 2.0 (the "License"); | ||
you may not use this file except in compliance with the License. | ||
You may obtain a copy of the License at | ||
http://www.apache.org/licenses/LICENSE-2.0 | ||
Unless required by applicable law or agreed to in writing, software | ||
distributed under the License is distributed on an "AS IS" BASIS, | ||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
See the License for the specific language governing permissions and | ||
limitations under the License. | ||
Author: Przemyslaw Wirkus <[email protected]> | ||
""" | ||
|
||
import os | ||
|
||
""" | ||
def __default_coverage_start_callback(self, key, value, timestamp): | ||
# {{__coverage_start;PATH;PAYLOAD}} | ||
# PAYLAODED is HEX coded string | ||
lcov_path, lcov_payload = value.split(';') | ||
try: | ||
bin_payload = coverage_pack_hex_payload(lcov_payload) | ||
coverage_dump_file(lcov_path, bin_payload) | ||
self.log("dumped %d bytes to '%s'"% (len(bin_payload), lcov_path)) | ||
except Exception as e: | ||
self.log("LCOV:" + str(e)) | ||
""" | ||
|
||
def coverage_pack_hex_payload(payload): | ||
"""! Convert a block of hex string data back to binary and return the binary data | ||
@param payload String with hex encoded ascii data, e.g.: '6164636772...' | ||
@return bytearray with payload with data | ||
""" | ||
# This payload might be packed with dot compression | ||
# where byte value 0x00 is coded as ".", and not as "00" | ||
payload = payload.replace('.', '00') | ||
|
||
hex_pairs = map(''.join, zip(*[iter(payload)] * 2)) # ['61', '64', '63', '67', '72', ... ] | ||
bin_payload = bytearray([int(s, 16) for s in hex_pairs]) | ||
return bin_payload | ||
|
||
def coverage_dump_file(path, payload): | ||
"""! Creates file and dumps payload to it on specified path (even if path doesn't exist) | ||
@param path Path to file | ||
@param payload Binary data to store in a file | ||
@return True if operation was completed | ||
""" | ||
result = True | ||
try: | ||
d = os.path.dirname(path) | ||
if not os.path.exists(d): | ||
os.makedirs(d) | ||
with open(path, "wb") as f: | ||
f.write(payload) | ||
except IOError as e: | ||
print str(e) | ||
result = False | ||
return result |
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,175 @@ | ||
""" | ||
mbed SDK | ||
Copyright (c) 2011-2015 ARM Limited | ||
Licensed under the Apache License, Version 2.0 (the "License"); | ||
you may not use this file except in compliance with the License. | ||
You may obtain a copy of the License at | ||
http://www.apache.org/licenses/LICENSE-2.0 | ||
Unless required by applicable law or agreed to in writing, software | ||
distributed under the License is distributed on an "AS IS" BASIS, | ||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
See the License for the specific language governing permissions and | ||
limitations under the License. | ||
Author: Przemyslaw Wirkus <[email protected]> | ||
""" | ||
|
||
import re | ||
import json | ||
from subprocess import Popen, PIPE | ||
from mbed_greentea.mbed_greentea_log import gt_logger | ||
|
||
""" | ||
List of available hooks: | ||
""" | ||
|
||
|
||
class GreenteaTestHook(): | ||
"""! Class used to define | ||
""" | ||
name = None | ||
|
||
def __init__(self, name): | ||
self.name = name | ||
|
||
def run(self, format=None): | ||
pass | ||
|
||
class GreenteaCliTestHook(GreenteaTestHook): | ||
"""! Class used to define a hook which will call command line program | ||
""" | ||
cmd = None | ||
|
||
def __init__(self, name, cmd): | ||
GreenteaTestHook.__init__(self, name) | ||
self.cmd = cmd | ||
|
||
def run_cli_process(self, cmd): | ||
"""! Runs command as a process and return stdout, stderr and ret code | ||
@param cmd Command to execute | ||
@return Tuple of (stdout, stderr, returncode) | ||
""" | ||
_stdout, _stderr, ret = None, None, -1 | ||
try: | ||
p = Popen(cmd, stdout=PIPE, stderr=PIPE, shell=True) | ||
_stdout, _stderr = p.communicate() | ||
ret = p.returncode | ||
except OSError as e: | ||
gt_logger.gt_log_err(str(e)) | ||
ret = -1 | ||
return _stdout, _stderr, ret | ||
|
||
def run(self, format=None): | ||
"""! Runs hook after command is formated with in-place {tags} | ||
@format Pass format dictionary to replace hook {tags} with real values | ||
@param format Used to format string with cmd, notation used is e.g: {build_name} | ||
""" | ||
gt_logger.gt_log("hook '%s' execution"% self.name) | ||
cmd = self.format_before_run(self.cmd, format) | ||
gt_logger.gt_log_tab("hook command: %s"% cmd) | ||
(_stdout, _stderr, ret) = self.run_cli_process(cmd) | ||
if _stdout: | ||
print _stdout | ||
if ret: | ||
gt_logger.gt_log_err("hook exited with error: %d, dumping stderr..."% ret) | ||
print _stderr | ||
return ret | ||
|
||
@staticmethod | ||
def format_before_run(cmd, format, verbose=False): | ||
if format: | ||
# We will expand first | ||
cmd_expand = GreenteaCliTestHook.expand_parameters(cmd, format) | ||
if cmd_expand: | ||
cmd = cmd_expand | ||
if verbose: | ||
gt_logger.gt_log_tab("hook expanded: %s"% cmd) | ||
|
||
cmd = cmd.format(**format) | ||
if verbose: | ||
gt_logger.gt_log_tab("hook formated: %s"% cmd) | ||
return cmd | ||
|
||
@staticmethod | ||
def expand_parameters(expr, expandables, delimiter=' '): | ||
"""! Expands lists for multiple parameters in hook command | ||
@param expr Expression to expand | ||
@param expandables Dictionary of token: list_to_expand See details for more info | ||
@param delimiter Delimiter used to combine expanded strings, space by default | ||
@details | ||
test_name_list = ['mbed-drivers-test-basic', 'mbed-drivers-test-hello', 'mbed-drivers-test-time_us'] | ||
build_path_list = ['./build/frdm-k64f-gcc', './build/frdm-k64f-armcc'] | ||
expandables = { | ||
"{test_name_list}": test_name_list, | ||
"{build_path_list}": build_path_list | ||
} | ||
expr = "lcov --gcov-tool arm-none-eabi-gcov [-a {build_path_list}/test/{test_name_list}.info] --output-file result.info" | ||
'expr' expression [-a {build_path_list}/test/{test_name_list}.info] will expand to: | ||
[ | ||
"-a ./build/frdm-k64f-gcc/test/mbed-drivers-test-basic.info", | ||
"-a ./build/frdm-k64f-armcc/test/mbed-drivers-test-basic.info", | ||
"-a ./build/frdm-k64f-gcc/test/mbed-drivers-test-hello.info", | ||
"-a ./build/frdm-k64f-armcc/test/mbed-drivers-test-hello.info", | ||
"-a ./build/frdm-k64f-gcc/test/mbed-drivers-test-time_us.info", | ||
"-a ./build/frdm-k64f-armcc/test/mbed-drivers-test-time_us.info" | ||
] | ||
""" | ||
result = None | ||
if expandables: | ||
expansion_result = [] | ||
m = re.search('\[.*?\]', expr) | ||
if m: | ||
expr_str_orig = m.group(0) | ||
expr_str_base = m.group(0)[1:-1] | ||
expr_str_list = [expr_str_base] | ||
for token in expandables: | ||
# We will expand only values which are lists (of strings) | ||
if type(expandables[token]) is list: | ||
# Use tokens with curly braces (Python string format like) | ||
format_token = '{' + token + '}' | ||
for expr_str in expr_str_list: | ||
if format_token in expr_str: | ||
patterns = expandables[token] | ||
for pattern in patterns: | ||
s = expr_str | ||
s = s.replace(format_token, pattern) | ||
expr_str_list.append(s) | ||
# Nothing to extend/change in this string | ||
if not any('{' + p + '}' in s for p in expandables.keys() if type(expandables[p]) is list): | ||
expansion_result.append(s) | ||
expansion_result.sort() | ||
result = expr.replace(expr_str_orig, delimiter.join(expansion_result)) | ||
return result | ||
|
||
class GreenteaHooks(): | ||
"""! Class used to store all hooks | ||
@details Hooks command starts with '$' dollar sign | ||
""" | ||
HOOKS = {} | ||
def __init__(self, path_to_hooks): | ||
"""! Opens JSON file with | ||
""" | ||
try: | ||
with open(path_to_hooks, 'r') as data_file: | ||
hooks = json.load(data_file) | ||
if 'hooks' in hooks: | ||
for hook in hooks['hooks']: | ||
hook_name = hook | ||
hook_expression = hooks['hooks'][hook] | ||
# This is a command line hook | ||
if hook_expression.startswith('$'): | ||
self.HOOKS[hook_name] = GreenteaCliTestHook(hook_name, hook_expression[1:]) | ||
except IOError as e: | ||
print str(e) | ||
self.HOOKS = None | ||
|
||
def is_hooked_to(self, hook_name): | ||
return hook_name in self.HOOKS | ||
|
||
def run_hook(self, hook_name, format): | ||
if hook_name in self.HOOKS: | ||
return self.HOOKS[hook_name].run(format) | ||
|
||
def run_hook_ext(self, hook_name, format): | ||
if self.is_hooked_to(hook_name): | ||
# We can execute this test hook just after all tests are finished ('hook_post_test_end') | ||
self.run_hook(hook_name, format) |
Oops, something went wrong.