From cc3de887dfe553a013426a46b7b48a3c5000d003 Mon Sep 17 00:00:00 2001 From: iwedaz Date: Sun, 31 Dec 2023 15:57:36 +0100 Subject: [PATCH 1/3] Add .NET 8 TFM; Fix tests --- .../workflows/dotnet-core-pull-request.yml | 3 +- .github/workflows/dotnet-core.yml | 5 +- .../DotNetEd.CoreAdmin.DemoAppDotNet6.csproj | 14 +- .../DotNetEd.CoreAdmin.csproj | 13 +- ...tNetEd.CoreAdmin.IntegrationTestApp.csproj | 2 +- .../IntegrationTestStartup.cs | 61 ------- .../Program.cs | 66 ++++--- .../BasicTests.cs | 38 ++-- .../CrudTests.cs | 164 +++++++++++------- ...DotNetEd.CoreAdmin.IntegrationTests.csproj | 30 ++-- .../IntegrationTestsWebHostFactory.cs | 54 +----- .../OptionsTests.cs | 26 +-- .../SecurityTests.cs | 42 +++-- .../TestAppFixture.cs | 51 ++++++ 14 files changed, 300 insertions(+), 269 deletions(-) delete mode 100644 tests/DotNetEd.CoreAdmin.IntegrationTestApp/IntegrationTestStartup.cs create mode 100644 tests/DotNetEd.CoreAdmin.IntegrationTests/TestAppFixture.cs diff --git a/.github/workflows/dotnet-core-pull-request.yml b/.github/workflows/dotnet-core-pull-request.yml index b1c8251..1261010 100644 --- a/.github/workflows/dotnet-core-pull-request.yml +++ b/.github/workflows/dotnet-core-pull-request.yml @@ -13,11 +13,10 @@ jobs: - name: Setup .NET uses: actions/setup-dotnet@v3 with: - dotnet-version: 7.0.x + dotnet-version: 8.0.x - name: Install dependencies run: dotnet restore - name: Build run: dotnet build --configuration Release --no-restore - name: Test run: dotnet test --no-restore --verbosity normal - diff --git a/.github/workflows/dotnet-core.yml b/.github/workflows/dotnet-core.yml index 0c1ee1a..616d0c8 100644 --- a/.github/workflows/dotnet-core.yml +++ b/.github/workflows/dotnet-core.yml @@ -13,7 +13,7 @@ jobs: - name: Setup .NET uses: actions/setup-dotnet@v3 with: - dotnet-version: 7.0.x + dotnet-version: 8.0.x - name: Install dependencies run: dotnet restore - name: Build @@ -23,11 +23,10 @@ jobs: - name: Build solution and generate NuGet package run: | cd src\DotNetEd.CoreAdmin - dotnet pack -c Release -o out + dotnet pack -c Release -o out - name: Setup nuget uses: nuget/setup-nuget@v1 with: nuget-api-key: ${{ secrets.NUGET_API_KEY }} - name: Push generated package to Nuget run: nuget push src\DotNetEd.CoreAdmin\out\*.nupkg -SkipDuplicate -NoSymbols -Source https://api.nuget.org/v3/index.json - diff --git a/src/DotNetEd.CoreAdmin.DemoAppDotNet6/DotNetEd.CoreAdmin.DemoAppDotNet6.csproj b/src/DotNetEd.CoreAdmin.DemoAppDotNet6/DotNetEd.CoreAdmin.DemoAppDotNet6.csproj index bbc1d29..faebdbe 100644 --- a/src/DotNetEd.CoreAdmin.DemoAppDotNet6/DotNetEd.CoreAdmin.DemoAppDotNet6.csproj +++ b/src/DotNetEd.CoreAdmin.DemoAppDotNet6/DotNetEd.CoreAdmin.DemoAppDotNet6.csproj @@ -1,7 +1,7 @@  - net7.0 + net6.0;net7.0;net8.0 enable enable @@ -17,13 +17,15 @@ - - - - + + + + - + + + diff --git a/src/DotNetEd.CoreAdmin/DotNetEd.CoreAdmin.csproj b/src/DotNetEd.CoreAdmin/DotNetEd.CoreAdmin.csproj index c8c8056..a1c214e 100644 --- a/src/DotNetEd.CoreAdmin/DotNetEd.CoreAdmin.csproj +++ b/src/DotNetEd.CoreAdmin/DotNetEd.CoreAdmin.csproj @@ -1,16 +1,16 @@ - net6.0;net7.0 + net6.0;net7.0;net8.0 true false false CoreAdmin 2.7.1 - Automagically add an Admin Panel to your .NET 6 or .NET 7 web app. + Automagically add an Admin Panel to your .NET 6, .NET 7 or .NET 8 web app. Core Admin Panel for ASP.NET Core edandersen - Copyright ©2022 Ed Andersen + Copyright © 2024 Ed Andersen https://github.com/edandersen/core-admin LGPL-3.0-or-later disable @@ -44,9 +44,10 @@ - - - + + + + diff --git a/tests/DotNetEd.CoreAdmin.IntegrationTestApp/DotNetEd.CoreAdmin.IntegrationTestApp.csproj b/tests/DotNetEd.CoreAdmin.IntegrationTestApp/DotNetEd.CoreAdmin.IntegrationTestApp.csproj index ec6d0fa..29263c1 100644 --- a/tests/DotNetEd.CoreAdmin.IntegrationTestApp/DotNetEd.CoreAdmin.IntegrationTestApp.csproj +++ b/tests/DotNetEd.CoreAdmin.IntegrationTestApp/DotNetEd.CoreAdmin.IntegrationTestApp.csproj @@ -1,7 +1,7 @@  - net6.0 + net6.0;net7.0;net8.0 disable diff --git a/tests/DotNetEd.CoreAdmin.IntegrationTestApp/IntegrationTestStartup.cs b/tests/DotNetEd.CoreAdmin.IntegrationTestApp/IntegrationTestStartup.cs deleted file mode 100644 index 333ce05..0000000 --- a/tests/DotNetEd.CoreAdmin.IntegrationTestApp/IntegrationTestStartup.cs +++ /dev/null @@ -1,61 +0,0 @@ -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Hosting; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; -using System; -using System.Collections.Generic; -using System.Text; -using DotNetEd.CoreAdmin; -using Microsoft.Extensions.Hosting; -using DotNetEd.CoreAdmin.Controllers; -using Microsoft.AspNetCore.Mvc.Authorization; -using DotNetEd.CoreAdmin.IntegrationTestApp.Middleware; - -namespace DotNetEd.CoreAdmin.IntegrationTests.TestApp -{ - public class IntegrationTestStartup - { - public IntegrationTestStartup(IConfiguration configuration) - { - Configuration = configuration; - } - - public IConfiguration Configuration { get; } - - // This method gets called by the runtime. Use this method to add services to the container. - public void ConfigureServices(IServiceCollection services) - { - services.AddControllersWithViews().AddApplicationPart(typeof(CoreAdminDataController).Assembly); ; - } - - // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. - public void Configure(IApplicationBuilder app, IWebHostEnvironment env) - { - app.UseMiddleware(); - - if (env.IsDevelopment()) - { - app.UseDeveloperExceptionPage(); - } - else - { - app.UseExceptionHandler("/Home/Error"); - // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. - app.UseHsts(); - } - app.UseHttpsRedirection(); - // app.UseStaticFiles(); - - app.UseRouting(); - - app.UseAuthorization(); - - app.UseEndpoints(endpoints => - { - endpoints.MapControllerRoute( - name: "default", - pattern: "{controller=Home}/{action=Index}/{id?}"); - }); - } - } -} diff --git a/tests/DotNetEd.CoreAdmin.IntegrationTestApp/Program.cs b/tests/DotNetEd.CoreAdmin.IntegrationTestApp/Program.cs index 479efe0..92c1d50 100644 --- a/tests/DotNetEd.CoreAdmin.IntegrationTestApp/Program.cs +++ b/tests/DotNetEd.CoreAdmin.IntegrationTestApp/Program.cs @@ -1,27 +1,47 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using DotNetEd.CoreAdmin.IntegrationTests.TestApp; -using Microsoft.AspNetCore.Hosting; -using Microsoft.Extensions.Configuration; +using DotNetEd.CoreAdmin.Controllers; +using DotNetEd.CoreAdmin.IntegrationTestApp.Middleware; + +using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.Logging; -namespace DotNetEd.CoreAdmin.IntegrationTestApp + + +var builder = WebApplication.CreateBuilder(args); + +builder.Services.AddControllersWithViews().AddApplicationPart(typeof(CoreAdminDataController).Assembly); + + +var app = builder.Build(); + +app.UseMiddleware(); + +if (app.Environment.IsDevelopment()) +{ + app.UseDeveloperExceptionPage(); +} +else { - public class Program - { - public static void Main(string[] args) - { - CreateHostBuilder(args).Build().Run(); - } - - public static IHostBuilder CreateHostBuilder(string[] args) => - Host.CreateDefaultBuilder(args) - .ConfigureWebHostDefaults(webBuilder => - { - webBuilder.UseStartup(); - }); - } + app.UseExceptionHandler("/Home/Error"); + // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. + app.UseHsts(); } +app.UseHttpsRedirection(); +// app.UseStaticFiles(); + +app.UseRouting(); + +app.UseAuthorization(); + +app.UseEndpoints(endpoints => +{ + endpoints.MapControllerRoute( + name: "default", + pattern: "{controller=Home}/{action=Index}/{id?}"); +}); + +app.Run(); + + + +public partial class Program { } diff --git a/tests/DotNetEd.CoreAdmin.IntegrationTests/BasicTests.cs b/tests/DotNetEd.CoreAdmin.IntegrationTests/BasicTests.cs index f7c3a5c..8032158 100644 --- a/tests/DotNetEd.CoreAdmin.IntegrationTests/BasicTests.cs +++ b/tests/DotNetEd.CoreAdmin.IntegrationTests/BasicTests.cs @@ -1,20 +1,23 @@ -using DotNetEd.CoreAdmin.IntegrationTests.TestApp; +using System; +using System.Threading.Tasks; + using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.TestHost; using Microsoft.Extensions.DependencyInjection; -using System; -using System.Threading.Tasks; using Xunit; +using DotNetEd.CoreAdmin.IntegrationTests.TestApp; + + namespace DotNetEd.CoreAdmin.IntegrationTests { - public class BasicTests : IClassFixture> + public class BasicTests : IClassFixture { - private readonly IntegrationTestsWebHostFactory _factory; + private readonly TestAppFixture _fixture; - public BasicTests(IntegrationTestsWebHostFactory factory) + public BasicTests(TestAppFixture fixture) { - _factory = factory; + _fixture = fixture; } static void ConfigureTestServices(IServiceCollection services) { } @@ -23,7 +26,7 @@ static void ConfigureTestServices(IServiceCollection services) { } public async Task ShowsTestEntitiesOnScreenOnAdminScreen() { // Arrange - var client = _factory.WithWebHostBuilder(builder => { + var client = _fixture.Factory.WithWebHostBuilder(builder => { builder.UseEnvironment("Development"); builder.ConfigureTestServices(ConfigureTestServices); }).CreateClient(); @@ -45,21 +48,26 @@ public async Task ShowsTestEntitiesOnScreenOnAdminScreen() [Fact] public async Task ShowDataInDbSetOnScreen() { - var dbContext = _factory.Services.GetService(); - var idGuid = Guid.NewGuid(); - var nameGuidString = Guid.NewGuid().ToString(); - dbContext.TestEntities.Add(new TestApp.Entities.TestEntity() { Id = idGuid, Name = nameGuidString}); - await dbContext.SaveChangesAsync(); - // Arrange - var client = _factory.WithWebHostBuilder(builder => { + var client = _fixture.Factory.WithWebHostBuilder(builder => { builder.UseEnvironment("Development"); builder.ConfigureTestServices(ConfigureTestServices); }).CreateClient(); + var idGuid = Guid.NewGuid(); + var nameGuidString = Guid.NewGuid().ToString(); + + using (var scope = _fixture.Factory.Services.CreateScope()) + { + var dbContext = scope.ServiceProvider.GetRequiredService(); + dbContext.TestEntities.Add(new TestApp.Entities.TestEntity() { Id = idGuid, Name = nameGuidString }); + await dbContext.SaveChangesAsync(); + } + // Act var response = await client.GetAsync("/coreadmindata/index/testentities"); + // Assert response.EnsureSuccessStatusCode(); // Status Code 200-299 Assert.Equal("text/html; charset=utf-8", response.Content.Headers.ContentType.ToString()); diff --git a/tests/DotNetEd.CoreAdmin.IntegrationTests/CrudTests.cs b/tests/DotNetEd.CoreAdmin.IntegrationTests/CrudTests.cs index 01666b4..9903213 100644 --- a/tests/DotNetEd.CoreAdmin.IntegrationTests/CrudTests.cs +++ b/tests/DotNetEd.CoreAdmin.IntegrationTests/CrudTests.cs @@ -3,22 +3,25 @@ using System.Linq; using System.Net.Http; using System.Threading.Tasks; -using DotNetEd.CoreAdmin.IntegrationTests.TestApp; + using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.TestHost; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; using Xunit; +using DotNetEd.CoreAdmin.IntegrationTests.TestApp; + + namespace DotNetEd.CoreAdmin.IntegrationTests { - public class CrudTests : IClassFixture> + public class CrudTests : IClassFixture { - private readonly IntegrationTestsWebHostFactory _factory; + private readonly TestAppFixture _fixture; - public CrudTests(IntegrationTestsWebHostFactory factory) + public CrudTests(TestAppFixture fixture) { - _factory = factory; + _fixture = fixture; } static void ConfigureTestServices(IServiceCollection services) { } @@ -26,168 +29,209 @@ static void ConfigureTestServices(IServiceCollection services) { } [Fact] public async Task DeleteHappyPath() { - var dbContext = _factory.Services.GetService(); - var idGuid = Guid.NewGuid(); - var nameGuidString = Guid.NewGuid().ToString(); - dbContext.TestEntities.Add(new TestApp.Entities.TestEntity() { Id = idGuid, Name = nameGuidString}); - await dbContext.SaveChangesAsync(); - // Arrange - var client = _factory.WithWebHostBuilder(builder => { + var client = _fixture.Factory.WithWebHostBuilder(builder => { builder.UseEnvironment("Development"); builder.ConfigureTestServices(ConfigureTestServices); }).CreateClient(); + var idGuid = Guid.NewGuid(); + var nameGuidString = Guid.NewGuid().ToString(); + + using (var scope = _fixture.Factory.Services.CreateScope()) + { + var dbContext = scope.ServiceProvider.GetRequiredService(); + dbContext.TestEntities.Add(new TestApp.Entities.TestEntity() { Id = idGuid, Name = nameGuidString }); + await dbContext.SaveChangesAsync(); + } + + // Act // Do the post to delete the item client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("*/*")); var data = new Dictionary() { { "id", idGuid.ToString() }, { "dbSetName", "testentities" } }; var response = await client.PostAsync("/coreadmindata/DeleteEntityPost", new FormUrlEncodedContent(data)); + + // Assert response.EnsureSuccessStatusCode(); // check to see if the item is deleted from DB context - Assert.False(await dbContext.TestEntities.AnyAsync(test => test.Id == idGuid)); - + using (var scope = _fixture.Factory.Services.CreateScope()) + { + var dbContext = scope.ServiceProvider.GetRequiredService(); + Assert.False(await dbContext.TestEntities.AnyAsync(test => test.Id == idGuid)); + } } [Fact] public async Task CreateHappyPath() { - var dbContext = _factory.Services.GetService(); - var idGuid = Guid.NewGuid(); - var nameGuidString = Guid.NewGuid().ToString(); - // Arrange - var client = _factory.WithWebHostBuilder(builder => { + var client = _fixture.Factory.WithWebHostBuilder(builder => { builder.UseEnvironment("Development"); builder.ConfigureTestServices(ConfigureTestServices); }).CreateClient(); + var nameGuidString = Guid.NewGuid().ToString(); + + // Act // Do the post to delete the item client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("*/*")); var data = new Dictionary() { { "Name", nameGuidString }, { "Id", nameGuidString } }; var response = await client.PostAsync("/coreadmindata/CreateEntityPost/testentities?dbSetName=testentities", new FormUrlEncodedContent(data)); - response.EnsureSuccessStatusCode(); - - Assert.True(await dbContext.TestEntities.AnyAsync(test => test.Name == nameGuidString)); + // Assert + response.EnsureSuccessStatusCode(); + using (var scope = _fixture.Factory.Services.CreateScope()) + { + var dbContext = scope.ServiceProvider.GetRequiredService(); + Assert.True(await dbContext.TestEntities.AnyAsync(test => test.Name == nameGuidString)); + } } [Fact] public async Task Create_ChildEntityWithNonNullableFK_HappyPath() { - var dbContext = _factory.Services.GetService(); - var idGuid = Guid.NewGuid(); - var nameGuidString = Guid.NewGuid().ToString(); - // Arrange - var client = _factory.WithWebHostBuilder(builder => { + var client = _fixture.Factory.WithWebHostBuilder(builder => { builder.UseEnvironment("Development"); builder.ConfigureTestServices(ConfigureTestServices); }).CreateClient(); + + var idGuid = Guid.NewGuid(); + var nameGuidString = Guid.NewGuid().ToString(); + + // Act // Do the post to create the child item client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("*/*")); var data = new Dictionary() { { "Name", nameGuidString }, { "Id", nameGuidString } }; var response = await client.PostAsync("/coreadmindata/CreateEntityPost/testchildentities?dbSetName=testchildentities", new FormUrlEncodedContent(data)); + + // Assert response.EnsureSuccessStatusCode(); - Assert.True(await dbContext.TestChildEntities.AnyAsync(test => test.Name == nameGuidString)); + using (var scope = _fixture.Factory.Services.CreateScope()) + { + var dbContext = scope.ServiceProvider.GetRequiredService(); + Assert.True(await dbContext.TestChildEntities.AnyAsync(test => test.Name == nameGuidString)); + } var parentId = Guid.NewGuid(); data = new Dictionary() { { "ParentId", parentId.ToString() }, { "ChildId", idGuid.ToString() }, { "dbSetName", "testparententities" } }; response = await client.PostAsync("/coreadmindata/CreateEntityPost/testparententities", new FormUrlEncodedContent(data)); - - response.EnsureSuccessStatusCode(); - Assert.True(await dbContext.TestParentEntities.AnyAsync(test => test.ChildId == idGuid)); + response.EnsureSuccessStatusCode(); + using (var scope = _fixture.Factory.Services.CreateScope()) + { + var dbContext = scope.ServiceProvider.GetRequiredService(); + Assert.True(await dbContext.TestParentEntities.AnyAsync(test => test.ChildId == idGuid)); + } } [Fact] public async Task CreateTestEntityWithValidationError_TooLongName() { - var dbContext = _factory.Services.GetService(); - var idGuid = Guid.NewGuid(); - var nameString = new string('*', 5000); // Name should have MaxLength(100) - // Arrange - var client = _factory.WithWebHostBuilder(builder => { + var client = _fixture.Factory.WithWebHostBuilder(builder => { builder.UseEnvironment("Development"); builder.ConfigureTestServices(ConfigureTestServices); }).CreateClient(); + + var idGuid = Guid.NewGuid(); + var nameString = new string('*', 5000); // Name should have MaxLength(100) + + // Act // Do the post to delete the item client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("*/*")); var data = new Dictionary() { { "Name", nameString }, { "Id", idGuid.ToString() } }; var response = await client.PostAsync("/coreadmindata/CreateEntityPost/testentities?dbSetName=testentities", new FormUrlEncodedContent(data)); + + // Assert response.EnsureSuccessStatusCode(); // make sure it has not written to DB - Assert.False(await dbContext.TestEntities.AnyAsync(test => test.Name == nameString)); - + using (var scope = _fixture.Factory.Services.CreateScope()) + { + var dbContext = scope.ServiceProvider.GetRequiredService(); + Assert.False(await dbContext.TestEntities.AnyAsync(test => test.Name == nameString)); + } } [Fact] public async Task CreateHappyPath_WithAutogeneratedKey() { - var dbContext = _factory.Services.GetService(); - // var idGuid = Guid.NewGuid(); - var nameGuidString = Guid.NewGuid().ToString(); - // Arrange - var client = _factory.WithWebHostBuilder(builder => { + var client = _fixture.Factory.WithWebHostBuilder(builder => { builder.UseEnvironment("Development"); builder.ConfigureTestServices(ConfigureTestServices); }).CreateClient(); + var nameGuidString = Guid.NewGuid().ToString(); + + // Act // Do the post to delete the item client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("*/*")); var data = new Dictionary() { { "Name", nameGuidString } }; var response = await client.PostAsync("/coreadmindata/CreateEntityPost/TestAutogeneratedKeyEntities?dbSetName=TestAutogeneratedKeyEntities", new FormUrlEncodedContent(data)); - response.EnsureSuccessStatusCode(); + // Assert + response.EnsureSuccessStatusCode(); - Assert.True(await dbContext.TestAutogeneratedKeyEntities.AnyAsync(test => test.Name == nameGuidString)); - + using (var scope = _fixture.Factory.Services.CreateScope()) + { + var dbContext = scope.ServiceProvider.GetRequiredService(); + Assert.True(await dbContext.TestAutogeneratedKeyEntities.AnyAsync(test => test.Name == nameGuidString)); + } } [Fact] public async Task UpdateHappyPath() { - var dbContext = _factory.Services.GetService(); - var idGuid = Guid.NewGuid(); - var nameGuidString = Guid.NewGuid().ToString(); - dbContext.TestEntities.Add(new TestApp.Entities.TestEntity() { Id = idGuid, Name = nameGuidString}); - await dbContext.SaveChangesAsync(); - - var updatedNameGuid = Guid.NewGuid().ToString(); - // Arrange - var client = _factory.WithWebHostBuilder(builder => { + var client = _fixture.Factory.WithWebHostBuilder(builder => { builder.UseEnvironment("Development"); builder.ConfigureTestServices(ConfigureTestServices); }).CreateClient(); + var idGuid = Guid.NewGuid(); + var nameGuidString = Guid.NewGuid().ToString(); + var updatedNameGuid = Guid.NewGuid().ToString(); + + using (var scope = _fixture.Factory.Services.CreateScope()) + { + var dbContext = scope.ServiceProvider.GetRequiredService(); + dbContext.TestEntities.Add(new TestApp.Entities.TestEntity() { Id = idGuid, Name = nameGuidString}); + await dbContext.SaveChangesAsync(); + } + + // Act // Do the post to update the item client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("*/*")); var data = new Dictionary() { { "Name", updatedNameGuid }, { "Id", idGuid.ToString() } }; var response = await client.PostAsync("/coreadmindata/editentityPost/" + idGuid.ToString() + "?dbSetName=TestEntities", new FormUrlEncodedContent(data)); + + // Assert response.EnsureSuccessStatusCode(); // check to see if the item is updated from DB context - var foundEntity = dbContext.TestEntities.First(e => e.Id == idGuid); - dbContext.Entry(foundEntity).Reload(); - Assert.True(dbContext.TestEntities.First(e => e.Id == idGuid).Name == updatedNameGuid); - + using (var scope = _fixture.Factory.Services.CreateScope()) + { + var dbContext = scope.ServiceProvider.GetRequiredService(); + var foundEntity = dbContext.TestEntities.First(e => e.Id == idGuid); + dbContext.Entry(foundEntity).Reload(); + Assert.True(dbContext.TestEntities.First(e => e.Id == idGuid).Name == updatedNameGuid); + } } } -} \ No newline at end of file +} diff --git a/tests/DotNetEd.CoreAdmin.IntegrationTests/DotNetEd.CoreAdmin.IntegrationTests.csproj b/tests/DotNetEd.CoreAdmin.IntegrationTests/DotNetEd.CoreAdmin.IntegrationTests.csproj index fa3cb29..b914a88 100644 --- a/tests/DotNetEd.CoreAdmin.IntegrationTests/DotNetEd.CoreAdmin.IntegrationTests.csproj +++ b/tests/DotNetEd.CoreAdmin.IntegrationTests/DotNetEd.CoreAdmin.IntegrationTests.csproj @@ -1,27 +1,37 @@  - net6.0 + net6.0;net7.0;net8.0 annotations false - - - - - - + + + + + + + + + + + all runtime; build; native; contentfiles; analyzers; buildtransitive - + - - + + + + + + + diff --git a/tests/DotNetEd.CoreAdmin.IntegrationTests/IntegrationTestsWebHostFactory.cs b/tests/DotNetEd.CoreAdmin.IntegrationTests/IntegrationTestsWebHostFactory.cs index 47204b9..b383c1b 100644 --- a/tests/DotNetEd.CoreAdmin.IntegrationTests/IntegrationTestsWebHostFactory.cs +++ b/tests/DotNetEd.CoreAdmin.IntegrationTests/IntegrationTestsWebHostFactory.cs @@ -1,74 +1,26 @@ using DotNetEd.CoreAdmin.IntegrationTests.TestApp; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Mvc.Testing; -using System; -using System.Collections.Generic; -using System.Text; -using System.Linq; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Hosting; -using Microsoft.AspNetCore.TestHost; -using Microsoft.AspNetCore.Mvc.Authorization; + namespace DotNetEd.CoreAdmin.IntegrationTests { - public class IntegrationTestsWebHostFactory - : WebApplicationFactory where TStartup : class + public class IntegrationTestsWebHostFactory : WebApplicationFactory { - protected override IHostBuilder CreateHostBuilder() - { - var builder = Host.CreateDefaultBuilder() - .ConfigureWebHostDefaults(x => - { - // x.UseEnvironment("Development"); - x.UseStartup().UseTestServer(); - }); - return builder; - } - protected override void ConfigureWebHost(IWebHostBuilder builder) { builder.ConfigureServices(services => - { + { // Add ApplicationDbContext using an in-memory database for testing. services.AddDbContext(options => { options.UseInMemoryDatabase("InMemoryDbForTesting"); }); - // Build the service provider. - var sp = services.BuildServiceProvider(); - - // Create a scope to obtain a reference to the database - // context (ApplicationDbContext). - using (var scope = sp.CreateScope()) - { - var scopedServices = scope.ServiceProvider; - var db = scopedServices.GetRequiredService(); - var logger = scopedServices - .GetRequiredService>>(); - - // Ensure the database is created. - db.Database.EnsureCreated(); - - try - { - // Seed the database with test data. - // Utilities.InitializeDbForTests(db); - } - catch (Exception ex) - { - logger.LogError(ex, "An error occurred seeding the " + - "database with test messages. Error: {Message}", ex.Message); - } - } - services.AddCoreAdmin(); }); - - } } } diff --git a/tests/DotNetEd.CoreAdmin.IntegrationTests/OptionsTests.cs b/tests/DotNetEd.CoreAdmin.IntegrationTests/OptionsTests.cs index 0ad18b3..e8c6828 100644 --- a/tests/DotNetEd.CoreAdmin.IntegrationTests/OptionsTests.cs +++ b/tests/DotNetEd.CoreAdmin.IntegrationTests/OptionsTests.cs @@ -1,23 +1,25 @@ -using DotNetEd.CoreAdmin.IntegrationTests.TestApp; -using DotNetEd.CoreAdmin.IntegrationTests.TestApp.Entities; +using System; +using System.Collections.Generic; +using System.Threading.Tasks; + using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.TestHost; using Microsoft.Extensions.DependencyInjection; -using System; -using System.Collections.Generic; -using System.Threading.Tasks; using Xunit; +using DotNetEd.CoreAdmin.IntegrationTests.TestApp.Entities; + + namespace DotNetEd.CoreAdmin.IntegrationTests { - public class OptionsTests : IClassFixture> + public class OptionsTests : IClassFixture { - private readonly IntegrationTestsWebHostFactory _factory; + private readonly TestAppFixture _fixture; - public OptionsTests(IntegrationTestsWebHostFactory factory) + public OptionsTests(TestAppFixture fixture) { - _factory = factory; + _fixture = fixture; } static void ConfigureTestServices(IServiceCollection services) { } @@ -26,7 +28,7 @@ static void ConfigureTestServices(IServiceCollection services) { } public async Task ReturnsBuiltInAssetPathWhenCdnOptionsNotSet() { // Arrange - var client = _factory.WithWebHostBuilder(builder => { + var client = _fixture.Factory.WithWebHostBuilder(builder => { builder.UseEnvironment("Development"); builder.ConfigureTestServices(ConfigureTestServices); }).CreateClient(); @@ -51,7 +53,7 @@ static void ConfigureTestServicesWithOptionsIgnoringDbSets(IServiceCollection se [Fact] public async Task IgnoreEntityTypes_DoesNotIncludeIgnoredDbSets() { // Arrange - var client = _factory.WithWebHostBuilder(builder => { + var client = _fixture.Factory.WithWebHostBuilder(builder => { builder.UseEnvironment("Development"); builder.ConfigureTestServices(services => ConfigureTestServicesWithOptionsIgnoringDbSets(services, @@ -72,7 +74,7 @@ public async Task ReturnsCdnAssetPathWhenCdnOptionsSet() var cdnPath = "https://wow-an-amazing-cdn.com/assets"; // Arrange - var client = _factory.WithWebHostBuilder(builder => { + var client = _fixture.Factory.WithWebHostBuilder(builder => { builder.UseEnvironment("Development"); builder.ConfigureTestServices(ConfigureTestServices); builder.Configure( diff --git a/tests/DotNetEd.CoreAdmin.IntegrationTests/SecurityTests.cs b/tests/DotNetEd.CoreAdmin.IntegrationTests/SecurityTests.cs index ebabe76..09b4ee7 100644 --- a/tests/DotNetEd.CoreAdmin.IntegrationTests/SecurityTests.cs +++ b/tests/DotNetEd.CoreAdmin.IntegrationTests/SecurityTests.cs @@ -1,27 +1,28 @@ -using DotNetEd.CoreAdmin.IntegrationTests.TestApp; +using System; +using System.Threading.Tasks; + using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.TestHost; using Microsoft.Extensions.DependencyInjection; -using System; -using System.Threading.Tasks; using Xunit; + namespace DotNetEd.CoreAdmin.IntegrationTests { - public class SecurityTests : IClassFixture> + public class SecurityTests : IClassFixture { - private readonly IntegrationTestsWebHostFactory _factory; + private readonly TestAppFixture _fixture; - public SecurityTests(IntegrationTestsWebHostFactory factory) + public SecurityTests(TestAppFixture fixture) { - _factory = factory; + _fixture = fixture; } static void ConfigureTestServices(IServiceCollection services) { } - static void ConfigureTestServicesWithSecurity(IServiceCollection services) { - services.AddCoreAdmin("TestRole"); + static void ConfigureTestServicesWithSecurity(IServiceCollection services) { + services.AddCoreAdmin("TestRole"); } [Obsolete] @@ -39,7 +40,7 @@ static void ConfigureTestServicesWithSecurityAndAlternativeTestRole(IServiceColl public async Task ShowsWarningMessageInDevelopmentModeWhenNoSecuritySet() { // Arrange - var client = _factory.WithWebHostBuilder(builder => { + var client = _fixture.Factory.WithWebHostBuilder(builder => { builder.UseEnvironment("Development"); builder.ConfigureTestServices(ConfigureTestServices); }).CreateClient(); @@ -61,7 +62,7 @@ public async Task ShowsWarningMessageInDevelopmentModeWhenNoSecuritySet() public async Task DoesNotShowWarningMessageInDevelopmentModeWhenSecurityIsSet() { // Arrange - var client = _factory.WithWebHostBuilder(builder => { + var client = _fixture.Factory.WithWebHostBuilder(builder => { builder.UseEnvironment("Development"); builder.ConfigureTestServices(ConfigureTestServicesWithSecurity); }).CreateClient(); @@ -84,7 +85,7 @@ public async Task DoesNotShowWarningMessageInDevelopmentModeWhenSecurityIsSet() public async Task ReturnsUnauthorisedInDevelopmentModeWhenSecurityIsSetAndCheckFails() { // Arrange - var client = _factory.WithWebHostBuilder(builder => { + var client = _fixture.Factory.WithWebHostBuilder(builder => { builder.UseEnvironment("Development"); builder.ConfigureTestServices(ConfigureTestServicesWithSecurityAndAlternativeTestRole); }).CreateClient(); @@ -100,8 +101,11 @@ public async Task ReturnsUnauthorisedInDevelopmentModeWhenSecurityIsSetAndCheckF public async Task ReturnsUnauthorizedWhenInProductionButNoSecuritySet() { // Arrange - var client = _factory.WithWebHostBuilder(builder => - builder.ConfigureTestServices(ConfigureTestServices)).CreateClient(); + var client = _fixture.Factory.WithWebHostBuilder(builder => + { + builder.ConfigureTestServices(ConfigureTestServices); + builder.UseEnvironment("Production"); + }).CreateClient(); // Act var response = await client.GetAsync("/coreadmin"); @@ -114,7 +118,7 @@ public async Task ReturnsUnauthorizedWhenInProductionButNoSecuritySet() public async Task SuccessStatusCodeAndUsesRoleWhenInProductionAndRoleCheckSet() { // Arrange - var client = _factory.WithWebHostBuilder(builder => + var client = _fixture.Factory.WithWebHostBuilder(builder => builder.ConfigureTestServices(ConfigureTestServicesWithSecurity)).CreateClient(); // Act @@ -134,8 +138,8 @@ public async Task SuccessStatusCodeAndCallsCustomAuthMethodInProductionAndAuthMe var authMethod = new Func>(() => { authCalled = true; return Task.FromResult(true); }); // Arrange - var client = _factory.WithWebHostBuilder(builder => - builder.ConfigureTestServices(services => + var client = _fixture.Factory.WithWebHostBuilder(builder => + builder.ConfigureTestServices(services => ConfigureTestServicesWithSecurityAuthMethod(services, authMethod))).CreateClient(); // Act @@ -155,7 +159,7 @@ public async Task ReturnsUnauthorizedWhenInProductionCustomAuthMethodFails() var authMethod = new Func>(() => { authCalled = true; return Task.FromResult(false); }); // Arrange - var client = _factory.WithWebHostBuilder(builder => + var client = _fixture.Factory.WithWebHostBuilder(builder => builder.ConfigureTestServices(services => ConfigureTestServicesWithSecurityAuthMethod(services, authMethod))).CreateClient(); @@ -175,7 +179,7 @@ public async Task ReturnsUnauthorizedWhenInProductionNewCustomAuthMethodFails() var authMethod = new Func>((serviceProvider) => { authCalled = true; return Task.FromResult(false); }); // Arrange - var client = _factory.WithWebHostBuilder(builder => { + var client = _fixture.Factory.WithWebHostBuilder(builder => { builder.UseEnvironment("Production"); builder.ConfigureTestServices(ConfigureTestServices); builder.Configure( diff --git a/tests/DotNetEd.CoreAdmin.IntegrationTests/TestAppFixture.cs b/tests/DotNetEd.CoreAdmin.IntegrationTests/TestAppFixture.cs new file mode 100644 index 0000000..c4219e2 --- /dev/null +++ b/tests/DotNetEd.CoreAdmin.IntegrationTests/TestAppFixture.cs @@ -0,0 +1,51 @@ +using System; +using System.Threading.Tasks; + +using DotNetEd.CoreAdmin.IntegrationTests.TestApp; + +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; + +using Xunit; + + +namespace DotNetEd.CoreAdmin.IntegrationTests; + +public sealed class TestAppFixture : IAsyncLifetime +{ + public IntegrationTestsWebHostFactory Factory { get; } = new(); + + public Task InitializeAsync() + { + // Create a scope to obtain a reference to the database + // context (ApplicationDbContext). + using (var scope = Factory.Services.CreateScope()) + { + var scopedServices = scope.ServiceProvider; + var db = scopedServices.GetRequiredService(); + var logger = scopedServices + .GetRequiredService>(); + + // Ensure the database is created. + db.Database.EnsureCreated(); + + try + { + // Seed the database with test data. + // Utilities.InitializeDbForTests(db); + } + catch (Exception ex) + { + logger.LogError(ex, "An error occurred seeding the " + + "database with test messages. Error: {Message}", ex.Message); + } + } + + return Task.CompletedTask; + } + + public async Task DisposeAsync() + { + await Factory.DisposeAsync(); + } +} From 97e28af296f1fef040b788a2501a555fee308d29 Mon Sep 17 00:00:00 2001 From: iwedaz Date: Sun, 14 Jan 2024 20:28:12 +0100 Subject: [PATCH 2/3] Delete redundant elements in ProjectReference; Update xunit --- .../DotNetEd.CoreAdmin.DemoAppDotNet6.csproj | 6 +++--- .../DotNetEd.CoreAdmin.IntegrationTests.csproj | 14 +++++++------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/DotNetEd.CoreAdmin.DemoAppDotNet6/DotNetEd.CoreAdmin.DemoAppDotNet6.csproj b/src/DotNetEd.CoreAdmin.DemoAppDotNet6/DotNetEd.CoreAdmin.DemoAppDotNet6.csproj index faebdbe..5682f11 100644 --- a/src/DotNetEd.CoreAdmin.DemoAppDotNet6/DotNetEd.CoreAdmin.DemoAppDotNet6.csproj +++ b/src/DotNetEd.CoreAdmin.DemoAppDotNet6/DotNetEd.CoreAdmin.DemoAppDotNet6.csproj @@ -23,9 +23,9 @@ - - - + + + diff --git a/tests/DotNetEd.CoreAdmin.IntegrationTests/DotNetEd.CoreAdmin.IntegrationTests.csproj b/tests/DotNetEd.CoreAdmin.IntegrationTests/DotNetEd.CoreAdmin.IntegrationTests.csproj index b914a88..d08b91e 100644 --- a/tests/DotNetEd.CoreAdmin.IntegrationTests/DotNetEd.CoreAdmin.IntegrationTests.csproj +++ b/tests/DotNetEd.CoreAdmin.IntegrationTests/DotNetEd.CoreAdmin.IntegrationTests.csproj @@ -16,7 +16,7 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive @@ -25,13 +25,13 @@ - - - + + + - - - + + + From 51ded4084e7a0dfa9f21aa6545bdd3404b6f4b23 Mon Sep 17 00:00:00 2001 From: iwedaz Date: Tue, 23 Jan 2024 09:34:51 +0100 Subject: [PATCH 3/3] Lower dependencies restrictions --- .github/workflows/dotnet-core.yml | 2 +- .../DotNetEd.CoreAdmin.DemoAppDotNet6.csproj | 6 +++--- src/DotNetEd.CoreAdmin/DotNetEd.CoreAdmin.csproj | 9 +++++---- .../DotNetEd.CoreAdmin.IntegrationTests.csproj | 12 ++++++------ 4 files changed, 15 insertions(+), 14 deletions(-) diff --git a/.github/workflows/dotnet-core.yml b/.github/workflows/dotnet-core.yml index 616d0c8..700cbe4 100644 --- a/.github/workflows/dotnet-core.yml +++ b/.github/workflows/dotnet-core.yml @@ -1,4 +1,4 @@ -name: .NET 6 & 7 +name: .NET 6, 7 & 8 on: push: diff --git a/src/DotNetEd.CoreAdmin.DemoAppDotNet6/DotNetEd.CoreAdmin.DemoAppDotNet6.csproj b/src/DotNetEd.CoreAdmin.DemoAppDotNet6/DotNetEd.CoreAdmin.DemoAppDotNet6.csproj index 5682f11..8425f4b 100644 --- a/src/DotNetEd.CoreAdmin.DemoAppDotNet6/DotNetEd.CoreAdmin.DemoAppDotNet6.csproj +++ b/src/DotNetEd.CoreAdmin.DemoAppDotNet6/DotNetEd.CoreAdmin.DemoAppDotNet6.csproj @@ -17,9 +17,9 @@ - - - + + + diff --git a/src/DotNetEd.CoreAdmin/DotNetEd.CoreAdmin.csproj b/src/DotNetEd.CoreAdmin/DotNetEd.CoreAdmin.csproj index a1c214e..ce07753 100644 --- a/src/DotNetEd.CoreAdmin/DotNetEd.CoreAdmin.csproj +++ b/src/DotNetEd.CoreAdmin/DotNetEd.CoreAdmin.csproj @@ -10,10 +10,11 @@ Automagically add an Admin Panel to your .NET 6, .NET 7 or .NET 8 web app. Core Admin Panel for ASP.NET Core edandersen - Copyright © 2024 Ed Andersen + Copyright © 2022 Ed Andersen https://github.com/edandersen/core-admin LGPL-3.0-or-later disable + true @@ -44,9 +45,9 @@ - - - + + + diff --git a/tests/DotNetEd.CoreAdmin.IntegrationTests/DotNetEd.CoreAdmin.IntegrationTests.csproj b/tests/DotNetEd.CoreAdmin.IntegrationTests/DotNetEd.CoreAdmin.IntegrationTests.csproj index d08b91e..c8d3af7 100644 --- a/tests/DotNetEd.CoreAdmin.IntegrationTests/DotNetEd.CoreAdmin.IntegrationTests.csproj +++ b/tests/DotNetEd.CoreAdmin.IntegrationTests/DotNetEd.CoreAdmin.IntegrationTests.csproj @@ -7,13 +7,13 @@ - - - + + + - - - + + +