Skip to content

Commit 2e36b36

Browse files
authoredMar 19, 2025··
Recording components logs and generate component yaml for smoke tests framework (#5333)
Signed-off-by: Zelin Hao <zelinhao@amazon.com>
1 parent 60ca9ed commit 2e36b36

File tree

3 files changed

+100
-5
lines changed

3 files changed

+100
-5
lines changed
 

‎src/test_workflow/smoke_test/smoke_test_runner.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ def run(self) -> Any:
7575
test_cluster.__start_cluster__(os.path.join(work_dir.path))
7676
is_cluster_ready = False
7777
for i in range(10):
78-
logging.info(f"Attempt {i} of 10 to check cluster.")
78+
logging.info(f"Attempt {i + 1} of 10 to check cluster.")
7979
if test_cluster.__check_cluster_ready__():
8080
is_cluster_ready = True
8181
break

‎src/test_workflow/smoke_test/smoke_test_runner_opensearch.py

+46-4
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,12 @@
55
# this file be licensed under the Apache-2.0 license or a
66
# compatible open source license.
77

8+
import io
89
import logging
910
import os
11+
from logging import Handler
1012
from pathlib import Path
11-
from typing import Any
13+
from typing import Any, Tuple
1214

1315
import requests
1416
from openapi_core import Spec, validate_request, validate_response
@@ -17,6 +19,7 @@
1719
from manifests.test_manifest import TestManifest
1820
from test_workflow.smoke_test.smoke_test_runner import SmokeTestRunner
1921
from test_workflow.test_args import TestArgs
22+
from test_workflow.test_recorder.test_result_data import TestResultData
2023
from test_workflow.test_result.test_component_results import TestComponentResults
2124
from test_workflow.test_result.test_result import TestResult
2225
from test_workflow.test_result.test_suite_results import TestSuiteResults
@@ -64,6 +67,31 @@ def validate_response_swagger(self, response: Any) -> None:
6467
validate_response(response=response, spec=self.spec_, request=request)
6568
logging.info("Response is validated.")
6669

70+
def record_test_result(self, component: str, test_api: str, api_action: str, stdout: str, stderr: str) -> None:
71+
test_config = f"{api_action}_{test_api.replace('/', '_')}"
72+
logging.info(f"Recording test result for {component} component, config {test_config}")
73+
file_path = self.test_recorder._create_base_folder_structure(component, test_config)
74+
self.test_recorder._generate_std_files(stdout, stderr, file_path)
75+
76+
def setup_logging_buffers(self) -> Tuple[io.StringIO, io.StringIO, logging.StreamHandler, logging.StreamHandler]:
77+
info_buffer = io.StringIO()
78+
error_buffer = io.StringIO()
79+
80+
info_handler = logging.StreamHandler(info_buffer)
81+
error_handler = logging.StreamHandler(error_buffer)
82+
83+
info_handler.setLevel(logging.INFO)
84+
error_handler.setLevel(logging.ERROR)
85+
86+
logging.getLogger().addHandler(info_handler)
87+
logging.getLogger().addHandler(error_handler)
88+
89+
return info_buffer, error_buffer, info_handler, error_handler
90+
91+
def cleanup_logging_handlers(self, info_handler: Handler, error_handler: Handler) -> None:
92+
logging.getLogger().removeHandler(info_handler)
93+
logging.getLogger().removeHandler(error_handler)
94+
6795
def start_test(self, work_dir: Path) -> TestSuiteResults:
6896
url = "https://localhost:9200"
6997

@@ -76,9 +104,11 @@ def start_test(self, work_dir: Path) -> TestSuiteResults:
76104
test_results = TestComponentResults()
77105
for api_requests, api_details in component_spec.items():
78106
request_url = ''.join([url, api_requests])
79-
logging.info(f"Validating api request {api_requests}")
80-
logging.info(f"API request URL is {request_url}")
81107
for method in api_details.keys(): # Iterates over each method, e.g., "GET", "POST"
108+
info_buffer, error_buffer, info_handler, error_handler = self.setup_logging_buffers()
109+
110+
logging.info(f"Validating api request {api_requests}")
111+
logging.info(f"API request URL is {request_url}")
82112
requests_method = getattr(requests, method.lower())
83113
parameters_data = self.convert_parameter_json(api_details.get(method).get("parameters"))
84114
header = api_details.get(method).get("header", self.mimetype)
@@ -87,15 +117,27 @@ def start_test(self, work_dir: Path) -> TestSuiteResults:
87117
status = 0
88118
try:
89119
response = requests_method(request_url, verify=False, auth=("admin", "myStrongPassword123!"), headers=header, data=parameters_data)
90-
logging.info(f"Response is {response.text}")
120+
logging.info(f"Response is \n{response.text}")
91121
self.validate_response_swagger(response)
92122
except Exception as e:
93123
status = 1
94124
logging.error(f"Unexpected Error type is {type(e)}")
95125
logging.error(e)
96126
logging.info("Response is not validated. Please check the response output text above.")
97127
finally:
128+
self.record_test_result(component.name, api_requests, method, info_buffer.getvalue(), error_buffer.getvalue())
98129
test_result = TestResult(component.name, ' '.join([api_requests, method]), status) # type: ignore
130+
test_result_data_local = TestResultData(
131+
component.name,
132+
f"{method}_{api_requests.replace('/', '_')}",
133+
status,
134+
info_buffer.getvalue(),
135+
error_buffer.getvalue(),
136+
{}
137+
)
138+
self.test_recorder.test_results_logs.generate_component_yml(test_result_data_local)
139+
self.cleanup_logging_handlers(info_handler, error_handler)
99140
test_results.append(test_result)
141+
100142
all_results.append(component.name, test_results)
101143
return all_results

‎tests/tests_test_workflow/test_smoke_workflow/smoke_test/test_smoke_test_runner_opensearch.py

+53
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
# The OpenSearch Contributors require contributions made to
55
# this file be licensed under the Apache-2.0 license or a
66
# compatible open source license.
7+
import logging
78
import os.path
89
import unittest
910
from pathlib import Path
@@ -149,3 +150,55 @@ def test_download_spec_https_fail(self, mock_file: Mock, mock_get: Mock, mock_te
149150
mock_file().write.assert_not_called()
150151

151152
self.assertTrue(runner.spec_path.endswith(os.path.join("smoke_tests_spec", "opensearch-openapi-local.yaml")))
153+
154+
@patch("requests.get")
155+
@patch("test_workflow.smoke_test.smoke_test_runner.TestRecorder")
156+
def test_record_test_result(self, mock_recorder: Mock, mock_requests: Mock) -> None:
157+
runner = SmokeTestRunnerOpenSearch(MagicMock(), MagicMock())
158+
159+
runner.test_recorder = mock_recorder
160+
161+
component = "test_component"
162+
test_api = "/api/test"
163+
api_action = "GET"
164+
stdout = "test output"
165+
stderr = "test error"
166+
167+
runner.record_test_result(component, test_api, api_action, stdout, stderr)
168+
169+
test_config = f"{api_action}_{test_api.replace('/', '_')}"
170+
mock_recorder._create_base_folder_structure.assert_called_once_with(component, test_config)
171+
mock_recorder._generate_std_files.assert_called_once()
172+
173+
@patch("requests.get")
174+
@patch("test_workflow.smoke_test.smoke_test_runner.TestRecorder")
175+
def test_setup_logging_buffers(self, mock_recorder: Mock, mock_requests: Mock) -> None:
176+
runner = SmokeTestRunnerOpenSearch(MagicMock(), MagicMock())
177+
178+
info_buffer, error_buffer, info_handler, error_handler = runner.setup_logging_buffers()
179+
180+
logger = logging.getLogger()
181+
logger.setLevel(logging.INFO)
182+
assert info_handler in logger.handlers
183+
assert error_handler in logger.handlers
184+
185+
logging.info("Test info message")
186+
logging.error("Test error message")
187+
188+
assert "Test info message" in info_buffer.getvalue()
189+
assert "Test error message" in error_buffer.getvalue()
190+
191+
@patch("requests.get")
192+
@patch("test_workflow.smoke_test.smoke_test_runner.TestRecorder")
193+
def test_cleanup_logging_handlers(self, mock_recorder: Mock, mock_requests: Mock) -> None:
194+
runner = SmokeTestRunnerOpenSearch(MagicMock(), MagicMock())
195+
info_buffer, error_buffer, info_handler, error_handler = runner.setup_logging_buffers()
196+
197+
logger = logging.getLogger()
198+
assert info_handler in logger.handlers
199+
assert error_handler in logger.handlers
200+
201+
runner.cleanup_logging_handlers(info_handler, error_handler)
202+
203+
assert info_handler not in logger.handlers
204+
assert error_handler not in logger.handlers

0 commit comments

Comments
 (0)
Please sign in to comment.