From 59a69f82d0e7c71a4d806660055362773aa5f170 Mon Sep 17 00:00:00 2001 From: Joseph Doherty Date: Sat, 28 Feb 2026 21:49:41 -0500 Subject: [PATCH] test(batch26): port websocket functional tests --- .../ImplBacklog/WebSocketHandlerTests.cs | 78 ++++++++++++++++++ porting.db | Bin 6742016 -> 6742016 bytes 2 files changed, 78 insertions(+) diff --git a/dotnet/tests/ZB.MOM.NatsNet.Server.Tests/ImplBacklog/WebSocketHandlerTests.cs b/dotnet/tests/ZB.MOM.NatsNet.Server.Tests/ImplBacklog/WebSocketHandlerTests.cs index 24b54ef..accbeae 100644 --- a/dotnet/tests/ZB.MOM.NatsNet.Server.Tests/ImplBacklog/WebSocketHandlerTests.cs +++ b/dotnet/tests/ZB.MOM.NatsNet.Server.Tests/ImplBacklog/WebSocketHandlerTests.cs @@ -150,6 +150,26 @@ public sealed partial class WebSocketHandlerTests Encoding.ASCII.GetString(bufs[2]).ShouldBe("third"); } + [Fact] // T:3084 + public void WSReadPartialFrameHeaderAtEndOfReadBuffer_ShouldSucceed() + { + var client = CreateWsClient(); + var readInfo = CreateReadInfo(); + + var first = CreateMaskedClientFrame(WsOpCode.Binary, 1, final: true, compressed: false, Encoding.ASCII.GetBytes("msg1")); + var second = CreateMaskedClientFrame(WsOpCode.Binary, 1, final: true, compressed: false, Encoding.ASCII.GetBytes("msg2")); + var source = first.Concat(second).ToArray(); + + var initial = source[..(first.Length + 1)]; + using var remainder = new MemoryStream(source[(first.Length + 1)..]); + + var bufs = client.WsRead(readInfo, remainder, initial); + + bufs.Count.ShouldBe(1); + Encoding.ASCII.GetString(bufs[0]).ShouldBe("msg1"); + remainder.Position.ShouldBe(5); + } + [Fact] // T:3085 public void WSReadPingFrame_ShouldSucceed() { @@ -202,6 +222,64 @@ public sealed partial class WebSocketHandlerTests Should.Throw(() => client.WsRead(readInfo, new MemoryStream(Array.Empty()), msg.Concat(close).ToArray())); } + [Fact] // T:3088 + public void WSReadControlFrameBetweebFragmentedFrames_ShouldSucceed() + { + var client = CreateWsClient(); + var readInfo = CreateReadInfo(); + + var frag1 = CreateMaskedClientFrame(WsOpCode.Binary, 1, final: false, compressed: false, Encoding.ASCII.GetBytes("first")); + var ctrl = CreateMaskedClientFrame(WsOpCode.Pong, 1, final: true, compressed: false, Array.Empty()); + var frag2 = CreateMaskedClientFrame(WsOpCode.Binary, 2, final: true, compressed: false, Encoding.ASCII.GetBytes("second")); + + var bufs = client.WsRead(readInfo, new MemoryStream(Array.Empty()), frag1.Concat(ctrl).Concat(frag2).ToArray()); + + bufs.Count.ShouldBe(2); + Encoding.ASCII.GetString(bufs[0]).ShouldBe("first"); + Encoding.ASCII.GetString(bufs[1]).ShouldBe("second"); + } + + [Fact] // T:3089 + public void WSCloseFrameWithPartialOrInvalid_ShouldSucceed() + { + var payloadText = Encoding.ASCII.GetBytes("hello"); + var payload = new byte[2 + payloadText.Length]; + BinaryPrimitives.WriteUInt16BigEndian(payload.AsSpan(0, 2), (ushort)WsConstants.CloseNormalClosure); + payloadText.CopyTo(payload.AsSpan(2)); + + var client = CreateWsClient(); + var readInfo = CreateReadInfo(); + var closeFrame = CreateMaskedClientFrame(WsOpCode.Close, 1, final: true, compressed: false, payload); + var initial = new[] { closeFrame[0] }; + using var remainder = new MemoryStream(closeFrame[1..]); + + Should.Throw(() => client.WsRead(readInfo, remainder, initial)); + lock (GetClientLock(client)) + { + var (chunks, _) = client.CollapsePtoNB(); + chunks.Count.ShouldBe(1); + chunks[0].Buffer.Length.ShouldBe(2 + 2 + payloadText.Length); + chunks[0].Buffer[0].ShouldBe((byte)((byte)WsOpCode.Close | WsConstants.FinalBit)); + BinaryPrimitives.ReadUInt16BigEndian(chunks[0].Buffer.AsSpan(2, 2)).ShouldBe((ushort)WsConstants.CloseNormalClosure); + chunks[0].Buffer.AsSpan(4).ToArray().ShouldBe(payloadText); + } + + client = CreateWsClient(); + readInfo = CreateReadInfo(); + closeFrame = CreateMaskedClientFrame(WsOpCode.Close, 1, final: true, compressed: false, payload[..1]); + var partialHeader = new[] { closeFrame[0] }; + using var invalidRemainder = new MemoryStream(closeFrame[1..]); + + Should.Throw(() => client.WsRead(readInfo, invalidRemainder, partialHeader)); + lock (GetClientLock(client)) + { + var (chunks, _) = client.CollapsePtoNB(); + chunks.Count.ShouldBe(1); + chunks[0].Buffer.Length.ShouldBe(2); + chunks[0].Buffer[0].ShouldBe((byte)((byte)WsOpCode.Close | WsConstants.FinalBit)); + } + } + [Fact] // T:3093 public void WSEnqueueCloseMsg_ShouldSucceed() { diff --git a/porting.db b/porting.db index baa47b0a45c9b998ae09c73ee31f95899b60eebb..0d6fe1f6b9bcaef4e490b27e5b23bd2a3e98a3f4 100644 GIT binary patch delta 1715 zcmaLXeM}Q~7zgmSch~aLmxD5Y2Q4o`sfvIVD*`%jh&Yi=K){JkK@Xy2BLp3PEX#(= zWh{#um~1|cX34fFE?Xuq>JH26_K#b#F=kxC+_E6VEzABPO|~oqVP6XN%0El-c#d6Dfwo9Mbd9KTPoGH}U^JYSoKJ=ncIns^98GyCH@5=rZKS zrpC6mM%nBTW^~R_Nf7i8!&WJ%e8A>8jbtu`8N<+ztlov`C zByFl0Nt+stWTgpSl*%w)>lcBf^)n%9{ftOjKLJVW$0J!)k0AcoY!mM5b9kH1xY3v( z%n38p9V2?w(pE9kz#EHbTCf2dfdwozHuHdK&tSIn|l#Y$}2VilbJ$ zOb;=h{_P7Nq!#wGcmoCAPg(7C@g~dFCaL#tGCM~DHL<}vagtkQyR}hoCi_Hk4zXnV zMP+H!GR#t!kK9z;9v|%IprS!mruCysgX|c6@`ojSMV>osYuG6*cUT?Wd%3oNuwH>o zezrxMc)rqSq06^1vB}SNP{3ajoO2-TdTEHgM^zWs1q)7kG{p9YRd)`v(_zbdIE*gZ zrlgOsX1Z60yTyZb(Dx%OPphi2qpVp^4JV$I{bS)5tBYf--A1XEcoM;Fx$y(rt6lxp zB>QqwD#@U><|q61`n4eR_!z`Ne~YS-~cBiLJ}lH z3ap1z)wGoMjT*XnMvkx|#miy3_7JC{aXkPdFx02^Tw zWWZ*~ge=I0E#QHzkOSMm3)>+Vc0eBFLjmlBUGOv%LJ{nSXP_ANKnd)HQrHL2!hR@& z15ggn!SiqsDxeao;1EIdF(LBSw^uck% z1)BR<{*)$W>&=weE8FxjG~XjT=xncCO+WR@&U~YVOEk1Mww-A@gD<$SCh=<$wJ1YDxg$@dp>13=Mg)y9ti8==;-Bji_#|mpve3*nSi%*7_ zn?p=o*o^ZK^+6NI5?{pq@yA-&>Grbt;6xMSoJI@F9!z{_cu+Ih=CAiw<9+xfzwbG} zbI$jkd+$W{LuI0XAsMov7^>kgoQBJA8>NQFC^O0p?*-q{DQWHGu_+%vHswDt=5j2T z%qrOujDIZGU0kP?N%%(IUxo2p!io9ZP!$eJT8e)qX#u(3tAylaY9uv2o=TS2*i^8f za8=P_s(Fg3T5QC2V~tH|Hs!Y|pG|pfs@$f^3JR~Qn%-lJyKTy4Q%;+5*p%s=M;+R? zuenM}q&C%Gg0nmPHFzi?SL4sKvWIt#Y0WYpAJ>Kzj4RskWczVVutrcJ2nZe!R0^ti z`*HSe3kE-BeR$31X~msqSQ5YcvowUcKlBjZKEt+RK2+ty<{8$Ddn$sBcydM8@!Sk+ zwi3V3u>Dxk=PFiAoMmlhLWxaFnE8y=^5wJah8u@}scgh-n$_T6v!dxq$>Zl;Uoa+P z_zLU9Q|DQ`S;xOW&ngrvn9J)9Y~rj7qaUe0rEXfo+6=41pEzs8BlE1GaB9MpqgBP$ z+vix1Weexnfnt*kQ!#ppZL$)tUt;_IOE}P#W*aTPyQjVQ!9~%1B+a(q)xX1L&t7vh zR%h4=Y-kObv0A*HVY{q$+veFT|1+>OFKW$&H7&4F98Wrnd&w1Ce7(Rr%q$OFW}_0W zI6Xza~pqN>P3zs9-=K>S~dJw1yXdTc)Ko0}02YLjk8E6Ag3(!WOD9|RL%|NX{ zF`zb}cAzal9Y9-wI)NSq+6MF((BnYcfx3Wp06hWJ4fG_?Q$SAx?F4!TXctfqP%ls) z(6d0#0rdmLfp!D!0eT+j1)vv!27vYgy#%xmXg|;apqGIT0u2Hk`jQfASp8MGF8;wq zO~?9NBJXhqy;r>#9C>H?=`Ohz6H5v8^q~9>=08c!@o2pim(VwwDxbW0D