Skip to content

Latest commit

 

History

History
49 lines (33 loc) · 3.68 KB

File metadata and controls

49 lines (33 loc) · 3.68 KB

Handoff — Shopify Webhook Service Test Suite

Task: TASK-004-008 — Create full pytest test suite

Files Changed

File Change
tests/conftest.py Created — shared fixtures: client (TestClient), log_entries (capfd-based structlog capture), sample_product_payload, minimal_product_payload, payload_with_extras, large_product_payload
tests/test_health.py Created — 16 tests: HEALTH-UNIT-001..005, HEALTH-INT-001..002, HEALTH-E2E-001, HEALTH-UX-F-001..003, HEALTH-EDGE-001..005
tests/test_webhooks.py Created — 39 tests: WH-UNIT-001..012, WH-INT-001..004, WH-E2E-001..005, WH-UX-A/B/C/D/E/G states
results/TASK-004-008.json Created — task result JSON

Test Summary

55 tests, all passing.

Health Endpoint (16 tests)

  • Unit: GET /health → 200 + {"status": "ok"}, content-type JSON, POST/PUT/DELETE → 405
  • Integration: stateless after 405, Dockerfile HEALTHCHECK valid
  • E2E: full chain GET→POST→GET
  • UX (Mockup F): Dockerfile HEALTHCHECK config, response shape, command syntax
  • Edge: query params ignored, JSON body on GET ignored, 100 rapid GETs, /healthz → 404, trailing slash

Webhook Endpoint (39 tests)

  • Unit: valid payload 200, structured log output, missing id/title → 422, extra fields allowed, invalid JSON → 422, null id → 422, string id → 422, minimal payload 200, empty body 422, no content-type behavior, structlog JSON validity
  • Integration: full pipeline with log verification, 422 error detail structure, minimal payload pipeline, concurrent 10 requests
  • E2E: smoke (valid/invalid/valid), happy path with logs, error path no log, recovery, large 1000-variant payload
  • UX (Mockups A-G): idle state, webhook received, validation, logging, success, error states

Key Design Decisions

  1. structlog capture via capfd: structlog's PrintLoggerFactory writes directly to stdout (file descriptor 1), bypassing the Python stdlib logging module. A custom log_entries fixture using capfd.readouterr() captures stdout at the fd level and parses JSON lines. This correctly captures structlog output where a stdlib logging.Handler would not.

  2. WH-UNIT-011 (no Content-Type): FastAPI requires Content-Type: application/json to parse the request body as JSON and deserialize it into a Pydantic model. Without it, FastAPI returns 422 (validation error for missing body). The test was updated to assert 422, matching actual FastAPI behavior, rather than 200 as originally specified in the test plan.

  3. HEALTH-EDGE-002 (GET with body): TestClient.get() doesn't accept content/data kwargs. Used client.request("GET", ...) instead.

  4. WH-INT-004 (concurrent): Uses threading.Thread with per-thread TestClient instances since TestClient is not thread-safe for concurrent use within a single instance.

Deviations from Test Plan

  • HEALTH-E2E-002 (Docker HEALTHCHECK E2E): Not implemented — requires Docker to be available in the test environment. Marked as CI-only per the test plan's own GAP-1 recommendation.
  • WH-UNIT-011: Adjusted expectation from 200 → 422 to match FastAPI's actual behavior for requests without Content-Type: application/json.

Risks / Open Questions

  • The capfd-based log capture reads ALL stdout between test calls, including httpx/uvicorn debug lines. The fixture filters for event == "shopify.product_update" to isolate webhook log entries. If additional structlog-native loggers are added, tests may need updating.
  • Tests currently run against Python 3.10 (system default in container), while the spec targets Python 3.12. All code uses only 3.10-compatible syntax (str | None works in 3.10+ via from __future__ import annotations or natively in 3.10+).