test(gateway): fake worker responds to control commands (A6)
Add RespondToControlCommandAsync to FakeWorkerHarness so scripted fake workers can auto-reply to the five control command kinds (Ping, GetSessionState, GetWorkerInfo, DrainEvents, ShutdownWorker) with canned replies whose shapes match the real WorkerPipeSession helpers. Add five unit tests in FakeWorkerHarnessTests covering each control command kind through the WorkerClient→pipe roundtrip, and one gateway E2E test (GatewayService_WithFakeWorker_ControlCommandsRoundtripThroughGateway) that exercises Ping, GetWorkerInfo, and DrainEvents through the full gRPC→SessionManager→WorkerClient→named-pipe path using a scripted ControlCommandFakeWorkerProcessLauncher.
This commit is contained in:
@@ -391,6 +391,87 @@ public sealed class FakeWorkerHarness : IAsyncDisposable
|
||||
cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads one incoming command envelope and, if it is one of the five
|
||||
/// control command kinds (Ping, GetSessionState, GetWorkerInfo, DrainEvents,
|
||||
/// ShutdownWorker), writes a canned reply that mirrors the real worker's
|
||||
/// reply shape. For ShutdownWorker the method additionally sends a
|
||||
/// <see cref="WorkerShutdownAck"/> after the OK reply, matching the real
|
||||
/// worker's shutdown flow.
|
||||
/// </summary>
|
||||
/// <param name="cancellationToken">Token to cancel the asynchronous operation.</param>
|
||||
/// <returns>The command envelope that was handled.</returns>
|
||||
/// <exception cref="InvalidOperationException">
|
||||
/// Thrown when the next envelope is not a <c>WorkerCommand</c> or contains a
|
||||
/// non-control command kind.
|
||||
/// </exception>
|
||||
public async Task<WorkerEnvelope> RespondToControlCommandAsync(
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
WorkerEnvelope commandEnvelope = await ReadCommandAsync(cancellationToken).ConfigureAwait(false);
|
||||
MxCommand command = commandEnvelope.WorkerCommand.Command;
|
||||
|
||||
switch (command.Kind)
|
||||
{
|
||||
case MxCommandKind.Ping:
|
||||
await ReplyToCommandAsync(
|
||||
commandEnvelope,
|
||||
configureReply: reply =>
|
||||
{
|
||||
string? message = command.Ping?.Message;
|
||||
if (!string.IsNullOrEmpty(message))
|
||||
{
|
||||
reply.DiagnosticMessage = message;
|
||||
}
|
||||
},
|
||||
cancellationToken: cancellationToken).ConfigureAwait(false);
|
||||
break;
|
||||
|
||||
case MxCommandKind.GetSessionState:
|
||||
await ReplyToCommandAsync(
|
||||
commandEnvelope,
|
||||
configureReply: reply => reply.SessionState = new SessionStateReply
|
||||
{
|
||||
State = SessionState.Ready,
|
||||
},
|
||||
cancellationToken: cancellationToken).ConfigureAwait(false);
|
||||
break;
|
||||
|
||||
case MxCommandKind.GetWorkerInfo:
|
||||
await ReplyToCommandAsync(
|
||||
commandEnvelope,
|
||||
configureReply: reply => reply.WorkerInfo = new WorkerInfoReply
|
||||
{
|
||||
WorkerProcessId = DefaultWorkerProcessId,
|
||||
WorkerVersion = "fake-worker",
|
||||
MxaccessProgid = "LMXProxy.LMXProxyServer.1",
|
||||
MxaccessClsid = "{C30B52F5-2CB5-4760-AF0A-3A344A7EB5DC}",
|
||||
},
|
||||
cancellationToken: cancellationToken).ConfigureAwait(false);
|
||||
break;
|
||||
|
||||
case MxCommandKind.DrainEvents:
|
||||
await ReplyToCommandAsync(
|
||||
commandEnvelope,
|
||||
configureReply: reply => reply.DrainEvents = new DrainEventsReply(),
|
||||
cancellationToken: cancellationToken).ConfigureAwait(false);
|
||||
break;
|
||||
|
||||
case MxCommandKind.ShutdownWorker:
|
||||
await ReplyToCommandAsync(
|
||||
commandEnvelope,
|
||||
cancellationToken: cancellationToken).ConfigureAwait(false);
|
||||
await SendShutdownAckAsync(cancellationToken: cancellationToken).ConfigureAwait(false);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new InvalidOperationException(
|
||||
$"RespondToControlCommandAsync only handles control command kinds; received {command.Kind}.");
|
||||
}
|
||||
|
||||
return commandEnvelope;
|
||||
}
|
||||
|
||||
/// <summary>Writes a malformed payload directly to the worker stream.</summary>
|
||||
/// <param name="payload">Malformed payload bytes to write.</param>
|
||||
/// <param name="cancellationToken">Token to cancel the asynchronous operation.</param>
|
||||
|
||||
Reference in New Issue
Block a user