Add integration tests for migration categories and execution
Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled
Policy Lint & Smoke / policy-lint (push) Has been cancelled
Concelier Attestation Tests / attestation-tests (push) Has been cancelled
AOC Guard CI / aoc-guard (push) Has been cancelled
AOC Guard CI / aoc-verify (push) Has been cancelled
Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled
Policy Lint & Smoke / policy-lint (push) Has been cancelled
Concelier Attestation Tests / attestation-tests (push) Has been cancelled
AOC Guard CI / aoc-guard (push) Has been cancelled
AOC Guard CI / aoc-verify (push) Has been cancelled
- Implemented MigrationCategoryTests to validate migration categorization for startup, release, seed, and data migrations. - Added tests for edge cases, including null, empty, and whitespace migration names. - Created StartupMigrationHostTests to verify the behavior of the migration host with real PostgreSQL instances using Testcontainers. - Included tests for migration execution, schema creation, and handling of pending release migrations. - Added SQL migration files for testing: creating a test table, adding a column, a release migration, and seeding data.
This commit is contained in:
@@ -0,0 +1,72 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
using MongoDB.Driver;
|
||||
using StellaOps.Concelier.Models;
|
||||
using StellaOps.Concelier.Storage.Mongo.Advisories;
|
||||
using StellaOps.Concelier.Storage.Postgres.Advisories;
|
||||
|
||||
namespace StellaOps.Concelier.WebService.DualWrite;
|
||||
|
||||
/// <summary>
|
||||
/// Dual-write advisory store that writes to both MongoDB and PostgreSQL simultaneously.
|
||||
/// Used during migration to verify parity between backends.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// MongoDB is the primary store; PostgreSQL writes are best-effort with error logging.
|
||||
/// Read operations are always served from MongoDB.
|
||||
/// </remarks>
|
||||
public sealed class DualWriteAdvisoryStore : IAdvisoryStore
|
||||
{
|
||||
private readonly AdvisoryStore _mongoStore;
|
||||
private readonly IPostgresAdvisoryStore _postgresStore;
|
||||
private readonly ILogger<DualWriteAdvisoryStore> _logger;
|
||||
|
||||
public DualWriteAdvisoryStore(
|
||||
AdvisoryStore mongoStore,
|
||||
IPostgresAdvisoryStore postgresStore,
|
||||
ILogger<DualWriteAdvisoryStore> logger)
|
||||
{
|
||||
_mongoStore = mongoStore ?? throw new ArgumentNullException(nameof(mongoStore));
|
||||
_postgresStore = postgresStore ?? throw new ArgumentNullException(nameof(postgresStore));
|
||||
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task UpsertAsync(Advisory advisory, CancellationToken cancellationToken, IClientSessionHandle? session = null)
|
||||
{
|
||||
// Write to MongoDB (primary)
|
||||
await _mongoStore.UpsertAsync(advisory, cancellationToken, session).ConfigureAwait(false);
|
||||
|
||||
// Write to PostgreSQL (secondary, best-effort)
|
||||
try
|
||||
{
|
||||
await _postgresStore.UpsertAsync(advisory, sourceId: null, cancellationToken).ConfigureAwait(false);
|
||||
_logger.LogDebug("Dual-write success for advisory {AdvisoryKey}", advisory.AdvisoryKey);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// Log but don't fail - MongoDB is primary during migration
|
||||
_logger.LogWarning(ex, "Dual-write to PostgreSQL failed for advisory {AdvisoryKey}. MongoDB write succeeded.", advisory.AdvisoryKey);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<Advisory?> FindAsync(string advisoryKey, CancellationToken cancellationToken, IClientSessionHandle? session = null)
|
||||
{
|
||||
// Always read from MongoDB during dual-write mode
|
||||
return _mongoStore.FindAsync(advisoryKey, cancellationToken, session);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<IReadOnlyList<Advisory>> GetRecentAsync(int limit, CancellationToken cancellationToken, IClientSessionHandle? session = null)
|
||||
{
|
||||
// Always read from MongoDB during dual-write mode
|
||||
return _mongoStore.GetRecentAsync(limit, cancellationToken, session);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public IAsyncEnumerable<Advisory> StreamAsync(CancellationToken cancellationToken, IClientSessionHandle? session = null)
|
||||
{
|
||||
// Always read from MongoDB during dual-write mode
|
||||
return _mongoStore.StreamAsync(cancellationToken, session);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user