adds ~60 new tests across RuntimeKey parsing, EnvVarKeyDelivery, the legacy and m2pack formats, ReleaseFormatFactory dispatch, manifest loader tolerance of unknown top-level fields, orchestrator wiring and the ClientAppliedReporter (disabled-by-default, success, 5xx, timeout, connection refused). The telemetry tests spin up an in-process HttpListener helper — no new NuGet dependency. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
125 lines
4.0 KiB
C#
125 lines
4.0 KiB
C#
using System.Net;
|
|
using System.Net.Http;
|
|
using Metin2Launcher.Telemetry;
|
|
using Xunit;
|
|
|
|
namespace Metin2Launcher.Tests;
|
|
|
|
public class ClientAppliedReporterTests
|
|
{
|
|
[Fact]
|
|
public void Disabled_when_template_is_empty()
|
|
{
|
|
using var http = new HttpClient();
|
|
var r = new ClientAppliedReporter(http, "");
|
|
Assert.False(r.IsEnabled);
|
|
}
|
|
|
|
[Fact]
|
|
public void Disabled_when_template_is_null()
|
|
{
|
|
using var http = new HttpClient();
|
|
var r = new ClientAppliedReporter(http, null);
|
|
Assert.False(r.IsEnabled);
|
|
}
|
|
|
|
[Fact]
|
|
public void Disabled_when_template_is_whitespace()
|
|
{
|
|
using var http = new HttpClient();
|
|
var r = new ClientAppliedReporter(http, " ");
|
|
Assert.False(r.IsEnabled);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task ReportAsync_noop_when_disabled()
|
|
{
|
|
using var http = new HttpClient();
|
|
var r = new ClientAppliedReporter(http, "");
|
|
var ok = await r.ReportAsync("m2pack", "v1", CancellationToken.None);
|
|
Assert.False(ok);
|
|
}
|
|
|
|
[Fact]
|
|
public void Expand_substitutes_placeholders()
|
|
{
|
|
var s = ClientAppliedReporter.Expand("https://x/{format}/{version}", "m2pack", "2026.04.14-1");
|
|
Assert.Equal("https://x/m2pack/2026.04.14-1", s);
|
|
}
|
|
|
|
[Fact]
|
|
public void Expand_uri_escapes_values()
|
|
{
|
|
var s = ClientAppliedReporter.Expand("https://x/{version}", "m2pack", "v 1+beta");
|
|
Assert.Contains("v%201%2Bbeta", s);
|
|
}
|
|
|
|
[Fact]
|
|
public void Expand_leaves_unknown_placeholders()
|
|
{
|
|
var s = ClientAppliedReporter.Expand("https://x/{other}", "m2pack", "v1");
|
|
Assert.Equal("https://x/{other}", s);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task ReportAsync_posts_json_on_success()
|
|
{
|
|
using var listener = new TestHttpListener();
|
|
var url = listener.Start();
|
|
listener.RespondWith(HttpStatusCode.OK);
|
|
|
|
using var http = new HttpClient { Timeout = TimeSpan.FromSeconds(10) };
|
|
var r = new ClientAppliedReporter(http, url + "?format={format}&version={version}");
|
|
var ok = await r.ReportAsync("m2pack", "2026.04.14-1", CancellationToken.None);
|
|
|
|
Assert.True(ok);
|
|
var req = listener.LastRequest!;
|
|
Assert.Equal("POST", req.Method);
|
|
Assert.Contains("format=m2pack", req.RawUrl);
|
|
Assert.Contains("\"Format\":\"m2pack\"", req.Body);
|
|
Assert.Contains("\"Version\":\"2026.04.14-1\"", req.Body);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task ReportAsync_returns_false_on_500()
|
|
{
|
|
using var listener = new TestHttpListener();
|
|
var url = listener.Start();
|
|
listener.RespondWith(HttpStatusCode.InternalServerError);
|
|
|
|
using var http = new HttpClient { Timeout = TimeSpan.FromSeconds(10) };
|
|
var r = new ClientAppliedReporter(http, url);
|
|
var ok = await r.ReportAsync("m2pack", "v1", CancellationToken.None);
|
|
Assert.False(ok);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task ReportAsync_swallows_connection_refused()
|
|
{
|
|
using var http = new HttpClient { Timeout = TimeSpan.FromSeconds(2) };
|
|
// pick a port unlikely to be listening
|
|
var r = new ClientAppliedReporter(http, "http://127.0.0.1:1/");
|
|
var ok = await r.ReportAsync("m2pack", "v1", CancellationToken.None);
|
|
Assert.False(ok);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task ReportAsync_times_out_after_five_seconds()
|
|
{
|
|
using var listener = new TestHttpListener();
|
|
var url = listener.Start();
|
|
listener.RespondAfter(TimeSpan.FromSeconds(10), HttpStatusCode.OK);
|
|
|
|
using var http = new HttpClient { Timeout = TimeSpan.FromSeconds(30) };
|
|
var r = new ClientAppliedReporter(http, url);
|
|
|
|
var sw = System.Diagnostics.Stopwatch.StartNew();
|
|
var ok = await r.ReportAsync("m2pack", "v1", CancellationToken.None);
|
|
sw.Stop();
|
|
|
|
Assert.False(ok);
|
|
// reporter caps at 5s internally — allow slack for CI schedulers
|
|
Assert.InRange(sw.Elapsed.TotalSeconds, 3.0, 9.0);
|
|
}
|
|
}
|