DriverHostActor.ApplyAndAck now reads the deployment artifact and reconciles its set of DriverInstanceActor children — spawn the missing, ApplyDelta to those with changed config, stop the removed/disabled. The diff lives in pure DriverSpawnPlanner so it can be unit-tested without an ActorSystem. Adds IDriverFactory in Core.Abstractions (consumed by Runtime) + DriverFactoryRegistryAdapter in Core.Hosting that wraps the existing v1 DriverFactoryRegistry — Runtime stays decoupled from Polly/Serilog, the Host wires the adapter once driver assemblies have registered. ShouldStub(type, roles) is now actually called on every spawn — Galaxy + Wonderware-Historian boot stubbed on macOS/Linux or whenever the host carries the dev role. Missing factory ⇒ stub fallback, never a crash. Tests: 24 → 34 in Runtime (+10): - DriverSpawnPlannerTests x7 (diff cases, type change ⇒ stop+respawn) - DeploymentArtifactTests x5 (empty/malformed/missing fields tolerant) - DriverHostActorReconcileTests x4 (spawn count, stub fallback, ShouldStub gate, second-apply stops the removed) All 6 v2 test suites green: 120 tests passing. Closes F20 (ShouldStub wired). F7 marked partial — subscription publishing + write path still stubbed in DriverInstanceActor itself.
36 lines
1.7 KiB
C#
36 lines
1.7 KiB
C#
namespace ZB.MOM.WW.OtOpcUa.Core.Abstractions;
|
|
|
|
/// <summary>
|
|
/// Abstraction over the process-wide driver registry. Runtime consumes this instead of
|
|
/// <c>DriverFactoryRegistry</c> directly so the Runtime project doesn't pull in
|
|
/// <c>ZB.MOM.WW.OtOpcUa.Core</c> (which would drag in Polly + driver hosting). The fused
|
|
/// Host binds a <c>DriverFactoryRegistryAdapter</c> after every <c>Driver.*.Register()</c>
|
|
/// extension has run.
|
|
/// </summary>
|
|
public interface IDriverFactory
|
|
{
|
|
/// <summary>
|
|
/// Return a new <see cref="IDriver"/> for the given <paramref name="driverType"/>, or
|
|
/// <c>null</c> when no factory is registered for that type (missing assembly, typo, etc.).
|
|
/// The DriverHostActor logs + skips the row rather than failing the whole apply.
|
|
/// </summary>
|
|
IDriver? TryCreate(string driverType, string driverInstanceId, string driverConfigJson);
|
|
|
|
/// <summary>Driver-type names this factory can materialise. Mostly for diagnostics + logs.</summary>
|
|
IReadOnlyCollection<string> SupportedTypes { get; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns <c>null</c> from every <see cref="IDriverFactory.TryCreate"/> call. Bound when the
|
|
/// fused Host hasn't registered any concrete driver assemblies yet (Mac dev path, smoke
|
|
/// tests). DriverHostActor sees zero supported types and treats the deployment as a no-op.
|
|
/// </summary>
|
|
public sealed class NullDriverFactory : IDriverFactory
|
|
{
|
|
public static readonly NullDriverFactory Instance = new();
|
|
private NullDriverFactory() { }
|
|
|
|
public IDriver? TryCreate(string driverType, string driverInstanceId, string driverConfigJson) => null;
|
|
public IReadOnlyCollection<string> SupportedTypes { get; } = Array.Empty<string>();
|
|
}
|