Merge remote-tracking branch 'origin/main' into agent-3/issue-32-implement-heartbeat-and-watchdog
# Conflicts: # src/MxGateway.Worker/Ipc/WorkerPipeSession.cs # src/MxGateway.Worker/MxAccess/MxAccessStaSession.cs
This commit is contained in:
@@ -0,0 +1,102 @@
|
||||
using System.Text.Json;
|
||||
using Google.Protobuf;
|
||||
using MxGateway.Contracts;
|
||||
using MxGateway.Contracts.Proto;
|
||||
|
||||
namespace MxGateway.Tests.Contracts;
|
||||
|
||||
public sealed class ClientProtoInputTests
|
||||
{
|
||||
[Fact]
|
||||
public void Manifest_DeclaresCurrentProtocolVersionsAndExistingInputs()
|
||||
{
|
||||
DirectoryInfo repositoryRoot = FindRepositoryRoot();
|
||||
string manifestPath = Path.Combine(repositoryRoot.FullName, "clients", "proto", "proto-inputs.json");
|
||||
|
||||
using JsonDocument manifest = JsonDocument.Parse(File.ReadAllText(manifestPath));
|
||||
JsonElement root = manifest.RootElement;
|
||||
|
||||
Assert.Equal(1, root.GetProperty("schemaVersion").GetInt32());
|
||||
Assert.Equal(GatewayContractInfo.GatewayProtocolVersion, root.GetProperty("gatewayProtocolVersion").GetUInt32());
|
||||
Assert.Equal(GatewayContractInfo.WorkerProtocolVersion, root.GetProperty("workerProtocolVersion").GetUInt32());
|
||||
|
||||
string protoRoot = Path.Combine(repositoryRoot.FullName, root.GetProperty("protoRoot").GetString()!);
|
||||
foreach (JsonElement sourceFile in root.GetProperty("sourceFiles").EnumerateArray())
|
||||
{
|
||||
string sourcePath = Path.Combine(protoRoot, sourceFile.GetProperty("path").GetString()!);
|
||||
Assert.True(File.Exists(sourcePath), $"Expected proto source file '{sourcePath}' to exist.");
|
||||
}
|
||||
|
||||
foreach (JsonProperty output in root.GetProperty("generatedOutputs").EnumerateObject())
|
||||
{
|
||||
string outputPath = Path.Combine(repositoryRoot.FullName, output.Value.GetString()!);
|
||||
Assert.True(Directory.Exists(outputPath), $"Expected generated output directory '{outputPath}' to exist.");
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OpenSessionReplyFixture_ParsesWithCurrentContract()
|
||||
{
|
||||
OpenSessionReply reply = ParseFixture(
|
||||
"open-session-reply.ok.json",
|
||||
OpenSessionReply.Parser);
|
||||
|
||||
Assert.Equal(GatewayContractInfo.GatewayProtocolVersion, reply.GatewayProtocolVersion);
|
||||
Assert.Equal(GatewayContractInfo.WorkerProtocolVersion, reply.WorkerProtocolVersion);
|
||||
Assert.Equal(ProtocolStatusCode.Ok, reply.ProtocolStatus.Code);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RegisterCommandRequestFixture_ParsesWithCurrentContract()
|
||||
{
|
||||
MxCommandRequest request = ParseFixture(
|
||||
"register-command-request.json",
|
||||
MxCommandRequest.Parser);
|
||||
|
||||
Assert.Equal(MxCommandKind.Register, request.Command.Kind);
|
||||
Assert.Equal("fixture-client", request.Command.Register.ClientName);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OnDataChangeEventFixture_ParsesWithCurrentContract()
|
||||
{
|
||||
MxEvent gatewayEvent = ParseFixture(
|
||||
"on-data-change-event.json",
|
||||
MxEvent.Parser);
|
||||
|
||||
Assert.Equal(MxEventFamily.OnDataChange, gatewayEvent.Family);
|
||||
Assert.Equal(1ul, gatewayEvent.WorkerSequence);
|
||||
Assert.Equal(MxDataType.Integer, gatewayEvent.Value.DataType);
|
||||
Assert.Equal(MxEvent.BodyOneofCase.OnDataChange, gatewayEvent.BodyCase);
|
||||
}
|
||||
|
||||
private static T ParseFixture<T>(
|
||||
string fixtureName,
|
||||
MessageParser<T> parser)
|
||||
where T : IMessage<T>
|
||||
{
|
||||
DirectoryInfo repositoryRoot = FindRepositoryRoot();
|
||||
string fixturePath = Path.Combine(repositoryRoot.FullName, "clients", "proto", "fixtures", "golden", fixtureName);
|
||||
|
||||
return parser.ParseJson(File.ReadAllText(fixturePath));
|
||||
}
|
||||
|
||||
private static DirectoryInfo FindRepositoryRoot()
|
||||
{
|
||||
DirectoryInfo? current = new(AppContext.BaseDirectory);
|
||||
|
||||
while (current is not null)
|
||||
{
|
||||
if (File.Exists(Path.Combine(current.FullName, "AGENTS.md"))
|
||||
&& Directory.Exists(Path.Combine(current.FullName, "src"))
|
||||
&& Directory.Exists(Path.Combine(current.FullName, "clients")))
|
||||
{
|
||||
return current;
|
||||
}
|
||||
|
||||
current = current.Parent;
|
||||
}
|
||||
|
||||
throw new DirectoryNotFoundException("Could not locate the repository root from the test output directory.");
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,12 @@ public sealed class GatewayContractInfoTests
|
||||
Assert.Equal("mxaccess-worker", GatewayContractInfo.DefaultBackendName);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GatewayProtocolVersion_StartsAtVersionOne()
|
||||
{
|
||||
Assert.Equal(1u, GatewayContractInfo.GatewayProtocolVersion);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WorkerProtocolVersion_StartsAtVersionOne()
|
||||
{
|
||||
|
||||
@@ -33,6 +33,37 @@ public sealed class GatewayApplicationTests
|
||||
Assert.NotNull(metrics);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Build_WhenDashboardEnabled_MapsBlazorDashboardAndAuthEndpoints()
|
||||
{
|
||||
WebApplication app = GatewayApplication.Build([]);
|
||||
IReadOnlyList<RouteEndpoint> endpoints = GetRouteEndpoints(app);
|
||||
|
||||
Assert.Contains(endpoints, endpoint => endpoint.RoutePattern.RawText == "/dashboard/");
|
||||
Assert.Contains(endpoints, endpoint => endpoint.RoutePattern.RawText == "/dashboard/sessions");
|
||||
Assert.Contains(endpoints, endpoint => endpoint.RoutePattern.RawText == "/dashboard/workers");
|
||||
Assert.Contains(endpoints, endpoint => endpoint.RoutePattern.RawText == "/dashboard/events");
|
||||
Assert.Contains(endpoints, endpoint => endpoint.RoutePattern.RawText == "/dashboard/settings");
|
||||
Assert.Contains(endpoints, endpoint =>
|
||||
endpoint.Metadata.GetMetadata<IEndpointNameMetadata>()?.EndpointName == "DashboardLogin");
|
||||
Assert.Contains(endpoints, endpoint =>
|
||||
endpoint.Metadata.GetMetadata<IEndpointNameMetadata>()?.EndpointName == "DashboardLogout");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Build_WhenDashboardDisabled_DoesNotMapDashboardRoutes()
|
||||
{
|
||||
WebApplication app = GatewayApplication.Build(["--MxGateway:Dashboard:Enabled=false"]);
|
||||
IReadOnlyList<RouteEndpoint> endpoints = GetRouteEndpoints(app);
|
||||
|
||||
Assert.DoesNotContain(endpoints, endpoint =>
|
||||
endpoint.RoutePattern.RawText?.StartsWith("/dashboard", StringComparison.Ordinal) == true);
|
||||
Assert.DoesNotContain(endpoints, endpoint =>
|
||||
endpoint.Metadata.GetMetadata<IEndpointNameMetadata>()?.EndpointName?.StartsWith(
|
||||
"Dashboard",
|
||||
StringComparison.Ordinal) == true);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(
|
||||
"MxGateway:Worker:ExecutablePath",
|
||||
@@ -65,4 +96,12 @@ public sealed class GatewayApplicationTests
|
||||
exception.Failures,
|
||||
failure => failure.Contains(expectedFailure, StringComparison.Ordinal));
|
||||
}
|
||||
|
||||
private static IReadOnlyList<RouteEndpoint> GetRouteEndpoints(WebApplication app)
|
||||
{
|
||||
return ((IEndpointRouteBuilder)app).DataSources
|
||||
.SelectMany(dataSource => dataSource.Endpoints)
|
||||
.OfType<RouteEndpoint>()
|
||||
.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,6 +37,7 @@ public sealed class MxAccessGatewayServiceTests
|
||||
Assert.Equal(GatewayContractInfo.DefaultBackendName, reply.BackendName);
|
||||
Assert.Equal(4321, reply.WorkerProcessId);
|
||||
Assert.Equal(GatewayContractInfo.WorkerProtocolVersion, reply.WorkerProtocolVersion);
|
||||
Assert.Equal(GatewayContractInfo.GatewayProtocolVersion, reply.GatewayProtocolVersion);
|
||||
Assert.Equal(ProtocolStatusCode.Ok, reply.ProtocolStatus.Code);
|
||||
Assert.Contains("unary-invoke", reply.Capabilities);
|
||||
Assert.Equal("Operator Key", sessionManager.LastClientIdentity);
|
||||
|
||||
Reference in New Issue
Block a user