private async Task SendMessagePoolOverAmqp( TestDeviceType type, Client.TransportType transport, int poolSize, int devicesCount, ConnectionStringAuthScope authScope = ConnectionStringAuthScope.Device) { Func <DeviceClient, TestDevice, Task> testOperation = async(deviceClient, testDevice) => { s_log.WriteLine($"{nameof(MessageSendE2EPoolAmqpTests)}: Preparing to send message for device {testDevice.Id}"); await deviceClient.OpenAsync().ConfigureAwait(false); (Client.Message testMessage, string messageId, string payload, string p1Value) = MessageSendE2ETests.ComposeD2cTestMessage(); s_log.WriteLine($"{nameof(MessageSendE2EPoolAmqpTests)}.{testDevice.Id}: messageId='{messageId}' payload='{payload}' p1Value='{p1Value}'"); await deviceClient.SendEventAsync(testMessage).ConfigureAwait(false); bool isReceived = EventHubTestListener.VerifyIfMessageIsReceived(testDevice.Id, payload, p1Value); Assert.IsTrue(isReceived, "Message is not received."); }; await PoolingOverAmqp .TestPoolAmqpAsync( _devicePrefix, transport, poolSize, devicesCount, null, testOperation, null, authScope, true) .ConfigureAwait(false); }
private async Task Twin_DeviceSetsReportedPropertyAndGetsItBackPoolOverAmqp( TestDeviceType type, Client.TransportType transport, int poolSize, int devicesCount, ConnectionStringAuthScope authScope = ConnectionStringAuthScope.Device) { async Task TestOperationAsync(DeviceClient deviceClient, TestDevice testDevice, TestDeviceCallbackHandler _) { Logger.Trace($"{nameof(TwinE2EPoolAmqpTests)}: Setting reported propery and verifying twin for device {testDevice.Id}"); await TwinE2ETests.Twin_DeviceSetsReportedPropertyAndGetsItBackAsync(deviceClient, testDevice.Id, Guid.NewGuid().ToString(), Logger).ConfigureAwait(false); } await PoolingOverAmqp .TestPoolAmqpAsync( _devicePrefix, transport, poolSize, devicesCount, null, TestOperationAsync, null, authScope, true, Logger) .ConfigureAwait(false); }
private async Task SendMessagePoolOverAmqp( TestDeviceType type, Client.TransportType transport, int poolSize, int devicesCount, ConnectionStringAuthScope authScope = ConnectionStringAuthScope.Device) { async Task TestOperationAsync(DeviceClient deviceClient, TestDevice testDevice, TestDeviceCallbackHandler _) { Logger.Trace($"{nameof(MessageSendE2EPoolAmqpTests)}: Preparing to send message for device {testDevice.Id}"); await deviceClient.OpenAsync().ConfigureAwait(false); (Client.Message testMessage, string payload, string p1Value) = MessageSendE2ETests.ComposeD2cTestMessage(Logger); Logger.Trace($"{nameof(MessageSendE2EPoolAmqpTests)}.{testDevice.Id}: messageId='{testMessage.MessageId}' payload='{payload}' p1Value='{p1Value}'"); await deviceClient.SendEventAsync(testMessage).ConfigureAwait(false); } await PoolingOverAmqp .TestPoolAmqpAsync( _devicePrefix, transport, poolSize, devicesCount, null, TestOperationAsync, null, authScope, true, Logger) .ConfigureAwait(false); }
private async Task Twin_DeviceSetsReportedPropertyAndGetsItBackPoolOverAmqp( TestDeviceType type, Client.TransportType transport, int poolSize, int devicesCount, ConnectionStringAuthScope authScope = ConnectionStringAuthScope.Device) { Func <DeviceClient, TestDevice, Task> testOperation = async(deviceClient, testDevice) => { _log.WriteLine($"{nameof(TwinE2EPoolAmqpTests)}: Setting reported propery and verifying twin for device {testDevice.Id}"); await TwinE2ETests.Twin_DeviceSetsReportedPropertyAndGetsItBack(deviceClient).ConfigureAwait(false); }; Func <IList <DeviceClient>, Task> cleanupOperation = async(deviceClients) => { foreach (DeviceClient deviceClient in deviceClients) { deviceClient.Dispose(); } await Task.FromResult <bool>(false).ConfigureAwait(false); }; await PoolingOverAmqp.TestPoolAmqpAsync( DevicePrefix, transport, poolSize, devicesCount, (d, t) => { return(Task.FromResult(false)); }, testOperation, cleanupOperation, authScope, true).ConfigureAwait(false); }
private async Task ReceiveMessageRecoveryPoolOverAmqp( TestDeviceType type, Client.TransportType transport, int poolSize, int devicesCount, string faultType, string reason, int delayInSec = FaultInjection.DefaultDelayInSec, int durationInSec = FaultInjection.DefaultDurationInSec, ConnectionStringAuthScope authScope = ConnectionStringAuthScope.Device) { // Initialize the service client ServiceClient serviceClient = ServiceClient.CreateFromConnectionString(Configuration.IoTHub.ConnectionString); Func <DeviceClient, TestDevice, Task> testOperation = async(deviceClient, testDevice) => { (Message msg, string payload, string p1Value) = MessageReceiveE2ETests.ComposeC2dTestMessage(Logger); Logger.Trace($"{nameof(FaultInjectionPoolAmqpTests)}: Sending message to device {testDevice.Id}: payload='{payload}' p1Value='{p1Value}'"); await serviceClient.SendAsync(testDevice.Id, msg) .ConfigureAwait(false); Logger.Trace($"{nameof(FaultInjectionPoolAmqpTests)}: Preparing to receive message for device {testDevice.Id}"); await deviceClient.OpenAsync() .ConfigureAwait(false); await MessageReceiveE2ETests.VerifyReceivedC2DMessageAsync(transport, deviceClient, testDevice.Id, msg, payload, Logger) .ConfigureAwait(false); }; Func <IList <DeviceClient>, Task> cleanupOperation = async(deviceClients) => { await serviceClient.CloseAsync() .ConfigureAwait(false); serviceClient.Dispose(); foreach (DeviceClient deviceClient in deviceClients) { deviceClient.Dispose(); } }; await FaultInjectionPoolingOverAmqp .TestFaultInjectionPoolAmqpAsync( MessageReceive_DevicePrefix, transport, poolSize, devicesCount, faultType, reason, delayInSec, durationInSec, (d, t) => { return(Task.FromResult(false)); }, testOperation, cleanupOperation, authScope, Logger) .ConfigureAwait(false); }
private async Task ReceiveMessageRecoveryPoolOverAmqpAsync( TestDeviceType type, Client.TransportType transport, int poolSize, int devicesCount, string faultType, string reason, TimeSpan delayInSec = default, TimeSpan durationInSec = default, ConnectionStringAuthScope authScope = ConnectionStringAuthScope.Device, string proxyAddress = null) { // Initialize the service client using var serviceClient = ServiceClient.CreateFromConnectionString(TestConfiguration.IoTHub.ConnectionString); async Task TestOperationAsync(DeviceClient deviceClient, TestDevice testDevice, TestDeviceCallbackHandler _) { (Message msg, string payload, string p1Value) = MessageReceiveE2ETests.ComposeC2dTestMessage(Logger); Logger.Trace($"{nameof(FaultInjectionPoolAmqpTests)}: Sending message to device {testDevice.Id}: payload='{payload}' p1Value='{p1Value}'"); await serviceClient.SendAsync(testDevice.Id, msg) .ConfigureAwait(false); Logger.Trace($"{nameof(FaultInjectionPoolAmqpTests)}: Preparing to receive message for device {testDevice.Id}"); await deviceClient.OpenAsync() .ConfigureAwait(false); await MessageReceiveE2ETests.VerifyReceivedC2DMessageAsync(transport, deviceClient, testDevice.Id, msg, payload, Logger) .ConfigureAwait(false); } async Task CleanupOperationAsync(List <DeviceClient> deviceClients, List <TestDeviceCallbackHandler> testDeviceCallbackHandlers) { await serviceClient.CloseAsync() .ConfigureAwait(false); serviceClient.Dispose(); deviceClients.ForEach(deviceClient => deviceClient.Dispose()); testDeviceCallbackHandlers.ForEach(testDeviceCallbackHandler => testDeviceCallbackHandler.Dispose()); } await FaultInjectionPoolingOverAmqp .TestFaultInjectionPoolAmqpAsync( MessageReceive_DevicePrefix, transport, proxyAddress, poolSize, devicesCount, faultType, reason, delayInSec == TimeSpan.Zero?FaultInjection.DefaultFaultDelay : delayInSec, durationInSec == TimeSpan.Zero?FaultInjection.DefaultFaultDuration : durationInSec, (d, t, h) => { return(Task.FromResult(false)); }, TestOperationAsync, CleanupOperationAsync, authScope, Logger) .ConfigureAwait(false); }
private async Task ReceiveMessagePoolOverAmqp( Client.TransportType transport, int poolSize, int devicesCount, ConnectionStringAuthScope authScope = ConnectionStringAuthScope.Device) { Dictionary <string, List <string> > messagesSent = new Dictionary <string, List <string> >(); // Initialize the service client ServiceClient serviceClient = ServiceClient.CreateFromConnectionString(Configuration.IoTHub.ConnectionString); Func <DeviceClient, TestDevice, Task> initOperation = async(deviceClient, testDevice) => { (Message msg, string messageId, string payload, string p1Value) = MessageReceiveE2ETests.ComposeC2DTestMessage(); messagesSent.Add(testDevice.Id, new List <string> { payload, p1Value }); await serviceClient.SendAsync(testDevice.Id, msg).ConfigureAwait(false); }; Func <DeviceClient, TestDevice, Task> testOperation = async(deviceClient, testDevice) => { _log.WriteLine($"{nameof(MessageReceiveE2EPoolAmqpTests)}: Preparing to receive message for device {testDevice.Id}"); await deviceClient.OpenAsync().ConfigureAwait(false); List <string> msgSent = messagesSent[testDevice.Id]; string payload = msgSent[0]; string p1Value = msgSent[1]; await MessageReceiveE2ETests.VerifyReceivedC2DMessageAsync(transport, deviceClient, testDevice.Id, payload, p1Value).ConfigureAwait(false); }; Func <IList <DeviceClient>, Task> cleanupOperation = async(deviceClients) => { await serviceClient.CloseAsync().ConfigureAwait(false); serviceClient.Dispose(); foreach (DeviceClient deviceClient in deviceClients) { deviceClient.Dispose(); } messagesSent.Clear(); }; await PoolingOverAmqp.TestPoolAmqpAsync( DevicePrefix, transport, poolSize, devicesCount, initOperation, testOperation, cleanupOperation, authScope, true).ConfigureAwait(false); }
private async Task SendMessagePoolOverAmqp( TestDeviceType type, Client.TransportType transport, int poolSize, int devicesCount, ConnectionStringAuthScope authScope = ConnectionStringAuthScope.Device) { Dictionary <string, EventHubTestListener> eventHubListeners = new Dictionary <string, EventHubTestListener>(); Func <DeviceClient, TestDevice, Task> initOperation = async(deviceClient, testDevice) => { EventHubTestListener testListener = await EventHubTestListener.CreateListener(testDevice.Id).ConfigureAwait(false); eventHubListeners.Add(testDevice.Id, testListener); }; Func <DeviceClient, TestDevice, Task> testOperation = async(deviceClient, testDevice) => { _log.WriteLine($"{nameof(MessageSendE2EPoolAmqpTests)}: Preparing to send message for device {testDevice.Id}"); await deviceClient.OpenAsync().ConfigureAwait(false); (Client.Message testMessage, string messageId, string payload, string p1Value) = MessageSendE2ETests.ComposeD2CTestMessage(); _log.WriteLine($"{nameof(MessageSendE2EPoolAmqpTests)}.{testDevice.Id}: messageId='{messageId}' payload='{payload}' p1Value='{p1Value}'"); await deviceClient.SendEventAsync(testMessage).ConfigureAwait(false); EventHubTestListener testListener = eventHubListeners[testDevice.Id]; bool isReceived = await testListener.WaitForMessage(testDevice.Id, payload, p1Value).ConfigureAwait(false); Assert.IsTrue(isReceived, "Message is not received."); }; Func <IList <DeviceClient>, Task> cleanupOperation = async(deviceClients) => { foreach (var listener in eventHubListeners) { await listener.Value.CloseAsync().ConfigureAwait(false); } foreach (DeviceClient deviceClient in deviceClients) { deviceClient.Dispose(); } eventHubListeners.Clear(); }; await PoolingOverAmqp.TestPoolAmqpAsync( DevicePrefix, transport, poolSize, devicesCount, initOperation, testOperation, cleanupOperation, authScope).ConfigureAwait(false); }
private async Task ServiceSetsDesiredPropertyAndDeviceReceivesEventPoolOverAmqp( TestDeviceType type, Client.TransportType transport, int poolSize, int devicesCount, Func <DeviceClient, string, string, Task <Task> > setTwinPropertyUpdateCallbackAsync, ConnectionStringAuthScope authScope = ConnectionStringAuthScope.Device) { Dictionary <string, List <string> > twinPropertyMap = new Dictionary <string, List <string> >(); Func <DeviceClient, TestDevice, Task> initOperation = async(deviceClient, testDevice) => { var propName = Guid.NewGuid().ToString(); var propValue = Guid.NewGuid().ToString(); twinPropertyMap.Add(testDevice.Id, new List <string> { propName, propValue }); _log.WriteLine($"{nameof(TwinE2EPoolAmqpTests)}: Setting desired propery callback for device {testDevice.Id}"); _log.WriteLine($"{nameof(ServiceSetsDesiredPropertyAndDeviceReceivesEventPoolOverAmqp)}: name={propName}, value={propValue}"); Task updateReceivedTask = await setTwinPropertyUpdateCallbackAsync(deviceClient, propName, propValue).ConfigureAwait(false); }; Func <DeviceClient, TestDevice, Task> testOperation = async(deviceClient, testDevice) => { _log.WriteLine($"{nameof(TwinE2EPoolAmqpTests)}: Updating the desired properties for device {testDevice.Id}"); List <string> twinProperties = twinPropertyMap[testDevice.Id]; var propName = twinProperties[0]; var propValue = twinProperties[1]; await TwinE2ETests.RegistryManagerUpdateDesiredPropertyAsync(testDevice.Id, propName, propValue).ConfigureAwait(false); }; Func <IList <DeviceClient>, Task> cleanupOperation = async(deviceClients) => { foreach (DeviceClient deviceClient in deviceClients) { deviceClient.Dispose(); } twinPropertyMap.Clear(); await Task.FromResult <bool>(false).ConfigureAwait(false); }; await PoolingOverAmqp.TestPoolAmqpAsync( DevicePrefix, transport, poolSize, devicesCount, initOperation, testOperation, cleanupOperation, authScope, true).ConfigureAwait(false); }
private async Task ServiceSetsDesiredPropertyAndDeviceReceivesEventPoolOverAmqp( TestDeviceType type, Client.TransportType transport, int poolSize, int devicesCount, Func <DeviceClient, string, string, MsTestLogger, Task <Task> > setTwinPropertyUpdateCallbackAsync, ConnectionStringAuthScope authScope = ConnectionStringAuthScope.Device) { var twinPropertyMap = new Dictionary <string, List <string> >(); async Task InitOperationAsync(DeviceClient deviceClient, TestDevice testDevice, TestDeviceCallbackHandler _) { string propName = Guid.NewGuid().ToString(); string propValue = Guid.NewGuid().ToString(); twinPropertyMap.Add(testDevice.Id, new List <string> { propName, propValue }); Logger.Trace($"{nameof(TwinE2EPoolAmqpTests)}: Setting desired propery callback for device {testDevice.Id}"); Logger.Trace($"{nameof(ServiceSetsDesiredPropertyAndDeviceReceivesEventPoolOverAmqp)}: name={propName}, value={propValue}"); Task updateReceivedTask = await setTwinPropertyUpdateCallbackAsync(deviceClient, propName, propValue, Logger).ConfigureAwait(false); } async Task TestOperationAsync(DeviceClient deviceClient, TestDevice testDevice, TestDeviceCallbackHandler _) { Logger.Trace($"{nameof(TwinE2EPoolAmqpTests)}: Updating the desired properties for device {testDevice.Id}"); List <string> twinProperties = twinPropertyMap[testDevice.Id]; string propName = twinProperties[0]; string propValue = twinProperties[1]; await TwinE2ETests.RegistryManagerUpdateDesiredPropertyAsync(testDevice.Id, propName, propValue).ConfigureAwait(false); } Task CleanupOperationAsync() { twinPropertyMap.Clear(); return(Task.FromResult(0)); } await PoolingOverAmqp .TestPoolAmqpAsync( _devicePrefix, transport, poolSize, devicesCount, InitOperationAsync, TestOperationAsync, CleanupOperationAsync, authScope, true, Logger) .ConfigureAwait(false); }
private async Task SendMessageRecoveryPoolOverAmqpAsync( TestDeviceType type, Client.TransportType transport, int poolSize, int devicesCount, string faultType, string reason, int delayInSec = FaultInjection.DefaultDelayInSec, int durationInSec = FaultInjection.DefaultDurationInSec, ConnectionStringAuthScope authScope = ConnectionStringAuthScope.Device) { Func <DeviceClient, TestDevice, Task> testOperation = async(deviceClient, testDevice) => { _log.WriteLine($"{nameof(FaultInjectionPoolAmqpTests)}: Preparing to send message for device {testDevice.Id}"); await deviceClient.OpenAsync().ConfigureAwait(false); (Client.Message testMessage, string messageId, string payload, string p1Value) = MessageSendE2ETests.ComposeD2cTestMessage(); _log.WriteLine($"{nameof(FaultInjectionPoolAmqpTests)}.{testDevice.Id}: payload='{payload}' p1Value='{p1Value}'"); await deviceClient.SendEventAsync(testMessage).ConfigureAwait(false); bool isReceived = EventHubTestListener.VerifyIfMessageIsReceived(testDevice.Id, payload, p1Value); Assert.IsTrue(isReceived, $"Message is not received for device {testDevice.Id}."); }; Func <IList <DeviceClient>, Task> cleanupOperation = (deviceClients) => { foreach (DeviceClient deviceClient in deviceClients) { deviceClient.Dispose(); } return(Task.FromResult(0)); }; await FaultInjectionPoolingOverAmqp .TestFaultInjectionPoolAmqpAsync( MessageSend_DevicePrefix, transport, poolSize, devicesCount, faultType, reason, delayInSec, durationInSec, (d, t) => { return(Task.FromResult(false)); }, testOperation, cleanupOperation, authScope) .ConfigureAwait(false); }
private async Task SendMessageRecoveryPoolOverAmqpAsync( TestDeviceType type, Client.TransportType transport, int poolSize, int devicesCount, string faultType, string reason, int delayInSec = FaultInjection.DefaultDelayInSec, int durationInSec = FaultInjection.DefaultDurationInSec, ConnectionStringAuthScope authScope = ConnectionStringAuthScope.Device, string proxyAddress = null) { Func <DeviceClient, TestDevice, Task> testOperation = async(deviceClient, testDevice) => { Logger.Trace($"{nameof(FaultInjectionPoolAmqpTests)}: Preparing to send message for device {testDevice.Id}"); await deviceClient.OpenAsync().ConfigureAwait(false); (Client.Message testMessage, string payload, string p1Value) = MessageSendE2ETests.ComposeD2cTestMessage(Logger); Logger.Trace($"{nameof(FaultInjectionPoolAmqpTests)}.{testDevice.Id}: payload='{payload}' p1Value='{p1Value}'"); await deviceClient.SendEventAsync(testMessage).ConfigureAwait(false); }; Func <IList <DeviceClient>, Task> cleanupOperation = (deviceClients) => { foreach (DeviceClient deviceClient in deviceClients) { deviceClient.Dispose(); } return(Task.FromResult(0)); }; await FaultInjectionPoolingOverAmqp .TestFaultInjectionPoolAmqpAsync( MessageSend_DevicePrefix, transport, proxyAddress, poolSize, devicesCount, faultType, reason, delayInSec, durationInSec, (d, t) => { return(Task.FromResult(false)); }, testOperation, cleanupOperation, authScope, Logger) .ConfigureAwait(false); }
private async Task ReceiveMessagePoolOverAmqpAsync( Client.TransportType transport, int poolSize, int devicesCount, ConnectionStringAuthScope authScope = ConnectionStringAuthScope.Device) { var messagesSent = new Dictionary <string, Tuple <Message, string> >(); // Initialize the service client var serviceClient = ServiceClient.CreateFromConnectionString(Configuration.IoTHub.ConnectionString); async Task InitOperationAsync(DeviceClient deviceClient, TestDevice testDevice, TestDeviceCallbackHandler _) { (Message msg, string payload, string p1Value) = MessageReceiveE2ETests.ComposeC2dTestMessage(Logger); messagesSent.Add(testDevice.Id, Tuple.Create(msg, payload)); await serviceClient.SendAsync(testDevice.Id, msg).ConfigureAwait(false); } async Task TestOperationAsync(DeviceClient deviceClient, TestDevice testDevice, TestDeviceCallbackHandler _) { Logger.Trace($"{nameof(MessageReceiveE2EPoolAmqpTests)}: Preparing to receive message for device {testDevice.Id}"); await deviceClient.OpenAsync().ConfigureAwait(false); Tuple <Message, string> msgSent = messagesSent[testDevice.Id]; await MessageReceiveE2ETests.VerifyReceivedC2DMessageAsync(transport, deviceClient, testDevice.Id, msgSent.Item1, msgSent.Item2, Logger).ConfigureAwait(false); } async Task CleanupOperationAsync() { await serviceClient.CloseAsync().ConfigureAwait(false); serviceClient.Dispose(); messagesSent.Clear(); } await PoolingOverAmqp .TestPoolAmqpAsync( DevicePrefix, transport, poolSize, devicesCount, InitOperationAsync, TestOperationAsync, CleanupOperationAsync, authScope, true, Logger) .ConfigureAwait(false); }
private async Task ReceiveMessageUsingCallbackPoolOverAmqpAsync( Client.TransportType transport, int poolSize, int devicesCount, ConnectionStringAuthScope authScope = ConnectionStringAuthScope.Device) { // Initialize the service client var serviceClient = ServiceClient.CreateFromConnectionString(Configuration.IoTHub.ConnectionString); async Task InitOperationAsync(DeviceClient deviceClient, TestDevice testDevice, TestDeviceCallbackHandler testDeviceCallbackHandler) { (Message msg, string payload, string p1Value) = MessageReceiveE2ETests.ComposeC2dTestMessage(Logger); await testDeviceCallbackHandler.SetMessageReceiveCallbackHandlerAsync().ConfigureAwait(false); testDeviceCallbackHandler.ExpectedMessageSentByService = msg; await serviceClient.SendAsync(testDevice.Id, msg).ConfigureAwait(false); } async Task TestOperationAsync(DeviceClient deviceClient, TestDevice testDevice, TestDeviceCallbackHandler testDeviceCallbackHandler) { Logger.Trace($"{nameof(MessageReceiveE2EPoolAmqpTests)}: Preparing to receive message for device {testDevice.Id}"); using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(20)); await testDeviceCallbackHandler.WaitForReceiveMessageCallbackAsync(cts.Token).ConfigureAwait(false); } async Task CleanupOperationAsync() { await serviceClient.CloseAsync().ConfigureAwait(false); serviceClient.Dispose(); } await PoolingOverAmqp .TestPoolAmqpAsync( DevicePrefix, transport, poolSize, devicesCount, InitOperationAsync, TestOperationAsync, CleanupOperationAsync, authScope, true, Logger) .ConfigureAwait(false); }
private async Task SendMessageRecoveryPoolOverAmqpAsync( TestDeviceType type, Client.TransportType transport, int poolSize, int devicesCount, string faultType, string reason, TimeSpan delayInSec = default, TimeSpan durationInSec = default, ConnectionStringAuthScope authScope = ConnectionStringAuthScope.Device, string proxyAddress = null) { async Task TestOperationAsync(DeviceClient deviceClient, TestDevice testDevice, TestDeviceCallbackHandler _) { Logger.Trace($"{nameof(FaultInjectionPoolAmqpTests)}: Preparing to send message for device {testDevice.Id}"); await deviceClient.OpenAsync().ConfigureAwait(false); (Client.Message testMessage, string payload, string p1Value) = MessageSendE2ETests.ComposeD2cTestMessage(Logger); Logger.Trace($"{nameof(FaultInjectionPoolAmqpTests)}.{testDevice.Id}: payload='{payload}' p1Value='{p1Value}'"); await deviceClient.SendEventAsync(testMessage).ConfigureAwait(false); } Task CleanupOperationAsync(List <DeviceClient> deviceClients, List <TestDeviceCallbackHandler> _) { deviceClients.ForEach(deviceClient => deviceClient.Dispose()); return(Task.FromResult(0)); } await FaultInjectionPoolingOverAmqp .TestFaultInjectionPoolAmqpAsync( MessageSend_DevicePrefix, transport, proxyAddress, poolSize, devicesCount, faultType, reason, delayInSec == TimeSpan.Zero?FaultInjection.DefaultFaultDelay : delayInSec, durationInSec == TimeSpan.Zero?FaultInjection.DefaultFaultDuration : durationInSec, (d, t, h) => { return(Task.FromResult(false)); }, TestOperationAsync, CleanupOperationAsync, authScope, Logger) .ConfigureAwait(false); }
private async Task SendMethodAndRespondPoolOverAmqp( Client.TransportType transport, int poolSize, int devicesCount, Func <DeviceClient, string, Task <Task> > setDeviceReceiveMethod, ConnectionStringAuthScope authScope = ConnectionStringAuthScope.Device) { Func <DeviceClient, TestDevice, Task> initOperation = async(deviceClient, testDevice) => { _log.WriteLine($"{nameof(MethodE2EPoolAmqpTests)}: Setting method for device {testDevice.Id}"); Task methodReceivedTask = await setDeviceReceiveMethod(deviceClient, MethodName).ConfigureAwait(false); }; Func <DeviceClient, TestDevice, Task> testOperation = async(deviceClient, testDevice) => { _log.WriteLine($"{nameof(MethodE2EPoolAmqpTests)}: Preparing to receive method for device {testDevice.Id}"); await MethodE2ETests.ServiceSendMethodAndVerifyResponse( testDevice.Id, MethodName, MethodE2ETests.DeviceResponseJson, MethodE2ETests.ServiceRequestJson).ConfigureAwait(false); }; Func <IList <DeviceClient>, Task> cleanupOperation = async(deviceClients) => { foreach (DeviceClient deviceClient in deviceClients) { deviceClient.Dispose(); } await Task.FromResult <bool>(false).ConfigureAwait(false); }; await PoolingOverAmqp.TestPoolAmqpAsync( DevicePrefix, transport, poolSize, devicesCount, initOperation, testOperation, cleanupOperation, authScope, true).ConfigureAwait(false); }
private async Task SendMethodAndRespondPoolOverAmqp( Client.TransportType transport, int poolSize, int devicesCount, Func <DeviceClient, string, MsTestLogger, Task <Task> > setDeviceReceiveMethod, ConnectionStringAuthScope authScope = ConnectionStringAuthScope.Device) { Func <DeviceClient, TestDevice, Task> initOperation = async(deviceClient, testDevice) => { Logger.Trace($"{nameof(MethodE2EPoolAmqpTests)}: Setting method for device {testDevice.Id}"); Task methodReceivedTask = await setDeviceReceiveMethod(deviceClient, MethodName, Logger).ConfigureAwait(false); }; Func <DeviceClient, TestDevice, Task> testOperation = async(deviceClient, testDevice) => { Logger.Trace($"{nameof(MethodE2EPoolAmqpTests)}: Preparing to receive method for device {testDevice.Id}"); await MethodE2ETests .ServiceSendMethodAndVerifyResponseAsync( testDevice.Id, MethodName, MethodE2ETests.DeviceResponseJson, MethodE2ETests.ServiceRequestJson, Logger) .ConfigureAwait(false); }; await PoolingOverAmqp .TestPoolAmqpAsync( _devicePrefix, transport, poolSize, devicesCount, initOperation, testOperation, null, authScope, true, Logger) .ConfigureAwait(false); }
private async Task Twin_DeviceSetsReportedPropertyAndGetsItBackPoolOverAmqp( TestDeviceType type, Client.TransportType transport, int poolSize, int devicesCount, ConnectionStringAuthScope authScope = ConnectionStringAuthScope.Device) { Func <DeviceClient, TestDevice, Task> testOperation = async(deviceClient, testDevice) => { s_log.WriteLine($"{nameof(TwinE2EPoolAmqpTests)}: Setting reported propery and verifying twin for device {testDevice.Id}"); await TwinE2ETests.Twin_DeviceSetsReportedPropertyAndGetsItBackAsync(deviceClient, Guid.NewGuid().ToString()).ConfigureAwait(false); }; await PoolingOverAmqp.TestPoolAmqpAsync( _devicePrefix, transport, poolSize, devicesCount, null, testOperation, null, authScope, true).ConfigureAwait(false); }
public const int TestSuccessRate = 80; // 4 out of 5 (80%) test runs should pass (even after accounting for network instability issues). public static async Task TestPoolAmqpAsync( string devicePrefix, Client.TransportType transport, int poolSize, int devicesCount, Func <DeviceClient, TestDevice, Task> initOperation, Func <DeviceClient, TestDevice, Task> testOperation, Func <Task> cleanupOperation, ConnectionStringAuthScope authScope, bool ignoreConnectionStatus, MsTestLogger logger) { var transportSettings = new ITransportSettings[] { new AmqpTransportSettings(transport) { AmqpConnectionPoolSettings = new AmqpConnectionPoolSettings() { MaxPoolSize = unchecked ((uint)poolSize), Pooling = true } } }; int totalRuns = 0; int successfulRuns = 0; int currentSuccessRate = 0; bool reRunTest = false; IList <TestDevice> testDevices = new List <TestDevice>(); IList <DeviceClient> deviceClients = new List <DeviceClient>(); IList <AmqpConnectionStatusChange> amqpConnectionStatuses = new List <AmqpConnectionStatusChange>(); IList <Task> operations = new List <Task>(); do { totalRuns++; // Arrange // Initialize the test device client instances // Set the device client connection status change handler logger.Trace($">>> {nameof(PoolingOverAmqp)} Initializing Device Clients for multiplexing test - Test run {totalRuns}"); for (int i = 0; i < devicesCount; i++) { TestDevice testDevice = await TestDevice.GetTestDeviceAsync(logger, $"{devicePrefix}_{i}_").ConfigureAwait(false); DeviceClient deviceClient = testDevice.CreateDeviceClient(transportSettings, authScope); var amqpConnectionStatusChange = new AmqpConnectionStatusChange(logger); deviceClient.SetConnectionStatusChangesHandler(amqpConnectionStatusChange.ConnectionStatusChangesHandler); testDevices.Add(testDevice); deviceClients.Add(deviceClient); amqpConnectionStatuses.Add(amqpConnectionStatusChange); if (initOperation != null) { operations.Add(initOperation(deviceClient, testDevice)); } } await Task.WhenAll(operations).ConfigureAwait(false); operations.Clear(); try { for (int i = 0; i < devicesCount; i++) { operations.Add(testOperation(deviceClients[i], testDevices[i])); } await Task.WhenAll(operations).ConfigureAwait(false); operations.Clear(); // Close the device client instances and verify the connection status change checks bool deviceConnectionStatusAsExpected = true; for (int i = 0; i < devicesCount; i++) { await deviceClients[i].CloseAsync().ConfigureAwait(false); if (!ignoreConnectionStatus) { // The connection status change count should be 2: connect (open) and disabled (close) if (amqpConnectionStatuses[i].ConnectionStatusChangesHandlerCount != 2) { deviceConnectionStatusAsExpected = false; } // The connection status should be "Disabled", with connection status change reason "Client_close" Assert.AreEqual( ConnectionStatus.Disabled, amqpConnectionStatuses[i].LastConnectionStatus, $"The actual connection status is = {amqpConnectionStatuses[i].LastConnectionStatus}"); Assert.AreEqual( ConnectionStatusChangeReason.Client_Close, amqpConnectionStatuses[i].LastConnectionStatusChangeReason, $"The actual connection status change reason is = {amqpConnectionStatuses[i].LastConnectionStatusChangeReason}"); } } if (deviceConnectionStatusAsExpected) { successfulRuns++; } currentSuccessRate = (int)((double)successfulRuns / totalRuns * 100); reRunTest = currentSuccessRate < TestSuccessRate; } finally { // Close the service-side components and dispose the device client instances. if (cleanupOperation != null) { await cleanupOperation().ConfigureAwait(false); } foreach (DeviceClient deviceClient in deviceClients) { deviceClient.Dispose(); } // Clean up the local lists testDevices.Clear(); deviceClients.Clear(); amqpConnectionStatuses.Clear(); } } while (reRunTest && totalRuns < MaxTestRunCount); Assert.IsFalse(reRunTest, $"Device client instances got disconnected in {totalRuns - successfulRuns} runs out of {totalRuns}; current testSuccessRate = {currentSuccessRate}%."); }
public DeviceClient CreateDeviceClient(ITransportSettings[] transportSettings, ConnectionStringAuthScope authScope = ConnectionStringAuthScope.Device, ClientOptions options = default) { DeviceClient deviceClient = null; if (AuthenticationMethod == null) { if (authScope == ConnectionStringAuthScope.Device) { deviceClient = DeviceClient.CreateFromConnectionString(ConnectionString, transportSettings, options); s_logger.Trace($"{nameof(CreateDeviceClient)}: Created {nameof(DeviceClient)} {Device.Id} from device connection string: ID={TestLogger.IdOf(deviceClient)}"); } else { deviceClient = DeviceClient.CreateFromConnectionString(Configuration.IoTHub.ConnectionString, Device.Id, transportSettings, options); s_logger.Trace($"{nameof(CreateDeviceClient)}: Created {nameof(DeviceClient)} {Device.Id} from IoTHub connection string: ID={TestLogger.IdOf(deviceClient)}"); } } else { deviceClient = DeviceClient.Create(IoTHubHostName, AuthenticationMethod, transportSettings, options); s_logger.Trace($"{nameof(CreateDeviceClient)}: Created {nameof(DeviceClient)} {Device.Id} from IAuthenticationMethod: ID={TestLogger.IdOf(deviceClient)}"); } return(deviceClient); }
private async Task ReceiveMessageUsingCallbackAndUnsubscribePoolOverAmqpAsync( Client.TransportType transport, int poolSize, int devicesCount, ConnectionStringAuthScope authScope = ConnectionStringAuthScope.Device) { // Initialize the service client var serviceClient = ServiceClient.CreateFromConnectionString(Configuration.IoTHub.ConnectionString); async Task InitOperationAsync(DeviceClient deviceClient, TestDevice testDevice, TestDeviceCallbackHandler testDeviceCallbackHandler) { await testDeviceCallbackHandler.SetMessageReceiveCallbackHandlerAsync().ConfigureAwait(false); } async Task TestOperationAsync(DeviceClient deviceClient, TestDevice testDevice, TestDeviceCallbackHandler testDeviceCallbackHandler) { var timeout = TimeSpan.FromSeconds(20); using var cts = new CancellationTokenSource(timeout); // Send a message to the device from the service. (Message firstMessage, string payload, _) = MessageReceiveE2ETests.ComposeC2dTestMessage(Logger); testDeviceCallbackHandler.ExpectedMessageSentByService = firstMessage; await serviceClient.SendAsync(testDevice.Id, firstMessage).ConfigureAwait(false); Logger.Trace($"Sent 1st C2D message from service - to be received on callback: deviceId={testDevice.Id}, messageId={firstMessage.MessageId}"); // The message should be received on the callback, while a call to ReceiveAsync() should return null. Client.Message receivedMessage = await deviceClient.ReceiveAsync(timeout).ConfigureAwait(false); await testDeviceCallbackHandler.WaitForReceiveMessageCallbackAsync(cts.Token).ConfigureAwait(false); receivedMessage.Should().BeNull(); // Now unsubscribe from receiving c2d messages over the callback. await deviceClient.SetReceiveMessageHandlerAsync(null, deviceClient).ConfigureAwait(false); // Send a message to the device from the service. (Message secondMessage, _, _) = MessageReceiveE2ETests.ComposeC2dTestMessage(Logger); await serviceClient.SendAsync(testDevice.Id, secondMessage).ConfigureAwait(false); Logger.Trace($"Sent 2nd C2D message from service - to be received on polling ReceiveAsync(): deviceId={testDevice.Id}, messageId={secondMessage.MessageId}"); // This time, the message should not be received on the callback, rather it should be received on a call to ReceiveAsync(). Func <Task> receiveMessageOverCallback = async() => { await testDeviceCallbackHandler.WaitForReceiveMessageCallbackAsync(cts.Token).ConfigureAwait(false); }; Client.Message message = await deviceClient.ReceiveAsync(timeout).ConfigureAwait(false); message.MessageId.Should().Be(secondMessage.MessageId); receiveMessageOverCallback.Should().Throw <OperationCanceledException>(); } async Task CleanupOperationAsync() { await serviceClient.CloseAsync().ConfigureAwait(false); serviceClient.Dispose(); } await PoolingOverAmqp .TestPoolAmqpAsync( DevicePrefix, transport, poolSize, devicesCount, InitOperationAsync, TestOperationAsync, CleanupOperationAsync, authScope, true, Logger) .ConfigureAwait(false); }
private async Task ReceiveMessageUsingCallbackRecoveryPoolOverAmqpAsync( TestDeviceType type, Client.TransportType transport, int poolSize, int devicesCount, string faultType, string reason, int delayInSec = FaultInjection.DefaultDelayInSec, int durationInSec = FaultInjection.DefaultDurationInSec, ConnectionStringAuthScope authScope = ConnectionStringAuthScope.Device, string proxyAddress = null) { // Initialize the service client var serviceClient = ServiceClient.CreateFromConnectionString(Configuration.IoTHub.ConnectionString); async Task InitOperationAsync(DeviceClient deviceClient, TestDevice testDevice, TestDeviceCallbackHandler testDeviceCallbackHandler) { await testDeviceCallbackHandler.SetMessageReceiveCallbackHandlerAsync().ConfigureAwait(false); } async Task TestOperationAsync(DeviceClient deviceClient, TestDevice testDevice, TestDeviceCallbackHandler testDeviceCallbackHandler) { var timeout = TimeSpan.FromSeconds(20); using var cts = new CancellationTokenSource(timeout); (Message msg, string payload, string p1Value) = MessageReceiveE2ETests.ComposeC2dTestMessage(Logger); testDeviceCallbackHandler.ExpectedMessageSentByService = msg; await serviceClient.SendAsync(testDevice.Id, msg).ConfigureAwait(false); Logger.Trace($"{nameof(FaultInjectionPoolAmqpTests)}: Sent message to device {testDevice.Id}: payload='{payload}' p1Value='{p1Value}'"); Client.Message receivedMessage = await deviceClient.ReceiveAsync(timeout).ConfigureAwait(false); await testDeviceCallbackHandler.WaitForReceiveMessageCallbackAsync(cts.Token).ConfigureAwait(false); receivedMessage.Should().BeNull(); } async Task CleanupOperationAsync(IList <DeviceClient> deviceClients) { await serviceClient.CloseAsync().ConfigureAwait(false); serviceClient.Dispose(); foreach (DeviceClient deviceClient in deviceClients) { deviceClient.Dispose(); } } await FaultInjectionPoolingOverAmqp .TestFaultInjectionPoolAmqpAsync( MessageReceive_DevicePrefix, transport, proxyAddress, poolSize, devicesCount, faultType, reason, delayInSec, durationInSec, InitOperationAsync, TestOperationAsync, CleanupOperationAsync, authScope, Logger) .ConfigureAwait(false); }
public static async Task TestFaultInjectionPoolAmqpAsync( string devicePrefix, Client.TransportType transport, int poolSize, int devicesCount, string faultType, string reason, int delayInSec, int durationInSec, Func <DeviceClient, TestDevice, Task> initOperation, Func <DeviceClient, TestDevice, Task> testOperation, Func <IList <DeviceClient>, Task> cleanupOperation, ConnectionStringAuthScope authScope) { var transportSettings = new ITransportSettings[] { new AmqpTransportSettings(transport) { AmqpConnectionPoolSettings = new AmqpConnectionPoolSettings() { MaxPoolSize = unchecked ((uint)poolSize), Pooling = true } } }; IList <TestDevice> testDevices = new List <TestDevice>(); IList <DeviceClient> deviceClients = new List <DeviceClient>(); IList <AmqpConnectionStatusChange> amqpConnectionStatuses = new List <AmqpConnectionStatusChange>(); IList <Task> operations = new List <Task>(); // Arrange // Initialize the test device client instances // Set the device client connection status change handler s_log.WriteLine($">>> {nameof(FaultInjectionPoolingOverAmqp)} Initializing Device Clients for multiplexing test."); for (int i = 0; i < devicesCount; i++) { TestDevice testDevice = await TestDevice.GetTestDeviceAsync($"{devicePrefix}_{i}_").ConfigureAwait(false); DeviceClient deviceClient = testDevice.CreateDeviceClient(transportSettings, authScope); var amqpConnectionStatusChange = new AmqpConnectionStatusChange(testDevice.Id); deviceClient.SetConnectionStatusChangesHandler(amqpConnectionStatusChange.ConnectionStatusChangesHandler); testDevices.Add(testDevice); deviceClients.Add(deviceClient); amqpConnectionStatuses.Add(amqpConnectionStatusChange); operations.Add(initOperation(deviceClient, testDevice)); } await Task.WhenAll(operations).ConfigureAwait(false); operations.Clear(); var watch = new Stopwatch(); try { // Act-Assert // Perform the test operation and verify the operation is successful // Perform baseline test operation for (int i = 0; i < devicesCount; i++) { s_log.WriteLine($">>> {nameof(FaultInjectionPoolingOverAmqp)}: Performing baseline operation for device {i}."); operations.Add(testOperation(deviceClients[i], testDevices[i])); } await Task.WhenAll(operations).ConfigureAwait(false); operations.Clear(); // Inject the fault into device 0 watch.Start(); s_log.WriteLine($"{nameof(FaultInjectionPoolingOverAmqp)}: Device {0} Requesting fault injection type={faultType} reason={reason}, delay={delayInSec}s, duration={durationInSec}s"); var faultInjectionMessage = FaultInjection.ComposeErrorInjectionProperties(faultType, reason, delayInSec, durationInSec); await deviceClients[0].SendEventAsync(faultInjectionMessage).ConfigureAwait(false); int delay = FaultInjection.WaitForReconnectMilliseconds - (int)watch.ElapsedMilliseconds; if (delay < 0) { delay = 0; } s_log.WriteLine($"{nameof(FaultInjectionPoolingOverAmqp)}: Waiting for fault injection to be active and device to be connected: {delay}ms"); await Task.Delay(delay).ConfigureAwait(false); // Perform the test operation for all devices for (int i = 0; i < devicesCount; i++) { s_log.WriteLine($">>> {nameof(FaultInjectionPoolingOverAmqp)}: Performing test operation for device {i}."); operations.Add(testOperation(deviceClients[i], testDevices[i])); } await Task.WhenAll(operations).ConfigureAwait(false); operations.Clear(); // Close the device client instances for (int i = 0; i < devicesCount; i++) { operations.Add(deviceClients[i].CloseAsync()); } await Task.WhenAll(operations).ConfigureAwait(false); operations.Clear(); // Verify the connection status change checks. // For all of the devices - last connection status should be "Disabled", with reason "Client_close" for (int i = 0; i < devicesCount; i++) { // For the faulted device [device 0] - verify the connection status change count. if (i == 0) { if (FaultInjection.FaultShouldDisconnect(faultType)) { // 4 is the minimum notification count: connect, fault, reconnect, disable. Assert.IsTrue(amqpConnectionStatuses[i].ConnectionStatusChangesHandlerCount >= 4, $"The actual connection status change count for faulted device[0] is = {amqpConnectionStatuses[i].ConnectionStatusChangesHandlerCount}"); } else { // 2 is the minimum notification count: connect, disable. Assert.IsTrue(amqpConnectionStatuses[i].ConnectionStatusChangesHandlerCount == 2, $"The actual connection status change count for for faulted device[0] is = {amqpConnectionStatuses[i].ConnectionStatusChangesHandlerCount}"); } } Assert.AreEqual(ConnectionStatus.Disabled, amqpConnectionStatuses[i].LastConnectionStatus); Assert.AreEqual(ConnectionStatusChangeReason.Client_Close, amqpConnectionStatuses[i].LastConnectionStatusChangeReason); } } finally { // Close the service-side components and dispose the device client instances. await cleanupOperation(deviceClients).ConfigureAwait(false); watch.Stop(); int timeToFinishFaultInjection = durationInSec * 1000 - (int)watch.ElapsedMilliseconds; if (timeToFinishFaultInjection > 0) { s_log.WriteLine($"{nameof(FaultInjection)}: Waiting {timeToFinishFaultInjection}ms to ensure that FaultInjection duration passed."); await Task.Delay(timeToFinishFaultInjection).ConfigureAwait(false); } } }
private async Task DeviceCombinedClientOperations( Client.TransportType transport, int poolSize, int devicesCount, ConnectionStringAuthScope authScope) { // Initialize service client for service-side operations ServiceClient serviceClient = ServiceClient.CreateFromConnectionString(Configuration.IoTHub.ConnectionString); // Message payload for C2D operation Dictionary <string, List <string> > messagesSent = new Dictionary <string, List <string> >(); // Twin properties Dictionary <string, List <string> > twinPropertyMap = new Dictionary <string, List <string> >(); Func <DeviceClient, TestDevice, Task> initOperation = async(deviceClient, testDevice) => { IList <Task> initOperations = new List <Task>(); // Send C2D Message _log.WriteLine($"{nameof(CombinedClientOperationsMultiplexingOverAmqpTests)}: Send C2D for device={testDevice.Id}"); (Message msg, string messageId, string payload, string p1Value) = MessageReceiveE2ETests.ComposeC2DTestMessage(); messagesSent.Add(testDevice.Id, new List <string> { payload, p1Value }); var sendC2DMessage = serviceClient.SendAsync(testDevice.Id, msg); initOperations.Add(sendC2DMessage); // Set method handler _log.WriteLine($"{nameof(CombinedClientOperationsMultiplexingOverAmqpTests)}: Set direct method {MethodName} for device={testDevice.Id}"); var methodReceivedTask = MethodE2ETests.SetDeviceReceiveMethod(deviceClient, MethodName); initOperations.Add(methodReceivedTask); // Set the twin desired properties callback _log.WriteLine($"{nameof(CombinedClientOperationsMultiplexingOverAmqpTests)}: Set desired property callback for device={testDevice.Id}"); var propName = Guid.NewGuid().ToString(); var propValue = Guid.NewGuid().ToString(); twinPropertyMap.Add(testDevice.Id, new List <string> { propName, propValue }); var updateReceivedTask = TwinE2ETests.SetTwinPropertyUpdateCallbackHandlerAsync(deviceClient, propName, propValue); initOperations.Add(updateReceivedTask); await Task.WhenAll(initOperations).ConfigureAwait(false); }; Func <DeviceClient, TestDevice, Task> testOperation = async(deviceClient, testDevice) => { IList <Task> clientOperations = new List <Task>(); await deviceClient.OpenAsync().ConfigureAwait(false); // D2C Operation _log.WriteLine($"{nameof(CombinedClientOperationsMultiplexingOverAmqpTests)}: Operation 1: Send D2C for device={testDevice.Id}"); var sendD2CMessage = MessageSendE2ETests.SendSingleMessageAndVerifyAsync(deviceClient, testDevice.Id); clientOperations.Add(sendD2CMessage); // C2D Operation _log.WriteLine($"{nameof(CombinedClientOperationsMultiplexingOverAmqpTests)}: Operation 2: Receive C2D for device={testDevice.Id}"); List <string> msgSent = messagesSent[testDevice.Id]; var payload = msgSent[0]; var p1Value = msgSent[1]; var verifyDeviceClientReceivesMessage = MessageReceiveE2ETests.VerifyReceivedC2DMessageAsync(transport, deviceClient, payload, p1Value); clientOperations.Add(verifyDeviceClientReceivesMessage); // Invoke direct methods _log.WriteLine($"{nameof(CombinedClientOperationsMultiplexingOverAmqpTests)}: Operation 3: Direct methods test for device={testDevice.Id}"); var serviceInvokeMethod = MethodE2ETests.ServiceSendMethodAndVerifyResponse(testDevice.Id, MethodName, MethodE2ETests.DeviceResponseJson, MethodE2ETests.ServiceRequestJson); clientOperations.Add(serviceInvokeMethod); // Set reported twin properties _log.WriteLine($"{nameof(CombinedClientOperationsMultiplexingOverAmqpTests)}: Operation 4: Set reported property for device={testDevice.Id}"); var setReportedProperties = TwinE2ETests.Twin_DeviceSetsReportedPropertyAndGetsItBack(deviceClient); clientOperations.Add(setReportedProperties); // Receive set desired twin properties _log.WriteLine($"{nameof(CombinedClientOperationsMultiplexingOverAmqpTests)}: Operation 5: Receive desired property for device={testDevice.Id}"); List <string> twinProperties = twinPropertyMap[testDevice.Id]; var propName = twinProperties[0]; var propValue = twinProperties[1]; var updateDesiredProperties = TwinE2ETests.RegistryManagerUpdateDesiredPropertyAsync(testDevice.Id, propName, propValue); clientOperations.Add(updateDesiredProperties); await Task.WhenAll(clientOperations).ConfigureAwait(false); _log.WriteLine($"{nameof(CombinedClientOperationsMultiplexingOverAmqpTests)}: All operations completed for device={testDevice.Id}"); }; Func <IList <DeviceClient>, Task> cleanupOperation = async(deviceClients) => { await serviceClient.CloseAsync().ConfigureAwait(false); serviceClient.Dispose(); foreach (DeviceClient deviceClient in deviceClients) { deviceClient.Dispose(); } messagesSent.Clear(); twinPropertyMap.Clear(); }; await MultiplexingOverAmqp.TestMultiplexingOperationAsync( DevicePrefix, transport, poolSize, devicesCount, initOperation, testOperation, cleanupOperation).ConfigureAwait(false); }
private async Task SendMethodAndRespondMuxedOverAmqp( ConnectionStringAuthScope authScope, Client.TransportType transport, int poolSize, int devicesCount, Func <DeviceClient, Task <Task> > setDeviceReceiveMethod ) { var transportSettings = new ITransportSettings[] { new AmqpTransportSettings(transport) { AmqpConnectionPoolSettings = new AmqpConnectionPoolSettings() { MaxPoolSize = unchecked ((uint)poolSize), Pooling = true } } }; ICollection <DeviceClient> deviceClients = new List <DeviceClient>(); Dictionary <DeviceClient, int> deviceClientConnectionStatusChangeCount = new Dictionary <DeviceClient, int>(); try { for (int i = 0; i < devicesCount; i++) { ConnectionStatus? lastConnectionStatus = null; ConnectionStatusChangeReason?lastConnectionStatusChangeReason = null; int setConnectionStatusChangesHandlerCount = 0; TestDevice testDevice = await TestDevice.GetTestDeviceAsync($"{DevicePrefix}_{i}_").ConfigureAwait(false); DeviceClient deviceClient = testDevice.CreateDeviceClient(transportSettings, authScope); deviceClients.Add(deviceClient); deviceClient.SetConnectionStatusChangesHandler((status, statusChangeReason) => { setConnectionStatusChangesHandlerCount++; lastConnectionStatus = status; lastConnectionStatusChangeReason = statusChangeReason; _log.WriteLine($"{nameof(MethodE2EMultiplexingTests)}.{nameof(ConnectionStatusChangesHandler)}: status={status} statusChangeReason={statusChangeReason} count={setConnectionStatusChangesHandlerCount}"); deviceClientConnectionStatusChangeCount[deviceClient] = setConnectionStatusChangesHandlerCount; }); Task methodReceivedTask = await setDeviceReceiveMethod(deviceClient).ConfigureAwait(false); await Task.WhenAll( MethodOperation.ServiceSendMethodAndVerifyResponse(testDevice.Id), methodReceivedTask).ConfigureAwait(false); } } finally { // Close and dispose all of the device client instances here foreach (DeviceClient deviceClient in deviceClients) { await deviceClient.CloseAsync().ConfigureAwait(false); // The connection status change count should be 2: connect (open) and disabled (close) Assert.IsTrue(deviceClientConnectionStatusChangeCount[deviceClient] == 2, $"Connection status change count for deviceClient {TestLogging.GetHashCode(deviceClient)} is {deviceClientConnectionStatusChangeCount[deviceClient]}"); _log.WriteLine($"{nameof(MethodE2EMultiplexingTests)}: Disposing deviceClient {TestLogging.GetHashCode(deviceClient)}"); deviceClient.Dispose(); } } }
private async Task Twin_ServiceSetsDesiredPropertyAndDeviceReceivesEventMuxedOverAmqp( ConnectionStringAuthScope authScope, Client.TransportType transport, int poolSize, int devicesCount, Func <DeviceClient, string, string, Task <Task> > setTwinPropertyUpdateCallbackAsync ) { var propName = Guid.NewGuid().ToString(); var propValue = Guid.NewGuid().ToString(); var transportSettings = new ITransportSettings[] { new AmqpTransportSettings(transport) { AmqpConnectionPoolSettings = new AmqpConnectionPoolSettings() { MaxPoolSize = unchecked ((uint)poolSize), Pooling = true } } }; ICollection <DeviceClient> deviceClients = new List <DeviceClient>(); Dictionary <DeviceClient, int> deviceClientConnectionStatusChangeCount = new Dictionary <DeviceClient, int>(); try { _log.WriteLine($"{nameof(TwinE2EMultiplexingTests)}: Starting the test execution for {devicesCount} devices"); for (int i = 0; i < devicesCount; i++) { ConnectionStatus? lastConnectionStatus = null; ConnectionStatusChangeReason?lastConnectionStatusChangeReason = null; int setConnectionStatusChangesHandlerCount = 0; TestDevice testDevice = await TestDevice.GetTestDeviceAsync($"{DevicePrefix}_{i}_").ConfigureAwait(false); DeviceClient deviceClient = testDevice.CreateDeviceClient(transportSettings, authScope); deviceClients.Add(deviceClient); deviceClient.SetConnectionStatusChangesHandler((status, statusChangeReason) => { setConnectionStatusChangesHandlerCount++; lastConnectionStatus = status; lastConnectionStatusChangeReason = statusChangeReason; _log.WriteLine($"{nameof(TwinE2EMultiplexingTests)}.{nameof(ConnectionStatusChangesHandler)}: status={status} statusChangeReason={statusChangeReason} count={setConnectionStatusChangesHandlerCount}"); deviceClientConnectionStatusChangeCount[deviceClient] = setConnectionStatusChangesHandlerCount; }); _log.WriteLine($"{nameof(Twin_ServiceSetsDesiredPropertyAndDeviceReceivesEventMuxedOverAmqp)}: name={propName}, value={propValue}"); Task updateReceivedTask = await setTwinPropertyUpdateCallbackAsync(deviceClient, propName, propValue).ConfigureAwait(false); await Task.WhenAll( TwinOperation.RegistryManagerUpdateDesiredPropertyAsync(testDevice.Id, propName, propValue), updateReceivedTask).ConfigureAwait(false); } } finally { // Close and dispose all of the device client instances here foreach (DeviceClient deviceClient in deviceClients) { await deviceClient.CloseAsync().ConfigureAwait(false); // The connection status change count should be 2: connect (open) and disabled (close) Assert.IsTrue(deviceClientConnectionStatusChangeCount[deviceClient] == 2); _log.WriteLine($"{nameof(TwinE2EMultiplexingTests)}: Disposing deviceClient {TestLogging.GetHashCode(deviceClient)}"); deviceClient.Dispose(); } } }
private async Task SendMessageMuxedOverAmqp( TestDeviceType type, Client.TransportType transport, int poolSize, int devicesCount, ConnectionStringAuthScope authScope = ConnectionStringAuthScope.Device) { var transportSettings = new ITransportSettings[] { new AmqpTransportSettings(transport) { AmqpConnectionPoolSettings = new AmqpConnectionPoolSettings() { MaxPoolSize = unchecked ((uint)poolSize), Pooling = true } } }; ICollection <DeviceClient> deviceClients = new List <DeviceClient>(); Dictionary <DeviceClient, int> deviceClientConnectionStatusChangeCount = new Dictionary <DeviceClient, int>(); try { _log.WriteLine($"{nameof(MessageSendE2EMultiplexingTests)}: Starting the test execution for {devicesCount} devices"); for (int i = 0; i < devicesCount; i++) { ConnectionStatus? lastConnectionStatus = null; ConnectionStatusChangeReason?lastConnectionStatusChangeReason = null; int setConnectionStatusChangesHandlerCount = 0; TestDevice testDevice = await TestDevice.GetTestDeviceAsync($"{DevicePrefix}_{i}_", type).ConfigureAwait(false); DeviceClient deviceClient = testDevice.CreateDeviceClient(transportSettings, authScope); deviceClients.Add(deviceClient); deviceClient.SetConnectionStatusChangesHandler((status, statusChangeReason) => { setConnectionStatusChangesHandlerCount++; lastConnectionStatus = status; lastConnectionStatusChangeReason = statusChangeReason; _log.WriteLine($"{nameof(MessageSendE2EMultiplexingTests)}.{nameof(ConnectionStatusChangesHandler)}: status={status} statusChangeReason={statusChangeReason} count={setConnectionStatusChangesHandlerCount}"); deviceClientConnectionStatusChangeCount[deviceClient] = setConnectionStatusChangesHandlerCount; }); _log.WriteLine($"{nameof(MessageSendE2EMultiplexingTests)}: Preparing to send message for device {i}"); await deviceClient.OpenAsync().ConfigureAwait(false); await MessageSend.SendSingleMessageAndVerifyAsync(deviceClient, testDevice.Id).ConfigureAwait(false); } } finally { // Close and dispose all of the device client instances here foreach (DeviceClient deviceClient in deviceClients) { await deviceClient.CloseAsync().ConfigureAwait(false); // The connection status change count should be 2: connect (open) and disabled (close) Assert.IsTrue(deviceClientConnectionStatusChangeCount[deviceClient] == 2, $"Connection status change count for deviceClient {TestLogging.GetHashCode(deviceClient)} is {deviceClientConnectionStatusChangeCount[deviceClient]}"); _log.WriteLine($"{nameof(MessageSendE2EMultiplexingTests)}: Disposing deviceClient {TestLogging.GetHashCode(deviceClient)}"); deviceClient.Dispose(); } } }
public static async Task TestFaultInjectionPoolAmqpAsync( string devicePrefix, Client.TransportType transport, string proxyAddress, int poolSize, int devicesCount, string faultType, string reason, int delayInSec, int durationInSec, Func <DeviceClient, TestDevice, TestDeviceCallbackHandler, Task> initOperation, Func <DeviceClient, TestDevice, TestDeviceCallbackHandler, Task> testOperation, Func <IList <DeviceClient>, Task> cleanupOperation, ConnectionStringAuthScope authScope, MsTestLogger logger) { var transportSettings = new ITransportSettings[] { new AmqpTransportSettings(transport) { AmqpConnectionPoolSettings = new AmqpConnectionPoolSettings() { MaxPoolSize = unchecked ((uint)poolSize), Pooling = true, }, Proxy = proxyAddress == null ? null : new WebProxy(proxyAddress), } }; IList <TestDevice> testDevices = new List <TestDevice>(); IList <DeviceClient> deviceClients = new List <DeviceClient>(); IList <TestDeviceCallbackHandler> testDeviceCallbackHandlers = new List <TestDeviceCallbackHandler>(); IList <AmqpConnectionStatusChange> amqpConnectionStatuses = new List <AmqpConnectionStatusChange>(); IList <Task> operations = new List <Task>(); // Arrange // Initialize the test device client instances // Set the device client connection status change handler logger.Trace($">>> {nameof(FaultInjectionPoolingOverAmqp)} Initializing Device Clients for multiplexing test."); for (int i = 0; i < devicesCount; i++) { TestDevice testDevice = await TestDevice.GetTestDeviceAsync(logger, $"{devicePrefix}_{i}_").ConfigureAwait(false); DeviceClient deviceClient = testDevice.CreateDeviceClient(transportSettings, authScope); var amqpConnectionStatusChange = new AmqpConnectionStatusChange(testDevice.Id, logger); deviceClient.SetConnectionStatusChangesHandler(amqpConnectionStatusChange.ConnectionStatusChangesHandler); var testDeviceCallbackHandler = new TestDeviceCallbackHandler(deviceClient, testDevice, logger); testDevices.Add(testDevice); deviceClients.Add(deviceClient); testDeviceCallbackHandlers.Add(testDeviceCallbackHandler); amqpConnectionStatuses.Add(amqpConnectionStatusChange); operations.Add(initOperation(deviceClient, testDevice, testDeviceCallbackHandler)); } await Task.WhenAll(operations).ConfigureAwait(false); operations.Clear(); var watch = new Stopwatch(); try { // Act-Assert // Perform the test operation and verify the operation is successful // Perform baseline test operation for (int i = 0; i < devicesCount; i++) { logger.Trace($">>> {nameof(FaultInjectionPoolingOverAmqp)}: Performing baseline operation for device {i}."); operations.Add(testOperation(deviceClients[i], testDevices[i], testDeviceCallbackHandlers[i])); } await Task.WhenAll(operations).ConfigureAwait(false); operations.Clear(); int countBeforeFaultInjection = amqpConnectionStatuses[0].ConnectionStatusChangeCount; // Inject the fault into device 0 watch.Start(); logger.Trace($"{nameof(FaultInjectionPoolingOverAmqp)}: {testDevices[0].Id} Requesting fault injection type={faultType} reason={reason}, delay={delayInSec}s, duration={durationInSec}s"); var faultInjectionMessage = FaultInjection.ComposeErrorInjectionProperties(faultType, reason, delayInSec, durationInSec); await deviceClients[0].SendEventAsync(faultInjectionMessage).ConfigureAwait(false); logger.Trace($"{nameof(FaultInjection)}: Waiting for fault injection to be active: {delayInSec} seconds."); await Task.Delay(TimeSpan.FromSeconds(delayInSec)).ConfigureAwait(false); // For disconnect type faults, the faulted device should disconnect and all devices should recover. if (FaultInjection.FaultShouldDisconnect(faultType)) { logger.Trace($"{nameof(FaultInjectionPoolingOverAmqp)}: Confirming fault injection has been actived."); // Check that service issued the fault to the faulting device [device 0] bool isFaulted = false; for (int i = 0; i < FaultInjection.LatencyTimeBufferInSec; i++) { if (amqpConnectionStatuses[0].ConnectionStatusChangeCount > countBeforeFaultInjection) { isFaulted = true; break; } await Task.Delay(TimeSpan.FromSeconds(1)).ConfigureAwait(false); } Assert.IsTrue(isFaulted, $"The device {testDevices[0].Id} did not get faulted with fault type: {faultType}"); logger.Trace($"{nameof(FaultInjectionPoolingOverAmqp)}: Confirmed fault injection has been actived."); // Check all devices are back online logger.Trace($"{nameof(FaultInjectionPoolingOverAmqp)}: Confirming all devices back online."); bool notRecovered = true; int j = 0; for (int i = 0; notRecovered && i < durationInSec + FaultInjection.LatencyTimeBufferInSec; i++) { notRecovered = false; for (j = 0; j < devicesCount; j++) { if (amqpConnectionStatuses[j].LastConnectionStatus != ConnectionStatus.Connected) { await Task.Delay(TimeSpan.FromSeconds(1)).ConfigureAwait(false); notRecovered = true; break; } } } if (notRecovered) { Assert.Fail($"{testDevices[j].Id} did not reconnect."); } logger.Trace($"{nameof(FaultInjectionPoolingOverAmqp)}: Confirmed all devices back online."); // Perform the test operation for all devices for (int i = 0; i < devicesCount; i++) { logger.Trace($">>> {nameof(FaultInjectionPoolingOverAmqp)}: Performing test operation for device {i}."); operations.Add(testOperation(deviceClients[i], testDevices[i], testDeviceCallbackHandlers[i])); } await Task.WhenAll(operations).ConfigureAwait(false); operations.Clear(); } else { logger.Trace($"{nameof(FaultInjectionPoolingOverAmqp)}: Performing test operation while fault injection is being activated."); // Perform the test operation for the faulted device multi times. for (int i = 0; i < FaultInjection.LatencyTimeBufferInSec; i++) { logger.Trace($">>> {nameof(FaultInjectionPoolingOverAmqp)}: Performing test operation for device 0 - Run {i}."); await testOperation(deviceClients[0], testDevices[0], testDeviceCallbackHandlers[0]).ConfigureAwait(false); await Task.Delay(TimeSpan.FromSeconds(1)).ConfigureAwait(false); } } // Close the device client instances for (int i = 0; i < devicesCount; i++) { operations.Add(deviceClients[i].CloseAsync()); } await Task.WhenAll(operations).ConfigureAwait(false); operations.Clear(); // Verify the connection status change checks. // For all of the devices - last connection status should be "Disabled", with reason "Client_close" for (int i = 0; i < devicesCount; i++) { // For the faulted device [device 0] - verify the connection status change count. if (i == 0) { if (FaultInjection.FaultShouldDisconnect(faultType)) { // 4 is the minimum notification count: connect, fault, reconnect, disable. Assert.IsTrue(amqpConnectionStatuses[i].ConnectionStatusChangeCount >= 4, $"The expected connection status change count for {testDevices[i].Id} should equals or greater than 4 but was {amqpConnectionStatuses[i].ConnectionStatusChangeCount}"); } else { // 2 is the minimum notification count: connect, disable. Assert.IsTrue(amqpConnectionStatuses[i].ConnectionStatusChangeCount >= 2, $"The expected connection status change count for {testDevices[i].Id} should be 2 but was {amqpConnectionStatuses[i].ConnectionStatusChangeCount}"); } } Assert.AreEqual(ConnectionStatus.Disabled, amqpConnectionStatuses[i].LastConnectionStatus, $"The expected connection status should be {ConnectionStatus.Disabled} but was {amqpConnectionStatuses[i].LastConnectionStatus}"); Assert.AreEqual(ConnectionStatusChangeReason.Client_Close, amqpConnectionStatuses[i].LastConnectionStatusChangeReason, $"The expected connection status change reason should be {ConnectionStatusChangeReason.Client_Close} but was {amqpConnectionStatuses[i].LastConnectionStatusChangeReason}"); } } finally { // Close the service-side components and dispose the device client instances. await cleanupOperation(deviceClients).ConfigureAwait(false); watch.Stop(); int timeToFinishFaultInjection = durationInSec * 1000 - (int)watch.ElapsedMilliseconds; if (timeToFinishFaultInjection > 0) { logger.Trace($"{nameof(FaultInjection)}: Waiting {timeToFinishFaultInjection}ms to ensure that FaultInjection duration passed."); await Task.Delay(timeToFinishFaultInjection).ConfigureAwait(false); } } }
private async Task DeviceCombinedClientOperations( Client.TransportType transport, int poolSize, int devicesCount, ConnectionStringAuthScope authScope ) { var transportSettings = new ITransportSettings[] { new AmqpTransportSettings(transport) { AmqpConnectionPoolSettings = new AmqpConnectionPoolSettings() { MaxPoolSize = unchecked ((uint)poolSize), Pooling = true } } }; // Initialize service client for service-side operations ServiceClient serviceClient = ServiceClient.CreateFromConnectionString(Configuration.IoTHub.ConnectionString); ICollection <DeviceClient> deviceClients = new List <DeviceClient>(); Dictionary <DeviceClient, int> deviceClientConnectionStatusChangeCount = new Dictionary <DeviceClient, int>(); try { _log.WriteLine($"{nameof(CombinedClientOperationsMultiplexingTests)}: Starting the test execution for {devicesCount} devices"); for (int i = 0; i < devicesCount; i++) { ConnectionStatus? lastConnectionStatus = null; ConnectionStatusChangeReason?lastConnectionStatusChangeReason = null; int setConnectionStatusChangesHandlerCount = 0; TestDevice testDevice = await TestDevice.GetTestDeviceAsync($"{DevicePrefix}_{i}_").ConfigureAwait(false); DeviceClient deviceClient = testDevice.CreateDeviceClient(transportSettings, authScope); deviceClients.Add(deviceClient); // Set the connection status change handler deviceClient.SetConnectionStatusChangesHandler((status, statusChangeReason) => { setConnectionStatusChangesHandlerCount++; lastConnectionStatus = status; lastConnectionStatusChangeReason = statusChangeReason; _log.WriteLine($"{nameof(CombinedClientOperationsMultiplexingTests)}.{nameof(ConnectionStatusChangesHandler)}: status={status} statusChangeReason={statusChangeReason} count={setConnectionStatusChangesHandlerCount}"); deviceClientConnectionStatusChangeCount[deviceClient] = setConnectionStatusChangesHandlerCount; }); // Perform D2C Operation _log.WriteLine($"{nameof(CombinedClientOperationsMultiplexingTests)}: Preparing to send message for device {i}"); await deviceClient.OpenAsync().ConfigureAwait(false); await MessageSend.SendSingleMessageAndVerifyAsync(deviceClient, testDevice.Id).ConfigureAwait(false); // Perform C2D Operation _log.WriteLine($"{nameof(CombinedClientOperationsMultiplexingTests)}: Setting the device {i} to receive C2D message."); string payload, messageId, p1Value; Message msg = MessageReceive.ComposeC2DTestMessage(out payload, out messageId, out p1Value); await serviceClient.SendAsync(testDevice.Id, msg).ConfigureAwait(false); await MessageReceive.VerifyReceivedC2DMessageAsync(transport, deviceClient, payload, p1Value).ConfigureAwait(false); // Invoke direct methods _log.WriteLine($"{nameof(CombinedClientOperationsMultiplexingTests)}: Testing direct methods for device {i}"); Task methodReceivedTask = await MethodOperation.SetDeviceReceiveMethod(deviceClient).ConfigureAwait(false); await Task.WhenAll( MethodOperation.ServiceSendMethodAndVerifyResponse(testDevice.Id), methodReceivedTask).ConfigureAwait(false); // Set reported twin properties _log.WriteLine($"{nameof(CombinedClientOperationsMultiplexingTests)}: Setting reported Twin properties for device {i}"); await TwinOperation.Twin_DeviceSetsReportedPropertyAndGetsItBack(deviceClient).ConfigureAwait(false); // Receive set desired twin properties _log.WriteLine($"{nameof(CombinedClientOperationsMultiplexingTests)}: Received set desired tein properties for device {i}"); var propName = Guid.NewGuid().ToString(); var propValue = Guid.NewGuid().ToString(); Task updateReceivedTask = await TwinOperation.SetTwinPropertyUpdateCallbackHandlerAsync(deviceClient, propName, propValue).ConfigureAwait(false); await Task.WhenAll( TwinOperation.RegistryManagerUpdateDesiredPropertyAsync(testDevice.Id, propName, propValue), updateReceivedTask).ConfigureAwait(false); } } finally { // Close and dispose all of the device client instances here foreach (DeviceClient deviceClient in deviceClients) { await deviceClient.CloseAsync().ConfigureAwait(false); // The connection status change count should be 2: connect (open) and disabled (close) Assert.IsTrue(deviceClientConnectionStatusChangeCount[deviceClient] == 2); _log.WriteLine($"{nameof(MessageSendE2EMultiplexingTests)}: Disposing deviceClient {TestLogging.GetHashCode(deviceClient)}"); deviceClient.Dispose(); } } }
private async Task SendMethodAndRespondRecoveryPoolOverAmqpAsync( TestDeviceType type, Client.TransportType transport, int poolSize, int devicesCount, Func <DeviceClient, string, Task <Task> > setDeviceReceiveMethod, string faultType, string reason, int delayInSec = FaultInjection.DefaultDelayInSec, int durationInSec = FaultInjection.DefaultDurationInSec, ConnectionStringAuthScope authScope = ConnectionStringAuthScope.Device) { var testDevicesWithCallbackHandler = new Dictionary <string, TestDeviceCallbackHandler>(); Func <DeviceClient, TestDevice, Task> initOperation = async(deviceClient, testDevice) => { var testDeviceCallbackHandler = new TestDeviceCallbackHandler(deviceClient); testDevicesWithCallbackHandler.Add(testDevice.Id, testDeviceCallbackHandler); _log.WriteLine($"{nameof(MethodE2EPoolAmqpTests)}: Setting method callback handler for device {testDevice.Id}"); await testDeviceCallbackHandler .SetDeviceReceiveMethodAsync(MethodName, MethodE2ETests.DeviceResponseJson, MethodE2ETests.ServiceRequestJson) .ConfigureAwait(false); }; Func <DeviceClient, TestDevice, Task> testOperation = async(deviceClient, testDevice) => { TestDeviceCallbackHandler testDeviceCallbackHandler = testDevicesWithCallbackHandler[testDevice.Id]; using var cts = new CancellationTokenSource(FaultInjection.RecoveryTimeMilliseconds); _log.WriteLine($"{nameof(MethodE2EPoolAmqpTests)}: Preparing to receive method for device {testDevice.Id}"); Task serviceSendTask = MethodE2ETests.ServiceSendMethodAndVerifyResponseAsync( testDevice.Id, MethodName, MethodE2ETests.DeviceResponseJson, MethodE2ETests.ServiceRequestJson); Task methodReceivedTask = testDeviceCallbackHandler.WaitForMethodCallbackAsync(cts.Token); await Task.WhenAll(serviceSendTask, methodReceivedTask).ConfigureAwait(false); }; Func <IList <DeviceClient>, Task> cleanupOperation = async(deviceClients) => { foreach (DeviceClient deviceClient in deviceClients) { deviceClient.Dispose(); } testDevicesWithCallbackHandler.Clear(); await Task.FromResult <bool>(false).ConfigureAwait(false); }; await FaultInjectionPoolingOverAmqp .TestFaultInjectionPoolAmqpAsync( MethodDevicePrefix, transport, poolSize, devicesCount, faultType, reason, delayInSec, durationInSec, initOperation, testOperation, cleanupOperation, authScope) .ConfigureAwait(false); }