Files
FlyShotHost/tests/Flyshot.Server.IntegrationTests/HostMvcConfigurationTests.cs
yunxiao.zhu 8a20d9f507 feat: 实现 ControllerClient HTTP 兼容层及 FANUC 运行时
- 新增 Flyshot.ControllerClientCompat 兼容层模块
  - 新增 Flyshot.Runtime.Fanuc 运行时模块
  - 新增 LegacyHttpApiController 暴露 HTTP 兼容 API
  - 补充 RuntimeOrchestrationTests 等测试覆盖
  - 补充 docs/ 兼容性需求与逆向工程文档
  - 更新 Host 注册、配置及解决方案引用

  变更概览:
  - Flyshot.ControllerClientCompat — 旧 ControllerClient 语义的 HTTP 适配
  - Flyshot.Runtime.Fanuc — IControllerRuntime 的 FANUC 真机实现
  - LegacyHttpApiController — HTTP API 兼容旧 SDK
  - docs/ — 兼容性需求与逆向工程分析文档
  - 测试:RuntimeOrchestrationTests、LegacyHttpApiCompatibilityTests
2026-04-24 16:55:25 +08:00

85 lines
4.0 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System.Net;
using System.Text.Json;
using Microsoft.AspNetCore.Mvc.Testing;
using Microsoft.Extensions.Configuration;
namespace Flyshot.Server.IntegrationTests;
/// <summary>
/// 锁定标准 MVC 宿主需要提供的 Swagger 与 CORS 行为,避免后续回退成只够跑通的最小配置。
/// </summary>
public sealed class HostMvcConfigurationTests(FlyshotServerFactory factory) : IClassFixture<FlyshotServerFactory>
{
/// <summary>
/// 验证宿主会公开标准 Swagger JSON并且文档标题和旧 HTTP 兼容路径都能从配置和控制器路由中导出。
/// </summary>
[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 _));
}
/// <summary>
/// 验证宿主会按配置对旧 HTTP API 路由返回标准 CORS 预检响应。
/// </summary>
[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));
}
/// <summary>
/// 为测试宿主注入标准 Swagger 与 CORS 配置,避免依赖开发机本地环境。
/// </summary>
private static WebApplicationFactory<Program> CreateConfiguredFactory(FlyshotServerFactory factory)
{
return factory.WithWebHostBuilder(builder =>
{
builder.ConfigureAppConfiguration((_, configurationBuilder) =>
{
configurationBuilder.AddInMemoryCollection(new Dictionary<string, string?>
{
["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"
});
});
});
}
}