mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-26 01:12:21 +00:00
* ci: run the unit_selection.sh shard files on every event instead of only fork pull requests Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> * ci: rename fork-flag to unit-flag now that it applies on every event * test: move tests/test_litellm root and small trees into tests/unit Pure renames, no content changes. Follow-up commits in this PR fix references, merge the three files that already existed in tests/unit, keep live-provider tests in tests/test_litellm and wire CI. * test: carry tests/test_litellm conftest isolation into tests/unit Callback lists, routing fallbacks, cached HTTP clients, logger state, AWS, proxy-URL and keychain env, and session-end client cleanup now reset for unit tests too. The environment isolation owns its MonkeyPatch so a test's own monkeypatch is undone before the model-cost teardown runs. * test: merge, split and prune the moved root and small-tree tests Merge batches/test_batch_utils.py and the chat_completions and messages dispatch tests into the files that already existed in tests/unit. Keep the live Gemini interactions tests, the async image-fetch format test and the OpenAI embedding scorer test in tests/test_litellm since they need real network or keys. Put test_router.py under tests/unit/test_router so the existing package no longer shadows it. Delete eight tests the audit found superseded by stronger ones kept in this move. * ci: run the moved root and small-tree tests under their legacy flags Add the misc and responses-caching-types flags to unit_selection.sh and CircleCI, extend enterprise-routing and mcp-integration, and point the legacy GHA shards, Makefile, redis-compat workflow, merge smoke manifest and change classifier at the new paths. * test: make the new tests/unit directories packages tests/unit/test_package_layout.py requires every directory to carry an __init__.py, and without one the moved and retained test_litellm_responses_bridge.py modules collide on import. * test: scope the unit socket block to tests/unit in shared sessions The GHA shards collect the legacy test-path and the unit selection in one pytest session. The unit conftest's loopback-only block leaked into legacy modules that reach the network at import. The legacy conftest now lifts the restriction at collect and setup time, and the unit conftest re-applies it when collecting its own modules. * test: give the shard-script tests their own GITHUB_OUTPUT They only passed where the runner set it. The CircleCI unit job's env allowlist drops it, so the script's redirect failed there. * test: point the router and module-deletion checks at tests/unit router_code_coverage and code_qa_check_tests only searched tests/test_litellm, so the moved router tests no longer counted. The two silent-experiment tests the audit deleted were the only direct callers of those methods; they are replaced with tests that assert the forwarded shadow request and the recursion guard. --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
160 lines
5.6 KiB
Python
160 lines
5.6 KiB
Python
"""Cover the Bedrock-ARN dispatch in ``litellm.batches.main.retrieve_batch``.
|
|
|
|
The dispatch picks one of two Bedrock handlers depending on the ARN
|
|
family in ``batch_id``:
|
|
|
|
* ``:async-invoke/<id>`` -> ``_handle_async_invoke_status`` (data plane)
|
|
* ``:model-invocation-job/<id>`` -> ``_handle_model_invocation_job_status``
|
|
(control plane, added in this PR)
|
|
|
|
Anything else falls through to the generic ``provider_config`` retrieve
|
|
flow. We mock the two handlers so the tests don't hit AWS — the focus
|
|
here is purely the dispatch logic that lives in ``main.py``.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from unittest.mock import MagicMock, patch
|
|
|
|
import pytest
|
|
|
|
|
|
import litellm # noqa: E402
|
|
import openai
|
|
|
|
ASYNC_INVOKE_ARN = "arn:aws:bedrock:us-west-2:123456789012:async-invoke/abc123def456"
|
|
MIJ_ARN = "arn:aws:bedrock:us-west-2:123456789012:model-invocation-job/abc1234567"
|
|
|
|
|
|
@pytest.fixture
|
|
def mock_handlers():
|
|
"""Patch both Bedrock retrieve handlers and yield the mocks.
|
|
|
|
We patch at the import site (litellm.batches.main) rather than the
|
|
definition site so the ``BedrockBatchesHandler`` reference inside
|
|
``retrieve_batch`` resolves to our mocks.
|
|
"""
|
|
fake_batch = MagicMock(name="LiteLLMBatch")
|
|
with (
|
|
patch(
|
|
"litellm.batches.main.BedrockBatchesHandler._handle_async_invoke_status",
|
|
return_value=fake_batch,
|
|
) as async_invoke,
|
|
patch(
|
|
"litellm.batches.main.BedrockBatchesHandler._handle_model_invocation_job_status",
|
|
return_value=fake_batch,
|
|
) as mij,
|
|
):
|
|
yield async_invoke, mij, fake_batch
|
|
|
|
|
|
def test_async_invoke_arn_routes_to_async_invoke_handler(mock_handlers):
|
|
"""``:async-invoke/`` ARNs go to the data-plane handler."""
|
|
async_invoke, mij, fake_batch = mock_handlers
|
|
|
|
result = litellm.retrieve_batch(
|
|
batch_id=ASYNC_INVOKE_ARN,
|
|
custom_llm_provider="bedrock",
|
|
aws_region_name="us-west-2",
|
|
)
|
|
|
|
assert result is fake_batch
|
|
async_invoke.assert_called_once()
|
|
mij.assert_not_called()
|
|
call_kwargs = async_invoke.call_args.kwargs
|
|
assert call_kwargs["batch_id"] == ASYNC_INVOKE_ARN
|
|
assert call_kwargs["aws_region_name"] == "us-west-2"
|
|
# Region must be stripped from the forwarded kwargs to avoid TypeError
|
|
# (it's already an explicit positional/keyword arg).
|
|
assert "aws_region_name" not in {
|
|
k
|
|
for k in call_kwargs
|
|
if k not in {"batch_id", "aws_region_name", "logging_obj"}
|
|
}
|
|
|
|
|
|
def test_async_invoke_arn_falls_back_to_default_region_when_unset(mock_handlers):
|
|
"""If no ``aws_region_name`` is passed, the data-plane handler defaults
|
|
to ``us-east-1`` (preserving prior behavior on this branch)."""
|
|
async_invoke, _mij, _ = mock_handlers
|
|
|
|
litellm.retrieve_batch(
|
|
batch_id=ASYNC_INVOKE_ARN,
|
|
custom_llm_provider="bedrock",
|
|
)
|
|
|
|
async_invoke.assert_called_once()
|
|
assert async_invoke.call_args.kwargs["aws_region_name"] == "us-east-1"
|
|
|
|
|
|
def test_model_invocation_job_arn_routes_to_mij_handler(mock_handlers):
|
|
"""``:model-invocation-job/`` ARNs go to the new control-plane handler."""
|
|
_async_invoke, mij, fake_batch = mock_handlers
|
|
|
|
result = litellm.retrieve_batch(
|
|
batch_id=MIJ_ARN,
|
|
custom_llm_provider="bedrock",
|
|
aws_region_name="us-west-2",
|
|
)
|
|
|
|
assert result is fake_batch
|
|
mij.assert_called_once()
|
|
_async_invoke.assert_not_called()
|
|
call_kwargs = mij.call_args.kwargs
|
|
assert call_kwargs["batch_id"] == MIJ_ARN
|
|
assert call_kwargs["aws_region_name"] == "us-west-2"
|
|
|
|
|
|
def test_model_invocation_job_arn_with_no_region_passes_none(mock_handlers):
|
|
"""The MIJ handler is responsible for sniffing region from the ARN
|
|
when none is explicitly provided. Dispatch must forward ``None``
|
|
rather than substituting a default — otherwise per-region jobs in
|
|
other AWS regions would silently route to ``us-east-1``."""
|
|
_async_invoke, mij, _ = mock_handlers
|
|
|
|
litellm.retrieve_batch(
|
|
batch_id=MIJ_ARN,
|
|
custom_llm_provider="bedrock",
|
|
)
|
|
|
|
mij.assert_called_once()
|
|
assert mij.call_args.kwargs["aws_region_name"] is None
|
|
|
|
|
|
def test_unrelated_bedrock_arn_falls_through_to_provider_config(mock_handlers):
|
|
"""Bedrock ARNs that aren't async-invoke or model-invocation-job
|
|
must NOT hit either special handler — they should fall through to
|
|
the existing generic provider_config path. We don't fully exercise
|
|
that path here (it requires a real provider config); we just assert
|
|
neither special handler is invoked."""
|
|
async_invoke, mij, _ = mock_handlers
|
|
|
|
# Use a plausible-but-unsupported Bedrock ARN family.
|
|
unrelated_arn = "arn:aws:bedrock:us-west-2:123456789012:provisioned-model/xyz"
|
|
|
|
with pytest.raises(litellm.BadRequestError):
|
|
# Will raise because no provider_config exists for this path —
|
|
# that's fine, we just need to assert neither bedrock handler ran
|
|
# before the failure.
|
|
litellm.retrieve_batch(
|
|
batch_id=unrelated_arn,
|
|
custom_llm_provider="bedrock",
|
|
)
|
|
|
|
async_invoke.assert_not_called()
|
|
mij.assert_not_called()
|
|
|
|
|
|
def test_non_bedrock_id_skips_bedrock_dispatch_entirely(mock_handlers):
|
|
"""Plain (non-ARN) batch ids must not even enter the Bedrock dispatch
|
|
block — they belong to other providers' retrieve flows."""
|
|
async_invoke, mij, _ = mock_handlers
|
|
|
|
with pytest.raises(openai.OpenAIError):
|
|
litellm.retrieve_batch(
|
|
batch_id="batch_abc123",
|
|
custom_llm_provider="openai",
|
|
)
|
|
|
|
async_invoke.assert_not_called()
|
|
mij.assert_not_called()
|