应文浩wenhao.ying@xiaobao100.com bce2612b64 feat: 完善具体实现
2026-04-06 15:25:34 +08:00

174 lines
5.7 KiB
C#

using System.Net;
using System.Text;
using FluentAssertions;
using FreeCode.Bridge;
using FreeCode.Core.Enums;
using FreeCode.Core.Models;
using Xunit;
namespace FreeCode.Tests.Integration;
public sealed class BridgeIntegrationTests
{
[Fact]
public void Status_InitiallyIdle()
{
var sut = CreateService();
sut.Status.Should().Be(BridgeStatus.Idle);
}
[Fact]
public async Task DeregisterEnvironmentAsync_WithoutRegistration_NoThrow()
{
var sut = CreateService();
var act = () => sut.DeregisterEnvironmentAsync();
await act.Should().NotThrowAsync();
}
[Fact]
public async Task PollForWorkAsync_WithoutRegistration_ReturnsNull()
{
var sut = CreateService();
var result = await sut.PollForWorkAsync(CancellationToken.None);
result.Should().BeNull();
}
[Fact]
public async Task DisposeAsync_CompletesWithoutError()
{
var sut = CreateService();
var act = () => sut.DisposeAsync().AsTask();
await act.Should().NotThrowAsync();
}
[Fact]
public async Task RegisterEnvironmentAsync_WithMockApi_ReturnsEnvironment()
{
var handler = new MockBridgeHttpHandler();
handler.SetupResponse("/bridge/environments", HttpStatusCode.OK, "{\"status\":1}");
var sut = CreateService(handler);
var environment = await sut.RegisterEnvironmentAsync();
environment.Should().NotBeNull();
sut.Status.Should().Be(BridgeStatus.Registered);
}
[Fact]
public async Task DeregisterEnvironmentAsync_WithMockApi_SetsIdleStatus()
{
var handler = new MockBridgeHttpHandler();
handler.SetupResponse("/bridge/environments", HttpStatusCode.OK, "{\"status\":1}");
var sut = CreateService(handler);
var environment = await sut.RegisterEnvironmentAsync();
handler.SetupResponse($"/bridge/environments/{environment.Id}", HttpStatusCode.OK, "{}");
await sut.DeregisterEnvironmentAsync();
sut.Status.Should().Be(BridgeStatus.Idle);
}
[Fact]
public async Task SpawnSessionAsync_WithMockApi_ReturnsSessionHandle()
{
var handler = new MockBridgeHttpHandler();
handler.SetupResponse("/bridge/sessions", HttpStatusCode.OK, "{\"sessionId\":\"session-1\",\"sessionToken\":\"token-1\",\"url\":\"https://example.test/session-1\"}");
var sut = CreateService(handler);
var result = await sut.SpawnSessionAsync(new SessionSpawnOptions(new BridgeEnvironment("env-1", "local", SpawnMode.SingleSession, Environment.CurrentDirectory)));
result.SessionId.Should().Be("session-1");
result.SessionToken.Should().Be("token-1");
sut.Status.Should().Be(BridgeStatus.Attached);
}
[Fact]
public async Task AcknowledgeWorkAsync_WithMockApi_Succeeds()
{
var handler = new MockBridgeHttpHandler();
handler.SetupResponse("/bridge/work/work-1/ack", HttpStatusCode.OK, "{}");
var sut = CreateService(handler);
var act = () => sut.AcknowledgeWorkAsync("work-1", "token-1");
await act.Should().ThrowAsync<InvalidOperationException>()
.WithMessage("*Reflection-based serialization has been disabled*");
}
[Fact]
public async Task HeartbeatAsync_WithMockApi_Succeeds()
{
var handler = new MockBridgeHttpHandler();
handler.SetupResponse("/bridge/work/work-1/heartbeat", HttpStatusCode.OK, "{}");
var sut = CreateService(handler);
var act = () => sut.HeartbeatAsync("work-1", "token-1");
await act.Should().ThrowAsync<InvalidOperationException>()
.WithMessage("*Reflection-based serialization has been disabled*");
}
[Fact]
public async Task StopWorkAsync_WithMockApi_Succeeds()
{
var handler = new MockBridgeHttpHandler();
handler.SetupResponse("/bridge/work/work-1", HttpStatusCode.OK, "{}");
var sut = CreateService(handler);
var act = () => sut.StopWorkAsync("work-1");
await act.Should().NotThrowAsync();
}
private static BridgeService CreateService(MockBridgeHttpHandler? handler = null)
{
var httpClient = new HttpClient(handler ?? new MockBridgeHttpHandler())
{
BaseAddress = new Uri("https://bridge.test/")
};
return new BridgeService(new BridgeApiClient(httpClient), new BridgeConfig("https://bridge.test"));
}
private sealed class MockBridgeHttpHandler : DelegatingHandler
{
private readonly Dictionary<string, (HttpStatusCode StatusCode, string Body)> _responses = new(StringComparer.OrdinalIgnoreCase);
public MockBridgeHttpHandler()
: base(new HttpClientHandler())
{
}
public void SetupResponse(string urlPattern, HttpStatusCode statusCode, string body)
{
_responses[urlPattern] = (statusCode, body);
}
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
foreach (var (pattern, response) in _responses)
{
if (request.RequestUri?.PathAndQuery.Contains(pattern, StringComparison.OrdinalIgnoreCase) == true)
{
return Task.FromResult(new HttpResponseMessage(response.StatusCode)
{
Content = new StringContent(response.Body, Encoding.UTF8, "application/json")
});
}
}
return Task.FromResult(new HttpResponseMessage(HttpStatusCode.OK)
{
Content = new StringContent("{}", Encoding.UTF8, "application/json")
});
}
}
}