87 lines
3.7 KiB
C#
87 lines
3.7 KiB
C#
using Microsoft.EntityFrameworkCore;
|
|
using Testcontainers.PostgreSql;
|
|
using w4c_workflows.Data;
|
|
using Xunit;
|
|
|
|
namespace w4c_workflows.Tests;
|
|
|
|
[CollectionDefinition("WorkflowsPostgres")]
|
|
public class WorkflowsPostgresCollection : ICollectionFixture<WorkflowsPostgresFixture>
|
|
{
|
|
}
|
|
|
|
/// <summary>
|
|
/// One Postgres 17 container per collection; applies the EF Core migration once
|
|
/// and hands out fresh (scoped-like) DbContext instances per test.
|
|
/// </summary>
|
|
public sealed class WorkflowsPostgresFixture : IAsyncLifetime
|
|
{
|
|
private PostgreSqlContainer? _container;
|
|
private string _connectionString = "";
|
|
|
|
public async Task InitializeAsync()
|
|
{
|
|
_container = new PostgreSqlBuilder()
|
|
.WithImage("postgres:17-alpine")
|
|
.WithDatabase("w4c_workflows_test")
|
|
.WithUsername("w4c")
|
|
.WithPassword("w4c_test_pw")
|
|
.Build();
|
|
await _container.StartAsync();
|
|
|
|
_connectionString = _container.GetConnectionString() + ";Timezone=UTC";
|
|
|
|
await using var context = CreateContext();
|
|
await context.Database.MigrateAsync();
|
|
|
|
// Mirror the production startup ordering (Program.cs): the add-on columns for
|
|
// W7 (ArchivedAt) and S8 (Server) are applied by idempotent raw SQL AFTER the
|
|
// EF migrations — no new EF migration is introduced (the project's house style).
|
|
await context.Database.ExecuteSqlRawAsync(
|
|
"ALTER TABLE workflows.\"Tasks\" ADD COLUMN IF NOT EXISTS \"ArchivedAt\" timestamptz NULL;");
|
|
await context.Database.ExecuteSqlRawAsync(
|
|
"ALTER TABLE workflows.\"Tasks\" ADD COLUMN IF NOT EXISTS \"Server\" text NULL;");
|
|
// Workflow repo scoping: the repo name column + per-tenant repo setting table.
|
|
await context.Database.ExecuteSqlRawAsync(
|
|
"ALTER TABLE workflows.\"Workflows\" ADD COLUMN IF NOT EXISTS \"Repo\" text NOT NULL DEFAULT 'workflows';");
|
|
await context.Database.ExecuteSqlRawAsync(
|
|
"CREATE TABLE IF NOT EXISTS workflows.\"WorkflowRepos\" (" +
|
|
"\"TenantId\" text NOT NULL, \"RepoName\" text NOT NULL, \"UpdatedAt\" timestamptz NULL, " +
|
|
"CONSTRAINT \"PK_WorkflowRepos\" PRIMARY KEY (\"TenantId\"));");
|
|
// Workflow runtime registry (mirrors Program.cs startup ordering).
|
|
await context.Database.ExecuteSqlRawAsync(
|
|
"CREATE TABLE IF NOT EXISTS workflows.\"WorkflowRuntimes\" (" +
|
|
"\"Id\" uuid NOT NULL, " +
|
|
"\"TenantId\" text NOT NULL, " +
|
|
"\"Label\" text NOT NULL, " +
|
|
"\"Kind\" text NOT NULL, " +
|
|
"\"Endpoint\" text NULL, " +
|
|
"\"ApiKeyHash\" text NULL, " +
|
|
"\"SecretHash\" text NULL, " +
|
|
"\"Status\" text NOT NULL DEFAULT 'unknown', " +
|
|
"\"LastSeenAt\" timestamptz NULL, " +
|
|
"\"LastError\" text NULL, " +
|
|
"\"InfoJson\" jsonb NULL, " +
|
|
"\"IsDefault\" boolean NOT NULL DEFAULT FALSE, " +
|
|
"\"CreatedAt\" timestamptz NOT NULL, " +
|
|
"\"UpdatedAt\" timestamptz NOT NULL, " +
|
|
"CONSTRAINT \"PK_WorkflowRuntimes\" PRIMARY KEY (\"Id\"));");
|
|
await context.Database.ExecuteSqlRawAsync(
|
|
"CREATE INDEX IF NOT EXISTS \"IX_WorkflowRuntimes_TenantId\" ON workflows.\"WorkflowRuntimes\" (\"TenantId\");");
|
|
}
|
|
|
|
public async Task DisposeAsync()
|
|
{
|
|
if (_container is not null)
|
|
await _container.DisposeAsync();
|
|
}
|
|
|
|
public WorkflowsDbContext CreateContext()
|
|
{
|
|
var options = new DbContextOptionsBuilder<WorkflowsDbContext>()
|
|
.UseNpgsql(_connectionString)
|
|
.Options;
|
|
return new WorkflowsDbContext(options);
|
|
}
|
|
}
|