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);
}
}