Testing Files Generator
日本語

テスト用の破損ファイルを作る方法

健全なファイルしか見せたことのない検証は、本当にはテストされていません。ここでは、意図的に壊してあり、求めたとおりのサイズで出てきて、システムがそれをどう扱うべきかを示すマニフェストを伴うファイルの作り方を説明します。

短い答え

tfg generate --format png --size 2mb --damage zero-head --out ./outは、ちょうど2097152バイトで先頭のバイトがゼロのPNGを書き出し、隣のマニフェストにはシステムがそれを拒否すべきだと記録されます。

よくあるやり方

手作業で壊したファイルがよくないテストになる理由

よくあるのは、16進エディタ、いくつかのランダムなバイトを反転させるスクリプト、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>はそのうちの1つが受け取る設定を示します。

破損 バイトへの作用 最小ファイル 設定
zero-head ファイルの先頭のバイトをゼロで上書きし、長さは変えません。ほとんどのリーダーはまずそこを見るので、この破損にはほぼどれも気づきます。 8 bytes

zero-headはファイルの先頭をゼロで上書きします。ほとんどのリーダーはまずそこを見ます。ファイルが何であるかを示すシグネチャとヘッダーです。そのため、ほぼどのリーダーでも気づきます。プレーンテキストやログにはシグネチャがありませんが、これらも拒否されます。ゼロのバイトの連なりはテキストではないからです。4バイト未満では、どのリーダーも文句を言わない破損になる形式があります。設定が4から始まるのはそのためです。

マニフェストの内容

何が起こるべきかを示すマニフェスト

破損したファイルにはそれぞれ、システムがそれを拒否すべきことを示す項目が付き、破損の内容がその横に記録されます。

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

2種類のリクエストは、何かが書き込まれる前に拒否されます。どちらもマニフェストの記述が誤ったファイルをディスクに残してしまうからです。

レシピで

1回の実行に健全なファイルと壊れたファイルを

両方を1つのレシピに入れると、マニフェストが各ファイルの期待を持つので、テストにどれがどれかの一覧は要りません。

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

よい拒否は、きれいな拒否です。何が悪かったかを伝えるメッセージが、求めている答えです。サーバーエラー、ハング、書きかけで保存されたファイルは、このテストが見つけるために存在する欠陥です。

次へ

ここからどこへ