refactor: 清理 AI 客户端死代码并统一错误处理
- 删除未使用的 OpenAiCompatibleClient,DTO 抽离到 ai_contracts.cs - 新增 AiHttpResponseGuard 统一 LLM/VLM 的 HTTP 错误处理: 错误响应带响应体(截断 2000 字符)、空响应与无效 JSON 显式抛 InvalidDataException - 空 catch 补全精确异常类型(IOException/UnauthorizedAccessException/JsonException) - 修正 Program.cs 数据库初始化注释 - 新增 AI 客户端错误处理单元测试
This commit is contained in:
50
backend/tests/Health.Tests/ai_client_error_tests.cs
Normal file
50
backend/tests/Health.Tests/ai_client_error_tests.cs
Normal file
@@ -0,0 +1,50 @@
|
||||
using System.Net;
|
||||
using Health.Infrastructure.AI;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
|
||||
namespace Health.Tests;
|
||||
|
||||
public sealed class AiClientErrorTests
|
||||
{
|
||||
[Fact]
|
||||
public async Task DeepSeek_ErrorResponse_IncludesStatusAndBody()
|
||||
{
|
||||
var client = CreateClient(HttpStatusCode.TooManyRequests, "{\"error\":\"rate limit\"}");
|
||||
|
||||
var error = await Assert.ThrowsAsync<HttpRequestException>(() => client.ChatAsync([]));
|
||||
|
||||
Assert.Contains("429", error.Message);
|
||||
Assert.Contains("rate limit", error.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task DeepSeek_NullJsonResponse_ThrowsClearDataError()
|
||||
{
|
||||
var client = CreateClient(HttpStatusCode.OK, "null");
|
||||
|
||||
var error = await Assert.ThrowsAsync<InvalidDataException>(() => client.ChatAsync([]));
|
||||
|
||||
Assert.Contains("响应内容为空", error.Message);
|
||||
}
|
||||
|
||||
private static DeepSeekClient CreateClient(HttpStatusCode statusCode, string body)
|
||||
{
|
||||
var http = new HttpClient(new StubHandler(statusCode, body))
|
||||
{
|
||||
BaseAddress = new Uri("https://example.test/"),
|
||||
};
|
||||
var config = new ConfigurationBuilder().AddInMemoryCollection(
|
||||
new Dictionary<string, string?> { ["DEEPSEEK_MODEL"] = "test-model" }).Build();
|
||||
return new DeepSeekClient(http, config);
|
||||
}
|
||||
|
||||
private sealed class StubHandler(HttpStatusCode statusCode, string body) : HttpMessageHandler
|
||||
{
|
||||
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) =>
|
||||
Task.FromResult(new HttpResponseMessage(statusCode)
|
||||
{
|
||||
Content = new StringContent(body),
|
||||
RequestMessage = request,
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user