using ZB.MOM.WW.ScadaBridge.DelmiaNotifier; namespace ZB.MOM.WW.ScadaBridge.DelmiaNotifier.Tests; public class NotifierTests { private sealed class FakeSender(params AttemptOutcome[] outcomes) : IRecipeSender { private readonly Queue _outcomes = new(outcomes); public int Calls { get; private set; } public Task SendAsync(string baseUrl, RecipeDownload payload, CancellationToken ct) { Calls++; return Task.FromResult(_outcomes.Dequeue()); } } private static readonly string[] TwoUrls = ["http://a", "http://b"]; private static readonly RecipeDownload Payload = new() { MachineCode = "Z", DownloadPath = "x", WorkOrderNumber = "W", PartNumber = "P" }; [Fact] public async Task ConnectFailure_advances_to_next_url() { var sender = new FakeSender( new AttemptOutcome(AttemptKind.ConnectFailed, 0, null, "refused"), new AttemptOutcome(AttemptKind.Connected, 200, new RecipeDownloadResult { Result = true }, null)); var result = await Notifier.RunAsync(TwoUrls, Payload, sender, CancellationToken.None); Assert.True(result.Ok); Assert.Equal(2, sender.Calls); } [Fact] public async Task Connected_result_false_is_final_no_failover() { var sender = new FakeSender( new AttemptOutcome(AttemptKind.Connected, 200, new RecipeDownloadResult { Result = false, ResultText = "bad machine" }, null), new AttemptOutcome(AttemptKind.Connected, 200, new RecipeDownloadResult { Result = true }, null)); var result = await Notifier.RunAsync(TwoUrls, Payload, sender, CancellationToken.None); Assert.False(result.Ok); Assert.Contains("bad machine", result.Reason); Assert.Equal(1, sender.Calls); } [Fact] public async Task Connected_5xx_is_final_no_failover() { var sender = new FakeSender( new AttemptOutcome(AttemptKind.Connected, 500, null, null), new AttemptOutcome(AttemptKind.Connected, 200, new RecipeDownloadResult { Result = true }, null)); var result = await Notifier.RunAsync(TwoUrls, Payload, sender, CancellationToken.None); Assert.False(result.Ok); Assert.Contains("500", result.Reason); Assert.Equal(1, sender.Calls); } [Fact] public async Task All_connect_failures_report_unreachable_with_last_error() { var sender = new FakeSender( new AttemptOutcome(AttemptKind.ConnectFailed, 0, null, "refused-a"), new AttemptOutcome(AttemptKind.ConnectFailed, 0, null, "refused-b")); var result = await Notifier.RunAsync(TwoUrls, Payload, sender, CancellationToken.None); Assert.False(result.Ok); Assert.Contains("unreachable", result.Reason); Assert.Contains("refused-b", result.Reason); Assert.Equal(2, sender.Calls); } }