public async Task TransientErrorInSecondBatch_FastFailsRest_OverwritesNonTransientResult()
        {
            var batchSize = 10;

            Core.IMessageConverter <IRoutingMessage> routingMessageConverter = new RoutingMessageConverter();
            string cloudEndpointId = Guid.NewGuid().ToString();

            var cloudProxy = ThrowingCloudProxy
                             .Create()
                             .WithBatchSize(batchSize)
                             .WithReportErrorInBatch(ThrowingCloudProxy.Throw <Exception>())
                             .WithReportErrorInBatch(ThrowingCloudProxy.Throw <Client.Exceptions.IotHubException>())
                             .WithReportSuccessfulBatch()
                             .Build();

            Task <Option <ICloudProxy> > GetCloudProxy(string id) => Task.FromResult(Option.Some(cloudProxy));

            var        cloudEndpoint         = new CloudEndpoint(cloudEndpointId, GetCloudProxy, routingMessageConverter);
            IProcessor cloudMessageProcessor = cloudEndpoint.CreateProcessor();

            var sinkResult = await cloudMessageProcessor.ProcessAsync(GetMessages("device1", 3 * batchSize), CancellationToken.None);

            Assert.False(sinkResult.IsSuccessful);
            Assert.Equal(0, sinkResult.Succeeded.Count);
            Assert.Equal(2 * batchSize, sinkResult.Failed.Count);
            Assert.Equal(1 * batchSize, sinkResult.InvalidDetailsList.Count);
            Assert.True(sinkResult.SendFailureDetails.HasValue);
            Assert.Equal(FailureKind.Transient, sinkResult.SendFailureDetails.Expect(() => new Exception()).FailureKind);
        }
Example #2
0
        public async Task TransientErrorInSecondBatch_OverwritesNonTransientFailureDetails()
        {
            var batchSize = 10;

            Core.IMessageConverter <IRoutingMessage> routingMessageConverter = new RoutingMessageConverter();
            string cloudEndpointId = Guid.NewGuid().ToString();

            var cloudProxy = ThrowingCloudProxy
                             .CreateWithResponses(3, ThrowingCloudProxy.Success())
                             .Then(ThrowingCloudProxy.Throw <Exception>())                         // non-transient error
                             .ThenMany(batchSize - 4, ThrowingCloudProxy.Success())                // first batch ends here (3 success + 1 fail -> 10 - 4 to go)
                             .ThenMany(3, ThrowingCloudProxy.Success())
                             .Then(ThrowingCloudProxy.Throw <Client.Exceptions.IotHubException>()) // transient error
                             .ThenMany(batchSize - 4, ThrowingCloudProxy.Success())                // second batch ends here
                             .ThenMany(1 * batchSize, ThrowingCloudProxy.Success())
                             .Build();

            Task <Option <ICloudProxy> > GetCloudProxy(string id) => Task.FromResult(Option.Some(cloudProxy));

            var        cloudEndpoint         = new CloudEndpoint(cloudEndpointId, GetCloudProxy, routingMessageConverter);
            IProcessor cloudMessageProcessor = cloudEndpoint.CreateProcessor();

            var sinkResult = await cloudMessageProcessor.ProcessAsync(GetMessages("device1", 3 * batchSize), CancellationToken.None);

            Assert.False(sinkResult.IsSuccessful);
            Assert.Equal(batchSize, sinkResult.Succeeded.Count);
            Assert.Equal(batchSize, sinkResult.Failed.Count);
            Assert.Equal(batchSize, sinkResult.InvalidDetailsList.Count);
            Assert.True(sinkResult.SendFailureDetails.HasValue);
            Assert.Equal(FailureKind.Transient, sinkResult.SendFailureDetails.Expect(() => new Exception()).FailureKind);
        }
        public async Task NonTransientErrorInFirstBatch_LetsTryTheRest_ButReportsSendFailure()
        {
            var batchSize = 10;

            Core.IMessageConverter <IRoutingMessage> routingMessageConverter = new RoutingMessageConverter();
            string cloudEndpointId = Guid.NewGuid().ToString();

            var cloudProxy = ThrowingCloudProxy
                             .Create()
                             .WithBatchSize(batchSize)
                             .WithReportErrorInBatch(ThrowingCloudProxy.Throw <Exception>())
                             .WithReportSuccessfulBatch(2)
                             .Build();

            Task <Option <ICloudProxy> > GetCloudProxy(string id) => Task.FromResult(Option.Some(cloudProxy));

            var        cloudEndpoint         = new CloudEndpoint(cloudEndpointId, GetCloudProxy, routingMessageConverter);
            IProcessor cloudMessageProcessor = cloudEndpoint.CreateProcessor();

            var sinkResult = await cloudMessageProcessor.ProcessAsync(GetMessages("device1", 3 * batchSize), CancellationToken.None);

            Assert.True(sinkResult.IsSuccessful); // non-transient errors are ignored, but reported in SendFailureDetails
            Assert.Equal(2 * batchSize, sinkResult.Succeeded.Count);
            Assert.Equal(0, sinkResult.Failed.Count);
            Assert.Equal(batchSize, sinkResult.InvalidDetailsList.Count);
            Assert.True(sinkResult.SendFailureDetails.HasValue);
            Assert.Equal(FailureKind.InvalidInput, sinkResult.SendFailureDetails.Expect(() => new Exception()).FailureKind);
        }
        public async Task TransientErrorInFirstBatch_FastFailsRest()
        {
            var batchSize = 10;

            Core.IMessageConverter <IRoutingMessage> routingMessageConverter = new RoutingMessageConverter();
            string cloudEndpointId = Guid.NewGuid().ToString();

            var cloudProxy = ThrowingCloudProxy
                             .Create()
                             .WithBatchSize(batchSize)
                             .WithReportErrorInBatch(ThrowingCloudProxy.Throw <Client.Exceptions.IotHubException>())
                             .WithReportSuccessfulBatch(2)
                             .Build();

            Task <Try <ICloudProxy> > GetCloudProxy(string id) => Task.FromResult(Try.Success(cloudProxy));

            var        cloudEndpoint         = new CloudEndpoint(cloudEndpointId, GetCloudProxy, routingMessageConverter, true);
            IProcessor cloudMessageProcessor = cloudEndpoint.CreateProcessor();

            var sinkResult = await cloudMessageProcessor.ProcessAsync(GetMessages("device1", 3 * batchSize), CancellationToken.None);

            // although the test is setup to succeed with batch 2 and 3, they will fast fail because of the first one
            Assert.False(sinkResult.IsSuccessful);
            Assert.Equal(0, sinkResult.Succeeded.Count);
            Assert.Equal(30, sinkResult.Failed.Count);
            Assert.Equal(0, sinkResult.InvalidDetailsList.Count);
            Assert.True(sinkResult.SendFailureDetails.HasValue);
            Assert.Equal(FailureKind.Transient, sinkResult.SendFailureDetails.Expect(() => new Exception()).FailureKind);
        }
        public async Task TransientErrorOfFirstIdentity_DoesNotFastFailsSecondIdentity_ButReportsError()
        {
            var batchSize = 10;

            Core.IMessageConverter <IRoutingMessage> routingMessageConverter = new RoutingMessageConverter();
            string cloudEndpointId = Guid.NewGuid().ToString();

            // this wont fast fail
            var cloudProxy1 = ThrowingCloudProxy
                              .Create()
                              .WithBatchSize(batchSize)
                              .WithReportSuccessfulBatch(3)
                              .Build();

            // this will fast fail after a batch (skipping the second and the third)
            var cloudProxy2 = ThrowingCloudProxy
                              .Create()
                              .WithBatchSize(batchSize)
                              .WithReportSuccessfulBatch()
                              .WithReportErrorInBatch(ThrowingCloudProxy.Throw <Client.Exceptions.IotHubException>())
                              .WithReportSuccessfulBatch()
                              .Build();

            var proxyMap = new Dictionary <string, ICloudProxy> {
                ["device1"] = cloudProxy1, ["device2"] = cloudProxy2
            };

            Task <Option <ICloudProxy> > GetCloudProxy(string id) => Task.FromResult(Option.Some(proxyMap[id]));

            var cloudEndpoint         = new CloudEndpoint(cloudEndpointId, GetCloudProxy, routingMessageConverter);
            var cloudMessageProcessor = cloudEndpoint.CreateProcessor();

            var random     = new Random(35325);
            var messages   = GetMessages("device1", 3 * batchSize).Concat(GetMessages("device2", 3 * batchSize)).OrderBy(order => random.Next()).ToList();
            var sinkResult = await cloudMessageProcessor.ProcessAsync(messages, CancellationToken.None);

            Assert.False(sinkResult.IsSuccessful);                                   // one batch went wrong, should report here
            Assert.Equal(3 * batchSize + 1 * batchSize, sinkResult.Succeeded.Count); // dev1 all good, dev2 1st good
            Assert.Equal(2 * batchSize, sinkResult.Failed.Count);
            Assert.Equal(0, sinkResult.InvalidDetailsList.Count);
            Assert.True(sinkResult.SendFailureDetails.HasValue);
            Assert.Equal(FailureKind.Transient, sinkResult.SendFailureDetails.Expect(() => new Exception()).FailureKind);
        }