test_validation_clip_usb_reel.py
Rama main · réplica de lectura del repositorio original.
"""Issue #49 : un VRAI clip USB de Sync Module dans la suite de tests.
Le défaut de #49 (chaque clip USB rejeté en silence par la validation de
ffprobe, depuis la 0.12.29) a échappé à la CI parce qu'elle n'avait que des clips
fabriqués par FFmpeg, et des tests qui simulaient la réponse de ffprobe. Ce
clip, enregistré sur une vraie clé USB, déclenche la ligne
« missing picture in access unit with size 9 » : la vraie validation doit
l'accepter, avec l'outil que la machine fournit (ffprobe, sinon ffmpeg).
Sautés sans ffprobe ni ffmpeg ; la CI Linux (job « chaîne vidéo ») installe
FFmpeg, donc y tourne."""
from __future__ import annotations
import hashlib
import subprocess
import tempfile
import unittest
from pathlib import Path
import merge_daily
CLIP = Path(__file__).parent / "fixtures" / "clip_usb_reel_neutre.mp4"
# Empreinte du clip tel que publié : un clip retouché, ou converti par une fin
# de ligne, ne prouverait plus rien.
SHA256 = "0089741365600fa231020176f3d761ce07e8f56a9dfbfde422a2ad204afd8aee"
class ClipUsbReel(unittest.TestCase):
@classmethod
def setUpClass(cls):
if not CLIP.is_file():
raise unittest.SkipTest("clip de test absent")
if merge_daily._outil_validation_media() is None:
raise unittest.SkipTest("ni ffprobe ni ffmpeg disponibles")
cls.genre, cls.exe = merge_daily._outil_validation_media()
def test_le_fichier_publie_est_intact(self):
self.assertEqual(hashlib.sha256(CLIP.read_bytes()).hexdigest(), SHA256,
"le clip de test a ete modifie")
def test_c_est_bien_un_clip_usb_a_un_seul_bloc_de_donnees(self):
# Structure des clips USB : ftyp, moov, un seul mdat (pas fragmenté comme
# un enregistrement du direct).
donnees = CLIP.read_bytes()
genres, pos = [], 0
while pos + 8 <= len(donnees):
taille = int.from_bytes(donnees[pos:pos + 4], "big")
genres.append(donnees[pos + 4:pos + 8].decode("latin-1"))
if taille < 8:
break
pos += taille
self.assertEqual(genres, ["ftyp", "moov", "mdat"])
self.assertEqual(donnees[8:12], b"isom")
def test_la_vraie_validation_accepte_le_clip(self):
self.assertTrue(merge_daily.valid_mp4_complet(CLIP), merge_daily.raison_refus_mp4(CLIP))
def test_la_sortie_de_ffprobe_ne_laisse_rien_de_refusable(self):
if self.genre != "ffprobe":
self.skipTest("la sonde de cette machine est ffmpeg")
resultat = subprocess.run(
[self.exe, "-v", "error", "-select_streams", "v:0", "-count_packets",
"-show_entries", "stream=nb_read_packets", "-of", "csv=p=0", str(CLIP)],
capture_output=True, text=True, encoding="utf-8", errors="replace", timeout=120)
self.assertEqual(resultat.returncode, 0)
self.assertGreater(int(resultat.stdout.split()[0]), 0)
# Selon la version de FFmpeg, la ligne de #49 est émise ou non ; dans
# tous les cas, le filtre n'en doit rien garder. L'ancienne règle
# (« toute ligne d'erreur = refus ») rejetait ce clip dès qu'elle l'était.
self.assertEqual(merge_daily._erreurs_ffprobe(resultat.stderr), [])
def test_des_copies_tronquees_du_vrai_clip_sont_refusees(self):
donnees = CLIP.read_bytes()
with tempfile.TemporaryDirectory(prefix="blink_clip_usb_") as dossier:
for part in (0.5, 0.9, 0.999):
copie = Path(dossier) / f"coupe_{int(part * 1000)}.mp4"
copie.write_bytes(donnees[: int(len(donnees) * part)])
with self.subTest(part=part):
self.assertFalse(merge_daily.valid_mp4_complet(copie))
if __name__ == "__main__":
unittest.main()