Skip to content

Commit fd33de9

Browse files
Merge pull request #319 from microsoft/deploy-v2-pipeline
feat: Added Deploy-v2 pipeline with manual dispatch and input parameter support and Updated Smoke Testing scenarios
2 parents 2f23365 + d8e1cf0 commit fd33de9

File tree

13 files changed

+2024
-72
lines changed

13 files changed

+2024
-72
lines changed

.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

docs/CustomizingAzdParameters.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ By default this template will use the environment name as the prefix to prevent
1717
| `AZURE_ENV_MODEL_VERSION` | string | `2024-08-06` | Specifies the GPT model version (allowed values: `2024-08-06`). |
1818
| `AZURE_ENV_MODEL_CAPACITY` | integer | `30` | Sets the model capacity (choose based on your subscription's available GPT capacity). |
1919
| `AZURE_ENV_IMAGETAG` | boolean | `latest` | Set the Image tag Like (allowed values: latest, dev, hotfix) |
20+
| `AZURE_ENV_CONTAINER_REGISTRY_ENDPOINT` | string | `cpscontainerreg.azurecr.io` | Sets the Azure Container Registry name (allowed value: `cpscontainerreg.azurecr.io`) |
21+
| `AZURE_ENV_CONTAINER_IMAGE_TAG` | string | `latest` | Sets the container image tag (e.g., `latest`, `dev`, `hotfix`). |
22+
| `AZURE_LOCATION` | string | `eastus` | Sets the primary Azure region for resource deployment. |
2023
| `AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID` | string | Guide to get your [Existing Workspace ID](/docs/re-use-log-analytics.md) | Reuses an existing Log Analytics Workspace instead of provisioning a new one. |
2124
| `AZURE_EXISTING_AI_PROJECT_RESOURCE_ID` | string | `<Existing AI Project resource Id>` | Reuses an existing AIFoundry and AIFoundryProject instead of creating a new one. |
2225

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)