feat(tooling): add standalone rendezvous test client (#25)
quality-gate / quality (push) Failing after 1m3s

This commit is contained in:
KyuubiYoru
2026-07-16 11:05:56 +02:00
parent 94aba8a3bb
commit 7e3be2cad1
16 changed files with 2721 additions and 12 deletions
@@ -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;
}
}
}