using Shouldly;
using Xunit;
using ZB.MOM.WW.OtOpcUa.Configuration.Entities;
using ZB.MOM.WW.OtOpcUa.Configuration.Enums;
using ZB.MOM.WW.OtOpcUa.Host.OpcUa;
using ZB.MOM.WW.OtOpcUa.OpcUaServer.Security;
namespace ZB.MOM.WW.OtOpcUa.Host.Tests.OpcUa;
///
/// The flag-off role (pluggable historian, spec §5). The
/// broader mapper behaviour is covered by .
///
public sealed class ApiKeyInterimRoleMapperTests
{
private const string Principal = "historian-editor";
[Fact]
public void A_cluster_scoped_history_update_grant_confers_the_history_update_role()
{
var roles = ApiKeyInterimRoleMapper.Map(
[Grant(NodeAclScopeKind.Cluster, NodePermissions.HistoryUpdate)], Principal);
roles.ShouldBe([OpcUaDataPlaneRoles.HistoryUpdate]);
}
///
/// Writing a live value and rewriting recorded history are different authorities, so a key that can
/// write must not thereby gain HistoryUpdate — neither from WriteOperate nor from any composite bundle
/// (HistoryUpdate is deliberately in none of them).
///
[Fact]
public void Write_operate_and_the_bundles_do_not_confer_history_update()
{
foreach (var flags in new[]
{
NodePermissions.WriteOperate, NodePermissions.HistoryRead, NodePermissions.ReadOnly,
NodePermissions.Operator, NodePermissions.Engineer, NodePermissions.Admin,
})
{
ApiKeyInterimRoleMapper.Map([Grant(NodeAclScopeKind.Cluster, flags)], Principal)
.ShouldNotContain(OpcUaDataPlaneRoles.HistoryUpdate, $"{flags} must not confer HistoryUpdate");
}
}
[Fact]
public void A_narrower_scoped_history_update_grant_confers_nothing()
{
foreach (var narrower in new[]
{
NodeAclScopeKind.Equipment, NodeAclScopeKind.UnsArea,
NodeAclScopeKind.UnsLine, NodeAclScopeKind.Namespace,
})
{
ApiKeyInterimRoleMapper.Map([Grant(narrower, NodePermissions.HistoryUpdate)], Principal)
.ShouldBeEmpty($"a {narrower}-scoped grant must not confer a server-wide role");
}
}
[Fact]
public void History_update_unions_with_the_other_roles()
{
var roles = ApiKeyInterimRoleMapper.Map(
[
Grant(NodeAclScopeKind.Cluster, NodePermissions.WriteOperate),
Grant(NodeAclScopeKind.Cluster, NodePermissions.HistoryUpdate | NodePermissions.AlarmAcknowledge),
], Principal);
roles.ShouldBe(
[OpcUaDataPlaneRoles.WriteOperate, OpcUaDataPlaneRoles.AlarmAck, OpcUaDataPlaneRoles.HistoryUpdate],
ignoreOrder: true);
}
private static NodeAcl Grant(NodeAclScopeKind scope, NodePermissions flags) => new()
{
NodeAclId = $"ACL-{scope}-{flags}",
ClusterId = "MAIN",
Principal = Principal,
ScopeKind = scope,
ScopeId = scope == NodeAclScopeKind.Cluster ? null : "SOME-SCOPE",
PermissionFlags = flags,
};
}