diff --git a/MusicStore.sln b/MusicStore.sln index d46ebebd0c..4d955ca818 100644 --- a/MusicStore.sln +++ b/MusicStore.sln @@ -35,6 +35,9 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Facebook", "Facebook", "{B5 EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "shared", "shared", "{E839AEB0-7926-4FEE-B22C-11AF7EF5D4BF}" + ProjectSection(SolutionItems) = preProject + shared\MusicStoreConfig.cs = shared\MusicStoreConfig.cs + EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Common", "Common", "{78715843-B625-414E-9074-56908C48EF28}" ProjectSection(SolutionItems) = preProject diff --git a/MusicStore.sln.DotSettings b/MusicStore.sln.DotSettings index 420ee5ca3d..4f3db97b47 100644 --- a/MusicStore.sln.DotSettings +++ b/MusicStore.sln.DotSettings @@ -1,9 +1,9 @@  - <?xml version="1.0" encoding="utf-16"?><Profile name="EntityFramework"><HtmlReformatCode>True</HtmlReformatCode><CSArrangeThisQualifier>True</CSArrangeThisQualifier><CSRemoveCodeRedundancies>True</CSRemoveCodeRedundancies><CSUseAutoProperty>True</CSUseAutoProperty><CSMakeFieldReadonly>True</CSMakeFieldReadonly><CSUseVar><BehavourStyle>CAN_CHANGE_TO_IMPLICIT</BehavourStyle><LocalVariableStyle>ALWAYS_IMPLICIT</LocalVariableStyle><ForeachVariableStyle>ALWAYS_IMPLICIT</ForeachVariableStyle></CSUseVar><CSOptimizeUsings><OptimizeUsings>True</OptimizeUsings><EmbraceInRegion>False</EmbraceInRegion><RegionName></RegionName></CSOptimizeUsings><CSShortenReferences>True</CSShortenReferences><CSReformatCode>True</CSReformatCode><XMLReformatCode>True</XMLReformatCode><CSUpdateFileHeader>True</CSUpdateFileHeader><CSharpFormatDocComments>True</CSharpFormatDocComments></Profile> + <?xml version="1.0" encoding="utf-16"?><Profile name="MusicStore"><HtmlReformatCode>True</HtmlReformatCode><CSArrangeThisQualifier>True</CSArrangeThisQualifier><CSRemoveCodeRedundancies>True</CSRemoveCodeRedundancies><CSUseAutoProperty>True</CSUseAutoProperty><CSMakeFieldReadonly>True</CSMakeFieldReadonly><CSUseVar><BehavourStyle>CAN_CHANGE_TO_IMPLICIT</BehavourStyle><LocalVariableStyle>ALWAYS_IMPLICIT</LocalVariableStyle><ForeachVariableStyle>ALWAYS_IMPLICIT</ForeachVariableStyle></CSUseVar><CSOptimizeUsings><OptimizeUsings>True</OptimizeUsings><EmbraceInRegion>False</EmbraceInRegion><RegionName></RegionName></CSOptimizeUsings><CSShortenReferences>True</CSShortenReferences><CSReformatCode>True</CSReformatCode><XMLReformatCode>True</XMLReformatCode><CSUpdateFileHeader>True</CSUpdateFileHeader><CSharpFormatDocComments>True</CSharpFormatDocComments></Profile> - EntityFramework - EntityFramework + MusicStore + MusicStore False False False @@ -45,7 +45,8 @@ True - + Copyright (c) .NET Foundation. All rights reserved. +See License.txt in the project root for license information True True True @@ -63,6 +64,45 @@ True $object$_On$event$ <Policy Inspect="True" Prefix="_" Suffix="" Style="aaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> + <Policy Inspect="True" Prefix="I" Suffix="" Style="AaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> + <Policy Inspect="True" Prefix="T" Suffix="" Style="AaBb" /> $object$_On$event$ + <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> + True True + True True \ No newline at end of file diff --git a/shared/MusicStoreConfig.cs b/shared/MusicStoreConfig.cs new file mode 100644 index 0000000000..c1bcba19c6 --- /dev/null +++ b/shared/MusicStoreConfig.cs @@ -0,0 +1,7 @@ +namespace MusicStore +{ + public class StoreConfig + { + public const string ConnectionStringKey = "Data__DefaultConnection__ConnectionString"; + } +} \ No newline at end of file diff --git a/src/MusicStore/Startup.cs b/src/MusicStore/Startup.cs index 1ffc59169e..2c0d11f6c9 100644 --- a/src/MusicStore/Startup.cs +++ b/src/MusicStore/Startup.cs @@ -52,7 +52,7 @@ namespace MusicStore services.AddEntityFramework() .AddSqlServer() .AddDbContext(options => - options.UseSqlServer(Configuration["Data:DefaultConnection:ConnectionString"])); + options.UseSqlServer(Configuration[StoreConfig.ConnectionStringKey.Replace("__",":")])); } // Add Identity services to the services container diff --git a/src/MusicStore/config.json b/src/MusicStore/config.json index e764ec63c9..e67e7d02d0 100644 --- a/src/MusicStore/config.json +++ b/src/MusicStore/config.json @@ -8,7 +8,7 @@ "DefaultConnection": { // Use a shared (and running) LocalDB database when executing in IIS e.g. // "Server=(localdb)\\.\\IIS_DB;Database=MusicStore;Trusted_Connection=False;MultipleActiveResultSets=true;User ID=iis_login;Password=********" - "Connectionstring": "Server=(localdb)\\MSSQLLocalDB;Database=MusicStore;Trusted_Connection=True;MultipleActiveResultSets=true;Connect Timeout=30;" + "ConnectionString": "Server=(localdb)\\MSSQLLocalDB;Database=MusicStore;Trusted_Connection=True;MultipleActiveResultSets=true;Connect Timeout=30;" } } } \ No newline at end of file diff --git a/test/E2ETests/Common/DbUtils.cs b/test/E2ETests/Common/DbUtils.cs index effc5c9189..c1acbe476d 100644 --- a/test/E2ETests/Common/DbUtils.cs +++ b/test/E2ETests/Common/DbUtils.cs @@ -1,5 +1,6 @@ using System; using System.Data.SqlClient; +using Microsoft.AspNetCore.Testing; using Microsoft.Extensions.Logging; namespace E2ETests @@ -9,14 +10,28 @@ namespace E2ETests /// public class DbUtils { - public const string CONNECTION_STRING_FORMAT = "Server=(localdb)\\MSSQLLocalDB;Database={0};Trusted_Connection=True;MultipleActiveResultSets=true;Connect Timeout=30;"; + private const string BaseConnString = @"Server=(localdb)\MSSQLLocalDB;Trusted_Connection=True;MultipleActiveResultSets=true;Connect Timeout=30;"; + + public static string CreateConnectionString(string dbName) + => new SqlConnectionStringBuilder(BaseConnString) + { + InitialCatalog = dbName + }.ToString(); + + public static string GetUniqueName() + => "MusicStore_Test_" + Guid.NewGuid().ToString().Replace("-", string.Empty); public static void DropDatabase(string databaseName, ILogger logger) { + if (Helpers.RunningOnMono + || !TestPlatformHelper.IsWindows) + { + return; + } try { logger.LogInformation("Trying to drop database '{0}'", databaseName); - using (var conn = new SqlConnection(string.Format(CONNECTION_STRING_FORMAT, "master"))) + using (var conn = new SqlConnection(CreateConnectionString("master"))) { conn.Open(); diff --git a/test/E2ETests/Common/XunitLogger.cs b/test/E2ETests/Common/XunitLogger.cs new file mode 100644 index 0000000000..510a3799cb --- /dev/null +++ b/test/E2ETests/Common/XunitLogger.cs @@ -0,0 +1,59 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// See License.txt in the project root for license information + +using System; +using Microsoft.Extensions.Logging; +using Xunit.Abstractions; +using System.Linq; + +namespace E2ETests.Common +{ + public class XunitLogger : ILogger, IDisposable + { + private readonly LogLevel _minLogLevel; + private readonly ITestOutputHelper _output; + private bool _disposed; + + public XunitLogger(ITestOutputHelper output, LogLevel minLogLevel) + { + _minLogLevel = minLogLevel; + _output = output; + } + + public void Log( + LogLevel logLevel, EventId eventId, TState state, Exception exception, Func formatter) + { + if (!IsEnabled(logLevel)) + { + return; + } + var firstLinePrefix = "| " + logLevel + ": "; + var lines = formatter(state, exception).Split('\n'); + _output.WriteLine(firstLinePrefix + lines.First()); + + var additionalLinePrefix = "|" + new string(' ', firstLinePrefix.Length - 1); + foreach (var line in lines.Skip(1)) + { + _output.WriteLine(additionalLinePrefix + line.Trim('\r')); + } + } + + public bool IsEnabled(LogLevel logLevel) + => logLevel >= _minLogLevel && !_disposed; + + public IDisposable BeginScopeImpl(object state) + => new NullScope(); + + private class NullScope : IDisposable + { + public void Dispose() + { + } + } + + public void Dispose() + { + _disposed = true; + } + } +} diff --git a/test/E2ETests/Implementation/Validator.cs b/test/E2ETests/Implementation/Validator.cs index 1fde9ccfb1..12f73956f0 100644 --- a/test/E2ETests/Implementation/Validator.cs +++ b/test/E2ETests/Implementation/Validator.cs @@ -37,7 +37,7 @@ namespace E2ETests if (response.StatusCode != HttpStatusCode.OK) { - Console.WriteLine("Home page content : {0}", responseContent); + _logger.LogInformation("Home page content : {0}", responseContent); } Assert.Equal(HttpStatusCode.OK, response.StatusCode); @@ -177,6 +177,7 @@ namespace E2ETests var content = new FormUrlEncodedContent(formParameters.ToArray()); response = await _httpClient.PostAsync("Account/Register", content); + await ThrowIfResponseStatusNotOk(response); responseContent = await response.Content.ReadAsStringAsync(); Assert.Null(_httpClientHandler.CookieContainer.GetCookies(new Uri(_deploymentResult.ApplicationBaseUri)).GetCookieWithName(".AspNetCore.Microsoft.AspNetCore.Identity.Application")); Assert.Contains("
  • The password and confirmation password do not match.
  • ", responseContent, StringComparison.OrdinalIgnoreCase); @@ -492,7 +493,11 @@ namespace E2ETests { if (response.StatusCode != HttpStatusCode.OK) { - _logger.LogError(await response.Content.ReadAsStringAsync()); + _logger.LogError( + "Headers: {0}", + string.Join("\n", response.Headers.Select(h => h.Key + "=" + string.Join(",", h.Value)))); + var content = await response.Content.ReadAsStringAsync(); + _logger.LogError("Content: Length={0}\n{1}", content.Length, content); throw new Exception(string.Format("Received the above response with status code : {0}", response.StatusCode)); } } diff --git a/test/E2ETests/NtlmAuthentationTest.cs b/test/E2ETests/NtlmAuthentationTest.cs index 646f2a770b..59d7018643 100644 --- a/test/E2ETests/NtlmAuthentationTest.cs +++ b/test/E2ETests/NtlmAuthentationTest.cs @@ -3,30 +3,34 @@ using System.Collections.Generic; using System.IO; using System.Net.Http; using System.Threading.Tasks; +using E2ETests.Common; using Microsoft.AspNetCore.Server.Testing; using Microsoft.AspNetCore.Testing.xunit; using Microsoft.Extensions.Logging; using Xunit; +using Xunit.Abstractions; namespace E2ETests { // Uses ports ranging 5050 - 5060. - public class NtlmAuthenticationTests + public class NtlmAuthenticationTests : IDisposable { + private readonly XunitLogger _logger; + + public NtlmAuthenticationTests(ITestOutputHelper output) + { + _logger = new XunitLogger(output, LogLevel.Information); + } + [ConditionalTheory, Trait("E2Etests", "E2Etests")] [OSSkipCondition(OperatingSystems.Linux)] [OSSkipCondition(OperatingSystems.MacOSX)] [InlineData(ServerType.WebListener, RuntimeFlavor.CoreClr, RuntimeArchitecture.x64, "http://localhost:5050/")] public async Task NtlmAuthenticationTest(ServerType serverType, RuntimeFlavor runtimeFlavor, RuntimeArchitecture architecture, string applicationBaseUrl) { - var logger = new LoggerFactory() - .AddConsole(LogLevel.Information) - .CreateLogger(string.Format("Ntlm:{0}:{1}:{2}", serverType, runtimeFlavor, architecture)); - - using (logger.BeginScope("NtlmAuthenticationTest")) + using (_logger.BeginScope("NtlmAuthenticationTest")) { - var musicStoreDbName = Guid.NewGuid().ToString().Replace("-", string.Empty); - var connectionString = string.Format(DbUtils.CONNECTION_STRING_FORMAT, musicStoreDbName); + var musicStoreDbName = DbUtils.GetUniqueName(); var deploymentParameters = new DeploymentParameters(Helpers.GetApplicationPath(), serverType, runtimeFlavor, architecture) { @@ -38,21 +42,17 @@ namespace E2ETests SiteName = "MusicStoreNtlmAuthentication", //This is configured in the NtlmAuthentication.config UserAdditionalCleanup = parameters => { - if (!Helpers.RunningOnMono) - { - // Mono uses InMemoryStore - DbUtils.DropDatabase(musicStoreDbName, logger); - } + DbUtils.DropDatabase(musicStoreDbName, _logger); } }; // Override the connection strings using environment based configuration deploymentParameters.EnvironmentVariables .Add(new KeyValuePair( - "SQLAZURECONNSTR_DefaultConnection", - string.Format(DbUtils.CONNECTION_STRING_FORMAT, musicStoreDbName))); + MusicStore.StoreConfig.ConnectionStringKey, + DbUtils.CreateConnectionString(musicStoreDbName))); - using (var deployer = ApplicationDeployerFactory.Create(deploymentParameters, logger)) + using (var deployer = ApplicationDeployerFactory.Create(deploymentParameters, _logger)) { var deploymentResult = deployer.Deploy(); var httpClientHandler = new HttpClientHandler() { UseDefaultCredentials = true, AllowAutoRedirect = false }; @@ -62,20 +62,25 @@ namespace E2ETests var response = await RetryHelper.RetryRequest(async () => { return await httpClient.GetAsync(string.Empty); - }, logger: logger, cancellationToken: deploymentResult.HostShutdownToken); + }, logger: _logger, cancellationToken: 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); + var validator = new Validator(httpClient, httpClientHandler, _logger, deploymentResult); await validator.VerifyNtlmHomePage(response); //Should be able to access the store as the Startup adds necessary permissions for the current user await validator.AccessStoreWithPermissions(); - logger.LogInformation("Variation completed successfully."); + _logger.LogInformation("Variation completed successfully."); } } } + + public void Dispose() + { + _logger.Dispose(); + } } } diff --git a/test/E2ETests/OpenIdConnectTests.cs b/test/E2ETests/OpenIdConnectTests.cs index a986da9af0..8af71af019 100644 --- a/test/E2ETests/OpenIdConnectTests.cs +++ b/test/E2ETests/OpenIdConnectTests.cs @@ -2,17 +2,26 @@ using System; using System.Collections.Generic; using System.Net.Http; using System.Threading.Tasks; +using E2ETests.Common; using Microsoft.AspNetCore.Server.Testing; using Microsoft.AspNetCore.Testing; using Microsoft.AspNetCore.Testing.xunit; using Microsoft.Extensions.Logging; using Xunit; +using Xunit.Abstractions; namespace E2ETests { // Uses ports ranging 5040 - 5049. - public class OpenIdConnectTests + public class OpenIdConnectTests : IDisposable { + private readonly XunitLogger _logger; + + public OpenIdConnectTests(ITestOutputHelper output) + { + _logger = new XunitLogger(output, LogLevel.Information); + } + [ConditionalTheory(Skip = "Temporarily skipped the test to fix potential product issue"), Trait("E2Etests", "E2Etests")] [OSSkipCondition(OperatingSystems.Linux)] [OSSkipCondition(OperatingSystems.MacOSX)] @@ -47,14 +56,9 @@ namespace E2ETests private async Task OpenIdConnectTestSuite(ServerType serverType, RuntimeFlavor runtimeFlavor, RuntimeArchitecture architecture, string applicationBaseUrl) { - var logger = new LoggerFactory() - .AddConsole(LogLevel.Information) - .CreateLogger(string.Format("OpenId:{0}:{1}:{2}", serverType, runtimeFlavor, architecture)); - - using (logger.BeginScope("OpenIdConnectTestSuite")) + using (_logger.BeginScope("OpenIdConnectTestSuite")) { - var musicStoreDbName = Guid.NewGuid().ToString().Replace("-", string.Empty); - var connectionString = string.Format(DbUtils.CONNECTION_STRING_FORMAT, musicStoreDbName); + var musicStoreDbName = DbUtils.GetUniqueName(); var deploymentParameters = new DeploymentParameters(Helpers.GetApplicationPath(), serverType, runtimeFlavor, architecture) { @@ -64,22 +68,17 @@ namespace E2ETests EnvironmentName = "OpenIdConnectTesting", UserAdditionalCleanup = parameters => { - if (!Helpers.RunningOnMono - && TestPlatformHelper.IsWindows) - { - // Mono uses InMemoryStore - DbUtils.DropDatabase(musicStoreDbName, logger); - } + DbUtils.DropDatabase(musicStoreDbName, _logger); } }; // Override the connection strings using environment based configuration deploymentParameters.EnvironmentVariables .Add(new KeyValuePair( - "SQLAZURECONNSTR_DefaultConnection", - string.Format(DbUtils.CONNECTION_STRING_FORMAT, musicStoreDbName))); + MusicStore.StoreConfig.ConnectionStringKey, + DbUtils.CreateConnectionString(musicStoreDbName))); - using (var deployer = ApplicationDeployerFactory.Create(deploymentParameters, logger)) + using (var deployer = ApplicationDeployerFactory.Create(deploymentParameters, _logger)) { var deploymentResult = deployer.Deploy(); var httpClientHandler = new HttpClientHandler() { AllowAutoRedirect = false }; @@ -89,20 +88,25 @@ namespace E2ETests var response = await RetryHelper.RetryRequest(async () => { return await httpClient.GetAsync(string.Empty); - }, logger: logger, cancellationToken: deploymentResult.HostShutdownToken); + }, logger: _logger, cancellationToken: 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); + var validator = new Validator(httpClient, httpClientHandler, _logger, deploymentResult); await validator.VerifyHomePage(response); // OpenIdConnect login. await validator.LoginWithOpenIdConnect(); - logger.LogInformation("Variation completed successfully."); + _logger.LogInformation("Variation completed successfully."); } } } + + public void Dispose() + { + _logger.Dispose(); + } } } \ No newline at end of file diff --git a/test/E2ETests/PublishAndRunTests.cs b/test/E2ETests/PublishAndRunTests.cs index a981a5a1b7..b10ab524c7 100644 --- a/test/E2ETests/PublishAndRunTests.cs +++ b/test/E2ETests/PublishAndRunTests.cs @@ -3,17 +3,26 @@ using System.Collections.Generic; using System.IO; using System.Net.Http; using System.Threading.Tasks; +using E2ETests.Common; using Microsoft.AspNetCore.Server.Testing; using Microsoft.AspNetCore.Testing; using Microsoft.AspNetCore.Testing.xunit; using Microsoft.Extensions.Logging; using Xunit; +using Xunit.Abstractions; namespace E2ETests { // Uses ports ranging 5025 - 5039. - public class PublishAndRunTests_OnX64 + public class PublishAndRunTests_OnX64 : IDisposable { + private readonly XunitLogger _logger; + + public PublishAndRunTests_OnX64(ITestOutputHelper output) + { + _logger = new XunitLogger(output, LogLevel.Information); + } + [ConditionalTheory, Trait("E2Etests", "PublishAndRun")] [OSSkipCondition(OperatingSystems.Linux)] [OSSkipCondition(OperatingSystems.MacOSX)] @@ -28,7 +37,7 @@ namespace E2ETests string applicationBaseUrl, bool noSource) { - var testRunner = new PublishAndRunTests(); + var testRunner = new PublishAndRunTests(_logger); await testRunner.Publish_And_Run_Tests( serverType, runtimeFlavor, architecture, applicationBaseUrl, noSource); } @@ -43,16 +52,28 @@ namespace E2ETests string applicationBaseUrl, bool noSource) { - var testRunner = new PublishAndRunTests(); + var testRunner = new PublishAndRunTests(_logger); await testRunner.Publish_And_Run_Tests( serverType, runtimeFlavor, architecture, applicationBaseUrl, noSource); } + + public void Dispose() + { + _logger.Dispose(); + } } // TODO: temporarily disabling x86 tests as dotnet xunit test runner currently does not support 32-bit // public - class PublishAndRunTests_OnX86 + class PublishAndRunTests_OnX86 : IDisposable { + private readonly XunitLogger _logger; + + public PublishAndRunTests_OnX86(ITestOutputHelper output) + { + _logger = new XunitLogger(output, LogLevel.Information); + } + [ConditionalTheory, Trait("E2Etests", "PublishAndRun")] [OSSkipCondition(OperatingSystems.Linux)] [OSSkipCondition(OperatingSystems.MacOSX)] @@ -67,7 +88,7 @@ namespace E2ETests string applicationBaseUrl, bool noSource) { - var testRunner = new PublishAndRunTests(); + var testRunner = new PublishAndRunTests(_logger); await testRunner.Publish_And_Run_Tests( serverType, runtimeFlavor, architecture, applicationBaseUrl, noSource); } @@ -82,14 +103,26 @@ namespace E2ETests string applicationBaseUrl, bool noSource) { - var testRunner = new PublishAndRunTests(); + var testRunner = new PublishAndRunTests(_logger); await testRunner.Publish_And_Run_Tests( serverType, runtimeFlavor, architecture, applicationBaseUrl, noSource); } + + public void Dispose() + { + _logger.Dispose(); + } } public class PublishAndRunTests { + private ILogger _logger; + + public PublishAndRunTests(ILogger logger) + { + _logger = logger; + } + public async Task Publish_And_Run_Tests( ServerType serverType, RuntimeFlavor runtimeFlavor, @@ -97,14 +130,9 @@ namespace E2ETests string applicationBaseUrl, bool noSource) { - var logger = new LoggerFactory() - .AddConsole(LogLevel.Information) - .CreateLogger($"Publish:{serverType}:{runtimeFlavor}:{architecture}:{noSource}"); - - using (logger.BeginScope("Publish_And_Run_Tests")) + using (_logger.BeginScope("Publish_And_Run_Tests")) { - var musicStoreDbName = Guid.NewGuid().ToString().Replace("-", string.Empty); - var connectionString = string.Format(DbUtils.CONNECTION_STRING_FORMAT, musicStoreDbName); + var musicStoreDbName = DbUtils.GetUniqueName(); var deploymentParameters = new DeploymentParameters( Helpers.GetApplicationPath(), serverType, runtimeFlavor, architecture) @@ -114,22 +142,17 @@ namespace E2ETests PublishTargetFramework = runtimeFlavor == RuntimeFlavor.Clr ? "dnx451" : "netstandardapp1.5", UserAdditionalCleanup = parameters => { - if (!Helpers.RunningOnMono - && TestPlatformHelper.IsWindows) - { - // Mono uses InMemoryStore - DbUtils.DropDatabase(musicStoreDbName, logger); - } + DbUtils.DropDatabase(musicStoreDbName, _logger); } }; // Override the connection strings using environment based configuration deploymentParameters.EnvironmentVariables .Add(new KeyValuePair( - "SQLAZURECONNSTR_DefaultConnection", - string.Format(DbUtils.CONNECTION_STRING_FORMAT, musicStoreDbName))); + MusicStore.StoreConfig.ConnectionStringKey, + DbUtils.CreateConnectionString(musicStoreDbName))); - using (var deployer = ApplicationDeployerFactory.Create(deploymentParameters, logger)) + using (var deployer = ApplicationDeployerFactory.Create(deploymentParameters, _logger)) { var deploymentResult = deployer.Deploy(); var httpClientHandler = new HttpClientHandler() { UseDefaultCredentials = true, AllowAutoRedirect = false }; @@ -139,15 +162,12 @@ namespace E2ETests // 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 response = await RetryHelper.RetryRequest(async () => - { - return await httpClient.GetAsync(string.Empty); - }, logger: logger, cancellationToken: deploymentResult.HostShutdownToken); + var response = await RetryHelper.RetryRequest(async () => await httpClient.GetAsync(string.Empty), logger: _logger, cancellationToken: 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); + var validator = new Validator(httpClient, httpClientHandler, _logger, deploymentResult); await validator.VerifyHomePage(response); // Static files are served? @@ -162,7 +182,7 @@ namespace E2ETests } } - logger.LogInformation("Variation completed successfully."); + _logger.LogInformation("Variation completed successfully."); } } } diff --git a/test/E2ETests/SmokeTests.cs b/test/E2ETests/SmokeTests.cs index f9dec258d9..487b8b8c6f 100644 --- a/test/E2ETests/SmokeTests.cs +++ b/test/E2ETests/SmokeTests.cs @@ -2,19 +2,27 @@ using System; using System.Collections.Generic; using System.Net.Http; using System.Threading.Tasks; +using E2ETests.Common; using Microsoft.AspNetCore.Server.Testing; -using Microsoft.AspNetCore.Testing; using Microsoft.AspNetCore.Testing.xunit; using Microsoft.Extensions.Logging; using Xunit; +using Xunit.Abstractions; namespace E2ETests { // Uses ports ranging 5001 - 5025. // TODO: temporarily disabling these tests as dotnet xunit runner does not support 32-bit yet. // public - class SmokeTests_X86 + class SmokeTests_X86 : IDisposable { + private readonly XunitLogger _logger; + + public SmokeTests_X86(ITestOutputHelper output) + { + _logger = new XunitLogger(output, LogLevel.Information); + } + [ConditionalTheory, Trait("E2Etests", "Smoke")] [OSSkipCondition(OperatingSystems.Linux)] [OSSkipCondition(OperatingSystems.MacOSX)] @@ -28,7 +36,7 @@ namespace E2ETests RuntimeArchitecture architecture, string applicationBaseUrl) { - var smokeTestRunner = new SmokeTests(); + var smokeTestRunner = new SmokeTests(_logger); await smokeTestRunner.SmokeTestSuite(serverType, runtimeFlavor, architecture, applicationBaseUrl); } @@ -41,13 +49,25 @@ namespace E2ETests RuntimeArchitecture architecture, string applicationBaseUrl) { - var smokeTestRunner = new SmokeTests(); + var smokeTestRunner = new SmokeTests(_logger); await smokeTestRunner.SmokeTestSuite(serverType, runtimeFlavor, architecture, applicationBaseUrl); } + + public void Dispose() + { + _logger.Dispose(); + } } - public class SmokeTests_X64 + public class SmokeTests_X64 : IDisposable { + private readonly XunitLogger _logger; + + public SmokeTests_X64(ITestOutputHelper output) + { + _logger = new XunitLogger(output, LogLevel.Information); + } + [ConditionalTheory, Trait("E2Etests", "Smoke")] [OSSkipCondition(OperatingSystems.Linux)] [OSSkipCondition(OperatingSystems.MacOSX)] @@ -61,7 +81,7 @@ namespace E2ETests RuntimeArchitecture architecture, string applicationBaseUrl) { - var smokeTestRunner = new SmokeTests(); + var smokeTestRunner = new SmokeTests(_logger); await smokeTestRunner.SmokeTestSuite(serverType, runtimeFlavor, architecture, applicationBaseUrl); } @@ -74,13 +94,24 @@ namespace E2ETests RuntimeArchitecture architecture, string applicationBaseUrl) { - var smokeTestRunner = new SmokeTests(); + var smokeTestRunner = new SmokeTests(_logger); await smokeTestRunner.SmokeTestSuite(serverType, runtimeFlavor, architecture, applicationBaseUrl); } + public void Dispose() + { + _logger.Dispose(); + } } - class SmokeTests_OnIIS + class SmokeTests_OnIIS : IDisposable { + private readonly XunitLogger _logger; + + public SmokeTests_OnIIS(ITestOutputHelper output) + { + _logger = new XunitLogger(output, LogLevel.Information); + } + [ConditionalTheory, Trait("E2Etests", "Smoke")] [OSSkipCondition(OperatingSystems.MacOSX)] [OSSkipCondition(OperatingSystems.Linux)] @@ -94,14 +125,26 @@ namespace E2ETests RuntimeArchitecture architecture, string applicationBaseUrl) { - var smokeTestRunner = new SmokeTests(); + var smokeTestRunner = new SmokeTests(_logger); await smokeTestRunner.SmokeTestSuite( serverType, runtimeFlavor, architecture, applicationBaseUrl, noSource: true); } + + public void Dispose() + { + _logger.Dispose(); + } } public class SmokeTests { + private ILogger _logger; + + public SmokeTests(ILogger logger) + { + _logger = logger; + } + public async Task SmokeTestSuite( ServerType serverType, RuntimeFlavor donetFlavor, @@ -109,13 +152,9 @@ namespace E2ETests string applicationBaseUrl, bool noSource = false) { - var logger = new LoggerFactory() - .AddConsole(LogLevel.Information) - .CreateLogger($"Smoke:{serverType}:{donetFlavor}:{architecture}"); - - using (logger.BeginScope("SmokeTestSuite")) + using (_logger.BeginScope("SmokeTestSuite")) { - var musicStoreDbName = Guid.NewGuid().ToString().Replace("-", string.Empty); + var musicStoreDbName = DbUtils.GetUniqueName(); var deploymentParameters = new DeploymentParameters( Helpers.GetApplicationPath(), serverType, donetFlavor, architecture) @@ -126,26 +165,20 @@ namespace E2ETests PublishTargetFramework = donetFlavor == RuntimeFlavor.Clr ? "dnx451" : "netstandardapp1.5", UserAdditionalCleanup = parameters => { - if (!Helpers.RunningOnMono - && TestPlatformHelper.IsWindows - && parameters.ServerType != ServerType.IIS) - { - // Mono uses InMemoryStore - DbUtils.DropDatabase(musicStoreDbName, logger); - } + DbUtils.DropDatabase(musicStoreDbName, _logger); } }; // Override the connection strings using environment based configuration deploymentParameters.EnvironmentVariables .Add(new KeyValuePair( - "SQLAZURECONNSTR_DefaultConnection", - string.Format(DbUtils.CONNECTION_STRING_FORMAT, musicStoreDbName))); + MusicStore.StoreConfig.ConnectionStringKey, + DbUtils.CreateConnectionString(musicStoreDbName))); - using (var deployer = ApplicationDeployerFactory.Create(deploymentParameters, logger)) + using (var deployer = ApplicationDeployerFactory.Create(deploymentParameters, _logger)) { var deploymentResult = deployer.Deploy(); - Helpers.SetInMemoryStoreForIIS(deploymentParameters, logger); + Helpers.SetInMemoryStoreForIIS(deploymentParameters, _logger); var httpClientHandler = new HttpClientHandler() { @@ -163,12 +196,12 @@ namespace E2ETests var response = await RetryHelper.RetryRequest(async () => { return await httpClient.GetAsync(string.Empty); - }, logger: logger, cancellationToken: deploymentResult.HostShutdownToken); + }, logger: _logger, cancellationToken: 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); + var validator = new Validator(httpClient, httpClientHandler, _logger, deploymentResult); await validator.VerifyHomePage(response); @@ -255,7 +288,7 @@ namespace E2ETests // MicrosoftAccountLogin await validator.LoginWithMicrosoftAccount(); - logger.LogInformation("Variation completed successfully."); + _logger.LogInformation("Variation completed successfully."); } } } diff --git a/test/MusicStore.Test/Models/ShoppingCartTest.cs b/test/MusicStore.Test/Models/ShoppingCartTest.cs index 0d51cef454..1f3eed93ec 100644 --- a/test/MusicStore.Test/Models/ShoppingCartTest.cs +++ b/test/MusicStore.Test/Models/ShoppingCartTest.cs @@ -1,4 +1,7 @@ -using System; +// Copyright (c) .NET Foundation. All rights reserved. +// See License.txt in the project root for license information + +using System; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; using MusicStore.Models;