Adding some tests for MusicStore
It executes a set of scenarios: 1. Launches the app in Helios and navigates to the home page and verifies 2. Make a request to a protected resource and verifies that request is redirected to the login page 3. Registers a user with a dynamically generated user name and verifies the user is created and logged in by verifying the cookies and display name in the home page. 4. Go back to the StoreManager controller which requires a specific permission and verifies that still we are being redirected to Login page. 5. Logoff of the current user session and verify the user is logged off and cookie cleared. 6. Login this time with Administrator user who has permission to manage store and verify successfully logged in 7. Verify that this time the user can access the StoreManager controller 8. Create an album and verify that album is successfully created. 9. Logout of the app and verify.
This commit is contained in:
parent
05d21fb249
commit
273c252db0
|
|
@ -0,0 +1,158 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using Xunit;
|
||||
|
||||
namespace E2ETests
|
||||
{
|
||||
public class SmokeTests
|
||||
{
|
||||
private const string APP_BASE_URL = "http://localhost:5001/";
|
||||
private const string APP_RELATIVE_PATH = @"..\..\src\MusicStore\";
|
||||
|
||||
[Fact]
|
||||
public void SmokeTestSuite()
|
||||
{
|
||||
string applicationPath = Path.GetFullPath(Path.Combine(Environment.CurrentDirectory, APP_RELATIVE_PATH));
|
||||
Utility.CopyAspNetLoader(applicationPath);
|
||||
var hostProcess = Utility.StartHeliosHost(applicationPath);
|
||||
|
||||
try
|
||||
{
|
||||
var httpClientHandler = new HttpClientHandler();
|
||||
var httpClient = new HttpClient(httpClientHandler) { BaseAddress = new Uri(APP_BASE_URL) };
|
||||
|
||||
//Request to base address and check if various parts of the body are rendered
|
||||
var response = httpClient.GetAsync(string.Empty).Result;
|
||||
var responseContent = response.Content.ReadAsStringAsync().Result;
|
||||
Assert.Equal<HttpStatusCode>(HttpStatusCode.OK, response.StatusCode);
|
||||
Assert.Contains("ASP.NET MVC Music Store", responseContent, StringComparison.OrdinalIgnoreCase);
|
||||
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);
|
||||
|
||||
//Making a request to a protected resource should automatically redirect to login page
|
||||
response = httpClient.GetAsync("/StoreManager/").Result;
|
||||
responseContent = response.Content.ReadAsStringAsync().Result;
|
||||
Assert.Contains("<h4>Use a local account to log in.</h4>", responseContent, StringComparison.OrdinalIgnoreCase);
|
||||
Assert.Equal<string>(APP_BASE_URL + "Account/Login?ReturnUrl=%2FStoreManager%2F", response.RequestMessage.RequestUri.AbsoluteUri);
|
||||
|
||||
//Register a user - Need a way to get the antiforgery token and send it in the request as a form encoded parameter
|
||||
response = httpClient.GetAsync("/Account/Register").Result;
|
||||
responseContent = response.Content.ReadAsStringAsync().Result;
|
||||
var antiForgeryToken = Utility.RetrieveAntiForgeryToken(responseContent, "/Account/Register");
|
||||
|
||||
var generatedUserName = Guid.NewGuid().ToString().Replace("-", string.Empty);
|
||||
var formParameters = new List<KeyValuePair<string, string>>
|
||||
{
|
||||
new KeyValuePair<string, string>("UserName", generatedUserName),
|
||||
new KeyValuePair<string, string>("Password", "Password~1"),
|
||||
new KeyValuePair<string, string>("ConfirmPassword", "Password~1"),
|
||||
new KeyValuePair<string, string>("__RequestVerificationToken", antiForgeryToken),
|
||||
};
|
||||
|
||||
var content = new FormUrlEncodedContent(formParameters.ToArray());
|
||||
response = httpClient.PostAsync("/Account/Register", content).Result;
|
||||
responseContent = response.Content.ReadAsStringAsync().Result;
|
||||
Assert.Contains(string.Format("Hello {0}!", generatedUserName), responseContent, StringComparison.OrdinalIgnoreCase);
|
||||
Assert.Contains("Log off", responseContent, StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
//Verify cookie sent
|
||||
Assert.NotNull(Utility.GetCookieWithName(httpClientHandler.CookieContainer.GetCookies(new Uri(APP_BASE_URL)), ".AspNet.Microsoft.AspNet.Identity.Security.Application"));
|
||||
|
||||
//Making a request to a protected resource that this user does not have access to - should automatically redirect to login page again
|
||||
response = httpClient.GetAsync("/StoreManager/").Result;
|
||||
responseContent = response.Content.ReadAsStringAsync().Result;
|
||||
Assert.Contains("<h4>Use a local account to log in.</h4>", responseContent, StringComparison.OrdinalIgnoreCase);
|
||||
Assert.Equal<string>(APP_BASE_URL + "Account/Login?ReturnUrl=%2FStoreManager%2F", response.RequestMessage.RequestUri.AbsoluteUri);
|
||||
|
||||
//Logout from this user session - This should take back to the home page
|
||||
antiForgeryToken = Utility.RetrieveAntiForgeryToken(responseContent, "/Account/LogOff");
|
||||
formParameters = new List<KeyValuePair<string, string>>
|
||||
{
|
||||
new KeyValuePair<string, string>("__RequestVerificationToken", antiForgeryToken),
|
||||
};
|
||||
|
||||
content = new FormUrlEncodedContent(formParameters.ToArray());
|
||||
response = httpClient.PostAsync("/Account/LogOff", content).Result;
|
||||
responseContent = response.Content.ReadAsStringAsync().Result;
|
||||
Assert.Contains("ASP.NET MVC Music Store", responseContent, StringComparison.OrdinalIgnoreCase);
|
||||
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);
|
||||
//Verify cookie cleared on logout
|
||||
Assert.Null(Utility.GetCookieWithName(httpClientHandler.CookieContainer.GetCookies(new Uri(APP_BASE_URL)), ".AspNet.Microsoft.AspNet.Identity.Security.Application"));
|
||||
|
||||
//Login as an admin user
|
||||
response = httpClient.GetAsync("/Account/Login").Result;
|
||||
responseContent = response.Content.ReadAsStringAsync().Result;
|
||||
antiForgeryToken = Utility.RetrieveAntiForgeryToken(responseContent, "/Account/Login");
|
||||
formParameters = new List<KeyValuePair<string, string>>
|
||||
{
|
||||
new KeyValuePair<string, string>("UserName", "Administrator"),
|
||||
new KeyValuePair<string, string>("Password", "YouShouldChangeThisPassword1!"),
|
||||
new KeyValuePair<string, string>("__RequestVerificationToken", antiForgeryToken),
|
||||
};
|
||||
|
||||
content = new FormUrlEncodedContent(formParameters.ToArray());
|
||||
response = httpClient.PostAsync("/Account/Login", content).Result;
|
||||
responseContent = response.Content.ReadAsStringAsync().Result;
|
||||
Assert.Contains(string.Format("Hello {0}!", "Administrator"), responseContent, StringComparison.OrdinalIgnoreCase);
|
||||
Assert.Contains("Log off", responseContent, StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
//Now navigating to the store manager should work fine as this user has the necessary permission to administer the store.
|
||||
response = httpClient.GetAsync("/StoreManager/").Result;
|
||||
responseContent = response.Content.ReadAsStringAsync().Result;
|
||||
Assert.Equal<string>(APP_BASE_URL + "StoreManager/", response.RequestMessage.RequestUri.AbsoluteUri);
|
||||
|
||||
//Create an album
|
||||
var albumName = Guid.NewGuid().ToString().Replace("-", string.Empty).Substring(0, 12);
|
||||
response = httpClient.GetAsync("/StoreManager/create").Result;
|
||||
responseContent = response.Content.ReadAsStringAsync().Result;
|
||||
antiForgeryToken = Utility.RetrieveAntiForgeryToken(responseContent, "/StoreManager/create");
|
||||
formParameters = new List<KeyValuePair<string, string>>
|
||||
{
|
||||
new KeyValuePair<string, string>("__RequestVerificationToken", antiForgeryToken),
|
||||
new KeyValuePair<string, string>("GenreId", "1"),
|
||||
new KeyValuePair<string, string>("ArtistId", "1"),
|
||||
new KeyValuePair<string, string>("Title", albumName),
|
||||
new KeyValuePair<string, string>("Price", "9.99"),
|
||||
new KeyValuePair<string, string>("AlbumArtUrl", "TestUrl"),
|
||||
};
|
||||
|
||||
content = new FormUrlEncodedContent(formParameters.ToArray());
|
||||
response = httpClient.PostAsync("/StoreManager/create", content).Result;
|
||||
responseContent = response.Content.ReadAsStringAsync().Result;
|
||||
Assert.Equal<string>(APP_BASE_URL + "StoreManager", response.RequestMessage.RequestUri.AbsoluteUri);
|
||||
Assert.Contains(albumName, responseContent);
|
||||
|
||||
//Logout from this user session - This should take back to the home page
|
||||
antiForgeryToken = Utility.RetrieveAntiForgeryToken(responseContent, "/Account/LogOff");
|
||||
formParameters = new List<KeyValuePair<string, string>>
|
||||
{
|
||||
new KeyValuePair<string, string>("__RequestVerificationToken", antiForgeryToken),
|
||||
};
|
||||
|
||||
content = new FormUrlEncodedContent(formParameters.ToArray());
|
||||
response = httpClient.PostAsync("/Account/LogOff", content).Result;
|
||||
responseContent = response.Content.ReadAsStringAsync().Result;
|
||||
Assert.Contains("ASP.NET MVC Music Store", responseContent, StringComparison.OrdinalIgnoreCase);
|
||||
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);
|
||||
//Verify cookie cleared on logout
|
||||
Assert.Null(Utility.GetCookieWithName(httpClientHandler.CookieContainer.GetCookies(new Uri(APP_BASE_URL)), ".AspNet.Microsoft.AspNet.Identity.Security.Application"));
|
||||
}
|
||||
finally
|
||||
{
|
||||
//Shutdown the host process
|
||||
hostProcess.Kill();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,128 @@
|
|||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Threading;
|
||||
using System.Xml;
|
||||
|
||||
namespace E2ETests
|
||||
{
|
||||
internal class Utility
|
||||
{
|
||||
public static string GetIISExpressPath()
|
||||
{
|
||||
var iisExpressPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86), "IIS Express", "iisexpress.exe");
|
||||
|
||||
//If X86 version does not exist
|
||||
if (!File.Exists(iisExpressPath))
|
||||
{
|
||||
iisExpressPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), "IIS Express", "iisexpress.exe");
|
||||
|
||||
if (!File.Exists(iisExpressPath))
|
||||
{
|
||||
throw new Exception("Unable to find IISExpress on the machine");
|
||||
}
|
||||
}
|
||||
|
||||
return iisExpressPath;
|
||||
}
|
||||
|
||||
public static Cookie GetCookieWithName(CookieCollection cookieCollection, string cookieName)
|
||||
{
|
||||
foreach (Cookie cookie in cookieCollection)
|
||||
{
|
||||
if (cookie.Name == cookieName)
|
||||
{
|
||||
return cookie;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static string RetrieveAntiForgeryToken(string htmlContent, string actionUrl)
|
||||
{
|
||||
int startSearchIndex = 0;
|
||||
|
||||
while (startSearchIndex < htmlContent.Length)
|
||||
{
|
||||
var antiForgeryToken = RetrieveAntiForgeryToken(htmlContent, actionUrl, ref startSearchIndex);
|
||||
|
||||
if (antiForgeryToken != null)
|
||||
{
|
||||
return antiForgeryToken;
|
||||
}
|
||||
}
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
private static string RetrieveAntiForgeryToken(string htmlContent, string actionLocation, ref int startIndex)
|
||||
{
|
||||
var formStartIndex = htmlContent.IndexOf("<form", startIndex, StringComparison.OrdinalIgnoreCase);
|
||||
var formEndIndex = htmlContent.IndexOf("</form>", startIndex, StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
if (formStartIndex == -1 || formEndIndex == -1)
|
||||
{
|
||||
//Unable to find the form start or end - finish the search
|
||||
startIndex = htmlContent.Length;
|
||||
return null;
|
||||
}
|
||||
|
||||
formEndIndex = formEndIndex + "</form>".Length;
|
||||
startIndex = formEndIndex + 1;
|
||||
|
||||
var htmlDocument = new XmlDocument();
|
||||
htmlDocument.LoadXml(htmlContent.Substring(formStartIndex, formEndIndex - formStartIndex));
|
||||
|
||||
foreach (XmlAttribute attribute in htmlDocument.DocumentElement.Attributes)
|
||||
{
|
||||
if (string.Compare(attribute.Name, "action", true) == 0 && attribute.Value.EndsWith(actionLocation, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
foreach (XmlNode input in htmlDocument.GetElementsByTagName("input"))
|
||||
{
|
||||
if (input.Attributes["name"].Value == "__RequestVerificationToken" && input.Attributes["type"].Value == "hidden")
|
||||
{
|
||||
return input.Attributes["value"].Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copy AspNet.Loader.dll to bin folder
|
||||
/// </summary>
|
||||
/// <param name="applicationPath"></param>
|
||||
public static void CopyAspNetLoader(string applicationPath)
|
||||
{
|
||||
string packagesDirectory = Path.GetFullPath(Path.Combine(Environment.CurrentDirectory, @"..\..\Packages"));
|
||||
var aspNetLoaderSrcPath = Path.Combine(Directory.GetDirectories(packagesDirectory, "Microsoft.AspNet.Loader.IIS.Interop.*").First(), @"tools\AspNet.Loader.dll");
|
||||
var aspNetLoaderDestPath = Path.Combine(applicationPath, @"bin\AspNet.Loader.dll");
|
||||
if (!File.Exists(aspNetLoaderDestPath))
|
||||
{
|
||||
File.Copy(aspNetLoaderSrcPath, aspNetLoaderDestPath);
|
||||
}
|
||||
}
|
||||
|
||||
public static Process StartHeliosHost(string applicationPath)
|
||||
{
|
||||
var startInfo = new ProcessStartInfo
|
||||
{
|
||||
FileName = Utility.GetIISExpressPath(),
|
||||
Arguments = string.Format("/port:5001 /path:{0}", applicationPath),
|
||||
UseShellExecute = true,
|
||||
CreateNoWindow = true
|
||||
};
|
||||
|
||||
var hostProcess = Process.Start(startInfo);
|
||||
Console.WriteLine("Started iisexpress. Process Id : {0}", hostProcess.Id);
|
||||
Thread.Sleep(2 * 1000);
|
||||
|
||||
return hostProcess;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
{
|
||||
"version": "0.1-alpha-*",
|
||||
"commands": {
|
||||
"test": "Xunit.KRunner"
|
||||
},
|
||||
"dependencies": {
|
||||
"Xunit.KRunner": "0.1-alpha-*",
|
||||
"xunit.abstractions": "2.0.0-aspnet-*",
|
||||
"xunit.assert": "2.0.0-aspnet-*",
|
||||
"xunit.core": "2.0.0-aspnet-*",
|
||||
"xunit.execution": "2.0.0-aspnet-*"
|
||||
},
|
||||
"configurations": {
|
||||
"net45": {
|
||||
"dependencies": {
|
||||
"System.Runtime": "",
|
||||
"System.Runtime.Extensions": "",
|
||||
"System.Net.Http": "",
|
||||
"System.Net.Http.WebRequest": "",
|
||||
"System.Diagnostics.Process": "",
|
||||
"System.Xml": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue