Parent: #297
Depends on: #298, #301
Goal
Add deterministic offline tests that lock down the async transport contract and prevent drift from the established 1.x HTTP behavior.
Contract source
#298 is the source of truth for the public async transport contract. This issue should translate that contract into executable tests rather than merely checking that methods exist.
Coverage
Use fake/mocked async HTTP responses to cover at minimum:
HTTP/result behavior
- 2xx success
- successful empty response body ->
{} through MlbResult
- non-404 4xx such as 400/403 with
strict_http=True -> MlbHttpError
- non-404 4xx with
strict_http=False -> MlbHttpCompatibilityWarning + empty result
- endpoint-specific 404 handling -> empty
MlbResult
- final 429 behavior after retries
- final 5xx behavior after retries
- other final non-2xx behavior
- structured
MlbHttpError status/reason/URL/method and bounded best-effort response context
- malformed error-response context must not replace the original HTTP error
- compatibility warning category and caller-oriented call site
- compatibility warning must not leak response bodies, headers, credentials, or other sensitive context
Timeout, transport, decode, and cancellation
- timeout ->
MlbTimeoutError
- generic transport failure ->
MlbTransportError
- successful response with invalid JSON ->
MlbDecodeError
- underlying async HTTP-library exception types do not escape as normal public failures
- caller cancellation propagates as
asyncio.CancelledError
- cancellation is not retried
Retry behavior
For library-owned transport verify:
- GET-only retries
- retryable statuses
429, 500, 502, 503, 504
- equivalent total/connect/read/status retry limits
- effective
0.5 backoff behavior
Retry-After is honored
- JSON decode and model/parsing failures are not retried
- retry/backoff yields to the event loop rather than blocking it
Do not require caller-injected clients to adopt the library retry policy.
Lifecycle and ownership
- library-owned client creation and cleanup
- explicit
aclose()
- repeated cleanup / idempotent
aclose()
- cleanup on normal exit, exception, and cancellation
- caller-injected client preservation
- caller-injected headers/configuration are not silently mutated
- caller-injected clients are not closed
- library-owned User-Agent behavior
- injected-client User-Agent remains caller-controlled
Concurrency
Add deterministic tests proving the #298 concurrency contract:
- one
AsyncMlbDataAdapter / async client can have at least two in-flight requests concurrently on the same event loop
- concurrent requests maintain independent params, responses, errors, and parsing state
- cancelling request A does not implicitly cancel unrelated request B
- failure of request A does not implicitly alter request B unless caller-owned orchestration does so
- retry/backoff in one request does not block another request from making progress
- no hidden request fan-out/background task is required for a normal endpoint request
The tests do not need to support or validate cross-thread or cross-event-loop use.
Constraints
- Tests must not contact the live MLB API
- Avoid freezing implementation-specific details that are not part of the public contract
- Reuse the existing public exception hierarchy and model/result semantics
- Prefer observable behavior assertions over assertions about the selected HTTP library internals
Acceptance criteria
Refs #297
Contract: #298
Parent: #297
Depends on: #298, #301
Goal
Add deterministic offline tests that lock down the async transport contract and prevent drift from the established 1.x HTTP behavior.
Contract source
#298 is the source of truth for the public async transport contract. This issue should translate that contract into executable tests rather than merely checking that methods exist.
Coverage
Use fake/mocked async HTTP responses to cover at minimum:
HTTP/result behavior
{}throughMlbResultstrict_http=True->MlbHttpErrorstrict_http=False->MlbHttpCompatibilityWarning+ empty resultMlbResultMlbHttpErrorstatus/reason/URL/method and bounded best-effort response contextTimeout, transport, decode, and cancellation
MlbTimeoutErrorMlbTransportErrorMlbDecodeErrorasyncio.CancelledErrorRetry behavior
For library-owned transport verify:
429,500,502,503,5040.5backoff behaviorRetry-Afteris honoredDo not require caller-injected clients to adopt the library retry policy.
Lifecycle and ownership
aclose()aclose()Concurrency
Add deterministic tests proving the #298 concurrency contract:
AsyncMlbDataAdapter/ async client can have at least two in-flight requests concurrently on the same event loopThe tests do not need to support or validate cross-thread or cross-event-loop use.
Constraints
Acceptance criteria
Refs #297
Contract: #298