diff --git a/shared/Mocks/StartupSocialTesting.cs b/shared/Mocks/StartupSocialTesting.cs index c37ea2967d..b6a62f20aa 100644 --- a/shared/Mocks/StartupSocialTesting.cs +++ b/shared/Mocks/StartupSocialTesting.cs @@ -25,7 +25,7 @@ namespace MusicStore { public class StartupSocialTesting { - private readonly IRuntimeEnvironment _runtimeEnvironment; + private readonly Platform _platform; public StartupSocialTesting(IApplicationEnvironment appEnvironment, IRuntimeEnvironment runtimeEnvironment) { @@ -38,7 +38,7 @@ namespace MusicStore .AddJsonFile("configoverride.json", optional: true); // Used to override some configuration parameters that cannot be overridden by environment. Configuration = builder.Build(); - _runtimeEnvironment = runtimeEnvironment; + _platform = new Platform(runtimeEnvironment); } public IConfiguration Configuration { get; private set; } @@ -48,7 +48,9 @@ namespace MusicStore services.Configure(Configuration.GetSection("AppSettings")); //Sql client not available on mono - var useInMemoryStore = !_runtimeEnvironment.OperatingSystem.Equals("Windows", StringComparison.OrdinalIgnoreCase); + var useInMemoryStore = !_platform.IsRunningOnWindows + || _platform.IsRunningOnMono + || _platform.IsRunningOnNanoServer; // Add EF services to the services container if (useInMemoryStore) diff --git a/test/E2ETests/RemoteDeploymentConfig.cs b/test/E2ETests/RemoteDeploymentConfig.cs new file mode 100644 index 0000000000..ba33a5ae0d --- /dev/null +++ b/test/E2ETests/RemoteDeploymentConfig.cs @@ -0,0 +1,15 @@ +namespace E2ETests +{ + public class RemoteDeploymentConfig + { + public string ServerName { get; set; } + + public string AccountName { get; set; } + + public string AccountPassword { get; set; } + + public string FileSharePath { get; set; } + + public string ExecutableRelativePath { get; set; } + } +} diff --git a/test/E2ETests/SmokeTestHelper.cs b/test/E2ETests/SmokeTestHelper.cs new file mode 100644 index 0000000000..196b35f235 --- /dev/null +++ b/test/E2ETests/SmokeTestHelper.cs @@ -0,0 +1,124 @@ +using System; +using System.Net.Http; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Server.Testing; +using Microsoft.Extensions.Logging; +using Xunit; + +namespace E2ETests +{ + public static class SmokeTestHelper + { + public static async Task RunTestsAsync(DeploymentResult deploymentResult, ILogger logger) + { + var httpClientHandler = new HttpClientHandler(); + var httpClient = new HttpClient(httpClientHandler) + { + BaseAddress = new Uri(deploymentResult.ApplicationBaseUri), + Timeout = TimeSpan.FromSeconds(5), + }; + + using (httpClient) + { + // Request to base address and check if various parts of the body are rendered + // & measure the cold startup time. + var response = await RetryHelper.RetryRequest(async () => + { + return await httpClient.GetAsync(string.Empty); + }, 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); + + await validator.VerifyHomePage(response); + + // Verify the static file middleware can serve static content. + await validator.VerifyStaticContentServed(); + + // Making a request to a protected resource should automatically redirect to login page. + await validator.AccessStoreWithoutPermissions(); + + // Register a user - Negative scenario where the Password & ConfirmPassword do not match. + await validator.RegisterUserWithNonMatchingPasswords(); + + // Register a valid user. + var generatedEmail = await validator.RegisterValidUser(); + + await validator.SignInWithUser(generatedEmail, "Password~1"); + + // Register a user - Negative scenario : Trying to register a user name that's already registered. + await validator.RegisterExistingUser(generatedEmail); + + // Logout from this user session - This should take back to the home page + await validator.SignOutUser(generatedEmail); + + // Sign in scenarios: Invalid password - Expected an invalid user name password error. + await validator.SignInWithInvalidPassword(generatedEmail, "InvalidPassword~1"); + + // Sign in scenarios: Valid user name & password. + await validator.SignInWithUser(generatedEmail, "Password~1"); + + // Change password scenario + await validator.ChangePassword(generatedEmail); + + // SignIn with old password and verify old password is not allowed and new password is allowed + await validator.SignOutUser(generatedEmail); + await validator.SignInWithInvalidPassword(generatedEmail, "Password~1"); + await validator.SignInWithUser(generatedEmail, "Password~2"); + + // Making a request to a protected resource that this user does not have access to - should + // automatically redirect to the configured access denied page + await validator.AccessStoreWithoutPermissions(generatedEmail); + + // Logout from this user session - This should take back to the home page + await validator.SignOutUser(generatedEmail); + + // Login as an admin user + await validator.SignInWithUser("Administrator@test.com", "YouShouldChangeThisPassword1!"); + + // Now navigating to the store manager should work fine as this user has + // the necessary permission to administer the store. + await validator.AccessStoreWithPermissions(); + + // Create an album + var albumName = await validator.CreateAlbum(); + var albumId = await validator.FetchAlbumIdFromName(albumName); + + // Get details of the album + await validator.VerifyAlbumDetails(albumId, albumName); + + // Verify status code pages acts on non-existing items. + await validator.VerifyStatusCodePages(); + + // Get the non-admin view of the album. + await validator.GetAlbumDetailsFromStore(albumId, albumName); + + // Add an album to cart and checkout the same + await validator.AddAlbumToCart(albumId, albumName); + await validator.CheckOutCartItems(); + + // Delete the album from store + await validator.DeleteAlbum(albumId, albumName); + + // Logout from this user session - This should take back to the home page + await validator.SignOutUser("Administrator"); + + // Google login + await validator.LoginWithGoogle(); + + // Facebook login + await validator.LoginWithFacebook(); + + // Twitter login + await validator.LoginWithTwitter(); + + // MicrosoftAccountLogin + await validator.LoginWithMicrosoftAccount(); + + logger.LogInformation("Variation completed successfully."); + } + } + } +} diff --git a/test/E2ETests/SmokeTests.cs b/test/E2ETests/SmokeTests.cs index ff3e842370..ca21609dd1 100644 --- a/test/E2ETests/SmokeTests.cs +++ b/test/E2ETests/SmokeTests.cs @@ -122,7 +122,7 @@ namespace E2ETests [OSSkipCondition(OperatingSystems.MacOSX)] [OSSkipCondition(OperatingSystems.Linux)] [SkipIfCurrentRuntimeIsCoreClr] - [SkipIfIISVariationsNotEnabled] + [SkipIfEnvironmentVariableNotEnabled("IIS_VARIATIONS_ENABLED")] //[InlineData(ServerType.IIS, RuntimeFlavor.Clr, RuntimeArchitecture.x86, "http://localhost:5015/")] [InlineData(ServerType.IIS, RuntimeFlavor.CoreClr, RuntimeArchitecture.x64, "http://localhost:5016/")] public async Task SmokeTestSuite_On_IIS_X86( @@ -186,113 +186,10 @@ namespace E2ETests using (var deployer = ApplicationDeployerFactory.Create(deploymentParameters, _logger)) { var deploymentResult = deployer.Deploy(); + Helpers.SetInMemoryStoreForIIS(deploymentParameters, _logger); - var httpClientHandler = new HttpClientHandler(); - var httpClient = new HttpClient(httpClientHandler) - { - BaseAddress = new Uri(deploymentResult.ApplicationBaseUri), - Timeout = TimeSpan.FromSeconds(5), - }; - - // Request to base address and check if various parts of the body are rendered - // & measure the cold startup time. - var response = await RetryHelper.RetryRequest(async () => - { - return 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); - - await validator.VerifyHomePage(response); - - // Verify the static file middleware can serve static content. - await validator.VerifyStaticContentServed(); - - // Making a request to a protected resource should automatically redirect to login page. - await validator.AccessStoreWithoutPermissions(); - - // Register a user - Negative scenario where the Password & ConfirmPassword do not match. - await validator.RegisterUserWithNonMatchingPasswords(); - - // Register a valid user. - var generatedEmail = await validator.RegisterValidUser(); - - await validator.SignInWithUser(generatedEmail, "Password~1"); - - // Register a user - Negative scenario : Trying to register a user name that's already registered. - await validator.RegisterExistingUser(generatedEmail); - - // Logout from this user session - This should take back to the home page - await validator.SignOutUser(generatedEmail); - - // Sign in scenarios: Invalid password - Expected an invalid user name password error. - await validator.SignInWithInvalidPassword(generatedEmail, "InvalidPassword~1"); - - // Sign in scenarios: Valid user name & password. - await validator.SignInWithUser(generatedEmail, "Password~1"); - - // Change password scenario - await validator.ChangePassword(generatedEmail); - - // SignIn with old password and verify old password is not allowed and new password is allowed - await validator.SignOutUser(generatedEmail); - await validator.SignInWithInvalidPassword(generatedEmail, "Password~1"); - await validator.SignInWithUser(generatedEmail, "Password~2"); - - // Making a request to a protected resource that this user does not have access to - should - // automatically redirect to the configured access denied page - await validator.AccessStoreWithoutPermissions(generatedEmail); - - // Logout from this user session - This should take back to the home page - await validator.SignOutUser(generatedEmail); - - // Login as an admin user - await validator.SignInWithUser("Administrator@test.com", "YouShouldChangeThisPassword1!"); - - // Now navigating to the store manager should work fine as this user has - // the necessary permission to administer the store. - await validator.AccessStoreWithPermissions(); - - // Create an album - var albumName = await validator.CreateAlbum(); - var albumId = await validator.FetchAlbumIdFromName(albumName); - - // Get details of the album - await validator.VerifyAlbumDetails(albumId, albumName); - - // Verify status code pages acts on non-existing items. - await validator.VerifyStatusCodePages(); - - // Get the non-admin view of the album. - await validator.GetAlbumDetailsFromStore(albumId, albumName); - - // Add an album to cart and checkout the same - await validator.AddAlbumToCart(albumId, albumName); - await validator.CheckOutCartItems(); - - // Delete the album from store - await validator.DeleteAlbum(albumId, albumName); - - // Logout from this user session - This should take back to the home page - await validator.SignOutUser("Administrator"); - - // Google login - await validator.LoginWithGoogle(); - - // Facebook login - await validator.LoginWithFacebook(); - - // Twitter login - await validator.LoginWithTwitter(); - - // MicrosoftAccountLogin - await validator.LoginWithMicrosoftAccount(); - - _logger.LogInformation("Variation completed successfully."); + await SmokeTestHelper.RunTestsAsync(deploymentResult, _logger); } } } diff --git a/test/E2ETests/SmokeTestsOnNanoServer.cs b/test/E2ETests/SmokeTestsOnNanoServer.cs new file mode 100644 index 0000000000..7c0bc05c7c --- /dev/null +++ b/test/E2ETests/SmokeTestsOnNanoServer.cs @@ -0,0 +1,81 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; +using E2ETests.Common; +using Microsoft.AspNetCore.Server.Testing; +using Microsoft.AspNetCore.Testing.xunit; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Logging; +using Xunit; +using Xunit.Abstractions; + +namespace E2ETests +{ + public class SmokeTestsOnNanoServer : IDisposable + { + private readonly XunitLogger _logger; + private readonly RemoteDeploymentConfig _remoteDeploymentConfig; + + public SmokeTestsOnNanoServer(ITestOutputHelper output) + { + _logger = new XunitLogger(output, LogLevel.Information); + + var configuration = new ConfigurationBuilder() + .SetBasePath(Directory.GetCurrentDirectory()) + .AddJsonFile("remoteDeploymentConfig.json") + .AddEnvironmentVariables() + .Build(); + + _remoteDeploymentConfig = new RemoteDeploymentConfig(); + configuration.GetSection("NanoServer").Bind(_remoteDeploymentConfig); + } + + [ConditionalTheory, Trait("E2Etests", "NanoServer")] + [OSSkipCondition(OperatingSystems.Linux)] + [OSSkipCondition(OperatingSystems.MacOSX)] + [SkipIfEnvironmentVariableNotEnabled("RUN_TESTS_ON_NANO")] + [InlineData(ServerType.Kestrel, 5000)] + [InlineData(ServerType.WebListener, 5000)] + public async Task Test(ServerType serverType, int portToListen) + { + var applicationBaseUrl = $"http://{_remoteDeploymentConfig.ServerName}:{portToListen}/"; + await RunTestsAsync(serverType, applicationBaseUrl); + } + + private async Task RunTestsAsync(ServerType serverType, string applicationBaseUrl) + { + using (_logger.BeginScope("SmokeTestSuite")) + { + var deploymentParameters = new RemoteWindowsDeploymentParameters( + Helpers.GetApplicationPath(), + serverType, + RuntimeFlavor.CoreClr, + RuntimeArchitecture.x64, + _remoteDeploymentConfig.FileSharePath, + _remoteDeploymentConfig.ServerName, + _remoteDeploymentConfig.AccountName, + _remoteDeploymentConfig.AccountPassword, + _remoteDeploymentConfig.ExecutableRelativePath) + { + PublishTargetFramework = "netstandardapp1.5", + ApplicationBaseUriHint = applicationBaseUrl + }; + deploymentParameters.EnvironmentVariables.Add( + new KeyValuePair("ASPNETCORE_ENVIRONMENT", "SocialTesting")); + + using (var deployer = new RemoteWindowsDeployer(deploymentParameters, _logger)) + { + var deploymentResult = deployer.Deploy(); + + await SmokeTestHelper.RunTestsAsync(deploymentResult, _logger); + } + } + } + + public void Dispose() + { + _logger.Dispose(); + } + } +} diff --git a/test/E2ETests/project.json b/test/E2ETests/project.json index ec3a3ea503..af70106274 100644 --- a/test/E2ETests/project.json +++ b/test/E2ETests/project.json @@ -11,7 +11,9 @@ "Microsoft.AspNetCore.Identity": "1.0.0-*", "Microsoft.AspNetCore.Server.Testing": "1.0.0-*", "Microsoft.AspNetCore.WebUtilities": "1.0.0-*", + "Microsoft.Extensions.Configuration.Binder": "1.0.0-*", "Microsoft.Extensions.Configuration.EnvironmentVariables": "1.0.0-*", + "Microsoft.Extensions.Configuration.Json": "1.0.0-*", "Microsoft.Extensions.Logging": "1.0.0-*", "Microsoft.Extensions.Logging.Console": "1.0.0-*", "xunit": "2.1.0" diff --git a/test/E2ETests/remoteDeploymentConfig.json b/test/E2ETests/remoteDeploymentConfig.json new file mode 100644 index 0000000000..3bdc799e85 --- /dev/null +++ b/test/E2ETests/remoteDeploymentConfig.json @@ -0,0 +1,9 @@ +{ + "NanoServer": { + "ServerName": "", + "AccountName": "", + "AccountPassword": "", + "FileSharePath": "", + "ExecutableRelativePath": "" + } +}