Skip to content

Commit

Permalink
Self Upgrade test for Ubuntu 18.04 (#456)
Browse files Browse the repository at this point in the history
  • Loading branch information
shiyi-peng committed Apr 14, 2023
1 parent 0b74a2d commit dd3d3a0
Show file tree
Hide file tree
Showing 8 changed files with 324 additions and 5 deletions.
2 changes: 1 addition & 1 deletion azurepipelines/build/native/adu-ubuntu-amd64-build.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
variables:
version.major: 1
version.minor: 0
version.patch: 2
version.patch: 3
version.pre-release: ""
version.build: $[format('{0:yyyyMMdd}-{0:HHmmss}', pipeline.startTime)]

Expand Down
9 changes: 8 additions & 1 deletion azurepipelines/build/templates/adu-docker-build-steps.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ parameters:
type: string
- name: targetArch # example: amd64
type: string
- name: patchVersion # exmaple: 3
default: ''
type: string

steps:
- task: ms.vss-governance-buildtask.governance-build-task-component-detection.ComponentGovernanceComponentDetection@0
Expand Down Expand Up @@ -42,7 +45,11 @@ steps:
sudo docker run -d -t --rm -v $(Build.SourcesDirectory):/iot-hub-device-update -v ~/.gitconfig:/etc/.gitconfig --name ARMcontainer aduccontainerregistry.azurecr.io/${{parameters.targetOs}}-${{parameters.targetArch}}:latest bash
displayName: "Run docker container"
- bash: |
sudo docker exec -w /iot-hub-device-update ARMcontainer scripts/build.sh --clean --build-unit-tests --type MinSizeRel --platform-layer linux --log-lib zlog --build-packages --out-dir out-${{parameters.targetOs}}-${{parameters.targetArch}}
if [ -n "${{parameters.patchVersion}}" ]; then
sudo docker exec -w /iot-hub-device-update ARMcontainer scripts/build.sh --clean --build-unit-tests --type MinSizeRel --platform-layer linux --log-lib zlog --build-packages --patch-version ${{parameters.patchVersion}} --out-dir out-${{parameters.targetOs}}-${{parameters.targetArch}}
else
sudo docker exec -w /iot-hub-device-update ARMcontainer scripts/build.sh --clean --build-unit-tests --type MinSizeRel --platform-layer linux --log-lib zlog --build-packages --out-dir out-${{parameters.targetOs}}-${{parameters.targetArch}}
fi
displayName: "Build Client, Unit Tests and Packages: linux-MinSizeRel"
- bash: |
cp out-${{parameters.targetOs}}-${{parameters.targetArch}}/*.deb $(Build.ArtifactStagingDirectory)
Expand Down
3 changes: 2 additions & 1 deletion azurepipelines/e2e_test/e2etest.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ stages:
parameters:
targetOs: ubuntu1804
targetArch: amd64
patchVersion: 4
- job: BuildUbuntu_1804_ARM64
displayName: Building the Device Update Package for Ubuntu 18.04 ARM64
continueOnError: False
Expand Down Expand Up @@ -129,7 +130,7 @@ stages:
du_tarball_script: >-
tar -xvf /tmp/testsetup.tar.gz -C ./ &&
chmod u=rwx,g=rwx,o=rx ./testsetup/setup.sh &&
./testsetup/setup.sh
./testsetup/setup.sh --self-upgrade
image_working_directory: $(E2E_WORKING_DIR)
- job: SetupUbuntu1804_ARM64_VM
displayName: "Setting up VM for Ubuntu 18.04 ARM64 Test VM"
Expand Down
161 changes: 161 additions & 0 deletions azurepipelines/e2e_test/scenarios/ubuntu-18.04-amd64/self_upgrade.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
# -------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for
# license information.
# --------------------------------------------------------------------------
import io
import sys
import time
import unittest
import xmlrunner

# Note: the intention is that this script is called like:
# python ./scenarios/<scenario-name>/testscript.py
sys.path.append('./scenarios/')
from testingtoolkit import DeviceUpdateTestHelper
from testingtoolkit import UpdateId
from testingtoolkit import DeploymentStatusResponse
from testingtoolkit import DuAutomatedTestConfigurationManager
from xmlrunner.extra.xunit_plugin import transform

# Note: the intention is that this script is called like:
# python ./scenarios/<scenario-name>/<test-script-name>.py
sys.path.append('./scenarios/ubuntu-18.04-amd64/')
from scenario_definitions import test_device_id, test_adu_group, test_result_file_prefix, test_apt_deployment_id, test_connection_timeout_tries, retry_wait_time_in_seconds

#
# Global Test Variables
#

apt_deployment_status_retries = 15

class AptDeploymentTest(unittest.TestCase):

#
# Every test within a subclass of a unittest.TestCase to be run by unittest must have the prefix test_
#
def test_AptDeployment(self):

#
# The first step to any test is to create the test helper that allows us to make calls to both the DU account and the
# IotHub. In the pipeline the parameters to create the test helper are passed to the environment from which we can read them
# here.
#
# For testing it might be convenient to simply define these above and directly instantiate the object or if you're not planning
# on running the tests as apart of a unittest.TestCase you can simply pass them via the CLI to the python program
# and create the test helper using the helper method
# DuAutomatedTestConfigurationManager.FromCliArgs()
#
self.aduTestConfig = DuAutomatedTestConfigurationManager.FromOSEnvironment()
self.duTestHelper = self.aduTestConfig.CreateDeviceUpdateTestHelper()


#
# We retrieve the apt deployment id to be used by the script from the scenario definitions file. It's important to keep
# things like the deployment id, device-id, module-id, and other scenario level definitions that might effect other
# tests in the scenario_definitions.py file.
#
self.deploymentId = test_apt_deployment_id

self.deploymentUpdateId = UpdateId(provider="Azure", name="DeviceUpdate", version="1.0.3")

#
# Before anything else we need to wait and check the device connection status
# We expect the device to connect within the configured amount of time of setting up the device in the step previous
#
connectionStatus = ""
for i in range(0,test_connection_timeout_tries):
connectionStatus = self.duTestHelper.GetConnectionStatusForDevice(test_device_id)
if (connectionStatus == "Connected"):
break
time.sleep(retry_wait_time_in_seconds)

self.assertEqual(connectionStatus, "Connected")

#
# The assumption is that we've already imported the update targeting the manufacturer and
# model for the device created in the devicesetup.py. Now we have to create the deployment for
# the device using the update-id for the update
#
# Note: ALL UPDATES SHOULD BE UPLOADED TO THE TEST AUTOMATION HUB NOTHING SHOULD BE IMPORTED AT TEST TIME
#
status_code = self.duTestHelper.StartDeploymentForGroup(deploymentId=self.deploymentId,groupName=test_adu_group,updateId=self.deploymentUpdateId)

self.assertEqual(status_code, 200)

#
# Once we've started the deployment for the group we can then query for the status of the deployment
# to see if/when the deployment finishes. We expect a timeout of the configured amount of time
#
deploymentStatus = None


for i in range(0,apt_deployment_status_retries):
deploymentStatus = self.duTestHelper.GetDeploymentStatusForGroup(self.deploymentId,test_adu_group)

#
# If we see all the devices have completed the deployment then we can exit early
#
if (len(deploymentStatus.subgroupStatuses) != 0):
if (deploymentStatus.subgroupStatuses[0].devicesCompletedSucceededCount == 1):
break
time.sleep(retry_wait_time_in_seconds)

#
# Should only be one device group in the deployment
#
self.assertEqual(len(deploymentStatus.subgroupStatuses),1)

#
# Devices in the group should have succeeded
#
self.assertEqual(deploymentStatus.subgroupStatuses[0].totalDevices,deploymentStatus.subgroupStatuses[0].devicesCompletedSucceededCount)

# Sleep to give time for changes to propagate and for DU to switch it's state back to idle
time.sleep(retry_wait_time_in_seconds)

#
# Once we've checked that we've reached the proper outcome for the
# deployment we need to check that the device itself has reported it
# is back in the idle state.
#
twin = self.duTestHelper.GetDeviceTwinForDevice(test_device_id)

self.assertEqual(twin.properties.reported["deviceUpdate"]["agent"]["state"],0)

#
# In case of a succeeded deployment we need to clean up the resources we created.
# mainly the deletion of the deployment
#
time.sleep(retry_wait_time_in_seconds)

deviceClassId = deploymentStatus.subgroupStatuses[0].deviceClassId

# self.assertEqual(self.duTestHelper.StopDeployment(self.deploymentId,test_adu_group,deviceClassId),200)
# time.sleep(retry_wait_time_in_seconds)

# Once stopped we can delete the deployment
self.assertEqual(self.duTestHelper.DeleteDeployment(self.deploymentId, test_adu_group), 204)


#
# Below is the section of code that uses the above class to run the test. It starts by running the test, capturing the output, transforming
# the output from Python Unittest to X/JUnit format. Then the function exports the values to an xml file in the testresults directory which is
# then uploaded by the Azure Pipelines PostTestResults job
#
if (__name__ == "__main__"):
#
# Create the IO pipe
#
out = io.BytesIO()

#
# Exercise the TestCase and all the tests within it.
#
unittest.main(testRunner = xmlrunner.XMLTestRunner(output=out),failfast=False,buffer=False,catchbreak=False,exit=False)

#
# Finally transform the output unto the X/JUnit XML file format
#
with open('./testresults/' + test_result_file_prefix + '-apt-deployment-test.xml','wb') as report:
report.write(transform(out.getvalue()))
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
#!/bin/bash

# Ensure we dont end the user's terminal session if invoked from source (".").
if [[ $0 != "${BASH_SOURCE[0]}" ]]; then
ret=return
else
ret=exit
fi

# Use sudo if user is not root
SUDO=""
if [ "$(id -u)" != "0" ]; then
SODO="sudo"
fi

warn() { echo -e "\033[1;33mWarning:\033[0m $*" >&2; }
error() { echo -e "\033[1;31mError:\033[0m $*" >&2; }

print_help() {
echo ""
echo "Usage: setup-local-package-repo.sh [options...]"
echo ""
echo " -d <packages-full-path> The fully qualified path to directory that contains your packages."
echo ""
}

# Setup defaults
private_packages_dir=/tmp/my_private_packages
local_packages_dir=/var/lib/local_packages
private_packages_list=/etc/apt/sources.list.d/my-private-packages.list

create_repo() {
echo '# Instaling dpkg-dev...'
apt-get -y install dpkg-dev

echo "# Create local package repos ($local_packages_dir)..."
mkdir -p $local_packages_dir

echo "# Copying private package(s) from '$private_pakcages_dir' to '$local_packages_dir'..."
cp -f $private_packages_dir/*.deb $local_packages_dir
ls -l -R $local_packages_dir

echo "# Updating $private_packages_list ..."
echo "deb [trusted=yes] file:$local_packages_dir ./" > $private_packages_list
cat $private_packages_list

echo '# Creating test packages catalogs...'
cd $local_packages_dir
dpkg-scanpackages . /dev/null | gzip -9c > Packages.gz

echo '# Updating APT sources cache...'
apt-get update

echo '#'
echo '# Done! See list of available adu-agent packages below... '
echo '#'
apt-cache policy deviceupdate-agent ms-doclient-lite ms-docsdk
}

# Check if no options were specified.
if [[ $1 == "" ]]; then
error "Must specified at least one options."
print_help
$ret 1
fi

# Parse cmd options
while [[ $1 != "" ]]; do
case $1 in
-h | --help)
print_help
$ret 0
;;
-d)
shift
private_packages_dir=$1
;;
esac
shift
done

if [[ $private_packages_dir != "" ]]; then
$SUDO create_repo
fi

$ret 0
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,35 @@
# ~/testsetup/setup.sh
# So we need to localize the path to that.
#

#
# Handling Self-Upgrade Scenario differently
#

self_upgrade=false
print_help() {
echo "setup.sh [-s] "
echo "-s, --self-upgrade Testing the self upgrade scenario, setup is different."
echo "-h, --help Show this help message."
}

while [[ $1 != "" ]]; do
case $1 in
-s | --self-upgrade)
self_upgrade=true
;;
-h | --help)
print_help
return 0
;;
*)
error "Invalid argument: $*"
return 1
;;
esac
shift
done

#
# Install the Microsoft APT repository
#
Expand Down Expand Up @@ -152,7 +181,14 @@ configure_apt_repository
#
# Install the Device Update Artifact Under Test
#
sudo apt-get install -y ./testsetup/deviceupdate-package.deb

if [[ $self_upgrade == "true" ]]; then
sudo apt-get install -y deviceupdate-agent
chmod u+x ./testsetup/apt_repo_setup.sh
sudo ./testsetup/apt_repo_setup.sh -d ./testsetup/
else
sudo apt-get install -y ./testsetup/deviceupdate-package.deb
fi

#
# Install the du-config.json so the device can be provisioned
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
# Licensed under the MIT License. See License.txt in the project root for
# license information.
# --------------------------------------------------------------------------
# Setup Script for Test: Ubuntu-18.04-amd64-APT-deployment
# Setup Script for Test: Ubuntu-20.04-amd64-APT-deployment
#
# Should be run on the Virtual Machine being provisioned for the work.

Expand Down

0 comments on commit dd3d3a0

Please sign in to comment.