From 1fbabe0000c1e9cdcb237afc2dd10a7109f8540a Mon Sep 17 00:00:00 2001 From: jvyden Date: Wed, 22 Dec 2021 22:33:50 -0500 Subject: [PATCH 1/8] Split normal tests from game api tests --- .../AuthenticationTests.cs | 5 ++- .../DatabaseTests.cs | 6 ++- .../MatchTests.cs | 5 ++- ...rojectLighthouse.Tests.GameApiTests.csproj | 41 +++++++++++++++++++ .../SlotTests.cs | 6 ++- .../UploadTests.cs | 5 ++- .../{Tests => }/FileTypeTests.cs | 0 ...hthouseTest.cs => LighthouseServerTest.cs} | 4 +- .../ProjectLighthouse.Tests.csproj | 2 +- .../{Tests => }/SerializerTests.cs | 2 +- ProjectLighthouse.sln | 12 ++++++ 11 files changed, 74 insertions(+), 14 deletions(-) rename {ProjectLighthouse.Tests/Tests => ProjectLighthouse.Tests.GameApiTests}/AuthenticationTests.cs (94%) rename {ProjectLighthouse.Tests/Tests => ProjectLighthouse.Tests.GameApiTests}/DatabaseTests.cs (81%) rename {ProjectLighthouse.Tests/Tests => ProjectLighthouse.Tests.GameApiTests}/MatchTests.cs (93%) create mode 100644 ProjectLighthouse.Tests.GameApiTests/ProjectLighthouse.Tests.GameApiTests.csproj rename {ProjectLighthouse.Tests/Tests => ProjectLighthouse.Tests.GameApiTests}/SlotTests.cs (94%) rename {ProjectLighthouse.Tests/Tests => ProjectLighthouse.Tests.GameApiTests}/UploadTests.cs (93%) rename ProjectLighthouse.Tests/{Tests => }/FileTypeTests.cs (100%) rename ProjectLighthouse.Tests/{LighthouseTest.cs => LighthouseServerTest.cs} (98%) rename ProjectLighthouse.Tests/{Tests => }/SerializerTests.cs (96%) diff --git a/ProjectLighthouse.Tests/Tests/AuthenticationTests.cs b/ProjectLighthouse.Tests.GameApiTests/AuthenticationTests.cs similarity index 94% rename from ProjectLighthouse.Tests/Tests/AuthenticationTests.cs rename to ProjectLighthouse.Tests.GameApiTests/AuthenticationTests.cs index d7f5fd19..05f0c413 100644 --- a/ProjectLighthouse.Tests/Tests/AuthenticationTests.cs +++ b/ProjectLighthouse.Tests.GameApiTests/AuthenticationTests.cs @@ -1,13 +1,14 @@ using System.Net; using System.Net.Http; using System.Threading.Tasks; +using LBPUnion.ProjectLighthouse.Tests; using LBPUnion.ProjectLighthouse.Types; using LBPUnion.ProjectLighthouse.Types.Settings; using Xunit; -namespace LBPUnion.ProjectLighthouse.Tests +namespace ProjectLighthouse.Tests.GameApiTests { - public class AuthenticationTests : LighthouseTest + public class AuthenticationTests : LighthouseServerTest { [Fact] public async Task ShouldReturnErrorOnNoPostData() diff --git a/ProjectLighthouse.Tests/Tests/DatabaseTests.cs b/ProjectLighthouse.Tests.GameApiTests/DatabaseTests.cs similarity index 81% rename from ProjectLighthouse.Tests/Tests/DatabaseTests.cs rename to ProjectLighthouse.Tests.GameApiTests/DatabaseTests.cs index 19416bcb..ccaa758b 100644 --- a/ProjectLighthouse.Tests/Tests/DatabaseTests.cs +++ b/ProjectLighthouse.Tests.GameApiTests/DatabaseTests.cs @@ -1,12 +1,14 @@ using System; using System.Threading.Tasks; +using LBPUnion.ProjectLighthouse; using LBPUnion.ProjectLighthouse.Helpers; +using LBPUnion.ProjectLighthouse.Tests; using LBPUnion.ProjectLighthouse.Types; using Xunit; -namespace LBPUnion.ProjectLighthouse.Tests +namespace ProjectLighthouse.Tests.GameApiTests { - public class DatabaseTests : LighthouseTest + public class DatabaseTests : LighthouseServerTest { [DatabaseFact] public async Task CanCreateUserTwice() diff --git a/ProjectLighthouse.Tests/Tests/MatchTests.cs b/ProjectLighthouse.Tests.GameApiTests/MatchTests.cs similarity index 93% rename from ProjectLighthouse.Tests/Tests/MatchTests.cs rename to ProjectLighthouse.Tests.GameApiTests/MatchTests.cs index 721dc941..c7e83feb 100644 --- a/ProjectLighthouse.Tests/Tests/MatchTests.cs +++ b/ProjectLighthouse.Tests.GameApiTests/MatchTests.cs @@ -4,12 +4,13 @@ using System.Text; using System.Threading; using System.Threading.Tasks; using LBPUnion.ProjectLighthouse.Helpers; +using LBPUnion.ProjectLighthouse.Tests; using LBPUnion.ProjectLighthouse.Types; using Xunit; -namespace LBPUnion.ProjectLighthouse.Tests +namespace ProjectLighthouse.Tests.GameApiTests { - public class MatchTests : LighthouseTest + public class MatchTests : LighthouseServerTest { private static readonly SemaphoreSlim semaphore = new(1, 1); diff --git a/ProjectLighthouse.Tests.GameApiTests/ProjectLighthouse.Tests.GameApiTests.csproj b/ProjectLighthouse.Tests.GameApiTests/ProjectLighthouse.Tests.GameApiTests.csproj new file mode 100644 index 00000000..4a5850d3 --- /dev/null +++ b/ProjectLighthouse.Tests.GameApiTests/ProjectLighthouse.Tests.GameApiTests.csproj @@ -0,0 +1,41 @@ + + + + net6.0 + enable + + false + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + + + + + PreserveNewest + + + + + diff --git a/ProjectLighthouse.Tests/Tests/SlotTests.cs b/ProjectLighthouse.Tests.GameApiTests/SlotTests.cs similarity index 94% rename from ProjectLighthouse.Tests/Tests/SlotTests.cs rename to ProjectLighthouse.Tests.GameApiTests/SlotTests.cs index 4eef03b6..568a9ed4 100644 --- a/ProjectLighthouse.Tests/Tests/SlotTests.cs +++ b/ProjectLighthouse.Tests.GameApiTests/SlotTests.cs @@ -1,15 +1,17 @@ using System; using System.Net.Http; using System.Threading.Tasks; +using LBPUnion.ProjectLighthouse; using LBPUnion.ProjectLighthouse.Helpers; +using LBPUnion.ProjectLighthouse.Tests; using LBPUnion.ProjectLighthouse.Types; using LBPUnion.ProjectLighthouse.Types.Levels; using LBPUnion.ProjectLighthouse.Types.Profiles; using Xunit; -namespace LBPUnion.ProjectLighthouse.Tests +namespace ProjectLighthouse.Tests.GameApiTests { - public class SlotTests : LighthouseTest + public class SlotTests : LighthouseServerTest { [DatabaseFact] public async Task ShouldOnlyShowUsersLevels() diff --git a/ProjectLighthouse.Tests/Tests/UploadTests.cs b/ProjectLighthouse.Tests.GameApiTests/UploadTests.cs similarity index 93% rename from ProjectLighthouse.Tests/Tests/UploadTests.cs rename to ProjectLighthouse.Tests.GameApiTests/UploadTests.cs index 8c7f0bd5..faac8aa9 100644 --- a/ProjectLighthouse.Tests/Tests/UploadTests.cs +++ b/ProjectLighthouse.Tests.GameApiTests/UploadTests.cs @@ -3,11 +3,12 @@ using System.IO; using System.Net; using System.Net.Http; using System.Threading.Tasks; +using LBPUnion.ProjectLighthouse.Tests; using Xunit; -namespace LBPUnion.ProjectLighthouse.Tests +namespace ProjectLighthouse.Tests.GameApiTests { - public class UploadTests : LighthouseTest + public class UploadTests : LighthouseServerTest { public UploadTests() { diff --git a/ProjectLighthouse.Tests/Tests/FileTypeTests.cs b/ProjectLighthouse.Tests/FileTypeTests.cs similarity index 100% rename from ProjectLighthouse.Tests/Tests/FileTypeTests.cs rename to ProjectLighthouse.Tests/FileTypeTests.cs diff --git a/ProjectLighthouse.Tests/LighthouseTest.cs b/ProjectLighthouse.Tests/LighthouseServerTest.cs similarity index 98% rename from ProjectLighthouse.Tests/LighthouseTest.cs rename to ProjectLighthouse.Tests/LighthouseServerTest.cs index dd96dbf0..0a02da01 100644 --- a/ProjectLighthouse.Tests/LighthouseTest.cs +++ b/ProjectLighthouse.Tests/LighthouseServerTest.cs @@ -14,12 +14,12 @@ using Microsoft.EntityFrameworkCore; namespace LBPUnion.ProjectLighthouse.Tests { [SuppressMessage("ReSharper", "UnusedMember.Global")] - public class LighthouseTest + public class LighthouseServerTest { public readonly HttpClient Client; public readonly TestServer Server; - public LighthouseTest() + public LighthouseServerTest() { this.Server = new TestServer(new WebHostBuilder().UseStartup()); diff --git a/ProjectLighthouse.Tests/ProjectLighthouse.Tests.csproj b/ProjectLighthouse.Tests/ProjectLighthouse.Tests.csproj index 0f656960..91fa33ee 100644 --- a/ProjectLighthouse.Tests/ProjectLighthouse.Tests.csproj +++ b/ProjectLighthouse.Tests/ProjectLighthouse.Tests.csproj @@ -32,9 +32,9 @@ - PreserveNewest + diff --git a/ProjectLighthouse.Tests/Tests/SerializerTests.cs b/ProjectLighthouse.Tests/SerializerTests.cs similarity index 96% rename from ProjectLighthouse.Tests/Tests/SerializerTests.cs rename to ProjectLighthouse.Tests/SerializerTests.cs index 2c8af05e..39a12ce4 100644 --- a/ProjectLighthouse.Tests/Tests/SerializerTests.cs +++ b/ProjectLighthouse.Tests/SerializerTests.cs @@ -4,7 +4,7 @@ using Xunit; namespace LBPUnion.ProjectLighthouse.Tests { - public class SerializerTests : LighthouseTest + public class SerializerTests { [Fact] public void BlankElementWorks() diff --git a/ProjectLighthouse.sln b/ProjectLighthouse.sln index 96db324b..745241a4 100644 --- a/ProjectLighthouse.sln +++ b/ProjectLighthouse.sln @@ -4,6 +4,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ProjectLighthouse", "Projec EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ProjectLighthouse.Tests", "ProjectLighthouse.Tests\ProjectLighthouse.Tests.csproj", "{AFC74569-B289-4ACC-B21C-313A3A62C017}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{D360C08E-EA47-43AC-A566-FDF413442980}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ProjectLighthouse.Tests.GameApiTests", "ProjectLighthouse.Tests.GameApiTests\ProjectLighthouse.Tests.GameApiTests.csproj", "{200EED99-FE3E-45C6-A51E-76ED9819CA2B}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -18,5 +22,13 @@ Global {AFC74569-B289-4ACC-B21C-313A3A62C017}.Debug|Any CPU.Build.0 = Debug|Any CPU {AFC74569-B289-4ACC-B21C-313A3A62C017}.Release|Any CPU.ActiveCfg = Release|Any CPU {AFC74569-B289-4ACC-B21C-313A3A62C017}.Release|Any CPU.Build.0 = Release|Any CPU + {200EED99-FE3E-45C6-A51E-76ED9819CA2B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {200EED99-FE3E-45C6-A51E-76ED9819CA2B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {200EED99-FE3E-45C6-A51E-76ED9819CA2B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {200EED99-FE3E-45C6-A51E-76ED9819CA2B}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {AFC74569-B289-4ACC-B21C-313A3A62C017} = {D360C08E-EA47-43AC-A566-FDF413442980} + {200EED99-FE3E-45C6-A51E-76ED9819CA2B} = {D360C08E-EA47-43AC-A566-FDF413442980} EndGlobalSection EndGlobal From 281be33640c6ea5706b59ae5081924a76851c5ab Mon Sep 17 00:00:00 2001 From: jvyden Date: Thu, 23 Dec 2021 00:03:04 -0500 Subject: [PATCH 2/8] Add website authentication tests --- .../DatabaseTests.cs | 2 - .../AuthenticationTests.cs | 133 ++++++++++++++++++ ...rojectLighthouse.Tests.WebsiteTests.csproj | 36 +++++ .../LighthouseServerTest.cs | 1 - ProjectLighthouse.sln | 7 + ProjectLighthouse.sln.DotSettings | 1 + 6 files changed, 177 insertions(+), 3 deletions(-) create mode 100644 ProjectLighthouse.Tests.WebsiteTests/AuthenticationTests.cs create mode 100644 ProjectLighthouse.Tests.WebsiteTests/ProjectLighthouse.Tests.WebsiteTests.csproj diff --git a/ProjectLighthouse.Tests.GameApiTests/DatabaseTests.cs b/ProjectLighthouse.Tests.GameApiTests/DatabaseTests.cs index ccaa758b..86b26ccd 100644 --- a/ProjectLighthouse.Tests.GameApiTests/DatabaseTests.cs +++ b/ProjectLighthouse.Tests.GameApiTests/DatabaseTests.cs @@ -23,8 +23,6 @@ namespace ProjectLighthouse.Tests.GameApiTests Assert.NotNull(userB); await database.RemoveUser(userA); // Only remove userA since userA and userB are the same user - - await database.SaveChangesAsync(); } } } \ No newline at end of file diff --git a/ProjectLighthouse.Tests.WebsiteTests/AuthenticationTests.cs b/ProjectLighthouse.Tests.WebsiteTests/AuthenticationTests.cs new file mode 100644 index 00000000..ce7f7f74 --- /dev/null +++ b/ProjectLighthouse.Tests.WebsiteTests/AuthenticationTests.cs @@ -0,0 +1,133 @@ +using System; +using System.Linq; +using System.Threading.Tasks; +using LBPUnion.ProjectLighthouse; +using LBPUnion.ProjectLighthouse.Helpers; +using LBPUnion.ProjectLighthouse.Tests; +using LBPUnion.ProjectLighthouse.Types; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Hosting.Server.Features; +using Microsoft.EntityFrameworkCore; +using OpenQA.Selenium; +using OpenQA.Selenium.Chrome; +using Xunit; + +namespace ProjectLighthouse.Tests.WebsiteTests +{ + public class AuthenticationTests : IDisposable + { + public readonly IWebHost WebHost = new WebHostBuilder().UseKestrel().UseStartup().UseWebRoot("StaticFiles").Build(); + public readonly string BaseAddress; + + public readonly IWebDriver Driver = new ChromeDriver(); + + public AuthenticationTests() + { + this.WebHost.Start(); + + IServerAddressesFeature? serverAddressesFeature = WebHost.ServerFeatures.Get(); + if (serverAddressesFeature == null) throw new ArgumentNullException(); + + this.BaseAddress = serverAddressesFeature.Addresses.First(); + } + + [DatabaseFact] + public async Task ShouldLoginWithPassword() + { + await using Database database = new(); + Random random = new(); + + string password = HashHelper.Sha256Hash(HashHelper.GenerateRandomBytes(64).ToArray()); + User user = await database.CreateUser($"unitTestUser{random.Next()}", HashHelper.BCryptHash(HashHelper.Sha256Hash(password))); + + this.Driver.Navigate().GoToUrl(this.BaseAddress + "/login"); + + this.Driver.FindElement(By.Id("text")).SendKeys(user.Username); + this.Driver.FindElement(By.Id("password")).SendKeys(password); + + this.Driver.FindElement(By.Id("submit")).Click(); + + WebToken? webToken = await database.WebTokens.FirstOrDefaultAsync(t => t.UserId == user.UserId); + Assert.NotNull(webToken); + + await database.RemoveUser(user); + } + + [DatabaseFact] + public async Task ShouldNotLoginWithNoPassword() + { + await using Database database = new(); + Random random = new(); + User user = await database.CreateUser($"unitTestUser{random.Next()}", HashHelper.BCryptHash("just like the hindenberg,")); + + this.Driver.Navigate().GoToUrl(this.BaseAddress + "/login"); + + this.Driver.FindElement(By.Id("text")).SendKeys(user.Username); + + this.Driver.FindElement(By.Id("submit")).Click(); + + WebToken? webToken = await database.WebTokens.FirstOrDefaultAsync(t => t.UserId == user.UserId); + Assert.Null(webToken); + + await database.RemoveUser(user); + } + + [DatabaseFact] + public async Task ShouldNotLoginWithWrongPassword() + { + await using Database database = new(); + Random random = new(); + User user = await database.CreateUser($"unitTestUser{random.Next()}", HashHelper.BCryptHash("i'm an engineering failure")); + + this.Driver.Navigate().GoToUrl(this.BaseAddress + "/login"); + + this.Driver.FindElement(By.Id("text")).SendKeys(user.Username); + this.Driver.FindElement(By.Id("password")).SendKeys("nah man"); + + this.Driver.FindElement(By.Id("submit")).Click(); + + WebToken? webToken = await database.WebTokens.FirstOrDefaultAsync(t => t.UserId == user.UserId); + Assert.Null(webToken); + + await database.RemoveUser(user); + } + + [DatabaseFact] + public async Task ShouldLoginWithInjectedCookie() + { + const string loggedInAsUsernameTextXPath = "/html/body/div/div/div/p[1]/b"; + + await using Database database = new(); + Random random = new(); + User user = await database.CreateUser($"unitTestUser{random.Next()}", HashHelper.BCryptHash("i'm an engineering failure")); + + WebToken webToken = new() + { + UserId = user.UserId, + UserToken = HashHelper.GenerateAuthToken(), + }; + + database.WebTokens.Add(webToken); + await database.SaveChangesAsync(); + + INavigation navigation = this.Driver.Navigate(); + + navigation.GoToUrl(this.BaseAddress + "/"); + this.Driver.Manage().Cookies.AddCookie(new Cookie("LighthouseToken", webToken.UserToken)); + Assert.Throws(() => this.Driver.FindElement(By.XPath(loggedInAsUsernameTextXPath))); + navigation.Refresh(); + Assert.True(this.Driver.FindElement(By.XPath(loggedInAsUsernameTextXPath)).Text == user.Username); + + await database.RemoveUser(user); + } + + public void Dispose() + { + this.Driver.Close(); + this.Driver.Dispose(); + this.WebHost.Dispose(); + + GC.SuppressFinalize(this); + } + } +} \ No newline at end of file diff --git a/ProjectLighthouse.Tests.WebsiteTests/ProjectLighthouse.Tests.WebsiteTests.csproj b/ProjectLighthouse.Tests.WebsiteTests/ProjectLighthouse.Tests.WebsiteTests.csproj new file mode 100644 index 00000000..93e88c08 --- /dev/null +++ b/ProjectLighthouse.Tests.WebsiteTests/ProjectLighthouse.Tests.WebsiteTests.csproj @@ -0,0 +1,36 @@ + + + + net6.0 + enable + + false + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + + + diff --git a/ProjectLighthouse.Tests/LighthouseServerTest.cs b/ProjectLighthouse.Tests/LighthouseServerTest.cs index 0a02da01..4e79d578 100644 --- a/ProjectLighthouse.Tests/LighthouseServerTest.cs +++ b/ProjectLighthouse.Tests/LighthouseServerTest.cs @@ -22,7 +22,6 @@ namespace LBPUnion.ProjectLighthouse.Tests public LighthouseServerTest() { this.Server = new TestServer(new WebHostBuilder().UseStartup()); - this.Client = this.Server.CreateClient(); } public async Task AuthenticateResponse(int number = -1, bool createUser = true) diff --git a/ProjectLighthouse.sln b/ProjectLighthouse.sln index 745241a4..c1ae0363 100644 --- a/ProjectLighthouse.sln +++ b/ProjectLighthouse.sln @@ -8,6 +8,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{D360C08E EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ProjectLighthouse.Tests.GameApiTests", "ProjectLighthouse.Tests.GameApiTests\ProjectLighthouse.Tests.GameApiTests.csproj", "{200EED99-FE3E-45C6-A51E-76ED9819CA2B}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ProjectLighthouse.Tests.WebsiteTests", "ProjectLighthouse.Tests.WebsiteTests\ProjectLighthouse.Tests.WebsiteTests.csproj", "{CF65EB5B-5364-4D2A-8639-F147A67F08E7}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -26,9 +28,14 @@ Global {200EED99-FE3E-45C6-A51E-76ED9819CA2B}.Debug|Any CPU.Build.0 = Debug|Any CPU {200EED99-FE3E-45C6-A51E-76ED9819CA2B}.Release|Any CPU.ActiveCfg = Release|Any CPU {200EED99-FE3E-45C6-A51E-76ED9819CA2B}.Release|Any CPU.Build.0 = Release|Any CPU + {CF65EB5B-5364-4D2A-8639-F147A67F08E7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CF65EB5B-5364-4D2A-8639-F147A67F08E7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CF65EB5B-5364-4D2A-8639-F147A67F08E7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CF65EB5B-5364-4D2A-8639-F147A67F08E7}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(NestedProjects) = preSolution {AFC74569-B289-4ACC-B21C-313A3A62C017} = {D360C08E-EA47-43AC-A566-FDF413442980} {200EED99-FE3E-45C6-A51E-76ED9819CA2B} = {D360C08E-EA47-43AC-A566-FDF413442980} + {CF65EB5B-5364-4D2A-8639-F147A67F08E7} = {D360C08E-EA47-43AC-A566-FDF413442980} EndGlobalSection EndGlobal diff --git a/ProjectLighthouse.sln.DotSettings b/ProjectLighthouse.sln.DotSettings index 385c8365..7bbd6e1f 100644 --- a/ProjectLighthouse.sln.DotSettings +++ b/ProjectLighthouse.sln.DotSettings @@ -89,6 +89,7 @@ True True True + True True True True From f36038910a4b3af874991dd71e002b006e3f9ff9 Mon Sep 17 00:00:00 2001 From: jvyden Date: Thu, 23 Dec 2021 00:23:14 -0500 Subject: [PATCH 3/8] Run ChromeDriver in headless mode if in a CI environment --- .../AuthenticationTests.cs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/ProjectLighthouse.Tests.WebsiteTests/AuthenticationTests.cs b/ProjectLighthouse.Tests.WebsiteTests/AuthenticationTests.cs index ce7f7f74..5266abf4 100644 --- a/ProjectLighthouse.Tests.WebsiteTests/AuthenticationTests.cs +++ b/ProjectLighthouse.Tests.WebsiteTests/AuthenticationTests.cs @@ -19,7 +19,7 @@ namespace ProjectLighthouse.Tests.WebsiteTests public readonly IWebHost WebHost = new WebHostBuilder().UseKestrel().UseStartup().UseWebRoot("StaticFiles").Build(); public readonly string BaseAddress; - public readonly IWebDriver Driver = new ChromeDriver(); + public readonly IWebDriver Driver; public AuthenticationTests() { @@ -29,6 +29,15 @@ namespace ProjectLighthouse.Tests.WebsiteTests if (serverAddressesFeature == null) throw new ArgumentNullException(); this.BaseAddress = serverAddressesFeature.Addresses.First(); + + ChromeOptions chromeOptions = new(); + if (Convert.ToBoolean(Environment.GetEnvironmentVariable("CI") ?? "false")) + { + chromeOptions.AddArgument("headless"); + Console.WriteLine("We are in a CI environment, so chrome headless mode has been enabled."); + } + + this.Driver = new ChromeDriver(chromeOptions); } [DatabaseFact] From cabe48585481d3ca4bc68e83966f284d51565997 Mon Sep 17 00:00:00 2001 From: jvyden Date: Thu, 23 Dec 2021 00:33:18 -0500 Subject: [PATCH 4/8] Disable chrome sandboxing and dev-shm usage in CI environment --- ProjectLighthouse.Tests.WebsiteTests/AuthenticationTests.cs | 2 ++ ProjectLighthouse.sln | 3 --- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/ProjectLighthouse.Tests.WebsiteTests/AuthenticationTests.cs b/ProjectLighthouse.Tests.WebsiteTests/AuthenticationTests.cs index 5266abf4..e3ed939c 100644 --- a/ProjectLighthouse.Tests.WebsiteTests/AuthenticationTests.cs +++ b/ProjectLighthouse.Tests.WebsiteTests/AuthenticationTests.cs @@ -34,6 +34,8 @@ namespace ProjectLighthouse.Tests.WebsiteTests if (Convert.ToBoolean(Environment.GetEnvironmentVariable("CI") ?? "false")) { chromeOptions.AddArgument("headless"); + chromeOptions.AddArgument("no-sandbox"); + chromeOptions.AddArgument("disable-dev-shm-usage"); Console.WriteLine("We are in a CI environment, so chrome headless mode has been enabled."); } diff --git a/ProjectLighthouse.sln b/ProjectLighthouse.sln index c1ae0363..9f80122f 100644 --- a/ProjectLighthouse.sln +++ b/ProjectLighthouse.sln @@ -23,15 +23,12 @@ Global {AFC74569-B289-4ACC-B21C-313A3A62C017}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {AFC74569-B289-4ACC-B21C-313A3A62C017}.Debug|Any CPU.Build.0 = Debug|Any CPU {AFC74569-B289-4ACC-B21C-313A3A62C017}.Release|Any CPU.ActiveCfg = Release|Any CPU - {AFC74569-B289-4ACC-B21C-313A3A62C017}.Release|Any CPU.Build.0 = Release|Any CPU {200EED99-FE3E-45C6-A51E-76ED9819CA2B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {200EED99-FE3E-45C6-A51E-76ED9819CA2B}.Debug|Any CPU.Build.0 = Debug|Any CPU {200EED99-FE3E-45C6-A51E-76ED9819CA2B}.Release|Any CPU.ActiveCfg = Release|Any CPU - {200EED99-FE3E-45C6-A51E-76ED9819CA2B}.Release|Any CPU.Build.0 = Release|Any CPU {CF65EB5B-5364-4D2A-8639-F147A67F08E7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {CF65EB5B-5364-4D2A-8639-F147A67F08E7}.Debug|Any CPU.Build.0 = Debug|Any CPU {CF65EB5B-5364-4D2A-8639-F147A67F08E7}.Release|Any CPU.ActiveCfg = Release|Any CPU - {CF65EB5B-5364-4D2A-8639-F147A67F08E7}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(NestedProjects) = preSolution {AFC74569-B289-4ACC-B21C-313A3A62C017} = {D360C08E-EA47-43AC-A566-FDF413442980} From bbaccef2e675a50a518a10e9903d190666e158e8 Mon Sep 17 00:00:00 2001 From: jvyden Date: Thu, 23 Dec 2021 00:42:04 -0500 Subject: [PATCH 5/8] Only do CI WebsiteTests on Linux --- .github/workflows/ci.yml | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 87ba9197..e36c241d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -13,9 +13,9 @@ jobs: fail-fast: false matrix: os: - - { prettyName: Windows, fullName: windows-latest, database: true } - - { prettyName: macOS, fullName: macos-latest, database: true } - - { prettyName: Linux, fullName: ubuntu-latest, database: true } + - { prettyName: Windows, fullName: windows-latest, database: true, webTest: false } + - { prettyName: macOS, fullName: macos-latest, database: true, webTest: false } + - { prettyName: Linux, fullName: ubuntu-latest, database: true, webTest: true } timeout-minutes: 10 env: DB_DATABASE: lighthouse @@ -44,11 +44,19 @@ jobs: - name: Compile run: dotnet build -c Debug - - name: Test + - name: ProjectLighthouse.Tests continue-on-error: true - run: dotnet test --logger "trx;LogFileName=${{github.workspace}}/TestResults-${{matrix.os.prettyName}}.trx" + run: dotnet test --logger "trx;LogFileName=${{github.workspace}}/TestResults-${{matrix.os.prettyName}}.trx" ProjectLighthouse.Tests + - name: ProjectLighthouse.Tests.GameApiTests + continue-on-error: true + run: dotnet test --logger "trx;LogFileName=${{github.workspace}}/TestResults-${{matrix.os.prettyName}}.trx" ProjectLighthouse.Tests.GameApiTests + - name: ProjectLighthouse.Tests.WebsiteTests + if: ${{ matrix.os.webTest }} + continue-on-error: true + run: dotnet test --logger "trx;LogFileName=${{github.workspace}}/TestResults-${{matrix.os.prettyName}}.trx" ProjectLighthouse.Tests.WebsiteTests + # Attempt to upload results even if test fails. # https://docs.github.com/en/actions/reference/context-and-expression-syntax-for-github-actions#always - name: Upload Test Results From 89857b99bcea4301ea0c1be6d48ce17bf00ac112 Mon Sep 17 00:00:00 2001 From: jvyden Date: Thu, 23 Dec 2021 00:47:23 -0500 Subject: [PATCH 6/8] Upload individual test log files --- .github/workflows/ci.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e36c241d..355cc520 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -44,18 +44,18 @@ jobs: - name: Compile run: dotnet build -c Debug - - name: ProjectLighthouse.Tests + - name: Run tests on ProjectLighthouse.Tests continue-on-error: true - run: dotnet test --logger "trx;LogFileName=${{github.workspace}}/TestResults-${{matrix.os.prettyName}}.trx" ProjectLighthouse.Tests + run: dotnet test --logger "trx;LogFileName=${{github.workspace}}/TestResults-${{matrix.os.prettyName}}-Tests.trx" ProjectLighthouse.Tests - - name: ProjectLighthouse.Tests.GameApiTests + - name: Run tests on ProjectLighthouse.Tests.GameApiTests continue-on-error: true - run: dotnet test --logger "trx;LogFileName=${{github.workspace}}/TestResults-${{matrix.os.prettyName}}.trx" ProjectLighthouse.Tests.GameApiTests + run: dotnet test --logger "trx;LogFileName=${{github.workspace}}/TestResults-${{matrix.os.prettyName}}-GameApiTests.trx" ProjectLighthouse.Tests.GameApiTests - - name: ProjectLighthouse.Tests.WebsiteTests + - name: Run tests on ProjectLighthouse.Tests.WebsiteTests if: ${{ matrix.os.webTest }} continue-on-error: true - run: dotnet test --logger "trx;LogFileName=${{github.workspace}}/TestResults-${{matrix.os.prettyName}}.trx" ProjectLighthouse.Tests.WebsiteTests + run: dotnet test --logger "trx;LogFileName=${{github.workspace}}/TestResults-${{matrix.os.prettyName}}-WebsiteTests.trx" ProjectLighthouse.Tests.WebsiteTests # Attempt to upload results even if test fails. # https://docs.github.com/en/actions/reference/context-and-expression-syntax-for-github-actions#always @@ -64,7 +64,7 @@ jobs: if: ${{ always() }} with: name: lighthouse-test-results-${{matrix.os.prettyName}} - path: ${{github.workspace}}/TestResults-${{matrix.os.prettyName}}.trx + path: ${{github.workspace}}/TestResults-${{matrix.os.prettyName}}-*.trx - name: Process Test Results id: process-trx From b5767c6f21e6b8b1939cc442dc69f9ab7d33b3a6 Mon Sep 17 00:00:00 2001 From: jvyden Date: Thu, 23 Dec 2021 01:22:48 -0500 Subject: [PATCH 7/8] Add registration tests --- .../AuthenticationTests.cs | 40 +-------- .../LighthouseWebTest.cs | 50 +++++++++++ .../RegisterTests.cs | 84 +++++++++++++++++++ 3 files changed, 135 insertions(+), 39 deletions(-) create mode 100644 ProjectLighthouse.Tests.WebsiteTests/LighthouseWebTest.cs create mode 100644 ProjectLighthouse.Tests.WebsiteTests/RegisterTests.cs diff --git a/ProjectLighthouse.Tests.WebsiteTests/AuthenticationTests.cs b/ProjectLighthouse.Tests.WebsiteTests/AuthenticationTests.cs index e3ed939c..598969d9 100644 --- a/ProjectLighthouse.Tests.WebsiteTests/AuthenticationTests.cs +++ b/ProjectLighthouse.Tests.WebsiteTests/AuthenticationTests.cs @@ -5,43 +5,14 @@ using LBPUnion.ProjectLighthouse; using LBPUnion.ProjectLighthouse.Helpers; using LBPUnion.ProjectLighthouse.Tests; using LBPUnion.ProjectLighthouse.Types; -using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.Hosting.Server.Features; using Microsoft.EntityFrameworkCore; using OpenQA.Selenium; -using OpenQA.Selenium.Chrome; using Xunit; namespace ProjectLighthouse.Tests.WebsiteTests { - public class AuthenticationTests : IDisposable + public class AuthenticationTests : LighthouseWebTest { - public readonly IWebHost WebHost = new WebHostBuilder().UseKestrel().UseStartup().UseWebRoot("StaticFiles").Build(); - public readonly string BaseAddress; - - public readonly IWebDriver Driver; - - public AuthenticationTests() - { - this.WebHost.Start(); - - IServerAddressesFeature? serverAddressesFeature = WebHost.ServerFeatures.Get(); - if (serverAddressesFeature == null) throw new ArgumentNullException(); - - this.BaseAddress = serverAddressesFeature.Addresses.First(); - - ChromeOptions chromeOptions = new(); - if (Convert.ToBoolean(Environment.GetEnvironmentVariable("CI") ?? "false")) - { - chromeOptions.AddArgument("headless"); - chromeOptions.AddArgument("no-sandbox"); - chromeOptions.AddArgument("disable-dev-shm-usage"); - Console.WriteLine("We are in a CI environment, so chrome headless mode has been enabled."); - } - - this.Driver = new ChromeDriver(chromeOptions); - } - [DatabaseFact] public async Task ShouldLoginWithPassword() { @@ -131,14 +102,5 @@ namespace ProjectLighthouse.Tests.WebsiteTests await database.RemoveUser(user); } - - public void Dispose() - { - this.Driver.Close(); - this.Driver.Dispose(); - this.WebHost.Dispose(); - - GC.SuppressFinalize(this); - } } } \ No newline at end of file diff --git a/ProjectLighthouse.Tests.WebsiteTests/LighthouseWebTest.cs b/ProjectLighthouse.Tests.WebsiteTests/LighthouseWebTest.cs new file mode 100644 index 00000000..dc96a596 --- /dev/null +++ b/ProjectLighthouse.Tests.WebsiteTests/LighthouseWebTest.cs @@ -0,0 +1,50 @@ +using System; +using System.Linq; +using LBPUnion.ProjectLighthouse; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Hosting.Server.Features; +using OpenQA.Selenium; +using OpenQA.Selenium.Chrome; +using Xunit; + +namespace ProjectLighthouse.Tests.WebsiteTests +{ + [Collection(nameof(LighthouseWebTest))] + public class LighthouseWebTest : IDisposable + { + public readonly IWebHost WebHost = new WebHostBuilder().UseKestrel().UseStartup().UseWebRoot("StaticFiles").Build(); + public readonly string BaseAddress; + + public readonly IWebDriver Driver; + + public LighthouseWebTest() + { + this.WebHost.Start(); + + IServerAddressesFeature? serverAddressesFeature = WebHost.ServerFeatures.Get(); + if (serverAddressesFeature == null) throw new ArgumentNullException(); + + this.BaseAddress = serverAddressesFeature.Addresses.First(); + + ChromeOptions chromeOptions = new(); + if (Convert.ToBoolean(Environment.GetEnvironmentVariable("CI") ?? "false")) + { + chromeOptions.AddArgument("headless"); + chromeOptions.AddArgument("no-sandbox"); + chromeOptions.AddArgument("disable-dev-shm-usage"); + Console.WriteLine("We are in a CI environment, so chrome headless mode has been enabled."); + } + + this.Driver = new ChromeDriver(chromeOptions); + } + + public void Dispose() + { + this.Driver.Close(); + this.Driver.Dispose(); + this.WebHost.Dispose(); + + GC.SuppressFinalize(this); + } + } +} \ No newline at end of file diff --git a/ProjectLighthouse.Tests.WebsiteTests/RegisterTests.cs b/ProjectLighthouse.Tests.WebsiteTests/RegisterTests.cs new file mode 100644 index 00000000..2c3cf855 --- /dev/null +++ b/ProjectLighthouse.Tests.WebsiteTests/RegisterTests.cs @@ -0,0 +1,84 @@ +using System; +using System.Linq; +using System.Threading.Tasks; +using LBPUnion.ProjectLighthouse; +using LBPUnion.ProjectLighthouse.Helpers; +using LBPUnion.ProjectLighthouse.Tests; +using LBPUnion.ProjectLighthouse.Types; +using Microsoft.EntityFrameworkCore; +using OpenQA.Selenium; +using Xunit; + +namespace ProjectLighthouse.Tests.WebsiteTests +{ + public class RegisterTests : LighthouseWebTest + { + [DatabaseFact] + public async Task ShouldRegister() + { + await using Database database = new(); + + string username = "unitTestUser" + new Random().Next(); + string password = HashHelper.Sha256Hash(HashHelper.GenerateRandomBytes(64).ToArray()); + + this.Driver.Navigate().GoToUrl(this.BaseAddress + "/register"); + + this.Driver.FindElement(By.Id("text")).SendKeys(username); + + this.Driver.FindElement(By.Id("password")).SendKeys(password); + this.Driver.FindElement(By.Id("confirmPassword")).SendKeys(password); + + this.Driver.FindElement(By.Id("submit")).Click(); + + User? user = await database.Users.FirstOrDefaultAsync(u => u.Username == username); + Assert.NotNull(user); + + await database.RemoveUser(user); + } + + [DatabaseFact] + public async Task ShouldNotRegisterWithMismatchingPasswords() + { + await using Database database = new(); + + string username = "unitTestUser" + new Random().Next(); + string password = HashHelper.Sha256Hash(HashHelper.GenerateRandomBytes(64).ToArray()); + + this.Driver.Navigate().GoToUrl(this.BaseAddress + "/register"); + + this.Driver.FindElement(By.Id("text")).SendKeys(username); + + this.Driver.FindElement(By.Id("password")).SendKeys(password); + this.Driver.FindElement(By.Id("confirmPassword")).SendKeys(password + "a"); + + this.Driver.FindElement(By.Id("submit")).Click(); + + User? user = await database.Users.FirstOrDefaultAsync(u => u.Username == username); + Assert.Null(user); + } + + [DatabaseFact] + public async Task ShouldNotRegisterWithTakenUsername() + { + await using Database database = new(); + + string username = "unitTestUser" + new Random().Next(); + string password = HashHelper.Sha256Hash(HashHelper.GenerateRandomBytes(64).ToArray()); + + await database.CreateUser(username, HashHelper.BCryptHash(password)); + User? user = await database.Users.FirstOrDefaultAsync(u => u.Username == username); + Assert.NotNull(user); + + this.Driver.Navigate().GoToUrl(this.BaseAddress + "/register"); + + this.Driver.FindElement(By.Id("text")).SendKeys(username); + + this.Driver.FindElement(By.Id("password")).SendKeys(password); + this.Driver.FindElement(By.Id("confirmPassword")).SendKeys(password); + + this.Driver.FindElement(By.Id("submit")).Click(); + + Assert.Contains("The username you've chosen is already taken.", this.Driver.PageSource); + } + } +} \ No newline at end of file From 456921d0c7cc6c589e98600b95b3a64a57cb335b Mon Sep 17 00:00:00 2001 From: jvyden Date: Thu, 23 Dec 2021 01:46:10 -0500 Subject: [PATCH 8/8] Add admin panel testing --- .../AdminTests.cs | 64 +++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 ProjectLighthouse.Tests.WebsiteTests/AdminTests.cs diff --git a/ProjectLighthouse.Tests.WebsiteTests/AdminTests.cs b/ProjectLighthouse.Tests.WebsiteTests/AdminTests.cs new file mode 100644 index 00000000..83d2118b --- /dev/null +++ b/ProjectLighthouse.Tests.WebsiteTests/AdminTests.cs @@ -0,0 +1,64 @@ +using System; +using System.Threading.Tasks; +using LBPUnion.ProjectLighthouse; +using LBPUnion.ProjectLighthouse.Helpers; +using LBPUnion.ProjectLighthouse.Tests; +using LBPUnion.ProjectLighthouse.Types; +using OpenQA.Selenium; +using Xunit; + +namespace ProjectLighthouse.Tests.WebsiteTests +{ + public class AdminTests : LighthouseWebTest + { + public const string AdminPanelButtonXPath = "/html/body/div/header/div/div/div/a[2]"; + + [DatabaseFact] + public async Task ShouldShowAdminPanelButtonWhenAdmin() + { + await using Database database = new(); + Random random = new(); + User user = await database.CreateUser($"unitTestUser{random.Next()}", HashHelper.BCryptHash("i'm an engineering failure")); + + WebToken webToken = new() + { + UserId = user.UserId, + UserToken = HashHelper.GenerateAuthToken(), + }; + + database.WebTokens.Add(webToken); + user.IsAdmin = true; + await database.SaveChangesAsync(); + + this.Driver.Navigate().GoToUrl(this.BaseAddress + "/"); + this.Driver.Manage().Cookies.AddCookie(new Cookie("LighthouseToken", webToken.UserToken)); + this.Driver.Navigate().Refresh(); + + Assert.Contains("Admin Panel", this.Driver.FindElement(By.XPath(AdminPanelButtonXPath)).Text); + } + + [DatabaseFact] + public async Task ShouldNotShowAdminPanelButtonWhenNotAdmin() + { + await using Database database = new(); + Random random = new(); + User user = await database.CreateUser($"unitTestUser{random.Next()}", HashHelper.BCryptHash("i'm an engineering failure")); + + WebToken webToken = new() + { + UserId = user.UserId, + UserToken = HashHelper.GenerateAuthToken(), + }; + + database.WebTokens.Add(webToken); + user.IsAdmin = false; + await database.SaveChangesAsync(); + + this.Driver.Navigate().GoToUrl(this.BaseAddress + "/"); + this.Driver.Manage().Cookies.AddCookie(new Cookie("LighthouseToken", webToken.UserToken)); + this.Driver.Navigate().Refresh(); + + Assert.DoesNotContain("Admin Panel", this.Driver.FindElement(By.XPath(AdminPanelButtonXPath)).Text); + } + } +} \ No newline at end of file