From 2d5ed417561c1593dfd605b924bbdbf1d0486610 Mon Sep 17 00:00:00 2001 From: Hakkyu Kim Date: Fri, 27 Aug 2021 17:28:47 +0900 Subject: [PATCH 1/8] Add recipe arg --- tools/commands/integration_test.py | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/tools/commands/integration_test.py b/tools/commands/integration_test.py index b2104a6ef..9cae26192 100755 --- a/tools/commands/integration_test.py +++ b/tools/commands/integration_test.py @@ -22,6 +22,9 @@ import sys import time +# (TODO: HakkyuKim) Install dependency with pip. +import yaml + import commands.command_utils as command_utils _TERM_RED = '\033[1;31m' @@ -56,6 +59,20 @@ def fail(cls, errors=[]): def parse_args(args): parser = command_utils.get_options_parser( plugins=True, exclude=True, run_on_changed_packages=True, base_sha=True, timeout=True, command='test') + parser.add_argument( + '--recipe', + type=str, + default='', + help=''' +The recipe file path. A recipe refers to a yaml file that defines a list of test targets plugins. +If --recipe is specified, --plugins, --exclude, --run-on-changed-packages, and --base-sha options are ignored. +( +plugins: + a: [wearable-5.5, tv-6.0] + b: [mobile-6.0] + c: [wearable-4.0] +) +''') return parser.parse_args(args) @@ -167,6 +184,18 @@ def _integration_test(plugin_dir, timeout): def run_integration_test(argv): args = parse_args(argv) + + test_targets = {} + if args.recipe: + if not os.path.isfile(args.recipe): + # (TODO: HakkyuKim) Print error log here. + exit(1) + with open(args.recipe) as f: + # (TODO: HakkyuKim) Validate yaml format here. + test_targets = yaml.load( + f.read(), Loader=yaml.FullLoader)['plugins'] + args.plugins = list(test_targets.keys()) + packages_dir = command_utils.get_package_dir() testing_plugins, excluded_plugins = command_utils.get_target_plugins( packages_dir, plugins=args.plugins, exclude=args.exclude, run_on_changed_packages=args.run_on_changed_packages, From 2d2a12a7301f75f89df7a213fd8486b48b9d8c47 Mon Sep 17 00:00:00 2001 From: Hakkyu Kim Date: Fri, 27 Aug 2021 17:36:36 +0900 Subject: [PATCH 2/8] Return list of TestResults --- tools/commands/integration_test.py | 180 +++++++++++++++++------------ 1 file changed, 106 insertions(+), 74 deletions(-) diff --git a/tools/commands/integration_test.py b/tools/commands/integration_test.py index 9cae26192..2e2e75ef2 100755 --- a/tools/commands/integration_test.py +++ b/tools/commands/integration_test.py @@ -43,17 +43,19 @@ class TestResult: details: A list of details about the test result. (e.g. reasons for failure.) """ - def __init__(self, run_state, details=[]): + def __init__(self, plugin_name, run_state, test_target='', details=[]): + self.plugin_name = plugin_name + self.test_target = test_target self.run_state = run_state self.details = details @classmethod - def success(cls): - return cls('succeeded') + def success(cls, plugin_name, test_target): + return cls(plugin_name, 'succeeded', test_target=test_target) @classmethod - def fail(cls, errors=[]): - return cls('failed', details=errors) + def fail(cls, plugin_name, test_target, errors=[]): + return cls(plugin_name, 'failed', test_target=test_target, details=errors) def parse_args(args): @@ -77,36 +79,43 @@ def parse_args(args): return parser.parse_args(args) -def _integration_test(plugin_dir, timeout): +def _integration_test(plugin_dir, test_targets, timeout): """Runs integration test in the example package for plugin_dir Currently the tools assumes that there's only one example package per plugin. Args: plugin_dir (str): The path to a single plugin directory. + test_targets (List[str]): A list of testing targets. timeout (int): Time limit in seconds before cancelling the test. Returns: TestResult: The result of the plugin integration test. """ + plugin_name = os.path.basename(plugin_dir) + + if not test_targets: + # (TODO: HakkyuKim) Get default test target + return [TestResult.fail(plugin_name, errors=['Test target not specified.'])] + example_dir = os.path.join(plugin_dir, 'example') if not os.path.isdir(example_dir): - return TestResult.fail([ + return [TestResult.fail(plugin_name, errors=[ 'Missing example directory (use --exclude if this is intentional).' - ]) + ])] pubspec_path = os.path.join(example_dir, 'pubspec') if not os.path.isfile(f'{pubspec_path}.yaml') and not os.path.isfile( f'{pubspec_path}.yml'): # TODO: Support multiple example packages. - return TestResult.fail(['Missing pubspec file in example directory']) + return [TestResult.fail(plugin_name, errors=['Missing pubspec file in example directory'])] integration_test_dir = os.path.join(example_dir, 'integration_test') if not os.path.isdir(integration_test_dir) or not os.listdir( integration_test_dir): - return TestResult.fail([ + return [TestResult.fail(plugin_name, errors=[ 'Missing integration tests (use --exclude if this is intentional).' - ]) + ])] errors = [] completed_process = subprocess.run('flutter-tizen pub get', @@ -120,66 +129,85 @@ def _integration_test(plugin_dir, timeout): in your project is valid.') else: errors.append(completed_process.stderr) - return TestResult.fail(errors) - - is_timed_out = False - process = subprocess.Popen('flutter-tizen test integration_test', - shell=True, - cwd=example_dir, - universal_newlines=True, - stderr=subprocess.PIPE, - stdout=subprocess.PIPE) - last_line = '' - start = time.time() - for line in process.stdout: - match = re.search(_LOG_PATTERN, line) - last_match = re.search(_LOG_PATTERN, last_line) - if match and last_match and last_match.group(2) == match.group(2): - sys.stdout.write(f'\r{line.strip()}') - else: - sys.stdout.write(f'\n{line.strip()}') + return [TestResult.fail(plugin_name, errors=errors)] + + test_results = [] + target_table = {} + + for test_target in test_targets: + if test_target not in target_table: + test_results.append(TestResult.fail(plugin_name, test_target, [ + f'Test target {test_target} not available in test server.'])) + continue + + is_timed_out = False + process = subprocess.Popen('flutter-tizen test integration_test', + shell=True, + cwd=example_dir, + universal_newlines=True, + stderr=subprocess.PIPE, + stdout=subprocess.PIPE) + last_line = '' + start = time.time() + for line in process.stdout: + match = re.search(_LOG_PATTERN, line) + last_match = re.search(_LOG_PATTERN, last_line) + if match and last_match and last_match.group(2) == match.group(2): + sys.stdout.write(f'\r{line.strip()}') + else: + sys.stdout.write(f'\n{line.strip()}') + sys.stdout.flush() + last_line = line + if time.time() - start > timeout: + process.kill() + is_timed_out = True + break + sys.stdout.write('\n') sys.stdout.flush() - last_line = line - if time.time() - start > timeout: - process.kill() - is_timed_out = True - break - sys.stdout.write('\n') - sys.stdout.flush() - process.wait() - - if is_timed_out: - errors.append("""Timeout expired. The test may need more time to finish. -If you expect the test to finish before timeout, check if the tests -require device screen to be awake or if they require manually -clicking the UI button for permissions.""") - return TestResult.fail(errors) - if last_line.strip() == 'No tests ran.': - return TestResult.fail(['No tests ran.']) - elif last_line.strip().startswith('No devices found'): - return TestResult.fail([ - 'The runner cannot find any devices to run tests. Check if the hosted test server has connections to Tizen devices.' - ]) - - match = re.search(_LOG_PATTERN, last_line.strip()) - if not match: - return TestResult.fail(['Log message is not formatted correctly.']) - - # In some cases, the command returns 0 for failed cases, so we check again - # with the last log message. - exit_code = process.returncode - if match.group(2) == 'All tests passed!': - exit_code = 0 - elif match.group(2) == 'Some tests failed.': - errors.append( - 'flutter-tizen test integration_test failed, see the output above for details.' - ) - exit_code = 1 + process.wait() + + if is_timed_out: + errors.append("""Timeout expired. The test may need more time to finish. + If you expect the test to finish before timeout, check if the tests + require device screen to be awake or if they require manually + clicking the UI button for permissions.""") + test_results.append(TestResult.fail( + plugin_name, test_target, errors=errors)) + continue + if last_line.strip() == 'No tests ran.': + test_results.append(TestResult.fail( + plugin_name, test_target, ['No tests ran.'])) + continue + elif last_line.strip().startswith('No devices found'): + test_results.append(TestResult.fail(plugin_name, test_target, [ + 'The runner cannot find any devices to run tests. Check if the hosted test server has connections to Tizen devices.' + ])) + continue + + match = re.search(_LOG_PATTERN, last_line.strip()) + if not match: + test_results.append(TestResult.fail(plugin_name, test_target, + ['Log message is not formatted correctly.'])) + continue + + # In some cases, the command returns 0 for failed cases, so we check again + # with the last log message. + exit_code = process.returncode + if match.group(2) == 'All tests passed!': + exit_code = 0 + elif match.group(2) == 'Some tests failed.': + errors.append( + 'flutter-tizen test integration_test failed, see the output above for details.' + ) + exit_code = 1 + + if exit_code == 0: + test_results.append(TestResult.success(plugin_name, test_target)) + else: + test_results.append(TestResult.fail( + plugin_name, test_target, errors=errors)) - if exit_code == 0: - return TestResult.success() - else: - return TestResult.fail(errors) + return test_results def run_integration_test(argv): @@ -203,24 +231,28 @@ def run_integration_test(argv): test_num = 0 total_plugin_num = len(testing_plugins) - results = {} + results = [] for testing_plugin in testing_plugins: test_num += 1 print( f'============= Testing for {testing_plugin} ({test_num}/{total_plugin_num}) =============' ) - results[testing_plugin] = _integration_test( - os.path.join(packages_dir, testing_plugin), args.timeout) + test_targets_list = [] + if testing_plugin in test_targets: + test_targets_list = test_targets[testing_plugin] + + results.extend(_integration_test( + os.path.join(packages_dir, testing_plugin), test_targets_list, args.timeout)) print(f'============= TEST RESULT =============') failed_plugins = [] - for testing_plugin, result in results.items(): + for result in results: color = _TERM_GREEN if result.run_state == 'failed': color = _TERM_RED print( - f'{color}{result.run_state.upper()}: {testing_plugin}{_TERM_EMPTY}') + f'{color}{result.run_state.upper()}: {result.plugin_name} {result.test_target}{_TERM_EMPTY}') if result.run_state != 'succeeded': for detail in result.details: print(f'{detail}') From ed4610ca2eac849bd27e0840e269e0f50fb370a8 Mon Sep 17 00:00:00 2001 From: Hakkyu Kim Date: Fri, 27 Aug 2021 17:40:49 +0900 Subject: [PATCH 3/8] Parse and match target ids to recipe inputs --- tools/commands/integration_test.py | 53 ++++++++++++++++++++++++++---- 1 file changed, 46 insertions(+), 7 deletions(-) diff --git a/tools/commands/integration_test.py b/tools/commands/integration_test.py index 2e2e75ef2..94180f8d8 100755 --- a/tools/commands/integration_test.py +++ b/tools/commands/integration_test.py @@ -132,7 +132,7 @@ def _integration_test(plugin_dir, test_targets, timeout): return [TestResult.fail(plugin_name, errors=errors)] test_results = [] - target_table = {} + target_table = _get_target_table() for test_target in test_targets: if test_target not in target_table: @@ -141,12 +141,12 @@ def _integration_test(plugin_dir, test_targets, timeout): continue is_timed_out = False - process = subprocess.Popen('flutter-tizen test integration_test', - shell=True, - cwd=example_dir, - universal_newlines=True, - stderr=subprocess.PIPE, - stdout=subprocess.PIPE) + process = subprocess.Popen(f'flutter-tizen -d {target_table[test_target]} test integration_test', + shell=True, + cwd=example_dir, + universal_newlines=True, + stderr=subprocess.PIPE, + stdout=subprocess.PIPE) last_line = '' start = time.time() for line in process.stdout: @@ -210,6 +210,45 @@ def _integration_test(plugin_dir, test_targets, timeout): return test_results +def _get_target_table(): + + def _parse_target_info(capability_info: str): + capability_info.rstrip() + profile_name = '' + platform_version = '' + for line in capability_info.split('\n'): + tokens = line.split(':') + if(tokens[0] == 'profile_name'): + profile_name = tokens[1] + elif(tokens[0] == 'platform_version'): + platform_version = tokens[1] + # (TODO: HakkyuKim) Handle empty values here. + return profile_name, platform_version + + completed_process = subprocess.run('sdb devices', + shell=True, + cwd='.', + universal_newlines=True, + stderr=subprocess.PIPE, + stdout=subprocess.PIPE) + + table = {} + if completed_process.returncode == 0: + lines = completed_process.stdout.rstrip().split('\n') + for line in lines[1:]: + id = line.split(' ')[0] + completed_process = subprocess.run(f'sdb -s {id} capability', + shell=True, + cwd='.', + universal_newlines=True, + stderr=subprocess.PIPE, + stdout=subprocess.PIPE) + profile, platform_version = _parse_target_info( + completed_process.stdout) + table[f'{profile}-{platform_version}'] = id + return table + + def run_integration_test(argv): args = parse_args(argv) From 5d8c02935db7fdc7becc16e54bbc9225318659f0 Mon Sep 17 00:00:00 2001 From: Hakkyu Kim Date: Wed, 1 Sep 2021 14:01:46 +0900 Subject: [PATCH 4/8] Handle error cases and add requirements.txt Also remove the word "server" from log messages. --- tools/commands/integration_test.py | 30 ++++++++++++++++++++---------- tools/commands/requirements.txt | 1 + 2 files changed, 21 insertions(+), 10 deletions(-) create mode 100644 tools/commands/requirements.txt diff --git a/tools/commands/integration_test.py b/tools/commands/integration_test.py index 94180f8d8..109a8ff36 100755 --- a/tools/commands/integration_test.py +++ b/tools/commands/integration_test.py @@ -22,7 +22,6 @@ import sys import time -# (TODO: HakkyuKim) Install dependency with pip. import yaml import commands.command_utils as command_utils @@ -34,6 +33,7 @@ _LOG_PATTERN = r'\d\d:\d\d\s+([(\+\d+\s+)|(~\d+\s+)|(\-\d+\s+)]+):\s+(.*)' +_DEFAULT_TEST_TARGET = 'wearable-5.5' class TestResult: """A class that specifies the result of a plugin integration test. @@ -95,8 +95,8 @@ def _integration_test(plugin_dir, test_targets, timeout): plugin_name = os.path.basename(plugin_dir) if not test_targets: - # (TODO: HakkyuKim) Get default test target - return [TestResult.fail(plugin_name, errors=['Test target not specified.'])] + # (TODO: HakkyuKim) Improve logic for setting default targets. + test_targets.append(_DEFAULT_TEST_TARGET) example_dir = os.path.join(plugin_dir, 'example') if not os.path.isdir(example_dir): @@ -137,7 +137,7 @@ def _integration_test(plugin_dir, test_targets, timeout): for test_target in test_targets: if test_target not in target_table: test_results.append(TestResult.fail(plugin_name, test_target, [ - f'Test target {test_target} not available in test server.'])) + f'Test runner cannot find target {test_target}.'])) continue is_timed_out = False @@ -180,7 +180,7 @@ def _integration_test(plugin_dir, test_targets, timeout): continue elif last_line.strip().startswith('No devices found'): test_results.append(TestResult.fail(plugin_name, test_target, [ - 'The runner cannot find any devices to run tests. Check if the hosted test server has connections to Tizen devices.' + 'The runner cannot find any devices to run tests.' ])) continue @@ -222,7 +222,6 @@ def _parse_target_info(capability_info: str): profile_name = tokens[1] elif(tokens[0] == 'platform_version'): platform_version = tokens[1] - # (TODO: HakkyuKim) Handle empty values here. return profile_name, platform_version completed_process = subprocess.run('sdb devices', @@ -245,6 +244,14 @@ def _parse_target_info(capability_info: str): stdout=subprocess.PIPE) profile, platform_version = _parse_target_info( completed_process.stdout) + if not profile or not platform_version: + print(f''' +Cannot extract {profile} or {platform_version} information from device {id} +profile: {profile} +platform_version: {platform_version} +''') + if f'{profile}-{platform_version}' in table: + print(f'Multiple targets of {profile}-{platform_version} found. Replacing {table[{profile}-{platform_version}]} to {id}...') table[f'{profile}-{platform_version}'] = id return table @@ -255,12 +262,15 @@ def run_integration_test(argv): test_targets = {} if args.recipe: if not os.path.isfile(args.recipe): - # (TODO: HakkyuKim) Print error log here. + print(f'The recipe file {args.recipe} does not exist.') exit(1) with open(args.recipe) as f: - # (TODO: HakkyuKim) Validate yaml format here. - test_targets = yaml.load( - f.read(), Loader=yaml.FullLoader)['plugins'] + try: + test_targets = yaml.load( + f.read(), Loader=yaml.FullLoader)['plugins'] + except yaml.parser.ParserError: + print(f'The recipe file {args.recipe} is not a valid yaml file.') + exit(1) args.plugins = list(test_targets.keys()) packages_dir = command_utils.get_package_dir() diff --git a/tools/commands/requirements.txt b/tools/commands/requirements.txt new file mode 100644 index 000000000..932bd69ef --- /dev/null +++ b/tools/commands/requirements.txt @@ -0,0 +1 @@ +PyYAML==5.4.1 From 6adb52cc68fbc974a327a8baff5ea1eeac4d2c0d Mon Sep 17 00:00:00 2001 From: Hakkyu Kim Date: Wed, 1 Sep 2021 14:37:45 +0900 Subject: [PATCH 5/8] Use recipe to tell the tool about testable targets --- tools/commands/integration_test.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tools/commands/integration_test.py b/tools/commands/integration_test.py index 109a8ff36..bdd19ee08 100755 --- a/tools/commands/integration_test.py +++ b/tools/commands/integration_test.py @@ -66,8 +66,8 @@ def parse_args(args): type=str, default='', help=''' -The recipe file path. A recipe refers to a yaml file that defines a list of test targets plugins. -If --recipe is specified, --plugins, --exclude, --run-on-changed-packages, and --base-sha options are ignored. +The recipe file path. A recipe refers to a yaml file that defines a list of test targets for plugins. +Passing this file will allow the tool to test with specified targets instead of the default target, wearable-5.5. ( plugins: a: [wearable-5.5, tv-6.0] @@ -271,7 +271,6 @@ def run_integration_test(argv): except yaml.parser.ParserError: print(f'The recipe file {args.recipe} is not a valid yaml file.') exit(1) - args.plugins = list(test_targets.keys()) packages_dir = command_utils.get_package_dir() testing_plugins, excluded_plugins = command_utils.get_target_plugins( From 6ceae7c4f9812b8bd15e68dcd1622085efa70f12 Mon Sep 17 00:00:00 2001 From: Hakkyu Kim Date: Wed, 1 Sep 2021 14:40:33 +0900 Subject: [PATCH 6/8] Apply yapf google style formatting --- tools/commands/integration_test.py | 124 ++++++++++++++++++----------- 1 file changed, 78 insertions(+), 46 deletions(-) diff --git a/tools/commands/integration_test.py b/tools/commands/integration_test.py index bdd19ee08..85b6fcb78 100755 --- a/tools/commands/integration_test.py +++ b/tools/commands/integration_test.py @@ -1,5 +1,4 @@ #!/usr/bin/env python3 - """A script that helps running integration tests for multiple Tizen plugins. To run integrations tests for all plugins under packages/, @@ -35,6 +34,7 @@ _DEFAULT_TEST_TARGET = 'wearable-5.5' + class TestResult: """A class that specifies the result of a plugin integration test. @@ -55,17 +55,23 @@ def success(cls, plugin_name, test_target): @classmethod def fail(cls, plugin_name, test_target, errors=[]): - return cls(plugin_name, 'failed', test_target=test_target, details=errors) + return cls(plugin_name, + 'failed', + test_target=test_target, + details=errors) def parse_args(args): - parser = command_utils.get_options_parser( - plugins=True, exclude=True, run_on_changed_packages=True, base_sha=True, timeout=True, command='test') - parser.add_argument( - '--recipe', - type=str, - default='', - help=''' + parser = command_utils.get_options_parser(plugins=True, + exclude=True, + run_on_changed_packages=True, + base_sha=True, + timeout=True, + command='test') + parser.add_argument('--recipe', + type=str, + default='', + help=''' The recipe file path. A recipe refers to a yaml file that defines a list of test targets for plugins. Passing this file will allow the tool to test with specified targets instead of the default target, wearable-5.5. ( @@ -100,22 +106,34 @@ def _integration_test(plugin_dir, test_targets, timeout): example_dir = os.path.join(plugin_dir, 'example') if not os.path.isdir(example_dir): - return [TestResult.fail(plugin_name, errors=[ - 'Missing example directory (use --exclude if this is intentional).' - ])] + return [ + TestResult.fail( + plugin_name, + errors=[ + 'Missing example directory (use --exclude if this is intentional).' + ]) + ] pubspec_path = os.path.join(example_dir, 'pubspec') if not os.path.isfile(f'{pubspec_path}.yaml') and not os.path.isfile( f'{pubspec_path}.yml'): # TODO: Support multiple example packages. - return [TestResult.fail(plugin_name, errors=['Missing pubspec file in example directory'])] + return [ + TestResult.fail( + plugin_name, + errors=['Missing pubspec file in example directory']) + ] integration_test_dir = os.path.join(example_dir, 'integration_test') if not os.path.isdir(integration_test_dir) or not os.listdir( integration_test_dir): - return [TestResult.fail(plugin_name, errors=[ - 'Missing integration tests (use --exclude if this is intentional).' - ])] + return [ + TestResult.fail( + plugin_name, + errors=[ + 'Missing integration tests (use --exclude if this is intentional).' + ]) + ] errors = [] completed_process = subprocess.run('flutter-tizen pub get', @@ -136,17 +154,20 @@ def _integration_test(plugin_dir, test_targets, timeout): for test_target in test_targets: if test_target not in target_table: - test_results.append(TestResult.fail(plugin_name, test_target, [ - f'Test runner cannot find target {test_target}.'])) + test_results.append( + TestResult.fail( + plugin_name, test_target, + [f'Test runner cannot find target {test_target}.'])) continue is_timed_out = False - process = subprocess.Popen(f'flutter-tizen -d {target_table[test_target]} test integration_test', - shell=True, - cwd=example_dir, - universal_newlines=True, - stderr=subprocess.PIPE, - stdout=subprocess.PIPE) + process = subprocess.Popen( + f'flutter-tizen -d {target_table[test_target]} test integration_test', + shell=True, + cwd=example_dir, + universal_newlines=True, + stderr=subprocess.PIPE, + stdout=subprocess.PIPE) last_line = '' start = time.time() for line in process.stdout: @@ -167,27 +188,30 @@ def _integration_test(plugin_dir, test_targets, timeout): process.wait() if is_timed_out: - errors.append("""Timeout expired. The test may need more time to finish. + errors.append( + """Timeout expired. The test may need more time to finish. If you expect the test to finish before timeout, check if the tests require device screen to be awake or if they require manually clicking the UI button for permissions.""") - test_results.append(TestResult.fail( - plugin_name, test_target, errors=errors)) + test_results.append( + TestResult.fail(plugin_name, test_target, errors=errors)) continue if last_line.strip() == 'No tests ran.': - test_results.append(TestResult.fail( - plugin_name, test_target, ['No tests ran.'])) + test_results.append( + TestResult.fail(plugin_name, test_target, ['No tests ran.'])) continue elif last_line.strip().startswith('No devices found'): - test_results.append(TestResult.fail(plugin_name, test_target, [ - 'The runner cannot find any devices to run tests.' - ])) + test_results.append( + TestResult.fail( + plugin_name, test_target, + ['The runner cannot find any devices to run tests.'])) continue match = re.search(_LOG_PATTERN, last_line.strip()) if not match: - test_results.append(TestResult.fail(plugin_name, test_target, - ['Log message is not formatted correctly.'])) + test_results.append( + TestResult.fail(plugin_name, test_target, + ['Log message is not formatted correctly.'])) continue # In some cases, the command returns 0 for failed cases, so we check again @@ -204,8 +228,8 @@ def _integration_test(plugin_dir, test_targets, timeout): if exit_code == 0: test_results.append(TestResult.success(plugin_name, test_target)) else: - test_results.append(TestResult.fail( - plugin_name, test_target, errors=errors)) + test_results.append( + TestResult.fail(plugin_name, test_target, errors=errors)) return test_results @@ -218,9 +242,9 @@ def _parse_target_info(capability_info: str): platform_version = '' for line in capability_info.split('\n'): tokens = line.split(':') - if(tokens[0] == 'profile_name'): + if (tokens[0] == 'profile_name'): profile_name = tokens[1] - elif(tokens[0] == 'platform_version'): + elif (tokens[0] == 'platform_version'): platform_version = tokens[1] return profile_name, platform_version @@ -251,7 +275,9 @@ def _parse_target_info(capability_info: str): platform_version: {platform_version} ''') if f'{profile}-{platform_version}' in table: - print(f'Multiple targets of {profile}-{platform_version} found. Replacing {table[{profile}-{platform_version}]} to {id}...') + print( + f'Multiple targets of {profile}-{platform_version} found. Replacing {table[{profile}-{platform_version}]} to {id}...' + ) table[f'{profile}-{platform_version}'] = id return table @@ -266,15 +292,19 @@ def run_integration_test(argv): exit(1) with open(args.recipe) as f: try: - test_targets = yaml.load( - f.read(), Loader=yaml.FullLoader)['plugins'] + test_targets = yaml.load(f.read(), + Loader=yaml.FullLoader)['plugins'] except yaml.parser.ParserError: - print(f'The recipe file {args.recipe} is not a valid yaml file.') + print( + f'The recipe file {args.recipe} is not a valid yaml file.') exit(1) packages_dir = command_utils.get_package_dir() testing_plugins, excluded_plugins = command_utils.get_target_plugins( - packages_dir, plugins=args.plugins, exclude=args.exclude, run_on_changed_packages=args.run_on_changed_packages, + packages_dir, + plugins=args.plugins, + exclude=args.exclude, + run_on_changed_packages=args.run_on_changed_packages, base_sha=args.base_sha) test_num = 0 @@ -289,8 +319,9 @@ def run_integration_test(argv): if testing_plugin in test_targets: test_targets_list = test_targets[testing_plugin] - results.extend(_integration_test( - os.path.join(packages_dir, testing_plugin), test_targets_list, args.timeout)) + results.extend( + _integration_test(os.path.join(packages_dir, testing_plugin), + test_targets_list, args.timeout)) print(f'============= TEST RESULT =============') failed_plugins = [] @@ -300,7 +331,8 @@ def run_integration_test(argv): color = _TERM_RED print( - f'{color}{result.run_state.upper()}: {result.plugin_name} {result.test_target}{_TERM_EMPTY}') + f'{color}{result.run_state.upper()}: {result.plugin_name} {result.test_target}{_TERM_EMPTY}' + ) if result.run_state != 'succeeded': for detail in result.details: print(f'{detail}') From 17c274c63b9f513010c4dec08818ba857c98d4e8 Mon Sep 17 00:00:00 2001 From: Hakkyu Kim Date: Thu, 2 Sep 2021 14:34:47 +0900 Subject: [PATCH 7/8] Update based on review --- tools/commands/integration_test.py | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/tools/commands/integration_test.py b/tools/commands/integration_test.py index 85b6fcb78..07447efed 100755 --- a/tools/commands/integration_test.py +++ b/tools/commands/integration_test.py @@ -68,19 +68,19 @@ def parse_args(args): base_sha=True, timeout=True, command='test') - parser.add_argument('--recipe', - type=str, - default='', - help=''' -The recipe file path. A recipe refers to a yaml file that defines a list of test targets for plugins. + parser.add_argument( + '--recipe', + type=str, + default='', + help= + '''The recipe file path. A recipe refers to a yaml file that defines a list of test targets for plugins. Passing this file will allow the tool to test with specified targets instead of the default target, wearable-5.5. ( plugins: a: [wearable-5.5, tv-6.0] b: [mobile-6.0] c: [wearable-4.0] -) -''') +)''') return parser.parse_args(args) @@ -121,7 +121,7 @@ def _integration_test(plugin_dir, test_targets, timeout): return [ TestResult.fail( plugin_name, - errors=['Missing pubspec file in example directory']) + errors=['Missing pubspec file in example directory.']) ] integration_test_dir = os.path.join(example_dir, 'integration_test') @@ -269,11 +269,10 @@ def _parse_target_info(capability_info: str): profile, platform_version = _parse_target_info( completed_process.stdout) if not profile or not platform_version: - print(f''' -Cannot extract {profile} or {platform_version} information from device {id} + print( + f'''Cannot extract profile or platform_version information from device {id}. profile: {profile} -platform_version: {platform_version} -''') +platform_version: {platform_version}''') if f'{profile}-{platform_version}' in table: print( f'Multiple targets of {profile}-{platform_version} found. Replacing {table[{profile}-{platform_version}]} to {id}...' From 5bc16b8d9c2a6848dd2679941a0baea45831c0a6 Mon Sep 17 00:00:00 2001 From: Hakkyu Kim Date: Thu, 2 Sep 2021 20:41:34 +0900 Subject: [PATCH 8/8] Remove argparse import --- tools/commands/integration_test.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tools/commands/integration_test.py b/tools/commands/integration_test.py index 07447efed..e5bd7a518 100755 --- a/tools/commands/integration_test.py +++ b/tools/commands/integration_test.py @@ -14,7 +14,6 @@ tools/run_integration_test.py --plugins a b c --exclude b # runs a c """ -import argparse import os import re import subprocess