public async Task Posting_command_JSON_applies_a_command_with_the_specified_name_to_an_aggregate_with_the_specified_id()
        {
            var order = new Order(Guid.NewGuid())
                        .Apply(new ChangeCustomerInfo {
                CustomerName = "Joe"
            })
                        .SavedToEventStore();

            var json = new AddItem
            {
                Quantity    = 5,
                Price       = 19.99m,
                ProductName = "Bag o' Treats"
            }.ToJson();

            var request = new HttpRequestMessage(HttpMethod.Post, $"http://contoso.com/orders/{order.Id}/additem")
            {
                Content = new StringContent(json, Encoding.UTF8, "application/json")
            };

            var testApi = new TestApi <Order>();
            var client  = testApi.GetClient();

            var response = client.SendAsync(request).Result;

            response.StatusCode.Should().Be(HttpStatusCode.OK);

            var updatedOrder = await Configuration.Current.Repository <Order>().GetLatest(order.Id);

            updatedOrder.Items.Single().Quantity.Should().Be(5);
        }
Пример #2
0
        public async Task Posting_a_second_constructor_command_with_the_same_aggregate_id_results_in_a_409_Conflict()
        {
            // arrange
            var testApi = new TestApi <Order>();

            var orderId = Any.Guid();
            await testApi.GetClient()
            .PostAsJsonAsync(string.Format("http://contoso.com/orders/createorder/{0}", orderId), new CreateOrder(Any.FullName()));

            // act
            var response = await testApi.GetClient()
                           .PostAsJsonAsync(string.Format("http://contoso.com/orders/createorder/{0}", orderId), new CreateOrder(Any.FullName()));

            // assert
            response.ShouldFailWith(HttpStatusCode.Conflict);
        }
Пример #3
0
        public async Task Posting_command_JSON_applies_a_command_with_the_specified_name_to_an_aggregate_with_the_specified_id()
        {
            var order = new Order(Guid.NewGuid())
                .Apply(new ChangeCustomerInfo { CustomerName = "Joe" })
                .SavedToEventStore();

            var json = new AddItem
            {
                Quantity = 5,
                Price = 19.99m,
                ProductName = "Bag o' Treats"
            }.ToJson();

            var request = new HttpRequestMessage(HttpMethod.Post, $"http://contoso.com/orders/{order.Id}/additem")
            {
                Content = new StringContent(json, Encoding.UTF8, "application/json")
            };

            var testApi = new TestApi<Order>();
            var client = testApi.GetClient();

            var response = client.SendAsync(request).Result;

            response.StatusCode.Should().Be(HttpStatusCode.OK);

            var updatedOrder = await Configuration.Current.Repository<Order>().GetLatest(order.Id);

            updatedOrder.Items.Single().Quantity.Should().Be(5);
        }
Пример #4
0
        public async Task Posting_an_invalid_command_does_not_affect_the_aggregate_state()
        {
            var order = new Order(Guid.NewGuid(),
                                  new Order.CustomerInfoChanged {
                CustomerName = "Joe"
            },
                                  new Order.Fulfilled());
            await order.SaveToEventStore();

            var json = new AddItem
            {
                Quantity    = 5,
                Price       = 19.99m,
                ProductName = "Bag o' Treats"
            }.ToJson();

            var request = new HttpRequestMessage(HttpMethod.Post, string.Format("http://contoso.com/orders/{0}/additem", order.Id))
            {
                Content = new StringContent(json, Encoding.UTF8, "application/json")
            };

            var testApi = new TestApi <Order>();
            var client  = testApi.GetClient();

            var response = client.SendAsync(request).Result;

            response.StatusCode.Should().Be(HttpStatusCode.BadRequest);

            var updatedOrder = await new SqlEventSourcedRepository <Order>().GetLatest(order.Id);

            updatedOrder.Items.Count().Should().Be(0);
        }
Пример #5
0
        public async Task Posting_an_invalid_create_command_returns_400_Bad_request()
        {
            var testApi  = new TestApi <Order>();
            var response = await testApi.GetClient()
                           .PostAsJsonAsync(string.Format("http://contoso.com/orders/createorder/{0}", Any.Guid()), new object());

            response.ShouldFailWith(HttpStatusCode.BadRequest);
        }
Пример #6
0
        public async Task Posting_a_constructor_command_creates_a_new_aggregate_instance()
        {
            var testApi = new TestApi <Order>();

            var orderId = Any.Guid();

            var response = await testApi.GetClient()
                           .PostAsJsonAsync(string.Format("http://contoso.com/orders/createorder/{0}", orderId), new CreateOrder(Any.FullName()));

            response.ShouldSucceed(HttpStatusCode.Created);
        }
Пример #7
0
        public async Task ApplyBatch_can_accept_an_array_of_commands()
        {
            var repository = new SqlEventSourcedRepository <Order>(new FakeEventBus());
            var order      = new Order();
            await repository.Save(order);

            var json = new[]
            {
                new
                {
                    AddItem = new
                    {
                        Quantity    = 1,
                        Price       = 1,
                        ProductName = "Sprocket"
                    }
                },
                new
                {
                    AddItem = new
                    {
                        Quantity    = 1,
                        Price       = 2,
                        ProductName = "Cog"
                    }
                }
            }.ToJson();

            var testApi = new TestApi <Order>();
            var client  = testApi.GetClient();

            var request = new HttpRequestMessage(HttpMethod.Post, string.Format("http://contoso.com/orders/{0}", order.Id))
            {
                Content = new StringContent(json, Encoding.UTF8, "application/json")
            };

            var response = await client.SendAsync(request);

            response.ShouldSucceed();

            order = await repository.GetLatest(order.Id);

            order.Items.Count.Should().Be(2);
            order.Balance.Should().Be(3);
        }
Пример #8
0
        public async Task Posting_a_command_that_causes_a_concurrency_error_returns_409_Conflict()
        {
            var order = new Order(Guid.NewGuid(), new Order.CustomerInfoChanged { CustomerName = "Joe" });

            var testApi = new TestApi<Order>();
            var repository = new Mock<IEventSourcedRepository<Order>>();
            repository.Setup(r => r.GetLatest(It.IsAny<Guid>()))
                      .Returns(order);
            repository.Setup(r => r.Save(It.IsAny<Order>()))
                      .Throws(new ConcurrencyException("oops!", new IEvent[0], new Exception("inner oops")));
            testApi.Container.Register(c => repository.Object);

            var client = testApi.GetClient();

            var response = await client.PostAsJsonAsync(string.Format("http://contoso.com/orders/{0}/additem", order.Id), new { Price = 3m, ProductName = Any.Word() });

            response.ShouldFailWith(HttpStatusCode.Conflict);
        }
Пример #9
0
        public async Task An_ETag_header_is_applied_to_the_command()
        {
            var order = new Order(Guid.NewGuid(),
                                  new Order.CustomerInfoChanged {
                CustomerName = "Joe"
            });
            await order.SaveToEventStore();

            var json = new AddItem
            {
                Quantity    = 5,
                Price       = 19.99m,
                ProductName = "Bag o' Treats"
            }.ToJson();

            var etag = new EntityTagHeaderValue("\"" + Any.Guid() + "\"");

            Func <HttpRequestMessage> createRequest = () =>
            {
                var request = new HttpRequestMessage(HttpMethod.Post, string.Format("http://contoso.com/orders/{0}/additem", order.Id))
                {
                    Content = new StringContent(json, Encoding.UTF8, "application/json"),
                };
                request.Headers.IfNoneMatch.Add(etag);
                return(request);
            };

            var testApi = new TestApi <Order>();
            var client  = testApi.GetClient();

            // act: send the request twice
            var response1 = await client.SendAsync(createRequest());

            var response2 = await client.SendAsync(createRequest());

            // assert
            response1.ShouldSucceed(HttpStatusCode.OK);
            response2.ShouldFailWith(HttpStatusCode.NotModified);

            var updatedOrder = await new SqlEventSourcedRepository <Order>().GetLatest(order.Id);

            updatedOrder.Items.Single().Quantity.Should().Be(5);
        }
        public async Task ApplyBatch_can_accept_an_array_of_commands()
        {
            var order = new Order().SavedToEventStore();

            var json = new[]
            {
                new
                {
                    AddItem = new
                    {
                        Quantity = 1,
                        Price = 1,
                        ProductName = "Sprocket"
                    }
                },
                new
                {
                    AddItem = new
                    {
                        Quantity = 1,
                        Price = 2,
                        ProductName = "Cog"
                    }
                }
            }.ToJson();

            var testApi = new TestApi<Order>();
            var client = testApi.GetClient();

            var request = new HttpRequestMessage(HttpMethod.Post, $"http://contoso.com/orders/{order.Id}")
            {
                Content = new StringContent(json, Encoding.UTF8, "application/json")
            };

            var response = await client.SendAsync(request);
            response.ShouldSucceed();

            order = await Configuration.Current.Repository<Order>().GetLatest(order.Id);

            order.Items.Count.Should().Be(2);
            order.Balance.Should().Be(3);
        }
        public async Task Posting_a_command_that_causes_a_concurrency_error_returns_409_Conflict()
        {
            var order = new Order(Guid.NewGuid())
                        .Apply(new ChangeCustomerInfo {
                CustomerName = "Joe"
            })
                        .SavedToEventStore();

            var testApi    = new TestApi <Order>();
            var repository = new Mock <IEventSourcedRepository <Order> >();

            repository.Setup(r => r.GetLatest(It.IsAny <Guid>()))
            .Returns(Task.FromResult(order));
            repository.Setup(r => r.Save(It.IsAny <Order>()))
            .Throws(new ConcurrencyException("oops!", new IEvent[0], new Exception("inner oops")));
            Configuration.Current.UseDependency(c => repository.Object);

            var client = testApi.GetClient();

            var response = await client.PostAsJsonAsync($"http://contoso.com/orders/{order.Id}/additem", new { Price = 3m, ProductName = Any.Word() });

            response.ShouldFailWith(HttpStatusCode.Conflict);
        }
Пример #12
0
        public async Task Posting_an_invalid_create_command_returns_400_Bad_request()
        {
            var testApi = new TestApi<Order>();
            var response = await testApi.GetClient()
                                        .PostAsJsonAsync(string.Format("http://contoso.com/orders/createorder/{0}", Any.Guid()), new object());

            response.ShouldFailWith(HttpStatusCode.BadRequest);
        }
        public async Task Posting_an_invalid_command_does_not_affect_the_aggregate_state()
        {
            var order = new Order(Guid.NewGuid(),
                                  new Order.CustomerInfoChanged { CustomerName = "Joe" },
                                  new Order.Fulfilled());
            await order.SaveToEventStore();
            var json = new AddItem
            {
                Quantity = 5,
                Price = 19.99m,
                ProductName = "Bag o' Treats"
            }.ToJson();

            var request = new HttpRequestMessage(HttpMethod.Post, string.Format("http://contoso.com/orders/{0}/additem", order.Id))
            {
                Content = new StringContent(json, Encoding.UTF8, "application/json")
            };

            var testApi = new TestApi<Order>();
            var client = testApi.GetClient();

            var response = client.SendAsync(request).Result;

            response.StatusCode.Should().Be(HttpStatusCode.BadRequest);

            var updatedOrder = await new SqlEventSourcedRepository<Order>().GetLatest(order.Id);

            updatedOrder.Items.Count().Should().Be(0);
        }
Пример #14
0
        public async Task Posting_a_command_that_causes_a_concurrency_error_returns_409_Conflict()
        {
            var order = new Order(Guid.NewGuid())
                .Apply(new ChangeCustomerInfo { CustomerName = "Joe" })
                .SavedToEventStore();

            var testApi = new TestApi<Order>();
            var repository = new Mock<IEventSourcedRepository<Order>>();
            repository.Setup(r => r.GetLatest(It.IsAny<Guid>()))
                      .Returns(Task.FromResult(order));
            repository.Setup(r => r.Save(It.IsAny<Order>()))
                      .Throws(new ConcurrencyException("oops!", new IEvent[0], new Exception("inner oops")));
            Configuration.Current.UseDependency(c => repository.Object);

            var client = testApi.GetClient();

            var response = await client.PostAsJsonAsync($"http://contoso.com/orders/{order.Id}/additem", new { Price = 3m, ProductName = Any.Word() });

            response.ShouldFailWith(HttpStatusCode.Conflict);
        }
Пример #15
0
        public async Task Posting_a_constructor_command_creates_a_new_aggregate_instance()
        {
            var testApi = new TestApi<Order>();

            var orderId = Any.Guid();

            var response = await testApi.GetClient()
                                        .PostAsJsonAsync($"http://contoso.com/orders/createorder/{orderId}", new CreateOrder(Any.FullName()));

            response.ShouldSucceed(HttpStatusCode.Created);
        }
Пример #16
0
        public async Task Posting_a_second_constructor_command_with_the_same_aggregate_id_results_in_a_409_Conflict()
        {
            // arrange
            var testApi = new TestApi<Order>();

            var orderId = Any.Guid();
            await testApi.GetClient()
                         .PostAsJsonAsync($"http://contoso.com/orders/createorder/{orderId}", new CreateOrder(Any.FullName()));

            // act
            var response = await testApi.GetClient()
                                        .PostAsJsonAsync($"http://contoso.com/orders/createorder/{orderId}", new CreateOrder(Any.FullName()));

            // assert
            response.ShouldFailWith(HttpStatusCode.Conflict);
        }
Пример #17
0
        public async Task An_ETag_header_is_applied_to_the_command()
        {
            var order = new Order(Guid.NewGuid())
                .Apply(new ChangeCustomerInfo { CustomerName = "Joe" })
                .SavedToEventStore();

            var json = new AddItem
            {
                Quantity = 5,
                Price = 19.99m,
                ProductName = "Bag o' Treats"
            }.ToJson();
            
            var etag = new EntityTagHeaderValue("\"" + Any.Guid() + "\"");

            Func<HttpRequestMessage> createRequest = () =>
            {
                var request = new HttpRequestMessage(HttpMethod.Post, $"http://contoso.com/orders/{order.Id}/additem")
                {
                    Content = new StringContent(json, Encoding.UTF8, "application/json")
                };
                request.Headers.IfNoneMatch.Add(etag);
                return request;
            };

            var testApi = new TestApi<Order>();
            var client = testApi.GetClient();

            // act: send the request twice
            var response1 = await client.SendAsync(createRequest());
            var response2 = await client.SendAsync(createRequest());

            // assert
            response1.ShouldSucceed(HttpStatusCode.OK);
            response2.ShouldFailWith(HttpStatusCode.NotModified);

            var updatedOrder = await Configuration.Current.Repository<Order>().GetLatest(order.Id);
            updatedOrder.Items.Single().Quantity.Should().Be(5);
        }