Files
ScadaBridge/tests/ZB.MOM.WW.ScadaBridge.Communication.Tests/Grpc/SiteCommandDtoMapperSecretsTests.cs
T

86 lines
3.8 KiB
C#

using Google.Protobuf.WellKnownTypes;
using ZB.MOM.WW.ScadaBridge.Commons.Messages.Artifacts;
using ZB.MOM.WW.ScadaBridge.Communication.Grpc;
namespace ZB.MOM.WW.ScadaBridge.Communication.Tests.Grpc;
/// <summary>
/// Round-trip tests for the additive <c>Secrets</c> / <c>SecretsApplied</c> wire contract
/// on <see cref="DeployArtifactsCommand"/> / <see cref="ArtifactDeploymentResponse"/>
/// (proto field 9 / field 6). Site secrets design §3.3, task-2 of
/// docs/plans/2026-09-28-site-secrets-artifact-deploy-design.md.
/// </summary>
public class SiteCommandDtoMapperSecretsTests
{
private static SecretArtifact Sample(string name) => new(name, "text/plain",
[1, 2, 3], [4], [5], [6, 7], [8], [9], "kek-A", 7,
DateTimeOffset.Parse("2026-09-01T00:00:00Z"), DateTimeOffset.Parse("2026-09-02T00:00:00Z"), "d");
[Fact]
public void DeployArtifacts_Secrets_RoundTrip_Verbatim()
{
var cmd = new DeployArtifactsCommand("dep", null, null, null, null, null, null,
DateTimeOffset.UtcNow, [Sample("A"), Sample("B")]);
var back = (DeployArtifactsCommand)SiteCommandDtoMapper.FromProto(SiteCommandDtoMapper.ToProto(cmd));
Assert.Equal(2, back.Secrets!.Count);
Assert.Equal(cmd.Secrets![0].Ciphertext, back.Secrets[0].Ciphertext);
Assert.Equal(cmd.Secrets[0].Nonce, back.Secrets[0].Nonce);
Assert.Equal(cmd.Secrets[0].Tag, back.Secrets[0].Tag);
Assert.Equal(cmd.Secrets[0].WrappedDek, back.Secrets[0].WrappedDek);
Assert.Equal(cmd.Secrets[0].WrapNonce, back.Secrets[0].WrapNonce);
Assert.Equal(cmd.Secrets[0].WrapTag, back.Secrets[0].WrapTag);
Assert.Equal(cmd.Secrets[0].ContentType, back.Secrets[0].ContentType);
Assert.Equal(cmd.Secrets[0].CreatedUtc, back.Secrets[0].CreatedUtc);
Assert.Equal(cmd.Secrets[0].UpdatedUtc, back.Secrets[0].UpdatedUtc);
Assert.Equal(cmd.Secrets[0].Description, back.Secrets[0].Description);
Assert.Equal("kek-A", back.Secrets[1].KekId);
Assert.Equal(7, back.Secrets[1].Revision);
}
[Fact]
public void DeployArtifacts_NullSecrets_StaysNull()
{
var cmd = new DeployArtifactsCommand("dep", null, null, null, null, null, null, DateTimeOffset.UtcNow);
var dto = SiteCommandDtoMapper.ToProto(cmd);
Assert.Null(dto.Secrets);
Assert.Null(((DeployArtifactsCommand)SiteCommandDtoMapper.FromProto(dto)).Secrets);
}
[Fact]
public void DeployArtifacts_EmptySecrets_StaysEmpty_NotNull()
{
var cmd = new DeployArtifactsCommand("dep", null, null, null, null, null, null,
DateTimeOffset.UtcNow, []);
var back = (DeployArtifactsCommand)SiteCommandDtoMapper.FromProto(SiteCommandDtoMapper.ToProto(cmd));
Assert.NotNull(back.Secrets);
Assert.Empty(back.Secrets!);
}
[Fact]
public void DeployArtifacts_CommandDtoWithoutField9_MapsToNullSecrets()
{
// Simulates an OLD CENTRAL that never set field 9 — the DTO here carries no
// Secrets wrapper at all, exactly as a pre-upgrade sender's wire bytes would
// decode. FromProto must treat that absence as null, not an empty list.
var dto = new DeployArtifactsCommandDto
{
DeploymentId = "dep",
Timestamp = Timestamp.FromDateTimeOffset(DateTimeOffset.UtcNow)
};
Assert.Null(dto.Secrets);
var back = SiteCommandDtoMapper.FromProto(dto);
Assert.Null(back.Secrets);
}
[Theory]
[InlineData(null)]
[InlineData(3)]
public void ArtifactResponse_SecretsApplied_RoundTrips(int? applied)
{
var r = new ArtifactDeploymentResponse("dep", "site-a", true, null, DateTimeOffset.UtcNow, applied);
Assert.Equal(applied, SiteCommandDtoMapper.FromProto(SiteCommandDtoMapper.ToProto(r)).SecretsApplied);
}
}