Testing Files Generator
Español

Cómo crear un archivo corrupto para pruebas

Un validador al que solo se le han mostrado archivos sanos no está realmente probado. Así se consigue un archivo roto a propósito, que sale con exactamente el tamaño que pides y trae un manifiesto que dice qué debe hacer tu sistema con él.

La respuesta corta

tfg generate --format png --size 2mb --damage zero-head --out ./out escribe un PNG de exactamente 2097152 bytes cuyos primeros bytes son ceros, y el manifiesto que lo acompaña registra que tu sistema debe rechazarlo.

La forma habitual

Por qué un archivo corrompido a mano es una mala prueba

Lo habitual es un editor hexadecimal, un script que cambia unos cuantos bytes al azar o cortar un archivo con head o truncate. Funciona una vez y después sale caro:

Lo que obtienes

Un archivo dañado conserva el tamaño que pediste

El archivo se genera con normalidad y se rompe después, de camino al disco. Conserva el tamaño que pediste, y el mismo comando vuelve a escribir los mismos bytes.

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

Los ajustes van después de dos puntos. La opción se puede repetir, y los daños se aplican en el orden en que los escribes. Funciona con cada uno de los 26 formatos.

Lo que puede hacer

¿Qué daños hay?

Esta es la lista que imprime el programa, leída de él al construir esta página. tfg damage imprime la misma, y tfg damage <id> dice qué admite cada uno.

Daño Qué hace con los bytes Archivo más pequeño Ajustes
zero-head Sobrescribe los primeros bytes del archivo con ceros sin tocar su longitud. La mayoría de los lectores miran ahí primero, así que casi todo nota este daño. 8 bytes

zero-head escribe ceros sobre el comienzo del archivo. La mayoría de los lectores miran ahí primero, la firma y la cabecera que dicen qué es el archivo, así que casi cualquier lector lo nota. El texto plano y los registros no tienen firma y también se rechazan, porque una serie de bytes nulos no es texto. Por debajo de cuatro bytes algunos formatos salen con un daño del que ningún lector se queja, por eso el ajuste empieza en cuatro.

Lo que dice el manifiesto

Un manifiesto que dice lo que debe ocurrir

Cada archivo dañado recibe una entrada que dice que tu sistema debe rechazarlo, con el daño anotado al lado:

"expected": {
  "outcome": "reject",
  "reason": "content_malformed",
  "confidence": "certain"
},
"damage": [
  {
    "type": "zero-head",
    "settings": {
      "bytes": "8"
    }
  }
]

Se rechazan dos peticiones antes de escribir nada, porque cada una dejaría en el disco un archivo que el manifiesto describe mal:

En una receta

Archivos sanos y rotos en una sola ejecución

Pon ambos en una receta y el manifiesto lleva lo esperado de cada archivo, así que la prueba no necesita una lista de cuál es cuál:

version: 1
targets:
  - id: healthy
    format: pdf
    size: 1mb
    expected: accept
  - id: broken
    format: pdf
    size: 1mb
    damage:
      - zero-head

En una prueba

Convertirlo en una prueba

La prueba lee el manifiesto y comprueba que lo ocurrido es lo declarado. No necesita una lista de nombres de archivo:

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 buen rechazo es un rechazo limpio. Un mensaje que dice qué estaba mal es la respuesta que quieres. Un error de servidor, un bloqueo o un archivo guardado a medias es el defecto que esta prueba existe para encontrar.

Siguiente

A dónde ir desde aquí