Dokumentacja
Wszystko, co narzędzie robi, ułożone jako pytania, z którymi ludzie naprawdę przychodzą. README w repozytorium jest pełną dokumentacją i zawsze odpowiada wersji, którą pobrałeś.
Jakie są komendy?
Każda robi jedną rzecz:
tfg generate tworzy pliki, z przepisu albo z flag
tfg validate sprawdza przepis i nic nie zapisuje
tfg verify sprawdza katalog względem manifestu
tfg cleanup usuwa pliki wypisane w manifeście
tfg recipe fmt wypisuje przepis w postaci uporządkowanej
tfg preset buduje zestaw plików z nazwanego pytania testowego
tfg formats wypisuje formaty, które ta wersja obsługuje
tfg version wypisuje wersję narzędzia
tfg license wypisuje licencję i to, co znaczy dla wygenerowanych plików
Jak wygenerować jeden plik o dokładnym rozmiarze?
Podaj format, rozmiar i katalog. Rozmiary liczą się po 1024, więc 2mb to 2097152
bajty. Zwykła liczba bajtów też zadziała, więc --size 10485761 prosi dokładnie
o tyle.
tfg generate --format png --size 2mb --out ./out
Przydatne flagi komendy generate:
| Flaga | Co robi |
|---|---|
--format <id> | format plików, na przykład txt |
--size <rozmiar> | dokładny rozmiar każdego pliku, na przykład 10mb albo liczba bajtów |
--size-range <a-b> | rozmiar losowany dla każdego pliku z zakresu, na przykład 1kb-8kb. Losowanie idzie z ziarna |
--boundary <rozmiar> | trzy pliki wokół limitu: bajt pod, dokładnie limit, bajt nad |
--count <n> | ile plików zapisać. Domyślnie 1 |
--name <szablon> | szablon nazwy, na przykład invoice_{index:04}.txt |
--out <katalog> | katalog, do którego trafiają pliki |
--seed <n> | ziarno przebiegu. To samo ziarno daje te same bajty |
--set <k>=<v> | ustawienie formatu, można powtarzać |
--expected <wynik> | accept, reject, sanitize albo unspecified |
--dry-run | policz i pokaż, nie zapisuj niczego |
--json | wypisz manifest na standardowe wyjście |
Jak wygląda przepis?
Przepis to plik YAML opisujący cały przebieg. Commitujesz go obok testów i dane testowe przestają być binariami w repozytorium - każdy może je odtworzyć, co do bajta, z pliku o długości kilkuset znaków.
# 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
Każdy cel potrzebuje dokładnie jednego z: size, size-range,
boundary albo contains. Dwa naraz to błąd, brak też. Niepoprawny przepis
nie tworzy ani jednego pliku i zgłasza wszystkie problemy naraz, a nie pierwszy
z brzegu, przy czym każdy nazywa ustawienie, o które chodzi.
Jak zadeklarować, co system ma zrobić z plikiem?
Krótka forma, gdy wystarczy sam wynik, i długa, gdy liczy się powód:
expected: accept
expected:
outcome: reject
reason: size_limit
Wyniki to accept, reject, sanitize i
unspecified. Powody są zamkniętą listą, żeby raport mógł po nich grupować:
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 i size_zero.
Powód nazywa regułę, o którą chodzi, a nie werdykt. Dlatego ten sam powód może
stać pod jednym i pod drugim wynikiem - plik bajt pod limitem jest accept, a reguła,
której dotyczy, to dalej size_limit.
Co zawiera manifest?
Powstaje obok plików na koniec każdego przebiegu, także takiego, który został przerwany. Jedna pozycja na plik:
{
"manifest_version": "1.0",
"tool": { "name": "testing-files-generator", "version": "0.1.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"
}
}
]
}
Do tego dochodzi recipe_hash, gdy przebieg pochodził z przepisu, oraz
preset i overrides, gdy pochodził z presetu - żeby manifest zawsze dało
się prześledzić z powrotem do tego, co go wyprodukowało.
Czym jest preset?
To gotowy zestaw plików odpowiadający na częste pytanie testowe, żebyś nie musiał projektować
zestawu samodzielnie. Presety są pod spodem zwykłymi przepisami, a eject wypisuje ten
przepis, więc możesz go od tego miejsca edytować.
-
size-boundariesCzy limit rozmiaru działa dokładnie tam, gdzie jest zadeklarowany?
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 mówi, ile zestaw będzie kosztował, zanim go zbudujesz, i wprost zaznacza, kiedy
liczba jest naszą wartością zastępczą, a nie Twoim limitem.
Co znaczą kody wyjścia?
Każde zakończenie ma własny kod, wyjście czytelne dla maszyny idzie na standardowe wyjście, a nieudany przebieg nie pisze tam nic. Tabela jest zamrożonym kontraktem - zmiana znaczenia kodu wymaga podniesienia wersji głównej.
| Kod | Znaczenie |
|---|---|
0 |
Wszystko się udało. |
1 |
Nieoczekiwany błąd wewnątrz narzędzia. |
2 |
Zła komenda albo flaga. |
3 |
Przepis jest niepoprawny. |
4 |
Format nie potrafi tego, o co poproszono. |
5 |
Odczyt albo zapis się nie powiódł. |
6 |
Za mało miejsca na dysku. |
7 |
verify znalazło niezgodność. |
8 |
Przebieg się zakończył, ale nie wszystko powstało. |
130 |
Przerwane przez Ctrl+C. |
143 |
Zatrzymane sygnałem - tak wygląda przekroczony czas w 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
Przebieg zatrzymany przez Ctrl+C i tak zostawia manifest i nigdy nie zostawia pliku zapisanego w połowie, więc anulowane zadanie da się posprzątać następnym.
Czy jest okno?
Tak, ten sam silnik z oknem, do testowania, które nie jest skryptowane. Nie jest okrojoną wersją: test porównuje obie powierzchnie możliwość po możliwości, a wszystko, co potrafi tylko jedna z nich, musi być zadeklarowane i uzasadnione, zamiast po cichu się rozjeżdżać.
Ekrany to pojedynczy wsad, presety, kilka wsadów naraz i informacje o programie. Okno pokazuje, ile przebieg będzie kosztował, zanim cokolwiek zapisze, melduje postęp w trakcie i da się je przerwać w połowie bez zostawiania pliku zapisanego do połowy. Nie wczytuje jeszcze przepisu z pliku - przepisy są na razie sprawą wiersza poleceń, a okno buduje swoje wsady w formularzu.