using System.Net;
using System.Text.Json;
using Microsoft.AspNetCore.Mvc.Testing;
using Microsoft.Extensions.Configuration;
namespace Flyshot.Server.IntegrationTests;
///
/// 锁定标准 MVC 宿主需要提供的 Swagger 与 CORS 行为,避免后续回退成只够跑通的最小配置。
///
public sealed class HostMvcConfigurationTests(FlyshotServerFactory factory) : IClassFixture
{
///
/// 验证宿主会公开标准 Swagger JSON,并且文档标题和旧 HTTP 兼容路径都能从配置和控制器路由中导出。
///
[Fact]
public async Task SwaggerDocument_ExposesConfiguredMetadataAndLegacyRoutes()
{
using var configuredFactory = CreateConfiguredFactory(factory);
using var client = configuredFactory.CreateClient();
using var response = await client.GetAsync("/swagger/v1/swagger.json");
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
await using var responseStream = await response.Content.ReadAsStreamAsync();
using var document = await JsonDocument.ParseAsync(responseStream);
var root = document.RootElement;
var paths = root.GetProperty("paths");
Assert.Equal("3.0.1", root.GetProperty("openapi").GetString());
Assert.Equal("Flyshot Replacement HTTP API", root.GetProperty("info").GetProperty("title").GetString());
// OpenAPI 文档会把部分带尾斜杠的路由规范化为无尾斜杠形式,这里同时接受两种键。
Assert.True(paths.TryGetProperty("/robot_info/", out _) || paths.TryGetProperty("/robot_info", out _));
Assert.True(paths.TryGetProperty("/healthz", out _) || paths.TryGetProperty("/healthz/", out _));
}
///
/// 验证宿主会按配置对旧 HTTP API 路由返回标准 CORS 预检响应。
///
[Fact]
public async Task CorsPreflight_ReturnsConfiguredAllowOriginHeaders()
{
using var configuredFactory = CreateConfiguredFactory(factory);
using var client = configuredFactory.CreateClient();
using var request = new HttpRequestMessage(HttpMethod.Options, "/robot_info/");
request.Headers.Add("Origin", "http://localhost:3000");
request.Headers.Add("Access-Control-Request-Method", "GET");
request.Headers.Add("Access-Control-Request-Headers", "content-type");
using var response = await client.SendAsync(request);
Assert.Equal(HttpStatusCode.NoContent, response.StatusCode);
Assert.True(response.Headers.TryGetValues("Access-Control-Allow-Origin", out var allowedOrigins));
Assert.Contains("http://localhost:3000", allowedOrigins);
Assert.True(response.Headers.TryGetValues("Access-Control-Allow-Methods", out var allowedMethods));
Assert.Contains("GET", string.Join(",", allowedMethods));
}
///
/// 为测试宿主注入标准 Swagger 与 CORS 配置,避免依赖开发机本地环境。
///
private static WebApplicationFactory CreateConfiguredFactory(FlyshotServerFactory factory)
{
return factory.WithWebHostBuilder(builder =>
{
builder.ConfigureAppConfiguration((_, configurationBuilder) =>
{
configurationBuilder.AddInMemoryCollection(new Dictionary
{
["Swagger:Enabled"] = "true",
["Swagger:DocumentName"] = "v1",
["Swagger:Title"] = "Flyshot Replacement HTTP API",
["Swagger:Version"] = "v1",
["Cors:PolicyName"] = "LegacyHttpApi",
["Cors:AllowedOrigins:0"] = "http://localhost:3000",
["Cors:AllowedMethods:0"] = "GET",
["Cors:AllowedMethods:1"] = "POST",
["Cors:AllowedMethods:2"] = "OPTIONS",
["Cors:AllowedHeaders:0"] = "content-type"
});
});
});
}
}