emma-hermes/skills/devops/gateway-identity-binding-li.../references/line-telegram-smoke-test-pa...

6.7 KiB
Raw Blame History

LINE / Telegram 驗證整合煙霧測試模式

這份文件給未來要補或修改 smoke / integration test 的人看。

目標不是「再寫一批單元測試」,而是驗證:真事件路徑接起來後,整條驗證 / 授權 / handoff 水管沒有漏水。

相關背景:

  • references/line-telegram-verification-lifecycle.md
  • references/line-telegram-test-map.md
  • references/line-telegram-must-run-commands.md

什麼情況該寫 smoke test

當你改到下面任一類時,不能只靠 helper / route unit tests

  • LINE / Telegram adapter intake gate
  • onboarding / verification state machine
  • verified email handoff guard
  • quota fallback / email fallback
  • admin unbind / pairing revoke
  • runner authz 與 verified binding 的交界

一句話判斷:

如果這個改動需要同時假設「adapter 有正確 dispatch」和「store / authz 也會照預期接住」,就該補 smoke test。


Smoke test 的最小骨架

一支合格的 LINE / Telegram 驗證 smoke test至少要穿過這些步驟

  1. 真平台事件進 adapter
  2. adapter 真的 dispatch 到 handle_message(...)
  3. GatewayUserStore.process_inbound_message(...) 產生 onboarding / verification decision
  4. verify_token(...) 後 verified binding 生效
  5. live auth / handoff 路徑真的吃到 verified binding
  6. unbind_identity(...) 後 verified / pairing / authz / handoff 失效
  7. 同一來源再次進來時,可重新 onboarding

如果只測到第 3 步或第 4 步,通常還不算 smoke只算比較胖的 unit test。


目前已存在的參考實作

檔案:

  • tests/gateway/test_line_telegram_verification_smoke.py

關鍵測試:

  • test_line_dm_verification_smoke
  • test_telegram_dm_verification_smoke

這兩顆目前已覆蓋:

LINE

  • DM event 經 LineAdapter._dispatch_event(...) 進來
  • GatewayUserStore.process_inbound_message(...)
  • verify_token(...)get_verified_email_for_source(...) 生效
  • _send_email_quota_fallback(...) 真的寄到 live 綁定 email
  • unbind_identity(...) 後 fallback 失效
  • 同來源再次進來可重新要求驗證

Telegram

  • text update 經 TelegramAdapter._handle_text_message(...) 進來
  • text batch flush 後真的 dispatch
  • verify_token(...) 後 verified source 生效
  • PairingStore()._approve_user(...) 後 runner authz 生效
  • unbind_identity(...) 後 runner authz 失效
  • 同來源再次進來可重新要求驗證

兩個最容易踩的坑

1. Telegram text handler 不是同步直送

症狀:

  • 你呼叫 _handle_text_message(...)
  • decisions / handle_message 沒收到任何東西
  • 看起來像 Telegram 流程壞掉

真正原因:

  • Telegram text path 先進 _enqueue_text_event(...)
  • 真正 dispatch 發生在 _flush_text_batch(...)
  • 如果測試沒等 flush會誤判成流程沒進去

建議模式:

async def _run_telegram_text(adapter, update):
    await adapter._handle_text_message(update, SimpleNamespace())
    pending = list(adapter._pending_text_batch_tasks.values())
    if pending:
        await asyncio.gather(*pending)

原則: 不要只呼叫 _handle_text_message() 就假設 event 已送達。


2. LINE / Telegram 第二次重送 onboarding 可能撞到 resend cooldown

症狀:

  • 你在 unbind 後立刻重送同一個 email
  • 預期拿到 send_verification_email
  • 實際卻拿到 handled

真正原因:

  • verification_requests.last_sent_at 還在 cooldown 視窗內
  • 你撞到 resend / rate-limit 保護,不是狀態機壞掉

建議模式: 在本地 smoke test 裡,把 last_sent_at 人工往前調,讓你驗的是「重新 onboarding 能否成立」,不是節流是否生效。

UPDATE verification_requests
SET last_sent_at = datetime('now', '-11 minutes')
WHERE platform = ? AND external_user_id = ?

原則: 當測試目標是驗證狀態轉換,允許把節流窗移開;但要在註解或文件說明這是為了避開 rate-limit 噪音。


建議測試設計原則

A. 盡量走真 adapter 入口

優先選:

  • LINE_dispatch_event(...)
  • Telegram_handle_text_message(...)

比起直接手刻 MessageEvent 然後呼叫 handle_message(...),這樣更能抓到:

  • source 解析錯誤
  • DM / group / room 分流錯誤
  • prefilter / batching / postback 之類的邊界問題

B. mock 要薄,不要整條路都 fake 掉

可以 mock

  • LINE client 的 reply / push / loading
  • email send function
  • bot network calls

不要 mock 到:

  • GatewayUserStore.process_inbound_message(...)
  • verify_token(...)
  • unbind_identity(...)
  • runner _is_user_authorized(...)

否則你只是把 smoke test 再拆回單元測試 cosplay。

C. 要驗「生效」與「失效」兩面

不夠只驗:

  • verify 後可用

還要驗:

  • unbind 後失效
  • pairing revoke 後失效
  • fallback / handoff 不再寄到舊綁定 email

D. 最後一輪最好重跑 onboarding

真正容易壞的常常不是第一次 onboarding而是

  • verify 過一次
  • unbind
  • 再次 onboarding

所以 smoke test 最後建議再讓同一來源進來一次,確認沒有殘留狀態把它卡死。


建議命名方式

推薦:

  • test_line_dm_verification_smoke
  • test_telegram_dm_verification_smoke
  • test_<platform>_<path>_smoke

不推薦:

  • test_integration_1
  • test_full_flow
  • test_regression

原則是: 檔名 / test name 一眼要看得出是哪個平台、哪條路、是不是 smoke。


什麼時候要擴充既有 smoke而不是另開新檔

優先擴充 tests/gateway/test_line_telegram_verification_smoke.py,如果你的改動仍屬於:

  • DM onboarding / verification
  • verified binding / handoff
  • unbind / pairing revoke
  • authz 存活與失效

只有在測試目標已明顯換成另一條主線時,再另開檔,例如:

  • forum / topic / group 專用 state machine
  • webhook retry / duplicate event idempotency
  • home-channel / control-channel 特化行為

Smoke test 完成後至少再跑什麼

最少建議:

pytest -q \
  tests/gateway/test_line_telegram_verification_smoke.py \
  tests/hermes_cli/test_web_verification_admin.py \
  tests/gateway/test_line_plugin.py \
  tests/gateway/test_telegram_auth_check.py \
  tests/gateway/test_verified_email_handoff_guard_helpers.py

如果改到 pairing / allowlist bypass再加

pytest -q \
  tests/gateway/test_pairing.py \
  tests/gateway/test_pairing_allowlist_bypass.py

一句話總結

Smoke test 的任務不是證明某個 helper 很乖, 而是證明 LINE / Telegram 真事件進來後adapter、store、authz、handoff、unbind 這幾層還能一起活著回家。