test(sms): regression tests for code-review fixes
Lock the behaviors changed by the review-fix commit + the security invariants: - ManagementActorTests: UpdateSms/SmtpConfig now require Administrator (updated the existing success cases from Designer); + UpdateSmsConfig_WithDesignerRole_Returns Unauthorized and _WithEmptyAuthToken_PreservesExistingToken regression tests. - SecretEncryptionTests: SmsConfiguration.AuthToken stored-encrypted round-trip + null round-trip (AccountSid stays plaintext) — guards ApplySecretColumnEncryption. - ArtifactDiffTests: CompareSmsConfiguration New/Identical/Modified + the secret presence-only invariant (value never echoed, presence-flip shows <present> only). - UpdateCommandContractTests: notification sms update core fields Required, --auth-token optional. - NotificationListsPageTests: SMS recipient badge shows phone, not "Name <>". - NotificationOutboxActorDispatchTests: SMS-typed notification routes to the SMS adapter (StubAdapter.Type made configurable), not the Email adapter. - NotificationRecipientTests (new): ForEmail/ForSms + public-ctor invariants.
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
using System.Text.Json;
|
||||
using ZB.MOM.WW.ScadaBridge.Commons.Entities.Instances;
|
||||
using ZB.MOM.WW.ScadaBridge.Commons.Entities.InboundApi;
|
||||
using ZB.MOM.WW.ScadaBridge.Commons.Entities.Notifications;
|
||||
using ZB.MOM.WW.ScadaBridge.Commons.Entities.Scripts;
|
||||
using ZB.MOM.WW.ScadaBridge.Commons.Entities.Sites;
|
||||
using ZB.MOM.WW.ScadaBridge.Commons.Entities.Templates;
|
||||
@@ -268,6 +269,78 @@ public sealed class ArtifactDiffTests
|
||||
Assert.DoesNotContain("4840", item.FieldDiffJson!);
|
||||
}
|
||||
|
||||
// ============ SMS: CompareSmsConfiguration (S10b) ============
|
||||
|
||||
private static SmsConfiguration ExistingSms() =>
|
||||
new("AC1", "+15550000000") { Id = 1, AuthToken = "stored-token" };
|
||||
|
||||
private static SmsConfigDto SmsDto(
|
||||
string from = "+15550000000",
|
||||
string? msgSid = null,
|
||||
bool withSecret = true) =>
|
||||
new("AC1", from, msgSid, ApiBaseUrl: null, ConnectionTimeoutSeconds: 30,
|
||||
MaxRetries: 10, RetryDelay: TimeSpan.FromMinutes(1),
|
||||
Secrets: withSecret
|
||||
? new SecretsBlock(new Dictionary<string, string> { ["AuthToken"] = "wire-token" })
|
||||
: null);
|
||||
|
||||
[Fact]
|
||||
public void CompareSmsConfiguration_ExistingNull_New()
|
||||
{
|
||||
var item = _diff.CompareSmsConfiguration(SmsDto(), existing: null);
|
||||
|
||||
Assert.Equal(ConflictKind.New, item.Kind);
|
||||
Assert.Equal("SmsConfiguration", item.EntityType);
|
||||
Assert.Equal("AC1", item.Name);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CompareSmsConfiguration_AllFieldsAndPresenceMatch_Identical()
|
||||
{
|
||||
var item = _diff.CompareSmsConfiguration(SmsDto(), ExistingSms());
|
||||
|
||||
Assert.Equal(ConflictKind.Identical, item.Kind);
|
||||
Assert.Null(item.FieldDiffJson);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CompareSmsConfiguration_FromNumberDiffers_Modified()
|
||||
{
|
||||
var item = _diff.CompareSmsConfiguration(SmsDto(from: "+15559999999"), ExistingSms());
|
||||
|
||||
Assert.Equal(ConflictKind.Modified, item.Kind);
|
||||
var change = ChangeFor(item, "FromNumber");
|
||||
Assert.Equal("+15550000000", change.GetProperty("oldValue").GetString());
|
||||
Assert.Equal("+15559999999", change.GetProperty("newValue").GetString());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CompareSmsConfiguration_AuthTokenValueChangesButPresencePreserved_NoSecretEcho()
|
||||
{
|
||||
// Both sides carry a token; only the value differs. Presence-only comparison =>
|
||||
// no Secrets.AuthToken change, and neither token value is ever echoed.
|
||||
var item = _diff.CompareSmsConfiguration(SmsDto(withSecret: true), ExistingSms());
|
||||
|
||||
Assert.Equal(ConflictKind.Identical, item.Kind);
|
||||
var json = item.FieldDiffJson ?? string.Empty;
|
||||
Assert.DoesNotContain("stored-token", json);
|
||||
Assert.DoesNotContain("wire-token", json);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CompareSmsConfiguration_AuthTokenPresenceFlips_ShowsPresentMarkerOnly()
|
||||
{
|
||||
// Existing has a token; incoming carries no secret => a presence change that
|
||||
// surfaces only the "<present>" marker, never the token value.
|
||||
var item = _diff.CompareSmsConfiguration(SmsDto(withSecret: false), ExistingSms());
|
||||
|
||||
Assert.Equal(ConflictKind.Modified, item.Kind);
|
||||
var change = ChangeFor(item, "Secrets.AuthToken");
|
||||
Assert.Equal("<present>", change.GetProperty("oldValue").GetString());
|
||||
Assert.False(change.TryGetProperty("newValue", out _));
|
||||
Assert.DoesNotContain("stored-token", item.FieldDiffJson!);
|
||||
}
|
||||
|
||||
// ============ M8: CompareInstance ============
|
||||
|
||||
[Fact]
|
||||
|
||||
Reference in New Issue
Block a user