88 lines
3.1 KiB
C#
88 lines
3.1 KiB
C#
using Microsoft.EntityFrameworkCore;
|
|
using Microsoft.EntityFrameworkCore.Diagnostics;
|
|
using Npgsql;
|
|
using Xunit;
|
|
|
|
namespace BuildFlow.Workflow.Tests.Reliability;
|
|
|
|
/// <summary>
|
|
/// 为工作流可靠性测试创建并销毁独立 PostgreSQL 数据库。
|
|
/// </summary>
|
|
public sealed class PostgresWorkflowFixture : IAsyncLifetime
|
|
{
|
|
private const string DefaultConnection =
|
|
"Host=127.0.0.1;Port=55432;Username=buildflow;Password=buildflow;Database=postgres";
|
|
|
|
private string _databaseName = default!;
|
|
private string _adminConnectionString = default!;
|
|
|
|
/// <summary>当前测试数据库连接串。</summary>
|
|
public string ConnectionString { get; private set; } = default!;
|
|
|
|
public async Task InitializeAsync()
|
|
{
|
|
var configured = Environment.GetEnvironmentVariable("BUILDFLOW_WORKFLOW_TEST_CONNECTION")
|
|
?? DefaultConnection;
|
|
var adminBuilder = new NpgsqlConnectionStringBuilder(configured)
|
|
{
|
|
Database = "postgres",
|
|
Pooling = false,
|
|
};
|
|
_adminConnectionString = adminBuilder.ConnectionString;
|
|
_databaseName = $"workflow_reliability_{Guid.NewGuid():N}";
|
|
|
|
await using (var connection = new NpgsqlConnection(_adminConnectionString))
|
|
{
|
|
await connection.OpenAsync();
|
|
await using var command = connection.CreateCommand();
|
|
command.CommandText = $"CREATE DATABASE \"{_databaseName}\"";
|
|
await command.ExecuteNonQueryAsync();
|
|
}
|
|
|
|
var databaseBuilder = new NpgsqlConnectionStringBuilder(configured)
|
|
{
|
|
Database = _databaseName,
|
|
Pooling = true,
|
|
};
|
|
ConnectionString = databaseBuilder.ConnectionString;
|
|
|
|
await using var db = CreateDbContext();
|
|
await db.Database.EnsureCreatedAsync();
|
|
}
|
|
|
|
/// <summary>创建指向独立测试数据库的 WorkflowDbContext。</summary>
|
|
public WorkflowDbContext CreateDbContext(params IInterceptor[] interceptors)
|
|
{
|
|
var optionsBuilder = new DbContextOptionsBuilder<WorkflowDbContext>()
|
|
.UseNpgsql(ConnectionString)
|
|
.UseSnakeCaseNamingConvention();
|
|
if (interceptors.Length > 0)
|
|
{
|
|
optionsBuilder.AddInterceptors(interceptors);
|
|
}
|
|
|
|
var db = new WorkflowDbContext(optionsBuilder.Options);
|
|
db.SavingChanges += AuditStub.OnSave;
|
|
return db;
|
|
}
|
|
|
|
public async Task DisposeAsync()
|
|
{
|
|
NpgsqlConnection.ClearAllPools();
|
|
await using var connection = new NpgsqlConnection(_adminConnectionString);
|
|
await connection.OpenAsync();
|
|
|
|
await using (var terminate = connection.CreateCommand())
|
|
{
|
|
terminate.CommandText =
|
|
"SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname = @database AND pid <> pg_backend_pid()";
|
|
terminate.Parameters.AddWithValue("database", _databaseName);
|
|
await terminate.ExecuteNonQueryAsync();
|
|
}
|
|
|
|
await using var drop = connection.CreateCommand();
|
|
drop.CommandText = $"DROP DATABASE IF EXISTS \"{_databaseName}\"";
|
|
await drop.ExecuteNonQueryAsync();
|
|
}
|
|
}
|