Come creare un file corrotto per i test
Un validatore a cui sono stati mostrati solo file sani non è stato davvero testato. Ecco come ottenere un file rotto di proposito, che esce con esattamente la dimensione richiesta e porta un manifest che dice cosa il tuo sistema deve farne.
La risposta breve
tfg generate --format png --size 2mb --damage zero-head --out ./out scrive un PNG di
esattamente 2097152 byte i cui primi byte sono zeri, e il manifest accanto registra che il tuo
sistema deve rifiutarlo.
Il modo solito
Perché un file corrotto a mano è un cattivo test
I modi soliti sono un editor esadecimale, uno script che cambia qualche byte a caso o un file
accorciato con head o truncate. Funzionano una volta, poi costano:
- È diverso ogni volta. Un byte casuale cade in un punto nuovo a ogni esecuzione, quindi un errore del martedì può non ripresentarsi il mercoledì.
- Cambia la dimensione. Un file tagliato è più piccolo del limite sotto cui doveva stare, quindi il controllo della dimensione risponde prima di quello del contenuto e il test passa per il motivo sbagliato.
- Spesso passa inosservato. Il testo semplice si legge ancora con un byte cambiato nel mezzo, e un lettore di immagini indulgente lo disegna e basta, così il file che doveva essere rotto viene accettato.
- Non dice nulla su cosa deve succedere. Il file è solo byte, e chi legge il test dopo deve indovinare se si voleva l'accettazione o il rifiuto.
Cosa ottieni
Un file danneggiato ha ancora la dimensione richiesta
Il file viene generato normalmente e rotto dopo, mentre va verso il disco. Mantiene la dimensione richiesta, e lo stesso comando riscrive gli stessi byte.
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
Le impostazioni vanno dopo i due punti. L'opzione si può ripetere, e i danni vengono applicati nell'ordine in cui li scrivi. Funziona con ognuno dei 26 formati.
Cosa sa fare
Quali danni ci sono?
Questa è la lista che il programma stampa, letta da lui quando si costruisce questa pagina.
tfg damage stampa la stessa, e tfg damage <id> dice cosa accetta
ciascuno.
| Danno | Cosa fa ai byte | File più piccolo | Impostazioni |
|---|---|---|---|
zero-head |
Sovrascrive con zeri i primi byte del file, lasciandone intatta la lunghezza. La maggior parte dei lettori guarda prima lì, quindi quasi tutto si accorge di questo danno. | 8 | bytes |
zero-head scrive zeri sull'inizio del file. La maggior parte dei lettori guarda prima
lì, la firma e l'intestazione che dicono cos'è il file, quindi quasi ogni lettore se ne accorge.
Il testo semplice e i log non hanno firma e vengono rifiutati lo stesso, perché una serie di
byte nulli non è testo. Sotto i quattro byte alcuni formati escono con un danno di cui nessun
lettore si lamenta, ed è per questo che l'impostazione parte da quattro.
Cosa dice il manifest
Un manifest che dice cosa deve succedere
Ogni file danneggiato riceve una voce che dice che il tuo sistema deve rifiutarlo, con il danno registrato accanto:
"expected": {
"outcome": "reject",
"reason": "content_malformed",
"confidence": "certain"
},
"damage": [
{
"type": "zero-head",
"settings": {
"bytes": "8"
}
}
]
Due richieste vengono rifiutate prima che venga scritto qualcosa, perché ciascuna lascerebbe su disco un file che il manifest descrive male:
- un file più piccolo di quanto serve al danno, che uscirebbe intatto
-
expected: acceptaccanto a un danno, perché nulla potrebbe soddisfarlo. Scrivisanitizese il tuo sistema deve riparare il file, oppureunspecifiedse è proprio questa la domanda che poni
In una ricetta
File sani e rotti in una sola esecuzione
Metti entrambi in una ricetta, e il manifest porta l'aspettativa di ogni file, così il test non ha bisogno di un elenco di quale sia quale:
version: 1
targets:
- id: healthy
format: pdf
size: 1mb
expected: accept
- id: broken
format: pdf
size: 1mb
damage:
- zero-head
In un test
Trasformarlo in un test
Il test legge il manifest e controlla che ciò che è successo sia ciò che era stato dichiarato. Non ha bisogno di un elenco di nomi di file:
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
Un buon rifiuto è un rifiuto pulito. Un messaggio che dice cosa non andava è la risposta che vuoi. Un errore del server, un blocco o un file salvato a metà è il difetto che questo test esiste per trovare.
Avanti
Dove andare da qui
- Il preset upload-validation pone a un modulo le altre due domande, quella sulla dimensione e quella sul tipo.
- File di test in CI esegue in una pipeline una ricetta come questa.
-
La documentazione riporta ogni opzione di
tfg generate.