Skip to content

Commit 5c92826

Browse files
Added Deploy-v2 pipeline with manual dispatch and input parameter support and Update E2e folder with Smoke Testing scenarios
1 parent 2f23365 commit 5c92826

13 files changed

Lines changed: 2021 additions & 75 deletions

File tree

.github/workflows/deploy-v2.yml

Lines changed: 893 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
name: Test Automation Content Processing-v2
2+
3+
on:
4+
workflow_call:
5+
inputs:
6+
CP_WEB_URL:
7+
required: true
8+
type: string
9+
description: "Web URL for Content Processing"
10+
TEST_SUITE:
11+
required: false
12+
type: string
13+
default: "GoldenPath-Testing"
14+
description: "Test suite to run: 'Smoke-Testing', 'GoldenPath-Testing' "
15+
secrets:
16+
EMAILNOTIFICATION_LOGICAPP_URL_TA:
17+
required: false
18+
description: "Logic App URL for email notifications"
19+
outputs:
20+
TEST_SUCCESS:
21+
description: "Whether tests passed"
22+
value: ${{ jobs.test.outputs.TEST_SUCCESS }}
23+
TEST_REPORT_URL:
24+
description: "URL to test report artifact"
25+
value: ${{ jobs.test.outputs.TEST_REPORT_URL }}
26+
27+
env:
28+
url: ${{ inputs.CP_WEB_URL }}
29+
accelerator_name: "Content Processing"
30+
test_suite: ${{ inputs.TEST_SUITE }}
31+
32+
jobs:
33+
test:
34+
runs-on: ubuntu-latest
35+
outputs:
36+
TEST_SUCCESS: ${{ steps.test1.outcome == 'success' || steps.test2.outcome == 'success' || steps.test3.outcome == 'success' }}
37+
TEST_REPORT_URL: ${{ steps.upload_report.outputs.artifact-url }}
38+
steps:
39+
- name: Checkout repository
40+
uses: actions/checkout@v5
41+
42+
- name: Set up Python
43+
uses: actions/setup-python@v6
44+
with:
45+
python-version: '3.13'
46+
47+
- name: Login to Azure
48+
run: |
49+
az login --service-principal -u ${{ secrets.AZURE_CLIENT_ID }} -p ${{ secrets.AZURE_CLIENT_SECRET }} --tenant ${{ secrets.AZURE_TENANT_ID }}
50+
az account set --subscription ${{ secrets.AZURE_SUBSCRIPTION_ID }}
51+
52+
- name: Install dependencies
53+
run: |
54+
python -m pip install --upgrade pip
55+
pip install -r tests/e2e-test/requirements.txt
56+
57+
- name: Ensure browsers are installed
58+
run: python -m playwright install --with-deps chromium
59+
60+
- name: Validate URL
61+
run: |
62+
if [ -z "${{ env.url }}" ]; then
63+
echo "ERROR: No URL provided for testing"
64+
exit 1
65+
fi
66+
echo "Testing URL: ${{ env.url }}"
67+
echo "Test Suite: ${{ env.test_suite }}"
68+
69+
70+
- name: Wait for Application to be Ready
71+
run: |
72+
echo "Waiting for application to be ready at ${{ env.url }} "
73+
max_attempts=10
74+
attempt=1
75+
76+
while [ $attempt -le $max_attempts ]; do
77+
echo "Attempt $attempt: Checking if application is ready..."
78+
if curl -f -s "${{ env.url }}" > /dev/null; then
79+
echo "Application is ready!"
80+
break
81+
82+
fi
83+
84+
if [ $attempt -eq $max_attempts ]; then
85+
echo "Application is not ready after $max_attempts attempts"
86+
exit 1
87+
fi
88+
89+
echo "Application not ready, waiting 30 seconds..."
90+
sleep 30
91+
attempt=$((attempt + 1))
92+
done
93+
94+
- name: Run tests(1)
95+
id: test1
96+
run: |
97+
if [ "${{ env.test_suite }}" == "GoldenPath-Testing" ]; then
98+
xvfb-run pytest -m gp --headed --html=report/report.html --self-contained-html
99+
else
100+
xvfb-run pytest --headed --html=report/report.html --self-contained-html
101+
fi
102+
working-directory: tests/e2e-test
103+
continue-on-error: true
104+
105+
- name: Sleep for 30 seconds
106+
if: ${{ steps.test1.outcome == 'failure' }}
107+
run: sleep 30s
108+
shell: bash
109+
110+
- name: Run tests(2)
111+
id: test2
112+
if: ${{ steps.test1.outcome == 'failure' }}
113+
run: |
114+
if [ "${{ env.test_suite }}" == "GoldenPath-Testing" ]; then
115+
xvfb-run pytest -m gp --headed --html=report/report.html --self-contained-html
116+
else
117+
xvfb-run pytest --headed --html=report/report.html --self-contained-html
118+
fi
119+
working-directory: tests/e2e-test
120+
continue-on-error: true
121+
122+
- name: Sleep for 60 seconds
123+
if: ${{ steps.test2.outcome == 'failure' }}
124+
run: sleep 60s
125+
shell: bash
126+
127+
- name: Run tests(3)
128+
id: test3
129+
if: ${{ steps.test2.outcome == 'failure' }}
130+
run: |
131+
if [ "${{ env.test_suite }}" == "GoldenPath-Testing" ]; then
132+
xvfb-run pytest -m gp --headed --html=report/report.html --self-contained-html
133+
else
134+
xvfb-run pytest --headed --html=report/report.html --self-contained-html
135+
fi
136+
working-directory: tests/e2e-test
137+
138+
- name: Upload test report
139+
id: upload_report
140+
uses: actions/upload-artifact@v4
141+
if: ${{ !cancelled() }}
142+
with:
143+
name: test-report
144+
path: tests/e2e-test/report/*
145+
146+
- name: Generate E2E Test Summary
147+
if: always()
148+
run: |
149+
# Determine test suite type for title
150+
if [ "${{ env.test_suite }}" == "GoldenPath-Testing" ]; then
151+
echo "## 🧪 E2E Test Job Summary : Golden Path Testing" >> $GITHUB_STEP_SUMMARY
152+
else
153+
echo "## 🧪 E2E Test Job Summary : Smoke Testing" >> $GITHUB_STEP_SUMMARY
154+
fi
155+
echo "" >> $GITHUB_STEP_SUMMARY
156+
echo "| Field | Value |" >> $GITHUB_STEP_SUMMARY
157+
echo "|-------|--------|" >> $GITHUB_STEP_SUMMARY
158+
159+
# Determine overall test result
160+
OVERALL_SUCCESS="${{ steps.test1.outcome == 'success' || steps.test2.outcome == 'success' || steps.test3.outcome == 'success' }}"
161+
if [[ "$OVERALL_SUCCESS" == "true" ]]; then
162+
echo "| **Job Status** | ✅ Success |" >> $GITHUB_STEP_SUMMARY
163+
else
164+
echo "| **Job Status** | ❌ Failed |" >> $GITHUB_STEP_SUMMARY
165+
fi
166+
167+
echo "| **Target URL** | [${{ env.url }}](${{ env.url }}) |" >> $GITHUB_STEP_SUMMARY
168+
echo "| **Test Suite** | \`${{ env.test_suite }}\` |" >> $GITHUB_STEP_SUMMARY
169+
echo "| **Test Report** | [Download Artifact](${{ steps.upload_report.outputs.artifact-url }}) |" >> $GITHUB_STEP_SUMMARY
170+
echo "" >> $GITHUB_STEP_SUMMARY
171+
172+
echo "### 📋 Test Execution Details" >> $GITHUB_STEP_SUMMARY
173+
echo "| Attempt | Status | Notes |" >> $GITHUB_STEP_SUMMARY
174+
echo "|---------|--------|-------|" >> $GITHUB_STEP_SUMMARY
175+
echo "| **Test Run 1** | ${{ steps.test1.outcome == 'success' && '✅ Passed' || '❌ Failed' }} | Initial test execution |" >> $GITHUB_STEP_SUMMARY
176+
177+
if [[ "${{ steps.test1.outcome }}" == "failure" ]]; then
178+
echo "| **Test Run 2** | ${{ steps.test2.outcome == 'success' && '✅ Passed' || steps.test2.outcome == 'failure' && '❌ Failed' || '⏸️ Skipped' }} | Retry after 30s delay |" >> $GITHUB_STEP_SUMMARY
179+
fi
180+
181+
if [[ "${{ steps.test2.outcome }}" == "failure" ]]; then
182+
echo "| **Test Run 3** | ${{ steps.test3.outcome == 'success' && '✅ Passed' || steps.test3.outcome == 'failure' && '❌ Failed' || '⏸️ Skipped' }} | Final retry after 60s delay |" >> $GITHUB_STEP_SUMMARY
183+
fi
184+
185+
echo "" >> $GITHUB_STEP_SUMMARY
186+
187+
if [[ "$OVERALL_SUCCESS" == "true" ]]; then
188+
echo "### ✅ Test Results" >> $GITHUB_STEP_SUMMARY
189+
echo "- End-to-end tests completed successfully" >> $GITHUB_STEP_SUMMARY
190+
echo "- Application is functioning as expected" >> $GITHUB_STEP_SUMMARY
191+
else
192+
echo "### ❌ Test Results" >> $GITHUB_STEP_SUMMARY
193+
echo "- All test attempts failed" >> $GITHUB_STEP_SUMMARY
194+
echo "- Check the e2e-test/test job for detailed error information" >> $GITHUB_STEP_SUMMARY
195+
fi

README.md

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,6 @@ These capabilities can be applied to numerous use cases including: contract proc
1212
</div>
1313
<br/>
1414

15-
**Note:** With any AI solutions you create using these templates, you are responsible for assessing all associated risks and for complying with all applicable laws and safety standards. Learn more in the transparency documents for [Agent Service](https://learn.microsoft.com/en-us/azure/ai-foundry/responsible-ai/agents/transparency-note) and [Agent Framework](https://github.com/microsoft/agent-framework/blob/main/TRANSPARENCY_FAQ.md).
16-
<br/>
17-
1815
<h2><img src="./docs/images/readme/solution-overview.png" width="48" />
1916
Solution overview
2017
</h2>

infra/main.bicep

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,9 @@ param secondaryLocation string = (location == 'eastus2') ? 'westus2' : 'eastus2'
6060
@description('Optional. The public container image endpoint.')
6161
param publicContainerImageEndpoint string = 'cpscontainerreg.azurecr.io'
6262

63+
@description('Optional. The image tag for the container images.')
64+
param imageTag string = 'latest'
65+
6366
@description('Optional. The resource group location.')
6467
param resourceGroupLocation string = resourceGroup().location
6568

@@ -717,7 +720,7 @@ module avmContainerApp 'br/public:avm/res/app/container-app:0.17.0' = {
717720
containers: [
718721
{
719722
name: 'ca-${solutionSuffix}'
720-
image: '${publicContainerImageEndpoint}/contentprocessor:latest'
723+
image: '${publicContainerImageEndpoint}/contentprocessor:${imageTag}'
721724

722725
resources: {
723726
cpu: '4'
@@ -766,7 +769,7 @@ module avmContainerApp_API 'br/public:avm/res/app/container-app:0.17.0' = {
766769
containers: [
767770
{
768771
name: 'ca-${solutionSuffix}-api'
769-
image: '${publicContainerImageEndpoint}/contentprocessorapi:latest'
772+
image: '${publicContainerImageEndpoint}/contentprocessorapi:${imageTag}'
770773
resources: {
771774
cpu: '4'
772775
memory: '8.0Gi'
@@ -896,7 +899,7 @@ module avmContainerApp_Web 'br/public:avm/res/app/container-app:0.17.0' = {
896899
containers: [
897900
{
898901
name: 'ca-${solutionSuffix}-web'
899-
image: '${publicContainerImageEndpoint}/contentprocessorweb:latest'
902+
image: '${publicContainerImageEndpoint}/contentprocessorweb:${imageTag}'
900903
resources: {
901904
cpu: '4'
902905
memory: '8.0Gi'
@@ -1190,7 +1193,7 @@ module avmContainerApp_update 'br/public:avm/res/app/container-app:0.17.0' = {
11901193
containers: [
11911194
{
11921195
name: 'ca-${solutionSuffix}'
1193-
image: '${publicContainerImageEndpoint}/contentprocessor:latest'
1196+
image: '${publicContainerImageEndpoint}/contentprocessor:${imageTag}'
11941197

11951198
resources: {
11961199
cpu: '4'
@@ -1250,7 +1253,7 @@ module avmContainerApp_API_update 'br/public:avm/res/app/container-app:0.17.0' =
12501253
containers: [
12511254
{
12521255
name: 'ca-${solutionSuffix}-api'
1253-
image: '${publicContainerImageEndpoint}/contentprocessorapi:latest'
1256+
image: '${publicContainerImageEndpoint}/contentprocessorapi:${imageTag}'
12541257
resources: {
12551258
cpu: '4'
12561259
memory: '8.0Gi'

infra/main.parameters.json

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,15 @@
3131
},
3232
"existingFoundryProjectResourceId": {
3333
"value": "${AZURE_ENV_FOUNDRY_PROJECT_ID}"
34+
},
35+
"publicContainerImageEndpoint": {
36+
"value": "${AZURE_ENV_CONTAINER_REGISTRY_ENDPOINT}"
37+
},
38+
"imageTag": {
39+
"value": "${AZURE_ENV_CONTAINER_IMAGE_TAG}"
40+
},
41+
"location": {
42+
"value": "${AZURE_LOCATION}"
3443
}
3544
}
3645
}

infra/main.waf.parameters.json

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,15 @@
4646
},
4747
"virtualMachineAdminPassword": {
4848
"value": "${AZURE_ENV_VM_ADMIN_PASSWORD}"
49+
},
50+
"publicContainerImageEndpoint": {
51+
"value": "${AZURE_ENV_CONTAINER_REGISTRY_ENDPOINT}"
52+
},
53+
"imageTag": {
54+
"value": "${AZURE_ENV_CONTAINER_IMAGE_TAG}"
55+
},
56+
"location": {
57+
"value": "${AZURE_LOCATION}"
4958
}
5059
}
5160
}

tests/e2e-test/base/base.py

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,38 @@
1+
"""
2+
Base page module providing common functionality for all page objects.
3+
"""
4+
5+
16
class BasePage:
7+
"""Base class for all page objects with common methods."""
8+
29
def __init__(self, page):
10+
"""
11+
Initialize the BasePage with a Playwright page instance.
12+
13+
Args:
14+
page: Playwright page object
15+
"""
316
self.page = page
417

518
def scroll_into_view(self, locator):
19+
"""
20+
Scroll the last element matching the locator into view.
21+
22+
Args:
23+
locator: Playwright locator object
24+
"""
625
reference_list = locator
726
locator.nth(reference_list.count() - 1).scroll_into_view_if_needed()
827

928
def is_visible(self, locator):
10-
locator.is_visible()
29+
"""
30+
Check if an element is visible on the page.
31+
32+
Args:
33+
locator: Playwright locator object
34+
35+
Returns:
36+
bool: True if visible, False otherwise
37+
"""
38+
return locator.is_visible()

tests/e2e-test/config/constants.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
1+
"""
2+
Configuration constants module for test environment settings.
3+
"""
4+
15
import os
26

37
from dotenv import load_dotenv
48

59
load_dotenv()
610
URL = os.getenv("url")
7-
if URL.endswith("/"):
11+
if URL and URL.endswith("/"):
812
URL = URL[:-1]

0 commit comments

Comments
 (0)