public async Task MemberPathIsTransformedForMultipleObjects()
        {
            var firstParameterName   = "one";
            var firstParameterValue  = new object();
            var secondParameterName  = "two";
            var secondParameterValue = new OrderFulfillmentMessage();
            var mockValidator        = new Mock <IValidator>();
            var mockActionDescriptor = new Mock <HttpActionDescriptor>();
            var mockDependencyScope  = new Mock <IDependencyScope>();
            var httpConfiguration    = new HttpConfiguration();
            var routeData            = new HttpRouteData(new HttpRoute());
            var request = new HttpRequestMessage();
            var controllerDescriptor = new HttpControllerDescriptor {
                Configuration = httpConfiguration, ControllerName = "generic"
            };
            var controllerContext = new HttpControllerContext(httpConfiguration, routeData, request)
            {
                ControllerDescriptor = controllerDescriptor
            };
            var actionContext    = new HttpActionContext(controllerContext, mockActionDescriptor.Object);
            var messageValidator = new ValidateMessageAttribute();

            mockActionDescriptor.SetupGet(descriptor => descriptor.ActionName).Returns("someAction");

            mockDependencyScope.Setup(scope => scope.GetService(It.IsAny <Type>()))
            .Returns(mockValidator.Object)
            .Verifiable("Tthe validator should have been requested.");

            mockValidator.Setup(validator => validator.Validate(It.Is <object>(param => param == firstParameterValue)))
            .Returns(new [] { new Error(ErrorCode.LengthIsInvalid, "someThing.Path", "Dummy description") })
            .Verifiable("The validator should have been used to validate the parameter.");

            mockValidator.Setup(validator => validator.Validate(It.Is <object>(param => param == secondParameterValue)))
            .Returns(new [] { new Error(ErrorCode.LengthIsInvalid, "order.OrderId", "Dummy description") })
            .Verifiable("The validator should have been used to validate the parameter.");

            actionContext.ActionArguments.Add(firstParameterName, firstParameterValue);
            actionContext.ActionArguments.Add(secondParameterName, secondParameterValue);

            request.SetConfiguration(httpConfiguration);
            request.SetRouteData(routeData);
            request.Properties.Add(HttpPropertyKeys.DependencyScope, mockDependencyScope.Object);

            await messageValidator.OnActionExecutingAsync(actionContext, new CancellationToken());

            actionContext.Response.Should().NotBeNull("because an invalid response should contain response");
            actionContext.Response.StatusCode.Should().Be(HttpStatusCode.BadRequest, "because a validation failure is a Bad Request");

            var errorSet = await actionContext.Response.Content.ReadAsAsync <ErrorSet>();

            errorSet.Should().NotBeNull("because an error set should be present for a failed validation");
            errorSet.Errors.Count().Should().Be(2, "because two failures were returned by validation");

            errorSet.Errors.Count(error => error.MemberPath.StartsWith($"{ firstParameterName }::")).Should().Be(1, "because a single error should have been mapped to the firstParameter");
            errorSet.Errors.Count(error => error.MemberPath.StartsWith($"{ secondParameterName }::")).Should().Be(1, "because a single error should have been mapped to the secondParameter");
        }
Beispiel #2
0
        public async Task FulfillOrderWebHookWithNonPriviledgedUserLogsWhenSupplyingTestData()
        {
            var mockLogger           = new Mock <ILogger>();
            var mockActionDescriptor = new Mock <HttpActionDescriptor>();
            var httpConfiguration    = new HttpConfiguration();
            var routeData            = new HttpRouteData(new HttpRoute());
            var request = new HttpRequestMessage();
            var controllerDescriptor = new HttpControllerDescriptor {
                Configuration = httpConfiguration, ControllerName = nameof(OrderSubmissionController)
            };
            var controllerContext = new HttpControllerContext(httpConfiguration, routeData, request)
            {
                ControllerDescriptor = controllerDescriptor
            };
            var actionContext         = new HttpActionContext(controllerContext, mockActionDescriptor.Object);
            var unpriviledgedIdentity = new ClaimsIdentity(new Claim[] { new Claim(CustomClaimTypes.IdentityType, "UnitTest") });

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

            mockActionDescriptor.SetupGet(descriptor => descriptor.ActionName).Returns("someAction");
            actionContext.RequestContext.Principal = new ClaimsPrincipal(unpriviledgedIdentity);
            request.SetConfiguration(httpConfiguration);
            request.SetRouteData(routeData);

            var controller = new OrderSubmissionController(Mock.Of <IClock>(), Mock.Of <ICommandPublisher <ProcessOrder> >(), Mock.Of <IEventPublisher <EventBase> >(), mockLogger.Object, new OrderSubmissionControllerConfiguration())
            {
                ControllerContext = controllerContext
            };

            var order = new OrderFulfillmentMessage
            {
                OrderRequestHeader = new OrderHeader {
                    OrderId = "ABC123", OrderDate = new DateTime(2017, 12, 09, 09, 00, 00, DateTimeKind.Utc)
                },
                LineItems = new List <LineItem>(),
                Emulation = new DependencyEmulation()
            };

            var partner      = "SQUIRE";
            var actionResult = await controller.FulfillOrderWebHook(partner, order);

            var result = await actionResult.ExecuteAsync(CancellationToken.None);

            mockLogger.Verify(logger => logger.Warning(It.IsAny <string>(),
                                                       It.Is <HttpStatusCode>(code => code == HttpStatusCode.Forbidden),
                                                       It.Is <string>(name => name == nameof(OrderSubmissionController)),
                                                       It.Is <string>(method => method == nameof(OrderSubmissionController.FulfillOrderWebHook)),
                                                       It.Is <string>(partnerName => partnerName == partner),
                                                       It.IsAny <HttpRequestHeaders>()),
                              Times.Once, "The failure should be logged");
        }
Beispiel #3
0
        public async Task FulfillOrderWebHookWithFailedCommandFails()
        {
            var mockLogger           = new Mock <ILogger>();
            var mockCommandPublisher = new Mock <ICommandPublisher <ProcessOrder> >();
            var mockActionDescriptor = new Mock <HttpActionDescriptor>();
            var httpConfiguration    = new HttpConfiguration();
            var routeData            = new HttpRouteData(new HttpRoute());
            var request = new HttpRequestMessage();
            var controllerDescriptor = new HttpControllerDescriptor {
                Configuration = httpConfiguration, ControllerName = nameof(OrderSubmissionController)
            };
            var controllerContext = new HttpControllerContext(httpConfiguration, routeData, request)
            {
                ControllerDescriptor = controllerDescriptor
            };
            var actionContext = new HttpActionContext(controllerContext, mockActionDescriptor.Object);

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

            mockCommandPublisher.Setup(publisher => publisher.TryPublishAsync(It.IsAny <ProcessOrder>(), It.IsAny <Instant?>()))
            .ReturnsAsync(false);

            mockActionDescriptor.SetupGet(descriptor => descriptor.ActionName).Returns("someAction");
            request.SetConfiguration(httpConfiguration);
            request.SetRouteData(routeData);

            var controller = new OrderSubmissionController(Mock.Of <IClock>(), mockCommandPublisher.Object, Mock.Of <IEventPublisher <EventBase> >(), mockLogger.Object, new OrderSubmissionControllerConfiguration {
                ServiceUnavailableeRetryAfterInSeconds = 5
            })
            {
                ControllerContext = controllerContext
            };

            var order = new OrderFulfillmentMessage
            {
                OrderRequestHeader = new OrderHeader {
                    OrderId = "ABC123", OrderDate = new DateTime(2017, 12, 09, 09, 00, 00, DateTimeKind.Utc)
                },
                LineItems = new List <LineItem>()
            };

            var actionResult = await controller.FulfillOrderWebHook("SQUIRE", order);

            var result = await actionResult.ExecuteAsync(CancellationToken.None);

            result.Should().NotBeNull("because a result should have been returned");
            result.StatusCode.Should().Be(HttpStatusCode.ServiceUnavailable, "because the request should have been rejected");
            result.Headers.RetryAfter.Should().NotBeNull("because a RETRY-AFTER header should be specified for an Service Unavailable result");
        }
Beispiel #4
0
        public async Task FulfillOrderWebHookPublishesTheCommandToTiriggerProcessingForAnAcceptedOrder()
        {
            var mockLogger           = new Mock <ILogger>();
            var mockCommandPublisher = new Mock <ICommandPublisher <ProcessOrder> >();
            var mockActionDescriptor = new Mock <HttpActionDescriptor>();
            var httpConfiguration    = new HttpConfiguration();
            var routeData            = new HttpRouteData(new HttpRoute());
            var request = new HttpRequestMessage();
            var controllerDescriptor = new HttpControllerDescriptor {
                Configuration = httpConfiguration, ControllerName = nameof(OrderSubmissionController)
            };
            var controllerContext = new HttpControllerContext(httpConfiguration, routeData, request)
            {
                ControllerDescriptor = controllerDescriptor
            };
            var actionContext = new HttpActionContext(controllerContext, mockActionDescriptor.Object);

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

            mockActionDescriptor.SetupGet(descriptor => descriptor.ActionName).Returns("someAction");
            request.SetConfiguration(httpConfiguration);
            request.SetRouteData(routeData);

            var controller = new OrderSubmissionController(Mock.Of <IClock>(), mockCommandPublisher.Object, Mock.Of <IEventPublisher <EventBase> >(), mockLogger.Object, new OrderSubmissionControllerConfiguration {
                OrderAcceptedRetryAfterInSeconds = 5
            })
            {
                ControllerContext = controllerContext
            };

            var order = new OrderFulfillmentMessage
            {
                OrderRequestHeader = new OrderHeader {
                    OrderId = "ABC123", OrderDate = new DateTime(2017, 12, 09, 09, 00, 00, DateTimeKind.Utc)
                },
                LineItems = new List <LineItem>()
            };

            var actionResult = await controller.FulfillOrderWebHook("SQUIRE", order);

            var result = await actionResult.ExecuteAsync(CancellationToken.None);

            result.Should().NotBeNull("because a result should have been returned");

            mockCommandPublisher.Verify(publisher => publisher.TryPublishAsync(It.Is <ProcessOrder>(command => command.OrderId == order.OrderRequestHeader.OrderId), It.Is <Instant?>(time => time == null)),
                                        Times.Once,
                                        "An accepted order should emit an Order Received event");
        }
Beispiel #5
0
        public async Task FulfillOrderWebHookAcceptsAnOrder()
        {
            var mockCommandPublisher = new Mock <ICommandPublisher <ProcessOrder> >();
            var mockActionDescriptor = new Mock <HttpActionDescriptor>();
            var httpConfiguration    = new HttpConfiguration();
            var routeData            = new HttpRouteData(new HttpRoute());
            var request = new HttpRequestMessage();
            var controllerDescriptor = new HttpControllerDescriptor {
                Configuration = httpConfiguration, ControllerName = nameof(OrderSubmissionController)
            };
            var controllerContext = new HttpControllerContext(httpConfiguration, routeData, request)
            {
                ControllerDescriptor = controllerDescriptor
            };
            var actionContext = new HttpActionContext(controllerContext, mockActionDescriptor.Object);

            mockCommandPublisher.Setup(publisher => publisher.TryPublishAsync(It.IsAny <ProcessOrder>(), It.IsAny <Instant?>()))
            .ReturnsAsync(true);

            mockActionDescriptor.SetupGet(descriptor => descriptor.ActionName).Returns("someAction");
            request.SetConfiguration(httpConfiguration);
            request.SetRouteData(routeData);

            var controller = new OrderSubmissionController(Mock.Of <IClock>(), mockCommandPublisher.Object, Mock.Of <IEventPublisher <EventBase> >(), Mock.Of <ILogger>(), new OrderSubmissionControllerConfiguration {
                OrderAcceptedRetryAfterInSeconds = 5
            })
            {
                ControllerContext = controllerContext
            };

            var order = new OrderFulfillmentMessage
            {
                OrderRequestHeader = new OrderHeader {
                    OrderId = "ABC123", OrderDate = new DateTime(2017, 12, 09, 09, 00, 00, DateTimeKind.Utc)
                },
                LineItems = new List <LineItem>()
            };

            var actionResult = await controller.FulfillOrderWebHook("SQUIRE", order);

            var result = await actionResult.ExecuteAsync(CancellationToken.None);

            result.Should().NotBeNull("because a result should have been returned");
            result.StatusCode.Should().Be(HttpStatusCode.Accepted, "because the request was valid");
            result.Headers.RetryAfter.Should().NotBeNull("because a RETRY-AFTER header should be specified for an Accepted result");

            result.TryGetContentValue <OrderFulfillmentAccepted>(out var response).Should().BeTrue("because the response should have been set");
            response.FulfillerData.OrderId.Should().Be(order.OrderRequestHeader.OrderId, "because the correct order should have been acknoledged");
        }
Beispiel #6
0
        public async Task FulfillOrderWebHookWithAPriviledgedUserAcceptsTestData()
        {
            var mockCommandPublisher = new Mock <ICommandPublisher <ProcessOrder> >();
            var mockActionDescriptor = new Mock <HttpActionDescriptor>();
            var httpConfiguration    = new HttpConfiguration();
            var routeData            = new HttpRouteData(new HttpRoute());
            var request = new HttpRequestMessage();
            var controllerDescriptor = new HttpControllerDescriptor {
                Configuration = httpConfiguration, ControllerName = nameof(OrderSubmissionController)
            };
            var controllerContext = new HttpControllerContext(httpConfiguration, routeData, request)
            {
                ControllerDescriptor = controllerDescriptor
            };
            var actionContext       = new HttpActionContext(controllerContext, mockActionDescriptor.Object);
            var priviledgedIdentity = new ClaimsIdentity(new Claim[] { new Claim(CustomClaimTypes.MayAccessPriviledgedOperations, "true") });

            mockCommandPublisher.Setup(publisher => publisher.TryPublishAsync(It.IsAny <ProcessOrder>(), It.IsAny <Instant?>()))
            .ReturnsAsync(true);

            mockActionDescriptor.SetupGet(descriptor => descriptor.ActionName).Returns("someAction");
            actionContext.RequestContext.Principal = new ClaimsPrincipal(priviledgedIdentity);
            request.SetConfiguration(httpConfiguration);
            request.SetRouteData(routeData);

            var controller = new OrderSubmissionController(Mock.Of <IClock>(), mockCommandPublisher.Object, Mock.Of <IEventPublisher <EventBase> >(), Mock.Of <ILogger>(), new OrderSubmissionControllerConfiguration())
            {
                ControllerContext = controllerContext
            };

            var order = new OrderFulfillmentMessage
            {
                OrderRequestHeader = new OrderHeader {
                    OrderId = "ABC123", OrderDate = new DateTime(2017, 12, 09, 09, 00, 00, DateTimeKind.Utc)
                },
                LineItems = new List <LineItem>(),
                Emulation = new DependencyEmulation()
            };

            var actionResult = await controller.FulfillOrderWebHook("SQUIRE", order);

            var result = await actionResult.ExecuteAsync(CancellationToken.None);

            result.Should().NotBeNull("because a result should have been returned");
            result.StatusCode.Should().Be(HttpStatusCode.Accepted, "because the request was valid");
        }
Beispiel #7
0
        public async Task FulfillOrderWebHookWithNonPriviledgedUserIsRejectedWhenSupplyingTestData()
        {
            var mockActionDescriptor = new Mock <HttpActionDescriptor>();
            var httpConfiguration    = new HttpConfiguration();
            var routeData            = new HttpRouteData(new HttpRoute());
            var request = new HttpRequestMessage();
            var controllerDescriptor = new HttpControllerDescriptor {
                Configuration = httpConfiguration, ControllerName = nameof(OrderSubmissionController)
            };
            var controllerContext = new HttpControllerContext(httpConfiguration, routeData, request)
            {
                ControllerDescriptor = controllerDescriptor
            };
            var actionContext         = new HttpActionContext(controllerContext, mockActionDescriptor.Object);
            var unpriviledgedIdentity = new ClaimsIdentity(new Claim[] { new Claim(CustomClaimTypes.IdentityType, "UnitTest") });

            mockActionDescriptor.SetupGet(descriptor => descriptor.ActionName).Returns("someAction");
            actionContext.RequestContext.Principal = new ClaimsPrincipal(unpriviledgedIdentity);
            request.SetConfiguration(httpConfiguration);
            request.SetRouteData(routeData);

            var controller = new OrderSubmissionController(Mock.Of <IClock>(), Mock.Of <ICommandPublisher <ProcessOrder> >(), Mock.Of <IEventPublisher <EventBase> >(), Mock.Of <ILogger>(), new OrderSubmissionControllerConfiguration())
            {
                ControllerContext = controllerContext
            };

            var order = new OrderFulfillmentMessage
            {
                OrderRequestHeader = new OrderHeader {
                    OrderId = "ABC123", OrderDate = new DateTime(2017, 12, 09, 09, 00, 00, DateTimeKind.Utc)
                },
                LineItems = new List <LineItem>(),
                Emulation = new DependencyEmulation()
            };

            var actionResult = await controller.FulfillOrderWebHook("SQUIRE", order);

            var result = await actionResult.ExecuteAsync(CancellationToken.None);

            result.Should().NotBeNull("because a result should have been returned");
            result.StatusCode.Should().Be(HttpStatusCode.Forbidden, "because the request should have been rejected");

            var errorSet = await result.Content.ReadAsAsync <ErrorSet>();

            errorSet.Should().BeNull("because no errors should be returned when the caller is unpriviledged");
        }
        public async Task RequestHeaderIsRequired()
        {
            var currentInstant   = Instant.FromUtc(2017, 08, 17, 12, 0, 0);
            var fakeClock        = new FakeClock(currentInstant);
            var headerValidator  = new OrderHeaderValidator(fakeClock) as IMessageValidator <OrderHeader>;
            var itemValidator    = new itemItemValidator() as IMessageValidator <ItemAsset>;
            var itemOutValidator = new ItemOutValidator(itemValidator) as IMessageValidator <LineItem>;
            var validator        = new OrderFulfillmentMessageValidator(headerValidator, itemOutValidator);

            var target = new OrderFulfillmentMessage
            {
                OrderRequestHeader = null,
                LineItems          = new List <LineItem>()
            };

            var result = await validator.ValidateAsync(target);

            result.Should().NotBeNull("because a validation result should have been returned");
            result.Should().ContainSingle(error => ((error.MemberPath == nameof(OrderFulfillmentMessage.OrderRequestHeader)) && (error.Code == ErrorCode.ValueIsRequired.ToString())), "because the order header was not provided");
        }
        public async Task RequestHeaderIsValidated()
        {
            var currentInstant   = Instant.FromUtc(2017, 08, 17, 12, 0, 0);
            var fakeClock        = new FakeClock(currentInstant);
            var headerValidator  = new OrderHeaderValidator(fakeClock) as IMessageValidator <OrderHeader>;
            var itemValidator    = new itemItemValidator() as IMessageValidator <ItemAsset>;
            var itemOutValidator = new ItemOutValidator(itemValidator) as IMessageValidator <LineItem>;
            var validator        = new OrderFulfillmentMessageValidator(headerValidator, itemOutValidator);
            var header           = new OrderHeader {
                OrderId = null, OrderDate = currentInstant.ToDateTimeUtc()
            };

            var target = new OrderFulfillmentMessage
            {
                OrderRequestHeader = header,
                LineItems          = new List <LineItem>()
            };

            var result = await validator.ValidateAsync(target);

            result.Should().NotBeNull("because a validation result should have been returned");
            result.Should().ContainSingle(error => (error.MemberPath == $"{ nameof(OrderFulfillmentMessage.OrderRequestHeader) }.{ nameof(OrderHeader.OrderId) }"), "because the order id was not provided in the header");
        }
        public async Task EmptyItemOutIsValid()
        {
            var currentInstant   = Instant.FromUtc(2017, 08, 17, 12, 0, 0);
            var fakeClock        = new FakeClock(currentInstant);
            var headerValidator  = new OrderHeaderValidator(fakeClock) as IMessageValidator <OrderHeader>;
            var itemValidator    = new itemItemValidator() as IMessageValidator <ItemAsset>;
            var itemOutValidator = new ItemOutValidator(itemValidator) as IMessageValidator <LineItem>;
            var validator        = new OrderFulfillmentMessageValidator(headerValidator, itemOutValidator);
            var header           = new OrderHeader {
                OrderId = "ABC123", OrderDate = currentInstant.ToDateTimeUtc()
            };

            var target = new OrderFulfillmentMessage
            {
                OrderRequestHeader = header,
                LineItems          = new List <LineItem>()
            };

            var result = await validator.ValidateAsync(target);

            result.Should().NotBeNull("because a validation result should have been returned");
            result.Should().BeEmpty("because an empty itemout set is allowed");
        }
        public async Task ItemOutsAreValidated()
        {
            var currentInstant   = Instant.FromUtc(2017, 08, 17, 12, 0, 0);
            var fakeClock        = new FakeClock(currentInstant);
            var headerValidator  = new OrderHeaderValidator(fakeClock) as IMessageValidator <OrderHeader>;
            var itemValidator    = new itemItemValidator() as IMessageValidator <ItemAsset>;
            var itemOutValidator = new ItemOutValidator(itemValidator) as IMessageValidator <LineItem>;
            var validator        = new OrderFulfillmentMessageValidator(headerValidator, itemOutValidator);
            var header           = new OrderHeader {
                OrderId = "ABC123", OrderDate = currentInstant.ToDateTimeUtc()
            };

            var itemOuts = new List <LineItem>
            {
                new LineItem
                {
                    Assets = new List <ItemAsset>
                    {
                        new ItemAsset(),
                        new ItemAsset()
                    }
                }
            };

            var target = new OrderFulfillmentMessage
            {
                OrderRequestHeader = header,
                LineItems          = itemOuts
            };

            var result = await validator.ValidateAsync(target);

            var failurePath = $"{ nameof(OrderFulfillmentMessage.LineItems) }[0].{ nameof(LineItem.Assets) }";

            result.Should().NotBeNull("because a validation result should have been returned");
            result.Should().ContainSingle(error => error.MemberPath == failurePath, "because the itemout violated a rule");
        }
Beispiel #12
0
        public async Task <IHttpActionResult> FulfillOrderWebHook(string partner,
                                                                  [FromBody] OrderFulfillmentMessage order)
        {
            // Verify that the order was sent as the request body.

            if (order == null)
            {
                var errorSet = new ErrorSet(ErrorCode.ValueIsRequired, nameof(order), "The order body is required.");

                try
                {
                    var body = await this.Request.SafeReadContentAsStringAsync();

                    this.Log
                    .WithCorrelationId(this.Request.GetOrderFulfillmentCorrelationId())
                    .Information($"Response: {{Response}} { Environment.NewLine } Missing order detected for {{Controller}}::{{ActionMethod}}({{Partner}}) with Headers: [{{Headers}}] { Environment.NewLine } Body: {{RequestBody}} { Environment.NewLine } The following errors were observed: { Environment.NewLine }{{ErrorSet}}",
                                 HttpStatusCode.BadRequest,
                                 nameof(OrderSubmissionController),
                                 nameof(FulfillOrderWebHook),
                                 partner,
                                 this.Request.Headers,
                                 body,
                                 errorSet);
                }

                catch
                {
                    // Do nothing; logging is a non-critical operation that should not cause
                    // cascading failures.
                }

                return(this.BadRequest(errorSet));
            }

            // If the emulation data was provided and the caller is not priviledged, then reject the request.

            var principal = this.User as ClaimsPrincipal;

            if ((order.Emulation != null) &&
                ((principal == null) || (!principal.HasClaim(claim => claim.Type == CustomClaimTypes.MayAccessPriviledgedOperations))))
            {
                try
                {
                    this.Log
                    .WithCorrelationId(this.Request.GetOrderFulfillmentCorrelationId())
                    .Warning($"Response: {{Response}} { Environment.NewLine } Unauthorized request detected for {{Controller}}::{{ActionMethod}}({{Partner}}) with Headers: [{{Headers}}] { Environment.NewLine }  The caller does not have permission to perform a priviledged operation.",
                             HttpStatusCode.Forbidden,
                             nameof(OrderSubmissionController),
                             nameof(FulfillOrderWebHook),
                             partner,
                             this.Request.Headers);
                }

                catch
                {
                    // Do nothing; logging is a non-critical operation that should not cause
                    // cascading failures.
                }

                return(this.Content <object>(HttpStatusCode.Forbidden, null));
            }

            var assets = order.LineItems
                         .SelectMany(item => item.Assets)
                         .Where(asset => asset != null)
                         .ToDictionary(asset => asset.Name, asset => this.ParseAssetLocationToUrl(asset.Location));

            // Create the command to trigger order processing and place it on the command queue

            var command = new ProcessOrder
            {
                OrderId         = order.OrderRequestHeader.OrderId,
                PartnerCode     = partner,
                Assets          = assets,
                Emulation       = order.Emulation,
                Id              = Guid.NewGuid(),
                CorrelationId   = this.Request.GetOrderFulfillmentCorrelationId(),
                OccurredTimeUtc = this.clock.GetCurrentInstant().ToDateTimeUtc(),
                CurrentUser     = principal?.Identity?.Name,
                Sequence        = 0
            };

            if (!(await this.processOrderCommandPublisher.TryPublishAsync(command)))
            {
                this.Log
                .WithCorrelationId(this.Request.GetOrderFulfillmentCorrelationId())
                .Error("Unable to publish the {CommandName} for {Partner}//{Order}", nameof(ProcessOrder), partner, command.OrderId);

                return(this.ServiceUnavailable(this.CaclulateRetryAfter(this.config.ServiceUnavailableeRetryAfterInSeconds)));
            }

            // This can't be fire-and-forget, as completing the handler with the outstanding request causes an exception.

            try
            {
                await this.eventPublisher.TryPublishAsync(command.CreateNewOrderEvent <OrderReceived>());
            }

            catch (Exception ex)
            {
                this.Log
                .WithCorrelationId(this.Request.GetOrderFulfillmentCorrelationId())
                .Error(ex, "The event {EventName} for {Partner}//{Order} could not be published.  This is non-critical for fulfillment processing.", nameof(OrderReceived), partner, command.OrderId);
            }

            return(this.Accepted(new OrderFulfillmentAccepted(command.OrderId), this.CaclulateRetryAfter(this.config.OrderAcceptedRetryAfterInSeconds)));
        }
Beispiel #13
0
        public async Task FulfillOrderWebHookAllowsNonUrlAssetsForAnAcceptedOrder()
        {
            var mockLogger           = new Mock <ILogger>();
            var mockCommandPublisher = new Mock <ICommandPublisher <ProcessOrder> >();
            var mockActionDescriptor = new Mock <HttpActionDescriptor>();
            var httpConfiguration    = new HttpConfiguration();
            var routeData            = new HttpRouteData(new HttpRoute());
            var request = new HttpRequestMessage();
            var controllerDescriptor = new HttpControllerDescriptor {
                Configuration = httpConfiguration, ControllerName = nameof(OrderSubmissionController)
            };
            var controllerContext = new HttpControllerContext(httpConfiguration, routeData, request)
            {
                ControllerDescriptor = controllerDescriptor
            };
            var actionContext    = new HttpActionContext(controllerContext, mockActionDescriptor.Object);
            var publishedCommand = default(ProcessOrder);

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

            mockCommandPublisher
            .Setup(publisher => publisher.TryPublishAsync(It.IsAny <ProcessOrder>(), It.IsAny <Instant?>()))
            .ReturnsAsync(true)
            .Callback <ProcessOrder, Instant?>((command, publishTime) => publishedCommand = command);

            mockActionDescriptor.SetupGet(descriptor => descriptor.ActionName).Returns("someAction");
            request.SetConfiguration(httpConfiguration);
            request.SetRouteData(routeData);

            var controller = new OrderSubmissionController(Mock.Of <IClock>(), mockCommandPublisher.Object, Mock.Of <IEventPublisher <EventBase> >(), mockLogger.Object, new OrderSubmissionControllerConfiguration {
                OrderAcceptedRetryAfterInSeconds = 5
            })
            {
                ControllerContext = controllerContext
            };

            var order = new OrderFulfillmentMessage
            {
                OrderRequestHeader = new OrderHeader {
                    OrderId = "ABC123", OrderDate = new DateTime(2017, 12, 09, 09, 00, 00, DateTimeKind.Utc)
                },
                LineItems = new List <LineItem>
                {
                    { new LineItem {
                          Assets = new List <ItemAsset> {
                              { new ItemAsset {
                                   Name = "one", Location = "Not a url"
                               } }
                          }
                      } }
                }
            };

            var actionResult = await controller.FulfillOrderWebHook("SQUIRE", order);

            var result = await actionResult.ExecuteAsync(CancellationToken.None);

            result.Should().NotBeNull("because a result should have been returned");
            publishedCommand.Should().NotBeNull("because the command should have been published");

            foreach (var item in order.LineItems)
            {
                var asset        = item.Assets.Single();
                var commandAsset = publishedCommand.Assets[asset.Name];

                commandAsset.Should().NotBeNull("because an asset for asset {0} should be present", asset.Name);
                commandAsset.Should().Be(asset.Location, "because the asset value should be unchanged for asset {0}", asset.Name);
            }
        }
Beispiel #14
0
        public async Task FulfillOrderWebHookForcesAssetUrlsToHttpsForAnAcceptedOrder()
        {
            var mockLogger           = new Mock <ILogger>();
            var mockCommandPublisher = new Mock <ICommandPublisher <ProcessOrder> >();
            var mockActionDescriptor = new Mock <HttpActionDescriptor>();
            var httpConfiguration    = new HttpConfiguration();
            var routeData            = new HttpRouteData(new HttpRoute());
            var request = new HttpRequestMessage();
            var controllerDescriptor = new HttpControllerDescriptor {
                Configuration = httpConfiguration, ControllerName = nameof(OrderSubmissionController)
            };
            var controllerContext = new HttpControllerContext(httpConfiguration, routeData, request)
            {
                ControllerDescriptor = controllerDescriptor
            };
            var actionContext    = new HttpActionContext(controllerContext, mockActionDescriptor.Object);
            var publishedCommand = default(ProcessOrder);

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

            mockCommandPublisher
            .Setup(publisher => publisher.TryPublishAsync(It.IsAny <ProcessOrder>(), It.IsAny <Instant?>()))
            .ReturnsAsync(true)
            .Callback <ProcessOrder, Instant?>((command, publishTime) => publishedCommand = command);

            mockActionDescriptor.SetupGet(descriptor => descriptor.ActionName).Returns("someAction");
            request.SetConfiguration(httpConfiguration);
            request.SetRouteData(routeData);

            var controller = new OrderSubmissionController(Mock.Of <IClock>(), mockCommandPublisher.Object, Mock.Of <IEventPublisher <EventBase> >(), mockLogger.Object, new OrderSubmissionControllerConfiguration {
                OrderAcceptedRetryAfterInSeconds = 5
            })
            {
                ControllerContext = controllerContext
            };

            var order = new OrderFulfillmentMessage
            {
                OrderRequestHeader = new OrderHeader {
                    OrderId = "ABC123", OrderDate = new DateTime(2017, 12, 09, 09, 00, 00, DateTimeKind.Utc)
                },
                LineItems = new List <LineItem>
                {
                    { new LineItem {
                          Assets = new List <ItemAsset> {
                              { new ItemAsset {
                                   Name = "one", Location = "https://www.bob.com/path"
                               } }
                          }
                      } },
                    { new LineItem {
                          Assets = new List <ItemAsset> {
                              { new ItemAsset {
                                   Name = "two", Location = "https://www.john.com:443/path/?name=john"
                               } }
                          }
                      } },
                    { new LineItem {
                          Assets = new List <ItemAsset> {
                              { new ItemAsset {
                                   Name = "three", Location = "gopher://www.frank.com:8086/path"
                               } }
                          }
                      } }
                }
            };

            var actionResult = await controller.FulfillOrderWebHook("SQUIRE", order);

            var result = await actionResult.ExecuteAsync(CancellationToken.None);

            result.Should().NotBeNull("because a result should have been returned");
            publishedCommand.Should().NotBeNull("because the command should have been published");

            foreach (var item in order.LineItems)
            {
                var asset        = item.Assets.Single();
                var commandAsset = publishedCommand.Assets[asset.Name];

                asset.Should().NotBeNull("because an asset for asset {0} should be present", asset.Name);

                var assetUri        = new Uri(asset.Location);
                var commandAssetUri = new Uri(commandAsset);

                commandAssetUri.Scheme.Should().Be(Uri.UriSchemeHttps, "because the uri scheme should have been forced to HTTPS for asset {0}", asset.Name);
                commandAssetUri.Host.Should().Be(assetUri.Host, "because the authorities should match for asset {0}", asset.Name);
                commandAssetUri.PathAndQuery.Should().Be(assetUri.PathAndQuery, "because the path and querystring should match for asset {0}", asset.Name);

                if (assetUri.IsDefaultPort)
                {
                    commandAssetUri.Port.Should().Be(443, "because the default port was used for asset {0}", asset.Name);
                }
                else
                {
                    commandAssetUri.Port.Should().Be(assetUri.Port, "because a non-default port was used for asset {0}", asset.Name);
                }
            }
        }