From efa44274b36ef48705212a0f2ce179ad808b2620 Mon Sep 17 00:00:00 2001 From: Roel Van Gils Date: Wed, 6 May 2026 01:01:38 +0200 Subject: [PATCH] dpub-meta: live Open Library smoke test (gated) Three tests in `crates/dpub-meta/tests/openlibrary.rs`: 1. ISBN-shaped identifier path: known-good lookup (Pride and Prejudice, ISBN 9780141439518) returns a real JPEG > 1 KiB. 2. Title + author fallback path (no identifier given): same book, same outcome via the search.json route. 3. Gibberish title + author returns Ok(None) (the intentionally-quiet miss path). All three are gated behind `DPUB_TEST_OPENLIBRARY=1` so CI and contributors without that env var skip silently. We don't want the test suite to fail because Open Library was briefly slow or someone is offline. Verified against the live API: ISBN path returned a 35 KiB JPEG ("Pride and Prejudice" by Jane Austen, cover_i=14348537); title+author path resolved to the same record; gibberish correctly returned None. README's local-development table gains a row advertising the env var. Co-Authored-By: Claude Opus 4.7 (1M context) --- README.md | 1 + crates/dpub-meta/tests/openlibrary.rs | 92 +++++++++++++++++++++++++++ 2 files changed, 93 insertions(+) create mode 100644 crates/dpub-meta/tests/openlibrary.rs diff --git a/README.md b/README.md index 316b69c..74e2a70 100644 --- a/README.md +++ b/README.md @@ -148,6 +148,7 @@ external assets or are slow: | `DPUB_TEST_WHISPER_MODEL=/path/ggml-*.bin` and `DPUB_TEST_AUDIO=/path/audio.mp3` | Enable the Whisper smoke test in `dpub-whisper`. Optional `DPUB_TEST_WHISPER_LANG=nl`. | | `epubcheck` on `PATH` | The `dpub-validate` and `epub3-writer` integration tests will run EPUBCheck and assert zero errors. They skip silently if the binary is missing. | | `ace` on `PATH` | (No CI-gated test yet.) Enables `dpub a11y` end-to-end. Install with `npm install -g @daisy/ace`. | +| `DPUB_TEST_OPENLIBRARY=1` | Enables the live Open Library cover-lookup smoke test in `dpub-meta`. Skipped on CI to avoid flakiness on third-party-service availability. | | `ffmpeg` on `PATH` | The `dpub-audio` and Opus re-encoding tests run; they skip silently otherwise. | | `cmake` on `PATH` | Required to build `dpub-whisper` (and therefore `dpub-cli` once it depends on it). The `whisper-rs-sys` crate compiles whisper.cpp from source. | diff --git a/crates/dpub-meta/tests/openlibrary.rs b/crates/dpub-meta/tests/openlibrary.rs new file mode 100644 index 0000000..ed6f5e1 --- /dev/null +++ b/crates/dpub-meta/tests/openlibrary.rs @@ -0,0 +1,92 @@ +//! Network-gated smoke test for the Open Library cover lookup. +//! +//! Skipped unless `DPUB_TEST_OPENLIBRARY=1` is set. Real CI runs (and +//! every contributor's `cargo test`) skip silently — we don't want +//! the test suite to fail because Open Library was briefly slow, +//! degraded, or because someone is offline. +//! +//! Run with: +//! +//! ```sh +//! DPUB_TEST_OPENLIBRARY=1 cargo test -p dpub-meta --test openlibrary -- --nocapture +//! ``` +//! +//! Asserts only that the path *can* return a real JPEG/PNG cover for +//! a known well-indexed book — not the exact bytes, since Open Library +//! image content can change. + +use dpub_meta::{LookupHints, lookup_cover}; + +fn enabled() -> bool { + std::env::var_os("DPUB_TEST_OPENLIBRARY").is_some() +} + +#[test] +fn fetches_cover_for_pride_and_prejudice_by_isbn() { + if !enabled() { + eprintln!("DPUB_TEST_OPENLIBRARY not set — skipping"); + return; + } + let hints = LookupHints { + title: "Pride and Prejudice", + creator: Some("Jane Austen"), + language: Some("eng"), + identifier: Some("9780141439518"), + }; + let got = lookup_cover(&hints).expect("lookup"); + let cover = got.expect("matched"); + assert!(cover.bytes.len() > 1024, "cover too small: {}", cover.bytes.len()); + assert!( + cover.media_type == "image/jpeg" || cover.media_type == "image/png", + "unexpected media type: {}", + cover.media_type, + ); + eprintln!( + "got {} bytes ({}); provenance: {}", + cover.bytes.len(), + cover.media_type, + cover.provenance, + ); +} + +#[test] +fn fetches_cover_by_title_and_author_when_no_isbn() { + if !enabled() { + eprintln!("DPUB_TEST_OPENLIBRARY not set — skipping"); + return; + } + let hints = LookupHints { + title: "Pride and Prejudice", + creator: Some("Jane Austen"), + language: Some("eng"), + identifier: None, // force the title+author path + }; + let got = lookup_cover(&hints).expect("lookup"); + let cover = got.expect("matched"); + assert!(cover.bytes.len() > 1024); + eprintln!( + "got {} bytes via {} path", + cover.bytes.len(), + cover.provenance, + ); +} + +#[test] +fn returns_none_for_obviously_nonexistent_book() { + if !enabled() { + eprintln!("DPUB_TEST_OPENLIBRARY not set — skipping"); + return; + } + let hints = LookupHints { + title: "ZZZZZZZZZZZZZZ_DPUB_TEST_NONEXISTENT_BOOK_XXXXX", + creator: Some("AAAAAAAAA Nonexistent Author"), + language: None, + identifier: None, + }; + let got = lookup_cover(&hints).expect("lookup"); + assert!( + got.is_none(), + "expected miss for gibberish title, got {:?}", + got.as_ref().map(|c| &c.provenance), + ); +}