883 lines
41 KiB
C#
883 lines
41 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Threading.Tasks;
|
|
using LCU.API.Internal.MemberPreferencesApi.Services;
|
|
using LCU.API.Internal.MemberPreferencesApiLib.Repositories;
|
|
using LCU.API.Internal.MemberPreferencesApi.Models.EmailPolicies;
|
|
using LCU.Library.Internal.MemberPreferencesApiModels.Entities;
|
|
using LCU.Library.Internal.MemberPreferencesApiModels.Enums;
|
|
using Moq;
|
|
using Newtonsoft.Json;
|
|
using NUnit.Framework;
|
|
|
|
namespace LCU.API.Internal.MemberPreferencesApi.UnitTests.Services
|
|
{
|
|
public class MemberEmailServiceTest
|
|
{
|
|
private readonly IMemberEmailService _service;
|
|
|
|
private readonly FakeUnifiedOptInRepository _repository;
|
|
|
|
private readonly Mock<IIntegrationService> _mockIntegrationService;
|
|
|
|
private readonly Mock<IMemberPreferenceService> _mockPreferenceService;
|
|
|
|
private readonly Mock<IEmailFailurePolicy>[] _policies =
|
|
{
|
|
new Mock<IEmailFailurePolicy>(),
|
|
new Mock<IEmailFailurePolicy>()
|
|
};
|
|
|
|
public MemberEmailServiceTest()
|
|
{
|
|
var unitOfWork = new FakeUnitOfWork();
|
|
_repository = new FakeUnifiedOptInRepository(unitOfWork);
|
|
_mockIntegrationService = new Mock<IIntegrationService>();
|
|
_mockPreferenceService = new Mock<IMemberPreferenceService>();
|
|
|
|
_service = new MemberEmailService(_repository, unitOfWork, _policies.Select(p => p.Object), _mockPreferenceService.Object, _mockIntegrationService.Object);
|
|
}
|
|
|
|
private static readonly (DateTime? firstSent, DateTime? lastSent, EmailStatus PriorStatus, int count)[]
|
|
PreUpdateStateScenarios =
|
|
{
|
|
(null, null, EmailStatus.FailingDelivery, 1),
|
|
(DateTime.Now.AddHours(-2), null, EmailStatus.FailingDelivery, 2),
|
|
(null, DateTime.Now.AddHours(-3), EmailStatus.FailingDelivery, 3),
|
|
(DateTime.Now.AddHours(-4), DateTime.Now.AddHours(-4), EmailStatus.FailingDelivery, 4),
|
|
(null, null, EmailStatus.DeliveredSuccessfully, 5),
|
|
(DateTime.Now.AddHours(-6), null, EmailStatus.DeliveredSuccessfully, 6),
|
|
(null, DateTime.Now.AddHours(-7), EmailStatus.DeliveredSuccessfully, 7),
|
|
(DateTime.Now.AddHours(-8), DateTime.Now.AddHours(-8), EmailStatus.DeliveredSuccessfully, 8),
|
|
};
|
|
|
|
private static readonly (bool isUnifiedOptIn, bool matchesUnifiedOptin, bool matchesENotification, bool matchesEstatement)[]
|
|
MatchScenarios =
|
|
{
|
|
(true, true, true, true),
|
|
(true, true, true, false),
|
|
(true, true, false, true),
|
|
(true, true, false, false),
|
|
(false, false, true, true),
|
|
(false, false, true, false),
|
|
(false, false, false, true),
|
|
(false, false, true, true),
|
|
(false, false, true, false),
|
|
(false, false, false, true),
|
|
};
|
|
|
|
private static IEnumerable<object> CombinedScenarios()
|
|
{
|
|
foreach (var match in MatchScenarios)
|
|
{
|
|
foreach (var state in PreUpdateStateScenarios)
|
|
{
|
|
yield return new UpdateScenario(state, match);
|
|
}
|
|
}
|
|
}
|
|
|
|
private static readonly object[] UpdateScenarios = CombinedScenarios().ToArray();
|
|
|
|
private static readonly Random Random = new Random(DateTime.Now.Millisecond);
|
|
private static string EmailAddressFactory()
|
|
{
|
|
static char RandomLetter() => (char)('a' + Random.Next(0, 26));
|
|
|
|
return string.Concat
|
|
(
|
|
Enumerable.Repeat<Func<char>>(RandomLetter, Random.Next(5, 50)).Select(f => f())
|
|
)
|
|
.RandomizeCase();
|
|
}
|
|
|
|
[Test]
|
|
public async Task EmailSucceededToSend_UserOptInSettingsNotFound_ReturnsFalse()
|
|
{
|
|
var userId = Guid.NewGuid().ToString();
|
|
_repository.MemberOptInSettings.Remove(userId);
|
|
|
|
var updated = await _service.EmailSucceededToSend(userId, Guid.NewGuid().ToString());
|
|
|
|
Assert.IsFalse(updated);
|
|
}
|
|
|
|
[Test]
|
|
public async Task EmailSucceededToSend_NoEmailMatches_ReturnsFalse()
|
|
{
|
|
var userId = Guid.NewGuid().ToString();
|
|
var email = EmailAddressFactory();
|
|
_repository.MemberOptInSettings[userId] = new MemberOptInSettings
|
|
{
|
|
UnifiedOptInEmail = EmailAddressFactory(),
|
|
EStatementsEmail = EmailAddressFactory(),
|
|
ENotificationsEmail = EmailAddressFactory()
|
|
};
|
|
|
|
var updated = await _service.EmailSucceededToSend(userId, email);
|
|
|
|
Assert.IsFalse(updated);
|
|
}
|
|
|
|
[Test]
|
|
public async Task EmailSucceededToSend_NullEmailNoMatches_ReturnsFalse()
|
|
{
|
|
var userId = Guid.NewGuid().ToString();
|
|
string email = null;
|
|
_repository.MemberOptInSettings[userId] = new MemberOptInSettings
|
|
{
|
|
UnifiedOptInEmail = EmailAddressFactory(),
|
|
EStatementsEmail = EmailAddressFactory(),
|
|
ENotificationsEmail = EmailAddressFactory()
|
|
};
|
|
|
|
var updated = await _service.EmailSucceededToSend(userId, email);
|
|
|
|
Assert.IsFalse(updated);
|
|
}
|
|
|
|
[TestCaseSource(nameof(UpdateScenarios))]
|
|
public async Task EmailSucceededToSend_EmailMatchesRegardlessOfCase_ReturnsTrue(UpdateScenario scenario)
|
|
{
|
|
var userId = Guid.NewGuid().ToString();
|
|
var email = EmailAddressFactory();
|
|
var unmatchedEmail = EmailAddressFactory();
|
|
_repository.MemberOptInSettings[userId] = new MemberOptInSettings
|
|
{
|
|
UnifiedOptInEmail = scenario.MatchScenario.matchesUnifiedOptin ? email.RandomizeCase() : unmatchedEmail,
|
|
EStatementsEmail = scenario.MatchScenario.matchesEstatement ? email.RandomizeCase() : unmatchedEmail,
|
|
ENotificationsEmail = scenario.MatchScenario.matchesENotification ? email.RandomizeCase() : unmatchedEmail
|
|
};
|
|
|
|
var updated = await _service.EmailSucceededToSend(userId, email);
|
|
|
|
Assert.IsTrue(updated);
|
|
}
|
|
|
|
[TestCaseSource(nameof(UpdateScenarios))]
|
|
public async Task EmailSucceededToSend_NullEmailMatched_ReturnsTrue(UpdateScenario scenario)
|
|
{
|
|
var userId = Guid.NewGuid().ToString();
|
|
string email = null;
|
|
var unmatchedEmail = EmailAddressFactory();
|
|
_repository.MemberOptInSettings[userId] = new MemberOptInSettings
|
|
{
|
|
UnifiedOptInEmail = scenario.MatchScenario.matchesUnifiedOptin ? null : unmatchedEmail,
|
|
EStatementsEmail = scenario.MatchScenario.matchesEstatement ? null : unmatchedEmail,
|
|
ENotificationsEmail = scenario.MatchScenario.matchesENotification ? null : unmatchedEmail
|
|
};
|
|
|
|
var updated = await _service.EmailSucceededToSend(userId, email);
|
|
|
|
Assert.IsTrue(updated);
|
|
}
|
|
|
|
[TestCaseSource(nameof(UpdateScenarios))]
|
|
public async Task EmailSucceededToSend_EmailMatchesRegardlessOfCase_UpdatesTrackingOnMatched(UpdateScenario scenario)
|
|
{
|
|
var userId = Guid.NewGuid().ToString();
|
|
var email = EmailAddressFactory();
|
|
var unmatchedEmail = EmailAddressFactory();
|
|
var (isUniversalOptin, matchesUnifiedOptin, matchesEstatement, matchesENotification) = scenario.MatchScenario;
|
|
var (firstSent, lastSent, status, count) = scenario.PriorState;
|
|
_repository.MemberOptInSettings[userId] = new MemberOptInSettings
|
|
{
|
|
UnifiedOptInEmail = matchesUnifiedOptin ? email.RandomizeCase() : unmatchedEmail,
|
|
UnifiedOptInEmailFirstSent = firstSent,
|
|
UnifiedOptInEmailLastSent = lastSent,
|
|
UnifiedOptInEmailStatus = status,
|
|
UnifiedOptInEmailStatusCount = count,
|
|
EStatementsEmail = matchesEstatement ? email.RandomizeCase() : unmatchedEmail,
|
|
EStatementsEmailFirstSent = firstSent,
|
|
EStatementsEmailLastSent = lastSent,
|
|
EStatementsEmailStatus = status,
|
|
EStatementsEmailStatusCount = count,
|
|
ENotificationsEmail = matchesENotification ? email.RandomizeCase() : unmatchedEmail,
|
|
ENotificationsEmailFirstSent = firstSent,
|
|
ENotificationsEmailLastSent = lastSent,
|
|
ENotificationsEmailStatus = status,
|
|
ENotificationsEmailStatusCount = count
|
|
};
|
|
var actionStart = DateTime.Now;
|
|
|
|
await _service.EmailSucceededToSend(userId, email);
|
|
|
|
var elapsedActionTime = DateTime.Now - actionStart;
|
|
var updatedSettings = _repository.MemberOptInSettings[userId];
|
|
if (matchesUnifiedOptin)
|
|
{
|
|
Assert.IsNull(updatedSettings.UnifiedOptInEmailFirstSent);
|
|
Assert.That(updatedSettings.UnifiedOptInEmailLastSent,
|
|
Is.EqualTo(actionStart).Within(elapsedActionTime));
|
|
Assert.AreEqual(EmailStatus.DeliveredSuccessfully, updatedSettings.UnifiedOptInEmailStatus);
|
|
Assert.AreEqual(0, updatedSettings.UnifiedOptInEmailStatusCount);
|
|
}
|
|
|
|
if (matchesEstatement)
|
|
{
|
|
Assert.IsNull(updatedSettings.EStatementsEmailFirstSent);
|
|
Assert.That(updatedSettings.EStatementsEmailLastSent,
|
|
Is.EqualTo(actionStart).Within(elapsedActionTime));
|
|
Assert.AreEqual(EmailStatus.DeliveredSuccessfully, updatedSettings.EStatementsEmailStatus);
|
|
Assert.AreEqual(0, updatedSettings.EStatementsEmailStatusCount);
|
|
}
|
|
|
|
if (matchesENotification)
|
|
{
|
|
Assert.IsNull(updatedSettings.ENotificationsEmailFirstSent);
|
|
Assert.That(updatedSettings.ENotificationsEmailLastSent,
|
|
Is.EqualTo(actionStart).Within(elapsedActionTime));
|
|
Assert.AreEqual(EmailStatus.DeliveredSuccessfully, updatedSettings.ENotificationsEmailStatus);
|
|
Assert.AreEqual(0, updatedSettings.ENotificationsEmailStatusCount);
|
|
}
|
|
}
|
|
|
|
[TestCaseSource(nameof(UpdateScenarios))]
|
|
public async Task EmailSucceededToSend_NullEmailMatched_UpdatesTrackingOnMatched(UpdateScenario scenario)
|
|
{
|
|
var userId = Guid.NewGuid().ToString();
|
|
string email = null;
|
|
var unmatchedEmail = EmailAddressFactory();
|
|
var (isUniversalOptin, matchesUnifiedOptin, matchesEstatement, matchesENotification) = scenario.MatchScenario;
|
|
var (firstSent, lastSent, status, count) = scenario.PriorState;
|
|
_repository.MemberOptInSettings[userId] = new MemberOptInSettings
|
|
{
|
|
UnifiedOptInEmail = matchesUnifiedOptin ? null : unmatchedEmail,
|
|
UnifiedOptInEmailFirstSent = firstSent,
|
|
UnifiedOptInEmailLastSent = lastSent,
|
|
UnifiedOptInEmailStatus = status,
|
|
UnifiedOptInEmailStatusCount = count,
|
|
EStatementsEmail = matchesEstatement ? null : unmatchedEmail,
|
|
EStatementsEmailFirstSent = firstSent,
|
|
EStatementsEmailLastSent = lastSent,
|
|
EStatementsEmailStatus = status,
|
|
EStatementsEmailStatusCount = count,
|
|
ENotificationsEmail = matchesENotification ? null : unmatchedEmail,
|
|
ENotificationsEmailFirstSent = firstSent,
|
|
ENotificationsEmailLastSent = lastSent,
|
|
ENotificationsEmailStatus = status,
|
|
ENotificationsEmailStatusCount = count
|
|
};
|
|
var actionStart = DateTime.Now;
|
|
|
|
await _service.EmailSucceededToSend(userId, email);
|
|
|
|
var elapsedActionTime = DateTime.Now - actionStart;
|
|
var updatedSettings = _repository.MemberOptInSettings[userId];
|
|
if (matchesUnifiedOptin)
|
|
{
|
|
Assert.IsNull(updatedSettings.UnifiedOptInEmailFirstSent);
|
|
Assert.That(updatedSettings.UnifiedOptInEmailLastSent,
|
|
Is.EqualTo(actionStart).Within(elapsedActionTime));
|
|
Assert.AreEqual(EmailStatus.DeliveredSuccessfully, updatedSettings.UnifiedOptInEmailStatus);
|
|
Assert.AreEqual(0, updatedSettings.UnifiedOptInEmailStatusCount);
|
|
}
|
|
|
|
if (matchesEstatement)
|
|
{
|
|
Assert.IsNull(updatedSettings.EStatementsEmailFirstSent);
|
|
Assert.That(updatedSettings.EStatementsEmailLastSent,
|
|
Is.EqualTo(actionStart).Within(elapsedActionTime));
|
|
Assert.AreEqual(EmailStatus.DeliveredSuccessfully, updatedSettings.EStatementsEmailStatus);
|
|
Assert.AreEqual(0, updatedSettings.EStatementsEmailStatusCount);
|
|
}
|
|
|
|
if (matchesENotification)
|
|
{
|
|
Assert.IsNull(updatedSettings.ENotificationsEmailFirstSent);
|
|
Assert.That(updatedSettings.ENotificationsEmailLastSent,
|
|
Is.EqualTo(actionStart).Within(elapsedActionTime));
|
|
Assert.AreEqual(EmailStatus.DeliveredSuccessfully, updatedSettings.ENotificationsEmailStatus);
|
|
Assert.AreEqual(0, updatedSettings.ENotificationsEmailStatusCount);
|
|
}
|
|
}
|
|
|
|
[TestCaseSource(nameof(UpdateScenarios))]
|
|
public async Task EmailSucceededToSend_EmailMatchesRegardlessOfCase_DoesNotUpdateTrackingOnUnmatched(
|
|
UpdateScenario scenario)
|
|
{
|
|
var userId = Guid.NewGuid().ToString();
|
|
var email = EmailAddressFactory();
|
|
var unmatchedEmail = EmailAddressFactory();
|
|
var (isUniversalOptin, matchesUnifiedOptin, matchesEstatement, matchesENotification) = scenario.MatchScenario;
|
|
var (firstSent, lastSent, status, count) = scenario.PriorState;
|
|
_repository.MemberOptInSettings[userId] = new MemberOptInSettings
|
|
{
|
|
UnifiedOptInEmail = matchesUnifiedOptin ? email.RandomizeCase() : unmatchedEmail,
|
|
UnifiedOptInEmailFirstSent = firstSent,
|
|
UnifiedOptInEmailLastSent = lastSent,
|
|
UnifiedOptInEmailStatus = status,
|
|
UnifiedOptInEmailStatusCount = count,
|
|
EStatementsEmail = matchesEstatement ? email.RandomizeCase() : unmatchedEmail,
|
|
EStatementsEmailFirstSent = firstSent,
|
|
EStatementsEmailLastSent = lastSent,
|
|
EStatementsEmailStatus = status,
|
|
EStatementsEmailStatusCount = count,
|
|
ENotificationsEmail = matchesENotification ? email.RandomizeCase() : unmatchedEmail,
|
|
ENotificationsEmailFirstSent = firstSent,
|
|
ENotificationsEmailLastSent = lastSent,
|
|
ENotificationsEmailStatus = status,
|
|
ENotificationsEmailStatusCount = count
|
|
};
|
|
|
|
await _service.EmailSucceededToSend(userId, email);
|
|
|
|
var updatedSettings = _repository.MemberOptInSettings[userId];
|
|
if (!matchesUnifiedOptin)
|
|
{
|
|
Assert.AreEqual(firstSent, updatedSettings.UnifiedOptInEmailFirstSent);
|
|
Assert.AreEqual(lastSent, updatedSettings.UnifiedOptInEmailLastSent);
|
|
Assert.AreEqual(status, updatedSettings.UnifiedOptInEmailStatus);
|
|
Assert.AreEqual(count, updatedSettings.UnifiedOptInEmailStatusCount);
|
|
}
|
|
|
|
if (!matchesEstatement)
|
|
{
|
|
Assert.AreEqual(firstSent, updatedSettings.EStatementsEmailFirstSent);
|
|
Assert.AreEqual(lastSent, updatedSettings.EStatementsEmailLastSent);
|
|
Assert.AreEqual(status, updatedSettings.EStatementsEmailStatus);
|
|
Assert.AreEqual(count, updatedSettings.EStatementsEmailStatusCount);
|
|
}
|
|
|
|
if (!matchesENotification)
|
|
{
|
|
Assert.AreEqual(firstSent, updatedSettings.ENotificationsEmailFirstSent);
|
|
Assert.AreEqual(lastSent, updatedSettings.ENotificationsEmailLastSent);
|
|
Assert.AreEqual(status, updatedSettings.ENotificationsEmailStatus);
|
|
Assert.AreEqual(count, updatedSettings.ENotificationsEmailStatusCount);
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public async Task EmailFailedToSend_UserOptInSettingsNotFound_ReturnsFalse()
|
|
{
|
|
var userId = Guid.NewGuid().ToString();
|
|
_repository.MemberOptInSettings.Remove(userId);
|
|
|
|
var updated = await _service.EmailFailedToSend(userId, EmailAddressFactory(), true);
|
|
|
|
Assert.IsFalse(updated);
|
|
}
|
|
|
|
[Test]
|
|
public async Task EmailFailedToSend_EmailMatchesNoOptinEmailPreference_ReturnsFalse()
|
|
{
|
|
var userId = Guid.NewGuid().ToString();
|
|
var email = EmailAddressFactory();
|
|
_repository.MemberOptInSettings[userId] = new MemberOptInSettings
|
|
{
|
|
UnifiedOptInEmail = EmailAddressFactory(),
|
|
EStatementsEmail = EmailAddressFactory(),
|
|
ENotificationsEmail = EmailAddressFactory()
|
|
};
|
|
|
|
var updated = await _service.EmailFailedToSend(userId, email, true);
|
|
|
|
Assert.IsFalse(updated);
|
|
}
|
|
|
|
[Test]
|
|
public async Task EmailFailedToSend_NullEmailMatchesNoOptinEmailPreference_ReturnsFalse()
|
|
{
|
|
var userId = Guid.NewGuid().ToString();
|
|
string email = null;
|
|
_repository.MemberOptInSettings[userId] = new MemberOptInSettings
|
|
{
|
|
UnifiedOptInEmail = EmailAddressFactory(),
|
|
EStatementsEmail = EmailAddressFactory(),
|
|
ENotificationsEmail = EmailAddressFactory()
|
|
};
|
|
|
|
var updated = await _service.EmailFailedToSend(userId, email, true);
|
|
|
|
Assert.IsFalse(updated);
|
|
}
|
|
|
|
[TestCaseSource(nameof(UpdateScenarios))]
|
|
public async Task EmailFailedToSend_EmailMatchesRegardlessOfCase_ReturnsTrue(UpdateScenario scenario)
|
|
{
|
|
var userId = Guid.NewGuid().ToString();
|
|
var email = EmailAddressFactory();
|
|
var unmatchedEmail = EmailAddressFactory();
|
|
var (isUniversalOptin, matchesUnifiedOptin, matchesEstatement, matchesENotification) = scenario.MatchScenario;
|
|
var (firstSent, lastSent, status, count) = scenario.PriorState;
|
|
_repository.MemberOptInSettings[userId] = new MemberOptInSettings
|
|
{
|
|
UniversalOptIn = isUniversalOptin ? "Electronic" : null,
|
|
UnifiedOptInEmail = matchesUnifiedOptin && isUniversalOptin ? email.RandomizeCase() : unmatchedEmail,
|
|
UnifiedOptInEmailFirstSent = isUniversalOptin ? DateTime.Now : firstSent,
|
|
UnifiedOptInEmailLastSent = isUniversalOptin ? DateTime.Now : lastSent,
|
|
UnifiedOptInEmailStatus = status,
|
|
UnifiedOptInEmailStatusCount = count,
|
|
EStatementsEmail = matchesEstatement && !isUniversalOptin ? email.RandomizeCase() : unmatchedEmail,
|
|
EStatementsEmailFirstSent = firstSent,
|
|
EStatementsEmailLastSent = lastSent,
|
|
EStatementsEmailStatus = status,
|
|
EStatementsEmailStatusCount = count,
|
|
ENotificationsEmail = matchesENotification && !isUniversalOptin ? email.RandomizeCase() : unmatchedEmail,
|
|
ENotificationsEmailFirstSent = firstSent,
|
|
ENotificationsEmailLastSent = lastSent,
|
|
ENotificationsEmailStatus = status,
|
|
ENotificationsEmailStatusCount = count
|
|
};
|
|
|
|
var updated = await _service.EmailFailedToSend(userId, email, true);
|
|
|
|
Assert.IsTrue(updated);
|
|
}
|
|
|
|
[TestCaseSource(nameof(UpdateScenarios))]
|
|
public async Task EmailFailedToSend_NullEmailMatched_ReturnsTrue(UpdateScenario scenario)
|
|
{
|
|
var userId = Guid.NewGuid().ToString();
|
|
string email = null;
|
|
var unmatchedEmail = EmailAddressFactory();
|
|
var (isUniversalOptin, matchesUnifiedOptin, matchesEstatement, matchesENotification) = scenario.MatchScenario;
|
|
var (firstSent, lastSent, status, count) = scenario.PriorState;
|
|
_repository.MemberOptInSettings[userId] = new MemberOptInSettings
|
|
{
|
|
UniversalOptIn = isUniversalOptin ? "Electronic" : null,
|
|
UnifiedOptInEmail = matchesUnifiedOptin && isUniversalOptin ? null : unmatchedEmail,
|
|
UnifiedOptInEmailFirstSent = firstSent,
|
|
UnifiedOptInEmailLastSent = lastSent,
|
|
UnifiedOptInEmailStatus = status,
|
|
UnifiedOptInEmailStatusCount = count,
|
|
EStatementsEmail = matchesEstatement && !isUniversalOptin ? null : unmatchedEmail,
|
|
EStatementsEmailFirstSent = firstSent,
|
|
EStatementsEmailLastSent = lastSent,
|
|
EStatementsEmailStatus = status,
|
|
EStatementsEmailStatusCount = count,
|
|
ENotificationsEmail = matchesENotification && !isUniversalOptin ? null : unmatchedEmail,
|
|
ENotificationsEmailFirstSent = firstSent,
|
|
ENotificationsEmailLastSent = lastSent,
|
|
ENotificationsEmailStatus = status,
|
|
ENotificationsEmailStatusCount = count
|
|
};
|
|
|
|
var updated = await _service.EmailFailedToSend(userId, email, true);
|
|
|
|
var updatedSettings = _repository.MemberOptInSettings[userId];
|
|
Assert.IsTrue(updated);
|
|
}
|
|
|
|
[TestCaseSource(nameof(UpdateScenarios))]
|
|
public async Task EmailFailedToSend_EmailMatchesRegardlessOfCase_UpdatesTrackingOnMatched(UpdateScenario scenario)
|
|
{
|
|
var userId = Guid.NewGuid().ToString();
|
|
var email = EmailAddressFactory();
|
|
var unmatchedEmail = EmailAddressFactory();
|
|
var (isUniversalOptin, matchesUnifiedOptin, matchesEstatement, matchesENotification) = scenario.MatchScenario;
|
|
var (firstSent, lastSent, status, count) = scenario.PriorState;
|
|
_repository.MemberOptInSettings[userId] = new MemberOptInSettings
|
|
{
|
|
UniversalOptIn = isUniversalOptin ? "Electronic" : null,
|
|
UnifiedOptInEmail = matchesUnifiedOptin && isUniversalOptin ? email.RandomizeCase() : unmatchedEmail,
|
|
UnifiedOptInEmailFirstSent = firstSent,
|
|
UnifiedOptInEmailLastSent = lastSent,
|
|
UnifiedOptInEmailStatus = status,
|
|
UnifiedOptInEmailStatusCount = count,
|
|
EStatementsEmail = matchesEstatement && !isUniversalOptin ? email.RandomizeCase() : unmatchedEmail,
|
|
EStatementsEmailFirstSent = firstSent,
|
|
EStatementsEmailLastSent = lastSent,
|
|
EStatementsEmailStatus = status,
|
|
EStatementsEmailStatusCount = count,
|
|
ENotificationsEmail = matchesENotification && !isUniversalOptin ? email.RandomizeCase() : unmatchedEmail,
|
|
ENotificationsEmailFirstSent = firstSent,
|
|
ENotificationsEmailLastSent = lastSent,
|
|
ENotificationsEmailStatus = status,
|
|
ENotificationsEmailStatusCount = count
|
|
};
|
|
var actionStart = DateTime.Now;
|
|
|
|
await _service.EmailFailedToSend(userId, email, true);
|
|
|
|
var elapsedActionTime = DateTime.Now - actionStart;
|
|
var updatedSettings = _repository.MemberOptInSettings[userId];
|
|
var updatedFirstSent = firstSent is null
|
|
? Is.EqualTo(actionStart).Within(elapsedActionTime)
|
|
: Is.EqualTo(firstSent);
|
|
if (matchesUnifiedOptin && isUniversalOptin)
|
|
{
|
|
Assert.That(updatedSettings.UnifiedOptInEmailFirstSent, updatedFirstSent);
|
|
Assert.That(updatedSettings.UnifiedOptInEmailLastSent,
|
|
Is.EqualTo(actionStart).Within(elapsedActionTime));
|
|
Assert.AreEqual(EmailStatus.FailingDelivery, updatedSettings.UnifiedOptInEmailStatus);
|
|
Assert.AreEqual(count + 1, updatedSettings.UnifiedOptInEmailStatusCount);
|
|
}
|
|
|
|
if (matchesEstatement && !isUniversalOptin)
|
|
{
|
|
Assert.That(updatedSettings.EStatementsEmailFirstSent, updatedFirstSent);
|
|
Assert.That(updatedSettings.EStatementsEmailLastSent,
|
|
Is.EqualTo(actionStart).Within(elapsedActionTime));
|
|
Assert.AreEqual(EmailStatus.FailingDelivery, updatedSettings.EStatementsEmailStatus);
|
|
Assert.AreEqual(count + 1, updatedSettings.EStatementsEmailStatusCount);
|
|
}
|
|
|
|
if (matchesENotification && !isUniversalOptin)
|
|
{
|
|
Assert.That(updatedSettings.ENotificationsEmailFirstSent, updatedFirstSent);
|
|
Assert.That(updatedSettings.ENotificationsEmailLastSent,
|
|
Is.EqualTo(actionStart).Within(elapsedActionTime));
|
|
Assert.AreEqual(EmailStatus.FailingDelivery, updatedSettings.ENotificationsEmailStatus);
|
|
Assert.AreEqual(count + 1, updatedSettings.ENotificationsEmailStatusCount);
|
|
}
|
|
}
|
|
|
|
[TestCaseSource(nameof(UpdateScenarios))]
|
|
public async Task EmailFailedToSend_NullEmailMatched_UpdatesTrackingOnMatched(UpdateScenario scenario)
|
|
{
|
|
var userId = Guid.NewGuid().ToString();
|
|
string email = null;
|
|
var unmatchedEmail = EmailAddressFactory();
|
|
var (isUniversalOptin, matchesUnifiedOptin, matchesEstatement, matchesENotification) = scenario.MatchScenario;
|
|
var (firstSent, lastSent, status, count) = scenario.PriorState;
|
|
_repository.MemberOptInSettings[userId] = new MemberOptInSettings
|
|
{
|
|
UniversalOptIn = isUniversalOptin ? "Electronic" : null,
|
|
UnifiedOptInEmail = matchesUnifiedOptin && isUniversalOptin ? null : unmatchedEmail,
|
|
UnifiedOptInEmailFirstSent = firstSent,
|
|
UnifiedOptInEmailLastSent = lastSent,
|
|
UnifiedOptInEmailStatus = status,
|
|
UnifiedOptInEmailStatusCount = count,
|
|
EStatementsEmail = matchesEstatement && !isUniversalOptin ? null : unmatchedEmail,
|
|
EStatementsEmailFirstSent = firstSent,
|
|
EStatementsEmailLastSent = lastSent,
|
|
EStatementsEmailStatus = status,
|
|
EStatementsEmailStatusCount = count,
|
|
ENotificationsEmail = matchesENotification && !isUniversalOptin ? null : unmatchedEmail,
|
|
ENotificationsEmailFirstSent = firstSent,
|
|
ENotificationsEmailLastSent = lastSent,
|
|
ENotificationsEmailStatus = status,
|
|
ENotificationsEmailStatusCount = count
|
|
};
|
|
var actionStart = DateTime.Now;
|
|
|
|
await _service.EmailFailedToSend(userId, email, true);
|
|
|
|
var elapsedActionTime = DateTime.Now - actionStart;
|
|
var updatedSettings = _repository.MemberOptInSettings[userId];
|
|
var updatedFirstSent = firstSent is null
|
|
? Is.EqualTo(actionStart).Within(elapsedActionTime)
|
|
: Is.EqualTo(firstSent);
|
|
if (matchesUnifiedOptin && isUniversalOptin)
|
|
{
|
|
Assert.That(updatedSettings.UnifiedOptInEmailFirstSent, updatedFirstSent);
|
|
Assert.That(updatedSettings.UnifiedOptInEmailLastSent,
|
|
Is.EqualTo(actionStart).Within(elapsedActionTime));
|
|
Assert.AreEqual(EmailStatus.FailingDelivery, updatedSettings.UnifiedOptInEmailStatus);
|
|
Assert.AreEqual(count + 1, updatedSettings.UnifiedOptInEmailStatusCount);
|
|
}
|
|
|
|
if (matchesEstatement && !isUniversalOptin)
|
|
{
|
|
Assert.That(updatedSettings.EStatementsEmailFirstSent, updatedFirstSent);
|
|
Assert.That(updatedSettings.EStatementsEmailLastSent,
|
|
Is.EqualTo(actionStart).Within(elapsedActionTime));
|
|
Assert.AreEqual(EmailStatus.FailingDelivery, updatedSettings.EStatementsEmailStatus);
|
|
Assert.AreEqual(count + 1, updatedSettings.EStatementsEmailStatusCount);
|
|
}
|
|
|
|
if (matchesENotification && !isUniversalOptin)
|
|
{
|
|
Assert.That(updatedSettings.ENotificationsEmailFirstSent, updatedFirstSent);
|
|
Assert.That(updatedSettings.ENotificationsEmailLastSent,
|
|
Is.EqualTo(actionStart).Within(elapsedActionTime));
|
|
Assert.AreEqual(EmailStatus.FailingDelivery, updatedSettings.ENotificationsEmailStatus);
|
|
Assert.AreEqual(count + 1, updatedSettings.ENotificationsEmailStatusCount);
|
|
}
|
|
}
|
|
|
|
[TestCaseSource(nameof(UpdateScenarios))]
|
|
public async Task EmailFailedToSend_EmailMatchesRegardlessOfCase_DoesNotUpdateTrackingOnUnmatched(UpdateScenario scenario)
|
|
{
|
|
var userId = Guid.NewGuid().ToString();
|
|
var email = EmailAddressFactory();
|
|
var unmatchedEmail = EmailAddressFactory();
|
|
var (isUniversalOptin, matchesUnifiedOptin, matchesEstatement, matchesENotification) = scenario.MatchScenario;
|
|
var (firstSent, lastSent, status, count) = scenario.PriorState;
|
|
_repository.MemberOptInSettings[userId] = new MemberOptInSettings
|
|
{
|
|
UnifiedOptInEmail = matchesUnifiedOptin && isUniversalOptin ? email.RandomizeCase() : unmatchedEmail,
|
|
UnifiedOptInEmailFirstSent = firstSent,
|
|
UnifiedOptInEmailLastSent = lastSent,
|
|
UnifiedOptInEmailStatus = status,
|
|
UnifiedOptInEmailStatusCount = count,
|
|
EStatementsEmail = matchesEstatement && !isUniversalOptin ? email.RandomizeCase() : unmatchedEmail,
|
|
EStatementsEmailFirstSent = firstSent,
|
|
EStatementsEmailLastSent = lastSent,
|
|
EStatementsEmailStatus = status,
|
|
EStatementsEmailStatusCount = count,
|
|
ENotificationsEmail = matchesENotification && !isUniversalOptin ? email.RandomizeCase() : unmatchedEmail,
|
|
ENotificationsEmailFirstSent = firstSent,
|
|
ENotificationsEmailLastSent = lastSent,
|
|
ENotificationsEmailStatus = status,
|
|
ENotificationsEmailStatusCount = count
|
|
};
|
|
|
|
await _service.EmailFailedToSend(userId, email, true);
|
|
|
|
var updatedSettings = _repository.MemberOptInSettings[userId];
|
|
if (!matchesUnifiedOptin)
|
|
{
|
|
Assert.AreEqual(firstSent, updatedSettings.UnifiedOptInEmailFirstSent);
|
|
Assert.AreEqual(lastSent, updatedSettings.UnifiedOptInEmailLastSent);
|
|
Assert.AreEqual(status, updatedSettings.UnifiedOptInEmailStatus);
|
|
Assert.AreEqual(count, updatedSettings.UnifiedOptInEmailStatusCount);
|
|
}
|
|
|
|
if (!matchesEstatement)
|
|
{
|
|
Assert.AreEqual(firstSent, updatedSettings.EStatementsEmailFirstSent);
|
|
Assert.AreEqual(lastSent, updatedSettings.EStatementsEmailLastSent);
|
|
Assert.AreEqual(status, updatedSettings.EStatementsEmailStatus);
|
|
Assert.AreEqual(count, updatedSettings.EStatementsEmailStatusCount);
|
|
}
|
|
|
|
if (!matchesENotification)
|
|
{
|
|
Assert.AreEqual(firstSent, updatedSettings.ENotificationsEmailFirstSent);
|
|
Assert.AreEqual(lastSent, updatedSettings.ENotificationsEmailLastSent);
|
|
Assert.AreEqual(status, updatedSettings.ENotificationsEmailStatus);
|
|
Assert.AreEqual(count, updatedSettings.ENotificationsEmailStatusCount);
|
|
}
|
|
}
|
|
|
|
[TestCaseSource(nameof(UpdateScenarios))]
|
|
public async Task EmailFailedToSend_NullEmailMatched_DoesNotUpdateTrackingOnUnmatched(UpdateScenario scenario)
|
|
{
|
|
var userId = Guid.NewGuid().ToString();
|
|
string email = null;
|
|
var unmatchedEmail = EmailAddressFactory();
|
|
var (isUniversalOptin, matchesUnifiedOptin, matchesEstatement, matchesENotification) = scenario.MatchScenario;
|
|
var (firstSent, lastSent, status, count) = scenario.PriorState;
|
|
_repository.MemberOptInSettings[userId] = new MemberOptInSettings
|
|
{
|
|
UnifiedOptInEmail = matchesUnifiedOptin ? null : unmatchedEmail,
|
|
UnifiedOptInEmailFirstSent = firstSent,
|
|
UnifiedOptInEmailLastSent = lastSent,
|
|
UnifiedOptInEmailStatus = status,
|
|
UnifiedOptInEmailStatusCount = count,
|
|
EStatementsEmail = matchesEstatement ? null : unmatchedEmail,
|
|
EStatementsEmailFirstSent = firstSent,
|
|
EStatementsEmailLastSent = lastSent,
|
|
EStatementsEmailStatus = status,
|
|
EStatementsEmailStatusCount = count,
|
|
ENotificationsEmail = matchesENotification ? null : unmatchedEmail,
|
|
ENotificationsEmailFirstSent = firstSent,
|
|
ENotificationsEmailLastSent = lastSent,
|
|
ENotificationsEmailStatus = status,
|
|
ENotificationsEmailStatusCount = count
|
|
};
|
|
|
|
await _service.EmailFailedToSend(userId, email, true);
|
|
|
|
var updatedSettings = _repository.MemberOptInSettings[userId];
|
|
if (!matchesUnifiedOptin)
|
|
{
|
|
Assert.AreEqual(firstSent, updatedSettings.UnifiedOptInEmailFirstSent);
|
|
Assert.AreEqual(lastSent, updatedSettings.UnifiedOptInEmailLastSent);
|
|
Assert.AreEqual(status, updatedSettings.UnifiedOptInEmailStatus);
|
|
Assert.AreEqual(count, updatedSettings.UnifiedOptInEmailStatusCount);
|
|
}
|
|
|
|
if (!matchesEstatement)
|
|
{
|
|
Assert.AreEqual(firstSent, updatedSettings.EStatementsEmailFirstSent);
|
|
Assert.AreEqual(lastSent, updatedSettings.EStatementsEmailLastSent);
|
|
Assert.AreEqual(status, updatedSettings.EStatementsEmailStatus);
|
|
Assert.AreEqual(count, updatedSettings.EStatementsEmailStatusCount);
|
|
}
|
|
|
|
if (!matchesENotification)
|
|
{
|
|
Assert.AreEqual(firstSent, updatedSettings.ENotificationsEmailFirstSent);
|
|
Assert.AreEqual(lastSent, updatedSettings.ENotificationsEmailLastSent);
|
|
Assert.AreEqual(status, updatedSettings.ENotificationsEmailStatus);
|
|
Assert.AreEqual(count, updatedSettings.ENotificationsEmailStatusCount);
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public async Task EmailFailedToSend_PolicyMakesUpdate_ReturnsTrue()
|
|
{
|
|
var userId = Guid.NewGuid().ToString();
|
|
_repository.MemberOptInSettings[userId] = new MemberOptInSettings { UserId = userId, EStatementsEmail = "" };
|
|
_policies[1]
|
|
.Setup(p => p.Apply(It.Is<MemberOptInSettings>(s => s.UserId == userId), It.IsAny<bool>()))
|
|
.ReturnsAsync(true);
|
|
|
|
var updated = await _service.EmailFailedToSend(userId, string.Empty, true);
|
|
|
|
Assert.IsTrue(updated);
|
|
}
|
|
|
|
[Test]
|
|
public async Task EmailFailedToSend_PolicyMakesUpdate_FeatureFlagReturnsFalse()
|
|
{
|
|
var userId = Guid.NewGuid().ToString();
|
|
_repository.MemberOptInSettings[userId] = new MemberOptInSettings { UserId = userId };
|
|
_policies[1]
|
|
.Setup(p => p.Apply(It.Is<MemberOptInSettings>(s => s.UserId == userId), It.IsAny<bool>()))
|
|
.ReturnsAsync(false);
|
|
|
|
var updated = await _service.EmailFailedToSend(userId, string.Empty, false);
|
|
|
|
Assert.IsFalse(updated);
|
|
}
|
|
|
|
[Test]
|
|
public async Task EmailFailedToSend_PolicyMakesUpdate_UpdatesTracking()
|
|
{
|
|
var userId = Guid.NewGuid().ToString();
|
|
_repository.MemberOptInSettings[userId] = new MemberOptInSettings { UserId = userId };
|
|
_policies[1]
|
|
.Setup(p => p.Apply(It.Is<MemberOptInSettings>(s => s.UserId == userId), It.IsAny<bool>()))
|
|
.Callback<MemberOptInSettings, bool>((s, b) => s.LastUpdatedBy = nameof(EmailFailedToSend_PolicyMakesUpdate_UpdatesTracking))
|
|
.ReturnsAsync(true);
|
|
|
|
await _service.EmailFailedToSend(userId, string.Empty, true);
|
|
|
|
var updatedSettings = _repository.MemberOptInSettings[userId];
|
|
Assert.AreEqual(nameof(EmailFailedToSend_PolicyMakesUpdate_UpdatesTracking), updatedSettings.LastUpdatedBy);
|
|
}
|
|
|
|
[Test]
|
|
public async Task EmailFailedToSend_AllCases_EvaluatesAllFailurePolicies()
|
|
{
|
|
var userId = Guid.NewGuid().ToString();
|
|
_repository.MemberOptInSettings[userId] = new MemberOptInSettings { UserId = userId };
|
|
_policies[1]
|
|
.Setup(p => p.Apply(It.Is<MemberOptInSettings>(s => s.UserId == userId), It.IsAny<bool>()))
|
|
.ReturnsAsync(true);
|
|
|
|
await _service.EmailFailedToSend(userId, string.Empty, true);
|
|
|
|
foreach (var policy in _policies)
|
|
{
|
|
policy.Verify(p => p.Apply(It.Is<MemberOptInSettings>(s => s.UserId == userId), It.IsAny<bool>()));
|
|
}
|
|
}
|
|
|
|
private interface IObservableRepository<in TKey, in TValue>
|
|
{
|
|
void ApplyChanges(TKey key, TValue value);
|
|
}
|
|
|
|
private class FakeUnifiedOptInRepository : IUnifiedOptInRepository,
|
|
IObservableRepository<string, MemberOptInSettings>
|
|
{
|
|
public IDictionary<string, MemberOptInSettings> MemberOptInSettings { get; } =
|
|
new Dictionary<string, MemberOptInSettings>();
|
|
|
|
private readonly IRepositoryObserver<string, MemberOptInSettings> _observer;
|
|
|
|
public FakeUnifiedOptInRepository(IRepositoryObserver<string, MemberOptInSettings> observer)
|
|
{
|
|
_observer = observer;
|
|
_observer.Observe(this);
|
|
}
|
|
|
|
public Task<MemberOptInSettings> GetMemberOptInSettings(string userId)
|
|
{
|
|
if (!MemberOptInSettings.TryGetValue(userId, out var optInSettings))
|
|
{
|
|
return Task.FromResult<MemberOptInSettings>(null);
|
|
}
|
|
|
|
var clonedSettings = JsonConvert.DeserializeObject<MemberOptInSettings>
|
|
(
|
|
JsonConvert.SerializeObject(optInSettings)
|
|
);
|
|
_observer.Track(userId, clonedSettings);
|
|
|
|
return Task.FromResult(clonedSettings);
|
|
}
|
|
|
|
public Task<MemberOptInSettings> GetMemberOptInSettingsNoTracking(string userId)
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
|
|
public Task<MemberOptInSettings> GetOrCreateMemberOptinSettings(string userId)
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
|
|
public Task<List<MemberOptInSettings>> GetAllMemberOptInSettings(List<string> memberNumbers)
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
|
|
public void ApplyChanges(string key, MemberOptInSettings value)
|
|
{
|
|
MemberOptInSettings[key] = value;
|
|
}
|
|
}
|
|
|
|
private interface IRepositoryObserver<TKey, TValue>
|
|
{
|
|
void Track(TKey key, TValue value);
|
|
void Observe(IObservableRepository<TKey, TValue> subject);
|
|
}
|
|
|
|
private class FakeUnitOfWork : IUnitOfWork, IRepositoryObserver<string, MemberOptInSettings>
|
|
{
|
|
private readonly IDictionary<string, MemberOptInSettings> _activeRecords =
|
|
new Dictionary<string, MemberOptInSettings>();
|
|
|
|
private IObservableRepository<string, MemberOptInSettings> _subject;
|
|
|
|
public Task CompleteAsync()
|
|
{
|
|
foreach (var record in _activeRecords)
|
|
{
|
|
_subject.ApplyChanges(record.Key, record.Value);
|
|
}
|
|
|
|
return Task.CompletedTask;
|
|
}
|
|
|
|
public Task CompleteAsync(string operatorId, DateTime dateAdded, UserType userType)
|
|
{
|
|
return CompleteAsync();
|
|
}
|
|
|
|
public void Track(string key, MemberOptInSettings value)
|
|
{
|
|
_activeRecords[key] = value;
|
|
}
|
|
|
|
public void Observe(IObservableRepository<string, MemberOptInSettings> subject)
|
|
{
|
|
_subject = subject;
|
|
}
|
|
}
|
|
|
|
public struct UpdateScenario
|
|
{
|
|
public (DateTime? firstSent, DateTime? lastSent, EmailStatus status, int count) PriorState { get; }
|
|
public (bool isUniversalOptIn, bool matchesUnifiedOptin, bool matchesENotification, bool matchesEstatement) MatchScenario { get; }
|
|
|
|
public UpdateScenario((DateTime? firstSent, DateTime? lastSent, EmailStatus status, int count) priorState,
|
|
(bool isUniveralsOptin, bool matchesUnifiedOptin, bool matchesENotification, bool matchesEstatement) matchScenario)
|
|
{
|
|
PriorState = priorState;
|
|
MatchScenario = matchScenario;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public static class RandomCaseExtension
|
|
{
|
|
private static readonly Random Random = new Random(DateTime.Now.Millisecond);
|
|
public static string RandomizeCase(this string s)
|
|
{
|
|
static char RandomCase(char c) => Random.Next() % 2 == 0 ? char.ToUpper(c) : char.ToLower(c);
|
|
|
|
return string.Concat(s.Select(RandomCase));
|
|
}
|
|
}
|