def load_rule_and_env(rule_dir_path, env_yaml, product=None): """ Loads a rule and returns the combination of the RuleYAML class and the corresponding local environment for that rule. """ # First build the path to the rule.yml file rule_path = get_rule_dir_yaml(rule_dir_path) # Load rule content in our environment. We use this to satisfy # some implied properties that might be used in the test suite. # Make sure we normalize to a specific product as well so that # when we load templated content it is correct. rule = RuleYAML.from_yaml(rule_path, env_yaml) rule.normalize(product) # Note that most places would check prodtype, but we don't care # about that here: if the rule is available to the product, we # load and parse it anyways as we have no knowledge of the # top-level profile or rule passed into the test suite. prodtypes = parse_prodtype(rule.prodtype) # Our local copy of env_yaml needs some properties from rule.yml # for completeness. local_env_yaml = dict() local_env_yaml.update(env_yaml) local_env_yaml['rule_id'] = rule.id_ local_env_yaml['rule_title'] = rule.title local_env_yaml['products'] = prodtypes return rule, local_env_yaml
def template_tests(product=None): """ Create a temporary directory with test cases parsed via jinja using product-specific context. """ # Set up an empty temp directory tmpdir = tempfile.mkdtemp() # We want to remove the temporary directory on failure, but preserve # it on success. Wrap in a try/except block and reraise the original # exception after removing the temporary directory. try: # Load product's YAML file if present. This will allow us to parse # tests in the context of the product we're executing under. product_yaml = dict() if product: yaml_path = product_yaml_path(SSG_ROOT, product) product_yaml = load_product_yaml(yaml_path) # Below we could run into a DocumentationNotComplete error. However, # because the test suite isn't executed in the context of a particular # build (though, ideally it would be linked), we may not know exactly # whether the top-level rule/profile we're testing is actually # completed. Thus, forcibly set the required property to bypass this # error. product_yaml['cmake_build_type'] = 'Debug' # Note that we're not exactly copying 1-for-1 the contents of the # directory structure into the temporary one. Instead we want a # flattened mapping with all rules in a single top-level directory # and all tests immediately contained within it. That is: # # /group_a/rule_a/tests/something.pass.sh -> /rule_a/something.pass.sh for dirpath, dirnames, _ in walk_through_benchmark_dirs(product): # Skip anything that isn't obviously a rule. if "tests" not in dirnames or not is_rule_dir(dirpath): continue # Load rule content in our environment. We use this to satisfy # some implied properties that might be used in the test suite. rule_path = get_rule_dir_yaml(dirpath) rule = RuleYAML.from_yaml(rule_path, product_yaml) # Note that most places would check prodtype, but we don't care # about that here: if the rule is available to the product, we # load and parse it anyways as we have no knowledge of the # top-level profile or rule passed into the test suite. prodtypes = parse_prodtype(rule.prodtype) # Our local copy of env_yaml needs some properties from rule.yml # for completeness. local_env_yaml = dict() local_env_yaml.update(product_yaml) local_env_yaml['rule_id'] = rule.id_ local_env_yaml['rule_title'] = rule.title local_env_yaml['products'] = prodtypes # Create the destination directory. dest_path = os.path.join(tmpdir, rule.id_) os.mkdir(dest_path) # Walk the test directory, writing all tests into the output # directory, recursively. tests_dir_path = os.path.join(dirpath, "tests") tests_dir_path = os.path.abspath(tests_dir_path) for dirpath, dirnames, filenames in os.walk(tests_dir_path): for dirname in dirnames: # We want to recreate the correct path under the temporary # directory. Resolve it to a relative path from the tests/ # directory. dir_path = _rel_abs_path(os.path.join(dirpath, dirname), tests_dir_path) assert '../' not in dir_path tmp_dir_path = os.path.join(dest_path, dir_path) os.mkdir(tmp_dir_path) for filename in filenames: # We want to recreate the correct path under the temporary # directory. Resolve it to a relative path from the tests/ # directory. Assumption: directories should be created # prior to recursing into them, so we don't need to handle # if a file's parent directory doesn't yet exist under the # destination. src_test_path = os.path.join(dirpath, filename) rel_test_path = _rel_abs_path(src_test_path, tests_dir_path) dest_test_path = os.path.join(dest_path, rel_test_path) # Rather than performing an OS-level copy, we need to # first parse the test with jinja and then write it back # out to the destination. parsed_test = process_file(src_test_path, local_env_yaml) with open(dest_test_path, 'w') as output_fp: print(parsed_test, file=output_fp) except Exception as exp: shutil.rmtree(tmpdir, ignore_errors=True) raise exp return tmpdir