From 54fdc6b81551f55c85a3862069af3e60f345f710 Mon Sep 17 00:00:00 2001
From: "oskar.dudycz" <oskar.dudycz@gmail.com>
Date: Sun, 16 May 2021 10:15:16 +0200
Subject: [PATCH] Updated project and test configuration to run migrations
 automatically

---
 Core.Marten/Config.cs                            |  7 +++++--
 Core.Testing/ApiFixture.cs                       |  2 ++
 Core.Testing/TestWebHostBuilder.cs               |  2 +-
 .../Meetings/CreateMeetingTests.cs               |  3 ---
 .../Meetings/ScheduleMeetingTests.cs             |  3 ---
 .../GetProductDetailsTests.cs                    |  2 --
 .../WarehouseTestWebHostBuilder.cs               | 13 ++++---------
 Sample/Warehouse/Warehouse.Api/Program.cs        |  9 +++------
 Sample/Warehouse/Warehouse/Configuration.cs      | 16 +++++++++++++++-
 .../Warehouse/Core/Extensions/HttpExtensions.cs  | 11 ++++++++---
 .../Core/Primitives/MappingExtensions.cs         |  2 +-
 .../Warehouse/Products/GettingProducts/Route.cs  |  3 +--
 Sample/Warehouse/Warehouse/Products/Product.cs   |  1 -
 13 files changed, 40 insertions(+), 34 deletions(-)

diff --git a/Core.Marten/Config.cs b/Core.Marten/Config.cs
index 5636cd7f8..1935438e9 100644
--- a/Core.Marten/Config.cs
+++ b/Core.Marten/Config.cs
@@ -53,8 +53,11 @@ private static void SetStoreOptions(StoreOptions options, Config config,
         {
             options.Connection(config.ConnectionString);
             options.AutoCreateSchemaObjects = AutoCreate.CreateOrUpdate;
-            options.Events.DatabaseSchemaName = config.WriteModelSchema;
-            options.DatabaseSchemaName = config.ReadModelSchema;
+
+            var schemaName = Environment.GetEnvironmentVariable("SchemaName");
+            options.Events.DatabaseSchemaName = schemaName ?? config.WriteModelSchema;
+            options.DatabaseSchemaName = schemaName ?? config.ReadModelSchema;
+
             options.UseDefaultSerialization(nonPublicMembersStorage: NonPublicMembersStorage.NonPublicSetters,
                 enumStorage: EnumStorage.AsString);
             options.PLV8Enabled = false;
diff --git a/Core.Testing/ApiFixture.cs b/Core.Testing/ApiFixture.cs
index b69738634..1ac0b8835 100644
--- a/Core.Testing/ApiFixture.cs
+++ b/Core.Testing/ApiFixture.cs
@@ -31,6 +31,8 @@ public abstract class ApiFixture: IAsyncLifetime
 
         protected ApiFixture()
         {
+            Environment.SetEnvironmentVariable("SchemaName", GetType().Name.ToLower());
+
             Sut = CreateTestContext();
         }
 
diff --git a/Core.Testing/TestWebHostBuilder.cs b/Core.Testing/TestWebHostBuilder.cs
index b0acae89d..3a2f643d4 100644
--- a/Core.Testing/TestWebHostBuilder.cs
+++ b/Core.Testing/TestWebHostBuilder.cs
@@ -15,7 +15,7 @@ public static IWebHostBuilder Create(Dictionary<string, string> configuration, A
             configureServices ??= _ => { };
 
             return new WebHostBuilder()
-                .UseEnvironment("Tests")
+                .UseEnvironment("Development")
                 .UseContentRoot(projectDir)
                 .UseConfiguration(new ConfigurationBuilder()
                     .SetBasePath(projectDir)
diff --git a/Sample/MeetingsManagement/MeetingsManagement.IntegrationTests/Meetings/CreateMeetingTests.cs b/Sample/MeetingsManagement/MeetingsManagement.IntegrationTests/Meetings/CreateMeetingTests.cs
index a9c09a011..05c6d4bae 100644
--- a/Sample/MeetingsManagement/MeetingsManagement.IntegrationTests/Meetings/CreateMeetingTests.cs
+++ b/Sample/MeetingsManagement/MeetingsManagement.IntegrationTests/Meetings/CreateMeetingTests.cs
@@ -45,7 +45,6 @@ public CreateMeetingTests(CreateMeetingFixture fixture)
         }
 
         [Fact]
-        [Trait("Category", "Exercise")]
         public async Task CreateCommand_ShouldReturn_CreatedStatus_With_MeetingId()
         {
             var commandResponse = fixture.CommandResponse;
@@ -58,7 +57,6 @@ public async Task CreateCommand_ShouldReturn_CreatedStatus_With_MeetingId()
         }
 
         [Fact]
-        [Trait("Category", "Exercise")]
         public void CreateCommand_ShouldPublish_MeetingCreateEvent()
         {
             // assert MeetingCreated event was produced to external bus
@@ -70,7 +68,6 @@ public void CreateCommand_ShouldPublish_MeetingCreateEvent()
         }
 
         [Fact]
-        [Trait("Category", "Exercise")]
         public async Task CreateCommand_ShouldUpdateReadModel()
         {
             // prepare query
diff --git a/Sample/MeetingsManagement/MeetingsManagement.IntegrationTests/Meetings/ScheduleMeetingTests.cs b/Sample/MeetingsManagement/MeetingsManagement.IntegrationTests/Meetings/ScheduleMeetingTests.cs
index 8b0f95412..d01fccfbd 100644
--- a/Sample/MeetingsManagement/MeetingsManagement.IntegrationTests/Meetings/ScheduleMeetingTests.cs
+++ b/Sample/MeetingsManagement/MeetingsManagement.IntegrationTests/Meetings/ScheduleMeetingTests.cs
@@ -53,7 +53,6 @@ public ScheduleMeetingTests(ScheduleMeetingFixture fixture)
         }
 
         [Fact]
-        [Trait("Category", "Exercise")]
         public async Task CreateMeeting_ShouldReturn_CreatedStatus_With_MeetingId()
         {
             var commandResponse = fixture.CreateMeetingCommandResponse.EnsureSuccessStatusCode();
@@ -64,7 +63,6 @@ public async Task CreateMeeting_ShouldReturn_CreatedStatus_With_MeetingId()
         }
 
         [Fact]
-        [Trait("Category", "Exercise")]
         public async Task ScheduleMeeting_ShouldSucceed()
         {
             var commandResponse = fixture.ScheduleMeetingCommandResponse.EnsureSuccessStatusCode();
@@ -75,7 +73,6 @@ public async Task ScheduleMeeting_ShouldSucceed()
         }
 
         [Fact]
-        [Trait("Category", "Exercise")]
         public async Task ScheduleMeeting_ShouldUpdateReadModel()
         {
             //send query
diff --git a/Sample/Warehouse/Warehouse.Api.Tests/Products/GettingProductDetails/GetProductDetailsTests.cs b/Sample/Warehouse/Warehouse.Api.Tests/Products/GettingProductDetails/GetProductDetailsTests.cs
index 5a9cb1bf3..4d629146d 100644
--- a/Sample/Warehouse/Warehouse.Api.Tests/Products/GettingProductDetails/GetProductDetailsTests.cs
+++ b/Sample/Warehouse/Warehouse.Api.Tests/Products/GettingProductDetails/GetProductDetailsTests.cs
@@ -1,12 +1,10 @@
 using System;
-using System.Collections.Generic;
 using System.Net;
 using System.Threading.Tasks;
 using Core.Testing;
 using FluentAssertions;
 using Microsoft.AspNetCore.Hosting;
 using Warehouse.Products.GettingProductDetails;
-using Warehouse.Products.GettingProducts;
 using Warehouse.Products.RegisteringProduct;
 using Xunit;
 
diff --git a/Sample/Warehouse/Warehouse.Api.Tests/WarehouseTestWebHostBuilder.cs b/Sample/Warehouse/Warehouse.Api.Tests/WarehouseTestWebHostBuilder.cs
index 4f3302874..d4616526b 100644
--- a/Sample/Warehouse/Warehouse.Api.Tests/WarehouseTestWebHostBuilder.cs
+++ b/Sample/Warehouse/Warehouse.Api.Tests/WarehouseTestWebHostBuilder.cs
@@ -1,5 +1,4 @@
-using Castle.Core.Configuration;
-using Core.WebApi.Middlewares.ExceptionHandling;
+using Core.WebApi.Middlewares.ExceptionHandling;
 using Microsoft.AspNetCore.Builder;
 using Microsoft.AspNetCore.Hosting;
 using Microsoft.EntityFrameworkCore;
@@ -18,8 +17,6 @@ public static IWebHostBuilder Configure(IWebHostBuilder webHostBuilder, string s
                 .ConfigureServices(services =>
                 {
                     services.AddRouting()
-                        .AddAuthorization()
-                        .AddCors()
                         .AddWarehouseServices()
                         .AddTransient<DbContextOptions<WarehouseDBContext>>(s =>
                         {
@@ -33,15 +30,13 @@ public static IWebHostBuilder Configure(IWebHostBuilder webHostBuilder, string s
                 })
                 .Configure(app =>
                 {
-                    app.UseHttpsRedirection()
-                        .UseMiddleware(typeof(ExceptionHandlingMiddleware))
+                    app.UseMiddleware(typeof(ExceptionHandlingMiddleware))
                         .UseRouting()
-                        .UseAuthorization()
-                        .UseEndpoints(endpoints => { endpoints.UseWarehouseEndpoints(); });
+                        .UseEndpoints(endpoints => { endpoints.UseWarehouseEndpoints(); })
+                        .ConfigureWarehouse();
 
                     // Kids, do not try this at home!
                     var database = app.ApplicationServices.GetRequiredService<WarehouseDBContext>().Database;
-                    database.Migrate();
                     database.ExecuteSqlRaw("TRUNCATE TABLE \"Product\"");
                 });
 
diff --git a/Sample/Warehouse/Warehouse.Api/Program.cs b/Sample/Warehouse/Warehouse.Api/Program.cs
index 359850504..bbd7f59da 100644
--- a/Sample/Warehouse/Warehouse.Api/Program.cs
+++ b/Sample/Warehouse/Warehouse.Api/Program.cs
@@ -12,20 +12,17 @@
             .ConfigureServices(services =>
             {
                 services.AddRouting()
-                    .AddCors()
-                    .AddAuthorization()
                     .AddWarehouseServices();
             })
             .Configure(app =>
             {
-                app.UseHttpsRedirection()
-                    .UseMiddleware(typeof(ExceptionHandlingMiddleware))
+                app.UseMiddleware(typeof(ExceptionHandlingMiddleware))
                     .UseRouting()
-                    .UseAuthorization()
                     .UseEndpoints(endpoints =>
                     {
                         endpoints.UseWarehouseEndpoints();
-                    });
+                    })
+                    .ConfigureWarehouse();
             });
     })
     .Build();
diff --git a/Sample/Warehouse/Warehouse/Configuration.cs b/Sample/Warehouse/Warehouse/Configuration.cs
index 626363940..403c14c0a 100644
--- a/Sample/Warehouse/Warehouse/Configuration.cs
+++ b/Sample/Warehouse/Warehouse/Configuration.cs
@@ -1,4 +1,6 @@
-using Microsoft.AspNetCore.Routing;
+using System;
+using Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.Routing;
 using Microsoft.EntityFrameworkCore;
 using Microsoft.Extensions.DependencyInjection;
 using Warehouse.Products;
@@ -16,5 +18,17 @@ public static IServiceCollection AddWarehouseServices(this IServiceCollection se
 
         public static IEndpointRouteBuilder UseWarehouseEndpoints(this IEndpointRouteBuilder endpoints)
             => endpoints.UseProductsEndpoints();
+
+        public static IApplicationBuilder ConfigureWarehouse(this IApplicationBuilder app)
+        {
+            var environment = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");
+
+            if (environment == "Development")
+            {
+                app.ApplicationServices.GetRequiredService<WarehouseDBContext>().Database.Migrate();
+            }
+
+            return app;
+        }
     }
 }
diff --git a/Sample/Warehouse/Warehouse/Core/Extensions/HttpExtensions.cs b/Sample/Warehouse/Warehouse/Core/Extensions/HttpExtensions.cs
index 52125983a..c8dbf755f 100644
--- a/Sample/Warehouse/Warehouse/Core/Extensions/HttpExtensions.cs
+++ b/Sample/Warehouse/Warehouse/Core/Extensions/HttpExtensions.cs
@@ -1,10 +1,11 @@
 using System;
 using System.ComponentModel;
-using System.Diagnostics.CodeAnalysis;
 using System.Net;
 using System.Threading.Tasks;
 using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Http.Headers;
 using Microsoft.Extensions.Primitives;
+using Microsoft.Net.Http.Headers;
 
 namespace Warehouse.Core.Extensions
 {
@@ -79,8 +80,12 @@ public static async Task<T> FromBody<T>(this HttpContext context)
         public static Task OK<T>(this HttpContext context, T result)
             => context.ReturnJSON(result);
 
-        public static Task Created<T>(this HttpContext context, T result)
-            => context.ReturnJSON(result, HttpStatusCode.Created);
+        public static Task Created<T>(this HttpContext context, T id, string? location = null)
+        {
+            context.Response.Headers[HeaderNames.Location] = location ?? $"{context.Request.Path}{id}";
+
+            return context.ReturnJSON(id, HttpStatusCode.Created);
+        }
 
         public static void NotFound(this HttpContext context)
             => context.Response.StatusCode = (int)HttpStatusCode.NotFound;
diff --git a/Sample/Warehouse/Warehouse/Core/Primitives/MappingExtensions.cs b/Sample/Warehouse/Warehouse/Core/Primitives/MappingExtensions.cs
index 89e89e358..53df141e3 100644
--- a/Sample/Warehouse/Warehouse/Core/Primitives/MappingExtensions.cs
+++ b/Sample/Warehouse/Warehouse/Core/Primitives/MappingExtensions.cs
@@ -14,7 +14,7 @@ public static T AssertNotNull<T>(this T? value, string? paramName = null)
         }
 
         public static string AssertNotEmpty(this string? value, string? paramName = null)
-            => string.IsNullOrWhiteSpace(value) ? value! : throw new ArgumentOutOfRangeException(paramName);
+            => !string.IsNullOrWhiteSpace(value) ? value : throw new ArgumentOutOfRangeException(paramName);
 
         public static T AssertNotEmpty<T>(this T value, string? paramName = null)
             where T : struct
diff --git a/Sample/Warehouse/Warehouse/Products/GettingProducts/Route.cs b/Sample/Warehouse/Warehouse/Products/GettingProducts/Route.cs
index d88eeb2e3..b1fc9df69 100644
--- a/Sample/Warehouse/Warehouse/Products/GettingProducts/Route.cs
+++ b/Sample/Warehouse/Warehouse/Products/GettingProducts/Route.cs
@@ -1,5 +1,4 @@
-using System;
-using System.Collections.Generic;
+using System.Collections.Generic;
 using Microsoft.AspNetCore.Builder;
 using Microsoft.AspNetCore.Routing;
 using Warehouse.Core.Extensions;
diff --git a/Sample/Warehouse/Warehouse/Products/Product.cs b/Sample/Warehouse/Warehouse/Products/Product.cs
index 8aadee1a3..cfef2a39e 100644
--- a/Sample/Warehouse/Warehouse/Products/Product.cs
+++ b/Sample/Warehouse/Warehouse/Products/Product.cs
@@ -1,5 +1,4 @@
 using System;
-using System.Text.Json.Serialization;
 using Warehouse.Products.Primitives;
 
 namespace Warehouse.Products