Testing Files Generator
Italiano

Documentazione

Tutto ciò che fa lo strumento, organizzato come le domande con cui le persone arrivano davvero. Il README nel repository è il riferimento completo e corrisponde sempre alla build che hai scaricato.

Quali comandi esistono?

Ognuno fa una cosa sola:

tfg generate    produrre file, da una ricetta o da opzioni
tfg validate    controllare una ricetta senza scrivere nulla
tfg verify      controllare una directory rispetto a un manifest
tfg cleanup     rimuovere i file elencati da un manifest
tfg recipe fmt  stampare una ricetta nella sua forma normalizzata
tfg preset      costruire un set di file a partire da una domanda di test con nome
tfg formats     elencare i formati supportati da questa versione
tfg damage      elencare i modi in cui questa versione può rompere un file di proposito
tfg tool        piccole utilità per file che hai già
tfg version     stampare la versione dello strumento
tfg license     stampare la licenza e cosa significa per i file generati

Come genero un singolo file di dimensione esatta?

Indica il formato, la dimensione e la destinazione. Le dimensioni si contano a 1024, quindi 2mb sono 2097152 byte. Funziona anche un semplice numero di byte, quindi --size 10485761 chiede esattamente quel numero.

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

Le opzioni utili di generate:

OpzioneCosa fa
--format <id>formato dei file, per esempio txt
--size <size>dimensione esatta di ogni file, come 10mb o un semplice numero di byte
--size-range <a-b>una dimensione estratta per file da un intervallo, come 1kb-8kb. L'estrazione viene dal seed
--boundary <size>tre file attorno a un limite: un byte sotto, il limite, un byte sopra
--count <n>quanti file produrre. Predefinito 1
--name <template>modello del nome, per esempio invoice_{index:04}.txt
--out <dir>directory in cui scrivere
--seed <n>seed dell'esecuzione. Lo stesso seed dà gli stessi byte
--set <k>=<v>un'impostazione di formato, ripetibile
--damage <name>rompere i file di proposito, ripetibile e applicato in ordine. Esegui tfg damage per l'elenco
--expected <outcome>accept, reject, sanitize oppure unspecified
--dry-runcontare e mostrare, senza scrivere assolutamente nulla
--jsonscrivere il manifest sullo standard output

Come faccio un file rotto di proposito?

Ogni altro file che questo strumento scrive è corretto per costruzione, il che risponde a due delle tre domande che pone un validatore di upload. --damage risponde alla terza - il file si apre, almeno. Il file viene prodotto normalmente e poi rotto, quindi ha ancora la dimensione che hai chiesto.

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

Le impostazioni vanno dopo i due punti. L'opzione si ripete, e l'ordine in cui le scrivi è l'ordine in cui vengono applicate. tfg damage elenca cosa può fare questa versione e cosa accetta ciascuno.

In una ricetta la chiave è un elenco, di nomi o di impostazioni:

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

Un file danneggiato riceve expected: reject nel manifest, con il danno registrato accanto. Due cose vengono rifiutate prima di scrivere qualsiasi cosa, perché ciascuna metterebbe su disco un file che il manifest descrive in modo sbagliato:

Una terza non si può sapere in anticipo. Se un danno viene eseguito e non sposta alcun byte, quel file viene scartato invece di essere scritto - l'esecuzione prosegue, dice di quale file si trattava e termina con il codice di uscita parziale.

Passo dopo passo, con un test che legge il manifest: come creare un file corrotto per i test.

Che aspetto ha una ricetta?

Una ricetta è un file YAML che descrive un'intera esecuzione. Committala accanto ai tuoi test e le fixture smettono di essere binari nel tuo repository - chiunque può ricostruirle, byte per byte, da un file di poche centinaia di caratteri.

# 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

Ogni target richiede esattamente una di queste chiavi: size, size-range, boundary o contains. Due è un errore, e anche nessuna. Una ricetta non valida scrive nessun file e segnala tutti i problemi insieme invece del solo primo, ognuno con il nome dell'impostazione a cui si riferisce.

Come dichiaro cosa deve fare il mio sistema con un file?

Forma breve quando basta l'esito, forma lunga quando conta il motivo:

expected: accept
expected:
  outcome: reject
  reason: size_limit

Gli esiti sono accept, reject, sanitize e unspecified. I motivi sono un elenco chiuso così un report può raggrupparli: 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 e size_zero.

Un motivo nomina la regola in gioco, non il verdetto. Ecco perché lo stesso motivo può stare sotto l'uno o l'altro esito - un file un byte sotto un limite è accept, e la regola in questione resta size_limit.

Cosa c'è nel manifest?

Viene scritto accanto ai file alla fine di ogni esecuzione, compresa un'esecuzione interrotta. Una voce per file:

{
  "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"
      }
    }
  ]
}

Un recipe_hash viene aggiunto quando l'esecuzione viene da una ricetta, e preset con overrides quando viene da un preset, così un manifest si può sempre ricondurre a ciò che lo ha prodotto.

Ogni voce porta anche target_id, l'id del target della ricetta che ha prodotto il file, e summary.by_target conta i file a cui è arrivato ciascun target. Una ricetta con più target si può quindi controllare target per target senza leggere i nomi dei file.

Cos'è un preset?

Un set di file pronto che risponde a una domanda di test comune, così non devi progettare il set tu. I preset sono ricette ordinarie sotto il cofano, e eject stampa la ricetta così puoi modificarla da lì. Ogni preset ha una pagina tutta sua con cosa trova di solito, cosa c'è nel set e ogni impostazione che accetta.

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 ti dice quanto costerebbe il set prima di costruirlo, e dice apertamente quando un numero è un segnaposto nostro anziché un limite tuo.

Cosa significano i codici di uscita?

Ogni conclusione ha il suo codice, l'output leggibile da macchina va sullo standard output, e un'esecuzione fallita non vi stampa nulla. La tabella è un contratto congelato - cambiare il significato di un codice richiede una versione maggiore.

Codice Significato
0 Tutto ha funzionato.
1 Un errore imprevisto dentro lo strumento.
2 Comando od opzione errati.
3 La ricetta non è valida.
4 Il formato non può fare ciò che è stato chiesto.
5 Una lettura o una scrittura è fallita.
6 Spazio su disco insufficiente.
7 verify ha trovato una discrepanza.
8 L'esecuzione è terminata ma non tutto è stato prodotto.
130 Interrotto con Ctrl+C.
143 Fermato da un segnale, che è l'aspetto di un timeout della 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

Un'esecuzione fermata con Ctrl+C lascia comunque un manifest e non lascia mai un file scritto a metà, così un job annullato può ancora essere ripulito dal successivo.

Workflow pronti per GitHub Actions e GitLab CI: come generare file di test in una pipeline CI.

Esiste una finestra desktop?

Sì, lo stesso motore con una finestra sopra, per il test che non è automatizzato. Non è una versione ridotta: un test confronta le due interfacce capacità per capacità, e tutto ciò che può fare solo una delle due va dichiarato e giustificato invece di divergere in silenzio.

Le schermate sono un lotto, i preset, più lotti insieme e Informazioni. Mostra quanto costerebbe un'esecuzione prima di scrivere qualsiasi cosa, riporta l'avanzamento mentre gira e si può annullare a metà senza lasciare un file scritto a metà. Non apre ancora un file di ricetta - per ora le ricette sono una faccenda da riga di comando, e la finestra costruisce i suoi lotti nel modulo.