From 32f790c5aced3d1d2d0ca65c510e580853d581bb Mon Sep 17 00:00:00 2001 From: Arthur Vickers Date: Wed, 29 Sep 2021 14:17:15 +0100 Subject: [PATCH] Test changes to make sure applicationName is set when using new template pattern EF-side tests for https://github.com/dotnet/runtime/pull/59743 These will fail until the new source package for HostFactoryResolver is available. I have tested locally that they work once this is done. --- .../AppServiceProviderFactoryTest.cs | 204 ++++++++++++++++++ .../EFCore.AspNet.Specification.Tests.csproj | 1 + .../Internal/AppServiceProviderFactoryTest.cs | 84 -------- .../TestUtilities/TestWebHostBuilder.cs | 18 ++ .../TestUtilities/MockAssembly.cs | 48 +---- .../TestUtilities/MockMethodInfo.cs | 61 ++++++ 6 files changed, 286 insertions(+), 130 deletions(-) create mode 100644 test/EFCore.AspNet.InMemory.FunctionalTests/AppServiceProviderFactoryTest.cs delete mode 100644 test/EFCore.Design.Tests/Design/Internal/AppServiceProviderFactoryTest.cs create mode 100644 test/EFCore.Design.Tests/TestUtilities/TestWebHostBuilder.cs create mode 100644 test/EFCore.Tests/TestUtilities/MockMethodInfo.cs diff --git a/test/EFCore.AspNet.InMemory.FunctionalTests/AppServiceProviderFactoryTest.cs b/test/EFCore.AspNet.InMemory.FunctionalTests/AppServiceProviderFactoryTest.cs new file mode 100644 index 00000000000..84ff8642909 --- /dev/null +++ b/test/EFCore.AspNet.InMemory.FunctionalTests/AppServiceProviderFactoryTest.cs @@ -0,0 +1,204 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Reflection; +using Microsoft.EntityFrameworkCore.Design.Internal; +using Microsoft.EntityFrameworkCore.Internal; +using Microsoft.EntityFrameworkCore.TestUtilities; +using Microsoft.Extensions.DependencyInjection; +using Xunit; + +namespace Microsoft.EntityFrameworkCore +{ + public class AppServiceProviderFactoryTest + { + [ConditionalFact] + public void Create_services_from_template_method() + { + TestCreateServices(typeof(ProgramWithBuildWebHost)); + TestCreateServices(typeof(ProgramWithCreateWebHostBuilder)); + TestCreateServices(typeof(ProgramWithCreateHostBuilder)); + } + + private static void TestCreateServices(Type programType) + { + var factory = new TestAppServiceProviderFactory( + MockAssembly.Create(programType)); + + Environment.SetEnvironmentVariable("ASPNETCORE_ENVIRONMENT", null); + Environment.SetEnvironmentVariable("DOTNET_ENVIRONMENT", null); + var services = factory.Create(new[] { "arg1" }); + + Assert.NotNull(services.GetRequiredService()); + } + + private class ProgramWithBuildWebHost + { + public static TestWebHost BuildWebHost(string[] args) + { + ValidateEnvironmentAndArgs(args); + + return new TestWebHost(BuildTestServiceProvider()); + } + } + + private class ProgramWithCreateWebHostBuilder + { + public static TestWebHostBuilder CreateWebHostBuilder(string[] args) + { + ValidateEnvironmentAndArgs(args); + + return new TestWebHostBuilder(BuildTestServiceProvider()); + } + } + + private class ProgramWithCreateHostBuilder + { + public static TestWebHostBuilder CreateHostBuilder(string[] args) + { + ValidateEnvironmentAndArgs(args); + + return new TestWebHostBuilder(BuildTestServiceProvider()); + } + } + + [ConditionalFact] + public void Create_with_no_builder_method() + { + var factory = new TestAppServiceProviderFactory( + MockAssembly.Create( + new[] { typeof(ProgramWithNoHostBuilder) }, + new MockMethodInfo(typeof(ProgramWithNoHostBuilder), InjectHostIntoDiagnostics))); + + Environment.SetEnvironmentVariable("ASPNETCORE_ENVIRONMENT", null); + Environment.SetEnvironmentVariable("DOTNET_ENVIRONMENT", null); + var services = factory.Create(new[] { "arg1" }); + + Assert.NotNull(services.GetRequiredService()); + } + + private static void InjectHostIntoDiagnostics(object[] args) + { + Assert.Equal("Development", Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT")); + Assert.Equal("Development", Environment.GetEnvironmentVariable("DOTNET_ENVIRONMENT")); + Assert.Single(args); + Assert.Equal((string[])args[0], new[] { "arg1", "--applicationName", "MockAssembly" }); + + using var diagnosticListener = new DiagnosticListener("Microsoft.Extensions.Hosting"); + + diagnosticListener.Write( + "HostBuilt", + new TestWebHost(BuildTestServiceProvider())); + } + + private class ProgramWithNoHostBuilder + { + } + + private static void ValidateEnvironmentAndArgs(string[] args) + { + Assert.Equal("Development", Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT")); + Assert.Equal("Development", Environment.GetEnvironmentVariable("DOTNET_ENVIRONMENT")); + Assert.Equal(args, new[] { "arg1" }); + } + + private static ServiceProvider BuildTestServiceProvider() + => new ServiceCollection() + .AddScoped() + .BuildServiceProvider(validateScopes: true); + + private class TestService + { + } + + [ConditionalFact] + public void Create_works_when_no_BuildWebHost() + { + var factory = new TestAppServiceProviderFactory( + MockAssembly.Create(typeof(ProgramWithoutBuildWebHost))); + + var services = factory.Create(Array.Empty()); + + Assert.NotNull(services); + } + + private class ProgramWithoutBuildWebHost + { + } + + [ConditionalFact] + public void Create_works_when_BuildWebHost_throws() + { + var reporter = new TestOperationReporter(); + var factory = new TestAppServiceProviderFactory( + MockAssembly.Create(typeof(ProgramWithThrowingBuildWebHost)), + reporter); + + var services = factory.Create(Array.Empty()); + + Assert.NotNull(services); + Assert.Contains( + "warn: " + DesignStrings.InvokeCreateHostBuilderFailed("This is a test."), + reporter.Messages); + } + + private static class ProgramWithThrowingBuildWebHost + { + public static TestWebHost BuildWebHost(string[] args) + => throw new Exception("This is a test."); + } + } + + public class TestAppServiceProviderFactory : AppServiceProviderFactory + { + public TestAppServiceProviderFactory(Assembly startupAssembly, IOperationReporter reporter = null) + : base(startupAssembly, reporter ?? new TestOperationReporter()) + { + } + } + + public class TestWebHost + { + public TestWebHost(IServiceProvider services) + => Services = services; + + public IServiceProvider Services { get; } + } + + public class TestWebHostBuilder + { + public TestWebHostBuilder(IServiceProvider services) + => Services = services; + + public IServiceProvider Services { get; } + + public TestWebHost Build() + => new TestWebHost(Services); + } + + public class TestOperationReporter : IOperationReporter + { + private readonly List _messages = new(); + + public IReadOnlyList Messages + => _messages; + + public void Clear() + => _messages.Clear(); + + public void WriteInformation(string message) + => _messages.Add("info: " + message); + + public void WriteVerbose(string message) + => _messages.Add("verbose: " + message); + + public void WriteWarning(string message) + => _messages.Add("warn: " + message); + + public void WriteError(string message) + => _messages.Add("error: " + message); + } +} diff --git a/test/EFCore.AspNet.Specification.Tests/EFCore.AspNet.Specification.Tests.csproj b/test/EFCore.AspNet.Specification.Tests/EFCore.AspNet.Specification.Tests.csproj index c954d2cda60..68f34b5e705 100644 --- a/test/EFCore.AspNet.Specification.Tests/EFCore.AspNet.Specification.Tests.csproj +++ b/test/EFCore.AspNet.Specification.Tests/EFCore.AspNet.Specification.Tests.csproj @@ -16,6 +16,7 @@ + diff --git a/test/EFCore.Design.Tests/Design/Internal/AppServiceProviderFactoryTest.cs b/test/EFCore.Design.Tests/Design/Internal/AppServiceProviderFactoryTest.cs deleted file mode 100644 index 44f08b58916..00000000000 --- a/test/EFCore.Design.Tests/Design/Internal/AppServiceProviderFactoryTest.cs +++ /dev/null @@ -1,84 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System; -using Microsoft.EntityFrameworkCore.Internal; -using Microsoft.EntityFrameworkCore.TestUtilities; -using Microsoft.Extensions.DependencyInjection; -using Xunit; - -#pragma warning disable RCS1102 // Make class static. -namespace Microsoft.EntityFrameworkCore.Design.Internal -{ - public class AppServiceProviderFactoryTest - { - [ConditionalFact] - public void Create_works() - { - var factory = new TestAppServiceProviderFactory( - MockAssembly.Create(typeof(Program))); - - Environment.SetEnvironmentVariable("ASPNETCORE_ENVIRONMENT", null); - Environment.SetEnvironmentVariable("DOTNET_ENVIRONMENT", null); - var services = factory.Create(new[] { "arg1" }); - - Assert.NotNull(services.GetRequiredService()); - } - - private class Program - { - public static TestWebHost BuildWebHost(string[] args) - { - Assert.Equal("Development", Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT")); - Assert.Equal("Development", Environment.GetEnvironmentVariable("DOTNET_ENVIRONMENT")); - Assert.Equal(args, new[] { "arg1" }); - - return new TestWebHost( - new ServiceCollection() - .AddScoped() - .BuildServiceProvider(validateScopes: true)); - } - } - - private class TestService - { - } - - [ConditionalFact] - public void Create_works_when_no_BuildWebHost() - { - var factory = new TestAppServiceProviderFactory( - MockAssembly.Create(typeof(ProgramWithoutBuildWebHost))); - - var services = factory.Create(Array.Empty()); - - Assert.NotNull(services); - } - - private class ProgramWithoutBuildWebHost - { - } - - [ConditionalFact] - public void Create_works_when_BuildWebHost_throws() - { - var reporter = new TestOperationReporter(); - var factory = new TestAppServiceProviderFactory( - MockAssembly.Create(typeof(ProgramWithThrowingBuildWebHost)), - reporter); - - var services = factory.Create(Array.Empty()); - - Assert.NotNull(services); - Assert.Contains( - "warn: " + DesignStrings.InvokeCreateHostBuilderFailed("This is a test."), - reporter.Messages); - } - - private static class ProgramWithThrowingBuildWebHost - { - public static TestWebHost BuildWebHost(string[] args) - => throw new Exception("This is a test."); - } - } -} diff --git a/test/EFCore.Design.Tests/TestUtilities/TestWebHostBuilder.cs b/test/EFCore.Design.Tests/TestUtilities/TestWebHostBuilder.cs new file mode 100644 index 00000000000..45c97c10fe1 --- /dev/null +++ b/test/EFCore.Design.Tests/TestUtilities/TestWebHostBuilder.cs @@ -0,0 +1,18 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; + +namespace Microsoft.EntityFrameworkCore.TestUtilities +{ + public class TestWebHostBuilder + { + public TestWebHostBuilder(IServiceProvider services) + => Services = services; + + public IServiceProvider Services { get; } + + public TestWebHost Build() + => new(Services); + } +} diff --git a/test/EFCore.Tests/TestUtilities/MockAssembly.cs b/test/EFCore.Tests/TestUtilities/MockAssembly.cs index 101412290b1..37287eb4c24 100644 --- a/test/EFCore.Tests/TestUtilities/MockAssembly.cs +++ b/test/EFCore.Tests/TestUtilities/MockAssembly.cs @@ -3,7 +3,6 @@ using System; using System.Collections.Generic; -using System.Globalization; using System.Linq; using System.Reflection; @@ -34,50 +33,7 @@ public MockAssembly(IEnumerable definedTypes, MethodInfo entryPoint) public override AssemblyName GetName() => new(nameof(MockAssembly)); - private class MockMethodInfo : MethodInfo - { - public MockMethodInfo(Type declaringType) - { - DeclaringType = declaringType; - } - - public override Type DeclaringType { get; } - - public override ICustomAttributeProvider ReturnTypeCustomAttributes - => throw new NotImplementedException(); - - public override RuntimeMethodHandle MethodHandle - => throw new NotImplementedException(); - - public override MethodAttributes Attributes - => throw new NotImplementedException(); - - public override string Name - => throw new NotImplementedException(); - - public override Type ReflectedType - => throw new NotImplementedException(); - - public override MethodInfo GetBaseDefinition() - => throw new NotImplementedException(); - - public override object[] GetCustomAttributes(bool inherit) - => throw new NotImplementedException(); - - public override object[] GetCustomAttributes(Type attributeType, bool inherit) - => throw new NotImplementedException(); - - public override MethodImplAttributes GetMethodImplementationFlags() - => throw new NotImplementedException(); - - public override ParameterInfo[] GetParameters() - => throw new NotImplementedException(); - - public override object Invoke(object obj, BindingFlags invokeAttr, Binder binder, object[] parameters, CultureInfo culture) - => throw new NotImplementedException(); - - public override bool IsDefined(Type attributeType, bool inherit) - => throw new NotImplementedException(); - } + public override string FullName + => nameof(MockAssembly); } } diff --git a/test/EFCore.Tests/TestUtilities/MockMethodInfo.cs b/test/EFCore.Tests/TestUtilities/MockMethodInfo.cs new file mode 100644 index 00000000000..bde49514d08 --- /dev/null +++ b/test/EFCore.Tests/TestUtilities/MockMethodInfo.cs @@ -0,0 +1,61 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Globalization; +using System.Reflection; + +namespace Microsoft.EntityFrameworkCore.TestUtilities +{ + public class MockMethodInfo : MethodInfo + { + private readonly Action _invoke; + + public MockMethodInfo(Type declaringType, Action invoke = null) + { + _invoke = invoke; + DeclaringType = declaringType; + } + + public override Type DeclaringType { get; } + + public override ICustomAttributeProvider ReturnTypeCustomAttributes + => throw new NotImplementedException(); + + public override RuntimeMethodHandle MethodHandle + => throw new NotImplementedException(); + + public override MethodAttributes Attributes + => throw new NotImplementedException(); + + public override string Name + => throw new NotImplementedException(); + + public override Type ReflectedType + => throw new NotImplementedException(); + + public override MethodInfo GetBaseDefinition() + => throw new NotImplementedException(); + + public override object[] GetCustomAttributes(bool inherit) + => throw new NotImplementedException(); + + public override object[] GetCustomAttributes(Type attributeType, bool inherit) + => throw new NotImplementedException(); + + public override MethodImplAttributes GetMethodImplementationFlags() + => throw new NotImplementedException(); + + public override ParameterInfo[] GetParameters() + => new ParameterInfo[1]; + + public override object Invoke(object obj, BindingFlags invokeAttr, Binder binder, object[] parameters, CultureInfo culture) + { + _invoke?.Invoke(parameters); + + return null; + } + public override bool IsDefined(Type attributeType, bool inherit) + => throw new NotImplementedException(); + } +}