WebSocket 協議測試實作
WebSocket 協議測試實作
WebSocket 協議測試的目標是驗證 client 端的 WebSocket 操作在真實服務上的行為。這個層級的 test 直接使用 IOWebSocketChannel(真實實作)連線到真實 ttyd 服務,不用 FakeWebSocketChannel。
要驗證什麼
從 T.C1 和 T.C2 的案例推導出 WebSocket protocol test 至少需要覆蓋的場景:
Frame type 驗證
IOWebSocketChannel 對 String 和 Uint8List 產生不同的 frame type(text vs binary)。ttyd 只接受 text frame,收到 binary frame 靜默忽略(T.C1)。
Protocol test 需要驗證:
- 發送
String→ ttyd 回應(text frame 被處理) - 發送
Uint8List→ ttyd 不回應(binary frame 被忽略) - 確認
sendData()函式實際發送的是 text frame
Auth handshake 驗證
ttyd 連線後需要發送 auth token JSON frame 完成認證,認證通過後才推送 terminal output(T.C2)。
Protocol test 需要驗證:
- 連線後發送正確的 auth token → 收到 terminal output
- 連線後不發送 auth token → 逾時無 output
- 連線後發送錯誤的 auth token → 連線被斷開或無 output
連線生命週期驗證
WebSocket 連線的建立、維持、斷開在 mock 環境中都是瞬間完成的。真實環境中有延遲、可能失敗、可能逾時。
Protocol test 需要驗證:
- 連線建立的成功路徑(TCP → WS 升級 → ready)
- 連線逾時的行為(server 不可達時 client 的回應)
- 連線斷開後的狀態(stream 是否正確關閉)
Test 結構
1setUp: 啟動本機 ttyd(Process.start('ttyd', ['bash']))
2tearDown: 停止 ttyd(process.kill())
3
4test('text frame is accepted by ttyd'):
5 channel = IOWebSocketChannel.connect('ws://localhost:7681/ws')
6 await channel.ready
7 channel.sink.add('{"AuthToken":"base64(user:pass)"}')
8 channel.sink.add('echo hello') // String → text frame
9 output = await channel.stream.first.timeout(5s)
10 expect(output, contains('hello'))
11
12test('binary frame is silently ignored by ttyd'):
13 channel = IOWebSocketChannel.connect(...)
14 await channel.ready
15 channel.sink.add('{"AuthToken":"..."}')
16 channel.sink.add(Uint8List.fromList(utf8.encode('echo hello')))
17 expect(channel.stream.first.timeout(2s), throwsTimeoutException)
18
19test('auth token required before output'):
20 channel = IOWebSocketChannel.connect(...)
21 await channel.ready
22 // 不發 auth token,直接發指令
23 channel.sink.add('echo hello')
24 expect(channel.stream.first.timeout(2s), throwsTimeoutException)執行成本
app_tunnel 的 server(ttyd)和 client 在同一台機器上。啟動 ttyd 是一行指令(ttyd bash),不需要 Docker、不需要雲端服務、不需要網路。整個 test suite 的執行時間主要是連線建立和逾時等待,每個 test case 約 2-5 秒。
這個低成本是自用工具的結構優勢 — server 可以在 test 的 setUp 中啟動、tearDown 中停止,不需要共享的 test 環境(本章合成,TF-8 Derive)。
下一步路由
- HTTP 的 contract test 設計 → HTTP contract test 設計
- CI 中的服務管理 → CI 中的服務 fixture 管理
- 什麼時候值得寫 protocol integration test → 成本判斷表