Skip to content

Add API contract and idempotency-under-retry tests#250

Merged
wpak-ai merged 2 commits into
cppalliance:developfrom
jonathanMLDev:feat/api-contract-idempotency-tests
May 28, 2026
Merged

Add API contract and idempotency-under-retry tests#250
wpak-ai merged 2 commits into
cppalliance:developfrom
jonathanMLDev:feat/api-contract-idempotency-tests

Conversation

@jonathanMLDev
Copy link
Copy Markdown
Collaborator

@jonathanMLDev jonathanMLDev commented May 28, 2026

Summary

Adds contract tests and idempotency-under-retry tests for GitHub and Slack ingestion boundaries (w4 issue 02 / eval B8).

  • Contract tests: Recorded JSON fixtures in tests/fixtures/api_contracts/ are deserialized through the existing Pydantic boundary parsers (parse_issue_bundle, parse_pr_bundle, parse_commit, parse_team, parse_channel, parse_user, parse_message). Failures indicate API shape drift before production sync breaks.
  • Idempotency tests: Three get_or_create_* service functions are called twice with identical inputs inside transaction.atomic(), asserting no duplicate rows and the same returned object—matching Celery at-least-once delivery behavior.

Changes

Area Files
Contract fixtures tests/fixtures/api_contracts/*_2026-05-28.json (7 fixtures)
Fixture docs tests/fixtures/api_contracts/README.md (recording dates, refresh process, redaction)
Contract tests tests/test_api_contracts.py
Idempotency tests tests/test_idempotency_under_retry.py

Idempotency targets:

  • get_or_create_slack_team
  • get_or_create_slack_channel
  • get_or_create_repository

Test plan

  • CI test job passes (uv run pytest picks up root tests/ automatically)
  • uv run pytest tests/test_api_contracts.py tests/test_idempotency_under_retry.py -v (requires Postgres per README)
  • Contract tests pass without live GitHub/Slack API calls (fixtures only)

Acceptance criteria (w4 #2)

  • Contract tests for GitHub and Slack API shapes against boundary schemas
  • Idempotency tests for ≥3 get_or_create_* service functions
  • Fixtures documented with recording date and refresh process
  • CI includes new tests (no workflow change)
  • Tests pass in CI
  • PR approved by ≥1 reviewer

Notes

  • Depends on issue 6 boundary schemas (already on develop).
  • Fixtures use dated filenames (*_2026-05-28.json); see README for refresh steps.
  • No pytest-recording/VCR added; recorded JSON only.

Related issue

Summary by CodeRabbit

  • Tests

    • Added API contract validation tests for GitHub and Slack integration fixtures, ensuring schema compliance and handling of missing required fields.
    • Added idempotency tests to verify database consistency when retry scenarios occur.
  • Documentation

    • Added comprehensive guide for API contract fixtures, including naming conventions, refresh workflow, redaction rules, and fixture inventory.

Review Change Stack

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 28, 2026

Warning

Review limit reached

@jonathanMLDev, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 49 minutes and 44 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 899d3dc8-10c1-4248-b217-b0f322cf802b

📥 Commits

Reviewing files that changed from the base of the PR and between 2ce1293 and 621cde9.

📒 Files selected for processing (1)
  • tests/test_api_contracts.py
📝 Walkthrough

Walkthrough

This PR adds comprehensive contract tests and idempotency validation. It introduces recorded API response fixtures for GitHub and Slack, documents their refresh workflow, validates those fixtures parse correctly against Pydantic schemas, and verifies that service functions are idempotent under retry conditions.

Changes

API Contract and Idempotency Tests

Layer / File(s) Summary
Fixture Infrastructure and Documentation
tests/fixtures/api_contracts/README.md, tests/fixtures/api_contracts/github_*.json, tests/fixtures/api_contracts/slack_*.json
Eight API contract fixture files (GitHub commit, issue bundle, PR bundle; Slack team, channel, user, message) are added with recorded response structures. The README documents fixture naming conventions (<provider>_<resource>_<YYYY-MM-DD>.json), refresh triggers, step-by-step refresh instructions including redaction rules, and a table mapping fixture filename patterns to Pydantic parser functions.
Contract Validation Tests
tests/test_api_contracts.py
Parameterized tests load fixture files by prefix, parse them through schema functions (parse_issue_bundle, parse_pr_bundle, parse_commit, parse_team, parse_channel, parse_user, parse_message), and assert required parsed fields are present. Negative tests mutate fixtures to remove required fields and verify schema validation raises expected GitHubApiValidationError or SlackApiValidationError.
Idempotency-Under-Retry Tests
tests/test_idempotency_under_retry.py
Database tests verify get_or_create_slack_team, get_or_create_slack_channel, and get_or_create_repository are idempotent when called twice with identical input inside transaction.atomic() boundaries. Each test asserts only one database row is created, both calls return the same primary key, and the created flag is True then False.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 Two calls to create, but just one row survives,
API contracts dance as our fixtures arrive,
Slack and GitHub shapes recorded in stone,
Idempotent service calls own what they've sown!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% 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
Title check ✅ Passed The title clearly summarizes the primary change—adding API contract and idempotency-under-retry tests—which directly aligns with the main objectives in the PR.
Description check ✅ Passed The PR description covers all required template sections: summary explains changes, test plan lists verification steps, acceptance criteria documented, and related issue linked; deployment/docs changes are not applicable.
Linked Issues check ✅ Passed All coding requirements from linked issue #239 are met: contract tests added for GitHub/Slack [tests/test_api_contracts.py], idempotency tests for 3+ service functions [tests/test_idempotency_under_retry.py], fixtures documented with dates [tests/fixtures/api_contracts/README.md], and CI integration verified.
Out of Scope Changes check ✅ Passed All changes are directly scoped to linked issue #239 objectives: fixture files, documentation, contract tests, and idempotency tests—no unrelated code modifications detected.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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 and usage tips.

@jonathanMLDev
Copy link
Copy Markdown
Collaborator Author

@coderabbitai full review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 28, 2026

✅ Actions performed

Full review triggered.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
tests/test_idempotency_under_retry.py (1)

22-25: ⚡ Quick win

Load the newest matching fixture instead of the oldest.

sorted(...)[0] picks the oldest dated fixture when multiple recordings exist. This can keep tests on stale payloads and weaken contract drift coverage over time.

Suggested diff
 def _load_fixture(name: str) -> dict:
     matches = sorted(FIXTURES_DIR.glob(name))
     assert matches, f"no fixture matching {name}"
-    return json.loads(matches[0].read_text(encoding="utf-8"))
+    return json.loads(matches[-1].read_text(encoding="utf-8"))
🤖 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 `@tests/test_idempotency_under_retry.py` around lines 22 - 25, The
_load_fixture function currently picks the oldest matching file because it
returns sorted(...)[0]; change it to select the newest matching fixture instead
(e.g., choose the last element of a reverse sort or use max(..., key=lambda p:
p.stat().st_mtime)) so tests use the most recent recording; update _load_fixture
to load and return the newest match accordingly.
🤖 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 `@tests/test_api_contracts.py`:
- Around line 32-33: The helper _fixture_paths currently returns an empty list
silently; change it to validate the result and raise a clear error when no
fixtures are found so CI fails fast. Update _fixture_paths(prefix: str) to
collect and sort the glob results, then if the resulting list is empty raise an
AssertionError or ValueError with a message that includes the prefix (e.g., "no
fixtures found for prefix '{prefix}'") so any tests calling _fixture_paths (and
other callers) fail immediately when a fixture set is missing.

---

Nitpick comments:
In `@tests/test_idempotency_under_retry.py`:
- Around line 22-25: The _load_fixture function currently picks the oldest
matching file because it returns sorted(...)[0]; change it to select the newest
matching fixture instead (e.g., choose the last element of a reverse sort or use
max(..., key=lambda p: p.stat().st_mtime)) so tests use the most recent
recording; update _load_fixture to load and return the newest match accordingly.
🪄 Autofix (Beta)

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

Run ID: d9b41b93-f732-440f-a705-672720bef123

📥 Commits

Reviewing files that changed from the base of the PR and between 8feb48b and 2ce1293.

📒 Files selected for processing (10)
  • tests/fixtures/api_contracts/README.md
  • tests/fixtures/api_contracts/github_commit_2026-05-28.json
  • tests/fixtures/api_contracts/github_issue_bundle_2026-05-28.json
  • tests/fixtures/api_contracts/github_pr_bundle_2026-05-28.json
  • tests/fixtures/api_contracts/slack_channel_2026-05-28.json
  • tests/fixtures/api_contracts/slack_message_2026-05-28.json
  • tests/fixtures/api_contracts/slack_team_2026-05-28.json
  • tests/fixtures/api_contracts/slack_user_2026-05-28.json
  • tests/test_api_contracts.py
  • tests/test_idempotency_under_retry.py

Comment thread tests/test_api_contracts.py Outdated
@wpak-ai wpak-ai merged commit cd269ef into cppalliance:develop May 28, 2026
5 checks passed
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.

Add Contract Tests for API Drift and Idempotency-Under-Retry

3 participants