128 lines
5.1 KiB
C#
128 lines
5.1 KiB
C#
using Akka.Actor;
|
|
using Akka.TestKit;
|
|
using Shouldly;
|
|
using Xunit;
|
|
using ZB.MOM.WW.OtOpcUa.Commons.Messages.Admin;
|
|
using ZB.MOM.WW.OtOpcUa.Commons.Messages.Deploy;
|
|
using ZB.MOM.WW.OtOpcUa.Commons.Types;
|
|
using ZB.MOM.WW.OtOpcUa.Configuration.Enums;
|
|
using ZB.MOM.WW.OtOpcUa.ControlPlane.AdminOperations;
|
|
using ZB.MOM.WW.OtOpcUa.ControlPlane.Tests.Harness;
|
|
using ZB.MOM.WW.OtOpcUa.Core.Abstractions;
|
|
|
|
namespace ZB.MOM.WW.OtOpcUa.ControlPlane.Tests;
|
|
|
|
public sealed class AdminOperationsActorTests : ControlPlaneActorTestBase
|
|
{
|
|
/// <summary>Verifies that starting a deployment inserts a row and dispatches to the coordinator.</summary>
|
|
[Fact]
|
|
public void StartDeployment_inserts_deployment_and_dispatches_to_coordinator()
|
|
{
|
|
var dbFactory = NewInMemoryDbFactory();
|
|
var coordinator = CreateTestProbe("coord");
|
|
var actor = Sys.ActorOf(AdminOperationsActor.Props(dbFactory, coordinator.Ref, Enumerable.Empty<IDriverProbe>()));
|
|
|
|
actor.Tell(new StartDeployment("joe", CorrelationId.NewId()));
|
|
|
|
var dispatch = coordinator.ExpectMsg<DispatchDeployment>(TimeSpan.FromSeconds(3));
|
|
dispatch.DeploymentId.Value.ShouldNotBe(Guid.Empty);
|
|
dispatch.RevisionHash.Value.Length.ShouldBe(64);
|
|
|
|
var reply = ExpectMsg<StartDeploymentResult>(TimeSpan.FromSeconds(3));
|
|
reply.Outcome.ShouldBe(StartDeploymentOutcome.Accepted);
|
|
reply.DeploymentId.ShouldBe(dispatch.DeploymentId);
|
|
reply.RevisionHash.ShouldBe(dispatch.RevisionHash);
|
|
|
|
using var db = dbFactory.CreateDbContext();
|
|
var row = db.Deployments.Single();
|
|
row.Status.ShouldBe(DeploymentStatus.Dispatching);
|
|
row.CreatedBy.ShouldBe("joe");
|
|
row.ArtifactBlob.Length.ShouldBeGreaterThan(0);
|
|
|
|
db.ConfigEdits.Count().ShouldBe(1);
|
|
db.ConfigEdits.Single().EntityType.ShouldBe("Deployment");
|
|
}
|
|
|
|
/// <summary>Verifies the surgical DraftValidator gate: a Tag↔VirtualTag NodeId collision in
|
|
/// the live config rejects the deploy (422-mapped <see cref="StartDeploymentOutcome.Rejected"/>)
|
|
/// before any coordinator dispatch — and inserts no Deployment row.</summary>
|
|
[Fact]
|
|
public void StartDeployment_rejects_on_Tag_VirtualTag_NodeId_collision()
|
|
{
|
|
var dbFactory = NewInMemoryDbFactory();
|
|
using (var db = dbFactory.CreateDbContext())
|
|
{
|
|
db.Equipment.Add(new Configuration.Entities.Equipment
|
|
{
|
|
EquipmentUuid = Guid.NewGuid(),
|
|
EquipmentId = "eq-1",
|
|
Name = "eq",
|
|
DriverInstanceId = "d",
|
|
UnsLineId = "line-a",
|
|
MachineCode = "m",
|
|
});
|
|
db.Tags.Add(new Configuration.Entities.Tag
|
|
{
|
|
TagId = "tag-speed",
|
|
DriverInstanceId = "d",
|
|
EquipmentId = "eq-1",
|
|
Name = "speed",
|
|
DataType = "Float",
|
|
AccessLevel = TagAccessLevel.Read,
|
|
TagConfig = "{}",
|
|
});
|
|
db.VirtualTags.Add(new Configuration.Entities.VirtualTag
|
|
{
|
|
VirtualTagId = "vtag-speed",
|
|
EquipmentId = "eq-1",
|
|
Name = "speed",
|
|
DataType = "Float",
|
|
ScriptId = "s-1",
|
|
});
|
|
db.SaveChanges();
|
|
}
|
|
|
|
var coordinator = CreateTestProbe("coord");
|
|
var actor = Sys.ActorOf(AdminOperationsActor.Props(dbFactory, coordinator.Ref, Enumerable.Empty<IDriverProbe>()));
|
|
|
|
actor.Tell(new StartDeployment("joe", CorrelationId.NewId()));
|
|
|
|
coordinator.ExpectNoMsg(TimeSpan.FromMilliseconds(500));
|
|
var reply = ExpectMsg<StartDeploymentResult>(TimeSpan.FromSeconds(3));
|
|
reply.Outcome.ShouldBe(StartDeploymentOutcome.Rejected);
|
|
reply.Message.ShouldNotBeNull();
|
|
reply.Message.ShouldContain("collide"); // the rule's message text
|
|
|
|
using var verify = dbFactory.CreateDbContext();
|
|
verify.Deployments.Count().ShouldBe(0);
|
|
}
|
|
|
|
/// <summary>Verifies that starting a deployment is refused when another is in flight.</summary>
|
|
[Fact]
|
|
public void StartDeployment_refuses_when_another_is_in_flight()
|
|
{
|
|
var dbFactory = NewInMemoryDbFactory();
|
|
// Seed an in-flight Deployment.
|
|
using (var db = dbFactory.CreateDbContext())
|
|
{
|
|
db.Deployments.Add(new Configuration.Entities.Deployment
|
|
{
|
|
RevisionHash = new string('a', 64),
|
|
Status = DeploymentStatus.Dispatching,
|
|
CreatedBy = "earlier",
|
|
});
|
|
db.SaveChanges();
|
|
}
|
|
|
|
var coordinator = CreateTestProbe("coord");
|
|
var actor = Sys.ActorOf(AdminOperationsActor.Props(dbFactory, coordinator.Ref, Enumerable.Empty<IDriverProbe>()));
|
|
|
|
actor.Tell(new StartDeployment("joe", CorrelationId.NewId()));
|
|
|
|
coordinator.ExpectNoMsg(TimeSpan.FromMilliseconds(500));
|
|
var reply = ExpectMsg<StartDeploymentResult>(TimeSpan.FromSeconds(3));
|
|
reply.Outcome.ShouldBe(StartDeploymentOutcome.AnotherDeploymentInFlight);
|
|
reply.DeploymentId.ShouldNotBeNull();
|
|
}
|
|
}
|