public async Task DeviceClient_TokenConnectionDoubleRelease_Ok()
        {
            TestDevice testDevice = await TestDevice.GetTestDeviceAsync(DevicePrefix).ConfigureAwait(false);

            string deviceConnectionString = testDevice.ConnectionString;

            var    config   = new Configuration.IoTHub.DeviceConnectionStringParser(deviceConnectionString);
            string iotHub   = config.IoTHub;
            string deviceId = config.DeviceID;
            string key      = config.SharedAccessKey;

            SharedAccessSignatureBuilder builder = new SharedAccessSignatureBuilder()
            {
                Key        = key,
                TimeToLive = new TimeSpan(0, 10, 0),
                Target     = $"{iotHub}/devices/{WebUtility.UrlEncode(deviceId)}",
            };

            DeviceAuthenticationWithToken auth = new DeviceAuthenticationWithToken(deviceId, builder.ToSignature());

            using (DeviceClient deviceClient = DeviceClient.Create(iotHub, auth, Client.TransportType.Amqp_Tcp_Only))
            {
                _log.WriteLine($"Created {nameof(DeviceClient)} ID={TestLogging.IdOf(deviceClient)}");

                Console.WriteLine("DeviceClient OpenAsync.");
                await deviceClient.OpenAsync().ConfigureAwait(false);

                Console.WriteLine("DeviceClient SendEventAsync.");
                await deviceClient.SendEventAsync(new Client.Message(Encoding.UTF8.GetBytes("TestMessage"))).ConfigureAwait(false);

                Console.WriteLine("DeviceClient CloseAsync.");
                await deviceClient.CloseAsync().ConfigureAwait(false);   // First release
            } // Second release
        }
Esempio n. 2
0
        private async Task ModuleClient_Gives_ConnectionStatus_DeviceDisabled_Base(
            Client.TransportType protocol, Func <RegistryManager, string, Task> registryManagerOperation)
        {
            AmqpTransportSettings amqpTransportSettings = new AmqpTransportSettings(protocol);

            ITransportSettings[] transportSettings = new ITransportSettings[] { amqpTransportSettings };

            TestModule testModule = await TestModule.GetTestModuleAsync(DevicePrefix + $"_{Guid.NewGuid()}", ModulePrefix).ConfigureAwait(false);

            ConnectionStatus?            status             = null;
            ConnectionStatusChangeReason?statusChangeReason = null;
            int deviceDisabledReceivedCount = 0;
            ConnectionStatusChangesHandler statusChangeHandler = (s, r) =>
            {
                if (r == ConnectionStatusChangeReason.Device_Disabled)
                {
                    status             = s;
                    statusChangeReason = r;
                    deviceDisabledReceivedCount++;
                }
            };

            using (ModuleClient moduleClient = ModuleClient.CreateFromConnectionString(testModule.ConnectionString, transportSettings))
            {
                moduleClient.SetConnectionStatusChangesHandler(statusChangeHandler);
                _log.WriteLine($"Created {nameof(DeviceClient)} ID={TestLogging.IdOf(moduleClient)}");

                Console.WriteLine("ModuleClient OpenAsync.");
                await moduleClient.OpenAsync().ConfigureAwait(false);

                // Receiving the module twin should succeed right now.
                Console.WriteLine("ModuleClient GetTwinAsync.");
                var twin = await moduleClient.GetTwinAsync().ConfigureAwait(false);

                Assert.IsNotNull(twin);

                // Delete/disable the device in IoT Hub.
                using (RegistryManager registryManager = RegistryManager.CreateFromConnectionString(Configuration.IoTHub.ConnectionString))
                {
                    await registryManagerOperation(registryManager, testModule.DeviceId).ConfigureAwait(false);
                }

                // Artificial sleep waiting for the connection status change handler to get triggered.
                int sleepCount = 50;
                for (int i = 0; i < sleepCount; i++)
                {
                    await Task.Delay(TimeSpan.FromSeconds(10)).ConfigureAwait(false);

                    if (deviceDisabledReceivedCount == 1)
                    {
                        break;
                    }
                }

                Assert.AreEqual(1, deviceDisabledReceivedCount);
                Assert.AreEqual(ConnectionStatus.Disconnected, status);
                Assert.AreEqual(ConnectionStatusChangeReason.Device_Disabled, statusChangeReason);
            }
        }
        private async Task DeviceClient_TokenIsRefreshed_Internal(Client.TransportType transport, int ttl = 20)
        {
            TestDevice testDevice = await TestDevice.GetTestDeviceAsync(DevicePrefix).ConfigureAwait(false);

            int           buffer             = 50;
            Device        device             = testDevice.Identity;
            SemaphoreSlim deviceDisconnected = new SemaphoreSlim(0);

            var refresher = new TestTokenRefresher(
                device.Id,
                device.Authentication.SymmetricKey.PrimaryKey,
                ttl,
                buffer,
                transport);

            using (DeviceClient deviceClient = DeviceClient.Create(testDevice.IoTHubHostName, refresher, transport))
            {
                _log.WriteLine($"Created {nameof(DeviceClient)} ID={TestLogging.IdOf(deviceClient)}");

                if (transport == Client.TransportType.Mqtt)
                {
                    deviceClient.SetConnectionStatusChangesHandler((ConnectionStatus status, ConnectionStatusChangeReason reason) =>
                    {
                        _log.WriteLine($"{nameof(ConnectionStatusChangesHandler)}: {status}; {reason}");
                        if (status == ConnectionStatus.Disconnected_Retrying || status == ConnectionStatus.Disconnected)
                        {
                            deviceDisconnected.Release();
                        }
                    });
                }

                var message = new Client.Message(Encoding.UTF8.GetBytes("Hello"));

                using (var cts = new CancellationTokenSource(TimeSpan.FromSeconds(ttl * 10)))
                {
                    try
                    {
                        // Create the first Token.
                        Console.WriteLine($"[{DateTime.UtcNow}] OpenAsync");
                        await deviceClient.OpenAsync(cts.Token).ConfigureAwait(false);

                        Console.WriteLine($"[{DateTime.UtcNow}] SendEventAsync (1)");
                        await deviceClient.SendEventAsync(message, cts.Token).ConfigureAwait(false);

                        await refresher.WaitForTokenRefreshAsync(cts.Token).ConfigureAwait(false);
                    }
                    catch (OperationCanceledException ex)
                    {
                        Assert.Fail($"{TestLogging.IdOf(deviceClient)} did not get the initial token. {ex}");
                        throw;
                    }

                    // Wait for the Token to expire.
                    if (transport == Client.TransportType.Http1)
                    {
                        float waitTime = (float)ttl * ((float)buffer / 100) + 1;
                        Console.WriteLine($"[{DateTime.UtcNow}] Waiting {waitTime} seconds.");
                        await Task.Delay(TimeSpan.FromSeconds(waitTime)).ConfigureAwait(false);
                    }
                    else if (transport == Client.TransportType.Mqtt)
                    {
                        Console.WriteLine($"[{DateTime.UtcNow}] Waiting for device disconnect.");
                        await deviceDisconnected.WaitAsync(cts.Token).ConfigureAwait(false);
                    }

                    try
                    {
                        Console.WriteLine($"[{DateTime.UtcNow}] SendEventAsync (2)");
                        await deviceClient.SendEventAsync(message, cts.Token).ConfigureAwait(false);

                        await refresher.WaitForTokenRefreshAsync(cts.Token).ConfigureAwait(false);
                    }
                    catch (OperationCanceledException ex)
                    {
                        Assert.Fail($"{TestLogging.IdOf(deviceClient)} did not refresh token after {refresher.DetectedRefreshInterval}. {ex}");
                        throw;
                    }

                    // Ensure that the token was refreshed.
                    Console.WriteLine($"[{DateTime.UtcNow}] Token was refreshed after {refresher.DetectedRefreshInterval} (ttl = {ttl} seconds).");
                    Assert.IsTrue(
                        refresher.DetectedRefreshInterval.TotalSeconds < (float)ttl * (1 + (float)buffer / 100), // Wait for more than what we expect.
                        $"Token was refreshed after {refresher.DetectedRefreshInterval} although ttl={ttl} seconds.");

                    Console.WriteLine($"[{DateTime.UtcNow}] CloseAsync");
                    await deviceClient.CloseAsync().ConfigureAwait(false);
                }
            }
        }
        public DeviceClient CreateDeviceClient(ITransportSettings[] transportSettings, ConnectionStringAuthScope authScope = ConnectionStringAuthScope.Device)
        {
            DeviceClient deviceClient = null;

            if (_authenticationMethod == null)
            {
                if (authScope == ConnectionStringAuthScope.Device)
                {
                    deviceClient = DeviceClient.CreateFromConnectionString(ConnectionString, transportSettings);
                    s_log.WriteLine($"{nameof(CreateDeviceClient)}: Created {nameof(DeviceClient)} {_device.Id} from device connection string: ID={TestLogging.IdOf(deviceClient)}");
                }
                else
                {
                    deviceClient = DeviceClient.CreateFromConnectionString(Configuration.IoTHub.ConnectionString, _device.Id, transportSettings);
                    s_log.WriteLine($"{nameof(CreateDeviceClient)}: Created {nameof(DeviceClient)} {_device.Id} from IoTHub connection string: ID={TestLogging.IdOf(deviceClient)}");
                }
            }
            else
            {
                deviceClient = DeviceClient.Create(IoTHubHostName, AuthenticationMethod, transportSettings);
                s_log.WriteLine($"{nameof(CreateDeviceClient)}: Created {nameof(DeviceClient)} {_device.Id} from IAuthenticationMethod: ID={TestLogging.IdOf(deviceClient)}");
            }

            return(deviceClient);
        }
        public DeviceClient CreateDeviceClient(Client.TransportType transport)
        {
            DeviceClient deviceClient = null;

            if (_authenticationMethod == null)
            {
                deviceClient = DeviceClient.CreateFromConnectionString(ConnectionString, transport);
                s_log.WriteLine($"{nameof(CreateDeviceClient)}: Created {nameof(DeviceClient)} {_device.Id} from connection string: {transport} ID={TestLogging.IdOf(deviceClient)}");
            }
            else
            {
                deviceClient = DeviceClient.Create(IoTHubHostName, AuthenticationMethod, transport);
                s_log.WriteLine($"{nameof(CreateDeviceClient)}: Created {nameof(DeviceClient)} {_device.Id} from IAuthenticationMethod: {transport} ID={TestLogging.IdOf(deviceClient)}");
            }

            return(deviceClient);
        }
Esempio n. 6
0
        async Task ModuleClient_Gives_ConnectionStatus_DeviceDisabled_Base(
            Client.TransportType protocol, Func <RegistryManager, string, Task> registryManagerOperation)
        {
            AmqpTransportSettings amqpTransportSettings = new AmqpTransportSettings(protocol);

            ITransportSettings[] transportSettings = new ITransportSettings[] { amqpTransportSettings };

            TestModule testModule = await TestModule.GetTestModuleAsync(DevicePrefix + $"_{Guid.NewGuid()}", ModulePrefix).ConfigureAwait(false);

            ConnectionStatus?            status             = null;
            ConnectionStatusChangeReason?statusChangeReason = null;
            int deviceDisabledReceivedCount = 0;
            ConnectionStatusChangesHandler statusChangeHandler = (s, r) =>
            {
                if (r == ConnectionStatusChangeReason.Device_Disabled)
                {
                    status             = s;
                    statusChangeReason = r;
                    deviceDisabledReceivedCount++;
                }
            };

            using (ModuleClient moduleClient = ModuleClient.CreateFromConnectionString(testModule.ConnectionString, transportSettings))
            {
                moduleClient.SetConnectionStatusChangesHandler(statusChangeHandler);
                _log.WriteLine($"Created {nameof(DeviceClient)} ID={TestLogging.IdOf(moduleClient)}");

                Console.WriteLine("ModuleClient OpenAsync.");
                await moduleClient.OpenAsync().ConfigureAwait(false);

                // Receiving the module twin should succeed right now.
                Console.WriteLine("ModuleClient GetTwinAsync.");
                var twin = await moduleClient.GetTwinAsync().ConfigureAwait(false);

                Assert.IsNotNull(twin);

                // Delete the device in IoT Hub.
                using (RegistryManager registryManager = RegistryManager.CreateFromConnectionString(Configuration.IoTHub.ConnectionString))
                {
                    await registryManagerOperation(registryManager, testModule.DeviceId).ConfigureAwait(false);
                }

                // Periodically keep retrieving the device twin to keep connection alive.
                // The ConnectionStatusChangesHandler should be triggered when the connection is closed from IoT hub with an
                // exception thrown.
                int twinRetrievals = 50;
                for (int i = 0; i < twinRetrievals; i++)
                {
                    try
                    {
                        await Task.Delay(TimeSpan.FromSeconds(10)).ConfigureAwait(false);

                        if (deviceDisabledReceivedCount == 1)
                        {
                            // Call an API on the client again to trigger the ConnectionStatusChangesHandler once again with the
                            // Device_Disabled status.
                            // This currently does not work due to some issues with IoT hub allowing new connections even when the
                            // device is deleted/disabled. Once that problem is investigated and fixed, we can re-enable this call
                            // and test for multiple invocations of the ConnectionStatusChangeHandler.
                            // await moduleClient.GetTwinAsync().ConfigureAwait(false);
                            break;
                        }
                    }
                    catch (IotHubException ex)
                    {
                        _log.WriteLine($"Exception occurred while retrieving module twin: {ex}");
                        Assert.IsInstanceOfType(ex.InnerException, typeof(DeviceNotFoundException));
                    }
                }

                Assert.AreEqual(1, deviceDisabledReceivedCount);
                Assert.AreEqual(ConnectionStatus.Disconnected, status);
                Assert.AreEqual(ConnectionStatusChangeReason.Device_Disabled, statusChangeReason);
            }
        }