зеркало из https://github.com/Azure/iotedge.git
EdgeHub Restart Tester (Sender)
Overall changes: - Introduce EdgeHubRestartTester module - Introduce edgehub_restart_deployment.template.json - Introduce EdgeHubRestartTester to Image Build pipeline - Introduce EdgeHubRestartTester to Container Registry publish - Make deployment file for connectivity test configurable from VSTS pipeline - Muffled soon-to-be a new report type for EdgeHubRestartTester The EdgeHub Restart Test does the following: 1. The EdgeHubRestartTester sends an edgeHub-restart command to edgeAgent to restart the edgeHub module. 2. The EdgeHubRestartTester spins up parallel tasks (configurable) to 2.1 Send messages until a message is sent successfully 2.2 Send directMethods until a directMethod is sent successfully 3. Record a time period between restart until either message or direct method succeed 4. Generate a test result for each of the sent methods { message, or directMethod } 5. For each corresponding result, trigger an appropriate TestResultCoordinator endpoint.
This commit is contained in:
Родитель
0d83f8e2bc
Коммит
e206650f63
|
@ -213,9 +213,11 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TwinTester", "test\modules\
|
||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DeploymentTester", "test\modules\DeploymentTester\DeploymentTester.csproj", "{1C1C8203-CD73-4CC1-9112-7315F9DE1AB6}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DeploymentTester", "test\modules\DeploymentTester\DeploymentTester.csproj", "{1C1C8203-CD73-4CC1-9112-7315F9DE1AB6}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Azure.Devices.Edge.Agent.Integration.Test", "edge-agent\test\Microsoft.Azure.Devices.Edge.Agent.Integration.Test\Microsoft.Azure.Devices.Edge.Agent.Integration.Test.csproj", "{B3C68519-B309-42FF-B4DF-9E77B2D4BD50}"
|
||||||
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MetricsValidator", "test\modules\MetricsValidator\MetricsValidator.csproj", "{5857DB4A-F61A-4467-96F1-003B47B8B2CF}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MetricsValidator", "test\modules\MetricsValidator\MetricsValidator.csproj", "{5857DB4A-F61A-4467-96F1-003B47B8B2CF}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Azure.Devices.Edge.Agent.Integration.Test", "edge-agent\test\Microsoft.Azure.Devices.Edge.Agent.Integration.Test\Microsoft.Azure.Devices.Edge.Agent.Integration.Test.csproj", "{B3C68519-B309-42FF-B4DF-9E77B2D4BD50}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EdgeHubRestartTester", "test\modules\EdgeHubRestartTester\EdgeHubRestartTester.csproj", "{DA073067-83EF-4F4C-8E58-51CA7870C1F6}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CloudToDeviceMessageTester", "test\modules\CloudToDeviceMessageTester\CloudToDeviceMessageTester.csproj", "{446F50F3-3E93-454B-8EBF-4830E92DFE5D}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CloudToDeviceMessageTester", "test\modules\CloudToDeviceMessageTester\CloudToDeviceMessageTester.csproj", "{446F50F3-3E93-454B-8EBF-4830E92DFE5D}"
|
||||||
EndProject
|
EndProject
|
||||||
|
@ -586,8 +588,10 @@ Global
|
||||||
{1C1C8203-CD73-4CC1-9112-7315F9DE1AB6}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{1C1C8203-CD73-4CC1-9112-7315F9DE1AB6}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{1C1C8203-CD73-4CC1-9112-7315F9DE1AB6}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{1C1C8203-CD73-4CC1-9112-7315F9DE1AB6}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{1C1C8203-CD73-4CC1-9112-7315F9DE1AB6}.Release|Any CPU.Build.0 = Release|Any CPU
|
{1C1C8203-CD73-4CC1-9112-7315F9DE1AB6}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
{B3C68519-B309-42FF-B4DF-9E77B2D4BD50}.CheckInBuild|Any CPU.ActiveCfg = Debug|Any CPU
|
{B3C68519-B309-42FF-B4DF-9E77B2D4BD50}.CheckInBuild|Any CPU.ActiveCfg = CheckInBuild|Any CPU
|
||||||
{B3C68519-B309-42FF-B4DF-9E77B2D4BD50}.CheckInBuild|Any CPU.Build.0 = Debug|Any CPU
|
{B3C68519-B309-42FF-B4DF-9E77B2D4BD50}.CheckInBuild|Any CPU.Build.0 = CheckInBuild|Any CPU
|
||||||
|
{B3C68519-B309-42FF-B4DF-9E77B2D4BD50}.CodeCoverage|Any CPU.ActiveCfg = CodeCoverage|Any CPU
|
||||||
|
{B3C68519-B309-42FF-B4DF-9E77B2D4BD50}.CodeCoverage|Any CPU.Build.0 = CodeCoverage|Any CPU
|
||||||
{B3C68519-B309-42FF-B4DF-9E77B2D4BD50}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
{B3C68519-B309-42FF-B4DF-9E77B2D4BD50}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
{B3C68519-B309-42FF-B4DF-9E77B2D4BD50}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{B3C68519-B309-42FF-B4DF-9E77B2D4BD50}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{B3C68519-B309-42FF-B4DF-9E77B2D4BD50}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{B3C68519-B309-42FF-B4DF-9E77B2D4BD50}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
@ -604,6 +608,14 @@ Global
|
||||||
{5857DB4A-F61A-4467-96F1-003B47B8B2CF}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{5857DB4A-F61A-4467-96F1-003B47B8B2CF}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{5857DB4A-F61A-4467-96F1-003B47B8B2CF}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{5857DB4A-F61A-4467-96F1-003B47B8B2CF}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{5857DB4A-F61A-4467-96F1-003B47B8B2CF}.Release|Any CPU.Build.0 = Release|Any CPU
|
{5857DB4A-F61A-4467-96F1-003B47B8B2CF}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{DA073067-83EF-4F4C-8E58-51CA7870C1F6}.CheckInBuild|Any CPU.ActiveCfg = CheckInBuild|Any CPU
|
||||||
|
{DA073067-83EF-4F4C-8E58-51CA7870C1F6}.CheckInBuild|Any CPU.Build.0 = CheckInBuild|Any CPU
|
||||||
|
{DA073067-83EF-4F4C-8E58-51CA7870C1F6}.CodeCoverage|Any CPU.ActiveCfg = CodeCoverage|Any CPU
|
||||||
|
{DA073067-83EF-4F4C-8E58-51CA7870C1F6}.CodeCoverage|Any CPU.Build.0 = CodeCoverage|Any CPU
|
||||||
|
{DA073067-83EF-4F4C-8E58-51CA7870C1F6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{DA073067-83EF-4F4C-8E58-51CA7870C1F6}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{DA073067-83EF-4F4C-8E58-51CA7870C1F6}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{DA073067-83EF-4F4C-8E58-51CA7870C1F6}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
@ -688,8 +700,9 @@ Global
|
||||||
{6208102C-151C-45CE-B573-B9C15B551B4D} = {F921339B-32F9-4BF3-B364-2DB01FA2F1A1}
|
{6208102C-151C-45CE-B573-B9C15B551B4D} = {F921339B-32F9-4BF3-B364-2DB01FA2F1A1}
|
||||||
{1447EC5D-DD23-4C51-8941-336A495A48EE} = {F921339B-32F9-4BF3-B364-2DB01FA2F1A1}
|
{1447EC5D-DD23-4C51-8941-336A495A48EE} = {F921339B-32F9-4BF3-B364-2DB01FA2F1A1}
|
||||||
{1C1C8203-CD73-4CC1-9112-7315F9DE1AB6} = {F921339B-32F9-4BF3-B364-2DB01FA2F1A1}
|
{1C1C8203-CD73-4CC1-9112-7315F9DE1AB6} = {F921339B-32F9-4BF3-B364-2DB01FA2F1A1}
|
||||||
{5857DB4A-F61A-4467-96F1-003B47B8B2CF} = {F921339B-32F9-4BF3-B364-2DB01FA2F1A1}
|
|
||||||
{B3C68519-B309-42FF-B4DF-9E77B2D4BD50} = {F5E37327-3AA9-4CC2-9FE3-B28271ADB5E3}
|
{B3C68519-B309-42FF-B4DF-9E77B2D4BD50} = {F5E37327-3AA9-4CC2-9FE3-B28271ADB5E3}
|
||||||
|
{5857DB4A-F61A-4467-96F1-003B47B8B2CF} = {F921339B-32F9-4BF3-B364-2DB01FA2F1A1}
|
||||||
|
{DA073067-83EF-4F4C-8E58-51CA7870C1F6} = {F921339B-32F9-4BF3-B364-2DB01FA2F1A1}
|
||||||
{446F50F3-3E93-454B-8EBF-4830E92DFE5D} = {F921339B-32F9-4BF3-B364-2DB01FA2F1A1}
|
{446F50F3-3E93-454B-8EBF-4830E92DFE5D} = {F921339B-32F9-4BF3-B364-2DB01FA2F1A1}
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
|
|
|
@ -102,7 +102,7 @@ jobs:
|
||||||
artifactName: $(images.artifact.name.linux)
|
artifactName: $(images.artifact.name.linux)
|
||||||
itemPattern: |
|
itemPattern: |
|
||||||
$(images.artifact.name.linux)/IotEdgeQuickstart.linux-x64.tar.gz
|
$(images.artifact.name.linux)/IotEdgeQuickstart.linux-x64.tar.gz
|
||||||
$(images.artifact.name.linux)/e2e_deployment_files/connectivity_deployment.template.json
|
$(images.artifact.name.linux)/e2e_deployment_files/$(deploymentFileName)
|
||||||
$(images.artifact.name.linux)/scripts/connectivityTest.sh
|
$(images.artifact.name.linux)/scripts/connectivityTest.sh
|
||||||
$(images.artifact.name.linux)/scripts/testHelper.sh
|
$(images.artifact.name.linux)/scripts/testHelper.sh
|
||||||
$(images.artifact.name.linux)/artifactInfo.txt
|
$(images.artifact.name.linux)/artifactInfo.txt
|
||||||
|
@ -120,8 +120,11 @@ jobs:
|
||||||
container.registry.password: '$(edgebuilds-azurecr-io-pwd)'
|
container.registry.password: '$(edgebuilds-azurecr-io-pwd)'
|
||||||
iotHub.connectionString: '$(EdgeConnectivityTestHubConnString)'
|
iotHub.connectionString: '$(EdgeConnectivityTestHubConnString)'
|
||||||
eventHub.connectionString: '$(EdgeConnectivityEventHubConnString)'
|
eventHub.connectionString: '$(EdgeConnectivityEventHubConnString)'
|
||||||
|
deploymentFileName: '$(deploymentFileName)'
|
||||||
upstream.protocol: '$(upstream.protocol)'
|
upstream.protocol: '$(upstream.protocol)'
|
||||||
loadGen.message.frequency: '$(loadGen.message.frequency.amd64)'
|
loadGen.message.frequency: '$(loadGen.message.frequency.amd64)'
|
||||||
|
edgeHubRestartTest.restartPeriod: '$(edgeHubRestartTest.restartPeriod)'
|
||||||
|
edgeHubRestartTest.sdkOperationTimeout: '$(edgeHubRestartTest.sdkOperationTimeout)'
|
||||||
testDuration: '$(testrun.duration)'
|
testDuration: '$(testrun.duration)'
|
||||||
testStartDelay: '$(testStartDelay)'
|
testStartDelay: '$(testStartDelay)'
|
||||||
networkController.frequencies: '$(testrun.network.frequencies)'
|
networkController.frequencies: '$(testrun.network.frequencies)'
|
||||||
|
@ -182,7 +185,7 @@ jobs:
|
||||||
artifactName: $(images.artifact.name.linux)
|
artifactName: $(images.artifact.name.linux)
|
||||||
itemPattern: |
|
itemPattern: |
|
||||||
$(images.artifact.name.linux)/IotEdgeQuickstart.linux-arm.tar.gz
|
$(images.artifact.name.linux)/IotEdgeQuickstart.linux-arm.tar.gz
|
||||||
$(images.artifact.name.linux)/e2e_deployment_files/connectivity_deployment.template.json
|
$(images.artifact.name.linux)/e2e_deployment_files/$(deploymentFileName)
|
||||||
$(images.artifact.name.linux)/scripts/connectivityTest.sh
|
$(images.artifact.name.linux)/scripts/connectivityTest.sh
|
||||||
$(images.artifact.name.linux)/scripts/testHelper.sh
|
$(images.artifact.name.linux)/scripts/testHelper.sh
|
||||||
$(images.artifact.name.linux)/artifactInfo.txt
|
$(images.artifact.name.linux)/artifactInfo.txt
|
||||||
|
|
|
@ -72,6 +72,9 @@ steps:
|
||||||
-metricsEndpointsCSV "${{ parameters['metricsCollector.metricsEndpointsCSV'] }}" \
|
-metricsEndpointsCSV "${{ parameters['metricsCollector.metricsEndpointsCSV'] }}" \
|
||||||
-metricsScrapeFrequencyInSecs "${{ parameters['metricsCollector.scrapeFrequencyInSecs'] }}" \
|
-metricsScrapeFrequencyInSecs "${{ parameters['metricsCollector.scrapeFrequencyInSecs'] }}" \
|
||||||
-metricsUploadTarget "${{ parameters['metricsCollector.uploadTarget'] }}" \
|
-metricsUploadTarget "${{ parameters['metricsCollector.uploadTarget'] }}" \
|
||||||
|
-deploymentFileName "${{ parameters['deploymentFileName'] }}" \
|
||||||
|
-EdgeHubRestartTestRestartPeriod "${{ parameters['edgeHubRestartTest.restartPeriod'] }}" \
|
||||||
|
-EdgeHubRestartTestSdkOperationTimeout "${{ parameters['edgeHubRestartTest.sdkOperationTimeout'] }}" \
|
||||||
-testBuildNumber "${{ parameters['test.buildNumber'] }}" \
|
-testBuildNumber "${{ parameters['test.buildNumber'] }}" \
|
||||||
-imagesBranchName "${{ parameters['images.branchName'] }}" \
|
-imagesBranchName "${{ parameters['images.branchName'] }}" \
|
||||||
-edgeletBranchName "${{ parameters['edgelet.branchName'] }}" \
|
-edgeletBranchName "${{ parameters['edgelet.branchName'] }}" \
|
||||||
|
|
|
@ -140,6 +140,13 @@ jobs:
|
||||||
filePath: scripts/linux/buildImage.sh
|
filePath: scripts/linux/buildImage.sh
|
||||||
arguments: -r $(registry.address) -u $(registry.user) -p $(registry.password) -i azureiotedge-deployment-tester -n microsoft -P DeploymentTester --target-arch aarch64
|
arguments: -r $(registry.address) -u $(registry.user) -p $(registry.password) -i azureiotedge-deployment-tester -n microsoft -P DeploymentTester --target-arch aarch64
|
||||||
|
|
||||||
|
# EdgeHubRestartTester - Not Using Template for ARM64 because we have 2 different .NET Core.
|
||||||
|
- task: Bash@3
|
||||||
|
displayName: Build Image - EdgeHub Restart Tester - aarch64
|
||||||
|
inputs:
|
||||||
|
filePath: scripts/linux/buildImage.sh
|
||||||
|
arguments: -r $(registry.address) -u $(registry.user) -p $(registry.password) -i azureiotedge-edgehub-restart-tester -n microsoft -P EdgeHubRestartTester --target-arch aarch64
|
||||||
|
|
||||||
# CloudToDeviceMessageTester - Not Using Template for ARM64 because we have 2 different .NET Core.
|
# CloudToDeviceMessageTester - Not Using Template for ARM64 because we have 2 different .NET Core.
|
||||||
- task: Bash@3
|
- task: Bash@3
|
||||||
displayName: Build Image - Cloud To Device Message Receiver Tester - aarch64
|
displayName: Build Image - Cloud To Device Message Receiver Tester - aarch64
|
||||||
|
@ -291,6 +298,13 @@ jobs:
|
||||||
imageName: azureiotedge-deployment-tester
|
imageName: azureiotedge-deployment-tester
|
||||||
project: DeploymentTester
|
project: DeploymentTester
|
||||||
|
|
||||||
|
# EdgeHub Restart Tester
|
||||||
|
- template: templates/image-linux.yaml
|
||||||
|
parameters:
|
||||||
|
name: EdgeHubRestartTester
|
||||||
|
imageName: azureiotedge-edgehub-restart-tester
|
||||||
|
project: EdgeHubRestartTester
|
||||||
|
|
||||||
# Cloud To Device Message Tester
|
# Cloud To Device Message Tester
|
||||||
- template: templates/image-linux.yaml
|
- template: templates/image-linux.yaml
|
||||||
parameters:
|
parameters:
|
||||||
|
@ -480,6 +494,13 @@ jobs:
|
||||||
imageName: azureiotedge-deployment-tester
|
imageName: azureiotedge-deployment-tester
|
||||||
project: DeploymentTester
|
project: DeploymentTester
|
||||||
|
|
||||||
|
# EdgeHub Restart Tester
|
||||||
|
- template: templates/image-windows.yaml
|
||||||
|
parameters:
|
||||||
|
name: EdgeHubRestartTester
|
||||||
|
imageName: azureiotedge-edgehub-restart-tester
|
||||||
|
project: EdgeHubRestartTester
|
||||||
|
|
||||||
# Cloud To Device Message Tester
|
# Cloud To Device Message Tester
|
||||||
- template: templates/image-windows.yaml
|
- template: templates/image-windows.yaml
|
||||||
parameters:
|
parameters:
|
||||||
|
|
|
@ -0,0 +1,217 @@
|
||||||
|
{
|
||||||
|
"modulesContent": {
|
||||||
|
"$edgeAgent": {
|
||||||
|
"properties.desired": {
|
||||||
|
"schemaVersion": "1.0",
|
||||||
|
"runtime": {
|
||||||
|
"type": "docker",
|
||||||
|
"settings": {
|
||||||
|
"minDockerVersion": "v1.25",
|
||||||
|
"loggingOptions": "",
|
||||||
|
"registryCredentials": {
|
||||||
|
"rc1": {
|
||||||
|
"username": "<CR.Username>",
|
||||||
|
"password": "<CR.Password>",
|
||||||
|
"address": "<Container_Registry>"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"systemModules": {
|
||||||
|
"edgeAgent": {
|
||||||
|
"type": "docker",
|
||||||
|
"env": {
|
||||||
|
"UpstreamProtocol": {
|
||||||
|
"value": "<UpstreamProtocol>"
|
||||||
|
},
|
||||||
|
"experimentalfeatures__enabled": {
|
||||||
|
"value": "true"
|
||||||
|
},
|
||||||
|
"experimentalfeatures__enableMetrics": {
|
||||||
|
"value": "true"
|
||||||
|
},
|
||||||
|
"ExperimentalFeatures__EnableUploadLogs": {
|
||||||
|
"value": "true"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"settings": {
|
||||||
|
"image": "<Container_Registry>/microsoft/azureiotedge-agent:<Build.BuildNumber>-linux-<Architecture>",
|
||||||
|
"createOptions": "{\"ExposedPorts\": {\"9600/tcp\": {}}, \"HostConfig\": {\"PortBindings\": {\"9600/tcp\": [{\"HostPort\": \"9600\"}]}}}"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"edgeHub": {
|
||||||
|
"type": "docker",
|
||||||
|
"settings": {
|
||||||
|
"image": "<Container_Registry>/microsoft/azureiotedge-hub:<Build.BuildNumber>-linux-<Architecture>",
|
||||||
|
"createOptions": "{\"ExposedPorts\": {\"9600/tcp\": {}}, \"HostConfig\": {\"PortBindings\": {\"8883/tcp\": [{\"HostPort\": \"8883\"}],\"443/tcp\": [{\"HostPort\": \"443\"}],\"5671/tcp\": [{\"HostPort\": \"5671\"}],\"9600/tcp\": [{\"HostPort\": \"9601\"}]}}}"
|
||||||
|
},
|
||||||
|
"env": {
|
||||||
|
"CollectMetrics": {
|
||||||
|
"value": "true"
|
||||||
|
},
|
||||||
|
"experimentalfeatures__enabled": {
|
||||||
|
"value": "true"
|
||||||
|
},
|
||||||
|
"experimentalfeatures__enableMetrics": {
|
||||||
|
"value": "true"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"status": "running",
|
||||||
|
"restartPolicy": "always"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"modules": {
|
||||||
|
"directMethodReceiver1": {
|
||||||
|
"version": "1.0",
|
||||||
|
"type": "docker",
|
||||||
|
"status": "running",
|
||||||
|
"restartPolicy": "always",
|
||||||
|
"env": {
|
||||||
|
"ClientTransportType": {
|
||||||
|
"value": "Amqp"
|
||||||
|
},
|
||||||
|
"ReportingEndpointUrl": {
|
||||||
|
"value": "http://testResultCoordinator:5001"
|
||||||
|
},
|
||||||
|
"trackingId": {
|
||||||
|
"value": "<TrackingId>"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"settings": {
|
||||||
|
"image": "<Container_Registry>/microsoft/azureiotedge-direct-method-receiver:<Build.BuildNumber>-linux-<Architecture>",
|
||||||
|
"createOptions": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"edgeHubRestartTester1": {
|
||||||
|
"version": "1.0",
|
||||||
|
"type": "docker",
|
||||||
|
"status": "running",
|
||||||
|
"restartPolicy": "always",
|
||||||
|
"env": {
|
||||||
|
"IOT_HUB_CONNECTION_STRING": {
|
||||||
|
"value": "<IoTHubConnectionString>"
|
||||||
|
},
|
||||||
|
"directMethodEnabled": {
|
||||||
|
"value": "true"
|
||||||
|
},
|
||||||
|
"directMethodTargetModuleId": {
|
||||||
|
"value": "directMethodReceiver1"
|
||||||
|
},
|
||||||
|
"messageEnabled": {
|
||||||
|
"value": "true"
|
||||||
|
},
|
||||||
|
"reportingEndpointUrl": {
|
||||||
|
"value": "http://localhost:5001"
|
||||||
|
},
|
||||||
|
"restartPeriod": {
|
||||||
|
"value": "<EdgeHubRestartTest.RestartPeriod>"
|
||||||
|
},
|
||||||
|
"sdkOperationTimeout": {
|
||||||
|
"value": "<EdgeHubRestartTest.SdkOperationTimeout>"
|
||||||
|
},
|
||||||
|
"testDuration": {
|
||||||
|
"value": "<TestDuration>"
|
||||||
|
},
|
||||||
|
"testStartDelay": {
|
||||||
|
"value": "<TestStartDelay>"
|
||||||
|
},
|
||||||
|
"trackingId": {
|
||||||
|
"value": "<TrackingId>"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"settings": {
|
||||||
|
"image": "<Container_Registry>/microsoft/azureiotedge-edgehub-restart-tester:<Build.BuildNumber>-linux-<Architecture>",
|
||||||
|
"createOptions": "{\"HostConfig\":{\"NetworkMode\":\"host\"},\"NetworkingConfig\":{\"EndpointsConfig\":{\"host\":{}}}}"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"relayer1": {
|
||||||
|
"version": "1.0",
|
||||||
|
"type": "docker",
|
||||||
|
"status": "running",
|
||||||
|
"restartPolicy": "always",
|
||||||
|
"env": {
|
||||||
|
"transportType": {
|
||||||
|
"value": "Amqp"
|
||||||
|
},
|
||||||
|
"inputName": {
|
||||||
|
"value": "input1"
|
||||||
|
},
|
||||||
|
"outputName": {
|
||||||
|
"value": "output1"
|
||||||
|
},
|
||||||
|
"testResultCoordinatorUrl": {
|
||||||
|
"value": "http://testResultCoordinator:5001"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"settings": {
|
||||||
|
"image": "<Container_Registry>/microsoft/azureiotedge-relayer:<Build.BuildNumber>-linux-<Architecture>",
|
||||||
|
"createOptions": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"testResultCoordinator": {
|
||||||
|
"version": "1.0",
|
||||||
|
"type": "docker",
|
||||||
|
"status": "running",
|
||||||
|
"restartPolicy": "always",
|
||||||
|
"env": {
|
||||||
|
"Logging:LogLevel:Microsoft": {
|
||||||
|
"value": "Error"
|
||||||
|
},
|
||||||
|
"trackingId": {
|
||||||
|
"value": "<TrackingId>"
|
||||||
|
},
|
||||||
|
"testStartDelay": {
|
||||||
|
"value": "<TestStartDelay>"
|
||||||
|
},
|
||||||
|
"testDuration": {
|
||||||
|
"value": "<TestDuration>"
|
||||||
|
},
|
||||||
|
"verificationDelay": {
|
||||||
|
"value": "<TestResultCoordinator.VerificationDelay>"
|
||||||
|
},
|
||||||
|
"eventHubConnectionString": {
|
||||||
|
"value": "<TestResultCoordinator.EventHubConnectionString>"
|
||||||
|
},
|
||||||
|
"ConsumerGroupName": {
|
||||||
|
"value": "<TestResultCoordinator.ConsumerGroupId>"
|
||||||
|
},
|
||||||
|
"optimizeForPerformance": {
|
||||||
|
"value": "<TestResultCoordinator.OptimizeForPerformance>"
|
||||||
|
},
|
||||||
|
"logAnalyticsWorkspaceId": {
|
||||||
|
"value": "<LogAnalyticsWorkspaceId>"
|
||||||
|
},
|
||||||
|
"logAnalyticsSharedKey": {
|
||||||
|
"value": "<LogAnalyticsSharedKey>"
|
||||||
|
},
|
||||||
|
"logAnalyticsLogType": {
|
||||||
|
"value": "<TestResultCoordinator.LogAnalyticsLogType>"
|
||||||
|
},
|
||||||
|
"IOT_HUB_CONNECTION_STRING": {
|
||||||
|
"value": "<IoTHubConnectionString>"
|
||||||
|
},
|
||||||
|
"STORAGE_ACCOUNT_CONNECTION_STRING": {
|
||||||
|
"value": "<TestResultCoordinator.StorageAccountConnectionString>"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"settings": {
|
||||||
|
"image": "<Container_Registry>/microsoft/azureiotedge-test-result-coordinator:<Build.BuildNumber>-linux-<Architecture>",
|
||||||
|
"createOptions": "{\"HostConfig\": {\"PortBindings\": {\"5001/tcp\": [{\"HostPort\": \"5001\"}]}}}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"$edgeHub": {
|
||||||
|
"properties.desired": {
|
||||||
|
"schemaVersion": "1.0",
|
||||||
|
"routes": {
|
||||||
|
"edgeHubRestarterToRelayer1": "FROM /messages/modules/loadGen1/outputs/output1 INTO BrokeredEndpoint(\"/modules/relayer1/inputs/input1\")"
|
||||||
|
},
|
||||||
|
"storeAndForwardConfiguration": {
|
||||||
|
"timeToLiveSecs": 86400
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -258,6 +258,7 @@ publish_app "MetricsCollector"
|
||||||
publish_app "TestResultCoordinator"
|
publish_app "TestResultCoordinator"
|
||||||
publish_app "NetworkController"
|
publish_app "NetworkController"
|
||||||
publish_app "DeploymentTester"
|
publish_app "DeploymentTester"
|
||||||
|
publish_app "EdgeHubRestartTester"
|
||||||
publish_app "MetricsValidator"
|
publish_app "MetricsValidator"
|
||||||
publish_app "CloudToDeviceMessageTester"
|
publish_app "CloudToDeviceMessageTester"
|
||||||
|
|
||||||
|
|
|
@ -154,6 +154,7 @@ $appProjectList.Add("Relayer.csproj")
|
||||||
$appProjectList.Add("MetricsCollector.csproj")
|
$appProjectList.Add("MetricsCollector.csproj")
|
||||||
$appProjectList.Add("TestResultCoordinator.csproj")
|
$appProjectList.Add("TestResultCoordinator.csproj")
|
||||||
$appProjectList.Add("DeploymentTester.csproj")
|
$appProjectList.Add("DeploymentTester.csproj")
|
||||||
|
$appProjectList.Add("EdgeHubRestartTester.csproj")
|
||||||
$appProjectList.Add("MetricsValidator.csproj")
|
$appProjectList.Add("MetricsValidator.csproj")
|
||||||
$appProjectList.Add("CloudToDeviceMessageTester.csproj")
|
$appProjectList.Add("CloudToDeviceMessageTester.csproj")
|
||||||
|
|
||||||
|
|
|
@ -52,6 +52,8 @@ function prepare_test_from_artifacts() {
|
||||||
sed -i -e "s@<TestStartDelay>@$TEST_START_DELAY@g" "$deployment_working_file"
|
sed -i -e "s@<TestStartDelay>@$TEST_START_DELAY@g" "$deployment_working_file"
|
||||||
sed -i -e "s@<TrackingId>@$tracking_id@g" "$deployment_working_file"
|
sed -i -e "s@<TrackingId>@$tracking_id@g" "$deployment_working_file"
|
||||||
sed -i -e "s@<UpstreamProtocol>@$UPSTREAM_PROTOCOL@g" "$deployment_working_file"
|
sed -i -e "s@<UpstreamProtocol>@$UPSTREAM_PROTOCOL@g" "$deployment_working_file"
|
||||||
|
sed -i -e "s@<EdgeHubRestartTest.RestartPeriod>@$RESTART_TEST_RESTART_PERIOD@g" "$deployment_working_file"
|
||||||
|
sed -i -e "s@<EdgeHubRestartTest.SdkOperationTimeout>@$RESTART_TEST_SDK_OPERATION_TIMEOUT@g" "$deployment_working_file"
|
||||||
|
|
||||||
sed -i -e "s@<TestResultCoordinator.VerificationDelay>@$VERIFICATION_DELAY@g" "$deployment_working_file"
|
sed -i -e "s@<TestResultCoordinator.VerificationDelay>@$VERIFICATION_DELAY@g" "$deployment_working_file"
|
||||||
sed -i -e "s@<TestResultCoordinator.OptimizeForPerformance>@$optimize_for_performance@g" "$deployment_working_file"
|
sed -i -e "s@<TestResultCoordinator.OptimizeForPerformance>@$optimize_for_performance@g" "$deployment_working_file"
|
||||||
|
@ -243,6 +245,15 @@ function process_args() {
|
||||||
elif [ $saveNextArg -eq 31 ]; then
|
elif [ $saveNextArg -eq 31 ]; then
|
||||||
DEVOPS_BUILDID="$arg"
|
DEVOPS_BUILDID="$arg"
|
||||||
saveNextArg=0
|
saveNextArg=0
|
||||||
|
elif [ $saveNextArg -eq 32 ]; then
|
||||||
|
DEPLOYMENT_FILE_NAME="$arg"
|
||||||
|
saveNextArg=0
|
||||||
|
elif [ $saveNextArg -eq 33 ]; then
|
||||||
|
RESTART_TEST_RESTART_PERIOD="$arg"
|
||||||
|
saveNextArg=0
|
||||||
|
elif [ $saveNextArg -eq 34 ]; then
|
||||||
|
RESTART_TEST_SDK_OPERATION_TIMEOUT="$arg"
|
||||||
|
saveNextArg=0
|
||||||
else
|
else
|
||||||
case "$arg" in
|
case "$arg" in
|
||||||
'-h' | '--help' ) usage;;
|
'-h' | '--help' ) usage;;
|
||||||
|
@ -277,6 +288,9 @@ function process_args() {
|
||||||
'-storageAccountConnectionString' ) saveNextArg=29;;
|
'-storageAccountConnectionString' ) saveNextArg=29;;
|
||||||
'-devOpsAccessToken' ) saveNextArg=30;;
|
'-devOpsAccessToken' ) saveNextArg=30;;
|
||||||
'-devOpsBuildId' ) saveNextArg=31;;
|
'-devOpsBuildId' ) saveNextArg=31;;
|
||||||
|
'-deploymentFileName' ) saveNextArg=32;;
|
||||||
|
'-EdgeHubRestartTestRestartPeriod' ) saveNextArg=33;;
|
||||||
|
'-EdgeHubRestartTestSdkOperationTimeout' ) saveNextArg=34;;
|
||||||
'-waitForTestComplete' ) WAIT_FOR_TEST_COMPLETE=1;;
|
'-waitForTestComplete' ) WAIT_FOR_TEST_COMPLETE=1;;
|
||||||
'-cleanAll' ) CLEAN_ALL=1;;
|
'-cleanAll' ) CLEAN_ALL=1;;
|
||||||
* ) usage;;
|
* ) usage;;
|
||||||
|
@ -289,6 +303,7 @@ function process_args() {
|
||||||
[[ -z "$ARTIFACT_IMAGE_BUILD_NUMBER" ]] && { print_error 'Artifact image build number is required'; exit 1; }
|
[[ -z "$ARTIFACT_IMAGE_BUILD_NUMBER" ]] && { print_error 'Artifact image build number is required'; exit 1; }
|
||||||
[[ -z "$CONTAINER_REGISTRY_USERNAME" ]] && { print_error 'Container registry username 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 "$CONTAINER_REGISTRY_PASSWORD" ]] && { print_error 'Container registry password is required'; exit 1; }
|
||||||
|
[[ -z "$DEPLOYMENT_FILE_NAME" ]] && { print_error 'Deployment file name is required'; exit 1; }
|
||||||
[[ -z "$EDGELET_BRANCH_NAME" ]] && { print_error 'Edgelet branch name is required'; exit 1; }
|
[[ -z "$EDGELET_BRANCH_NAME" ]] && { print_error 'Edgelet branch name is required'; exit 1; }
|
||||||
[[ -z "$EVENTHUB_CONNECTION_STRING" ]] && { print_error 'Event hub connection string is required'; exit 1; }
|
[[ -z "$EVENTHUB_CONNECTION_STRING" ]] && { print_error 'Event hub connection string is required'; exit 1; }
|
||||||
[[ -z "$HOST_PLATFORM" ]] && { print_error 'Host platform is required'; exit 1; }
|
[[ -z "$HOST_PLATFORM" ]] && { print_error 'Host platform is required'; exit 1; }
|
||||||
|
@ -470,6 +485,9 @@ function usage() {
|
||||||
echo ' -edgeletBranchName Branch name that built the edgelet artifacts'
|
echo ' -edgeletBranchName Branch name that built the edgelet artifacts'
|
||||||
echo ' -testBuildNumber Unique identifier for the main connectivity test run'
|
echo ' -testBuildNumber Unique identifier for the main connectivity test run'
|
||||||
echo ' -hostPlatform Describes the host OS and cpu architecture.'
|
echo ' -hostPlatform Describes the host OS and cpu architecture.'
|
||||||
|
echo ' -deploymentFileName Deployment file name'
|
||||||
|
echo ' -EdgeHubRestartTestRestartPeriod EdgeHub restart period (must be greater than 1 minutes)'
|
||||||
|
echo ' -EdgeHubRestartTestSdkOperationTimeout SDK retry timeout'
|
||||||
echo ' -storageAccountConnectionString Azure storage account connection string with privilege to create blob container.'
|
echo ' -storageAccountConnectionString Azure storage account connection string with privilege to create blob container.'
|
||||||
|
|
||||||
echo ' -cleanAll Do docker prune for containers, logs and volumes.'
|
echo ' -cleanAll Do docker prune for containers, logs and volumes.'
|
||||||
|
@ -509,7 +527,7 @@ fi
|
||||||
|
|
||||||
iotedged_artifact_folder="$(get_iotedged_artifact_folder $E2E_TEST_DIR)"
|
iotedged_artifact_folder="$(get_iotedged_artifact_folder $E2E_TEST_DIR)"
|
||||||
iotedge_quickstart_artifact_file="$(get_iotedge_quickstart_artifact_file $E2E_TEST_DIR)"
|
iotedge_quickstart_artifact_file="$(get_iotedge_quickstart_artifact_file $E2E_TEST_DIR)"
|
||||||
connectivity_deployment_artifact_file="$E2E_TEST_DIR/artifacts/core-linux/e2e_deployment_files/connectivity_deployment.template.json"
|
connectivity_deployment_artifact_file="$E2E_TEST_DIR/artifacts/core-linux/e2e_deployment_files/$DEPLOYMENT_FILE_NAME"
|
||||||
deployment_working_file="$working_folder/deployment.json"
|
deployment_working_file="$working_folder/deployment.json"
|
||||||
|
|
||||||
testRet=0
|
testRet=0
|
||||||
|
|
|
@ -0,0 +1,65 @@
|
||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup Condition="'$(DotNet_Runtime)' != 'netcoreapp3.0'">
|
||||||
|
<TargetFramework>netcoreapp2.1</TargetFramework>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition="'$(OS)|$(DotNet_Runtime)' == 'Unix|netcoreapp3.0'">
|
||||||
|
<TargetFramework>netcoreapp3.0</TargetFramework>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<TreatWarningsAsErrors>True</TreatWarningsAsErrors>
|
||||||
|
<Configurations>Debug;Release;CodeCoverage;CheckInBuild</Configurations>
|
||||||
|
<HighEntropyVA>true</HighEntropyVA>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Normally, the 'Debug' configuration would work for code coverage, but Microsoft.CodeCoverage currently requires '<DebugType>full</DebugType>' for .NET Core.
|
||||||
|
See https://github.com/Microsoft/vstest-docs/blob/06f9dc0aeb47be7204dc4e1a98c110ead3e978c7/docs/analyze.md#setup-a-project.
|
||||||
|
That setting seems to break the "Open Test" context menu in VS IDE, so we'll use a dedicated configuration for code coverage.
|
||||||
|
-->
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'CodeCoverage|AnyCPU' ">
|
||||||
|
<IntermediateOutputPath>obj\CodeCoverage</IntermediateOutputPath>
|
||||||
|
<DebugType>full</DebugType>
|
||||||
|
<Optimize>false</Optimize>
|
||||||
|
<OutputPath>bin\CodeCoverage</OutputPath>
|
||||||
|
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Content Include="docker*/**/*.*" CopyToPublishDirectory="Always" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.Azure.Devices" Version="1.18.2" />
|
||||||
|
<PackageReference Include="Microsoft.Azure.Devices.Client" Version="1.22.0" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Configuration" Version="2.2.0" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="2.2.0" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="2.2.0" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="2.2.0" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Configuration.FileExtensions" Version="2.2.0" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="2.0.0" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\..\edge-util\src\Microsoft.Azure.Devices.Edge.Util\Microsoft.Azure.Devices.Edge.Util.csproj" />
|
||||||
|
<ProjectReference Include="..\ModuleLib\Microsoft.Azure.Devices.Edge.ModuleUtil.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<None Update="config/appsettings.json">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<AdditionalFiles Include="..\..\..\stylecop.json" Link="stylecop.json" />
|
||||||
|
</ItemGroup>
|
||||||
|
<PropertyGroup>
|
||||||
|
<CodeAnalysisRuleSet>..\..\..\stylecop.ruleset</CodeAnalysisRuleSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="..\..\..\stylecop.props" />
|
||||||
|
|
||||||
|
</Project>
|
|
@ -0,0 +1,32 @@
|
||||||
|
{
|
||||||
|
"IOT_HUB_CONNECTION_STRING": {
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
"directMethodEnabled": {
|
||||||
|
"value": "true"
|
||||||
|
},
|
||||||
|
"directMethodTargetModuleId": {
|
||||||
|
"value": "directMethodReceiver1"
|
||||||
|
},
|
||||||
|
"messageEnabled": {
|
||||||
|
"value": "true"
|
||||||
|
},
|
||||||
|
"reportingEndpointUrl": {
|
||||||
|
"value": "http://localhost:5001"
|
||||||
|
},
|
||||||
|
"restartPeriod": {
|
||||||
|
"value": "00:05:00.000"
|
||||||
|
},
|
||||||
|
"sdkOperationTimeout": {
|
||||||
|
"value": "00:00:00.020"
|
||||||
|
},
|
||||||
|
"testDuration": {
|
||||||
|
"value": "01:00:00.000"
|
||||||
|
},
|
||||||
|
"testStartDelay": {
|
||||||
|
"value": "00:02:00.000"
|
||||||
|
},
|
||||||
|
"trackingId": {
|
||||||
|
"value": ""
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
ARG base_tag=2.1.10-alpine3.7
|
||||||
|
FROM mcr.microsoft.com/dotnet/core/runtime:${base_tag}
|
||||||
|
|
||||||
|
ARG EXE_DIR=.
|
||||||
|
|
||||||
|
ENV MODULE_NAME "EdgeHubRestartTester.dll"
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
COPY $EXE_DIR/ ./
|
||||||
|
|
||||||
|
# Add an unprivileged user account for running the module
|
||||||
|
RUN adduser -Ds /bin/sh moduleuser
|
||||||
|
USER moduleuser
|
||||||
|
|
||||||
|
CMD echo "$(date --utc +"[%Y-%m-%d %H:%M:%S %:z]"): Starting Module" && \
|
||||||
|
exec /usr/bin/dotnet EdgeHubRestartTester.dll
|
|
@ -0,0 +1,15 @@
|
||||||
|
ARG base_tag=1.0.3-linux-arm32v7
|
||||||
|
FROM azureiotedge/azureiotedge-module-base:${base_tag}
|
||||||
|
|
||||||
|
ARG EXE_DIR=.
|
||||||
|
|
||||||
|
ENV MODULE_NAME "EdgeHubRestartTester.dll"
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
COPY $EXE_DIR/ ./
|
||||||
|
|
||||||
|
USER moduleuser
|
||||||
|
|
||||||
|
CMD echo "$(date --utc +"[%Y-%m-%d %H:%M:%S %:z]"): Starting Module" && \
|
||||||
|
exec /usr/bin/dotnet EdgeHubRestartTester.dll
|
|
@ -0,0 +1,15 @@
|
||||||
|
ARG base_tag=1.0.3-linux-arm64v8
|
||||||
|
FROM azureiotedge/azureiotedge-module-base:${base_tag}
|
||||||
|
|
||||||
|
ARG EXE_DIR=.
|
||||||
|
|
||||||
|
ENV MODULE_NAME "EdgeHubRestartTester.dll"
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
COPY $EXE_DIR/ ./
|
||||||
|
|
||||||
|
USER moduleuser
|
||||||
|
|
||||||
|
CMD echo "$(date --utc +"%Y-%m-%d %H:%M:%S %:z") Starting Module" && \
|
||||||
|
exec /usr/bin/dotnet EdgeHubRestartTester.dll
|
|
@ -0,0 +1,10 @@
|
||||||
|
ARG base_tag=2.1.10-nanoserver-1809
|
||||||
|
FROM mcr.microsoft.com/dotnet/core/runtime:${base_tag}
|
||||||
|
|
||||||
|
ARG EXE_DIR=.
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
COPY $EXE_DIR/ ./
|
||||||
|
|
||||||
|
CMD ["dotnet", "EdgeHubRestartTester.dll"]
|
|
@ -0,0 +1,11 @@
|
||||||
|
ARG base_tag=1.0.2-windows-arm32v7
|
||||||
|
ARG base_registry
|
||||||
|
FROM ${base_registry}/azureiotedge/azureiotedge-module-base:${base_tag}
|
||||||
|
|
||||||
|
ARG EXE_DIR=.
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
COPY $EXE_DIR/ ./
|
||||||
|
|
||||||
|
CMD ["dotnet", "EdgeHubRestartTester.dll"]
|
|
@ -0,0 +1,159 @@
|
||||||
|
// Copyright (c) Microsoft. All rights reserved.
|
||||||
|
namespace EdgeHubRestartTester
|
||||||
|
{
|
||||||
|
using System;
|
||||||
|
using System.Net;
|
||||||
|
using System.Net.Sockets;
|
||||||
|
using System.Text;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.Azure.Devices.Client;
|
||||||
|
using Microsoft.Azure.Devices.Client.Exceptions;
|
||||||
|
using Microsoft.Azure.Devices.Edge.ModuleUtil;
|
||||||
|
using Microsoft.Azure.Devices.Edge.ModuleUtil.TestResults;
|
||||||
|
using Microsoft.Azure.Devices.Edge.Util;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
|
class DirectMethodEdgeHubConnectorTest : IEdgeHubConnector
|
||||||
|
{
|
||||||
|
readonly ModuleClient dmModuleClient;
|
||||||
|
readonly Guid batchId;
|
||||||
|
readonly DateTime runExpirationTime;
|
||||||
|
readonly CancellationToken cancellationToken;
|
||||||
|
readonly DateTime edgeHubRestartedTime;
|
||||||
|
readonly uint restartSequenceNumber;
|
||||||
|
readonly ILogger logger;
|
||||||
|
long directMethodCount = 0;
|
||||||
|
|
||||||
|
public DirectMethodEdgeHubConnectorTest(
|
||||||
|
ModuleClient dmModuleClient,
|
||||||
|
Guid batchId,
|
||||||
|
DateTime runExpirationTime,
|
||||||
|
DateTime edgeHubRestartedTime,
|
||||||
|
uint restartSequenceNumber,
|
||||||
|
ILogger logger,
|
||||||
|
CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
this.dmModuleClient = Preconditions.CheckNotNull(dmModuleClient, nameof(dmModuleClient));
|
||||||
|
this.batchId = batchId;
|
||||||
|
this.runExpirationTime = runExpirationTime;
|
||||||
|
this.cancellationToken = Preconditions.CheckNotNull(cancellationToken, nameof(cancellationToken));
|
||||||
|
this.edgeHubRestartedTime = edgeHubRestartedTime;
|
||||||
|
this.restartSequenceNumber = restartSequenceNumber;
|
||||||
|
this.logger = Preconditions.CheckNotNull(logger, nameof(logger));
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task StartAsync()
|
||||||
|
{
|
||||||
|
(DateTime dmCompletedTime, HttpStatusCode dmStatusCode) = await this.SendDirectMethodAsync(
|
||||||
|
Settings.Current.DeviceId,
|
||||||
|
Settings.Current.DirectMethodTargetModuleId,
|
||||||
|
this.dmModuleClient,
|
||||||
|
Settings.Current.DirectMethodName,
|
||||||
|
this.runExpirationTime,
|
||||||
|
this.cancellationToken,
|
||||||
|
this.logger);
|
||||||
|
|
||||||
|
TestResultBase dmTestResult = new EdgeHubRestartDirectMethodResult(
|
||||||
|
Settings.Current.ModuleId + "." + TestOperationResultType.EdgeHubRestartDirectMethod.ToString(),
|
||||||
|
DateTime.UtcNow,
|
||||||
|
Settings.Current.TrackingId,
|
||||||
|
this.batchId,
|
||||||
|
Interlocked.Read(ref this.directMethodCount).ToString(),
|
||||||
|
this.edgeHubRestartedTime,
|
||||||
|
dmCompletedTime,
|
||||||
|
dmStatusCode,
|
||||||
|
this.restartSequenceNumber);
|
||||||
|
|
||||||
|
var reportClient = new TestResultReportingClient { BaseUrl = Settings.Current.ReportingEndpointUrl.AbsoluteUri };
|
||||||
|
await ModuleUtil.ReportTestResultUntilSuccessAsync(
|
||||||
|
reportClient,
|
||||||
|
this.logger,
|
||||||
|
dmTestResult,
|
||||||
|
this.cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
async Task<Tuple<DateTime, HttpStatusCode>> SendDirectMethodAsync(
|
||||||
|
string deviceId,
|
||||||
|
string targetModuleId,
|
||||||
|
ModuleClient moduleClient,
|
||||||
|
string directMethodName,
|
||||||
|
DateTime runExpirationTime,
|
||||||
|
CancellationToken cancellationToken,
|
||||||
|
ILogger logger)
|
||||||
|
{
|
||||||
|
while ((!cancellationToken.IsCancellationRequested) && (DateTime.UtcNow < runExpirationTime))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Direct Method sequence number is always increasing regardless of sending result.
|
||||||
|
Interlocked.Increment(ref this.directMethodCount);
|
||||||
|
MethodRequest request = new MethodRequest(
|
||||||
|
directMethodName,
|
||||||
|
Encoding.UTF8.GetBytes($"{{ \"Message\": \"Hello\", \"DirectMethodCount\": \"{Interlocked.Read(ref this.directMethodCount).ToString()}\" }}"),
|
||||||
|
Settings.Current.SdkOperationTimeout,
|
||||||
|
Settings.Current.SdkOperationTimeout);
|
||||||
|
MethodResponse result = await moduleClient.InvokeMethodAsync(deviceId, targetModuleId, request);
|
||||||
|
logger.LogInformation($"[DirectMethodEdgeHubConnector] Invoke DirectMethod with count {Interlocked.Read(ref this.directMethodCount).ToString()}");
|
||||||
|
|
||||||
|
if ((HttpStatusCode)result.Status == HttpStatusCode.OK)
|
||||||
|
{
|
||||||
|
logger.LogDebug(result.ResultAsJson);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
logger.LogError(result.ResultAsJson);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Tuple<DateTime, HttpStatusCode>(DateTime.UtcNow, (HttpStatusCode)result.Status);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
// Only handle the exception that relevant to our test case; otherwise, re-throw it.
|
||||||
|
if (this.IsEdgeHubDownDuringDirectMethodSend(e) || this.IsDirectMethodReceiverNotConnected(e))
|
||||||
|
{
|
||||||
|
// swallow exeception and retry until success
|
||||||
|
logger.LogDebug(e, $"[DirectMethodEdgeHubConnector] Exception caught with SequenceNumber {Interlocked.Read(ref this.directMethodCount).ToString()}");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// TODO: Use the TRC result type
|
||||||
|
// something is wrong, Log and send report to TRC
|
||||||
|
logger.LogError(e, $"[DirectMethodEdgeHubConnector] Exception caught with SequenceNumber {Interlocked.Read(ref this.directMethodCount).ToString()}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Tuple<DateTime, HttpStatusCode>(DateTime.UtcNow, HttpStatusCode.InternalServerError);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsEdgeHubDownDuringDirectMethodSend(Exception e)
|
||||||
|
{
|
||||||
|
// This is a socket exception error code when EdgeHub is down.
|
||||||
|
const int EdgeHubNotAvailableErrorCode = 111;
|
||||||
|
|
||||||
|
if (e is IotHubCommunicationException)
|
||||||
|
{
|
||||||
|
if (e?.InnerException?.InnerException is SocketException)
|
||||||
|
{
|
||||||
|
int errorCode = ((SocketException)e.InnerException.InnerException).ErrorCode;
|
||||||
|
return errorCode == EdgeHubNotAvailableErrorCode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsDirectMethodReceiverNotConnected(Exception e)
|
||||||
|
{
|
||||||
|
if (e is DeviceNotFoundException)
|
||||||
|
{
|
||||||
|
string errorMsg = e.Message;
|
||||||
|
return Regex.IsMatch(errorMsg, $"\\b{Settings.Current.DirectMethodTargetModuleId}\\b");
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
// Copyright (c) Microsoft. All rights reserved.
|
||||||
|
namespace EdgeHubRestartTester
|
||||||
|
{
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
public interface IEdgeHubConnector
|
||||||
|
{
|
||||||
|
Task StartAsync();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,112 @@
|
||||||
|
// Copyright (c) Microsoft. All rights reserved.
|
||||||
|
namespace EdgeHubRestartTester
|
||||||
|
{
|
||||||
|
using System;
|
||||||
|
using System.Net;
|
||||||
|
using System.Net.Sockets;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.Azure.Devices.Client;
|
||||||
|
using Microsoft.Azure.Devices.Edge.ModuleUtil;
|
||||||
|
using Microsoft.Azure.Devices.Edge.ModuleUtil.TestResults;
|
||||||
|
using Microsoft.Azure.Devices.Edge.Util;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
class MessageEdgeHubConnectorTest : IEdgeHubConnector
|
||||||
|
{
|
||||||
|
readonly ModuleClient msgModuleClient;
|
||||||
|
readonly Guid batchId;
|
||||||
|
readonly DateTime runExpirationTime;
|
||||||
|
readonly CancellationToken cancellationToken;
|
||||||
|
readonly DateTime edgeHubRestartedTime;
|
||||||
|
readonly ILogger logger;
|
||||||
|
long messageCount = 0;
|
||||||
|
|
||||||
|
public MessageEdgeHubConnectorTest(
|
||||||
|
ModuleClient msgModuleClient,
|
||||||
|
Guid batchId,
|
||||||
|
DateTime runExpirationTime,
|
||||||
|
DateTime edgeHubRestartedTime,
|
||||||
|
ILogger logger,
|
||||||
|
CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
this.msgModuleClient = Preconditions.CheckNotNull(msgModuleClient, nameof(msgModuleClient));
|
||||||
|
this.batchId = batchId;
|
||||||
|
this.runExpirationTime = runExpirationTime;
|
||||||
|
this.cancellationToken = Preconditions.CheckNotNull(cancellationToken, nameof(cancellationToken));
|
||||||
|
this.edgeHubRestartedTime = edgeHubRestartedTime;
|
||||||
|
this.logger = Preconditions.CheckNotNull(logger, nameof(logger));
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task StartAsync()
|
||||||
|
{
|
||||||
|
(DateTime msgCompletedTime, HttpStatusCode mgsStatusCode) = await this.SendMessageAsync(
|
||||||
|
this.msgModuleClient,
|
||||||
|
Settings.Current.TrackingId,
|
||||||
|
this.batchId,
|
||||||
|
Settings.Current.MessageOutputEndpoint,
|
||||||
|
this.runExpirationTime,
|
||||||
|
this.cancellationToken);
|
||||||
|
|
||||||
|
TestResultBase msgTestResult = new EdgeHubRestartMessageResult(
|
||||||
|
Settings.Current.ModuleId + "." + TestOperationResultType.EdgeHubRestartMessage.ToString(),
|
||||||
|
DateTime.UtcNow,
|
||||||
|
Settings.Current.TrackingId,
|
||||||
|
this.batchId.ToString(),
|
||||||
|
Interlocked.Read(ref this.messageCount).ToString(),
|
||||||
|
this.edgeHubRestartedTime,
|
||||||
|
msgCompletedTime,
|
||||||
|
mgsStatusCode);
|
||||||
|
|
||||||
|
var reportClient = new TestResultReportingClient { BaseUrl = Settings.Current.ReportingEndpointUrl.AbsoluteUri };
|
||||||
|
await ModuleUtil.ReportTestResultUntilSuccessAsync(
|
||||||
|
reportClient,
|
||||||
|
this.logger,
|
||||||
|
msgTestResult,
|
||||||
|
this.cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
async Task<Tuple<DateTime, HttpStatusCode>> SendMessageAsync(
|
||||||
|
ModuleClient moduleClient,
|
||||||
|
string trackingId,
|
||||||
|
Guid batchId,
|
||||||
|
string msgOutputEndpoint,
|
||||||
|
DateTime runExpirationTime,
|
||||||
|
CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
Interlocked.Increment(ref this.messageCount);
|
||||||
|
while ((!cancellationToken.IsCancellationRequested) && (DateTime.UtcNow < runExpirationTime))
|
||||||
|
{
|
||||||
|
Message message = new Message(Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(new { data = DateTime.UtcNow.ToString() })));
|
||||||
|
message.Properties.Add("sequenceNumber", Interlocked.Read(ref this.messageCount).ToString());
|
||||||
|
message.Properties.Add("batchId", batchId.ToString());
|
||||||
|
message.Properties.Add("trackingId", trackingId);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Sending the result via edgeHub
|
||||||
|
await moduleClient.SendEventAsync(msgOutputEndpoint, message);
|
||||||
|
this.logger.LogInformation($"[SendMessageAsync] Send Message with count {Interlocked.Read(ref this.messageCount).ToString()}: finished.");
|
||||||
|
return new Tuple<DateTime, HttpStatusCode>(DateTime.UtcNow, HttpStatusCode.OK);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
if (ex is TimeoutException)
|
||||||
|
{
|
||||||
|
// TimeoutException is expected to happen while the EdgeHub is down.
|
||||||
|
// Let's log the attempt and retry the message send until successful
|
||||||
|
this.logger.LogDebug(ex, $"[SendMessageAsync] Exception caught with SequenceNumber {this.messageCount}, BatchId: {batchId.ToString()};");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this.logger.LogError(ex, $"[SendMessageAsync] Exception caught with SequenceNumber {this.messageCount}, BatchId: {batchId.ToString()};");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Tuple<DateTime, HttpStatusCode>(DateTime.UtcNow, HttpStatusCode.InternalServerError);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,172 @@
|
||||||
|
// Copyright (c) Microsoft. All rights reserved.
|
||||||
|
namespace EdgeHubRestartTester
|
||||||
|
{
|
||||||
|
using System;
|
||||||
|
using System.Net;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.Azure.Devices;
|
||||||
|
using Microsoft.Azure.Devices.Client;
|
||||||
|
using Microsoft.Azure.Devices.Edge.ModuleUtil;
|
||||||
|
using Microsoft.Azure.Devices.Edge.Util;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
|
class Program
|
||||||
|
{
|
||||||
|
static readonly ILogger Logger = ModuleUtil.CreateLogger("EdgeHubRestartTester");
|
||||||
|
|
||||||
|
public static int Main() => MainAsync().Result;
|
||||||
|
|
||||||
|
static async Task<int> MainAsync()
|
||||||
|
{
|
||||||
|
uint restartCount = 0;
|
||||||
|
|
||||||
|
Guid batchId = Guid.NewGuid();
|
||||||
|
Logger.LogInformation($"Starting EdgeHubRestartTester ({batchId}) with the following settings:\r\n{Settings.Current}");
|
||||||
|
|
||||||
|
Logger.LogInformation($"EdgeHubRestartTester delay start for {Settings.Current.TestStartDelay}.");
|
||||||
|
await Task.Delay(Settings.Current.TestStartDelay);
|
||||||
|
|
||||||
|
(CancellationTokenSource cts, ManualResetEventSlim completed, Option<object> handler) = ShutdownHandler.Init(TimeSpan.FromSeconds(5), Logger);
|
||||||
|
|
||||||
|
ServiceClient iotHubServiceClient = null;
|
||||||
|
ModuleClient msgModuleClient = null;
|
||||||
|
ModuleClient dmModuleClient = null;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
iotHubServiceClient = ServiceClient.CreateFromConnectionString(Settings.Current.IoTHubConnectionString);
|
||||||
|
|
||||||
|
if (Settings.Current.MessageEnabled)
|
||||||
|
{
|
||||||
|
msgModuleClient = await ModuleUtil.CreateModuleClientAsync(
|
||||||
|
Settings.Current.TransportType,
|
||||||
|
ModuleUtil.DefaultTimeoutErrorDetectionStrategy,
|
||||||
|
ModuleUtil.DefaultTransientRetryStrategy,
|
||||||
|
Logger);
|
||||||
|
|
||||||
|
msgModuleClient.OperationTimeoutInMilliseconds = (uint)Settings.Current.SdkOperationTimeout.TotalMilliseconds;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Settings.Current.DirectMethodEnabled)
|
||||||
|
{
|
||||||
|
dmModuleClient = await ModuleUtil.CreateModuleClientAsync(
|
||||||
|
Settings.Current.TransportType,
|
||||||
|
ModuleUtil.DefaultTimeoutErrorDetectionStrategy,
|
||||||
|
ModuleUtil.DefaultTransientRetryStrategy,
|
||||||
|
Logger);
|
||||||
|
}
|
||||||
|
|
||||||
|
DateTime testStart = DateTime.UtcNow;
|
||||||
|
DateTime testExpirationTime = testStart + Settings.Current.TestDuration;
|
||||||
|
|
||||||
|
while ((!cts.IsCancellationRequested) && (DateTime.UtcNow < testExpirationTime))
|
||||||
|
{
|
||||||
|
(DateTime restartTime, _) = await RestartEdgeHub(iotHubServiceClient);
|
||||||
|
DateTime eachTestExpirationTime = restartTime.Add(Settings.Current.RestartPeriod);
|
||||||
|
|
||||||
|
// Increment the counter when issue an edgeHub restart
|
||||||
|
restartCount++;
|
||||||
|
|
||||||
|
// Setup Message Task
|
||||||
|
Task sendMessageTask = Task.CompletedTask;
|
||||||
|
if (Settings.Current.MessageEnabled)
|
||||||
|
{
|
||||||
|
sendMessageTask =
|
||||||
|
new MessageEdgeHubConnectorTest(
|
||||||
|
msgModuleClient,
|
||||||
|
batchId,
|
||||||
|
eachTestExpirationTime,
|
||||||
|
restartTime,
|
||||||
|
Logger,
|
||||||
|
cts.Token)
|
||||||
|
.StartAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup Direct Method Task
|
||||||
|
Task directMethodTask = Task.CompletedTask;
|
||||||
|
if (Settings.Current.DirectMethodEnabled)
|
||||||
|
{
|
||||||
|
directMethodTask =
|
||||||
|
new DirectMethodEdgeHubConnectorTest(
|
||||||
|
dmModuleClient,
|
||||||
|
batchId,
|
||||||
|
eachTestExpirationTime,
|
||||||
|
restartTime,
|
||||||
|
restartCount,
|
||||||
|
Logger,
|
||||||
|
cts.Token)
|
||||||
|
.StartAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for the two task to be done before do a restart
|
||||||
|
await Task.WhenAll(new[] { sendMessageTask, directMethodTask });
|
||||||
|
|
||||||
|
// Wait until the specified restart period to do another restart
|
||||||
|
await Task.Delay((int)(eachTestExpirationTime - DateTime.UtcNow).TotalMilliseconds, cts.Token);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Logger.LogError($"Exception caught: {e}");
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
iotHubServiceClient?.Dispose();
|
||||||
|
dmModuleClient?.Dispose();
|
||||||
|
msgModuleClient?.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
await cts.Token.WhenCanceled();
|
||||||
|
completed.Set();
|
||||||
|
handler.ForEach(h => GC.KeepAlive(h));
|
||||||
|
Logger.LogInformation("EdgeHubRestartTester Main() finished.");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static async Task<Tuple<DateTime, HttpStatusCode>> RestartEdgeHub(
|
||||||
|
ServiceClient iotHubServiceClient)
|
||||||
|
{
|
||||||
|
const uint maxRetry = 3;
|
||||||
|
uint restartCount = 0;
|
||||||
|
|
||||||
|
CloudToDeviceMethod c2dMethod = new CloudToDeviceMethod("RestartModule");
|
||||||
|
string payloadSchema = "{{ \"SchemaVersion\": \"1.0\", \"Id\": \"{0}\" }}";
|
||||||
|
string payload = string.Format(payloadSchema, "edgeHub");
|
||||||
|
Logger.LogInformation("RestartModule Method Payload: {0}", payload);
|
||||||
|
c2dMethod.SetPayloadJson(payload);
|
||||||
|
|
||||||
|
while (restartCount < maxRetry)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
restartCount++;
|
||||||
|
// TODO: Introduce the offline scenario to use docker command.
|
||||||
|
CloudToDeviceMethodResult response = await iotHubServiceClient.InvokeDeviceMethodAsync(Settings.Current.DeviceId, "$edgeAgent", c2dMethod);
|
||||||
|
if ((HttpStatusCode)response.Status != HttpStatusCode.OK)
|
||||||
|
{
|
||||||
|
Logger.LogError($"Calling EdgeHub restart failed with status code {response.Status} : {response.GetPayloadAsJson()}.");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Logger.LogInformation($"Calling EdgeHub restart succeeded with status code {response.Status}.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Tuple<DateTime, HttpStatusCode>(DateTime.UtcNow, (HttpStatusCode)response.Status);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Logger.LogError($"Exception caught for payload {payload}: {e}");
|
||||||
|
|
||||||
|
if (restartCount == maxRetry - 1)
|
||||||
|
{
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Tuple<DateTime, HttpStatusCode>(DateTime.UtcNow, HttpStatusCode.InternalServerError);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,150 @@
|
||||||
|
// Copyright (c) Microsoft. All rights reserved.
|
||||||
|
namespace EdgeHubRestartTester
|
||||||
|
{
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using Microsoft.Azure.Devices.Client;
|
||||||
|
using Microsoft.Azure.Devices.Edge.Util;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
|
||||||
|
class Settings
|
||||||
|
{
|
||||||
|
internal static Settings Current = Create();
|
||||||
|
|
||||||
|
Settings(
|
||||||
|
TimeSpan sdkOperationTimeout,
|
||||||
|
string serviceClientConnectionString,
|
||||||
|
string deviceId,
|
||||||
|
string reportingEndpointUrl,
|
||||||
|
TimeSpan restartPeriod,
|
||||||
|
TimeSpan testStartDelay,
|
||||||
|
TimeSpan testDuration,
|
||||||
|
bool directMethodEnabled,
|
||||||
|
string directMethodName,
|
||||||
|
string directMethodTargetModuleId,
|
||||||
|
bool messageEnabled,
|
||||||
|
string messageOutputEndpoint,
|
||||||
|
TransportType transportType,
|
||||||
|
string moduleId,
|
||||||
|
string trackingId)
|
||||||
|
{
|
||||||
|
Preconditions.CheckRange(sdkOperationTimeout.Ticks, 0);
|
||||||
|
Preconditions.CheckRange(restartPeriod.Ticks, 0);
|
||||||
|
Preconditions.CheckRange(testStartDelay.Ticks, 0);
|
||||||
|
Preconditions.CheckRange(testDuration.Ticks, 0);
|
||||||
|
|
||||||
|
this.DeviceId = Preconditions.CheckNonWhiteSpace(deviceId, nameof(deviceId));
|
||||||
|
this.DirectMethodEnabled = directMethodEnabled;
|
||||||
|
this.DirectMethodName = this.DirectMethodEnabled ? Preconditions.CheckNonWhiteSpace(directMethodName, nameof(directMethodName)) : string.Empty;
|
||||||
|
this.DirectMethodTargetModuleId = this.DirectMethodEnabled ? Preconditions.CheckNonWhiteSpace(directMethodTargetModuleId, nameof(directMethodTargetModuleId)) : string.Empty;
|
||||||
|
this.MessageEnabled = messageEnabled;
|
||||||
|
this.MessageOutputEndpoint = this.MessageEnabled ? Preconditions.CheckNonWhiteSpace(messageOutputEndpoint, nameof(messageOutputEndpoint)) : string.Empty;
|
||||||
|
this.TransportType = transportType;
|
||||||
|
this.ModuleId = Preconditions.CheckNonWhiteSpace(moduleId, nameof(moduleId));
|
||||||
|
this.ReportingEndpointUrl = new Uri(Preconditions.CheckNonWhiteSpace(reportingEndpointUrl, nameof(reportingEndpointUrl)));
|
||||||
|
this.RestartPeriod = restartPeriod;
|
||||||
|
this.SdkOperationTimeout = sdkOperationTimeout;
|
||||||
|
this.IoTHubConnectionString = Preconditions.CheckNonWhiteSpace(serviceClientConnectionString, nameof(serviceClientConnectionString));
|
||||||
|
this.TestDuration = testDuration;
|
||||||
|
this.TestStartDelay = testStartDelay;
|
||||||
|
this.TrackingId = Preconditions.CheckNonWhiteSpace(trackingId, nameof(trackingId));
|
||||||
|
|
||||||
|
if (!(this.DirectMethodEnabled || this.MessageEnabled))
|
||||||
|
{
|
||||||
|
throw new NotSupportedException("EdgeHubRestartTester requires at least one of the sending methods {DirectMethodEnabled, MessageEnabled} to be enabled to perform the EdgeHub restarting test.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (restartPeriod < sdkOperationTimeout)
|
||||||
|
{
|
||||||
|
throw new InvalidDataException("sdkOperationTimeout period must be less than restartInterval period.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.RestartPeriod.Ticks < TimeSpan.FromMinutes(1).Ticks)
|
||||||
|
{
|
||||||
|
throw new InvalidDataException("RestartPeriod period must be at least one minute");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static Settings Create()
|
||||||
|
{
|
||||||
|
IConfiguration configuration = new ConfigurationBuilder()
|
||||||
|
.SetBasePath(Directory.GetCurrentDirectory())
|
||||||
|
.AddJsonFile("config/settings.json", optional: true)
|
||||||
|
.AddEnvironmentVariables()
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
return new Settings(
|
||||||
|
configuration.GetValue("sdkOperationTimeout", TimeSpan.FromMilliseconds(20)),
|
||||||
|
configuration.GetValue<string>("IOT_HUB_CONNECTION_STRING", string.Empty),
|
||||||
|
configuration.GetValue<string>("IOTEDGE_DEVICEID", string.Empty),
|
||||||
|
configuration.GetValue<string>("reportingEndpointUrl"),
|
||||||
|
configuration.GetValue("restartPeriod", TimeSpan.FromMinutes(5)),
|
||||||
|
configuration.GetValue("testStartDelay", TimeSpan.FromMinutes(2)),
|
||||||
|
configuration.GetValue("testDuration", TimeSpan.Zero),
|
||||||
|
configuration.GetValue<bool>("directMethodEnabled", false),
|
||||||
|
configuration.GetValue<string>("directMethodName", "HelloWorldMethod"),
|
||||||
|
configuration.GetValue<string>("directMethodTargetModuleId", "DirectMethodReceiver"),
|
||||||
|
configuration.GetValue<bool>("messageEnabled", false),
|
||||||
|
configuration.GetValue("messageOutputEndpoint", "output1"),
|
||||||
|
configuration.GetValue("transportType", TransportType.Amqp_Tcp_Only),
|
||||||
|
configuration.GetValue<string>("IOTEDGE_MODULEID"),
|
||||||
|
configuration.GetValue("trackingId", string.Empty));
|
||||||
|
}
|
||||||
|
|
||||||
|
public string IoTHubConnectionString { get; }
|
||||||
|
|
||||||
|
public string DeviceId { get; }
|
||||||
|
|
||||||
|
public bool DirectMethodEnabled { get; }
|
||||||
|
|
||||||
|
public string DirectMethodName { get; }
|
||||||
|
|
||||||
|
public string DirectMethodTargetModuleId { get; }
|
||||||
|
|
||||||
|
public bool MessageEnabled { get; }
|
||||||
|
|
||||||
|
public string MessageOutputEndpoint { get; }
|
||||||
|
|
||||||
|
public TransportType TransportType { get; }
|
||||||
|
|
||||||
|
public string ModuleId { get; }
|
||||||
|
|
||||||
|
public Uri ReportingEndpointUrl { get; }
|
||||||
|
|
||||||
|
public TimeSpan RestartPeriod { get; }
|
||||||
|
|
||||||
|
public TimeSpan SdkOperationTimeout { get; }
|
||||||
|
|
||||||
|
public TimeSpan TestStartDelay { get; }
|
||||||
|
|
||||||
|
public TimeSpan TestDuration { get; }
|
||||||
|
|
||||||
|
public string TrackingId { get; }
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
// serializing in this pattern so that secrets don't accidentally get added anywhere in the future
|
||||||
|
var fields = new Dictionary<string, string>
|
||||||
|
{
|
||||||
|
{ nameof(this.DeviceId), this.DeviceId },
|
||||||
|
{ nameof(this.DirectMethodEnabled), this.DirectMethodEnabled.ToString() },
|
||||||
|
{ nameof(this.DirectMethodName), this.DirectMethodName },
|
||||||
|
{ nameof(this.DirectMethodTargetModuleId), this.DirectMethodTargetModuleId },
|
||||||
|
{ nameof(this.MessageEnabled), this.MessageEnabled.ToString() },
|
||||||
|
{ nameof(this.MessageOutputEndpoint), this.MessageOutputEndpoint },
|
||||||
|
{ nameof(this.TransportType), this.TransportType.ToString() },
|
||||||
|
{ nameof(this.ModuleId), this.ModuleId },
|
||||||
|
{ nameof(this.ReportingEndpointUrl), this.ReportingEndpointUrl.ToString() },
|
||||||
|
{ nameof(this.RestartPeriod), this.RestartPeriod.ToString() },
|
||||||
|
{ nameof(this.SdkOperationTimeout), this.SdkOperationTimeout.ToString() },
|
||||||
|
{ nameof(this.TestStartDelay), this.TestStartDelay.ToString() },
|
||||||
|
{ nameof(this.TestDuration), this.TestDuration.ToString() },
|
||||||
|
{ nameof(this.TrackingId), this.TrackingId }
|
||||||
|
};
|
||||||
|
|
||||||
|
return $"Settings:{Environment.NewLine}{string.Join(Environment.NewLine, fields.Select(f => $"{f.Key}={f.Value}"))}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,6 +2,7 @@
|
||||||
namespace Microsoft.Azure.Devices.Edge.ModuleUtil
|
namespace Microsoft.Azure.Devices.Edge.ModuleUtil
|
||||||
{
|
{
|
||||||
using System;
|
using System;
|
||||||
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.Azure.Devices.Client;
|
using Microsoft.Azure.Devices.Client;
|
||||||
using Microsoft.Azure.Devices.Client.Transport.Mqtt;
|
using Microsoft.Azure.Devices.Client.Transport.Mqtt;
|
||||||
|
@ -62,6 +63,25 @@ namespace Microsoft.Azure.Devices.Edge.ModuleUtil
|
||||||
await apiClient.ReportResultAsync(testResult.ToTestOperationResultDto());
|
await apiClient.ReportResultAsync(testResult.ToTestOperationResultDto());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Remove this function once the TRC support the two new endpoint properly.
|
||||||
|
public static async Task ReportTestResultUntilSuccessAsync(TestResultReportingClient apiClient, ILogger logger, TestResultBase testResult, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
bool isSuccessful = false;
|
||||||
|
while (!isSuccessful && !cancellationToken.IsCancellationRequested)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
logger.LogInformation($"Sending test result: Source={testResult.Source}, Type={testResult.ResultType}, CreatedAt={testResult.CreatedAt}, Result={testResult.GetFormattedResult()}");
|
||||||
|
await apiClient.ReportResultAsync(testResult.ToTestOperationResultDto(), cancellationToken);
|
||||||
|
isSuccessful = true;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
logger.LogDebug(ex, "Exception caught in ReportTestResultAsync()");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static async Task<ModuleClient> InitializeModuleClientAsync(TransportType transportType, ILogger logger)
|
static async Task<ModuleClient> InitializeModuleClientAsync(TransportType transportType, ILogger logger)
|
||||||
{
|
{
|
||||||
ITransportSettings[] GetTransportSettings()
|
ITransportSettings[] GetTransportSettings()
|
||||||
|
|
|
@ -10,6 +10,8 @@ namespace Microsoft.Azure.Devices.Edge.ModuleUtil
|
||||||
Twin,
|
Twin,
|
||||||
Network,
|
Network,
|
||||||
Deployment,
|
Deployment,
|
||||||
|
EdgeHubRestartMessage,
|
||||||
|
EdgeHubRestartDirectMethod,
|
||||||
Error
|
Error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,8 +14,9 @@ namespace Microsoft.Azure.Devices.Edge.ModuleUtil.TestResults
|
||||||
string trackingId,
|
string trackingId,
|
||||||
Guid batchId,
|
Guid batchId,
|
||||||
string sequenceNumber,
|
string sequenceNumber,
|
||||||
HttpStatusCode result)
|
HttpStatusCode result,
|
||||||
: base(source, TestOperationResultType.DirectMethod, createdAt)
|
TestOperationResultType testOperationResultType = TestOperationResultType.DirectMethod)
|
||||||
|
: base(source, testOperationResultType, createdAt)
|
||||||
{
|
{
|
||||||
this.TrackingId = trackingId ?? string.Empty;
|
this.TrackingId = trackingId ?? string.Empty;
|
||||||
this.BatchId = Preconditions.CheckNotNull(batchId, nameof(batchId)).ToString();
|
this.BatchId = Preconditions.CheckNotNull(batchId, nameof(batchId)).ToString();
|
||||||
|
|
|
@ -0,0 +1,48 @@
|
||||||
|
// Copyright (c) Microsoft. All rights reserved.
|
||||||
|
namespace Microsoft.Azure.Devices.Edge.ModuleUtil.TestResults
|
||||||
|
{
|
||||||
|
using System;
|
||||||
|
using System.Net;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
public class EdgeHubRestartDirectMethodResult : DirectMethodTestResult
|
||||||
|
{
|
||||||
|
public EdgeHubRestartDirectMethodResult(
|
||||||
|
string source,
|
||||||
|
DateTime createdAt,
|
||||||
|
string trackingId,
|
||||||
|
Guid batchId,
|
||||||
|
string sequenceNumber,
|
||||||
|
DateTime edgeHubRestartedTime,
|
||||||
|
DateTime directMethodCompletedTime,
|
||||||
|
HttpStatusCode directMethodCompletedStatusCode,
|
||||||
|
uint restartSequenceNumber)
|
||||||
|
: base(
|
||||||
|
source,
|
||||||
|
createdAt,
|
||||||
|
trackingId,
|
||||||
|
batchId,
|
||||||
|
sequenceNumber,
|
||||||
|
directMethodCompletedStatusCode,
|
||||||
|
TestOperationResultType.EdgeHubRestartDirectMethod)
|
||||||
|
{
|
||||||
|
this.EdgeHubRestartedTime = edgeHubRestartedTime;
|
||||||
|
this.DirectMethodCompletedTime = directMethodCompletedTime;
|
||||||
|
this.DirectMethodCompletedStatusCode = directMethodCompletedStatusCode;
|
||||||
|
this.RestartSequenceNumber = restartSequenceNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
DateTime EdgeHubRestartedTime { get; set; }
|
||||||
|
|
||||||
|
public DateTime DirectMethodCompletedTime { get; set; }
|
||||||
|
|
||||||
|
public HttpStatusCode DirectMethodCompletedStatusCode { get; set; }
|
||||||
|
|
||||||
|
public uint RestartSequenceNumber { get; set; }
|
||||||
|
|
||||||
|
public override string GetFormattedResult()
|
||||||
|
{
|
||||||
|
return JsonConvert.SerializeObject(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,46 @@
|
||||||
|
// Copyright (c) Microsoft. All rights reserved.
|
||||||
|
namespace Microsoft.Azure.Devices.Edge.ModuleUtil.TestResults
|
||||||
|
{
|
||||||
|
using System;
|
||||||
|
using System.Net;
|
||||||
|
using Microsoft.Azure.Devices.Edge.Util;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
public class EdgeHubRestartMessageResult : MessageTestResult
|
||||||
|
{
|
||||||
|
public EdgeHubRestartMessageResult(
|
||||||
|
string source,
|
||||||
|
DateTime createdAt,
|
||||||
|
string trackingId,
|
||||||
|
string batchId,
|
||||||
|
string sequenceNumber,
|
||||||
|
DateTime edgeHubRestartedTime,
|
||||||
|
DateTime messageCompletedTime,
|
||||||
|
HttpStatusCode messageCompletedStatusCode)
|
||||||
|
: base(source, createdAt, TestOperationResultType.EdgeHubRestartMessage)
|
||||||
|
{
|
||||||
|
this.TrackingId = trackingId;
|
||||||
|
this.BatchId = batchId;
|
||||||
|
this.SequenceNumber = sequenceNumber;
|
||||||
|
this.EdgeHubRestartedTime = edgeHubRestartedTime;
|
||||||
|
this.MessageCompletedTime = messageCompletedTime;
|
||||||
|
this.MessageCompletedStatusCode = messageCompletedStatusCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
DateTime EdgeHubRestartedTime { get; set; }
|
||||||
|
|
||||||
|
public DateTime MessageCompletedTime { get; set; }
|
||||||
|
|
||||||
|
public HttpStatusCode MessageCompletedStatusCode { get; set; }
|
||||||
|
|
||||||
|
public string GetMessageTestResult()
|
||||||
|
{
|
||||||
|
return base.GetFormattedResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string GetFormattedResult()
|
||||||
|
{
|
||||||
|
return JsonConvert.SerializeObject(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,8 +5,8 @@ namespace Microsoft.Azure.Devices.Edge.ModuleUtil.TestResults
|
||||||
|
|
||||||
public class MessageTestResult : TestResultBase
|
public class MessageTestResult : TestResultBase
|
||||||
{
|
{
|
||||||
public MessageTestResult(string source, DateTime createdAt)
|
public MessageTestResult(string source, DateTime createdAt, TestOperationResultType testOperationResultType = TestOperationResultType.Messages)
|
||||||
: base(source, TestOperationResultType.Messages, createdAt)
|
: base(source, testOperationResultType, createdAt)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,7 @@ namespace TestResultCoordinator.Reports.DirectMethod
|
||||||
string resultType,
|
string resultType,
|
||||||
NetworkStatusTimeline networkStatusTimeline)
|
NetworkStatusTimeline networkStatusTimeline)
|
||||||
{
|
{
|
||||||
if ((receiverSource.HasValue && !receiverTestResults.HasValue) || (!receiverSource.HasValue && receiverTestResults.HasValue))
|
if (receiverSource.HasValue ^ receiverTestResults.HasValue)
|
||||||
{
|
{
|
||||||
throw new ArgumentException("Provide both receiverSource and receiverTestResults or neither.");
|
throw new ArgumentException("Provide both receiverSource and receiverTestResults or neither.");
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,8 @@ namespace TestResultCoordinator.Reports
|
||||||
public enum TestReportType
|
public enum TestReportType
|
||||||
{
|
{
|
||||||
CountingReport,
|
CountingReport,
|
||||||
|
EdgeHubRestartDirectMethodReport,
|
||||||
|
EdgeHubRestartMessageReport,
|
||||||
TwinCountingReport,
|
TwinCountingReport,
|
||||||
DeploymentTestReport,
|
DeploymentTestReport,
|
||||||
DirectMethodReport,
|
DirectMethodReport,
|
||||||
|
|
|
@ -153,7 +153,13 @@ namespace TestResultCoordinator
|
||||||
internal async Task<HashSet<string>> GetResultSourcesAsync(ILogger logger)
|
internal async Task<HashSet<string>> GetResultSourcesAsync(ILogger logger)
|
||||||
{
|
{
|
||||||
HashSet<string> sources = (await this.GetReportMetadataListAsync(logger)).SelectMany(r => r.ResultSources).ToHashSet();
|
HashSet<string> sources = (await this.GetReportMetadataListAsync(logger)).SelectMany(r => r.ResultSources).ToHashSet();
|
||||||
string[] additionalResultSources = new string[] { };
|
string[] additionalResultSources = new string[]
|
||||||
|
{
|
||||||
|
"edgeHubRestartTester1.EdgeHubRestartDirectMethod",
|
||||||
|
"directMethodReceiver1.receive",
|
||||||
|
"edgeHubRestartTester1.EdgeHubRestartMessage",
|
||||||
|
"relayer1.receive"
|
||||||
|
};
|
||||||
|
|
||||||
foreach (string rs in additionalResultSources)
|
foreach (string rs in additionalResultSources)
|
||||||
{
|
{
|
||||||
|
|
Загрузка…
Ссылка в новой задаче