Minos Galanakis | ea42123 | 2019-06-20 17:11:28 +0100 | [diff] [blame] | 1 | #!/usr/bin/env python3 |
| 2 | |
| 3 | """ fvp_dispatcher.py: |
| 4 | |
| 5 | Fastmodel dispatcher takes an build report input from build_helper and |
| 6 | selects the appropriate tests, lauched in separate fastmodel Wrapper |
| 7 | instances """ |
| 8 | |
| 9 | from __future__ import print_function |
| 10 | |
| 11 | __copyright__ = """ |
| 12 | /* |
Karl Zhang | 08681e6 | 2020-10-30 13:56:03 +0800 | [diff] [blame] | 13 | * Copyright (c) 2018-2020, Arm Limited. All rights reserved. |
Minos Galanakis | ea42123 | 2019-06-20 17:11:28 +0100 | [diff] [blame] | 14 | * |
| 15 | * SPDX-License-Identifier: BSD-3-Clause |
| 16 | * |
| 17 | */ |
| 18 | """ |
Karl Zhang | 08681e6 | 2020-10-30 13:56:03 +0800 | [diff] [blame] | 19 | |
| 20 | __author__ = "tf-m@lists.trustedfirmware.org" |
Minos Galanakis | ea42123 | 2019-06-20 17:11:28 +0100 | [diff] [blame] | 21 | __project__ = "Trusted Firmware-M Open CI" |
Xinyu Zhang | 06286a9 | 2021-07-22 14:00:51 +0800 | [diff] [blame] | 22 | __version__ = "1.4.0" |
Minos Galanakis | ea42123 | 2019-06-20 17:11:28 +0100 | [diff] [blame] | 23 | |
| 24 | import os |
| 25 | import sys |
| 26 | import argparse |
| 27 | from copy import deepcopy |
| 28 | from fastmodel_dispatcher_configs import fvp_config_map |
| 29 | |
| 30 | try: |
| 31 | from tfm_ci_pylib.utils import load_json, print_test, save_json, \ |
| 32 | show_progress |
| 33 | from tfm_ci_pylib.fastmodel_wrapper import FastmodelWrapper |
| 34 | from tfm_ci_pylib.tfm_build_manager import TFM_Build_Manager |
| 35 | |
| 36 | except ImportError: |
| 37 | dir_path = os.path.dirname(os.path.realpath(__file__)) |
| 38 | sys.path.append(os.path.join(dir_path, "../")) |
| 39 | from tfm_ci_pylib.utils import load_json, print_test, save_json, \ |
| 40 | show_progress |
| 41 | from tfm_ci_pylib.fastmodel_wrapper import FastmodelWrapper |
| 42 | from tfm_ci_pylib.tfm_build_manager import TFM_Build_Manager |
| 43 | |
| 44 | |
| 45 | def cfilter(config_list, match): |
| 46 | """Filter a list of items in _text1_text2_ format and only include |
| 47 | results who contain the match term between two underscores """ |
| 48 | |
| 49 | # Ensure the match has the format of _text_ |
| 50 | match = "_%s_" % match.strip("_") |
| 51 | |
| 52 | return [n for n in config_list if match in n] |
| 53 | |
| 54 | |
| 55 | def main(user_args): |
| 56 | """ Main logic """ |
| 57 | |
| 58 | test_config_list = None |
| 59 | |
| 60 | if user_args.list_cfg: |
| 61 | print("Built-in configs:") |
| 62 | print("\n".join(fvp_config_map.list())) |
| 63 | sys.exit(0) |
| 64 | elif user_args.single_cfg: |
| 65 | try: |
| 66 | # Try to fetch the config to validate it exists |
| 67 | fvp_config_map.get_config(user_args.single_cfg) |
| 68 | test_config_list = [user_args.single_cfg] |
| 69 | except Exception as e: |
| 70 | print("Error: %s" % e) |
| 71 | sys.exit(1) |
| 72 | elif user_args.build_all: |
| 73 | test_config_list = fvp_config_map.list() |
| 74 | # If a build report is provided parse it |
| 75 | elif user_args.build_report: |
| 76 | build_report = load_json(user_args.build_report) |
| 77 | |
| 78 | build_cfg = build_report["_metadata_"]["input_build_cfg"] |
| 79 | |
| 80 | # build and test configs share common key name enties |
| 81 | config_list = list(map(str.lower, |
| 82 | (map(str, build_report["report"].keys())))) |
Karl Zhang | aff558a | 2020-05-15 14:28:23 +0100 | [diff] [blame] | 83 | print("zss config_list %s" % config_list) |
Minos Galanakis | ea42123 | 2019-06-20 17:11:28 +0100 | [diff] [blame] | 84 | |
| 85 | # Only choose the tests that have been defined in the map |
| 86 | test_config_list = [n for n in fvp_config_map.list() |
| 87 | if n in config_list] |
Karl Zhang | aff558a | 2020-05-15 14:28:23 +0100 | [diff] [blame] | 88 | print("zss test_config_list original %s" % test_config_list) |
Minos Galanakis | ea42123 | 2019-06-20 17:11:28 +0100 | [diff] [blame] | 89 | |
| 90 | # Use the Build manager to calcuate the rejection list in the same |
| 91 | # manner. |
| 92 | rj = TFM_Build_Manager.generate_rejection_list( |
| 93 | build_cfg["seed_params"], |
| 94 | build_cfg["common_params"], |
| 95 | fvp_config_map.get_invalid()).keys() |
| 96 | |
| 97 | # Remove every config that is included in the rejection. |
| 98 | # Ignore generated rejection configs that have not been set in the |
| 99 | # test map. |
| 100 | for name in rj: |
| 101 | name = name.lower() |
| 102 | try: |
| 103 | test_config_list.pop(test_config_list.index(name)) |
| 104 | print("Rejecting config %s" % name) |
| 105 | except Exception as e: |
| 106 | print("Rejection ignored with exception:", e) |
| 107 | else: |
| 108 | print("Noting to do. Please provide a report or a config name to test") |
| 109 | sys.exit(1) |
| 110 | |
| 111 | # Apply filters if specified by user |
| 112 | if user_args.build_armclang: |
| 113 | test_config_list = cfilter(test_config_list, "armclang") |
| 114 | elif user_args.build_gnuarm: |
| 115 | test_config_list = cfilter(test_config_list, "gnuarm") |
| 116 | elif user_args.filter: |
| 117 | test_config_list = cfilter(test_config_list, user_args.filter) |
| 118 | else: |
| 119 | pass |
| 120 | |
Karl Zhang | aff558a | 2020-05-15 14:28:23 +0100 | [diff] [blame] | 121 | # print("Working on Test list: \n%s" % "\n".join(sorted(test_config_list))) |
| 122 | |
Minos Galanakis | ea42123 | 2019-06-20 17:11:28 +0100 | [diff] [blame] | 123 | if user_args.p_command: |
| 124 | |
| 125 | for test_cfg in test_config_list: |
| 126 | |
| 127 | test_cfg_obj = fvp_config_map.get_config_object(test_cfg) |
Karl Zhang | aff558a | 2020-05-15 14:28:23 +0100 | [diff] [blame] | 128 | |
Minos Galanakis | ea42123 | 2019-06-20 17:11:28 +0100 | [diff] [blame] | 129 | _tmp_cfg = FastmodelWrapper(fvp_cfg=test_cfg_obj.get_config()) |
| 130 | |
| 131 | print("\nCommand line:") |
| 132 | print("") |
| 133 | _tmp_cfg.show_cmd() |
| 134 | print("\n") |
| 135 | sys.exit(0) |
| 136 | |
| 137 | # Run tests |
| 138 | rep = [] |
| 139 | test_count = 0 |
Karl Zhang | aff558a | 2020-05-15 14:28:23 +0100 | [diff] [blame] | 140 | # print("zss print_list list") |
| 141 | # fvp_config_map.print_list() |
| 142 | print("zss test_config_list", test_config_list) |
Minos Galanakis | ea42123 | 2019-06-20 17:11:28 +0100 | [diff] [blame] | 143 | for test_cfg in test_config_list: |
| 144 | |
| 145 | # Check if the config hardcoded binary path is same as the one |
| 146 | # in the build report. If not update the config |
| 147 | test_cfg_obj = fvp_config_map.get_config_object(test_cfg) |
Karl Zhang | aff558a | 2020-05-15 14:28:23 +0100 | [diff] [blame] | 148 | print("+++test_cfg_obj %s\r\n %s\r\ntest_cfg %s" % (test_cfg_obj, test_cfg_obj.get_config(), test_cfg)) |
Minos Galanakis | ea42123 | 2019-06-20 17:11:28 +0100 | [diff] [blame] | 149 | |
Karl Zhang | aff558a | 2020-05-15 14:28:23 +0100 | [diff] [blame] | 150 | print("---- test_cfg_obj.get_config()", test_cfg_obj.get_config()) |
Minos Galanakis | ea42123 | 2019-06-20 17:11:28 +0100 | [diff] [blame] | 151 | rep.append(FastmodelWrapper( |
| 152 | fvp_cfg=test_cfg_obj.get_config()) |
| 153 | .start().block_wait().test().save_report().get_report()) |
| 154 | test_count += 1 |
| 155 | print("Testing progress:") |
| 156 | show_progress(test_count, len(test_config_list)) |
| 157 | |
| 158 | # Export the report in a file |
| 159 | if user_args.report: |
| 160 | f_report = {"report": {}, "_metadata_": {}} |
| 161 | f_report["report"] = {k["name"]: deepcopy(k) for k in rep} |
| 162 | save_json(user_args.report, f_report) |
| 163 | |
| 164 | sl = [x["name"] for x in rep if x["success"] is True] |
| 165 | fl = [x["name"] for x in rep if x["success"] is False] |
| 166 | |
| 167 | print("\n") |
| 168 | |
| 169 | if sl: |
| 170 | print_test(t_list=sl, status="passed", tname="Tests") |
| 171 | if fl: |
| 172 | print_test(t_list=fl, status="failed", tname="Tests") |
| 173 | if user_args.eif: |
| 174 | sys.exit(1) |
| 175 | |
| 176 | |
| 177 | def get_cmd_args(): |
| 178 | """ Parse command line arguments """ |
| 179 | |
| 180 | # Parse command line arguments to override config |
| 181 | parser = argparse.ArgumentParser(description="TFM Fastmodel wrapper.") |
| 182 | parser.add_argument("-b", "--build_report", |
| 183 | dest="build_report", |
| 184 | action="store", |
| 185 | help="JSON file produced by build_helper (input)") |
| 186 | parser.add_argument("-a", "--build_all", |
| 187 | dest="build_all", |
| 188 | action="store_true", |
| 189 | help="If set build every configuration combination") |
| 190 | parser.add_argument("-e", "--error_if_failed", |
| 191 | dest="eif", |
| 192 | action="store_true", |
| 193 | help="If set will change the script exit code if one " |
| 194 | "or more tests fail") |
| 195 | parser.add_argument("-r", "--report", |
| 196 | dest="report", |
| 197 | action="store", |
| 198 | help="JSON file containing fastmodel report (output)") |
| 199 | parser.add_argument("-g", "--build_gnuarm", |
| 200 | dest="build_gnuarm", |
| 201 | action="store_true", |
| 202 | help="If set build every gnuarm configuration") |
| 203 | parser.add_argument("-c", "--build_armclang", |
| 204 | dest="build_armclang", |
| 205 | action="store_true", |
| 206 | help="If set build every armclang configuration") |
| 207 | parser.add_argument("-f", "--filter", |
| 208 | dest="filter", |
| 209 | action="store", |
| 210 | help="Only select configs that contain this string") |
| 211 | parser.add_argument("-l", "--list-configs", |
| 212 | dest="list_cfg", |
| 213 | action="store_true", |
| 214 | help="Print a list of the built-in configurations and" |
| 215 | "exit") |
| 216 | parser.add_argument("-s", "--single-config", |
| 217 | dest="single_cfg", |
| 218 | action="store", |
| 219 | help="Launch testing for a single built-in config, " |
| 220 | "picked by name") |
| 221 | parser.add_argument("-p", "--print-command", |
| 222 | dest="p_command", |
| 223 | action="store_true", |
Karl Zhang | aff558a | 2020-05-15 14:28:23 +0100 | [diff] [blame] | 224 | help="Print the FVP launch command to console & exit") |
Minos Galanakis | ea42123 | 2019-06-20 17:11:28 +0100 | [diff] [blame] | 225 | return parser.parse_args() |
| 226 | |
| 227 | |
| 228 | if __name__ == "__main__": |
| 229 | main(get_cmd_args()) |