feat(tooling): add standalone rendezvous test client (#25)
quality-gate / quality (push) Failing after 1m3s
quality-gate / quality (push) Failing after 1m3s
This commit is contained in:
@@ -0,0 +1,95 @@
|
||||
namespace FinalFactory.Rendezvous.TestClient;
|
||||
|
||||
internal enum TestClientExitCode
|
||||
{
|
||||
Success = 0,
|
||||
Usage = 2,
|
||||
Configuration = 3,
|
||||
ServiceFailure = 10,
|
||||
NoCompatibleSession = 11,
|
||||
TraversalFailed = 12,
|
||||
DirectTrafficFailed = 13,
|
||||
Cancelled = 130,
|
||||
}
|
||||
|
||||
internal interface ITestClientCommandRunner
|
||||
{
|
||||
Task<TestClientExitCode> RunAsync(
|
||||
TestClientOptions options,
|
||||
TestClientOutput output,
|
||||
TextReader input,
|
||||
CancellationToken cancellationToken);
|
||||
}
|
||||
|
||||
internal sealed class TestClientApplication(ITestClientCommandRunner runner)
|
||||
{
|
||||
private readonly ITestClientCommandRunner _runner = runner ?? throw new ArgumentNullException(nameof(runner));
|
||||
|
||||
internal async Task<int> RunAsync(
|
||||
string[] args,
|
||||
TextReader input,
|
||||
TextWriter standardOutput,
|
||||
TextWriter standardError,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
bool jsonRequested = args.Contains("--json", StringComparer.Ordinal);
|
||||
TestClientParseResult parsed = TestClientOptionParser.Parse(args);
|
||||
TestClientOutput output = new(standardOutput, standardError, jsonRequested);
|
||||
if (parsed.ShowHelp)
|
||||
{
|
||||
if (jsonRequested)
|
||||
{
|
||||
output.Write(
|
||||
"cli.help",
|
||||
"complete",
|
||||
phase: "configuration",
|
||||
message: "Run without --json to read the full command reference.");
|
||||
}
|
||||
else
|
||||
{
|
||||
await standardOutput.WriteLineAsync(TestClientOptionParser.Usage).ConfigureAwait(false);
|
||||
}
|
||||
return (int)TestClientExitCode.Success;
|
||||
}
|
||||
if (!parsed.Succeeded || parsed.Options is null)
|
||||
{
|
||||
if (jsonRequested)
|
||||
{
|
||||
output.WriteError(
|
||||
"cli.usage",
|
||||
"failed",
|
||||
parsed.Error ?? "Invalid command line.",
|
||||
phase: "configuration");
|
||||
}
|
||||
else
|
||||
{
|
||||
await standardError.WriteLineAsync(parsed.Error ?? "Invalid command line.").ConfigureAwait(false);
|
||||
await standardError.WriteLineAsync("Use --help for documented options.").ConfigureAwait(false);
|
||||
}
|
||||
return (int)TestClientExitCode.Usage;
|
||||
}
|
||||
|
||||
output = new TestClientOutput(standardOutput, standardError, parsed.Options.Json);
|
||||
try
|
||||
{
|
||||
return (int)await _runner.RunAsync(
|
||||
parsed.Options,
|
||||
output,
|
||||
input,
|
||||
cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
catch (OperationCanceledException) when (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
output.Write("lifecycle.cancelled", "cancelled", phase: "lifecycle");
|
||||
return (int)TestClientExitCode.Cancelled;
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
output.WriteError(
|
||||
"lifecycle.failed",
|
||||
"failed",
|
||||
$"Unexpected {exception.GetType().Name}; credentials remain redacted.");
|
||||
return (int)TestClientExitCode.ServiceFailure;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user