LocalDb adoption Phase 1 + 2: consolidate the site database, delete the bespoke replicators #23
@@ -1,7 +1,9 @@
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using ZB.MOM.WW.LocalDb;
|
||||
using ZB.MOM.WW.ScadaBridge.SiteEventLogging;
|
||||
using ZB.MOM.WW.ScadaBridge.SiteRuntime.Persistence;
|
||||
using ZB.MOM.WW.ScadaBridge.SiteRuntime.Tracking;
|
||||
using ZB.MOM.WW.ScadaBridge.StoreAndForward;
|
||||
|
||||
namespace ZB.MOM.WW.ScadaBridge.Host;
|
||||
|
||||
@@ -44,6 +46,12 @@ public static class SiteLocalDbSetup
|
||||
{
|
||||
OperationTrackingSchema.Apply(connection);
|
||||
SiteEventLogSchema.Apply(connection);
|
||||
|
||||
// Phase 2: the site's configuration tables and the store-and-forward buffer
|
||||
// now live in this file too. Created here, deliberately NOT registered — see
|
||||
// below.
|
||||
SiteStorageSchema.Apply(connection);
|
||||
StoreAndForwardSchema.Apply(connection);
|
||||
}
|
||||
|
||||
// Both tables qualify: each has an explicit primary key (RegisterReplicated
|
||||
@@ -52,6 +60,13 @@ public static class SiteLocalDbSetup
|
||||
db.RegisterReplicated("OperationTracking");
|
||||
db.RegisterReplicated("site_events");
|
||||
|
||||
// The Phase 2 tables are created above but NOT registered yet. The bespoke
|
||||
// SiteReplicationActor / StoreAndForward ReplicationService still own replicating
|
||||
// them until the Task 14 cutover deletes both and registers these in one commit.
|
||||
// Registering them now would mean two independent replicators writing the same
|
||||
// rows — harmless in principle (both upsert) but it would mask a defect in either
|
||||
// one, which is exactly what the cutover needs to be able to see.
|
||||
|
||||
// AFTER registration, so migrated rows enter the oplog and reach the peer like
|
||||
// any other write. Before it, they would be invisible to replication forever.
|
||||
SiteLocalDbLegacyMigrator.Migrate(db, config);
|
||||
|
||||
@@ -215,6 +215,62 @@ public class SiteLocalDbWiringTests : IDisposable
|
||||
Assert.Contains(LocalDbMetrics.MeterName, SiteServiceRegistration.ObservedMeters);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Site_LocalDb_CreatesThePhase2Tables_InTheConsolidatedFile()
|
||||
{
|
||||
// Phase 2 (Task 7). The nine configuration tables and the store-and-forward buffer
|
||||
// now live in the consolidated file rather than in scadabridge.db and
|
||||
// store-and-forward.db. Asserting through the REAL composition root is what proves
|
||||
// OnReady applies both schemas — the stores themselves also call Apply, so a test
|
||||
// that went through a store would pass even if OnReady never touched them.
|
||||
var db = _host.Services.GetRequiredService<ILocalDb>();
|
||||
|
||||
var tables = TableNames(db);
|
||||
|
||||
// One from each Phase 1 schema, then every Phase 2 table.
|
||||
Assert.Contains("OperationTracking", tables);
|
||||
Assert.Contains("site_events", tables);
|
||||
Assert.Contains("sf_messages", tables);
|
||||
foreach (var table in new[]
|
||||
{
|
||||
"deployed_configurations", "static_attribute_overrides", "shared_scripts",
|
||||
"external_systems", "database_connections", "notification_lists",
|
||||
"data_connection_definitions", "smtp_configurations", "native_alarm_state",
|
||||
})
|
||||
{
|
||||
Assert.Contains(table, tables);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Site_LocalDb_DoesNotYetRegisterThePhase2Tables()
|
||||
{
|
||||
// The "not yet" is the assertion that matters, and it is why this is an EXACTLY
|
||||
// check rather than a Contains. Until the Task 14 cutover, the bespoke
|
||||
// SiteReplicationActor and the StoreAndForward ReplicationService still own these
|
||||
// tables. Registering them early would run two replicators over the same rows and
|
||||
// hide a defect in either one behind the other's writes.
|
||||
//
|
||||
// When Task 14 lands, this test does not get deleted — it gets inverted.
|
||||
var db = _host.Services.GetRequiredService<ILocalDb>();
|
||||
|
||||
Assert.Equal(
|
||||
["OperationTracking", "site_events"],
|
||||
db.ReplicatedTables.Keys.OrderBy(k => k, StringComparer.Ordinal).ToArray());
|
||||
}
|
||||
|
||||
private static HashSet<string> TableNames(ILocalDb db)
|
||||
{
|
||||
using var connection = db.CreateConnection();
|
||||
using var cmd = connection.CreateCommand();
|
||||
cmd.CommandText = "SELECT name FROM sqlite_master WHERE type = 'table'";
|
||||
using var reader = cmd.ExecuteReader();
|
||||
|
||||
var names = new HashSet<string>(StringComparer.Ordinal);
|
||||
while (reader.Read()) names.Add(reader.GetString(0));
|
||||
return names;
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Site_LocalDb_CreatesTheConfiguredFile()
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user