// // ReplayTests.swift — T-iOS-16 测试 3:>1 MiB 单帧回放(吸收 spike③ + 对抗变体) // // ring-buffer 回放是单帧全量(src/session/session.ts attachWs → buffer.snapshot()), // JSON 会把控制字节 \uXXXX 转义膨胀 1-6×(src/protocol.ts:186): // - 复现分支:平台默认 maximumMessageSize=1 MiB 收不下(withKnownIssue 常驻记录, // 若"意外通过"说明平台行为变了,须重新评估 Tunables.maxWSMessageBytes) // - 修复分支:Tunables.maxWSMessageBytes(16 MiB)→ 回放完整 // - 对抗变体:ESC/C0 密集输出(转义膨胀 ~6×)→ 仍完整 import Foundation import Testing import WireProtocol @Suite("T-iOS-16 回放上限(真服务器)", .serialized, .timeLimit(.minutes(5))) struct ReplayTests { @Test(">1MiB 单帧回放 — 默认 1MiB 上限复现失败(known issue);Tunables 16MiB 成功") func replayOver1MiBFailsAtDefaultLimitAndSucceedsAt16MiB() async throws { let server = try await ServerHarness.shared.server() // 造数据:attach(null) 后灌 >1MiB 普通输出,再 detach(PTY/ring 存活)。 let generator = WSTestClient(server: server, origin: server.origin) let sessionId = try await attachAndAwaitAttached(client: generator, sessionId: nil) try await generator.send(shellCommand( "perl -e 'print \"a\" x \(HarnessTunables.bulkOutputBytes)'")) let produced = try await accumulateOutputBytes( client: generator, minBytes: HarnessTunables.bulkOutputBytes) #expect(produced >= HarnessTunables.bulkOutputBytes) generator.close() // 复现分支:平台默认 maximumMessageSize(1 MiB) → 回放必失败。 let defaultClient = WSTestClient(server: server, origin: server.origin, maxMessageBytes: nil) let defaultResult = await replayResult( client: defaultClient, sessionId: sessionId, minBytes: HarnessTunables.bulkOutputBytes) defaultClient.close() if case .failure(let error) = defaultResult { #expect(isMessageTooLongError(error), "失败模式应为 NSPOSIXErrorDomain EMSGSIZE(40)/ENOBUFS(55),实际 \(describeError(error))") } withKnownIssue("默认 maximumMessageSize=1MiB 收不下 >1MiB 单帧 ring-buffer 回放 — 平台限制,修法即 Tunables.maxWSMessageBytes=16MiB(若此处'意外通过',说明平台行为变了,须重新评估)") { _ = try defaultResult.get() } // 修复分支:16 MiB → 全量回放成功,attached 采用同一 sessionId。 let bigClient = WSTestClient(server: server, origin: server.origin) let summary = try await replayResult( client: bigClient, sessionId: sessionId, minBytes: HarnessTunables.bulkOutputBytes).get() #expect(summary.adoptedSessionId == sessionId) #expect(summary.totalOutputBytes >= HarnessTunables.bulkOutputBytes) bigClient.close() await killSessionBestEffort(server: server, id: sessionId) } @Test("对抗: ESC/C0 密集输出(JSON 转义膨胀~6×)回放,16MiB 仍完整") func escDenseReplayStillSucceedsAt16MiB() async throws { let server = try await ServerHarness.shared.server() let generator = WSTestClient(server: server, origin: server.origin) let sessionId = try await attachAndAwaitAttached(client: generator, sessionId: nil) // perl 的 \e = ESC(0x1B):每 4 原始字节 JSON 转义成 9 字节("[0m")。 try await generator.send(shellCommand( "perl -e 'print \"\\e[0m\" x \(HarnessTunables.escSequenceRepeats)'")) let produced = try await accumulateOutputBytes( client: generator, minBytes: HarnessTunables.escSequenceRawBytes) #expect(produced >= HarnessTunables.escSequenceRawBytes) generator.close() let bigClient = WSTestClient(server: server, origin: server.origin) let summary = try await replayResult( client: bigClient, sessionId: sessionId, minBytes: HarnessTunables.escSequenceRawBytes).get() #expect(summary.adoptedSessionId == sessionId) #expect(summary.totalOutputBytes >= HarnessTunables.escSequenceRawBytes) #expect(summary.containsSoftReset, "回放应含 ESC[0m(转义序列在回放中原样保留)") bigClient.close() await killSessionBestEffort(server: server, id: sessionId) } }