private async Task DoNotReceiveMessagesSentBeforeSubscriptionAsync(TestDeviceType type, ITransportSettings[] settings) { TestDevice testDevice = await TestDevice.GetTestDeviceAsync(Logger, s_devicePrefix, type).ConfigureAwait(false); DeviceClient deviceClient = testDevice.CreateDeviceClient(settings); var testDeviceCallbackHandler = new TestDeviceCallbackHandler(deviceClient, testDevice, Logger); using var serviceClient = ServiceClient.CreateFromConnectionString(Configuration.IoTHub.ConnectionString); (Message msg, string payload, string p1Value) = ComposeC2dTestMessage(Logger); // Subscribe to receive C2D messages over the callback. await testDeviceCallbackHandler.SetMessageReceiveCallbackHandlerAsync().ConfigureAwait(false); // Now dispose and reinitialize the client instance. deviceClient.Dispose(); deviceClient = null; testDeviceCallbackHandler.Dispose(); testDeviceCallbackHandler = null; deviceClient = testDevice.CreateDeviceClient(settings); testDeviceCallbackHandler = new TestDeviceCallbackHandler(deviceClient, testDevice, Logger); // Open the device client - for MQTT, this will connect the device with CleanSession flag set to true. // This will ensure that messages sent before the device had subscribed to c2d topic are not delivered. await deviceClient.OpenAsync().ConfigureAwait(false); // Send the message from service. Logger.Trace($"Sending C2D message from service, messageId={msg.MessageId}"); await serviceClient.SendAsync(testDevice.Id, msg).ConfigureAwait(false); // Subscribe to receive C2D messages over the callback. testDeviceCallbackHandler.ExpectedMessageSentByService = msg; await testDeviceCallbackHandler.SetMessageReceiveCallbackHandlerAsync().ConfigureAwait(false); // Wait to ensure that the message was not received. using var cts = new CancellationTokenSource(s_tenSeconds); Func <Task> receiveMessageOverCallback = async() => { await testDeviceCallbackHandler.WaitForReceiveMessageCallbackAsync(cts.Token).ConfigureAwait(false); }; receiveMessageOverCallback.Should().Throw <OperationCanceledException>(); await serviceClient.CloseAsync().ConfigureAwait(false); deviceClient.Dispose(); testDeviceCallbackHandler.Dispose(); }
private async Task ReceiveMessagesSentBeforeSubscriptionAsync(TestDeviceType type, Client.TransportType transport) { TestDevice testDevice = await TestDevice.GetTestDeviceAsync(Logger, s_devicePrefix, type).ConfigureAwait(false); DeviceClient deviceClient = testDevice.CreateDeviceClient(transport); var testDeviceCallbackHandler = new TestDeviceCallbackHandler(deviceClient, testDevice, Logger); using var serviceClient = ServiceClient.CreateFromConnectionString(Configuration.IoTHub.ConnectionString); (Message msg, string payload, string p1Value) = ComposeC2dTestMessage(Logger); // Subscribe to receive C2D messages over the callback. await testDeviceCallbackHandler.SetMessageReceiveCallbackHandlerAsync().ConfigureAwait(false); // Now dispose and reinitialize the client instance. deviceClient.Dispose(); deviceClient = null; testDeviceCallbackHandler.Dispose(); testDeviceCallbackHandler = null; deviceClient = testDevice.CreateDeviceClient(transport); testDeviceCallbackHandler = new TestDeviceCallbackHandler(deviceClient, testDevice, Logger); // Open the device client - for MQTT, this will connect the device with CleanSession flag set to false. await deviceClient.OpenAsync().ConfigureAwait(false); // Send the message from service. Logger.Trace($"Sending C2D message from service, messageId={msg.MessageId}"); await serviceClient.SendAsync(testDevice.Id, msg).ConfigureAwait(false); // Subscribe to receive C2D messages over the callback. testDeviceCallbackHandler.ExpectedMessageSentByService = msg; await testDeviceCallbackHandler.SetMessageReceiveCallbackHandlerAsync().ConfigureAwait(false); // Wait to ensure that the message was received. using var cts = new CancellationTokenSource(s_tenSeconds); await testDeviceCallbackHandler.WaitForReceiveMessageCallbackAsync(cts.Token).ConfigureAwait(false); await serviceClient.CloseAsync().ConfigureAwait(false); deviceClient.Dispose(); testDeviceCallbackHandler.Dispose(); }
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, TestDeviceCallbackHandler, Task> initOperation, Func <DeviceClient, TestDevice, TestDeviceCallbackHandler, 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; var testDevices = new List <TestDevice>(); var deviceClients = new List <DeviceClient>(); var testDeviceCallbackHandlers = new List <TestDeviceCallbackHandler>(); var amqpConnectionStatuses = new List <AmqpConnectionStatusChange>(); var 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); var testDeviceCallbackHandler = new TestDeviceCallbackHandler(deviceClient, testDevice, logger); testDevices.Add(testDevice); deviceClients.Add(deviceClient); testDeviceCallbackHandlers.Add(testDeviceCallbackHandler); amqpConnectionStatuses.Add(amqpConnectionStatusChange); if (initOperation != null) { operations.Add(initOperation(deviceClient, testDevice, testDeviceCallbackHandler)); } } await Task.WhenAll(operations).ConfigureAwait(false); operations.Clear(); try { for (int i = 0; i < devicesCount; i++) { operations.Add(testOperation(deviceClients[i], testDevices[i], testDeviceCallbackHandlers[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); } deviceClients.ForEach(deviceClient => deviceClient.Dispose()); testDeviceCallbackHandlers.ForEach(testDeviceCallbackHandler => testDeviceCallbackHandler.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}%."); }