Adding E2E Test for Twin Operations. (#754)

* Adding E2E Test for Twin Operations.

* Fixing StyleCop Issues.

* Addressing Code Review Comments.

* Fixing Code Style.

* Adressing more code review comments.

* Passing Code Style.
This commit is contained in:
Angelo Ribeiro 2019-01-29 11:51:13 -08:00 коммит произвёл GitHub
Родитель 6f7c6cdbff
Коммит 5bbcec092a
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
5 изменённых файлов: 84 добавлений и 1 удалений

Просмотреть файл

@ -0,0 +1,14 @@
{
"moduleId" : "tempSensor",
"properties" : {
"desired" : {
"SendInterval": 42,
"SendData": true,
"OtherType" : "test"
},
"reported" : {
"SendInterval": 42,
"SendData": true
}
}
}

Просмотреть файл

@ -114,6 +114,9 @@ Defaults:
[Option("-l|--deployment <filename>", Description = "Deployment json file")] [Option("-l|--deployment <filename>", Description = "Deployment json file")]
public string DeploymentFileName { get; } = Environment.GetEnvironmentVariable("deployment"); public string DeploymentFileName { get; } = Environment.GetEnvironmentVariable("deployment");
[Option("-tw|--twin_test <filename>", Description = "A file with Json content to set desired property and check reported property in a module.")]
public string TwinTestFileName { get; } = null;
[Option("--device_ca_cert", Description = "path to the device ca certificate and its chain")] [Option("--device_ca_cert", Description = "path to the device ca certificate and its chain")]
public string DeviceCaCert { get; } = string.Empty; public string DeviceCaCert { get; } = string.Empty;
@ -197,6 +200,8 @@ Defaults:
Option<string> deployment = this.DeploymentFileName != null ? Option.Some(this.DeploymentFileName) : Option.None<string>(); Option<string> deployment = this.DeploymentFileName != null ? Option.Some(this.DeploymentFileName) : Option.None<string>();
Option<string> twinTest = this.TwinTestFileName != null ? Option.Some(this.TwinTestFileName) : Option.None<string>();
string tag = this.ImageTag ?? "1.0"; string tag = this.ImageTag ?? "1.0";
var test = new Quickstart( var test = new Quickstart(
@ -213,6 +218,7 @@ Defaults:
this.NoVerify, this.NoVerify,
this.VerifyDataFromModule, this.VerifyDataFromModule,
deployment, deployment,
twinTest,
this.DeviceCaCert, this.DeviceCaCert,
this.DeviceCaPk, this.DeviceCaPk,
this.DeviceCaCerts, this.DeviceCaCerts,

Просмотреть файл

@ -27,13 +27,14 @@ namespace IotEdgeQuickstart
bool noVerify, bool noVerify,
string verifyDataFromModule, string verifyDataFromModule,
Option<string> deploymentFileName, Option<string> deploymentFileName,
Option<string> twinTestFileName,
string deviceCaCert, string deviceCaCert,
string deviceCaPk, string deviceCaPk,
string deviceCaCerts, string deviceCaCerts,
bool optimizedForPerformance, bool optimizedForPerformance,
LogLevel runtimeLogLevel, LogLevel runtimeLogLevel,
bool cleanUpExistingDeviceOnSuccess) bool cleanUpExistingDeviceOnSuccess)
: base(bootstrapper, credentials, iothubConnectionString, eventhubCompatibleEndpointWithEntityPath, upstreamProtocol, imageTag, deviceId, hostname, deploymentFileName, deviceCaCert, deviceCaPk, deviceCaCerts, optimizedForPerformance, runtimeLogLevel, cleanUpExistingDeviceOnSuccess) : base(bootstrapper, credentials, iothubConnectionString, eventhubCompatibleEndpointWithEntityPath, upstreamProtocol, imageTag, deviceId, hostname, deploymentFileName, twinTestFileName, deviceCaCert, deviceCaPk, deviceCaCerts, optimizedForPerformance, runtimeLogLevel, cleanUpExistingDeviceOnSuccess)
{ {
this.leaveRunning = leaveRunning; this.leaveRunning = leaveRunning;
this.noDeployment = noDeployment; this.noDeployment = noDeployment;
@ -67,6 +68,7 @@ namespace IotEdgeQuickstart
if (!this.noVerify) if (!this.noVerify)
{ {
await this.VerifyDataOnIoTHub(this.verifyDataFromModule); await this.VerifyDataOnIoTHub(this.verifyDataFromModule);
await this.VerifyTwinAsync();
} }
if (this.leaveRunning == LeaveRunning.Core) if (this.leaveRunning == LeaveRunning.Core)

Просмотреть файл

@ -4,6 +4,7 @@ namespace IotEdgeQuickstart.Details
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -21,6 +22,8 @@ namespace IotEdgeQuickstart.Details
{ {
public readonly Option<string> DeploymentFileName; public readonly Option<string> DeploymentFileName;
public readonly Option<string> TwinTestFileName;
const string DeployJson = @" const string DeployJson = @"
{ {
""modulesContent"": { ""modulesContent"": {
@ -138,6 +141,7 @@ namespace IotEdgeQuickstart.Details
string deviceId, string deviceId,
string hostname, string hostname,
Option<string> deploymentFileName, Option<string> deploymentFileName,
Option<string> twinTestFileName,
string deviceCaCert, string deviceCaCert,
string deviceCaPk, string deviceCaPk,
string deviceCaCerts, string deviceCaCerts,
@ -172,6 +176,7 @@ namespace IotEdgeQuickstart.Details
this.deviceId = deviceId; this.deviceId = deviceId;
this.hostname = hostname; this.hostname = hostname;
this.DeploymentFileName = deploymentFileName; this.DeploymentFileName = deploymentFileName;
this.TwinTestFileName = twinTestFileName;
this.deviceCaCert = deviceCaCert; this.deviceCaCert = deviceCaCert;
this.deviceCaPk = deviceCaPk; this.deviceCaPk = deviceCaPk;
this.deviceCaCerts = deviceCaCerts; this.deviceCaCerts = deviceCaCerts;
@ -334,6 +339,46 @@ namespace IotEdgeQuickstart.Details
await eventHubClient.CloseAsync(); await eventHubClient.CloseAsync();
} }
protected async Task VerifyTwinAsync()
{
await this.TwinTestFileName.ForEachAsync(
async fileName =>
{
string twinTestJson = File.ReadAllText(fileName);
var twinTest = JsonConvert.DeserializeObject<TwinTestConfiguration>(twinTestJson);
Twin currentTwin = await this.context.RegistryManager.GetTwinAsync(this.context.Device.Id, twinTest.ModuleId);
if (twinTest.Properties?.Desired?.Count > 0)
{
// Build Patch Object.
string patch = JsonConvert.SerializeObject(twinTest, Formatting.Indented);
await this.context.RegistryManager.UpdateTwinAsync(this.context.Device.Id, twinTest.ModuleId, patch, currentTwin.ETag);
}
if (twinTest.Properties?.Reported?.Count > 0)
{
TimeSpan retryInterval = TimeSpan.FromSeconds(10);
bool IsValid(TwinCollection currentTwinReportedProperty) => twinTest.Properties.Reported.Cast<KeyValuePair<string, object>>().All(p => currentTwinReportedProperty.Cast<KeyValuePair<string, object>>().Contains(p));
using (var cts = new CancellationTokenSource(TimeSpan.FromSeconds(20)))
{
async Task<TwinCollection> Func()
{
// Removing reSharper warning for CTS, Code Block will never exit before the delegate code completes because of using.
// ReSharper disable AccessToDisposedClosure
currentTwin = await this.context.RegistryManager.GetTwinAsync(this.context.Device.Id, twinTest.ModuleId, cts.Token);
// ReSharper restore AccessToDisposedClosure
return await Task.FromResult(currentTwin.Properties.Reported);
}
await Retry.Do(Func, IsValid, null, retryInterval, cts.Token);
}
}
});
}
protected Task RemoveTempSensorFromEdgeDevice() protected Task RemoveTempSensorFromEdgeDevice()
{ {
(string deployJson, string[] _) = this.DeploymentJson(); (string deployJson, string[] _) = this.DeploymentJson();

Просмотреть файл

@ -0,0 +1,16 @@
// Copyright (c) Microsoft. All rights reserved.
namespace IotEdgeQuickstart.Details
{
using System.Collections.Generic;
using Microsoft.Azure.Devices.Shared;
using Newtonsoft.Json;
public class TwinTestConfiguration
{
[JsonProperty(PropertyName = "moduleId")]
public string ModuleId { get; set; }
[JsonProperty(PropertyName = "properties")]
public TwinProperties Properties { get; set; }
}
}