import asyncio from contextlib import asynccontextmanager from dataclasses import replace import httpx import pytest from fastapi import FastAPI from src.api.endpoints import router from src.core import fastgpt_client as wiring from src.core.config import Config from src.storage.runtime import open_storage from .test_persistence import RecordingLLM, run, settings def test_http_restart_replay_headers_and_switching(settings, monkeypatch): import src.agent.llm as llm_module monkeypatch.setattr(Config, 'AGENT_BACKEND', 'langgraph') monkeypatch.setattr(Config, 'LLM_PROVIDER', 'fake') monkeypatch.setattr(Config, 'AGENT_STORAGE', settings.kind) monkeypatch.setattr(Config, 'AGENT_SQLITE_PATH', settings.sqlite_path) monkeypatch.setattr(Config, 'AGENT_POSTGRES_DSN', settings.postgres_dsn) monkeypatch.setattr(Config, 'AGENT_DB_POOL_SIZE', settings.pool_size) monkeypatch.setattr(Config, 'AGENT_DB_AUTO_MIGRATE', True) monkeypatch.setattr(llm_module, 'build_llm_service', lambda: RecordingLLM()) app = FastAPI() app.include_router(router) @asynccontextmanager async def client(): async with wiring.lifespan(app): async with httpx.AsyncClient(transport=httpx.ASGITransport(app=app), base_url='http://test') as value: yield value async def scenario(): import uuid payload = {'sessionId': uuid.uuid4().hex, 'timeStamp':'20261022120000'} request = {**payload, 'text':'新对话'} async with client() as http: assert (await http.post('/set_info', json={**payload,'key':'hphm1','value':'http-plate'})).json()['code']=='200' first = (await http.post('/chat', json=request, headers={'Idempotency-Key':'http-key'})).json() assert first['nextStageCode']=='1001' monkeypatch.setattr(Config, 'AGENT_DB_AUTO_MIGRATE', False) async with client() as http: assert (await http.post('/chat', json=request, headers={'Idempotency-Key':'http-key'})).json()==first conflict = await http.post('/chat', json={**request,'text':'different'}, headers={'Idempotency-Key':'http-key'}) assert conflict.json()['code']=='409' stream = await http.post('/chat?stream=true', json={**payload,'text':'继续办理','needFormUpdate':False}) assert 'event: done' in stream.text assert 'event: formUpdate' not in stream.text assert '"0"' == (await http.post('/get_info', json={**payload,'key':'jdcsl'})).json()['value'] assert (await http.request('DELETE','/delete_session',json=payload)).json()['code']=='200' async with client() as http: assert (await http.post('/get_info',json={**payload,'key':'hphm1'})).json()['value']=='""' assert (await http.post('/chat',json=request,headers={'Idempotency-Key':'http-key'})).json()['nextStageCode']=='1001' run(scenario())