From 5d091df908c041f1fc7aa4432197fb490c5e9c29 Mon Sep 17 00:00:00 2001 From: Javier Calvarro Nelson Date: Thu, 6 Jun 2019 22:01:33 -0700 Subject: [PATCH] Move identity functional test website to generic host (#10974) --- ...ctionalTestsServiceCollectionExtensions.cs | 41 +++++++++++-- .../Infrastructure/ServerFactory.cs | 27 +++++++-- .../Identity.DefaultUI.WebSite.csproj | 2 + .../PocoUserStartup.cs | 2 +- .../Identity.DefaultUI.WebSite/Program.cs | 57 +++---------------- .../Identity.DefaultUI.WebSite/StartupBase.cs | 38 ++++++++++++- .../StartupWithoutEndpointRouting.cs | 2 +- 7 files changed, 104 insertions(+), 65 deletions(-) diff --git a/src/Identity/test/Identity.FunctionalTests/Infrastructure/FunctionalTestsServiceCollectionExtensions.cs b/src/Identity/test/Identity.FunctionalTests/Infrastructure/FunctionalTestsServiceCollectionExtensions.cs index 9070d6ba14..649e534181 100644 --- a/src/Identity/test/Identity.FunctionalTests/Infrastructure/FunctionalTestsServiceCollectionExtensions.cs +++ b/src/Identity/test/Identity.FunctionalTests/Infrastructure/FunctionalTestsServiceCollectionExtensions.cs @@ -1,8 +1,10 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Collections.Generic; using System.Data.Common; +using System.Linq; using System.Security.Claims; using System.Threading.Tasks; using Identity.DefaultUI.WebSite; @@ -12,16 +14,45 @@ using Microsoft.AspNetCore.Identity.UI.Services; using Microsoft.AspNetCore.Mvc.Authorization; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Diagnostics; +using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.Extensions.DependencyInjection; namespace Microsoft.AspNetCore.Identity.FunctionalTests { public static class FunctionalTestsServiceCollectionExtensions { - public static IServiceCollection SetupTestDatabase(this IServiceCollection services, DbConnection connection) where TContext : DbContext => - services.AddDbContext(options => - options.ConfigureWarnings(b => b.Log(CoreEventId.ManyServiceProvidersCreatedWarning)) - .UseSqlite(connection)); + public static IServiceCollection SetupTestDatabase(this IServiceCollection services, DbConnection connection) where TContext : DbContext + { + var descriptor = services.SingleOrDefault(d => d.ServiceType == typeof(DbContextOptions)); + if (descriptor != null) + { + services.Remove(descriptor); + } + + services.AddScoped(p => + DbContextOptionsFactory( + p, + (sp, options) => options + .ConfigureWarnings(b => b.Log(CoreEventId.ManyServiceProvidersCreatedWarning)) + .UseSqlite(connection))); + + return services; + } + + private static DbContextOptions DbContextOptionsFactory( + IServiceProvider applicationServiceProvider, + Action optionsAction) + where TContext : DbContext + { + var builder = new DbContextOptionsBuilder( + new DbContextOptions(new Dictionary())); + + builder.UseApplicationServiceProvider(applicationServiceProvider); + + optionsAction?.Invoke(applicationServiceProvider, builder); + + return builder.Options; + } public static IServiceCollection SetupTestThirdPartyLogin(this IServiceCollection services) => services.AddAuthentication() diff --git a/src/Identity/test/Identity.FunctionalTests/Infrastructure/ServerFactory.cs b/src/Identity/test/Identity.FunctionalTests/Infrastructure/ServerFactory.cs index cfdada335d..7082dfb442 100644 --- a/src/Identity/test/Identity.FunctionalTests/Infrastructure/ServerFactory.cs +++ b/src/Identity/test/Identity.FunctionalTests/Infrastructure/ServerFactory.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using Identity.DefaultUI.WebSite; using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Mvc.Testing; @@ -9,6 +10,7 @@ using Microsoft.AspNetCore.TestHost; using Microsoft.Data.Sqlite; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; namespace Microsoft.AspNetCore.Identity.FunctionalTests { @@ -27,6 +29,12 @@ namespace Microsoft.AspNetCore.Identity.FunctionalTests ClientOptions.BaseAddress = new Uri("https://localhost"); } + protected override IHostBuilder CreateHostBuilder() + { + Program.UseStartup = false; + return base.CreateHostBuilder(); + } + protected override void ConfigureWebHost(IWebHostBuilder builder) { base.ConfigureWebHost(builder); @@ -42,18 +50,25 @@ namespace Microsoft.AspNetCore.Identity.FunctionalTests }); } - protected override TestServer CreateServer(IWebHostBuilder builder) + protected override IHost CreateHost(IHostBuilder builder) { - var result = base.CreateServer(builder); - EnsureDatabaseCreated(result); + var result = base.CreateHost(builder); + EnsureDatabaseCreated(result.Services); return result; } - public void EnsureDatabaseCreated(TestServer server) + protected override TestServer CreateServer(IWebHostBuilder builder) { - using (var scope = server.Host.Services.CreateScope()) + var result = base.CreateServer(builder); + EnsureDatabaseCreated(result.Host.Services); + return result; + } + + public void EnsureDatabaseCreated(IServiceProvider services) + { + using (var scope = services.CreateScope()) { - scope.ServiceProvider.GetService().Database.EnsureCreated(); + scope.ServiceProvider.GetService()?.Database?.EnsureCreated(); } } diff --git a/src/Identity/testassets/Identity.DefaultUI.WebSite/Identity.DefaultUI.WebSite.csproj b/src/Identity/testassets/Identity.DefaultUI.WebSite/Identity.DefaultUI.WebSite.csproj index e2ec0518f3..199d523d7d 100644 --- a/src/Identity/testassets/Identity.DefaultUI.WebSite/Identity.DefaultUI.WebSite.csproj +++ b/src/Identity/testassets/Identity.DefaultUI.WebSite/Identity.DefaultUI.WebSite.csproj @@ -11,6 +11,7 @@ + @@ -36,6 +37,7 @@ + diff --git a/src/Identity/testassets/Identity.DefaultUI.WebSite/PocoUserStartup.cs b/src/Identity/testassets/Identity.DefaultUI.WebSite/PocoUserStartup.cs index 0277bd669a..df60be2eed 100644 --- a/src/Identity/testassets/Identity.DefaultUI.WebSite/PocoUserStartup.cs +++ b/src/Identity/testassets/Identity.DefaultUI.WebSite/PocoUserStartup.cs @@ -1,4 +1,4 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using Microsoft.AspNetCore.Builder; diff --git a/src/Identity/testassets/Identity.DefaultUI.WebSite/Program.cs b/src/Identity/testassets/Identity.DefaultUI.WebSite/Program.cs index 313e5546ce..44d81e4099 100644 --- a/src/Identity/testassets/Identity.DefaultUI.WebSite/Program.cs +++ b/src/Identity/testassets/Identity.DefaultUI.WebSite/Program.cs @@ -14,60 +14,19 @@ namespace Identity.DefaultUI.WebSite { public static void Main(string[] args) { - CreateWebHostBuilder(args).Build().Run(); + CreateHostBuilder(args).Build().Run(); } - public static IWebHostBuilder CreateWebHostBuilder(string[] args) - { - var builder = new WebHostBuilder() - .UseKestrel((builderContext, options) => - { - options.Configure(builderContext.Configuration.GetSection("Kestrel")); - }) - .UseContentRoot(Directory.GetCurrentDirectory()) - .ConfigureAppConfiguration((hostingContext, config) => - { - var env = hostingContext.HostingEnvironment; + public static bool UseStartup { get; set; } = true; - config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: false) - .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: false); - - if (env.IsDevelopment()) + public static IHostBuilder CreateHostBuilder(string[] args) => + Host.CreateDefaultBuilder(args) + .ConfigureWebHostDefaults(webBuilder => + { + if (UseStartup) { - var appAssembly = Assembly.Load(new AssemblyName(env.ApplicationName)); - if (appAssembly != null) - { - config.AddUserSecrets(appAssembly, optional: true); - } + webBuilder.UseStartup(); } - - config.AddEnvironmentVariables(); - - if (args != null) - { - config.AddCommandLine(args); - } - }) - .ConfigureLogging((hostingContext, logging) => - { - logging.AddConfiguration(hostingContext.Configuration.GetSection("Logging")); - logging.AddConsole(); - logging.AddDebug(); - }) - .UseIISIntegration() - .UseDefaultServiceProvider((context, options) => - { - options.ValidateScopes = context.HostingEnvironment.IsDevelopment(); }); - - if (args != null) - { - builder.UseConfiguration(new ConfigurationBuilder().AddCommandLine(args).Build()); - } - - builder.UseStartup(); - - return builder; - } } } diff --git a/src/Identity/testassets/Identity.DefaultUI.WebSite/StartupBase.cs b/src/Identity/testassets/Identity.DefaultUI.WebSite/StartupBase.cs index f3915ed44e..a0713da1e0 100644 --- a/src/Identity/testassets/Identity.DefaultUI.WebSite/StartupBase.cs +++ b/src/Identity/testassets/Identity.DefaultUI.WebSite/StartupBase.cs @@ -1,6 +1,8 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +using System; +using System.Collections.Generic; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Identity; @@ -49,9 +51,8 @@ namespace Identity.DefaultUI.WebSite .AddDefaultUI(Framework) .AddRoles() .AddEntityFrameworkStores(); - - services.AddMvc(); + services.AddMvc(); services.AddSingleton(); } @@ -59,7 +60,7 @@ namespace Identity.DefaultUI.WebSite public virtual void Configure(IApplicationBuilder app, IWebHostEnvironment env) { // This prevents running out of file watchers on some linux machines - ((PhysicalFileProvider)env.WebRootFileProvider).UseActivePolling = false; + DisableFilePolling(env); if (env.IsDevelopment()) { @@ -87,5 +88,36 @@ namespace Identity.DefaultUI.WebSite endpoints.MapRazorPages(); }); } + + protected static void DisableFilePolling(IWebHostEnvironment env) + { + var pendingProviders = new Stack(); + pendingProviders.Push(env.WebRootFileProvider); + while (pendingProviders.TryPop(out var currentProvider)) + { + switch (currentProvider) + { + case PhysicalFileProvider physical: + physical.UseActivePolling = false; + break; + case IFileProvider staticWebAssets when staticWebAssets.GetType().Name == "StaticWebAssetsFileProvider": + GetUnderlyingProvider(staticWebAssets).UseActivePolling = false; + break; + case CompositeFileProvider composite: + foreach (var childFileProvider in composite.FileProviders) + { + pendingProviders.Push(childFileProvider); + } + break; + default: + throw new InvalidOperationException("Unknown provider"); + } + } + } + + private static PhysicalFileProvider GetUnderlyingProvider(IFileProvider staticWebAssets) + { + return (PhysicalFileProvider) staticWebAssets.GetType().GetProperty("InnerProvider").GetValue(staticWebAssets); + } } } diff --git a/src/Identity/testassets/Identity.DefaultUI.WebSite/StartupWithoutEndpointRouting.cs b/src/Identity/testassets/Identity.DefaultUI.WebSite/StartupWithoutEndpointRouting.cs index d8916594d3..cc7f7367de 100644 --- a/src/Identity/testassets/Identity.DefaultUI.WebSite/StartupWithoutEndpointRouting.cs +++ b/src/Identity/testassets/Identity.DefaultUI.WebSite/StartupWithoutEndpointRouting.cs @@ -28,7 +28,7 @@ namespace Identity.DefaultUI.WebSite public override void Configure(IApplicationBuilder app, IWebHostEnvironment env) { // This prevents running out of file watchers on some linux machines - ((PhysicalFileProvider)env.WebRootFileProvider).UseActivePolling = false; + DisableFilePolling(env); if (env.IsDevelopment()) {