From cc0eaf9a7635239cd35ebe864aa6b3bf1cacd54a Mon Sep 17 00:00:00 2001 From: Pranav K Date: Sun, 25 Feb 2018 20:47:04 -0800 Subject: [PATCH] Add a functional test to verify RazorCompileOnBuild * Verify precompiled views are used * Merge developer exception page tests with dotnet run tests * Turn logging down for EF DbCommands to make logs less noisy --- samples/MusicStore/Program.cs | 3 + samples/MusicStore/Views/Home/Index.cshtml | 2 +- .../MusicStore/Views/Shared/_Layout.cshtml | 5 +- test/MusicStore.E2ETests/Common/Helpers.cs | 4 +- .../DotnetRunTestRunner.cs | 85 +++++++++++++++++++ .../MusicStore.E2ETests/DotnetRunTests_X64.cs | 39 +++++++++ .../Implementation/FacebookLoginScenarios.cs | 2 +- .../Implementation/Validator.cs | 19 ++++- .../NtlmAuthentationTest.cs | 2 +- .../MusicStore.E2ETests/OpenIdConnectTests.cs | 2 +- .../PublishAndRunTestRunner.cs | 55 +----------- .../PublishAndRunTests_X64.cs | 13 --- test/MusicStore.E2ETests/SmokeTestRunner.cs | 2 +- .../SmokeTestsOnNanoServer.cs | 2 +- .../SmokeTestsUsingStore/TestHelper.cs | 2 +- 15 files changed, 155 insertions(+), 82 deletions(-) create mode 100644 test/MusicStore.E2ETests/DotnetRunTestRunner.cs create mode 100644 test/MusicStore.E2ETests/DotnetRunTests_X64.cs diff --git a/samples/MusicStore/Program.cs b/samples/MusicStore/Program.cs index 07c8104ace..195f5ec95e 100644 --- a/samples/MusicStore/Program.cs +++ b/samples/MusicStore/Program.cs @@ -57,6 +57,9 @@ namespace MusicStore var logLevel = string.Equals(environment, "Development", StringComparison.Ordinal) ? LogLevel.Information : LogLevel.Warning; factory.SetMinimumLevel(logLevel); + + // Turn off Info logging for EF commands + factory.AddFilter("Microsoft.EntityFrameworkCore.Database.Command", LogLevel.Warning); }); var host = builder.Build(); diff --git a/samples/MusicStore/Views/Home/Index.cshtml b/samples/MusicStore/Views/Home/Index.cshtml index 2216fbbb3b..b22793a9d3 100644 --- a/samples/MusicStore/Views/Home/Index.cshtml +++ b/samples/MusicStore/Views/Home/Index.cshtml @@ -18,4 +18,4 @@ } - \ No newline at end of file + diff --git a/samples/MusicStore/Views/Shared/_Layout.cshtml b/samples/MusicStore/Views/Shared/_Layout.cshtml index d2009c0b2b..6f21bc7d87 100644 --- a/samples/MusicStore/Views/Shared/_Layout.cshtml +++ b/samples/MusicStore/Views/Shared/_Layout.cshtml @@ -1,4 +1,4 @@ -@inject IOptions AppSettings +@inject IOptions AppSettings @@ -51,6 +51,7 @@

www.github.com/aspnet/MusicStore

@Html.ActionLink("admin", "Index", "StoreManager", new { area = "Admin" }) + This view served from @GetType().Assembly.FullName
@@ -71,4 +72,4 @@ @RenderSection("scripts", required: false) - \ No newline at end of file + diff --git a/test/MusicStore.E2ETests/Common/Helpers.cs b/test/MusicStore.E2ETests/Common/Helpers.cs index eb8da01c4c..d73d2d08f9 100644 --- a/test/MusicStore.E2ETests/Common/Helpers.cs +++ b/test/MusicStore.E2ETests/Common/Helpers.cs @@ -7,7 +7,7 @@ namespace E2ETests { public class Helpers { - public static string GetApplicationPath(ApplicationType applicationType) + public static string GetApplicationPath() { var solutionDirectory = TestPathUtilities.GetSolutionRootDirectory("MusicStore"); return Path.GetFullPath(Path.Combine(solutionDirectory, "samples", "MusicStore")); @@ -60,4 +60,4 @@ namespace E2ETests throw new ArgumentException($"Unknown runtime flavor '{flavor}."); } } -} \ No newline at end of file +} diff --git a/test/MusicStore.E2ETests/DotnetRunTestRunner.cs b/test/MusicStore.E2ETests/DotnetRunTestRunner.cs new file mode 100644 index 0000000000..d5f38e8de2 --- /dev/null +++ b/test/MusicStore.E2ETests/DotnetRunTestRunner.cs @@ -0,0 +1,85 @@ +// 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.IO; +using System.Net.Http; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Server.IntegrationTesting; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Testing; +using Xunit; +using Xunit.Abstractions; + +namespace E2ETests +{ + public class DotnetRunTestRunner : LoggedTest + { + public DotnetRunTestRunner(ITestOutputHelper output) + : base(output) + { + } + + public async Task RunTests( + ServerType serverType, + RuntimeFlavor runtimeFlavor, + ApplicationType applicationType, + RuntimeArchitecture runtimeArchitecture) + { + var testName = $"DotnetRunTests_{serverType}_{runtimeFlavor}_{applicationType}"; + using (StartLog(out var loggerFactory, testName)) + { + var logger = loggerFactory.CreateLogger("DotnetRunTests"); + var musicStoreDbName = DbUtils.GetUniqueName(); + var applicationPath = Helpers.GetApplicationPath(); + var deploymentParameters = new DeploymentParameters( + applicationPath, serverType, runtimeFlavor, runtimeArchitecture) + { + PublishApplicationBeforeDeployment = false, + TargetFramework = Helpers.GetTargetFramework(runtimeFlavor), + Configuration = Helpers.GetCurrentBuildConfiguration(), + EnvironmentName = "Development", + ApplicationType = applicationType, + UserAdditionalCleanup = parameters => + { + DbUtils.DropDatabase(musicStoreDbName, logger); + }, + EnvironmentVariables = + { + { MusicStoreConfig.ConnectionStringKey, DbUtils.CreateConnectionString(musicStoreDbName) }, + }, + }; + + using (var deployer = ApplicationDeployerFactory.Create(deploymentParameters, loggerFactory)) + { + var deploymentResult = await deployer.DeployAsync(); + var httpClientHandler = new HttpClientHandler { UseDefaultCredentials = true }; + var httpClient = deploymentResult.CreateHttpClient(httpClientHandler); + + var response = await RetryHelper.RetryRequest( + () => httpClient.GetAsync(string.Empty), logger, deploymentResult.HostShutdownToken); + + Assert.False(response == null, "Response object is null because the client could not " + + "connect to the server after multiple retries"); + + var validator = new Validator(httpClient, httpClientHandler, logger, deploymentResult); + + logger.LogInformation("Verifying home page"); + // Verify HomePage should validate that we're using precompiled views. + await validator.VerifyHomePage(response); + + // Verify developer exception page + logger.LogInformation("Verifying developer exception page"); + response = await RetryHelper.RetryRequest( + () => httpClient.GetAsync("PageThatThrows"), logger, cancellationToken: deploymentResult.HostShutdownToken); + await validator.VerifyDeveloperExceptionPage(response); + + logger.LogInformation("Variation completed successfully."); + } + } + } + } +} diff --git a/test/MusicStore.E2ETests/DotnetRunTests_X64.cs b/test/MusicStore.E2ETests/DotnetRunTests_X64.cs new file mode 100644 index 0000000000..062b0ac287 --- /dev/null +++ b/test/MusicStore.E2ETests/DotnetRunTests_X64.cs @@ -0,0 +1,39 @@ +// 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.Threading.Tasks; +using Microsoft.AspNetCore.Server.IntegrationTesting; +using Microsoft.AspNetCore.Testing.xunit; +using Xunit; +using Xunit.Abstractions; + +namespace E2ETests +{ + [Trait("E2Etests", "DotnetRun")] + public class DotnetRunTests_X64 + { + private readonly DotnetRunTestRunner _testRunner; + + public DotnetRunTests_X64(ITestOutputHelper output) + { + _testRunner = new DotnetRunTestRunner(output); + } + + [Fact] + public Task DotnetRunTests_X64_Kestrel_CoreClr() + { + return RunTests(ServerType.Kestrel, RuntimeFlavor.CoreClr, ApplicationType.Portable); + } + + [ConditionalFact] + [OSSkipCondition(OperatingSystems.Linux | OperatingSystems.MacOSX)] + public Task DotnetRunTests_X64_Kestrel_Clr() + { + // CLR must be published as standalone to perform rid specific deployment + return RunTests(ServerType.Kestrel, RuntimeFlavor.Clr, ApplicationType.Standalone); + } + + private Task RunTests(ServerType serverType, RuntimeFlavor runtimeFlavor, ApplicationType applicationType) + => _testRunner.RunTests(serverType, runtimeFlavor, applicationType, RuntimeArchitecture.x64); + } +} diff --git a/test/MusicStore.E2ETests/Implementation/FacebookLoginScenarios.cs b/test/MusicStore.E2ETests/Implementation/FacebookLoginScenarios.cs index 1f8274c912..e98b2985ef 100644 --- a/test/MusicStore.E2ETests/Implementation/FacebookLoginScenarios.cs +++ b/test/MusicStore.E2ETests/Implementation/FacebookLoginScenarios.cs @@ -95,4 +95,4 @@ namespace E2ETests _logger.LogInformation("Middleware events were fired successfully"); } } -} \ No newline at end of file +} diff --git a/test/MusicStore.E2ETests/Implementation/Validator.cs b/test/MusicStore.E2ETests/Implementation/Validator.cs index 92b2a1fe2d..52f6822d1a 100644 --- a/test/MusicStore.E2ETests/Implementation/Validator.cs +++ b/test/MusicStore.E2ETests/Implementation/Validator.cs @@ -110,8 +110,8 @@ namespace E2ETests //Helpers.ThrowIfResponseStatusNotOk(runtimeResponse, _logger); } - //var runtimeInfo = await runtimeResponse.Content.ReadAsStringAsync(); - //_logger.LogInformation(runtimeInfo); + // Verify the app is using precompiled views + Assert.Contains("MusicStore.Views, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null", responseContent); } public async Task VerifyNtlmHomePage(HttpResponseMessage response) @@ -130,8 +130,8 @@ namespace E2ETests public async Task VerifyDeveloperExceptionPage(HttpResponseMessage response) { var responseContent = await response.Content.ReadAsStringAsync(); - Assert.Contains(responseContent, "PageThatThrows.cshtml"); - Assert.Contains(responseContent, "@{ throw new InvalidOperationException(); }"); + Assert.Contains("PageThatThrows.cshtml", responseContent); + Assert.Contains("@{ throw new InvalidOperationException(); }", responseContent); } public void ValidateLayoutPage(string responseContent) @@ -143,6 +143,17 @@ namespace E2ETests Assert.Contains("
  • ", responseContent, StringComparison.OrdinalIgnoreCase); } + public async Task VerifyRuntimeCompiledHomePage(HttpResponseMessage response) + { + var responseContent = await response.Content.ReadAsStringAsync(); + + // Smoke test to make sure the page is served correctly. + Assert.Contains("Home Page – ASP.NET MVC Music Store", responseContent); + + // Verify the app is using a runtime compiled view + Assert.DoesNotContain("MusicStore.Views, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null", responseContent); + } + public async Task VerifyStaticContentServed() { _logger.LogInformation("Validating if static contents are served.."); diff --git a/test/MusicStore.E2ETests/NtlmAuthentationTest.cs b/test/MusicStore.E2ETests/NtlmAuthentationTest.cs index 28b94ecddd..62692ab165 100644 --- a/test/MusicStore.E2ETests/NtlmAuthentationTest.cs +++ b/test/MusicStore.E2ETests/NtlmAuthentationTest.cs @@ -68,7 +68,7 @@ namespace E2ETests var logger = loggerFactory.CreateLogger("NtlmAuthenticationTest"); var musicStoreDbName = DbUtils.GetUniqueName(); - var deploymentParameters = new DeploymentParameters(Helpers.GetApplicationPath(applicationType), serverType, runtimeFlavor, architecture) + var deploymentParameters = new DeploymentParameters(Helpers.GetApplicationPath(), serverType, runtimeFlavor, architecture) { PublishApplicationBeforeDeployment = true, PreservePublishedApplicationForDebugging = Helpers.PreservePublishedApplicationForDebugging, diff --git a/test/MusicStore.E2ETests/OpenIdConnectTests.cs b/test/MusicStore.E2ETests/OpenIdConnectTests.cs index 191a42a86b..4e2ef063ae 100644 --- a/test/MusicStore.E2ETests/OpenIdConnectTests.cs +++ b/test/MusicStore.E2ETests/OpenIdConnectTests.cs @@ -46,7 +46,7 @@ namespace E2ETests var logger = loggerFactory.CreateLogger("OpenIdConnectTestSuite"); var musicStoreDbName = DbUtils.GetUniqueName(); - var deploymentParameters = new DeploymentParameters(Helpers.GetApplicationPath(applicationType), serverType, runtimeFlavor, architecture) + var deploymentParameters = new DeploymentParameters(Helpers.GetApplicationPath(), serverType, runtimeFlavor, architecture) { PublishApplicationBeforeDeployment = true, PreservePublishedApplicationForDebugging = Helpers.PreservePublishedApplicationForDebugging, diff --git a/test/MusicStore.E2ETests/PublishAndRunTestRunner.cs b/test/MusicStore.E2ETests/PublishAndRunTestRunner.cs index c1fbd55b2f..f12a68f25c 100644 --- a/test/MusicStore.E2ETests/PublishAndRunTestRunner.cs +++ b/test/MusicStore.E2ETests/PublishAndRunTestRunner.cs @@ -31,7 +31,7 @@ namespace E2ETests var musicStoreDbName = DbUtils.GetUniqueName(); var deploymentParameters = new DeploymentParameters( - Helpers.GetApplicationPath(applicationType), serverType, runtimeFlavor, runtimeArchitecture) + Helpers.GetApplicationPath(), serverType, runtimeFlavor, runtimeArchitecture) { PublishApplicationBeforeDeployment = true, PreservePublishedApplicationForDebugging = Helpers.PreservePublishedApplicationForDebugging, @@ -85,58 +85,5 @@ namespace E2ETests } } } - - public async Task RunDeveloperTests( - ServerType serverType, - RuntimeFlavor runtimeFlavor, - ApplicationType applicationType, - RuntimeArchitecture runtimeArchitecture) - { - var testName = $"PublishAndRunTests_{serverType}_{runtimeFlavor}_{applicationType}"; - using (StartLog(out var loggerFactory, testName)) - { - var logger = loggerFactory.CreateLogger("Publish_And_Run_Development"); - var musicStoreDbName = DbUtils.GetUniqueName(); - - var deploymentParameters = new DeploymentParameters( - Helpers.GetApplicationPath(applicationType), serverType, runtimeFlavor, runtimeArchitecture) - { - PublishApplicationBeforeDeployment = true, - PreservePublishedApplicationForDebugging = Helpers.PreservePublishedApplicationForDebugging, - TargetFramework = Helpers.GetTargetFramework(runtimeFlavor), - Configuration = Helpers.GetCurrentBuildConfiguration(), - EnvironmentName = "Development", - ApplicationType = applicationType, - UserAdditionalCleanup = parameters => - { - DbUtils.DropDatabase(musicStoreDbName, logger); - } - }; - - // Override the connection strings using environment based configuration - deploymentParameters.EnvironmentVariables - .Add(new KeyValuePair( - MusicStoreConfig.ConnectionStringKey, - DbUtils.CreateConnectionString(musicStoreDbName))); - - using (var deployer = ApplicationDeployerFactory.Create(deploymentParameters, loggerFactory)) - { - var deploymentResult = await deployer.DeployAsync(); - var httpClientHandler = new HttpClientHandler { UseDefaultCredentials = true }; - var httpClient = deploymentResult.CreateHttpClient(httpClientHandler); - - // Request to base address and check if various parts of the body are rendered & - // measure the cold startup time. - // Add retry logic since tests are flaky on mono due to connection issues - var validator = new Validator(httpClient, httpClientHandler, logger, deploymentResult); - var response = await RetryHelper.RetryRequest(() => httpClient.GetAsync("PageThatThrows"), logger, cancellationToken: deploymentResult.HostShutdownToken); - - logger.LogInformation("Verifying developer exception page"); - await validator.VerifyDeveloperExceptionPage(response); - - logger.LogInformation("Variation completed successfully."); - } - } - } } } diff --git a/test/MusicStore.E2ETests/PublishAndRunTests_X64.cs b/test/MusicStore.E2ETests/PublishAndRunTests_X64.cs index a6e2776956..76161cb6f9 100644 --- a/test/MusicStore.E2ETests/PublishAndRunTests_X64.cs +++ b/test/MusicStore.E2ETests/PublishAndRunTests_X64.cs @@ -44,19 +44,6 @@ namespace E2ETests return RunTests(ServerType.Kestrel, RuntimeFlavor.CoreClr, ApplicationType.Portable); } - [Fact] - public Task PublishAndRunDevelopmentTests_X64_Kestrel_CoreClr_Portable() - { - return _testRunner.RunTests(ServerType.Kestrel, RuntimeFlavor.CoreClr, ApplicationType.Portable, RuntimeArchitecture.x64); - } - - [ConditionalFact] - [OSSkipCondition(OperatingSystems.Linux | OperatingSystems.MacOSX)] - public Task PublishAndRunDevelopmentTests_X64_Kestrel_Clr_Portable() - { - return _testRunner.RunTests(ServerType.Kestrel, RuntimeFlavor.Clr, ApplicationType.Portable, RuntimeArchitecture.x64); - } - [Fact] public Task PublishAndRunTests_X64_Kestrel_CoreClr_Standalone() { diff --git a/test/MusicStore.E2ETests/SmokeTestRunner.cs b/test/MusicStore.E2ETests/SmokeTestRunner.cs index 715db35066..eb766b7da4 100644 --- a/test/MusicStore.E2ETests/SmokeTestRunner.cs +++ b/test/MusicStore.E2ETests/SmokeTestRunner.cs @@ -30,7 +30,7 @@ namespace E2ETests var musicStoreDbName = DbUtils.GetUniqueName(); var deploymentParameters = new DeploymentParameters( - Helpers.GetApplicationPath(applicationType), serverType, runtimeFlavor, architecture) + Helpers.GetApplicationPath(), serverType, runtimeFlavor, architecture) { EnvironmentName = "SocialTesting", ServerConfigTemplateContent = (serverType == ServerType.IISExpress) ? File.ReadAllText("Http.config") : null, diff --git a/test/MusicStore.E2ETests/SmokeTestsOnNanoServer.cs b/test/MusicStore.E2ETests/SmokeTestsOnNanoServer.cs index b72c1d1e7c..e5960c9bc9 100644 --- a/test/MusicStore.E2ETests/SmokeTestsOnNanoServer.cs +++ b/test/MusicStore.E2ETests/SmokeTestsOnNanoServer.cs @@ -236,7 +236,7 @@ namespace E2ETests { var logger = loggerFactory.CreateLogger(nameof(SmokeTestsOnNanoServerUsingStandaloneRuntime)); var deploymentParameters = new RemoteWindowsDeploymentParameters( - Helpers.GetApplicationPath(applicationType), + Helpers.GetApplicationPath(), _remoteDeploymentConfig.DotnetRuntimePathOnShare, serverType, RuntimeFlavor.CoreClr, diff --git a/test/MusicStore.E2ETests/SmokeTestsUsingStore/TestHelper.cs b/test/MusicStore.E2ETests/SmokeTestsUsingStore/TestHelper.cs index d0ad3de500..1d2e8d771e 100644 --- a/test/MusicStore.E2ETests/SmokeTestsUsingStore/TestHelper.cs +++ b/test/MusicStore.E2ETests/SmokeTestsUsingStore/TestHelper.cs @@ -30,7 +30,7 @@ namespace E2ETests.SmokeTestsUsingStore var musicStoreDbName = DbUtils.GetUniqueName(); var deploymentParameters = new DeploymentParameters( - Helpers.GetApplicationPath(ApplicationType.Portable), serverType, RuntimeFlavor.CoreClr, RuntimeArchitecture.x64) + Helpers.GetApplicationPath(), serverType, RuntimeFlavor.CoreClr, RuntimeArchitecture.x64) { EnvironmentName = "SocialTesting", SiteName = "MusicStoreTestSiteUsingStore",