using Microsoft.EntityFrameworkCore; using Moq; using System.Globalization; using System.Text; using TechTalk.SpecFlow; using TechTalk.SpecFlow.Assist; using TechTalk.SpecFlow.Assist.ValueRetrievers; using Xunit; using ReserveManagementSystemApi.ServiceClients; using ReserveManagementSystemApi.Services; using ReserveManagementSystemLib.Configuration; using ReserveManagementSystemLib.Models; using ReserveManagementSystemLib.Persistence; using ReserveManagementSystemLib.Repositories; using LCU.Library.Internal.ApiSecurity.Enums; using LCU.Library.Internal.ApiSecurity.Models; using LCU.Library.Internal.CoreApiWrapperModel.CoreModels.IndirectLoan; using LCU.Library.Internal.LcuHttpClient.HttpRequest; namespace ReserveManagementSystemApi.Tests.Features { [Binding] public sealed class ImportReadServiceSteps { // For additional details on SpecFlow step definitions see https://go.specflow.org/doc-stepdef private readonly ScenarioContext _scenarioContext; private ApiSecurityConfiguration _apiSecurityConfiguration; private ImportReadService _importReadService; private LoanRepository _loanRepository; private LoanTypeRepository _loanTypeRepository; private DealerRepository _dealerRepository; private DealerService _dealerService; private Mock _mockAuditHistRepo; private Mock _mockExportService; private LoanService _loanService; private ImportRepository _importRepository; private ImportService _importService; private AppDbContext _appDbContext; private Import _importResult; private Exception _exception; private string _importFileName; private StreamReader _importStreamReader; private List _loansResult; private List _dealersResult; private List _loanDetailsFromDNA; private List _closedLoansFromDNA; private Mock _mockCoreApiConfiguration; private Mock _mockgetRequest; private Mock _mockpostRequest; private Mock _mockputRequest; public ImportReadServiceSteps(ScenarioContext scenarioContext) { _scenarioContext = scenarioContext; Service.Instance.ValueRetrievers.Register(new NullValueRetriever("")); } [BeforeScenario] public void CreateDatabase() { var options = new DbContextOptionsBuilder() .UseInMemoryDatabase(Guid.NewGuid().ToString()) .Options; _apiSecurityConfiguration = new ApiSecurityConfiguration(ApiKeyAuthenticationFailureBehavior.Warn); _mockCoreApiConfiguration = new Mock(); _mockCoreApiConfiguration.Object.ApiTimeOutInSeconds = "420"; _mockpostRequest = new Mock(); _mockputRequest = new Mock(); _mockgetRequest = new Mock(); _appDbContext = new AppDbContext(options); _loanRepository = new LoanRepository(_appDbContext); _loanTypeRepository = new LoanTypeRepository(_appDbContext); _dealerRepository = new DealerRepository(_appDbContext); _importRepository = new ImportRepository(_appDbContext); _mockAuditHistRepo = new Mock(); _mockExportService = new Mock(); _dealerService = new DealerService(_dealerRepository); _loanService = new LoanService(_loanRepository, _loanTypeRepository, new AuditHistoryService(_mockAuditHistRepo.Object), new Mock().Object); _importService = new ImportService(_importRepository); _importReadService = new ImportReadService( _loanService, _importService, _dealerService, _mockExportService.Object, new CoreApiServiceClient(_apiSecurityConfiguration, _mockCoreApiConfiguration.Object, _mockgetRequest.Object, _mockpostRequest.Object, _mockputRequest.Object), new Mock().Object ); } [AfterScenario] public void DisposeAppDbContext() { _appDbContext.Database.EnsureDeleted(); _appDbContext.Dispose(); } [Given(@"an import file named ""(.*)"" that contains")] public void GivenAnImportFileNamedThatContains(string fileName, string fileContent) { _importFileName = fileName; var byteArray = Encoding.UTF8.GetBytes(fileContent); var stream = new MemoryStream(byteArray); _importStreamReader = new StreamReader(stream); } [Given(@"that I get these closed loans back from DNA")] public void GivenThatIGetTheseClosedLoansBackFromDNA(Table table) { _closedLoansFromDNA = table.CreateSet().ToList(); } [Given(@"an import from DNA that contains")] public void GivenAnImportFromDNAThatContains(Table table) { _loanDetailsFromDNA = table.CreateSet().ToList(); } [Given(@"a loan table consisting of")] public void GivenALoanTableConsistingOf(Table table) { var loans = table.CreateSet().ToList(); _appDbContext.Loans.AddRange(loans); _appDbContext.SaveChanges(); } [Given(@"a loan type table consisting of")] public void GivenALoanTypeTableConsistingOf(Table table) { var types = table.CreateSet().ToList(); _appDbContext.LoanTypes.AddRange(types); _appDbContext.SaveChanges(); } [Given(@"dealers that look like")] public void GivenDealersThatLookLike(Table table) { var dealers = table.CreateSet().ToList(); _appDbContext.Dealers.AddRange(dealers); _appDbContext.SaveChanges(); } [Given(@"the current vehicle for loanId (.*) is")] public void GivenTheCurrentVehicleForLoanIdIs(int loanId, Table table) { var vehicle = table.CreateInstance(); vehicle.LoanId = loanId; _appDbContext.Vehicles.Add(vehicle); _appDbContext.SaveChanges(); } [When(@"I read this new loan import file at ""(.*)""")] public async void WhenIReadThisNewLoanImportFileAt(DateTime currentTime) { try { _importResult = await _importReadService.ReadNewLoanImportFile(_importStreamReader, _importFileName, currentTime); } catch (Exception ex) { _exception = ex; } } [When(@"I process this DNA new/updated loan import at ""(.*)""")] public async void WhenIReadThisNewDNALoanImportFileAt(DateTime currentTime) { try { _importResult = await _importReadService.ProcessActiveLoanImport(_loanDetailsFromDNA, currentTime); } catch (Exception ex) { _exception = ex; } } [When(@"I process this DNA new/updated loan import at ""(.*)"" and skip the export")] public async void WhenIProcessThisDNANewUpdatedLoanImportAtAndSkipTheExport(DateTime currentTime) { try { _importResult = await _importReadService.ProcessActiveLoanImport(_loanDetailsFromDNA, currentTime, true); } catch (Exception ex) { _exception = ex; } } [When(@"I process the closed loan import from DNA at ""(.*)""")] public async void WhenIReadTheClosedLoanImportFromDNAAt(DateTime currentTime) { try { _importResult = await _importReadService.ProcessClosedLoanImport(_closedLoansFromDNA, currentTime, string.Empty); } catch (Exception ex) { _exception = ex; } } [When(@"I process the closed loan import with missing loan ""(.*)"" with date from DNA at ""(.*)"" and select from ""(.*)""")] public async void WhenIProcessTheClosedLoanImportWithMissingLoanWithDateFromDNAAt(string missingLoanNumber, DateTime currentTime, DateTime newerThan) { try { var stringDate = newerThan.ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture); _importResult = await _importReadService.ProcessClosedLoanImport(_closedLoansFromDNA.Where(l => l.LoanNumber != missingLoanNumber).ToList(), currentTime, stringDate); } catch (Exception ex) { _exception = ex; } } [When(@"I process the missing active loans with detail from DNA at ""(.*)"" and export")] public async void WhenIProcessTheMissingActiveLoansWithDetailFromDNAAtAndExport(DateTime currentTime) { try { _importResult = await _importReadService.ProcessClosedLoansWithUpdates(_loanDetailsFromDNA, currentTime, false); } catch (Exception ex) { _exception = ex; } } [When(@"I process the closed loan import with detail from DNA at ""(.*)""")] public async void WhenIReadTheInitialClosedLoanImportFromDNAAt(DateTime currentTime) { try { _importResult = await _importReadService.ProcessClosedLoansWithUpdates(_loanDetailsFromDNA, currentTime, false); } catch (Exception ex) { _exception = ex; } } [When(@"I process the closed loan import with detail from DNA at ""(.*)"" and skip the export")] public async void WhenIReadTheInitialClosedLoanImportFromDNAAtAndSkipTheExport(DateTime currentTime) { try { _importResult = await _importReadService.ProcessClosedLoansWithUpdates(_loanDetailsFromDNA, currentTime, true); } catch (Exception ex) { _exception = ex; } } [When(@"I read this closed loan import file at ""(.*)""")] public async void WhenIReadThisClosedLoanImportFileAt(DateTime currentTime) { try { _importResult = await _importReadService.ReadClosedLoanImportFile(_importStreamReader, _importFileName, currentTime); } catch (Exception ex) { _exception = ex; } } [When(@"I get the record from the ImportTable")] public async void WhenIGetTheRecordFromTheImportTable() { _importResult = (await _importRepository.GetAll().ToListAsync()).First(); } [Then(@"the import has start date ""(.*)""")] public void ThenTheImportHasStartDate(DateTime startDate) { Assert.Equal(startDate, _importResult.StartDate); } [Then(@"the import has an end date that is greater or equal to the start date")] public void ThenTheImportHasAnEndDateThatIsGreaterOrEqualToTheStartDate() { Assert.True(_importResult.EndDate >= _importResult.StartDate); } [Then(@"the import has record count (.*)")] public void ThenTheImportHasRecordCount(int recordCount) { Assert.Equal(recordCount, _importResult.RecordCount); } [Then(@"the import has success ""(.*)""")] public void ThenTheImportHasSuccess(bool success) { Assert.Equal(success, _importResult.Success); } [Then(@"the import has file name ""(.*)""")] public void ThenTheImportHasFileName(string fileName) { Assert.Equal(fileName, _importResult.FileName); } [Then(@"an exception is thrown")] public void ThenAnExceptionIsThrown() { Assert.NotNull(_exception); } [Then(@"the import looks like")] public void ThenTheImportLooksLike(Table table) { table.CompareToInstance(_importResult); } [Then(@"there is a record added to the Audit History table")] public void ThenThereIsARecordAddedToTheAuditHistoryTable() { _mockAuditHistRepo.Verify(x => x.AddHistoriesAsync(It.IsAny>())); } [Then(@"no audit history record is added")] public void ThenNoAuditHistoryRecordIsAdded() { _mockAuditHistRepo.Verify(x => x.AddHistoriesAsync(It.IsAny>()), Times.Never); } [Then(@"AddHistoriesAsync is called with (.*) history/ies having OldValue ""(.*)"" and NewValue ""(.*)""")] public void ThenAddHistoriesAsyncIsCalledWithHistoryIesHavingOldValueAndNewValue(int number, string oldValue, string newValue) { _mockAuditHistRepo.Verify(x => x.AddHistoriesAsync(It.Is>(a => a.Count(x => x.NewValue == newValue && x.OldValue == oldValue) == number))); } [Then(@"AddHistoriesAsync is called with (.*) history/ies having ActivityType ""(.*)"" and AuditDescription ""(.*)""")] public void ThenAddHistoriesAsyncIsCalledWithHistoryHavingActivityTypeAndAuditDescription(int number, string type, string description) { _mockAuditHistRepo.Verify(x => x.AddHistoriesAsync(It.Is>(a => a.Count(x => x.ActivityType == type && x.AuditDescription == description) == number))); } [Then(@"AddHistoriesAsync is called with (.*) history/ies having LoanNumber ""(.*)"" and MemberNumber ""(.*)""")] public void ThenAddHistoriesAsyncIsCalledWithHistoryHavingLoanNumberAndMemberNumber(int number, string loanNumber, string memberNumber) { _mockAuditHistRepo.Verify(x => x.AddHistoriesAsync(It.Is>(a => a.Count(x => x.MemberNumber == memberNumber && x.LoanNumber == loanNumber) == number))); } [Then(@"ExportChargebacksAsync is called")] public void ThenExportChargebacksAsyncIsCalled() { _mockExportService.Verify(x => x.ExportChargebacksAsync(It.IsAny())); } [Then(@"ExportChargebacksAsync is not called")] public void ThenExportChargebacksAsyncIsNotCalled() { _mockExportService.Verify(x => x.ExportChargebacksAsync(It.IsAny()), Times.Never); } [Then(@"MarkReservesAndChargebacksAsExportedAsync is called")] public void ThenMarkReservesAndChargebacksAsExportedAsyncIsCalled() { _mockExportService.Verify(x => x.MarkReservesAndChargebacksAsExportedAsync(It.IsAny>(), It.IsAny())); } [Then(@"all loans have non-null ExportedChargebackDate")] public void ThenAllLoansHaveNon_NullExportedChargebackDate() { Assert.DoesNotContain(_loansResult, l => l.ExportedChargebackDate == null); } [Then(@"ExportReservesAsync is called")] public void ThenExportReservesAsyncIsCalled() { _mockExportService.Verify(x => x.ExportReservesAsync(It.IsAny())); } [Then(@"ExportReservesAsync is not called")] public void ThenExportReservesAsyncIsNotCalled() { _mockExportService.Verify(x => x.ExportReservesAsync(It.IsAny()), Times.Never); } [Then(@"MarkReservesAsExportedAsync is called")] public void ThenMarkReservesAsExportedAsyncIsCalled() { _mockExportService.Verify(x => x.MarkReservesAsExportedAsync(It.IsAny>(), It.IsAny())); } [Then(@"all loans have non-null ExportedReserveDate")] public void ThenAllLoansHaveNon_NullExportedReserveDate() { Assert.DoesNotContain(_loansResult, l => l.ExportedReserveDate == null); } [Then(@"the loans now look like")] public async void ThenTheLoansNowLookLike(Table table) { _loansResult = await _loanRepository.GetAll().AsNoTracking().ToListAsync(); table.CompareToSet(_loansResult); } [Then(@"the dealers now look like")] public async void ThenTheDealersNowLookLike(Table table) { _dealersResult = await _dealerRepository.GetAll().ToListAsync(); table.CompareToSet(_dealersResult); } [Then(@"the vehicle for LoanId (.*) looks like this")] public void ThenTheVehicleForLoanIdLooksLikeThis(int loanId, Table table) { var result = _loansResult.FirstOrDefault(v => v.LoanId == loanId)?.Vehicle; table.CompareToInstance(result); } [Then(@"the vehicle for LoanId (.*) is null")] public void ThenTheVehicleForLoanIdIsNull(int loanId) { Assert.Null(_loansResult.FirstOrDefault(v => v.LoanId == loanId).Vehicle); } [Then(@"the loans with details now look like")] public void ThenTheLoansWithDetailsNowLookLike(Table table) { var loans = table.CreateInstance(); _loansResult.Add(loans); } } }