feat(screenshot): GNOME focused-window capture on test failure (#18) #36
No reviewers
Labels
No labels
area:assertions
area:cli
area:client
area:harness
area:meta
area:reporting
area:runner
type:user-story
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
charles/ws-rpc-test!36
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "feat/18-gnome-screenshot"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Closes #18. Stacked on #35.
Summary
Adds opt-in GNOME focused-window screenshot capture on test failure. No full-screen fallback — if window detection or the Shell screenshot interface is unavailable, capture is skipped with a stderr warning. Test outcomes are never affected by screenshot-pipeline failures.
Mechanism
XDG_CURRENT_DESKTOP; disables capture unless it containsGNOMEorGNOME-Classic.gdbusandgnome-screenshoton PATH. If neither exists, capture is disabled for the run with a single stderr warning.gdbus call --session --dest org.gnome.Shell --object-path /org/gnome/Shell/Screenshot --method org.gnome.Shell.Screenshot.ScreenshotWindow false false false "<path>".gnome-screenshot --window --file=<path>— used when the D-Bus call fails on older / stripped GNOME installs.tokio::time::timeoutwithkill_on_drop.t{epoch_ms}_{sanitised_name}.png. Raw epoch ms avoids achronodep and still sorts lexically by time.Runner integration
RunConfig.screenshot_on_failure: bool+RunConfig.screenshot_dir: Option<PathBuf>.TestRunner::screenshot_on_failure(dir)setter (matches the issue's API sketch).TestCaseResult.screenshot: Option<PathBuf>— populated when capture succeeds.run()probesScreenshotCaptureronce at the top of the run; logs a startup warning if disabled.after_each, so cleanup hooks don't alter the window state.Reporter integration
Screenshot: <path> (window)below the failure block."screenshot": "<path>" | nullper test.CLI
--screenshot-on-failure--screenshot-dir <PATH>Both wired through #15's
Cli::apply_to.Checklist (from issue #18)
Configuration
RunConfig.screenshot_on_failure(default false)RunConfig.screenshot_dir(Option; default./test-screenshotsat run time)TestRunner::screenshot_on_failure(dir)builder shortcutCapture trigger
Skip)after_eachWindow detection & capture
gdbus ScreenshotWindowprimarygnome-screenshot --windowfallbackSession detection
XDG_CURRENT_DESKTOPgate (GNOME, GNOME-Classic)Output
t{epoch_ms}_{sanitised_name}.pngTestCaseResult.screenshotpopulated on successReporter integration
Screenshot: <path> (window)line under the failure blockscreenshotfield per testTest plan
sanitise_replaces_non_alphanumericsprobe_disabled_on_non_gnome_desktop— setsXDG_CURRENT_DESKTOP=KDE, asserts disabled + reason contains "KDE"capture_is_noop_when_disabled— probe disabled,capture()returns Nonejust qagreen locally — 105 unit + 5 integration = 110/110Notes for the reviewer
ScreenshotCapturerlives on theTestRunner's stack and would need to beArc-wrapped to cross theJoinSetboundary without holding a borrow. Sequential capture covers the primary user flow (cargo run --example basic); parallel capture is a follow-up — add anArc<ScreenshotCapturer>clone into each parallel task.chrono. If humans need readable filenames, a later PR can add a format helper; the prefixt{ms}keeps lexical sorting correct.unsafeblocks in the env-var tests are forstd::env::set_var, which is now marked unsafe in Rust edition 2024 / newer nightlies due to thread-safety concerns. The tests save and restore the env var around each case so they don't leak between tests.YYYYMMDD-HHMMSS-mmmwhich would need a calendar-aware formatter. I documented this trade-off in the code comment — thet{epoch_ms}form is strictly unambiguous and sort-stable, just less human-readable. Easy to swap once chrono or time lands.gdbusshell script on PATH thattouches the PNG and exits 0 — the framework accepts any tool on PATH.Review PR #36 — GNOME focused-window capture on test failure
Implémentation solide dans l'ensemble. Le mécanisme probe-once + capture-per-failure est bien pensé, les chemins d'échec sont silencieux (pas d'erreur propagée), la priorité gdbus > gnome-screenshot est correcte. Quelques points à noter.
1.
unsafe { std::env::set_var }dans les tests asyncDeux tests
#[tokio::test]mutentXDG_CURRENT_DESKTOPviaunsafe. En parallèle (le runtime tokio exécute les tests concurremment dans le thread pool par défaut), les deux tests peuvent se chevaucher sur la lecture/écriture de cette variable d'environnement — undefined behavior selon la spec Rust (la variable est un état global mutable partagé par tous les threads). En pratique, les deux tests se comportent de façon identique (KDE dans les deux cas) donc il est peu probable que ce soit un problème réel, mais le compilateur et les sanitizers peuvent légitimement se plaindre.Fix propre : ajouter
#[tokio::test(flavor = "current_thread")]aux deux tests pour forcer l'exécution séquentielle, ou utiliser le crateserial_testpour sérialiser ces deux tests entre eux.2. Screenshot absent en mode parallèle
Dans le chemin séquentiel, le screenshot est capturé après chaque test Failed :
Ce code est dans la boucle séquentielle. Le chemin parallèle (
JoinSet+Semaphore) a bien reçuscreenshot: Nonedans les struct literals, mais aucune capture n'y est effectuée. Les tests parallèles n'auront jamais de screenshot, même avec--screenshot-on-failure. Ce n'est pas un bug (c'est une limitation), mais mérite un commentaire ou un TODO dans le code parallèle.3.
std::fs::create_dir_allsynchrone dans une fonction asyncAppel fs bloquant dans
probe()qui estasync. Pour une création de répertoire unique au démarrage, le coût est négligeable en pratique (le syscall est quasi-instantané). Mais idéalement :tokio::fs::create_dir_all(&dir).await. Mineur.4. Passages de chemin à
gdbusviaOsStrLe path est passé comme argument direct à
gdbus call, pas via un shell. Aucun risque d'injection shell. ✓5.
which()viash -c "command -v ..."Correct mais spawn un sous-shell pour chaque vérification. Pourrait être remplacé par une recherche dans
PATH, mais ce n'est pas un hotpath —probe()n'est appelé qu'une fois. Acceptable.6.
timestamp_now()et nommage des fichiersFormat
t{epoch_ms}_{sanitized_name}.png. Ordonnancement lexical garanti par le préfixet. Noms sûrs pour tous les OS. La note dans le commentaire sur chrono est honnête. ✓Points positifs
kill_on_drop(true)sur leCommand: garantit que le subprocess screenshot est tué si le timeout expire. Bien.after_each: correct, les hooks de cleanup ne doivent pas affecter ce qui est visible à l'écran.capture()ne propage jamais d'erreur (Option<PathBuf>+eprintln!en cas d'échec) : le test outcome n'est pas affecté par un screenshot raté. ✓--screenshot-on-failure+--screenshot-dir. ✓✅ Aucun bug bloquant. Le point 2 (pas de screenshot en parallèle) est une limitation acceptable pour v0.1 si documentée. Peut merger avec les ajustements mineurs.
d8beb66f29to6288b303e2