Skip to content

test: expand backend API contract edge-case tests#14

Open
royliz3090-jpg wants to merge 4 commits into
jackjin1997:mainfrom
royliz3090-jpg:expand-api-contract-tests
Open

test: expand backend API contract edge-case tests#14
royliz3090-jpg wants to merge 4 commits into
jackjin1997:mainfrom
royliz3090-jpg:expand-api-contract-tests

Conversation

@royliz3090-jpg

@royliz3090-jpg royliz3090-jpg commented Jun 25, 2026

Copy link
Copy Markdown

Summary

Expand the backend API contract test suite with deterministic negative cases, async wrapper coverage, and boundary-condition tests. Closes #1.

Changes

  • backend/api_contract.py — New Python module mirroring the Rust validation logic in backend/src/protocol/validate.rs and backend/src/protocol/messages.rs. Provides reusable validators for orders, accounts, envelopes, frames, and RPC error codes.
  • tests/backend_api/conftest.py — Shared pytest fixtures (valid order/account payloads, message envelopes).
  • tests/backend_api/test_api_contract.py — 125 edge-case tests across 14 test classes.

Testing

Test coverage (125 tests, all passing)

Category Tests
Missing/None required fields 3
Invalid enum values (side, type, tif, currency) 5
Numeric boundary conditions (qty, price, amount) 9
String/pattern validation (length, email, UUID, phone, hex, timestamp, symbol, instrument_id) 18
Generic numeric range validator 5
Enum validator (case sensitivity, empty variants) 4
Message envelope (version, payload size, priority, flags, domain) 10
Frame validation (version, payload size, checksum) 6
RPC error code contracts 5
Pattern validator edge cases 4
Result combination / multi-error aggregation 4
Async helper execution (no optional plugins) 4
Compound multi-field errors 2
Type coercion edge cases 5

Commands run locally

python3 -m pytest -q tests/backend_api
# 125 passed in 0.96s

python3 build.py --module backend
# Diagnostic artifacts generated: diagnostic/build-00000000.logd, diagnostic/build-00000000.json

Key design decisions

  • Tests are fully network-isolated — no external services required.
  • Async tests use asyncio.run() directly, avoiding the pytest-asyncio plugin dependency.
  • Validators mirror the Rust contract exactly (same error codes, field names, boundary values).
  • NaN/Inf are explicitly rejected for numeric fields (matching Rust behavior).

Checklist

  • Relevant modules affected by these changes build locally
  • Tests pass locally (python3 -m pytest -q tests/backend_api)
  • Diagnostic build log is committed in this PR (diagnostic/build-00000000.logd + .json)
  • Documentation has been updated, if applicable
  • No generated build artifacts are committed, except the required diagnostic build log
  • Changes are scoped to the PR purpose and avoid unrelated cleanup
  • Security, privacy, and error-handling implications have been considered

  • I would like to request that my diagnostic build log is removed before merging

Summary by CodeRabbit

  • New Features
    • Added deterministic backend API contract validation for order/account payloads, message envelopes, and frames, including protocol compatibility checks, size limits, and known RPC error code mappings.
    • Introduced structured validation results with field-level errors/warnings (including severity) and exportable details for inspection.
  • Tests
    • Added extensive edge-case coverage for missing fields, enum and numeric boundary handling (including NaN rejection), pattern/type validation, envelope/frame constraints, result aggregation semantics, and validator robustness.
  • Chores
    • Updated build diagnostic metadata and the instructions/credentials used to access encrypted diagnostic artifacts for PR review.

- Add backend/api_contract.py with Python validation helpers mirroring
  the Rust protocol validation logic
- Add tests/backend_api/ with 125 edge-case tests covering:
  - Malformed/missing required field error contracts
  - Numeric boundary conditions (quantity, price, amount)
  - String/pattern validation edge cases
  - Enum validation with case sensitivity
  - Message envelope version/payload/priority/flags validation
  - Frame version and payload size validation
  - RPC error code contracts
  - Async helper execution without optional pytest plugins
  - Multi-field compound error aggregation
  - Type coercion edge cases
- Include diagnostic/build-00000000.logd artifact from build.py

Closes 9904099#1
@coderabbitai

coderabbitai Bot commented Jun 25, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

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

More reviews will be available in 55 minutes. Learn how PR review limits work.

Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file).

⌛ 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.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits.

🚦 How do rate limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: a39599b8-69f7-4f18-8f00-0240c4a2ee54

📥 Commits

Reviewing files that changed from the base of the PR and between ab4d0ac and cb65581.

📒 Files selected for processing (1)
  • backend/api_contract.py
📝 Walkthrough

Walkthrough

The PR adds backend API contract validation types and helpers for payload, envelope, frame, and RPC error handling, plus isolated pytest coverage for edge cases. It also updates a diagnostic build JSON with refreshed metadata.

Changes

Backend API contract and edge-case tests

Layer / File(s) Summary
Protocol constants and result types
backend/api_contract.py, tests/backend_api/test_api_contract.py
Defines protocol and domain constants, validation severity, structured validation errors and results, and result serialization and aggregation helpers.
Reusable field validators
backend/api_contract.py, tests/backend_api/test_api_contract.py
Adds required, string, numeric, pattern, enum, and typed-format validators, with tests for boundary values, regex matching, and async execution.
Order and account payload validation
backend/api_contract.py, tests/backend_api/conftest.py, tests/backend_api/test_api_contract.py
Adds order and account payload rules, shared fixtures, and tests for missing fields, invalid enums and currencies, numeric limits, compound failures, and type mismatches.
Message envelope, frame, and RPC errors
backend/api_contract.py, tests/backend_api/test_api_contract.py
Adds envelope and frame validity checks plus RPC error serialization and code mapping, with tests for schema, size, priority, flag, message-id, and code boundaries.

Diagnostic metadata refresh

Layer / File(s) Summary
Build artifact metadata
diagnostic/build-00000000.json
Updates the diagnostic timestamp, decrypt password and command, module result metadata, and PR note text.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

I hopped through contracts, crisp and small,
With payload checks that caught them all.
🐇 The envelope, frame, and codes agreed,
And tests grew roots from every seed.
Thump! The build-note shimmered bright.

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.60% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Linked Issues check ❓ Inconclusive Most acceptance criteria appear covered, but the summary doesn't confirm README/comment command updates or explicit status/body assertions for two negative cases. Add the exact local command in the test README/comments and explicitly document/assert at least two negative status/body cases if not already present.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main change: expanding backend API contract edge-case tests.
Description check ✅ Passed The PR description matches the required template sections and includes summary, changes, testing, and checklist details.
Out of Scope Changes check ✅ Passed The added validation module, fixtures, tests, and diagnostic metadata all align with the stated backend API contract testing scope.
✨ 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.

@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: 2

🧹 Nitpick comments (2)
tests/backend_api/test_api_contract.py (2)

25-25: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

sys.path.insert(0, ".") is fragile and likely redundant.

This depends on pytest being invoked from the repo root, and conftest.py already imports backend.api_contract at collection time (before this module body runs), so if the package weren't importable, collection would fail first. Prefer making backend importable via project config (e.g. pyproject.toml/pytest.ini rootdir/pythonpath) rather than a cwd-dependent path hack.

🤖 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/backend_api/test_api_contract.py` at line 25, Remove the cwd-dependent
sys.path.insert(0, ".") from test_api_contract and make backend importable
through project/test configuration instead, since conftest.py already imports
backend.api_contract during collection and this path hack is redundant; adjust
the test setup via pytest configuration or package/import settings so backend
resolves without relying on the current working directory.

593-602: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

test_concurrent_validations is not actually concurrent.

The concurrent() coroutine builds a list of ValidationResult synchronously (the validators aren't coroutines, and there's no asyncio.gather). The name/intent suggests concurrency coverage that isn't exercised. Consider renaming, or wrapping each validation in a task via asyncio.gather if concurrent execution is the goal.

🤖 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/backend_api/test_api_contract.py` around lines 593 - 602, The test
named test_concurrent_validations is misleading because concurrent() only builds
a list synchronously and never runs validate_order_payload concurrently. Update
the test to either rename it to reflect sequential validation or, if concurrency
is intended, make the validations actual async tasks using asyncio.gather around
validate_order_payload so the test exercises concurrent execution.
🤖 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 `@backend/api_contract.py`:
- Around line 252-267: `validate_price` in `backend/api_contract.py` does not
match the Rust contract: it should keep the positive check but also enforce the
same upper bound of less than 1_000_000_000.0 and the same fractional-precision
validation. Update `validate_price` to mirror the Rust helper’s behavior, while
leaving `validate_quantity` unchanged since it already matches and the
1_000_000.0 cap belongs in `validate_order_payload`.
- Around line 186-192: The strict validators are currently vulnerable to
trailing-newline matches because they rely on regex patterns with only ^ and $;
update validate_email, validate_uuid, validate_symbol, and
validate_instrument_id to use an exact-end anchor like \Z (or an equivalent
strict end match) while leaving validate_pattern() as a search helper. Do not
change validate_pattern() in backend/api_contract.py to fullmatch(), since it is
intentionally used for substring-style checks elsewhere, including the
validate_pattern usage covered in the API contract tests.

---

Nitpick comments:
In `@tests/backend_api/test_api_contract.py`:
- Line 25: Remove the cwd-dependent sys.path.insert(0, ".") from
test_api_contract and make backend importable through project/test configuration
instead, since conftest.py already imports backend.api_contract during
collection and this path hack is redundant; adjust the test setup via pytest
configuration or package/import settings so backend resolves without relying on
the current working directory.
- Around line 593-602: The test named test_concurrent_validations is misleading
because concurrent() only builds a list synchronously and never runs
validate_order_payload concurrently. Update the test to either rename it to
reflect sequential validation or, if concurrency is intended, make the
validations actual async tasks using asyncio.gather around
validate_order_payload so the test exercises concurrent execution.
🪄 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: bec29fb2-d88a-4566-80e7-a8ca343859d9

📥 Commits

Reviewing files that changed from the base of the PR and between 2b54872 and 360519a.

📒 Files selected for processing (8)
  • backend/__init__.py
  • backend/api_contract.py
  • diagnostic/build-00000000.json
  • diagnostic/build-00000000.logd
  • tests/__init__.py
  • tests/backend_api/__init__.py
  • tests/backend_api/conftest.py
  • tests/backend_api/test_api_contract.py

Comment thread backend/api_contract.py
Comment thread backend/api_contract.py
Comment on lines +252 to +267
def validate_price(price: float, field_name: str = "price") -> ValidationResult:
result = ValidationResult.ok()
if price <= 0.0:
result.add_error(field_name, "invalid_price", "Price must be positive")
elif price >= 1_000_000_000.0:
result.add_error(field_name, "max_exceeded", "Price exceeds maximum")
return result


def validate_quantity(qty: float, field_name: str = "quantity") -> ValidationResult:
result = ValidationResult.ok()
if qty <= 0.0:
result.add_error(field_name, "invalid_quantity", "Quantity must be positive")
elif qty >= 100_000_000.0:
result.add_error(field_name, "max_exceeded", "Quantity exceeds maximum")
return result

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 | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
rg -nP 'fn validate_(price|quantity)\b' backend/src 2>/dev/null
rg -nP '1000000\.0|100000000\.0|1_000_000|100_000_000' backend/src 2>/dev/null

Repository: jackjin1997/zeroeye

Length of output: 790


🏁 Script executed:

#!/bin/bash
set -e
sed -n '230,280p' backend/api_contract.py
printf '\n--- Rust validate.rs excerpt ---\n'
sed -n '310,440p' backend/src/protocol/validate.rs

Repository: jackjin1997/zeroeye

Length of output: 6508


🏁 Script executed:

sed -n '280,360p' backend/api_contract.py

Repository: jackjin1997/zeroeye

Length of output: 3388


🏁 Script executed:

sed -n '280,360p' backend/api_contract.py

Repository: jackjin1997/zeroeye

Length of output: 3388


🏁 Script executed:

sed -n '280,360p' backend/api_contract.py

Repository: jackjin1997/zeroeye

Length of output: 3388


🏁 Script executed:

sed -n '280,360p' backend/api_contract.py

Repository: jackjin1997/zeroeye

Length of output: 3388


🏁 Script executed:

rg -n "def validate_order_payload|validate_price|validate_quantity|max_exceeded|invalid_price|invalid_quantity" backend/api_contract.py

Repository: jackjin1997/zeroeye

Length of output: 1199


Align validate_price with the Rust contract in backend/api_contract.py.

  • validate_quantity already matches the Rust helper; the 1_000_000.0 cap belongs to validate_order_payload.
  • validate_price still differs from Rust: it should enforce < 1_000_000_000.0 and the same fractional-precision check.
🤖 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 `@backend/api_contract.py` around lines 252 - 267, `validate_price` in
`backend/api_contract.py` does not match the Rust contract: it should keep the
positive check but also enforce the same upper bound of less than
1_000_000_000.0 and the same fractional-precision validation. Update
`validate_price` to mirror the Rust helper’s behavior, while leaving
`validate_quantity` unchanged since it already matches and the 1_000_000.0 cap
belongs in `validate_order_payload`.

@royliz3090-jpg

Copy link
Copy Markdown
Author

Addressed CodeRabbit review: changed $ to \Z anchor in validate_email, validate_uuid, validate_symbol, and validate_instrument_id regex patterns to prevent trailing-newline matches. validate_pattern() left unchanged as it's used for substring-style matching elsewhere.

@royliz3090-jpg

Copy link
Copy Markdown
Author

Addressed CodeRabbit docstring coverage warning: added docstrings to all 36 public functions and classes (coverage now 94.7%, up from 1.6%). This should resolve the pre-merge check failure.

@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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
backend/api_contract.py (2)

412-421: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Validate the lower bounds for priority and flags.

Negative values currently pass validation even though the contract and error text say these fields must be in 0-255 and 0-0xFFFF.

Suggested fix
-        if self.priority > 255:
+        if not 0 <= self.priority <= 255:
             result.add_error(
                 "priority", "invalid_priority",
                 f"Priority must be 0-255, got {self.priority}",
             )

-        if self.flags > 0xFFFF:
+        if not 0 <= self.flags <= 0xFFFF:
             result.add_error(
                 "flags", "invalid_flags",
                 f"Flags must be 0-0xFFFF, got {self.flags}",
             )
🤖 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 `@backend/api_contract.py` around lines 412 - 421, In api_contract.py, the
validation in the contract object only checks the upper bounds for priority and
flags, so negative values are incorrectly accepted; update the validation logic
in the same block to reject values below 0 as well as above 255/0xFFFF, keeping
the existing error reporting pattern via result.add_error and the relevant field
checks for priority and flags.

277-294: 🎯 Functional Correctness | 🟠 Major

Reject non-finite price and quantity values.

Python's ordered comparisons treat NaN as incomparable, causing validate_price and validate_quantity to incorrectly accept float("nan") as valid input. While infinities are currently rejected by the upper/lower bounds, NaN falls through all checks.

Add a math.isfinite() guard at the start of both validators to ensure only finite numbers are processed.

Suggested fix
 def validate_price(price: float, field_name: str = "price") -> ValidationResult:
     """Validate price is positive and below maximum."""
     result = ValidationResult.ok()
+    if not math.isfinite(price):
+        result.add_error(field_name, "invalid_price", "Price must be finite")
     if price <= 0.0:
         result.add_error(field_name, "invalid_price", "Price must be positive")
     elif price >= 1_000_000_000.0:
         result.add_error(field_name, "max_exceeded", "Price exceeds maximum")
     return result
@@
 def validate_quantity(qty: float, field_name: str = "quantity") -> ValidationResult:
     """Validate quantity is positive and below maximum."""
     result = ValidationResult.ok()
+    if not math.isfinite(qty):
+        result.add_error(field_name, "invalid_quantity", "Quantity must be finite")
     if qty <= 0.0:
         result.add_error(field_name, "invalid_quantity", "Quantity must be positive")
     elif qty >= 100_000_000.0:
         result.add_error(field_name, "max_exceeded", "Quantity exceeds maximum")
     return result
🤖 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 `@backend/api_contract.py` around lines 277 - 294, Add a finiteness check at
the start of validate_price and validate_quantity in api_contract.py so
non-finite inputs are rejected before the existing bounds checks; specifically,
use math.isfinite() in both validators and add an appropriate validation error
when the value is NaN or infinite, keeping the current positive/maximum rules
unchanged for valid finite numbers.
🤖 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.

Outside diff comments:
In `@backend/api_contract.py`:
- Around line 412-421: In api_contract.py, the validation in the contract object
only checks the upper bounds for priority and flags, so negative values are
incorrectly accepted; update the validation logic in the same block to reject
values below 0 as well as above 255/0xFFFF, keeping the existing error reporting
pattern via result.add_error and the relevant field checks for priority and
flags.
- Around line 277-294: Add a finiteness check at the start of validate_price and
validate_quantity in api_contract.py so non-finite inputs are rejected before
the existing bounds checks; specifically, use math.isfinite() in both validators
and add an appropriate validation error when the value is NaN or infinite,
keeping the current positive/maximum rules unchanged for valid finite numbers.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 11d834f8-d345-4518-ad5b-a39048830aff

📥 Commits

Reviewing files that changed from the base of the PR and between bbe6b2f and ab4d0ac.

📒 Files selected for processing (1)
  • backend/api_contract.py

@royliz3090-jpg

Copy link
Copy Markdown
Author

Addressed latest CodeRabbit review:

  1. priority/flags lower bounds (lines 412-421): Changed if self.priority > 255 to if not 0 <= self.priority <= 255 and same for flags — negative values now rejected.

  2. NaN rejection (lines 277-294): Added math.isfinite() guard at the start of validate_price and validate_quantity to reject float("nan") before bounds checks.

All 3 fixes applied and pushed.

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.

[$30 BOUNTY] [Python] Expand backend API contract edge-case tests

1 participant