补充 OpenAI 主备验收与可复用双协议测试

This commit is contained in:
Codex
2026-10-28 18:23:21 -07:00
parent 205bd3bbbc
commit 81c475464e
2 changed files with 84 additions and 0 deletions
@@ -0,0 +1,69 @@
#!/usr/bin/env python3
"""Run inside a separate LiteLLM container exec: fake OAuth failures, real API backup."""
import asyncio
from copy import deepcopy
from functools import wraps
import json
import os
from pathlib import Path
from unittest.mock import patch
import litellm
import yaml
litellm.suppress_debug_info = True
async def main():
config = yaml.safe_load(Path('/tmp/litellm.yaml').read_text())
primary, backup = 'codex/gpt-luna-latest', 'openai/gpt-luna-latest'
routes = [deepcopy(r) for r in config['model_list'] if r['model_name'] in (primary, backup)]
assert len(routes) == 2
assert {primary: [backup]} in config['router_settings']['fallbacks']
for route in routes:
if route['model_name'] == backup:
route['litellm_params']['api_key'] = os.environ['OPENAI_API_KEY']
actual_chat, actual_responses = litellm.acompletion, litellm.aresponses
for protocol in ('chat', 'responses'):
for error_type, expected in ((litellm.RateLimitError, 429),
(litellm.AuthenticationError, 401),
(litellm.ServiceUnavailableError, 503)):
calls = []
async def invoke(real, *args, **kwargs):
model = kwargs.get('model', '')
if model.startswith('chatgpt/'):
calls.append('subscription-rejected')
raise error_type(message='Synthetic OAuth failure; isolated test only',
llm_provider='chatgpt', model=model)
assert model.startswith('openai/')
calls.append('official-api')
return await real(*args, **kwargs)
@wraps(actual_chat)
async def chat(*args, **kwargs):
return await invoke(actual_chat, *args, **kwargs)
@wraps(actual_responses)
async def responses(*args, **kwargs):
return await invoke(actual_responses, *args, **kwargs)
with patch.object(litellm, 'acompletion', chat), patch.object(litellm, 'aresponses', responses):
router = litellm.Router(model_list=deepcopy(routes), fallbacks=[{primary: [backup]}],
num_retries=0, timeout=60)
if protocol == 'chat':
result = await router.acompletion(model=primary, messages=[
{'role': 'user', 'content': 'Reply only OK. Synthetic test.'}], max_tokens=32)
assert result.choices and result.choices[0].message.content
else:
result = await router.aresponses(model=primary, input=[
{'role': 'user', 'content': 'Reply only OK. Synthetic test.'}],
max_output_tokens=32, store=False)
assert result.status == 'completed'
assert calls[0] == 'subscription-rejected' and calls[-1] == 'official-api', calls
print(json.dumps({'protocol': protocol, 'injected_error': expected,
'calls': calls, 'backup': backup, 'passed': True}), flush=True)
if __name__ == '__main__':
asyncio.run(main())