Merge nucleic/warm-north-vole-pf37 into dev
This commit is contained in:
@@ -0,0 +1,120 @@
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Text.Json;
|
||||
using NucleicApp.Services;
|
||||
using NucleicProtocol.Interop;
|
||||
|
||||
namespace NucleicApp.Tests;
|
||||
|
||||
public sealed class RendererCoreTests
|
||||
{
|
||||
[Fact]
|
||||
public void StoreProjectsSessionsApprovalsAndSettingsFromHostMessagesOnly()
|
||||
{
|
||||
using var store = new RendererStore();
|
||||
store.Apply(TestRepository.Fixture("host", "sessionList"));
|
||||
store.Apply(TestRepository.Fixture("host", "approvalRequested"));
|
||||
store.Apply(TestRepository.Fixture("host", "dashboard"));
|
||||
store.Apply(TestRepository.Fixture("host", "settings"));
|
||||
|
||||
var session = Assert.Single(store.Sessions);
|
||||
Assert.Equal("session-1", session.Id);
|
||||
Assert.Equal("awaitingApproval", session.Status);
|
||||
Assert.Equal(1, session.PendingApprovalCount);
|
||||
Assert.Equal("approval-1", Assert.Single(store.PendingApprovals).Id);
|
||||
Assert.NotNull(store.Dashboard);
|
||||
Assert.True(store.Settings!.Value.GetProperty("resolveApprovalsViaCloud").GetBoolean());
|
||||
|
||||
store.Apply(TestRepository.Fixture("host", "approvalResolved"));
|
||||
Assert.Empty(store.PendingApprovals);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task HostConnectionReadsRendezvousAndRequestsInitialStateOnReady()
|
||||
{
|
||||
var directory = Directory.CreateTempSubdirectory("nucleic-renderer-");
|
||||
try
|
||||
{
|
||||
var rendezvousPath = Path.Combine(directory.FullName, "hostd.json");
|
||||
await File.WriteAllTextAsync(rendezvousPath, JsonSerializer.Serialize(
|
||||
ProtocolInteropTests.ValidRendezvous()));
|
||||
using var store = new RendererStore();
|
||||
var client = new FakeProtocolClient();
|
||||
var factory = new FakeProtocolClientFactory(client);
|
||||
await using var connection = new HostConnection(
|
||||
store, Path.Combine(directory.FullName, "identity"), factory,
|
||||
InlineRendererDispatcher.Instance);
|
||||
|
||||
await connection.StartLocalAsync(rendezvousPath);
|
||||
Assert.Equal("host-1", client.Rendezvous?.HostId);
|
||||
client.EmitState("{\"state\":\"ready\",\"hostID\":\"host-1\",\"welcome\":{}}");
|
||||
Assert.Equal(HostConnectionState.Connected, connection.State);
|
||||
|
||||
var tags = client.Intents.Select(json => ProtocolMessage.Parse(json).Tag).ToArray();
|
||||
Assert.Equal(["listSessions", "listDashboard", "listPeers"], tags);
|
||||
|
||||
client.EmitMessage(TestRepository.Fixture("host", "sessionUpdated"));
|
||||
Assert.Equal("session-1", Assert.Single(store.Sessions).Id);
|
||||
}
|
||||
finally { directory.Delete(recursive: true); }
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task HostConnectionKeepsRetryingAfterSynchronousAdmissionFailures()
|
||||
{
|
||||
var directory = Directory.CreateTempSubdirectory("nucleic-reconnect-");
|
||||
try
|
||||
{
|
||||
var rendezvousPath = Path.Combine(directory.FullName, "hostd.json");
|
||||
await File.WriteAllTextAsync(rendezvousPath, JsonSerializer.Serialize(
|
||||
ProtocolInteropTests.ValidRendezvous()));
|
||||
using var store = new RendererStore();
|
||||
var client = new FakeProtocolClient();
|
||||
client.ConnectLocalResults.Enqueue(ProtocolResult.InvalidState);
|
||||
client.ConnectLocalResults.Enqueue(ProtocolResult.InvalidState);
|
||||
client.ConnectLocalResults.Enqueue(ProtocolResult.Ok);
|
||||
await using var connection = new HostConnection(
|
||||
store, Path.Combine(directory.FullName, "identity"),
|
||||
new FakeProtocolClientFactory(client), InlineRendererDispatcher.Instance);
|
||||
|
||||
await connection.StartLocalAsync(rendezvousPath);
|
||||
await WaitUntilAsync(() => client.ConnectLocalCount == 3, TimeSpan.FromSeconds(3));
|
||||
|
||||
Assert.Equal(3, client.ConnectLocalCount);
|
||||
Assert.Equal(HostConnectionState.Reconnecting, connection.State);
|
||||
}
|
||||
finally { directory.Delete(recursive: true); }
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task LauncherAcceptsOnlyALiveLoopbackRendezvous()
|
||||
{
|
||||
var directory = Directory.CreateTempSubdirectory("nucleic-launcher-");
|
||||
var listener = new TcpListener(IPAddress.Loopback, 0);
|
||||
listener.Start();
|
||||
try
|
||||
{
|
||||
var record = ProtocolInteropTests.ValidRendezvous() with
|
||||
{
|
||||
Port = ((IPEndPoint)listener.LocalEndpoint).Port,
|
||||
};
|
||||
var path = Path.Combine(directory.FullName, "hostd.json");
|
||||
await File.WriteAllTextAsync(path, JsonSerializer.Serialize(record));
|
||||
var launcher = new HostdLauncher(new HostdLaunchOptions(
|
||||
Path.Combine(directory.FullName, "must-not-launch.exe"), path));
|
||||
var result = await launcher.EnsureRunningAsync();
|
||||
Assert.Equal(record.Port, result.Port);
|
||||
}
|
||||
finally
|
||||
{
|
||||
listener.Stop();
|
||||
directory.Delete(recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
private static async Task WaitUntilAsync(Func<bool> condition, TimeSpan timeout)
|
||||
{
|
||||
using var deadline = new CancellationTokenSource(timeout);
|
||||
while (!condition()) await Task.Delay(10, deadline.Token);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user