Skip to content

PDFCLOUD-5595 Improve testing speed#31

Merged
datalogics-cgreen merged 5 commits intopdfrest:mainfrom
datalogics-kam:pdfcloud-5595-test-speed-and-gating
Feb 20, 2026
Merged

PDFCLOUD-5595 Improve testing speed#31
datalogics-cgreen merged 5 commits intopdfrest:mainfrom
datalogics-kam:pdfcloud-5595-test-speed-and-gating

Conversation

@datalogics-kam
Copy link
Copy Markdown
Contributor

@datalogics-kam datalogics-kam commented Feb 20, 2026

PDFCLOUD-5595

Why this change

Our CI runtime and flake exposure were higher than needed because live API tests ran in the full tests matrix on both pushes and pull requests across Python 3.10–3.14. That made every update slower and tied routine feedback to external service availability. This change keeps live coverage as a quality gate while reducing redundant cost on everyday branch activity.

After splitting live/non-live lanes, we also needed to preserve function-level coverage for customer-facing classes without relying on live suites, because the class-function coverage gate is evaluated from the non-live coverage artifact.

What changed (high level)

We split test execution into non-live and live lanes, then scoped where each lane runs:

  • Added a live pytest marker in pyproject.toml.
  • Added automatic live-test tagging in tests/conftest.py for:
    • tests under tests/live/
    • tests named test_live_*
  • Updated test-and-publish.yml:
    • tests job now runs only non-live tests (-m "not live") across Python 3.10–3.14.
    • Introduced a dedicated live-tests job running only live tests (-m live) on Python 3.11.
    • live-tests runs on pull_request and nightly schedule (cron).
    • Increased CI pytest worker count to -n 5 for both non-live and live jobs.
  • Moved class-based live file download tests from tests/test_files.py to tests/live/test_live_file_downloads.py so they are unambiguously routed to the live lane.

Coverage follow-up (non-live gate hardening):

  • Added/updated endpoint-owned sync+async unit tests in each endpoint’s home module to explicitly cover optional payload branches (output, output_prefix, pages, page_groups, redaction preview payloads) that were previously under-covered when live tests moved out of the non-live lane.
  • Added async preview_redactions unit coverage in tests/test_pdf_redaction_preview.py.
  • Updated TESTING_GUIDELINES.md to require endpoint-home test ownership and optional-branch coverage in both sync and async customization/success tests.

Tradeoff: live coverage is no longer exercised in all Python versions on every push, but remains enforced before merge and is checked nightly.

Behavior changes

CI behavior now differs by event type:

  • push:
    • tests matrix (3.10–3.14): non-live only, 5 workers.
    • examples matrix unchanged.
  • pull_request:
    • same non-live matrix as push.
    • plus live-tests gate on Python 3.11, 5 workers.
  • nightly schedule:
    • runs live-tests on Python 3.11.
  • release:
    • publish still depends on docs/tests/examples; live tests are no longer in the release dependency path.

Test location behavior:

  • TestLiveFileDownloads and TestLiveAsyncFileDownloads now execute only from tests/live/test_live_file_downloads.py.
  • Mocked download coverage remains in tests/test_files.py (TestDownloadHelpers and TestAsyncDownloadHelpers) for non-live gating.
  • Endpoint branch coverage is now asserted in each endpoint’s own test file rather than a cross-endpoint helper module.

No SDK runtime/API behavior changed; this is CI/test routing and test organization only.

Validation

Validated the live/non-live split and test routing:

  • uv run pytest --collect-only -m live -q
  • uv run pytest --collect-only -m "not live" -q
  • uv run pytest --collect-only -m "not live" -q tests/test_files.py tests/live/test_live_file_downloads.py
  • uv run pytest --collect-only -m live -q tests/test_files.py tests/live/test_live_file_downloads.py

Validated endpoint-home coverage updates:

  • uv run ruff check on modified endpoint test modules
  • uv run pytest on modified endpoint test modules

Validated non-live coverage gate behavior with the same failing command path:

  • uvx nox --python 3.10 --session tests -- -n 5 -m "not live"
  • uv run python scripts/check_class_function_coverage.py coverage/py3.10/coverage.json --class PdfRestClient --class AsyncPdfRestClient --class _FilesClient --class _AsyncFilesClient --fail-under 90 --markdown-report coverage/py3.10/class-function-coverage.md

Result: class-function coverage gate passes from non-live coverage artifacts.

Limitation: full multi-version nox matrix was not rerun locally for this follow-up; validation focused on the exact non-live gate path and impacted test modules.

Risks and follow-ups

Main risk is classification drift: a new live test that does not live under tests/live/ and does not use the test_live_* naming pattern could be routed incorrectly. The current hook mitigates known patterns, and the moved class-based download tests remove one concrete misclassification source.

Follow-ups to consider:

  • Optionally add a lint/check that enforces live-test naming/location conventions.
  • Monitor first few nightly runs for duration/flakiness and tune worker count if needed.
  • If desired, add a lightweight report that surfaces live lane pass rate trends over time.

- Introduced a daily cron schedule at 7:00 AM to trigger workflows.
- Added a dedicated "Live Tests" job for Python 3.11:
  - Configured to run on pull requests and scheduled events.
  - Includes live tests marked with the `live` pytest marker.
  - Uploads coverage results for live test runs.
- Updated `pytest_collection_modifyitems` to mark live tests automatically.
- Defined a `live` marker in `pyproject.toml` for consistent usage.
- Removed `ci-live` environment from general test jobs and updated live-specific conditions.

Assisted-by: Codex
…sing

- Updated `nox` commands in `test-and-publish.yml` to use `-n 5` for parallel
  pytest execution in both regular and live tests.
- Ensures faster test completion while maintaining existing markers like `not
  live` and `live`.

Assisted-by: Codex
@netlify
Copy link
Copy Markdown

netlify Bot commented Feb 20, 2026

Deploy Preview for pdfrest-python ready!

Name Link
🔨 Latest commit a60ea19
🔍 Latest deploy log https://app.netlify.com/projects/pdfrest-python/deploys/6998b6aed6295f00075f0a40
😎 Deploy Preview https://deploy-preview-31--pdfrest-python.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 40211008af

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread tests/conftest.py Outdated
Comment thread .github/workflows/test-and-publish.yml
- Move TestLiveFileDownloads from tests/test_files.py ->
  tests/live/test_live_file_downloads.py
- Move TestLiveAsyncFileDownloads from tests/test_files.py ->
  tests/live/test_live_file_downloads.py
- Keep mocked coverage in tests/test_files.py via TestDownloadHelpers and
  TestAsyncDownloadHelpers so non-live CI remains fully covered

Assisted-by: Codex
- Add non-live sync and async coverage for optional payload branches
  (output/output_prefix/pages/page_groups) in each endpoint's home
  test module
- Add async preview_redactions unit coverage in test_pdf_redaction_preview
- Keep coverage aligned with endpoint ownership instead of a shared
  cross-endpoint helper module
- Update TESTING_GUIDELINES.md to require endpoint-home tests and
  optional-branch coverage in both sync and async customization/success
  cases

Assisted-by: Codex
- Added `_is_live_test_path` utility to identify live test paths more robustly.
- Updated `pytest_collection_modifyitems` to use `Path` objects and the new
  utility for determining live test markers.
- Ensures compatibility with varied file path formats and improves maintainability.

Assisted-by: Codex
Copy link
Copy Markdown
Contributor

@datalogics-cgreen datalogics-cgreen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

No critical findings from Codex audit

Comment thread .github/workflows/test-and-publish.yml
@datalogics-cgreen datalogics-cgreen merged commit ea1db92 into pdfrest:main Feb 20, 2026
20 checks passed
@datalogics-kam datalogics-kam deleted the pdfcloud-5595-test-speed-and-gating branch February 20, 2026 20:50
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.

2 participants