|
| 1 | +# Copyright OpenSearch Contributors |
| 2 | +# SPDX-License-Identifier: Apache-2.0 |
| 3 | +# |
| 4 | +# The OpenSearch Contributors require contributions made to |
| 5 | +# this file be licensed under the Apache-2.0 license or a |
| 6 | +# compatible open source license. |
| 7 | + |
| 8 | +import logging |
| 9 | +import os |
| 10 | +import urllib.request |
| 11 | +from typing import Any |
| 12 | +from urllib.error import HTTPError |
| 13 | + |
| 14 | +import validators |
| 15 | +import yaml |
| 16 | + |
| 17 | +from manifests.test_manifest import TestManifest |
| 18 | +from manifests.test_run_manifest import TestRunManifest |
| 19 | +from report_workflow.report_args import ReportArgs |
| 20 | + |
| 21 | + |
| 22 | +class TestRunRunner: |
| 23 | + args: ReportArgs |
| 24 | + test_manifest: TestManifest |
| 25 | + tests_dir: str |
| 26 | + test_run_manifest: TestRunManifest |
| 27 | + test_run_data: dict |
| 28 | + |
| 29 | + def __init__(self, args: ReportArgs, test_manifest: TestManifest) -> None: |
| 30 | + self.args = args |
| 31 | + self.base_path = args.base_path |
| 32 | + self.test_manifest = test_manifest |
| 33 | + self.test_run_data = self.test_run_manifest_data_template("manifest") |
| 34 | + self.product_name = test_manifest.__to_dict__().get("name") |
| 35 | + self.name = self.product_name.replace(" ", "-").lower() |
| 36 | + self.components = self.args.components |
| 37 | + self.test_run_id = args.test_run_id |
| 38 | + self.test_type = self.args.test_type |
| 39 | + self.test_manifest_path = self.args.test_manifest_path |
| 40 | + self.artifact_paths = "" |
| 41 | + for k, v in self.args.artifact_paths.items(): |
| 42 | + self.artifact_paths = " ".join([self.artifact_paths, k + "=" + v]).strip(" ") |
| 43 | + |
| 44 | + self.dist_manifest = "/".join([self.args.artifact_paths[self.name], "dist", self.name, "manifest.yml"]) if self.args.artifact_paths[self.name].startswith("https://") \ |
| 45 | + else os.path.join(self.args.artifact_paths[self.name], "dist", self.name, "manifest.yml") |
| 46 | + self.test_components = self.test_manifest.components |
| 47 | + |
| 48 | + def update_data(self) -> dict: |
| 49 | + self.test_run_data["name"] = self.product_name |
| 50 | + self.test_run_data["test-run"] = self.update_test_run_data() |
| 51 | + for component in self.test_components.select(focus=self.args.components): |
| 52 | + self.test_run_data["components"].append(self.component_entry(component.name)) |
| 53 | + return self.test_run_data |
| 54 | + |
| 55 | + def update_test_run_data(self) -> dict: |
| 56 | + test_run_data = { |
| 57 | + "Command": generate_test_command(self.test_type, self.test_manifest_path, self.artifact_paths), |
| 58 | + "TestType": self.test_type, |
| 59 | + "TestManifest": self.test_manifest_path, |
| 60 | + "DistributionManifest": self.dist_manifest, |
| 61 | + "TestID": str(self.test_run_id) |
| 62 | + } |
| 63 | + return test_run_data |
| 64 | + |
| 65 | + def generate_report(self, data: dict, output_dir: str) -> Any: |
| 66 | + test_run_manifest = TestRunManifest(data) |
| 67 | + test_run_manifetest_run_manifest_file = os.path.join(output_dir, "test-run.yml") |
| 68 | + logging.info(f"Generating test-run.yml in {output_dir}") |
| 69 | + return test_run_manifest.to_file(test_run_manifetest_run_manifest_file) |
| 70 | + |
| 71 | + def component_entry(self, component_name: str) -> Any: |
| 72 | + component = self.test_run_manifest_data_template("component") |
| 73 | + component["name"] = component_name |
| 74 | + component["command"] = generate_test_command(self.test_type, self.test_manifest_path, self.artifact_paths, component_name) |
| 75 | + |
| 76 | + test_component = self.test_manifest.components[component_name] |
| 77 | + |
| 78 | + config_names = [config for config in test_component.__to_dict__().get(self.test_type)["test-configs"]] |
| 79 | + logging.info(f"Configs for {component_name} on {self.test_type} are {config_names}") |
| 80 | + for config in config_names: |
| 81 | + config_dict = { |
| 82 | + "name": config, |
| 83 | + } |
| 84 | + |
| 85 | + component_yml_ref = generate_component_yml_ref(self.base_path, str(self.test_run_id), self.test_type, component_name, config) |
| 86 | + logging.info(f"Loading {component_yml_ref}") |
| 87 | + try: |
| 88 | + if validators.url(component_yml_ref): |
| 89 | + with urllib.request.urlopen(component_yml_ref) as f: |
| 90 | + component_yml = yaml.safe_load(f.read().decode("utf-8")) |
| 91 | + test_result = component_yml["test_result"] |
| 92 | + else: |
| 93 | + with open(component_yml_ref, "r", encoding='utf8') as f: |
| 94 | + component_yml = yaml.safe_load(f) |
| 95 | + test_result = component_yml["test_result"] |
| 96 | + except (FileNotFoundError, HTTPError): |
| 97 | + logging.info(f"Component yml file for {component_name} for {config} is missing or the base path is incorrect.") |
| 98 | + test_result = "Not Available" |
| 99 | + component_yml_ref = "URL not available" |
| 100 | + config_dict["yml"] = component_yml_ref |
| 101 | + config_dict["status"] = test_result |
| 102 | + component["configs"].append(config_dict) |
| 103 | + return component |
| 104 | + |
| 105 | + def test_run_manifest_data_template(self, template_type: str) -> Any: |
| 106 | + templates = { |
| 107 | + "manifest": { |
| 108 | + "schema-version": "1.0", |
| 109 | + "name": "", |
| 110 | + "test-run": {}, |
| 111 | + "components": [] |
| 112 | + }, |
| 113 | + "component": { |
| 114 | + "name": "", |
| 115 | + "command": "", |
| 116 | + "configs": [] |
| 117 | + } |
| 118 | + } |
| 119 | + return templates[template_type] |
| 120 | + |
| 121 | + |
| 122 | +def generate_component_yml_ref(base_path: str, test_number: str, test_type: str, component_name: str, config: str) -> str: |
| 123 | + if base_path.startswith("https://"): |
| 124 | + return "/".join([base_path.strip("/"), "test-results", test_number, test_type, component_name, config, f"{component_name}.yml"]) |
| 125 | + else: |
| 126 | + return os.path.join(base_path, "test-results", test_number, test_type, component_name, config, f"{component_name}.yml") |
| 127 | + |
| 128 | + |
| 129 | +def generate_test_command(test_type: str, test_manifest_path: str, artifacts_path: str, component: str = "") -> str: |
| 130 | + command = " ".join(["./test.sh", test_type, test_manifest_path, "--paths", artifacts_path]) |
| 131 | + if component: |
| 132 | + command = " ".join([command, "--component", component]) |
| 133 | + logging.info(command) |
| 134 | + return command |
| 135 | + |
| 136 | + |
| 137 | +TestRunRunner.__test__ = False # type:ignore |
0 commit comments