Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add 1.1 version of test report yml with bundle and rc information #4887

Merged
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
165 changes: 165 additions & 0 deletions src/manifests/test_report/test_report_manifest_1_0.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
# Copyright OpenSearch Contributors
# SPDX-License-Identifier: Apache-2.0
#
# The OpenSearch Contributors require contributions made to
# this file be licensed under the Apache-2.0 license or a
# compatible open source license.

from typing import Optional

from manifests.component_manifest import Component, ComponentManifest, Components


class TestReportManifest_1_0(ComponentManifest['TestReportManifest_1_0', 'TestComponents_1_0']):
"""
TestReportManifest contains the aggregated test results for the components.

The format for schema version 1.0 is:
schema-version: '1.0'
name: name of the product e.g. OpenSearch
test-run:
Command: command to trigger the integ test
TestType: type of test this manifest reports. e.g. integ-test
TestManifest: location of the test manifest used
DistributionManifest: URL or local path of the bundle manifest.
TestID: test id
components:
- name: sql
command: command to trigger the integ test for only sql component
configs:
- name: with-security
status: the status of the test run with this config. e.g. pass/fail
yml: URL or local path to the component yml file
cluster_stdout:
- URL or local path to the OpenSearch cluster logs
cluster_stderr:
- URL or local path to the OpenSearch cluster error logs
"""

SCHEMA = {
"schema-version": {"required": True, "type": "string", "allowed": ["1.0"]},
"name": {"required": True, "type": "string", "allowed": ["OpenSearch", "OpenSearch Dashboards"]},
"test-run": {
"required": False,
"type": "dict",
"schema": {
"Command": {"required": False, "type": "string"},
"TestType": {"required": False, "type": "string"},
"TestManifest": {"required": False, "type": "string"},
"DistributionManifest": {"required": False, "type": "string"},
"TestID": {"required": False, "type": "string"}
},
},
"components": {
"type": "list",
"schema": {
"type": "dict",
"schema": {
"name": {"required": True, "type": "string"},
"command": {"type": "string"},
"configs": {
"type": "list",
"schema": {
"type": "dict",
"schema": {
"name": {"type": "string"},
"status": {"type": "string"},
"yml": {"type": "string"},
"cluster_stdout": {"type": "list"},
"cluster_stderr": {"type": "list"}
}
},
},
},
},
},
}

def __init__(self, data: dict) -> None:
super().__init__(data)
self.name = str(data["name"])
self.test_run = self.TestRun(data.get("test-run", None))
self.components = TestComponents_1_0(data.get("components", [])) # type: ignore[assignment]

def __to_dict__(self) -> dict:
return {
"schema-version": "1.0",
"name": self.name,
"test-run": None if self.test_run is None else self.test_run.__to_dict__(),
"components": self.components.__to_dict__()
}

class TestRun:
def __init__(self, data: dict) -> None:
if data is None:
self.test_run = None
else:
self.command = data["Command"]
self.test_type = data["TestType"]
self.test_manifest = data["TestManifest"]
self.distribution_manifest = data["DistributionManifest"]
self.test_id = data["TestID"]

def __to_dict__(self) -> Optional[dict]:
if (self.command and self.test_type and self.test_manifest and self.distribution_manifest and self.test_id) is None:
return None
else:
return {
"Command": self.command,
"TestType": self.test_type,
"TestManifest": self.test_manifest,
"DistributionManifest": self.distribution_manifest,
"TestID": self.test_id
}


class TestComponents_1_0(Components['TestComponent_1_0']):
@classmethod
def __create__(self, data: dict) -> 'TestComponent_1_0':
return TestComponent_1_0(data)


class TestComponent_1_0(Component):
def __init__(self, data: dict) -> None:
super().__init__(data)
self.command = data["command"]
self.configs = self.TestComponentConfigs_1_0(data.get("configs", None))

def __to_dict__(self) -> dict:
return {
"name": self.name,
"command": self.command,
"configs": self.configs.__to_list__()
}

class TestComponentConfigs_1_0:
def __init__(self, data: list) -> None:
self.configs = []
for config in data:
self.configs.append(self.TestComponentConfig_1_0(config).__to_dict__())

def __to_list__(self) -> list:
return self.configs

class TestComponentConfig_1_0:
def __init__(self, data: dict) -> None:
self.name = data["name"]
self.status = data["status"]
self.yml = data["yml"]
self.cluster_stdout = data["cluster_stdout"]
self.cluster_stderr = data["cluster_stderr"]

def __to_dict__(self) -> dict:
return {
"name": self.name,
"status": self.status,
"yml": self.yml,
"cluster_stdout": self.cluster_stdout,
"cluster_stderr": self.cluster_stderr
}


TestReportManifest_1_0.VERSIONS = {"1.0": TestReportManifest_1_0}

TestComponent_1_0.__test__ = False # type: ignore[attr-defined]
TestReportManifest_1_0.__test__ = False # type: ignore[attr-defined]
40 changes: 35 additions & 5 deletions src/manifests/test_report_manifest.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,22 @@
from typing import Optional

from manifests.component_manifest import Component, ComponentManifest, Components
from manifests.test_report.test_report_manifest_1_0 import TestReportManifest_1_0


class TestReportManifest(ComponentManifest['TestReportManifest', 'TestComponents']):
"""
TestReportManifest contains the aggregated test results for the components.

The format for schema version 1.0 is:
schema-version: '1.0'
The format for schema version 1.1 is:
schema-version: '1.1'
name: name of the product e.g. OpenSearch
version: string
platform: linux, darwin or windows
architecture: x64 or arm64
distribution: tar, zip, deb and rpm
id: build id
rc: release candidate information
test-run:
Command: command to trigger the integ test
TestType: type of test this manifest reports. e.g. integ-test
Expand All @@ -36,9 +43,20 @@ class TestReportManifest(ComponentManifest['TestReportManifest', 'TestComponents
- URL or local path to the OpenSearch cluster error logs
"""

VERSIONS = {
"1.0": TestReportManifest_1_0,
# "1.1": current
}

SCHEMA = {
"schema-version": {"required": True, "type": "string", "allowed": ["1.0"]},
"schema-version": {"required": True, "type": "string", "allowed": ["1.1"]},
"name": {"required": True, "type": "string", "allowed": ["OpenSearch", "OpenSearch Dashboards"]},
"version": {"required": True, "type": "string"}, # added in 1.1
"platform": {"required": True, "type": "string"}, # added in 1.1
"architecture": {"required": True, "type": "string"}, # added in 1.1
"distribution": {"required": True, "type": "string"}, # added in 1.1
"id": {"required": True, "type": "string"}, # added in 1.1
"rc": {"required": True, "type": "string"}, # added in 1.1
"test-run": {
"required": False,
"type": "dict",
Expand Down Expand Up @@ -78,13 +96,25 @@ class TestReportManifest(ComponentManifest['TestReportManifest', 'TestComponents
def __init__(self, data: dict) -> None:
super().__init__(data)
self.name = str(data["name"])
self.version = str(data["version"])
self.platform = str(data["platform"])
self.architecture = str(data["architecture"])
self.distribution = str(data["distribution"])
self.build_id = str(data["id"])
self.release_candidate = str(data["rc"])
self.test_run = self.TestRun(data.get("test-run", None))
self.components = TestComponents(data.get("components", [])) # type: ignore[assignment]

def __to_dict__(self) -> dict:
return {
"schema-version": "1.0",
"schema-version": "1.1",
"name": self.name,
"version": self.version,
"platform": self.platform,
"architecture": self.architecture,
"distribution": self.distribution,
"id": self.build_id,
"rc": self.release_candidate,
"test-run": None if self.test_run is None else self.test_run.__to_dict__(),
"components": self.components.__to_dict__()
}
Expand Down Expand Up @@ -159,7 +189,7 @@ def __to_dict__(self) -> dict:
}


TestReportManifest.VERSIONS = {"1.0": TestReportManifest}
TestReportManifest.VERSIONS = {"1.0": TestReportManifest_1_0, "1.1": TestReportManifest}

TestComponent.__test__ = False # type: ignore[attr-defined]
TestReportManifest.__test__ = False # type: ignore[attr-defined]
6 changes: 6 additions & 0 deletions src/report_workflow/report_args.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ class ReportArgs:
test_manifest_path: str
artifact_paths: dict
test_type: str
schema_version: str
release_candidate: str
logging_level: int

def __init__(self) -> None:
Expand All @@ -33,6 +35,8 @@ def __init__(self) -> None:
parser.add_argument("--output-path", type=str, help="Specify the path location for the test-report manifest.")
parser.add_argument("--test-run-id", type=int, help="The unique execution id for the test")
parser.add_argument("--component", type=str, dest="components", nargs='*', help="Test a specific component or components instead of the entire distribution.")
parser.add_argument("--schema-version", type=str, default="1.1", help="The schema version for the test-report manifest.")
parser.add_argument("--release-candidate", type=str, default="0", help="The release candidate (rc) information of the artifacts, added in schema-version='1.1'.")
peterzhuamazon marked this conversation as resolved.
Show resolved Hide resolved
parser.add_argument(
"-v", "--verbose", help="Show more verbose output.", action="store_const", default=logging.INFO, const=logging.DEBUG, dest="logging_level"
)
Expand All @@ -45,4 +49,6 @@ def __init__(self) -> None:
self.base_path = args.base_path
self.test_type = args.test_type
self.components = args.components
self.schema_version = args.schema_version
self.release_candidate = args.release_candidate
self.output_path = args.output_path
46 changes: 43 additions & 3 deletions src/report_workflow/test_report_runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import validators
import yaml

from manifests.bundle_manifest import BundleManifest
from manifests.test_manifest import TestManifest
from manifests.test_report_manifest import TestReportManifest
from report_workflow.report_args import ReportArgs
Expand All @@ -26,11 +27,14 @@ class TestReportRunner:
tests_dir: str
test_report_manifest: TestReportManifest
test_run_data: dict
bundle_manifest: BundleManifest

def __init__(self, args: ReportArgs, test_manifest: TestManifest) -> None:
self.args = args
self.base_path = args.base_path
self.test_manifest = test_manifest
self.schema_version = self.args.schema_version
self.release_candidate = self.args.release_candidate
self.test_run_data = self.test_report_manifest_data_template("manifest")
self.product_name = test_manifest.__to_dict__().get("name")
self.name = self.product_name.replace(" ", "-").lower()
Expand All @@ -48,6 +52,14 @@ def __init__(self, args: ReportArgs, test_manifest: TestManifest) -> None:

def update_data(self) -> dict:
self.test_run_data["name"] = self.product_name
if float(self.schema_version) > 1.0:
peterzhuamazon marked this conversation as resolved.
Show resolved Hide resolved
self.bundle_manifest = BundleManifest.from_urlpath(self.dist_manifest)
self.test_run_data["version"] = self.bundle_manifest.build.version
self.test_run_data["platform"] = self.bundle_manifest.build.platform
self.test_run_data["architecture"] = self.bundle_manifest.build.architecture
self.test_run_data["distribution"] = self.bundle_manifest.build.distribution
self.test_run_data["id"] = self.bundle_manifest.build.id
self.test_run_data["rc"] = self.release_candidate
peterzhuamazon marked this conversation as resolved.
Show resolved Hide resolved
self.test_run_data["test-run"] = self.update_test_run_data()
for component in self.test_components.select(focus=self.args.components):
if self.test_manifest.components[component.name].__to_dict__().get(self.test_type) is not None:
Expand All @@ -65,7 +77,8 @@ def update_test_run_data(self) -> dict:
return test_run_data

def generate_report(self, data: dict, output_dir: str) -> Any:
test_report_manifest = TestReportManifest(data)
logging.info(f"Use schema-version {self.schema_version}")
test_report_manifest = TestReportManifest.from_version(self.schema_version)(data)
test_report_manifest_file = os.path.join(output_dir, "test-report.yml")
logging.info(f"Generating test-report.yml in {output_dir}")
return test_report_manifest.to_file(test_report_manifest_file)
Expand Down Expand Up @@ -107,7 +120,8 @@ def component_entry(self, component_name: str) -> Any:
return component

def test_report_manifest_data_template(self, template_type: str) -> Any:
templates = {

templates_1_0 = {
"manifest": {
"schema-version": "1.0",
"name": "",
Expand All @@ -120,7 +134,33 @@ def test_report_manifest_data_template(self, template_type: str) -> Any:
"configs": []
}
}
return templates[template_type]

templates_1_1 = {
"manifest": {
"schema-version": "1.1",
"name": "",
"version": "",
"platform": "",
"architecture": "",
"distribution": "",
"id": "",
"rc": "",
"test-run": {},
"components": []
},
"component": {
"name": "",
"command": "",
"configs": []
}
}

templates_map = {
"1.0": templates_1_0,
"1.1": templates_1_1,
}

return templates_map[self.schema_version][template_type]


def generate_component_yml_ref(base_path: str, test_number: str, test_type: str, component_name: str,
Expand Down
Loading
Loading