diff --git a/renovate.json b/renovate.json new file mode 100644 index 0000000000..5d78e56c20 --- /dev/null +++ b/renovate.json @@ -0,0 +1,114 @@ +{ + "$schema": "https://docs.renovatebot.com/renovate-schema.json", + "extends": [ + "config:base" + ], + "schedule": "every weekend", + "packageRules": [ + { + "matchPaths": ["*"], + "ignorePaths": ["src/"], + "groupName": "config-no-service" + }, + { + "matchPaths": ["src/accountingservice"], + "groupName": "accountingservice", + "assigneesFromCodeOwners": true + }, + { + "matchPaths": ["src/adservice"], + "groupName": "adservice", + "assigneesFromCodeOwners": true + }, + { + "matchPaths": ["src/cartservice"], + "groupName": "cartservice", + "assigneesFromCodeOwners": true + }, + { + "matchPaths": ["src/checkoutservice"], + "groupName": "checkoutservice", + "assigneesFromCodeOwners": true + }, + { + "matchPaths": ["src/currencyservice"], + "groupName": "currencyservice", + "assigneesFromCodeOwners": true + }, + { + "matchPaths": ["src/emailservice"], + "groupName": "emailservice", + "assigneesFromCodeOwners": true + }, + { + "matchPaths": ["src/featureflagservice"], + "groupName": "featureflagservice", + "assigneesFromCodeOwners": true + }, + { + "matchPaths": ["src/frauddetectionservice"], + "groupName": "frauddetectionservice", + "assigneesFromCodeOwners": true + }, + { + "matchPaths": ["src/frontend"], + "groupName": "frontend", + "assigneesFromCodeOwners": true + }, + { + "matchPaths": ["src/frontendproxy"], + "groupName": "frontendproxy", + "assigneesFromCodeOwners": true + }, + { + "matchPaths": ["src/grafana"], + "groupName": "grafana", + "assigneesFromCodeOwners": true + }, + { + "matchPaths": ["src/kakfa"], + "groupName": "kakfa", + "assigneesFromCodeOwners": true + }, + { + "matchPaths": ["src/loadgenerator"], + "groupName": "loadgenerator", + "assigneesFromCodeOwners": true + }, + { + "matchPaths": ["src/otelcollector"], + "groupName": "otelcollector", + "assigneesFromCodeOwners": true + }, + { + "matchPaths": ["src/paymentservice"], + "groupName": "paymentservice", + "assigneesFromCodeOwners": true + }, + { + "matchPaths": ["src/productcatalogservice"], + "groupName": "productcatalogservice", + "assigneesFromCodeOwners": true + }, + { + "matchPaths": ["src/prometheus"], + "groupName": "prometheus", + "assigneesFromCodeOwners": true + }, + { + "matchPaths": ["src/quoteservice"], + "groupName": "quoteservice", + "assigneesFromCodeOwners": true + }, + { + "matchPaths": ["src/recommendationservice"], + "groupName": "recommendationservice", + "assigneesFromCodeOwners": true + }, + { + "matchPaths": ["src/shippingservice"], + "groupName": "shippingservice", + "assigneesFromCodeOwners": true + } + ] +} \ No newline at end of file diff --git a/src/cartservice/src/Program.cs b/src/cartservice/src/Program.cs index ea42d613f1..24ea5bf7f0 100644 --- a/src/cartservice/src/Program.cs +++ b/src/cartservice/src/Program.cs @@ -18,13 +18,12 @@ var builder = WebApplication.CreateBuilder(args); string redisAddress = builder.Configuration["REDIS_ADDR"]; -RedisCartStore cartStore = null; if (string.IsNullOrEmpty(redisAddress)) { Console.WriteLine("REDIS_ADDR environment variable is required."); Environment.Exit(1); } -cartStore = new RedisCartStore(redisAddress); +var cartStore = new RedisCartStore(redisAddress); // Initialize the redis store await cartStore.InitializeAsync(); @@ -41,7 +40,7 @@ builder.Services.AddOpenTelemetry() .ConfigureResource(appResourceBuilder) - .WithTracing(builder => builder + .WithTracing(tracerBuilder => tracerBuilder .AddRedisInstrumentation( cartStore.GetConnection(), options => options.SetVerboseDatabaseStatements = true) @@ -49,7 +48,7 @@ .AddGrpcClientInstrumentation() .AddHttpClientInstrumentation() .AddOtlpExporter()) - .WithMetrics(builder => builder + .WithMetrics(meterBuilder => meterBuilder .AddRuntimeInstrumentation() .AddAspNetCoreInstrumentation() .AddOtlpExporter()); diff --git a/src/cartservice/src/cartstore/ICartStore.cs b/src/cartservice/src/cartstore/ICartStore.cs index 8eda4330b9..21d0e65fc4 100644 --- a/src/cartservice/src/cartstore/ICartStore.cs +++ b/src/cartservice/src/cartstore/ICartStore.cs @@ -2,17 +2,16 @@ // SPDX-License-Identifier: Apache-2.0 using System.Threading.Tasks; -namespace cartservice.cartstore +namespace cartservice.cartstore; + +public interface ICartStore { - public interface ICartStore - { - Task InitializeAsync(); + Task InitializeAsync(); - Task AddItemAsync(string userId, string productId, int quantity); - Task EmptyCartAsync(string userId); + Task AddItemAsync(string userId, string productId, int quantity); + Task EmptyCartAsync(string userId); - Task GetCartAsync(string userId); + Task GetCartAsync(string userId); - bool Ping(); - } + bool Ping(); } diff --git a/src/cartservice/src/cartstore/LocalCartStore.cs b/src/cartservice/src/cartstore/LocalCartStore.cs index 5824839dcc..52b813f832 100644 --- a/src/cartservice/src/cartstore/LocalCartStore.cs +++ b/src/cartservice/src/cartstore/LocalCartStore.cs @@ -6,31 +6,31 @@ using System.Linq; using System.Threading.Tasks; -namespace cartservice.cartstore +namespace cartservice.cartstore; + +internal class LocalCartStore : ICartStore { - internal class LocalCartStore : ICartStore - { - // Maps between user and their cart - private ConcurrentDictionary userCartItems = new ConcurrentDictionary(); - private readonly Oteldemo.Cart emptyCart = new Oteldemo.Cart(); + // Maps between user and their cart + private readonly ConcurrentDictionary _userCartItems = new(); + private readonly Oteldemo.Cart _emptyCart = new(); - public Task InitializeAsync() - { - Console.WriteLine("Local Cart Store was initialized"); + public Task InitializeAsync() + { + Console.WriteLine("Local Cart Store was initialized"); - return Task.CompletedTask; - } + return Task.CompletedTask; + } - public Task AddItemAsync(string userId, string productId, int quantity) + public Task AddItemAsync(string userId, string productId, int quantity) + { + Console.WriteLine($"AddItemAsync called with userId={userId}, productId={productId}, quantity={quantity}"); + var newCart = new Oteldemo.Cart { - Console.WriteLine($"AddItemAsync called with userId={userId}, productId={productId}, quantity={quantity}"); - var newCart = new Oteldemo.Cart - { - UserId = userId, - Items = { new Oteldemo.CartItem { ProductId = productId, Quantity = quantity } } - }; - userCartItems.AddOrUpdate(userId, newCart, - (k, exVal) => + UserId = userId, + Items = { new Oteldemo.CartItem { ProductId = productId, Quantity = quantity } } + }; + _userCartItems.AddOrUpdate(userId, newCart, + (_, exVal) => { // If the item exists, we update its quantity var existingItem = exVal.Items.SingleOrDefault(item => item.ProductId == productId); @@ -46,35 +46,32 @@ public Task AddItemAsync(string userId, string productId, int quantity) return exVal; }); - return Task.CompletedTask; - } + return Task.CompletedTask; + } - public Task EmptyCartAsync(string userId) - { - var eventTags = new ActivityTagsCollection(); - eventTags.Add("userId", userId); - Activity.Current?.AddEvent(new ActivityEvent("EmptyCartAsync called.", default, eventTags)); + public Task EmptyCartAsync(string userId) + { + var eventTags = new ActivityTagsCollection {{"userId", userId}}; + Activity.Current?.AddEvent(new ActivityEvent("EmptyCartAsync called.", default, eventTags)); - userCartItems[userId] = new Oteldemo.Cart(); - return Task.CompletedTask; - } + _userCartItems[userId] = new Oteldemo.Cart(); + return Task.CompletedTask; + } - public Task GetCartAsync(string userId) + public Task GetCartAsync(string userId) + { + Console.WriteLine($"GetCartAsync called with userId={userId}"); + if (!_userCartItems.TryGetValue(userId, out var cart)) { - Console.WriteLine($"GetCartAsync called with userId={userId}"); - Oteldemo.Cart cart = null; - if (!userCartItems.TryGetValue(userId, out cart)) - { - Console.WriteLine($"No carts for user {userId}"); - return Task.FromResult(emptyCart); - } - - return Task.FromResult(cart); + Console.WriteLine($"No carts for user {userId}"); + return Task.FromResult(_emptyCart); } - public bool Ping() - { - return true; - } + return Task.FromResult(cart); + } + + public bool Ping() + { + return true; } } diff --git a/src/cartservice/src/cartstore/RedisCartStore.cs b/src/cartservice/src/cartstore/RedisCartStore.cs index 0bc889ea23..bccfce7b5f 100644 --- a/src/cartservice/src/cartstore/RedisCartStore.cs +++ b/src/cartservice/src/cartstore/RedisCartStore.cs @@ -7,201 +7,202 @@ using StackExchange.Redis; using Google.Protobuf; -namespace cartservice.cartstore +namespace cartservice.cartstore; + +public class RedisCartStore : ICartStore { - public class RedisCartStore : ICartStore - { - private const string CART_FIELD_NAME = "cart"; - private const int REDIS_RETRY_NUM = 30; + private const string CartFieldName = "cart"; + private const int RedisRetryNumber = 30; - private volatile ConnectionMultiplexer redis; - private volatile bool isRedisConnectionOpened = false; + private volatile ConnectionMultiplexer _redis; + private volatile bool _isRedisConnectionOpened; - private readonly object locker = new object(); - private readonly byte[] emptyCartBytes; - private readonly string connectionString; + private readonly object _locker = new(); + private readonly byte[] _emptyCartBytes; + private readonly string _connectionString; - private readonly ConfigurationOptions redisConnectionOptions; + private readonly ConfigurationOptions _redisConnectionOptions; - public RedisCartStore(string redisAddress) - { - // Serialize empty cart into byte array. - var cart = new Oteldemo.Cart(); - emptyCartBytes = cart.ToByteArray(); - connectionString = $"{redisAddress},ssl=false,allowAdmin=true,abortConnect=false"; + public RedisCartStore(string redisAddress) + { + // Serialize empty cart into byte array. + var cart = new Oteldemo.Cart(); + _emptyCartBytes = cart.ToByteArray(); + _connectionString = $"{redisAddress},ssl=false,allowAdmin=true,abortConnect=false"; - redisConnectionOptions = ConfigurationOptions.Parse(connectionString); + _redisConnectionOptions = ConfigurationOptions.Parse(_connectionString); - // Try to reconnect multiple times if the first retry fails. - redisConnectionOptions.ConnectRetry = REDIS_RETRY_NUM; - redisConnectionOptions.ReconnectRetryPolicy = new ExponentialRetry(1000); + // Try to reconnect multiple times if the first retry fails. + _redisConnectionOptions.ConnectRetry = RedisRetryNumber; + _redisConnectionOptions.ReconnectRetryPolicy = new ExponentialRetry(1000); - redisConnectionOptions.KeepAlive = 180; - } + _redisConnectionOptions.KeepAlive = 180; + } - public ConnectionMultiplexer GetConnection() - { - EnsureRedisConnected(); - return redis; - } + public ConnectionMultiplexer GetConnection() + { + EnsureRedisConnected(); + return _redis; + } - public Task InitializeAsync() + public Task InitializeAsync() + { + EnsureRedisConnected(); + return Task.CompletedTask; + } + + private void EnsureRedisConnected() + { + if (_isRedisConnectionOpened) { - EnsureRedisConnected(); - return Task.CompletedTask; + return; } - private void EnsureRedisConnected() + // Connection is closed or failed - open a new one but only at the first thread + lock (_locker) { - if (isRedisConnectionOpened) + if (_isRedisConnectionOpened) { return; } - // Connection is closed or failed - open a new one but only at the first thread - lock (locker) - { - if (isRedisConnectionOpened) - { - return; - } - - Console.WriteLine("Connecting to Redis: " + connectionString); - redis = ConnectionMultiplexer.Connect(redisConnectionOptions); + Console.WriteLine("Connecting to Redis: " + _connectionString); + _redis = ConnectionMultiplexer.Connect(_redisConnectionOptions); - if (redis == null || !redis.IsConnected) - { - Console.WriteLine("Wasn't able to connect to redis"); + if (_redis == null || !_redis.IsConnected) + { + Console.WriteLine("Wasn't able to connect to redis"); - // We weren't able to connect to Redis despite some retries with exponential backoff. - throw new ApplicationException("Wasn't able to connect to redis"); - } + // We weren't able to connect to Redis despite some retries with exponential backoff. + throw new ApplicationException("Wasn't able to connect to redis"); + } - Console.WriteLine("Successfully connected to Redis"); - var cache = redis.GetDatabase(); + Console.WriteLine("Successfully connected to Redis"); + var cache = _redis.GetDatabase(); - Console.WriteLine("Performing small test"); - cache.StringSet("cart", "OK" ); - object res = cache.StringGet("cart"); - Console.WriteLine($"Small test result: {res}"); + Console.WriteLine("Performing small test"); + cache.StringSet("cart", "OK" ); + object res = cache.StringGet("cart"); + Console.WriteLine($"Small test result: {res}"); - redis.InternalError += (o, e) => { Console.WriteLine(e.Exception); }; - redis.ConnectionRestored += (o, e) => - { - isRedisConnectionOpened = true; - Console.WriteLine("Connection to redis was restored successfully."); - }; - redis.ConnectionFailed += (o, e) => - { - Console.WriteLine("Connection failed. Disposing the object"); - isRedisConnectionOpened = false; - }; + _redis.InternalError += (_, e) => { Console.WriteLine(e.Exception); }; + _redis.ConnectionRestored += (_, _) => + { + _isRedisConnectionOpened = true; + Console.WriteLine("Connection to redis was restored successfully."); + }; + _redis.ConnectionFailed += (_, _) => + { + Console.WriteLine("Connection failed. Disposing the object"); + _isRedisConnectionOpened = false; + }; - isRedisConnectionOpened = true; - } + _isRedisConnectionOpened = true; } + } - public async Task AddItemAsync(string userId, string productId, int quantity) - { - Console.WriteLine($"AddItemAsync called with userId={userId}, productId={productId}, quantity={quantity}"); + public async Task AddItemAsync(string userId, string productId, int quantity) + { + Console.WriteLine($"AddItemAsync called with userId={userId}, productId={productId}, quantity={quantity}"); - try - { - EnsureRedisConnected(); + try + { + EnsureRedisConnected(); - var db = redis.GetDatabase(); + var db = _redis.GetDatabase(); - // Access the cart from the cache - var value = await db.HashGetAsync(userId, CART_FIELD_NAME); + // Access the cart from the cache + var value = await db.HashGetAsync(userId, CartFieldName); - Oteldemo.Cart cart; - if (value.IsNull) + Oteldemo.Cart cart; + if (value.IsNull) + { + cart = new Oteldemo.Cart + { + UserId = userId + }; + cart.Items.Add(new Oteldemo.CartItem { ProductId = productId, Quantity = quantity }); + } + else + { + cart = Oteldemo.Cart.Parser.ParseFrom(value); + var existingItem = cart.Items.SingleOrDefault(i => i.ProductId == productId); + if (existingItem == null) { - cart = new Oteldemo.Cart(); - cart.UserId = userId; cart.Items.Add(new Oteldemo.CartItem { ProductId = productId, Quantity = quantity }); } else { - cart = Oteldemo.Cart.Parser.ParseFrom(value); - var existingItem = cart.Items.SingleOrDefault(i => i.ProductId == productId); - if (existingItem == null) - { - cart.Items.Add(new Oteldemo.CartItem { ProductId = productId, Quantity = quantity }); - } - else - { - existingItem.Quantity += quantity; - } + existingItem.Quantity += quantity; } - - await db.HashSetAsync(userId, new[]{ new HashEntry(CART_FIELD_NAME, cart.ToByteArray()) }); - await db.KeyExpireAsync(userId, TimeSpan.FromMinutes(60)); - } - catch (Exception ex) - { - throw new RpcException(new Status(StatusCode.FailedPrecondition, $"Can't access cart storage. {ex}")); } - } - public async Task EmptyCartAsync(string userId) + await db.HashSetAsync(userId, new[]{ new HashEntry(CartFieldName, cart.ToByteArray()) }); + await db.KeyExpireAsync(userId, TimeSpan.FromMinutes(60)); + } + catch (Exception ex) { - Console.WriteLine($"EmptyCartAsync called with userId={userId}"); + throw new RpcException(new Status(StatusCode.FailedPrecondition, $"Can't access cart storage. {ex}")); + } + } - try - { - EnsureRedisConnected(); - var db = redis.GetDatabase(); + public async Task EmptyCartAsync(string userId) + { + Console.WriteLine($"EmptyCartAsync called with userId={userId}"); - // Update the cache with empty cart for given user - await db.HashSetAsync(userId, new[] { new HashEntry(CART_FIELD_NAME, emptyCartBytes) }); - await db.KeyExpireAsync(userId, TimeSpan.FromMinutes(60)); - } - catch (Exception ex) - { - throw new RpcException(new Status(StatusCode.FailedPrecondition, $"Can't access cart storage. {ex}")); - } - } + try + { + EnsureRedisConnected(); + var db = _redis.GetDatabase(); - public async Task GetCartAsync(string userId) + // Update the cache with empty cart for given user + await db.HashSetAsync(userId, new[] { new HashEntry(CartFieldName, _emptyCartBytes) }); + await db.KeyExpireAsync(userId, TimeSpan.FromMinutes(60)); + } + catch (Exception ex) { - Console.WriteLine($"GetCartAsync called with userId={userId}"); + throw new RpcException(new Status(StatusCode.FailedPrecondition, $"Can't access cart storage. {ex}")); + } + } - try - { - EnsureRedisConnected(); + public async Task GetCartAsync(string userId) + { + Console.WriteLine($"GetCartAsync called with userId={userId}"); - var db = redis.GetDatabase(); + try + { + EnsureRedisConnected(); - // Access the cart from the cache - var value = await db.HashGetAsync(userId, CART_FIELD_NAME); + var db = _redis.GetDatabase(); - if (!value.IsNull) - { - return Oteldemo.Cart.Parser.ParseFrom(value); - } + // Access the cart from the cache + var value = await db.HashGetAsync(userId, CartFieldName); - // We decided to return empty cart in cases when user wasn't in the cache before - return new Oteldemo.Cart(); - } - catch (Exception ex) + if (!value.IsNull) { - throw new RpcException(new Status(StatusCode.FailedPrecondition, $"Can't access cart storage. {ex}")); + return Oteldemo.Cart.Parser.ParseFrom(value); } + + // We decided to return empty cart in cases when user wasn't in the cache before + return new Oteldemo.Cart(); } + catch (Exception ex) + { + throw new RpcException(new Status(StatusCode.FailedPrecondition, $"Can't access cart storage. {ex}")); + } + } - public bool Ping() + public bool Ping() + { + try { - try - { - var cache = redis.GetDatabase(); - var res = cache.Ping(); - return res != TimeSpan.Zero; - } - catch (Exception) - { - return false; - } + var cache = _redis.GetDatabase(); + var res = cache.Ping(); + return res != TimeSpan.Zero; + } + catch (Exception) + { + return false; } } } diff --git a/src/cartservice/src/featureflags/FeatureFlagHelper.cs b/src/cartservice/src/featureflags/FeatureFlagHelper.cs index 6fe6fe147a..af9cf3d291 100644 --- a/src/cartservice/src/featureflags/FeatureFlagHelper.cs +++ b/src/cartservice/src/featureflags/FeatureFlagHelper.cs @@ -8,7 +8,7 @@ namespace cartservice.featureflags; public class FeatureFlagHelper { - private readonly static Random Random = new Random(); + private static readonly Random Random = new(); private readonly FeatureFlagService.FeatureFlagServiceClient _featureFlagServiceClient; public FeatureFlagHelper() diff --git a/src/cartservice/src/services/CartService.cs b/src/cartservice/src/services/CartService.cs index 26ee0390b3..244042ddf3 100644 --- a/src/cartservice/src/services/CartService.cs +++ b/src/cartservice/src/services/CartService.cs @@ -8,74 +8,73 @@ using cartservice.featureflags; using Oteldemo; -namespace cartservice.services +namespace cartservice.services; + +public class CartService : Oteldemo.CartService.CartServiceBase { - public class CartService : Oteldemo.CartService.CartServiceBase + private static readonly Empty Empty = new(); + private static readonly ICartStore BadCartStore = new RedisCartStore("badhost:1234"); + private readonly ICartStore _cartStore; + private readonly FeatureFlagHelper _featureFlagHelper; + + public CartService(ICartStore cartStore, FeatureFlagHelper featureFlagService) { - private readonly static Empty Empty = new Empty(); - private readonly static ICartStore BadCartStore = new RedisCartStore("badhost:1234"); - private readonly ICartStore _cartStore; - private readonly FeatureFlagHelper _featureFlagHelper; + _cartStore = cartStore; + _featureFlagHelper = featureFlagService; + } - public CartService(ICartStore cartStore, FeatureFlagHelper featureFlagService) - { - _cartStore = cartStore; - _featureFlagHelper = featureFlagService; - } + public override async Task AddItem(AddItemRequest request, ServerCallContext context) + { + var activity = Activity.Current; + activity?.SetTag("app.user.id", request.UserId); + activity?.SetTag("app.product.id", request.Item.ProductId); + activity?.SetTag("app.product.quantity", request.Item.Quantity); - public async override Task AddItem(AddItemRequest request, ServerCallContext context) - { - var activity = Activity.Current; - activity?.SetTag("app.user.id", request.UserId); - activity?.SetTag("app.product.id", request.Item.ProductId); - activity?.SetTag("app.product.quantity", request.Item.Quantity); + await _cartStore.AddItemAsync(request.UserId, request.Item.ProductId, request.Item.Quantity); + return Empty; + } - await _cartStore.AddItemAsync(request.UserId, request.Item.ProductId, request.Item.Quantity); - return Empty; - } + public override async Task GetCart(GetCartRequest request, ServerCallContext context) + { + var activity = Activity.Current; + activity?.SetTag("app.user.id", request.UserId); + activity?.AddEvent(new("Fetch cart")); - public async override Task GetCart(GetCartRequest request, ServerCallContext context) + var cart = await _cartStore.GetCartAsync(request.UserId); + var totalCart = 0; + foreach (var item in cart.Items) { - var activity = Activity.Current; - activity?.SetTag("app.user.id", request.UserId); - activity?.AddEvent(new("Fetch cart")); + totalCart += item.Quantity; + } + activity?.SetTag("app.cart.items.count", totalCart); - var cart = await _cartStore.GetCartAsync(request.UserId); - var totalCart = 0; - foreach (var item in cart.Items) - { - totalCart += item.Quantity; - } - activity?.SetTag("app.cart.items.count", totalCart); + return cart; + } - return cart; - } + public override async Task EmptyCart(EmptyCartRequest request, ServerCallContext context) + { + var activity = Activity.Current; + activity?.SetTag("app.user.id", request.UserId); + activity?.AddEvent(new("Empty cart")); - public async override Task EmptyCart(EmptyCartRequest request, ServerCallContext context) + try { - var activity = Activity.Current; - activity?.SetTag("app.user.id", request.UserId); - activity?.AddEvent(new("Empty cart")); - - try + if (await _featureFlagHelper.GenerateCartError()) { - if (await _featureFlagHelper.GenerateCartError()) - { - await BadCartStore.EmptyCartAsync(request.UserId); - } - else - { - await _cartStore.EmptyCartAsync(request.UserId); - } + await BadCartStore.EmptyCartAsync(request.UserId); } - catch (RpcException ex) + else { - Activity.Current?.RecordException(ex); - Activity.Current?.SetStatus(ActivityStatusCode.Error, ex.Message); - throw; + await _cartStore.EmptyCartAsync(request.UserId); } - - return Empty; } + catch (RpcException ex) + { + Activity.Current?.RecordException(ex); + Activity.Current?.SetStatus(ActivityStatusCode.Error, ex.Message); + throw; + } + + return Empty; } } diff --git a/src/cartservice/tests/CartServiceTests.cs b/src/cartservice/tests/CartServiceTests.cs index b55970b18b..372b10cc41 100644 --- a/src/cartservice/tests/CartServiceTests.cs +++ b/src/cartservice/tests/CartServiceTests.cs @@ -4,145 +4,143 @@ using System.Threading.Tasks; using Grpc.Net.Client; using Oteldemo; -using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.TestHost; using Microsoft.Extensions.Hosting; using Xunit; using static Oteldemo.CartService; -namespace cartservice.tests +namespace cartservice.tests; + +public class CartServiceTests { - public class CartServiceTests - { - private readonly IHostBuilder _host; + private readonly IHostBuilder _host; - public CartServiceTests() - { - _host = new HostBuilder().ConfigureWebHost(webBuilder => - { - webBuilder - // .UseStartup() - .UseTestServer(); - }); - } - - [Fact(Skip = "See https://github.com/open-telemetry/opentelemetry-demo/pull/746#discussion_r1107931240")] - public async Task GetItem_NoAddItemBefore_EmptyCartReturned() + public CartServiceTests() + { + _host = new HostBuilder().ConfigureWebHost(webBuilder => { - // Setup test server and client - using var server = await _host.StartAsync(); - var httpClient = server.GetTestClient(); + webBuilder + // .UseStartup() + .UseTestServer(); + }); + } - string userId = Guid.NewGuid().ToString(); + [Fact(Skip = "See https://github.com/open-telemetry/opentelemetry-demo/pull/746#discussion_r1107931240")] + public async Task GetItem_NoAddItemBefore_EmptyCartReturned() + { + // Setup test server and client + using var server = await _host.StartAsync(); + var httpClient = server.GetTestClient(); - // Create a GRPC communication channel between the client and the server - var channel = GrpcChannel.ForAddress(httpClient.BaseAddress, new GrpcChannelOptions - { - HttpClient = httpClient - }); + string userId = Guid.NewGuid().ToString(); - var cartClient = new CartServiceClient(channel); + // Create a GRPC communication channel between the client and the server + var channel = GrpcChannel.ForAddress(httpClient.BaseAddress, new GrpcChannelOptions + { + HttpClient = httpClient + }); - var request = new GetCartRequest - { - UserId = userId, - }; + var cartClient = new CartServiceClient(channel); - var cart = await cartClient.GetCartAsync(request); - Assert.NotNull(cart); + var request = new GetCartRequest + { + UserId = userId, + }; - // All grpc objects implement IEquitable, so we can compare equality with by-value semantics - Assert.Equal(new Cart(), cart); - } + var cart = await cartClient.GetCartAsync(request); + Assert.NotNull(cart); - [Fact(Skip = "See https://github.com/open-telemetry/opentelemetry-demo/pull/746#discussion_r1107931240")] - public async Task AddItem_ItemExists_Updated() - { - // Setup test server and client - using var server = await _host.StartAsync(); - var httpClient = server.GetTestClient(); + // All grpc objects implement IEquitable, so we can compare equality with by-value semantics + Assert.Equal(new Cart(), cart); + } - string userId = Guid.NewGuid().ToString(); + [Fact(Skip = "See https://github.com/open-telemetry/opentelemetry-demo/pull/746#discussion_r1107931240")] + public async Task AddItem_ItemExists_Updated() + { + // Setup test server and client + using var server = await _host.StartAsync(); + var httpClient = server.GetTestClient(); - // Create a GRPC communication channel between the client and the server - var channel = GrpcChannel.ForAddress(httpClient.BaseAddress, new GrpcChannelOptions - { - HttpClient = httpClient - }); + string userId = Guid.NewGuid().ToString(); + + // Create a GRPC communication channel between the client and the server + var channel = GrpcChannel.ForAddress(httpClient.BaseAddress, new GrpcChannelOptions + { + HttpClient = httpClient + }); - var client = new CartServiceClient(channel); - var request = new AddItemRequest + var client = new CartServiceClient(channel); + var request = new AddItemRequest + { + UserId = userId, + Item = new CartItem { - UserId = userId, - Item = new CartItem - { - ProductId = "1", - Quantity = 1 - } - }; + ProductId = "1", + Quantity = 1 + } + }; - // First add - nothing should fail - await client.AddItemAsync(request); + // First add - nothing should fail + await client.AddItemAsync(request); - // Second add of existing product - quantity should be updated - await client.AddItemAsync(request); + // Second add of existing product - quantity should be updated + await client.AddItemAsync(request); - var getCartRequest = new GetCartRequest - { - UserId = userId - }; - var cart = await client.GetCartAsync(getCartRequest); - Assert.NotNull(cart); - Assert.Equal(userId, cart.UserId); - Assert.Single(cart.Items); - Assert.Equal(2, cart.Items[0].Quantity); - - // Cleanup - await client.EmptyCartAsync(new EmptyCartRequest { UserId = userId }); - } - - [Fact(Skip = "See https://github.com/open-telemetry/opentelemetry-demo/pull/746#discussion_r1107931240")] - public async Task AddItem_New_Inserted() + var getCartRequest = new GetCartRequest { - // Setup test server and client - using var server = await _host.StartAsync(); - var httpClient = server.GetTestClient(); + UserId = userId + }; + var cart = await client.GetCartAsync(getCartRequest); + Assert.NotNull(cart); + Assert.Equal(userId, cart.UserId); + Assert.Single(cart.Items); + Assert.Equal(2, cart.Items[0].Quantity); + + // Cleanup + await client.EmptyCartAsync(new EmptyCartRequest { UserId = userId }); + } - string userId = Guid.NewGuid().ToString(); + [Fact(Skip = "See https://github.com/open-telemetry/opentelemetry-demo/pull/746#discussion_r1107931240")] + public async Task AddItem_New_Inserted() + { + // Setup test server and client + using var server = await _host.StartAsync(); + var httpClient = server.GetTestClient(); - // Create a GRPC communication channel between the client and the server - var channel = GrpcChannel.ForAddress(httpClient.BaseAddress, new GrpcChannelOptions - { - HttpClient = httpClient - }); + string userId = Guid.NewGuid().ToString(); + + // Create a GRPC communication channel between the client and the server + var channel = GrpcChannel.ForAddress(httpClient.BaseAddress, new GrpcChannelOptions + { + HttpClient = httpClient + }); - // Create a proxy object to work with the server - var client = new CartServiceClient(channel); + // Create a proxy object to work with the server + var client = new CartServiceClient(channel); - var request = new AddItemRequest + var request = new AddItemRequest + { + UserId = userId, + Item = new CartItem { - UserId = userId, - Item = new CartItem - { - ProductId = "1", - Quantity = 1 - } - }; + ProductId = "1", + Quantity = 1 + } + }; - await client.AddItemAsync(request); + await client.AddItemAsync(request); - var getCartRequest = new GetCartRequest - { - UserId = userId - }; - var cart = await client.GetCartAsync(getCartRequest); - Assert.NotNull(cart); - Assert.Equal(userId, cart.UserId); - Assert.Single(cart.Items); - - await client.EmptyCartAsync(new EmptyCartRequest { UserId = userId }); - cart = await client.GetCartAsync(getCartRequest); - Assert.Empty(cart.Items); - } + var getCartRequest = new GetCartRequest + { + UserId = userId + }; + var cart = await client.GetCartAsync(getCartRequest); + Assert.NotNull(cart); + Assert.Equal(userId, cart.UserId); + Assert.Single(cart.Items); + + await client.EmptyCartAsync(new EmptyCartRequest { UserId = userId }); + cart = await client.GetCartAsync(getCartRequest); + Assert.Empty(cart.Items); } }