Skip to content

Expand test matrix: +143 tests across 4 new test files#1330

Merged
chazlarson merged 2 commits into
developfrom
tests/expand-test-matrix
Jun 25, 2026
Merged

Expand test matrix: +143 tests across 4 new test files#1330
chazlarson merged 2 commits into
developfrom
tests/expand-test-matrix

Conversation

@chazlarson

Copy link
Copy Markdown
Contributor

Summary

Closes the zero-coverage gap on every module and blueprint added in the quickstart.py refactor sprint, and adds HTTP-level tests for the most critical untested routes.

Before: 801 tests, 37/120 routes exercised (31%)
After: 944 tests, ~60/120 routes exercised (~50%)


New files

tests/test_bundle_artifacts.py (+75 tests)

Pure-function tests for all 25 helpers in modules/bundle_artifacts.py -- no Flask client or monkeypatching needed.

What's tested:

Function Cases
yaml_path_suffix .yml/.yaml, case-insensitive, other extensions, empty/None
normalize_bundle_member_name leading slashes, backslashes, double-slashes, empty
is_allowed_bundle_member yml, fonts, README, executables, path traversal (../../etc/passwd)
normalize_config_name lowercasing, space→underscore, default fallback
safe_bundle_name special chars, default fallback
safe_overlay_bundle_slug special→underscore, empty→fallback, dots/dashes preserved
is_overlay_source_override_file_key file, file_N, unrelated keys
parse_managed_overlay_image_relative_path config-root layout, display layout, unrelated path
normalized_managed_overlay_image_relative_path round-trip from both layouts, unrelated path
display_managed_overlay_image_location canonical→display conversion, unknown passthrough, empty
dump_yaml_text valid YAML output, round-trip through ruamel
build_config_bundle None when no fonts/artifacts, zip with fonts, zip with artifacts, redacted flag in README, empty config_text → None
get_custom_font_files empty dir, TTF/OTF discovery (TXT excluded), deduplication across dirs
iter_bundle_artifacts non-dict/None smoke, no libraries smoke
iter_overlay_source_bundle_artifacts non-dict/None smoke, no overlay_files smoke
bundle_write_artifact single file, directory recursion, missing source (no raise), redacted YAML strips secrets

tests/test_tmdb_lookup.py (+35 tests)

All 6 helpers in modules/tmdb_lookup.py. All HTTP calls mocked via unittest.mock.patch on modules.tmdb_lookup.requests -- no live network.

Function Cases
normalize_tmdb_library_media_type movie variants (mov/movies/Movie), show variants (sho/tv/season/episode), unknown passthrough
build_tmdb_library_type_warning types agree → empty, show-in-movie-library, movie-in-show-library, unknown result_type (collection), unknown expected → empty, custom value_label
get_active_tmdb_api_key no session → "", DB-stored apikey, alternate key name (api_key)
lookup_tmdb_by_imdb_id movie hit, show hit, media_type=movie prefers movie, media_type=show prefers show, 404 (verified=True), 401 (bad key), no key, network error, empty results
lookup_tmdb_numeric_id movie hit, TVDb ID in message, all-404 exhaustion, 401 short-circuit, no key
lookup_tmdb_external_ids returns payload, bad endpoint → {}, HTTP 500 → {}, missing args → {}

tests/test_validate_service_routes.py (+21 tests)

HTTP-level coverage for all 14 previously-untested validate_* routes in blueprints/validation_routes.py.

  • Passthrough routes (tautulli, trakt, mal, webhook): success + failure proxy
  • Tuple-unpack routes (radarr, sonarr): 200 on success, 400 via (response, 400) tuple on failure
  • Direct-get_json routes (omdb, github, tmdb, mdblist, notifiarr): 200 on success, 400 hardcoded on failure
  • URL-gate routes (gotify, ntfy): bad URL → 400 before the validator runs, missing URL → 400, valid URL → 200
  • validate_trakt_token: missing access+client_id → 400, valid token → 200, 401 without refresh → 400, network error → 400
  • validate_mal_token: missing token → 400, valid token → 200, 401 → 400
  • validate_library_service_overrides: endpoint responds (200 or 400)

Key pattern documented in tests: radarr/sonarr unpack (response, status_code) tuples while omdb/github/tmdb/mdblist/notifiarr call result.get_json() directly. The parametrize is split to reflect this.

tests/test_config_and_library_routes.py (+32 tests)

HTTP-level tests for config lifecycle + library autosave routes.

Route Cases
POST /activate-config creates new (created=True), re-activates existing (created=False), empty name → 400, missing name → 400, name sanitization (special chars stripped)
POST /clear_session returns success with name, falls back to session config without name
GET /clear_data/<name> 302 redirect, DB entries removed after clear
GET /clear_data/<name>/<section> 302 redirect
POST /autosave_library/<id> success (empty payload), 400 on collection errors, 400 on overlay errors, 400 on normalization errors, normalized=True flag propagation
POST /autosave-imagemaid success response, validated=False when config changed while previously validated
POST /validate-imagemaid 200 with command_preview when valid, 400 when invalid
POST /lookup_template_string_value missing preset/value → 400, unknown preset → 400, numeric_id hit, numeric_id type-mismatch warning (level=warning), imdb_id_tmdb hit, imdb_id_plex missing library_name, tmdb_collection_id hit, tmdb_collection_id no key

Gotcha documented: database.reset_data() does not call CREATE TABLE IF NOT EXISTS before the DELETE, unlike every other DB helper. Tests that exercise /clear_session or /clear_data call database.get_unique_config_names() first to ensure the table exists.


Test count by file

File Tests
test_bundle_artifacts.py 75
test_tmdb_lookup.py 35
test_config_and_library_routes.py 32
test_validate_service_routes.py 21
Total new 143

CI

  • 944 tests pass (801 existing + 143 new), zero regressions
  • ruff check clean on all 4 new files

Closes the zero-coverage gap on every module and blueprint added in the
quickstart.py refactor sprint, and adds HTTP-level tests for the most
critical untested routes.

New files
---------

tests/test_bundle_artifacts.py  (+75 tests)
  Pure-function tests for all 25 helpers in modules/bundle_artifacts.py:
  yaml_path_suffix, normalize_bundle_member_name, is_allowed_bundle_member
  (including path-traversal rejection), normalize_config_name,
  safe_bundle_name, safe_overlay_bundle_slug, is_overlay_source_override_file_key,
  parse_managed_overlay_image_relative_path (both layouts),
  normalized_managed_overlay_image_relative_path, display_managed_overlay_image_location,
  dump_yaml_text, build_config_bundle (empty/fonts/artifacts/redacted/empty-text
  cases), get_custom_font_files (empty dir, font discovery, deduplication),
  iter_bundle_artifacts (smoke), iter_overlay_source_bundle_artifacts (smoke),
  bundle_write_artifact (single file, directory recursion, missing source,
  redacted YAML content).
  No Flask client needed -- purely isolated unit tests.

tests/test_tmdb_lookup.py  (+35 tests)
  Tests for all 6 helpers in modules/tmdb_lookup.py.
  normalize_tmdb_library_media_type: movie/show variant normalization,
    unknown passthrough.
  build_tmdb_library_type_warning: matching types (empty), mismatch in both
    directions, unknown result_type, custom value_label.
  get_active_tmdb_api_key: no session, DB-stored apikey, alternate key names.
  lookup_tmdb_by_imdb_id: movie hit, show hit, media_type hint ordering (both
    directions), 404, 401, no-key, network error, empty results.
  lookup_tmdb_numeric_id: movie hit, TVDb ID inclusion, exhausted endpoints,
    401 short-circuit, no-key.
  lookup_tmdb_external_ids: payload, bad endpoint, HTTP error, missing args.
  All HTTP calls mocked via unittest.mock.patch on modules.tmdb_lookup.requests.

tests/test_validate_service_routes.py  (+21 tests)
  HTTP-level tests for all 14 previously-untested validate_* routes in
  blueprints/validation_routes.py.
  Parametrized success/failure for tautulli, trakt, mal, webhook (passthrough
  routes), radarr/sonarr (tuple-unpack routes), and omdb/github/tmdb/mdblist/
  notifiarr (direct-get_json routes).
  URL-validation gate tests for gotify and ntfy (bad URL → 400 before
  the validator even runs, missing URL → 400).
  validate_trakt_token: missing access+client_id → 400, valid token → 200,
    401 without refresh_token → 400, network error → 400.
  validate_mal_token: missing token → 400, valid token → 200, 401 → 400.
  validate_library_service_overrides: endpoint responds (200 or 400).

tests/test_config_and_library_routes.py  (+32 tests)
  HTTP-level tests for config lifecycle and library autosave.
  /activate-config: create new, re-activate existing (created=False),
    empty name → 400, missing name → 400, name sanitization.
  /clear_session: returns success with and without explicit name.
  /clear_data/<name> and /clear_data/<name>/<section>: redirect, DB cleanup.
  /autosave_library/<library_id>: success (empty payload), 400 on collection
    errors, 400 on overlay errors, 400 on normalization errors, normalized
    flag propagation.
  /autosave-imagemaid: success, validated=False when config changed while
    previously-validated.
  /validate-imagemaid: 200 when valid (command_preview present), 400 when
    invalid.
  /lookup_template_string_value: missing preset/value → 400, unknown preset
    → 400, numeric_id hit, numeric_id type-mismatch warning, imdb_id_tmdb
    hit, imdb_id_plex missing library_name, tmdb_collection_id hit,
    tmdb_collection_id no key.

Summary
-------
  Before: 801 tests, 37/120 routes exercised (31%)
  After:  944 tests, ~60/120 routes exercised (~50%)
@chazlarson chazlarson merged commit 58a84c6 into develop Jun 25, 2026
10 checks passed
@chazlarson chazlarson deleted the tests/expand-test-matrix branch June 25, 2026 15:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant