我現在請 AI 補測試,會請它把這次要防的錯誤故意加進去,看看原本的測試會不會失敗。不然測試都過了,我還是不知道程式真的寫錯時,它抓不抓得到。
這次拿 Kafka 實際試,就看到兩種不同的結果:把錯誤吞掉,拒收測試會失敗;把發送確認的設定改錯,拒收測試卻照樣通過,要靠另一個單元測試抓。
那次跟 AI 改一段 kafka-go 的發送程式,我們設定成 RequireAll,等同步中的副本都確認收到。同時也補測試,確認 Kafka 拒收訊息時,呼叫它的程式拿得到錯誤。
原本想用只有一份副本的 topic,把最低同步副本數設成 2。只有一份,卻要求兩份,看起來應該送不進去。
查下去才發現,本機用的 Kafka 3.8.0 會取設定值和副本數比較小的那個。副本只有 1,填 2 也還是按 1 算,原始碼裡就有這段處理。這樣沒辦法讓它拒收。
後來換成訊息大小限制。在本機測試用的 topic,把 max.message.bytes 設成 1 byte,再從應用程式送超過限制的訊息。測試要收到 MessageSizeTooLarge 才算過,否則連不上 Kafka 也有 error,就不知道到底測到什麼。正常的 topic 則送出再讀回,確認同一套程式能正常發送。
整理這篇時,我請 AI 在隔離副本裡做 mutation testing(變異測試),本機用的是單一 broker 的 Kafka 3.8.0。先確認測試通過,再一次改一處程式,測試不動,跑完再還原。
先改一般發送路徑,讓程式收到拒收錯誤後回傳 nil。原本會過的拒收測試立刻失敗,指出應該收到錯誤,實際卻沒有。把錯誤傳遞還原,再跑就通過了。
接著只把 RequireAll 改成只等 leader 的 acks=1。這次拒收和正常讀回測試全部通過,失敗的是檢查 RequiredAcks 值的單元測試:預期是 -1(all),實際是 1。改回來後,兩邊又都通過。
訊息超過大小限制,設定成 acks=1 也能收到拒收錯誤,所以那個案例分不出有沒有等同步副本確認。它確實抓得到吞錯誤的問題;設定被改掉,則是另一個測試負責抓。至於副本掉線或 leader 故障後資料還在不在,這次沒有測到。
換到其他服務,測試要接的位置也可能不同。我們用的 Kafka 套件不只一種,所以我會讓 AI 先看各個專案的 go.mod,再找建立 client、發送訊息和接收結果的地方。像非同步發送,錯誤可能在後面的 callback 或 delivery report 才回來。下面留一份對照,依指定版本的文件和原始碼整理,沒有逐套跑故障測試。
| 套件/這次查的版本 | 預設等誰確認 | 結果去哪裡看 |
|---|---|---|
| kafka-go v0.4.48 | 直接建立 Writer 是 acks=0;舊的 NewWriter 會把 0 補成 all。 |
同步看 WriteMessages 回傳值;非同步接 Completion。 |
| franz-go v1.21.7 | acks=all。 |
Produce 看 callback;ProduceSync 等送完,再檢查每筆結果的錯誤。 |
| IBM Sarama v1.60.2 | NewConfig() 預設 acks=1,等 leader 確認。 |
同步看回傳錯誤;非同步要持續讀取已啟用的 Errors()/Successes() channel。 |
| confluent-kafka-go v2.15.0/librdkafka v2.15.0 | acks=all。 |
Produce 先告訴你有沒有排進佇列;送出結果看 delivery report 裡的 TopicPartition.Error。 |