Files
ScadaBridge/tests/ZB.MOM.WW.ScadaBridge.SiteRuntime.Tests/Persistence/SiteStorageSchemaTests.cs
T
Joseph Doherty 513fa1aa16 docs(tests): fix CommentChecker findings across tests/ — 13,392 → 0 (repo-wide scan clean)
Comment/XML-doc changes only:
- add summaries to ~10k test methods, fixtures, fakes and helpers
  (+ <param> on theories, <returns> on async Task methods,
  <inheritdoc/> on interface implementations the checker can resolve)
- strip ~2.6k project-tracking references (WP*, P*-*, row-NN, Task N,
  #NN, Component-0NN) from comments, keeping the explanatory text;
  reword false positives in comments only
- real docs on fakes implementing BCL/library interfaces
  (IDisposable, ILogger, IOptionsMonitor, IAsyncLifetime)
- reword the last 5 src/ false positives (CWE-1236, failures-1,
  year-0001, M365)

Only non-comment edits: four one-line nested classes split across lines
so members can carry docs. Build 0 errors / 0 warnings.
2026-10-07 15:05:49 -04:00

131 lines
5.8 KiB
C#

using Microsoft.Data.Sqlite;
using ZB.MOM.WW.ScadaBridge.SiteRuntime.Persistence;
namespace ZB.MOM.WW.ScadaBridge.SiteRuntime.Tests.Persistence;
/// <summary>
/// Pins <see cref="SiteStorageSchema"/> as the single owner of the site config DDL.
/// The Host applies this to a LocalDb-managed connection before
/// <c>RegisterReplicated</c> installs the capture triggers, so the shape it produces
/// is the shape that replicates.
/// </summary>
public class SiteStorageSchemaTests
{
/// <summary>Verifies that applying the schema is idempotent and creates every table.</summary>
[Fact]
public void Apply_IsIdempotent_AndCreatesEveryTable()
{
var path = Path.Combine(Path.GetTempPath(), $"site-schema-{Guid.NewGuid():N}.db");
try
{
using var connection = new SqliteConnection($"Data Source={path}");
connection.Open();
SiteStorageSchema.Apply(connection);
SiteStorageSchema.Apply(connection); // second run must not throw
// Every table is named explicitly on purpose — a loop asserting "12 tables"
// would still pass if one were renamed.
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",
"deployed_secrets", "mirrored_secrets", "secret_mirror_status",
})
{
Assert.True(TableExists(connection, table), $"missing table: {table}");
}
}
finally
{
SqliteConnection.ClearAllPools();
File.Delete(path);
}
}
/// <summary>
/// The migration columns exist to upgrade a database created by an older build in
/// place. Asserting only against a freshly-created table would pass even if every
/// <c>ALTER</c> were deleted, because <c>CREATE TABLE</c> already lists them — so
/// this starts from the pre-migration shape and proves the migration path runs.
/// </summary>
[Fact]
public void Apply_AddsMigrationColumns_ToALegacyDatabase()
{
var path = Path.Combine(Path.GetTempPath(), $"site-schema-legacy-{Guid.NewGuid():N}.db");
try
{
using var connection = new SqliteConnection($"Data Source={path}");
connection.Open();
// The shapes as they existed before backup_configuration /
// failover_retry_count / metadata_json / timeout_seconds were added.
using (var legacy = connection.CreateCommand())
{
legacy.CommandText = """
CREATE TABLE data_connection_definitions (
name TEXT PRIMARY KEY,
protocol TEXT NOT NULL,
configuration TEXT,
updated_at TEXT NOT NULL
);
CREATE TABLE native_alarm_state (
instance_unique_name TEXT NOT NULL,
source_canonical_name TEXT NOT NULL,
source_reference TEXT NOT NULL,
condition_json TEXT NOT NULL,
last_transition_at TEXT NOT NULL,
PRIMARY KEY (instance_unique_name, source_canonical_name, source_reference)
);
CREATE TABLE external_systems (
name TEXT PRIMARY KEY,
endpoint_url TEXT NOT NULL,
auth_type TEXT NOT NULL,
auth_configuration TEXT,
method_definitions TEXT,
updated_at TEXT NOT NULL
);
INSERT INTO external_systems (name, endpoint_url, auth_type, updated_at)
VALUES ('legacy-system', 'http://example.invalid', 'None', '2026-01-01T00:00:00Z');
""";
legacy.ExecuteNonQuery();
}
SiteStorageSchema.Apply(connection);
Assert.True(ColumnExists(connection, "data_connection_definitions", "backup_configuration"));
Assert.True(ColumnExists(connection, "data_connection_definitions", "failover_retry_count"));
Assert.True(ColumnExists(connection, "native_alarm_state", "metadata_json"));
Assert.True(ColumnExists(connection, "external_systems", "timeout_seconds"));
// The pre-existing row survives the upgrade and reads back the NOT NULL
// column's default rather than failing.
using var check = connection.CreateCommand();
check.CommandText = "SELECT timeout_seconds FROM external_systems WHERE name = 'legacy-system'";
Assert.Equal(0, Convert.ToInt32(check.ExecuteScalar()));
}
finally
{
SqliteConnection.ClearAllPools();
File.Delete(path);
}
}
private static bool TableExists(SqliteConnection connection, string table)
{
using var cmd = connection.CreateCommand();
cmd.CommandText = "SELECT COUNT(*) FROM sqlite_master WHERE type = 'table' AND name = $name";
cmd.Parameters.AddWithValue("$name", table);
return Convert.ToInt32(cmd.ExecuteScalar()) > 0;
}
private static bool ColumnExists(SqliteConnection connection, string table, string column)
{
using var cmd = connection.CreateCommand();
cmd.CommandText = $"SELECT COUNT(*) FROM pragma_table_info('{table}') WHERE name = $name";
cmd.Parameters.AddWithValue("$name", column);
return Convert.ToInt32(cmd.ExecuteScalar()) > 0;
}
}