Testing Files Generator
Русский

Как сделать повреждённый файл для тестов

Валидатор, которому показывали только здоровые файлы, на самом деле не проверен. Вот как получить файл, намеренно испорченный, выходящий точно того размера, который вы просите, и несущий манифест с указанием, что ваша система должна с ним сделать.

Короткий ответ

tfg generate --format png --size 2mb --damage zero-head --out ./out записывает PNG ровно в 2097152 байта, первые байты которого нули, а манифест рядом фиксирует, что ваша система должна его отклонить.

Обычный путь

Почему файл, испорченный вручную, - плохой тест

Обычно берут шестнадцатеричный редактор, скрипт, переворачивающий несколько случайных байтов, или укорачивают файл через 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

Хороший отказ - это чистый отказ. Сообщение, говорящее, что было не так, - тот ответ, который вам нужен. Ошибка сервера, зависание или наполовину сохранённый файл - тот дефект, ради которого этот тест и существует.

Дальше

Куда идти отсюда