LoRa E2E CI #536
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
name: LoRa E2E CI | |
concurrency: e2e | |
on: # rebuild any PRs and main branch changes | |
schedule: | |
- cron: '59 23 * * 1,2,3,4,5' | |
pull_request: | |
types: [labeled] | |
workflow_dispatch: | |
inputs: | |
RunE2ETestsOnly: | |
description: 'Run E2E tests only' | |
default: false | |
RunLoadTests: | |
description: 'Include Load Tests in current run' | |
default: 'false' | |
TestsToRun: | |
default: '[SensorDecodingTest,OTAAJoinTest,ABPTest,OTAATest,MacTest,ClassCTest,C2DMessageTest,MultiGatewayTest,MultiConcentratorTest,CupsTest,LnsDiscoveryTest,CloudDeploymentTest]' | |
description: 'tests to run' | |
TxPower: | |
description: 'TXPower value to use in E2E tests' | |
default: '6' | |
env: | |
BUILD_CONFIGURATION: 'Release' | |
TESTS_FOLDER: Tests | |
TESTS_RESULTS_FOLDER: Tests/TestResults | |
# these environments variable are for the deployment to IoT Edge | |
CONTAINER_REGISTRY_ADDRESS: "${{ secrets.CI_ACR_NAME }}.azurecr.io" | |
CONTAINER_REGISTRY_USERNAME: "${{ secrets.CI_ACR_NAME }}" | |
CONTAINER_REGISTRY_PASSWORD: ${{ secrets.CI_ACR_CREDENTIALS }} | |
IOT_EDGE_DEPLOYMENT_ID: "" | |
NET_SRV_LOG_LEVEL: 1 | |
NET_SRV_LOG_TO_HUB: false | |
NET_SRV_LOG_TO_TCP: true | |
NET_SRV_IOTEDGE_TIMEOUT: 0 | |
EDGEHUB_ROUTE: "FROM /* INTO $upstream" | |
RESET_PIN: 7 | |
REGION: "EU" | |
EDGEHUB_OPTIMIZEFORPERFORMANCE: false | |
EDGEHUB_MQTTSETTINGS_ENABLED: false | |
EDGEHUB_HTTPSETTINGS_ENABLED: false | |
# these are used for the docker tag computation | |
BUILD_BUILDID: ${{ github.run_id }} | |
DEV_IMAGE_TAG: dev | |
MASTER_IMAGE_TAG: master | |
MAJOR_VERSION: 2 | |
jobs: | |
env_var: | |
name: Set environment variables | |
runs-on: ubuntu-latest | |
steps: | |
- id: e2e_list_step | |
shell: bash | |
name: Set E2E tests to run | |
run: | | |
if [ ${{ github.event_name }} == 'workflow_dispatch' ]; then | |
echo "Set up for workflow dispatch" | |
echo "::set-output name=E2ETestsToRun::${{ github.event.inputs.TestsToRun }}" | |
elif [ ${{ github.event_name }} == 'pull_request' ]; then | |
echo "Set up for pull request" | |
echo "::set-output name=E2ETestsToRun::[SensorDecodingTest,OTAAJoinTest,ABPTest,OTAATest,MacTest,ClassCTest,C2DMessageTest,MultiGatewayTest,MultiConcentratorTest,CupsTest,LnsDiscoveryTest,CloudDeploymentTest]" | |
else | |
echo "Set up for cron trigger" | |
echo "::set-output name=E2ETestsToRun::[SensorDecodingTest,OTAAJoinTest,ABPTest,OTAATest,MacTest,ClassCTest,C2DMessageTest,MultiGatewayTest,MultiConcentratorTest,CupsTest,LnsDiscoveryTest,CloudDeploymentTest]" | |
fi | |
- id: check-if-run | |
name: Check if deploy on local ci | |
shell: bash | |
if: github.event_name == 'pull_request' && contains(github.event.pull_request.labels.*.name, 'fullci' ) != true | |
run: | | |
echo "::set-output name=StopFullCi::true" | |
- id: set_txpower | |
name: Set TXPower value | |
shell: bash | |
run: | | |
if [ ${{ github.event.inputs.TxPower }} -ge 1 ] && [ ${{ github.event.inputs.TxPower }} -le 14 ]; then | |
txPower=${{ github.event.inputs.TxPower }} | |
else | |
txPower=14 | |
fi | |
echo "Setting TxPower to $txPower" | |
echo "::set-output name=TxPower::$txPower" | |
outputs: | |
RunE2ETestsOnly: ${{ github.event.inputs.RunE2ETestsOnly == 'true' || contains(github.event.client_payload.labels.*.name, 'RunE2ETestsOnly') == true}} | |
E2ETestsToRun: ${{ steps.e2e_list_step.outputs.E2ETestsToRun }} | |
StopFullCi: ${{ steps.check-if-run.outputs.StopFullCi }} | |
TxPower: ${{ steps.set_txpower.outputs.TxPower }} | |
CertRemotePath: "/var/lorastarterkit/certs" | |
power_on_azure_vm: | |
name: Power ON EFLOW | |
if: needs.env_var.outputs.StopFullCi != 'true' | |
runs-on: ubuntu-latest | |
steps: | |
- uses: actions/checkout@v3 | |
- name: Power ON Azure VM | |
uses: ./.github/actions/power-azure-vm | |
with: | |
AZURE_VM_NAME: eflow | |
AZURE_RG_NAME: lorae2etests | |
POWER_SWITCH: true | |
AZURE_SP_CLIENTID: ${{ secrets.AZURE_SP_CLIENTID }} | |
AZURE_SP_SECRET: ${{ secrets.AZURE_SP_SECRET }} | |
AZURE_TENANTID: ${{ secrets.AZURE_TENANTID }} | |
reset_redis_cache: | |
name: Reset the Redis Cache | |
if: needs.env_var.outputs.StopFullCi != 'true' | |
runs-on: ubuntu-latest | |
steps: | |
- name: Flush the database | |
shell: bash | |
run: | | |
wget https://github.com/IBM-Cloud/redli/releases/download/v0.5.2/redli_0.5.2_linux_amd64.tar.gz | |
tar xzf redli_0.5.2_linux_amd64.tar.gz | |
chmod +x redli | |
./redli --tls -h ${{ secrets.REDIS_HOSTNAME }}.redis.cache.windows.net -p 6380 -a ${{ secrets.REDIS_PASSWORD }} FLUSHALL | |
# Build and deploy Facade Azure Function | |
deploy_facade_function: | |
environment: | |
name: CI_AZURE_ENVIRONMENT | |
needs: | |
- env_var | |
name: Build and Deploy Facade Azure Function | |
runs-on: ubuntu-latest | |
if: needs.env_var.outputs.RunE2ETestsOnly != 'true' && needs.env_var.outputs.StopFullCi != 'true' | |
env: | |
AZURE_FUNCTIONAPP_PACKAGE_PATH: 'LoRaEngine/LoraKeysManagerFacade/' | |
steps: | |
- uses: actions/checkout@v3 | |
name: Checkout current branch | |
- uses: actions/setup-dotnet@v3.0.1 | |
with: | |
dotnet-version: '6.0.x' | |
- name: 'Resolve Project Dependencies Using Dotnet' | |
shell: bash | |
run: | | |
pushd './${{ env.AZURE_FUNCTIONAPP_PACKAGE_PATH }}' | |
dotnet build --configuration ${{ env.BUILD_CONFIGURATION }} --output ./output | |
popd | |
- name: 'Run Azure Functions Action' | |
uses: Azure/functions-action@v1 | |
id: fa | |
with: | |
app-name: ${{ secrets.FUNCTION_FACADE_APP_NAME }} | |
package: '${{ env.AZURE_FUNCTIONAPP_PACKAGE_PATH }}output' | |
publish-profile: ${{ secrets.AZURE_FUNCTIONAPP_PUBLISH_PROFILE }} | |
build_push_docker_images: | |
needs: | |
- env_var | |
name: Build and Push Docker images | |
runs-on: ubuntu-latest | |
env: | |
DEV_IMAGE_TAG: dev | |
MASTER_IMAGE_TAG: master | |
if: needs.env_var.outputs.RunE2ETestsOnly != 'true' && needs.env_var.outputs.StopFullCi != 'true' | |
steps: | |
- uses: actions/checkout@v3 | |
name: Checkout current branch | |
with: | |
fetch-depth: '2' | |
- id: image_tag_definition | |
run: | | |
if [ ${{ github.ref }} = "refs/heads/dev" ]; then | |
echo "dev" | |
IMAGE_TAG="$DEV_IMAGE_TAG" | |
elif [ ${{ github.ref }} = "refs/heads/master" ]; then | |
echo "master" | |
IMAGE_TAG="$MASTER_IMAGE_TAG" | |
elif [ ${{ github.event_name }} == "pull_request" ]; then | |
echo "pull request" | |
IMAGE_TAG="pr-${{ github.event.number}}" | |
else | |
echo "all others" | |
IMAGE_TAG="custom-${GITHUB_REF##*/}" | |
fi | |
echo "Using image tag prefix $IMAGE_TAG" | |
IMAGE_TAG="$MAJOR_VERSION.${{ github.run_number }}.$IMAGE_TAG-${{ github.run_attempt }}" | |
echo "Using image tag $IMAGE_TAG" | |
echo "::set-env name=NET_SRV_VERSION::$IMAGE_TAG" | |
echo "::set-env name=LBS_VERSION::$IMAGE_TAG" | |
echo "::set-output name=imagetag::$IMAGE_TAG" | |
env: | |
ACTIONS_ALLOW_UNSECURE_COMMANDS: true | |
- uses: docker/setup-buildx-action@v2 | |
id: buildx | |
with: | |
install: true | |
- name: Set up QEMU | |
uses: docker/setup-qemu-action@v2 | |
- name: Build Docker LoRaWanNetworkServer images | |
run: | | |
echo ${{ env.CONTAINER_REGISTRY_PASSWORD }} | docker login "${{ env.CONTAINER_REGISTRY_ADDRESS }}" --username "${{ env.CONTAINER_REGISTRY_USERNAME }}" --password-stdin | |
docker buildx bake --push LoRaWanNetworkServerarm32 LoRaWanNetworkServerarm64v8 LoRaWanNetworkServerx64 | |
working-directory: LoRaEngine | |
env: | |
CONTAINER_REGISTRY_ADDRESS: ${{ env.CONTAINER_REGISTRY_ADDRESS }} | |
# This image is very costly to rebuild and we rebuild it only when something change in the folders since last commit. | |
- name: Build Docker LoRaWanBasicsStation images | |
run: | | |
git diff --quiet HEAD HEAD~1 -- modules/LoRaBasicsStationModule/ || docker buildx bake --push LoraBasicsStationarm32v7 LoraBasicsStationarm64v8 --set *.args.SOURCE_CONTAINER_REGISTRY_ADDRESS=${{ env.CONTAINER_REGISTRY_ADDRESS }} | |
working-directory: LoRaEngine | |
env: | |
CONTAINER_REGISTRY_ADDRESS: ${{ env.CONTAINER_REGISTRY_ADDRESS }} | |
outputs: | |
imagetag: ${{ steps.image_tag_definition.outputs.imagetag }} | |
# Generate root and server certificates and copy required files to RPi | |
certificates_job : | |
timeout-minutes: 5 | |
name: Generate and copy certificates | |
environment: | |
name: CI_AZURE_ENVIRONMENT | |
if: needs.env_var.outputs.RunE2ETestsOnly != 'true' && needs.env_var.outputs.StopFullCi != 'true' | |
needs: | |
- env_var | |
runs-on: [ self-hosted, x64 ] | |
steps: | |
- uses: actions/checkout@v3 | |
name: Checkout current branch | |
- id: generate_step | |
shell: bash | |
name: Generate server and client certificates | |
env: | |
SERVER_PFX_PASSWORD: ${{ secrets.SERVER_PFX_PASSWORD }} | |
SSH_PRIVATE_KEY_PATH: ${{ secrets.SSH_PRIVATE_KEY_PATH }} | |
RPI_USERNAME: ${{ secrets.RPI_USERNAME }} | |
RPI_HOST: ${{ secrets.RPI_HOST }} | |
CERT_REMOTE_PATH: ${{ needs.env_var.outputs.CertRemotePath }} | |
CUPS_STATION_EUI: ${{ secrets.DEFAULTCUPSSTATIONEUI }} | |
CUPS_CREDENTIALS_BLOB_URL: ${{ secrets.CUPSCREDENTIALSBLOBURL }} | |
CUPS_FIRMWARE_BLOB_URL: ${{ secrets.CUPSFIRMWAREBLOBURL }} | |
run: | | |
# -- Credential generation section -- | |
chmod +x ./Tools/BasicStation-Certificates-Generation/certificate-generate.sh | |
./Tools/BasicStation-Certificates-Generation/certificate-generate.sh server $RPI_HOST $SERVER_PFX_PASSWORD | |
./Tools/BasicStation-Certificates-Generation/certificate-generate.sh client $CUPS_STATION_EUI | |
# following copy commands are copying trust certificate to a pre-created $CERT_REMOTE_PATH location in local ci | |
cp ./Tools/BasicStation-Certificates-Generation/ca/root-ca.crt $CERT_REMOTE_PATH/tc.trust | |
cp ./Tools/BasicStation-Certificates-Generation/ca/root-ca.crt $CERT_REMOTE_PATH/cups.trust | |
cp ./Tools/BasicStation-Certificates-Generation/client/$CUPS_STATION_EUI.crt $CERT_REMOTE_PATH/cups.crt | |
cp ./Tools/BasicStation-Certificates-Generation/client/$CUPS_STATION_EUI.key $CERT_REMOTE_PATH/cups.key | |
curl -X PUT -T ./Tools/BasicStation-Certificates-Generation/client/$CUPS_STATION_EUI.bundle -H "x-ms-date: $(date -u)" -H "x-ms-blob-type: BlockBlob" "$CUPS_CREDENTIALS_BLOB_URL" | |
echo "::set-output name=clientbundlecrc::$(cat ./Tools/BasicStation-Certificates-Generation/client/$CUPS_STATION_EUI.bundle | gzip -1 | tail -c 8 | od -t ${1:-u}4 -N 4 -An --endian=little | xargs echo)" | |
echo "::set-output name=clientthumbprint::$(sha1sum $CERT_REMOTE_PATH/cups.crt | awk '{print $1;}')" | |
# -- Firmware upgrade generation section -- | |
chmod +x ./Tools/Cups-Firmware-Upgrade/firmwarePrep.sh | |
NEW_FW_VERSION=$(date -u +%s) | |
sed -i "s/1.0.1-e2e/$NEW_FW_VERSION/g" ./Tools/Cups-Firmware-Upgrade/fwUpdateSample.sh | |
./Tools/Cups-Firmware-Upgrade/firmwarePrep.sh $CUPS_STATION_EUI "$(realpath ./Tools/Cups-Firmware-Upgrade/fwUpdateSample.sh)" | |
cp ./Tools/Cups-Firmware-Upgrade/$CUPS_STATION_EUI/sig-0.key $CERT_REMOTE_PATH/sig-0.key | |
echo "::set-output name=clientsigkeycrc::$(cat ./Tools/Cups-Firmware-Upgrade/$CUPS_STATION_EUI/sig-0.crc)" | |
echo "::set-output name=clientfwdigest::$(cat ./Tools/Cups-Firmware-Upgrade/$CUPS_STATION_EUI/fwUpdate.digest)" | |
echo "::set-output name=clientfwversion::$NEW_FW_VERSION" | |
curl -X PUT -T ./Tools/Cups-Firmware-Upgrade/fwUpdateSample.sh -H "x-ms-date: $(date -u)" -H "x-ms-blob-type: BlockBlob" "$CUPS_FIRMWARE_BLOB_URL" | |
# following commands are copying to remote "aio" device the required server and trust certificates | |
ssh -i $SSH_PRIVATE_KEY_PATH $RPI_USERNAME@$RPI_HOST "sudo rm -rf $CERT_REMOTE_PATH && sudo mkdir -p $CERT_REMOTE_PATH && sudo chown -R "'$(whoami)'" $CERT_REMOTE_PATH" | |
scp -i $SSH_PRIVATE_KEY_PATH ./Tools/BasicStation-Certificates-Generation/ca/root-ca.crt $RPI_USERNAME@$RPI_HOST:$CERT_REMOTE_PATH/tc.trust | |
scp -i $SSH_PRIVATE_KEY_PATH ./Tools/BasicStation-Certificates-Generation/server/$RPI_HOST.pfx $RPI_USERNAME@$RPI_HOST:$CERT_REMOTE_PATH/server.pfx | |
# following is needed for the proper setup of trusted ca certificate | |
openssl x509 -in ./Tools/BasicStation-Certificates-Generation/ca/root-ca.crt -inform DER -out ./Tools/BasicStation-Certificates-Generation/ca/root-ca.crt.pem -outform PEM | |
scp -i $SSH_PRIVATE_KEY_PATH ./Tools/BasicStation-Certificates-Generation/ca/root-ca.crt.pem $RPI_USERNAME@$RPI_HOST:$CERT_REMOTE_PATH/client.ca.crt | |
- id: get_self_hosted_runner_ip_address | |
shell: bash | |
name: Get internal Ip address of the itestup device | |
run: | | |
echo "::set-output name=itestupip::$(ip address list tun0 | grep -Po 'inet \K[\d.]+')" | |
outputs: | |
itestupip: ${{ steps.get_self_hosted_runner_ip_address.outputs.itestupip }} | |
clientthumbprint: ${{ steps.generate_step.outputs.clientthumbprint }} | |
clientbundlecrc: ${{ steps.generate_step.outputs.clientbundlecrc }} | |
clientsigkeycrc: ${{ steps.generate_step.outputs.clientsigkeycrc }} | |
clientfwdigest: ${{ steps.generate_step.outputs.clientfwdigest }} | |
clientfwversion: ${{ steps.generate_step.outputs.clientfwversion }} | |
# Deploy Cloud based LoRaWAN Network Server | |
deploy_cloud_lns: | |
needs: | |
- env_var | |
- build_push_docker_images | |
- certificates_job | |
runs-on: ubuntu-latest | |
if: needs.env_var.outputs.RunE2ETestsOnly != 'true' && needs.env_var.outputs.StopFullCi != 'true' | |
name: Deploy Cloud based LNS | |
steps: | |
- name: "Deploy container instance" | |
id: "deploycloudlns" | |
shell: bash | |
run: | | |
az login --service-principal -u ${{ secrets.AZURE_SP_CLIENTID }} -p ${{ secrets.AZURE_SP_SECRET }} --tenant ${{ secrets.AZURE_TENANTID }} | |
az container create --resource-group ${{ secrets.AZURE_RG }} --ip-address Private --location westeurope --name cloudlns \ | |
--environment-variables LOG_TO_TCP_ADDRESS=${{ needs.certificates_job.outputs.itestupip }} LOG_TO_TCP_PORT=6100 LOG_TO_TCP=true LOG_LEVEL=1 IOTHUBHOSTNAME=${{secrets.IOTHUB_HOSTNAME}} ENABLE_GATEWAY=false CLOUD_DEPLOYMENT=true \ | |
--image ${{ env.CONTAINER_REGISTRY_ADDRESS }}/lorawannetworksrvmodule:${{needs.build_push_docker_images.outputs.imagetag}}-amd64 \ | |
--ports 5000 \ | |
--protocol TCP \ | |
--registry-username ${{ env.CONTAINER_REGISTRY_USERNAME }} \ | |
--registry-password ${{ env.CONTAINER_REGISTRY_PASSWORD }} \ | |
--restart-policy Never \ | |
--secure-environment-variables FACADE_AUTH_CODE=${{ secrets.FUNCTION_FACADE_AUTH_CODE }} FACADE_SERVER_URL=${{ secrets.FUNCTION_FACADE_SERVER_URL }} REDIS_CONNECTION_STRING=${{ secrets.REDIS_HOSTNAME }}.redis.cache.windows.net:6380,password=${{ secrets.REDIS_PASSWORD }},ssl=True,abortConnect=False \ | |
--subnet ${{ secrets.AZURE_SUBNET_NAME }} \ | |
--vnet ${{ secrets.AZURE_VNET_NAME }} --output none | |
echo "::set-output name=cloudlnsprivateip::$(az container show --name cloudlns --resource-group ${{ secrets.AZURE_RG }} --query ipAddress.ip -o tsv)" | |
outputs: | |
cloudlnsprivateip: ${{ steps.deploycloudlns.outputs.cloudlnsprivateip }} | |
# Deploy IoT Edge solution to ARM gateway | |
deploy_arm_gw_iot_edge: | |
timeout-minutes: 20 | |
environment: | |
name: CI_ALL_IN_ONE_ARM_GATEWAY | |
needs: | |
- env_var | |
- build_push_docker_images | |
- certificates_job | |
if: needs.env_var.outputs.RunE2ETestsOnly != 'true' && needs.env_var.outputs.StopFullCi != 'true' | |
runs-on: ubuntu-latest | |
name: Deploy IoT Edge on All-In-One ARM gateway | |
env: | |
EDGE_AGENT_VERSION: 1.2.6 | |
EDGE_HUB_VERSION: 1.2.6 | |
steps: | |
- uses: actions/checkout@v3 | |
name: Checkout current branch | |
- name: Iot Edge Push Solution | |
uses: ./.github/actions/deployedge | |
id: deploy_edge | |
env: | |
LBS_FIXED_STATION_EUI: ${{ secrets.LBS_FIXED_STATION_EUI }} | |
IOTHUB_CONNECTION_STRING: ${{ secrets.IOTHUB_OWNER_CONNECTION_STRING }} | |
DEVICE_ID: ${{ secrets.DEVICE_ID }} | |
IOT_EDGE_DEPLOYMENT_ID: ${{ secrets.IOT_EDGE_DEPLOYMENT_ID }} | |
FACADE_SERVER_URL: ${{ secrets.FUNCTION_FACADE_SERVER_URL }} | |
FACADE_AUTH_CODE: ${{ secrets.FUNCTION_FACADE_AUTH_CODE }} | |
IOT_HUB_RESOURCE_ID: ${{ secrets.IOT_HUB_RESOURCE_ID }} | |
LOG_ANALYTICS_WORKSPACE_ID: ${{ secrets.LOG_ANALYTICS_WORKSPACE_ID }} | |
LOG_ANALYTICS_SHARED_KEY: ${{ secrets.LOG_ANALYTICS_SHARED_KEY }} | |
APPLICATIONINSIGHTS_CONNECTION_STRING: ${{ secrets.APPLICATIONINSIGHTS_CONNECTION_STRING }} | |
CERT_REMOTE_PATH: ${{ needs.env_var.outputs.CertRemotePath }} | |
SERVER_PFX_PASSWORD: ${{ secrets.SERVER_PFX_PASSWORD }} | |
NET_SRV_LOG_TO_TCP_ADDRESS: "itestup" | |
with: | |
deployment_file_name: '${{ secrets.DEPLOYMENT_FILE_NAME }}' | |
architecture: '${{ secrets.ARCHITECTURE }}' | |
iot_edge_deployment_id: '${{ secrets.IOT_EDGE_DEPLOYMENT_ID }}' | |
# Deploy IoT Edge solution to EFLOW gateway | |
deploy_eflow_gw_iot_edge: | |
timeout-minutes: 20 | |
environment: | |
name: CI_EFLOW_AZURE_VM | |
needs: | |
- env_var | |
- build_push_docker_images | |
- certificates_job | |
if: needs.env_var.outputs.RunE2ETestsOnly != 'true' && needs.env_var.outputs.StopFullCi != 'true' | |
runs-on: ubuntu-latest | |
name: Deploy IoT Edge on EFLOW VM gateway | |
env: | |
DEVICE_ID: ${{ secrets.DEVICE_ID }} | |
NET_SRV_LOG_TO_TCP_ADDRESS: ${{ needs.certificates_job.outputs.itestupip }} | |
IOTHUB_CONNECTION_STRING: ${{ secrets.IOTHUB_OWNER_CONNECTION_STRING }} | |
FACADE_SERVER_URL: ${{ secrets.FUNCTION_FACADE_SERVER_URL }} | |
FACADE_AUTH_CODE: ${{ secrets.FUNCTION_FACADE_AUTH_CODE }} | |
EDGE_AGENT_VERSION: 1.1.8 | |
EDGE_HUB_VERSION: 1.1.8 | |
IOT_HUB_RESOURCE_ID: ${{ secrets.IOT_HUB_RESOURCE_ID }} | |
LOG_ANALYTICS_WORKSPACE_ID: ${{ secrets.LOG_ANALYTICS_WORKSPACE_ID }} | |
LOG_ANALYTICS_SHARED_KEY: ${{ secrets.LOG_ANALYTICS_SHARED_KEY }} | |
APPLICATIONINSIGHTS_CONNECTION_STRING: ${{ secrets.APPLICATIONINSIGHTS_CONNECTION_STRING }} | |
steps: | |
- uses: actions/checkout@v3 | |
name: Checkout current branch | |
- name: Iot Edge Push Solution | |
uses: ./.github/actions/deployedge | |
id: deploy_edge | |
env: | |
IOTHUB_CONNECTION_STRING: ${{ secrets.IOTHUB_OWNER_CONNECTION_STRING }} | |
DEVICE_ID: ${{ secrets.DEVICE_ID }} | |
IOT_EDGE_DEPLOYMENT_ID: ${{ secrets.IOT_EDGE_DEPLOYMENT_ID }} | |
with: | |
deployment_file_name: '${{ secrets.DEPLOYMENT_FILE_NAME }}' | |
architecture: '${{ secrets.ARCHITECTURE }}' | |
iot_edge_deployment_id: '${{ secrets.IOT_EDGE_DEPLOYMENT_ID }}' | |
# Deploy IoT Edge solution to standalone Concentrator | |
deploy_eflow_concentrator_iot_edge: | |
timeout-minutes: 20 | |
needs: | |
- env_var | |
- build_push_docker_images | |
environment: | |
name: CI_CONCENTRATOR_EFLOW_ARM32 | |
if: needs.env_var.outputs.RunE2ETestsOnly != 'true' && needs.env_var.outputs.StopFullCi != 'true' | |
runs-on: ubuntu-latest | |
name: Deploy IoT Edge on ItestArm2 concentrator | |
env: | |
DEVICE_ID: ${{ secrets.DEVICE_ID }} | |
LBS_TC_URI: ${{ secrets.TC_URI }} | |
IOTHUB_CONNECTION_STRING: ${{ secrets.IOTHUB_OWNER_CONNECTION_STRING }} | |
FACADE_SERVER_URL: ${{ secrets.FUNCTION_FACADE_SERVER_URL }} | |
FACADE_AUTH_CODE: ${{ secrets.FUNCTION_FACADE_AUTH_CODE }} | |
EDGE_AGENT_VERSION: 1.1.8 | |
EDGE_HUB_VERSION: 1.1.8 | |
steps: | |
- uses: actions/checkout@v3 | |
name: Checkout current branch | |
- name: Iot Edge Push Solution | |
uses: ./.github/actions/deployedge | |
id: deploy_edge | |
env: | |
IOTHUB_CONNECTION_STRING: ${{ secrets.IOTHUB_OWNER_CONNECTION_STRING }} | |
DEVICE_ID: ${{ secrets.DEVICE_ID }} | |
IOT_EDGE_DEPLOYMENT_ID: ${{ secrets.IOT_EDGE_DEPLOYMENT_ID }} | |
LBS_FIXED_STATION_EUI: ${{ secrets.LBS_FIXED_STATION_EUI }} | |
IOT_HUB_RESOURCE_ID: ${{ secrets.IOT_HUB_RESOURCE_ID }} | |
LOG_ANALYTICS_WORKSPACE_ID: ${{ secrets.LOG_ANALYTICS_WORKSPACE_ID }} | |
LOG_ANALYTICS_SHARED_KEY: ${{ secrets.LOG_ANALYTICS_SHARED_KEY }} | |
APPLICATIONINSIGHTS_CONNECTION_STRING: ${{ secrets.APPLICATIONINSIGHTS_CONNECTION_STRING }} | |
with: | |
deployment_file_name: '${{ secrets.DEPLOYMENT_FILE_NAME }}' | |
architecture: '${{ secrets.ARCHITECTURE }}' | |
iot_edge_deployment_id: '${{ secrets.IOT_EDGE_DEPLOYMENT_ID }}' | |
waitForLnsDeployment: false | |
load_test_job: | |
timeout-minutes: 150 | |
name: Run Load Tests | |
environment: | |
name: CI_AZURE_ENVIRONMENT | |
url: ${{ needs.env_var.outputs.CheckSuiteUrl }} | |
if: always() && (github.event_name == 'schedule' || github.event.inputs.RunLoadTests == 'true') && needs.deploy_arm_gw_iot_edge.result == 'success' && needs.deploy_eflow_gw_iot_edge.result == 'success' && needs.deploy_facade_function.result == 'success' && needs.env_var.outputs.StopFullCi != 'true' | |
needs: | |
- deploy_arm_gw_iot_edge | |
- deploy_eflow_gw_iot_edge | |
- deploy_facade_function | |
- deploy_eflow_concentrator_iot_edge | |
- env_var | |
- certificates_job | |
runs-on: [ self-hosted, x64 ] | |
env: | |
INTEGRATIONTEST_IoTHubEventHubConnectionString: ${{ secrets.IOTHUB_EVENT_HUB_CONNECTION_STRING }} | |
INTEGRATIONTEST_IoTHubEventHubConsumerGroup: ${{ secrets.IOTHUB_CI_CONSUMER_GROUP }} | |
INTEGRATIONTEST_IoTHubConnectionString: ${{ secrets.IOTHUB_OWNER_CONNECTION_STRING }} | |
INTEGRATIONTEST_LeafDeviceGatewayID: itestarm1 | |
INTEGRATIONTEST_DevicePrefix: '03' | |
INTEGRATIONTEST_RunningInCI: true | |
INTEGRATIONTEST_LoadTestLnsEndpoints: ${{ secrets.LOAD_TEST_LNS_ENDPOINTS }} | |
INTEGRATIONTEST_NumberOfLoadTestDevices: 10 | |
INTEGRATIONTEST_NumberOfLoadTestConcentrators: 4 | |
INTEGRATIONTEST_FunctionAppCode: ${{ secrets.FUNCTION_FACADE_AUTH_CODE }} | |
INTEGRATIONTEST_FunctionAppBaseUrl: ${{ secrets.FUNCTION_FACADE_SERVER_URL }} | |
INTEGRATIONTEST_TcpLogPort: 6000 | |
steps: | |
- uses: actions/checkout@v3 | |
name: Checkout current branch | |
- name: Setup .NET | |
uses: actions/setup-dotnet@v3.0.1 | |
with: | |
dotnet-version: '6.0.x' # SDK Version to use. | |
- name: .NET SDK Information | |
run: | |
dotnet --info | |
- name: Configuration for load tests | |
uses: cschleiden/replace-tokens@v1 | |
with: | |
files: '${{ env.TESTS_FOLDER }}/Simulation/appsettings.json' | |
- name: Build load tests | |
run: | | |
dotnet build --configuration ${{ env.BUILD_CONFIGURATION }} ${{ env.TESTS_FOLDER }}/Simulation/LoRaWan.Tests.Simulation.csproj | |
- name: Runs load tests | |
shell: bash | |
run: | | |
dotnet test --logger trx --no-build --configuration ${{ env.BUILD_CONFIGURATION }} \ | |
-r ${{ env.TESTS_RESULTS_FOLDER }}/LoadTest/ --filter "SimulatedLoadTests" \ | |
${{ env.TESTS_FOLDER }}/Simulation/LoRaWan.Tests.Simulation.csproj | |
# Upload test results as artifact | |
- uses: actions/upload-artifact@v3 | |
if: always() | |
with: | |
name: load-test-results | |
path: ${{ env.TESTS_RESULTS_FOLDER }}/LoadTest/ | |
cloud_test_job: | |
timeout-minutes: 150 | |
name: Run cloud only deployment Tests | |
environment: | |
name: CI_AZURE_ENVIRONMENT | |
url: ${{ needs.env_var.outputs.CheckSuiteUrl }} | |
if: always() && needs.deploy_cloud_lns.result == 'success' && needs.deploy_facade_function.result == 'success' && needs.env_var.outputs.StopFullCi != 'true' && contains(needs.env_var.outputs.E2ETestsToRun, 'CloudDeploymentTest') && !(github.event_name == 'pull_request' && contains(github.event.pull_request.labels.*.name, 'CloudDeploymentTest')) | |
needs: | |
- deploy_facade_function | |
- deploy_cloud_lns | |
- env_var | |
- certificates_job | |
runs-on: [ self-hosted, x64 ] | |
env: | |
INTEGRATIONTEST_IoTHubEventHubConnectionString: ${{ secrets.IOTHUB_EVENT_HUB_CONNECTION_STRING }} | |
INTEGRATIONTEST_IoTHubEventHubConsumerGroup: ${{ secrets.IOTHUB_CI_CONSUMER_GROUP }} | |
INTEGRATIONTEST_IoTHubConnectionString: ${{ secrets.IOTHUB_OWNER_CONNECTION_STRING }} | |
INTEGRATIONTEST_LeafDeviceGatewayID: itestarm1 | |
INTEGRATIONTEST_DevicePrefix: '12' | |
INTEGRATIONTEST_RunningInCI: true | |
INTEGRATIONTEST_LoadTestLnsEndpoints: "{ \\\"1\\\": \\\"ws://${{ needs.deploy_cloud_lns.outputs.cloudlnsprivateip }}:5000\\\" }" | |
INTEGRATIONTEST_NumberOfLoadTestDevices: 1 | |
INTEGRATIONTEST_NumberOfLoadTestConcentrators: 2 | |
INTEGRATIONTEST_FunctionAppCode: ${{ secrets.FUNCTION_FACADE_AUTH_CODE }} | |
INTEGRATIONTEST_FunctionAppBaseUrl: ${{ secrets.FUNCTION_FACADE_SERVER_URL }} | |
INTEGRATIONTEST_TcpLogPort: 6100 | |
steps: | |
- uses: actions/checkout@v2 | |
name: Checkout current branch | |
- name: Setup .NET | |
uses: actions/setup-dotnet@v3.0.1 | |
with: | |
dotnet-version: '6.0.x' # SDK Version to use. | |
- name: .NET SDK Information | |
run: | |
dotnet --info | |
- name: Configuration for simulated cloud tests | |
uses: cschleiden/replace-tokens@v1 | |
with: | |
files: '${{ env.TESTS_FOLDER }}/Simulation/appsettings.json' | |
- name: Build simulated cloud tests | |
run: | | |
dotnet build --configuration ${{ env.BUILD_CONFIGURATION }} ${{ env.TESTS_FOLDER }}/Simulation/LoRaWan.Tests.Simulation.csproj | |
- name: Runs simulated cloud tests | |
shell: bash | |
run: | | |
dotnet test --logger trx --no-build --configuration ${{ env.BUILD_CONFIGURATION }} \ | |
-r ${{ env.TESTS_RESULTS_FOLDER }}/LoadTest/ --filter "SimulatedCloudTests" \ | |
${{ env.TESTS_FOLDER }}/Simulation/LoRaWan.Tests.Simulation.csproj | |
- name: Add CloudDeploymentTest Test Label | |
uses: buildsville/add-remove-label@v1 | |
if: github.event_name == 'pull_request' && success() | |
with: | |
token: ${{ github.token }} | |
label: 'CloudDeploymentTest' | |
type: add | |
# Upload simulated cloud results as artifact | |
- uses: actions/upload-artifact@v1 | |
if: always() | |
with: | |
name: simulated-cloud-test-results | |
path: ${{ env.TESTS_RESULTS_FOLDER }}/LoadTest/ | |
# Runs E2E tests in dedicated agent, while having modules deployed into PI (arm32v7) | |
e2e_tests_job: | |
timeout-minutes: 150 | |
name: Run E2E Tests | |
environment: | |
name: CI_AZURE_ENVIRONMENT | |
url: ${{ needs.env_var.outputs.CheckSuiteUrl }} | |
if: always() && (needs.env_var.outputs.RunE2ETestsOnly == 'true' || (needs.deploy_arm_gw_iot_edge.result == 'success' && needs.deploy_eflow_gw_iot_edge.result == 'success' && needs.deploy_facade_function.result == 'success')) && needs.env_var.outputs.StopFullCi != 'true' | |
needs: | |
- deploy_arm_gw_iot_edge | |
- deploy_eflow_gw_iot_edge | |
- deploy_facade_function | |
- deploy_eflow_concentrator_iot_edge | |
- env_var | |
- certificates_job | |
- load_test_job | |
runs-on: [ self-hosted, x64 ] | |
env: | |
E2ETESTS_LeafDeviceSerialPort: '/dev/ttyACM0' | |
E2ETESTS_IoTHubEventHubConsumerGroup: ${{ secrets.IOTHUB_CI_CONSUMER_GROUP }} | |
E2ETESTS_LeafDeviceGatewayID: itestarm1 | |
E2ETESTS_DevicePrefix: '01' | |
E2ETESTS_EnsureHasEventDelayBetweenReadsInSeconds: 15 | |
E2ETESTS_EnsureHasEventMaximumTries: 5 | |
E2ETESTS_IoTHubConnectionString: ${{ secrets.IOTHUB_OWNER_CONNECTION_STRING }} | |
E2ETESTS_IoTHubEventHubConnectionString: ${{ secrets.IOTHUB_EVENT_HUB_CONNECTION_STRING }} | |
E2ETESTS_FunctionAppCode: ${{ secrets.FUNCTION_FACADE_AUTH_CODE }} | |
E2ETESTS_FunctionAppBaseUrl: ${{ secrets.FUNCTION_FACADE_SERVER_URL }} | |
E2ETESTS_RunningInCI: true | |
E2ETESTS_RemoteConcentratorConnection: ${{ secrets.REMOTECONCENTRATORCONNECTION }} | |
E2ETESTS_BasicStationExecutablePath: ${{ secrets.BASICSTATIONEXECUTABLEPATH }} | |
E2ETESTS_SshPrivateKeyPath: ${{ secrets.SSHPRIVATEKEYPATH }} | |
E2ETESTS_SharedLnsEndpoint: ${{ secrets.SHAREDLNSENDPOINT }} | |
E2ETESTS_SharedCupsEndpoint: ${{ secrets.SHAREDCUPSENDPOINT }} | |
E2ETESTS_DefaultBasicStationEui: ${{ secrets.DEFAULTCISTATIONEUI }} | |
E2ETESTS_RadioDev: ${{ secrets.CIBASICSTATIONRADIODEV }} | |
E2ETESTS_CupsBasicStationEui: ${{ secrets.DEFAULTCUPSSTATIONEUI }} | |
E2ETESTS_IsCorecellBasicStation: false | |
E2ETESTS_ClientThumbprint: ${{ needs.certificates_job.outputs.clientthumbprint }} | |
E2ETESTS_ClientBundleCrc: ${{ needs.certificates_job.outputs.clientbundlecrc }} | |
E2ETESTS_CupsSigKeyChecksum: ${{ needs.certificates_job.outputs.clientsigkeycrc }} | |
E2ETESTS_CupsFwDigest: ${{ needs.certificates_job.outputs.clientfwdigest }} | |
E2ETESTS_CupsBasicStationVersion: "2.0.6(rak833x64/std)" | |
E2ETESTS_CupsBasicStationPackage: ${{ needs.certificates_job.outputs.clientfwversion }} | |
E2ETESTS_CupsFwUrl: ${{ secrets.CUPSFIRMWAREBLOBURL }} | |
TestsToRun: ${{ needs.env_var.outputs.E2ETestsToRun }} | |
E2ETESTS_TxPower: ${{ needs.env_var.outputs.TxPower }} | |
steps: | |
- uses: actions/checkout@v3 | |
name: Checkout current branch | |
- name: Setup .NET | |
uses: actions/setup-dotnet@v3.0.1 | |
with: | |
dotnet-version: '6.0.x' # SDK Version to use. | |
- name: .NET SDK Information | |
run: | |
dotnet --info | |
- name: Configuration for E2E tests | |
uses: cschleiden/replace-tokens@v1 | |
with: | |
files: '${{ env.TESTS_FOLDER }}/E2E/appsettings.json' | |
# Builds and runs E2E tests | |
- name: Build E2E tests | |
run: | | |
echo "killing process listening on TCP 6000" | |
sudo lsof -i:6000 -t | xargs -r sudo kill | |
dotnet build --configuration ${{ env.BUILD_CONFIGURATION }} ${{ env.TESTS_FOLDER }}/E2E/LoRaWan.Tests.E2E.csproj | |
# The tests need to run if: | |
# - In PRs, when DON'T have the matchin test label | |
# - In other runs, all the tests present in env.TestsToRun | |
- name: Runs SensorDecoding E2E tests | |
if: always() && contains(env.TestsToRun, 'SensorDecodingTest') && !(github.event_name == 'pull_request' && contains(github.event.pull_request.labels.*.name, 'SensorDecodingTest')) | |
uses: ./.github/actions/rune2etest | |
id: e2e_tests_sensordecoding | |
with: | |
test_name: 'SensorDecodingTest' | |
- name: Runs OTAAJoin E2E tests | |
if: always() && contains(env.TestsToRun, 'OTAAJoinTest') && !(github.event_name == 'pull_request' && contains(github.event.pull_request.labels.*.name, 'OTAAJoinTest')) | |
uses: ./.github/actions/rune2etest | |
id: e2e_tests_otaajointest | |
with: | |
test_name: 'OTAAJoinTest' | |
- name: Runs ABP E2E tests | |
if: always() && contains(env.TestsToRun, 'ABPTest') && !(github.event_name == 'pull_request' && contains(github.event.pull_request.labels.*.name, 'ABPTest')) | |
uses: ./.github/actions/rune2etest | |
id: e2e_tests_abptest | |
with: | |
test_name: 'ABPTest' | |
- name: Runs OTAA E2E tests | |
if: always() && contains(env.TestsToRun, 'OTAATest') && !(github.event_name == 'pull_request' && contains(github.event.pull_request.labels.*.name, 'OTAATest')) | |
uses: ./.github/actions/rune2etest | |
id: e2e_tests_otaatest | |
with: | |
test_name: 'OTAATest' | |
- name: Runs MacTest E2E tests | |
if: always() && contains(env.TestsToRun, 'MacTest') && !(github.event_name == 'pull_request' && contains(github.event.pull_request.labels.*.name, 'MacTest')) | |
uses: ./.github/actions/rune2etest | |
id: e2e_tests_mactest | |
with: | |
test_name: 'MacTest' | |
- name: Runs ClassC E2E tests | |
if: always() && contains(env.TestsToRun, 'ClassCTest') && !(github.event_name == 'pull_request' && contains(github.event.pull_request.labels.*.name, 'ClassCTest')) | |
uses: ./.github/actions/rune2etest | |
id: e2e_tests_classctest | |
with: | |
test_name: 'ClassCTest' | |
- name: Runs C2D E2E tests | |
if: always() && contains(env.TestsToRun, 'C2DMessageTest') && !(github.event_name == 'pull_request' && contains(github.event.pull_request.labels.*.name, 'C2DMessageTest')) | |
uses: ./.github/actions/rune2etest | |
id: e2e_tests_c2dctest | |
with: | |
test_name: 'C2DMessageTest' | |
- name: Runs MultiGatewayTest E2E tests | |
if: always() && contains(env.TestsToRun, 'MultiGatewayTest') && !(github.event_name == 'pull_request' && contains(github.event.pull_request.labels.*.name, 'MultiGatewayTest')) | |
uses: ./.github/actions/rune2etest | |
id: e2e_tests_multigwtest | |
with: | |
test_name: 'MultiGatewayTest' | |
- name: Runs MultiConcentrator E2E tests | |
if: always() && contains(env.TestsToRun, 'MultiConcentratorTest') && !(github.event_name == 'pull_request' && contains(github.event.pull_request.labels.*.name, 'MultiConcentratorTest')) | |
uses: ./.github/actions/rune2etest | |
id: e2e_tests_multiconctest | |
with: | |
test_name: 'MultiConcentratorTest' | |
- name: Runs CUPS E2E tests | |
if: always() && contains(env.TestsToRun, 'CupsTest') && !(github.event_name == 'pull_request' && contains(github.event.pull_request.labels.*.name, 'CupsTest')) | |
uses: ./.github/actions/rune2etest | |
id: e2e_tests_cupstest | |
with: | |
test_name: 'CupsTest' | |
- name: Runs LNS discovery E2E tests | |
if: always() && contains(env.TestsToRun, 'LnsDiscoveryTest') && !(github.event_name == 'pull_request' && contains(github.event.pull_request.labels.*.name, 'LnsDiscoveryTest')) | |
uses: ./.github/actions/rune2etest | |
id: e2e_tests_lnsdiscoverytest | |
with: | |
test_name: 'LnsDiscoveryTest' | |
# Upload test results as artifact | |
- uses: actions/upload-artifact@v3 | |
if: always() | |
with: | |
name: e2e-test-results | |
path: ${{ env.TESTS_RESULTS_FOLDER }}/E2E/ | |
power_off_azure_vm: | |
name: Power OFF EFLOW | |
if: always() | |
runs-on: ubuntu-latest | |
needs: | |
- e2e_tests_job | |
steps: | |
- uses: actions/checkout@v3 | |
- name: Power OFF Azure VM | |
uses: ./.github/actions/power-azure-vm | |
with: | |
AZURE_VM_NAME: eflow | |
AZURE_RG_NAME: lorae2etests | |
POWER_SWITCH: false | |
AZURE_SP_CLIENTID: ${{ secrets.AZURE_SP_CLIENTID }} | |
AZURE_SP_SECRET: ${{ secrets.AZURE_SP_SECRET }} | |
AZURE_TENANTID: ${{ secrets.AZURE_TENANTID }} | |
delete_cloud_lns: | |
name: Delete cloud LNS | |
if: always() | |
runs-on: ubuntu-latest | |
needs: | |
- e2e_tests_job | |
steps: | |
- uses: actions/checkout@v2 | |
- name: "Delete azure container instance for cloudlns" | |
shell: bash | |
run: | | |
az login --service-principal -u ${{ secrets.AZURE_SP_CLIENTID }} -p ${{ secrets.AZURE_SP_SECRET }} --tenant ${{ secrets.AZURE_TENANTID }} | |
az container logs -g ${{ secrets.AZURE_RG }} --name cloudlns | |
az container delete --yes --resource-group ${{ secrets.AZURE_RG }} --name cloudlns --output none |