litellm/tests/integration/providers/test_moderations.py
devin-ai-integration[bot] 1dbde0845e
test: migrate SDK and proxy-booting legacy CircleCI tests to their tiers (#45758)
* test: move guardrails, image, audio, batches, search legacy tests to unit

* test: restore the custom guardrail and remaining chunk 1 unit rows

* test: move the ocr matrix to e2e

* test: drop comments from moved tests and fix vertex ocr credentials

* test: move litellm utils and unified google legacy tests to their tiers

* test: move logging callback and pass-through unit legacy tests to their tiers

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* test: move store_model_in_db legacy tests and start the admin ui migration

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* test: finish the proxy job rows and drop their CircleCI jobs

Moves the remaining multi-instance, openai endpoint, otel, pass-through and
top-level proxy tests into tests/integration with scripted upstreams, rewrites
the weak replacements to assert the outbound wire and exact responses, and
removes the build_and_test job group this PR owns from CircleCI

* test: tighten the key generation and error log assertions, rename migrated unit files to their mapped names

* test: shard the pagerduty unit tests and record the rust harness file on the coverage allowlist

* test: drive the SSO sign-in tests through a scripted IdP and isolate the cost center stand-in

* test: type the e2e beta header, prompt cache and secret manager values

* test: assert the missing model error message on the OpenAI routes

* test: drop the deleted otel base class import and restore mcp redaction and exact langfuse usage checks

* test: make the langfuse fixture directory a package for the layout check

* test: restore collected no-match cases, real langfuse and gcs payload checks, and gate the aws secret lane

* test: keep the ocr e2e pdf fixture next to the test

* test: put meta below covers on the streaming tool search e2e

* test: run the OCR matrix against a scripted upstream and fix two runner-only e2e failures

* test: count only OCR calls in the OCR matrix recorder

* test: pin OCR parse bodies and billed cost, group new e2e cases into classes

* ci: restore the python image anchor dropped in the main sync

---------

Co-authored-by: yuneng <yuneng@berri.ai>
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-10-11 00:17:21 -07:00

62 lines
2.3 KiB
Python

import json
from typing import Final
from tests.integration._support.client import Gateway
from tests.integration._support.wire import Reply, Request, wire_server
_MODERATION_RESULT: Final = {
"id": "modr-integration",
"model": "omni-moderation-latest",
"results": [
{
"flagged": True,
"categories": {"violence": True},
"category_scores": {"violence": 0.99},
}
],
}
def _present(fields: dict[str, object]) -> dict[str, object]:
return {name: value for name, value in fields.items() if value is not None}
def _moderation_response(request: Request) -> Reply:
if (request.method, request.target) == ("GET", "/v1/models"):
return Reply(body=b'{"object":"list","data":[]}')
if (request.method, request.target) == ("POST", "/v1/moderations"):
return Reply(body=json.dumps(_MODERATION_RESULT).encode())
return Reply(status=404, body=b'{"error":"unexpected moderation request"}')
def test_moderations_forwards_the_selected_model_and_input(gateway: Gateway) -> None:
with wire_server(_moderation_response) as wire, gateway.scenario() as scenario:
model: Final = scenario.model(
model="omni-moderation-latest",
custom_llm_provider="openai",
api_key="moderation-integration-key",
api_base=f"{wire.url}/v1",
)
text: Final = "I want to harm someone"
response: Final = gateway.request(
"POST",
"/v1/moderations",
{"input": text, "model": model},
)
assert response.status_code == 200, response.text
body: Final = response.json()
assert (body["id"], body["model"]) == (_MODERATION_RESULT["id"], _MODERATION_RESULT["model"])
assert [
(
result["flagged"],
_present(result["categories"]),
_present(result["category_scores"]),
)
for result in body["results"]
] == [(True, {"violence": True}, {"violence": 0.99})]
requests: Final = tuple(
request for request in wire.drain() if request.target == "/v1/moderations"
)
assert len(requests) == 1
assert json.loads(requests[0].body) == {"input": text, "model": "omni-moderation-latest"}