@ -1,16 +1,11 @@ | |||||
using Microsoft.AspNetCore.TestHost; | |||||
using System; | |||||
using System.Net.Http; | |||||
namespace FunctionalTests.Extensions; | |||||
namespace FunctionalTests.Extensions | |||||
static class HttpClientExtensions | |||||
{ | { | ||||
static class HttpClientExtensions | |||||
public static HttpClient CreateIdempotentClient(this TestServer server) | |||||
{ | { | ||||
public static HttpClient CreateIdempotentClient(this TestServer server) | |||||
{ | |||||
var client = server.CreateClient(); | |||||
client.DefaultRequestHeaders.Add("x-requestid", Guid.NewGuid().ToString()); | |||||
return client; | |||||
} | |||||
var client = server.CreateClient(); | |||||
client.DefaultRequestHeaders.Add("x-requestid", Guid.NewGuid().ToString()); | |||||
return client; | |||||
} | } | ||||
} | } |
@ -1,31 +1,26 @@ | |||||
using Microsoft.AspNetCore.Http; | |||||
using System.Security.Claims; | |||||
using System.Threading.Tasks; | |||||
namespace FunctionalTests.Middleware; | |||||
namespace FunctionalTests.Middleware | |||||
class AutoAuthorizeMiddleware | |||||
{ | { | ||||
class AutoAuthorizeMiddleware | |||||
{ | |||||
public const string IDENTITY_ID = "9e3163b9-1ae6-4652-9dc6-7898ab7b7a00"; | |||||
public const string IDENTITY_ID = "9e3163b9-1ae6-4652-9dc6-7898ab7b7a00"; | |||||
private readonly RequestDelegate _next; | |||||
private readonly RequestDelegate _next; | |||||
public AutoAuthorizeMiddleware(RequestDelegate rd) | |||||
{ | |||||
_next = rd; | |||||
} | |||||
public AutoAuthorizeMiddleware(RequestDelegate rd) | |||||
{ | |||||
_next = rd; | |||||
} | |||||
public async Task Invoke(HttpContext httpContext) | |||||
{ | |||||
var identity = new ClaimsIdentity("cookies"); | |||||
public async Task Invoke(HttpContext httpContext) | |||||
{ | |||||
var identity = new ClaimsIdentity("cookies"); | |||||
identity.AddClaim(new Claim("sub", IDENTITY_ID)); | |||||
identity.AddClaim(new Claim("unique_name", IDENTITY_ID)); | |||||
identity.AddClaim(new Claim(ClaimTypes.Name, IDENTITY_ID)); | |||||
identity.AddClaim(new Claim("sub", IDENTITY_ID)); | |||||
identity.AddClaim(new Claim("unique_name", IDENTITY_ID)); | |||||
identity.AddClaim(new Claim(ClaimTypes.Name, IDENTITY_ID)); | |||||
httpContext.User.AddIdentity(identity); | |||||
await _next.Invoke(httpContext); | |||||
} | |||||
httpContext.User.AddIdentity(identity); | |||||
await _next.Invoke(httpContext); | |||||
} | } | ||||
} | } |
@ -1,49 +1,42 @@ | |||||
using Microsoft.AspNetCore.Hosting; | |||||
using Microsoft.AspNetCore.TestHost; | |||||
using Microsoft.Extensions.Configuration; | |||||
using System.IO; | |||||
using System.Reflection; | |||||
namespace FunctionalTests.Services.Basket; | |||||
namespace FunctionalTests.Services.Basket | |||||
public class BasketScenariosBase | |||||
{ | { | ||||
public class BasketScenariosBase | |||||
{ | |||||
private const string ApiUrlBase = "api/v1/basket"; | |||||
private const string ApiUrlBase = "api/v1/basket"; | |||||
public TestServer CreateServer() | |||||
{ | |||||
var path = Assembly.GetAssembly(typeof(BasketScenariosBase)) | |||||
.Location; | |||||
var hostBuilder = new WebHostBuilder() | |||||
.UseContentRoot(Path.GetDirectoryName(path)) | |||||
.ConfigureAppConfiguration(cb => | |||||
{ | |||||
cb.AddJsonFile("Services/Basket/appsettings.json", optional: false) | |||||
.AddEnvironmentVariables(); | |||||
}).UseStartup<BasketTestsStartup>(); | |||||
return new TestServer(hostBuilder); | |||||
} | |||||
public TestServer CreateServer() | |||||
{ | |||||
var path = Assembly.GetAssembly(typeof(BasketScenariosBase)) | |||||
.Location; | |||||
public static class Get | |||||
{ | |||||
public static string GetBasket(int id) | |||||
var hostBuilder = new WebHostBuilder() | |||||
.UseContentRoot(Path.GetDirectoryName(path)) | |||||
.ConfigureAppConfiguration(cb => | |||||
{ | { | ||||
return $"{ApiUrlBase}/{id}"; | |||||
} | |||||
cb.AddJsonFile("Services/Basket/appsettings.json", optional: false) | |||||
.AddEnvironmentVariables(); | |||||
}).UseStartup<BasketTestsStartup>(); | |||||
public static string GetBasketByCustomer(string customerId) | |||||
{ | |||||
return $"{ApiUrlBase}/{customerId}"; | |||||
} | |||||
return new TestServer(hostBuilder); | |||||
} | |||||
public static class Get | |||||
{ | |||||
public static string GetBasket(int id) | |||||
{ | |||||
return $"{ApiUrlBase}/{id}"; | |||||
} | } | ||||
public static class Post | |||||
public static string GetBasketByCustomer(string customerId) | |||||
{ | { | ||||
public static string CreateBasket = $"{ApiUrlBase}/"; | |||||
public static string CheckoutOrder = $"{ApiUrlBase}/checkout"; | |||||
return $"{ApiUrlBase}/{customerId}"; | |||||
} | } | ||||
} | } | ||||
public static class Post | |||||
{ | |||||
public static string CreateBasket = $"{ApiUrlBase}/"; | |||||
public static string CheckoutOrder = $"{ApiUrlBase}/checkout"; | |||||
} | |||||
} | } |
@ -1,27 +1,21 @@ | |||||
using FunctionalTests.Middleware; | |||||
using Microsoft.AspNetCore.Builder; | |||||
namespace FunctionalTests.Services.Basket; | |||||
using Microsoft.eShopOnContainers.Services.Basket.API; | using Microsoft.eShopOnContainers.Services.Basket.API; | ||||
using Microsoft.Extensions.Configuration; | |||||
namespace FunctionalTests.Services.Basket | |||||
class BasketTestsStartup : Startup | |||||
{ | { | ||||
class BasketTestsStartup : Startup | |||||
public BasketTestsStartup(IConfiguration env) : base(env) | |||||
{ | { | ||||
public BasketTestsStartup(IConfiguration env) : base(env) | |||||
} | |||||
protected override void ConfigureAuth(IApplicationBuilder app) | |||||
{ | |||||
if (Configuration["isTest"] == bool.TrueString.ToLowerInvariant()) | |||||
{ | { | ||||
app.UseMiddleware<AutoAuthorizeMiddleware>(); | |||||
app.UseAuthorization(); | |||||
} | } | ||||
protected override void ConfigureAuth(IApplicationBuilder app) | |||||
else | |||||
{ | { | ||||
if (Configuration["isTest"] == bool.TrueString.ToLowerInvariant()) | |||||
{ | |||||
app.UseMiddleware<AutoAuthorizeMiddleware>(); | |||||
app.UseAuthorization(); | |||||
} | |||||
else | |||||
{ | |||||
base.ConfigureAuth(app); | |||||
} | |||||
base.ConfigureAuth(app); | |||||
} | } | ||||
} | } | ||||
} | } |
@ -1,65 +1,53 @@ | |||||
using Microsoft.AspNetCore.Hosting; | |||||
using Microsoft.AspNetCore.TestHost; | |||||
using Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF; | |||||
namespace FunctionalTests.Services.Catalog; | |||||
using Microsoft.eShopOnContainers.Services.Catalog.API; | using Microsoft.eShopOnContainers.Services.Catalog.API; | ||||
using Microsoft.eShopOnContainers.Services.Catalog.API.Infrastructure; | |||||
using Microsoft.Extensions.Configuration; | |||||
using Microsoft.Extensions.DependencyInjection; | |||||
using Microsoft.Extensions.Logging; | |||||
using Microsoft.Extensions.Options; | |||||
using System.IO; | |||||
using System.Reflection; | |||||
namespace FunctionalTests.Services.Catalog | |||||
public class CatalogScenariosBase | |||||
{ | { | ||||
public class CatalogScenariosBase | |||||
public TestServer CreateServer() | |||||
{ | { | ||||
public TestServer CreateServer() | |||||
{ | |||||
var path = Assembly.GetAssembly(typeof(CatalogScenariosBase)) | |||||
.Location; | |||||
var path = Assembly.GetAssembly(typeof(CatalogScenariosBase)) | |||||
.Location; | |||||
var hostBuilder = new WebHostBuilder() | |||||
.UseContentRoot(Path.GetDirectoryName(path)) | |||||
.ConfigureAppConfiguration(cb => | |||||
{ | |||||
cb.AddJsonFile("Services/Catalog/appsettings.json", optional: false) | |||||
.AddEnvironmentVariables(); | |||||
}).UseStartup<Startup>(); | |||||
var hostBuilder = new WebHostBuilder() | |||||
.UseContentRoot(Path.GetDirectoryName(path)) | |||||
.ConfigureAppConfiguration(cb => | |||||
{ | |||||
cb.AddJsonFile("Services/Catalog/appsettings.json", optional: false) | |||||
.AddEnvironmentVariables(); | |||||
}).UseStartup<Startup>(); | |||||
var testServer = new TestServer(hostBuilder); | |||||
var testServer = new TestServer(hostBuilder); | |||||
testServer.Host | |||||
.MigrateDbContext<CatalogContext>((context, services) => | |||||
{ | |||||
var env = services.GetService<IWebHostEnvironment>(); | |||||
var settings = services.GetService<IOptions<CatalogSettings>>(); | |||||
var logger = services.GetService<ILogger<CatalogContextSeed>>(); | |||||
testServer.Host | |||||
.MigrateDbContext<CatalogContext>((context, services) => | |||||
{ | |||||
var env = services.GetService<IWebHostEnvironment>(); | |||||
var settings = services.GetService<IOptions<CatalogSettings>>(); | |||||
var logger = services.GetService<ILogger<CatalogContextSeed>>(); | |||||
new CatalogContextSeed() | |||||
.SeedAsync(context, env, settings, logger) | |||||
.Wait(); | |||||
}) | |||||
.MigrateDbContext<IntegrationEventLogContext>((_, __) => { }); | |||||
new CatalogContextSeed() | |||||
.SeedAsync(context, env, settings, logger) | |||||
.Wait(); | |||||
}) | |||||
.MigrateDbContext<IntegrationEventLogContext>((_, __) => { }); | |||||
return testServer; | |||||
} | |||||
public static class Get | |||||
{ | |||||
public static string Orders = "api/v1/orders"; | |||||
return testServer; | |||||
} | |||||
public static string Items = "api/v1/catalog/items"; | |||||
public static class Get | |||||
{ | |||||
public static string Orders = "api/v1/orders"; | |||||
public static string ProductByName(string name) | |||||
{ | |||||
return $"api/v1/catalog/items/withname/{name}"; | |||||
} | |||||
} | |||||
public static string Items = "api/v1/catalog/items"; | |||||
public static class Put | |||||
public static string ProductByName(string name) | |||||
{ | { | ||||
public static string UpdateCatalogProduct = "api/v1/catalog/items"; | |||||
return $"api/v1/catalog/items/withname/{name}"; | |||||
} | } | ||||
} | } | ||||
public static class Put | |||||
{ | |||||
public static string UpdateCatalogProduct = "api/v1/catalog/items"; | |||||
} | |||||
} | } |
@ -1,134 +1,122 @@ | |||||
using FunctionalTests.Services.Basket; | |||||
using FunctionalTests.Services.Catalog; | |||||
namespace FunctionalTests.Services; | |||||
using Microsoft.eShopOnContainers.Services.Basket.API.Model; | using Microsoft.eShopOnContainers.Services.Basket.API.Model; | ||||
using Microsoft.eShopOnContainers.Services.Catalog.API.Model; | using Microsoft.eShopOnContainers.Services.Catalog.API.Model; | ||||
using Microsoft.eShopOnContainers.Services.Catalog.API.ViewModel; | using Microsoft.eShopOnContainers.Services.Catalog.API.ViewModel; | ||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Linq; | |||||
using System.Net.Http; | |||||
using System.Text; | |||||
using System.Text.Json; | |||||
using System.Threading.Tasks; | |||||
using Xunit; | |||||
namespace FunctionalTests.Services | |||||
public class IntegrationEventsScenarios | |||||
{ | { | ||||
public class IntegrationEventsScenarios | |||||
[Fact] | |||||
public async Task Post_update_product_price_and_catalog_and_basket_list_modified() | |||||
{ | { | ||||
[Fact] | |||||
public async Task Post_update_product_price_and_catalog_and_basket_list_modified() | |||||
decimal priceModification = 0.15M; | |||||
string userId = "JohnId"; | |||||
using (var catalogServer = new CatalogScenariosBase().CreateServer()) | |||||
using (var basketServer = new BasketScenariosBase().CreateServer()) | |||||
{ | { | ||||
decimal priceModification = 0.15M; | |||||
string userId = "JohnId"; | |||||
var catalogClient = catalogServer.CreateClient(); | |||||
var basketClient = basketServer.CreateClient(); | |||||
using (var catalogServer = new CatalogScenariosBase().CreateServer()) | |||||
using (var basketServer = new BasketScenariosBase().CreateServer()) | |||||
{ | |||||
var catalogClient = catalogServer.CreateClient(); | |||||
var basketClient = basketServer.CreateClient(); | |||||
// GIVEN a product catalog list | |||||
var originalCatalogProducts = await GetCatalogAsync(catalogClient); | |||||
// AND a user basket filled with products | |||||
var basket = ComposeBasket(userId, originalCatalogProducts.Data.Take(3)); | |||||
var res = await basketClient.PostAsync( | |||||
BasketScenariosBase.Post.CreateBasket, | |||||
new StringContent(JsonSerializer.Serialize(basket), UTF8Encoding.UTF8, "application/json") | |||||
); | |||||
// WHEN the price of one product is modified in the catalog | |||||
var itemToModify = basket.Items[2]; | |||||
var oldPrice = itemToModify.UnitPrice; | |||||
var newPrice = oldPrice + priceModification; | |||||
var pRes = await catalogClient.PutAsync(CatalogScenariosBase.Put.UpdateCatalogProduct, new StringContent(ChangePrice(itemToModify, newPrice, originalCatalogProducts), UTF8Encoding.UTF8, "application/json")); | |||||
var modifiedCatalogProducts = await GetCatalogAsync(catalogClient); | |||||
var itemUpdated = await GetUpdatedBasketItem(newPrice, itemToModify.ProductId, userId, basketClient); | |||||
if (itemUpdated == null) | |||||
{ | |||||
Assert.False(true, $"The basket service has not been updated."); | |||||
} | |||||
else | |||||
{ | |||||
//THEN the product price changes in the catalog | |||||
Assert.Equal(newPrice, modifiedCatalogProducts.Data.Single(it => it.Id == itemToModify.ProductId).Price); | |||||
// AND the products in the basket reflects the changed priced and the original price | |||||
Assert.Equal(newPrice, itemUpdated.UnitPrice); | |||||
Assert.Equal(oldPrice, itemUpdated.OldUnitPrice); | |||||
} | |||||
} | |||||
} | |||||
// GIVEN a product catalog list | |||||
var originalCatalogProducts = await GetCatalogAsync(catalogClient); | |||||
private async Task<BasketItem> GetUpdatedBasketItem(decimal newPrice, int productId, string userId, HttpClient basketClient) | |||||
{ | |||||
bool continueLoop = true; | |||||
var counter = 0; | |||||
BasketItem itemUpdated = null; | |||||
// AND a user basket filled with products | |||||
var basket = ComposeBasket(userId, originalCatalogProducts.Data.Take(3)); | |||||
var res = await basketClient.PostAsync( | |||||
BasketScenariosBase.Post.CreateBasket, | |||||
new StringContent(JsonSerializer.Serialize(basket), UTF8Encoding.UTF8, "application/json") | |||||
); | |||||
// WHEN the price of one product is modified in the catalog | |||||
var itemToModify = basket.Items[2]; | |||||
var oldPrice = itemToModify.UnitPrice; | |||||
var newPrice = oldPrice + priceModification; | |||||
var pRes = await catalogClient.PutAsync(CatalogScenariosBase.Put.UpdateCatalogProduct, new StringContent(ChangePrice(itemToModify, newPrice, originalCatalogProducts), UTF8Encoding.UTF8, "application/json")); | |||||
var modifiedCatalogProducts = await GetCatalogAsync(catalogClient); | |||||
while (continueLoop && counter < 20) | |||||
var itemUpdated = await GetUpdatedBasketItem(newPrice, itemToModify.ProductId, userId, basketClient); | |||||
if (itemUpdated == null) | |||||
{ | { | ||||
//get the basket and verify that the price of the modified product is updated | |||||
var basketGetResponse = await basketClient.GetAsync(BasketScenariosBase.Get.GetBasketByCustomer(userId)); | |||||
var basketUpdated = JsonSerializer.Deserialize<CustomerBasket>(await basketGetResponse.Content.ReadAsStringAsync(), new JsonSerializerOptions | |||||
{ | |||||
PropertyNameCaseInsensitive = true | |||||
}); | |||||
itemUpdated = basketUpdated.Items.Single(pr => pr.ProductId == productId); | |||||
if (itemUpdated.UnitPrice == newPrice) | |||||
{ | |||||
continueLoop = false; | |||||
} | |||||
else | |||||
{ | |||||
counter++; | |||||
await Task.Delay(100); | |||||
} | |||||
Assert.False(true, $"The basket service has not been updated."); | |||||
} | } | ||||
else | |||||
{ | |||||
//THEN the product price changes in the catalog | |||||
Assert.Equal(newPrice, modifiedCatalogProducts.Data.Single(it => it.Id == itemToModify.ProductId).Price); | |||||
return itemUpdated; | |||||
// AND the products in the basket reflects the changed priced and the original price | |||||
Assert.Equal(newPrice, itemUpdated.UnitPrice); | |||||
Assert.Equal(oldPrice, itemUpdated.OldUnitPrice); | |||||
} | |||||
} | } | ||||
} | |||||
private async Task<PaginatedItemsViewModel<CatalogItem>> GetCatalogAsync(HttpClient catalogClient) | |||||
private async Task<BasketItem> GetUpdatedBasketItem(decimal newPrice, int productId, string userId, HttpClient basketClient) | |||||
{ | |||||
bool continueLoop = true; | |||||
var counter = 0; | |||||
BasketItem itemUpdated = null; | |||||
while (continueLoop && counter < 20) | |||||
{ | { | ||||
var response = await catalogClient.GetAsync(CatalogScenariosBase.Get.Items); | |||||
var items = await response.Content.ReadAsStringAsync(); | |||||
return JsonSerializer.Deserialize<PaginatedItemsViewModel<CatalogItem>>(items, new JsonSerializerOptions | |||||
//get the basket and verify that the price of the modified product is updated | |||||
var basketGetResponse = await basketClient.GetAsync(BasketScenariosBase.Get.GetBasketByCustomer(userId)); | |||||
var basketUpdated = JsonSerializer.Deserialize<CustomerBasket>(await basketGetResponse.Content.ReadAsStringAsync(), new JsonSerializerOptions | |||||
{ | { | ||||
PropertyNameCaseInsensitive = true | PropertyNameCaseInsensitive = true | ||||
}); | }); | ||||
itemUpdated = basketUpdated.Items.Single(pr => pr.ProductId == productId); | |||||
if (itemUpdated.UnitPrice == newPrice) | |||||
{ | |||||
continueLoop = false; | |||||
} | |||||
else | |||||
{ | |||||
counter++; | |||||
await Task.Delay(100); | |||||
} | |||||
} | } | ||||
private string ChangePrice(BasketItem itemToModify, decimal newPrice, PaginatedItemsViewModel<CatalogItem> catalogProducts) | |||||
return itemUpdated; | |||||
} | |||||
private async Task<PaginatedItemsViewModel<CatalogItem>> GetCatalogAsync(HttpClient catalogClient) | |||||
{ | |||||
var response = await catalogClient.GetAsync(CatalogScenariosBase.Get.Items); | |||||
var items = await response.Content.ReadAsStringAsync(); | |||||
return JsonSerializer.Deserialize<PaginatedItemsViewModel<CatalogItem>>(items, new JsonSerializerOptions | |||||
{ | { | ||||
var catalogProduct = catalogProducts.Data.Single(pr => pr.Id == itemToModify.ProductId); | |||||
catalogProduct.Price = newPrice; | |||||
return JsonSerializer.Serialize(catalogProduct); | |||||
} | |||||
PropertyNameCaseInsensitive = true | |||||
}); | |||||
} | |||||
private string ChangePrice(BasketItem itemToModify, decimal newPrice, PaginatedItemsViewModel<CatalogItem> catalogProducts) | |||||
{ | |||||
var catalogProduct = catalogProducts.Data.Single(pr => pr.Id == itemToModify.ProductId); | |||||
catalogProduct.Price = newPrice; | |||||
return JsonSerializer.Serialize(catalogProduct); | |||||
} | |||||
private CustomerBasket ComposeBasket(string customerId, IEnumerable<CatalogItem> items) | |||||
private CustomerBasket ComposeBasket(string customerId, IEnumerable<CatalogItem> items) | |||||
{ | |||||
var basket = new CustomerBasket(customerId); | |||||
foreach (var item in items) | |||||
{ | { | ||||
var basket = new CustomerBasket(customerId); | |||||
foreach (var item in items) | |||||
basket.Items.Add(new BasketItem() | |||||
{ | { | ||||
basket.Items.Add(new BasketItem() | |||||
{ | |||||
Id = Guid.NewGuid().ToString(), | |||||
UnitPrice = item.Price, | |||||
PictureUrl = item.PictureUri, | |||||
ProductId = item.Id, | |||||
OldUnitPrice = 0, | |||||
ProductName = item.Name, | |||||
Quantity = 1 | |||||
}); | |||||
} | |||||
return basket; | |||||
Id = Guid.NewGuid().ToString(), | |||||
UnitPrice = item.Price, | |||||
PictureUrl = item.PictureUri, | |||||
ProductId = item.Id, | |||||
OldUnitPrice = 0, | |||||
ProductName = item.Name, | |||||
Quantity = 1 | |||||
}); | |||||
} | } | ||||
return basket; | |||||
} | } | ||||
} | |||||
} |
@ -1,156 +1,141 @@ | |||||
using FunctionalTests.Extensions; | |||||
using FunctionalTests.Services.Basket; | |||||
using Microsoft.eShopOnContainers.Services.Basket.API.Model; | |||||
using Microsoft.eShopOnContainers.WebMVC.ViewModels; | |||||
using System; | |||||
using System.Text.Json; | |||||
using System.Collections.Generic; | |||||
using System.Linq; | |||||
using System.Net.Http; | |||||
using System.Text; | |||||
using System.Threading.Tasks; | |||||
using WebMVC.Services.ModelDTOs; | |||||
using Xunit; | |||||
namespace FunctionalTests.Services.Ordering | |||||
namespace FunctionalTests.Services.Ordering; | |||||
public class OrderingScenarios : OrderingScenariosBase | |||||
{ | { | ||||
public class OrderingScenarios : OrderingScenariosBase | |||||
[Fact] | |||||
public async Task Cancel_basket_and_check_order_status_cancelled() | |||||
{ | { | ||||
[Fact] | |||||
public async Task Cancel_basket_and_check_order_status_cancelled() | |||||
using (var orderServer = new OrderingScenariosBase().CreateServer()) | |||||
using (var basketServer = new BasketScenariosBase().CreateServer()) | |||||
{ | { | ||||
using (var orderServer = new OrderingScenariosBase().CreateServer()) | |||||
using (var basketServer = new BasketScenariosBase().CreateServer()) | |||||
{ | |||||
// Expected data | |||||
var cityExpected = $"city-{Guid.NewGuid()}"; | |||||
var orderStatusExpected = "cancelled"; | |||||
// Expected data | |||||
var cityExpected = $"city-{Guid.NewGuid()}"; | |||||
var orderStatusExpected = "cancelled"; | |||||
var basketClient = basketServer.CreateIdempotentClient(); | |||||
var orderClient = orderServer.CreateIdempotentClient(); | |||||
var basketClient = basketServer.CreateIdempotentClient(); | |||||
var orderClient = orderServer.CreateIdempotentClient(); | |||||
// GIVEN a basket is created | |||||
var contentBasket = new StringContent(BuildBasket(), UTF8Encoding.UTF8, "application/json"); | |||||
await basketClient.PostAsync(BasketScenariosBase.Post.CreateBasket, contentBasket); | |||||
// GIVEN a basket is created | |||||
var contentBasket = new StringContent(BuildBasket(), UTF8Encoding.UTF8, "application/json"); | |||||
await basketClient.PostAsync(BasketScenariosBase.Post.CreateBasket, contentBasket); | |||||
// AND basket checkout is sent | |||||
await basketClient.PostAsync(BasketScenariosBase.Post.CheckoutOrder, new StringContent(BuildCheckout(cityExpected), UTF8Encoding.UTF8, "application/json")); | |||||
// AND basket checkout is sent | |||||
await basketClient.PostAsync(BasketScenariosBase.Post.CheckoutOrder, new StringContent(BuildCheckout(cityExpected), UTF8Encoding.UTF8, "application/json")); | |||||
// WHEN Order is created in Ordering.api | |||||
var newOrder = await TryGetNewOrderCreated(cityExpected, orderClient); | |||||
// WHEN Order is created in Ordering.api | |||||
var newOrder = await TryGetNewOrderCreated(cityExpected, orderClient); | |||||
// AND Order is cancelled in Ordering.api | |||||
await orderClient.PutAsync(OrderingScenariosBase.Put.CancelOrder, new StringContent(BuildCancelOrder(newOrder.OrderNumber), UTF8Encoding.UTF8, "application/json")); | |||||
// AND Order is cancelled in Ordering.api | |||||
await orderClient.PutAsync(OrderingScenariosBase.Put.CancelOrder, new StringContent(BuildCancelOrder(newOrder.OrderNumber), UTF8Encoding.UTF8, "application/json")); | |||||
// AND the requested order is retrieved | |||||
var order = await TryGetOrder(newOrder.OrderNumber, orderClient); | |||||
// AND the requested order is retrieved | |||||
var order = await TryGetOrder(newOrder.OrderNumber, orderClient); | |||||
// THEN check status | |||||
Assert.Equal(orderStatusExpected, order.Status); | |||||
} | |||||
// THEN check status | |||||
Assert.Equal(orderStatusExpected, order.Status); | |||||
} | } | ||||
} | |||||
async Task<Order> TryGetOrder(string orderNumber, HttpClient orderClient) | |||||
async Task<Order> TryGetOrder(string orderNumber, HttpClient orderClient) | |||||
{ | |||||
var ordersGetResponse = await orderClient.GetStringAsync(OrderingScenariosBase.Get.Orders); | |||||
var orders = JsonSerializer.Deserialize<List<Order>>(ordersGetResponse, new JsonSerializerOptions | |||||
{ | { | ||||
PropertyNameCaseInsensitive = true | |||||
}); | |||||
return orders.Single(o => o.OrderNumber == orderNumber); | |||||
} | |||||
private async Task<Order> TryGetNewOrderCreated(string city, HttpClient orderClient) | |||||
{ | |||||
var counter = 0; | |||||
Order order = null; | |||||
while (counter < 20) | |||||
{ | |||||
//get the orders and verify that the new order has been created | |||||
var ordersGetResponse = await orderClient.GetStringAsync(OrderingScenariosBase.Get.Orders); | var ordersGetResponse = await orderClient.GetStringAsync(OrderingScenariosBase.Get.Orders); | ||||
var orders = JsonSerializer.Deserialize<List<Order>>(ordersGetResponse, new JsonSerializerOptions | var orders = JsonSerializer.Deserialize<List<Order>>(ordersGetResponse, new JsonSerializerOptions | ||||
{ | { | ||||
PropertyNameCaseInsensitive = true | PropertyNameCaseInsensitive = true | ||||
}); | }); | ||||
return orders.Single(o => o.OrderNumber == orderNumber); | |||||
} | |||||
private async Task<Order> TryGetNewOrderCreated(string city, HttpClient orderClient) | |||||
{ | |||||
var counter = 0; | |||||
Order order = null; | |||||
if (orders == null || orders.Count == 0) | |||||
{ | |||||
counter++; | |||||
await Task.Delay(100); | |||||
continue; | |||||
} | |||||
while (counter < 20) | |||||
var lastOrder = orders.OrderByDescending(o => o.Date).First(); | |||||
int.TryParse(lastOrder.OrderNumber, out int id); | |||||
var orderDetails = await orderClient.GetStringAsync(OrderingScenariosBase.Get.OrderBy(id)); | |||||
order = JsonSerializer.Deserialize<Order>(orderDetails, new JsonSerializerOptions | |||||
{ | { | ||||
//get the orders and verify that the new order has been created | |||||
var ordersGetResponse = await orderClient.GetStringAsync(OrderingScenariosBase.Get.Orders); | |||||
var orders = JsonSerializer.Deserialize<List<Order>>(ordersGetResponse, new JsonSerializerOptions | |||||
{ | |||||
PropertyNameCaseInsensitive = true | |||||
}); | |||||
if (orders == null || orders.Count == 0) | |||||
{ | |||||
counter++; | |||||
await Task.Delay(100); | |||||
continue; | |||||
} | |||||
var lastOrder = orders.OrderByDescending(o => o.Date).First(); | |||||
int.TryParse(lastOrder.OrderNumber, out int id); | |||||
var orderDetails = await orderClient.GetStringAsync(OrderingScenariosBase.Get.OrderBy(id)); | |||||
order = JsonSerializer.Deserialize<Order>(orderDetails, new JsonSerializerOptions | |||||
{ | |||||
PropertyNameCaseInsensitive = true | |||||
}); | |||||
PropertyNameCaseInsensitive = true | |||||
}); | |||||
order.City = city; | |||||
order.City = city; | |||||
if (IsOrderCreated(order, city)) | |||||
{ | |||||
break; | |||||
} | |||||
if (IsOrderCreated(order, city)) | |||||
{ | |||||
break; | |||||
} | } | ||||
return order; | |||||
} | } | ||||
private bool IsOrderCreated(Order order, string city) | |||||
{ | |||||
return order.City == city; | |||||
} | |||||
return order; | |||||
} | |||||
string BuildBasket() | |||||
private bool IsOrderCreated(Order order, string city) | |||||
{ | |||||
return order.City == city; | |||||
} | |||||
string BuildBasket() | |||||
{ | |||||
var order = new CustomerBasket("9e3163b9-1ae6-4652-9dc6-7898ab7b7a00"); | |||||
order.Items = new List<Microsoft.eShopOnContainers.Services.Basket.API.Model.BasketItem>() | |||||
{ | { | ||||
var order = new CustomerBasket("9e3163b9-1ae6-4652-9dc6-7898ab7b7a00"); | |||||
order.Items = new List<Microsoft.eShopOnContainers.Services.Basket.API.Model.BasketItem>() | |||||
new Microsoft.eShopOnContainers.Services.Basket.API.Model.BasketItem() | |||||
{ | { | ||||
new Microsoft.eShopOnContainers.Services.Basket.API.Model.BasketItem() | |||||
{ | |||||
Id = "1", | |||||
ProductName = "ProductName", | |||||
ProductId = 1, | |||||
UnitPrice = 10, | |||||
Quantity = 1 | |||||
} | |||||
}; | |||||
return JsonSerializer.Serialize(order); | |||||
} | |||||
Id = "1", | |||||
ProductName = "ProductName", | |||||
ProductId = 1, | |||||
UnitPrice = 10, | |||||
Quantity = 1 | |||||
} | |||||
}; | |||||
return JsonSerializer.Serialize(order); | |||||
} | |||||
string BuildCancelOrder(string orderId) | |||||
string BuildCancelOrder(string orderId) | |||||
{ | |||||
var order = new OrderDTO() | |||||
{ | { | ||||
var order = new OrderDTO() | |||||
{ | |||||
OrderNumber = orderId | |||||
}; | |||||
return JsonSerializer.Serialize(order); | |||||
} | |||||
OrderNumber = orderId | |||||
}; | |||||
return JsonSerializer.Serialize(order); | |||||
} | |||||
string BuildCheckout(string cityExpected) | |||||
string BuildCheckout(string cityExpected) | |||||
{ | |||||
var checkoutBasket = new BasketDTO() | |||||
{ | { | ||||
var checkoutBasket = new BasketDTO() | |||||
{ | |||||
City = cityExpected, | |||||
Street = "street", | |||||
State = "state", | |||||
Country = "coutry", | |||||
ZipCode = "zipcode", | |||||
CardNumber = "1111111111111", | |||||
CardHolderName = "CardHolderName", | |||||
CardExpiration = DateTime.Now.AddYears(1), | |||||
CardSecurityNumber = "123", | |||||
CardTypeId = 1, | |||||
Buyer = "Buyer", | |||||
RequestId = Guid.NewGuid() | |||||
}; | |||||
return JsonSerializer.Serialize(checkoutBasket); | |||||
} | |||||
City = cityExpected, | |||||
Street = "street", | |||||
State = "state", | |||||
Country = "coutry", | |||||
ZipCode = "zipcode", | |||||
CardNumber = "1111111111111", | |||||
CardHolderName = "CardHolderName", | |||||
CardExpiration = DateTime.Now.AddYears(1), | |||||
CardSecurityNumber = "123", | |||||
CardTypeId = 1, | |||||
Buyer = "Buyer", | |||||
RequestId = Guid.NewGuid() | |||||
}; | |||||
return JsonSerializer.Serialize(checkoutBasket); | |||||
} | } | ||||
} | } |
@ -1,77 +1,63 @@ | |||||
using Microsoft.AspNetCore.Hosting; | |||||
using Microsoft.AspNetCore.TestHost; | |||||
using Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF; | |||||
using Microsoft.eShopOnContainers.Services.Ordering.API; | |||||
using Microsoft.eShopOnContainers.Services.Ordering.API.Infrastructure; | |||||
using Microsoft.eShopOnContainers.Services.Ordering.Infrastructure; | |||||
using Microsoft.Extensions.Configuration; | |||||
using Microsoft.Extensions.DependencyInjection; | |||||
using Microsoft.Extensions.Logging; | |||||
using Microsoft.Extensions.Options; | |||||
using System.IO; | |||||
using System.Reflection; | |||||
namespace FunctionalTests.Services.Ordering; | |||||
namespace FunctionalTests.Services.Ordering | |||||
public class OrderingScenariosBase | |||||
{ | { | ||||
public class OrderingScenariosBase | |||||
public TestServer CreateServer() | |||||
{ | { | ||||
public TestServer CreateServer() | |||||
{ | |||||
var path = Assembly.GetAssembly(typeof(OrderingScenariosBase)) | |||||
.Location; | |||||
var hostBuilder = new WebHostBuilder() | |||||
.UseContentRoot(Path.GetDirectoryName(path)) | |||||
.ConfigureAppConfiguration(cb => | |||||
{ | |||||
cb.AddJsonFile("Services/Ordering/appsettings.json", optional: false) | |||||
.AddEnvironmentVariables(); | |||||
}).UseStartup<OrderingTestsStartup>(); | |||||
var path = Assembly.GetAssembly(typeof(OrderingScenariosBase)) | |||||
.Location; | |||||
var testServer = new TestServer(hostBuilder); | |||||
var hostBuilder = new WebHostBuilder() | |||||
.UseContentRoot(Path.GetDirectoryName(path)) | |||||
.ConfigureAppConfiguration(cb => | |||||
{ | |||||
cb.AddJsonFile("Services/Ordering/appsettings.json", optional: false) | |||||
.AddEnvironmentVariables(); | |||||
}).UseStartup<OrderingTestsStartup>(); | |||||
testServer.Host | |||||
.MigrateDbContext<OrderingContext>((context, services) => | |||||
{ | |||||
var env = services.GetService<IWebHostEnvironment>(); | |||||
var settings = services.GetService<IOptions<OrderingSettings>>(); | |||||
var logger = services.GetService<ILogger<OrderingContextSeed>>(); | |||||
var testServer = new TestServer(hostBuilder); | |||||
new OrderingContextSeed() | |||||
.SeedAsync(context, env, settings, logger) | |||||
.Wait(); | |||||
}) | |||||
.MigrateDbContext<IntegrationEventLogContext>((_, __) => { }); | |||||
testServer.Host | |||||
.MigrateDbContext<OrderingContext>((context, services) => | |||||
{ | |||||
var env = services.GetService<IWebHostEnvironment>(); | |||||
var settings = services.GetService<IOptions<OrderingSettings>>(); | |||||
var logger = services.GetService<ILogger<OrderingContextSeed>>(); | |||||
return testServer; | |||||
} | |||||
new OrderingContextSeed() | |||||
.SeedAsync(context, env, settings, logger) | |||||
.Wait(); | |||||
}) | |||||
.MigrateDbContext<IntegrationEventLogContext>((_, __) => { }); | |||||
public static class Get | |||||
{ | |||||
public static string Orders = "api/v1/orders"; | |||||
return testServer; | |||||
} | |||||
public static string OrderBy(int id) | |||||
{ | |||||
return $"api/v1/orders/{id}"; | |||||
} | |||||
} | |||||
public static class Get | |||||
{ | |||||
public static string Orders = "api/v1/orders"; | |||||
public static class Post | |||||
public static string OrderBy(int id) | |||||
{ | { | ||||
public static string AddNewOrder = "api/v1/orders/new"; | |||||
return $"api/v1/orders/{id}"; | |||||
} | } | ||||
} | |||||
public static class Put | |||||
{ | |||||
public static string CancelOrder = "api/v1/orders/cancel"; | |||||
} | |||||
public static class Post | |||||
{ | |||||
public static string AddNewOrder = "api/v1/orders/new"; | |||||
} | |||||
public static class Delete | |||||
public static class Put | |||||
{ | |||||
public static string CancelOrder = "api/v1/orders/cancel"; | |||||
} | |||||
public static class Delete | |||||
{ | |||||
public static string OrderBy(int id) | |||||
{ | { | ||||
public static string OrderBy(int id) | |||||
{ | |||||
return $"api/v1/orders/{id}"; | |||||
} | |||||
return $"api/v1/orders/{id}"; | |||||
} | } | ||||
} | } | ||||
} | } |
@ -1,27 +1,22 @@ | |||||
using FunctionalTests.Middleware; | |||||
using Microsoft.AspNetCore.Builder; | |||||
namespace FunctionalTests.Services.Ordering; | |||||
using Microsoft.eShopOnContainers.Services.Ordering.API; | using Microsoft.eShopOnContainers.Services.Ordering.API; | ||||
using Microsoft.Extensions.Configuration; | |||||
namespace FunctionalTests.Services.Ordering | |||||
public class OrderingTestsStartup : Startup | |||||
{ | { | ||||
public class OrderingTestsStartup : Startup | |||||
public OrderingTestsStartup(IConfiguration env) : base(env) | |||||
{ | { | ||||
public OrderingTestsStartup(IConfiguration env) : base(env) | |||||
} | |||||
protected override void ConfigureAuth(IApplicationBuilder app) | |||||
{ | |||||
if (Configuration["isTest"] == bool.TrueString.ToLowerInvariant()) | |||||
{ | { | ||||
app.UseMiddleware<AutoAuthorizeMiddleware>(); | |||||
app.UseAuthorization(); | |||||
} | } | ||||
protected override void ConfigureAuth(IApplicationBuilder app) | |||||
else | |||||
{ | { | ||||
if (Configuration["isTest"] == bool.TrueString.ToLowerInvariant()) | |||||
{ | |||||
app.UseMiddleware<AutoAuthorizeMiddleware>(); | |||||
app.UseAuthorization(); | |||||
} | |||||
else | |||||
{ | |||||
base.ConfigureAuth(app); | |||||
} | |||||
base.ConfigureAuth(app); | |||||
} | } | ||||
} | } | ||||
} | } |