From 3765a94a72c35b2b60358bf800e01a8905413404 Mon Sep 17 00:00:00 2001 From: JosepFe Date: Sun, 15 Jun 2025 13:37:14 +0200 Subject: [PATCH 01/13] refactor code to align with stylecop --- .gitignore | 1 - src/.editorconfig | 157 ++++++++++++++++++ src/Directory.Build.props | 43 +++++ src/Faura.sln | 13 +- .../Extensions/ApiExtensions.cs | 5 +- .../Extensions/ConfigurationExtensions.cs | 6 +- .../HeadersPropagationExtensions.cs | 13 +- .../Extensions/SwaggerExtension.cs | 16 +- .../WebApplicationBuilderExtensions.cs | 9 +- .../Extensions/WebApplicationExtensions.cs | 6 +- ...aura.Infrastructure.ApiBootstrapper.csproj | 9 +- .../CorrelationId/CorrelationIdMiddleware.cs | 22 +-- .../Middlewares/MiddlewareConfiguration.cs | 10 +- .../Authentication/ApiKey/ApiKeyExtensions.cs | 15 +- .../Authentication/ApiKey/ApiKeyOptions.cs | 4 +- .../BasicAuth/BasicAuthExtensions.cs | 17 +- .../BasicAuth/BasicAuthOptions.cs | 2 +- .../Authentication/Bearer/BearerExtensions.cs | 12 +- .../Authentication/OAuth2/OAuth2Extensions.cs | 16 +- .../Authentication/OAuth2/OAuth2Options.cs | 8 +- .../Models/FauraEnvironment.cs | 5 +- .../Utils/FileUtils.cs | 17 +- .../Utils/OptionUtils.cs | 9 +- .../Extensions/ConfigurationExtensions.cs | 6 +- .../HeadersPropagationExtensions.cs | 20 +-- .../WebApplicationBuilderExtensions.cs | 16 +- .../Extensions/WebApplicationExtensions.cs | 14 +- ...ura.Infrastructure.GrpcBootstrapper.csproj | 7 +- .../Interceptors/CorrelationIdInterceptor.cs | 19 +-- .../Factory/BaseWebApplicationFactory.cs | 37 ++--- ...a.Infrastructure.IntegrationTesting.csproj | 15 +- .../Seeders/TestDataSeeder.cs | 6 +- .../MongoContainerConfiguration.cs | 12 +- .../PostgresContainerConfiguration.cs | 10 +- .../RedisContainerConfiguration.cs | 12 +- .../SqlServerContainerConfiguration.cs | 10 +- .../Core/TestContainerInstance.cs | 10 +- .../Extensions/ServiceCollectionExtensions.cs | 12 +- .../Faura.Infrastructure.JWT.csproj | 5 +- .../Enrichers/ConfigureLogEnrichers.cs | 4 +- .../Enrichers/CorrelationIdEnricher.cs | 7 +- .../Faura.Infrastructure.Logger.csproj | 9 +- .../LoggingConfiguration.cs | 3 +- .../Options/LoggingOptions.cs | 4 +- .../Outputs/Console/LogConsoleExtensions.cs | 4 +- .../Outputs/Console/LogConsoleOptions.cs | 4 +- .../Outputs/GrayLog/LogGraylogExtensions.cs | 10 +- .../Outputs/GrayLog/LogGraylogOptions.cs | 6 +- .../Outputs/Seq/LogSeqExtensions.cs | 6 +- .../Outputs/Seq/LogSeqOptions.cs | 9 +- .../Outputs/SqLiteDb/LogSqLiteDbExtensions.cs | 4 +- .../Outputs/SqLiteDb/LogSqLiteDbOptions.cs | 4 +- .../Faura.Infrastructure.Result.csproj | 1 - .../Faura.Infrastructure.Result/FauraError.cs | 20 +-- .../FauraResult.cs | 85 ++++------ .../Helpers/FauraErrorHelper.cs | 4 +- .../IFauraResult.cs | 4 +- .../Common/DatabaseConfiguration.cs | 25 ++- .../Enums/SortDirection.cs | 8 +- .../Exceptions/NullContextException.cs | 20 +-- .../Exceptions/RepositoryExceptions.cs | 16 +- .../RepositoryOperationException.cs | 12 +- .../Exceptions/RepositoryQueryException.cs | 14 +- .../Exceptions/TransactionNullException.cs | 20 +-- .../Models/PagedResult.cs | 23 +-- .../Projectors/IProjector.cs | 17 +- .../Projectors/Projector.cs | 10 +- .../Repositories/EntityRepository.cs | 113 +++++-------- .../Repositories/IEntityRepository.cs | 156 +++++++++-------- .../Repositories/IRawSqlRepository.cs | 19 +-- .../Repositories/RawSqlRepository.cs | 23 ++- .../UnitOfWork/IUnitOfWork.cs | 6 +- .../UnitOfWork/UnitOfWork.cs | 24 +-- .../UnitOfWorkConfiguration.cs | 4 +- .../Bootstrappers/ApplicationBootstrapper.cs | 8 +- .../Bootstrappers/GrpcBootstrapper.cs | 13 +- .../Bootstrappers/OptionsBootstrapper.cs | 5 +- src/Templates/Faura.Grpc/Faura.Grpc.csproj | 2 +- src/Templates/Faura.Grpc/Program.cs | 9 +- .../Faura.Grpc/Services/GreeterService.cs | 11 +- .../CustomWebApplicationFactory.cs | 35 ++-- .../Faura.IntegrationTest.csproj | 13 +- .../Seeders/EmployeeTestDataSeeder.cs | 11 +- .../UseCases/WeatherForecastTests.cs | 11 +- .../Bootstrappers/ApiBootstrapper.cs | 6 +- .../Bootstrappers/ApplicationBootstrapper.cs | 18 +- .../Bootstrappers/OptionsBootstrapper.cs | 5 +- .../Controllers/WeatherForecastController.cs | 83 +++------ .../Faura.WebAPI/Domain/EmployeeRepository.cs | 17 +- .../Faura.WebAPI/Domain/Entities/Employee.cs | 4 +- .../Domain/IEmployeeRepository.cs | 10 +- .../Faura.WebAPI/Faura.WebAPI.csproj | 8 +- .../Persistence/EmployeeDbContext.cs | 10 +- .../Infrastructure/Persistence/EmployeeUoW.cs | 9 +- .../Persistence/IEmployeeUoW.cs | 8 +- src/Templates/Faura.WebAPI/Program.cs | 2 +- src/global.json | 6 + src/stylecop.json | 11 ++ 98 files changed, 826 insertions(+), 813 deletions(-) create mode 100644 src/.editorconfig create mode 100644 src/Directory.Build.props create mode 100644 src/global.json create mode 100644 src/stylecop.json diff --git a/.gitignore b/.gitignore index 4c071b2..8de49f6 100644 --- a/.gitignore +++ b/.gitignore @@ -150,7 +150,6 @@ AppPackages/ sql/ *.Cache ClientBin/ -[Ss]tyle[Cc]op.* ~$* *~ *.dbmdl diff --git a/src/.editorconfig b/src/.editorconfig new file mode 100644 index 0000000..ded567f --- /dev/null +++ b/src/.editorconfig @@ -0,0 +1,157 @@ +root = true + +[*] +charset = utf-8 +indent_size = 4 +indent_style = space +insert_final_newline = true +time_trailing_whitespace = true +end_of_line = lf + +[*.cs] +csharp_using_directive_placement = inside_namespace:warning +dotnet_sort_system_directives_first = true +csharp_style_expression_bodied_methods = true:warning +csharp_style_expression_bodied_constructors = true:warning +csharp_style_expression_bodied_properties = true:warning +csharp_style_expression_bodied_indexers = true:warning +csharp_style_expression_bodied_accessors = true:warning + + +### IDE specific rules + +# IDE0090: Use 'new(...)' +csharp_style_implicit_object_creation_when_type_is_apparent = true + +# IDE0017: Simplify object initialization +dotnet_style_object_initializer = true + +### StyleCop.Analyzers custom configuration + +# SA0001: Xml comment analysis disabled +dotnet_diagnostic.SA0001.severity = none + +# Methods should only be documented if shipped as a public API, the best documentation is the code implementation +dotnet_diagnostic.SA1516.severity = none +dotnet_diagnostic.SA1600.severity = none +dotnet_diagnostic.SA1601.severity = none +dotnet_diagnostic.SA1602.severity = none +dotnet_diagnostic.SA1611.severity = none +dotnet_diagnostic.SA1615.severity = none +dotnet_diagnostic.SA1618.severity = none +dotnet_diagnostic.SA1619.severity = none + +# SA1633: File should have header +dotnet_diagnostic.SA1633.severity = none + +# SA1101: Prefix local calls with this +dotnet_diagnostic.SA1101.severity = none + +# SX1101: Do not prefix local calls with 'this.' +dotnet_diagnostic.SX1101.severity = warning + +# SA1309: Field names should not begin with underscore +dotnet_diagnostic.SA1309.severity = none + +# SX1309: Field names should begin with underscore +dotnet_diagnostic.SX1309.severity = warning + +# SA1130: Classes should not be empty +dotnet_diagnostic.SA1130.severity = none + +# SA1400: Access modifier must be declared +dotnet_diagnostic.SA1400.severity = warning + +# SA1413: Use trailing commas in multi-line initializers +dotnet_diagnostic.SA1413.severity = warning + +# SA1503: Braces should not be omitted +dotnet_diagnostic.SA1503.severity = none + +### SonarAnalyzer.CSharp custom configuration + +# S1128: Unused "using" should be removed +dotnet_diagnostic.S1128.severity = warning + +# S2094: Classes should not be empty +dotnet_diagnostic.S2094.severity = none + +# S4487: Unread "private" fields should be removed +dotnet_diagnostic.S4487.severity = warning + +# S1172: Unused method parameters should be removed +dotnet_diagnostic.S1172.severity = warning + +#Disable S1133 for obsolete +dotnet_diagnostic.S1133.severity = suggestion + +#Disable CS0618 for obsolete +dotnet_diagnostic.CS0618.severity = suggestion +csharp_indent_labels = one_less_than_current +csharp_prefer_simple_using_statement = true:suggestion +csharp_prefer_braces = true:silent +csharp_style_namespace_declarations = file_scoped:silent +csharp_style_prefer_method_group_conversion = true:silent +csharp_style_prefer_top_level_statements = true:silent +csharp_style_prefer_primary_constructors = true:suggestion +csharp_prefer_system_threading_lock = true:suggestion +csharp_style_expression_bodied_operators = false:silent +csharp_style_expression_bodied_lambdas = true:silent +csharp_style_expression_bodied_local_functions = false:silent +csharp_space_around_binary_operators = before_and_after +dotnet_diagnostic.SA1010.severity = none +dotnet_diagnostic.SA1000.severity = none + +[*.{cs,vb}] +#### Naming styles #### + +# Naming rules + +dotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion +dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface +dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i + +dotnet_naming_rule.types_should_be_pascal_case.severity = suggestion +dotnet_naming_rule.types_should_be_pascal_case.symbols = types +dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case + +dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = suggestion +dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members +dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case + +# Symbol specifications + +dotnet_naming_symbols.interface.applicable_kinds = interface +dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.interface.required_modifiers = + +dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum +dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.types.required_modifiers = + +dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method +dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.non_field_members.required_modifiers = + +# Naming styles + +dotnet_naming_style.begins_with_i.required_prefix = I +dotnet_naming_style.begins_with_i.required_suffix = +dotnet_naming_style.begins_with_i.word_separator = +dotnet_naming_style.begins_with_i.capitalization = pascal_case + +dotnet_naming_style.pascal_case.required_prefix = +dotnet_naming_style.pascal_case.required_suffix = +dotnet_naming_style.pascal_case.word_separator = +dotnet_naming_style.pascal_case.capitalization = pascal_case + +dotnet_naming_style.pascal_case.required_prefix = +dotnet_naming_style.pascal_case.required_suffix = +dotnet_naming_style.pascal_case.word_separator = +dotnet_naming_style.pascal_case.capitalization = pascal_case +dotnet_style_operator_placement_when_wrapping = beginning_of_line +tab_width = 4 +dotnet_style_coalesce_expression = true:suggestion +dotnet_style_null_propagation = true:suggestion +dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion +dotnet_style_prefer_auto_properties = true:silent diff --git a/src/Directory.Build.props b/src/Directory.Build.props new file mode 100644 index 0000000..7d28e81 --- /dev/null +++ b/src/Directory.Build.props @@ -0,0 +1,43 @@ + + + net8.0 + enable + enable + latest + false + en + true + Faura + Faura + git + 1.0.0 + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + diff --git a/src/Faura.sln b/src/Faura.sln index 6adf77b..bf3c225 100644 --- a/src/Faura.sln +++ b/src/Faura.sln @@ -29,6 +29,15 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Faura.Infrastructure.Integr EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Faura.IntegrationTest", "Templates\Faura.IntegrationTest\Faura.IntegrationTest.csproj", "{89320569-AAF8-4290-B912-699F792319F5}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SolutionItems", "SolutionItems", "{02EA681E-C7D8-13C7-8484-4AC65E1B71E8}" + ProjectSection(SolutionItems) = preProject + .editorconfig = .editorconfig + ..\.gitignore = ..\.gitignore + Directory.Build.props = Directory.Build.props + global.json = global.json + stylecop.json = stylecop.json + EndProjectSection +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -90,11 +99,11 @@ Global {2B690895-0614-4013-85D8-7FC47B956C26} = {0C2B5D2F-B5EE-48E0-ACEE-A064E0232A26} {F749C616-5B16-4A0B-9F88-D08BEAA5F27B} = {420A3EFF-9247-407D-B58F-EC8144EB14F4} {CE7C267E-97CF-4C7F-A5D0-B8AFC30C6130} = {420A3EFF-9247-407D-B58F-EC8144EB14F4} - {09790598-6AD0-D698-A32D-D9A056BAF8D0} = {420A3EFF-9247-407D-B58F-EC8144EB14F4} - {89320569-AAF8-4290-B912-699F792319F5} = {0C2B5D2F-B5EE-48E0-ACEE-A064E0232A26} {AFC92389-71C2-BB14-10A4-CA1B415F02E9} = {420A3EFF-9247-407D-B58F-EC8144EB14F4} {31D599B8-9C10-410E-9ACD-0F2201C2BD4E} = {0C2B5D2F-B5EE-48E0-ACEE-A064E0232A26} {93D57E51-3F79-19CF-B65F-08600B130F57} = {420A3EFF-9247-407D-B58F-EC8144EB14F4} + {09790598-6AD0-D698-A32D-D9A056BAF8D0} = {420A3EFF-9247-407D-B58F-EC8144EB14F4} + {89320569-AAF8-4290-B912-699F792319F5} = {0C2B5D2F-B5EE-48E0-ACEE-A064E0232A26} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {7B487365-BA97-49F1-93FD-C12DB361C20B} diff --git a/src/Modules/Faura.Infrastructure.ApiBootstrapper/Extensions/ApiExtensions.cs b/src/Modules/Faura.Infrastructure.ApiBootstrapper/Extensions/ApiExtensions.cs index 8283470..88bc600 100644 --- a/src/Modules/Faura.Infrastructure.ApiBootstrapper/Extensions/ApiExtensions.cs +++ b/src/Modules/Faura.Infrastructure.ApiBootstrapper/Extensions/ApiExtensions.cs @@ -1,14 +1,13 @@ -using Microsoft.Extensions.DependencyInjection; - namespace Faura.Infrastructure.ApiBootstrapper.Extensions; +using Microsoft.Extensions.DependencyInjection; + public static class ApiExtensions { /// /// Configures controllers. /// /// services. - /// public static IMvcBuilder ConfigureControllers(this IServiceCollection services) => services.AddControllers(); } diff --git a/src/Modules/Faura.Infrastructure.ApiBootstrapper/Extensions/ConfigurationExtensions.cs b/src/Modules/Faura.Infrastructure.ApiBootstrapper/Extensions/ConfigurationExtensions.cs index 71c0402..73956eb 100644 --- a/src/Modules/Faura.Infrastructure.ApiBootstrapper/Extensions/ConfigurationExtensions.cs +++ b/src/Modules/Faura.Infrastructure.ApiBootstrapper/Extensions/ConfigurationExtensions.cs @@ -1,8 +1,8 @@ -using Faura.Configurations; -using Microsoft.Extensions.Configuration; - namespace Faura.Infrastructure.ApiBootstrapper.Extensions; +using Faura.Infrastructure.Common.Models; +using Microsoft.Extensions.Configuration; + public static class ConfigurationExtensions { public static void ConfigureUserSecrets(this IConfigurationBuilder configBuilder) diff --git a/src/Modules/Faura.Infrastructure.ApiBootstrapper/Extensions/HeadersPropagationExtensions.cs b/src/Modules/Faura.Infrastructure.ApiBootstrapper/Extensions/HeadersPropagationExtensions.cs index 0538053..f639345 100644 --- a/src/Modules/Faura.Infrastructure.ApiBootstrapper/Extensions/HeadersPropagationExtensions.cs +++ b/src/Modules/Faura.Infrastructure.ApiBootstrapper/Extensions/HeadersPropagationExtensions.cs @@ -1,22 +1,21 @@ -using Microsoft.AspNetCore.Builder; +namespace Faura.Infrastructure.ApiBootstrapper.Extensions; + +using Microsoft.AspNetCore.Builder; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; -namespace Faura.Infrastructure.ApiBootstrapper.Extensions; - public static class HeadersPropagationExtensions { public const string CorrelationIdHeaderKey = "x-correlation-id"; public static void AddHeadersPropagation( this WebApplicationBuilder builder, - IConfiguration config - ) => builder.Services.AddHeadersPropagation(config); + IConfiguration config) + => builder.Services.AddHeadersPropagation(config); public static IServiceCollection AddHeadersPropagation( this IServiceCollection services, - IConfiguration config - ) + IConfiguration config) { services.AddHeaderPropagation(options => { diff --git a/src/Modules/Faura.Infrastructure.ApiBootstrapper/Extensions/SwaggerExtension.cs b/src/Modules/Faura.Infrastructure.ApiBootstrapper/Extensions/SwaggerExtension.cs index fd7cf3b..706dc27 100644 --- a/src/Modules/Faura.Infrastructure.ApiBootstrapper/Extensions/SwaggerExtension.cs +++ b/src/Modules/Faura.Infrastructure.ApiBootstrapper/Extensions/SwaggerExtension.cs @@ -1,15 +1,15 @@ -using Faura.Configurations; +namespace Faura.Infrastructure.ApiBootstrapper.Extensions; + using Faura.Infrastructure.ApiBootstrapper.Swagger.Authentication.ApiKey; using Faura.Infrastructure.ApiBootstrapper.Swagger.Authentication.BasicAuth; using Faura.Infrastructure.ApiBootstrapper.Swagger.Authentication.Bearer; using Faura.Infrastructure.ApiBootstrapper.Swagger.Authentication.OAuth2; +using Faura.Infrastructure.Common.Models; using Microsoft.AspNetCore.Builder; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Swashbuckle.AspNetCore.SwaggerGen; -namespace Faura.Infrastructure.ApiBootstrapper.Extensions; - public static class SwaggerExtensions { /// @@ -29,8 +29,7 @@ public static void ConfigureUseSwagger(this IApplicationBuilder app) public static IServiceCollection SetUpSwagger( this IServiceCollection services, - IConfiguration configuration - ) + IConfiguration configuration) { if (FauraEnvironment.IsProduction) { @@ -49,13 +48,10 @@ IConfiguration configuration private static SwaggerGenOptions AddSwaggerSecurityConfigurations( this SwaggerGenOptions options, - IConfiguration configuration - ) - { - return options + IConfiguration configuration) + => options .AddOAuth2Authentication(configuration) .AddBearerAuthentication(configuration) .AddBasicAuthentication(configuration) .AddApiKeyAuthentication(configuration); - } } diff --git a/src/Modules/Faura.Infrastructure.ApiBootstrapper/Extensions/WebApplicationBuilderExtensions.cs b/src/Modules/Faura.Infrastructure.ApiBootstrapper/Extensions/WebApplicationBuilderExtensions.cs index 1089e15..b3255ad 100644 --- a/src/Modules/Faura.Infrastructure.ApiBootstrapper/Extensions/WebApplicationBuilderExtensions.cs +++ b/src/Modules/Faura.Infrastructure.ApiBootstrapper/Extensions/WebApplicationBuilderExtensions.cs @@ -1,15 +1,14 @@ -using Microsoft.AspNetCore.Builder; +namespace Faura.Infrastructure.ApiBootstrapper.Extensions; + +using Microsoft.AspNetCore.Builder; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; -namespace Faura.Infrastructure.ApiBootstrapper.Extensions; - public static class WebApplicationBuilderExtensions { public static WebApplicationBuilder BootstrapCommonFauraServices( - this WebApplicationBuilder builder - ) + this WebApplicationBuilder builder) { builder.Services.ConfigureControllers(); diff --git a/src/Modules/Faura.Infrastructure.ApiBootstrapper/Extensions/WebApplicationExtensions.cs b/src/Modules/Faura.Infrastructure.ApiBootstrapper/Extensions/WebApplicationExtensions.cs index fd32aaa..2091220 100644 --- a/src/Modules/Faura.Infrastructure.ApiBootstrapper/Extensions/WebApplicationExtensions.cs +++ b/src/Modules/Faura.Infrastructure.ApiBootstrapper/Extensions/WebApplicationExtensions.cs @@ -1,8 +1,8 @@ -using Faura.Infrastructure.ApiBootstrapper.Middlewares; -using Microsoft.AspNetCore.Builder; - namespace Faura.Infrastructure.ApiBootstrapper.Extensions; +using Faura.Infrastructure.ApiBootstrapper.Middlewares; +using Microsoft.AspNetCore.Builder; + public static class WebApplicationExtensions { public static WebApplication ConfigureCommonFauraWebApplication(this WebApplication app) diff --git a/src/Modules/Faura.Infrastructure.ApiBootstrapper/Faura.Infrastructure.ApiBootstrapper.csproj b/src/Modules/Faura.Infrastructure.ApiBootstrapper/Faura.Infrastructure.ApiBootstrapper.csproj index 33e005c..5f5ab4f 100644 --- a/src/Modules/Faura.Infrastructure.ApiBootstrapper/Faura.Infrastructure.ApiBootstrapper.csproj +++ b/src/Modules/Faura.Infrastructure.ApiBootstrapper/Faura.Infrastructure.ApiBootstrapper.csproj @@ -17,11 +17,10 @@ - - - + + @@ -34,5 +33,9 @@ \ + + + + diff --git a/src/Modules/Faura.Infrastructure.ApiBootstrapper/Middlewares/CorrelationId/CorrelationIdMiddleware.cs b/src/Modules/Faura.Infrastructure.ApiBootstrapper/Middlewares/CorrelationId/CorrelationIdMiddleware.cs index 4cd4371..5a641bd 100644 --- a/src/Modules/Faura.Infrastructure.ApiBootstrapper/Middlewares/CorrelationId/CorrelationIdMiddleware.cs +++ b/src/Modules/Faura.Infrastructure.ApiBootstrapper/Middlewares/CorrelationId/CorrelationIdMiddleware.cs @@ -1,9 +1,9 @@ -using Faura.Infrastructure.ApiBootstrapper.Extensions; +namespace Faura.Infrastructure.ApiBootstrapper.Middlewares.CorrelationId; + +using Faura.Infrastructure.ApiBootstrapper.Extensions; using Microsoft.AspNetCore.HeaderPropagation; using Microsoft.AspNetCore.Http; -namespace Faura.Infrastructure.ApiBootstrapper.Middlewares.CorrelationId; - public class CorrelationIdMiddleware { private readonly RequestDelegate _next; @@ -11,14 +11,13 @@ public class CorrelationIdMiddleware public CorrelationIdMiddleware( RequestDelegate next, - HeaderPropagationValues headerPropagationValues - ) + HeaderPropagationValues headerPropagationValues) { _next = next; _headerPropagationValues = headerPropagationValues; } - public async Task InvokeAsync(HttpContext context) + public Task InvokeAsync(HttpContext context) { var correlationId = context .Request.Headers[HeadersPropagationExtensions.CorrelationIdHeaderKey] @@ -28,12 +27,10 @@ public async Task InvokeAsync(HttpContext context) correlationId = Guid.NewGuid().ToString(); context.Request.Headers.TryAdd( HeadersPropagationExtensions.CorrelationIdHeaderKey, - correlationId - ); + correlationId); _headerPropagationValues.Headers!.TryAdd( HeadersPropagationExtensions.CorrelationIdHeaderKey, - correlationId - ); + correlationId); } var responseHeader = context @@ -43,10 +40,9 @@ public async Task InvokeAsync(HttpContext context) { context.Response.Headers.TryAdd( HeadersPropagationExtensions.CorrelationIdHeaderKey, - correlationId - ); + correlationId); } - await _next(context); + return _next(context); } } diff --git a/src/Modules/Faura.Infrastructure.ApiBootstrapper/Middlewares/MiddlewareConfiguration.cs b/src/Modules/Faura.Infrastructure.ApiBootstrapper/Middlewares/MiddlewareConfiguration.cs index 2765988..7f9504d 100644 --- a/src/Modules/Faura.Infrastructure.ApiBootstrapper/Middlewares/MiddlewareConfiguration.cs +++ b/src/Modules/Faura.Infrastructure.ApiBootstrapper/Middlewares/MiddlewareConfiguration.cs @@ -1,12 +1,10 @@ -using Faura.Infrastructure.ApiBootstrapper.Middlewares.CorrelationId; -using Microsoft.AspNetCore.Builder; - namespace Faura.Infrastructure.ApiBootstrapper.Middlewares; +using Faura.Infrastructure.ApiBootstrapper.Middlewares.CorrelationId; +using Microsoft.AspNetCore.Builder; + public static class MiddlewareConfiguration { public static void ConfigureMiddlewares(this IApplicationBuilder app) - { - app.UseMiddleware(); - } + => app.UseMiddleware(); } diff --git a/src/Modules/Faura.Infrastructure.ApiBootstrapper/Swagger/Authentication/ApiKey/ApiKeyExtensions.cs b/src/Modules/Faura.Infrastructure.ApiBootstrapper/Swagger/Authentication/ApiKey/ApiKeyExtensions.cs index 988f01d..2c5aff5 100644 --- a/src/Modules/Faura.Infrastructure.ApiBootstrapper/Swagger/Authentication/ApiKey/ApiKeyExtensions.cs +++ b/src/Modules/Faura.Infrastructure.ApiBootstrapper/Swagger/Authentication/ApiKey/ApiKeyExtensions.cs @@ -1,16 +1,15 @@ -using Microsoft.Extensions.Configuration; +namespace Faura.Infrastructure.ApiBootstrapper.Swagger.Authentication.ApiKey; + +using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.OpenApi.Models; using Swashbuckle.AspNetCore.SwaggerGen; -namespace Faura.Infrastructure.ApiBootstrapper.Swagger.Authentication.ApiKey; - public static class ApiKeyExtensions { public static SwaggerGenOptions AddApiKeyAuthentication( this SwaggerGenOptions options, - IConfiguration configuration - ) + IConfiguration configuration) { var apiKeyOptions = configuration .GetSection(ApiKeyOptions.SectionName) @@ -27,8 +26,7 @@ IConfiguration configuration Name = apiKeyOptions.Name, In = apiKeyOptions.In, Description = "API Key Authentication", - } - ); + }); options.AddSecurityRequirement( new OpenApiSecurityRequirement @@ -44,8 +42,7 @@ IConfiguration configuration }, new List() }, - } - ); + }); return options; } diff --git a/src/Modules/Faura.Infrastructure.ApiBootstrapper/Swagger/Authentication/ApiKey/ApiKeyOptions.cs b/src/Modules/Faura.Infrastructure.ApiBootstrapper/Swagger/Authentication/ApiKey/ApiKeyOptions.cs index a804272..0d6cc1b 100644 --- a/src/Modules/Faura.Infrastructure.ApiBootstrapper/Swagger/Authentication/ApiKey/ApiKeyOptions.cs +++ b/src/Modules/Faura.Infrastructure.ApiBootstrapper/Swagger/Authentication/ApiKey/ApiKeyOptions.cs @@ -1,7 +1,7 @@ -using Microsoft.OpenApi.Models; - namespace Faura.Infrastructure.ApiBootstrapper.Swagger.Authentication.ApiKey; +using Microsoft.OpenApi.Models; + public class ApiKeyOptions { public const string SectionName = "Swagger:Authentication:ApiKey"; diff --git a/src/Modules/Faura.Infrastructure.ApiBootstrapper/Swagger/Authentication/BasicAuth/BasicAuthExtensions.cs b/src/Modules/Faura.Infrastructure.ApiBootstrapper/Swagger/Authentication/BasicAuth/BasicAuthExtensions.cs index 675f674..943ce6b 100644 --- a/src/Modules/Faura.Infrastructure.ApiBootstrapper/Swagger/Authentication/BasicAuth/BasicAuthExtensions.cs +++ b/src/Modules/Faura.Infrastructure.ApiBootstrapper/Swagger/Authentication/BasicAuth/BasicAuthExtensions.cs @@ -1,16 +1,15 @@ -using Microsoft.Extensions.Configuration; +namespace Faura.Infrastructure.ApiBootstrapper.Swagger.Authentication.BasicAuth; + +using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.OpenApi.Models; using Swashbuckle.AspNetCore.SwaggerGen; -namespace Faura.Infrastructure.ApiBootstrapper.Swagger.Authentication.BasicAuth; - public static class BasicAuthExtensions { public static SwaggerGenOptions AddBasicAuthentication( this SwaggerGenOptions options, - IConfiguration configuration - ) + IConfiguration configuration) { var basicAuthOptions = configuration .GetSection(BasicAuthOptions.SectionName) @@ -21,14 +20,13 @@ IConfiguration configuration // Security Definition options.AddSecurityDefinition( - basicAuthOptions.Name, + basicAuthOptions!.Name, new OpenApiSecurityScheme { Type = SecuritySchemeType.Http, Scheme = "basic", Description = "Basic Authentication", - } - ); + }); // Security Requirement options.AddSecurityRequirement( @@ -45,8 +43,7 @@ IConfiguration configuration }, new List() }, - } - ); + }); return options; } diff --git a/src/Modules/Faura.Infrastructure.ApiBootstrapper/Swagger/Authentication/BasicAuth/BasicAuthOptions.cs b/src/Modules/Faura.Infrastructure.ApiBootstrapper/Swagger/Authentication/BasicAuth/BasicAuthOptions.cs index ec55c56..5ed0e2e 100644 --- a/src/Modules/Faura.Infrastructure.ApiBootstrapper/Swagger/Authentication/BasicAuth/BasicAuthOptions.cs +++ b/src/Modules/Faura.Infrastructure.ApiBootstrapper/Swagger/Authentication/BasicAuth/BasicAuthOptions.cs @@ -1,4 +1,4 @@ -namespace Faura.Infrastructure.ApiBootstrapper.Swagger.Authentication.BasicAuth; +namespace Faura.Infrastructure.ApiBootstrapper.Swagger.Authentication.BasicAuth; public class BasicAuthOptions { diff --git a/src/Modules/Faura.Infrastructure.ApiBootstrapper/Swagger/Authentication/Bearer/BearerExtensions.cs b/src/Modules/Faura.Infrastructure.ApiBootstrapper/Swagger/Authentication/Bearer/BearerExtensions.cs index c88990a..5f5ff7b 100644 --- a/src/Modules/Faura.Infrastructure.ApiBootstrapper/Swagger/Authentication/Bearer/BearerExtensions.cs +++ b/src/Modules/Faura.Infrastructure.ApiBootstrapper/Swagger/Authentication/Bearer/BearerExtensions.cs @@ -1,16 +1,15 @@ -using Microsoft.Extensions.Configuration; +namespace Faura.Infrastructure.ApiBootstrapper.Swagger.Authentication.Bearer; + +using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.OpenApi.Models; using Swashbuckle.AspNetCore.SwaggerGen; -namespace Faura.Infrastructure.ApiBootstrapper.Swagger.Authentication.Bearer; - public static class BearerExtensions { public static SwaggerGenOptions AddBearerAuthentication( this SwaggerGenOptions options, - IConfiguration configuration - ) + IConfiguration configuration) { var bearerOptions = configuration .GetSection(BearerOptions.SectionName) @@ -30,8 +29,7 @@ IConfiguration configuration BearerFormat = "JWT", In = ParameterLocation.Header, Description = "JWT Authorization header using the Bearer scheme.", - } - ); + }); // Security Requirement var requirement = new OpenApiSecurityRequirement diff --git a/src/Modules/Faura.Infrastructure.ApiBootstrapper/Swagger/Authentication/OAuth2/OAuth2Extensions.cs b/src/Modules/Faura.Infrastructure.ApiBootstrapper/Swagger/Authentication/OAuth2/OAuth2Extensions.cs index 706b125..a328beb 100644 --- a/src/Modules/Faura.Infrastructure.ApiBootstrapper/Swagger/Authentication/OAuth2/OAuth2Extensions.cs +++ b/src/Modules/Faura.Infrastructure.ApiBootstrapper/Swagger/Authentication/OAuth2/OAuth2Extensions.cs @@ -1,16 +1,15 @@ -using Microsoft.Extensions.Configuration; +namespace Faura.Infrastructure.ApiBootstrapper.Swagger.Authentication.OAuth2; + +using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.OpenApi.Models; using Swashbuckle.AspNetCore.SwaggerGen; -namespace Faura.Infrastructure.ApiBootstrapper.Swagger.Authentication.OAuth2; - public static class OAuth2Extensions { public static SwaggerGenOptions AddOAuth2Authentication( this SwaggerGenOptions options, - IConfiguration configuration - ) + IConfiguration configuration) { var oauth2Options = configuration .GetSection(OAuth2Options.SectionName) @@ -21,7 +20,7 @@ IConfiguration configuration // Security Definition options.AddSecurityDefinition( - oauth2Options.Name, + oauth2Options!.Name, new OpenApiSecurityScheme { Type = SecuritySchemeType.OAuth2, @@ -29,12 +28,11 @@ IConfiguration configuration { Implicit = new OpenApiOAuthFlow { - AuthorizationUrl = new Uri(oauth2Options.AuthenticationURL), + AuthorizationUrl = new Uri(oauth2Options.AuthenticationURL!), Scopes = oauth2Options.Scopes, }, }, - } - ); + }); // Security Requirement var requirement = new OpenApiSecurityRequirement diff --git a/src/Modules/Faura.Infrastructure.ApiBootstrapper/Swagger/Authentication/OAuth2/OAuth2Options.cs b/src/Modules/Faura.Infrastructure.ApiBootstrapper/Swagger/Authentication/OAuth2/OAuth2Options.cs index 64ce93a..58bb9ff 100644 --- a/src/Modules/Faura.Infrastructure.ApiBootstrapper/Swagger/Authentication/OAuth2/OAuth2Options.cs +++ b/src/Modules/Faura.Infrastructure.ApiBootstrapper/Swagger/Authentication/OAuth2/OAuth2Options.cs @@ -1,12 +1,12 @@ -namespace Faura.Infrastructure.ApiBootstrapper.Swagger.Authentication.OAuth2; +namespace Faura.Infrastructure.ApiBootstrapper.Swagger.Authentication.OAuth2; public class OAuth2Options { public const string SectionName = "Swagger:Authentication:OAuth2"; public bool Enable { get; set; } = false; - public string Name { get; set; } - public string AuthenticationURL { get; set; } + public string? Name { get; set; } + public string? AuthenticationURL { get; set; } public Dictionary Scopes { get; set; } = - new() { { "openid", "openid" }, { "profile", "profile" } }; + new () { { "openid", "openid" }, { "profile", "profile" } }; } diff --git a/src/Modules/Faura.Infrastructure.Common/Models/FauraEnvironment.cs b/src/Modules/Faura.Infrastructure.Common/Models/FauraEnvironment.cs index 9424115..eb82fa1 100644 --- a/src/Modules/Faura.Infrastructure.Common/Models/FauraEnvironment.cs +++ b/src/Modules/Faura.Infrastructure.Common/Models/FauraEnvironment.cs @@ -1,5 +1,4 @@ -namespace Faura.Configurations; - +namespace Faura.Infrastructure.Common.Models; public enum FauraDeploymentMode { Local, @@ -12,8 +11,8 @@ public enum FauraDeploymentMode public static class FauraEnvironment { - private static FauraDeploymentMode? _currentMode; private const string FauraEnvVariableName = "FAURA_ENVIRONMENT"; + private static FauraDeploymentMode? _currentMode; public static FauraDeploymentMode CurrentMode => _currentMode ??= DetectMode(); diff --git a/src/Modules/Faura.Infrastructure.Common/Utils/FileUtils.cs b/src/Modules/Faura.Infrastructure.Common/Utils/FileUtils.cs index d7aa150..657d159 100644 --- a/src/Modules/Faura.Infrastructure.Common/Utils/FileUtils.cs +++ b/src/Modules/Faura.Infrastructure.Common/Utils/FileUtils.cs @@ -1,10 +1,10 @@ -using System.Reflection; - namespace Faura.Infrastructure.Common.Utils; +using System.Reflection; + public static class FileUtils { - private static string? AapplicationDirectory; + private static string? applicationDirectory; public static List SearchFiles(string pattern, string baseDirectory = "") { @@ -27,16 +27,11 @@ public static List SearchFiles(string pattern, string baseDirectory = "" } public static string? GetApplicationDirectory() - { - return AapplicationDirectory ??= Path.GetDirectoryName( - Assembly.GetEntryAssembly()?.Location - ); - } + => applicationDirectory ??= Path.GetDirectoryName( + Assembly.GetEntryAssembly()?.Location); private static string ResolveDirectory(string baseDirectory) - { - return !string.IsNullOrWhiteSpace(baseDirectory) && Directory.Exists(baseDirectory) + => !string.IsNullOrWhiteSpace(baseDirectory) && Directory.Exists(baseDirectory) ? baseDirectory : Directory.GetCurrentDirectory(); - } } diff --git a/src/Modules/Faura.Infrastructure.Common/Utils/OptionUtils.cs b/src/Modules/Faura.Infrastructure.Common/Utils/OptionUtils.cs index 2633acd..0b53a54 100644 --- a/src/Modules/Faura.Infrastructure.Common/Utils/OptionUtils.cs +++ b/src/Modules/Faura.Infrastructure.Common/Utils/OptionUtils.cs @@ -1,16 +1,15 @@ -using Microsoft.Extensions.Configuration; +namespace Faura.Infrastructure.Common.Utils; + +using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; -namespace Faura.Infrastructure.Common.Utils; - public static class OptionUtils { public static T? GetTypedOptions( this IServiceCollection services, IConfiguration configuration, - string sectionName - ) + string sectionName) where T : class, new() { if (configuration == null || string.IsNullOrWhiteSpace(sectionName)) diff --git a/src/Modules/Faura.Infrastructure.GrpcBootstrapper/Extensions/ConfigurationExtensions.cs b/src/Modules/Faura.Infrastructure.GrpcBootstrapper/Extensions/ConfigurationExtensions.cs index e83571d..5ad0189 100644 --- a/src/Modules/Faura.Infrastructure.GrpcBootstrapper/Extensions/ConfigurationExtensions.cs +++ b/src/Modules/Faura.Infrastructure.GrpcBootstrapper/Extensions/ConfigurationExtensions.cs @@ -1,8 +1,8 @@ -using Faura.Configurations; -using Microsoft.Extensions.Configuration; - namespace Faura.Infrastructure.GrpcBootstrapper.Extensions; +using Faura.Infrastructure.Common.Models; +using Microsoft.Extensions.Configuration; + public static class ConfigurationExtensions { public static void ConfigureUserSecrets(this IConfigurationBuilder configBuilder) diff --git a/src/Modules/Faura.Infrastructure.GrpcBootstrapper/Extensions/HeadersPropagationExtensions.cs b/src/Modules/Faura.Infrastructure.GrpcBootstrapper/Extensions/HeadersPropagationExtensions.cs index 3d4cf74..11c45e7 100644 --- a/src/Modules/Faura.Infrastructure.GrpcBootstrapper/Extensions/HeadersPropagationExtensions.cs +++ b/src/Modules/Faura.Infrastructure.GrpcBootstrapper/Extensions/HeadersPropagationExtensions.cs @@ -1,27 +1,19 @@ -using Microsoft.AspNetCore.Builder; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; - namespace Faura.Infrastructure.GrpcBootstrapper.Extensions; +using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.DependencyInjection; + public static class HeadersPropagationExtensions { public const string CorrelationIdHeaderKey = "x-correlation-id"; public static void AddHeadersPropagation( - this WebApplicationBuilder builder, - IConfiguration config - ) => builder.Services.AddHeadersPropagation(config); + this WebApplicationBuilder builder) => builder.Services.AddHeadersPropagation(); public static IServiceCollection AddHeadersPropagation( - this IServiceCollection services, - IConfiguration config - ) + this IServiceCollection services) { - services.AddHeaderPropagation(options => - { - options.Headers.Add(CorrelationIdHeaderKey); - }); + services.AddHeaderPropagation(options => options.Headers.Add(CorrelationIdHeaderKey)); return services; } } diff --git a/src/Modules/Faura.Infrastructure.GrpcBootstrapper/Extensions/WebApplicationBuilderExtensions.cs b/src/Modules/Faura.Infrastructure.GrpcBootstrapper/Extensions/WebApplicationBuilderExtensions.cs index 38a7f03..6c2f453 100644 --- a/src/Modules/Faura.Infrastructure.GrpcBootstrapper/Extensions/WebApplicationBuilderExtensions.cs +++ b/src/Modules/Faura.Infrastructure.GrpcBootstrapper/Extensions/WebApplicationBuilderExtensions.cs @@ -1,23 +1,19 @@ -using Faura.Infrastructure.GrpcBootstrapper.Interceptors; +namespace Faura.Infrastructure.GrpcBootstrapper.Extensions; + +using Faura.Infrastructure.GrpcBootstrapper.Interceptors; using Microsoft.AspNetCore.Builder; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; -namespace Faura.Infrastructure.GrpcBootstrapper.Extensions; - public static class WebApplicationBuilderExtensions { public static WebApplicationBuilder BootstrapCommonFauraServices( - this WebApplicationBuilder builder - ) + this WebApplicationBuilder builder) { - builder.Services.AddGrpc(options => - { - options.Interceptors.Add(); - }); + builder.Services.AddGrpc(options => options.Interceptors.Add()); - builder.Services.AddHeadersPropagation(builder.Configuration); + builder.Services.AddHeadersPropagation(); return builder; } diff --git a/src/Modules/Faura.Infrastructure.GrpcBootstrapper/Extensions/WebApplicationExtensions.cs b/src/Modules/Faura.Infrastructure.GrpcBootstrapper/Extensions/WebApplicationExtensions.cs index 0cb7e3d..f6a8ff7 100644 --- a/src/Modules/Faura.Infrastructure.GrpcBootstrapper/Extensions/WebApplicationExtensions.cs +++ b/src/Modules/Faura.Infrastructure.GrpcBootstrapper/Extensions/WebApplicationExtensions.cs @@ -1,23 +1,19 @@ -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Routing; - namespace Faura.Infrastructure.GrpcBootstrapper.Extensions; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Routing; + public static class WebApplicationExtensions { public static IApplicationBuilder ConfigureCommonFauraWebApplication( this IApplicationBuilder app, - Action mapGrpcServices - ) + Action mapGrpcServices) { app.UseRouting(); app.UseHeaderPropagation(); - app.UseEndpoints(endpoints => - { - mapGrpcServices(endpoints); - }); + app.UseEndpoints(endpoints => mapGrpcServices(endpoints)); return app; } diff --git a/src/Modules/Faura.Infrastructure.GrpcBootstrapper/Faura.Infrastructure.GrpcBootstrapper.csproj b/src/Modules/Faura.Infrastructure.GrpcBootstrapper/Faura.Infrastructure.GrpcBootstrapper.csproj index 5fe256f..cb7ec3a 100644 --- a/src/Modules/Faura.Infrastructure.GrpcBootstrapper/Faura.Infrastructure.GrpcBootstrapper.csproj +++ b/src/Modules/Faura.Infrastructure.GrpcBootstrapper/Faura.Infrastructure.GrpcBootstrapper.csproj @@ -18,8 +18,7 @@ - - + @@ -33,4 +32,8 @@ + + + + diff --git a/src/Modules/Faura.Infrastructure.GrpcBootstrapper/Interceptors/CorrelationIdInterceptor.cs b/src/Modules/Faura.Infrastructure.GrpcBootstrapper/Interceptors/CorrelationIdInterceptor.cs index c1339d9..7f0485f 100644 --- a/src/Modules/Faura.Infrastructure.GrpcBootstrapper/Interceptors/CorrelationIdInterceptor.cs +++ b/src/Modules/Faura.Infrastructure.GrpcBootstrapper/Interceptors/CorrelationIdInterceptor.cs @@ -1,24 +1,21 @@ -using Grpc.Core; +namespace Faura.Infrastructure.GrpcBootstrapper.Interceptors; + +using Grpc.Core; using Grpc.Core.Interceptors; using Microsoft.AspNetCore.HeaderPropagation; -namespace Faura.Infrastructure.GrpcBootstrapper.Interceptors; - public class CorrelationIdInterceptor : Interceptor { - private readonly HeaderPropagationValues _headerPropagationValues; private const string HeaderKey = "x-correlation-id"; + private readonly HeaderPropagationValues _headerPropagationValues; public CorrelationIdInterceptor(HeaderPropagationValues headerPropagationValues) - { - _headerPropagationValues = headerPropagationValues; - } + => _headerPropagationValues = headerPropagationValues; - public override async Task UnaryServerHandler( + public override Task UnaryServerHandler( TRequest request, ServerCallContext context, - UnaryServerMethod continuation - ) + UnaryServerMethod continuation) { var correlationId = context.RequestHeaders.GetValue(HeaderKey) ?? Guid.NewGuid().ToString(); @@ -26,6 +23,6 @@ UnaryServerMethod continuation context.ResponseTrailers.Add(HeaderKey, correlationId); - return await continuation(request, context); + return continuation(request, context); } } diff --git a/src/Modules/Faura.Infrastructure.IntegrationTesting/Factory/BaseWebApplicationFactory.cs b/src/Modules/Faura.Infrastructure.IntegrationTesting/Factory/BaseWebApplicationFactory.cs index 45dbcbc..a0a96a9 100644 --- a/src/Modules/Faura.Infrastructure.IntegrationTesting/Factory/BaseWebApplicationFactory.cs +++ b/src/Modules/Faura.Infrastructure.IntegrationTesting/Factory/BaseWebApplicationFactory.cs @@ -1,4 +1,6 @@ -using Faura.Infrastructure.IntegrationTesting.Constants; +namespace Faura.Infrastructure.IntegrationTesting.Factory; + +using Faura.Infrastructure.IntegrationTesting.Constants; using Faura.Infrastructure.IntegrationTesting.Seeders; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Mvc.Testing; @@ -6,8 +8,6 @@ using Microsoft.Extensions.DependencyInjection; using Xunit; -namespace Faura.Infrastructure.IntegrationTesting.Factory; - /// /// Base factory for integration tests with container setup and service customization. /// @@ -16,23 +16,18 @@ public abstract class BaseWebApplicationFactory IAsyncLifetime where TEntryPoint : class { - /// - /// Final configuration used during the test run. - /// - protected IConfiguration? Configuration; + protected IConfiguration? Configuration { get; set; } public async Task InitializeAsync() { Environment.SetEnvironmentVariable( "ASPNETCORE_ENVIRONMENT", - IntegrationTestConstants.Environment - ); + IntegrationTestConstants.Environment); var testProjectPath = Directory.GetCurrentDirectory(); var settingsFile = Path.Combine( testProjectPath, - $"appsettings.{IntegrationTestConstants.Environment}.json" - ); + $"appsettings.{IntegrationTestConstants.Environment}.json"); var configBuilder = new ConfigurationBuilder() .AddJsonFile(settingsFile, optional: false) @@ -44,7 +39,7 @@ public async Task InitializeAsync() Configuration = await ConfigureTestContainersAsync(baseConfig); } - public virtual Task DisposeAsync() => Task.CompletedTask; + public new virtual Task DisposeAsync() => Task.CompletedTask; protected override void ConfigureWebHost(IWebHostBuilder builder) { @@ -55,8 +50,7 @@ protected override void ConfigureWebHost(IWebHostBuilder builder) { config.Sources.Clear(); config.AddConfiguration(Configuration!); - } - ); + }); builder.ConfigureServices(services => { @@ -79,26 +73,27 @@ protected virtual Task ConfigureConfigurationAsync(IConfigurationBuilder builder /// Starts containers and returns updated configuration (e.g., with connection strings). /// protected virtual Task ConfigureTestContainersAsync( - IConfiguration configuration - ) => Task.FromResult(configuration); + IConfiguration configuration) => Task.FromResult(configuration); /// /// Registers test-specific or mocked services. /// protected virtual void ConfigureTestServices( IServiceCollection services, - IConfiguration configuration - ) { } + IConfiguration configuration) + { + } /// /// Registers database context and ensures schema is created. /// protected virtual void ConfigureTestDatabase( IServiceCollection services, - IConfiguration configuration - ) { } + IConfiguration configuration) + { + } - private async Task RunSeedersAsync(IServiceProvider serviceProvider) + private static async Task RunSeedersAsync(IServiceProvider serviceProvider) { foreach (var seeder in serviceProvider.GetServices()) { diff --git a/src/Modules/Faura.Infrastructure.IntegrationTesting/Faura.Infrastructure.IntegrationTesting.csproj b/src/Modules/Faura.Infrastructure.IntegrationTesting/Faura.Infrastructure.IntegrationTesting.csproj index 6d62275..b6d3bd5 100644 --- a/src/Modules/Faura.Infrastructure.IntegrationTesting/Faura.Infrastructure.IntegrationTesting.csproj +++ b/src/Modules/Faura.Infrastructure.IntegrationTesting/Faura.Infrastructure.IntegrationTesting.csproj @@ -19,16 +19,11 @@ - - - - - - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - + + + + + diff --git a/src/Modules/Faura.Infrastructure.IntegrationTesting/Seeders/TestDataSeeder.cs b/src/Modules/Faura.Infrastructure.IntegrationTesting/Seeders/TestDataSeeder.cs index 76b270c..28b0911 100644 --- a/src/Modules/Faura.Infrastructure.IntegrationTesting/Seeders/TestDataSeeder.cs +++ b/src/Modules/Faura.Infrastructure.IntegrationTesting/Seeders/TestDataSeeder.cs @@ -1,8 +1,8 @@ -using Microsoft.EntityFrameworkCore; -using Microsoft.Extensions.DependencyInjection; - namespace Faura.Infrastructure.IntegrationTesting.Seeders; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.DependencyInjection; + public abstract class TestDataSeeder : ITestDataSeeder where TContext : DbContext { diff --git a/src/Modules/Faura.Infrastructure.IntegrationTesting/TestContainers/Configurations/MongoContainerConfiguration.cs b/src/Modules/Faura.Infrastructure.IntegrationTesting/TestContainers/Configurations/MongoContainerConfiguration.cs index b4b40eb..37305f8 100644 --- a/src/Modules/Faura.Infrastructure.IntegrationTesting/TestContainers/Configurations/MongoContainerConfiguration.cs +++ b/src/Modules/Faura.Infrastructure.IntegrationTesting/TestContainers/Configurations/MongoContainerConfiguration.cs @@ -1,17 +1,15 @@ -using Faura.Infrastructure.IntegrationTesting.Options; +namespace Faura.Infrastructure.IntegrationTesting.TestContainers.Configurations; + +using Faura.Infrastructure.IntegrationTesting.Options; using Faura.Infrastructure.IntegrationTesting.TestContainers.Constants; using Faura.Infrastructure.IntegrationTesting.TestContainers.Core; -namespace Faura.Infrastructure.IntegrationTesting.TestContainers.Configurations; - public class MongoContainerConfiguration : ITestContainerConfiguration { private readonly ContainerOptions _options; public MongoContainerConfiguration(ContainerOptions options) - { - _options = options; - } + => _options = options; public string Image => string.IsNullOrWhiteSpace(_options.Image) @@ -24,7 +22,7 @@ public MongoContainerConfiguration(ContainerOptions options) public string Password => _options.Password ?? string.Empty; public string Database => _options.Database ?? "test"; - public Dictionary GetEnvironmentVariables() => new(); + public Dictionary GetEnvironmentVariables() => []; public string BuildConnectionString(int mappedPort) => $"mongodb://localhost:{mappedPort}/{Database}"; diff --git a/src/Modules/Faura.Infrastructure.IntegrationTesting/TestContainers/Configurations/PostgresContainerConfiguration.cs b/src/Modules/Faura.Infrastructure.IntegrationTesting/TestContainers/Configurations/PostgresContainerConfiguration.cs index 05ce5f2..bd9bd1f 100644 --- a/src/Modules/Faura.Infrastructure.IntegrationTesting/TestContainers/Configurations/PostgresContainerConfiguration.cs +++ b/src/Modules/Faura.Infrastructure.IntegrationTesting/TestContainers/Configurations/PostgresContainerConfiguration.cs @@ -1,17 +1,15 @@ -using Faura.Infrastructure.IntegrationTesting.Options; +namespace Faura.Infrastructure.IntegrationTesting.TestContainers.Configurations; + +using Faura.Infrastructure.IntegrationTesting.Options; using Faura.Infrastructure.IntegrationTesting.TestContainers.Constants; using Faura.Infrastructure.IntegrationTesting.TestContainers.Core; -namespace Faura.Infrastructure.IntegrationTesting.TestContainers.Configurations; - public class PostgresContainerConfiguration : ITestContainerConfiguration { private readonly ContainerOptions _options; public PostgresContainerConfiguration(ContainerOptions options) - { - _options = options; - } + => _options = options; public string Image => string.IsNullOrWhiteSpace(_options.Image) diff --git a/src/Modules/Faura.Infrastructure.IntegrationTesting/TestContainers/Configurations/RedisContainerConfiguration.cs b/src/Modules/Faura.Infrastructure.IntegrationTesting/TestContainers/Configurations/RedisContainerConfiguration.cs index c123cb0..9918e8d 100644 --- a/src/Modules/Faura.Infrastructure.IntegrationTesting/TestContainers/Configurations/RedisContainerConfiguration.cs +++ b/src/Modules/Faura.Infrastructure.IntegrationTesting/TestContainers/Configurations/RedisContainerConfiguration.cs @@ -1,17 +1,15 @@ -using Faura.Infrastructure.IntegrationTesting.Options; +namespace Faura.Infrastructure.IntegrationTesting.TestContainers.Configurations; + +using Faura.Infrastructure.IntegrationTesting.Options; using Faura.Infrastructure.IntegrationTesting.TestContainers.Constants; using Faura.Infrastructure.IntegrationTesting.TestContainers.Core; -namespace Faura.Infrastructure.IntegrationTesting.TestContainers.Configurations; - public class RedisContainerConfiguration : ITestContainerConfiguration { private readonly ContainerOptions _options; public RedisContainerConfiguration(ContainerOptions options) - { - _options = options; - } + => _options = options; public string Image => string.IsNullOrWhiteSpace(_options.Image) @@ -24,7 +22,7 @@ public RedisContainerConfiguration(ContainerOptions options) public string Password => _options.Password ?? string.Empty; public string Database => _options.Database ?? string.Empty; - public Dictionary GetEnvironmentVariables() => new(); + public Dictionary GetEnvironmentVariables() => []; public string BuildConnectionString(int mappedPort) => $"localhost:{mappedPort}"; } diff --git a/src/Modules/Faura.Infrastructure.IntegrationTesting/TestContainers/Configurations/SqlServerContainerConfiguration.cs b/src/Modules/Faura.Infrastructure.IntegrationTesting/TestContainers/Configurations/SqlServerContainerConfiguration.cs index 3c3efb4..ef6ce19 100644 --- a/src/Modules/Faura.Infrastructure.IntegrationTesting/TestContainers/Configurations/SqlServerContainerConfiguration.cs +++ b/src/Modules/Faura.Infrastructure.IntegrationTesting/TestContainers/Configurations/SqlServerContainerConfiguration.cs @@ -1,17 +1,15 @@ -using Faura.Infrastructure.IntegrationTesting.Options; +namespace Faura.Infrastructure.IntegrationTesting.TestContainers.Configurations; + +using Faura.Infrastructure.IntegrationTesting.Options; using Faura.Infrastructure.IntegrationTesting.TestContainers.Constants; using Faura.Infrastructure.IntegrationTesting.TestContainers.Core; -namespace Faura.Infrastructure.IntegrationTesting.TestContainers.Configurations; - public class SqlServerContainerConfiguration : ITestContainerConfiguration { private readonly ContainerOptions _options; public SqlServerContainerConfiguration(ContainerOptions options) - { - _options = options; - } + => _options = options; public string Image => string.IsNullOrWhiteSpace(_options.Image) diff --git a/src/Modules/Faura.Infrastructure.IntegrationTesting/TestContainers/Core/TestContainerInstance.cs b/src/Modules/Faura.Infrastructure.IntegrationTesting/TestContainers/Core/TestContainerInstance.cs index 0232f37..a2c19cc 100644 --- a/src/Modules/Faura.Infrastructure.IntegrationTesting/TestContainers/Core/TestContainerInstance.cs +++ b/src/Modules/Faura.Infrastructure.IntegrationTesting/TestContainers/Core/TestContainerInstance.cs @@ -1,16 +1,14 @@ -using DotNet.Testcontainers.Builders; -using DotNet.Testcontainers.Containers; - namespace Faura.Infrastructure.IntegrationTesting.TestContainers.Core; +using DotNet.Testcontainers.Builders; +using DotNet.Testcontainers.Containers; + public class TestContainerInstance where T : ITestContainerConfiguration { private readonly T _config; private readonly IContainer _container; - public string ConnectionString { get; private set; } = string.Empty; - public TestContainerInstance(T config) { _config = config; @@ -29,6 +27,8 @@ public TestContainerInstance(T config) _container = builder.Build(); } + public string ConnectionString { get; private set; } = string.Empty; + public async Task StartAsync() { await _container.StartAsync(); diff --git a/src/Modules/Faura.Infrastructure.JWT/Extensions/ServiceCollectionExtensions.cs b/src/Modules/Faura.Infrastructure.JWT/Extensions/ServiceCollectionExtensions.cs index 06e0656..b0b6690 100644 --- a/src/Modules/Faura.Infrastructure.JWT/Extensions/ServiceCollectionExtensions.cs +++ b/src/Modules/Faura.Infrastructure.JWT/Extensions/ServiceCollectionExtensions.cs @@ -1,23 +1,21 @@ -using Faura.Infrastructure.Common.Utils; +namespace Faura.Infrastructure.JWT.Extensions; + +using Faura.Infrastructure.Common.Utils; using Faura.Infrastructure.JWT.Options; using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.IdentityModel.Tokens; -namespace Faura.Infrastructure.JWT.Extensions; - public static class ServiceCollectionExtensions { public static IServiceCollection SetUpJwt( this IServiceCollection services, - IConfiguration configuration - ) + IConfiguration configuration) { var jwtOptions = services.GetTypedOptions( configuration, - JwtOptions.SectionName - ); + JwtOptions.SectionName); services.AddAuthorization(); services diff --git a/src/Modules/Faura.Infrastructure.JWT/Faura.Infrastructure.JWT.csproj b/src/Modules/Faura.Infrastructure.JWT/Faura.Infrastructure.JWT.csproj index 169a8d1..b0ed9e9 100644 --- a/src/Modules/Faura.Infrastructure.JWT/Faura.Infrastructure.JWT.csproj +++ b/src/Modules/Faura.Infrastructure.JWT/Faura.Infrastructure.JWT.csproj @@ -16,9 +16,12 @@ - + + + + diff --git a/src/Modules/Faura.Infrastructure.Logger/Enrichers/ConfigureLogEnrichers.cs b/src/Modules/Faura.Infrastructure.Logger/Enrichers/ConfigureLogEnrichers.cs index 9ea5424..9b5827e 100644 --- a/src/Modules/Faura.Infrastructure.Logger/Enrichers/ConfigureLogEnrichers.cs +++ b/src/Modules/Faura.Infrastructure.Logger/Enrichers/ConfigureLogEnrichers.cs @@ -1,4 +1,4 @@ -namespace Faura.Infrastructure.Logger.Enrichers; +namespace Faura.Infrastructure.Logger.Enrichers; using Microsoft.Extensions.Configuration; using Serilog; @@ -11,7 +11,7 @@ public static LoggerConfiguration ConfigureLogEnrichers(this LoggerConfiguration var loggingOptions = configuration.GetSection(LoggingOptions.SectionName).Get(); return loggerConfiguration - .Enrich.WithProperty("ApplicationName", loggingOptions.ApplicationName) + .Enrich.WithProperty("ApplicationName", loggingOptions!.ApplicationName) .Enrich.With(new CorrelationIdEnricher()); } } diff --git a/src/Modules/Faura.Infrastructure.Logger/Enrichers/CorrelationIdEnricher.cs b/src/Modules/Faura.Infrastructure.Logger/Enrichers/CorrelationIdEnricher.cs index 9671625..de88be3 100644 --- a/src/Modules/Faura.Infrastructure.Logger/Enrichers/CorrelationIdEnricher.cs +++ b/src/Modules/Faura.Infrastructure.Logger/Enrichers/CorrelationIdEnricher.cs @@ -1,4 +1,4 @@ -namespace Faura.Infrastructure.Logger.Enrichers; +namespace Faura.Infrastructure.Logger.Enrichers; using Microsoft.AspNetCore.HeaderPropagation; using Serilog.Core; @@ -10,7 +10,10 @@ public class CorrelationIdEnricher : ILogEventEnricher private const string HeaderKey = "x-correlation-id"; private readonly HeaderPropagationValues _headerPropagationValues; - public CorrelationIdEnricher() : this(new HeaderPropagationValues()) { } + public CorrelationIdEnricher() + : this(new HeaderPropagationValues()) + { + } public CorrelationIdEnricher(HeaderPropagationValues headerPropagationValues) => _headerPropagationValues = headerPropagationValues; diff --git a/src/Modules/Faura.Infrastructure.Logger/Faura.Infrastructure.Logger.csproj b/src/Modules/Faura.Infrastructure.Logger/Faura.Infrastructure.Logger.csproj index 1f6de5f..345faf7 100644 --- a/src/Modules/Faura.Infrastructure.Logger/Faura.Infrastructure.Logger.csproj +++ b/src/Modules/Faura.Infrastructure.Logger/Faura.Infrastructure.Logger.csproj @@ -16,16 +16,19 @@ - - + - + + + + + True diff --git a/src/Modules/Faura.Infrastructure.Logger/LoggingConfiguration.cs b/src/Modules/Faura.Infrastructure.Logger/LoggingConfiguration.cs index b694a58..b81471c 100644 --- a/src/Modules/Faura.Infrastructure.Logger/LoggingConfiguration.cs +++ b/src/Modules/Faura.Infrastructure.Logger/LoggingConfiguration.cs @@ -13,6 +13,7 @@ namespace Faura.Infrastructure.Logger; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Faura.Infrastructure.Logger.Options; +using Faura.Infrastructure.Logger.Outputs.Seq; public static class LoggingConfiguration { @@ -56,4 +57,4 @@ public static LoggerConfiguration ConfigureFauraLogging( return loggerConfiguration; } -} \ No newline at end of file +} diff --git a/src/Modules/Faura.Infrastructure.Logger/Options/LoggingOptions.cs b/src/Modules/Faura.Infrastructure.Logger/Options/LoggingOptions.cs index 86457d8..e8e418f 100644 --- a/src/Modules/Faura.Infrastructure.Logger/Options/LoggingOptions.cs +++ b/src/Modules/Faura.Infrastructure.Logger/Options/LoggingOptions.cs @@ -1,8 +1,8 @@ -namespace Faura.Infrastructure.Logger.Options +namespace Faura.Infrastructure.Logger.Options { public class LoggingOptions { public const string SectionName = "Logging"; - public string ApplicationName { get; set; } + public string? ApplicationName { get; set; } } } diff --git a/src/Modules/Faura.Infrastructure.Logger/Outputs/Console/LogConsoleExtensions.cs b/src/Modules/Faura.Infrastructure.Logger/Outputs/Console/LogConsoleExtensions.cs index daa5dc9..4474dda 100644 --- a/src/Modules/Faura.Infrastructure.Logger/Outputs/Console/LogConsoleExtensions.cs +++ b/src/Modules/Faura.Infrastructure.Logger/Outputs/Console/LogConsoleExtensions.cs @@ -1,4 +1,4 @@ -namespace Faura.Infrastructure.Logger.Outputs.Console; +namespace Faura.Infrastructure.Logger.Outputs.Console; using Microsoft.Extensions.Configuration; using Serilog.Core; @@ -8,7 +8,7 @@ public static class LogConsoleExtensions { public const string BaseLogTemplate = "[{Timestamp:yyyy-MM-dd HH:mm:ss} {Level:u3}] {SourceContext}: {Message:lj}{NewLine}{Exception}"; - public static LoggerConfiguration ConfigureLogConsole(this LoggerConfiguration loggerConfiguration, IConfiguration configuration, List logEnrichers = null) + public static LoggerConfiguration ConfigureLogConsole(this LoggerConfiguration loggerConfiguration, IConfiguration configuration, List? logEnrichers = null) { var consoleOptions = configuration.GetSection(LogConsoleOptions.SectionName).Get() ?? new LogConsoleOptions(); diff --git a/src/Modules/Faura.Infrastructure.Logger/Outputs/Console/LogConsoleOptions.cs b/src/Modules/Faura.Infrastructure.Logger/Outputs/Console/LogConsoleOptions.cs index 33e1ef5..a773ae9 100644 --- a/src/Modules/Faura.Infrastructure.Logger/Outputs/Console/LogConsoleOptions.cs +++ b/src/Modules/Faura.Infrastructure.Logger/Outputs/Console/LogConsoleOptions.cs @@ -1,9 +1,9 @@ -namespace Faura.Infrastructure.Logger.Outputs.Console; +namespace Faura.Infrastructure.Logger.Outputs.Console; public class LogConsoleOptions { public const string SectionName = "Logging:Outputs:Console"; public bool Enable { get; set; } = false; - public string LogTemplate { get; set; } + public string? LogTemplate { get; set; } } diff --git a/src/Modules/Faura.Infrastructure.Logger/Outputs/GrayLog/LogGraylogExtensions.cs b/src/Modules/Faura.Infrastructure.Logger/Outputs/GrayLog/LogGraylogExtensions.cs index cdbd7f1..1d6759d 100644 --- a/src/Modules/Faura.Infrastructure.Logger/Outputs/GrayLog/LogGraylogExtensions.cs +++ b/src/Modules/Faura.Infrastructure.Logger/Outputs/GrayLog/LogGraylogExtensions.cs @@ -1,4 +1,4 @@ -namespace Faura.Infrastructure.Logger.Outputs.GrayLog; +namespace Faura.Infrastructure.Logger.Outputs.GrayLog; using Serilog.Sinks.Graylog; using Serilog; @@ -8,7 +8,7 @@ public static class LogGrayLogExtensions { - public static LoggerConfiguration ConfigureLogGraylog(this LoggerConfiguration loggerConfiguration, IConfiguration configuration, List logEnrichers = null) + public static LoggerConfiguration ConfigureLogGraylog(this LoggerConfiguration loggerConfiguration, IConfiguration configuration, List? logEnrichers = null) { var graylogOptions = configuration.GetSection(LogGraylogOptions.SectionName).Get(); @@ -17,11 +17,11 @@ public static LoggerConfiguration ConfigureLogGraylog(this LoggerConfiguration l var graylogSinkConfig = new GraylogSinkOptions { HostnameOrAddress = graylogOptions.GrayLogHost, - TransportType = GetGraylogTransportTypeFromString(graylogOptions.GrayLogProtocol), - HostnameOverride = graylogOptions.GrayLogHost, + TransportType = GetGraylogTransportTypeFromString(graylogOptions.GrayLogProtocol!), + HostnameOverride = graylogOptions.GrayLogHost!, Port = graylogOptions.GrayLogPort, MaxMessageSizeInUdp = graylogOptions.MaxUdpMessageSize, - Facility = "FauraApp" + Facility = "FauraApp", }; return loggerConfiguration diff --git a/src/Modules/Faura.Infrastructure.Logger/Outputs/GrayLog/LogGraylogOptions.cs b/src/Modules/Faura.Infrastructure.Logger/Outputs/GrayLog/LogGraylogOptions.cs index 6f190ad..2a40857 100644 --- a/src/Modules/Faura.Infrastructure.Logger/Outputs/GrayLog/LogGraylogOptions.cs +++ b/src/Modules/Faura.Infrastructure.Logger/Outputs/GrayLog/LogGraylogOptions.cs @@ -1,12 +1,12 @@ -namespace Faura.Infrastructure.Logger.Outputs.GrayLog; +namespace Faura.Infrastructure.Logger.Outputs.GrayLog; public class LogGraylogOptions { public const string SectionName = "Logging:Outputs:Graylog"; public bool Enable { get; set; } = false; - public string GrayLogHost { get; set; } + public string? GrayLogHost { get; set; } public int GrayLogPort { get; set; } - public string GrayLogProtocol { get; set; } + public string? GrayLogProtocol { get; set; } public int MaxUdpMessageSize { get; set; } } diff --git a/src/Modules/Faura.Infrastructure.Logger/Outputs/Seq/LogSeqExtensions.cs b/src/Modules/Faura.Infrastructure.Logger/Outputs/Seq/LogSeqExtensions.cs index 40ac89b..8eed022 100644 --- a/src/Modules/Faura.Infrastructure.Logger/Outputs/Seq/LogSeqExtensions.cs +++ b/src/Modules/Faura.Infrastructure.Logger/Outputs/Seq/LogSeqExtensions.cs @@ -1,4 +1,4 @@ -namespace Faura.Infrastructure.Logger.Outputs.GrayLog; +namespace Faura.Infrastructure.Logger.Outputs.Seq; using Serilog; using Microsoft.Extensions.Configuration; @@ -6,12 +6,12 @@ public static class LogSeqExtensions { - public static LoggerConfiguration ConfigureLogSeq(this LoggerConfiguration loggerConfiguration, IConfiguration configuration, List logEnrichers = null) + public static LoggerConfiguration ConfigureLogSeq(this LoggerConfiguration loggerConfiguration, IConfiguration configuration, List? logEnrichers = null) { var seqOptions = configuration.GetSection(LogSeqOptions.SectionName).Get() ?? new LogSeqOptions(); if (!seqOptions.Enable) return loggerConfiguration; return loggerConfiguration - .WriteTo.Seq(serverUrl: seqOptions.ServerUrl, apiKey: seqOptions.ApiKey); + .WriteTo.Seq(serverUrl: seqOptions.ServerUrl!, apiKey: seqOptions.ApiKey); } } diff --git a/src/Modules/Faura.Infrastructure.Logger/Outputs/Seq/LogSeqOptions.cs b/src/Modules/Faura.Infrastructure.Logger/Outputs/Seq/LogSeqOptions.cs index fb908d2..95cc0d2 100644 --- a/src/Modules/Faura.Infrastructure.Logger/Outputs/Seq/LogSeqOptions.cs +++ b/src/Modules/Faura.Infrastructure.Logger/Outputs/Seq/LogSeqOptions.cs @@ -1,12 +1,11 @@ -namespace Faura.Infrastructure.Logger.Outputs.GrayLog; +namespace Faura.Infrastructure.Logger.Outputs.Seq; public class LogSeqOptions { public const string SectionName = "Logging:Outputs:Seq"; public bool Enable { get; set; } = false; - public string ServerUrl { get; set; } - public string ApplicationName { get; set; } - public string ApiKey { get; set; } - + public string? ServerUrl { get; set; } + public string? ApplicationName { get; set; } + public string? ApiKey { get; set; } } diff --git a/src/Modules/Faura.Infrastructure.Logger/Outputs/SqLiteDb/LogSqLiteDbExtensions.cs b/src/Modules/Faura.Infrastructure.Logger/Outputs/SqLiteDb/LogSqLiteDbExtensions.cs index 72d494c..98cd289 100644 --- a/src/Modules/Faura.Infrastructure.Logger/Outputs/SqLiteDb/LogSqLiteDbExtensions.cs +++ b/src/Modules/Faura.Infrastructure.Logger/Outputs/SqLiteDb/LogSqLiteDbExtensions.cs @@ -1,4 +1,4 @@ -namespace Faura.Infrastructure.Logger.Outputs.SqLiteDb; +namespace Faura.Infrastructure.Logger.Outputs.SqLiteDb; using Faura.Infrastructure.Common.Utils; using Microsoft.Extensions.Configuration; @@ -15,7 +15,7 @@ public static LoggerConfiguration ConfigureLogSqLiteDb(this LoggerConfiguration if (!sqLiteDbOptions.Enable) return loggerConfiguration; return loggerConfiguration - .WriteTo.SQLite(GetSqliteDbLogFilePath(sqLiteDbOptions.LogSqLiteFile, DefaultLogSqLiteFileName)); + .WriteTo.SQLite(GetSqliteDbLogFilePath(sqLiteDbOptions.LogSqLiteFile!, DefaultLogSqLiteFileName)); } internal static string GetSqliteDbLogFilePath(string file, string defaultFileName) diff --git a/src/Modules/Faura.Infrastructure.Logger/Outputs/SqLiteDb/LogSqLiteDbOptions.cs b/src/Modules/Faura.Infrastructure.Logger/Outputs/SqLiteDb/LogSqLiteDbOptions.cs index 2faf4fc..fc09a02 100644 --- a/src/Modules/Faura.Infrastructure.Logger/Outputs/SqLiteDb/LogSqLiteDbOptions.cs +++ b/src/Modules/Faura.Infrastructure.Logger/Outputs/SqLiteDb/LogSqLiteDbOptions.cs @@ -1,9 +1,9 @@ -namespace Faura.Infrastructure.Logger.Outputs.SqLiteDb; +namespace Faura.Infrastructure.Logger.Outputs.SqLiteDb; public class LogSqLiteDbOptions { public const string SectionName = "Logging:Outputs:SqLiteDb"; public bool Enable { get; set; } = false; - public string LogSqLiteFile { get; set; } + public string? LogSqLiteFile { get; set; } } diff --git a/src/Modules/Faura.Infrastructure.Result/Faura.Infrastructure.Result.csproj b/src/Modules/Faura.Infrastructure.Result/Faura.Infrastructure.Result.csproj index b6d782e..0b90746 100644 --- a/src/Modules/Faura.Infrastructure.Result/Faura.Infrastructure.Result.csproj +++ b/src/Modules/Faura.Infrastructure.Result/Faura.Infrastructure.Result.csproj @@ -16,7 +16,6 @@ - diff --git a/src/Modules/Faura.Infrastructure.Result/FauraError.cs b/src/Modules/Faura.Infrastructure.Result/FauraError.cs index bc58773..9e06525 100644 --- a/src/Modules/Faura.Infrastructure.Result/FauraError.cs +++ b/src/Modules/Faura.Infrastructure.Result/FauraError.cs @@ -1,20 +1,12 @@ -namespace Faura.Infrastructure.Result; +namespace Faura.Infrastructure.Result; using System.Net; -public class FauraError +public class FauraError(string code, string message, HttpStatusCode? httpStatus = null) { - public string Code { get; init; } + public string Code { get; init; } = code; - public string Message { get; init; } + public string Message { get; init; } = message; - public HttpStatusCode HttpStatus { get; private set; } - - public FauraError(string code, string message, HttpStatusCode? httpStatus = null) - { - Code = code; - Message = message; - HttpStatus = httpStatus ?? HttpStatusCode.InternalServerError; - } - -} \ No newline at end of file + public HttpStatusCode HttpStatus { get; private set; } = httpStatus ?? HttpStatusCode.InternalServerError; +} diff --git a/src/Modules/Faura.Infrastructure.Result/FauraResult.cs b/src/Modules/Faura.Infrastructure.Result/FauraResult.cs index 591825b..7f9ad6d 100644 --- a/src/Modules/Faura.Infrastructure.Result/FauraResult.cs +++ b/src/Modules/Faura.Infrastructure.Result/FauraResult.cs @@ -1,25 +1,24 @@ -namespace Faura.Infrastructure.Result; +namespace Faura.Infrastructure.Result; -using Faura.Infrastructure.Result.Helpers; -using Microsoft.AspNetCore.Mvc; using System.Net; using System.Text.Json.Serialization; +using Microsoft.AspNetCore.Mvc; +using Faura.Infrastructure.Result.Helpers; +using System.Collections.Generic; +using System; +using System.Linq; public class FauraResult : IFauraResult { - protected FauraResult() { } + public FauraResult(T value) => Data = value; - public FauraResult(T value) + protected FauraResult() { - Data = value; } - public static implicit operator T(FauraResult result) => result.Data; - public static implicit operator FauraResult(T value) => new FauraResult(value); - [JsonInclude] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - public T Data { get; init; } + public T? Data { get; init; } [JsonIgnore] public Type ValueType => typeof(T); @@ -31,78 +30,52 @@ public FauraResult(T value) [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public IEnumerable Errors { get; protected set; } = []; - public object GetData() - { - return Data; - } + public static implicit operator T(FauraResult result) => result.Data!; - public static FauraResult Success(T value) - { - return new FauraResult(value); - } + public static implicit operator FauraResult(T value) => new(value); - public static FauraResult Error(FauraError fauraError) - { - return new FauraResult() { Errors = [fauraError] }; - } + public static FauraResult Success(T value) => new (value); - public static FauraResult Error(IEnumerable fauraErrors = null) + public static FauraResult Error(FauraError fauraError) => new() { - return new FauraResult() - { - Errors = fauraErrors - }; - } + Errors = [fauraError], + }; - public void AddError(FauraError error) + public static FauraResult Error(IEnumerable? fauraErrors = null) => new() { - IEnumerable errors; - if (Errors != null) - { - errors = Errors.Append(error); - } - else - { - errors = []; - } + Errors = fauraErrors ?? [], + }; - Errors = errors; - } + public object? GetData() => Data; + + public void AddError(FauraError error) + => Errors = Errors.Append(error); public IEnumerable GetErrors() - { - return Errors; - } + => Errors; public bool ReturnedError(FauraError errorCode) - { - return Errors?.Any((myError) => myError.Code == $"{errorCode}") ?? false; - } + => Errors?.Any(e => e.Code == errorCode.Code) ?? false; public bool ReturnedError(IEnumerable errorCodes) - { - return errorCodes.Any((errorCode) => Errors?.Any((myError) => myError.Code == $"{errorCode}") ?? false); - } + => errorCodes.Any(code => Errors?.Any(e => e.Code == code.Code) ?? false); public IActionResult BuildResult(HttpStatusCode httpStatusCode = HttpStatusCode.OK) { if (IsSuccess) { - T dataAsT = Data; - if (dataAsT == null) - { + if (EqualityComparer.Default.Equals(Data!, default!)) return new NoContentResult(); - } - return new OkObjectResult(dataAsT) + return new OkObjectResult(Data) { StatusCode = (int)httpStatusCode, }; - } + return new ObjectResult(Errors) { StatusCode = Errors.ToHigherHttpStatusCode(), }; } -} \ No newline at end of file +} diff --git a/src/Modules/Faura.Infrastructure.Result/Helpers/FauraErrorHelper.cs b/src/Modules/Faura.Infrastructure.Result/Helpers/FauraErrorHelper.cs index 4bb2ede..998d99c 100644 --- a/src/Modules/Faura.Infrastructure.Result/Helpers/FauraErrorHelper.cs +++ b/src/Modules/Faura.Infrastructure.Result/Helpers/FauraErrorHelper.cs @@ -1,6 +1,4 @@ -namespace Faura.Infrastructure.Result.Helpers; - -using Faura.Infrastructure.Result; +namespace Faura.Infrastructure.Result.Helpers; public static class FauraErrorHelper { diff --git a/src/Modules/Faura.Infrastructure.Result/IFauraResult.cs b/src/Modules/Faura.Infrastructure.Result/IFauraResult.cs index ccaad13..b57bad8 100644 --- a/src/Modules/Faura.Infrastructure.Result/IFauraResult.cs +++ b/src/Modules/Faura.Infrastructure.Result/IFauraResult.cs @@ -1,7 +1,7 @@ -namespace Faura.Infrastructure.Result; +namespace Faura.Infrastructure.Result; public interface IFauraResult { IEnumerable Errors { get; } Type ValueType { get; } - object GetData(); + object? GetData(); } diff --git a/src/Modules/Faura.Infrastructure.UnitOfWork/Common/DatabaseConfiguration.cs b/src/Modules/Faura.Infrastructure.UnitOfWork/Common/DatabaseConfiguration.cs index 4f9575c..c1a7eac 100644 --- a/src/Modules/Faura.Infrastructure.UnitOfWork/Common/DatabaseConfiguration.cs +++ b/src/Modules/Faura.Infrastructure.UnitOfWork/Common/DatabaseConfiguration.cs @@ -1,4 +1,4 @@ -namespace Faura.Infrastructure.UnitOfWork.Common; +namespace Faura.Infrastructure.UnitOfWork.Common; using Faura.Infrastructure.UnitOfWork.Enums; using Microsoft.EntityFrameworkCore; @@ -17,7 +17,8 @@ public static void ConfigureDatabase( this IServiceCollection services, string connectionString, DatabaseType databaseType, - ServiceLifetime serviceLifetime = ServiceLifetime.Scoped) where TContext : DbContext + ServiceLifetime serviceLifetime = ServiceLifetime.Scoped) + where TContext : DbContext { if (string.IsNullOrWhiteSpace(connectionString)) throw new ArgumentException("Connection string cannot be null or empty.", nameof(connectionString)); @@ -31,7 +32,8 @@ public static async Task ConfigureDatabase( string connectionStringName, DatabaseType databaseType, ServiceLifetime serviceLifetime = ServiceLifetime.Scoped, - bool runMigrations = false) where TContext : DbContext + bool runMigrations = false) + where TContext : DbContext { var connectionString = configuration.GetConnectionString(connectionStringName) ?? throw new ArgumentException($"Connection string '{connectionStringName}' not found or is empty."); @@ -58,7 +60,8 @@ private static void ConfigureDatabaseOptions( break; case DatabaseType.MySql: - options.UseMySql(ServerVersion.AutoDetect(connectionString), + options.UseMySql( + ServerVersion.AutoDetect(connectionString), mysqlOptions => mysqlOptions.EnableRetryOnFailure(MaxRetryCount, TimeSpan.FromSeconds(MaxRetryDelay), null)); break; @@ -75,7 +78,8 @@ private static void ConfigureDatabaseOptions( } } - private static async Task ApplyMigrations(IServiceCollection services) where TContext : DbContext + private static async Task ApplyMigrations(IServiceCollection services) + where TContext : DbContext { using var serviceProvider = services.BuildServiceProvider(); var logger = serviceProvider.GetService(); @@ -83,7 +87,8 @@ private static async Task ApplyMigrations(IServiceCollection services) if (context == null) { - logger?.LogError($"Unable to resolve {typeof(TContext).FullName}. Database migration will not be performed."); + string message = $"Unable to resolve {typeof(TContext).FullName}. Database migration will not be performed."; + logger?.LogError(message); return; } @@ -93,8 +98,10 @@ private static async Task ApplyMigrations(IServiceCollection services) } catch (Exception ex) { - logger?.LogError(ex, "An error occurred while migrating the database."); - throw; + string contextName = typeof(TContext).FullName ?? "UnknownContext"; + string errorMessage = $"An error occurred while migrating the database for context {contextName}. See inner exception for details."; + logger?.LogError(ex, errorMessage); + throw new InvalidOperationException(errorMessage, ex); } } -} \ No newline at end of file +} diff --git a/src/Modules/Faura.Infrastructure.UnitOfWork/Enums/SortDirection.cs b/src/Modules/Faura.Infrastructure.UnitOfWork/Enums/SortDirection.cs index c0ee16d..6c4c552 100644 --- a/src/Modules/Faura.Infrastructure.UnitOfWork/Enums/SortDirection.cs +++ b/src/Modules/Faura.Infrastructure.UnitOfWork/Enums/SortDirection.cs @@ -1,7 +1,7 @@ -namespace Faura.Infrastructure.UnitOfWork.Enums; +namespace Faura.Infrastructure.UnitOfWork.Enums; /// -/// Direction for sorting operations +/// Direction for sorting operations. /// public enum SortDirection { @@ -13,5 +13,5 @@ public enum SortDirection /// /// Sort in descending order /// - Descending -} \ No newline at end of file + Descending, +} diff --git a/src/Modules/Faura.Infrastructure.UnitOfWork/Exceptions/NullContextException.cs b/src/Modules/Faura.Infrastructure.UnitOfWork/Exceptions/NullContextException.cs index e3ca4fe..76293dd 100644 --- a/src/Modules/Faura.Infrastructure.UnitOfWork/Exceptions/NullContextException.cs +++ b/src/Modules/Faura.Infrastructure.UnitOfWork/Exceptions/NullContextException.cs @@ -1,24 +1,18 @@ -namespace Faura.Infrastructure.UnitOfWork.Exceptions; +namespace Faura.Infrastructure.UnitOfWork.Exceptions; -using System.Runtime.Serialization; - -[Serializable] public class NullContextException : Exception { - public NullContextException() : base() - { - } - - public NullContextException(string message) : base(message) + public NullContextException() { } - public NullContextException(string message, Exception innerException) : base(message, innerException) + public NullContextException(string message) + : base(message) { } - protected NullContextException(SerializationInfo serializationInfo, StreamingContext streamingContext) - : base(serializationInfo, streamingContext) + public NullContextException(string message, Exception innerException) + : base(message, innerException) { } -} \ No newline at end of file +} diff --git a/src/Modules/Faura.Infrastructure.UnitOfWork/Exceptions/RepositoryExceptions.cs b/src/Modules/Faura.Infrastructure.UnitOfWork/Exceptions/RepositoryExceptions.cs index 96adabb..26386ac 100644 --- a/src/Modules/Faura.Infrastructure.UnitOfWork/Exceptions/RepositoryExceptions.cs +++ b/src/Modules/Faura.Infrastructure.UnitOfWork/Exceptions/RepositoryExceptions.cs @@ -1,15 +1,21 @@ -namespace Faura.Infrastructure.UnitOfWork.Exceptions; +namespace Faura.Infrastructure.UnitOfWork.Exceptions; /// -/// Base exception for repository-related errors +/// Base exception for repository-related errors. /// public abstract class RepositoryException : Exception { - protected RepositoryException(string message) : base(message) + protected RepositoryException() { } - protected RepositoryException(string message, Exception innerException) : base(message, innerException) + protected RepositoryException(string message) + : base(message) { } -} \ No newline at end of file + + protected RepositoryException(string message, Exception innerException) + : base(message, innerException) + { + } +} diff --git a/src/Modules/Faura.Infrastructure.UnitOfWork/Exceptions/RepositoryOperationException.cs b/src/Modules/Faura.Infrastructure.UnitOfWork/Exceptions/RepositoryOperationException.cs index 816f198..0f9313c 100644 --- a/src/Modules/Faura.Infrastructure.UnitOfWork/Exceptions/RepositoryOperationException.cs +++ b/src/Modules/Faura.Infrastructure.UnitOfWork/Exceptions/RepositoryOperationException.cs @@ -1,15 +1,21 @@ -namespace Faura.Infrastructure.UnitOfWork.Exceptions; +namespace Faura.Infrastructure.UnitOfWork.Exceptions; /// /// Exception for errors during repository operations (create, update, delete) /// public class RepositoryOperationException : RepositoryException { - public RepositoryOperationException(string message) : base(message) + public RepositoryOperationException() { } - public RepositoryOperationException(string message, Exception innerException) : base(message, innerException) + public RepositoryOperationException(string message) + : base(message) + { + } + + public RepositoryOperationException(string message, Exception innerException) + : base(message, innerException) { } } diff --git a/src/Modules/Faura.Infrastructure.UnitOfWork/Exceptions/RepositoryQueryException.cs b/src/Modules/Faura.Infrastructure.UnitOfWork/Exceptions/RepositoryQueryException.cs index 81dabe5..51269ba 100644 --- a/src/Modules/Faura.Infrastructure.UnitOfWork/Exceptions/RepositoryQueryException.cs +++ b/src/Modules/Faura.Infrastructure.UnitOfWork/Exceptions/RepositoryQueryException.cs @@ -1,15 +1,21 @@ -namespace Faura.Infrastructure.UnitOfWork.Exceptions; +namespace Faura.Infrastructure.UnitOfWork.Exceptions; /// -/// Exception for errors during repository queries +/// Exception for errors during repository queries. /// public class RepositoryQueryException : RepositoryException { - public RepositoryQueryException(string message) : base(message) + public RepositoryQueryException() { } - public RepositoryQueryException(string message, Exception innerException) : base(message, innerException) + public RepositoryQueryException(string message) + : base(message) + { + } + + public RepositoryQueryException(string message, Exception innerException) + : base(message, innerException) { } } diff --git a/src/Modules/Faura.Infrastructure.UnitOfWork/Exceptions/TransactionNullException.cs b/src/Modules/Faura.Infrastructure.UnitOfWork/Exceptions/TransactionNullException.cs index d7e2009..6885a3b 100644 --- a/src/Modules/Faura.Infrastructure.UnitOfWork/Exceptions/TransactionNullException.cs +++ b/src/Modules/Faura.Infrastructure.UnitOfWork/Exceptions/TransactionNullException.cs @@ -1,24 +1,18 @@ -namespace Faura.Infrastructure.UnitOfWork.Exceptions; +namespace Faura.Infrastructure.UnitOfWork.Exceptions; -using System.Runtime.Serialization; - -[Serializable] public class NullTransactionException : Exception { - public NullTransactionException() : base() - { - } - - public NullTransactionException(string message) : base(message) + public NullTransactionException() { } - public NullTransactionException(string message, Exception innerException) : base(message, innerException) + public NullTransactionException(string message) + : base(message) { } - protected NullTransactionException(SerializationInfo serializationInfo, StreamingContext streamingContext) - : base(serializationInfo, streamingContext) + public NullTransactionException(string message, Exception innerException) + : base(message, innerException) { } -} \ No newline at end of file +} diff --git a/src/Modules/Faura.Infrastructure.UnitOfWork/Models/PagedResult.cs b/src/Modules/Faura.Infrastructure.UnitOfWork/Models/PagedResult.cs index 8ca1473..9a76443 100644 --- a/src/Modules/Faura.Infrastructure.UnitOfWork/Models/PagedResult.cs +++ b/src/Modules/Faura.Infrastructure.UnitOfWork/Models/PagedResult.cs @@ -1,42 +1,43 @@ -namespace Faura.Infrastructure.UnitOfWork.Models; +namespace Faura.Infrastructure.UnitOfWork.Models; /// -/// Represents a paginated result set +/// Represents a paginated result set. /// -public class PagedResult where T : class +public class PagedResult + where T : class { /// - /// Items in the current page + /// Gets or sets items in the current page. /// public IList Items { get; set; } = new List(); /// - /// Current page number + /// Gets or sets current page number. /// public int CurrentPage { get; set; } /// - /// Number of items per page + /// Gets or sets number of items per page. /// public int PageSize { get; set; } /// - /// Total number of items across all pages + /// Gets or sets total number of items across all pages. /// public long TotalCount { get; set; } /// - /// Total number of pages + /// Gets or sets total number of pages. /// public int TotalPages { get; set; } /// - /// Whether a previous page exists + /// Gets or sets a value indicating whether whether a previous page exists. /// public bool HasPreviousPage { get; set; } /// - /// Whether a next page exists + /// Gets or sets a value indicating whether whether a next page exists. /// public bool HasNextPage { get; set; } -} \ No newline at end of file +} diff --git a/src/Modules/Faura.Infrastructure.UnitOfWork/Projectors/IProjector.cs b/src/Modules/Faura.Infrastructure.UnitOfWork/Projectors/IProjector.cs index 6a32df6..13d51ce 100644 --- a/src/Modules/Faura.Infrastructure.UnitOfWork/Projectors/IProjector.cs +++ b/src/Modules/Faura.Infrastructure.UnitOfWork/Projectors/IProjector.cs @@ -1,17 +1,18 @@ namespace Faura.Infrastructure.UnitOfWork.Projectors; -public interface IProjector where TEntity : class +public interface IProjector + where TEntity : class { /// - /// Gets a projection from the entity + /// Gets a projection from the entity. /// - /// The result type of the projection - /// The projection function - /// Optional page number for pagination - /// Optional page size for pagination - /// A task that represents the asynchronous operation, containing the projected results + /// The result type of the projection. + /// The projection function. + /// Optional page number for pagination. + /// Optional page size for pagination. + /// A task that represents the asynchronous operation, containing the projected results. Task> GetProjectionAsync( Func, IQueryable> projection, int? page = null, int? pageSize = null); -} \ No newline at end of file +} diff --git a/src/Modules/Faura.Infrastructure.UnitOfWork/Projectors/Projector.cs b/src/Modules/Faura.Infrastructure.UnitOfWork/Projectors/Projector.cs index 23ccead..e09f4d8 100644 --- a/src/Modules/Faura.Infrastructure.UnitOfWork/Projectors/Projector.cs +++ b/src/Modules/Faura.Infrastructure.UnitOfWork/Projectors/Projector.cs @@ -1,16 +1,14 @@ namespace Faura.Infrastructure.UnitOfWork.Projectors; -using System.Linq.Expressions; using Microsoft.EntityFrameworkCore; -public class Projector : IProjector where TEntity : class +public class Projector : IProjector + where TEntity : class { private readonly DbContext _context; public Projector(DbContext context) - { - _context = context ?? throw new ArgumentNullException(nameof(context)); - } + => _context = context ?? throw new ArgumentNullException(nameof(context)); public async Task> GetProjectionAsync( Func, IQueryable> projection, @@ -28,4 +26,4 @@ public async Task> GetProjectionAsync( var projectionQuery = projection(query); return await projectionQuery.ToListAsync(); } -} \ No newline at end of file +} diff --git a/src/Modules/Faura.Infrastructure.UnitOfWork/Repositories/EntityRepository.cs b/src/Modules/Faura.Infrastructure.UnitOfWork/Repositories/EntityRepository.cs index df2593c..bef44fe 100644 --- a/src/Modules/Faura.Infrastructure.UnitOfWork/Repositories/EntityRepository.cs +++ b/src/Modules/Faura.Infrastructure.UnitOfWork/Repositories/EntityRepository.cs @@ -1,29 +1,29 @@ -namespace Faura.Infrastructure.UnitOfWork.Repositories; +namespace Faura.Infrastructure.UnitOfWork.Repositories; using Faura.Infrastructure.UnitOfWork.Enums; using Faura.Infrastructure.UnitOfWork.Exceptions; using Faura.Infrastructure.UnitOfWork.Models; -using Microsoft.Data.SqlClient; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; using System.Linq.Expressions; /// -/// Generic repository implementation for data access operations +/// Generic repository implementation for data access operations. /// -/// The entity type this repository works with -public class EntityRepository : IEntityRepository where TEntity : class +/// The entity type this repository works with. +public class EntityRepository : IEntityRepository + where TEntity : class { private readonly DbContext _dbContext; private readonly ILogger> _logger; private readonly bool _enableTracking; /// - /// Creates a new instance of the repository + /// Initializes a new instance of the class. /// - /// Database context to use for operations - /// Logger for capturing operation information - /// Whether to enable entity tracking + /// Database context to use for operations. + /// Logger for capturing operation information. + /// Whether to enable entity tracking. public EntityRepository( DbContext dbContext, ILogger> logger, @@ -37,7 +37,7 @@ public EntityRepository( } /// - /// Base queryable for this entity type + /// Gets base queryable for this entity type. /// private IQueryable BaseQuery => GetBaseQuery(); @@ -212,35 +212,15 @@ public async Task> DeleteRangeAsync(IEnumerable en } /// - public Task GetFirstOrDefaultAsync(Expression> predicate = null) - { - try - { - return ApplyPredicate(predicate).FirstOrDefaultAsync(); - } - catch (Exception ex) - { - _logger.LogError(ex, "Error retrieving first entity of type {EntityType}", typeof(TEntity).Name); - throw new RepositoryQueryException($"Failed to retrieve first entity: {ex.Message}", ex); - } - } + public Task GetFirstOrDefaultAsync(Expression>? predicate = null) + => ApplyPredicate(predicate).FirstOrDefaultAsync(); /// - public Task GetLastOrDefaultAsync(Expression> predicate = null) - { - try - { - return ApplyPredicate(predicate).LastOrDefaultAsync(); - } - catch (Exception ex) - { - _logger.LogError(ex, "Error retrieving last entity of type {EntityType}", typeof(TEntity).Name); - throw new RepositoryQueryException($"Failed to retrieve last entity: {ex.Message}", ex); - } - } + public Task GetLastOrDefaultAsync(Expression>? predicate = null) + => ApplyPredicate(predicate).LastOrDefaultAsync(); /// - public async Task> GetAsync(Expression> predicate = null) + public async Task> GetAsync(Expression>? predicate = null) { try { @@ -274,7 +254,7 @@ public async Task> GetSortedAsync( /// public async Task> GetWithIncludesAsync( IEnumerable includes, - Expression> predicate = null) + Expression>? predicate = null) { try { @@ -292,7 +272,7 @@ public async Task> GetWithIncludesAsync( public async Task> GetPagedAsync( int page, int pageSize, - Expression> predicate = null) + Expression>? predicate = null) { try { @@ -310,7 +290,7 @@ public async Task> GetPagedWithIncludesAsync( int page, int pageSize, IEnumerable includes, - Expression> predicate = null) + Expression>? predicate = null) { try { @@ -345,7 +325,7 @@ public async Task> GetPagedSortedAsync( } /// - public Task CountAsync(Expression> predicate = null) + public Task CountAsync(Expression>? predicate = null) { try { @@ -360,12 +340,23 @@ public Task CountAsync(Expression> predicate = null) } } + private static IQueryable ApplySorting( + IQueryable query, + Expression> orderBy, + SortDirection sortDirection) + => sortDirection == SortDirection.Ascending + ? query.OrderBy(orderBy) + : query.OrderByDescending(orderBy); + + private static IQueryable ApplyIncludes( + IQueryable query, + IEnumerable includes) + => includes.Aggregate(query, (current, includePath) => current.Include(includePath)); + private IQueryable GetBaseQuery() - { - return _enableTracking + => _enableTracking ? _dbContext.Set() : _dbContext.Set().AsNoTracking(); - } private void ConfigureContextBehavior() { @@ -376,27 +367,8 @@ private void ConfigureContextBehavior() : QueryTrackingBehavior.NoTracking; } - private IQueryable ApplyPredicate(Expression> predicate) - { - return predicate != null ? BaseQuery.Where(predicate) : BaseQuery; - } - - private IQueryable ApplySorting( - IQueryable query, - Expression> orderBy, - SortDirection sortDirection) - { - return sortDirection == SortDirection.Ascending - ? query.OrderBy(orderBy) - : query.OrderByDescending(orderBy); - } - - private IQueryable ApplyIncludes( - IQueryable query, - IEnumerable includes) - { - return includes.Aggregate(query, (current, includePath) => current.Include(includePath)); - } + private IQueryable ApplyPredicate(Expression>? predicate) + => predicate != null ? BaseQuery.Where(predicate) : BaseQuery; private async Task> CreatePagedResultAsync( int page, @@ -411,7 +383,7 @@ private async Task> CreatePagedResultAsync( { CurrentPage = page, PageSize = pageSize, - TotalCount = await query.CountAsync() + TotalCount = await query.CountAsync(), }; var skip = (page - 1) * pageSize; @@ -422,15 +394,4 @@ private async Task> CreatePagedResultAsync( return result; } - - private (string Query, object[] ParameterValues) BuildStoredProcedureCommand( - string procedureName, - SqlParameter[] parameters) - { - var paramList = parameters.ToList(); - var paramPlaceholders = string.Join(", ", paramList.Select((p, i) => $"@p{i}")); - var paramValues = paramList.Select(p => p.Value).ToArray(); - - return ($"EXEC {procedureName} {paramPlaceholders}", paramValues); - } -} \ No newline at end of file +} diff --git a/src/Modules/Faura.Infrastructure.UnitOfWork/Repositories/IEntityRepository.cs b/src/Modules/Faura.Infrastructure.UnitOfWork/Repositories/IEntityRepository.cs index afb518d..0012480 100644 --- a/src/Modules/Faura.Infrastructure.UnitOfWork/Repositories/IEntityRepository.cs +++ b/src/Modules/Faura.Infrastructure.UnitOfWork/Repositories/IEntityRepository.cs @@ -1,151 +1,145 @@ -namespace Faura.Infrastructure.UnitOfWork.Repositories; +namespace Faura.Infrastructure.UnitOfWork.Repositories; using Faura.Infrastructure.UnitOfWork.Enums; using Faura.Infrastructure.UnitOfWork.Models; using System.Linq.Expressions; /// -/// Repository interface for entity operations +/// Repository interface for entity operations. /// -/// Entity type -public interface IEntityRepository where TEntity : class +/// Entity type. +public interface IEntityRepository + where TEntity : class { /// - /// Creates a new entity + /// Creates a new entity. /// - /// Entity to create - /// Save options - /// Created entity + /// Entity to create. + /// Created entity. Task CreateAsync(TEntity entity, bool detach = true, bool autoSaveChanges = true); /// - /// Creates multiple entities + /// Creates multiple entities. /// - /// Entities to create - /// Save options - /// Created entities + /// Entities to create. + /// Created entities. Task> CreateRangeAsync(IEnumerable entities, bool autoSaveChanges = true); /// - /// Updates an existing entity + /// Updates an existing entity. /// - /// Entity to update - /// Save options - /// Updated entity + /// Entity to update. + /// Updated entity. Task UpdateAsync(TEntity entity, bool detach = true, bool autoSaveChanges = true); /// - /// Updates multiple entities + /// Updates multiple entities. /// - /// Entities to update - /// Save options - /// Updated entities + /// Entities to update. + /// Updated entities. Task> UpdateRangeAsync(IEnumerable entities, bool autoSaveChanges = true); /// - /// Deletes an entity + /// Deletes an entity. /// - /// Entity to delete - /// Save options - /// Deleted entity + /// Entity to delete. + /// Deleted entity. Task DeleteAsync(TEntity entity, bool detach = true, bool autoSaveChanges = true); /// - /// Deletes entities matching a predicate + /// Deletes entities matching a predicate. /// - /// Filter predicate - /// Save options - /// True if entities were deleted + /// Filter predicate. + /// True if entities were deleted. Task DeleteByPredicateAsync(Expression> predicate, bool autoSaveChanges = true); /// - /// Deletes multiple entities + /// Deletes multiple entities. /// - /// Entities to delete - /// Save options - /// Deleted entities + /// Entities to delete. + /// Deleted entities. Task> DeleteRangeAsync(IEnumerable entities, bool autoSaveChanges = true); /// - /// Gets the first entity matching the predicate or default if none + /// Gets the first entity matching the predicate or default if none. /// - /// Filter predicate - /// First matching entity or default - Task GetFirstOrDefaultAsync(Expression> predicate = null); + /// Filter predicate. + /// First matching entity or default. + Task GetFirstOrDefaultAsync(Expression>? predicate = null); /// - /// Gets the last entity matching the predicate or default if none + /// Gets the last entity matching the predicate or default if none. /// - /// Filter predicate - /// Last matching entity or default - Task GetLastOrDefaultAsync(Expression> predicate = null); + /// Filter predicate. + /// Last matching entity or default. + Task GetLastOrDefaultAsync(Expression>? predicate = null); /// - /// Gets all entities matching the predicate + /// Gets all entities matching the predicate. /// - /// Filter predicate - /// List of matching entities - Task> GetAsync(Expression> predicate = null); + /// Filter predicate. + /// List of matching entities. + Task> GetAsync(Expression>? predicate = null); /// - /// Gets sorted entities matching the predicate + /// Gets sorted entities matching the predicate. /// - /// Type of the sort key - /// Filter predicate - /// Property to sort by - /// Sort direction - /// Sorted list of matching entities + /// Type of the sort key. + /// Filter predicat. + /// Property to sort by. + /// Sort direction. + /// Sorted list of matching entities. Task> GetSortedAsync( Expression> predicate, Expression> orderBy, SortDirection sortDirection = SortDirection.Ascending); /// - /// Gets entities with included related entities + /// Gets entities with included related entities. /// - /// Properties to include - /// Filter predicate - /// List of entities with included properties + /// Properties to include. + /// Filter predicate. + /// List of entities with included properties. Task> GetWithIncludesAsync( IEnumerable includes, - Expression> predicate = null); + Expression>? predicate = null); /// - /// Gets a page of entities matching the predicate + /// Gets a page of entities matching the predicate. /// - /// Page number (1-based) - /// Page size - /// Filter predicate - /// Paged result + /// Page number (1-based). + /// Page size. + /// Filter predicate. + /// Paged result. Task> GetPagedAsync( int page, int pageSize, - Expression> predicate = null); + Expression>? predicate = null); /// - /// Gets a page of entities with included related entities + /// Gets a page of entities with included related entities. /// - /// Page number (1-based) - /// Page size - /// Properties to include - /// Filter predicate - /// Paged result with included properties + /// Page number (1-based). + /// Page size. + /// Properties to include. + /// Filter predicate. + /// Paged result with included properties. Task> GetPagedWithIncludesAsync( int page, int pageSize, IEnumerable includes, - Expression> predicate = null); + Expression>? predicate = null); /// - /// Gets a sorted page of entities matching the predicate + /// Gets a sorted page of entities matching the predicate. /// - /// Type of the sort key - /// Page number (1-based) - /// Page size - /// Filter predicate - /// Property to sort by - /// Sort direction - /// Sorted paged result + /// Type of the sort key. + /// Page number (1-based). + /// Page size. + /// Filter predicate. + /// Property to sort by. + /// Sort direction. + /// Sorted paged result. Task> GetPagedSortedAsync( int page, int pageSize, @@ -154,9 +148,9 @@ Task> GetPagedSortedAsync( SortDirection sortDirection = SortDirection.Ascending); /// - /// Counts entities matching the predicate + /// Counts entities matching the predicate. /// - /// Filter predicate - /// Number of matching entities - Task CountAsync(Expression> predicate = null); -} \ No newline at end of file + /// Filter predicate. + /// Number of matching entities. + Task CountAsync(Expression>? predicate = null); +} diff --git a/src/Modules/Faura.Infrastructure.UnitOfWork/Repositories/IRawSqlRepository.cs b/src/Modules/Faura.Infrastructure.UnitOfWork/Repositories/IRawSqlRepository.cs index c6e370e..57eac99 100644 --- a/src/Modules/Faura.Infrastructure.UnitOfWork/Repositories/IRawSqlRepository.cs +++ b/src/Modules/Faura.Infrastructure.UnitOfWork/Repositories/IRawSqlRepository.cs @@ -1,16 +1,13 @@ -namespace Faura.Infrastructure.UnitOfWork.Repositories; +namespace Faura.Infrastructure.UnitOfWork.Repositories; using System.Data; -public interface IRawSqlRepository where TModel : class +public interface IRawSqlRepository + where TModel : class { /// /// This method executes a SQL query against the database using the Dapper library. /// - /// - /// - /// - /// /// /// It returns an IEnumerable of the provided object containing the results of the query. /// @@ -19,10 +16,6 @@ public interface IRawSqlRepository where TModel : class /// /// This method executes a SQL query against the database using the Dapper library. /// - /// - /// - /// - /// /// /// Returns the first result, or null if the query returns no results. /// @@ -31,12 +24,8 @@ public interface IRawSqlRepository where TModel : class /// /// This method executes a SQL query against the database using the Dapper library. /// - /// - /// - /// - /// /// /// It returns the number of affected rows. /// Task ExecuteAsync(string sql, object? parameters = null, IDbTransaction? transaction = null); -} \ No newline at end of file +} diff --git a/src/Modules/Faura.Infrastructure.UnitOfWork/Repositories/RawSqlRepository.cs b/src/Modules/Faura.Infrastructure.UnitOfWork/Repositories/RawSqlRepository.cs index ef7983d..2708613 100644 --- a/src/Modules/Faura.Infrastructure.UnitOfWork/Repositories/RawSqlRepository.cs +++ b/src/Modules/Faura.Infrastructure.UnitOfWork/Repositories/RawSqlRepository.cs @@ -1,33 +1,32 @@ -namespace Faura.Infrastructure.UnitOfWork.Repositories; +namespace Faura.Infrastructure.UnitOfWork.Repositories; using System.Data; using Dapper; using Microsoft.EntityFrameworkCore; -public class RawSqlRepository : IRawSqlRepository where TModel : class +public class RawSqlRepository : IRawSqlRepository + where TModel : class { private readonly DbContext _context; public RawSqlRepository(DbContext context) - { - _context = context ?? throw new ArgumentNullException(nameof(context)); - } + => _context = context ?? throw new ArgumentNullException(nameof(context)); - public async Task> QueryAsync(string sql, object? parameters = null, IDbTransaction? transaction = null) + public Task> QueryAsync(string sql, object? parameters = null, IDbTransaction? transaction = null) { var connection = _context.Database.GetDbConnection(); - return await connection.QueryAsync(sql, parameters, transaction); + return connection.QueryAsync(sql, parameters, transaction); } - public async Task QueryFirstOrDefaultAsync(string sql, object? parameters = null, IDbTransaction? transaction = null) + public Task QueryFirstOrDefaultAsync(string sql, object? parameters = null, IDbTransaction? transaction = null) { var connection = _context.Database.GetDbConnection(); - return await connection.QueryFirstOrDefaultAsync(sql, parameters, transaction); + return connection.QueryFirstOrDefaultAsync(sql, parameters, transaction); } - public async Task ExecuteAsync(string sql, object? parameters = null, IDbTransaction? transaction = null) + public Task ExecuteAsync(string sql, object? parameters = null, IDbTransaction? transaction = null) { var connection = _context.Database.GetDbConnection(); - return await connection.ExecuteAsync(sql, parameters, transaction); + return connection.ExecuteAsync(sql, parameters, transaction); } -} \ No newline at end of file +} diff --git a/src/Modules/Faura.Infrastructure.UnitOfWork/UnitOfWork/IUnitOfWork.cs b/src/Modules/Faura.Infrastructure.UnitOfWork/UnitOfWork/IUnitOfWork.cs index 6dd42b5..4231a2d 100644 --- a/src/Modules/Faura.Infrastructure.UnitOfWork/UnitOfWork/IUnitOfWork.cs +++ b/src/Modules/Faura.Infrastructure.UnitOfWork/UnitOfWork/IUnitOfWork.cs @@ -1,4 +1,4 @@ -namespace Faura.Infrastructure.UnitOfWork.UnitOfWork; +namespace Faura.Infrastructure.UnitOfWork.UnitOfWork; using System.Data; using Microsoft.EntityFrameworkCore.Storage; @@ -6,7 +6,7 @@ public interface IUnitOfWork { /// - /// Begins the transaction + /// Begins the transaction. /// Task GetDbTransaction(int secondsTimeout = 30); @@ -18,4 +18,4 @@ public interface IUnitOfWork /// Commit the transaction if is correct, else rollback. Both cases dispose. /// Task CommitTransaction(IDbTransaction transaction); -} \ No newline at end of file +} diff --git a/src/Modules/Faura.Infrastructure.UnitOfWork/UnitOfWork/UnitOfWork.cs b/src/Modules/Faura.Infrastructure.UnitOfWork/UnitOfWork/UnitOfWork.cs index abe0110..7ed260f 100644 --- a/src/Modules/Faura.Infrastructure.UnitOfWork/UnitOfWork/UnitOfWork.cs +++ b/src/Modules/Faura.Infrastructure.UnitOfWork/UnitOfWork/UnitOfWork.cs @@ -1,18 +1,17 @@ -namespace Faura.Infrastructure.UnitOfWork.UnitOfWork; +namespace Faura.Infrastructure.UnitOfWork.UnitOfWork; using System.Data; using Faura.Infrastructure.UnitOfWork.Exceptions; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Storage; -public class UnitOfWork : IUnitOfWork where TContext : DbContext +public class UnitOfWork : IUnitOfWork + where TContext : DbContext { private const int DefaultSecondsTimeout = 30; protected UnitOfWork(TContext context) - { - Context = context ?? throw new NullContextException(nameof(context)); - } + => Context = context ?? throw new NullContextException(nameof(context)); private TContext Context { get; } @@ -24,16 +23,11 @@ public async Task GetDbTransaction(int secondsTimeout = DefaultS return dbContextTransaction.GetDbTransaction(); } - public Task SaveChanges() - { - //Auditable entities - return Context.SaveChangesAsync(); - } + public Task SaveChanges() => + Context.SaveChangesAsync(); public IExecutionStrategy CreateExecutionStrategy() - { - return Context.Database.CreateExecutionStrategy(); - } + => Context.Database.CreateExecutionStrategy(); public async Task CommitTransaction(IDbTransaction transaction) { @@ -46,7 +40,7 @@ public async Task CommitTransaction(IDbTransaction transaction) transaction.Commit(); } - catch (Exception ex) + catch (Exception) { transaction.Rollback(); throw; @@ -57,4 +51,4 @@ public async Task CommitTransaction(IDbTransaction transaction) transaction.Dispose(); } } -} \ No newline at end of file +} diff --git a/src/Modules/Faura.Infrastructure.UnitOfWork/UnitOfWorkConfiguration.cs b/src/Modules/Faura.Infrastructure.UnitOfWork/UnitOfWorkConfiguration.cs index 1cf2186..20b10f5 100644 --- a/src/Modules/Faura.Infrastructure.UnitOfWork/UnitOfWorkConfiguration.cs +++ b/src/Modules/Faura.Infrastructure.UnitOfWork/UnitOfWorkConfiguration.cs @@ -1,4 +1,4 @@ -namespace Faura.Infrastructure.UnitOfWork; +namespace Faura.Infrastructure.UnitOfWork; using Faura.Infrastructure.UnitOfWork.Projectors; using Faura.Infrastructure.UnitOfWork.Repositories; @@ -12,4 +12,4 @@ public static void SetupUnitOfWork(this IServiceCollection services) services.AddScoped(typeof(IRawSqlRepository<>), typeof(RawSqlRepository<>)); services.AddScoped(typeof(IProjector<>), typeof(Projector<>)); } -} \ No newline at end of file +} diff --git a/src/Templates/Faura.Grpc/Bootstrappers/ApplicationBootstrapper.cs b/src/Templates/Faura.Grpc/Bootstrappers/ApplicationBootstrapper.cs index 097f3e2..23997bd 100644 --- a/src/Templates/Faura.Grpc/Bootstrappers/ApplicationBootstrapper.cs +++ b/src/Templates/Faura.Grpc/Bootstrappers/ApplicationBootstrapper.cs @@ -1,11 +1,7 @@ -namespace Faura.Grpc.Bootstrappers; +namespace Faura.Grpc.Bootstrappers; public static class ApplicationBootstrapper { public static WebApplicationBuilder RegisterApplicationDependencies( - this WebApplicationBuilder builder - ) - { - return builder; - } + this WebApplicationBuilder builder) => builder; } diff --git a/src/Templates/Faura.Grpc/Bootstrappers/GrpcBootstrapper.cs b/src/Templates/Faura.Grpc/Bootstrappers/GrpcBootstrapper.cs index 80baf53..a5441ba 100644 --- a/src/Templates/Faura.Grpc/Bootstrappers/GrpcBootstrapper.cs +++ b/src/Templates/Faura.Grpc/Bootstrappers/GrpcBootstrapper.cs @@ -1,9 +1,9 @@ -using Faura.Grpc.Services; +namespace Faura.Grpc.Bootstrappers; + +using Faura.Grpc.Services; using Faura.Infrastructure.GrpcBootstrapper.Extensions; using Faura.Infrastructure.Logger; -namespace Faura.Grpc.Bootstrappers; - public static class GrpcBootstrapper { public static WebApplicationBuilder RegisterDependencies(this WebApplicationBuilder builder) @@ -16,10 +16,5 @@ public static WebApplicationBuilder RegisterDependencies(this WebApplicationBuil } public static Action RegisterGrpcServices() - { - return endpoints => - { - endpoints.MapGrpcService(); - }; - } + => endpoints => endpoints.MapGrpcService(); } diff --git a/src/Templates/Faura.Grpc/Bootstrappers/OptionsBootstrapper.cs b/src/Templates/Faura.Grpc/Bootstrappers/OptionsBootstrapper.cs index 104c5b8..e2d28f3 100644 --- a/src/Templates/Faura.Grpc/Bootstrappers/OptionsBootstrapper.cs +++ b/src/Templates/Faura.Grpc/Bootstrappers/OptionsBootstrapper.cs @@ -1,11 +1,10 @@ -namespace Faura.Grpc.Bootstrappers; +namespace Faura.Grpc.Bootstrappers; public static class OptionsBootstrapper { public static void RegisterOptions( this IServiceCollection services, - IConfiguration configuration - ) + IConfiguration configuration) { // Add Options here } diff --git a/src/Templates/Faura.Grpc/Faura.Grpc.csproj b/src/Templates/Faura.Grpc/Faura.Grpc.csproj index e56d51f..6651ab9 100644 --- a/src/Templates/Faura.Grpc/Faura.Grpc.csproj +++ b/src/Templates/Faura.Grpc/Faura.Grpc.csproj @@ -11,7 +11,7 @@ - + diff --git a/src/Templates/Faura.Grpc/Program.cs b/src/Templates/Faura.Grpc/Program.cs index fa44dcd..83e9bbb 100644 --- a/src/Templates/Faura.Grpc/Program.cs +++ b/src/Templates/Faura.Grpc/Program.cs @@ -10,4 +10,11 @@ app.ConfigureCommonFauraWebApplication(GrpcBootstrapper.RegisterGrpcServices()); -app.Run(); +await app.RunAsync(); + +public partial class Program +{ + protected Program() + { + } +} diff --git a/src/Templates/Faura.Grpc/Services/GreeterService.cs b/src/Templates/Faura.Grpc/Services/GreeterService.cs index a0a3bf2..87b6075 100644 --- a/src/Templates/Faura.Grpc/Services/GreeterService.cs +++ b/src/Templates/Faura.Grpc/Services/GreeterService.cs @@ -1,16 +1,13 @@ -using Faura.Infrastructure.Logger.Extensions; -using Grpc.Core; - namespace Faura.Grpc.Services; +using Faura.Infrastructure.Logger.Extensions; +using global::Grpc.Core; + public class GreeterService : Greeter.GreeterBase { private readonly ILogger _logger; - public GreeterService(ILogger logger) - { - _logger = logger; - } + public GreeterService(ILogger logger) => _logger = logger; public override Task SayHello(HelloRequest request, ServerCallContext context) { diff --git a/src/Templates/Faura.IntegrationTest/Configuration/CustomWebApplicationFactory.cs b/src/Templates/Faura.IntegrationTest/Configuration/CustomWebApplicationFactory.cs index 7e37e39..f04a61d 100644 --- a/src/Templates/Faura.IntegrationTest/Configuration/CustomWebApplicationFactory.cs +++ b/src/Templates/Faura.IntegrationTest/Configuration/CustomWebApplicationFactory.cs @@ -1,4 +1,6 @@ -using DotNet.Testcontainers.Containers; +namespace Faura.IntegrationTest.Configuration; + +using DotNet.Testcontainers.Containers; using Faura.Infrastructure.IntegrationTesting.Factory; using Faura.Infrastructure.IntegrationTesting.Options; using Faura.Infrastructure.IntegrationTesting.Seeders; @@ -7,18 +9,18 @@ using Faura.Infrastructure.UnitOfWork.Common; using Faura.Infrastructure.UnitOfWork.Enums; using Faura.IntegrationTest.Seeders; +using Faura.WebAPI.Infrastructure.Persistence; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; -using YourNamespace.Data; - -namespace Faura.IntegrationTest.Configuration; public class CustomWebApplicationFactory : BaseWebApplicationFactory where TEntryPoint : class { - private IContainer? _postgresContainer; + private readonly IContainer? _postgresContainer; + + public CustomWebApplicationFactory(IContainer? postgresContainer) => _postgresContainer = postgresContainer; public override async Task DisposeAsync() { @@ -26,11 +28,12 @@ public override async Task DisposeAsync() { await _postgresContainer.StopAsync(); } + + await base.DisposeAsync(); } protected override async Task ConfigureTestContainersAsync( - IConfiguration configuration - ) + IConfiguration configuration) { var containerOptions = configuration.GetSection("Containers").Get(); var pgOptions = containerOptions!.Postgres; @@ -46,29 +49,23 @@ IConfiguration configuration new Dictionary { ["ConnectionStrings:Employee"] = containerInstance.ConnectionString, - } - ) + }) .Build(); } protected override void ConfigureTestServices( IServiceCollection services, - IConfiguration configuration - ) - { - services.AddScoped(); - } + IConfiguration configuration) + => services.AddScoped(); protected override void ConfigureTestDatabase( IServiceCollection services, - IConfiguration configuration - ) + IConfiguration configuration) { services.RemoveAll(typeof(DbContextOptions)); services.ConfigureDatabase( - configuration.GetConnectionString("Employee")!, + configuration.GetConnectionString("Employee") !, DatabaseType.PostgreSQL, - ServiceLifetime.Scoped - ); + ServiceLifetime.Scoped); } } diff --git a/src/Templates/Faura.IntegrationTest/Faura.IntegrationTest.csproj b/src/Templates/Faura.IntegrationTest/Faura.IntegrationTest.csproj index 57cd07a..8e2e15e 100644 --- a/src/Templates/Faura.IntegrationTest/Faura.IntegrationTest.csproj +++ b/src/Templates/Faura.IntegrationTest/Faura.IntegrationTest.csproj @@ -1,29 +1,18 @@ - + net8.0 enable enable - false true - - - - - - - - - - PreserveNewest diff --git a/src/Templates/Faura.IntegrationTest/Seeders/EmployeeTestDataSeeder.cs b/src/Templates/Faura.IntegrationTest/Seeders/EmployeeTestDataSeeder.cs index fc22111..9addb57 100644 --- a/src/Templates/Faura.IntegrationTest/Seeders/EmployeeTestDataSeeder.cs +++ b/src/Templates/Faura.IntegrationTest/Seeders/EmployeeTestDataSeeder.cs @@ -1,17 +1,16 @@ -using Faura.Infrastructure.IntegrationTesting.Seeders; +namespace Faura.IntegrationTest.Seeders; + +using Faura.Infrastructure.IntegrationTesting.Seeders; using Faura.WebAPI.Domain; using Faura.WebAPI.Domain.Entities; +using Faura.WebAPI.Infrastructure.Persistence; using Microsoft.Extensions.DependencyInjection; -using YourNamespace.Data; - -namespace Faura.IntegrationTest.Seeders; public class EmployeeTestDataSeeder : TestDataSeeder { protected override Task SeedDataAsync( EmployeeDbContext context, - IServiceProvider scopedProvider - ) + IServiceProvider scopedProvider) { var repo = scopedProvider.GetRequiredService(); diff --git a/src/Templates/Faura.IntegrationTest/UseCases/WeatherForecastTests.cs b/src/Templates/Faura.IntegrationTest/UseCases/WeatherForecastTests.cs index 72f9e31..c5564e9 100644 --- a/src/Templates/Faura.IntegrationTest/UseCases/WeatherForecastTests.cs +++ b/src/Templates/Faura.IntegrationTest/UseCases/WeatherForecastTests.cs @@ -1,17 +1,16 @@ -using System.Net.Http.Json; +namespace Faura.IntegrationTest.UseCases; + +using System.Net.Http.Json; using Faura.IntegrationTest.Configuration; using Faura.WebAPI.Controllers; - -namespace Faura.IntegrationTest.UseCases; +using Xunit; public class WeatherForecastTests : IClassFixture> { private readonly HttpClient _client; public WeatherForecastTests(CustomWebApplicationFactory factory) - { - _client = factory.CreateClient(); - } + => _client = factory.CreateClient(); [Fact] public async Task Should_Return_WeatherForecast() diff --git a/src/Templates/Faura.WebAPI/Bootstrappers/ApiBootstrapper.cs b/src/Templates/Faura.WebAPI/Bootstrappers/ApiBootstrapper.cs index 894655b..423aeb5 100644 --- a/src/Templates/Faura.WebAPI/Bootstrappers/ApiBootstrapper.cs +++ b/src/Templates/Faura.WebAPI/Bootstrappers/ApiBootstrapper.cs @@ -1,8 +1,8 @@ -using Faura.Infrastructure.ApiBootstrapper.Extensions; +namespace Faura.WebAPI.Bootstrappers; + using Faura.Infrastructure.JWT.Extensions; using Faura.Infrastructure.Logger; - -namespace Faura.WebAPI.Bootstrappers; +using Faura.Infrastructure.ApiBootstrapper.Extensions; public static class ApiBootstrapper { diff --git a/src/Templates/Faura.WebAPI/Bootstrappers/ApplicationBootstrapper.cs b/src/Templates/Faura.WebAPI/Bootstrappers/ApplicationBootstrapper.cs index 562e81a..67520e4 100644 --- a/src/Templates/Faura.WebAPI/Bootstrappers/ApplicationBootstrapper.cs +++ b/src/Templates/Faura.WebAPI/Bootstrappers/ApplicationBootstrapper.cs @@ -1,17 +1,15 @@ -using Faura.Infrastructure.UnitOfWork; +namespace Faura.WebAPI.Bootstrappers; + +using Faura.Infrastructure.UnitOfWork; using Faura.Infrastructure.UnitOfWork.Common; using Faura.Infrastructure.UnitOfWork.Enums; using Faura.WebAPI.Domain; using Faura.WebAPI.Infrastructure.Persistence; -using YourNamespace.Data; - -namespace Faura.WebAPI.Bootstrappers; public static class ApplicationBootstrapper { public static WebApplicationBuilder RegisterApplicationDependencies( - this WebApplicationBuilder builder - ) + this WebApplicationBuilder builder) { builder.Services.SetupDatabase(builder.Configuration); @@ -23,12 +21,9 @@ this WebApplicationBuilder builder /// /// Setup here your database connections. /// - /// - /// private static void SetupDatabase( this IServiceCollection services, - IConfiguration configuration - ) + IConfiguration configuration) { services.SetupUnitOfWork(); services @@ -36,8 +31,7 @@ IConfiguration configuration configuration, "Employee", DatabaseType.PostgreSQL, - ServiceLifetime.Scoped - ) + ServiceLifetime.Scoped) .ConfigureAwait(false); } } diff --git a/src/Templates/Faura.WebAPI/Bootstrappers/OptionsBootstrapper.cs b/src/Templates/Faura.WebAPI/Bootstrappers/OptionsBootstrapper.cs index ef95385..2ae9097 100644 --- a/src/Templates/Faura.WebAPI/Bootstrappers/OptionsBootstrapper.cs +++ b/src/Templates/Faura.WebAPI/Bootstrappers/OptionsBootstrapper.cs @@ -1,11 +1,10 @@ -namespace Faura.WebAPI.Bootstrappers; +namespace Faura.WebAPI.Bootstrappers; public static class OptionsBootstrapper { public static void RegisterOptions( this IServiceCollection services, - IConfiguration configuration - ) + IConfiguration configuration) { // Add Options here } diff --git a/src/Templates/Faura.WebAPI/Controllers/WeatherForecastController.cs b/src/Templates/Faura.WebAPI/Controllers/WeatherForecastController.cs index cc8e2df..dfae535 100644 --- a/src/Templates/Faura.WebAPI/Controllers/WeatherForecastController.cs +++ b/src/Templates/Faura.WebAPI/Controllers/WeatherForecastController.cs @@ -1,82 +1,37 @@ +namespace Faura.WebAPI.Controllers; + +using Faura.Infrastructure.Logger.Extensions; using Faura.WebAPI.Domain; using Faura.WebAPI.Domain.Entities; using Faura.WebAPI.Infrastructure.Persistence; -using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; - -namespace Faura.WebAPI.Controllers; +using Microsoft.Extensions.Logging; [ApiController] [Route("[controller]")] -public class WeatherForecastController : ControllerBase +public class WeatherForecastController( + ILogger logger, + IEmployeeRepository employeeRepository, + IEmployeeUoW uoW) + : ControllerBase { - private static readonly string[] Summaries = new[] - { - "Freezing", - "Bracing", - "Chilly", - "Cool", - "Mild", - "Warm", - "Balmy", - "Hot", - "Sweltering", - "Scorching", - }; - - private readonly ILogger _logger; - private readonly IEmployeeRepository _employeeRepository; - private readonly IEmployeeUoW _uoW; - - public WeatherForecastController( - ILogger logger, - IEmployeeRepository employeeRepository, - IEmployeeUoW uoW - ) - { - _logger = logger; - _employeeRepository = employeeRepository; - _uoW = uoW; - } - [HttpGet(Name = "GetWeatherForecast")] - public async Task> Get() + public async Task Get() { - var res = await _employeeRepository.GetAsync(); + logger.LogFauraInformation("Starting Get"); - var transaction = await _uoW.GetDbTransaction(); + await employeeRepository.GetAsync(); - var res2 = await _employeeRepository.CreateAsync( - new Employee("Josep", "Ferrandis", "algo@example.com"), - false, - false - ); - var res3 = await _employeeRepository.CreateAsync( - new Employee("Josep", "Ferrandis", "algo@example.com"), - false, - false - ); + var transaction = await uoW.GetDbTransaction(); - // send event 1 - // send event 2 + await employeeRepository.CreateAsync( + new Employee("Josep", "Ferrandis", "algo@example.com")); - await _uoW.CommitTransaction(transaction); + await employeeRepository.CreateAsync( + new Employee("Josep", "Ferrandis", "algo@example.com")); - return Enumerable - .Range(1, 5) - .Select(index => new WeatherForecast - { - Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)), - TemperatureC = Random.Shared.Next(-20, 55), - Summary = Summaries[Random.Shared.Next(Summaries.Length)], - }) - .ToArray(); - } + await uoW.CommitTransaction(transaction); - [HttpGet("Test")] - [Authorize] - public string GetTst() - { - return "Hola"; + return Ok(); } } diff --git a/src/Templates/Faura.WebAPI/Domain/EmployeeRepository.cs b/src/Templates/Faura.WebAPI/Domain/EmployeeRepository.cs index 3e2038c..e8edd06 100644 --- a/src/Templates/Faura.WebAPI/Domain/EmployeeRepository.cs +++ b/src/Templates/Faura.WebAPI/Domain/EmployeeRepository.cs @@ -1,15 +1,16 @@ -using Faura.Infrastructure.UnitOfWork.Repositories; -using Faura.WebAPI.Domain.Entities; -using YourNamespace.Data; - namespace Faura.WebAPI.Domain; +using Faura.Infrastructure.UnitOfWork.Repositories; +using Faura.WebAPI.Domain.Entities; +using Faura.WebAPI.Infrastructure.Persistence; + public class EmployeeRepository : EntityRepository, IEmployeeRepository { public EmployeeRepository( EmployeeDbContext dbContext, - ILogger> logger, - bool enableTracking = false - ) - : base(dbContext, logger, enableTracking) { } + ILogger logger, + bool enableTracking = false) + : base(dbContext, logger, enableTracking) + { + } } diff --git a/src/Templates/Faura.WebAPI/Domain/Entities/Employee.cs b/src/Templates/Faura.WebAPI/Domain/Entities/Employee.cs index 36ac673..f861528 100644 --- a/src/Templates/Faura.WebAPI/Domain/Entities/Employee.cs +++ b/src/Templates/Faura.WebAPI/Domain/Entities/Employee.cs @@ -1,7 +1,7 @@ -using System.ComponentModel.DataAnnotations.Schema; - namespace Faura.WebAPI.Domain.Entities; +using System.ComponentModel.DataAnnotations.Schema; + [Table("employee")] public class Employee { diff --git a/src/Templates/Faura.WebAPI/Domain/IEmployeeRepository.cs b/src/Templates/Faura.WebAPI/Domain/IEmployeeRepository.cs index e6f2c49..26c8d0a 100644 --- a/src/Templates/Faura.WebAPI/Domain/IEmployeeRepository.cs +++ b/src/Templates/Faura.WebAPI/Domain/IEmployeeRepository.cs @@ -1,6 +1,8 @@ -using Faura.Infrastructure.UnitOfWork.Repositories; -using Faura.WebAPI.Domain.Entities; - namespace Faura.WebAPI.Domain; -public interface IEmployeeRepository : IEntityRepository { } +using Faura.Infrastructure.UnitOfWork.Repositories; +using Faura.WebAPI.Domain.Entities; + +public interface IEmployeeRepository : IEntityRepository +{ +} diff --git a/src/Templates/Faura.WebAPI/Faura.WebAPI.csproj b/src/Templates/Faura.WebAPI/Faura.WebAPI.csproj index ff18345..0a26370 100644 --- a/src/Templates/Faura.WebAPI/Faura.WebAPI.csproj +++ b/src/Templates/Faura.WebAPI/Faura.WebAPI.csproj @@ -8,19 +8,15 @@ - - + + - - - - diff --git a/src/Templates/Faura.WebAPI/Infrastructure/Persistence/EmployeeDbContext.cs b/src/Templates/Faura.WebAPI/Infrastructure/Persistence/EmployeeDbContext.cs index 3a220b6..5328c48 100644 --- a/src/Templates/Faura.WebAPI/Infrastructure/Persistence/EmployeeDbContext.cs +++ b/src/Templates/Faura.WebAPI/Infrastructure/Persistence/EmployeeDbContext.cs @@ -1,12 +1,14 @@ -using Faura.WebAPI.Domain.Entities; -using Microsoft.EntityFrameworkCore; +namespace Faura.WebAPI.Infrastructure.Persistence; -namespace YourNamespace.Data; +using Faura.WebAPI.Domain.Entities; +using Microsoft.EntityFrameworkCore; public class EmployeeDbContext : DbContext { public EmployeeDbContext(DbContextOptions options) - : base(options) { } + : base(options) + { + } public DbSet Employee { get; set; } diff --git a/src/Templates/Faura.WebAPI/Infrastructure/Persistence/EmployeeUoW.cs b/src/Templates/Faura.WebAPI/Infrastructure/Persistence/EmployeeUoW.cs index 8658c6b..74e4e01 100644 --- a/src/Templates/Faura.WebAPI/Infrastructure/Persistence/EmployeeUoW.cs +++ b/src/Templates/Faura.WebAPI/Infrastructure/Persistence/EmployeeUoW.cs @@ -1,10 +1,11 @@ -using Faura.Infrastructure.UnitOfWork.UnitOfWork; -using YourNamespace.Data; - namespace Faura.WebAPI.Infrastructure.Persistence; +using Faura.Infrastructure.UnitOfWork.UnitOfWork; + public class EmployeeUoW : UnitOfWork, IEmployeeUoW { public EmployeeUoW(EmployeeDbContext context) - : base(context) { } + : base(context) + { + } } diff --git a/src/Templates/Faura.WebAPI/Infrastructure/Persistence/IEmployeeUoW.cs b/src/Templates/Faura.WebAPI/Infrastructure/Persistence/IEmployeeUoW.cs index 3343fc0..cdc3374 100644 --- a/src/Templates/Faura.WebAPI/Infrastructure/Persistence/IEmployeeUoW.cs +++ b/src/Templates/Faura.WebAPI/Infrastructure/Persistence/IEmployeeUoW.cs @@ -1,5 +1,7 @@ -using Faura.Infrastructure.UnitOfWork.UnitOfWork; - namespace Faura.WebAPI.Infrastructure.Persistence; -public interface IEmployeeUoW : IUnitOfWork { } +using Faura.Infrastructure.UnitOfWork.UnitOfWork; + +public interface IEmployeeUoW : IUnitOfWork +{ +} diff --git a/src/Templates/Faura.WebAPI/Program.cs b/src/Templates/Faura.WebAPI/Program.cs index cb68196..a450736 100644 --- a/src/Templates/Faura.WebAPI/Program.cs +++ b/src/Templates/Faura.WebAPI/Program.cs @@ -10,7 +10,7 @@ app.ConfigureCommonFauraWebApplication(); -app.Run(); +await app.RunAsync(); public partial class Program { diff --git a/src/global.json b/src/global.json new file mode 100644 index 0000000..dc998b1 --- /dev/null +++ b/src/global.json @@ -0,0 +1,6 @@ +{ + "sdk": { + "rollForward": "latestFeature", + "version": "8.0.300" + } +} diff --git a/src/stylecop.json b/src/stylecop.json new file mode 100644 index 0000000..2289c6a --- /dev/null +++ b/src/stylecop.json @@ -0,0 +1,11 @@ +{ + "@schema": "https://raw.githubusercontent.com/DotNetAnalyzers/StyleCopAnalyzers/master/StyleCop.Analyzers/StyleCop.Analyzers/Settings/stylecop.schema.json", + "settings": { + "layoutRules": { + "newlineAtEndOfFile": "require" + }, + "orderingRules": { + "blankLinesBetweenUsingGroups": "omit" + } + } +} From 235d8d44c9fde0409a791dd711e060722d081ae7 Mon Sep 17 00:00:00 2001 From: JosepFe Date: Sun, 15 Jun 2025 13:50:52 +0200 Subject: [PATCH 02/13] refactor csprojs to adjust dependencies --- .../Faura.Infrastructure.IntegrationTesting.csproj | 1 + .../Faura.Infrastructure.UnitOfWork.csproj | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/Modules/Faura.Infrastructure.IntegrationTesting/Faura.Infrastructure.IntegrationTesting.csproj b/src/Modules/Faura.Infrastructure.IntegrationTesting/Faura.Infrastructure.IntegrationTesting.csproj index b6d3bd5..50a0963 100644 --- a/src/Modules/Faura.Infrastructure.IntegrationTesting/Faura.Infrastructure.IntegrationTesting.csproj +++ b/src/Modules/Faura.Infrastructure.IntegrationTesting/Faura.Infrastructure.IntegrationTesting.csproj @@ -13,6 +13,7 @@ LICENSE True $(NoWarn);NETSDK1206;1701;1702;NU1608;CA1822 + true diff --git a/src/Modules/Faura.Infrastructure.UnitOfWork/Faura.Infrastructure.UnitOfWork.csproj b/src/Modules/Faura.Infrastructure.UnitOfWork/Faura.Infrastructure.UnitOfWork.csproj index 80c765b..bbc9ab7 100644 --- a/src/Modules/Faura.Infrastructure.UnitOfWork/Faura.Infrastructure.UnitOfWork.csproj +++ b/src/Modules/Faura.Infrastructure.UnitOfWork/Faura.Infrastructure.UnitOfWork.csproj @@ -16,9 +16,9 @@ - - - + + + From dc09273f224d441efb9819a63ecde3ebd2220834 Mon Sep 17 00:00:00 2001 From: JosepFe Date: Sun, 15 Jun 2025 18:32:08 +0200 Subject: [PATCH 03/13] sonar coverage exclusion and solved code smells --- src/Faura.sln | 12 +++++++++--- ...Faura.Infrastructure.ApiBootstrapper.csproj | 18 ++++++++++++------ .../Faura.Infrastructure.Common.csproj | 9 ++++++++- ...aura.Infrastructure.GrpcBootstrapper.csproj | 18 ++++++++++++------ ...ra.Infrastructure.IntegrationTesting.csproj | 8 +++++++- .../Faura.Infrastructure.JWT.csproj | 10 ++++++++-- .../Faura.Infrastructure.Logger.csproj | 6 ++++++ .../Faura.Infrastructure.Result.csproj | 6 ++++++ .../Common/DatabaseConfiguration.cs | 7 ++----- .../Faura.Infrastructure.UnitOfWork.csproj | 6 ++++++ 10 files changed, 76 insertions(+), 24 deletions(-) diff --git a/src/Faura.sln b/src/Faura.sln index bf3c225..ac1d393 100644 --- a/src/Faura.sln +++ b/src/Faura.sln @@ -38,6 +38,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SolutionItems", "SolutionIt stylecop.json = stylecop.json EndProjectSection EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "WebAPI", "WebAPI", "{F1517752-590B-4773-A4D6-9E670C639523}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "WebAPIGrpc", "WebAPIGrpc", "{F3ABDB5B-F5E0-43DE-898B-4170F6852893}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -96,14 +100,16 @@ Global {F0757E5C-ACCD-44DD-B755-64CAFE654A7A} = {420A3EFF-9247-407D-B58F-EC8144EB14F4} {8146A031-8E30-4F0F-940E-F77795C208F8} = {420A3EFF-9247-407D-B58F-EC8144EB14F4} {1F34C695-2396-428D-87EF-7D3FDD9BD8C2} = {420A3EFF-9247-407D-B58F-EC8144EB14F4} - {2B690895-0614-4013-85D8-7FC47B956C26} = {0C2B5D2F-B5EE-48E0-ACEE-A064E0232A26} + {2B690895-0614-4013-85D8-7FC47B956C26} = {F1517752-590B-4773-A4D6-9E670C639523} {F749C616-5B16-4A0B-9F88-D08BEAA5F27B} = {420A3EFF-9247-407D-B58F-EC8144EB14F4} {CE7C267E-97CF-4C7F-A5D0-B8AFC30C6130} = {420A3EFF-9247-407D-B58F-EC8144EB14F4} {AFC92389-71C2-BB14-10A4-CA1B415F02E9} = {420A3EFF-9247-407D-B58F-EC8144EB14F4} - {31D599B8-9C10-410E-9ACD-0F2201C2BD4E} = {0C2B5D2F-B5EE-48E0-ACEE-A064E0232A26} + {31D599B8-9C10-410E-9ACD-0F2201C2BD4E} = {F3ABDB5B-F5E0-43DE-898B-4170F6852893} {93D57E51-3F79-19CF-B65F-08600B130F57} = {420A3EFF-9247-407D-B58F-EC8144EB14F4} {09790598-6AD0-D698-A32D-D9A056BAF8D0} = {420A3EFF-9247-407D-B58F-EC8144EB14F4} - {89320569-AAF8-4290-B912-699F792319F5} = {0C2B5D2F-B5EE-48E0-ACEE-A064E0232A26} + {89320569-AAF8-4290-B912-699F792319F5} = {F1517752-590B-4773-A4D6-9E670C639523} + {F1517752-590B-4773-A4D6-9E670C639523} = {0C2B5D2F-B5EE-48E0-ACEE-A064E0232A26} + {F3ABDB5B-F5E0-43DE-898B-4170F6852893} = {0C2B5D2F-B5EE-48E0-ACEE-A064E0232A26} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {7B487365-BA97-49F1-93FD-C12DB361C20B} diff --git a/src/Modules/Faura.Infrastructure.ApiBootstrapper/Faura.Infrastructure.ApiBootstrapper.csproj b/src/Modules/Faura.Infrastructure.ApiBootstrapper/Faura.Infrastructure.ApiBootstrapper.csproj index 5f5ab4f..69022d8 100644 --- a/src/Modules/Faura.Infrastructure.ApiBootstrapper/Faura.Infrastructure.ApiBootstrapper.csproj +++ b/src/Modules/Faura.Infrastructure.ApiBootstrapper/Faura.Infrastructure.ApiBootstrapper.csproj @@ -1,5 +1,5 @@  - + net8.0 enable @@ -23,6 +23,16 @@ + + + + + + + **/**/*.cs + + + True @@ -33,9 +43,5 @@ \ - - - - - + diff --git a/src/Modules/Faura.Infrastructure.Common/Faura.Infrastructure.Common.csproj b/src/Modules/Faura.Infrastructure.Common/Faura.Infrastructure.Common.csproj index afd0134..969efbf 100644 --- a/src/Modules/Faura.Infrastructure.Common/Faura.Infrastructure.Common.csproj +++ b/src/Modules/Faura.Infrastructure.Common/Faura.Infrastructure.Common.csproj @@ -1,5 +1,5 @@  - + net8.0 enable @@ -22,6 +22,12 @@ + + + **/**/*.cs + + + True @@ -32,4 +38,5 @@ \ + diff --git a/src/Modules/Faura.Infrastructure.GrpcBootstrapper/Faura.Infrastructure.GrpcBootstrapper.csproj b/src/Modules/Faura.Infrastructure.GrpcBootstrapper/Faura.Infrastructure.GrpcBootstrapper.csproj index cb7ec3a..246f0c9 100644 --- a/src/Modules/Faura.Infrastructure.GrpcBootstrapper/Faura.Infrastructure.GrpcBootstrapper.csproj +++ b/src/Modules/Faura.Infrastructure.GrpcBootstrapper/Faura.Infrastructure.GrpcBootstrapper.csproj @@ -1,5 +1,5 @@  - + net8.0 enable @@ -21,6 +21,16 @@ + + + + + + + **/**/*.cs + + + True @@ -31,9 +41,5 @@ \ - - - - - + diff --git a/src/Modules/Faura.Infrastructure.IntegrationTesting/Faura.Infrastructure.IntegrationTesting.csproj b/src/Modules/Faura.Infrastructure.IntegrationTesting/Faura.Infrastructure.IntegrationTesting.csproj index 50a0963..7a8f31b 100644 --- a/src/Modules/Faura.Infrastructure.IntegrationTesting/Faura.Infrastructure.IntegrationTesting.csproj +++ b/src/Modules/Faura.Infrastructure.IntegrationTesting/Faura.Infrastructure.IntegrationTesting.csproj @@ -27,6 +27,12 @@ + + + **/**/*.cs + + + True @@ -37,5 +43,5 @@ \ - + diff --git a/src/Modules/Faura.Infrastructure.JWT/Faura.Infrastructure.JWT.csproj b/src/Modules/Faura.Infrastructure.JWT/Faura.Infrastructure.JWT.csproj index b0ed9e9..1003781 100644 --- a/src/Modules/Faura.Infrastructure.JWT/Faura.Infrastructure.JWT.csproj +++ b/src/Modules/Faura.Infrastructure.JWT/Faura.Infrastructure.JWT.csproj @@ -1,5 +1,5 @@  - + net8.0 enable @@ -23,6 +23,12 @@ + + + **/**/*.cs + + + True @@ -33,5 +39,5 @@ \ - + diff --git a/src/Modules/Faura.Infrastructure.Logger/Faura.Infrastructure.Logger.csproj b/src/Modules/Faura.Infrastructure.Logger/Faura.Infrastructure.Logger.csproj index 345faf7..fe26329 100644 --- a/src/Modules/Faura.Infrastructure.Logger/Faura.Infrastructure.Logger.csproj +++ b/src/Modules/Faura.Infrastructure.Logger/Faura.Infrastructure.Logger.csproj @@ -29,6 +29,12 @@ + + + **/**/*.cs + + + True diff --git a/src/Modules/Faura.Infrastructure.Result/Faura.Infrastructure.Result.csproj b/src/Modules/Faura.Infrastructure.Result/Faura.Infrastructure.Result.csproj index 0b90746..7b2785e 100644 --- a/src/Modules/Faura.Infrastructure.Result/Faura.Infrastructure.Result.csproj +++ b/src/Modules/Faura.Infrastructure.Result/Faura.Infrastructure.Result.csproj @@ -19,6 +19,12 @@ + + + **/**/*.cs + + + True diff --git a/src/Modules/Faura.Infrastructure.UnitOfWork/Common/DatabaseConfiguration.cs b/src/Modules/Faura.Infrastructure.UnitOfWork/Common/DatabaseConfiguration.cs index c1a7eac..98c7637 100644 --- a/src/Modules/Faura.Infrastructure.UnitOfWork/Common/DatabaseConfiguration.cs +++ b/src/Modules/Faura.Infrastructure.UnitOfWork/Common/DatabaseConfiguration.cs @@ -87,8 +87,7 @@ private static async Task ApplyMigrations(IServiceCollection services) if (context == null) { - string message = $"Unable to resolve {typeof(TContext).FullName}. Database migration will not be performed."; - logger?.LogError(message); + logger?.LogError("Unable to resolve {ContextType}. Database migration will not be performed.", typeof(TContext).FullName); return; } @@ -99,9 +98,7 @@ private static async Task ApplyMigrations(IServiceCollection services) catch (Exception ex) { string contextName = typeof(TContext).FullName ?? "UnknownContext"; - string errorMessage = $"An error occurred while migrating the database for context {contextName}. See inner exception for details."; - logger?.LogError(ex, errorMessage); - throw new InvalidOperationException(errorMessage, ex); + logger?.LogError(ex, "An error occurred while migrating the database for context {ContextName}. See inner exception for details.", contextName); } } } diff --git a/src/Modules/Faura.Infrastructure.UnitOfWork/Faura.Infrastructure.UnitOfWork.csproj b/src/Modules/Faura.Infrastructure.UnitOfWork/Faura.Infrastructure.UnitOfWork.csproj index bbc9ab7..e49dad9 100644 --- a/src/Modules/Faura.Infrastructure.UnitOfWork/Faura.Infrastructure.UnitOfWork.csproj +++ b/src/Modules/Faura.Infrastructure.UnitOfWork/Faura.Infrastructure.UnitOfWork.csproj @@ -24,6 +24,12 @@ + + + **/**/*.cs + + + True From ed4a4a0462e29c160df20aa167f7e43e236395a4 Mon Sep 17 00:00:00 2001 From: JosepFe Date: Sun, 15 Jun 2025 19:40:34 +0200 Subject: [PATCH 04/13] refactor code to include tests --- src/Faura.sln | 21 ++- ...a.Infrastructure.IntegrationTesting.csproj | 2 +- .../Core/TestContainerInstance.cs | 2 + .../Faura.Infrastructure.UnitOfWork.csproj | 3 +- .../UseCases/WeatherForecastTests.cs | 28 ---- .../CustomWebApplicationFactory.cs | 6 +- .../Faura.WebAPI.IntegrationTests.csproj} | 0 .../Seeders/EmployeeTestDataSeeder.cs | 2 +- .../UseCases/EmployeeTests.cs | 92 +++++++++++++ .../appsettings.Test.json | 0 .../EmployeeControllerTests.cs | 127 ++++++++++++++++++ .../Faura.WebAPI.UnitTests.csproj | 20 +++ .../Bootstrappers/ApplicationBootstrapper.cs | 3 +- .../Controllers/EmployeeController.cs | 65 +++++++++ .../Controllers/WeatherForecast.cs | 12 -- .../Controllers/WeatherForecastController.cs | 37 ----- .../{ => Repositories}/IEmployeeRepository.cs | 3 +- .../Faura.WebAPI/Faura.WebAPI.csproj | 13 ++ .../Repositories}/EmployeeRepository.cs | 7 +- 19 files changed, 350 insertions(+), 93 deletions(-) delete mode 100644 src/Templates/Faura.IntegrationTest/UseCases/WeatherForecastTests.cs rename src/Templates/{Faura.IntegrationTest => Faura.WebAPI.IntegrationTests}/Configuration/CustomWebApplicationFactory.cs (93%) rename src/Templates/{Faura.IntegrationTest/Faura.IntegrationTest.csproj => Faura.WebAPI.IntegrationTests/Faura.WebAPI.IntegrationTests.csproj} (100%) rename src/Templates/{Faura.IntegrationTest => Faura.WebAPI.IntegrationTests}/Seeders/EmployeeTestDataSeeder.cs (93%) create mode 100644 src/Templates/Faura.WebAPI.IntegrationTests/UseCases/EmployeeTests.cs rename src/Templates/{Faura.IntegrationTest => Faura.WebAPI.IntegrationTests}/appsettings.Test.json (100%) create mode 100644 src/Templates/Faura.WebAPI.UnitTests/EmployeeControllerTests.cs create mode 100644 src/Templates/Faura.WebAPI.UnitTests/Faura.WebAPI.UnitTests.csproj create mode 100644 src/Templates/Faura.WebAPI/Controllers/EmployeeController.cs delete mode 100644 src/Templates/Faura.WebAPI/Controllers/WeatherForecast.cs delete mode 100644 src/Templates/Faura.WebAPI/Controllers/WeatherForecastController.cs rename src/Templates/Faura.WebAPI/Domain/{ => Repositories}/IEmployeeRepository.cs (64%) rename src/Templates/Faura.WebAPI/{Domain => Infrastructure/Repositories}/EmployeeRepository.cs (65%) diff --git a/src/Faura.sln b/src/Faura.sln index ac1d393..0b0ea62 100644 --- a/src/Faura.sln +++ b/src/Faura.sln @@ -27,8 +27,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Faura.Infrastructure.ApiBoo EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Faura.Infrastructure.IntegrationTesting", "Modules\Faura.Infrastructure.IntegrationTesting\Faura.Infrastructure.IntegrationTesting.csproj", "{09790598-6AD0-D698-A32D-D9A056BAF8D0}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Faura.IntegrationTest", "Templates\Faura.IntegrationTest\Faura.IntegrationTest.csproj", "{89320569-AAF8-4290-B912-699F792319F5}" -EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SolutionItems", "SolutionItems", "{02EA681E-C7D8-13C7-8484-4AC65E1B71E8}" ProjectSection(SolutionItems) = preProject .editorconfig = .editorconfig @@ -42,6 +40,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "WebAPI", "WebAPI", "{F15177 EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "WebAPIGrpc", "WebAPIGrpc", "{F3ABDB5B-F5E0-43DE-898B-4170F6852893}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Faura.WebAPI.UnitTests", "Templates\Faura.WebAPI.UnitTests\Faura.WebAPI.UnitTests.csproj", "{38B3C54C-1AED-42E7-A510-0734DF5A7B8F}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Faura.WebAPI.IntegrationTests", "Templates\Faura.WebAPI.IntegrationTests\Faura.WebAPI.IntegrationTests.csproj", "{71A15B05-FF1A-8D1F-0833-4F72927CEC48}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -88,10 +90,14 @@ Global {09790598-6AD0-D698-A32D-D9A056BAF8D0}.Debug|Any CPU.Build.0 = Debug|Any CPU {09790598-6AD0-D698-A32D-D9A056BAF8D0}.Release|Any CPU.ActiveCfg = Release|Any CPU {09790598-6AD0-D698-A32D-D9A056BAF8D0}.Release|Any CPU.Build.0 = Release|Any CPU - {89320569-AAF8-4290-B912-699F792319F5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {89320569-AAF8-4290-B912-699F792319F5}.Debug|Any CPU.Build.0 = Debug|Any CPU - {89320569-AAF8-4290-B912-699F792319F5}.Release|Any CPU.ActiveCfg = Release|Any CPU - {89320569-AAF8-4290-B912-699F792319F5}.Release|Any CPU.Build.0 = Release|Any CPU + {38B3C54C-1AED-42E7-A510-0734DF5A7B8F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {38B3C54C-1AED-42E7-A510-0734DF5A7B8F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {38B3C54C-1AED-42E7-A510-0734DF5A7B8F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {38B3C54C-1AED-42E7-A510-0734DF5A7B8F}.Release|Any CPU.Build.0 = Release|Any CPU + {71A15B05-FF1A-8D1F-0833-4F72927CEC48}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {71A15B05-FF1A-8D1F-0833-4F72927CEC48}.Debug|Any CPU.Build.0 = Debug|Any CPU + {71A15B05-FF1A-8D1F-0833-4F72927CEC48}.Release|Any CPU.ActiveCfg = Release|Any CPU + {71A15B05-FF1A-8D1F-0833-4F72927CEC48}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -107,9 +113,10 @@ Global {31D599B8-9C10-410E-9ACD-0F2201C2BD4E} = {F3ABDB5B-F5E0-43DE-898B-4170F6852893} {93D57E51-3F79-19CF-B65F-08600B130F57} = {420A3EFF-9247-407D-B58F-EC8144EB14F4} {09790598-6AD0-D698-A32D-D9A056BAF8D0} = {420A3EFF-9247-407D-B58F-EC8144EB14F4} - {89320569-AAF8-4290-B912-699F792319F5} = {F1517752-590B-4773-A4D6-9E670C639523} {F1517752-590B-4773-A4D6-9E670C639523} = {0C2B5D2F-B5EE-48E0-ACEE-A064E0232A26} {F3ABDB5B-F5E0-43DE-898B-4170F6852893} = {0C2B5D2F-B5EE-48E0-ACEE-A064E0232A26} + {38B3C54C-1AED-42E7-A510-0734DF5A7B8F} = {F1517752-590B-4773-A4D6-9E670C639523} + {71A15B05-FF1A-8D1F-0833-4F72927CEC48} = {F1517752-590B-4773-A4D6-9E670C639523} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {7B487365-BA97-49F1-93FD-C12DB361C20B} diff --git a/src/Modules/Faura.Infrastructure.IntegrationTesting/Faura.Infrastructure.IntegrationTesting.csproj b/src/Modules/Faura.Infrastructure.IntegrationTesting/Faura.Infrastructure.IntegrationTesting.csproj index 7a8f31b..542f6e7 100644 --- a/src/Modules/Faura.Infrastructure.IntegrationTesting/Faura.Infrastructure.IntegrationTesting.csproj +++ b/src/Modules/Faura.Infrastructure.IntegrationTesting/Faura.Infrastructure.IntegrationTesting.csproj @@ -18,7 +18,7 @@ - + diff --git a/src/Modules/Faura.Infrastructure.IntegrationTesting/TestContainers/Core/TestContainerInstance.cs b/src/Modules/Faura.Infrastructure.IntegrationTesting/TestContainers/Core/TestContainerInstance.cs index a2c19cc..5a61df6 100644 --- a/src/Modules/Faura.Infrastructure.IntegrationTesting/TestContainers/Core/TestContainerInstance.cs +++ b/src/Modules/Faura.Infrastructure.IntegrationTesting/TestContainers/Core/TestContainerInstance.cs @@ -27,6 +27,8 @@ public TestContainerInstance(T config) _container = builder.Build(); } + public IContainer Container => _container; + public string ConnectionString { get; private set; } = string.Empty; public async Task StartAsync() diff --git a/src/Modules/Faura.Infrastructure.UnitOfWork/Faura.Infrastructure.UnitOfWork.csproj b/src/Modules/Faura.Infrastructure.UnitOfWork/Faura.Infrastructure.UnitOfWork.csproj index e49dad9..367c237 100644 --- a/src/Modules/Faura.Infrastructure.UnitOfWork/Faura.Infrastructure.UnitOfWork.csproj +++ b/src/Modules/Faura.Infrastructure.UnitOfWork/Faura.Infrastructure.UnitOfWork.csproj @@ -16,7 +16,8 @@ - + + diff --git a/src/Templates/Faura.IntegrationTest/UseCases/WeatherForecastTests.cs b/src/Templates/Faura.IntegrationTest/UseCases/WeatherForecastTests.cs deleted file mode 100644 index c5564e9..0000000 --- a/src/Templates/Faura.IntegrationTest/UseCases/WeatherForecastTests.cs +++ /dev/null @@ -1,28 +0,0 @@ -namespace Faura.IntegrationTest.UseCases; - -using System.Net.Http.Json; -using Faura.IntegrationTest.Configuration; -using Faura.WebAPI.Controllers; -using Xunit; - -public class WeatherForecastTests : IClassFixture> -{ - private readonly HttpClient _client; - - public WeatherForecastTests(CustomWebApplicationFactory factory) - => _client = factory.CreateClient(); - - [Fact] - public async Task Should_Return_WeatherForecast() - { - // Act - var response = await _client.GetAsync("/WeatherForecast"); - - // Assert - response.EnsureSuccessStatusCode(); - - var data = await response.Content.ReadFromJsonAsync>(); - Assert.NotNull(data); - Assert.NotEmpty(data); - } -} diff --git a/src/Templates/Faura.IntegrationTest/Configuration/CustomWebApplicationFactory.cs b/src/Templates/Faura.WebAPI.IntegrationTests/Configuration/CustomWebApplicationFactory.cs similarity index 93% rename from src/Templates/Faura.IntegrationTest/Configuration/CustomWebApplicationFactory.cs rename to src/Templates/Faura.WebAPI.IntegrationTests/Configuration/CustomWebApplicationFactory.cs index f04a61d..78ff953 100644 --- a/src/Templates/Faura.IntegrationTest/Configuration/CustomWebApplicationFactory.cs +++ b/src/Templates/Faura.WebAPI.IntegrationTests/Configuration/CustomWebApplicationFactory.cs @@ -18,9 +18,7 @@ namespace Faura.IntegrationTest.Configuration; public class CustomWebApplicationFactory : BaseWebApplicationFactory where TEntryPoint : class { - private readonly IContainer? _postgresContainer; - - public CustomWebApplicationFactory(IContainer? postgresContainer) => _postgresContainer = postgresContainer; + private IContainer? _postgresContainer; public override async Task DisposeAsync() { @@ -41,6 +39,8 @@ protected override async Task ConfigureTestContainersAsync( var pgConfig = new PostgresContainerConfiguration(pgOptions); var containerInstance = new TestContainerInstance(pgConfig); + _postgresContainer = containerInstance.Container; + await containerInstance.StartAsync(); return new ConfigurationBuilder() diff --git a/src/Templates/Faura.IntegrationTest/Faura.IntegrationTest.csproj b/src/Templates/Faura.WebAPI.IntegrationTests/Faura.WebAPI.IntegrationTests.csproj similarity index 100% rename from src/Templates/Faura.IntegrationTest/Faura.IntegrationTest.csproj rename to src/Templates/Faura.WebAPI.IntegrationTests/Faura.WebAPI.IntegrationTests.csproj diff --git a/src/Templates/Faura.IntegrationTest/Seeders/EmployeeTestDataSeeder.cs b/src/Templates/Faura.WebAPI.IntegrationTests/Seeders/EmployeeTestDataSeeder.cs similarity index 93% rename from src/Templates/Faura.IntegrationTest/Seeders/EmployeeTestDataSeeder.cs rename to src/Templates/Faura.WebAPI.IntegrationTests/Seeders/EmployeeTestDataSeeder.cs index 9addb57..9933c45 100644 --- a/src/Templates/Faura.IntegrationTest/Seeders/EmployeeTestDataSeeder.cs +++ b/src/Templates/Faura.WebAPI.IntegrationTests/Seeders/EmployeeTestDataSeeder.cs @@ -1,8 +1,8 @@ namespace Faura.IntegrationTest.Seeders; using Faura.Infrastructure.IntegrationTesting.Seeders; -using Faura.WebAPI.Domain; using Faura.WebAPI.Domain.Entities; +using Faura.WebAPI.Domain.Repositories; using Faura.WebAPI.Infrastructure.Persistence; using Microsoft.Extensions.DependencyInjection; diff --git a/src/Templates/Faura.WebAPI.IntegrationTests/UseCases/EmployeeTests.cs b/src/Templates/Faura.WebAPI.IntegrationTests/UseCases/EmployeeTests.cs new file mode 100644 index 0000000..57e4215 --- /dev/null +++ b/src/Templates/Faura.WebAPI.IntegrationTests/UseCases/EmployeeTests.cs @@ -0,0 +1,92 @@ +namespace Faura.IntegrationTest.UseCases; + +using System.Net; +using System.Net.Http.Json; +using Faura.IntegrationTest.Configuration; +using Faura.WebAPI.Domain.Entities; +using Xunit; + +public class EmployeeTests : IClassFixture> +{ + private readonly HttpClient _client; + + public EmployeeTests(CustomWebApplicationFactory factory) + => _client = factory.CreateClient(); + + [Fact] + public async Task Should_Get_Employees() + { + // Act + var response = await _client.GetAsync("/Employee"); + + // Assert + response.EnsureSuccessStatusCode(); + var employees = await response.Content.ReadFromJsonAsync>(); + + Assert.NotNull(employees); + } + + [Fact] + public async Task Should_Create_Employee() + { + // Arrange + var newEmployee = new Employee("Test", "User", "test.user@example.com"); + + // Act + var response = await _client.PostAsJsonAsync("/Employee", newEmployee); + + // Assert + response.EnsureSuccessStatusCode(); + var created = await response.Content.ReadFromJsonAsync(); + + Assert.NotNull(created); + Assert.Equal(newEmployee.Email, created?.Email); + } + + [Fact] + public async Task Should_Get_Employee_By_Id() + { + // Arrange + var employee = new Employee("Get", "ById", "get.byid@example.com"); + var post = await _client.PostAsJsonAsync("/Employee", employee); + var created = await post.Content.ReadFromJsonAsync(); + + // Act + var response = await _client.GetAsync($"/Employee/{created!.Id}"); + + // Assert + response.EnsureSuccessStatusCode(); + var result = await response.Content.ReadFromJsonAsync(); + Assert.Equal(created.Id, result?.Id); + } + + [Fact] + public async Task Should_Delete_Employee() + { + // Arrange + var employee = new Employee("To", "Delete", "to.delete@example.com"); + var post = await _client.PostAsJsonAsync("/Employee", employee); + var created = await post.Content.ReadFromJsonAsync(); + + // Act + var delete = await _client.DeleteAsync($"/Employee/{created!.Id}"); + + // Assert + Assert.Equal(HttpStatusCode.NoContent, delete.StatusCode); + + var get = await _client.GetAsync($"/Employee/{created.Id}"); + Assert.Equal(HttpStatusCode.NotFound, get.StatusCode); + } + + [Fact] + public async Task Should_Create_Two_Employees_In_Transaction() + { + // Act + var response = await _client.PostAsync("/Employee/batch", null); + + // Assert + response.EnsureSuccessStatusCode(); + var result = await response.Content.ReadAsStringAsync(); + Assert.Equal("Two employees created in transaction.", result.Trim()); + } +} diff --git a/src/Templates/Faura.IntegrationTest/appsettings.Test.json b/src/Templates/Faura.WebAPI.IntegrationTests/appsettings.Test.json similarity index 100% rename from src/Templates/Faura.IntegrationTest/appsettings.Test.json rename to src/Templates/Faura.WebAPI.IntegrationTests/appsettings.Test.json diff --git a/src/Templates/Faura.WebAPI.UnitTests/EmployeeControllerTests.cs b/src/Templates/Faura.WebAPI.UnitTests/EmployeeControllerTests.cs new file mode 100644 index 0000000..4c50a81 --- /dev/null +++ b/src/Templates/Faura.WebAPI.UnitTests/EmployeeControllerTests.cs @@ -0,0 +1,127 @@ +namespace Faura.WebAPI.Tests.Controllers; + +using System; +using System.Collections.Generic; +using System.Data; +using System.Threading.Tasks; +using Faura.WebAPI.Controllers; +using Faura.WebAPI.Domain.Entities; +using Faura.WebAPI.Domain.Repositories; +using Faura.WebAPI.Infrastructure.Persistence; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging; +using NSubstitute; +using Xunit; + +public class EmployeeControllerTests +{ + private readonly ILogger _logger = Substitute.For>(); + private readonly IEmployeeRepository _repository = Substitute.For(); + private readonly IEmployeeUoW _uow = Substitute.For(); + private readonly EmployeeController _controller; + + public EmployeeControllerTests() + => _controller = new EmployeeController(_logger, _repository, _uow); + + [Fact] + public async Task Get_ReturnsEmployees() + { + // Arrange + var employees = new List { new("Josep", "Ferrandis", "test@example.com") }; + _repository.GetAsync().Returns(employees); + + // Act + var result = await _controller.Get(); + + // Assert + var okResult = Assert.IsType(result); + Assert.Equal(employees, okResult.Value); + } + + [Fact] + public async Task Create_ReturnsCreatedAtAction() + { + // Arrange + var employee = new Employee("Test", "User", "test@domain.com"); + await _repository.CreateAsync(employee); + + // Act + var result = await _controller.Create(employee); + + // Assert + var created = Assert.IsType(result); + Assert.Equal(nameof(_controller.GetById), created.ActionName); + Assert.Equal(employee, created.Value); + } + + [Fact] + public async Task CreateBatch_CreatesTwoEmployeesAndCommitsTransaction() + { + // Arrange + var fakeTransaction = Substitute.For(); + _uow.GetDbTransaction(Arg.Any()).Returns(fakeTransaction); + + // Act + var result = await _controller.CreateBatch(); + + // Assert + await _repository.Received(2).CreateAsync(Arg.Is(e => + e.FirstName == "Josep" && e.LastName == "Ferrandis" && e.Email.StartsWith("josep"))); + + await _uow.Received(1).CommitTransaction(fakeTransaction); + + var okResult = Assert.IsType(result); + Assert.Equal("Two employees created in transaction.", okResult.Value); + } + + [Fact] + public async Task GetById_EmployeeExists_ReturnsOk() + { + // Arrange + var id = 1; + var employee = new Employee("A", "B", "a@b.com") { Id = id }; + _repository.GetByIdAsync(id).Returns(employee); + + // Act + var result = await _controller.GetById(id); + + // Assert + var ok = Assert.IsType(result); + Assert.Equal(employee, ok.Value); + } + + [Fact] + public async Task GetById_EmployeeNotFound_ReturnsNotFound() + { + var id = 1; + _repository.GetByIdAsync(id).Returns((Employee?)null); + + var result = await _controller.GetById(id); + + Assert.IsType(result); + } + + [Fact] + public async Task Delete_EmployeeExists_DeletesAndReturnsNoContent() + { + var id = 1; + var employee = new Employee("Del", "Ete", "del@ete.com") { Id = id }; + _repository.GetByIdAsync(id).Returns(employee); + + var result = await _controller.Delete(id); + + await _repository.Received(1).DeleteAsync(employee); + Assert.IsType(result); + } + + [Fact] + public async Task Delete_EmployeeNotFound_ReturnsNotFound() + { + var id = 1; + _repository.GetByIdAsync(id).Returns((Employee?)null); + + var result = await _controller.Delete(id); + + Assert.IsType(result); + } +} diff --git a/src/Templates/Faura.WebAPI.UnitTests/Faura.WebAPI.UnitTests.csproj b/src/Templates/Faura.WebAPI.UnitTests/Faura.WebAPI.UnitTests.csproj new file mode 100644 index 0000000..85bea97 --- /dev/null +++ b/src/Templates/Faura.WebAPI.UnitTests/Faura.WebAPI.UnitTests.csproj @@ -0,0 +1,20 @@ + + + + net8.0 + enable + enable + false + true + + + + + + + + + + + + diff --git a/src/Templates/Faura.WebAPI/Bootstrappers/ApplicationBootstrapper.cs b/src/Templates/Faura.WebAPI/Bootstrappers/ApplicationBootstrapper.cs index 67520e4..f42a882 100644 --- a/src/Templates/Faura.WebAPI/Bootstrappers/ApplicationBootstrapper.cs +++ b/src/Templates/Faura.WebAPI/Bootstrappers/ApplicationBootstrapper.cs @@ -3,8 +3,9 @@ namespace Faura.WebAPI.Bootstrappers; using Faura.Infrastructure.UnitOfWork; using Faura.Infrastructure.UnitOfWork.Common; using Faura.Infrastructure.UnitOfWork.Enums; -using Faura.WebAPI.Domain; +using Faura.WebAPI.Domain.Repositories; using Faura.WebAPI.Infrastructure.Persistence; +using Faura.WebAPI.Infrastructure.Repositories; public static class ApplicationBootstrapper { diff --git a/src/Templates/Faura.WebAPI/Controllers/EmployeeController.cs b/src/Templates/Faura.WebAPI/Controllers/EmployeeController.cs new file mode 100644 index 0000000..baa178b --- /dev/null +++ b/src/Templates/Faura.WebAPI/Controllers/EmployeeController.cs @@ -0,0 +1,65 @@ +namespace Faura.WebAPI.Controllers; + +using Faura.Infrastructure.Logger.Extensions; +using Faura.WebAPI.Domain.Entities; +using Faura.WebAPI.Domain.Repositories; +using Faura.WebAPI.Infrastructure.Persistence; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging; + +[ApiController] +[Route("[controller]")] +public class EmployeeController( + ILogger logger, + IEmployeeRepository employeeRepository, + IEmployeeUoW uoW) + : ControllerBase +{ + [HttpGet(Name = "GetEmployees")] + public async Task Get() + { + logger.LogFauraInformation("Getting all employees"); + var employees = await employeeRepository.GetAsync(); + return Ok(employees); + } + + [HttpPost("batch")] + public async Task CreateBatch() + { + logger.LogFauraInformation("Creating two employees in a transaction"); + + var transaction = await uoW.GetDbTransaction(); + + await employeeRepository.CreateAsync(new Employee("Josep", "Ferrandis", "josep1@example.com")); + await employeeRepository.CreateAsync(new Employee("Josep", "Ferrandis", "josep2@example.com")); + + await uoW.CommitTransaction(transaction); + + return Ok("Two employees created in transaction."); + } + + [HttpPost] + public async Task Create([FromBody] Employee employee) + { + await employeeRepository.CreateAsync(employee); + return CreatedAtAction(nameof(GetById), new { id = employee.Id }, employee); + } + + [HttpGet("{id}")] + public async Task GetById(long id) + { + var employee = await employeeRepository.GetByIdAsync(id); + return employee is not null ? Ok(employee) : NotFound(); + } + + [HttpDelete("{id}")] + public async Task Delete(long id) + { + var employee = await employeeRepository.GetByIdAsync(id); + if (employee is null) + return NotFound(); + + await employeeRepository.DeleteAsync(employee); + return NoContent(); + } +} diff --git a/src/Templates/Faura.WebAPI/Controllers/WeatherForecast.cs b/src/Templates/Faura.WebAPI/Controllers/WeatherForecast.cs deleted file mode 100644 index 0664827..0000000 --- a/src/Templates/Faura.WebAPI/Controllers/WeatherForecast.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace Faura.WebAPI.Controllers; - -public class WeatherForecast -{ - public DateOnly Date { get; set; } - - public int TemperatureC { get; set; } - - public int TemperatureF => 32 + (int)(TemperatureC / 0.5556); - - public string? Summary { get; set; } -} diff --git a/src/Templates/Faura.WebAPI/Controllers/WeatherForecastController.cs b/src/Templates/Faura.WebAPI/Controllers/WeatherForecastController.cs deleted file mode 100644 index dfae535..0000000 --- a/src/Templates/Faura.WebAPI/Controllers/WeatherForecastController.cs +++ /dev/null @@ -1,37 +0,0 @@ -namespace Faura.WebAPI.Controllers; - -using Faura.Infrastructure.Logger.Extensions; -using Faura.WebAPI.Domain; -using Faura.WebAPI.Domain.Entities; -using Faura.WebAPI.Infrastructure.Persistence; -using Microsoft.AspNetCore.Mvc; -using Microsoft.Extensions.Logging; - -[ApiController] -[Route("[controller]")] -public class WeatherForecastController( - ILogger logger, - IEmployeeRepository employeeRepository, - IEmployeeUoW uoW) - : ControllerBase -{ - [HttpGet(Name = "GetWeatherForecast")] - public async Task Get() - { - logger.LogFauraInformation("Starting Get"); - - await employeeRepository.GetAsync(); - - var transaction = await uoW.GetDbTransaction(); - - await employeeRepository.CreateAsync( - new Employee("Josep", "Ferrandis", "algo@example.com")); - - await employeeRepository.CreateAsync( - new Employee("Josep", "Ferrandis", "algo@example.com")); - - await uoW.CommitTransaction(transaction); - - return Ok(); - } -} diff --git a/src/Templates/Faura.WebAPI/Domain/IEmployeeRepository.cs b/src/Templates/Faura.WebAPI/Domain/Repositories/IEmployeeRepository.cs similarity index 64% rename from src/Templates/Faura.WebAPI/Domain/IEmployeeRepository.cs rename to src/Templates/Faura.WebAPI/Domain/Repositories/IEmployeeRepository.cs index 26c8d0a..24618aa 100644 --- a/src/Templates/Faura.WebAPI/Domain/IEmployeeRepository.cs +++ b/src/Templates/Faura.WebAPI/Domain/Repositories/IEmployeeRepository.cs @@ -1,8 +1,9 @@ -namespace Faura.WebAPI.Domain; +namespace Faura.WebAPI.Domain.Repositories; using Faura.Infrastructure.UnitOfWork.Repositories; using Faura.WebAPI.Domain.Entities; public interface IEmployeeRepository : IEntityRepository { + Task GetByIdAsync(long id); } diff --git a/src/Templates/Faura.WebAPI/Faura.WebAPI.csproj b/src/Templates/Faura.WebAPI/Faura.WebAPI.csproj index 0a26370..948f62a 100644 --- a/src/Templates/Faura.WebAPI/Faura.WebAPI.csproj +++ b/src/Templates/Faura.WebAPI/Faura.WebAPI.csproj @@ -19,4 +19,17 @@ + + + **/Bootstrappers/*.cs + **/Domain/*.cs + **/Persistence/*.cs + **/**/Program.cs + + + + + + + diff --git a/src/Templates/Faura.WebAPI/Domain/EmployeeRepository.cs b/src/Templates/Faura.WebAPI/Infrastructure/Repositories/EmployeeRepository.cs similarity index 65% rename from src/Templates/Faura.WebAPI/Domain/EmployeeRepository.cs rename to src/Templates/Faura.WebAPI/Infrastructure/Repositories/EmployeeRepository.cs index e8edd06..b33aa70 100644 --- a/src/Templates/Faura.WebAPI/Domain/EmployeeRepository.cs +++ b/src/Templates/Faura.WebAPI/Infrastructure/Repositories/EmployeeRepository.cs @@ -1,7 +1,9 @@ -namespace Faura.WebAPI.Domain; +namespace Faura.WebAPI.Infrastructure.Repositories; +using System.Threading.Tasks; using Faura.Infrastructure.UnitOfWork.Repositories; using Faura.WebAPI.Domain.Entities; +using Faura.WebAPI.Domain.Repositories; using Faura.WebAPI.Infrastructure.Persistence; public class EmployeeRepository : EntityRepository, IEmployeeRepository @@ -13,4 +15,7 @@ public EmployeeRepository( : base(dbContext, logger, enableTracking) { } + + public Task GetByIdAsync(long id) + => GetFirstOrDefaultAsync(e => e.Id == id); } From 69a210aa953ddc5c0694775993fa0d315db83d8b Mon Sep 17 00:00:00 2001 From: JosepFe Date: Sun, 15 Jun 2025 19:47:27 +0200 Subject: [PATCH 05/13] upload sonar coverage --- .github/workflows/sonarcloud.yml | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/.github/workflows/sonarcloud.yml b/.github/workflows/sonarcloud.yml index 85a8338..7f9b620 100644 --- a/.github/workflows/sonarcloud.yml +++ b/.github/workflows/sonarcloud.yml @@ -36,11 +36,20 @@ jobs: /k:"JosepFe_faura" \ /o:"josepfe" \ /d:sonar.login="${SONAR_TOKEN}" \ - /d:sonar.host.url="https://sonarcloud.io" + /d:sonar.host.url="https://sonarcloud.io" \ + /d:sonar.cs.opencover.reportsPaths="**/coverage.opencover.xml" - name: Build solution run: dotnet build src/Faura.sln --no-restore --no-incremental + - name: Test with coverage + run: | + dotnet test src/Faura.sln --no-build --configuration Release \ + /p:CollectCoverage=true \ + /p:CoverletOutputFormat=opencover \ + /p:CoverletOutput=TestResults/coverage. \ + /p:Exclude="[xunit.*]*" + - name: End SonarCloud Analysis env: SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} From def553ef8f2a5d47315ca7b2f0888f6ff1448be6 Mon Sep 17 00:00:00 2001 From: JosepFe Date: Sun, 15 Jun 2025 20:03:55 +0200 Subject: [PATCH 06/13] test coverage --- .github/workflows/sonarcloud.yml | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/.github/workflows/sonarcloud.yml b/.github/workflows/sonarcloud.yml index 7f9b620..e356c5f 100644 --- a/.github/workflows/sonarcloud.yml +++ b/.github/workflows/sonarcloud.yml @@ -28,7 +28,7 @@ jobs: - name: Restore dependencies run: dotnet restore src/Faura.sln - - name: Begin SonarCloud Analysis + - name: Begin SonarCloud analysis env: SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} run: | @@ -37,18 +37,25 @@ jobs: /o:"josepfe" \ /d:sonar.login="${SONAR_TOKEN}" \ /d:sonar.host.url="https://sonarcloud.io" \ - /d:sonar.cs.opencover.reportsPaths="**/coverage.opencover.xml" + /d:sonar.cs.opencover.reportsPaths="coverage/combined/coverage.opencover.xml" - name: Build solution run: dotnet build src/Faura.sln --no-restore --no-incremental - - name: Test with coverage + - name: Run Unit Tests with Coverage (WebAPI) run: | - dotnet test src/Faura.sln --no-build --configuration Release \ + dotnet test src/Templates/Faura.WebAPI.UnitTests/Faura.WebAPI.UnitTests.csproj \ + --no-build --configuration Release \ /p:CollectCoverage=true \ /p:CoverletOutputFormat=opencover \ - /p:CoverletOutput=TestResults/coverage. \ - /p:Exclude="[xunit.*]*" + /p:CoverletOutput=coverage/webapi/ + + - name: Merge coverage reports + run: | + ~/.dotnet/tools/reportgenerator \ + -reports:"coverage/**/coverage.opencover.xml" \ + -targetdir:"coverage/combined" \ + -reporttypes:Html - name: End SonarCloud Analysis env: From 8661a8ca15c0467c19c7a36d2b60a6983fcc09be Mon Sep 17 00:00:00 2001 From: JosepFe Date: Sun, 15 Jun 2025 20:08:23 +0200 Subject: [PATCH 07/13] update pipeline --- .github/workflows/sonarcloud.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/sonarcloud.yml b/.github/workflows/sonarcloud.yml index e356c5f..babbdb0 100644 --- a/.github/workflows/sonarcloud.yml +++ b/.github/workflows/sonarcloud.yml @@ -45,7 +45,7 @@ jobs: - name: Run Unit Tests with Coverage (WebAPI) run: | dotnet test src/Templates/Faura.WebAPI.UnitTests/Faura.WebAPI.UnitTests.csproj \ - --no-build --configuration Release \ + --configuration Release \ /p:CollectCoverage=true \ /p:CoverletOutputFormat=opencover \ /p:CoverletOutput=coverage/webapi/ From d6b19176328e82321a874cf5fd2ced89cdabf00a Mon Sep 17 00:00:00 2001 From: JosepFe Date: Sun, 15 Jun 2025 20:11:14 +0200 Subject: [PATCH 08/13] pipeline --- .github/workflows/sonarcloud.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/sonarcloud.yml b/.github/workflows/sonarcloud.yml index babbdb0..19e23c1 100644 --- a/.github/workflows/sonarcloud.yml +++ b/.github/workflows/sonarcloud.yml @@ -44,7 +44,7 @@ jobs: - name: Run Unit Tests with Coverage (WebAPI) run: | - dotnet test src/Templates/Faura.WebAPI.UnitTests/Faura.WebAPI.UnitTests.csproj \ + dotnet test src/Templates/FFaura.WebAPI.IntegrationTests/Faura.WebAPI.IntegrationTests.csproj \ --configuration Release \ /p:CollectCoverage=true \ /p:CoverletOutputFormat=opencover \ From 2921634aaa661243ea0ef5f084b8bd92347fea52 Mon Sep 17 00:00:00 2001 From: JosepFe Date: Sun, 15 Jun 2025 20:12:35 +0200 Subject: [PATCH 09/13] pipeline --- .github/workflows/sonarcloud.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/sonarcloud.yml b/.github/workflows/sonarcloud.yml index 19e23c1..1fb9023 100644 --- a/.github/workflows/sonarcloud.yml +++ b/.github/workflows/sonarcloud.yml @@ -44,7 +44,7 @@ jobs: - name: Run Unit Tests with Coverage (WebAPI) run: | - dotnet test src/Templates/FFaura.WebAPI.IntegrationTests/Faura.WebAPI.IntegrationTests.csproj \ + dotnet test src/Templates/Faura.WebAPI.IntegrationTests/Faura.WebAPI.IntegrationTests.csproj \ --configuration Release \ /p:CollectCoverage=true \ /p:CoverletOutputFormat=opencover \ From 3bb3a2f8211e2e8c61a805fb7b567be3d2b7ec6b Mon Sep 17 00:00:00 2001 From: JosepFe Date: Sun, 15 Jun 2025 20:18:51 +0200 Subject: [PATCH 10/13] pipeline --- .github/workflows/sonarcloud.yml | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/.github/workflows/sonarcloud.yml b/.github/workflows/sonarcloud.yml index 1fb9023..0719692 100644 --- a/.github/workflows/sonarcloud.yml +++ b/.github/workflows/sonarcloud.yml @@ -22,8 +22,13 @@ jobs: with: dotnet-version: '8.0.x' - - name: Install SonarScanner - run: dotnet tool install --global dotnet-sonarscanner + - name: Install global tools (SonarScanner + ReportGenerator) + run: | + dotnet tool install --global dotnet-sonarscanner + dotnet tool install --global dotnet-reportgenerator-globaltool + + - name: Add tool path to environment + run: echo "$HOME/.dotnet/tools" >> $GITHUB_PATH - name: Restore dependencies run: dotnet restore src/Faura.sln @@ -40,23 +45,37 @@ jobs: /d:sonar.cs.opencover.reportsPaths="coverage/combined/coverage.opencover.xml" - name: Build solution - run: dotnet build src/Faura.sln --no-restore --no-incremental + run: dotnet build src/Faura.sln --no-restore --configuration Release - name: Run Unit Tests with Coverage (WebAPI) + run: | + dotnet test src/Templates/Faura.WebAPI.UnitTests/Faura.WebAPI.UnitTests.csproj \ + --configuration Release \ + /p:CollectCoverage=true \ + /p:CoverletOutputFormat=opencover \ + /p:CoverletOutput=coverage/unit/ + + - name: Run Integration Tests with Coverage (Testcontainers) run: | dotnet test src/Templates/Faura.WebAPI.IntegrationTests/Faura.WebAPI.IntegrationTests.csproj \ --configuration Release \ /p:CollectCoverage=true \ /p:CoverletOutputFormat=opencover \ - /p:CoverletOutput=coverage/webapi/ - + /p:CoverletOutput=coverage/integration/ + - name: Merge coverage reports run: | - ~/.dotnet/tools/reportgenerator \ + reportgenerator \ -reports:"coverage/**/coverage.opencover.xml" \ -targetdir:"coverage/combined" \ -reporttypes:Html + - name: Upload Coverage Report Artifact + uses: actions/upload-artifact@v4 + with: + name: CoverageReport + path: coverage/combined + - name: End SonarCloud Analysis env: SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} From 28d69f7ca64b614bc3d821cce21c45a0e8598943 Mon Sep 17 00:00:00 2001 From: JosepFe Date: Sun, 15 Jun 2025 20:48:51 +0200 Subject: [PATCH 11/13] pipeline --- .../CustomWebApplicationFactory.cs | 31 ++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/src/Templates/Faura.WebAPI.IntegrationTests/Configuration/CustomWebApplicationFactory.cs b/src/Templates/Faura.WebAPI.IntegrationTests/Configuration/CustomWebApplicationFactory.cs index 78ff953..5f4c085 100644 --- a/src/Templates/Faura.WebAPI.IntegrationTests/Configuration/CustomWebApplicationFactory.cs +++ b/src/Templates/Faura.WebAPI.IntegrationTests/Configuration/CustomWebApplicationFactory.cs @@ -41,7 +41,7 @@ protected override async Task ConfigureTestContainersAsync( _postgresContainer = containerInstance.Container; - await containerInstance.StartAsync(); + await StartContainerWithRetriesAsync(containerInstance); return new ConfigurationBuilder() .AddConfiguration(configuration) @@ -68,4 +68,33 @@ protected override void ConfigureTestDatabase( DatabaseType.PostgreSQL, ServiceLifetime.Scoped); } + + private static async Task StartContainerWithRetriesAsync( + TestContainerInstance containerInstance) + where TConfig : ITestContainerConfiguration + { + const int maxRetries = 5; + var delay = TimeSpan.FromSeconds(5); + Exception? lastException = null; + + for (int attempt = 1; attempt <= maxRetries; attempt++) + { + try + { + Console.WriteLine($"Starting container (attempt {attempt}/{maxRetries})..."); + await containerInstance.StartAsync(); + Console.WriteLine($"Container started successfully."); + return; + } + catch (Exception ex) + { + lastException = ex; + Console.WriteLine($"Failed to start container: {ex.Message}"); + if (attempt < maxRetries) + await Task.Delay(delay); + } + } + + throw new InvalidOperationException($"Could not start container after {maxRetries} attempts.", lastException); + } } From a133618ef03c75a2127c0a6c584a2e365d409d79 Mon Sep 17 00:00:00 2001 From: JosepFe Date: Sun, 15 Jun 2025 20:50:54 +0200 Subject: [PATCH 12/13] pipeline --- .github/workflows/sonarcloud.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/sonarcloud.yml b/.github/workflows/sonarcloud.yml index 0719692..8766ab2 100644 --- a/.github/workflows/sonarcloud.yml +++ b/.github/workflows/sonarcloud.yml @@ -55,13 +55,13 @@ jobs: /p:CoverletOutputFormat=opencover \ /p:CoverletOutput=coverage/unit/ - - name: Run Integration Tests with Coverage (Testcontainers) - run: | - dotnet test src/Templates/Faura.WebAPI.IntegrationTests/Faura.WebAPI.IntegrationTests.csproj \ - --configuration Release \ - /p:CollectCoverage=true \ - /p:CoverletOutputFormat=opencover \ - /p:CoverletOutput=coverage/integration/ + # - name: Run Integration Tests with Coverage (Testcontainers) + # run: | + # dotnet test src/Templates/Faura.WebAPI.IntegrationTests/Faura.WebAPI.IntegrationTests.csproj \ + # --configuration Release \ + # /p:CollectCoverage=true \ + # /p:CoverletOutputFormat=opencover \ + # /p:CoverletOutput=coverage/integration/ - name: Merge coverage reports run: | From 9abd0692d9910e7225c901237a4402d267a12905 Mon Sep 17 00:00:00 2001 From: JosepFe Date: Sun, 15 Jun 2025 21:06:19 +0200 Subject: [PATCH 13/13] pipeline --- .github/workflows/sonarcloud.yml | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/.github/workflows/sonarcloud.yml b/.github/workflows/sonarcloud.yml index 8766ab2..49284a2 100644 --- a/.github/workflows/sonarcloud.yml +++ b/.github/workflows/sonarcloud.yml @@ -49,24 +49,19 @@ jobs: - name: Run Unit Tests with Coverage (WebAPI) run: | + mkdir -p coverage/unit dotnet test src/Templates/Faura.WebAPI.UnitTests/Faura.WebAPI.UnitTests.csproj \ --configuration Release \ /p:CollectCoverage=true \ /p:CoverletOutputFormat=opencover \ - /p:CoverletOutput=coverage/unit/ - - # - name: Run Integration Tests with Coverage (Testcontainers) - # run: | - # dotnet test src/Templates/Faura.WebAPI.IntegrationTests/Faura.WebAPI.IntegrationTests.csproj \ - # --configuration Release \ - # /p:CollectCoverage=true \ - # /p:CoverletOutputFormat=opencover \ - # /p:CoverletOutput=coverage/integration/ + /p:CoverletOutput=coverage/unit/ \ + --no-build - name: Merge coverage reports run: | + mkdir -p coverage/combined reportgenerator \ - -reports:"coverage/**/coverage.opencover.xml" \ + -reports:"coverage/unit/coverage.opencover.xml" \ -targetdir:"coverage/combined" \ -reporttypes:Html