private async Task Twin_DeviceReportedPropertiesRecovery(Client.TransportType transport, string faultType, string reason, int delayInSec)
        {
            var propName = Guid.NewGuid().ToString();
            var props    = new TwinCollection();

            Func <DeviceClient, TestDevice, Task> testOperation = async(deviceClient, testDevice) =>
            {
                var propValue = Guid.NewGuid().ToString();
                props[propName] = propValue;

                await deviceClient.UpdateReportedPropertiesAsync(props).ConfigureAwait(false);

                var deviceTwin = await deviceClient.GetTwinAsync().ConfigureAwait(false);

                Assert.AreEqual <String>(deviceTwin.Properties.Reported[propName].ToString(), propValue);
            };

            await FaultInjection.TestErrorInjectionAsync(
                DevicePrefix,
                TestDeviceType.Sasl,
                transport,
                faultType,
                reason,
                delayInSec,
                FaultInjection.DefaultDurationInSec,
                (d, t) => { return(Task.FromResult <bool>(false)); },
                testOperation,
                () => { return(Task.FromResult <bool>(false)); }).ConfigureAwait(false);
        }
        private async Task Twin_DeviceDesiredPropertyUpdateRecoveryAsync(
            Client.TransportType transport,
            string faultType,
            string reason,
            int delayInSec)
        {
            TestDeviceCallbackHandler testDeviceCallbackHandler = null;
            var registryManager = RegistryManager.CreateFromConnectionString(Configuration.IoTHub.ConnectionString);

            using var cts = new CancellationTokenSource(FaultInjection.RecoveryTimeMilliseconds);

            var propName = Guid.NewGuid().ToString();
            var props    = new TwinCollection();

            // Configure the callback and start accepting twin changes.
            Func <DeviceClient, TestDevice, Task> initOperation = async(deviceClient, testDevice) =>
            {
                testDeviceCallbackHandler = new TestDeviceCallbackHandler(deviceClient);
                await testDeviceCallbackHandler.SetTwinPropertyUpdateCallbackHandlerAsync(propName).ConfigureAwait(false);
            };

            // Change the twin from the service side and verify the device received it.
            Func <DeviceClient, TestDevice, Task> testOperation = async(deviceClient, testDevice) =>
            {
                var propValue = Guid.NewGuid().ToString();
                testDeviceCallbackHandler.ExpectedTwinPropertyValue = propValue;

                s_log.WriteLine($"{nameof(Twin_DeviceDesiredPropertyUpdateRecoveryAsync)}: name={propName}, value={propValue}");

                Task serviceSendTask  = RegistryManagerUpdateDesiredPropertyAsync(testDevice.Id, propName, propValue);
                Task twinReceivedTask = testDeviceCallbackHandler.WaitForTwinCallbackAsync(cts.Token);

                var tasks = new List <Task>()
                {
                    serviceSendTask, twinReceivedTask
                };
                while (tasks.Count > 0)
                {
                    Task completedTask = await Task.WhenAny(tasks).ConfigureAwait(false);

                    completedTask.GetAwaiter().GetResult();
                    tasks.Remove(completedTask);
                }
            };

            await FaultInjection
            .TestErrorInjectionAsync(
                s_devicePrefix,
                TestDeviceType.Sasl,
                transport,
                faultType,
                reason,
                delayInSec,
                FaultInjection.DefaultDurationInSec,
                initOperation,
                testOperation,
                () => { return(Task.FromResult(false)); })
            .ConfigureAwait(false);
        }
        internal async Task SendMessageRecovery(
            TestDeviceType type,
            Client.TransportType transport,
            string faultType,
            string reason,
            int delayInSec,
            int durationInSec           = FaultInjection.DefaultDurationInSec,
            int retryDurationInMilliSec = FaultInjection.RecoveryTimeMilliseconds)
        {
            EventHubTestListener testListener = null;

            Func <DeviceClient, TestDevice, Task> init = async(deviceClient, testDevice) =>
            {
                testListener = await EventHubTestListener.CreateListener(testDevice.Id).ConfigureAwait(false);

                deviceClient.OperationTimeoutInMilliseconds = (uint)retryDurationInMilliSec;
            };

            Func <DeviceClient, TestDevice, Task> testOperation = async(deviceClient, testDevice) =>
            {
                string payload, p1Value;

                Client.Message testMessage = ComposeD2CTestMessage(out payload, out p1Value);
                await deviceClient.SendEventAsync(testMessage).ConfigureAwait(false);

                bool isReceived = false;
                isReceived = await testListener.WaitForMessage(testDevice.Id, payload, p1Value).ConfigureAwait(false);

                Assert.IsTrue(isReceived);
            };

            Func <Task> cleanupOperation = () =>
            {
                if (testListener != null)
                {
                    return(testListener.CloseAsync());
                }
                else
                {
                    return(Task.FromResult(false));
                }
            };

            await FaultInjection.TestErrorInjectionAsync(
                DevicePrefix,
                type,
                transport,
                faultType,
                reason,
                delayInSec,
                durationInSec,
                init,
                testOperation,
                cleanupOperation).ConfigureAwait(false);
        }
        private async Task ReceiveMessageRecovery(
            TestDeviceType type,
            Client.TransportType transport,
            string faultType,
            string reason,
            int delayInSec)
        {
            using (ServiceClient serviceClient = ServiceClient.CreateFromConnectionString(Configuration.IoTHub.ConnectionString))
            {
                Func <DeviceClient, TestDevice, Task> init = async(deviceClient, testDevice) =>
                {
                    await serviceClient.OpenAsync().ConfigureAwait(false);

                    if (transport == Client.TransportType.Mqtt_Tcp_Only ||
                        transport == Client.TransportType.Mqtt_WebSocket_Only)
                    {
                        // Dummy ReceiveAsync to ensure mqtt subscription registration before SendAsync() is called on service client.
                        await deviceClient.ReceiveAsync(TimeSpan.FromSeconds(1)).ConfigureAwait(false);
                    }
                };

                Func <DeviceClient, TestDevice, Task> testOperation = async(deviceClient, testDevice) =>
                {
                    string payload, messageId, p1Value;
                    await serviceClient.SendAsync(
                        testDevice.Id,
                        MessageReceiveE2ETests.ComposeC2DTestMessage(out payload, out messageId, out p1Value)).ConfigureAwait(false);

                    await MessageReceiveE2ETests.VerifyReceivedC2DMessageAsync(transport, deviceClient, payload, p1Value).ConfigureAwait(false);
                };

                Func <Task> cleanupOperation = () =>
                {
                    return(serviceClient.CloseAsync());
                };

                await FaultInjection.TestErrorInjectionAsync(
                    DevicePrefix,
                    type,
                    transport,
                    faultType,
                    reason,
                    delayInSec,
                    FaultInjection.DefaultDurationInSec,
                    init,
                    testOperation,
                    cleanupOperation).ConfigureAwait(false);
            }
        }
        private async Task SendMethodAndRespondRecoveryAsync(Client.TransportType transport, string faultType, string reason, int delayInSec)
        {
            TestDeviceCallbackHandler testDeviceCallbackHandler = null;

            using var cts = new CancellationTokenSource(FaultInjection.RecoveryTimeMilliseconds);

            // Configure the callback and start accepting method calls.
            Func <DeviceClient, TestDevice, Task> initOperation = async(deviceClient, testDevice) =>
            {
                testDeviceCallbackHandler = new TestDeviceCallbackHandler(deviceClient);
                await testDeviceCallbackHandler
                .SetDeviceReceiveMethodAsync(MethodName, DeviceResponseJson, ServiceRequestJson)
                .ConfigureAwait(false);
            };

            // Call the method from the service side and verify the device received the call.
            Func <DeviceClient, TestDevice, Task> testOperation = async(deviceClient, testDevice) =>
            {
                Task serviceSendTask    = ServiceSendMethodAndVerifyResponseAsync(testDevice.Id, MethodName, DeviceResponseJson, ServiceRequestJson);
                Task methodReceivedTask = testDeviceCallbackHandler.WaitForMethodCallbackAsync(cts.Token);

                var tasks = new List <Task>()
                {
                    serviceSendTask, methodReceivedTask
                };
                while (tasks.Count > 0)
                {
                    Task completedTask = await Task.WhenAny(tasks).ConfigureAwait(false);

                    completedTask.GetAwaiter().GetResult();
                    tasks.Remove(completedTask);
                }
            };

            await FaultInjection
            .TestErrorInjectionAsync(
                DevicePrefix,
                TestDeviceType.Sasl,
                transport,
                faultType,
                reason,
                delayInSec,
                FaultInjection.DefaultDelayInSec,
                initOperation,
                testOperation,
                () => { return(Task.FromResult <bool>(false)); })
            .ConfigureAwait(false);
        }
Exemple #6
0
        internal async Task SendMessageRecoveryAsync(
            TestDeviceType type,
            Client.TransportType transport,
            string faultType,
            string reason,
            int delayInSec,
            int durationInSec           = FaultInjection.DefaultDurationInSec,
            int retryDurationInMilliSec = FaultInjection.RecoveryTimeMilliseconds)
        {
            Func <DeviceClient, TestDevice, Task> init = (deviceClient, testDevice) =>
            {
                deviceClient.OperationTimeoutInMilliseconds = (uint)retryDurationInMilliSec;
                return(Task.FromResult(0));
            };

            Func <DeviceClient, TestDevice, Task> testOperation = async(deviceClient, testDevice) =>
            {
                (Client.Message testMessage, string messageId, string payload, string p1Value) = MessageSendE2ETests.ComposeD2cTestMessage();
                await deviceClient.SendEventAsync(testMessage).ConfigureAwait(false);

                bool isReceived = false;
                isReceived = EventHubTestListener.VerifyIfMessageIsReceived(testDevice.Id, payload, p1Value);
                Assert.IsTrue(isReceived);
            };

            await FaultInjection
            .TestErrorInjectionAsync(
                _devicePrefix,
                type,
                transport,
                faultType,
                reason,
                delayInSec,
                durationInSec,
                init,
                testOperation,
                () => { return(Task.FromResult(false)); })
            .ConfigureAwait(false);
        }
        private async Task SendMethodAndRespondRecovery(Client.TransportType transport, string faultType, string reason, int delayInSec)
        {
            TestDeviceCallbackHandler testDeviceCallbackHandler = null;
            var cts = new CancellationTokenSource(FaultInjection.RecoveryTimeMilliseconds);

            // Configure the callback and start accepting method calls.
            Func <DeviceClient, TestDevice, Task> initOperation = async(deviceClient, testDevice) =>
            {
                testDeviceCallbackHandler = new TestDeviceCallbackHandler(deviceClient);
                await testDeviceCallbackHandler.SetDeviceReceiveMethodAsync(MethodName, DeviceResponseJson, ServiceRequestJson).ConfigureAwait(false);
            };

            // Call the method from the service side and verify the device received the call.
            Func <DeviceClient, TestDevice, Task> testOperation = async(deviceClient, testDevice) =>
            {
                Task serviceSendTask    = ServiceSendMethodAndVerifyResponse(testDevice.Id, MethodName, DeviceResponseJson, ServiceRequestJson);
                Task methodReceivedTask = testDeviceCallbackHandler.WaitForMethodCallbackAsync(cts.Token);

                var tasks = new List <Task>()
                {
                    serviceSendTask, methodReceivedTask
                };
                while (tasks.Count > 0)
                {
                    Task completedTask = await Task.WhenAny(tasks).ConfigureAwait(false);

                    completedTask.GetAwaiter().GetResult();
                    tasks.Remove(completedTask);
                }
            };

            // This is a simple hack to ensure that we're still exercising these tests while we address the race conditions causing the following issues:
            // [Ignore] // TODO: #571
            // [Ignore] // TODO: #558
            int retryCount = 3;

            while (retryCount-- > 0)
            {
                try
                {
                    await FaultInjection.TestErrorInjectionAsync(
                        DevicePrefix,
                        TestDeviceType.Sasl,
                        transport,
                        faultType,
                        reason,
                        delayInSec,
                        FaultInjection.DefaultDelayInSec,
                        initOperation,
                        testOperation,
                        () => { return(Task.FromResult <bool>(false)); }).ConfigureAwait(false);
                }
                catch (DeviceNotFoundException e)
                {
                    s_log.WriteLine($"Retrying fault injection test ({retryCount} left): {e}");
                }
                catch (TaskCanceledException e)
                {
                    s_log.WriteLine($"Retrying fault injection test ({retryCount} left): {e}");
                }
            }
        }
        private async Task Twin_DeviceDesiredPropertyUpdateRecovery(Client.TransportType transport, string faultType, string reason, int delayInSec)
        {
            TestDeviceCallbackHandler testDeviceCallbackHandler = null;
            RegistryManager           registryManager           = RegistryManager.CreateFromConnectionString(Configuration.IoTHub.ConnectionString);
            var cts = new CancellationTokenSource(FaultInjection.RecoveryTimeMilliseconds);

            var propName = Guid.NewGuid().ToString();
            var props    = new TwinCollection();

            // Configure the callback and start accepting twin changes.
            Func <DeviceClient, TestDevice, Task> initOperation = async(deviceClient, testDevice) =>
            {
                testDeviceCallbackHandler = new TestDeviceCallbackHandler(deviceClient);
                await testDeviceCallbackHandler.SetTwinPropertyUpdateCallbackHandlerAsync(propName).ConfigureAwait(false);
            };

            // Change the twin from the service side and verify the device received it.
            Func <DeviceClient, TestDevice, Task> testOperation = async(deviceClient, testDevice) =>
            {
                var propValue = Guid.NewGuid().ToString();
                testDeviceCallbackHandler.ExpectedTwinPropertyValue = propValue;

                s_log.WriteLine($"{nameof(Twin_DeviceDesiredPropertyUpdateRecovery)}: name={propName}, value={propValue}");

                Task serviceSendTask  = RegistryManagerUpdateDesiredPropertyAsync(testDevice.Id, propName, propValue);
                Task twinReceivedTask = testDeviceCallbackHandler.WaitForTwinCallbackAsync(cts.Token);

                var tasks = new List <Task>()
                {
                    serviceSendTask, twinReceivedTask
                };
                while (tasks.Count > 0)
                {
                    Task completedTask = await Task.WhenAny(tasks).ConfigureAwait(false);

                    completedTask.GetAwaiter().GetResult();
                    tasks.Remove(completedTask);
                }
            };

            // This is a simple hack to ensure that we're still exercising these tests while we address the race conditions causing the following issues:
            // [Ignore] // TODO: #571
            // [Ignore] // TODO: #558
            int retryCount = 3;

            while (retryCount-- > 0)
            {
                try
                {
                    await FaultInjection.TestErrorInjectionAsync(
                        DevicePrefix,
                        TestDeviceType.Sasl,
                        transport,
                        faultType,
                        reason,
                        delayInSec,
                        FaultInjection.DefaultDurationInSec,
                        initOperation,
                        testOperation,
                        () => { return(Task.FromResult <bool>(false)); }).ConfigureAwait(false);
                }
                catch (DeviceNotFoundException e)
                {
                    s_log.WriteLine($"Retrying fault injection test ({retryCount} left)");
                }
            }
        }