feat(mqtt): wire will message delivery on abnormal disconnect

Add DeliverWill to MqttPacketHandlers — extracts and clears the will,
then delivers via ProcessInboundClientMsg. Call from CloseConnection
when client is MQTT. Clean DISCONNECT already clears the will (Task 3),
so DeliverWill is a no-op after DISCONNECT. 3 new tests: abnormal
close delivers will, DISCONNECT suppresses will, no-will is a no-op.
This commit is contained in:
Joseph Doherty
2026-03-01 16:10:53 -05:00
parent b465d095e3
commit 710f443eda
4 changed files with 96 additions and 1 deletions

View File

@@ -383,4 +383,68 @@ public sealed class MqttConnectTests
// Will should be cleared.
c.Mqtt.Will.ShouldBeNull();
}
// =========================================================================
// Will message delivery tests
// =========================================================================
[Fact]
public void DeliverWill_AbnormalClose_ShouldDeliverAndClearWill()
{
var c = CreateMqttClient();
// CONNECT with a will.
var connectBuf = BuildConnectPacket(
willTopic: "test/will",
willMessage: Encoding.UTF8.GetBytes("goodbye"));
var err = MqttParser.Parse(c, connectBuf, connectBuf.Length);
err.ShouldBeNull();
c.Mqtt!.Will.ShouldNotBeNull();
// Simulate abnormal close (not DISCONNECT) — will should be delivered.
MqttPacketHandlers.DeliverWill(c);
// Will should be cleared after delivery.
c.Mqtt.Will.ShouldBeNull();
}
[Fact]
public void DeliverWill_AfterDisconnect_ShouldNotDeliver()
{
var c = CreateMqttClient();
// CONNECT with a will.
var connectBuf = BuildConnectPacket(
willTopic: "test/will",
willMessage: Encoding.UTF8.GetBytes("goodbye"));
var err = MqttParser.Parse(c, connectBuf, connectBuf.Length);
err.ShouldBeNull();
// Clean DISCONNECT — clears the will.
var disconnectBuf = new byte[] { MqttPacket.Disconnect, 0x00 };
err = MqttParser.Parse(c, disconnectBuf, disconnectBuf.Length);
err.ShouldBeNull();
// Will was already cleared by DISCONNECT, so DeliverWill should be a no-op.
MqttPacketHandlers.DeliverWill(c);
c.Mqtt!.Will.ShouldBeNull();
}
[Fact]
public void DeliverWill_NoWill_ShouldBeNoOp()
{
var c = CreateMqttClient();
// CONNECT without a will.
var connectBuf = BuildConnectPacket();
var err = MqttParser.Parse(c, connectBuf, connectBuf.Length);
err.ShouldBeNull();
c.Mqtt!.Will.ShouldBeNull();
// DeliverWill with no will configured — should be a no-op.
MqttPacketHandlers.DeliverWill(c);
c.Mqtt.Will.ShouldBeNull();
}
}