Initial commit for TF-A CI scripts
Signed-off-by: Fathi Boudra <fathi.boudra@linaro.org>
diff --git a/script/gen_test_desc.py b/script/gen_test_desc.py
new file mode 100755
index 0000000..5913c32
--- /dev/null
+++ b/script/gen_test_desc.py
@@ -0,0 +1,131 @@
+#!/usr/bin/env python3
+#
+# Copyright (c) 2019, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#
+# Generate .test files in $workspace based on the $TEST_GROUPS parameter. Test
+# files are prefixed with a zero-padded number for a predictable ordering
+# amongst them.
+
+import os
+
+TEST_SUFFIX = ".test"
+
+
+def touch(a_file):
+ with open(a_file, "w"):
+ pass
+
+
+# Obtain the value of either $variable or $VARIABLE.
+def get_env(variable):
+ var_list = [variable, variable.upper()]
+ for v in var_list:
+ value = os.environ.get(v)
+ if value:
+ return value
+ else:
+ raise Exception("couldn't find {} in env".format(" or ".join(var_list)))
+
+
+# Perform group-specific translation on the build config
+def translate_build_config(group, config_list):
+ # config_list contains build configs as read from the test config
+ if group.startswith("scp-"):
+ # SCP configs would be specified in the following format:
+ # scp_config, tf_config, tftf_config
+ # Reshuffle them into the canonical format
+ config_list = [config_list[1], config_list[2], config_list[0]]
+
+ return config_list
+
+
+def gen_desc(group, test):
+ global num_spawn
+
+ build_config, run_config = test.split(":")
+
+ # Test descriptors are always generated in the following order:
+ # tf_config, tftf_config, scp_config
+ # Fill missing configs to the right with "nil".
+ config_list = (build_config.split(",") + ["nil"] * 3)[:3]
+
+ # Perform any group-specific translation on the config
+ config_list = translate_build_config(group, config_list)
+
+ test_config = ",".join(config_list) + ":" + run_config
+
+ # Create descriptor. Write the name of the original test config as its
+ # content.
+ desc = os.path.join(workspace, "%".join([str(num_spawn).zfill(3), group,
+ test_config + TEST_SUFFIX]))
+ with open(desc, "wt") as fd:
+ print(test, file=fd)
+
+ num_spawn += 1
+
+
+def process_item(item):
+ # If an item starts with @, then it's deemed to be an indirection--a file
+ # from which test groups are to be read.
+ if item.startswith("@"):
+ with open(item[1:]) as fd:
+ for line in fd:
+ line = line.strip()
+ if not line:
+ continue
+ process_item(line)
+
+ return
+
+ item_loc = os.path.join(group_dir, item)
+
+ if os.path.isfile(item_loc):
+ gen_desc(*item_loc.split(os.sep)[-2:])
+ elif os.path.isdir(item_loc):
+ # If it's a directory, select all files inside it
+ for a_file in next(os.walk(item_loc))[2]:
+ gen_desc(item, a_file)
+ else:
+ # The item doesn't exist
+ if ":" in item:
+ # A non-existent test config is specified
+ if "/" in item:
+ # The test config doesn't exist, and a group is also specified.
+ # This is not allowed.
+ raise Exception("'{}' doesn't exist.".format(item))
+ else:
+ # The user probably intended to create one on the fly; so create
+ # one in the superficial 'GENERATED' group.
+ print("note: '{}' doesn't exist; generated.".format(item))
+ touch(os.path.join(generated_dir, item))
+ gen_desc(os.path.basename(generated_dir), item)
+ else:
+ raise Exception("'{}' is not valid for test generation!".format(item))
+
+
+ci_root = os.path.abspath(os.path.join(__file__, os.pardir, os.pardir))
+group_dir = os.path.join(ci_root, "group")
+num_spawn = 0
+
+# Obtain variables from environment
+test_groups = get_env("test_groups")
+workspace = get_env("workspace")
+
+# Remove all test files, if any
+_, _, files = next(os.walk(workspace))
+for test_file in files:
+ if test_file.endswith(TEST_SUFFIX):
+ os.remove(os.path.join(workspace, test_file))
+
+generated_dir = os.path.join(group_dir, "GENERATED")
+os.makedirs(generated_dir, exist_ok=True)
+
+for item in test_groups.split():
+ process_item(item)
+
+print()
+print("{} children to be spawned...".format(num_spawn))
+print()