public void HandleSubmitOrderForProductionAsyncFailsWhenTheMessageContainsNoCommand()
        {
            var mockClock            = new Mock <IClock>();
            var mockSubmitter        = new Mock <IOrderSubmitter>();
            var mockSubmitPublisher  = new Mock <ICommandPublisher <SubmitOrderForProduction> >();
            var mockFailurePublisher = new Mock <ICommandPublisher <NotifyOfFatalFailure> >();
            var mockEventPublisher   = new Mock <IEventPublisher <EventBase> >();
            var mockLogger           = new Mock <ILogger>();
            var mockLifetimeScope    = new Mock <IDisposable>();
            var serializerSettings   = new JsonSerializerSettings();
            var serializer           = new JsonSerializer {
                ContractResolver = new CamelCasePropertyNamesContractResolver()
            };
            var processorFunctions = new TestOrderSubmitterFunctions(serializer, new CommandRetryThresholds(-1, 0, 0), mockClock.Object, mockSubmitter.Object, mockSubmitPublisher.Object, mockFailurePublisher.Object, mockEventPublisher.Object, mockLogger.Object, mockLifetimeScope.Object);

            serializer.Converters.Add(new StringEnumConverter());
            serializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
            serializerSettings.Converters.Add(new StringEnumConverter());

            mockLogger
            .Setup(logger => logger.ForContext(It.IsAny <string>(), It.IsAny <object>(), It.IsAny <bool>()))
            .Returns(mockLogger.Object);

            using (var memStream = new MemoryStream())
                using (var writer = new StreamWriter(memStream))
                    using (var jsonWriter = new JsonTextWriter(writer))
                    {
                        serializer.Serialize(jsonWriter, new { Name = "Test Guy" });
                        jsonWriter.Flush();

                        memStream.Seek(0, SeekOrigin.Begin);

                        var message = new BrokeredMessage(memStream)
                        {
                            ContentType   = MimeTypes.Json,
                            CorrelationId = Guid.NewGuid().ToString(),
                            MessageId     = Guid.NewGuid().ToString()
                        };

                        Action actionUnderTest = () => processorFunctions.HandleSubmitOrderForProductionAsync(message).GetAwaiter().GetResult();
                        actionUnderTest.ShouldThrow <MissingDependencyException>("because the brokered message must contain a command");

                        jsonWriter.Close();
                        writer.Close();
                        memStream.Close();
                    };
        }
        public void HandleSubmitOrderForProductionAsyncValidatesTheBrokeredMessage()
        {
            var mockClock            = new Mock <IClock>();
            var mockSubmitter        = new Mock <IOrderSubmitter>();
            var mockSubmitPublisher  = new Mock <ICommandPublisher <SubmitOrderForProduction> >();
            var mockFailurePublisher = new Mock <ICommandPublisher <NotifyOfFatalFailure> >();
            var mockEventPublisher   = new Mock <IEventPublisher <EventBase> >();
            var mockLogger           = new Mock <ILogger>();
            var mockLifetimeScope    = new Mock <IDisposable>();
            var serializerSettings   = new JsonSerializerSettings();
            var serializer           = new JsonSerializer {
                ContractResolver = new CamelCasePropertyNamesContractResolver()
            };
            var processorFunctions = new TestOrderSubmitterFunctions(serializer, new CommandRetryThresholds(-1, 0, 0), mockClock.Object, mockSubmitter.Object, mockSubmitPublisher.Object, mockFailurePublisher.Object, mockEventPublisher.Object, mockLogger.Object, mockLifetimeScope.Object);

            serializer.Converters.Add(new StringEnumConverter());
            serializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
            serializerSettings.Converters.Add(new StringEnumConverter());

            Action actionUnderTest = () => processorFunctions.HandleSubmitOrderForProductionAsync(null).GetAwaiter().GetResult();

            actionUnderTest.ShouldThrow <ArgumentNullException>("because the brokered order message is required");
        }
        public async Task HandleSubmitOrderForProductionAsyncPublishesTheProperEventWhenOrderSubmissionSucceeds()
        {
            var mockClock            = new Mock <IClock>();
            var mockSubmitter        = new Mock <IOrderSubmitter>();
            var mockSubmitPublisher  = new Mock <ICommandPublisher <SubmitOrderForProduction> >();
            var mockFailurePublisher = new Mock <ICommandPublisher <NotifyOfFatalFailure> >();
            var mockEventPublisher   = new Mock <IEventPublisher <EventBase> >();
            var mockLogger           = new Mock <ILogger>();
            var mockLifetimeScope    = new Mock <IDisposable>();
            var serializerSettings   = new JsonSerializerSettings();
            var serializer           = new JsonSerializer {
                ContractResolver = new CamelCasePropertyNamesContractResolver()
            };
            var processorFunctions = new TestOrderSubmitterFunctions(serializer, new CommandRetryThresholds(-1, 0, 0), mockClock.Object, mockSubmitter.Object, mockSubmitPublisher.Object, mockFailurePublisher.Object, mockEventPublisher.Object, mockLogger.Object, mockLifetimeScope.Object);

            serializer.Converters.Add(new StringEnumConverter());
            serializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
            serializerSettings.Converters.Add(new StringEnumConverter());

            mockLogger
            .Setup(logger => logger.ForContext(It.IsAny <string>(), It.IsAny <object>(), It.IsAny <bool>()))
            .Returns(mockLogger.Object);

            mockSubmitter
            .Setup(processor => processor.SubmitOrderForProductionAsync(It.IsAny <string>(),
                                                                        It.IsAny <string>(),
                                                                        It.IsAny <DependencyEmulation>(),
                                                                        It.IsAny <string>()))
            .ReturnsAsync(new OperationResult {
                Outcome = Outcome.Success
            });

            var command = new SubmitOrderForProduction
            {
                Id              = Guid.NewGuid(),
                CorrelationId   = "ABC",
                PartnerCode     = "Bob",
                OrderId         = "123",
                OccurredTimeUtc = new DateTime(2017, 12, 09, 9, 0, 0, DateTimeKind.Utc)
            };

            using (var memStream = new MemoryStream())
                using (var writer = new StreamWriter(memStream))
                    using (var jsonWriter = new JsonTextWriter(writer))
                    {
                        serializer.Serialize(jsonWriter, command);
                        jsonWriter.Flush();

                        memStream.Seek(0, SeekOrigin.Begin);

                        using (var message = new BrokeredMessage(memStream))
                        {
                            message.ContentType   = MimeTypes.Json;
                            message.CorrelationId = Guid.NewGuid().ToString();
                            message.MessageId     = Guid.NewGuid().ToString();

                            try { await processorFunctions.HandleSubmitOrderForProductionAsync(message); }  catch {}
                        }

                        jsonWriter.Close();
                        writer.Close();
                        memStream.Close();
                    };

            mockEventPublisher.Verify(pub => pub.TryPublishAsync(It.Is <OrderSubmitted>(evt =>
                                                                                        ((evt.OrderId == command.OrderId) &&
                                                                                         (evt.CorrelationId == command.CorrelationId) &&
                                                                                         (evt.PartnerCode == command.PartnerCode)))),
                                      Times.Once, "because the event should have been published");
        }
        public void HandleSubmitOrderForProductionAsyncThrowsWhenOrderSubmissionThrowsAndTheRetryThrows()
        {
            var mockClock            = new Mock <IClock>();
            var mockSubmitter        = new Mock <IOrderSubmitter>();
            var mockSubmitPublisher  = new Mock <ICommandPublisher <SubmitOrderForProduction> >();
            var mockFailurePublisher = new Mock <ICommandPublisher <NotifyOfFatalFailure> >();
            var mockEventPublisher   = new Mock <IEventPublisher <EventBase> >();
            var mockLogger           = new Mock <ILogger>();
            var mockLifetimeScope    = new Mock <IDisposable>();
            var serializerSettings   = new JsonSerializerSettings();
            var serializer           = new JsonSerializer {
                ContractResolver = new CamelCasePropertyNamesContractResolver()
            };
            var processorFunctions = new TestOrderSubmitterFunctions(serializer, new CommandRetryThresholds(1, 1, 1), mockClock.Object, mockSubmitter.Object, mockSubmitPublisher.Object, mockFailurePublisher.Object, mockEventPublisher.Object, mockLogger.Object, mockLifetimeScope.Object);
            var expectedException  = new OrderProcessingException();


            serializer.Converters.Add(new StringEnumConverter());
            serializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
            serializerSettings.Converters.Add(new StringEnumConverter());

            mockLogger
            .Setup(logger => logger.ForContext(It.IsAny <string>(), It.IsAny <object>(), It.IsAny <bool>()))
            .Returns(mockLogger.Object);

            mockSubmitPublisher
            .Setup(publisher => publisher.PublishAsync(It.IsAny <SubmitOrderForProduction>(), It.Is <Instant?>(value => value.HasValue)))
            .Throws(expectedException);

            mockSubmitter
            .Setup(processor => processor.SubmitOrderForProductionAsync(It.IsAny <string>(),
                                                                        It.IsAny <string>(),
                                                                        It.IsAny <DependencyEmulation>(),
                                                                        It.IsAny <string>()))
            .ThrowsAsync(new ApplicationException());

            var command = new SubmitOrderForProduction
            {
                Id              = Guid.NewGuid(),
                CorrelationId   = "ABC",
                PartnerCode     = "Bob",
                OrderId         = "123",
                OccurredTimeUtc = new DateTime(2017, 12, 09, 9, 0, 0, DateTimeKind.Utc)
            };

            using (var memStream = new MemoryStream())
                using (var writer = new StreamWriter(memStream))
                    using (var jsonWriter = new JsonTextWriter(writer))
                    {
                        serializer.Serialize(jsonWriter, command);
                        jsonWriter.Flush();

                        memStream.Seek(0, SeekOrigin.Begin);

                        using (var message = new BrokeredMessage(memStream))
                        {
                            message.ContentType   = MimeTypes.Json;
                            message.CorrelationId = Guid.NewGuid().ToString();
                            message.MessageId     = Guid.NewGuid().ToString();

                            Action actionUnderTest = () => processorFunctions.HandleSubmitOrderForProductionAsync(message).GetAwaiter().GetResult();

                            actionUnderTest.ShouldThrow <OrderProcessingException>("because the command retry publishing experienced an exception")
                            .Subject.SingleOrDefault().Should().Be(expectedException, "because the exception should bubble");
                        }

                        jsonWriter.Close();
                        writer.Close();
                        memStream.Close();
                    }
        }
        public void HandleSubmitOrderForProductionAsyncThrowsWhenOrderSubmissionFailsAndIsNotRetried()
        {
            var mockClock            = new Mock <IClock>();
            var mockSubmitter        = new Mock <IOrderSubmitter>();
            var mockSubmitPublisher  = new Mock <ICommandPublisher <SubmitOrderForProduction> >();
            var mockFailurePublisher = new Mock <ICommandPublisher <NotifyOfFatalFailure> >();
            var mockEventPublisher   = new Mock <IEventPublisher <EventBase> >();
            var mockLogger           = new Mock <ILogger>();
            var mockLifetimeScope    = new Mock <IDisposable>();
            var serializerSettings   = new JsonSerializerSettings();
            var serializer           = new JsonSerializer {
                ContractResolver = new CamelCasePropertyNamesContractResolver()
            };
            var processorFunctions = new TestOrderSubmitterFunctions(serializer, new CommandRetryThresholds(-1, 0, 0), mockClock.Object, mockSubmitter.Object, mockSubmitPublisher.Object, mockFailurePublisher.Object, mockEventPublisher.Object, mockLogger.Object, mockLifetimeScope.Object);
            var expectedException  = new OrderProcessingException();


            serializer.Converters.Add(new StringEnumConverter());
            serializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
            serializerSettings.Converters.Add(new StringEnumConverter());

            mockLogger
            .Setup(logger => logger.ForContext(It.IsAny <string>(), It.IsAny <object>(), It.IsAny <bool>()))
            .Returns(mockLogger.Object);

            mockSubmitter
            .Setup(processor => processor.SubmitOrderForProductionAsync(It.IsAny <string>(),
                                                                        It.IsAny <string>(),
                                                                        It.IsAny <DependencyEmulation>(),
                                                                        It.IsAny <string>()))
            .ReturnsAsync(OperationResult.ExceptionResult);

            var command = new SubmitOrderForProduction
            {
                Id              = Guid.NewGuid(),
                CorrelationId   = "ABC",
                PartnerCode     = "Bob",
                OrderId         = "123",
                OccurredTimeUtc = new DateTime(2017, 12, 09, 9, 0, 0, DateTimeKind.Utc)
            };

            using (var memStream = new MemoryStream())
                using (var writer = new StreamWriter(memStream))
                    using (var jsonWriter = new JsonTextWriter(writer))
                    {
                        serializer.Serialize(jsonWriter, command);
                        jsonWriter.Flush();

                        memStream.Seek(0, SeekOrigin.Begin);

                        using (var message = new BrokeredMessage(memStream))
                        {
                            message.ContentType   = MimeTypes.Json;
                            message.CorrelationId = Guid.NewGuid().ToString();
                            message.MessageId     = Guid.NewGuid().ToString();

                            Action actionUnderTest = () => processorFunctions.HandleSubmitOrderForProductionAsync(message).GetAwaiter().GetResult();

                            actionUnderTest.ShouldThrow <FailedtoHandleCommandException>("because the order submitter failed to submit the order");
                        }

                        jsonWriter.Close();
                        writer.Close();
                        memStream.Close();
                    };

            mockFailurePublisher.Verify(publisher => publisher.TryPublishAsync(It.IsAny <NotifyOfFatalFailure>(), It.Is <Instant?>(value => value == null)),
                                        Times.Once,
                                        "The failure notification should have been published because the command wasn't eligible for retries");
        }
        public async Task HandleSubmitOrderForProductionAsyncSubmitsTheOrder()
        {
            var mockClock            = new Mock <IClock>();
            var mockSubmitter        = new Mock <IOrderSubmitter>();
            var mockSubmitPublisher  = new Mock <ICommandPublisher <SubmitOrderForProduction> >();
            var mockFailurePublisher = new Mock <ICommandPublisher <NotifyOfFatalFailure> >();
            var mockEventPublisher   = new Mock <IEventPublisher <EventBase> >();
            var mockLogger           = new Mock <ILogger>();
            var mockLifetimeScope    = new Mock <IDisposable>();
            var serializerSettings   = new JsonSerializerSettings();
            var serializer           = new JsonSerializer {
                ContractResolver = new CamelCasePropertyNamesContractResolver()
            };
            var processorFunctions = new TestOrderSubmitterFunctions(serializer, new CommandRetryThresholds(-1, 0, 0), mockClock.Object, mockSubmitter.Object, mockSubmitPublisher.Object, mockFailurePublisher.Object, mockEventPublisher.Object, mockLogger.Object, mockLifetimeScope.Object);
            var partner            = "That guy";
            var orderId            = "ABC123";
            var correlationId      = "Hello";
            var emulation          = new DependencyEmulation {
                OrderDetails = new OperationResult {
                    Payload = "Yay!"
                }
            };

            serializer.Converters.Add(new StringEnumConverter());
            serializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
            serializerSettings.Converters.Add(new StringEnumConverter());

            mockLogger
            .Setup(logger => logger.ForContext(It.IsAny <string>(), It.IsAny <object>(), It.IsAny <bool>()))
            .Returns(mockLogger.Object);

            mockSubmitter
            .Setup(processor => processor.SubmitOrderForProductionAsync(It.Is <string>(partnerCode => partnerCode == partner),
                                                                        It.Is <string>(order => order == orderId),
                                                                        It.Is <DependencyEmulation>(emu => emu.OrderDetails.Payload == emulation.OrderDetails.Payload),
                                                                        It.Is <string>(correlation => correlation == correlationId)))
            .ReturnsAsync(new OperationResult {
                Outcome = Outcome.Success
            })
            .Verifiable("The order should have been submitted");

            var command = new SubmitOrderForProduction
            {
                Id              = Guid.NewGuid(),
                CorrelationId   = correlationId,
                PartnerCode     = partner,
                OrderId         = orderId,
                Emulation       = emulation,
                OccurredTimeUtc = new DateTime(2017, 12, 09, 9, 0, 0, DateTimeKind.Utc)
            };

            using (var memStream = new MemoryStream())
                using (var writer = new StreamWriter(memStream))
                    using (var jsonWriter = new JsonTextWriter(writer))
                    {
                        serializer.Serialize(jsonWriter, command);
                        jsonWriter.Flush();

                        memStream.Seek(0, SeekOrigin.Begin);

                        using (var message = new BrokeredMessage(memStream))
                        {
                            message.ContentType   = MimeTypes.Json;
                            message.CorrelationId = Guid.NewGuid().ToString();
                            message.MessageId     = Guid.NewGuid().ToString();

                            await processorFunctions.HandleSubmitOrderForProductionAsync(message);
                        }

                        jsonWriter.Close();
                        writer.Close();
                        memStream.Close();
                    };

            mockSubmitter.VerifyAll();
        }