Skip to content

test(litellm): parametrize sync/async test pairs - #739

Open
starfolkai[bot] wants to merge 3 commits into
mainfrom
refactor/litellm-sync-async-parametrize
Open

test(litellm): parametrize sync/async test pairs#739
starfolkai[bot] wants to merge 3 commits into
mainfrom
refactor/litellm-sync-async-parametrize

Conversation

@starfolkai

@starfolkai starfolkai Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

Summary

Collapses 13 duplicated sync/async LiteLLM test pairs into single parametrized tests, addressing the ~15 mechanical duplicate pairs in test_litellm.py. The file shrinks from 1088 → 828 lines (−242 net) with no loss of coverage.

A shared marker plus two small helpers drive the dispatch:

sync_async = pytest.mark.parametrize("is_async", [False, True], ids=["sync", "async"])

async def _call(is_async, sync_fn, async_fn, *args, **kwargs): ...   # awaits async_fn when is_async
async def _collect_stream(stream, is_async): ...                     # drains sync or async streams

Parametrized pairs: completion, text_completion, completion_streaming, responses, embedding, moderation, image_generation, completion_with_system_prompt, transcription, speech, completion_error, responses_streaming, rerank.

Genuinely-single tests (prompt_caching, async_parallel_requests, tool_calls, async_streaming_with_break, the boolean/rerank unit tests, the patch_litellm_* subprocess tests, and auto-instrument) are left untouched.

Small coverage gains

Where an async variant historically asserted less than its sync twin, the unified body applies the stronger set to both — verified against the existing cassettes first:

  • streaming variants now assert response content / "24" in the async case too
  • rerank[async] now checks results[0]["index"] == 0, output-key shape, and search_units
  • completion_metrics[async] now checks the litellm-auto span origin

Cassettes

Because pytest-recording names cassettes after the test node, the 24 paired cassettes were renamed to their parametrized names (e.g. test_litellm_acompletion_metrics.yamltest_litellm_completion_metrics[async].yaml) across both the latest/ and 1.74.0/ matrix dirs — 48 pure git mv renames, no recorded content changed.

Validation

  • nox -s "test_litellm(latest)"38 passed (matches pre-change baseline)
  • nox -s "test_litellm(1.74.0)"38 passed
  • make pylint (--errors-only) → clean; pre-commit (ruff-format, ruff check, codespell) → clean
  • make check-stale-cassettes → no stale dirs

🤖 Generated with Claude Code

Created by Abhijeet Prasad (@AbhiPrasad)

Slack thread

Collapse 13 duplicated sync/async LiteLLM test pairs into single
parametrized tests using a shared `sync_async` marker plus two small
helpers (`_call` and `_collect_stream`). Cuts test_litellm.py from 1088
to ~828 lines with no loss of coverage.

Where the async variant historically asserted less than its sync twin,
the unified body now applies the stronger assertions to both (verified
against the existing cassettes): streaming content/output checks, rerank
index/output-shape/search_units, and the litellm-auto span origin.

Cassettes are renamed to the parametrized node names (e.g.
test_litellm_acompletion_metrics.yaml ->
test_litellm_completion_metrics[async].yaml) across both the latest and
1.74.0 matrix dirs. Pure git renames, no recorded content changed.

Validated: nox -s "test_litellm(latest)" and "test_litellm(1.74.0)"
both pass 38 tests; pylint (--errors-only) and pre-commit clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5ecf1a5954

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "Codex (@codex) review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "Codex (@codex) address that feedback".

Comment on lines +44 to +46
if is_async:
return await async_fn(*args, **kwargs)
return sync_fn(*args, **kwargs)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Run sync cases outside the asyncio loop

For every is_async=False parameter, sync_fn is now invoked from inside a coroutine managed by pytest-asyncio, so these tests no longer exercise LiteLLM's synchronous entry points in the no-running-event-loop context used by ordinary synchronous callers. LiteLLM and its transports can select loop-dependent execution paths, meaning this refactor can hide sync-only failures even though both parameter values pass; keep a synchronous test driver for the sync variants while sharing only the call arguments and assertions.

Useful? React with 👍 / 👎.

starfolkbot and others added 2 commits September 4, 2026 20:02
Address /simplify review feedback:
- _collect_stream now uses (async) comprehensions instead of a manual
  append loop.
- test_litellm_image_generation sends the blue prompt on the async
  variant, matching the recorded [async] cassette body (the sync
  variant keeps red) so code and cassettes agree.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Addresses PR review (P2): the parametrized tests were `async def` +
@pytest.mark.asyncio, so the `is_async=False` variants invoked LiteLLM's
sync entrypoints from inside a running event loop -- not how ordinary
synchronous callers use them. LiteLLM and its transports can select
loop-dependent code paths, so sync-only failures could be hidden even
though both parameter values pass.

The parametrized tests are now plain `def` functions. `_run` calls the
sync entrypoint directly (no running loop) and drives the async
entrypoint with `asyncio.run`; `_run_stream` does the same for streaming
(await + async-drain under asyncio.run). The genuinely async-only tests
(async_parallel_requests, async_streaming_with_break) keep
@pytest.mark.asyncio.

Validated: nox test_litellm(latest) and (1.74.0) both pass 38; pylint
and pre-commit clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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