feat(mqtt): implement PUBLISH QoS 0, SUBSCRIBE, and UNSUBSCRIBE handlers
Add ParsePub, ParseSubsOrUnsubs, ProcessPub (QoS 0), ProcessSubs, ProcessUnsubs, EnqueueSubAck, and EnqueueUnsubAck to MqttPacketHandlers. Wire PUB/SUB/UNSUB dispatch cases in MqttParser. Add ReadSlice to MqttReader for raw payload extraction. 18 new unit tests covering parsing, flags, error cases, QoS downgrade, and full flow. 1 new integration test verifying SUBSCRIBE handshake over TCP.
This commit is contained in:
@@ -24,7 +24,7 @@ public sealed class MqttParserTests
|
||||
/// </summary>
|
||||
private static ClientConnection CreateMqttClient()
|
||||
{
|
||||
var c = new ClientConnection(ClientKind.Client);
|
||||
var c = new ClientConnection(ClientKind.Client, nc: new MemoryStream());
|
||||
c.InitMqtt(new MqttHandler());
|
||||
return c;
|
||||
}
|
||||
@@ -164,37 +164,38 @@ public sealed class MqttParserTests
|
||||
[Fact]
|
||||
public void Parse_SingleByteRemainingLength_ShouldWork()
|
||||
{
|
||||
// SUB packet with remaining length = 5 (single byte < 128)
|
||||
// After CONNECT is received, a SUB packet should parse the remaining length correctly.
|
||||
// SUBSCRIBE with remaining length = 6 (single byte < 128).
|
||||
// Proves single-byte remaining length decoding works.
|
||||
var c = CreateMqttClient();
|
||||
c.Flags |= ClientFlags.ConnectReceived;
|
||||
|
||||
// SUBSCRIBE: type=0x82, remaining len=5, then 5 bytes of payload
|
||||
var buf = new byte[] { 0x82, 0x05, 0x00, 0x01, 0x00, 0x01, 0x74 };
|
||||
// SUBSCRIBE: type=0x82, remlen=6, PI=1, filter="t" (len=1), QoS=0
|
||||
var buf = new byte[] { 0x82, 0x06, 0x00, 0x01, 0x00, 0x01, (byte)'t', 0x00 };
|
||||
var err = MqttParser.Parse(c, buf, buf.Length);
|
||||
// Will hit NotImplementedException for SUBSCRIBE — that's fine, it proves parsing worked.
|
||||
err.ShouldNotBeNull();
|
||||
err.ShouldBeOfType<NotImplementedException>();
|
||||
err.ShouldBeNull();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Parse_TwoByteRemainingLength_ShouldWork()
|
||||
{
|
||||
// PUBLISH QoS 0 with remaining length = 200 → encoded as [0xC8, 0x01].
|
||||
// Proves two-byte remaining length decoding works.
|
||||
var c = CreateMqttClient();
|
||||
c.Flags |= ClientFlags.ConnectReceived;
|
||||
|
||||
// Remaining length = 200 → encoded as [0xC8, 0x01]
|
||||
// (200 & 0x7F) | 0x80 = 0xC8, 200 >> 7 = 1 → 0x01
|
||||
// type(1) + remlen(2) + payload(200) = 203 bytes total.
|
||||
var buf = new byte[203];
|
||||
buf[0] = MqttPacket.Pub;
|
||||
buf[0] = MqttPacket.Pub; // 0x30, QoS 0
|
||||
buf[1] = 0xC8;
|
||||
buf[2] = 0x01;
|
||||
// Remaining 200 bytes are zero (payload).
|
||||
// Topic "t": length prefix (2 bytes) + 1 byte.
|
||||
buf[3] = 0x00;
|
||||
buf[4] = 0x01;
|
||||
buf[5] = (byte)'t';
|
||||
// Bytes 6..202 are zero (197-byte payload).
|
||||
|
||||
var err = MqttParser.Parse(c, buf, buf.Length);
|
||||
err.ShouldNotBeNull();
|
||||
err.ShouldBeOfType<NotImplementedException>(); // PUBLISH not yet implemented
|
||||
err.ShouldBeNull();
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
|
||||
Reference in New Issue
Block a user