public async Task RegistryManager_ImportDevices(StorageAuthenticationType storageAuthenticationType, bool isUserAssignedMsi) { // arrange const string idPrefix = nameof(RegistryManager_ImportDevices); string deviceId = $"{idPrefix}-device-{StorageContainer.GetRandomSuffix(4)}"; string configId = $"{idPrefix}-config-{StorageContainer.GetRandomSuffix(4)}".ToLower(); // Configuration Id characters must be all lower-case. Logger.Trace($"Using Ids {deviceId} and {configId}."); string devicesFileName = $"{idPrefix}-devices-{StorageContainer.GetRandomSuffix(4)}.txt"; string configsFileName = $"{idPrefix}-configs-{StorageContainer.GetRandomSuffix(4)}.txt"; using RegistryManager registryManager = RegistryManager.CreateFromConnectionString(TestConfiguration.IoTHub.ConnectionString); try { string containerName = StorageContainer.BuildContainerName(nameof(RegistryManager_ImportDevices)); using StorageContainer storageContainer = await StorageContainer.GetInstanceAsync(containerName).ConfigureAwait(false); Logger.Trace($"Using devices container {storageContainer.Uri}"); Uri containerUri = storageAuthenticationType == StorageAuthenticationType.KeyBased ? storageContainer.SasUri : storageContainer.Uri; using Stream devicesStream = ImportExportHelpers.BuildImportStream( new List <ExportImportDevice> { new ExportImportDevice( new Device(deviceId) { Authentication = new AuthenticationMechanism { Type = AuthenticationType.Sas } }, ImportMode.Create), }); await UploadFileAndConfirmAsync(storageContainer, devicesStream, devicesFileName).ConfigureAwait(false); using Stream configsStream = ImportExportHelpers.BuildImportStream( new List <ImportConfiguration> { new ImportConfiguration(configId) { ImportMode = ConfigurationImportMode.CreateOrUpdateIfMatchETag, Priority = 3, Labels = { { "labelName", "labelValue" } }, TargetCondition = "*", Content = { DeviceContent = { { "properties.desired.x", 5L } }, }, Metrics = { Queries = { { "successfullyConfigured", "select deviceId from devices where properties.reported.x = 5" } } }, }, }); await UploadFileAndConfirmAsync(storageContainer, configsStream, configsFileName).ConfigureAwait(false); ManagedIdentity identity = isUserAssignedMsi ? new ManagedIdentity { UserAssignedIdentity = TestConfiguration.IoTHub.UserAssignedMsiResourceId } : null; // act JobProperties importJobResponse = await CreateAndWaitForJobAsync( storageAuthenticationType, devicesFileName, configsFileName, registryManager, containerUri, identity) .ConfigureAwait(false); // assert importJobResponse.Status.Should().Be(JobStatus.Completed, "Otherwise import failed"); importJobResponse.FailureReason.Should().BeNullOrEmpty("Otherwise import failed"); // should not throw due to 404, but device may not immediately appear in registry Device device = null; Configuration config = null; for (int i = 0; i < MaxIterationWait; ++i) { await Task.Delay(s_waitDuration).ConfigureAwait(false); try { device = await registryManager.GetDeviceAsync(deviceId).ConfigureAwait(false); config = await registryManager.GetConfigurationAsync(configId).ConfigureAwait(false); break; } catch (Exception ex) { Logger.Trace($"Could not find device/config on iteration {i} due to [{ex.Message}]"); } } if (device == null) { Assert.Fail($"Device {deviceId} not found in registry manager"); } if (config == null) { Assert.Fail($"Config {configId} not found in registry manager"); } } finally { try { await registryManager.RemoveDeviceAsync(deviceId).ConfigureAwait(false); await registryManager.RemoveConfigurationAsync(configId).ConfigureAwait(false); } catch (Exception ex) { Logger.Trace($"Failed to clean up device/config due to {ex}"); } } }
public async Task RegistryManager_ImportDevices(StorageAuthenticationType storageAuthenticationType) { // arrange StorageContainer storageContainer = null; string deviceId = $"{nameof(RegistryManager_ImportDevices)}-{StorageContainer.GetRandomSuffix(4)}"; var registryManager = RegistryManager.CreateFromConnectionString(Configuration.IoTHub.ConnectionString); Logger.Trace($"Using deviceId {deviceId}"); try { string containerName = StorageContainer.BuildContainerName(nameof(RegistryManager_ImportDevices)); storageContainer = await StorageContainer .GetInstanceAsync(containerName) .ConfigureAwait(false); Logger.Trace($"Using container {storageContainer.Uri}"); Uri containerUri = storageAuthenticationType == StorageAuthenticationType.KeyBased ? storageContainer.SasUri : storageContainer.Uri; Stream devicesFile = ImportExportDevicesHelpers.BuildDevicesStream( new List <ExportImportDevice> { new ExportImportDevice( new Device(deviceId) { Authentication = new AuthenticationMechanism { Type = AuthenticationType.Sas } }, ImportMode.Create), }); await UploadFileAndConfirmAsync(storageContainer, devicesFile).ConfigureAwait(false); // act JobProperties importJobResponse = null; int tryCount = 0; while (true) { try { importJobResponse = await registryManager .ImportDevicesAsync( JobProperties.CreateForImportJob( containerUri.ToString(), containerUri.ToString(), null, storageAuthenticationType)) .ConfigureAwait(false); break; } // Concurrent jobs can be rejected, so implement a retry mechanism to handle conflicts with other tests catch (JobQuotaExceededException) when(++tryCount < MaxIterationWait) { Logger.Trace($"JobQuotaExceededException... waiting."); await Task.Delay(s_waitDuration).ConfigureAwait(false); continue; } } // wait for job to complete for (int i = 0; i < MaxIterationWait; ++i) { await Task.Delay(1000).ConfigureAwait(false); importJobResponse = await registryManager.GetJobAsync(importJobResponse.JobId).ConfigureAwait(false); Logger.Trace($"Job {importJobResponse.JobId} is {importJobResponse.Status} with progress {importJobResponse.Progress}%"); if (!s_incompleteJobs.Contains(importJobResponse.Status)) { break; } } // assert importJobResponse.Status.Should().Be(JobStatus.Completed, "Otherwise import failed"); importJobResponse.FailureReason.Should().BeNullOrEmpty("Otherwise import failed"); // should not throw due to 404, but device may not immediately appear in registry Device device = null; for (int i = 0; i < MaxIterationWait; ++i) { await Task.Delay(s_waitDuration).ConfigureAwait(false); try { device = await registryManager.GetDeviceAsync(deviceId).ConfigureAwait(false); break; } catch (Exception ex) { Logger.Trace($"Could not find device on iteration {i} due to [{ex.Message}]"); } } if (device == null) { Assert.Fail($"Device {deviceId} not found in registry manager"); } } finally { try { storageContainer?.Dispose(); await registryManager.RemoveDeviceAsync(deviceId).ConfigureAwait(false); } catch { } } }
public async Task RegistryManager_ImportDevices() { StorageContainer storageContainer = null; string deviceId = $"{nameof(RegistryManager_ImportDevices)}-{StorageContainer.GetRandomSuffix(4)}"; var registryManager = RegistryManager.CreateFromConnectionString(Configuration.IoTHub.ConnectionString); _log.WriteLine($"Using deviceId {deviceId}"); try { // arrange string containerName = StorageContainer.BuildContainerName(nameof(RegistryManager_ImportDevices)); storageContainer = await StorageContainer .GetInstanceAsync(containerName) .ConfigureAwait(false); _log.WriteLine($"Using container {storageContainer.Uri}"); Stream devicesFile = ImportExportDevicesHelpers.BuildDevicesStream( new List <ExportImportDevice> { new ExportImportDevice( new Device(deviceId) { Authentication = new AuthenticationMechanism { Type = AuthenticationType.Sas } }, ImportMode.Create), }); BlobClient blobClient = storageContainer.BlobContainerClient.GetBlobClient(ImportFileNameDefault); Response <BlobContentInfo> uploadBlobResponse = await blobClient.UploadAsync(devicesFile).ConfigureAwait(false); // wait for copy completion bool foundBlob = false; for (int i = 0; i < MaxIterationWait; ++i) { await Task.Delay(s_waitDuration).ConfigureAwait(false); if (await blobClient.ExistsAsync().ConfigureAwait(false)) { foundBlob = true; break; } } foundBlob.Should().BeTrue($"Failed to find {ImportFileNameDefault} in storage container, required for test."); // act JobProperties importJobResponse = null; for (int i = 0; i < MaxIterationWait; ++i) { try { importJobResponse = await registryManager .ImportDevicesAsync(storageContainer.SasUri.ToString(), storageContainer.SasUri.ToString()) .ConfigureAwait(false); break; } // Concurrent jobs can be rejected, so implement a retry mechanism to handle conflicts with other tests catch (JobQuotaExceededException) { _log.WriteLine($"JobQuoteExceededException... waiting."); await Task.Delay(s_waitDuration).ConfigureAwait(false); continue; } } // wait for job to complete while (s_incompleteJobs.Contains(importJobResponse.Status)) { await Task.Delay(1000).ConfigureAwait(false); importJobResponse = await registryManager.GetJobAsync(importJobResponse.JobId).ConfigureAwait(false); } // assert importJobResponse.Status.Should().Be(JobStatus.Completed, "Otherwise import failed"); importJobResponse.FailureReason.Should().BeNullOrEmpty("Otherwise import failed"); // should not throw due to 404, but device may not appear immediately in registry Device device = null; for (int i = 0; i < MaxIterationWait; ++i) { await Task.Delay(s_waitDuration).ConfigureAwait(false); try { device = await registryManager.GetDeviceAsync(deviceId).ConfigureAwait(false); break; } catch (Exception ex) { _log.WriteLine($"Could not find device on iteration {i} due to [{ex.Message}]"); } } if (device == null) { Assert.Fail($"Device {deviceId} not found in registry manager"); } } finally { try { storageContainer?.Dispose(); await registryManager.RemoveDeviceAsync(deviceId).ConfigureAwait(false); } catch { } } }
public async Task RegistryManager_ExportDevices(StorageAuthenticationType storageAuthenticationType) { // arrange StorageContainer storageContainer = null; string deviceId = $"{nameof(RegistryManager_ExportDevices)}-{StorageContainer.GetRandomSuffix(4)}"; var registryManager = RegistryManager.CreateFromConnectionString(Configuration.IoTHub.ConnectionString); _log.WriteLine($"Using deviceId {deviceId}"); try { string containerName = StorageContainer.BuildContainerName(nameof(RegistryManager_ExportDevices)); storageContainer = await StorageContainer .GetInstanceAsync(containerName) .ConfigureAwait(false); _log.WriteLine($"Using container {storageContainer.Uri}"); Uri containerUri = storageAuthenticationType == StorageAuthenticationType.KeyBased ? storageContainer.SasUri : storageContainer.Uri; await registryManager .AddDeviceAsync( new Device(deviceId) { Authentication = new AuthenticationMechanism { Type = AuthenticationType.Sas }, }) .ConfigureAwait(false); // act JobProperties exportJobResponse = null; int tryCount = 0; while (true) { try { exportJobResponse = await registryManager .ExportDevicesAsync( JobProperties.CreateForExportJob( containerUri.ToString(), true, null, storageAuthenticationType)) .ConfigureAwait(false); break; } // Concurrent jobs can be rejected, so implement a retry mechanism to handle conflicts with other tests catch (JobQuotaExceededException) when(++tryCount < MaxIterationWait) { _log.WriteLine($"JobQuotaExceededException... waiting."); await Task.Delay(s_waitDuration).ConfigureAwait(false); continue; } } // wait for job to complete for (int i = 0; i < MaxIterationWait; ++i) { await Task.Delay(s_waitDuration).ConfigureAwait(false); exportJobResponse = await registryManager.GetJobAsync(exportJobResponse.JobId).ConfigureAwait(false); _log.WriteLine($"Job {exportJobResponse.JobId} is {exportJobResponse.Status} with progress {exportJobResponse.Progress}%"); if (!s_incompleteJobs.Contains(exportJobResponse.Status)) { break; } } // assert exportJobResponse.Status.Should().Be(JobStatus.Completed, "Otherwise import failed"); exportJobResponse.FailureReason.Should().BeNullOrEmpty("Otherwise import failed"); string content = await DownloadFileAsync(storageContainer).ConfigureAwait(false); string[] serializedDevices = content.Split(s_newlines, StringSplitOptions.RemoveEmptyEntries); bool foundDeviceInExport = false; foreach (string serializedDeivce in serializedDevices) { // The first line may be a comment to the user, so skip any lines that don't start with a json object initial character: curly brace if (serializedDeivce[0] != '{') { continue; } ExportImportDevice device = JsonConvert.DeserializeObject <ExportImportDevice>(serializedDeivce); if (StringComparer.Ordinal.Equals(device.Id, deviceId)) { _log.WriteLine($"Found device in export as [{serializedDeivce}]"); foundDeviceInExport = true; break; } } foundDeviceInExport.Should().BeTrue("Expected device did not appear in the export"); } finally { try { storageContainer?.Dispose(); await registryManager.RemoveDeviceAsync(deviceId).ConfigureAwait(false); } catch { } } }
public async Task RegistryManager_ExportDevices(StorageAuthenticationType storageAuthenticationType, bool isUserAssignedMsi) { // arrange const string idPrefix = nameof(RegistryManager_ExportDevices); string edgeId1 = $"{idPrefix}-Edge-{StorageContainer.GetRandomSuffix(4)}"; string edgeId2 = $"{idPrefix}-Edge-{StorageContainer.GetRandomSuffix(4)}"; string deviceId = $"{idPrefix}-{StorageContainer.GetRandomSuffix(4)}"; string configurationId = (idPrefix + Guid.NewGuid()).ToLower(); // Configuration Id characters must be all lower-case. Logger.Trace($"Using Ids {deviceId}, {edgeId1}, {edgeId2}, and {configurationId}"); string devicesFileName = $"{idPrefix}-devicesexport-{StorageContainer.GetRandomSuffix(4)}.txt"; string configsFileName = $"{idPrefix}-configsexport-{StorageContainer.GetRandomSuffix(4)}.txt"; using RegistryManager registryManager = RegistryManager.CreateFromConnectionString(TestConfiguration.IoTHub.ConnectionString); try { string containerName = StorageContainer.BuildContainerName(idPrefix); using StorageContainer storageContainer = await StorageContainer .GetInstanceAsync(containerName) .ConfigureAwait(false); Logger.Trace($"Using container {storageContainer.Uri}"); Uri containerUri = storageAuthenticationType == StorageAuthenticationType.KeyBased ? storageContainer.SasUri : storageContainer.Uri; Device edge1 = await registryManager .AddDeviceAsync( new Device(edgeId1) { Authentication = new AuthenticationMechanism { Type = AuthenticationType.Sas }, Capabilities = new Shared.DeviceCapabilities { IotEdge = true }, }) .ConfigureAwait(false); Device edge2 = await registryManager .AddDeviceAsync( new Device(edgeId2) { Authentication = new AuthenticationMechanism { Type = AuthenticationType.Sas }, Capabilities = new Shared.DeviceCapabilities { IotEdge = true }, ParentScopes = { edge1.Scope }, }) .ConfigureAwait(false); Device device = await registryManager .AddDeviceAsync( new Device(deviceId) { Authentication = new AuthenticationMechanism { Type = AuthenticationType.Sas }, Scope = edge1.Scope, }) .ConfigureAwait(false); Configuration configuration = await registryManager .AddConfigurationAsync( new Configuration(configurationId) { Priority = 2, Labels = { { "labelName", "labelValue" } }, TargetCondition = "*", Content = { DeviceContent = { { "properties.desired.x", 4L } }, }, Metrics = { Queries = { { "successfullyConfigured", "select deviceId from devices where properties.reported.x = 4" } } }, }) .ConfigureAwait(false); // act JobProperties exportJobResponse = await CreateAndWaitForJobAsync( storageAuthenticationType, isUserAssignedMsi, devicesFileName, configsFileName, registryManager, containerUri) .ConfigureAwait(false); // assert await ValidateDevicesAsync( devicesFileName, storageContainer, edge1, edge2, device) .ConfigureAwait(false); await ValidateConfigurationsAsync( configsFileName, storageContainer, configuration) .ConfigureAwait(false); } finally { await CleanUpDevicesAsync(edgeId1, edgeId2, deviceId, configurationId, registryManager).ConfigureAwait(false); } }