diff --git a/tests/Server/ZB.MOM.WW.OtOpcUa.Host.IntegrationTests/DriverReconnectE2eTests.cs b/tests/Server/ZB.MOM.WW.OtOpcUa.Host.IntegrationTests/DriverReconnectE2eTests.cs
index 002bd4c2..0eba864a 100644
--- a/tests/Server/ZB.MOM.WW.OtOpcUa.Host.IntegrationTests/DriverReconnectE2eTests.cs
+++ b/tests/Server/ZB.MOM.WW.OtOpcUa.Host.IntegrationTests/DriverReconnectE2eTests.cs
@@ -1,8 +1,15 @@
+using Akka.Actor;
+using Microsoft.AspNetCore.SignalR;
using Microsoft.Extensions.DependencyInjection;
+using Moq;
using Shouldly;
using Xunit;
+using ZB.MOM.WW.OtOpcUa.AdminUI.Hubs;
using ZB.MOM.WW.OtOpcUa.Commons.Interfaces;
using ZB.MOM.WW.OtOpcUa.Commons.Messages.Admin;
+using ZB.MOM.WW.OtOpcUa.Commons.Messages.Drivers;
+using ZB.MOM.WW.OtOpcUa.Configuration.Entities;
+using ZB.MOM.WW.OtOpcUa.Configuration.Enums;
namespace ZB.MOM.WW.OtOpcUa.Host.IntegrationTests;
@@ -10,17 +17,20 @@ namespace ZB.MOM.WW.OtOpcUa.Host.IntegrationTests;
/// E2E integration coverage for the ReconnectDriver command path through
/// .
///
-/// Scope note: wiring a live DriverInstanceActor for the full
-/// Healthy → Reconnecting → Healthy health-transition assertion requires a deployed
-/// driver row in the config DB, a real fixture endpoint, and the
-/// DriverHostActor to have registered the instance — substantially more
-/// harness complexity than the two-node cluster setup alone provides. That deeper
-/// fixture is tracked as a follow-up. This suite instead verifies the message
-/// round-trip through the AdminOperationsActor singleton: the command is
+/// The first two tests verify the message round-trip through the
+/// AdminOperationsActor singleton against a non-deployed instance id: the command is
/// accepted, persisted as a ConfigEdit audit row, and the reply carries
-/// Ok = true with the matching CorrelationId. The DPS broadcast
-/// that triggers the actor-side reconnect is exercised by the control-plane unit
-/// tests that mock IActorRef.
+/// Ok = true with the matching CorrelationId.
+///
+///
+/// goes the full distance: it deploys a real driver (via the opt-in
+/// wired into the harness) so the
+/// DriverHostActor spawns a managed DriverInstanceActor, then drives the
+/// end-to-end reconnect path —
+/// ReconnectDriver → AdminOperationsActor → DriverHostActor.HandleReconnectDriver →
+/// DriverInstanceActor.ForceReconnect (FSM) → PublishHealthSnapshot → driver-health DPS topic →
+/// DriverStatusSignalRBridge → snapshot store / hub push — and asserts the published health
+/// transitions Healthy → Reconnecting → Healthy.
///
[Trait("Category", "Integration")]
public sealed class DriverReconnectE2eTests
@@ -83,4 +93,175 @@ public sealed class DriverReconnectE2eTests
r1.CorrelationId.ShouldBe(first.CorrelationId);
r2.CorrelationId.ShouldBe(second.CorrelationId);
}
+
+ private const string ClusterId = "RECONNECT-E2E";
+ private const string DriverId = "drv-modbus";
+
+ ///
+ /// Full-stack reconnect: deploys a real driver (the in-process
+ /// ), proves it reaches Healthy on the driver-health DPS
+ /// topic, simulates a lost connection (), issues
+ /// a through , and asserts the
+ /// published health walks Healthy → Reconnecting → Healthy — captured at the
+ /// hub-push seam. Confirms the operator Reconnect threads
+ /// the whole cluster path and genuinely re-initialises the driver (InitializeCount ≥ 2).
+ ///
+ [Fact]
+ public async Task Reconnect_DeployedDriver_TransitionsThroughReconnectingBackToHealthy()
+ {
+ var factory = new FakeReconnectDriverFactory();
+ await using var harness = await TwoNodeClusterHarness.StartAsync(driverFactory: factory);
+
+ var store = harness.NodeA.Services.GetRequiredService();
+
+ // Capture every DriverHealthChanged the bridge pushes to the hub (the first SendCoreAsync arg).
+ var captured = new List();
+ var captureLock = new object();
+ var mockClients = new Mock();
+ var mockClientProxy = new Mock();
+ mockClients.Setup(c => c.Group(It.IsAny())).Returns(mockClientProxy.Object);
+ mockClientProxy
+ .Setup(p => p.SendCoreAsync(It.IsAny(), It.IsAny