private async Task <JobProperties> CreateAndWaitForJobAsync(
            StorageAuthenticationType storageAuthenticationType,
            string devicesFileName,
            string configsFileName,
            RegistryManager registryManager,
            Uri containerUri,
            ManagedIdentity identity)
        {
            int           tryCount          = 0;
            JobProperties importJobResponse = null;

            JobProperties jobProperties = JobProperties.CreateForImportJob(
                containerUri.ToString(),
                containerUri.ToString(),
                devicesFileName,
                storageAuthenticationType,
                identity);

            jobProperties.ConfigurationsBlobName = configsFileName;
            jobProperties.IncludeConfigurations  = true;

            while (tryCount < MaxIterationWait)
            {
                try
                {
                    importJobResponse = await registryManager.ImportDevicesAsync(jobProperties).ConfigureAwait(false);

                    if (!string.IsNullOrWhiteSpace(importJobResponse.FailureReason))
                    {
                        Logger.Trace($"Job failed due to {importJobResponse.FailureReason}");
                    }
                    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;
                }
            }

            return(importJobResponse);
        }
        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}");
                }
            }
        }
示例#3
0
        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 { }
            }
        }
示例#4
0
        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);
            }
        }
        private async Task <JobProperties> CreateAndWaitForJobAsync(
            StorageAuthenticationType storageAuthenticationType,
            bool isUserAssignedMsi,
            string devicesFileName,
            string configsFileName,
            RegistryManager registryManager,
            Uri containerUri)
        {
            int tryCount = 0;

            ManagedIdentity identity = isUserAssignedMsi
                ? new ManagedIdentity
            {
                UserAssignedIdentity = TestConfiguration.IoTHub.UserAssignedMsiResourceId
            }
                : null;

            JobProperties exportJobResponse = JobProperties.CreateForExportJob(
                containerUri.ToString(),
                true,
                devicesFileName,
                storageAuthenticationType,
                identity);

            exportJobResponse.IncludeConfigurations  = true;
            exportJobResponse.ConfigurationsBlobName = configsFileName;

            while (tryCount < MaxIterationWait)
            {
                try
                {
                    exportJobResponse = await registryManager.ExportDevicesAsync(exportJobResponse).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;
                }
            }

            for (int i = 0; i < MaxIterationWait; ++i)
            {
                await Task.Delay(s_waitDuration).ConfigureAwait(false);

                exportJobResponse = await registryManager.GetJobAsync(exportJobResponse.JobId).ConfigureAwait(false);

                Logger.Trace($"Job {exportJobResponse.JobId} is {exportJobResponse.Status} with progress {exportJobResponse.Progress}%");
                if (!s_incompleteJobs.Contains(exportJobResponse.Status))
                {
                    break;
                }
            }

            exportJobResponse.Status.Should().Be(JobStatus.Completed, "Otherwise import failed");
            exportJobResponse.FailureReason.Should().BeNullOrEmpty("Otherwise import failed");

            return(exportJobResponse);
        }