Files
lmxopcua/tests/Server/ZB.MOM.WW.OtOpcUa.Runtime.Tests/ServiceCollectionExtensionsTests.cs
T
Joseph Doherty 64e3fbe035
v2-ci / build (push) Failing after 1m43s
v2-ci / unit-tests (tests/Core/ZB.MOM.WW.OtOpcUa.Cluster.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.ControlPlane.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.Runtime.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.Security.Tests) (push) Has been skipped
v2-ci / integration (tests/Server/ZB.MOM.WW.OtOpcUa.Host.IntegrationTests) (push) Has been skipped
v2-ci / integration (tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.IntegrationTests) (push) Has been skipped
docs: backfill XML documentation across 756 files
Adds <summary>, <param>, <typeparam>, and <inheritdoc/> tags to public
members surfaced by commentchecker — resolves 5,847 of 5,869 issues
(99.6%) across three /fixdocs passes.
2026-05-28 08:10:17 -04:00

110 lines
5.0 KiB
C#

using Akka.Hosting;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Shouldly;
using Xunit;
using ZB.MOM.WW.OtOpcUa.Commons.Interfaces;
using ZB.MOM.WW.OtOpcUa.Commons.Types;
using ZB.MOM.WW.OtOpcUa.Configuration;
namespace ZB.MOM.WW.OtOpcUa.Runtime.Tests;
/// <summary>
/// Verifies <c>WithOtOpcUaRuntimeActors</c> spawns <c>DriverHostActor</c> + <c>DbHealthProbeActor</c>
/// on the host's <c>ActorSystem</c> and registers both under their marker keys. This is the
/// driver-role mirror of the admin-role <c>WithOtOpcUaControlPlaneSingletons</c> bootstrap.
/// </summary>
public sealed class ServiceCollectionExtensionsTests
{
/// <summary>Verifies that WithOtOpcUaRuntimeActors spawns driver host and DB health probe actors.</summary>
[Fact]
public async Task WithOtOpcUaRuntimeActors_spawns_driver_host_and_db_health_probe()
{
using var host = Host.CreateDefaultBuilder()
.ConfigureServices((_, services) =>
{
services.AddSingleton<IDbContextFactory<OtOpcUaConfigDbContext>>(
new InMemoryConfigDbFactory(Guid.NewGuid().ToString("N")));
services.AddSingleton<IClusterRoleInfo>(new FakeClusterRoleInfo());
services.AddAkka("otopcua-test", (ab, _) =>
{
ab.AddHocon(@"
akka.actor.provider = ""Akka.Cluster.ClusterActorRefProvider, Akka.Cluster""
akka.remote.dot-netty.tcp.hostname = ""127.0.0.1""
akka.remote.dot-netty.tcp.port = 0
akka.cluster.seed-nodes = []
akka.cluster.roles = [""driver""]
", HoconAddMode.Prepend);
ab.WithOtOpcUaRuntimeActors();
});
})
.Build();
await host.StartAsync();
try
{
var driverHost = host.Services.GetRequiredService<IRequiredActor<DriverHostActorKey>>();
var dbHealth = host.Services.GetRequiredService<IRequiredActor<DbHealthProbeActorKey>>();
var historian = host.Services.GetRequiredService<IRequiredActor<HistorianAdapterActorKey>>();
var mux = host.Services.GetRequiredService<IRequiredActor<DependencyMuxActorKey>>();
var publish = host.Services.GetRequiredService<IRequiredActor<OpcUaPublishActorKey>>();
driverHost.ActorRef.ShouldNotBeNull();
dbHealth.ActorRef.ShouldNotBeNull();
historian.ActorRef.ShouldNotBeNull();
mux.ActorRef.ShouldNotBeNull();
publish.ActorRef.ShouldNotBeNull();
driverHost.ActorRef.Path.Name.ShouldBe(ServiceCollectionExtensions.DriverHostActorName);
dbHealth.ActorRef.Path.Name.ShouldBe(ServiceCollectionExtensions.DbHealthProbeActorName);
historian.ActorRef.Path.Name.ShouldBe(ServiceCollectionExtensions.HistorianAdapterActorName);
mux.ActorRef.Path.Name.ShouldBe(ServiceCollectionExtensions.DependencyMuxActorName);
publish.ActorRef.Path.Name.ShouldBe(ServiceCollectionExtensions.OpcUaPublishActorName);
}
finally
{
await host.StopAsync();
}
}
/// <summary>In-memory database factory for testing.</summary>
private sealed class InMemoryConfigDbFactory(string dbName) : IDbContextFactory<OtOpcUaConfigDbContext>
{
/// <summary>Creates a new in-memory database context.</summary>
public OtOpcUaConfigDbContext CreateDbContext()
{
var opts = new DbContextOptionsBuilder<OtOpcUaConfigDbContext>()
.UseInMemoryDatabase(dbName)
.Options;
return new OtOpcUaConfigDbContext(opts);
}
}
/// <summary>Fake cluster role information for testing.</summary>
private sealed class FakeClusterRoleInfo : IClusterRoleInfo
{
/// <summary>Gets the local node ID.</summary>
public NodeId LocalNode { get; } = NodeId.Parse("test-node");
/// <summary>Gets the local roles.</summary>
public IReadOnlySet<string> LocalRoles { get; } = new HashSet<string>(["driver"]);
/// <summary>Determines whether the local node has the specified role.</summary>
/// <param name="role">The role to check.</param>
public bool HasRole(string role) => LocalRoles.Contains(role);
/// <summary>Gets the members with the specified role.</summary>
/// <param name="role">The role to query.</param>
public IReadOnlyList<NodeId> MembersWithRole(string role) => Array.Empty<NodeId>();
/// <summary>Gets the leader node for the specified role.</summary>
/// <param name="role">The role to query.</param>
public NodeId? RoleLeader(string role) => null;
/// <summary>Raised when the role leader changes.</summary>
public event EventHandler<RoleLeaderChangedEventArgs>? RoleLeaderChanged
{
add { _ = value; }
remove { _ = value; }
}
}
}