mirror of
https://github.com/bitwarden/server.git
synced 2026-01-31 06:03:12 +08:00
Add some integration tests for the Server project (#6839)
* Add some integration tests for the Server project * Not sure why this project got removed? * Format * capture debug output * Update tests to work with the now legacy WebHostBuilder - I accidentally had the updated Program locally and that was why tests were working for me locally * Formatting...again
This commit is contained in:
@@ -140,10 +140,13 @@ EndProject
|
|||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SeederApi", "util\SeederApi\SeederApi.csproj", "{9F08DFBB-482B-4C9D-A5F4-6BDA6EC2E68F}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SeederApi", "util\SeederApi\SeederApi.csproj", "{9F08DFBB-482B-4C9D-A5F4-6BDA6EC2E68F}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SeederApi.IntegrationTest", "test\SeederApi.IntegrationTest\SeederApi.IntegrationTest.csproj", "{A2E067EF-609C-4D13-895A-E054C61D48BB}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SeederApi.IntegrationTest", "test\SeederApi.IntegrationTest\SeederApi.IntegrationTest.csproj", "{A2E067EF-609C-4D13-895A-E054C61D48BB}"
|
||||||
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SSO.Test", "bitwarden_license\test\SSO.Test\SSO.Test.csproj", "{7D98784C-C253-43FB-9873-25B65C6250D6}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SSO.Test", "bitwarden_license\test\SSO.Test\SSO.Test.csproj", "{7D98784C-C253-43FB-9873-25B65C6250D6}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sso.IntegrationTest", "bitwarden_license\test\Sso.IntegrationTest\Sso.IntegrationTest.csproj", "{FFB09376-595B-6F93-36F0-70CAE90AFECB}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sso.IntegrationTest", "bitwarden_license\test\Sso.IntegrationTest\Sso.IntegrationTest.csproj", "{FFB09376-595B-6F93-36F0-70CAE90AFECB}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Server.IntegrationTest", "test\Server.IntegrationTest\Server.IntegrationTest.csproj", "{E75E1F10-BC6F-4EB1-BA75-D897C45AEA0D}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
@@ -372,6 +375,10 @@ Global
|
|||||||
{FFB09376-595B-6F93-36F0-70CAE90AFECB}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{FFB09376-595B-6F93-36F0-70CAE90AFECB}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{FFB09376-595B-6F93-36F0-70CAE90AFECB}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{FFB09376-595B-6F93-36F0-70CAE90AFECB}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{FFB09376-595B-6F93-36F0-70CAE90AFECB}.Release|Any CPU.Build.0 = Release|Any CPU
|
{FFB09376-595B-6F93-36F0-70CAE90AFECB}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{E75E1F10-BC6F-4EB1-BA75-D897C45AEA0D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{E75E1F10-BC6F-4EB1-BA75-D897C45AEA0D}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{E75E1F10-BC6F-4EB1-BA75-D897C45AEA0D}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{E75E1F10-BC6F-4EB1-BA75-D897C45AEA0D}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
@@ -432,6 +439,7 @@ Global
|
|||||||
{A2E067EF-609C-4D13-895A-E054C61D48BB} = {DD5BD056-4AAE-43EF-BBD2-0B569B8DA84F}
|
{A2E067EF-609C-4D13-895A-E054C61D48BB} = {DD5BD056-4AAE-43EF-BBD2-0B569B8DA84F}
|
||||||
{7D98784C-C253-43FB-9873-25B65C6250D6} = {287CFF34-BBDB-4BC4-AF88-1E19A5A4679B}
|
{7D98784C-C253-43FB-9873-25B65C6250D6} = {287CFF34-BBDB-4BC4-AF88-1E19A5A4679B}
|
||||||
{FFB09376-595B-6F93-36F0-70CAE90AFECB} = {287CFF34-BBDB-4BC4-AF88-1E19A5A4679B}
|
{FFB09376-595B-6F93-36F0-70CAE90AFECB} = {287CFF34-BBDB-4BC4-AF88-1E19A5A4679B}
|
||||||
|
{E75E1F10-BC6F-4EB1-BA75-D897C45AEA0D} = {DD5BD056-4AAE-43EF-BBD2-0B569B8DA84F}
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
SolutionGuid = {E01CBF68-2E20-425F-9EDB-E0A6510CA92F}
|
SolutionGuid = {E01CBF68-2E20-425F-9EDB-E0A6510CA92F}
|
||||||
|
|||||||
1
test/Server.IntegrationTest/Properties/AssemblyInfo.cs
Normal file
1
test/Server.IntegrationTest/Properties/AssemblyInfo.cs
Normal file
@@ -0,0 +1 @@
|
|||||||
|
[assembly: CaptureTrace]
|
||||||
23
test/Server.IntegrationTest/Server.IntegrationTest.csproj
Normal file
23
test/Server.IntegrationTest/Server.IntegrationTest.csproj
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Using Include="Xunit" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.11.0" />
|
||||||
|
<PackageReference Include="xunit.v3" Version="3.0.1" />
|
||||||
|
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.4" />
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="8.0.10" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\util\Server\Server.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
45
test/Server.IntegrationTest/Server.cs
Normal file
45
test/Server.IntegrationTest/Server.cs
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
using Microsoft.AspNetCore.Hosting;
|
||||||
|
using Microsoft.AspNetCore.Mvc.Testing;
|
||||||
|
using Microsoft.AspNetCore.TestHost;
|
||||||
|
|
||||||
|
namespace Bit.Server.IntegrationTest;
|
||||||
|
|
||||||
|
public class Server : WebApplicationFactory<Program>
|
||||||
|
{
|
||||||
|
public string? ContentRoot { get; set; }
|
||||||
|
public string? WebRoot { get; set; }
|
||||||
|
public bool ServeUnknown { get; set; }
|
||||||
|
public bool? WebVault { get; set; }
|
||||||
|
public string? AppIdLocation { get; set; }
|
||||||
|
|
||||||
|
protected override IWebHostBuilder? CreateWebHostBuilder()
|
||||||
|
{
|
||||||
|
var args = new List<string>
|
||||||
|
{
|
||||||
|
"/contentRoot",
|
||||||
|
ContentRoot ?? "",
|
||||||
|
"/webRoot",
|
||||||
|
WebRoot ?? "",
|
||||||
|
"/serveUnknown",
|
||||||
|
ServeUnknown.ToString().ToLowerInvariant(),
|
||||||
|
};
|
||||||
|
|
||||||
|
if (WebVault.HasValue)
|
||||||
|
{
|
||||||
|
args.Add("/webVault");
|
||||||
|
args.Add(WebVault.Value.ToString().ToLowerInvariant());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(AppIdLocation))
|
||||||
|
{
|
||||||
|
args.Add("/appIdLocation");
|
||||||
|
args.Add(AppIdLocation);
|
||||||
|
}
|
||||||
|
|
||||||
|
var builder = WebHostBuilderFactory.CreateFromTypesAssemblyEntryPoint<Program>([.. args])
|
||||||
|
?? throw new InvalidProgramException("Could not create builder from assembly.");
|
||||||
|
|
||||||
|
builder.UseSetting("TEST_CONTENTROOT_SERVER", ContentRoot);
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
}
|
||||||
102
test/Server.IntegrationTest/ServerTests.cs
Normal file
102
test/Server.IntegrationTest/ServerTests.cs
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
using System.Net;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
|
namespace Bit.Server.IntegrationTest;
|
||||||
|
|
||||||
|
public class ServerTests
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public async Task AttachmentsStyleUse()
|
||||||
|
{
|
||||||
|
using var tempDir = new TempDir();
|
||||||
|
|
||||||
|
await tempDir.WriteAsync("my-file.txt", "Hello!");
|
||||||
|
|
||||||
|
using var server = new Server
|
||||||
|
{
|
||||||
|
ContentRoot = tempDir.Info.FullName,
|
||||||
|
WebRoot = ".",
|
||||||
|
ServeUnknown = true,
|
||||||
|
};
|
||||||
|
|
||||||
|
var client = server.CreateClient();
|
||||||
|
|
||||||
|
var response = await client.GetAsync("/my-file.txt", TestContext.Current.CancellationToken);
|
||||||
|
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||||
|
Assert.Equal("Hello!", await response.Content.ReadAsStringAsync(TestContext.Current.CancellationToken));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task WebVaultStyleUse()
|
||||||
|
{
|
||||||
|
using var tempDir = new TempDir();
|
||||||
|
|
||||||
|
await tempDir.WriteAsync("index.html", "<html></html>");
|
||||||
|
await tempDir.WriteAsync(Path.Join("app", "file.js"), "AppStuff");
|
||||||
|
await tempDir.WriteAsync(Path.Join("locales", "file.json"), "LocalesStuff");
|
||||||
|
await tempDir.WriteAsync(Path.Join("fonts", "file.ttf"), "FontsStuff");
|
||||||
|
await tempDir.WriteAsync(Path.Join("connectors", "file.js"), "ConnectorsStuff");
|
||||||
|
await tempDir.WriteAsync(Path.Join("scripts", "file.js"), "ScriptsStuff");
|
||||||
|
await tempDir.WriteAsync(Path.Join("images", "file.avif"), "ImagesStuff");
|
||||||
|
await tempDir.WriteAsync(Path.Join("test", "file.json"), "{}");
|
||||||
|
|
||||||
|
using var server = new Server
|
||||||
|
{
|
||||||
|
ContentRoot = tempDir.Info.FullName,
|
||||||
|
WebRoot = ".",
|
||||||
|
ServeUnknown = false,
|
||||||
|
WebVault = true,
|
||||||
|
AppIdLocation = Path.Join(tempDir.Info.FullName, "test", "file.json"),
|
||||||
|
};
|
||||||
|
|
||||||
|
var client = server.CreateClient();
|
||||||
|
|
||||||
|
// Going to root should return the default file
|
||||||
|
var response = await client.GetAsync("", TestContext.Current.CancellationToken);
|
||||||
|
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||||
|
Assert.Equal("<html></html>", await response.Content.ReadAsStringAsync(TestContext.Current.CancellationToken));
|
||||||
|
// No caching on the default document
|
||||||
|
Assert.Null(response.Headers.CacheControl?.MaxAge);
|
||||||
|
|
||||||
|
await ExpectMaxAgeAsync("app/file.js", TimeSpan.FromDays(14));
|
||||||
|
await ExpectMaxAgeAsync("locales/file.json", TimeSpan.FromDays(14));
|
||||||
|
await ExpectMaxAgeAsync("fonts/file.ttf", TimeSpan.FromDays(14));
|
||||||
|
await ExpectMaxAgeAsync("connectors/file.js", TimeSpan.FromDays(14));
|
||||||
|
await ExpectMaxAgeAsync("scripts/file.js", TimeSpan.FromDays(14));
|
||||||
|
await ExpectMaxAgeAsync("images/file.avif", TimeSpan.FromDays(7));
|
||||||
|
|
||||||
|
response = await client.GetAsync("app-id.json", TestContext.Current.CancellationToken);
|
||||||
|
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||||
|
Assert.Equal("application/json", response.Content.Headers.ContentType?.MediaType);
|
||||||
|
|
||||||
|
async Task ExpectMaxAgeAsync(string path, TimeSpan maxAge)
|
||||||
|
{
|
||||||
|
response = await client.GetAsync(path);
|
||||||
|
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||||
|
Assert.NotNull(response.Headers.CacheControl);
|
||||||
|
Assert.Equal(maxAge, response.Headers.CacheControl.MaxAge);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class TempDir([CallerMemberName] string test = null!) : IDisposable
|
||||||
|
{
|
||||||
|
public DirectoryInfo Info { get; } = Directory.CreateTempSubdirectory(test);
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
Info.Delete(recursive: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task WriteAsync(string fileName, string content)
|
||||||
|
{
|
||||||
|
var fullPath = Path.Join(Info.FullName, fileName);
|
||||||
|
var directory = Path.GetDirectoryName(fullPath);
|
||||||
|
if (directory != null)
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory(directory);
|
||||||
|
}
|
||||||
|
|
||||||
|
await File.WriteAllTextAsync(fullPath, content, TestContext.Current.CancellationToken);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,6 +6,13 @@ namespace Bit.Server;
|
|||||||
public class Program
|
public class Program
|
||||||
{
|
{
|
||||||
public static void Main(string[] args)
|
public static void Main(string[] args)
|
||||||
|
{
|
||||||
|
var builder = CreateWebHostBuilder(args);
|
||||||
|
var host = builder.Build();
|
||||||
|
host.Run();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IWebHostBuilder CreateWebHostBuilder(string[] args)
|
||||||
{
|
{
|
||||||
var config = new ConfigurationBuilder()
|
var config = new ConfigurationBuilder()
|
||||||
.AddCommandLine(args)
|
.AddCommandLine(args)
|
||||||
@@ -37,7 +44,6 @@ public class Program
|
|||||||
builder.UseWebRoot(webRoot);
|
builder.UseWebRoot(webRoot);
|
||||||
}
|
}
|
||||||
|
|
||||||
var host = builder.Build();
|
return builder;
|
||||||
host.Run();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user