feat(management): Transport on UpdateSmtpConfigCommand with EWS shape validation
This commit is contained in:
@@ -1667,6 +1667,154 @@ public class ManagementActorTests : TestKit, IDisposable
|
||||
Assert.Equal("old.scope/.default", existing.OAuth2Scope);
|
||||
}
|
||||
|
||||
// ========================================================================
|
||||
// UpdateSmtpConfig — Transport (EWS) write-path gate
|
||||
// ========================================================================
|
||||
|
||||
[Fact]
|
||||
public void UpdateSmtpConfig_WithEwsTransport_PersistsTransportAndSurfacesItInPublicShape()
|
||||
{
|
||||
var notifRepo = Substitute.For<INotificationRepository>();
|
||||
var existing = new Commons.Entities.Notifications.SmtpConfiguration(
|
||||
"old.example.com", "Basic", "old@example.com")
|
||||
{
|
||||
Id = 1,
|
||||
Port = 25,
|
||||
};
|
||||
notifRepo.GetSmtpConfigurationByIdAsync(1, Arg.Any<CancellationToken>()).Returns(existing);
|
||||
_services.AddScoped(_ => notifRepo);
|
||||
|
||||
var actor = CreateActor();
|
||||
var envelope = Envelope(
|
||||
new UpdateSmtpConfigCommand(
|
||||
1, "https://ews.example.test/ews/exchange.asmx", 443, "basic", "new@example.com",
|
||||
Transport: "Ews"),
|
||||
"Administrator");
|
||||
|
||||
actor.Tell(envelope);
|
||||
|
||||
var response = ExpectMsg<ManagementSuccess>(TimeSpan.FromSeconds(5));
|
||||
Assert.Equal(envelope.CorrelationId, response.CorrelationId);
|
||||
Assert.Equal("Ews", existing.Transport);
|
||||
Assert.Equal("https://ews.example.test/ews/exchange.asmx", existing.Host);
|
||||
// The transport is a non-secret field, so it belongs on the public shape
|
||||
// the response and audit afterState carry.
|
||||
Assert.Contains("\"transport\":\"Ews\"", response.JsonData, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void UpdateSmtpConfig_WithUnknownTransport_ReturnsManagementError()
|
||||
{
|
||||
var notifRepo = Substitute.For<INotificationRepository>();
|
||||
var existing = new Commons.Entities.Notifications.SmtpConfiguration(
|
||||
"old.example.com", "Basic", "old@example.com")
|
||||
{
|
||||
Id = 1,
|
||||
Port = 25,
|
||||
};
|
||||
notifRepo.GetSmtpConfigurationByIdAsync(1, Arg.Any<CancellationToken>()).Returns(existing);
|
||||
_services.AddScoped(_ => notifRepo);
|
||||
|
||||
var actor = CreateActor();
|
||||
var envelope = Envelope(
|
||||
new UpdateSmtpConfigCommand(
|
||||
1, "https://graph.example.test/", 443, "basic", "new@example.com",
|
||||
Transport: "Graph"),
|
||||
"Administrator");
|
||||
|
||||
actor.Tell(envelope);
|
||||
|
||||
var response = ExpectMsg<ManagementError>(TimeSpan.FromSeconds(5));
|
||||
Assert.Equal("COMMAND_FAILED", response.ErrorCode);
|
||||
Assert.Contains("Unknown email transport", response.Error);
|
||||
Assert.Contains("Graph", response.Error);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void UpdateSmtpConfig_WithEwsTransportAndNonHttpsHost_ReturnsManagementError()
|
||||
{
|
||||
var notifRepo = Substitute.For<INotificationRepository>();
|
||||
var existing = new Commons.Entities.Notifications.SmtpConfiguration(
|
||||
"old.example.com", "Basic", "old@example.com")
|
||||
{
|
||||
Id = 1,
|
||||
Port = 25,
|
||||
};
|
||||
notifRepo.GetSmtpConfigurationByIdAsync(1, Arg.Any<CancellationToken>()).Returns(existing);
|
||||
_services.AddScoped(_ => notifRepo);
|
||||
|
||||
var actor = CreateActor();
|
||||
var envelope = Envelope(
|
||||
new UpdateSmtpConfigCommand(
|
||||
1, "http://ews.example.test/ews/exchange.asmx", 80, "basic", "new@example.com",
|
||||
Transport: "Ews"),
|
||||
"Administrator");
|
||||
|
||||
actor.Tell(envelope);
|
||||
|
||||
var response = ExpectMsg<ManagementError>(TimeSpan.FromSeconds(5));
|
||||
Assert.Equal("COMMAND_FAILED", response.ErrorCode);
|
||||
Assert.Contains("https://", response.Error);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void UpdateSmtpConfig_WithEwsTransportAndOAuth2Auth_ReturnsManagementError()
|
||||
{
|
||||
var notifRepo = Substitute.For<INotificationRepository>();
|
||||
var existing = new Commons.Entities.Notifications.SmtpConfiguration(
|
||||
"old.example.com", "Basic", "old@example.com")
|
||||
{
|
||||
Id = 1,
|
||||
Port = 25,
|
||||
};
|
||||
notifRepo.GetSmtpConfigurationByIdAsync(1, Arg.Any<CancellationToken>()).Returns(existing);
|
||||
_services.AddScoped(_ => notifRepo);
|
||||
|
||||
var actor = CreateActor();
|
||||
var envelope = Envelope(
|
||||
new UpdateSmtpConfigCommand(
|
||||
1, "https://ews.example.test/ews/exchange.asmx", 443, "oauth2", "new@example.com",
|
||||
Transport: "Ews"),
|
||||
"Administrator");
|
||||
|
||||
actor.Tell(envelope);
|
||||
|
||||
var response = ExpectMsg<ManagementError>(TimeSpan.FromSeconds(5));
|
||||
Assert.Equal("COMMAND_FAILED", response.ErrorCode);
|
||||
Assert.Contains("Basic authentication", response.Error);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void UpdateSmtpConfig_WithNullTransport_PreservesExistingValue()
|
||||
{
|
||||
var notifRepo = Substitute.For<INotificationRepository>();
|
||||
var existing = new Commons.Entities.Notifications.SmtpConfiguration(
|
||||
"https://ews.example.test/ews/exchange.asmx", "basic", "old@example.com")
|
||||
{
|
||||
Id = 1,
|
||||
Port = 443,
|
||||
Transport = "Ews",
|
||||
};
|
||||
notifRepo.GetSmtpConfigurationByIdAsync(1, Arg.Any<CancellationToken>()).Returns(existing);
|
||||
_services.AddScoped(_ => notifRepo);
|
||||
|
||||
var actor = CreateActor();
|
||||
// Transport omitted (a pre-EWS caller, or Newtonsoft deserializing a
|
||||
// payload without the field): the stored transport survives, and the
|
||||
// EWS shape rules are still enforced against that preserved value.
|
||||
var envelope = Envelope(
|
||||
new UpdateSmtpConfigCommand(
|
||||
1, "https://ews2.example.test/ews/exchange.asmx", 443, "basic", "new@example.com"),
|
||||
"Administrator");
|
||||
|
||||
actor.Tell(envelope);
|
||||
|
||||
var response = ExpectMsg<ManagementSuccess>(TimeSpan.FromSeconds(5));
|
||||
Assert.Equal(envelope.CorrelationId, response.CorrelationId);
|
||||
Assert.Equal("Ews", existing.Transport);
|
||||
Assert.Equal("https://ews2.example.test/ews/exchange.asmx", existing.Host);
|
||||
}
|
||||
|
||||
// ========================================================================
|
||||
// SMS Notifications (S5) — list Type discriminator + SMS-config management
|
||||
// ========================================================================
|
||||
|
||||
Reference in New Issue
Block a user