* Included globalusing in Application.FunctionalTests project * Included file scoped namespacepull/1785/head
@ -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; | |||
} | |||
} |
@ -0,0 +1,35 @@ | |||
global using Microsoft.AspNetCore.TestHost; | |||
global using System; | |||
global using System.Net.Http; | |||
global using Microsoft.AspNetCore.Http; | |||
global using System.Security.Claims; | |||
global using System.Threading.Tasks; | |||
global using Microsoft.AspNetCore.Hosting; | |||
global using Microsoft.Extensions.Configuration; | |||
global using System.IO; | |||
global using System.Reflection; | |||
global using FunctionalTests.Middleware; | |||
global using Microsoft.AspNetCore.Builder; | |||
global using Microsoft.eShopOnContainers.Services.Basket.API; | |||
global using Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF; | |||
global using Microsoft.eShopOnContainers.Services.Catalog.API; | |||
global using Microsoft.eShopOnContainers.Services.Catalog.API.Infrastructure; | |||
global using Microsoft.Extensions.DependencyInjection; | |||
global using Microsoft.Extensions.Logging; | |||
global using Microsoft.Extensions.Options; | |||
global using FunctionalTests.Extensions; | |||
global using FunctionalTests.Services.Basket; | |||
global using Microsoft.eShopOnContainers.Services.Basket.API.Model; | |||
global using Microsoft.eShopOnContainers.WebMVC.ViewModels; | |||
global using System.Text.Json; | |||
global using System.Collections.Generic; | |||
global using System.Linq; | |||
global using System.Text; | |||
global using WebMVC.Services.ModelDTOs; | |||
global using Xunit; | |||
global using Microsoft.eShopOnContainers.Services.Ordering.API; | |||
global using Microsoft.eShopOnContainers.Services.Ordering.API.Infrastructure; | |||
global using Microsoft.eShopOnContainers.Services.Ordering.Infrastructure; | |||
global using FunctionalTests.Services.Catalog; | |||
global using Microsoft.eShopOnContainers.Services.Catalog.API.Model; | |||
global using Microsoft.eShopOnContainers.Services.Catalog.API.ViewModel; |
@ -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.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.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.Catalog.API.Model; | |||
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 | |||
}); | |||
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 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; | |||
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.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); | |||
} | |||
} | |||
} |