public async Task Callbacks()

in DeviceBridgeTests/Services/ConnectionManagerTests.cs [290:368]


        public async Task Callbacks()
        {
            using (ShimsContext.Create())
            {
                var connectionManager = CreateConnectionManager();

                // Checks that callbacks are registered even if the was already open at registration time.
                var capturedSemaphores = new List<SemaphoreSlim>();
                MethodCallback capturedMethodCallback = null;
                ReceiveMessageCallback capturedMessageCallback = null;
                DesiredPropertyUpdateCallback capturedPropertyUpdateCallback = null;
                ShimDeviceClientAndCaptureAllHandlers(handler => capturedMethodCallback = handler, handler => capturedMessageCallback = handler, handler => capturedPropertyUpdateCallback = handler);
                ShimDps("test-hub.azure.devices.net");
                TestUtils.CaptureSemaphoreOnWait((semaphore) => capturedSemaphores.Add(semaphore));
                await connectionManager.AssertDeviceConnectionOpenAsync("test-device-id");
                bool desiredPropertyCallbackCalled = false, methodCallbackCalled = false, c2dCallbackCalled = false;
                await connectionManager.SetMethodCallbackAsync("test-device-id", "method-callback-id", (_, __) =>
                {
                    methodCallbackCalled = true;
                    return Task.FromResult(new MethodResponse(200));
                });
                await connectionManager.SetMessageCallbackAsync("test-device-id", "message-callback-id", (_) =>
                {
                    c2dCallbackCalled = true;
                    return Task.FromResult(ReceiveMessageCallbackStatus.Accept);
                });
                await connectionManager.SetDesiredPropertyUpdateCallbackAsync("test-device-id", "property-callback-id", (_, __) => Task.FromResult(desiredPropertyCallbackCalled = true));
                await capturedMethodCallback(null, null);
                await capturedMessageCallback(null, null);
                await capturedPropertyUpdateCallback(null, null);
                Assert.True(desiredPropertyCallbackCalled);
                Assert.True(methodCallbackCalled);
                Assert.True(c2dCallbackCalled);

                // Check that callback Ids are correctly returned.
                Assert.AreEqual("method-callback-id", connectionManager.GetCurrentMethodCallbackId("test-device-id"));
                Assert.AreEqual("message-callback-id", connectionManager.GetCurrentMessageCallbackId("test-device-id"));
                Assert.AreEqual("property-callback-id", connectionManager.GetCurrentDesiredPropertyUpdateCallbackId("test-device-id"));

                // Check that callbacks are properly removed.
                capturedMethodCallback = null;
                capturedMessageCallback = null;
                var oldCapturedPropertyUpdateCallback = capturedPropertyUpdateCallback;
                capturedPropertyUpdateCallback = null;
                await connectionManager.RemoveMethodCallbackAsync("test-device-id");
                await connectionManager.RemoveMessageCallbackAsync("test-device-id");
                await connectionManager.RemoveDesiredPropertyUpdateCallbackAsync("test-device-id");
                Assert.IsNull(connectionManager.GetCurrentMethodCallbackId("test-device-id"));
                Assert.IsNull(connectionManager.GetCurrentMessageCallbackId("test-device-id"));
                Assert.IsNull(connectionManager.GetCurrentDesiredPropertyUpdateCallbackId("test-device-id"));
                Assert.IsNull(capturedMethodCallback);
                Assert.IsNull(capturedMessageCallback);
                Assert.AreNotEqual(capturedPropertyUpdateCallback, oldCapturedPropertyUpdateCallback); // Removing the property callback just replaces it with an empty one

                // Check that all callback register/unregister operations locked on the same semaphore as the connection open operation
                Assert.AreEqual(7 /* 1 open, 3 register, 3 unregister */, capturedSemaphores.Count);
                Assert.IsNull(capturedSemaphores.Find(s => s != capturedSemaphores[0]));

                // Check that C2D messages are acknowledged according to the callback result.
                ReceiveMessageCallbackStatus status = ReceiveMessageCallbackStatus.Accept;
                await connectionManager.SetMessageCallbackAsync("test-device-id", "message-callback-id", (_) =>
                {
                    return Task.FromResult(status);
                });
                bool completed = false, rejected = false, abandoned = false;
                Microsoft.Azure.Devices.Client.Fakes.ShimDeviceClient.AllInstances.CompleteAsyncMessage = (@this, message) => Task.FromResult(completed = true);
                Microsoft.Azure.Devices.Client.Fakes.ShimDeviceClient.AllInstances.RejectAsyncMessage = (@this, message) => Task.FromResult(rejected = true);
                Microsoft.Azure.Devices.Client.Fakes.ShimDeviceClient.AllInstances.AbandonAsyncMessage = (@this, message) => Task.FromResult(abandoned = true);
                status = ReceiveMessageCallbackStatus.Accept;
                await capturedMessageCallback(null, null);
                Assert.True(completed);
                status = ReceiveMessageCallbackStatus.Reject;
                await capturedMessageCallback(null, null);
                Assert.True(rejected);
                status = ReceiveMessageCallbackStatus.Abandon;
                await capturedMessageCallback(null, null);
                Assert.True(abandoned);
            }
        }