Skip to content

test: harden offline coverage, coverage gate, and nightly integration - #39

Open
robertoecf wants to merge 1 commit into
mainfrom
test/harden-reliability
Open

test: harden offline coverage, coverage gate, and nightly integration#39
robertoecf wants to merge 1 commit into
mainfrom
test/harden-reliability

Conversation

@robertoecf

@robertoecf robertoecf commented Aug 4, 2026

Copy link
Copy Markdown
Owner

Summary

  • Add offline unit/API coverage for previously thin surfaces: HTTP 429 retries, rate-limit helpers/handler, BCB PTAX/Focus, IBGE, CVM companies/financials, Tesouro bonds, B3 quotes (mocked yfinance), thin REST smoke, and CLI smoke.
  • Wire CI coverage on the Python 3.12 leg (--cov-fail-under=60) and a scheduled nightly pytest -m integration workflow (plus workflow_dispatch).
  • Hygiene: AuthError assertion, chart-explorer JS asserts trimmed to high-signal invariants, docs/guardrails aligned with “integration is nightly, not default CI”.

Test plan

  • Local: ruff format --check, ruff check, mypy src/findata, pytest tests/ -q340 passed, 16 integration deselected
  • Local coverage: pytest --cov=findata --cov-fail-under=60~68%
  • CI matrix 3.11/3.12/3.13 green on this PR
  • Optional: Actions → “Nightly integration” → Run workflow

Made with Cursor

Summary by CodeRabbit

  • Tests

    • Expanded automated coverage for data sources, API routes, CLI commands, authentication, retries, rate limiting, and financial data parsing.
    • Added offline smoke tests with mocked external services for more consistent validation.
    • Added checks for chart explorer limits and request timeouts.
  • Documentation

    • Updated contribution guidance and changelog with the latest testing and integration workflow details.
  • Chores

    • Added scheduled and manual integration test runs.
    • Enforced a minimum 60% coverage threshold in CI.

Close reliability gaps for previously thin sources and production paths
(429 retries, rate limits, CLI smoke) while keeping live API checks on a
scheduled workflow instead of default PR CI.

Co-authored-by: Cursor <cursoragent@cursor.com>
@coderabbitai

coderabbitai Bot commented Aug 4, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The pull request expands mocked coverage for data sources, API routes, CLI commands, retries, authentication, and rate limiting. CI adds a 60% Python 3.12 coverage gate and a scheduled or manual integration workflow.

Changes

Test hardening and CI

Layer / File(s) Summary
Test execution and coverage controls
.github/workflows/ci.yml, .github/workflows/integration.yml, pyproject.toml, CHANGELOG.md, CONTRIBUTING.md, scripts/git/guardrails.sh, tests/conftest.py
CI adds branch coverage enforcement for Python 3.12. A nightly or manually triggered workflow runs integration tests and uploads failure logs. Test and guardrail documentation reflects this split.
Source and API validation
tests/test_bcb_ptax_focus.py, tests/test_ibge.py, tests/test_tesouro_bonds.py, tests/test_cvm_companies_financials.py, tests/test_api_sources_smoke.py
Mocked tests cover source requests, parsing, filtering, normalization, pagination, historical data, and API responses for BCB, IBGE, Tesouro, and CVM data.
Client and policy validation
tests/test_b3_quotes.py, tests/test_http_client.py, tests/test_auth.py, tests/test_limits.py
Tests cover deterministic B3 quote and history mapping, retry handling for HTTP 429 responses, specific authentication errors, and rate-limit behavior.
CLI and asset smoke validation
tests/test_cli.py, tests/test_api.py
CLI smoke tests cover help, version, catalog output, and mocked data retrieval. The chart asset test checks the point limit and request timeout constants.

Estimated code review effort: 3 (Moderate) | ~25 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 1.92% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main changes: stronger offline coverage, a coverage gate, and nightly integration testing.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch test/harden-reliability

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/integration.yml:
- Around line 30-33: Update the integration test workflow step running `pytest
-m integration` to preserve pytest’s nonzero exit status through the `tee`
pipeline by enabling `pipefail` or explicitly checking the pytest result.
Broaden the `Upload failure log` condition to also run when the job is canceled,
using the appropriate `failure()`/`cancelled()` handling alongside
`steps.integration-tests.outcome == 'failure'`.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: f3946044-d109-48dc-8c07-a99f996f0448

📥 Commits

Reviewing files that changed from the base of the PR and between f8a932b and 9cbecd6.

📒 Files selected for processing (18)
  • .github/workflows/ci.yml
  • .github/workflows/integration.yml
  • CHANGELOG.md
  • CONTRIBUTING.md
  • pyproject.toml
  • scripts/git/guardrails.sh
  • tests/conftest.py
  • tests/test_api.py
  • tests/test_api_sources_smoke.py
  • tests/test_auth.py
  • tests/test_b3_quotes.py
  • tests/test_bcb_ptax_focus.py
  • tests/test_cli.py
  • tests/test_cvm_companies_financials.py
  • tests/test_http_client.py
  • tests/test_ibge.py
  • tests/test_limits.py
  • tests/test_tesouro_bonds.py
💤 Files with no reviewable changes (2)
  • tests/test_api.py
  • tests/conftest.py

Comment on lines +30 to +33
run: pytest -m integration -v 2>&1 | tee pytest-integration.log

- name: Upload failure log
if: steps.integration-tests.outcome == 'failure'

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== files =="
git ls-files | rg '(^|/)(integration\.yml|.*workflow.*\.ya?ml|README|.*\.md)$' || true

echo
echo "== workflow excerpt =="
if [ -f .github/workflows/integration.yml ]; then
  nl -ba .github/workflows/integration.yml | sed -n '1,100p'
fi

echo
echo "== search for related workflows/pytest logs =="
rg -n "Run integration tests|Upload failure log|pytest-integration\.log|steps\.integration-tests\.outcome|failure\(\)|set -o pipefail|pytest -m integration" .github/workflows . || true

echo
echo "== deterministic pipeline/status probes =="
python3 - <<'PY'
import subprocess, shlex, tempfile, os

cases = [
    ("normal_exit", "echo ok | tee /tmp/pytest-integration.log"),
    ("pytest_exit_pipefail_missing", "false | true"),
    ("pytest_exit_pipefail_set", "set -o pipefail; false | true"),
]
original = os.environ.get("SHELL")
os.environ["SHELL"] = "/bin/bash"
for name, cmd in cases:
    rc = subprocess.run(["/bin/bash", "-c", cmd], text=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    print(f"{name}: cmd={cmd!r} returncode={rc.returncode} stdout={rc.stdout.strip()!r} stderr={rc.stderr.strip()!r}")
os.environ["SHELL"] = original or ""

from pathlib import Path
if Path("/tmp/pytest-integration.log").exists():
    print("tmp log contains:", Path("/tmp/pytest-integration.log").read_text().strip())
PY

echo
echo "== bash status docs excerpt from local bash if available =="
if command -v bash >/dev/null 2>&1; then
  bash --version | head -1
  bash -c 'false | true; echo pipe=$?'
  bash -c 'set -o pipefail; false | true; echo pipefail=$?'
fi

Repository: robertoecf/OpenFinData

Length of output: 694


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== workflow excerpt =="
if [ -f .github/workflows/integration.yml ]; then
  sed -n '1,120p' .github/workflows/integration.yml
fi

echo
echo "== search for related workflows/pytest logs =="
rg -n "Run integration tests|Upload failure log|pytest-integration\.log|steps\.integration-tests\.outcome|failure\(\)|set -o pipefail|pytest -m integration" .github/workflows . || true

echo
echo "== deterministic pipeline/status probes =="
python3 - <<'PY'
import subprocess, os

cases = {
    "normal_exit": "echo ok | tee /tmp/pytest-integration.log",
    "pytest_exit_pipefail_missing": "false | true",
    "pytest_exit_pipefail_set": "set -o pipefail; false | true",
}
for name, cmd in cases.items():
    rc = subprocess.run(["/bin/bash", "-c", cmd], text=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    print(f"{name}: cmd={cmd!r} returncode={rc.returncode} stdout={rc.stdout.strip()!r} stderr={rc.stderr.strip()!r}")
PY

echo
echo "== bash status probes =="
bash -c 'false | true; echo pipe=$?'
bash -c 'set -o pipefail; false | true; echo pipefail=$?'

Repository: robertoecf/OpenFinData

Length of output: 2263


Preserve pytest failures before uploading the failure log.

The run command exits with tee’s status, so a failed pytest can make the step succeed without pipefail. Add Failure() or check() to the upload condition when the job can be canceled, because steps.integration-tests.outcome == 'failure' can have no value if the job is canceled.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/integration.yml around lines 30 - 33, Update the
integration test workflow step running `pytest -m integration` to preserve
pytest’s nonzero exit status through the `tee` pipeline by enabling `pipefail`
or explicitly checking the pytest result. Broaden the `Upload failure log`
condition to also run when the job is canceled, using the appropriate
`failure()`/`cancelled()` handling alongside `steps.integration-tests.outcome ==
'failure'`.

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