174 lines
5.7 KiB
C#
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")
|
|
});
|
|
}
|
|
}
|
|
}
|