Phase 2 WP-1–13+23: Template Engine CRUD, composition, overrides, locking, collision detection, acyclicity
- WP-23: ITemplateEngineRepository full EF Core implementation - WP-1: Template CRUD with deletion constraints (instances, children, compositions) - WP-2–4: Attribute, alarm, script definitions with lock flags and override granularity - WP-5: Shared script CRUD with syntax validation - WP-6–7: Composition with recursive nesting and canonical naming - WP-8–11: Override granularity, locking rules, inheritance/composition scope - WP-12: Naming collision detection on canonical names (recursive) - WP-13: Graph acyclicity (inheritance + composition cycles) Core services: TemplateService, SharedScriptService, TemplateResolver, LockEnforcer, CollisionDetector, CycleDetector. 358 tests pass.
This commit is contained in:
@@ -0,0 +1,118 @@
|
||||
using System.Text.Json;
|
||||
using ScadaLink.Commons.Types.Flattening;
|
||||
|
||||
namespace ScadaLink.TemplateEngine.Tests.Flattening;
|
||||
|
||||
public class DeploymentPackageTests
|
||||
{
|
||||
[Fact]
|
||||
public void DeploymentPackage_JsonSerializable()
|
||||
{
|
||||
var package = new DeploymentPackage
|
||||
{
|
||||
InstanceUniqueName = "PumpStation1",
|
||||
DeploymentId = "dep-abc123",
|
||||
RevisionHash = "sha256:abcdef1234567890",
|
||||
DeployedBy = "admin@company.com",
|
||||
DeployedAtUtc = new DateTimeOffset(2026, 3, 16, 12, 0, 0, TimeSpan.Zero),
|
||||
Configuration = new FlattenedConfiguration
|
||||
{
|
||||
InstanceUniqueName = "PumpStation1",
|
||||
TemplateId = 1,
|
||||
SiteId = 1,
|
||||
Attributes =
|
||||
[
|
||||
new ResolvedAttribute
|
||||
{
|
||||
CanonicalName = "Temperature",
|
||||
Value = "25.0",
|
||||
DataType = "Double",
|
||||
BoundDataConnectionId = 100,
|
||||
BoundDataConnectionName = "OPC-Server1",
|
||||
BoundDataConnectionProtocol = "OpcUa",
|
||||
DataSourceReference = "ns=2;s=Temp"
|
||||
}
|
||||
],
|
||||
Alarms =
|
||||
[
|
||||
new ResolvedAlarm
|
||||
{
|
||||
CanonicalName = "HighTemp",
|
||||
TriggerType = "RangeViolation",
|
||||
PriorityLevel = 1
|
||||
}
|
||||
],
|
||||
Scripts =
|
||||
[
|
||||
new ResolvedScript
|
||||
{
|
||||
CanonicalName = "Monitor",
|
||||
Code = "var x = Attributes[\"Temperature\"].Value;"
|
||||
}
|
||||
]
|
||||
},
|
||||
PreviousRevisionHash = null
|
||||
};
|
||||
|
||||
var json = JsonSerializer.Serialize(package);
|
||||
Assert.NotNull(json);
|
||||
Assert.Contains("PumpStation1", json);
|
||||
Assert.Contains("sha256:abcdef1234567890", json);
|
||||
|
||||
var deserialized = JsonSerializer.Deserialize<DeploymentPackage>(json);
|
||||
Assert.NotNull(deserialized);
|
||||
Assert.Equal("PumpStation1", deserialized.InstanceUniqueName);
|
||||
Assert.Equal("dep-abc123", deserialized.DeploymentId);
|
||||
Assert.Single(deserialized.Configuration.Attributes);
|
||||
Assert.Equal("Temperature", deserialized.Configuration.Attributes[0].CanonicalName);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DeploymentPackage_WithDiff_Serializable()
|
||||
{
|
||||
var package = new DeploymentPackage
|
||||
{
|
||||
InstanceUniqueName = "Inst1",
|
||||
DeploymentId = "dep-1",
|
||||
RevisionHash = "sha256:new",
|
||||
DeployedBy = "admin",
|
||||
DeployedAtUtc = DateTimeOffset.UtcNow,
|
||||
Configuration = new FlattenedConfiguration { InstanceUniqueName = "Inst1" },
|
||||
Diff = new ConfigurationDiff
|
||||
{
|
||||
InstanceUniqueName = "Inst1",
|
||||
OldRevisionHash = "sha256:old",
|
||||
NewRevisionHash = "sha256:new",
|
||||
AttributeChanges =
|
||||
[
|
||||
new DiffEntry<ResolvedAttribute>
|
||||
{
|
||||
CanonicalName = "Temp",
|
||||
ChangeType = DiffChangeType.Changed,
|
||||
OldValue = new ResolvedAttribute { CanonicalName = "Temp", Value = "25", DataType = "Double" },
|
||||
NewValue = new ResolvedAttribute { CanonicalName = "Temp", Value = "50", DataType = "Double" }
|
||||
}
|
||||
]
|
||||
},
|
||||
PreviousRevisionHash = "sha256:old"
|
||||
};
|
||||
|
||||
var json = JsonSerializer.Serialize(package);
|
||||
var deserialized = JsonSerializer.Deserialize<DeploymentPackage>(json);
|
||||
|
||||
Assert.NotNull(deserialized?.Diff);
|
||||
Assert.True(deserialized.Diff.HasChanges);
|
||||
Assert.Equal("sha256:old", deserialized.PreviousRevisionHash);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FlattenedConfiguration_DefaultValues()
|
||||
{
|
||||
var config = new FlattenedConfiguration();
|
||||
|
||||
Assert.Equal(string.Empty, config.InstanceUniqueName);
|
||||
Assert.Empty(config.Attributes);
|
||||
Assert.Empty(config.Alarms);
|
||||
Assert.Empty(config.Scripts);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user