Files
2026-11-06 19:25:36 +08:00

69 lines
3.1 KiB
C#

using System.ComponentModel.DataAnnotations;
using MAX.Plugins;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Hosting.Server;
using Microsoft.AspNetCore.Hosting.Server.Features;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Store.Modules.CloudProduct;
using Store.Modules.CloudProduct.Services;
// 本地模拟站点验证服务自行创建的 HttpClient,不调用真实扣费接口。
var builder = WebApplication.CreateBuilder();
builder.Logging.ClearProviders();
builder.WebHost.UseUrls("http://127.0.0.1:0");
await using var app = builder.Build();
var calls = 0;
var status = 200;
app.MapPost("/wxxd_user/UseImageAnalysisQuota", async (HttpContext http) =>
{
calls++;
if (http.Request.Query["token"] != "key+&=?" || http.Request.Query["username"] != "用户 +&=?")
throw new Exception("查询参数编码不符合外部协议。");
http.Response.StatusCode = status;
await http.Response.WriteAsync("{\"success\":true}");
});
await app.StartAsync();
var address = app.Services.GetRequiredService<IServer>().Features.Get<IServerAddressesFeature>()!.Addresses.Single();
using var context = new PluginContext("CloudProduct", "Plugins/CloudProduct", builder.Environment);
context.Configuration["ImageAnalysisQuota:APIKey"] = "key+&=?";
var typedContext = new PluginContext<CloudProductPlugin>(context);
// 根地址带或不带末尾斜杠时,都应命中固定接口路径。
foreach (var url in new[] { address, address + "/" })
{
context.Configuration["ImageAnalysisQuota:Url"] = url;
using var service = new ImageAnalysisQuotaService(typedContext);
var body = await service.UseImageAnalysisQuotaAsync(new() { Username = "用户 +&=?" });
if (body != "{\"success\":true}") throw new Exception("应返回原始响应。");
await RejectAsync<ValidationException>(() => service.UseImageAnalysisQuotaAsync(new() { Username = " " }));
context.Configuration["ImageAnalysisQuota:APIKey"] = "";
await RejectAsync<InvalidOperationException>(() => service.UseImageAnalysisQuotaAsync(new() { Username = "test" }));
context.Configuration["ImageAnalysisQuota:APIKey"] = "key+&=?";
}
if (calls != 2) throw new Exception("无效输入或配置不能发送扣减请求。");
context.Configuration["ImageAnalysisQuota:Url"] = "file:///invalid";
await RejectAsync<InvalidOperationException>(() =>
{
using var invalid = new ImageAnalysisQuotaService(typedContext);
return Task.CompletedTask;
});
context.Configuration["ImageAnalysisQuota:Url"] = address;
using (var service = new ImageAnalysisQuotaService(typedContext))
{
status = 500;
await RejectAsync<HttpRequestException>(() => service.UseImageAnalysisQuotaAsync(new() { Username = "用户 +&=?" }));
}
if (calls != 3) throw new Exception("失败请求不能自动重试。");
await app.StopAsync();
Console.WriteLine("Image analysis quota checks passed.");
static async Task RejectAsync<T>(Func<Task> action) where T : Exception
{
try { await action(); }
catch (T) { return; }
throw new Exception($"应抛出 {typeof(T).Name}。");
}