From 22816bb0df7657861f60319733485101340b195d Mon Sep 17 00:00:00 2001 From: Philip Lin Date: Thu, 11 Apr 2019 11:56:34 -0700 Subject: [PATCH] merge latest e2e test script in order to run e2e in vsts pipeline for release 1.0.7 (#1076) --- scripts/linux/runE2ETest.sh | 871 +++++++++++++++++++++++++++ scripts/windows/test/Run-E2ETest.ps1 | 536 +++++++++++++---- 2 files changed, 1289 insertions(+), 118 deletions(-) create mode 100644 scripts/linux/runE2ETest.sh diff --git a/scripts/linux/runE2ETest.sh b/scripts/linux/runE2ETest.sh new file mode 100644 index 00000000000..a21a33124de --- /dev/null +++ b/scripts/linux/runE2ETest.sh @@ -0,0 +1,871 @@ +#!/bin/bash + +############################################################################### +# This script is used to streamline running E2E tests for Linux. +############################################################################### +set -e + +function clean_up() { + print_highlighted_message 'Clean up' + + echo 'Stop IoT Edge services' + systemctl stop iotedge.socket iotedge.mgmt.socket || true + systemctl kill iotedge || true + systemctl stop iotedge || true + + echo 'Remove IoT Edge and config file' + apt-get purge libiothsm-std --yes || true + rm -rf /var/lib/iotedge/ + rm -rf /var/run/iotedge/ + rm -rf /etc/iotedge/config.yaml + + echo 'Do docker system prune' + docker system prune -af || true +} + +function create_iotedge_service_config { + print_highlighted_message 'Create IoT Edge service config' + mkdir /etc/systemd/system/iotedge.service.d/ || true + bash -c "echo '[Service] +Environment=IOTEDGE_LOG=edgelet=debug' > /etc/systemd/system/iotedge.service.d/override.conf" +} + +function get_image_architecture_label() { + local arch + arch="$(uname -m)" + + case "$arch" in + 'x86_64' ) image_architecture_label='amd64';; + 'armv7l' ) image_architecture_label='arm32v7';; + 'aarch64' ) image_architecture_label='arm64v8';; + *) print_error "Unsupported OS architecture: $arch"; exit 1;; + esac +} + +function get_iotedge_quickstart_artifact_file() { + local path + if [ "$image_architecture_label" = 'amd64' ]; then + path="$E2E_TEST_DIR/artifacts/core-linux/IotEdgeQuickstart.linux-x64.tar.gz" + elif [ "$image_architecture_label" = 'arm64v8' ]; then + path="$E2E_TEST_DIR/artifacts/core-linux/IotEdgeQuickstart.linux-arm64.tar.gz" + else + path="$E2E_TEST_DIR/artifacts/core-linux/IotEdgeQuickstart.linux-arm.tar.gz" + fi + + echo "$path" +} + +function get_iotedged_artifact_folder() { + local path + if [ "$image_architecture_label" = 'amd64' ]; then + path="$E2E_TEST_DIR/artifacts/iotedged-ubuntu-amd64" + elif [ "$image_architecture_label" = 'arm64v8' ]; then + path="$E2E_TEST_DIR/artifacts/iotedged-ubuntu16.04-aarch64" + else + path="$E2E_TEST_DIR/artifacts/iotedged-ubuntu-armhf" + fi + + echo "$path" +} + +function get_leafdevice_artifact_file() { + local path + if [ "$image_architecture_label" = 'amd64' ]; then + path="$E2E_TEST_DIR/artifacts/core-linux/LeafDevice.linux-x64.tar.gz" + elif [ "$image_architecture_label" = 'arm64v8' ]; then + path="$E2E_TEST_DIR/artifacts/core-linux/LeafDevice.linux-arm64.tar.gz" + else + path="$E2E_TEST_DIR/artifacts/core-linux/LeafDevice.linux-arm.tar.gz" + fi + + echo "$path" +} + +function get_long_haul_deployment_artifact_file() { + local path + if [ "$image_architecture_label" = 'amd64' ] || + [ "$image_architecture_label" = 'arm64v8' ]; then + path="$E2E_TEST_DIR/artifacts/core-linux/e2e_deployment_files/long_haul_deployment.template.json" + else + path="$E2E_TEST_DIR/artifacts/core-linux/e2e_deployment_files/long_haul_deployment.template.arm32v7.$LONG_HAUL_PROTOCOL_HEAD.json" + fi + + echo "$path" +} + +function prepare_test_from_artifacts() { + print_highlighted_message 'Prepare test from artifacts' + + echo 'Remove working folder' + rm -rf "$working_folder" + mkdir -p "$working_folder" + + declare -a pkg_list=( $iotedged_artifact_folder/*.deb ) + iotedge_package="${pkg_list[*]}" + echo "iotedge_package=$iotedge_package" + + echo 'Extract quickstart to working folder' + mkdir -p "$quickstart_working_folder" + tar -C "$quickstart_working_folder" -xzf "$iotedge_quickstart_artifact_file" + + if [[ "${TEST_NAME,,}" == 'quickstartcerts' ]]; then + echo 'Extract leaf device to working folder' + mkdir -p "$leafdevice_working_folder" + tar -C "$leafdevice_working_folder" -xzf "$leafdevice_artifact_file" + fi + + if [[ "${TEST_NAME,,}" == directmethod* ]] || + [[ "${TEST_NAME,,}" == 'longhaul' ]] || + [[ "${TEST_NAME,,}" == 'stress' ]] || + [[ "${TEST_NAME,,}" == 'tempfilter' ]] || + [[ "${TEST_NAME,,}" == 'tempfilterfunctions' ]]; then + case "${TEST_NAME,,}" in + 'directmethodamqp') + echo "Copy deployment file from $dm_module_to_module_deployment_artifact_file" + cp "$dm_module_to_module_deployment_artifact_file" "$deployment_working_file" + + sed -i -e "s@@Amqp@g" "$deployment_working_file" + sed -i -e "s@@Amqp_Tcp_Only@g" "$deployment_working_file";; + 'directmethodamqpws') + echo "Copy deployment file from $dm_module_to_module_deployment_artifact_file" + cp "$dm_module_to_module_deployment_artifact_file" "$deployment_working_file" + + sed -i -e "s@@Amqpws@g" "$deployment_working_file" + sed -i -e "s@@Amqp_WebSocket_Only@g" "$deployment_working_file";; + 'directmethodmqtt') + echo "Copy deployment file from $dm_module_to_module_deployment_artifact_file" + cp "$dm_module_to_module_deployment_artifact_file" "$deployment_working_file" + + # Temporarily fix to avoid edgeHub fail when running on RPi, bug is created (https://msazure.visualstudio.com/One/_workitems/edit/4396517) + if [[ "$image_architecture_label" == 'arm32v7' ]]; then + sed -i -e "s@@Amqp@g" "$deployment_working_file" + else + sed -i -e "s@@Mqtt@g" "$deployment_working_file" + fi + sed -i -e "s@@Mqtt@g" "$deployment_working_file" + sed -i -e "s@@Mqtt_Tcp_Only@g" "$deployment_working_file";; + 'directmethodmqttws') + echo "Copy deployment file from $dm_module_to_module_deployment_artifact_file" + cp "$dm_module_to_module_deployment_artifact_file" "$deployment_working_file" + + # Temporarily fix to avoid edgeHub fail when running on RPi, bug is created (https://msazure.visualstudio.com/One/_workitems/edit/4396517) + if [[ "$image_architecture_label" == 'arm32v7' ]]; then + sed -i -e "s@@AmqpWs@g" "$deployment_working_file" + else + sed -i -e "s@@MqttWs@g" "$deployment_working_file" + fi + sed -i -e "s@@Mqtt_WebSocket_Only@g" "$deployment_working_file";; + 'longhaul' | 'stress') + if [[ "${TEST_NAME,,}" == 'longhaul' ]]; then + echo "Copy deployment file from $long_haul_deployment_artifact_file" + cp "$long_haul_deployment_artifact_file" "$deployment_working_file" + + sed -i -e "s@@$LOADGEN_TRANSPORT_TYPE@g" "$deployment_working_file" + sed -i -e "s@@$IOTHUB_CONNECTION_STRING@g" "$deployment_working_file" + else + echo "Copy deployment file from $stress_deployment_artifact_file" + cp "$stress_deployment_artifact_file" "$deployment_working_file" + sed -i -e "s@@$LOADGEN1_TRANSPORT_TYPE@g" "$deployment_working_file" + sed -i -e "s@@$LOADGEN2_TRANSPORT_TYPE@g" "$deployment_working_file" + sed -i -e "s@@$LOADGEN3_TRANSPORT_TYPE@g" "$deployment_working_file" + sed -i -e "s@@$LOADGEN4_TRANSPORT_TYPE@g" "$deployment_working_file" + sed -i -e "s@@$AMQP_SETTINGS_ENABLED@g" "$deployment_working_file" + sed -i -e "s@@$MQTT_SETTINGS_ENABLED@g" "$deployment_working_file" + fi + + local escapedSnitchAlertUrl + local escapedBuildId + sed -i -e "s@@$EVENTHUB_CONNECTION_STRING@g" "$deployment_working_file" + sed -i -e "s@@$LOADGEN_MESSAGE_FREQUENCY@g" "$deployment_working_file" + escapedSnitchAlertUrl="${SNITCH_ALERT_URL//&/\\&}" + escapedBuildId="${ARTIFACT_IMAGE_BUILD_NUMBER//./}" + sed -i -e "s@@$escapedSnitchAlertUrl@g" "$deployment_working_file" + sed -i -e "s@@$SNITCH_BUILD_NUMBER@g" "$deployment_working_file" + sed -i -e "s@@$RELEASE_LABEL-$image_architecture_label-linux-$escapedBuildId@g" "$deployment_working_file" + sed -i -e "s@@$SNITCH_REPORTING_INTERVAL_IN_SECS@g" "$deployment_working_file" + sed -i -e "s@@$SNITCH_STORAGE_ACCOUNT@g" "$deployment_working_file" + sed -i -e "s@@$SNITCH_STORAGE_MASTER_KEY@g" "$deployment_working_file" + sed -i -e "s@@$SNITCH_TEST_DURATION_IN_SECS@g" "$deployment_working_file";; + 'tempfilter') + echo "Copy deployment file from $module_to_module_deployment_artifact_file" + cp "$module_to_module_deployment_artifact_file" "$deployment_working_file";; + 'tempfilterfunctions') + echo "Copy deployment file from $module_to_functions_deployment_artifact_file" + cp "$module_to_functions_deployment_artifact_file" "$deployment_working_file";; + esac + + sed -i -e "s@@$image_architecture_label@g" "$deployment_working_file" + sed -i -e "s//$ARTIFACT_IMAGE_BUILD_NUMBER/g" "$deployment_working_file" + sed -i -e "s@@$CONTAINER_REGISTRY_USERNAME@g" "$deployment_working_file" + sed -i -e "s@@$CONTAINER_REGISTRY_PASSWORD@g" "$deployment_working_file" + fi +} + +function print_error() { + local message=$1 + local red='\033[0;31m' + local color_reset='\033[0m' + echo -e "${red}$message${color_reset}" +} + +function print_highlighted_message() { + local message=$1 + local cyan='\033[0;36m' + local color_reset='\033[0m' + echo -e "${cyan}$message${color_reset}" +} + +function print_logs() { + local ret=$1 + local test_end_time=$2 + local elapsed_seconds=$3 + + elapsed_time="$(TZ=UTC0 printf '%(%H:%M:%S)T\n' "$elapsed_seconds")" + print_highlighted_message "Test completed at $test_end_time, took $elapsed_time." + + if (( ret < 1 )); then + return; + fi + + print_highlighted_message 'Print logs' + print_highlighted_message 'LOGS FROM IOTEDGED' + journalctl -u iotedge -u docker --since "$test_start_time" --no-pager || true + + print_highlighted_message 'EDGE AGENT LOGS' + docker logs edgeAgent || true + + print_highlighted_message 'EDGE HUB LOGS' + docker logs edgeHub || true + + if [[ "${TEST_NAME,,}" == 'tempsensor' ]]; then + print_highlighted_message 'TEMP SENSOR LOGS' + docker logs tempSensor || true + fi + + if [[ "${TEST_NAME,,}" == 'tempfilter' ]]; then + print_highlighted_message 'TEMP FILTER LOGS' + docker logs tempFilter || true + fi + + if [[ "${TEST_NAME,,}" == 'tempfilterfunctions' ]]; then + print_highlighted_message 'TEMP FILTER FUNCTIONS LOGS' + docker logs tempFilterFunctions || true + fi + + if [[ "${TEST_NAME,,}" == directmethod* ]]; then + print_highlighted_message 'DIRECT MTEHOD SENDER LOGS' + docker logs DirectMethodSender || true + + print_highlighted_message 'DIRECT MTEHOD RECEIVER LOGS' + docker logs DirectMethodReceiver || true + fi +} + +function process_args() { + print_highlighted_message 'Process arguments' + saveNextArg=0 + for arg in "$@" + do + if [ $saveNextArg -eq 1 ]; then + E2E_TEST_DIR="$arg" + saveNextArg=0 + elif [ $saveNextArg -eq 2 ]; then + RELEASE_LABEL="$arg" + saveNextArg=0 + elif [ $saveNextArg -eq 3 ]; then + ARTIFACT_IMAGE_BUILD_NUMBER="$arg" + saveNextArg=0 + elif [ $saveNextArg -eq 4 ]; then + TEST_NAME="$arg" + saveNextArg=0 + elif [ $saveNextArg -eq 5 ]; then + CONTAINER_REGISTRY="$arg" + saveNextArg=0 + elif [ $saveNextArg -eq 6 ]; then + CONTAINER_REGISTRY_USERNAME="$arg" + saveNextArg=0 + elif [ $saveNextArg -eq 7 ]; then + CONTAINER_REGISTRY_PASSWORD="$arg" + saveNextArg=0 + elif [ $saveNextArg -eq 8 ]; then + IOTHUB_CONNECTION_STRING="$arg" + saveNextArg=0 + elif [ $saveNextArg -eq 9 ]; then + EVENTHUB_CONNECTION_STRING="$arg" + saveNextArg=0 + elif [ $saveNextArg -eq 10 ]; then + LOADGEN_TRANSPORT_TYPE="$arg" + saveNextArg=0 + elif [ $saveNextArg -eq 11 ]; then + LOADGEN_MESSAGE_FREQUENCY="$arg" + saveNextArg=0 + elif [ $saveNextArg -eq 12 ]; then + SNITCH_ALERT_URL="$arg" + saveNextArg=0 + elif [ $saveNextArg -eq 13 ]; then + SNITCH_BUILD_NUMBER="$arg" + saveNextArg=0 + elif [ $saveNextArg -eq 14 ]; then + SNITCH_REPORTING_INTERVAL_IN_SECS="$arg" + saveNextArg=0 + elif [ $saveNextArg -eq 15 ]; then + SNITCH_STORAGE_ACCOUNT="$arg" + saveNextArg=0 + elif [ $saveNextArg -eq 16 ]; then + SNITCH_STORAGE_MASTER_KEY="$arg" + saveNextArg=0 + elif [ $saveNextArg -eq 17 ]; then + SNITCH_TEST_DURATION_IN_SECS="$arg" + saveNextArg=0 + elif [ $saveNextArg -eq 18 ]; then + LOADGEN1_TRANSPORT_TYPE="$arg" + saveNextArg=0 + elif [ $saveNextArg -eq 19 ]; then + LOADGEN2_TRANSPORT_TYPE="$arg" + saveNextArg=0 + elif [ $saveNextArg -eq 20 ]; then + LOADGEN3_TRANSPORT_TYPE="$arg" + saveNextArg=0 + elif [ $saveNextArg -eq 21 ]; then + LOADGEN4_TRANSPORT_TYPE="$arg" + saveNextArg=0 + elif [ $saveNextArg -eq 22 ]; then + AMQP_SETTINGS_ENABLED="$arg" + saveNextArg=0 + elif [ $saveNextArg -eq 23 ]; then + MQTT_SETTINGS_ENABLED="$arg" + saveNextArg=0 + elif [ $saveNextArg -eq 24 ]; then + LONG_HAUL_PROTOCOL_HEAD="$arg" + saveNextArg=0 + else + case "$arg" in + '-h' | '--help' ) usage;; + '-testDir' ) saveNextArg=1;; + '-releaseLabel' ) saveNextArg=2;; + '-artifactImageBuildNumber' ) saveNextArg=3;; + '-testName' ) saveNextArg=4;; + '-containerRegistry' ) saveNextArg=5;; + '-containerRegistryUsername' ) saveNextArg=6;; + '-containerRegistryPassword' ) saveNextArg=7;; + '-iotHubConnectionString' ) saveNextArg=8;; + '-eventHubConnectionString' ) saveNextArg=9;; + '-loadGenTransportType' ) saveNextArg=10;; + '-loadGenMessageFrequency' ) saveNextArg=11;; + '-snitchAlertUrl' ) saveNextArg=12;; + '-snitchBuildNumber' ) saveNextArg=13;; + '-snitchReportingIntervalInSecs' ) saveNextArg=14;; + '-snitchStorageAccount' ) saveNextArg=15;; + '-snitchStorageMasterKey' ) saveNextArg=16;; + '-snitchTestDurationInSecs' ) saveNextArg=17;; + '-loadGen1TransportType' ) saveNextArg=18;; + '-loadGen2TransportType' ) saveNextArg=19;; + '-loadGen3TransportType' ) saveNextArg=20;; + '-loadGen4TransportType' ) saveNextArg=21;; + '-amqpSettingsEnabled' ) saveNextArg=22;; + '-mqttSettingsEnabled' ) saveNextArg=23;; + '-longHaulProtocolHead' ) saveNextArg=24;; + * ) usage;; + esac + fi + done + + # Required parameters + [[ -z "$RELEASE_LABEL" ]] && { print_error 'Release label is required.'; exit 1; } + [[ -z "$ARTIFACT_IMAGE_BUILD_NUMBER" ]] && { print_error 'Artifact image build number is required'; exit 1; } + [[ -z "$TEST_NAME" ]] && { print_error 'Test name is required'; exit 1; } + [[ -z "$CONTAINER_REGISTRY" ]] && { print_error 'Container registry is required'; exit 1; } + [[ -z "$CONTAINER_REGISTRY_USERNAME" ]] && { print_error 'Container registry username is required'; exit 1; } + [[ -z "$CONTAINER_REGISTRY_PASSWORD" ]] && { print_error 'Container registry password is required'; exit 1; } + [[ -z "$IOTHUB_CONNECTION_STRING" ]] && { print_error 'IoT hub connection string is required'; exit 1; } + [[ -z "$EVENTHUB_CONNECTION_STRING" ]] && { print_error 'Event hub connection string is required'; exit 1; } + + echo 'Required parameters are provided' +} + +function run_all_tests() +{ + local funcRet=0 + local testRet=0 + + TEST_NAME='DirectMethodAmqp' + run_directmethodamqp_test && funcRet=$? || funcRet=$? + + TEST_NAME='DirectMethodAmqpws' + run_directmethodamqpws_test && testRet=$? || testRet=$? + if (( funcRet = 0 )); then funcRet=$testRet; fi + + TEST_NAME='DirectMethodMqtt' + run_directmethodmqtt_test && testRet=$? || testRet=$? + if (( funcRet = 0 )); then funcRet=$testRet; fi + + TEST_NAME='DirectMethodMqttws' + run_directmethodmqttws_test && testRet=$? || testRet=$? + if (( funcRet = 0 )); then funcRet=$testRet; fi + + TEST_NAME='TempFilter' + run_tempfilter_test && testRet=$? || testRet=$? + if (( funcRet = 0 )); then funcRet=$testRet; fi + + TEST_NAME='TempFilterFunctions' + run_tempfilterfunctions_test && testRet=$? || testRet=$? + if (( funcRet = 0 )); then funcRet=$testRet; fi + + TEST_NAME='TempSensor' + run_tempsensor_test && testRet=$? || testRet=$? + if (( funcRet = 0 )); then funcRet=$testRet; fi + + return $funcRet +} + +function run_directmethod_test() +{ + SECONDS=0 + local ret=0 + "$quickstart_working_folder/IotEdgeQuickstart" \ + -d "$device_id" \ + -a "$iotedge_package" \ + -c "$IOTHUB_CONNECTION_STRING" \ + -e "$EVENTHUB_CONNECTION_STRING" \ + -r "$CONTAINER_REGISTRY" \ + -u "$CONTAINER_REGISTRY_USERNAME" \ + -p "$CONTAINER_REGISTRY_PASSWORD" \ + -n "$(hostname)" \ + -t "$ARTIFACT_IMAGE_BUILD_NUMBER-linux-$image_architecture_label" \ + --verify-data-from-module "DirectMethodSender" \ + -l "$deployment_working_file" && ret=$? || ret=$? + + local elapsed_seconds=$SECONDS + test_end_time="$(date '+%Y-%m-%d %H:%M:%S')" + print_logs $ret "$test_end_time" $elapsed_seconds + + return $ret +} + +function run_directmethodamqp_test() { + print_highlighted_message "Run DirectMethod Amqp test on $image_architecture_label" + test_setup + + device_id="e2e-$RELEASE_LABEL-Linux-$image_architecture_label-DMAmqp" + test_start_time="$(date '+%Y-%m-%d %H:%M:%S')" + print_highlighted_message "Run DirectMethod Amqp test with -d '$device_id' started at $test_start_time" + + run_directmethod_test && ret=$? || ret=$? + + return $ret +} + +function run_directmethodamqpws_test() { + print_highlighted_message "Run DirectMethod Amqpws test on $image_architecture_label" + test_setup + + device_id="e2e-$RELEASE_LABEL-Linux-$image_architecture_label-DMAmqpws" + test_start_time="$(date '+%Y-%m-%d %H:%M:%S')" + print_highlighted_message "Run DirectMethod Amqpws test with -d '$device_id' started at $test_start_time" + + run_directmethod_test && ret=$? || ret=$? + + return $ret +} + +function run_directmethodmqtt_test() { + print_highlighted_message "Run DirectMethod Mqtt test on $image_architecture_label" + test_setup + + device_id="e2e-$RELEASE_LABEL-Linux-$image_architecture_label-DMMqtt" + test_start_time="$(date '+%Y-%m-%d %H:%M:%S')" + print_highlighted_message "Run DirectMethod Mqtt test with -d '$device_id' started at $test_start_time" + + run_directmethod_test && ret=$? || ret=$? + + return $ret +} + +function run_directmethodmqttws_test() { + print_highlighted_message "Run DirectMethod Mqttws test on $image_architecture_label" + test_setup + + device_id="e2e-$RELEASE_LABEL-Linux-$image_architecture_label-DMMqttws" + test_start_time="$(date '+%Y-%m-%d %H:%M:%S')" + print_highlighted_message "Run DirectMethod Mqttws test with -d '$device_id' started at $test_start_time" + + run_directmethod_test && ret=$? || ret=$? + + return $ret +} + +function run_longhaul_test() { + print_highlighted_message "Run Long Haul test on $image_architecture_label" + test_setup + + local device_id="$RELEASE_LABEL-Linux-$image_architecture_label-longhaul" + + sed -i -e "s@@$device_id@g" "$deployment_working_file" + + test_start_time="$(date '+%Y-%m-%d %H:%M:%S')" + print_highlighted_message "Run Long Haul test with -d '$device_id' started at $test_start_time" + + SECONDS=0 + local ret=0 + "$quickstart_working_folder/IotEdgeQuickstart" \ + -d "$device_id" \ + -a "$iotedge_package" \ + -c "$IOTHUB_CONNECTION_STRING" \ + -e "$EVENTHUB_CONNECTION_STRING" \ + -r "$CONTAINER_REGISTRY" \ + -u "$CONTAINER_REGISTRY_USERNAME" \ + -p "$CONTAINER_REGISTRY_PASSWORD" \ + -n "$(hostname)" \ + -t "$ARTIFACT_IMAGE_BUILD_NUMBER-linux-$image_architecture_label" \ + --leave-running=All \ + -l "$deployment_working_file" \ + --runtime-log-level "Info" \ + --no-verify && ret=$? || ret=$? + + local elapsed_seconds=$SECONDS + test_end_time="$(date '+%Y-%m-%d %H:%M:%S')" + print_logs $ret "$test_end_time" $elapsed_seconds + + return $ret +} + +function run_quickstartcerts_test() { + print_highlighted_message "Run Quickstart Certs test on $image_architecture_label" + test_setup + + local device_id="e2e-$RELEASE_LABEL-Linux-$image_architecture_label-QuickstartCert" + test_start_time="$(date '+%Y-%m-%d %H:%M:%S')" + print_highlighted_message "Run Quickstart Certs test with -d '$device_id' started at $test_start_time" + + SECONDS=0 + local ret=0 + "$quickstart_working_folder/IotEdgeQuickstart" \ + -d "$device_id" \ + -a "$iotedge_package" \ + -c "$IOTHUB_CONNECTION_STRING" \ + -e "doesNotNeed" \ + -n "$(hostname)" \ + -r "$CONTAINER_REGISTRY" \ + -u "$CONTAINER_REGISTRY_USERNAME" \ + -p "$CONTAINER_REGISTRY_PASSWORD" \ + -t "$ARTIFACT_IMAGE_BUILD_NUMBER-linux-$image_architecture_label" \ + --leave-running=Core \ + --no-verify && ret=$? || ret=$? + + declare -a certs=( /var/lib/iotedge/hsm/certs/edge_owner_ca*.pem ) + echo "cert: ${certs[0]}" + # Workaround for multiple certificates in the x509store - remove this after quick start certs have Authority Key Identifier + rm -rf ~/.dotnet/corefx/cryptography/x509stores/root/ + + "$leafdevice_working_folder/LeafDevice" \ + -c "$IOTHUB_CONNECTION_STRING" \ + -e "$EVENTHUB_CONNECTION_STRING" \ + -d "$device_id-leaf" \ + -ct "${certs[0]}" \ + -ed "$(hostname)" && ret=$? || ret=$? + + local elapsed_seconds=$SECONDS + test_end_time="$(date '+%Y-%m-%d %H:%M:%S')" + print_logs $ret "$test_end_time" $elapsed_seconds + + return $ret +} + +function run_stress_test() { + print_highlighted_message "Run Stress test on $image_architecture_label" + test_setup + + local device_id="$RELEASE_LABEL-Linux-$image_architecture_label-stress" + + sed -i -e "s@@$device_id@g" "$deployment_working_file" + + test_start_time="$(date '+%Y-%m-%d %H:%M:%S')" + print_highlighted_message "Run Stress test with -d '$device_id' started at $test_start_time" + + SECONDS=0 + local ret=0 + "$quickstart_working_folder/IotEdgeQuickstart" \ + -d "$device_id" \ + -a "$iotedge_package" \ + -c "$IOTHUB_CONNECTION_STRING" \ + -e "doesNotNeed" \ + -r "$CONTAINER_REGISTRY" \ + -u "$CONTAINER_REGISTRY_USERNAME" \ + -p "$CONTAINER_REGISTRY_PASSWORD" \ + -n "$(hostname)" \ + -t "$ARTIFACT_IMAGE_BUILD_NUMBER-linux-$image_architecture_label" \ + --leave-running=All \ + -l "$deployment_working_file" \ + --runtime-log-level "Info" \ + --no-verify && ret=$? || ret=$? + + local elapsed_seconds=$SECONDS + test_end_time="$(date '+%Y-%m-%d %H:%M:%S')" + print_logs $ret "$test_end_time" $elapsed_seconds + + return $ret +} + +function run_tempfilter_test() { + print_highlighted_message "Run TempFilter test on $image_architecture_label" + test_setup + + local device_id="e2e-$RELEASE_LABEL-Linux-$image_architecture_label-tempFilter" + test_start_time="$(date '+%Y-%m-%d %H:%M:%S')" + print_highlighted_message "Run TempFilter test with -d '$device_id' started at $test_start_time" + + SECONDS=0 + local ret=0 + "$quickstart_working_folder/IotEdgeQuickstart" \ + -d "$device_id" \ + -a "$iotedge_package" \ + -c "$IOTHUB_CONNECTION_STRING" \ + -e "$EVENTHUB_CONNECTION_STRING" \ + -r "$CONTAINER_REGISTRY" \ + -u "$CONTAINER_REGISTRY_USERNAME" \ + -p "$CONTAINER_REGISTRY_PASSWORD" \ + -n "$(hostname)" \ + --verify-data-from-module "tempFilter" \ + -t "$ARTIFACT_IMAGE_BUILD_NUMBER-linux-$image_architecture_label" \ + -l "$deployment_working_file" && ret=$? || ret=$? + + local elapsed_seconds=$SECONDS + test_end_time="$(date '+%Y-%m-%d %H:%M:%S')" + print_logs $ret "$test_end_time" $elapsed_seconds + + return $ret +} + +function run_tempfilterfunctions_test() { + print_highlighted_message "Run TempFilterFunctions test on $image_architecture_label" + test_setup + + local device_id="e2e-$RELEASE_LABEL-Linux-$image_architecture_label-tempFilterFunc" + test_start_time="$(date '+%Y-%m-%d %H:%M:%S')" + print_highlighted_message "Run TempFilterFunctions test with -d '$device_id' started at $test_start_time" + + SECONDS=0 + local ret=0 + "$quickstart_working_folder/IotEdgeQuickstart" \ + -d "$device_id" \ + -a "$iotedge_package" \ + -c "$IOTHUB_CONNECTION_STRING" \ + -e "$EVENTHUB_CONNECTION_STRING" \ + -r "$CONTAINER_REGISTRY" \ + -u "$CONTAINER_REGISTRY_USERNAME" \ + -p "$CONTAINER_REGISTRY_PASSWORD" \ + -n "$(hostname)" \ + --verify-data-from-module "tempFilterFunctions" \ + -t "$ARTIFACT_IMAGE_BUILD_NUMBER-linux-$image_architecture_label" \ + -l "$deployment_working_file" && ret=$? || ret=$? + + local elapsed_seconds=$SECONDS + test_end_time="$(date '+%Y-%m-%d %H:%M:%S')" + print_logs $ret "$test_end_time" $elapsed_seconds + + return $ret +} + +function run_tempsensor_test() { + print_highlighted_message "Run TempSensor test on $image_architecture_label" + test_setup + + local device_id="e2e-$RELEASE_LABEL-Linux-$image_architecture_label-tempSensor" + test_start_time="$(date '+%Y-%m-%d %H:%M:%S')" + print_highlighted_message "Run TempSensor test with -d '$device_id' started at $test_start_time" + + SECONDS=0 + local ret=0 + "$quickstart_working_folder/IotEdgeQuickstart" \ + -d "$device_id" \ + -a "$iotedge_package" \ + -c "$IOTHUB_CONNECTION_STRING" \ + -e "$EVENTHUB_CONNECTION_STRING" \ + -r "$CONTAINER_REGISTRY" \ + -u "$CONTAINER_REGISTRY_USERNAME" \ + -p "$CONTAINER_REGISTRY_PASSWORD" \ + -n "$(hostname)" \ + -tw "$E2E_TEST_DIR/artifacts/core-linux/e2e_test_files/twin_test_tempSensor.json" \ + -t "$ARTIFACT_IMAGE_BUILD_NUMBER-linux-$image_architecture_label" && ret=$? || ret=$? + + local elapsed_seconds=$SECONDS + test_end_time="$(date '+%Y-%m-%d %H:%M:%S')" + print_logs $ret "$test_end_time" $elapsed_seconds + + return $ret +} + +function run_test() +{ + local ret=0 + case "${TEST_NAME,,}" in + 'all') run_all_tests && ret=$? || ret=$?;; + 'directmethodamqp') run_directmethodamqp_test && ret=$? || ret=$?;; + 'directmethodamqpws') run_directmethodamqpws_test && ret=$? || ret=$?;; + 'directmethodmqtt') run_directmethodmqtt_test && ret=$? || ret=$?;; + 'directmethodmqttws') run_directmethodmqttws_test && ret=$? || ret=$?;; + 'quickstartcerts') run_quickstartcerts_test && ret=$? || ret=$?;; + 'longhaul') run_longhaul_test && ret=$? || ret=$?;; + 'stress') run_stress_test && ret=$? || ret=$?;; + 'tempfilter') run_tempfilter_test && ret=$? || ret=$?;; + 'tempfilterfunctions') run_tempfilterfunctions_test && ret=$? || ret=$?;; + 'tempsensor') run_tempsensor_test && ret=$? || ret=$?;; + *) print_highlighted_message "Can't find any test with name '$TEST_NAME'";; + esac + + echo "Test exit with result code $ret" + exit $ret +} + +function test_setup() { + validate_test_parameters + clean_up + prepare_test_from_artifacts + create_iotedge_service_config +} + +function validate_test_parameters() { + print_highlighted_message "Validate test parameters for $TEST_NAME" + + local required_files=() + local required_folders=() + + required_files+=("$iotedge_quickstart_artifact_file") + required_folders+=("$iotedged_artifact_folder") + + case "${TEST_NAME,,}" in + 'tempsensor') + required_files+=($twin_testfile_artifact_file);; + 'tempfilter') + required_files+=($module_to_module_deployment_artifact_file);; + 'tempfilterfunctions') + required_files+=($module_to_functions_deployment_artifact_file);; + 'longhaul') + required_files+=($long_haul_deployment_artifact_file);; + 'quickstartcerts') + required_files+=($leafdevice_artifact_file);; + 'stress') + required_files+=($stress_deployment_artifact_file);; + esac + + if [[ "${TEST_NAME,,}" == directmethod* ]]; then + required_files+=($dm_module_to_module_deployment_artifact_file) + fi + + local error=0 + for f in "${required_files[@]}" + do + if [ ! -f "$f" ]; then + print_error "Required file, $f doesn't exist." + ((error++)) + fi + done + + for d in "${required_folders[@]}" + do + if [ ! -d "$d" ]; then + print_error "Required directory, $d doesn't exist." + ((error++)) + fi + done + + if [[ "${TEST_NAME,,}" == "longhaul" ]] || + [[ "${TEST_NAME,,}" == "stress" ]]; then + if [[ -z "$SNITCH_ALERT_URL" ]]; then + print_error "Required snitch alert URL." + ((error++)) + fi + + if [[ -z "$SNITCH_STORAGE_ACCOUNT" ]]; then + print_error "Required snitch storage account." + ((error++)) + fi + + if [[ -z "$SNITCH_STORAGE_MASTER_KEY" ]]; then + print_error "Required snitch storage master key." + ((error++)) + fi + fi + + if (( error > 0 )); then + exit 1 + fi +} + +function usage() { + echo "$SCRIPT_NAME [options]" + echo '' + echo 'options' + echo ' -testDir Path of E2E test directory which contains artifacts and certs folders; defaul to current directory.' + echo ' -releaseLabel Release label can be uniquely identify the build (e.g -); which is used as part of Edge device name.' + echo ' -testName Name of E2E test to be run.' + echo " Values are 'All', 'DirectMethodAmqp', 'DirectMethodAmqpWs', 'DirectMethodMqtt', 'DirectMethodMqttWs', 'LongHaul', 'QuickstartCerts', " + echo " 'Stress', 'TempFilter', 'TempFilterFunctions', 'TempSensor'" + echo " Note: 'All' option doesn't include long hual and stress test." + echo ' -artifactImageBuildNumber Artifact image build number is used to construct path of docker images, pulling from docker registry. E.g. 20190101.1.' + echo " -containerRegistry Host address of container registry." + echo " -containerRegistryUsername Username of container registry." + echo ' -containerRegistryPassword Password of given username for container registory.' + echo ' -iotHubConnectionString IoT hub connection string for creating edge device.' + echo ' -eventHubConnectionString Event hub connection string for receive D2C messages.' + echo ' -loadGenTransportType Transport type for LoadGen for long haul test. Default is mqtt.' + echo ' -loadGenMessageFrequency Frequency to send messages in LoadGen module for long haul and stress test. Default is 00.00.01 for long haul and 00:00:00.03 for stress test.' + echo ' -snitchAlertUrl Alert Url pointing to Azure Logic App for email preparation and sending for long haul and stress test.' + echo ' -snitchBuildNumber Build number for snitcher docker image for long haul and stress test. Default is 1.1.' + echo ' -snitchReportingIntervalInSecs Reporting frequency in seconds to send status email for long hual and stress test. Default is 86400 (1 day) for long haul and 1700000 for stress test.' + echo ' -snitchStorageAccount Azure blob Sstorage account for store logs used in status email for long haul and stress test.' + echo ' -snitchStorageMasterKey Master key of snitch storage account for long haul and stress test.' + echo ' -snitchTestDurationInSecs Test duration in seconds for long haul and stress test.' + echo ' -loadGen1TransportType Transport type for LoadGen1 for stress test. Default is amqp.' + echo ' -loadGen2TransportType Transport type for LoadGen2 for stress test. Default is amqp.' + echo ' -loadGen3TransportType Transport type for LoadGen3 for stress test. Default is mqtt.' + echo ' -loadGen4TransportType Transport type for LoadGen4 for stress test. Default is mqtt.' + echo ' -amqpSettingsEnabled Enable amqp protocol head in Edge Hub.' + echo ' -mqttSettingsEnabled Enable mqtt protocol head in Edge Hub.' + echo ' -longHaulProtocolHead Specify which protocol head is used to run long haul test for ARM32v7 device. Valid values are amqp (default) and mqtt.' + exit 1; +} + +process_args "$@" + +E2E_TEST_DIR="${E2E_TEST_DIR:-$(pwd)}" +LOADGEN_TRANSPORT_TYPE="${LOADGEN_TRANSPORT_TYPE:-mqtt}" +LONG_HAUL_PROTOCOL_HEAD="${LONG_HAUL_PROTOCOL_HEAD:-amqp}" +SNITCH_BUILD_NUMBER="${SNITCH_BUILD_NUMBER:-1.1}" +LOADGEN1_TRANSPORT_TYPE="${LOADGEN1_TRANSPORT_TYPE:-amqp}" +LOADGEN2_TRANSPORT_TYPE="${LOADGEN2_TRANSPORT_TYPE:-amqp}" +LOADGEN3_TRANSPORT_TYPE="${LOADGEN3_TRANSPORT_TYPE:-mqtt}" +LOADGEN4_TRANSPORT_TYPE="${LOADGEN4_TRANSPORT_TYPE:-mqtt}" +if [[ "${TEST_NAME,,}" == "longhaul" ]]; then + LOADGEN_MESSAGE_FREQUENCY="${LOADGEN_MESSAGE_FREQUENCY:-00:00:01}" + SNITCH_REPORTING_INTERVAL_IN_SECS="${SNITCH_REPORTING_INTERVAL_IN_SECS:-86400}" + SNITCH_TEST_DURATION_IN_SECS="${SNITCH_TEST_DURATION_IN_SECS:-604800}" +fi +if [[ "${TEST_NAME,,}" == "stress" ]]; then + LOADGEN_MESSAGE_FREQUENCY="${LOADGEN_MESSAGE_FREQUENCY:-00:00:00.03}" + SNITCH_REPORTING_INTERVAL_IN_SECS="${SNITCH_REPORTING_INTERVAL_IN_SECS:-1700000}" + SNITCH_TEST_DURATION_IN_SECS="${SNITCH_TEST_DURATION_IN_SECS:-14400}" +fi +if [ "$AMQP_SETTINGS_ENABLED" != "false" ]; then + AMQP_SETTINGS_ENABLED="true" +fi +if [ "$MQTT_SETTINGS_ENABLED" != "false" ]; then + MQTT_SETTINGS_ENABLED="true" +fi + +working_folder="$E2E_TEST_DIR/working" +get_image_architecture_label +iotedged_artifact_folder="$(get_iotedged_artifact_folder)" +iotedge_quickstart_artifact_file="$(get_iotedge_quickstart_artifact_file)" +leafdevice_artifact_file="$(get_leafdevice_artifact_file)" +twin_testfile_artifact_file="$E2E_TEST_DIR/artifacts/core-linux/e2e_test_files/twin_test_tempSensor.json" +module_to_module_deployment_artifact_file="$E2E_TEST_DIR/artifacts/core-linux/e2e_deployment_files/module_to_module_deployment.template.json" +module_to_functions_deployment_artifact_file="$E2E_TEST_DIR/artifacts/core-linux/e2e_deployment_files/module_to_functions_deployment.template.json" +dm_module_to_module_deployment_artifact_file="$E2E_TEST_DIR/artifacts/core-linux/e2e_deployment_files/dm_module_to_module_deployment.json" +long_haul_deployment_artifact_file="$(get_long_haul_deployment_artifact_file)" +stress_deployment_artifact_file="$E2E_TEST_DIR/artifacts/core-linux/e2e_deployment_files/stress_deployment.template.json" +deployment_working_file="$working_folder/deployment.json" +quickstart_working_folder="$working_folder/quickstart" +leafdevice_working_folder="$working_folder/leafdevice" + +run_test diff --git a/scripts/windows/test/Run-E2ETest.ps1 b/scripts/windows/test/Run-E2ETest.ps1 index 7816d6b1156..fc377602e01 100644 --- a/scripts/windows/test/Run-E2ETest.ps1 +++ b/scripts/windows/test/Run-E2ETest.ps1 @@ -5,33 +5,35 @@ .DESCRIPTION It is used to wrap all related steps to run E2E tests for Windows; it runs clean up, E2E test of given name, and print logs. - + To get details about parameters, please run "Get-Help .\Run-E2ETest.ps1 -Parameter *" To find out what E2E tests are supported, just run "Get-Help .\Run-E2ETest.ps1 -Parameter TestName" - + Please ensure that E2E test folder have below folders/files: - artifacts\core-windows: artifact from Image build. - artifacts\iotedged-windows: artifact from edgelet build. - artifacts\packages: contains packages of Moby docker engine, CLI and IoT Edge security daemon. Either artifacts\iotedged-windows or packages folder exists, which is used for IoT Edge security daemon installation. - - certs: contains CA certs for certificate-related testing. .PARAMETER E2ETestFolder - Path of E2E test folder + Path of E2E test folder which contains artifacts and certs folders; Default is current directory. .PARAMETER ReleaseLabel Release label, can be uniquely identify the build (e.g -); which is used as part of Edge device name. - .PARAMETER ReleaseArtifactImageBuildNumber - Release artifact image build number; it is used to construct path of docker images, pulling from EdgeBuilds docker registry. E.g. 20190101.1. + .PARAMETER ArtifactImageBuildNumber + Artifact image build number; it is used to construct path of docker images, pulling from docker registry. E.g. 20190101.1. .PARAMETER TestName Name of E2E test to be run - Note: Valid values are: + Note: Valid values are: "All", "DirectMethodAmqp", "DirectMethodMqtt", "QuickstartCerts", "TempFilter", "TempFilterFunctions", "TempSensor", "TransparentGateway" - .PARAMETER ContainerRegistryUserName - Username of container registry + .PARAMETER ContainerRegistry + Host address of container registry. It could be azure container registry, docker hub, or your own hosted container registry. + + .PARAMETER ContainerRegistryUsername + Username of container registry. .PARAMETER ContainerRegistryPassword Password of given username for container registory @@ -42,8 +44,37 @@ .PARAMETER EventHubConnectionString Event hub connection string for receive D2C messages + .PARAMETER ProxyUri + (Optional) The URI of an HTTPS proxy server; if specified, all communications to IoT Hub will go through this proxy. + .EXAMPLE - .\Run-E2ETest.ps1 -E2ETestFolder "C:\Data\e2etests" -ReleaseLabel "Release-ARM-1" -ReleaseArtifactImageBuildNumber "20190101.1" -Architecture "x64" -TestName "TempSensor" -ContainerRegistryUsername "EdgeBuilds" -ContainerRegistryPassword "xxxx" -IoTHubConnectionString "xxxx" -EventHubConnectionString "xxxx" + .\Run-E2ETest.ps1 + -E2ETestFolder "C:\Data\e2etests" + -ReleaseLabel "Release-ARM-1" + -ArtifactImageBuildNumber "20190101.1" + -TestName "TempSensor" + -ContainerRegistry "yourpipeline.azurecr.io" + -ContainerRegistryUsername "xxxx" + -ContainerRegistryPassword "xxxx" + -IoTHubConnectionString "xxxx" + -EventHubConnectionString "xxxx" + -ProxyUri "http://proxyserver:3128" + + Transparent gateway test command with custom Edge device certificates: + .\Run-E2ETest.ps1 + -E2ETestFolder "C:\Data\e2etests" + -ReleaseLabel "Release-ARM-1" + -ArtifactImageBuildNumber "20190101.1" + -TestName "TransparentGateway" + -ContainerRegistry "yourpipeline.azurecr.io" + -ContainerRegistryUsername "xxxx" + -ContainerRegistryPassword "xxxx" + -IoTHubConnectionString "xxxx" + -EventHubConnectionString "xxxx" + -ProxyUri "http://proxyserver:3128" + -EdgeE2ERootCACertRSAFile "file path" #if not provided, a default path will be checked + -EdgeE2ERootCAKeyRSAFile "file path" #if not provided, a default path will be checked + -EdgeE2ETestRootCAPassword "xxxx" .NOTES This script is to make running E2E tests easier and centralize E2E test steps in 1 place for reusability. @@ -61,11 +92,14 @@ Param ( [string] $ReleaseLabel = $(Throw "Release label is required"), [ValidateNotNullOrEmpty()] - [string] $ReleaseArtifactImageBuildNumber = $(Throw "Release artifact image build number is required"), + [string] $ArtifactImageBuildNumber = $(Throw "Artifact image build number is required"), [ValidateSet("All", "DirectMethodAmqp", "DirectMethodMqtt", "QuickstartCerts", "TempFilter", "TempFilterFunctions", "TempSensor", "TransparentGateway")] [string] $TestName = "All", + [ValidateNotNullOrEmpty()] + [string] $ContainerRegistry = $(Throw "Container registry is required"), + [ValidateNotNullOrEmpty()] [string] $ContainerRegistryUsername = $(Throw "Container registry username is required"), @@ -76,11 +110,24 @@ Param ( [string] $IoTHubConnectionString = $(Throw "IoT hub connection string is required"), [ValidateNotNullOrEmpty()] - [string] $EventHubConnectionString = $(Throw "Event hub connection string is required") + [string] $EventHubConnectionString = $(Throw "Event hub connection string is required"), + + [ValidateNotNullOrEmpty()] + [string] $EdgeE2ERootCACertRSAFile = $null, + + [ValidateNotNullOrEmpty()] + [string] $EdgeE2ERootCAKeyRSAFile = $null, + + [ValidateNotNullOrEmpty()] + [string] $EdgeE2ETestRootCAPassword = $null, + + [ValidateScript({($_ -as [System.Uri]).AbsoluteUri -ne $null})] + [string] $ProxyUri = $null ) Set-StrictMode -Version "Latest" $ErrorActionPreference = "Stop" +$global:ProgressPreference = "SilentlyContinue" Function AppendInstallationOption([string] $testCommand) { @@ -97,7 +144,7 @@ Function CleanUp PrintHighlightedMessage "Test Clean Up" Write-Host "Do IoT Edge Moby system prune" - Try + Try { docker -H npipe:////./pipe/iotedge_moby_engine system prune -f } @@ -121,17 +168,17 @@ Function GetArchitecture { $processorArchitecture = $ENV:PROCESSOR_ARCHITECTURE $Is64Bit = if ((Get-CimInstance -ClassName win32_operatingsystem).OSArchitecture.StartsWith("64")) { $True } Else { $False } - + If ($processorArchitecture.StartsWith("AMD") -And $Is64Bit) { Return "x64" } - + If ($processorArchitecture.StartsWith("ARM") -And -Not $Is64Bit) { Return "arm32v7" } - + Throw "Unsupported processor architecture $processorArchitecture (64-bit: $Is64Bit)" } @@ -175,8 +222,8 @@ Function PrepareTestFromArtifacts } # IoT Edge Quickstart - Write-Host "Copy IoT Edge Quickstart from $IoTEdgeQuickstartArtifactFolder to $QuickstartWorkingFolder" - Copy-Item $IoTEdgeQuickstartArtifactFolder -Destination $QuickstartWorkingFolder -Recurse -Force + Write-Host "Copy IoT Edge Quickstart from $IotEdgeQuickstartArtifactFolder to $QuickstartWorkingFolder" + Copy-Item $IotEdgeQuickstartArtifactFolder -Destination $QuickstartWorkingFolder -Recurse -Force # Leaf device If (($TestName -eq "QuickstartCerts") -Or ($TestName -eq "TransparentGateway")) @@ -189,9 +236,10 @@ Function PrepareTestFromArtifacts If (($TestName -eq "DirectMethodAmqp") -Or ($TestName -eq "DirectMethodMqtt") -Or ($TestName -eq "TempFilter") -Or - ($TestName -eq "TempFilterFunctions")) + ($TestName -eq "TempFilterFunctions") -Or + (($ProxyUri) -and ($TestName -in "TempSensor", "QuickstartCerts", "TransparentGateway"))) { - Switch ($TestName) + Switch -Regex ($TestName) { "DirectMethodAmqp" { @@ -206,11 +254,6 @@ Function PrepareTestFromArtifacts Copy-Item $DirectMethodModuleToModuleDeploymentArtifactFilePath -Destination $DeploymentWorkingFilePath -Force (Get-Content $DeploymentWorkingFilePath).replace('','Mqtt') | Set-Content $DeploymentWorkingFilePath (Get-Content $DeploymentWorkingFilePath).replace('','Mqtt_Tcp_Only') | Set-Content $DeploymentWorkingFilePath - - If ($Architecture -eq "arm32v7") - { - (Get-Content $DeploymentWorkingFilePath).replace('','1') | Set-Content $DeploymentWorkingFilePath - } } "TempFilter" { @@ -222,16 +265,74 @@ Function PrepareTestFromArtifacts Write-Host "Copy deployment file from $ModuleToFunctionDeploymentArtifactFilePath" Copy-Item $ModuleToFunctionDeploymentArtifactFilePath -Destination $DeploymentWorkingFilePath -Force } + "TempSensor" # Only when $ProxyUri is specified + { + Write-Host "Copy deployment file from $QuickstartDeploymentArtifactFilePath" + Copy-Item $QuickstartDeploymentArtifactFilePath -Destination $DeploymentWorkingFilePath -Force + } + "QuickstartCerts|TransparentGateway" # Only when $ProxyUri is specified + { + Write-Host "Copy deployment file from $RuntimeOnlyDeploymentArtifactFilePath" + Copy-Item $RuntimeOnlyDeploymentArtifactFilePath -Destination $DeploymentWorkingFilePath -Force + } } $ImageArchitectureLabel = $(GetImageArchitectureLabel) (Get-Content $DeploymentWorkingFilePath).replace('', $ImageArchitectureLabel) | Set-Content $DeploymentWorkingFilePath - (Get-Content $DeploymentWorkingFilePath).replace('', 'true') | Set-Content $DeploymentWorkingFilePath - (Get-Content $DeploymentWorkingFilePath).replace('', $ReleaseArtifactImageBuildNumber) | Set-Content $DeploymentWorkingFilePath + (Get-Content $DeploymentWorkingFilePath).replace('', $ArtifactImageBuildNumber) | Set-Content $DeploymentWorkingFilePath (Get-Content $DeploymentWorkingFilePath).replace('', $ContainerRegistryUsername) | Set-Content $DeploymentWorkingFilePath (Get-Content $DeploymentWorkingFilePath).replace('', $ContainerRegistryPassword) | Set-Content $DeploymentWorkingFilePath (Get-Content $DeploymentWorkingFilePath).replace('-linux-', '-windows-') | Set-Content $DeploymentWorkingFilePath + + If ($ProxyUri) + { + # Add/remove/edit JSON values *after* replacing all the '<>' placeholders because + # ConvertTo-Json will encode angle brackets. + $httpsProxy = "{ `"value`": `"$ProxyUri`" }" | ConvertFrom-Json + $json = Get-Content $DeploymentWorkingFilePath | ConvertFrom-Json + $edgeAgentDesired = $json.modulesContent.'$edgeAgent'.'properties.desired' + $upstreamProtocol = $edgeAgentDesired.systemModules.edgeHub.env.PSObject.Properties['UpstreamProtocol'] + If (($upstreamProtocol -ne $null) -and ($upstreamProtocol.Value.value -eq 'Mqtt')) { + $upstreamProtocol = '{ "value": "MqttWs" }' | ConvertFrom-Json + } else { + $upstreamProtocol = '{ "value": "AmqpWs" }' | ConvertFrom-Json + } + + # Add edgeAgent env with 'https_proxy' and 'UpstreamProtocol' + if ($edgeAgentDesired.systemModules.edgeAgent.PSObject.Properties['env'] -eq $null) { + $edgeAgentDesired.systemModules.edgeAgent | ` + Add-Member -Name 'env' -Value ([pscustomobject]@{}) -MemberType NoteProperty + } + $edgeAgentDesired.systemModules.edgeAgent.env | ` + Add-Member -Name 'https_proxy' -Value $httpsProxy -MemberType NoteProperty + $edgeAgentDesired.systemModules.edgeAgent.env | ` + Add-Member -Name 'UpstreamProtocol' -Value $upstreamProtocol -MemberType NoteProperty -Force + + # Add 'https_proxy' and 'UpstreamProtocol' to edgeHub env + $edgeAgentDesired.systemModules.edgeHub.env | ` + Add-Member -Name 'https_proxy' -Value $httpsProxy -MemberType NoteProperty + $edgeAgentDesired.systemModules.edgeHub.env | ` + Add-Member -Name 'UpstreamProtocol' -Value $upstreamProtocol -MemberType NoteProperty -Force + + $json | ConvertTo-Json -Depth 20 | Set-Content $DeploymentWorkingFilePath + } + } +} + +Function PrepareCertificateTools +{ + # setup environment before invoking cert gen script + $OpenSSLExeName="openssl.exe" + if ($null -eq (Get-Command $OpenSSLExeName -ErrorAction SilentlyContinue)) + { + # if openssl is not in path add default openssl install path and try again + $env:PATH += ";$DefaultOpensslInstallPath" + if ($null -eq (Get-Command $OpenSSLExeName -ErrorAction SilentlyContinue)) + { + throw ("$OpenSSLExeName is unavailable. Please install $OpenSSLExeName and set it in the PATH before proceeding.") + } } + $env:FORCE_NO_PROD_WARNING="True" } Function PrintLogs @@ -253,7 +354,7 @@ Function PrintLogs Get-WinEvent -ea SilentlyContinue ` -FilterHashtable @{ProviderName= "iotedged"; LogName = "application"; StartTime = $testStartTime} | - select TimeCreated, Message | + select TimeCreated, Message | sort-object @{Expression="TimeCreated";Descending=$false} | format-table -autosize -wrap | Out-Host @@ -262,8 +363,8 @@ Function PrintLogs Try { Write-Host "EDGE AGENT LOGS" - Invoke-Expression "$dockerCmd logs edgeAgent" - } + Invoke-Expression "$dockerCmd logs edgeAgent" | Out-Host + } Catch { Write-Host "Exception caught when output Edge Agent logs" @@ -272,8 +373,8 @@ Function PrintLogs Try { Write-Host "EDGE HUB LOGS" - Invoke-Expression "$dockerCmd logs edgeHub" - } + Invoke-Expression "$dockerCmd logs edgeHub" | Out-Host + } Catch { Write-Host "Exception caught when output Edge Hub logs" @@ -286,8 +387,8 @@ Function PrintLogs Try { Write-Host "TEMP SENSOR LOGS" - Invoke-Expression "$dockerCmd logs tempSensor" - } + Invoke-Expression "$dockerCmd logs tempSensor" | Out-Host + } Catch { Write-Host "Exception caught when output Temp Sensor logs" @@ -298,7 +399,7 @@ Function PrintLogs { Try { Write-Host "TEMP FILTER LOGS" - Invoke-Expression "$dockerCmd logs tempFilter" + Invoke-Expression "$dockerCmd logs tempFilter" | Out-Host } Catch { @@ -310,7 +411,7 @@ Function PrintLogs { Try { Write-Host "TEMP FILTER FUNCTIONS LOGS" - Invoke-Expression "$dockerCmd logs tempFilterFunctions" + Invoke-Expression "$dockerCmd logs tempFilterFunctions" | Out-Host } Catch { @@ -323,15 +424,15 @@ Function RunAllTests { $TestName = "DirectMethodAmqp" $lastTestExitCode = RunDirectMethodAmqpTest - + $TestName = "DirectMethodMqtt" $testExitCode = RunDirectMethodMqttTest $lastTestExitCode = If ($testExitCode -gt 0) { $testExitCode } Else { $lastTestExitCode } - + $TestName = "QuickstartCerts" $testExitCode = RunQuickstartCertsTest $lastTestExitCode = If ($testExitCode -gt 0) { $testExitCode } Else { $lastTestExitCode } - + $TestName = "TempFilter" $testExitCode = RunTempFilterTest $lastTestExitCode = If ($testExitCode -gt 0) { $testExitCode } Else { $lastTestExitCode } @@ -339,15 +440,15 @@ Function RunAllTests $TestName = "TempFilterFunctions" $testExitCode = RunTempFilterFunctionsTest $lastTestExitCode = If ($testExitCode -gt 0) { $testExitCode } Else { $lastTestExitCode } - + $TestName = "TempSensor" $testExitCode = RunTempSensorTest $lastTestExitCode = If ($testExitCode -gt 0) { $testExitCode } Else { $lastTestExitCode } - + $TestName = "TransparentGateway" $testExitCode = RunTransparentGatewayTest $lastTestExitCode = If ($testExitCode -gt 0) { $testExitCode } Else { $lastTestExitCode } - + Return $lastTestExitCode } @@ -357,18 +458,24 @@ Function RunDirectMethodAmqpTest TestSetup $testStartAt = Get-Date - $deviceId = "e2e-${ReleaseLabel}-Windows-DMAmqp" - PrintHighlightedMessage "Run quickstart test with -d ""$deviceId"" and deployment file $DeploymentWorkingFilePath started at $testStartAt" - - $testCommand = "&$IoTEdgeQuickstartExeTestPath `` + $deviceId = "e2e-${ReleaseLabel}-Windows-${Architecture}-DMAmqp" + PrintHighlightedMessage "Run quickstart test with -d ""$deviceId"" started at $testStartAt" + + $testCommand = "&$IotEdgeQuickstartExeTestPath `` -d `"$deviceId`" `` -c `"$IoTHubConnectionString`" `` -e `"$EventHubConnectionString`" `` + -n `"$env:computername`" `` -r `"$ContainerRegistry`" `` -u `"$ContainerRegistryUsername`" `` -p `"$ContainerRegistryPassword`" --verify-data-from-module `"DirectMethodSender`" `` - -t `"${ReleaseArtifactImageBuildNumber}-windows-$(GetImageArchitectureLabel)`" `` + -t `"${ArtifactImageBuildNumber}-windows-$(GetImageArchitectureLabel)`" `` -l `"$DeploymentWorkingFilePath`"" + If ($ProxyUri) { + $testCommand = "$testCommand `` + --upstream-protocol 'AmqpWs' `` + --proxy `"$ProxyUri`"" + } $testCommand = AppendInstallationOption($testCommand) Invoke-Expression $testCommand | Out-Host $testExitCode = $LastExitCode @@ -383,18 +490,24 @@ Function RunDirectMethodMqttTest TestSetup $testStartAt = Get-Date - $deviceId = "e2e-${ReleaseLabel}-Windows-DMMqtt" - PrintHighlightedMessage "Run quickstart test with -d ""$deviceId"" and deployment file $DeploymentWorkingFilePath started at $testStartAt" - - $testCommand = "&$IoTEdgeQuickstartExeTestPath `` + $deviceId = "e2e-${ReleaseLabel}-Windows-${Architecture}-DMMqtt" + PrintHighlightedMessage "Run quickstart test with -d ""$deviceId"" started at $testStartAt" + + $testCommand = "&$IotEdgeQuickstartExeTestPath `` -d `"$deviceId`" `` -c `"$IoTHubConnectionString`" `` -e `"$EventHubConnectionString`" `` + -n `"$env:computername`" `` -r `"$ContainerRegistry`" `` -u `"$ContainerRegistryUsername`" `` -p `"$ContainerRegistryPassword`" --verify-data-from-module `"DirectMethodSender`" `` - -t `"${ReleaseArtifactImageBuildNumber}-windows-$(GetImageArchitectureLabel)`" `` + -t `"${ArtifactImageBuildNumber}-windows-$(GetImageArchitectureLabel)`" `` -l `"$DeploymentWorkingFilePath`"" + If ($ProxyUri) { + $testCommand = "$testCommand `` + --upstream-protocol 'MqttWs' `` + --proxy `"$ProxyUri`"" + } $testCommand = AppendInstallationOption($testCommand) Invoke-Expression $testCommand | Out-Host $testExitCode = $LastExitCode @@ -409,20 +522,26 @@ Function RunQuickstartCertsTest TestSetup $testStartAt = Get-Date - $deviceId = "e2e-${ReleaseLabel}-Windows-QuickstartCerts" + $deviceId = "e2e-${ReleaseLabel}-Windows-${Architecture}-QuickstartCerts" PrintHighlightedMessage "Run quickstart test with -d ""$deviceId"" started at $testStartAt" - $testCommand = "&$IoTEdgeQuickstartExeTestPath `` + $testCommand = "&$IotEdgeQuickstartExeTestPath `` -d `"$deviceId`" `` -c `"$IoTHubConnectionString`" `` -e `"doesNotNeed`" `` -n `"$env:computername`" `` -r `"$ContainerRegistry`" `` -u `"$ContainerRegistryUsername`" `` - -p `"$ContainerRegistryPassword`" --optimize_for_performance true `` - -t `"${ReleaseArtifactImageBuildNumber}-windows-$(GetImageArchitectureLabel)`" `` - --leave-running=Core `` + -p `"$ContainerRegistryPassword`" `` + -t `"${ArtifactImageBuildNumber}-windows-$(GetImageArchitectureLabel)`" `` + --leave-running=All `` --no-verify" + If ($ProxyUri) { + $testCommand = "$testCommand `` + -l `"$DeploymentWorkingFilePath`" `` + --upstream-protocol 'AmqpWs' `` + --proxy `"$ProxyUri`"" + } $testCommand = AppendInstallationOption($testCommand) Invoke-Expression $testCommand | Out-Host @@ -430,14 +549,18 @@ Function RunQuickstartCertsTest Write-Host "CA certificate path=$caCertPath" Write-Host "Run LeafDevice" - &$LeafDeviceExeTestPath ` - -d "${deviceId}-leaf" ` - -c "$IoTHubConnectionString" ` - -e "$EventHubConnectionString" ` - -ct "$caCertPath" ` - -ed "$env:computername" | Out-Host + $testCommand = "&$LeafDeviceExeTestPath `` + -d `"${deviceId}-leaf`" `` + -c `"$IoTHubConnectionString`" `` + -e `"$EventHubConnectionString`" `` + -ct `"$caCertPath`" `` + -ed `"$env:computername`"" + If ($ProxyUri) { + $testCommand = "$testCommand --proxy `"$ProxyUri`"" + } + Invoke-Expression $testCommand | Out-Host $testExitCode = $LastExitCode - + PrintLogs $testStartAt $testExitCode Return $testExitCode } @@ -448,18 +571,24 @@ Function RunTempFilterTest TestSetup $testStartAt = Get-Date - $deviceId = "e2e-${ReleaseLabel}-Windows-tempFilter" - PrintHighlightedMessage "Run quickstart test with -d ""$deviceId"" and deployment file $DeploymentWorkingFilePath started at $testStartAt" - - $testCommand = "&$IoTEdgeQuickstartExeTestPath `` + $deviceId = "e2e-${ReleaseLabel}-Windows-${Architecture}-tempFilter" + PrintHighlightedMessage "Run quickstart test with -d ""$deviceId"" started at $testStartAt" + + $testCommand = "&$IotEdgeQuickstartExeTestPath `` -d `"$deviceId`" `` -c `"$IoTHubConnectionString`" `` -e `"$EventHubConnectionString`" `` + -n `"$env:computername`" `` -r `"$ContainerRegistry`" `` -u `"$ContainerRegistryUsername`" `` -p `"$ContainerRegistryPassword`" --verify-data-from-module `"tempFilter`" `` - -t `"${ReleaseArtifactImageBuildNumber}-windows-$(GetImageArchitectureLabel)`" `` + -t `"${ArtifactImageBuildNumber}-windows-$(GetImageArchitectureLabel)`" `` -l `"$DeploymentWorkingFilePath`"" + If ($ProxyUri) { + $testCommand = "$testCommand `` + --upstream-protocol 'AmqpWs' `` + --proxy `"$ProxyUri`"" + } $testCommand = AppendInstallationOption($testCommand) Invoke-Expression $testCommand | Out-Host $testExitCode = $LastExitCode @@ -480,18 +609,24 @@ Function RunTempFilterFunctionsTest TestSetup $testStartAt = Get-Date - $deviceId = "e2e-${ReleaseLabel}-Windows-tempFilterFunc" - PrintHighlightedMessage "Run quickstart test with -d ""$deviceId"" and deployment file $DeploymentWorkingFilePath started at $testStartAt" - - $testCommand = "&$IoTEdgeQuickstartExeTestPath `` + $deviceId = "e2e-${ReleaseLabel}-Windows-${Architecture}-tempFilterFunc" + PrintHighlightedMessage "Run quickstart test with -d ""$deviceId"" started at $testStartAt" + + $testCommand = "&$IotEdgeQuickstartExeTestPath `` -d `"$deviceId`" `` -c `"$IoTHubConnectionString`" `` -e `"$EventHubConnectionString`" `` + -n `"$env:computername`" `` -r `"$ContainerRegistry`" `` -u `"$ContainerRegistryUsername`" `` -p `"$ContainerRegistryPassword`" --verify-data-from-module `"tempFilterFunctions`" `` - -t `"${ReleaseArtifactImageBuildNumber}-windows-$(GetImageArchitectureLabel)`" `` + -t `"${ArtifactImageBuildNumber}-windows-$(GetImageArchitectureLabel)`" `` -l `"$DeploymentWorkingFilePath`"" + If ($ProxyUri) { + $testCommand = "$testCommand `` + --upstream-protocol 'AmqpWs' `` + --proxy `"$ProxyUri`"" + } $testCommand = AppendInstallationOption($testCommand) Invoke-Expression $testCommand | Out-Host $testExitCode = $LastExitCode @@ -506,18 +641,26 @@ Function RunTempSensorTest TestSetup $testStartAt = Get-Date - $deviceId = "e2e-${ReleaseLabel}-Windows-tempSensor" + $deviceId = "e2e-${ReleaseLabel}-Windows-${Architecture}-tempSensor" PrintHighlightedMessage "Run quickstart test with -d ""$deviceId"" started at $testStartAt." - $testCommand = "&$IoTEdgeQuickstartExeTestPath `` + $testCommand = "&$IotEdgeQuickstartExeTestPath `` -d `"$deviceId`" `` -c `"$IoTHubConnectionString`" `` -e `"$EventHubConnectionString`" `` + -n `"$env:computername`" `` -r `"$ContainerRegistry`" `` -u `"$ContainerRegistryUsername`" `` - -p `"$ContainerRegistryPassword`" --optimize_for_performance true `` - -t `"${ReleaseArtifactImageBuildNumber}-windows-$(GetImageArchitectureLabel)`" `` + -p `"$ContainerRegistryPassword`" `` + -t `"${ArtifactImageBuildNumber}-windows-$(GetImageArchitectureLabel)`" `` -tw `"$TwinTestFileArtifactFilePath`"" + + If ($ProxyUri) { + $testCommand = "$testCommand `` + -l `"$DeploymentWorkingFilePath`" `` + --upstream-protocol 'AmqpWs' `` + --proxy `"$ProxyUri`"" + } $testCommand = AppendInstallationOption($testCommand) Invoke-Expression $testCommand | Out-Host $testExitCode = $LastExitCode @@ -526,49 +669,181 @@ Function RunTempSensorTest Return $testExitCode } +Function RunLeafDeviceTest +( + [ValidateSet("sas","x509CA","x509Thumprint")][string]$authType, + [ValidateSet("Mqtt","MqttWs","Amqp", "AmqpWs")][string]$protocol, + [ValidateNotNullOrEmpty()][string]$leafDeviceId, + [string]$edgeDeviceId +) +{ + $testCommand = $null + switch ($authType) { + "sas" + { + if ([string]::IsNullOrWhiteSpace($edgeDeviceId)) + { + Write-Host "Run LeafDevice with SAS auth not in scope" + $testCommand = "&$LeafDeviceExeTestPath `` + -d `"$leafDeviceId`" `` + -c `"$IoTHubConnectionString`" `` + -e `"$EventHubConnectionString`" `` + -proto `"$protocol`" `` + -ct `"$TrustedCACertificatePath`" `` + -ed `"$env:computername`"" + } + else + { + Write-Host "Run LeafDevice with SAS auth in scope" + $testCommand = "&$LeafDeviceExeTestPath `` + -d `"$leafDeviceId`" `` + -c `"$IoTHubConnectionString`" `` + -e `"$EventHubConnectionString`" `` + -proto `"$protocol`" `` + -ct `"$TrustedCACertificatePath`" `` + -ed-id `"$edgeDeviceId`" `` + -ed `"$env:computername`"" + } + break + } + + "x509CA" + { + if ([string]::IsNullOrWhiteSpace($edgeDeviceId)) + { + $(Throw "For X.509 leaf device, the Edge device Id is requried") + } + Write-Host "Run LeafDevice with X.509 CA auth in scope" + New-CACertsDevice "$leafDeviceId" + $testCommand = "&$LeafDeviceExeTestPath `` + -d `"$leafDeviceId`" `` + -c `"$IoTHubConnectionString`" `` + -e `"$EventHubConnectionString`" `` + -proto `"$protocol`" `` + -ct `"$TrustedCACertificatePath`" `` + -cac `"$EdgeCertGenScriptDir\certs\iot-device-${leafDeviceId}-full-chain.cert.pem`" `` + -cak `"$EdgeCertGenScriptDir\private\iot-device-${leafDeviceId}.key.pem`" `` + -ed-id `"$edgeDeviceId`" `` + -ed `"$env:computername`"" + break + } + + "x509Thumprint" + { + if ([string]::IsNullOrWhiteSpace($edgeDeviceId)) + { + $(Throw "For X.509 leaf device, the Edge device Id is requried") + } + Write-Host "Run LeafDevice with X.509 thumbprint auth in scope" + New-CACertsDevice "$leafDeviceId-pri" + New-CACertsDevice "$leafDeviceId-sec" + $testCommand = "&$LeafDeviceExeTestPath `` + -d `"$leafDeviceId`" `` + -c `"$IoTHubConnectionString`" `` + -e `"$EventHubConnectionString`" `` + -proto `"$protocol`" `` + -ct `"$TrustedCACertificatePath`" `` + -ctpc `"$EdgeCertGenScriptDir\certs\iot-device-${leafDeviceId}-pri-full-chain.cert.pem`" `` + -ctpk `"$EdgeCertGenScriptDir\private\iot-device-${leafDeviceId}-pri.key.pem`" `` + -ctsc `"$EdgeCertGenScriptDir\certs\iot-device-${leafDeviceId}-sec-full-chain.cert.pem`" `` + -ctsk `"$EdgeCertGenScriptDir\private\iot-device-${leafDeviceId}-sec.key.pem`" `` + -ed-id `"$edgeDeviceId`" `` + -ed `"$env:computername`"" + break + } + + default + { + $(Throw "Unsupported auth mode $authType") + } + } + + If ($ProxyUri) { + $testCommand = "$testCommand --proxy `"$ProxyUri`"" + } + + $testStartAt = Get-Date + Invoke-Expression $testCommand | Out-Host + $testExitCode = $LastExitCode + PrintLogs $testStartAt $testExitCode + + Return $testExitCode +} + Function RunTransparentGatewayTest { PrintHighlightedMessage "Run Transparent Gateway test for $Architecture" + + if ([string]::IsNullOrWhiteSpace($EdgeE2ERootCACertRSAFile)) + { + $EdgeE2ERootCACertRSAFile=$DefaultInstalledRSARootCACert + } + if ([string]::IsNullOrWhiteSpace($EdgeE2ERootCAKeyRSAFile)) + { + $EdgeE2ERootCAKeyRSAFile=$DefaultInstalledRSARootCAKey + } TestSetup $testStartAt = Get-Date - $deviceId = "e2e-${ReleaseLabel}-Windows-TransGW" - PrintHighlightedMessage "Run quickstart test with -d ""$deviceId"" started at $testStartAt." - - $testCommand = "&$IoTEdgeQuickstartExeTestPath `` - -d `"$deviceId`" `` + $edgeDeviceId = "e2e-${ReleaseLabel}-Windows-${Architecture}-TransGW" + PrintHighlightedMessage "Run quickstart test with -d ""$edgeDeviceId"" started at $testStartAt." + + # setup certificate generation tools to create the Edge device and leaf device certificates + PrepareCertificateTools + # dot source the certificate generation script + . "$EdgeCertGenScript" + # install the provided root CA to seed the certificate chain + Install-RootCACertificate $EdgeE2ERootCACertRSAFile $EdgeE2ERootCAKeyRSAFile "rsa" $EdgeE2ETestRootCAPassword + + # generate the edge gateway certs + New-CACertsEdgeDevice $edgeDeviceId + + #launch the edge as a transparent gateway + $testCommand = "&$IotEdgeQuickstartExeTestPath `` + -d `"$edgeDeviceId`" `` -c `"$IoTHubConnectionString`" `` -e `"doesNotNeed`" `` -n `"$env:computername`" `` -r `"$ContainerRegistry`" `` -u `"$ContainerRegistryUsername`" `` - -p `"$ContainerRegistryPassword`" --optimize_for_performance true `` - -t `"${ReleaseArtifactImageBuildNumber}-windows-$(GetImageArchitectureLabel)`" `` - --leave-running=Core `` - --no-verify `` - --device_ca_cert `"$DeviceCACertificatePath`" `` - --device_ca_pk `"$DeviceCAPrimaryKeyPath`" `` - --trusted_ca_certs `"$TrustedCACertificatePath`"" + -p `"$ContainerRegistryPassword`" `` + -t `"${ArtifactImageBuildNumber}-windows-$(GetImageArchitectureLabel)`" `` + --device_ca_cert `"$EdgeCertGenScriptDir\certs\iot-edge-device-$edgeDeviceId-full-chain.cert.pem`" `` + --device_ca_pk `"$EdgeCertGenScriptDir\private\iot-edge-device-$edgeDeviceId.key.pem`" `` + --trusted_ca_certs `"$TrustedCACertificatePath`" `` + --leave-running=All `` + --no-verify" + + If ($ProxyUri) { + $testCommand = "$testCommand `` + -l `"$DeploymentWorkingFilePath`" `` + --upstream-protocol 'AmqpWs' `` + --proxy `"$ProxyUri`"" + } $testCommand = AppendInstallationOption($testCommand) Invoke-Expression $testCommand | Out-Host - Write-Host "Run LeafDevice" - &$LeafDeviceExeTestPath ` - -d "${deviceId}-leaf" ` - -c "$IoTHubConnectionString" ` - -e "$EventHubConnectionString" ` - -ct "$TrustedCACertificatePath" ` - -ed "$env:computername" | Out-Host - $testExitCode = $LastExitCode - - PrintLogs $testStartAt $testExitCode + # run the various leaf device tests + $deviceId = "e2e-${ReleaseLabel}-Win-${Architecture}" + RunLeafDeviceTest "sas" "Mqtt" "$deviceId-mqtt-sas-noscope-leaf" $null + RunLeafDeviceTest "sas" "Amqp" "$deviceId-amqp-sas-noscope-leaf" $null + + RunLeafDeviceTest "sas" "Mqtt" "$deviceId-mqtt-sas-inscope-leaf" $edgeDeviceId + RunLeafDeviceTest "sas" "Amqp" "$deviceId-amqp-sas-inscope-leaf" $edgeDeviceId + + RunLeafDeviceTest "x509CA" "Mqtt" "$deviceId-mqtt-x509ca-inscope-leaf" $edgeDeviceId + RunLeafDeviceTest "x509CA" "Amqp" "$deviceId-amqp-x509ca-inscope-leaf" $edgeDeviceId + + RunLeafDeviceTest "x509Thumprint" "Mqtt" "$deviceId-mqtt-x509th-inscope-leaf" $edgeDeviceId + RunLeafDeviceTest "x509Thumprint" "Amqp" "$deviceId-amqp-x509th-inscope-leaf" $edgeDeviceId + Return $testExitCode } Function RunTest { $testExitCode = 0 - + Switch ($TestName) { "All" { $testExitCode = RunAllTests; break } @@ -582,20 +857,29 @@ Function RunTest default { Throw "$TestName test is not supported." } } - Exit $testExitCode -gt 0 + Return $testExitCode +} + +Function SetEnvironmentVariable +{ + # IotEdgeQuickstart runs different processes to call iotedge list right after running installation script. + # E2E test failed randomly when running iotedge list command throws Win32Exception as Path environment variable may not be in place yet. + # Therefore set it explicitly before running each test. + $env:Path="$env:Path;C:\Program Files\iotedge-moby;C:\Program Files\iotedge" } Function TestSetup { - ValidateE2ETestParameters + ValidateTestParameters CleanUp | Out-Host InitializeWorkingFolder PrepareTestFromArtifacts + SetEnvironmentVariable } -Function ValidateE2ETestParameters +Function ValidateTestParameters { - PrintHighlightedMessage "Validate E2E test parameters for $TestName" + PrintHighlightedMessage "Validate test parameters for $TestName" If (-Not((Test-Path (Join-Path $IoTEdgedArtifactFolder "*")) -Or (Test-Path (Join-Path $PackagesArtifactFolder "*")))) { @@ -603,7 +887,7 @@ Function ValidateE2ETestParameters } $validatingItems = @( - (Join-Path $IoTEdgeQuickstartArtifactFolder "*"), + (Join-Path $IotEdgeQuickstartArtifactFolder "*"), $InstallationScriptPath) If (($TestName -eq "DirectMethodAmqp") -Or ($TestName -eq "DirectMethodMqtt")) @@ -613,6 +897,10 @@ Function ValidateE2ETestParameters If (($TestName -eq "QuickstartCerts") -Or ($TestName -eq "TransparentGateway")) { + if ($ProxyUri) + { + $validatingItems += $RuntimeOnlyDeploymentArtifactFilePath + } $validatingItems += (Join-Path $LeafDeviceArtifactFolder "*") } @@ -628,18 +916,22 @@ Function ValidateE2ETestParameters If ($TestName -eq "TempSensor") { + if ($ProxyUri) + { + $validatingItems += $QuickstartDeploymentArtifactFilePath + } $validatingItems += $TwinTestFileArtifactFilePath } If ($TestName -eq "TransparentGateway") { - $validatingItems += $DeviceCACertificatePath - $validatingItems += $DeviceCAPrimaryKeyPath - $validatingItems += $TrustedCACertificatePath + $validatingItems += $EdgeCertGenScriptDir + $validatingItems += $EdgeE2ERootCACertRSAFile + $validatingItems += $EdgeE2ERootCAKeyRSAFile } $validatingItems | ForEach-Object { - If (-Not (Test-Path $_)) + If (-Not (Test-Path -Path $_)) { Throw "$_ is not found or it is empty" } @@ -654,15 +946,22 @@ Function PrintHighlightedMessage } $Architecture = GetArchitecture -$ContainerRegistry = "edgebuilds.azurecr.io" $E2ETestFolder = (Resolve-Path $E2ETestFolder).Path +$DefaultOpensslInstallPath = "C:\vcpkg\installed\x64-windows\tools\openssl" $InstallationScriptPath = Join-Path $E2ETestFolder "artifacts\core-windows\scripts\windows\setup\IotEdgeSecurityDaemon.ps1" +$EdgeCertGenScriptDir = Join-Path $E2ETestFolder "artifacts\core-windows\CACertificates" +$EdgeCertGenScript = Join-Path $EdgeCertGenScriptDir "ca-certs.ps1" +$DefaultInstalledRSARootCACert = Join-Path $EdgeCertGenScriptDir "rsa_root_ca.cert.pem" +$DefaultInstalledRSARootCAKey = Join-Path $EdgeCertGenScriptDir "rsa_root_ca.key.pem" +$TrustedCACertificatePath= Join-Path $EdgeCertGenScriptDir "\certs\azure-iot-test-only.root.ca.cert.pem" $ModuleToModuleDeploymentFilename = "module_to_module_deployment.template.json" $ModuleToFunctionsDeploymentFilename = "module_to_functions_deployment.template.json" $DirectMethodModuleToModuleDeploymentFilename = "dm_module_to_module_deployment.json" +$RuntimeOnlyDeploymentFilename = 'runtime_only_deployment.template.json' +$QuickstartDeploymentFilename = 'quickstart_deployment.template.json' $TwinTestFilename = "twin_test_tempSensor.json" -$IoTEdgeQuickstartArtifactFolder = Join-Path $E2ETestFolder "artifacts\core-windows\IoTEdgeQuickstart\$Architecture" +$IotEdgeQuickstartArtifactFolder = Join-Path $E2ETestFolder "artifacts\core-windows\IotEdgeQuickstart\$Architecture" $LeafDeviceArtifactFolder = Join-Path $E2ETestFolder "artifacts\core-windows\LeafDevice\$Architecture" $IoTEdgedArtifactFolder = Join-Path $E2ETestFolder "artifacts\iotedged-windows" $PackagesArtifactFolder = Join-Path $E2ETestFolder "artifacts\packages" @@ -670,6 +969,8 @@ $DeploymentFilesFolder = Join-Path $E2ETestFolder "artifacts\core-windows\e2e_de $TestFileFolder = Join-Path $E2ETestFolder "artifacts\core-windows\e2e_test_files" $ModuleToModuleDeploymentArtifactFilePath = Join-Path $DeploymentFilesFolder $ModuleToModuleDeploymentFilename $ModuleToFunctionDeploymentArtifactFilePath = Join-Path $DeploymentFilesFolder $ModuleToFunctionsDeploymentFilename +$RuntimeOnlyDeploymentArtifactFilePath = Join-Path $DeploymentFilesFolder $RuntimeOnlyDeploymentFilename +$QuickstartDeploymentArtifactFilePath = Join-Path $DeploymentFilesFolder $QuickstartDeploymentFilename $TwinTestFileArtifactFilePath = Join-Path $TestFileFolder $TwinTestFilename $DirectMethodModuleToModuleDeploymentArtifactFilePath = Join-Path $DeploymentFilesFolder $DirectMethodModuleToModuleDeploymentFilename @@ -678,13 +979,12 @@ $QuickstartWorkingFolder = (Join-Path $TestWorkingFolder "quickstart") $LeafDeviceWorkingFolder = (Join-Path $TestWorkingFolder "leafdevice") $IoTEdgedWorkingFolder = (Join-Path $TestWorkingFolder "iotedged") $PackagesWorkingFolder = (Join-Path $TestWorkingFolder "packages") -$IoTEdgeQuickstartExeTestPath = (Join-Path $QuickstartWorkingFolder "IotEdgeQuickstart.exe") +$IotEdgeQuickstartExeTestPath = (Join-Path $QuickstartWorkingFolder "IotEdgeQuickstart.exe") $LeafDeviceExeTestPath = (Join-Path $LeafDeviceWorkingFolder "LeafDevice.exe") $DeploymentWorkingFilePath = Join-Path $QuickstartWorkingFolder "deployment.json" -$DeviceCACertificatePath = (Join-Path $E2ETestFolder "certs\new-edge-device-full-chain.cert.pem") -$DeviceCAPrimaryKeyPath = (Join-Path $E2ETestFolder "certs\private\new-edge-device.key.pem") -$TrustedCACertificatePath = (Join-Path $E2ETestFolder "certs\azure-iot-test-only.root.ca.cert.pem") - &$InstallationScriptPath -RunTest \ No newline at end of file + +$retCode = RunTest +Write-Host "Exit test with code $retCode" +Exit $retCode -gt 0 \ No newline at end of file