Skip to content

Integration tests

Integration tests #305

Workflow file for this run

name: Integration tests
on:
workflow_call:
inputs:
resource-group:
description: Resource group for cluster creation
type: string
required: true
default: ops-cli-int-test-rg
runtime-init-args:
description: Additional INIT arguments (beyond cluster name, resource group, schema registry).
type: string
required: false
default: ''
runtime-create-args:
description: Additional CREATE arguments (beyond cluster name, resource group, instance name).
type: string
required: false
default: ''
custom-locations-oid:
description: Custom Locations OID
type: string
required: false
default: '51dfe1e8-70c6-4de5-a08e-e18aff23d815'
init-continue-on-error:
description: Continue on error for init integration tests
type: boolean
required: false
default: true
use-container:
description: Build container image for tests
type: boolean
required: false
default: false
secrets:
# required for az login
AZURE_CLIENT_ID:
required: true
AZURE_TENANT_ID:
required: true
AZURE_SUBSCRIPTION_ID:
required: true
workflow_dispatch:
inputs:
resource-group:
description: Resource group for cluster creation
type: string
required: true
default: ops-cli-int-test-rg
custom-locations-oid:
description: Object ID of Custom Locations RP
type: string
required: false
default: '51dfe1e8-70c6-4de5-a08e-e18aff23d815'
runtime-init-args:
description: Additional INIT arguments (beyond cluster name, resource group, schema registry).
type: string
required: false
default: ''
runtime-create-args:
description: Additional CREATE arguments (beyond cluster name, resource group, instance name).
type: string
required: false
default: ''
init-continue-on-error:
description: Continue on error for init integration tests
type: boolean
required: false
default: true
use-container:
description: Build container image for tests
type: boolean
required: false
default: false
permissions:
# required for OpenID federation
contents: 'read'
id-token: 'write'
env:
RESOURCE_GROUP: "${{ inputs.resource-group }}"
K3S_VERSION: "v1.28.5+k3s1"
CUSTOM_LOCATIONS_OID: "${{ inputs.custom-locations-oid }}"
jobs:
test:
env:
CLUSTER_NAME: "opt${{ github.run_number }}${{ matrix.feature }}"
INSTANCE_NAME: "inst${{ github.run_number }}${{ matrix.feature }}"
KEYVAULT_NAME: "kv${{ github.run_number }}"
strategy:
fail-fast: false
matrix:
feature: [secretsync] # [custom-input, default, insecure-listener, syncrules, redeploy, trustbundle]
# runtime-args:
# - ${{ inputs.runtime-init-args != '' || inputs.runtime-create-args != '' }}
# exclude:
# - feature: custom-input
# runtime-args: false
# - feature: default
# runtime-args: true
# - feature: insecure-listener
# runtime-args: true
# - feature: syncrules
# runtime-args: true
# - feature: redeploy
# runtime-args: true
# - feature: trustbundle
# runtime-args: true
name: "Run cluster tests"
runs-on: ubuntu-22.04
steps:
- name: "Determine Init Args"
id: "init"
run: |
echo "NO_PREFLIGHT=false" >> $GITHUB_OUTPUT
if [[ ${{ matrix.feature }} == "insecure-listener" ]]; then
echo "CREATE_ARG=--add-insecure-listener --broker-listener-type NodePort" >> $GITHUB_OUTPUT
echo "NO_PREFLIGHT=true" >> $GITHUB_OUTPUT
elif [[ ${{ matrix.feature }} == "syncrules" ]]; then
echo "CREATE_ARG=--enable-rsync" >> $GITHUB_OUTPUT
elif [[ ${{ matrix.feature }} == "custom-input" ]]; then
echo "CREATE_ARG=${{ inputs.runtime-create-args }}" >> $GITHUB_OUTPUT
echo "INIT_ARG=${{ inputs.runtime-init-args }}" >> $GITHUB_OUTPUT
elif [[ ${{ matrix.feature }} == "trustbundle" ]]; then
echo "CREATE_ARG=--trust-settings configMapName=example-bundle configMapKey=trust-bundle.pem issuerKind=Issuer issuerName=selfsigned-issuer " >> $GITHUB_OUTPUT
echo "INIT_ARG=--user-trust true" >> $GITHUB_OUTPUT
fi
- name: "Output variables for future steps"
id: "env_out"
run: |
echo "RESOURCE_GROUP=${{ env.RESOURCE_GROUP }}" >> $GITHUB_OUTPUT
echo "CLUSTER_NAME=${{ env.CLUSTER_NAME }}" >> $GITHUB_OUTPUT
echo "INSTANCE_NAME=${{ env.INSTANCE_NAME }}" >> $GITHUB_OUTPUT
- name: "Setup python"
uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: "Checkout extension source for build"
uses: actions/checkout@v4
- name: "Build and install local IoT Ops extension from source"
run: |
pip install -r dev_requirements.txt
python -m setup bdist_wheel -d dist
wheel=$(find ./dist/*.whl)
az extension add --source $wheel -y
- name: "Create k3s cluster"
uses: ./.github/actions/create-k3s-cluster
- name: "Apply custom cluster issuer"
if: ${{ matrix.feature == 'trustbundle' || contains(inputs.runtime-init-args, '--user-trust') }}
run: |
set -x
helm repo add jetstack https://charts.jetstack.io --force-update
helm install \
cert-manager jetstack/cert-manager \
--namespace cert-manager \
--create-namespace \
--version v1.13.6 \
--set installCRDs=true \
--set startupapicheck.timeout=5m
kubectl create namespace azure-iot-operations
helm upgrade trust-manager jetstack/trust-manager \
--install \
--namespace cert-manager \
--set app.trust.namespace=cert-manager \
--wait
kubectl apply -f - <<EOF
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
name: selfsigned-issuer
namespace: cert-manager
spec:
selfSigned: {}
---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: trust-manager-example-ca
namespace: cert-manager
spec:
isCA: true
commonName: trust-manager-example-ca
secretName: trust-manager-example-ca-secret
privateKey:
algorithm: ECDSA
size: 256
issuerRef:
name: selfsigned-issuer
kind: Issuer
group: cert-manager.io
EOF
kubectl apply -f - <<EOF
apiVersion: trust.cert-manager.io/v1alpha1
kind: Bundle
metadata:
name: example-bundle
namespace: cert-manager
spec:
sources:
- useDefaultCAs: true
- secret:
name: "trust-manager-example-ca-secret"
key: "tls.crt"
target:
configMap:
key: "trust-bundle.pem"
namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: azure-iot-operations
EOF
kubectl apply -f - <<EOF
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
name: selfsigned-issuer
namespace: azure-iot-operations
spec:
selfSigned: {}
EOF
- name: "Tox test environment setup for init"
run: |
python -m pip install tox
tox r -vv -e python-init-int --notest
- name: "Tox test environment setup for integration tests"
if: ${{ matrix.feature == 'default' && !inputs.use-container }}
run: |
tox r -vv -e "python-all-int" --notest
- name: "Tox test environment setup for integration tests"
if: ${{ matrix.feature == 'secretsync' && !inputs.use-container }}
run: |
tox r -vv -e "python-secretsync-int" --notest
- name: "Az CLI login"
uses: azure/login@v2
with:
client-id: ${{ secrets.AZURE_CLIENT_ID }}
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
- name: "ARC connect cluster"
uses: ./.github/actions/connect-arc
with:
cluster-name: ${{ env.CLUSTER_NAME }}
resource-group: ${{ env.RESOURCE_GROUP }}
custom-locations-oid: ${{ env.CUSTOM_LOCATIONS_OID }}
enable-workload-identity: ${{ matrix.feature == 'secretsync' }}
- name: "Az CLI login"
if: ${{ matrix.feature == 'secretsync' && !inputs.use-container }}
uses: azure/login@v2
with:
client-id: ${{ secrets.AZURE_CLIENT_ID }}
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
- name: "Tox INIT Integration Tests"
env:
AIO_CLI_INIT_PREFLIGHT_DISABLED: ${{ steps.init.outputs.NO_PREFLIGHT }}
azext_edge_init_continue_on_error: ${{ inputs.init-continue-on-error || '' }}
azext_edge_rg: ${{ steps.env_out.outputs.RESOURCE_GROUP }}
azext_edge_cluster: ${{ steps.env_out.outputs.CLUSTER_NAME }}
azext_edge_instance: ${{ steps.env_out.outputs.INSTANCE_NAME }}
azext_edge_init_args: ${{ steps.init.outputs.INIT_ARG }}
azext_edge_create_args: ${{ steps.init.outputs.CREATE_ARG }}
# redeploy tested later in this workflow
azext_edge_init_redeployment: false
run: |
tox r -e python-init-int --skip-pkg-install -- --durations=0
- name: "Tox Integration Tests"
if: ${{ matrix.feature == 'default' && !inputs.use-container }}
env:
azext_edge_rg: ${{ steps.env_out.outputs.RESOURCE_GROUP }}
azext_edge_cluster: ${{ steps.env_out.outputs.CLUSTER_NAME }}
azext_edge_instance: ${{ steps.env_out.outputs.INSTANCE_NAME }}
run: |
tox r -e "python-all-int" --skip-pkg-install -- --durations=0 --dist=loadfile -n auto
coverage=$(jq .totals.percent_covered coverage.json | cut -c1-4)
echo "Code coverage: $coverage%" >> $GITHUB_STEP_SUMMARY
- name: "Tox SecretSync Integration Tests"
if: ${{ matrix.feature == 'secretsync' && !inputs.use-container }}
env:
azext_edge_rg: ${{ steps.env_out.outputs.RESOURCE_GROUP }}
azext_edge_instance: ${{ steps.env_out.outputs.INSTANCE_NAME }}
azext_edge_sp_object_id: ${{ secrets.AZURE_CLIENT_ID }}
run: |
tox r -e "python-secretsync-int" --skip-pkg-install -- --durations=0 --dist=loadfile -n auto
coverage=$(jq .totals.percent_covered coverage.json | cut -c1-4)
echo "Code coverage: $coverage%" >> $GITHUB_STEP_SUMMARY
- name: "Containerized tests"
if: ${{ matrix.feature == 'default' && inputs.use-container }}
env:
azext_edge_skip_init: true # skip init tests in container
azext_edge_init_redeployment: false # ensure no redeployment in container
AIO_CLI_INIT_PREFLIGHT_DISABLED: ${{ steps.init.outputs.NO_PREFLIGHT }}
azext_edge_rg: ${{ steps.env_out.outputs.RESOURCE_GROUP }}
azext_edge_cluster: ${{ steps.env_out.outputs.CLUSTER_NAME }}
azext_edge_instance: ${{ steps.env_out.outputs.INSTANCE_NAME }}
run: |
# volume mounts
azure_dir=$(realpath ~/.azure)
kubeconfig=$(realpath ~/.kube/config)
kubeconfig_mount=/root/.kube/config
tempLog=$(mktemp -d)
# env vars
envVars=()
envVars+=("-e" "azext_edge_skip_init=$azext_edge_skip_init")
envVars+=("-e" "azext_edge_init_redeployment=$azext_edge_init_redeployment")
envVars+=("-e" "AIO_CLI_INIT_PREFLIGHT_DISABLED=$AIO_CLI_INIT_PREFLIGHT_DISABLED")
envVars+=("-e" "azext_edge_rg=$azext_edge_rg")
envVars+=("-e" "azext_edge_cluster=$azext_edge_cluster")
envVars+=("-e" "azext_edge_instance=$azext_edge_instance")
envVars+=("-e" "KUBECONFIG=$kubeconfig_mount")
# Run tests
set +e
docker run \
--rm \
"${envVars[@]}" \
-v "$kubeconfig:$kubeconfig_mount:ro" \
-v "${azure_dir}:/root/.azure" \
-v "${tempLog}:/usr/src/azure-iot-ops/junit" \
--network host \
$(docker build . -q)
- name: "Run smoke tests"
run: |
az iot ops support create-bundle
az iot ops support create-bundle --svc broker --broker-traces
az iot ops support create-bundle --ops-service acs secretstore
az iot ops check
az iot ops check --pre
az iot ops check --post
az iot ops check --as-object
az iot ops check --svc broker --resources broker brokerlistener
az iot ops asset query -g ${{ env.RESOURCE_GROUP }} --location westus -o table
- name: "Delete Cluster for redeployment"
if: ${{ matrix.feature == 'redeploy' }}
run: |
az iot ops delete -n ${{ env.INSTANCE_NAME }} -g ${{ env.RESOURCE_GROUP }} -y
- name: "Redeploy cluster via tox"
if: ${{ matrix.feature == 'redeploy' }}
env:
azext_edge_rg: ${{ steps.env_out.outputs.RESOURCE_GROUP }}
azext_edge_cluster: ${{ steps.env_out.outputs.CLUSTER_NAME }}
azext_edge_instance: ${{ steps.env_out.outputs.INSTANCE_NAME }}
azext_edge_init_args: ${{ steps.init.outputs.INIT_ARG }}
azext_edge_create_args: ${{ steps.init.outputs.CREATE_ARG }}
run: |
tox r -e python-init-int --skip-pkg-install -- --durations=0
- name: "Delete AIO resources"
if: ${{ always() }}
run: |
az iot ops delete --cluster ${{ env.CLUSTER_NAME }} -g ${{ env.RESOURCE_GROUP }} -y
- name: "Delete connected cluster"
if: ${{ always() }}
run: |
az resource delete -v --name ${{ env.CLUSTER_NAME }} -g ${{ env.RESOURCE_GROUP }} --resource-type Microsoft.Kubernetes/connectedClusters --verbose