Skip to content

Commit e448537

Browse files
authored
Add support for snaps to the end-to-end tests (Azure#7178)
This change gets the end-to-end tests passing from the local command line. There's more work to do to get it working in our pipelines (e.g., we need to build snaps in the CI build pipeline).
1 parent 7693684 commit e448537

39 files changed

+693
-498
lines changed

test/Microsoft.Azure.Devices.Edge.Test.Common/DaemonConfiguration.cs

Lines changed: 68 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -13,43 +13,40 @@ namespace Microsoft.Azure.Devices.Edge.Test.Common
1313

1414
public class DaemonConfiguration
1515
{
16-
struct Config
17-
{
18-
public string ConfigPath;
19-
public TomlDocument Document;
20-
}
21-
2216
const string GlobalEndPoint = "https://global.azure-devices-provisioning.net";
23-
Config config;
17+
TomlDocument document;
18+
string path;
2419

2520
public DaemonConfiguration(string superTomlPath)
2621
{
2722
Directory.CreateDirectory(Directory.GetParent(superTomlPath).FullName);
2823
string contents = File.Exists(superTomlPath) ? File.ReadAllText(superTomlPath) : string.Empty;
29-
this.config = new Config
30-
{
31-
ConfigPath = superTomlPath,
32-
Document = new TomlDocument(contents)
33-
};
24+
this.document = new TomlDocument(contents);
25+
this.path = superTomlPath;
3426
}
3527

3628
public void AddHttpsProxy(Uri proxy)
3729
{
38-
this.config.Document.ReplaceOrAdd("agent.env.https_proxy", proxy.ToString());
30+
this.document.ReplaceOrAdd("agent.env.https_proxy", proxy.ToString());
3931
// The config file is configured during test suite initialization, before we know which
4032
// protocol a given test will use. Always use AmqpWs, and when each test deploys a
4133
// configuration, it can update the config to use whatever it wants.
42-
this.config.Document.ReplaceOrAdd("agent.env.UpstreamProtocol", "AmqpWs");
34+
this.document.ReplaceOrAdd("agent.env.UpstreamProtocol", "AmqpWs");
35+
}
36+
37+
public void AddAgentUserId(string uid)
38+
{
39+
this.document.ReplaceOrAdd("agent.env.EDGEAGENTUSER_ID", uid);
4340
}
4441

4542
void SetBasicDpsParam(string idScope)
4643
{
47-
this.config.Document.ReplaceOrAdd("auto_reprovisioning_mode", "AlwaysOnStartup");
44+
this.document.ReplaceOrAdd("auto_reprovisioning_mode", "AlwaysOnStartup");
4845

49-
this.config.Document.RemoveIfExists("provisioning");
50-
this.config.Document.ReplaceOrAdd("provisioning.source", "dps");
51-
this.config.Document.ReplaceOrAdd("provisioning.global_endpoint", GlobalEndPoint);
52-
this.config.Document.ReplaceOrAdd("provisioning.id_scope", idScope);
46+
this.document.RemoveIfExists("provisioning");
47+
this.document.ReplaceOrAdd("provisioning.source", "dps");
48+
this.document.ReplaceOrAdd("provisioning.global_endpoint", GlobalEndPoint);
49+
this.document.ReplaceOrAdd("provisioning.id_scope", idScope);
5350
}
5451

5552
public void SetManualSasProvisioning(
@@ -58,24 +55,24 @@ public void SetManualSasProvisioning(
5855
string deviceId,
5956
string key)
6057
{
61-
this.config.Document.ReplaceOrAdd("auto_reprovisioning_mode", "AlwaysOnStartup");
58+
this.document.ReplaceOrAdd("auto_reprovisioning_mode", "AlwaysOnStartup");
6259
parentHostname.ForEach(parent_hostame => this.SetParentHostname(parent_hostame));
6360

64-
this.config.Document.RemoveIfExists("provisioning");
65-
this.config.Document.ReplaceOrAdd("provisioning.source", "manual");
66-
this.config.Document.ReplaceOrAdd("provisioning.iothub_hostname", hubHostname);
67-
this.config.Document.ReplaceOrAdd("provisioning.device_id", deviceId);
68-
this.config.Document.ReplaceOrAdd("provisioning.authentication.method", "sas");
69-
this.config.Document.ReplaceOrAdd("provisioning.authentication.device_id_pk.value", key);
61+
this.document.RemoveIfExists("provisioning");
62+
this.document.ReplaceOrAdd("provisioning.source", "manual");
63+
this.document.ReplaceOrAdd("provisioning.iothub_hostname", hubHostname);
64+
this.document.ReplaceOrAdd("provisioning.device_id", deviceId);
65+
this.document.ReplaceOrAdd("provisioning.authentication.method", "sas");
66+
this.document.ReplaceOrAdd("provisioning.authentication.device_id_pk.value", key);
7067
}
7168

7269
public void SetImageGarbageCollection(int minutesUntilCleanup)
7370
{
74-
this.config.Document.ReplaceOrAdd("image_garbage_collection.enabled", true);
75-
this.config.Document.ReplaceOrAdd("image_garbage_collection.cleanup_recurrence", "1d");
76-
this.config.Document.ReplaceOrAdd("image_garbage_collection.image_age_cleanup_threshold", "10s");
71+
this.document.ReplaceOrAdd("image_garbage_collection.enabled", true);
72+
this.document.ReplaceOrAdd("image_garbage_collection.cleanup_recurrence", "1d");
73+
this.document.ReplaceOrAdd("image_garbage_collection.image_age_cleanup_threshold", "10s");
7774
string cleanupTime = DateTime.Now.Add(new TimeSpan(0, 0, minutesUntilCleanup, 0)).ToString("HH:mm");
78-
this.config.Document.ReplaceOrAdd("image_garbage_collection.cleanup_time", cleanupTime);
75+
this.document.ReplaceOrAdd("image_garbage_collection.cleanup_time", cleanupTime);
7976
}
8077

8178
public void SetDeviceManualX509(
@@ -95,24 +92,24 @@ public void SetDeviceManualX509(
9592
throw new InvalidOperationException($"{identityPkPath} does not exist");
9693
}
9794

98-
this.config.Document.ReplaceOrAdd("auto_reprovisioning_mode", "AlwaysOnStartup");
95+
this.document.ReplaceOrAdd("auto_reprovisioning_mode", "AlwaysOnStartup");
9996
parentHostname.ForEach(parent_hostame => this.SetParentHostname(parent_hostame));
10097

101-
this.config.Document.RemoveIfExists("provisioning");
102-
this.config.Document.ReplaceOrAdd("provisioning.source", "manual");
103-
this.config.Document.ReplaceOrAdd("provisioning.iothub_hostname", hubhostname);
104-
this.config.Document.ReplaceOrAdd("provisioning.device_id", deviceId);
105-
this.config.Document.ReplaceOrAdd("provisioning.authentication.method", "x509");
106-
this.config.Document.ReplaceOrAdd("provisioning.authentication.identity_cert", "file://" + identityCertPath);
107-
this.config.Document.ReplaceOrAdd("provisioning.authentication.identity_pk", "file://" + identityPkPath);
98+
this.document.RemoveIfExists("provisioning");
99+
this.document.ReplaceOrAdd("provisioning.source", "manual");
100+
this.document.ReplaceOrAdd("provisioning.iothub_hostname", hubhostname);
101+
this.document.ReplaceOrAdd("provisioning.device_id", deviceId);
102+
this.document.ReplaceOrAdd("provisioning.authentication.method", "x509");
103+
this.document.ReplaceOrAdd("provisioning.authentication.identity_cert", "file://" + identityCertPath);
104+
this.document.ReplaceOrAdd("provisioning.authentication.identity_pk", "file://" + identityPkPath);
108105
}
109106

110107
public void SetDpsSymmetricKey(string idScope, string registrationId, string deviceKey)
111108
{
112109
this.SetBasicDpsParam(idScope);
113-
this.config.Document.ReplaceOrAdd("provisioning.attestation.method", "symmetric_key");
114-
this.config.Document.ReplaceOrAdd("provisioning.attestation.registration_id", registrationId);
115-
this.config.Document.ReplaceOrAdd("provisioning.attestation.symmetric_key.value", deviceKey);
110+
this.document.ReplaceOrAdd("provisioning.attestation.method", "symmetric_key");
111+
this.document.ReplaceOrAdd("provisioning.attestation.registration_id", registrationId);
112+
this.document.ReplaceOrAdd("provisioning.attestation.symmetric_key.value", deviceKey);
116113
}
117114

118115
public void SetDpsX509(string idScope, string identityCertPath, string identityPkPath)
@@ -128,16 +125,16 @@ public void SetDpsX509(string idScope, string identityCertPath, string identityP
128125
}
129126

130127
this.SetBasicDpsParam(idScope);
131-
this.config.Document.ReplaceOrAdd("provisioning.attestation.method", "x509");
132-
this.config.Document.ReplaceOrAdd("provisioning.attestation.identity_cert", "file://" + identityCertPath);
133-
this.config.Document.ReplaceOrAdd("provisioning.attestation.identity_pk", "file://" + identityPkPath);
128+
this.document.ReplaceOrAdd("provisioning.attestation.method", "x509");
129+
this.document.ReplaceOrAdd("provisioning.attestation.identity_cert", "file://" + identityCertPath);
130+
this.document.ReplaceOrAdd("provisioning.attestation.identity_pk", "file://" + identityPkPath);
134131
}
135132

136133
public void SetEdgeAgentImage(string value, IEnumerable<Registry> registries)
137134
{
138-
this.config.Document.ReplaceOrAdd("agent.name", "edgeAgent");
139-
this.config.Document.ReplaceOrAdd("agent.type", "docker");
140-
this.config.Document.ReplaceOrAdd("agent.config.image", value);
135+
this.document.ReplaceOrAdd("agent.name", "edgeAgent");
136+
this.document.ReplaceOrAdd("agent.type", "docker");
137+
this.document.ReplaceOrAdd("agent.config.image", value);
141138

142139
// Currently, the only place for registries is [agent.config.auth]
143140
// So only one registry is supported.
@@ -148,60 +145,55 @@ public void SetEdgeAgentImage(string value, IEnumerable<Registry> registries)
148145

149146
foreach (Registry registry in registries)
150147
{
151-
this.config.Document.ReplaceOrAdd("agent.config.auth.serveraddress", registry.Address);
152-
this.config.Document.ReplaceOrAdd("agent.config.auth.username", registry.Username);
153-
this.config.Document.ReplaceOrAdd("agent.config.auth.password", registry.Password);
148+
this.document.ReplaceOrAdd("agent.config.auth.serveraddress", registry.Address);
149+
this.document.ReplaceOrAdd("agent.config.auth.username", registry.Username);
150+
this.document.ReplaceOrAdd("agent.config.auth.password", registry.Password);
154151
}
155152
}
156153

157154
public void SetDeviceHostname(string value)
158155
{
159-
this.config.Document.ReplaceOrAdd("hostname", value);
156+
this.document.ReplaceOrAdd("hostname", value);
157+
}
158+
159+
public void SetDeviceHomedir(string value)
160+
{
161+
this.document.ReplaceOrAdd("homedir", value);
160162
}
161163

162164
public void SetParentHostname(string value)
163165
{
164-
this.config.Document.ReplaceOrAdd("parent_hostname", value);
166+
this.document.ReplaceOrAdd("parent_hostname", value);
167+
}
168+
169+
public void SetMobyRuntimeUri(string value)
170+
{
171+
this.document.ReplaceOrAdd("moby_runtime.uri", value);
172+
this.document.ReplaceOrAdd("moby_runtime.network", "azure-iot-edge");
165173
}
166174

167175
public void SetConnectSockets(string workloadUri, string managementUri)
168176
{
169-
this.config.Document.ReplaceOrAdd("connect.workload_uri", workloadUri);
170-
this.config.Document.ReplaceOrAdd("connect.management_uri", managementUri);
177+
this.document.ReplaceOrAdd("connect.workload_uri", workloadUri);
178+
this.document.ReplaceOrAdd("connect.management_uri", managementUri);
171179
}
172180

173181
public void SetListenSockets(string workloadUri, string managementUri)
174182
{
175-
this.config.Document.ReplaceOrAdd("listen.workload_uri", workloadUri);
176-
this.config.Document.ReplaceOrAdd("listen.management_uri", managementUri);
183+
this.document.ReplaceOrAdd("listen.workload_uri", workloadUri);
184+
this.document.ReplaceOrAdd("listen.management_uri", managementUri);
177185
}
178186

179187
public void SetCertificates(CaCertificates certs)
180188
{
181-
if (!File.Exists(certs.CertificatePath))
182-
{
183-
throw new InvalidOperationException($"{certs.CertificatePath} does not exist");
184-
}
185-
186-
if (!File.Exists(certs.KeyPath))
187-
{
188-
throw new InvalidOperationException($"{certs.KeyPath} does not exist");
189-
}
190-
191-
if (!File.Exists(certs.TrustedCertificatesPath))
192-
{
193-
throw new InvalidOperationException($"{certs.TrustedCertificatesPath} does not exist");
194-
}
195-
196-
this.config.Document.ReplaceOrAdd("edge_ca.cert", "file://" + certs.CertificatePath);
197-
this.config.Document.ReplaceOrAdd("edge_ca.pk", "file://" + certs.KeyPath);
198-
this.config.Document.ReplaceOrAdd("trust_bundle_cert", "file://" + certs.TrustedCertificatesPath);
189+
this.document.ReplaceOrAdd("edge_ca.cert", "file://" + certs.CertificatePath);
190+
this.document.ReplaceOrAdd("edge_ca.pk", "file://" + certs.KeyPath);
191+
this.document.ReplaceOrAdd("trust_bundle_cert", "file://" + certs.TrustedCertificatesPath);
199192
}
200193

201194
public async Task UpdateAsync(CancellationToken token)
202195
{
203-
await File.WriteAllTextAsync(this.config.ConfigPath, this.config.Document.ToString());
204-
// Serilog.Log.Information(await File.ReadAllTextAsync(path));
196+
await File.WriteAllTextAsync(this.path, this.document.ToString());
205197
}
206198
}
207199
}

test/Microsoft.Azure.Devices.Edge.Test.Common/EdgeLogs.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,20 +13,20 @@ public static class EdgeLogs
1313
{
1414
// Make an effort to collect logs, but swallow any exceptions to prevent tests/fixtures
1515
// from failing if this function fails.
16-
public static async Task<IEnumerable<string>> CollectAsync(DateTime testStartTime, string filePrefix, CancellationToken token)
16+
public static async Task<IEnumerable<string>> CollectAsync(DateTime testStartTime, string filePrefix, IotedgeCli cli, CancellationToken token)
1717
{
1818
var paths = new List<string>();
1919

2020
// Save module logs
2121
try
2222
{
23-
string[] output = await Process.RunAsync("iotedge", "list", token);
23+
string[] output = await cli.RunAsync("list", token);
2424
string[] modules = output.Select(ln => ln.Split(null as char[], StringSplitOptions.RemoveEmptyEntries).First()).Skip(1).ToArray();
2525

2626
foreach (string name in modules)
2727
{
2828
string moduleLog = $"{filePrefix}-{name}.log";
29-
output = await Process.RunAsync("iotedge", $"logs {name}", token, logVerbose: false);
29+
output = await cli.RunAsync($"logs {name}", token, logVerbose: false);
3030
await File.WriteAllLinesAsync(moduleLog, output, token);
3131
paths.Add(moduleLog);
3232
}

test/Microsoft.Azure.Devices.Edge.Test.Common/EdgeModule.cs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ namespace Microsoft.Azure.Devices.Edge.Test.Common
1212
using Microsoft.Azure.Devices.Shared;
1313
using Newtonsoft.Json;
1414
using Newtonsoft.Json.Linq;
15-
using Newtonsoft.Json.Serialization;
1615
using Serilog;
1716

1817
public enum EdgeModuleStatus
@@ -35,7 +34,7 @@ public EdgeModule(string id, string deviceId, IotHub iotHub)
3534
this.iotHub = iotHub;
3635
}
3736

38-
public static Task WaitForStatusAsync(IEnumerable<EdgeModule> modules, EdgeModuleStatus desired, CancellationToken token)
37+
public static Task WaitForStatusAsync(IEnumerable<EdgeModule> modules, EdgeModuleStatus desired, IotedgeCli cli, CancellationToken token)
3938
{
4039
string[] moduleIds = modules.Select(m => m.Id.TrimStart('$')).Distinct().ToArray();
4140

@@ -46,7 +45,7 @@ async Task WaitForStatusAsync()
4645
await Retry.Do(
4746
async () =>
4847
{
49-
string[] output = await Process.RunAsync("iotedge", "list", token);
48+
string[] output = await cli.RunAsync("list", token);
5049

5150
return output
5251
.Where(
@@ -90,8 +89,8 @@ static bool DaemonNotReady(string details) =>
9089
desired.ToString().ToLower());
9190
}
9291

93-
public Task WaitForStatusAsync(EdgeModuleStatus desired, CancellationToken token) =>
94-
WaitForStatusAsync(new[] { this }, desired, token);
92+
public Task WaitForStatusAsync(EdgeModuleStatus desired, IotedgeCli cli, CancellationToken token) =>
93+
WaitForStatusAsync(new[] { this }, desired, cli, token);
9594

9695
public Task<string> WaitForEventsReceivedAsync(
9796
DateTime seekTime,

test/Microsoft.Azure.Devices.Edge.Test.Common/EdgeRuntime.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ public EdgeRuntime(string deviceId, Option<string> agentImage, Option<string> hu
4040
// receive it and start up all the modules.
4141
public async Task<EdgeDeployment> DeployConfigurationAsync(
4242
Action<EdgeConfigBuilder> addConfig,
43+
IotedgeCli cli,
4344
CancellationToken token,
4445
bool nestedEdge)
4546
{
@@ -78,12 +79,12 @@ public async Task<EdgeDeployment> DeployConfigurationAsync(
7879
EdgeModule[] modules = edgeConfiguration.ModuleNames
7980
.Select(id => new EdgeModule(id, this.DeviceId, this.iotHub))
8081
.ToArray();
81-
await EdgeModule.WaitForStatusAsync(modules, EdgeModuleStatus.Running, token);
82+
await EdgeModule.WaitForStatusAsync(modules, EdgeModuleStatus.Running, cli, token);
8283
await edgeConfiguration.VerifyAsync(this.iotHub, token);
8384
return new EdgeDeployment(deployTime, modules);
8485
}
8586

86-
public Task<EdgeDeployment> DeployConfigurationAsync(CancellationToken token, bool nestedEdge) =>
87-
this.DeployConfigurationAsync(_ => { }, token, nestedEdge);
87+
public Task<EdgeDeployment> DeployConfigurationAsync(IotedgeCli cli, CancellationToken token, bool nestedEdge) =>
88+
this.DeployConfigurationAsync(_ => { }, cli, token, nestedEdge);
8889
}
8990
}

test/Microsoft.Azure.Devices.Edge.Test.Common/IEdgeDaemon.cs

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,29 +2,27 @@
22
namespace Microsoft.Azure.Devices.Edge.Test.Common
33
{
44
using System;
5-
using System.ServiceProcess;
65
using System.Threading;
76
using System.Threading.Tasks;
87
using Microsoft.Azure.Devices.Edge.Util;
98

10-
public enum EdgeDaemonStatus
11-
{
12-
Running = ServiceControllerStatus.Running,
13-
Stopped = ServiceControllerStatus.Stopped
14-
}
15-
169
public interface IEdgeDaemon
1710
{
18-
Task InstallAsync(Option<string> packagesPath, Option<Uri> proxy, CancellationToken token);
11+
Task InstallAsync(Option<Uri> proxy, CancellationToken token);
1912

20-
Task ConfigureAsync(Func<DaemonConfiguration, Task<(string message, object[] properties)>> config, CancellationToken token, bool restart = true);
13+
Task ConfigureAsync(
14+
Func<DaemonConfiguration, Task<(string message, object[] properties)>> config,
15+
CancellationToken token,
16+
bool restart = true);
2117

2218
Task StartAsync(CancellationToken token);
2319

2420
Task StopAsync(CancellationToken token);
2521

2622
Task UninstallAsync(CancellationToken token);
2723

28-
Task WaitForStatusAsync(EdgeDaemonStatus desired, CancellationToken token);
24+
string GetCertificatesPath();
25+
26+
IotedgeCli GetCli();
2927
}
3028
}

0 commit comments

Comments
 (0)