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")]
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")]
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> twinTest = this.TwinTestFileName != null ? Option.Some(this.TwinTestFileName) : Option.None<string>();
string tag = this.ImageTag ?? "1.0";
var test = new Quickstart(
@ -213,6 +218,7 @@ Defaults:
this.NoVerify,
this.VerifyDataFromModule,
deployment,
twinTest,
this.DeviceCaCert,
this.DeviceCaPk,
this.DeviceCaCerts,

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

@ -27,13 +27,14 @@ namespace IotEdgeQuickstart
bool noVerify,
string verifyDataFromModule,
Option<string> deploymentFileName,
Option<string> twinTestFileName,
string deviceCaCert,
string deviceCaPk,
string deviceCaCerts,
bool optimizedForPerformance,
LogLevel runtimeLogLevel,
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.noDeployment = noDeployment;
@ -67,6 +68,7 @@ namespace IotEdgeQuickstart
if (!this.noVerify)
{
await this.VerifyDataOnIoTHub(this.verifyDataFromModule);
await this.VerifyTwinAsync();
}
if (this.leaveRunning == LeaveRunning.Core)

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

@ -4,6 +4,7 @@ namespace IotEdgeQuickstart.Details
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
@ -21,6 +22,8 @@ namespace IotEdgeQuickstart.Details
{
public readonly Option<string> DeploymentFileName;
public readonly Option<string> TwinTestFileName;
const string DeployJson = @"
{
""modulesContent"": {
@ -138,6 +141,7 @@ namespace IotEdgeQuickstart.Details
string deviceId,
string hostname,
Option<string> deploymentFileName,
Option<string> twinTestFileName,
string deviceCaCert,
string deviceCaPk,
string deviceCaCerts,
@ -172,6 +176,7 @@ namespace IotEdgeQuickstart.Details
this.deviceId = deviceId;
this.hostname = hostname;
this.DeploymentFileName = deploymentFileName;
this.TwinTestFileName = twinTestFileName;
this.deviceCaCert = deviceCaCert;
this.deviceCaPk = deviceCaPk;
this.deviceCaCerts = deviceCaCerts;
@ -334,6 +339,46 @@ namespace IotEdgeQuickstart.Details
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()
{
(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; }
}
}