This commit is contained in:
Zeeshaun
2026-03-13 09:27:34 -05:00
parent 256f579489
commit a675c5f5b0
381 changed files with 20992 additions and 0 deletions
@@ -0,0 +1,41 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
</PropertyGroup>
<ItemGroup>
<None Remove="RepoTestData.json" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="RepoTestData.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<PackageReference Include="LCU.Library.Internal.ApiResponse" Version="3.4.1" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.5.0" />
<PackageReference Include="Moq" Version="4.18.4" />
<PackageReference Include="xunit" Version="2.4.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="coverlet.collector" Version="3.2.0">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\LCU.API.Internal.RepoApi\LCU.API.Internal.RepoApi.csproj" />
<ProjectReference Include="..\LCU.API.Interal.RepoApi.Repos\LCU.API.Internal.RepoApi.Repos.csproj" />
</ItemGroup>
</Project>
@@ -0,0 +1,106 @@
{
"RepoTest": {
"Repo": {
"RepoId": "12351",
"AccountNo": "19620203513",
"MemberNo": "9067950",
"LoanNo": "19620203513",
"AccountTypeCode": "AUI",
"Branch": "0",
"Collector": "Bryan Schuyler",
"Status": "04R",
"Balance": "36214.90",
"DueToPayDate": "2025-01-04 00:00:00.000",
"O4RDate": "2025-03-31 16:15:14.077",
"DateFirstDelinquent": "",
"DelinquentAmount": "1800.77",
"DaysDelinquent": "86",
"PaidSkipAmount": "",
"SubStatus": "",
"RequiredPaymentAmount": "1800.77",
"CurrentDelinquentAmount": "1800.77",
"LstPmtAmt": "844.96",
"OrigAmount": "50167.72",
"LastPaymentDate": "2025-01-07 00:00:00.000",
"DateFirstIntellect": "2025-03-31 16:15:14.077",
"PrimaryIndividualId": "557697",
"Bankruptcy": "False",
"ManualRedemptionDate": "",
"RedemptionExpiredDate": "",
"DateClosed": "",
"WrittenOffDate": "",
"ReferenceStatus": "Active",
"ReferenceId": "1298878",
"ReferenceCaseId": "24433",
"AccountLastProcessed": "2025-03-31 15:48:46.370",
"OrigAccountTypeCode": "AUI",
"SixtyPlusCollectorId": ""
},
"Collateral": {
"CollateralId": 1,
"RepoId": 1
},
"TemenosCaseFailure": {
"CaseId": 10,
"CaseNumber": "123456789",
"CaseDescription": "Test Case",
"CaseStageId": "1",
"RepoStatus": "10",
"CaseStatusId": "1",
"CaseTitle": "Test Case Title",
"CaseTypeBasisId": "1",
"CaseTypeId": "1",
"CreatedUserId": "1",
"TitleOrdered": "false",
"RepoTypeId": "1",
"RepoAgentId": "1"
},
"TemenosCaseSuccess": {
"CaseId": 10,
"CaseNumber": "123456789",
"CaseDescription": "Test Case",
"CaseStageId": "1",
"RepoStatus": "100",
"CaseStatusId": "1",
"CaseTitle": "Test Case Title",
"CaseTypeBasisId": "1",
"CaseTypeId": "7",
"CreatedUserId": "1",
"TitleOrdered": "false",
"RepoTypeId": "1",
"RepoAgentId": "1"
},
"TemenosAccount": {
"CustomFieldMap": [
{
"User Status Code 1": "True"
}
]
},
"Loan": {
"MemberId": "9067950",
"LoanId": "12351",
"ExternalLoanId": "12351",
"LoanType": "AUI"
},
"Letters": {
"NoticeType": "Repo"
},
"Transaction": {
"runningBalance": 20000.00,
"postingDate": "2025-01-07 00:00:00.000",
"amount": 1000.00,
"transactionTypeCode": "TRC",
"transactionTypeDescription": "Test Transaction"
},
"Member": {
"MemberId": "9067950",
"MemberName": "Timmy Tester"
},
"AuctionAssignment": {
"Id": 1,
"AuctionId": "12345"
},
"Settings": {}
}
}
@@ -0,0 +1,187 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using LCU.API.Internal.RepoApi.Models.Old_Repo_Models;
using LCU.API.Internal.RepoApi.Old_Repo_Exceptions;
using LCU.API.Internal.RepoApi.Repos.Exceptions;
using LCU.API.Internal.RepoApi.Repos.Models;
using LCU.API.Internal.RepoApi.Repos.Repositories;
using LCU.API.Internal.RepoApi.Old_Repo_Services;
using Moq;
using Xunit;
namespace LCU.API.Internal.RepoApiTests.ServiceTests
{
public class EventAlertServiceTests
{
private readonly Mock<IEventAlertRepository> _eventAlertRepositoryMock;
private readonly Mock<IUnitOfWork> _unitOfWorkMock;
private readonly Mock<IRepoAccountRepository> _accountRepositoryMock;
private readonly EventAlertService _service;
public EventAlertServiceTests()
{
_eventAlertRepositoryMock = new Mock<IEventAlertRepository>();
_unitOfWorkMock = new Mock<IUnitOfWork>();
_accountRepositoryMock = new Mock<IRepoAccountRepository>();
_service = new EventAlertService(
_eventAlertRepositoryMock.Object,
_unitOfWorkMock.Object,
_accountRepositoryMock.Object);
}
[Fact]
public async Task ListAll_ShouldReturnAllEventAlerts()
{
// Arrange
var eventAlerts = new List<EventAlert> { new EventAlert { Id = 1 }, new EventAlert { Id = 2 } };
_eventAlertRepositoryMock.Setup(repo => repo.ListAllAsync()).ReturnsAsync(eventAlerts);
// Act
var result = await _service.ListAll();
// Assert
Assert.Equal(eventAlerts, result);
}
[Fact]
public async Task ListAll_ShouldThrowServerErrorException_OnException()
{
// Arrange
_eventAlertRepositoryMock.Setup(repo => repo.ListAllAsync()).ThrowsAsync(new Exception());
// Act & Assert
await Assert.ThrowsAsync<ServerErrorException>(() => _service.ListAll());
}
[Fact]
public async Task ListUnread_ShouldReturnUnreadEventAlerts()
{
// Arrange
var unreadAlerts = new List<EventAlert> { new EventAlert { Id = 1 } };
_eventAlertRepositoryMock.Setup(repo => repo.ListUnreadAsync()).ReturnsAsync(unreadAlerts);
// Act
var result = await _service.ListUnread();
// Assert
Assert.Equal(unreadAlerts, result);
}
[Fact]
public async Task ListUnread_ShouldThrowServerErrorException_OnException()
{
// Arrange
_eventAlertRepositoryMock.Setup(repo => repo.ListUnreadAsync()).ThrowsAsync(new Exception());
// Act & Assert
await Assert.ThrowsAsync<ServerErrorException>(() => _service.ListUnread());
}
[Fact]
public async Task ListWithinDateRange_ShouldReturnAlertsWithinDateRange()
{
// Arrange
var start = DateTime.Now.AddDays(-1);
var end = DateTime.Now;
var alerts = new List<EventAlert> { new EventAlert { Id = 1 } };
_eventAlertRepositoryMock.Setup(repo => repo.ListWithinDateRangeAsync(start, end)).ReturnsAsync(alerts);
// Act
var result = await _service.ListWithinDateRange(start, end);
// Assert
Assert.Equal(alerts, result);
}
[Fact]
public async Task ListWithinDateRange_ShouldThrowServerErrorException_OnException()
{
// Arrange
var start = DateTime.Now.AddDays(-1);
var end = DateTime.Now;
_eventAlertRepositoryMock.Setup(repo => repo.ListWithinDateRangeAsync(start, end)).ThrowsAsync(new Exception());
// Act & Assert
await Assert.ThrowsAsync<ServerErrorException>(() => _service.ListWithinDateRange(start, end));
}
[Fact]
public async Task SaveAsync_ShouldSaveEventAlert()
{
// Arrange
var eventAlert = new EventAlert { RepoId = 1, AccountNo = "123" };
_accountRepositoryMock.Setup(repo => repo.FindByIdAsync(eventAlert.RepoId.Value))
.ReturnsAsync(new RepoAccount { Status = "ACTIVE" });
// Act
var result = await _service.SaveAsync(eventAlert);
// Assert
_eventAlertRepositoryMock.Verify(repo => repo.AddAsync(eventAlert), Times.Once);
_unitOfWorkMock.Verify(uow => uow.CompleteAsync(), Times.Once);
Assert.Equal(eventAlert, result);
}
[Fact]
public async Task SaveAsync_ShouldThrowUnwantedStatusException_WhenStatusIsCancelledOrRedeemed()
{
// Arrange
var eventAlert = new EventAlert { RepoId = 1, AccountNo = "123" };
_accountRepositoryMock.Setup(repo => repo.FindByIdAsync(eventAlert.RepoId.Value))
.ReturnsAsync(new RepoAccount { Status = "REDEEMED" });
// Act & Assert
await Assert.ThrowsAsync<UnwantedStatusException>(() => _service.SaveAsync(eventAlert));
}
[Fact]
public async Task SaveAsync_ShouldThrowServerErrorException_OnException()
{
// Arrange
var eventAlert = new EventAlert { RepoId = 1, AccountNo = "123" };
_accountRepositoryMock.Setup(repo => repo.FindByIdAsync(eventAlert.RepoId.Value))
.ThrowsAsync(new Exception());
// Act & Assert
await Assert.ThrowsAsync<ServerErrorException>(() => _service.SaveAsync(eventAlert));
}
[Fact]
public async Task DeleteAsync_ShouldDeleteEventAlert()
{
// Arrange
var eventAlert = new EventAlert { Id = 1 };
_eventAlertRepositoryMock.Setup(repo => repo.FindByIdAsync(eventAlert.Id)).ReturnsAsync(eventAlert);
// Act
var result = await _service.DeleteAsync(eventAlert.Id);
// Assert
_eventAlertRepositoryMock.Verify(repo => repo.Remove(eventAlert), Times.Once);
_unitOfWorkMock.Verify(uow => uow.CompleteAsync(), Times.Once);
Assert.Equal(eventAlert, result);
}
[Fact]
public async Task DeleteAsync_ShouldThrowNotFoundException_WhenEventAlertNotFound()
{
// Arrange
_eventAlertRepositoryMock.Setup(repo => repo.FindByIdAsync(It.IsAny<int>())).ReturnsAsync((EventAlert)null);
// Act & Assert
await Assert.ThrowsAsync<NotFoundException>(() => _service.DeleteAsync(1));
}
[Fact]
public async Task DeleteAsync_ShouldThrowServerErrorException_OnException()
{
// Arrange
_eventAlertRepositoryMock.Setup(repo => repo.FindByIdAsync(It.IsAny<int>())).ThrowsAsync(new Exception());
// Act & Assert
await Assert.ThrowsAsync<ServerErrorException>(() => _service.DeleteAsync(1));
}
}
}
@@ -0,0 +1,271 @@
using LCU.API.Internal.RepoApi.Models.Old_Repo_Models;
using LCU.API.Internal.RepoApi.Old_Repo_DataAccess;
using LCU.API.Internal.RepoApi.Old_Repo_Exceptions;
using LCU.API.Internal.RepoApi.Repos.Models;
using LCU.API.Internal.RepoApi.Repos.Models.Producer;
using LCU.API.Internal.RepoApi.Old_Repo_Services.Producer;
using LCU.API.Internal.RepoApi.Old_Repo_Services;
using LCU.API.Collections.CollectionsApiLib.Models;
using LCU.API.Internal.RepoApi.Repos.Models.Consumer;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using LCU.API.Internal.RepoApi.Repos.Models.Settings;
using System.IO;
using System.Reflection;
namespace LCU.API.Internal.RepoApiTests.ServiceTests
{
public class RepoAccountProcessorTests
{
private readonly Mock<IRepoAccountProcessorService> _mockRepoAccountProcessorService;
private readonly Mock<IAccountAlertCheckService> _mockAccountAlertCheckService;
private readonly Mock<IEmailer> _mockEmailer;
private readonly Mock<ISettingsService> _mockSettingsService;
private readonly Mock<ICollectionsDao> _mockCollectionsDao;
private readonly Mock<ICoreDao> _mockCoreDao;
private readonly Mock<IRepoAccountService> _mockRepoAccountService;
private readonly Mock<IRepoLetterService> _mockRepoLetterService;
private readonly Mock<IAuctionAssignmentService> _mockAuctionAssignmentService;
private readonly RepoAccountProcessor _processor;
private readonly JObject _mockJObject;
public RepoAccountProcessorTests()
{
_mockRepoAccountProcessorService = new Mock<IRepoAccountProcessorService>();
_mockAccountAlertCheckService = new Mock<IAccountAlertCheckService>();
_mockEmailer = new Mock<IEmailer>();
_mockSettingsService = new Mock<ISettingsService>();
_mockCollectionsDao = new Mock<ICollectionsDao>();
_mockCoreDao = new Mock<ICoreDao>();
_mockRepoAccountService = new Mock<IRepoAccountService>();
_mockRepoLetterService = new Mock<IRepoLetterService>();
_mockAuctionAssignmentService = new Mock<IAuctionAssignmentService>();
_processor = new RepoAccountProcessor(
_mockRepoAccountProcessorService.Object,
_mockAccountAlertCheckService.Object,
_mockCollectionsDao.Object,
_mockEmailer.Object,
_mockSettingsService.Object,
_mockRepoAccountService.Object,
_mockRepoLetterService.Object,
_mockCoreDao.Object,
_mockAuctionAssignmentService.Object
);
JsonSerializer se = new JsonSerializer();
string testFile = "./RepoTestData.json";
using (StreamReader r = new StreamReader(testFile))
{
string json = r.ReadToEnd();
JsonTextReader reader = new JsonTextReader(new StringReader(json));
_mockJObject = JObject.Load(reader);
}
}
[Fact]
public async Task HandleAccount_ShouldReturnAutoclosed()
{
var accountNumber = _mockJObject["RepoTest"]["Repo"]["AccountNo"].ToString();
var item = new ProcessingItem { AccountNo = accountNumber };
var processingSlip = new RepoAccountProcessingSlip
{
AccountNo = accountNumber,
RecoveryAccount = null,
ExistingRepoAccount = _mockJObject["RepoTest"]["Repo"].ToObject<RepoAccount>()
};
_mockRepoAccountService.Setup(x => x.GetNewestOpenAccount(processingSlip.AccountNo)).ReturnsAsync(processingSlip.ExistingRepoAccount);
var result = await _processor.HandleAccount(item);
Assert.Equal(RepoProcessingResult.Autoclosed, result);
}
[Fact]
public async Task HandleAccount_IsUnconvertedIntellectAccount()
{
var accountNumber = _mockJObject["RepoTest"]["Repo"]["AccountNo"].ToString();
var item = new ProcessingItem { AccountNo = accountNumber };
TemenosAccount recoveryAccount = new TemenosAccount() {Cases = new List<TemenosCase> { _mockJObject["RepoTest"]["TemenosCaseSuccess"].ToObject<TemenosCase>() } };
recoveryAccount.CustomFieldMap = new Dictionary<string, string> { { "User Status Code 1", "04R" } };
_mockRepoAccountService.Setup(x => x.GetNewestOpenAccount(accountNumber)).ReturnsAsync(_mockJObject["RepoTest"]["Repo"].ToObject<RepoAccount>());
_mockCollectionsDao.Setup(x => x.RetrieveAccountAsync(accountNumber)).ReturnsAsync(recoveryAccount);
_mockSettingsService.Setup(x => x.GetCachedRepoSettingsAsync()).ReturnsAsync(_mockJObject["RepoTest"]["Settings"].ToObject<Settings>());
var result = await _processor.HandleAccount(item);
Assert.Equal(RepoProcessingResult.Unconverted, result);
}
[Fact]
public void VerifyAccountNo_ShouldThrowException_WhenItemIsNull()
{
// Act & Assert
Assert.Throws<IneligibleAccountException>(() => _processor.VerifyAccountNo(null));
}
[Fact]
public async Task CreateProcessingSlip_ShouldReturnSlip_WithValidData()
{
// Arrange
var item = new ProcessingItem { AccountNo = "12345", CaseId = "1" };
var recoveryAccount = new TemenosAccount();
var loan = new LoanDetail();
_mockCollectionsDao
.Setup(x => x.RetrieveAccountAsync("12345"))
.ReturnsAsync(recoveryAccount);
_mockCoreDao
.Setup(x => x.RetrieveLoanAsync("12345"))
.ReturnsAsync(loan);
// Act
var result = await _processor.CreateProcessingSlip(item);
// Assert
Assert.NotNull(result);
Assert.Equal("12345", result.AccountNo);
Assert.Equal(recoveryAccount, result.RecoveryAccount);
Assert.Equal(loan, result.Loan);
}
[Fact]
public async Task HandleAccount_ShouldReturnIneligible_WhenNotPossiblyRepossessionCase()
{
// Arrange
var accountNumber = _mockJObject["RepoTest"]["Repo"]["AccountNo"].ToString();
var item = new ProcessingItem { AccountNo = accountNumber, CaseId = "10" };
TemenosAccount recoveryAccount = new TemenosAccount() { Cases = new List<TemenosCase> { _mockJObject["RepoTest"]["TemenosCaseFailure"].ToObject<TemenosCase>() } };
RepoAccount existingAccount = _mockJObject["RepoTest"]["Repo"].ToObject<RepoAccount>();
existingAccount.Collaterals = new List<Collateral>
{
_mockJObject["RepoTest"]["Collateral"].ToObject<Collateral>()
};
_mockRepoAccountService.Setup(x => x.GetNewestOpenAccount(accountNumber)).ReturnsAsync(existingAccount);
_mockRepoAccountProcessorService.Setup(x => x.UpdateRepoAccountFromParts(It.IsAny<RepoAccountProcessingSlip>()))
.Returns(_mockJObject["RepoTest"]["Repo"].ToObject<RepoAccount>());
_mockCollectionsDao.Setup(x => x.RetrieveAccountAsync(accountNumber)).ReturnsAsync(recoveryAccount);
_mockCoreDao.Setup(x => x.RetrieveLoanAsync(accountNumber)).ReturnsAsync(_mockJObject["RepoTest"]["Loan"].ToObject<LoanDetail>());
_mockRepoLetterService.Setup(x => x.ListByAccountIdAsync(recoveryAccount.AccountId)).ReturnsAsync(new List<RepoLetter>());
_mockRepoAccountProcessorService.Setup(x => x.CreateRepoAccount(It.IsAny<TemenosAccount>(), It.IsAny<TemenosCase>(), It.IsAny<LoanDetail>()))
.Returns(new RepoAccount());
_mockSettingsService.Setup(x => x.GetCachedRepoSettingsAsync()).ReturnsAsync(_mockJObject["RepoTest"]["Settings"].ToObject<Settings>());
// Act
var result = await _processor.HandleAccount(item);
// Assert
Assert.Equal(RepoProcessingResult.Ineligible, result);
}
[Fact]
public async Task HandleAccount_ShouldThrowException_WhenExistingRepoAccountHasNoCollateral()
{
// Arrange
var accountNumber = "12345";
var item = new ProcessingItem { AccountNo = accountNumber };
// var existingRepoAccount = new RepoAccount { Collateral = null };
var processingSlip = new RepoAccountProcessingSlip
{
AccountNo = accountNumber,
RecoveryAccount = new TemenosAccount(),
ExistingRepoAccount = _mockJObject["RepoTest"]["Repo"].ToObject<RepoAccount>()
};
_mockRepoAccountService.Setup(x => x.GetNewestOpenAccount(accountNumber)).ReturnsAsync(_mockJObject["RepoTest"]["Repo"].ToObject<RepoAccount>());
_mockCollectionsDao.Setup(x => x.RetrieveAccountAsync(accountNumber)).ReturnsAsync(processingSlip.RecoveryAccount);
_mockSettingsService.Setup(x => x.GetCachedRepoSettingsAsync()).ReturnsAsync(new Settings());
// Act & Assert
await Assert.ThrowsAsync<MissingRequirementException>(() => _processor.HandleAccount(item));
}
[Fact]
public async Task HandleAccount_ShouldReturnUpdated_WhenExistingAccountIsUpdated()
{
// Arrange
var accountNumber = _mockJObject["RepoTest"]["Repo"]["AccountNo"].ToString();
var item = new ProcessingItem { AccountNo = accountNumber, CaseId = "10" };
TemenosAccount recoveryAccount = new TemenosAccount() { Cases = new List<TemenosCase> { _mockJObject["RepoTest"]["TemenosCaseSuccess"].ToObject<TemenosCase>() } };
RepoAccount existingAccount = _mockJObject["RepoTest"]["Repo"].ToObject<RepoAccount>();
existingAccount.Collaterals = new List<Collateral>
{
_mockJObject["RepoTest"]["Collateral"].ToObject<Collateral>()
};
List<CoreTransaction> transactions = new List<CoreTransaction>
{
_mockJObject["RepoTest"]["Transaction"].ToObject<CoreTransaction>()
};
_mockRepoAccountService.Setup(x => x.GetNewestOpenAccount(accountNumber)).ReturnsAsync(existingAccount);
_mockRepoAccountProcessorService.Setup(x => x.UpdateRepoAccountFromParts(It.IsAny<RepoAccountProcessingSlip>()))
.Returns(_mockJObject["RepoTest"]["Repo"].ToObject<RepoAccount>());
_mockCollectionsDao.Setup(x => x.RetrieveAccountAsync(accountNumber)).ReturnsAsync(recoveryAccount);
_mockSettingsService.Setup(x => x.GetCachedRepoSettingsAsync()).ReturnsAsync(_mockJObject["RepoTest"]["Settings"].ToObject<Settings>());
_mockCoreDao.Setup(x => x.RetrieveLoanAsync(accountNumber)).ReturnsAsync(_mockJObject["RepoTest"]["Loan"].ToObject<LoanDetail>());
_mockCoreDao.Setup(x => x.RetrieveTransactionsAsync(accountNumber)).ReturnsAsync(transactions);
_mockCoreDao.Setup(x => x.RetrieveMemberAsync(accountNumber)).ReturnsAsync(_mockJObject["RepoTest"]["Member"].ToObject<MemberDetail>());
_mockRepoLetterService.Setup(x => x.ListByAccountIdAsync(recoveryAccount.AccountId)).ReturnsAsync(new List<RepoLetter>());
_mockAuctionAssignmentService.Setup(x => x.GetListByIdsAsync(It.IsAny<List<int>>()))
.ReturnsAsync(new List<AuctionAssignment> { _mockJObject["RepoTest"]["AuctionAssignment"].ToObject<AuctionAssignment>() });
_mockRepoAccountProcessorService.Setup(x => x.UpdateRepoAccountFromParts(It.IsAny<RepoAccountProcessingSlip>()))
.Returns(_mockJObject["RepoTest"]["Repo"].ToObject<RepoAccount>());
// Act
var result = await _processor.HandleAccount(item);
// Assert
Assert.Equal(RepoProcessingResult.Updated, result);
}
[Fact]
public async Task HandleAccount_ShouldThrowException_WhenProcessingItemIsNull()
{
// Act & Assert
await Assert.ThrowsAsync<IneligibleAccountException>(() => _processor.HandleAccount(null));
}
[Fact]
public async Task HandleAccount_ShouldReturnUnconverted_WhenRecoveryAccountHasOldIntellectStatus()
{
// Arrange
var accountNumber = "12345";
var item = new ProcessingItem { AccountNo = accountNumber };
var recoveryAccount = new TemenosAccount
{
CustomFieldMap = new Dictionary<string, string> { { RepoAccountProcessor.UserStatusFieldOld, "OldStatus" } }
};
var existingRepoAccount = new RepoAccount { Status = "OldStatus" };
var processingSlip = new RepoAccountProcessingSlip
{
AccountNo = accountNumber,
RecoveryAccount = recoveryAccount,
ExistingRepoAccount = existingRepoAccount
};
_mockRepoAccountService.Setup(x => x.GetNewestOpenAccount(accountNumber)).ReturnsAsync(existingRepoAccount);
_mockCollectionsDao.Setup(x => x.RetrieveAccountAsync(accountNumber)).ReturnsAsync(recoveryAccount);
_mockSettingsService.Setup(x => x.GetCachedRepoSettingsAsync()).ReturnsAsync(new Settings());
// Act
var result = await _processor.HandleAccount(item);
// Assert
Assert.Equal(RepoProcessingResult.Unconverted, result);
}
}
}
@@ -0,0 +1,188 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using LCU.API.Internal.RepoApi.Old_Repo_Services;
using LCU.API.Internal.RepoApi.Repos.Exceptions;
using LCU.API.Internal.RepoApi.Repos.Models;
using LCU.API.Internal.RepoApi.Repos.Models.Results;
using LCU.API.Internal.RepoApi.Repos.Repositories;
using LCU.API.Internal.RepoApi.Models.Old_Repo_Models.Filters;
using LCU.API.Internal.RepoApi.Models.Old_Repo_Models.Requests;
using Moq;
using Xunit;
using LCU.API.Internal.RepoApi.Old_Repo_Exceptions;
namespace LCU.API.Internal.RepoApiTests.ServiceTests
{
public class RepoAccountServiceTests
{
private readonly Mock<IRepoAccountRepository> _repoAccountRepositoryMock;
private readonly Mock<IRepoStatusChangeRepository> _repoStatusChangeRepositoryMock;
private readonly Mock<IRepoManualStatusRepository> _repoManualStatusRepositoryMock;
private readonly Mock<ICollateralRepository> _collateralRepositoryMock;
private readonly Mock<IUnitOfWork> _unitOfWorkMock;
private readonly RepoAccountService _service;
public RepoAccountServiceTests()
{
_repoAccountRepositoryMock = new Mock<IRepoAccountRepository>();
_repoStatusChangeRepositoryMock = new Mock<IRepoStatusChangeRepository>();
_repoManualStatusRepositoryMock = new Mock<IRepoManualStatusRepository>();
_collateralRepositoryMock = new Mock<ICollateralRepository>();
_unitOfWorkMock = new Mock<IUnitOfWork>();
_service = new RepoAccountService(
_repoAccountRepositoryMock.Object,
_repoStatusChangeRepositoryMock.Object,
_repoManualStatusRepositoryMock.Object,
_collateralRepositoryMock.Object,
_unitOfWorkMock.Object);
}
[Fact]
public async Task ListAll_ShouldReturnPagedResult_WhenCalled()
{
// Arrange
var pageFilter = new PageFilter { Page = 1, Limit = 10 };
var repoAccountFilter = new RepoAccountPostFilter { RepoIdList = new List<int?> { 1, 2 }, Status = "Open" };
var expectedResult = new PagedResult<RepoAccount>();
_repoAccountRepositoryMock
.Setup(repo => repo.ListAsync(It.IsAny<List<int?>>(), It.IsAny<int>(), It.IsAny<int>(), It.IsAny<string>(), It.IsAny<string?>(), It.IsAny<int?>(), It.IsAny<bool?>()))
.ReturnsAsync(expectedResult);
// Act
var result = await _service.ListAll(pageFilter, repoAccountFilter);
// Assert
Assert.Equal(expectedResult, result);
}
[Fact]
public async Task ListAll_ShouldThrowServerErrorException_WhenExceptionOccurs()
{
// Arrange
var pageFilter = new PageFilter { Page = 1, Limit = 10 };
var repoAccountFilter = new RepoAccountPostFilter();
_repoAccountRepositoryMock
.Setup(repo => repo.ListAsync(It.IsAny<List<int?>>(), It.IsAny<int>(), It.IsAny<int>(), It.IsAny<string>(), It.IsAny<string?>(), It.IsAny<int?>(), It.IsAny<bool?>()))
.ThrowsAsync(new Exception());
// Act & Assert
await Assert.ThrowsAsync<ServerErrorException>(() => _service.ListAll(pageFilter, repoAccountFilter));
}
[Fact]
public async Task FindByAuctionAssignmentId_ShouldReturnRepoAccount_WhenFound()
{
// Arrange
var auctionAssignmentId = 1;
var expectedRepoAccount = new RepoAccount();
_repoAccountRepositoryMock
.Setup(repo => repo.FindByAuctionAssignmentIdAsync(auctionAssignmentId))
.ReturnsAsync(expectedRepoAccount);
// Act
var result = await _service.FindByAuctionAssignmentId(auctionAssignmentId);
// Assert
Assert.Equal(expectedRepoAccount, result);
}
[Fact]
public async Task FindByAuctionAssignmentId_ShouldThrowServerErrorException_WhenExceptionOccurs()
{
// Arrange
var auctionAssignmentId = 1;
_repoAccountRepositoryMock
.Setup(repo => repo.FindByAuctionAssignmentIdAsync(auctionAssignmentId))
.ThrowsAsync(new Exception());
// Act & Assert
await Assert.ThrowsAsync<ServerErrorException>(() => _service.FindByAuctionAssignmentId(auctionAssignmentId));
}
[Fact]
public async Task SaveAsync_ShouldSaveRepoAccountAndAddStatusChange()
{
// Arrange
var repoAccount = new RepoAccount { RepoId = 1, Status = "Open" };
var savedRepoAccount = new RepoAccount { RepoId = 1, Status = "Open" };
_repoAccountRepositoryMock
.Setup(repo => repo.AddAsync(repoAccount))
.ReturnsAsync(savedRepoAccount);
// Act
var result = await _service.SaveAsync(repoAccount);
// Assert
Assert.Equal(repoAccount, result);
_unitOfWorkMock.Verify(uow => uow.CompleteAsync(), Times.Once);
}
[Fact]
public async Task SaveAsync_ShouldThrowServerErrorException_WhenExceptionOccurs()
{
// Arrange
var repoAccount = new RepoAccount { RepoId = 1, Status = "Open" };
_repoAccountRepositoryMock
.Setup(repo => repo.AddAsync(repoAccount))
.ThrowsAsync(new Exception());
// Act & Assert
await Assert.ThrowsAsync<RepoApi.Old_Repo_Exceptions.ServerErrorException>(() => _service.SaveAsync(repoAccount));
}
[Fact]
public async Task Get_ShouldReturnRepoAccount_WhenFound()
{
// Arrange
var id = 1;
var expectedRepoAccount = new RepoAccount();
_repoAccountRepositoryMock
.Setup(repo => repo.FindByIdAsync(id))
.ReturnsAsync(expectedRepoAccount);
// Act
var result = await _service.Get(id);
// Assert
Assert.Equal(expectedRepoAccount, result);
}
[Fact]
public async Task Get_ShouldThrowNotFoundException_WhenRepoAccountNotFound()
{
// Arrange
var id = 1;
_repoAccountRepositoryMock
.Setup(repo => repo.FindByIdAsync(id))
.ReturnsAsync((RepoAccount)null);
// Act & Assert
await Assert.ThrowsAsync<NotFoundException>(() => _service.Get(id));
}
[Fact]
public async Task Get_ShouldThrowServerErrorException_WhenExceptionOccurs()
{
// Arrange
var id = 1;
_repoAccountRepositoryMock
.Setup(repo => repo.FindByIdAsync(id))
.ThrowsAsync(new Exception());
// Act & Assert
await Assert.ThrowsAsync<ServerErrorException>(() => _service.Get(id));
}
}
}
@@ -0,0 +1,110 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using LCU.API.Internal.RepoApi.Old_Repo_Exceptions;
using LCU.API.Internal.RepoApi.Repos.Models;
using LCU.API.Internal.RepoApi.Repos.Repositories;
using LCU.API.Internal.RepoApi.Old_Repo_Services;
using Moq;
using Xunit;
namespace LCU.API.Internal.RepoApiTests.ServiceTests
{
public class RepoCompanySelectionServiceTests
{
private readonly Mock<IRepoCompanySelectionRepository> _mockRepoCompanySelectionRepository;
private readonly Mock<IUnitOfWork> _mockUnitOfWork;
private readonly RepoCompanySelectionService _service;
public RepoCompanySelectionServiceTests()
{
_mockRepoCompanySelectionRepository = new Mock<IRepoCompanySelectionRepository>();
_mockUnitOfWork = new Mock<IUnitOfWork>();
_service = new RepoCompanySelectionService(_mockRepoCompanySelectionRepository.Object, _mockUnitOfWork.Object);
}
[Fact]
public async Task ListAllAsync_ShouldReturnAllRepoCompanySelections()
{
// Arrange
var mockData = new List<RepoCompanySelection>
{
new RepoCompanySelection { Id = 1},
new RepoCompanySelection { Id = 2}
};
_mockRepoCompanySelectionRepository.Setup(repo => repo.ListAllAsync()).ReturnsAsync(mockData);
// Act
var result = await _service.ListAllAsync();
// Assert
Assert.Equal(mockData, result);
_mockRepoCompanySelectionRepository.Verify(repo => repo.ListAllAsync(), Times.Once);
}
[Fact]
public async Task ListAllAsync_ShouldThrowServerErrorException_OnException()
{
// Arrange
_mockRepoCompanySelectionRepository.Setup(repo => repo.ListAllAsync()).ThrowsAsync(new Exception());
// Act & Assert
await Assert.ThrowsAsync<ServerErrorException>(() => _service.ListAllAsync());
}
[Fact]
public async Task GetAsync_ShouldReturnRepoCompanySelection_WhenFound()
{
// Arrange
var mockData = new RepoCompanySelection { Id = 1};
_mockRepoCompanySelectionRepository.Setup(repo => repo.FindByIdAsync(1)).ReturnsAsync(mockData);
// Act
var result = await _service.GetAsync(1);
// Assert
Assert.Equal(mockData, result);
_mockRepoCompanySelectionRepository.Verify(repo => repo.FindByIdAsync(1), Times.Once);
}
[Fact]
public async Task GetAsync_ShouldThrowNotFoundException_WhenNotFound()
{
// Arrange
_mockRepoCompanySelectionRepository.Setup(repo => repo.FindByIdAsync(1)).ReturnsAsync((RepoCompanySelection)null);
// Act & Assert
var exception = await Assert.ThrowsAsync<NotFoundException>(() => _service.GetAsync(1));
Assert.Equal("Repo Company Selection with id 1 not found", exception.Message);
}
[Fact]
public async Task GetAsync_ShouldThrowNotFoundException_OnRepositoryException()
{
// Arrange
_mockRepoCompanySelectionRepository.Setup(repo => repo.FindByIdAsync(1)).ThrowsAsync(new Exception());
// Act & Assert
var exception = await Assert.ThrowsAsync<NotFoundException>(() => _service.GetAsync(1));
Assert.Equal("Repo Company Selection with id 1 not found", exception.Message);
}
[Fact]
public async Task SaveChangesAsync_ShouldSaveRepoCompanySelections()
{
// Arrange
var mockData = new List<RepoCompanySelection>
{
new RepoCompanySelection { Id = 1},
new RepoCompanySelection { Id = 2}
};
// Act
await _service.SaveChangesAsync(mockData);
// Assert
_mockRepoCompanySelectionRepository.Verify(repo => repo.SaveRange(mockData), Times.Once);
_mockUnitOfWork.Verify(uow => uow.CompleteAsync(), Times.Once);
}
}
}
@@ -0,0 +1,121 @@
using LCU.API.Collections.CollectionsApiLib.Models;
using LCU.API.Internal.RepoApi.Old_Repo_DataAccess;
using LCU.API.Internal.RepoApi.Old_Repo_Exceptions;
using LCU.API.Internal.RepoApi.Repos.Models;
using LCU.API.Internal.RepoApi.Repos.Repositories;
using LCU.API.Internal.RepoApi.Old_Repo_Services;
namespace LCU.API.Internal.RepoApiTests.ServiceTests
{
public class RepoLetterServiceTests
{
private readonly Mock<ILetterRepository> _mockLetterRepository;
private readonly Mock<ICollectionsDao> _mockCollectionsDao;
private readonly RepoLetterService _service;
public RepoLetterServiceTests()
{
_mockLetterRepository = new Mock<ILetterRepository>();
_mockCollectionsDao = new Mock<ICollectionsDao>();
_service = new RepoLetterService(_mockLetterRepository.Object, _mockCollectionsDao.Object);
}
[Fact]
public async Task ListByAccountIdAsync_ReturnsEmptyList_WhenNoCollectionsLetters()
{
// Arrange
int accountId = 1;
_mockCollectionsDao
.Setup(x => x.RetrieveHistoryAsync(accountId))
.ReturnsAsync(new List<TemenosHistory>());
// Act
var result = await _service.ListByAccountIdAsync(accountId);
// Assert
Assert.Empty(result);
}
[Fact]
public async Task ListByAccountIdAsync_ReturnsProcessedLetters_WhenCollectionsLettersExist()
{
// Arrange
int accountId = 1;
var collectionsHistory = new List<TemenosHistory>
{
new TemenosHistory { Type = HistoryType.Letter, Message = "Test Message", Created = DateTime.UtcNow }
};
var letters = new List<Letter>
{
new Letter { LetterDescription = "Test", DaysToWait = 5, ActionCode = "A1" }
};
_mockCollectionsDao
.Setup(x => x.RetrieveHistoryAsync(accountId))
.ReturnsAsync(collectionsHistory);
_mockLetterRepository
.Setup(x => x.ListAsync())
.ReturnsAsync(letters);
// Act
var result = await _service.ListByAccountIdAsync(accountId);
// Assert
Assert.Single(result);
Assert.Equal("Test Message", result.First().NoticeType);
}
[Fact]
public async Task ListByAccountIdAsync_ThrowsServerErrorException_OnGeneralException()
{
// Arrange
int accountId = 1;
_mockCollectionsDao
.Setup(x => x.RetrieveHistoryAsync(accountId))
.ThrowsAsync(new Exception("Test Exception"));
// Act & Assert
await Assert.ThrowsAsync<ServerErrorException>(() => _service.ListByAccountIdAsync(accountId));
}
[Fact]
public void ProcessLetters_ThrowsMissingRequirementException_WhenLetterDescriptionIsNull()
{
// Arrange
var collectionsLetters = new List<TemenosHistory>
{
new TemenosHistory { Message = "Test Message", Created = DateTime.UtcNow }
};
var letters = new List<Letter>
{
new Letter { LetterDescription = null }
};
// Act & Assert
Assert.Throws<MissingRequirementException>(() =>
RepoLetterService.ProcessLetters(collectionsLetters, letters));
}
[Fact]
public void ProcessLetters_ReturnsProcessedLetters_WhenValidDataProvided()
{
// Arrange
var collectionsLetters = new List<TemenosHistory>
{
new TemenosHistory { Message = "Test Message", Created = DateTime.UtcNow }
};
var letters = new List<Letter>
{
new Letter { LetterDescription = "Test", DaysToWait = 5, ActionCode = "A1" }
};
// Act
var result = RepoLetterService.ProcessLetters(collectionsLetters, letters);
// Assert
Assert.Single(result);
Assert.Equal("Test Message", result.First().NoticeType);
}
}
}
@@ -0,0 +1,153 @@
using Microsoft.Extensions.Caching.Memory;
using LCU.API.Internal.RepoApi.Old_Repo_Services;
using LCU.API.Internal.RepoApi.Repos.Repositories;
using LCU.API.Internal.RepoApi.Repos.Models.Settings;
using LCU.API.Internal.RepoApi.Configurations;
using LCU.API.Internal.RepoApi.Old_Repo_DataAccess;
using LCU.API.Internal.RepoApi.Repos.Repositories.Settings;
namespace LCU.API.Internal.RepoApiTests.ServiceTests
{
public class SettingsServiceTests
{
private readonly Mock<IAccountTypeRepository> _mockAccountTypeRepository;
private readonly Mock<IAllowedStatusChangeRepository> _mockAllowedStatusChangeRepository;
private readonly Mock<IBodyStyleRepository> _mockBodyStyleRepository;
private readonly Mock<ICleaningLevelRepository> _mockCleaningLevelRepository;
private readonly Mock<ICollateralTypeRepository> _mockCollateralTypeRepository;
private readonly Mock<ICollateralTypeToVehicleTypeRepository> _mockCollateralTypeToVehicleTypeRepository;
private readonly Mock<IHoldStatusRepository> _mockHoldStatusRepository;
private readonly Mock<ILoanCategoryRepository> _mockLoanCategoryRepository;
private readonly Mock<ILocationTypeRepository> _mockLocationTypeRepository;
private readonly Mock<IVehicleTypeRepository> _mockVehicleTypeRepository;
private readonly Mock<IExternalUserRepository> _mockExternalUserRepository;
private readonly Mock<IRepoCompanyRepository> _mockRepoCompanyRepository;
private readonly Mock<IUnitOfWork> _mockUnitOfWork;
private readonly Mock<IMemoryCache> _mockMemoryCache;
private readonly Mock<ICollectionsDao> _mockCollectionsDao;
private readonly ApiConfiguration _apiConfiguration;
private readonly SettingsService _settingsService;
public SettingsServiceTests()
{
_mockAccountTypeRepository = new Mock<IAccountTypeRepository>();
_mockAllowedStatusChangeRepository = new Mock<IAllowedStatusChangeRepository>();
_mockBodyStyleRepository = new Mock<IBodyStyleRepository>();
_mockCleaningLevelRepository = new Mock<ICleaningLevelRepository>();
_mockCollateralTypeRepository = new Mock<ICollateralTypeRepository>();
_mockCollateralTypeToVehicleTypeRepository = new Mock<ICollateralTypeToVehicleTypeRepository>();
_mockHoldStatusRepository = new Mock<IHoldStatusRepository>();
_mockLoanCategoryRepository = new Mock<ILoanCategoryRepository>();
_mockLocationTypeRepository = new Mock<ILocationTypeRepository>();
_mockVehicleTypeRepository = new Mock<IVehicleTypeRepository>();
_mockExternalUserRepository = new Mock<IExternalUserRepository>();
_mockRepoCompanyRepository = new Mock<IRepoCompanyRepository>();
_mockUnitOfWork = new Mock<IUnitOfWork>();
_mockMemoryCache = new Mock<IMemoryCache>();
_mockCollectionsDao = new Mock<ICollectionsDao>();
_apiConfiguration = new ApiConfiguration
{
SettingsCacheExpirationSeconds = 60,
TransactionTypeCodes = new List<string> { "Code1", "Code2" },
TransactionTypeCodeQueryPrefix = "Prefix",
TransactionHistoryParameterDateFormat = "yyyy-MM-dd",
TransactionHistoryStartDateOffset = 30
};
_settingsService = new SettingsService(
_mockAccountTypeRepository.Object,
_mockAllowedStatusChangeRepository.Object,
_mockBodyStyleRepository.Object,
_mockCleaningLevelRepository.Object,
_mockCollateralTypeRepository.Object,
_mockCollateralTypeToVehicleTypeRepository.Object,
_mockHoldStatusRepository.Object,
_mockLoanCategoryRepository.Object,
_mockLocationTypeRepository.Object,
_mockVehicleTypeRepository.Object,
_mockExternalUserRepository.Object,
_mockRepoCompanyRepository.Object,
_mockUnitOfWork.Object,
_mockMemoryCache.Object,
_mockCollectionsDao.Object,
_apiConfiguration
);
}
[Fact]
public async Task GetCachedRepoSettingsAsync_ShouldReturnSettings_WhenCacheIsEmpty()
{
// Arrange
var cacheEntryMock = new Mock<ICacheEntry>();
_mockMemoryCache
.Setup(mc => mc.CreateEntry(It.IsAny<object>()))
.Returns(cacheEntryMock.Object);
_mockAccountTypeRepository.Setup(repo => repo.ListAllAsync())
.ReturnsAsync(new List<AccountType> { new AccountType { ID = 1, AccountTypeCode = "AT1" } });
// Act
var result = await _settingsService.GetCachedRepoSettingsAsync();
// Assert
Assert.NotNull(result);
Assert.NotEmpty(result.AccountTypes);
}
[Fact]
public async Task SaveAsync_ShouldSaveAccountType()
{
// Arrange
var accountType = new AccountType { ID = 1, AccountTypeCode = "AT1" };
// Act
var result = await _settingsService.SaveAsync(accountType);
// Assert
_mockAccountTypeRepository.Verify(repo => repo.AddAsync(accountType), Times.Once);
_mockUnitOfWork.Verify(uow => uow.CompleteAsync(), Times.Once);
Assert.Equal(accountType, result);
}
[Fact]
public async Task SaveAsync_ShouldThrowException_WhenRepositoryFails()
{
// Arrange
var accountType = new AccountType { ID = 1, AccountTypeCode = "AT1" };
_mockAccountTypeRepository.Setup(repo => repo.AddAsync(accountType))
.ThrowsAsync(new Exception("Repository failure"));
// Act & Assert
await Assert.ThrowsAsync<RepoApi.Old_Repo_Exceptions.ServerErrorException>(() => _settingsService.SaveAsync(accountType));
}
[Fact]
public async Task UpdateAsync_ShouldUpdateAccountType()
{
// Arrange
var accountType = new AccountType { ID = 1, AccountTypeCode = "AT1", Description = "Updated" };
_mockAccountTypeRepository.Setup(repo => repo.FindByIdAsync(accountType.ID))
.ReturnsAsync(new AccountType { ID = 1, AccountTypeCode = "AT1" });
// Act
var result = await _settingsService.UpdateAsync(accountType);
// Assert
_mockAccountTypeRepository.Verify(repo => repo.Update(It.IsAny<AccountType>()), Times.Once);
_mockUnitOfWork.Verify(uow => uow.CompleteAsync(), Times.Once);
Assert.Equal(accountType.Description, result.Description);
}
[Fact]
public async Task UpdateAsync_ShouldThrowNotFoundException_WhenAccountTypeDoesNotExist()
{
// Arrange
var accountType = new AccountType { ID = 1, AccountTypeCode = "AT1" };
_mockAccountTypeRepository.Setup(repo => repo.FindByIdAsync(accountType.ID))
.ReturnsAsync((AccountType)null);
// Act & Assert
await Assert.ThrowsAsync<RepoApi.Old_Repo_Exceptions.NotFoundException> (() => _settingsService.UpdateAsync(accountType));
}
}
}
@@ -0,0 +1,2 @@
global using Xunit;
global using Moq;