diff --git a/src/MusicStore/StartupNtlmAuthentication.cs b/src/MusicStore/StartupNtlmAuthentication.cs index db269c05b4..cc44a7ef2d 100644 --- a/src/MusicStore/StartupNtlmAuthentication.cs +++ b/src/MusicStore/StartupNtlmAuthentication.cs @@ -46,7 +46,7 @@ namespace MusicStore //Who will get admin access? For demo sake I'm listing the currently logged on user as the application administrator. But this can be changed to suit the needs. var identity = (ClaimsIdentity)context.User.Identity; -#if ASPNET501 +#if ASPNET50 if (identity.GetUserName() == Environment.UserDomainName + "\\" + Environment.UserName) { identity.AddClaim(new Claim("ManageStore", "Allowed")); diff --git a/test/E2ETests/DeploymentUtility.cs b/test/E2ETests/DeploymentUtility.cs index d040c8b2d3..4d643d709c 100644 --- a/test/E2ETests/DeploymentUtility.cs +++ b/test/E2ETests/DeploymentUtility.cs @@ -55,48 +55,55 @@ namespace E2ETests private const string APP_RELATIVE_PATH = @"..\..\src\MusicStore\"; - public static Process StartApplication(ServerType hostType, KreFlavor kreFlavor, KreArchitecture kreArchitecture, string identityDbName) + public static Process StartApplication(StartParameters startParameters, string identityDbName) { - string applicationPath = Path.GetFullPath(Path.Combine(Environment.CurrentDirectory, APP_RELATIVE_PATH)); + startParameters.ApplicationPath = Path.GetFullPath(Path.Combine(Environment.CurrentDirectory, APP_RELATIVE_PATH)); - var backupKreDefaultLibPath = Environment.GetEnvironmentVariable("KRE_DEFAULT_LIB"); //To avoid the KRE_DEFAULT_LIB of the test process flowing into Helios, set it to empty + var backupKreDefaultLibPath = Environment.GetEnvironmentVariable("KRE_DEFAULT_LIB"); Environment.SetEnvironmentVariable("KRE_DEFAULT_LIB", string.Empty); + if (!string.IsNullOrWhiteSpace(startParameters.EnvironmentName)) + { + //To choose an environment based Startup + Environment.SetEnvironmentVariable("ENV", startParameters.EnvironmentName); + } + Process hostProcess = null; - if (kreFlavor == KreFlavor.Mono) + if (startParameters.KreFlavor == KreFlavor.Mono) { - hostProcess = StartMonoHost(hostType, applicationPath); + hostProcess = StartMonoHost(startParameters); } else { //Tweak the %PATH% to the point to the right KREFLAVOR - Environment.SetEnvironmentVariable("PATH", SwitchPathToKreFlavor(kreFlavor, kreArchitecture)); + Environment.SetEnvironmentVariable("PATH", SwitchPathToKreFlavor(startParameters.KreFlavor, startParameters.KreArchitecture)); - if (hostType == ServerType.Helios) + if (startParameters.ServerType == ServerType.Helios) { - hostProcess = StartHeliosHost(applicationPath, kreArchitecture); + hostProcess = StartHeliosHost(startParameters); } else { - hostProcess = StartSelfHost(hostType, applicationPath, identityDbName); + hostProcess = StartSelfHost(startParameters, identityDbName); } } //Restore the KRE_DEFAULT_LIB after starting the host process Environment.SetEnvironmentVariable("KRE_DEFAULT_LIB", backupKreDefaultLibPath); + Environment.SetEnvironmentVariable("ENV", string.Empty); return hostProcess; } - private static Process StartMonoHost(ServerType hostType, string applicationPath) + private static Process StartMonoHost(StartParameters startParameters) { //Mono needs this as GetFullPath does not work if it has \ - applicationPath = Path.GetFullPath(applicationPath.Replace('\\', '/')); + startParameters.ApplicationPath = Path.GetFullPath(startParameters.ApplicationPath.Replace('\\', '/')); //Mono does not have a way to pass in a --appbase switch. So it will be an environment variable. - Environment.SetEnvironmentVariable("KRE_APPBASE", applicationPath); - Console.WriteLine("Setting the KRE_APPBASE to {0}", applicationPath); + Environment.SetEnvironmentVariable("KRE_APPBASE", startParameters.ApplicationPath); + Console.WriteLine("Setting the KRE_APPBASE to {0}", startParameters.ApplicationPath); var path = Environment.GetEnvironmentVariable("PATH"); var kreBin = path.Split(new char[] { ':' }, StringSplitOptions.RemoveEmptyEntries).Where(c => c.Contains("KRE-Mono")).FirstOrDefault(); @@ -110,12 +117,12 @@ namespace E2ETests var klrMonoManaged = Path.Combine(kreBin, "klr.mono.managed.dll"); var applicationHost = Path.Combine(kreBin, "Microsoft.Framework.ApplicationHost"); - Console.WriteLine(string.Format("Executing command: {0} {1} {3} {4}", monoPath, klrMonoManaged, applicationPath, applicationHost, hostType.ToString())); + Console.WriteLine(string.Format("Executing command: {0} {1} {3} {4}", monoPath, klrMonoManaged, startParameters.ApplicationPath, applicationHost, startParameters.ServerType.ToString())); var startInfo = new ProcessStartInfo { FileName = monoPath, - Arguments = string.Format("{0} {1} {2}", klrMonoManaged, applicationHost, hostType.ToString()), + Arguments = string.Format("{0} {1} {2}", klrMonoManaged, applicationHost, startParameters.ServerType.ToString()), UseShellExecute = true, CreateNoWindow = true }; @@ -129,14 +136,31 @@ namespace E2ETests return hostProcess; } - private static Process StartHeliosHost(string applicationPath, KreArchitecture kreArchitecture) + private static Process StartHeliosHost(StartParameters startParameters) { - CopyAspNetLoader(applicationPath); + CopyAspNetLoader(startParameters.ApplicationPath); + + if (!string.IsNullOrWhiteSpace(startParameters.ApplicationHostConfigTemplateContent)) + { + //Pass on the applicationhost.config to iis express. With this don't need to pass in the /path /port switches as they are in the applicationHost.config + //We take a copy of the original specified applicationHost.Config to prevent modifying the one in the repo. + var tempApplicationHostConfig = Path.GetTempFileName(); + File.WriteAllText(tempApplicationHostConfig, startParameters.ApplicationHostConfigTemplateContent.Replace("[ApplicationPhysicalPath]", startParameters.ApplicationPath)); + startParameters.ApplicationHostConfigLocation = tempApplicationHostConfig; + } + + var parameters = string.IsNullOrWhiteSpace(startParameters.ApplicationHostConfigLocation) ? + string.Format("/port:5001 /path:{0}", startParameters.ApplicationPath) : + string.Format("/site:{0} /config:{1}", startParameters.SiteName, startParameters.ApplicationHostConfigLocation); + + var iisExpressPath = GetIISExpressPath(startParameters.KreArchitecture); + + Console.WriteLine("Executing command : {0} {1}", iisExpressPath, parameters); var startInfo = new ProcessStartInfo { - FileName = GetIISExpressPath(kreArchitecture), - Arguments = string.Format("/port:5001 /path:{0}", applicationPath), + FileName = iisExpressPath, + Arguments = parameters, UseShellExecute = true, CreateNoWindow = true }; @@ -147,14 +171,15 @@ namespace E2ETests return hostProcess; } - private static Process StartSelfHost(ServerType hostType, string applicationPath, string identityDbName) + private static Process StartSelfHost(StartParameters startParameters, string identityDbName) { - Console.WriteLine(string.Format("Executing klr.exe --appbase {0} \"Microsoft.Framework.ApplicationHost\" {1}", applicationPath, hostType.ToString())); + //ServerType hostType, string applicationPath, string identityDbName + Console.WriteLine(string.Format("Executing klr.exe --appbase {0} \"Microsoft.Framework.ApplicationHost\" {1}", startParameters.ApplicationPath, startParameters.ServerType.ToString())); var startInfo = new ProcessStartInfo { FileName = "klr.exe", - Arguments = string.Format("--appbase {0} \"Microsoft.Framework.ApplicationHost\" {1}", applicationPath, hostType.ToString()), + Arguments = string.Format("--appbase {0} \"Microsoft.Framework.ApplicationHost\" {1}", startParameters.ApplicationPath, startParameters.ServerType.ToString()), UseShellExecute = true, CreateNoWindow = true }; @@ -239,7 +264,7 @@ namespace E2ETests } } - public static void CleanUpApplication(Process hostProcess, string musicStoreDbName) + public static void CleanUpApplication(StartParameters startParameters, Process hostProcess, string musicStoreDbName) { if (hostProcess != null && !hostProcess.HasExited) { @@ -265,6 +290,23 @@ namespace E2ETests //Mono uses InMemoryStore DbUtils.DropDatabase(musicStoreDbName); } + + if (!string.IsNullOrWhiteSpace(startParameters.ApplicationHostConfigLocation)) + { + //Delete the temp applicationHostConfig that we created + if (File.Exists(startParameters.ApplicationHostConfigLocation)) + { + try + { + File.Delete(startParameters.ApplicationHostConfigLocation); + } + catch (Exception exception) + { + //Ignore delete failures - just write a log + Console.WriteLine("Failed to delete '{0}'. Exception : {1}", startParameters.ApplicationHostConfigLocation, exception.Message); + } + } + } } } } \ No newline at end of file diff --git a/test/E2ETests/Helpers.cs b/test/E2ETests/Helpers.cs index f2b971b4a6..cad8f55672 100644 --- a/test/E2ETests/Helpers.cs +++ b/test/E2ETests/Helpers.cs @@ -11,5 +11,31 @@ namespace E2ETests return Type.GetType("Mono.Runtime") != null; } } + + public static bool SkipTestOnCurrentConfiguration(bool RunTestOnMono, KreArchitecture architecture) + { + if (RunTestOnMono && !RunningOnMono) + { + //Skip Mono variations on Windows + Console.WriteLine("Skipping mono variation on .NET"); + return true; + } + + if (!RunTestOnMono && RunningOnMono) + { + //Skip .net variations on mono + Console.WriteLine("Skipping .NET variation on mono"); + return true; + } + + // Check if processor architecture is x64, else skip test + if (architecture == KreArchitecture.amd64 && !Environment.Is64BitOperatingSystem) + { + Console.WriteLine("Skipping x64 test since machine is of type x86"); + return true; + } + + return false; + } } } \ No newline at end of file diff --git a/test/E2ETests/NtlmAuthentation.config b/test/E2ETests/NtlmAuthentation.config new file mode 100644 index 0000000000..4a8bf5d9e3 --- /dev/null +++ b/test/E2ETests/NtlmAuthentation.config @@ -0,0 +1,1038 @@ + + + + + + + + +
+
+
+
+
+
+
+
+ + + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+ +
+
+
+
+
+
+ +
+
+
+
+
+ +
+
+
+ +
+
+ +
+
+ +
+
+
+ + +
+
+
+
+
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/E2ETests/NtlmAuthentationTest.cs b/test/E2ETests/NtlmAuthentationTest.cs new file mode 100644 index 0000000000..96c6216903 --- /dev/null +++ b/test/E2ETests/NtlmAuthentationTest.cs @@ -0,0 +1,90 @@ +using System; +using System.Diagnostics; +using System.IO; +using System.Net.Http; +using Xunit; + +namespace E2ETests +{ + public partial class SmokeTests + { + [Theory] + [InlineData(ServerType.Helios, KreFlavor.DesktopClr, KreArchitecture.x86, "http://localhost:5001/", false)] + [InlineData(ServerType.WebListener, KreFlavor.DesktopClr, KreArchitecture.x86, "http://localhost:5002/", false)] + [InlineData(ServerType.Helios, KreFlavor.DesktopClr, KreArchitecture.amd64, "http://localhost:5001/", false)] + //WindowsIdentity not available on CoreCLR + //[InlineData(ServerType.Helios, KreFlavor.CoreClr, KreArchitecture.x86, "http://localhost:5001/", false)] + //[InlineData(ServerType.WebListener, KreFlavor.CoreClr, KreArchitecture.x86, "http://localhost:5002/", false)] + public void NtlmAuthenticationTest(ServerType serverType, KreFlavor kreFlavor, KreArchitecture architecture, string applicationBaseUrl, bool RunTestOnMono = false) + { + Console.WriteLine("Variation Details : HostType = {0}, KreFlavor = {1}, Architecture = {2}, applicationBaseUrl = {3}", serverType, kreFlavor, architecture, applicationBaseUrl); + + if (Helpers.SkipTestOnCurrentConfiguration(RunTestOnMono, architecture)) + { + Assert.True(true); + return; + } + + var startParameters = new StartParameters + { + ServerType = serverType, + KreFlavor = kreFlavor, + KreArchitecture = architecture, + EnvironmentName = "NtlmAuthentication", //Will pick the Start class named 'StartupNtlmAuthentication' + ApplicationHostConfigTemplateContent = (serverType == ServerType.Helios) ? File.ReadAllText("NtlmAuthentation.config") : null, + SiteName = "MusicStoreNtlmAuthentication" //This is configured in the NtlmAuthentication.config + }; + + var testStartTime = DateTime.Now; + var musicStoreDbName = Guid.NewGuid().ToString().Replace("-", string.Empty); + + Console.WriteLine("Pointing MusicStore DB to '{0}'", string.Format(Connection_string_Format, musicStoreDbName)); + + //Override the connection strings using environment based configuration + Environment.SetEnvironmentVariable("SQLAZURECONNSTR_DefaultConnection", string.Format(Connection_string_Format, musicStoreDbName)); + + ApplicationBaseUrl = applicationBaseUrl; + Process hostProcess = null; + bool testSuccessful = false; + + try + { + hostProcess = DeploymentUtility.StartApplication(startParameters, musicStoreDbName); + + httpClientHandler = new HttpClientHandler() { UseDefaultCredentials = true }; + httpClient = new HttpClient(httpClientHandler) { BaseAddress = new Uri(applicationBaseUrl) }; + + //Request to base address and check if various parts of the body are rendered & measure the cold startup time. + var response = httpClient.GetAsync(string.Empty).Result; + var responseContent = response.Content.ReadAsStringAsync().Result; + var initializationCompleteTime = DateTime.Now; + Console.WriteLine("[Time]: Approximate time taken for application initialization : '{0}' seconds", (initializationCompleteTime - testStartTime).TotalSeconds); + VerifyHomePage(response, responseContent, true); + + //Check if the user name appears in the page + Assert.Contains(string.Format("{0}\\{1}", Environment.UserDomainName, Environment.UserName), responseContent, StringComparison.OrdinalIgnoreCase); + + if (serverType != ServerType.Helios) + { + //https://github.com/aspnet/Helios/issues/53 + //Should be able to access the store as the Startup adds necessary permissions for the current user + AccessStoreWithPermissions(); + } + + var testCompletionTime = DateTime.Now; + Console.WriteLine("[Time]: All tests completed in '{0}' seconds", (testCompletionTime - initializationCompleteTime).TotalSeconds); + Console.WriteLine("[Time]: Total time taken for this test variation '{0}' seconds", (testCompletionTime - testStartTime).TotalSeconds); + testSuccessful = true; + } + finally + { + if (!testSuccessful) + { + Console.WriteLine("Some tests failed. Proceeding with cleanup."); + } + + DeploymentUtility.CleanUpApplication(startParameters, hostProcess, musicStoreDbName); + } + } + } +} \ No newline at end of file diff --git a/test/E2ETests/Scenarios.cs b/test/E2ETests/Scenarios.cs index df97342c3d..4eb5c11cad 100644 --- a/test/E2ETests/Scenarios.cs +++ b/test/E2ETests/Scenarios.cs @@ -32,15 +32,21 @@ namespace E2ETests Console.WriteLine("Verified static contents are served successfully"); } - private void VerifyHomePage(HttpResponseMessage response, string responseContent) + private void VerifyHomePage(HttpResponseMessage response, string responseContent, bool useNtlmAuthentication = false) { Console.WriteLine("Home page content : {0}", responseContent); Assert.Equal(HttpStatusCode.OK, response.StatusCode); ValidateLayoutPage(responseContent); Assert.Contains("Home Page – MVC Music Store", responseContent, StringComparison.OrdinalIgnoreCase); - Assert.Contains("Register", responseContent, StringComparison.OrdinalIgnoreCase); - Assert.Contains("Login", responseContent, StringComparison.OrdinalIgnoreCase); + + if (!useNtlmAuthentication) + { + //We don't display these for Ntlm + Assert.Contains("Register", responseContent, StringComparison.OrdinalIgnoreCase); + Assert.Contains("Login", responseContent, StringComparison.OrdinalIgnoreCase); + } + Assert.Contains("mvcmusicstore.codeplex.com", responseContent, StringComparison.OrdinalIgnoreCase); Assert.Contains("/Images/home-showcase.png", responseContent, StringComparison.OrdinalIgnoreCase); Console.WriteLine("Application initialization successful."); diff --git a/test/E2ETests/ServerType.cs b/test/E2ETests/ServerType.cs index aee4b4ef3e..a71186357a 100644 --- a/test/E2ETests/ServerType.cs +++ b/test/E2ETests/ServerType.cs @@ -6,4 +6,4 @@ WebListener, Kestrel } -} +} \ No newline at end of file diff --git a/test/E2ETests/SmokeTests.cs b/test/E2ETests/SmokeTests.cs index 258206b13c..3a5e321343 100644 --- a/test/E2ETests/SmokeTests.cs +++ b/test/E2ETests/SmokeTests.cs @@ -24,33 +24,22 @@ namespace E2ETests [InlineData(ServerType.Kestrel, KreFlavor.Mono, KreArchitecture.x86, "http://localhost:5004/", true)] [InlineData(ServerType.Helios, KreFlavor.CoreClr, KreArchitecture.amd64, "http://localhost:5001/", false)] [InlineData(ServerType.Kestrel, KreFlavor.CoreClr, KreArchitecture.amd64, "http://localhost:5004/", false)] - public void SmokeTestSuite(ServerType hostType, KreFlavor kreFlavor, KreArchitecture architecture, string applicationBaseUrl, bool RunTestOnMono = false) + public void SmokeTestSuite(ServerType serverType, KreFlavor kreFlavor, KreArchitecture architecture, string applicationBaseUrl, bool RunTestOnMono = false) { - Console.WriteLine("Variation Details : HostType = {0}, KreFlavor = {1}, Architecture = {2}, applicationBaseUrl = {3}", hostType, kreFlavor, architecture, applicationBaseUrl); + Console.WriteLine("Variation Details : HostType = {0}, KreFlavor = {1}, Architecture = {2}, applicationBaseUrl = {3}", serverType, kreFlavor, architecture, applicationBaseUrl); - if (RunTestOnMono && !Helpers.RunningOnMono) + if (Helpers.SkipTestOnCurrentConfiguration(RunTestOnMono, architecture)) { - //Skip Mono variations on Windows - Console.WriteLine("Skipping mono variation on .NET"); Assert.True(true); return; } - if (!RunTestOnMono && Helpers.RunningOnMono) + var startParameters = new StartParameters { - //Skip .net variations on mono - Console.WriteLine("Skipping .NET variation on mono"); - Assert.True(true); - return; - } - - // Check if processor architecture is x64, else skip test - if (architecture == KreArchitecture.amd64 && !Environment.Is64BitOperatingSystem) - { - Console.WriteLine("Skipping x64 test since machine is of type x86"); - Assert.True(true); - return; - } + ServerType = serverType, + KreFlavor = kreFlavor, + KreArchitecture = architecture + }; var testStartTime = DateTime.Now; var musicStoreDbName = Guid.NewGuid().ToString().Replace("-", string.Empty); @@ -66,8 +55,7 @@ namespace E2ETests try { - //Deployment helpers not setup for mono yet. Until then set the ApplicationBaseUrl to some static url. - hostProcess = DeploymentUtility.StartApplication(hostType, kreFlavor, architecture, musicStoreDbName); + hostProcess = DeploymentUtility.StartApplication(startParameters, musicStoreDbName); httpClientHandler = new HttpClientHandler(); httpClient = new HttpClient(httpClientHandler) { BaseAddress = new Uri(applicationBaseUrl) }; @@ -152,7 +140,7 @@ namespace E2ETests Console.WriteLine("Some tests failed. Proceeding with cleanup."); } - DeploymentUtility.CleanUpApplication(hostProcess, musicStoreDbName); + DeploymentUtility.CleanUpApplication(startParameters, hostProcess, musicStoreDbName); } } } diff --git a/test/E2ETests/StartParameters.cs b/test/E2ETests/StartParameters.cs new file mode 100644 index 0000000000..aed59c2882 --- /dev/null +++ b/test/E2ETests/StartParameters.cs @@ -0,0 +1,24 @@ +namespace E2ETests +{ + /// + /// Summary description for StartParameters + /// + public class StartParameters + { + public ServerType ServerType { get; set; } + + public KreFlavor KreFlavor { get; set; } + + public KreArchitecture KreArchitecture { get; set; } + + public string EnvironmentName { get; set; } + + public string ApplicationHostConfigTemplateContent { get; set; } + + public string ApplicationHostConfigLocation { get; set; } + + public string SiteName { get; set; } + + public string ApplicationPath { get; set; } + } +} \ No newline at end of file