public async Task ProcessAsyncTest() { Core.IMessageConverter <IRoutingMessage> routingMessageConverter = new RoutingMessageConverter(); const string Mod1Id = "device1/module1"; const string ModEndpointId = "in1"; var deviceProxyMock = new Mock <IDeviceProxy>(); deviceProxyMock.Setup(c => c.SendMessageAsync(It.IsAny <IMessage>(), It.Is <string>((ep) => ep.Equals(ModEndpointId, StringComparison.OrdinalIgnoreCase)))) .Returns(Task.CompletedTask); deviceProxyMock.SetupGet(p => p.IsActive).Returns(true); IReadOnlyDictionary <DeviceSubscription, bool> deviceSubscriptions = new ReadOnlyDictionary <DeviceSubscription, bool>( new Dictionary <DeviceSubscription, bool> { [DeviceSubscription.ModuleMessages] = true }); var connectionManager = new Mock <IConnectionManager>(); connectionManager.Setup(c => c.GetDeviceConnection(It.IsAny <string>())).Returns(Option.Some(deviceProxyMock.Object)); connectionManager.Setup(c => c.GetSubscriptions(It.IsAny <string>())).Returns(Option.Some(deviceSubscriptions)); byte[] messageBody = Encoding.UTF8.GetBytes("Message body"); var properties = new Dictionary <string, string>() { { "Prop1", "Val1" }, { "Prop2", "Val2" }, }; var systemProperties = new Dictionary <string, string> { { SystemProperties.DeviceId, Mod1Id } }; var message1 = new RoutingMessage(TelemetryMessageSource.Instance, messageBody, properties, systemProperties); var message2 = new RoutingMessage(TelemetryMessageSource.Instance, messageBody, properties, systemProperties); var moduleEndpoint = new ModuleEndpoint($"{Mod1Id}/{ModEndpointId}", Mod1Id, ModEndpointId, connectionManager.Object, routingMessageConverter); IProcessor moduleMessageProcessor = moduleEndpoint.CreateProcessor(); ISinkResult <IRoutingMessage> result = await moduleMessageProcessor.ProcessAsync(message1, CancellationToken.None); Assert.NotNull(result); Assert.NotEmpty(result.Succeeded); Assert.Empty(result.Failed); Assert.Empty(result.InvalidDetailsList); Assert.False(result.SendFailureDetails.HasValue); ISinkResult <IRoutingMessage> resultBatch = await moduleMessageProcessor.ProcessAsync(new[] { message1, message2 }, CancellationToken.None); Assert.NotNull(resultBatch); Assert.NotEmpty(resultBatch.Succeeded); Assert.Empty(resultBatch.Failed); Assert.Empty(resultBatch.InvalidDetailsList); Assert.False(resultBatch.SendFailureDetails.HasValue); }
static IRoutingMessage GetMessage(string id) { byte[] messageBody = Encoding.UTF8.GetBytes("Message body"); var properties = new Dictionary <string, string>() { { "Prop1", "Val1" }, { "Prop2", "Val2" } }; var systemProperties = new Dictionary <string, string> { { SystemProperties.DeviceId, id } }; var message = new RoutingMessage(TelemetryMessageSource.Instance, messageBody, properties, systemProperties); return(message); }
public async Task RetryableExceptionsTest(Exception exception, bool isRetryable) { // Arrange string id = "d1"; var cloudProxy = new Mock <ICloudProxy>(); cloudProxy.Setup(c => c.SendMessageAsync(It.IsAny <IMessage>())) .ThrowsAsync(exception); var cloudEndpoint = new CloudEndpoint(Guid.NewGuid().ToString(), _ => Task.FromResult(Option.Some(cloudProxy.Object)), new RoutingMessageConverter()); IProcessor processor = cloudEndpoint.CreateProcessor(); var message = new RoutingMessage(TelemetryMessageSource.Instance, new byte[0], ImmutableDictionary <string, string> .Empty, new Dictionary <string, string> { [Core.SystemProperties.ConnectionDeviceId] = id }); // Act ISinkResult <IRoutingMessage> result = await processor.ProcessAsync(message, CancellationToken.None); // Assert Assert.NotNull(result); if (isRetryable) { Assert.Equal(1, result.Failed.Count); Assert.Equal(0, result.Succeeded.Count); Assert.Equal(0, result.InvalidDetailsList.Count); Assert.Equal(message, result.Failed.First()); } else { Assert.Equal(1, result.InvalidDetailsList.Count); Assert.Equal(0, result.Succeeded.Count); Assert.Equal(0, result.Failed.Count); Assert.Equal(message, result.InvalidDetailsList.First().Item); Assert.Equal(FailureKind.InvalidInput, result.InvalidDetailsList.First().FailureKind); } }
public async Task ProcessAsyncTest() { Core.IMessageConverter <IRoutingMessage> routingMessageConverter = new RoutingMessageConverter(); string cloudEndpointId = Guid.NewGuid().ToString(); var cloudProxyMock = new Mock <ICloudProxy>(); cloudProxyMock.Setup(c => c.SendMessageAsync(It.IsAny <IMessage>())) .Callback <IMessage>( msg => { if (msg.Properties.ContainsKey("Delay")) { Task.Delay(TimeSpan.FromSeconds(10)).Wait(); } }) .Returns(Task.CompletedTask); cloudProxyMock.SetupGet(p => p.IsActive).Returns(true); string device1Id = "device1"; string device2Id = "device2"; byte[] messageBody = Encoding.UTF8.GetBytes("Message body"); var properties = new Dictionary <string, string>() { { "Prop1", "Val1" }, { "Prop2", "Val2" } }; var device1SystemProperties = new Dictionary <string, string> { { SystemProperties.DeviceId, device1Id } }; var device2SystemProperties = new Dictionary <string, string> { { SystemProperties.DeviceId, device2Id } }; var cancelProperties = new Dictionary <string, string>() { { "Delay", "true" }, { "Prop2", "Val2" } }; var message1 = new RoutingMessage(TelemetryMessageSource.Instance, messageBody, properties, device1SystemProperties); var message2 = new RoutingMessage(TelemetryMessageSource.Instance, messageBody, properties, device2SystemProperties); var message3 = new RoutingMessage(TelemetryMessageSource.Instance, messageBody, cancelProperties, device1SystemProperties); Task <Option <ICloudProxy> > GetCloudProxy(string id) { return(Task.FromResult( id.Equals(device1Id) ? Option.Some(cloudProxyMock.Object) : Option.None <ICloudProxy>())); } var cloudEndpoint = new CloudEndpoint(cloudEndpointId, GetCloudProxy, routingMessageConverter, maxBatchSize: 1); IProcessor cloudMessageProcessor = cloudEndpoint.CreateProcessor(); ISinkResult <IRoutingMessage> result1 = await cloudMessageProcessor.ProcessAsync(message1, CancellationToken.None); Assert.NotNull(result1); Assert.NotEmpty(result1.Succeeded); Assert.Empty(result1.Failed); Assert.Empty(result1.InvalidDetailsList); Assert.False(result1.SendFailureDetails.HasValue); ISinkResult <IRoutingMessage> result2 = await cloudMessageProcessor.ProcessAsync(message2, CancellationToken.None); Assert.NotNull(result2); Assert.Empty(result2.InvalidDetailsList); Assert.NotEmpty(result2.Failed); Assert.Empty(result2.Succeeded); Assert.True(result2.SendFailureDetails.HasValue); ISinkResult <IRoutingMessage> resultBatch = await cloudMessageProcessor.ProcessAsync(new[] { message1, message2 }, CancellationToken.None); Assert.NotNull(resultBatch); Assert.Equal(1, resultBatch.Succeeded.Count); Assert.Equal(1, resultBatch.Failed.Count); Assert.Empty(resultBatch.InvalidDetailsList); Assert.True(resultBatch.SendFailureDetails.HasValue); ISinkResult <IRoutingMessage> resultBatchCancelled = await cloudMessageProcessor.ProcessAsync(new[] { message1, message2 }, new CancellationToken(true)); Assert.NotNull(resultBatchCancelled); Assert.Empty(resultBatchCancelled.Succeeded); Assert.NotEmpty(resultBatchCancelled.Failed); Assert.Empty(resultBatchCancelled.InvalidDetailsList); Assert.True(resultBatchCancelled.SendFailureDetails.HasValue); var cts = new CancellationTokenSource(TimeSpan.FromSeconds(5)); ISinkResult <IRoutingMessage> resultBatchCancelled2 = await cloudMessageProcessor.ProcessAsync(new[] { message1, message3, message1 }, cts.Token); Assert.NotNull(resultBatchCancelled2); Assert.Equal(2, resultBatchCancelled2.Succeeded.Count); Assert.Equal(1, resultBatchCancelled2.Failed.Count); Assert.Empty(resultBatchCancelled2.InvalidDetailsList); Assert.True(resultBatchCancelled2.SendFailureDetails.HasValue); }
public async Task ProcessAsync_SendThrows_Test() { Core.IMessageConverter <IRoutingMessage> routingMessageConverter = new RoutingMessageConverter(); string cloudEndpointId = Guid.NewGuid().ToString(); var cloudProxyMock = new Mock <ICloudProxy>(); cloudProxyMock.Setup(c => c.SendMessageAsync(It.IsAny <IMessage>())) .Throws <TimeoutException>(); cloudProxyMock.SetupGet(p => p.IsActive).Returns(true); string device1Id = "device1"; string device2Id = "device2"; byte[] messageBody = Encoding.UTF8.GetBytes("Message body"); var properties = new Dictionary <string, string>() { { "Prop1", "Val1" }, { "Prop2", "Val2" } }; var device1SystemProperties = new Dictionary <string, string> { { SystemProperties.DeviceId, device1Id } }; var device2SystemProperties = new Dictionary <string, string> { { SystemProperties.DeviceId, device2Id } }; var message1 = new RoutingMessage(TelemetryMessageSource.Instance, messageBody, properties, device1SystemProperties); var message2 = new RoutingMessage(TelemetryMessageSource.Instance, messageBody, properties, device2SystemProperties); Task <Option <ICloudProxy> > GetCloudProxy(string id) { return(Task.FromResult(Option.Some(cloudProxyMock.Object))); } var cloudEndpoint = new CloudEndpoint(cloudEndpointId, GetCloudProxy, routingMessageConverter); IProcessor cloudMessageProcessor = cloudEndpoint.CreateProcessor(); ISinkResult <IRoutingMessage> result = await cloudMessageProcessor.ProcessAsync(new[] { message1, message2 }, CancellationToken.None); Assert.NotNull(result); Assert.Empty(result.Succeeded); Assert.Equal(2, result.Failed.Count); Assert.Empty(result.InvalidDetailsList); Assert.True(result.SendFailureDetails.HasValue); // throw non-retryable cloudProxyMock.Setup(c => c.SendMessageAsync(It.IsAny <IMessage>())) .Throws <Exception>(); ISinkResult <IRoutingMessage> result1 = await cloudMessageProcessor.ProcessAsync(new[] { message1, message2 }, CancellationToken.None); Assert.NotNull(result1); Assert.Empty(result1.Succeeded); Assert.Empty(result1.Failed); Assert.Equal(2, result1.InvalidDetailsList.Count); Assert.True(result1.SendFailureDetails.HasValue); }
public async Task ProcessAsyncTest() { Core.IMessageConverter <IRoutingMessage> routingMessageConverter = new RoutingMessageConverter(); string cloudEndpointId = Guid.NewGuid().ToString(); var cloudProxyMock = new Mock <ICloudProxy>(); cloudProxyMock.Setup(c => c.SendMessageAsync(It.IsAny <IMessage>())) .Callback <IMessage>( msg => { if (msg.Properties.ContainsKey("Delay")) { Task.Delay(TimeSpan.FromSeconds(10)).Wait(); } }) .Returns(Task.CompletedTask); cloudProxyMock.SetupGet(p => p.IsActive).Returns(true); string device1Id = "device1"; string device2Id = "device2"; string device3Id = "device3"; byte[] messageBody = Encoding.UTF8.GetBytes("Message body"); var properties = new Dictionary <string, string>() { { "Prop1", "Val1" }, { "Prop2", "Val2" } }; var device1SystemProperties = new Dictionary <string, string> { { SystemProperties.DeviceId, device1Id } }; var device2SystemProperties = new Dictionary <string, string> { { SystemProperties.DeviceId, device2Id } }; var device3SystemProperties = new Dictionary <string, string> { { SystemProperties.DeviceId, device3Id } }; var cancelProperties = new Dictionary <string, string>() { { "Delay", "true" }, { "Prop2", "Val2" } }; var message1 = new RoutingMessage(TelemetryMessageSource.Instance, messageBody, properties, device1SystemProperties); var message2 = new RoutingMessage(TelemetryMessageSource.Instance, messageBody, properties, device2SystemProperties); var message3 = new RoutingMessage(TelemetryMessageSource.Instance, messageBody, cancelProperties, device1SystemProperties); var message4 = new RoutingMessage(TelemetryMessageSource.Instance, messageBody, properties, device3SystemProperties); Task <Try <ICloudProxy> > GetCloudProxy(string id) { if (id == device1Id) { return(Task.FromResult(Try.Success(cloudProxyMock.Object))); } else if (id == device2Id) { return(Task.FromResult(Try <ICloudProxy> .Failure(new DeviceInvalidStateException()))); } else { return(Task.FromResult(Try <ICloudProxy> .Failure(new Exception()))); } } var cloudEndpoint = new CloudEndpoint(cloudEndpointId, GetCloudProxy, routingMessageConverter, false, maxBatchSize: 1); IProcessor cloudMessageProcessor = cloudEndpoint.CreateProcessor(); ISinkResult <IRoutingMessage> result1 = await cloudMessageProcessor.ProcessAsync(message1, CancellationToken.None); Assert.NotNull(result1); Assert.NotEmpty(result1.Succeeded); Assert.Empty(result1.Failed); Assert.Empty(result1.InvalidDetailsList); Assert.False(result1.SendFailureDetails.HasValue); ISinkResult <IRoutingMessage> result2 = await cloudMessageProcessor.ProcessAsync(message2, CancellationToken.None); Assert.NotNull(result2); Assert.Empty(result2.InvalidDetailsList); Assert.NotEmpty(result2.Failed); Assert.Empty(result2.Succeeded); Assert.True(result2.SendFailureDetails.HasValue); ISinkResult <IRoutingMessage> resultBatch = await cloudMessageProcessor.ProcessAsync(new[] { message1, message2 }, CancellationToken.None); Assert.NotNull(resultBatch); Assert.Equal(1, resultBatch.Succeeded.Count); Assert.Equal(1, resultBatch.Failed.Count); Assert.Empty(resultBatch.InvalidDetailsList); Assert.True(resultBatch.SendFailureDetails.HasValue); ISinkResult <IRoutingMessage> resultBatchCancelled = await cloudMessageProcessor.ProcessAsync(new[] { message1, message2 }, new CancellationToken(true)); Assert.NotNull(resultBatchCancelled); Assert.Empty(resultBatchCancelled.Succeeded); Assert.NotEmpty(resultBatchCancelled.Failed); Assert.Empty(resultBatchCancelled.InvalidDetailsList); Assert.True(resultBatchCancelled.SendFailureDetails.HasValue); var cts = new CancellationTokenSource(TimeSpan.FromSeconds(5)); ISinkResult <IRoutingMessage> resultBatchCancelled2 = await cloudMessageProcessor.ProcessAsync(new[] { message1, message3, message1 }, cts.Token); Assert.NotNull(resultBatchCancelled2); Assert.Equal(2, resultBatchCancelled2.Succeeded.Count); Assert.Equal(1, resultBatchCancelled2.Failed.Count); Assert.Empty(resultBatchCancelled2.InvalidDetailsList); Assert.True(resultBatchCancelled2.SendFailureDetails.HasValue); // Should handle as no connection on unhandled exception ISinkResult <IRoutingMessage> result4 = await cloudMessageProcessor.ProcessAsync(message4, CancellationToken.None); Assert.NotNull(result4); Assert.Empty(result4.InvalidDetailsList); Assert.NotEmpty(result4.Failed); Assert.Empty(result4.Succeeded); Assert.True(result4.SendFailureDetails.HasValue); // Initialize CloudEndpoint with trackDeviceState=true var cloudEndpoint2 = new CloudEndpoint(cloudEndpointId, GetCloudProxy, routingMessageConverter, true, maxBatchSize: 1); var cloudMessageProcessor2 = cloudEndpoint2.CreateProcessor(); // Should fail and mark operation invalid on UnauthorizedException which will drop the message var invalidOnDeviceInvalidStateException = await cloudMessageProcessor2.ProcessAsync(message2, CancellationToken.None); Assert.NotNull(invalidOnDeviceInvalidStateException); Assert.NotEmpty(invalidOnDeviceInvalidStateException.InvalidDetailsList); Assert.Empty(invalidOnDeviceInvalidStateException.Failed); Assert.Empty(invalidOnDeviceInvalidStateException.Succeeded); Assert.True(invalidOnDeviceInvalidStateException.SendFailureDetails.HasValue); // Should fail and mark operation invalid on unhandled exception which will drop the message var invalidOnUnhandledException = await cloudMessageProcessor2.ProcessAsync(message4, CancellationToken.None); Assert.NotNull(invalidOnUnhandledException); Assert.NotEmpty(invalidOnUnhandledException.InvalidDetailsList); Assert.Empty(invalidOnUnhandledException.Failed); Assert.Empty(invalidOnUnhandledException.Succeeded); Assert.True(invalidOnUnhandledException.SendFailureDetails.HasValue); }