v3 batch1 WP1: greenfield DbContext + V3Initial squash + seeds + tests
DbContext (OtOpcUaConfigDbContext): - Drop Namespace/EquipmentImportBatch/EquipmentImportRow DbSets + Configure methods. - Add RawFolder/TagGroup/UnsTagReference DbSets + Configure methods with sibling-name filtered unique indexes over nullable parents (two-filtered pattern per level). - Reshape DriverInstance (RawFolderId + UX_DriverInstance_Folder_Name/_ClusterRoot_Name), Tag (required DeviceId, nullable TagGroupId, UX_Tag_Group_Name/_Device_Name, IX_Tag_Device), Equipment (drop DriverInstanceId/DeviceId + IX_Equipment_Driver), Device (UX_Device_Driver_Name). Migration squash -> V3Initial: - Delete the whole Migrations/ folder; scaffold one V3Initial (applies clean to a fresh DB). - Port the hand-written procs + AuthorizationGrants into V3Initial.StoredProcedures.cs. The v1 generation-model procs (ConfigGeneration/GenerationId, dead since V2HostingAlignment) are rewritten as v3-schema-valid retirement stubs that preserve the two-role EXECUTE-grant surface + AuthorizationTests behaviors; sp_ComputeGenerationDiff now references the v3 tables; sp_ReleaseExternalIdReservation ported verbatim. Compile-fixes for the build gate (Wave-C-owned, minimal + TODO(v3 WP4) markers): - DraftSnapshot/DraftSnapshotFactory: drop the retired Namespaces list. - DraftValidator: delete namespace-binding + Galaxy-FullName rules; collision rule now VirtualTag-only. Seeds -> v3 schema: - seed-clusters.sql summary SELECTs; all 5 scripts/smoke/seed-*.sql rewritten (DriverInstance RawFolderId, Device+DeviceConfig endpoint, Tag DeviceId, UnsTagReference; no ConfigGeneration/ Namespace/sp_PublishGeneration). Verified: all seeds apply clean against a fresh V3Initial DB. Tests (Configuration.Tests, 107 pass): - SchemaComplianceTests rewritten to v3 tables + filtered indexes. - New RawSchemaIntegrityTests: DB-enforced sibling-name uniqueness per raw level + UnsTagReference (Equipment,Tag) uniqueness. - Delete DraftValidatorGalaxyFullNameCorpusTests (WP2/WP6 replaces); fix DraftValidatorTests + DraftSnapshotFactoryTests to v3 shapes; repoint scripting-migration existence test to V3Initial.
This commit is contained in:
@@ -28,14 +28,15 @@ public sealed class SchemaComplianceTests
|
||||
{
|
||||
"ServerCluster", "ClusterNode", "ClusterNodeCredential",
|
||||
"ConfigAuditLog",
|
||||
"Namespace", "UnsArea", "UnsLine",
|
||||
"UnsArea", "UnsLine",
|
||||
// v3 Raw-tree tables (Namespace retired; RawFolder/TagGroup/UnsTagReference added)
|
||||
"RawFolder", "TagGroup", "UnsTagReference",
|
||||
"DriverInstance", "Device", "Equipment", "Tag", "PollGroup", "VirtualTag",
|
||||
"NodeAcl", "ExternalIdReservation",
|
||||
"DriverHostStatus",
|
||||
"DriverInstanceResilienceStatus",
|
||||
"LdapGroupRoleMapping",
|
||||
"EquipmentImportBatch",
|
||||
"EquipmentImportRow",
|
||||
// v3 dropped the orphaned EquipmentImportBatch / EquipmentImportRow tables
|
||||
"Script", "ScriptedAlarm", "ScriptedAlarmState",
|
||||
// v2 deploy-model tables (Phase 1 of Akka + fused-hosting alignment)
|
||||
"Deployment", "NodeDeploymentState", "ConfigEdit", "DataProtectionKeys",
|
||||
@@ -60,6 +61,15 @@ SELECT name FROM sys.tables WHERE name <> '__EFMigrationsHistory' ORDER BY name;
|
||||
{
|
||||
("UX_ClusterNodeCredential_Value", "([Enabled]=(1))"),
|
||||
("UX_ExternalIdReservation_KindValue_Active", "([ReleasedAt] IS NULL)"),
|
||||
// v3 sibling-name filtered unique indexes over nullable parent columns.
|
||||
("UX_RawFolder_Parent_Name", "([ParentRawFolderId] IS NOT NULL)"),
|
||||
("UX_RawFolder_ClusterRoot_Name", "([ParentRawFolderId] IS NULL)"),
|
||||
("UX_DriverInstance_Folder_Name", "([RawFolderId] IS NOT NULL)"),
|
||||
("UX_DriverInstance_ClusterRoot_Name", "([RawFolderId] IS NULL)"),
|
||||
("UX_TagGroup_Parent_Name", "([ParentTagGroupId] IS NOT NULL)"),
|
||||
("UX_TagGroup_DeviceRoot_Name", "([ParentTagGroupId] IS NULL)"),
|
||||
("UX_Tag_Group_Name", "([TagGroupId] IS NOT NULL)"),
|
||||
("UX_Tag_Device_Name", "([TagGroupId] IS NULL)"),
|
||||
};
|
||||
|
||||
var rows = QueryRows(@"
|
||||
@@ -148,20 +158,36 @@ SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'Equipment
|
||||
columns.ShouldContain(col, $"Equipment missing expected column: {col}");
|
||||
}
|
||||
|
||||
/// <summary>Verifies that Namespace has at least one unique index.</summary>
|
||||
/// <summary>Verifies the retired v2 tables (Namespace, EquipmentImportBatch/Row) are absent.</summary>
|
||||
[Fact]
|
||||
public void Namespace_has_some_unique_index()
|
||||
public void Retired_v2_tables_are_absent()
|
||||
{
|
||||
// v2 dropped the "per-generation" qualifier from namespace uniqueness when live-edit
|
||||
// replaced draft/publish. The v2 index name is implementation-defined; assert that
|
||||
// *some* unique index exists on Namespace to catch unintentional index drops.
|
||||
var indexes = QueryStrings(@"
|
||||
var tables = QueryStrings("SELECT name FROM sys.tables;").ToHashSet();
|
||||
tables.ShouldNotContain("Namespace");
|
||||
tables.ShouldNotContain("EquipmentImportBatch");
|
||||
tables.ShouldNotContain("EquipmentImportRow");
|
||||
}
|
||||
|
||||
/// <summary>Verifies the new v3 Raw-tree tables each carry their logical-id unique index.</summary>
|
||||
[Fact]
|
||||
public void V3_raw_tree_tables_have_logical_id_unique_indexes()
|
||||
{
|
||||
var expected = new[]
|
||||
{
|
||||
("RawFolder", "UX_RawFolder_LogicalId"),
|
||||
("TagGroup", "UX_TagGroup_LogicalId"),
|
||||
("UnsTagReference", "UX_UnsTagReference_LogicalId"),
|
||||
};
|
||||
|
||||
foreach (var (table, index) in expected)
|
||||
{
|
||||
var indexes = QueryStrings($@"
|
||||
SELECT i.name
|
||||
FROM sys.indexes i
|
||||
JOIN sys.tables t ON i.object_id = t.object_id
|
||||
WHERE t.name = 'Namespace' AND i.is_unique = 1;").ToList();
|
||||
|
||||
indexes.ShouldNotBeEmpty();
|
||||
WHERE t.name = '{table}' AND i.is_unique = 1;").ToHashSet();
|
||||
indexes.ShouldContain(index, $"{table} missing unique index {index}");
|
||||
}
|
||||
}
|
||||
|
||||
private List<string> QueryStrings(string sql)
|
||||
|
||||
Reference in New Issue
Block a user