Testing Files Generator
Українська

Документація

Усе, що робить інструмент, розкладено за питаннями, з якими люди справді приходять. README у репозиторії - повний довідник, і він завжди відповідає завантаженій вами збірці.

Які є команди?

Кожна робить одну справу:

tfg generate    створити файли за рецептом або за прапорцями
tfg validate    перевірити рецепт, нічого не записуючи
tfg verify      звірити каталог із маніфестом
tfg cleanup     видалити файли, перелічені в маніфесті
tfg recipe fmt  вивести рецепт у усталеному вигляді
tfg preset      зібрати набір файлів за іменованим тестовим питанням
tfg formats     перелічити формати цієї збірки
tfg damage      перелічити способи, якими ця збірка може навмисно зіпсувати файл
tfg tool        невеликі інструменти для вже наявних файлів
tfg version     вивести версію інструмента
tfg license     вивести ліцензію та що вона означає для створених файлів

Як створити один файл точного розміру?

Укажіть формат, розмір і місце призначення. Розміри рахуються по 1024, тому 2mb - це 2097152 байти. Підійде й просте число байтів, тож --size 10485761 запитує рівно стільки.

tfg generate --format png --size 2mb --out ./out

Корисні прапорці команди generate:

ПрапорецьЩо робить
--format <id>формат файлів, наприклад txt
--size <size>точний розмір кожного файлу, наприклад 10mb або просте число байтів
--size-range <a-b>розмір, що вибирається для кожного файлу з діапазону, наприклад 1kb-8kb. Вибір іде від seed
--boundary <size>три файли навколо ліміту: на байт менше, сам ліміт, на байт більше
--count <n>скільки файлів створити. За замовчуванням 1
--name <template>шаблон імені, наприклад invoice_{index:04}.txt
--out <dir>каталог, у який записувати
--seed <n>seed запуску. Той самий seed дає ті самі байти
--set <k>=<v>налаштування формату, можна повторювати
--damage <name>навмисно зіпсувати файли, можна повторювати, застосовується по порядку. Список виводить tfg damage
--expected <outcome>accept, reject, sanitize або unspecified
--dry-runпорахувати й показати, нічого не записуючи
--jsonзаписати маніфест у стандартний вивід

Як зробити навмисно зламаний файл?

Будь-який інший файл, що його записує цей інструмент, коректний за побудовою, і це відповідає на два з трьох питань, які ставить перевірка завантаження. --damage відповідає на третє - чи відкривається файл узагалі. Файл створюється як зазвичай, а потім псується, тому в нього лишається запитаний розмір.

tfg generate --format png --size 2mb --damage zero-head --out ./out
tfg generate --format png --size 2mb --damage zero-head:bytes=16 --out ./out

Налаштування вказуються після двокрапки. Прапорець можна повторювати, і порядок запису - це порядок застосування. tfg damage перелічує, що вміє ця збірка та що приймає кожен вид пошкодження.

У рецепті ключ - це список імен або налаштувань:

targets:
  - id: broken
    format: png
    count: 5
    size: 2mb
    damage:
      - zero-head
      - type: zero-head
        bytes: 16

Пошкоджений файл отримує в маніфесті expected: reject із записаним поруч пошкодженням. Дві речі відхиляються до запису чого-небудь, бо кожна залишила б на диску файл, неправильно описаний маніфестом:

Третє наперед дізнатися не можна. Якщо пошкодження виконується й не змінює жодного байта, такий файл відкидається, а не записується - запуск триває, повідомляє, що це був за файл, і завершується кодом часткового завершення.

Крок за кроком, з тестом, який читає маніфест: як зробити пошкоджений файл для тестів.

Як виглядає рецепт?

Рецепт - це файл YAML, що описує цілий запуск. Закомітьте його поряд із тестами, і фікстури перестануть бути бінарними файлами у вашому репозиторії - будь-хто зможе відтворити їх байт у байт із файлу в кілька сотень символів.

# fixtures.yaml
version: 1
seed: 7741

defaults:
  label: true

targets:
  - id: invoices
    format: pdf
    count: 25
    size: 300kb
    name: invoice_{index:04}.pdf
    properties:
      pages: 3
      page_size: a4
    expected: accept

  - id: over_the_limit
    format: png
    count: 2
    size: 12mb
    expected:
      outcome: reject
      reason: size_limit

  - id: bundle
    format: zip
    contains:
      - format: txt
        count: 200
        size: 4kb

output:
  dir: ./fixtures
  manifest: manifest.json
tfg validate fixtures.yaml
tfg generate fixtures.yaml

Кожній цілі потрібен рівно один із ключів size, size-range, boundary або contains. Два - це помилка, і жодного - теж. Недійсний рецепт записує жодного файлу і повідомляє про всі проблеми одразу, а не лише про першу, щоразу називаючи налаштування, якого вона стосується.

Як оголосити, що моя система має робити з файлом?

Коротка форма, коли досить результату, і довга, коли важлива причина:

expected: accept
expected:
  outcome: reject
  reason: size_limit

Результати - accept, reject, sanitize і unspecified. Причини утворюють закритий список, щоб звіт міг за ними групувати: content_malformed, count_limit, dimensions_limit, duplicate, encoding_invalid, extension_rule, filename_invalid, filename_too_long, filename_traversal, malware_signature, mime_mismatch, nesting_depth, none, size_limit і size_zero.

Причина називає чинне правило, а не вердикт. Тому та сама причина може стояти під будь-яким результатом - файл на байт менший за ліміт отримує accept, а правило, про яке йдеться, усе одно size_limit.

Що в маніфесті?

Він записується поряд із файлами наприкінці кожного запуску, зокрема й перерваного. Один запис на файл:

{
  "manifest_version": "1.0",
  "tool": { "name": "testing-files-generator", "version": "0.4.0" },
  "run": {
    "id": "run_b359aa8d94",
    "seed": 0,
    "command": "tfg generate --format png --size 2mb --out ./out",
    "platform": { "os": "windows", "arch": "amd64" },
    "complete": true
  },
  "summary": {
    "file_count": 1,
    "total_bytes": 2097152,
    "by_format": { "png": 1 },
    "by_expected": { "unspecified": 1 }
  },
  "files": [
    {
      "path": "files_0001.png",
      "bytes": 2097152,
      "format": "png",
      "fidelity": "full",
      "determinism": "byte",
      "seed": "8dc2d18c",
      "hashes": { "sha256": "1a1f7c..." },
      "properties": { "width": 640, "height": 480 },
      "expected": {
        "outcome": "unspecified",
        "detail": "No expectation was declared for this file.",
        "confidence": "policy_dependent"
      }
    }
  ]
}

recipe_hash додається, якщо запуск був за рецептом, а preset з overrides - якщо за пресетом, тож маніфест завжди можна простежити до того, що його створило.

Кожен запис також містить target_id - id цілі рецепта, що створила файл, а summary.by_target рахує файли кожної цілі. Рецепт із кількома цілями можна тому перевірити ціль за ціллю, не читаючи імена файлів.

Що таке пресет?

Готовий набір файлів, що відповідає на поширене тестове питання, щоб вам не доводилося проєктувати набір самостійно. Пресети - звичайні рецепти всередині, а eject виводить рецепт, щоб ви могли його відредагувати. Кожен пресет має окрему сторінку про те, що він зазвичай знаходить, що входить у набір і які налаштування приймає.

tfg preset list
tfg preset show size-boundaries
tfg generate --preset size-boundaries --limit 10mb --out ./edges
tfg preset eject size-boundaries > my.yaml

show повідомляє, скільки коштував би набір, перш ніж ви його зберете, і прямо каже, коли число - наша тимчасова підстановка, а не ваш ліміт.

Що означають коди завершення?

Кожен кінець має власний код, машиночитний вивід іде в стандартний вивід, а невдалий запуск нічого туди не друкує. Таблиця - заморожений контракт: зміна значення коду вимагає підвищення мажорної версії.

Код Значення
0 Усе спрацювало.
1 Непередбачена помилка всередині інструмента.
2 Неправильна команда або прапорець.
3 Рецепт недійсний.
4 Формат не може зробити те, що просили.
5 Не вдалося прочитати або записати.
6 Недостатньо місця на диску.
7 verify виявив розбіжність.
8 Запуск завершено, але створено не все.
130 Перервано за допомогою Ctrl+C.
143 Зупинено сигналом, так виглядає тайм-аут у CI.
- name: build the fixtures
  run: tfg generate fixtures.yaml --out ./fixtures

- name: run the tests
  run: pytest tests/

- name: nothing moved
  run: tfg verify ./fixtures/manifest.json

Запуск, зупинений за допомогою Ctrl+C, усе одно залишає маніфест і ніколи не залишає наполовину записаного файлу, тож скасоване завдання може бути прибране наступним.

Готові workflow для GitHub Actions і GitLab CI: як генерувати тестові файли в конвеєрі CI.

Чи є десктопне вікно?

Так, той самий рушій із вікном згори, для тестування, яке не автоматизується. Це не урізана версія: тест порівнює два інтерфейси можливість за можливістю, і все, що вміє лише один із них, має бути оголошене й обґрунтоване, а не тихо розходитися.

Екрани: одна партія, пресети, кілька партій одночасно та про програму. Вікно показує, скільки коштував би запуск, перш ніж щось записати, відображає перебіг роботи й може бути скасоване на півдорозі без наполовину записаного файлу. Файл рецепта воно поки не відкриває - рецепти поки справа командного рядка, а вікно збирає свої партії у формі.