PrivaPubHost is a WebApplicationFactory<Program> on the fixture's database, configured only through UseSetting (visible before Build, unlike ConfigureAppConfiguration). It drops the background workers so tests run the jobs they queue (Jobs.Run, RunInbox), gives each client its own address for the rate limiter, and has a SecureMode variant. Accounts signs up roots, adds personas and gets Mastodon tokens through the real /oauth code flow. RemoteActor signs HttpRequestMessages for the real /peasants routes; Peer records bodies and headers and serves files with ranges and text pages. Program registers the Guid serializer with TryRegisterSerializer, so a second host in one process starts; the fixture runs the migrations in production's order before any test. HostBootTests: the host shares the fixture database; the harness handles exactly the activities the server registers; every job kind has one handler; every controller and page model can be made; the service graph validates with ValidateOnBuild and ValidateScopes; Swagger is 404 outside Development; a persona's token never names its root; a signed DM through the real /mouth route is queued, processed and stored. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ELjqpznMFMNrJoJUj6K5p2
82 lines
3.1 KiB
C#
82 lines
3.1 KiB
C#
using MongoDB.Bson;
|
|
using MongoDB.Bson.Serialization;
|
|
using MongoDB.Bson.Serialization.Serializers;
|
|
using MongoDB.Driver;
|
|
using MongoDB.Entities;
|
|
|
|
using PrivaPub.Infrastructure.Data;
|
|
|
|
[assembly: AssemblyFixture(typeof(PrivaPub.Tests.Support.MongoFixture))]
|
|
|
|
namespace PrivaPub.Tests.Support
|
|
{
|
|
public sealed class MongoFixture : IAsyncLifetime
|
|
{
|
|
public const string Skip = "set PRIVAPUB_TEST_MONGOD=1 (and optionally PRIVAPUB_TEST_MONGO) to run the tests that need a mongod";
|
|
const int ProductionPort = 27022;
|
|
const int DefaultPort = 27017;
|
|
|
|
public static bool Enabled => Environment.GetEnvironmentVariable("PRIVAPUB_TEST_MONGOD") == "1";
|
|
static bool Required => Environment.GetEnvironmentVariable("PRIVAPUB_TEST_REQUIRE_MONGOD") == "1";
|
|
static bool InCi => !string.IsNullOrEmpty(Environment.GetEnvironmentVariable("CI")) || !string.IsNullOrEmpty(Environment.GetEnvironmentVariable("GITEA_ACTIONS"));
|
|
|
|
public static string Connection { get; } = Environment.GetEnvironmentVariable("PRIVAPUB_TEST_MONGO") ?? $"mongodb://127.0.0.1:{DefaultPort}";
|
|
public static string Database { get; } = $"PrivaPubTests_{Guid.NewGuid():N}";
|
|
|
|
public async ValueTask InitializeAsync()
|
|
{
|
|
if (Required && !Enabled)
|
|
throw new InvalidOperationException("PRIVAPUB_TEST_REQUIRE_MONGOD=1 but PRIVAPUB_TEST_MONGOD is not 1: the integration tests would be skipped");
|
|
if (!Enabled)
|
|
return;
|
|
var settings = MongoClientSettings.FromConnectionString(Connection);
|
|
Refuse(settings);
|
|
try
|
|
{
|
|
BsonSerializer.RegisterSerializer(new GuidSerializer(GuidRepresentation.Standard));
|
|
}
|
|
catch (BsonSerializationException)
|
|
{
|
|
}
|
|
await DB.InitAsync(Database, settings);
|
|
await RefuseProductionData();
|
|
EntityMaps.Warm();
|
|
await DB.Default.MigrateAsync<Program>();
|
|
await Indexes.Create();
|
|
}
|
|
|
|
public async ValueTask DisposeAsync()
|
|
{
|
|
if (Enabled)
|
|
await DB.Default.Database().Client.DropDatabaseAsync(Database);
|
|
}
|
|
|
|
static void Refuse(MongoClientSettings settings)
|
|
{
|
|
var ports = settings.Servers.Select(s => s.Port).ToList();
|
|
if (ports.Contains(ProductionPort))
|
|
throw new InvalidOperationException($"the tests never run against port {ProductionPort}: that is production's mongod");
|
|
if (InCi && (Environment.GetEnvironmentVariable("PRIVAPUB_TEST_MONGO") == default || ports.Contains(DefaultPort)))
|
|
throw new InvalidOperationException("in CI the tests run only against a throwaway mongod: use tools/ci/with-test-mongod.sh");
|
|
}
|
|
|
|
static async Task RefuseProductionData()
|
|
{
|
|
BsonDocument options;
|
|
try
|
|
{
|
|
options = await DB.Default.Database().Client.GetDatabase("admin").RunCommandAsync<BsonDocument>(new BsonDocument("getCmdLineOpts", 1));
|
|
}
|
|
catch (MongoCommandException)
|
|
{
|
|
return;
|
|
}
|
|
var dbPath = options.GetValue("parsed", new BsonDocument()).AsBsonDocument
|
|
.GetValue("storage", new BsonDocument()).AsBsonDocument
|
|
.GetValue("dbPath", BsonNull.Value);
|
|
if (dbPath.IsString && dbPath.AsString.StartsWith("/var/lib/privapub", StringComparison.Ordinal))
|
|
throw new InvalidOperationException($"the mongod at {Connection} keeps its data in {dbPath.AsString}: that is production's");
|
|
}
|
|
}
|
|
}
|