test(localdb): convergence polish — provable LWW race arbitration, collection serialization, dead-letter diagnostics
Claude-Session: https://claude.ai/code/session_01BL2Vu1ESDQ9SCN4gVKkdts
This commit is contained in:
@@ -15,6 +15,15 @@ using ZB.MOM.WW.LocalDb.Replication.Internal;
|
||||
|
||||
namespace ZB.MOM.WW.LocalDb.Tests.Convergence;
|
||||
|
||||
/// <summary>
|
||||
/// Serializes the convergence test classes against EACH OTHER (no shared class fixture — each test
|
||||
/// still builds its own <see cref="ConvergenceFixture"/>): both classes stand up real Kestrel
|
||||
/// listeners plus four SQLite files per test, and running the two heavy classes concurrently under
|
||||
/// CI contention is a flakiness risk. The rest of the assembly still parallelizes normally.
|
||||
/// </summary>
|
||||
[CollectionDefinition("Convergence")]
|
||||
public sealed class ConvergenceCollection;
|
||||
|
||||
/// <summary>
|
||||
/// Two FULL replication stacks over a REAL loopback gRPC transport (Kestrel h2c on 127.0.0.1),
|
||||
/// proving end-to-end bidirectional convergence. Node A is the initiator (client:
|
||||
@@ -183,9 +192,25 @@ public sealed class ConvergenceFixture : IAsyncDisposable
|
||||
sb.AppendLine("--- B.orders ---").AppendLine(await DumpOrdersAsync(_dbB));
|
||||
sb.AppendLine("--- A.row_version ---").AppendLine(await DumpRowVersionAsync(_dbA));
|
||||
sb.AppendLine("--- B.row_version ---").AppendLine(await DumpRowVersionAsync(_dbB));
|
||||
sb.AppendLine("--- A.dead_letter ---").AppendLine(await DumpDeadLettersAsync(_dbA));
|
||||
sb.AppendLine("--- B.dead_letter ---").AppendLine(await DumpDeadLettersAsync(_dbB));
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
// Dead-lettered entries are a prime suspect when convergence stalls (a poison row silently
|
||||
// diverts instead of applying), so the timeout dump surfaces the count + a small sample.
|
||||
private static async Task<string> DumpDeadLettersAsync(ILocalDb db)
|
||||
{
|
||||
var count = (await db.QueryAsync(
|
||||
"SELECT COUNT(*) FROM __localdb_dead_letter", static r => r.GetInt64(0)))[0];
|
||||
if (count == 0)
|
||||
return "count: 0";
|
||||
var sample = await db.QueryAsync(
|
||||
"SELECT table_name, pk_json, hlc, node_id, error FROM __localdb_dead_letter ORDER BY id LIMIT 5",
|
||||
static r => $"{r.GetString(0)}|{r.GetString(1)}|{r.GetInt64(2)}|{r.GetString(3)}|{r.GetString(4)}");
|
||||
return $"count: {count} (first {sample.Count})\n" + string.Join("\n", sample);
|
||||
}
|
||||
|
||||
// ---- test helpers -----------------------------------------------------------------------
|
||||
|
||||
/// <summary>
|
||||
|
||||
Reference in New Issue
Block a user