From c35bcdad90acc94225be093c018954ef51fd1585 Mon Sep 17 00:00:00 2001 From: Stevan Freeborn <65925598+StevanFreeborn@users.noreply.github.com> Date: Sun, 25 Aug 2024 17:08:44 -0500 Subject: [PATCH] feat: implement cleaning up table --- .../Integration/DatabaseMaintainerTests.cs | 8 +++-- .../Integration/EfUnitOfWorkTests.cs | 15 ++++++++-- .../Integration/SdnRepositoryTests.cs | 29 +++++++++++++++++++ .../Unit/EfUnitOfWorkTests.cs | 17 +++++++++-- .../Interfaces/IDatabaseMaintainer.cs | 1 + .../Interfaces/ISdnRepository.cs | 1 + .../Models/DatabaseMaintainer.cs | 21 ++++++++++++++ .../Persistence/EfUnitOfWork.cs | 8 +++-- .../Persistence/SdnRepository.cs | 4 +++ .../Workers/DatabaseWorker.cs | 1 + 10 files changed, 96 insertions(+), 9 deletions(-) diff --git a/src/SanctionsSearch.Worker.Tests/Integration/DatabaseMaintainerTests.cs b/src/SanctionsSearch.Worker.Tests/Integration/DatabaseMaintainerTests.cs index 653be14..a2d538f 100644 --- a/src/SanctionsSearch.Worker.Tests/Integration/DatabaseMaintainerTests.cs +++ b/src/SanctionsSearch.Worker.Tests/Integration/DatabaseMaintainerTests.cs @@ -36,9 +36,11 @@ public class DatabaseMaintainerTests : DatabaseTest, IDisposable _ofacFileServiceOptions ); - var uow = new EfUnitOfWork(_context, _loggerFactory); - var logger = _loggerFactory.CreateLogger(); - _databaseMaintainer = new DatabaseMaintainer(uow, ofacFileService, logger); + var uowLogger = _loggerFactory.CreateLogger(); + var dbMaintainerLogger = _loggerFactory.CreateLogger(); + + var uow = new EfUnitOfWork(_context, uowLogger, _loggerFactory); + _databaseMaintainer = new DatabaseMaintainer(uow, ofacFileService, dbMaintainerLogger); } [Fact] diff --git a/src/SanctionsSearch.Worker.Tests/Integration/EfUnitOfWorkTests.cs b/src/SanctionsSearch.Worker.Tests/Integration/EfUnitOfWorkTests.cs index 2ce61f3..b1481fc 100644 --- a/src/SanctionsSearch.Worker.Tests/Integration/EfUnitOfWorkTests.cs +++ b/src/SanctionsSearch.Worker.Tests/Integration/EfUnitOfWorkTests.cs @@ -10,9 +10,10 @@ public class EfUnitOfWorkTests : DatabaseTest public EfUnitOfWorkTests() { - var logger = LoggerFactory.Create(c => c.ClearProviders()); + var loggerFactory = LoggerFactory.Create(c => c.ClearProviders()); + var logger = loggerFactory.CreateLogger(); - _uow = new(_context, logger); + _uow = new(_context, logger, loggerFactory); } [Fact] @@ -78,4 +79,14 @@ public class EfUnitOfWorkTests : DatabaseTest await action.Should().ThrowAsync(); } + + [Fact] + public void Dispose_WhenCalled_ItShouldDisposeContext() + { + _uow.Dispose(); + + var action = () => _context.SaveChangesAsync(); + + action.Should().ThrowAsync(); + } } \ No newline at end of file diff --git a/src/SanctionsSearch.Worker.Tests/Integration/SdnRepositoryTests.cs b/src/SanctionsSearch.Worker.Tests/Integration/SdnRepositoryTests.cs index 58d7d91..417eb0d 100644 --- a/src/SanctionsSearch.Worker.Tests/Integration/SdnRepositoryTests.cs +++ b/src/SanctionsSearch.Worker.Tests/Integration/SdnRepositoryTests.cs @@ -82,4 +82,33 @@ public class SdnRepositoryTests : RepositoryTest result.Should().HaveCount(1); result.First().Should().BeEquivalentTo(target); } + + [Fact] + public async Task DeleteWhereAsync_WithPredicate_ShouldDeleteEntitiesMatchingPredicate() + { + var entities = _faker.Generate(3); + var entityIds = entities.Select(x => x.Id).ToList(); + + foreach (var entity in entities) + { + await _repository.Upsert(entity); + } + + await _context.SaveChangesAsync(); + + var createdEntities = await _context.Set() + .Where(x => entityIds.Contains(x.Id)) + .ToListAsync(); + + createdEntities.Should().HaveCount(3); + + var target = entities[0]; + await _repository.DeleteWhereAsync(x => entityIds.Contains(x.Id)); + + var remainingEntities = await _context.Set() + .Where(x => entityIds.Contains(x.Id)) + .ToListAsync(); + + remainingEntities.Should().HaveCount(0); + } } \ No newline at end of file diff --git a/src/SanctionsSearch.Worker.Tests/Unit/EfUnitOfWorkTests.cs b/src/SanctionsSearch.Worker.Tests/Unit/EfUnitOfWorkTests.cs index 1bf6865..3356acd 100644 --- a/src/SanctionsSearch.Worker.Tests/Unit/EfUnitOfWorkTests.cs +++ b/src/SanctionsSearch.Worker.Tests/Unit/EfUnitOfWorkTests.cs @@ -3,12 +3,13 @@ namespace SanctionsSearch.Worker.Tests.Unit; public class EfUnitOfWorkTests { private readonly Mock _contextMock = new(); + private readonly Mock> _loggerMock = new(); private readonly Mock _loggerFactoryMock = new(); private readonly EfUnitOfWork _unitOfWork; public EfUnitOfWorkTests() { - _unitOfWork = new(_contextMock.Object, _loggerFactoryMock.Object); + _unitOfWork = new(_contextMock.Object, _loggerMock.Object, _loggerFactoryMock.Object); } [Fact] @@ -66,7 +67,19 @@ public class EfUnitOfWorkTests .Setup(x => x.DisposeAsync()) .Throws(new Exception()); - var action = _unitOfWork.DisposeAsync; + var action = async () => await _unitOfWork.DisposeAsync(); + + action.Should().NotThrowAsync(); + } + + [Fact] + public void Dispose_WhenExceptionIsThrown_ItShouldBeCaught() + { + _contextMock + .Setup(x => x.Dispose()) + .Throws(new Exception()); + + var action = _unitOfWork.Dispose; action.Should().NotThrow(); } diff --git a/src/SanctionsSearch.Worker/Interfaces/IDatabaseMaintainer.cs b/src/SanctionsSearch.Worker/Interfaces/IDatabaseMaintainer.cs index 1b031cf..fd49115 100644 --- a/src/SanctionsSearch.Worker/Interfaces/IDatabaseMaintainer.cs +++ b/src/SanctionsSearch.Worker/Interfaces/IDatabaseMaintainer.cs @@ -6,4 +6,5 @@ interface IDatabaseMaintainer Task BuildAddressTableAsync(); Task BuiltAliasTableAsync(); Task BuildCommentTableAsync(); + Task CleanupTablesAsync(); } \ No newline at end of file diff --git a/src/SanctionsSearch.Worker/Interfaces/ISdnRepository.cs b/src/SanctionsSearch.Worker/Interfaces/ISdnRepository.cs index a64d046..ed5cea6 100644 --- a/src/SanctionsSearch.Worker/Interfaces/ISdnRepository.cs +++ b/src/SanctionsSearch.Worker/Interfaces/ISdnRepository.cs @@ -2,4 +2,5 @@ namespace SanctionsSearch.Worker.Interfaces; interface ISdnRepository : IRepository { + Task DeleteWhereAsync(Expression> predicate); } \ No newline at end of file diff --git a/src/SanctionsSearch.Worker/Models/DatabaseMaintainer.cs b/src/SanctionsSearch.Worker/Models/DatabaseMaintainer.cs index 5b31c29..3597b86 100644 --- a/src/SanctionsSearch.Worker/Models/DatabaseMaintainer.cs +++ b/src/SanctionsSearch.Worker/Models/DatabaseMaintainer.cs @@ -167,6 +167,27 @@ class DatabaseMaintainer( _logger.LogInformation("Comment table built"); } + public async Task CleanupTablesAsync() + { + _logger.LogInformation("Cleaning up tables"); + + var result = await _ofacFileService.GetSdnFileAsync(); + + if (result.IsFailed) + { + _logger.LogError("Failed to get SDN file from OFAC."); + return; + } + + using var stream = result.Value; + var records = GetRecordsFromStream(stream); + var sdnIds = records.Select(s => s.Id).ToList(); + + await _unitOfWork.Sdns.DeleteWhereAsync(s => sdnIds.Contains(s.Id) == false); + + _logger.LogInformation("Tables cleaned up"); + } + public void Dispose() { _csvReaders.ForEach(csv => csv.Dispose()); diff --git a/src/SanctionsSearch.Worker/Persistence/EfUnitOfWork.cs b/src/SanctionsSearch.Worker/Persistence/EfUnitOfWork.cs index 0603caf..e688d30 100644 --- a/src/SanctionsSearch.Worker/Persistence/EfUnitOfWork.cs +++ b/src/SanctionsSearch.Worker/Persistence/EfUnitOfWork.cs @@ -1,9 +1,13 @@ namespace SanctionsSearch.Worker.Persistence; -class EfUnitOfWork(DbContext context, ILoggerFactory loggerFactory) : IUnitOfWork, IAsyncDisposable, IDisposable +class EfUnitOfWork( + DbContext context, + ILogger logger, + ILoggerFactory loggerFactory +) : IUnitOfWork, IAsyncDisposable, IDisposable { private readonly DbContext _context = context; - private readonly ILogger _logger = loggerFactory.CreateLogger(); + private readonly ILogger _logger = logger; public ISdnRepository Sdns { get; } = new SdnRepository(context, loggerFactory.CreateLogger()); public IAddressRepository Addresses { get; } = new AddressRepository(context, loggerFactory.CreateLogger()); public IAliasRepository Aliases { get; } = new AliasRepository(context, loggerFactory.CreateLogger()); diff --git a/src/SanctionsSearch.Worker/Persistence/SdnRepository.cs b/src/SanctionsSearch.Worker/Persistence/SdnRepository.cs index d52b445..b926717 100644 --- a/src/SanctionsSearch.Worker/Persistence/SdnRepository.cs +++ b/src/SanctionsSearch.Worker/Persistence/SdnRepository.cs @@ -5,4 +5,8 @@ class SdnRepository( ILogger logger ) : EfRepository(dbContext, logger), ISdnRepository { + public Task DeleteWhereAsync(Expression> predicate) + { + return _context.Set().Where(predicate).ExecuteDeleteAsync(); + } } \ No newline at end of file diff --git a/src/SanctionsSearch.Worker/Workers/DatabaseWorker.cs b/src/SanctionsSearch.Worker/Workers/DatabaseWorker.cs index 79a5d0e..246c07b 100644 --- a/src/SanctionsSearch.Worker/Workers/DatabaseWorker.cs +++ b/src/SanctionsSearch.Worker/Workers/DatabaseWorker.cs @@ -52,6 +52,7 @@ public class DatabaseWorker( await databaseMaintainer.BuildAddressTableAsync(); await databaseMaintainer.BuiltAliasTableAsync(); await databaseMaintainer.BuildCommentTableAsync(); + await databaseMaintainer.CleanupTablesAsync(); _logger.LogInformation("Database updated"); }