Skip to content

Commit ec451a2

Browse files
test: Implemented Log execution time per prompt in Report
2 parents 069fc59 + b590fe0 commit ec451a2

6 files changed

Lines changed: 132 additions & 35 deletions

File tree

infra/deploy_ai_foundry.bicep

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ resource applicationInsights 'Microsoft.Insights/components@2020-02-02' = {
6464
Application_Type: 'web'
6565
publicNetworkAccessForIngestion: 'Enabled'
6666
publicNetworkAccessForQuery: 'Enabled'
67-
WorkspaceResourceId: logAnalytics.id
67+
WorkspaceResourceId: useExisting ? existingLogAnalyticsWorkspaceId : logAnalytics.id
6868
}
6969
}
7070

tests/e2e-test/pytest.ini

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,4 @@ log_cli = true
33
log_cli_level = INFO
44
log_file = logs/tests.log
55
log_file_level = INFO
6-
addopts = -p no:warnings
6+
addopts = -p no:warnings --tb=short

tests/e2e-test/readme.MD

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ Installing Playwright Pytest from Virtual Environment
2424

2525
Run test cases
2626

27-
- To run test cases from your 'tests' folder : "pytest --html=report.html --self-contained-html"
27+
- To run test cases from your 'tests/e2e-test' folder : "pytest --html=report.html --self-contained-html"
2828

2929
Create .env file in project root level with web app url and client credentials
3030

tests/e2e-test/requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@ python-dotenv
44
pytest-check
55
pytest-html
66
py
7+
beautifulsoup4

tests/e2e-test/tests/conftest.py

Lines changed: 94 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
1+
import atexit
2+
import io
3+
import logging
14
import os
25

6+
7+
from bs4 import BeautifulSoup
8+
39
from config.constants import URL
410

511
from playwright.sync_api import sync_playwright
612

7-
from py.xml import html # type: ignore
8-
913
import pytest
1014

1115

@@ -31,22 +35,99 @@ def pytest_html_report_title(report):
3135

3236

3337
# Add a column for descriptions
34-
def pytest_html_results_table_header(cells):
35-
cells.insert(1, html.th("Description"))
38+
# def pytest_html_results_table_header(cells):
39+
# cells.insert(1, html.th("Description"))
3640

3741

38-
def pytest_html_results_table_row(report, cells):
39-
cells.insert(
40-
1, html.td(report.description if hasattr(report, "description") else "")
41-
)
42+
# def pytest_html_results_table_row(report, cells):
43+
# cells.insert(
44+
# 1, html.td(report.description if hasattr(report, "description") else "")
45+
# )
46+
47+
48+
log_streams = {}
49+
50+
51+
@pytest.hookimpl(tryfirst=True)
52+
def pytest_runtest_setup(item):
53+
# Prepare StringIO for capturing logs
54+
stream = io.StringIO()
55+
handler = logging.StreamHandler(stream)
56+
handler.setLevel(logging.INFO)
57+
58+
logger = logging.getLogger()
59+
logger.addHandler(handler)
60+
61+
# Save handler and stream
62+
log_streams[item.nodeid] = (handler, stream)
4263

4364

44-
# Add logs and docstring to report
4565
@pytest.hookimpl(hookwrapper=True)
4666
def pytest_runtest_makereport(item, call):
4767
outcome = yield
4868
report = outcome.get_result()
49-
report.description = str(item.function.__doc__)
50-
os.makedirs("logs", exist_ok=True)
51-
extra = getattr(report, "extra", [])
52-
report.extra = extra
69+
70+
handler, stream = log_streams.get(item.nodeid, (None, None))
71+
72+
if handler and stream:
73+
# Make sure logs are flushed
74+
handler.flush()
75+
log_output = stream.getvalue()
76+
77+
# Only remove the handler, don't close the stream yet
78+
logger = logging.getLogger()
79+
logger.removeHandler(handler)
80+
81+
# Store the log output on the report object for HTML reporting
82+
report.description = f"<pre>{log_output.strip()}</pre>"
83+
84+
# Clean up references
85+
log_streams.pop(item.nodeid, None)
86+
else:
87+
report.description = ""
88+
89+
90+
def pytest_collection_modifyitems(items):
91+
for item in items:
92+
if hasattr(item, 'callspec'):
93+
prompt = item.callspec.params.get("prompt")
94+
if prompt:
95+
item._nodeid = prompt # This controls how the test name appears in the report
96+
97+
98+
def rename_duration_column():
99+
report_path = os.path.abspath("report.html") # or your report filename
100+
if not os.path.exists(report_path):
101+
print("Report file not found, skipping column rename.")
102+
return
103+
104+
with open(report_path, 'r', encoding='utf-8') as f:
105+
soup = BeautifulSoup(f, 'html.parser')
106+
107+
# Find and rename the header
108+
headers = soup.select('table#results-table thead th')
109+
for th in headers:
110+
if th.text.strip() == 'Duration':
111+
th.string = 'Execution Time'
112+
# print("Renamed 'Duration' to 'Execution Time'")
113+
break
114+
else:
115+
print("'Duration' column not found in report.")
116+
117+
with open(report_path, 'w', encoding='utf-8') as f:
118+
f.write(str(soup))
119+
120+
121+
# Register this function to run after everything is done
122+
atexit.register(rename_duration_column)
123+
124+
125+
# Add logs and docstring to report
126+
# @pytest.hookimpl(hookwrapper=True)
127+
# def pytest_runtest_makereport(item, call):
128+
# outcome = yield
129+
# report = outcome.get_result()
130+
# report.description = str(item.function.__doc__)
131+
# os.makedirs("logs", exist_ok=True)
132+
# extra = getattr(report, "extra", [])
133+
# report.extra = extra

tests/e2e-test/tests/test_codegen_gp_tc.py

Lines changed: 34 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -5,27 +5,42 @@
55

66
import pytest
77

8-
98
logger = logging.getLogger(__name__)
109

10+
# Define step-wise test actions for Golden Path
11+
golden_path_steps = [
12+
("01. Validate home page is loaded", lambda home: home.validate_home_page()),
13+
("02. Validate Upload of other than SQL files", lambda home: home.upload_unsupported_files()),
14+
("03. Validate Upload input files for SQL only", lambda home: home.upload_files()),
15+
("04. Validate translation process for uploaded files", lambda home: _timed_translation(home)),
16+
("05. Check batch history", lambda home: home.validate_batch_history()),
17+
("06. Download all files and return home", lambda home: home.validate_download_files()),
18+
]
1119

12-
@pytest.mark.testcase_id("TC001")
13-
def test_CodeGen_Golden_path_test(login_logout):
14-
"""Validate Golden path test case for Modernize your code Accelerator"""
15-
page = login_logout
16-
home_page = HomePage(page)
17-
logger.info("Step 1: Validate home page is loaded.")
18-
home_page.validate_home_page()
19-
logger.info("Step 2: Validate Upload of other than SQL files.")
20-
home_page.upload_unsupported_files()
21-
logger.info("Step 3: Validate Upload input files for SQL only.")
22-
home_page.upload_files()
23-
logger.info("Step 4: Validate translation process for uploaded files.")
20+
21+
def _timed_translation(home):
2422
start = time.time()
25-
home_page.validate_translate()
23+
home.validate_translate()
2624
end = time.time()
27-
print(f"Translation process for uploaded files took {end - start:.2f} seconds")
28-
logger.info("Step 5: Check batch history.")
29-
home_page.validate_batch_history()
30-
logger.info("Step 6: Download all files and return home.")
31-
home_page.validate_download_files()
25+
logger.info(f"Translation process for uploaded files took {end - start:.2f} seconds")
26+
27+
28+
@pytest.mark.parametrize("description, action", golden_path_steps, ids=[desc for desc, _ in golden_path_steps])
29+
def test_codegen_golden_path(login_logout, description, action, request):
30+
"""
31+
Executes golden path test steps for Modernize Your Code Accelerator with detailed logging.
32+
"""
33+
request.node._nodeid = description # To improve test output readability
34+
35+
page = login_logout
36+
home = HomePage(page)
37+
38+
logger.info(f"Running test step: {description}")
39+
try:
40+
action(home)
41+
except Exception:
42+
logger.error(f"Step failed: {description}", exc_info=True)
43+
raise
44+
45+
# Optional reporting hook
46+
request.node._report_sections.append(("call", "log", f"Step passed: {description}"))

0 commit comments

Comments
 (0)