Testing Files Generator
繁體中文

如何製作用於測試的損毀檔案

一個只見過完好檔案的驗證器,並沒有真正被測試過。以下說明如何取得一個刻意弄壞的檔案:它的大小恰好就是你要求的大小,並附帶一份清單,說明你的系統該如何處理它。

簡短回答

tfg generate --format png --size 2mb --damage zero-head --out ./out 會寫出一個恰好 2097152 位元組的 PNG,它開頭的幾個位元組是零,旁邊的清單則記錄你的系統應該拒絕它。

常見做法

為什麼手工弄壞的檔案不是好測試

常見做法是用十六進位編輯器、用指令碼翻轉幾個隨機位元組,或用 head 或 truncate 把檔案截短。這些做法能用一次,之後就要付出代價:

你會得到什麼

損毀的檔案仍然是你要求的大小

檔案先正常產生,再在寫入磁碟的途中被弄壞。它保持你要求的大小,同一個指令再次寫出的位元組也完全相同。

tfg generate --format png --size 2mb --damage zero-head --out ./out
tfg generate --format pdf --size 1mb --count 5 --damage zero-head:bytes=16 --out ./broken

設定寫在冒號之後。該選項可以重複,損毀依你寫下的順序逐一套用。它適用於全部 26 種格式。

它能做什麼

有哪些損毀方式?

這是程式印出的清單,在建置本頁時從程式中讀取。tfg damage 印出的是同一份清單,tfg damage <id> 則說明其中某一項接受什麼設定。

損毀方式 對位元組做了什麼 最小檔案 設定
zero-head 用零覆蓋檔案開頭的若干位元組,長度保持不變。大多數讀取器最先看的就是那裡,所以幾乎任何東西都會發現這種損毀。 8 bytes

zero-head 把檔案開頭寫成零。大多數讀取器最先看的就是那裡,也就是說明檔案是什麼的簽章和檔頭,所以幾乎任何讀取器都會發現。純文字和日誌沒有簽章,同樣會被拒絕,因為一串零位元組不是文字。低於四個位元組時,有些格式產生的損毀沒有任何讀取器會抱怨,這就是該設定從四開始的原因。

清單怎麼說

一份說明應發生什麼的清單

每個損毀的檔案都會得到一筆記錄,說明你的系統應該拒絕它,損毀方式記在旁邊:

"expected": {
  "outcome": "reject",
  "reason": "content_malformed",
  "confidence": "certain"
},
"damage": [
  {
    "type": "zero-head",
    "settings": {
      "bytes": "8"
    }
  }
]

有兩種請求會在寫入任何內容之前被拒絕,因為各自都會在磁碟上留下一個清單描述有誤的檔案:

在配方中

一次執行中的完好檔案和損毀檔案

把兩者放進同一個配方,清單就帶有每個檔案的預期,測試因此不需要一份說明哪個是哪個的列表:

version: 1
targets:
  - id: healthy
    format: pdf
    size: 1mb
    expected: accept
  - id: broken
    format: pdf
    size: 1mb
    damage:
      - zero-head

在測試中

把它變成測試

測試讀取清單,檢查實際發生的是否就是所宣告的。它不需要檔名列表:

import json, os

directory = "healthy-and-broken"
manifest = json.load(open(os.path.join(directory, "manifest.json")))

for entry in manifest["files"]:
    response = upload(os.path.join(directory, entry["path"]))
    if entry["expected"]["outcome"] == "reject":
        assert not response.ok
    else:
        assert response.ok

好的拒絕是乾淨的拒絕。一則說明錯在哪裡的訊息,就是你想要的答案。伺服器錯誤、卡死或只儲存了一半的檔案,正是這個測試要找出來的缺陷。

接下來

從這裡去哪裡