Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
873ad0c
Added Test Automation Scripts and Pipeline
Harsh-Microsoft May 30, 2025
f7a84e8
Update Azure CLI login step to include client secret
Harsh-Microsoft May 30, 2025
98e791c
Refactor Azure CLI login step to use a single creds JSON string for a…
Harsh-Microsoft May 30, 2025
76d9758
Update AKS resource group and name references in test automation work…
Harsh-Microsoft May 30, 2025
96c5987
Merge pull request #387 from microsoft/main
Prajwal-Microsoft May 30, 2025
4fb8b8d
Merge branch 'dev' into migrate-test-automation
Harsh-Microsoft May 30, 2025
2af9c2b
Update email notification body to include hyperlinks for Run URL and …
Harsh-Microsoft Jun 2, 2025
a6ddd23
rename test automation workflow file
Harsh-Microsoft Jun 2, 2025
115d811
folder renamed for test automatioon
Harsh-Microsoft Jun 2, 2025
5e40115
renaming Test Automation script folder
Harsh-Microsoft Jun 2, 2025
57d6b8a
test: Migrate test automation scripts and pipeline for DKM
Avijit-Microsoft Jun 2, 2025
d255fee
fix: Escape quotes in email notification body for Run URL and Test Re…
Harsh-Microsoft Jun 3, 2025
02b5528
test: Escape quotes in email notification body in test automation wor…
Avijit-Microsoft Jun 3, 2025
add344d
test: DKM - Create individual test case for each prompt and capture e…
Ritesh-Microsoft Jun 5, 2025
f4abab7
test: DKM - Create individual test case for each prompt and capture e…
Avijit-Microsoft Jun 5, 2025
3caed68
Added support for reusing existing Resource Groups by introducing two…
Prasanjeet-Microsoft Jun 6, 2025
8923f8a
Added resourceprefix.bicep file to standardize and simplify resource…
Prasanjeet-Microsoft Jun 6, 2025
8686300
Merge pull request #392 from microsoft/PSL-US-18607
Prajwal-Microsoft Jun 9, 2025
55164a3
Updated CI pipeline to dynamically generate a unique environment name
Prasanjeet-Microsoft Jun 12, 2025
a1c6131
Merge pull request #395 from microsoft/update_CI_workflow
Prajwal-Microsoft Jun 13, 2025
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
431 changes: 219 additions & 212 deletions .github/workflows/CI.yml

Large diffs are not rendered by default.

130 changes: 130 additions & 0 deletions .github/workflows/test-automation.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
name: Test Automation DKM

on:
push:
branches:
- main
- dev
paths:
- 'tests/e2e-test/**'
schedule:
- cron: '0 13 * * *' # Runs at 1 PM UTC
workflow_dispatch:

env:
url: ${{ vars.DKM_URL }}
accelerator_name: "DKM"

jobs:
test:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.13'

- name: Azure CLI Login
uses: azure/login@v2
with:
creds: '{"clientId":"${{ secrets.AZURE_CLIENT_ID }}","clientSecret":"${{ secrets.AZURE_CLIENT_SECRET }}","subscriptionId":"${{ secrets.AZURE_SUBSCRIPTION_ID }}","tenantId":"${{ secrets.AZURE_TENANT_ID }}"}'

- name: Start AKS
id: start-aks
uses: azure/cli@v2
with:
azcliversion: 'latest'
inlineScript: |
az aks install-cli
if [ "$(az aks show --resource-group ${{ vars.DKM_RG }} --name ${{ vars.DKM_AKS_NAME }} --query "powerState.code" -o tsv)" = "Running" ]; then echo "AKS is running"; else az aks start --resource-group ${{ vars.DKM_RG }} --name ${{ vars.DKM_AKS_NAME }}; fi

- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r tests/e2e-test/requirements.txt

- name: Ensure browsers are installed
run: python -m playwright install --with-deps chromium

- name: Run tests(1)
id: test1
run: |
xvfb-run pytest --headed --html=report/report.html --self-contained-html
working-directory: tests/e2e-test
continue-on-error: true

- name: Sleep for 30 seconds
if: ${{ steps.test1.outcome == 'failure' }}
run: sleep 30s
shell: bash

- name: Run tests(2)
id: test2
if: ${{ steps.test1.outcome == 'failure' }}
run: |
xvfb-run pytest --headed --html=report/report.html --self-contained-html
working-directory: tests/e2e-test
continue-on-error: true

- name: Sleep for 60 seconds
if: ${{ steps.test2.outcome == 'failure' }}
run: sleep 60s
shell: bash

- name: Run tests(3)
id: test3
if: ${{ steps.test2.outcome == 'failure' }}
run: |
xvfb-run pytest --headed --html=report/report.html --self-contained-html
working-directory: tests/e2e-test

- name: Upload test report
id: upload_report
uses: actions/upload-artifact@v4
if: ${{ !cancelled() }}
with:
name: test-report
path: tests/e2e-test/report/*

- name: Send Notification
if: always()
run: |
RUN_URL="https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}"
REPORT_URL=${{ steps.upload_report.outputs.artifact-url }}
IS_SUCCESS=${{ steps.test1.outcome == 'success' || steps.test2.outcome == 'success' || steps.test3.outcome == 'success' }}
# Construct the email body
if [ "$IS_SUCCESS" = "true" ]; then
EMAIL_BODY=$(cat <<EOF
{
"body": "<p>Dear Team,</p><p>We would like to inform you that the ${{ env.accelerator_name }} Test Automation process has completed successfully.</p><p><strong>Run URL:</strong> <a href=\"${RUN_URL}\">${RUN_URL}</a><br></p><p><strong>Test Report:</strong> <a href=\"${REPORT_URL}\">${REPORT_URL}</a></p><p>Best regards,<br>Your Automation Team</p>",
"subject": "${{ env.accelerator_name }} Test Automation - Success"
}
EOF
)
else
EMAIL_BODY=$(cat <<EOF
{
"body": "<p>Dear Team,</p><p>We would like to inform you that the ${{ env.accelerator_name }} Test Automation process has encountered an issue and has failed to complete successfully.</p><p><strong>Run URL:</strong> <a href=\"${RUN_URL}\">${RUN_URL}</a><br></p><p><strong>Test Report:</strong> <a href=\"${REPORT_URL}\">${REPORT_URL}</a></p><p>Please investigate the matter at your earliest convenience.</p><p>Best regards,<br>Your Automation Team</p>",
"subject": "${{ env.accelerator_name }} Test Automation - Failure"
}
EOF
)
fi

# Send the notification
curl -X POST "${{ secrets.EMAILNOTIFICATION_LOGICAPP_URL_TA }}" \
-H "Content-Type: application/json" \
-d "$EMAIL_BODY" || echo "Failed to send notification"

- name: Stop AKS
if: always()
uses: azure/cli@v2
with:
azcliversion: 'latest'
inlineScript: |
az aks install-cli
if [ "$(az aks show --resource-group ${{ vars.DKM_RG }} --name ${{ vars.DKM_AKS_NAME }} --query "powerState.code" -o tsv)" = "Running" ]; then az aks stop --resource-group ${{ vars.DKM_RG }} --name ${{ vars.DKM_AKS_NAME }}; else echo "AKS is already stopped"; fi
az logout
63 changes: 37 additions & 26 deletions Deployment/main.bicep
Original file line number Diff line number Diff line change
@@ -1,57 +1,67 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

targetScope = 'resourceGroup'

@minLength(3)
@maxLength(20)
@description('A unique prefix for all resources in this deployment. This should be 3-20 characters long:')
param environmentName string

@description('The Data Center where the model is deployed.')
param modeldatacenter string
var abbrs = loadJsonContent('./abbreviations.json')

targetScope = 'subscription'
var resourceprefix = padLeft(take(uniqueString(deployment().name), 5), 5, '0')
@description('Azure data center region where resources will be deployed. This should be a valid Azure region, e.g., eastus, westus, etc.')
param location string

var uniqueId = toLower(uniqueString(subscription().id, environmentName, location))
var resourceprefix = padLeft(take(uniqueId, 10), 10, '0')
var resourceprefix_name = 'kmgs'

// Create a resource group
resource gs_resourcegroup 'Microsoft.Resources/resourceGroups@2021-04-01' = {
name: '${abbrs.managementGovernance.resourceGroup}${resourceprefix_name}${resourceprefix}'
location: deployment().location
}
var resourceGroupLocation = resourceGroup().location

// Load the abbrevations file required to name the azure resources.
var abbrs = loadJsonContent('./abbreviations.json')


// Create a storage account
module gs_storageaccount 'bicep/azurestorageaccount.bicep' = {
name: '${abbrs.storage.storageAccount}${resourceprefix_name}${resourceprefix}'
scope: gs_resourcegroup
scope: resourceGroup()
params: {
storageAccountName: '${abbrs.storage.storageAccount}${resourceprefix}'
location: deployment().location
location: resourceGroupLocation
}
}

// Create a Azure Search Service
module gs_azsearch 'bicep/azuresearch.bicep' = {
name: '${abbrs.ai.aiSearch}${resourceprefix_name}${resourceprefix}'
scope: gs_resourcegroup
scope: resourceGroup()
params: {
searchServiceName: '${abbrs.ai.aiSearch}${resourceprefix}'
location: deployment().location
location: resourceGroupLocation
}
}


// Create Container Registry
module gs_containerregistry 'bicep/azurecontainerregistry.bicep' = {
name: '${abbrs.containers.containerRegistry}${resourceprefix_name}${resourceprefix}'
scope: gs_resourcegroup
scope: resourceGroup()
params: {
acrName: '${abbrs.containers.containerRegistry}${resourceprefix_name}${resourceprefix}'
location: deployment().location
location: resourceGroupLocation
}
}

// Create AKS Cluster
module gs_aks 'bicep/azurekubernetesservice.bicep' = {
name: '${abbrs.compute.arcEnabledKubernetesCluster}${resourceprefix_name}${resourceprefix}'
scope: gs_resourcegroup
scope: resourceGroup()
params: {
aksName: '${abbrs.compute.arcEnabledKubernetesCluster}${resourceprefix_name}${resourceprefix}'
location: deployment().location
location: resourceGroupLocation
}
dependsOn: [
gs_containerregistry
Expand All @@ -76,7 +86,7 @@ module gs_aks 'bicep/azurekubernetesservice.bicep' = {
// Create Azure Cognitive Service
module gs_azcognitiveservice 'bicep/azurecognitiveservice.bicep' = {
name: '${abbrs.ai.documentIntelligence}${resourceprefix_name}${resourceprefix}'
scope: gs_resourcegroup
scope: resourceGroup()
params: {
cognitiveServiceName: '${abbrs.ai.documentIntelligence}${resourceprefix_name}${resourceprefix}'
location: 'eastus'
Expand All @@ -86,7 +96,7 @@ module gs_azcognitiveservice 'bicep/azurecognitiveservice.bicep' = {
// Create Azure Open AI Service
module gs_openaiservice 'bicep/azureopenaiservice.bicep' = {
name: '${abbrs.ai.openAIService}${resourceprefix_name}${resourceprefix}'
scope: gs_resourcegroup
scope: resourceGroup()
params: {
openAIServiceName: '${abbrs.ai.openAIService}${resourceprefix_name}${resourceprefix}'
// GPT-4-32K model & GPT-4o available Data center information.
Expand All @@ -99,7 +109,7 @@ module gs_openaiservice 'bicep/azureopenaiservice.bicep' = {
// Set the minimum capacity of each model
// Based on customer's Model capacity, it needs to be updated in Azure Portal.
module gs_openaiservicemodels_gpt4o 'bicep/azureopenaiservicemodel.bicep' = {
scope: gs_resourcegroup
scope: resourceGroup()
name: 'gpt-4o-mini'
params: {
parentResourceName: gs_openaiservice.outputs.openAIServiceName
Expand All @@ -119,7 +129,7 @@ module gs_openaiservicemodels_gpt4o 'bicep/azureopenaiservicemodel.bicep' = {
}

module gs_openaiservicemodels_text_embedding 'bicep/azureopenaiservicemodel.bicep' = {
scope: gs_resourcegroup
scope: resourceGroup()
name: 'text-embedding-large'
params: {
parentResourceName: gs_openaiservice.outputs.openAIServiceName
Expand All @@ -140,25 +150,26 @@ module gs_openaiservicemodels_text_embedding 'bicep/azureopenaiservicemodel.bice
// Create Azure Cosmos DB Mongo
module gs_cosmosdb 'bicep/azurecosmosdb.bicep' = {
name: '${abbrs.databases.cosmosDBDatabase}${resourceprefix_name}${resourceprefix}'
scope: gs_resourcegroup
scope: resourceGroup()
params: {
cosmosDbAccountName: '${abbrs.databases.cosmosDBDatabase}${resourceprefix_name}${resourceprefix}'
location: deployment().location
location: resourceGroupLocation
}
}

// Create Azure App Configuration
module gs_appconfig 'bicep/azureappconfigservice.bicep' = {
name: 'appconfig-${resourceprefix_name}${resourceprefix}'
scope: gs_resourcegroup
scope: resourceGroup()
params: {
appConfigName: 'appconfig-${resourceprefix_name}${resourceprefix}'
location: deployment().location
location: resourceGroupLocation
}
}

// return all resource names as a output
output gs_resourcegroup_name string = '${abbrs.managementGovernance.resourceGroup}${resourceprefix_name}${resourceprefix}'
// output gs_resourcegroup_name string = '${abbrs.managementGovernance.resourceGroup}${resourceprefix_name}${resourceprefix}'
output gs_resourcegroup_name string = resourceGroup().name
output gs_solution_prefix string = '${resourceprefix_name}${resourceprefix}'
output gs_storageaccount_name string = gs_storageaccount.outputs.storageAccountName
output gs_azsearch_name string = gs_azsearch.outputs.searchServiceName
Expand Down Expand Up @@ -189,5 +200,5 @@ output gs_appconfig_endpoint string = gs_appconfig.outputs.appConfigEndpoint
output gs_containerregistry_endpoint string = gs_containerregistry.outputs.acrEndpoint

//return resourcegroup resource ID
output gs_resourcegroup_id string = gs_resourcegroup.id
output gs_resourcegroup_id string = resourceGroup().id

9 changes: 9 additions & 0 deletions Deployment/resourcePrefix.bicep
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
targetScope = 'subscription'

param environmentName string
param location string

var uniqueId = toLower(uniqueString(subscription().id, environmentName, location))
var resourceprefix = padLeft(take(uniqueId, 10), 10, '0')

output resourcePrefix string = resourceprefix
Loading