Ein blanker Hostname ist eine relative URI; HttpClient lehnt sie mit InvalidOperationException ab. Die lief an dem zu engen catch-Filter vorbei, flog roh aus dem Hub und wurde von TryInvokeAsync zu null verschluckt - die UI meldete "Worker not reachable", obwohl der Worker lief und die Ursache eine Eingabe war. - TicketSystemConfig ergaenzt fehlendes http:// - BandelTicketClient uebersetzt jede Transport-Exception in eine lesbare TicketApiException - TestTicketConnection faengt alles und antwortet mit dem Grund - GetTicketSettings liefert die effektive URL, damit die Ergaenzung sichtbar ist
61 lines
2.3 KiB
C#
61 lines
2.3 KiB
C#
using ClaudeDo.Worker.Config;
|
|
using ClaudeDo.Worker.Tickets;
|
|
|
|
namespace ClaudeDo.Worker.Tests.Tickets;
|
|
|
|
public sealed class TicketSystemConfigTests : IDisposable
|
|
{
|
|
private readonly string _dir = Path.Combine(Path.GetTempPath(), "cdo-tcfg-" + Guid.NewGuid().ToString("N"));
|
|
|
|
private TicketSystemConfig Make(string? baseUrl, string? pat)
|
|
{
|
|
Directory.CreateDirectory(_dir);
|
|
var store = new DpapiTokenStore(Path.Combine(_dir, "ticket.pat"));
|
|
if (pat is not null) store.Save(pat);
|
|
var worker = new WorkerConfig { TicketApiBaseUrl = baseUrl };
|
|
return new TicketSystemConfig(worker, new TicketPatStore(store));
|
|
}
|
|
|
|
[Fact]
|
|
public void Not_configured_without_base_url()
|
|
=> Assert.False(Make(null, "tsp_x").IsConfigured);
|
|
|
|
[Fact]
|
|
public void Not_configured_without_pat()
|
|
=> Assert.False(Make("http://api.local", null).IsConfigured);
|
|
|
|
[Fact]
|
|
public void Configured_with_both()
|
|
=> Assert.True(Make("http://api.local", "tsp_x").IsConfigured);
|
|
|
|
[Fact]
|
|
public void Blank_base_url_counts_as_missing()
|
|
=> Assert.False(Make(" ", "tsp_x").IsConfigured);
|
|
|
|
[Fact]
|
|
public void Base_url_trailing_slash_is_trimmed()
|
|
=> Assert.Equal("http://api.local", Make("http://api.local/", "tsp_x").BaseUrl);
|
|
|
|
// Ein blanker Hostname ist das, was man in ein Feld namens "API base URL" tippt. Ohne Schema
|
|
// ist das eine RELATIVE URI, und HttpClient lehnt sie mit InvalidOperationException ab —
|
|
// genau daran ist die erste Einrichtung gescheitert.
|
|
[Theory]
|
|
[InlineData("bandelapis.fb-tuning.local", "http://bandelapis.fb-tuning.local")]
|
|
[InlineData("bandelapis.fb-tuning.local/", "http://bandelapis.fb-tuning.local")]
|
|
[InlineData(" bandelapis.fb-tuning.local ", "http://bandelapis.fb-tuning.local")]
|
|
[InlineData("api.local:8080", "http://api.local:8080")]
|
|
public void Missing_scheme_defaults_to_http(string entered, string expected)
|
|
=> Assert.Equal(expected, Make(entered, "tsp_x").BaseUrl);
|
|
|
|
[Theory]
|
|
[InlineData("https://api.local")]
|
|
[InlineData("http://api.local")]
|
|
public void Explicit_scheme_is_left_alone(string entered)
|
|
=> Assert.Equal(entered, Make(entered, "tsp_x").BaseUrl);
|
|
|
|
public void Dispose()
|
|
{
|
|
if (Directory.Exists(_dir)) Directory.Delete(_dir, recursive: true);
|
|
}
|
|
}
|