Skip to content

test: auth tests, 401 coverage, and test suite gaps#15

Merged
podmar merged 7 commits into
mainfrom
test/auth
Jun 18, 2026
Merged

test: auth tests, 401 coverage, and test suite gaps#15
podmar merged 7 commits into
mainfrom
test/auth

Conversation

@podmar

@podmar podmar commented Jun 18, 2026

Copy link
Copy Markdown
Owner

Closes the remaining test gaps from the integration suite: auth flow, unauthenticated access, and two coverage holes identified on review.

Decisions worth noting

  • Auth tests use only client, no auth fixture — testing the auth flow with a pre-authenticated state would defeat the purpose.
  • One 401 test per resource, not per endpoint — a single unauthenticated request is sufficient to prove the router-level dependency is wired correctly; testing every verb would be redundant.
  • GET /items/{id} isolation added explicitly — the existing isolation tests covered list, update, and delete for items but missed the single-item GET. The other resources don't have a GET-by-ID endpoint so this is items-specific.
  • /expiring boundary test checks both sides of the cutoff — the filter is expiry_date <= today + days; a batch expiring exactly on the cutoff day must be included, one day after must not. Off-by-one bugs live at boundaries.
  • filterwarnings scoped tightly to fastapi_users_db_sqlalchemy — the library emits a SQLModel deprecation warning on every query. Suppressing broadly would hide genuine warnings; the tight scope limits it to that package only.
  • Compensating transaction in on_after_register is not tested — verifying that the orphaned user is deleted when household creation fails would require mocking SQLAlchemy internals. The blanket no-mocks rule exists because isolation bugs are the risk here, not exception handling; this edge case doesn't meet the bar.

What's next

Frontend — auth UI against the existing endpoints.

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

Review Summary

This PR adds comprehensive test coverage for auth flows and 401 responses across all endpoints. The tests correctly verify both happy paths and error conditions.

Critical

None — no security issues or data isolation bugs.

Minor

  • TIL formatting issue — one entry was accidentally split across two lines with another entry inserted in the middle. Clean read-through fix.
  • Nice catch on the boundary testtest_expiring_boundary verifies the <= operator is correct, which prevents off-by-one bugs in expiry queries.

What I verified

✅ All auth tests match the actual fastapi-users behavior (login uses data= form encoding with username field)
✅ 401 tests correctly target unauthenticated access
✅ Household isolation tests still comprehensive
✅ No missing household_id filters in any query
✅ Boundary test aligns with the Batch.expiry_date <= cutoff logic in batches.py:271

Cost: $0.67

Comment thread docs/til.md
- **Guard `TEST_DATABASE_URL != DATABASE_URL` at import time.**
- **`filterwarnings` in `pyproject.toml` scopes warning suppression to a specific package** — `"ignore::DeprecationWarning:fastapi_users_db_sqlalchemy"` suppresses only that library's warnings without risking hiding your own. Useful when a dependency emits unavoidable noise on every test run. A per-test TRUNCATE against production is catastrophic. Read both URLs via the settings class and raise `RuntimeError` at module import — fails before any connection is made.

---

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Typo in the TIL entry: The sentence "filterwarnings..." was inserted in the middle of the existing "Guard TEST_DATABASE_URL != DATABASE_URL..." entry, breaking it across lines 100 and 103. The guard entry should be on one line, and the filterwarnings entry should be separate.

Why this matters: This makes the TIL file harder to read — the guard note is split in half with an unrelated note in between.

resp = await client.get("/expiring?days=7", headers=auth)
expiry_dates = [b["expiry_date"] for b in resp.json()]
assert cutoff in expiry_dates
assert just_outside not in expiry_dates

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Good boundary test! This confirms that the <= operator on line 271 of batches.py is correct — batches expiring on the cutoff day should be included. A common off-by-one bug in expiry logic.

This is the kind of test that catches subtle regressions when someone "simplifies" the query later.

@claude

claude Bot commented Jun 18, 2026

Copy link
Copy Markdown

Review Summary

Critical

None — no security issues or data isolation bugs.

Minor

  • TIL formatting: one entry accidentally split across lines
  • Good boundary test for expiry logic — catches off-by-one bugs

Cost: $0.67

@podmar
podmar merged commit 960f637 into main Jun 18, 2026
@podmar
podmar deleted the test/auth branch June 18, 2026 20:36
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