diff --git a/graphcode/Tests/OutboundChannelReviewTests.swift b/graphcode/Tests/OutboundChannelReviewTests.swift index 1c7d4b08..b446528f 100644 --- a/graphcode/Tests/OutboundChannelReviewTests.swift +++ b/graphcode/Tests/OutboundChannelReviewTests.swift @@ -136,4 +136,83 @@ struct OutboundChannelReviewTests { let elapsed = Date().timeIntervalSince(started) #expect(elapsed < 20, "150 rounds of open/send/close took \(elapsed)s") } + + /// The writer now hands the kernel whatever it will take per call and resumes from + /// where it stopped. Every partial write must resume at the right byte and nothing may + /// be sent twice: a peer that drains in small gulps, with a receive buffer far smaller + /// than any frame, must reassemble every frame intact and in order. + @Test + func partialWritesResumeWithoutTruncatingOrDuplicating() throws { + let (daemon, client) = makeSocketPair() + var tiny: Int32 = 2048 + setsockopt(client, SOL_SOCKET, SO_RCVBUF, &tiny, socklen_t(MemoryLayout.size)) + setsockopt(daemon, SOL_SOCKET, SO_SNDBUF, &tiny, socklen_t(MemoryLayout.size)) + OutboundChannels.open(daemon) + defer { + OutboundChannels.close(daemon) + close(client) + } + + let sizes = [1, 3, 2047, 2048, 2049, 4095, 8191, 8192, 100_000, 7, 65_537, 300_000, 2] + let sent = sizes.enumerated().map { index, size in + Data((0..