using System.Reflection; using System.Text.Json; using HrynCo.NotificationService.DAL.Abstract.Providers; using HrynCo.NotificationService.Web.Controllers.Admin; using MediatR; using Microsoft.AspNetCore.Mvc; namespace HrynCo.NotificationService.Web.IntegrationTests; public sealed class AdminSmtpTestControllerTests { private static readonly Guid ChannelId = Guid.NewGuid(); [Fact] public async Task BlankPasswordUsesSavedSecretAndCurrentUnsavedSender() { var (controller, recorder) = CreateController(); var response = await controller.TestSmtp(Request(), CancellationToken.None); Assert.True(Succeeded(response)); Assert.Equal("saved-test-secret", recorder.SentCommand?.Password); Assert.Equal("changed@example.invalid", recorder.SentCommand?.FromEmail); Assert.Equal("Changed sender", recorder.SentCommand?.FromName); Assert.Equal(1, recorder.LookupCount); Assert.DoesNotContain("saved-test-secret", JsonSerializer.Serialize(((OkObjectResult)response).Value)); } [Fact] public async Task ExplicitPasswordOverridesSavedWithoutLookup() { var (controller, recorder) = CreateController(); var response = await controller.TestSmtp(Request() with { Password = "typed-test-secret" }, CancellationToken.None); Assert.True(Succeeded(response)); Assert.Equal("typed-test-secret", recorder.SentCommand?.Password); Assert.Equal(0, recorder.LookupCount); } [Theory] [InlineData("host")] [InlineData("port")] [InlineData("username")] [InlineData("ssl")] public async Task ChangedConnectionRequiresExplicitPassword(string field) { var (controller, recorder) = CreateController(); var request = field switch { "host" => Request() with { Host = "other.example.invalid" }, "port" => Request() with { Port = 2525 }, "username" => Request() with { Username = "other-user" }, _ => Request() with { UseSsl = false } }; var response = await controller.TestSmtp(request, CancellationToken.None); Assert.False(Succeeded(response)); Assert.Null(recorder.SentCommand); } [Fact] public async Task UnknownChannelDoesNotSend() { var (controller, recorder) = CreateController(); recorder.Channel = null; var response = await controller.TestSmtp(Request(), CancellationToken.None); Assert.False(Succeeded(response)); Assert.Null(recorder.SentCommand); } [Fact] public async Task NewChannelKeepsAdHocTestBehavior() { var (controller, recorder) = CreateController(); var response = await controller.TestSmtp(Request() with { ChannelId = null }, CancellationToken.None); Assert.True(Succeeded(response)); Assert.Equal(string.Empty, recorder.SentCommand?.Password); Assert.Equal(0, recorder.LookupCount); } private static (AdminChannelsController Controller, RecordingAdminSmtpMediator Recorder) CreateController() { var mediator = DispatchProxy.Create(); var recorder = (RecordingAdminSmtpMediator)mediator; recorder.Channel = new EmailChannel { Id = ChannelId, ServiceName = "TestService", EmailChannelType = EmailChannelType.Smtp, Settings = new SmtpChannelSettings { Host = "smtp.example.invalid", Port = 587, Username = "test-user", Password = "saved-test-secret", UseSsl = true } }; return (new AdminChannelsController(mediator), recorder); } private static TestSmtpRequest Request() => new( "smtp.example.invalid", 587, "test-user", "", true, "changed@example.invalid", "Changed sender", "recipient@example.invalid", ChannelId); private static bool Succeeded(IActionResult response) { var body = JsonSerializer.Serialize(((OkObjectResult)response).Value); return JsonDocument.Parse(body).RootElement.GetProperty("success").GetBoolean(); } }