Exemple #1
0
        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);
        }
Exemple #3
0
        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);
        }