fix(transport): carry Transport + OAuth2 authority/scope on SmtpConfigDto (OAuth2 fields were silently dropped)
This commit is contained in:
@@ -938,4 +938,118 @@ public sealed class EntitySerializerTests
|
||||
var rt = new EntitySerializer().FromBundleContent(dto);
|
||||
Assert.Null(Assert.Single(rt.SmsConfigurations).AuthToken);
|
||||
}
|
||||
|
||||
// --- EWS: Transport + the pre-existing OAuth2 authority/scope drop ---------
|
||||
|
||||
[Fact]
|
||||
public void Roundtrip_smtp_config_preserves_transport_and_oauth2_fields()
|
||||
{
|
||||
// Transport is the EWS selector; OAuth2Authority/OAuth2Scope predate it and
|
||||
// were silently dropped by the bundle (they were never on the DTO). All
|
||||
// three are non-sensitive endpoint metadata, so they ride as plain DTO
|
||||
// fields — only Credentials belongs in the SecretsBlock.
|
||||
var smtp = new SmtpConfiguration("https://mail.example.test/EWS/Exchange.asmx", "Basic", "noreply@example.com")
|
||||
{
|
||||
Id = 1,
|
||||
Port = 587,
|
||||
Credentials = "user:p@ssw0rd",
|
||||
TlsMode = "StartTLS",
|
||||
ConnectionTimeoutSeconds = 25,
|
||||
MaxConcurrentConnections = 3,
|
||||
MaxRetries = 4,
|
||||
RetryDelay = TimeSpan.FromSeconds(90),
|
||||
Transport = "Ews",
|
||||
OAuth2Authority = "https://login.example.test/token",
|
||||
OAuth2Scope = "https://mail.example.test/.default",
|
||||
};
|
||||
var aggregate = MakeEmptyAggregate() with { SmtpConfigurations = new[] { smtp } };
|
||||
|
||||
var sut = new EntitySerializer();
|
||||
var dto = sut.ToBundleContent(aggregate);
|
||||
|
||||
var dtoSmtp = Assert.Single(dto.SmtpConfigs);
|
||||
Assert.Equal("Ews", dtoSmtp.Transport);
|
||||
Assert.Equal("https://login.example.test/token", dtoSmtp.OAuth2Authority);
|
||||
Assert.Equal("https://mail.example.test/.default", dtoSmtp.OAuth2Scope);
|
||||
|
||||
var rt = sut.FromBundleContent(dto);
|
||||
|
||||
var rtSmtp = Assert.Single(rt.SmtpConfigurations);
|
||||
Assert.Equal("Ews", rtSmtp.Transport);
|
||||
Assert.Equal("https://login.example.test/token", rtSmtp.OAuth2Authority);
|
||||
Assert.Equal("https://mail.example.test/.default", rtSmtp.OAuth2Scope);
|
||||
// The pre-existing fields still survive alongside the new ones.
|
||||
Assert.Equal("https://mail.example.test/EWS/Exchange.asmx", rtSmtp.Host);
|
||||
Assert.Equal(587, rtSmtp.Port);
|
||||
Assert.Equal("StartTLS", rtSmtp.TlsMode);
|
||||
Assert.Equal("user:p@ssw0rd", rtSmtp.Credentials);
|
||||
Assert.Equal(25, rtSmtp.ConnectionTimeoutSeconds);
|
||||
Assert.Equal(3, rtSmtp.MaxConcurrentConnections);
|
||||
Assert.Equal(4, rtSmtp.MaxRetries);
|
||||
Assert.Equal(TimeSpan.FromSeconds(90), rtSmtp.RetryDelay);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FromDto_smtp_config_without_transport_or_oauth2_fields_yields_nulls()
|
||||
{
|
||||
// Backward-compat at the DTO level (mirrors the PhoneNumber precedent): an
|
||||
// SMTP DTO built without the three trailing params — as an old bundle's JSON
|
||||
// deserializes, since those properties are simply absent — imports with all
|
||||
// three null, i.e. legacy SMTP delivery and provider-default OAuth2 endpoints.
|
||||
var dto = new BundleContentDto(
|
||||
TemplateFolders: Array.Empty<TemplateFolderDto>(),
|
||||
Templates: Array.Empty<TemplateDto>(),
|
||||
SharedScripts: Array.Empty<SharedScriptDto>(),
|
||||
ExternalSystems: Array.Empty<ExternalSystemDto>(),
|
||||
DatabaseConnections: Array.Empty<DatabaseConnectionDto>(),
|
||||
NotificationLists: Array.Empty<NotificationListDto>(),
|
||||
SmtpConfigs: new[]
|
||||
{
|
||||
new SmtpConfigDto(
|
||||
Host: "smtp.example.com",
|
||||
Port: 587,
|
||||
AuthType: "Basic",
|
||||
FromAddress: "noreply@example.com",
|
||||
TlsMode: "StartTLS",
|
||||
ConnectionTimeoutSeconds: 30,
|
||||
MaxConcurrentConnections: 2,
|
||||
MaxRetries: 3,
|
||||
RetryDelay: TimeSpan.FromSeconds(60),
|
||||
Secrets: null),
|
||||
},
|
||||
ApiMethods: Array.Empty<ApiMethodDto>());
|
||||
|
||||
var aggregate = new EntitySerializer().FromBundleContent(dto);
|
||||
|
||||
var smtp = Assert.Single(aggregate.SmtpConfigurations);
|
||||
Assert.Null(smtp.Transport);
|
||||
Assert.Null(smtp.OAuth2Authority);
|
||||
Assert.Null(smtp.OAuth2Scope);
|
||||
Assert.Equal("smtp.example.com", smtp.Host);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SmtpConfigDto_omits_null_transport_and_oauth2_fields_from_json()
|
||||
{
|
||||
// WhenWritingNull keeps the three new properties out of a plain-SMTP
|
||||
// bundle's JSON entirely, so the wire shape is unchanged for existing
|
||||
// exports (additive evolution — no bundleFormatVersion bump).
|
||||
var dto = new SmtpConfigDto(
|
||||
Host: "smtp.example.com",
|
||||
Port: 587,
|
||||
AuthType: "Basic",
|
||||
FromAddress: "noreply@example.com",
|
||||
TlsMode: "StartTLS",
|
||||
ConnectionTimeoutSeconds: 30,
|
||||
MaxConcurrentConnections: 2,
|
||||
MaxRetries: 3,
|
||||
RetryDelay: TimeSpan.FromSeconds(60),
|
||||
Secrets: null);
|
||||
|
||||
var json = JsonSerializer.Serialize(dto, BundleJsonOptions.Default);
|
||||
|
||||
Assert.DoesNotContain("Transport", json, StringComparison.Ordinal);
|
||||
Assert.DoesNotContain("OAuth2Authority", json, StringComparison.Ordinal);
|
||||
Assert.DoesNotContain("OAuth2Scope", json, StringComparison.Ordinal);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user