From a347b2f5b1678af492c176cb70dc5c3fd57fca8e Mon Sep 17 00:00:00 2001 From: Wodan Date: Wed, 19 Oct 2022 14:31:47 +0200 Subject: [PATCH] feat: or-1244 create repository for elastic (testablity) --- .../Projections/ElasticEventHandler.cs | 34 ++++---- .../Projections/ElasticRepository.cs | 25 ++++++ .../Projections/IElasticRepository.cs | 7 ++ src/AssociationRegistry.Public.Api/Startup.cs | 2 +- .../ElasticRepositoryFixture.cs | 86 +++++++++++++++++++ .../Given_A_Valid_VerenigingDocument.cs | 41 +++++++++ .../Fixtures/PublicElasticFixture.cs | 2 +- 7 files changed, 176 insertions(+), 21 deletions(-) create mode 100644 src/AssociationRegistry.Public.Api/Projections/ElasticRepository.cs create mode 100644 src/AssociationRegistry.Public.Api/Projections/IElasticRepository.cs create mode 100644 test/AssociationRegistry.Test/Projections.Tests/When_Saving_A_Document_To_Elastic/ElasticRepositoryFixture.cs create mode 100644 test/AssociationRegistry.Test/Projections.Tests/When_Saving_A_Document_To_Elastic/Given_A_Valid_VerenigingDocument.cs diff --git a/src/AssociationRegistry.Public.Api/Projections/ElasticEventHandler.cs b/src/AssociationRegistry.Public.Api/Projections/ElasticEventHandler.cs index d618c341b..b7590a879 100644 --- a/src/AssociationRegistry.Public.Api/Projections/ElasticEventHandler.cs +++ b/src/AssociationRegistry.Public.Api/Projections/ElasticEventHandler.cs @@ -2,34 +2,30 @@ namespace AssociationRegistry.Public.Api.Projections; using System.Linq; using Events; -using Nest; using SearchVerenigingen; public class ElasticEventHandler { - private readonly IElasticClient _elasticClient; + private readonly IElasticRepository _elasticRepository; private readonly IVerenigingBrolFeeder _brolFeeder; - public ElasticEventHandler(IElasticClient elasticClient, IVerenigingBrolFeeder brolFeeder) + public ElasticEventHandler(IElasticRepository elasticRepository, IVerenigingBrolFeeder brolFeeder) { - _elasticClient = elasticClient; + _elasticRepository = elasticRepository; _brolFeeder = brolFeeder; } public void HandleEvent(VerenigingWerdGeregistreerd message) - { - var document = new VerenigingDocument( - message.VCode, - message.Naam, - _brolFeeder.KorteNaam, - _brolFeeder.Hoofdlocatie, - _brolFeeder.Locaties.ToArray(), - _brolFeeder.Hoofdactiviteiten, - _brolFeeder.Doelgroep, - _brolFeeder.Activiteiten.ToArray()); - var response = _elasticClient.IndexDocument(document); - - if (!response.IsValid) - throw new IndexDocumentFailed(response.DebugInformation); - } + => _elasticRepository.Save( + new VerenigingDocument( + message.VCode, + message.Naam, + _brolFeeder.KorteNaam, + _brolFeeder.Hoofdlocatie, + _brolFeeder.Locaties.ToArray(), + _brolFeeder.Hoofdactiviteiten, + _brolFeeder.Doelgroep, + _brolFeeder.Activiteiten.ToArray() + ) + ); } diff --git a/src/AssociationRegistry.Public.Api/Projections/ElasticRepository.cs b/src/AssociationRegistry.Public.Api/Projections/ElasticRepository.cs new file mode 100644 index 000000000..fd755c04f --- /dev/null +++ b/src/AssociationRegistry.Public.Api/Projections/ElasticRepository.cs @@ -0,0 +1,25 @@ +namespace AssociationRegistry.Public.Api.Projections; + +using Nest; + +public class ElasticRepository : IElasticRepository +{ + private readonly IElasticClient _elasticClient; + + public ElasticRepository(IElasticClient elasticClient) + { + _elasticClient = elasticClient; + } + + public void Save(TDocument document) + where TDocument : class + { + var response = _elasticClient.IndexDocument(document); + + if (!response.IsValid) + { + // todo: log ? (should never happen in test/staging/production) + throw new IndexDocumentFailed(response.DebugInformation); + } + } +} diff --git a/src/AssociationRegistry.Public.Api/Projections/IElasticRepository.cs b/src/AssociationRegistry.Public.Api/Projections/IElasticRepository.cs new file mode 100644 index 000000000..145d6afbd --- /dev/null +++ b/src/AssociationRegistry.Public.Api/Projections/IElasticRepository.cs @@ -0,0 +1,7 @@ +namespace AssociationRegistry.Public.Api.Projections; + +public interface IElasticRepository +{ + void Save(TDocument document) + where TDocument : class; +} diff --git a/src/AssociationRegistry.Public.Api/Startup.cs b/src/AssociationRegistry.Public.Api/Startup.cs index 8f5f89a09..2f6d59342 100755 --- a/src/AssociationRegistry.Public.Api/Startup.cs +++ b/src/AssociationRegistry.Public.Api/Startup.cs @@ -100,7 +100,7 @@ public IServiceProvider ConfigureServices(IServiceCollection services) opts.Events.StreamIdentity = StreamIdentity.AsString; - var esEventHandler = new ElasticEventHandler(elasticClient, new VerenigingBrolFeeder()); + var esEventHandler = new ElasticEventHandler(new ElasticRepository(elasticClient), new VerenigingBrolFeeder()); opts.Projections.Add( new MartenSubscription( diff --git a/test/AssociationRegistry.Test/Projections.Tests/When_Saving_A_Document_To_Elastic/ElasticRepositoryFixture.cs b/test/AssociationRegistry.Test/Projections.Tests/When_Saving_A_Document_To_Elastic/ElasticRepositoryFixture.cs new file mode 100644 index 000000000..a27f8cfd4 --- /dev/null +++ b/test/AssociationRegistry.Test/Projections.Tests/When_Saving_A_Document_To_Elastic/ElasticRepositoryFixture.cs @@ -0,0 +1,86 @@ +namespace AssociationRegistry.Test.Projections.Tests.When_Saving_A_Document_To_Elastic; + +using System.Reflection; +using AssociationRegistry.Public.Api; +using AssociationRegistry.Public.Api.Projections; +using AssociationRegistry.Public.Api.SearchVerenigingen; +using Microsoft.Extensions.Configuration; +using Nest; + +public abstract class ElasticRepositoryFixture : IDisposable +{ + private readonly string _identifier; + private readonly IConfigurationRoot _configurationRoot; + private readonly ElasticClient _elasticClient; + public ElasticRepository ElasticRepository { get; } + + private string VerenigingenIndexName + => _configurationRoot["ElasticClientOptions:Indices:Verenigingen"]; + + protected ElasticRepositoryFixture(string identifier) + { + _identifier += "_" + identifier.ToLowerInvariant(); + GoToRootDirectory(); + + _configurationRoot = SetConfigurationRoot(); + + _elasticClient = ConfigureElasticClient(); + + ElasticRepository = new ElasticRepository(_elasticClient); + } + + private static void GoToRootDirectory() + { + var maybeRootDirectory = Directory + .GetParent(typeof(Startup).GetTypeInfo().Assembly.Location)?.Parent?.Parent?.Parent?.FullName; + if (maybeRootDirectory is not { } rootDirectory) + throw new NullReferenceException("Root directory cannot be null"); + Directory.SetCurrentDirectory(rootDirectory); + } + + private IConfigurationRoot SetConfigurationRoot() + { + var builder = new ConfigurationBuilder() + .SetBasePath(Directory.GetCurrentDirectory()) + .AddJsonFile("appsettings.json", optional: true) + .AddJsonFile($"appsettings.{Environment.MachineName.ToLowerInvariant()}.json", optional: true); + var tempConfiguration = builder.Build(); + tempConfiguration["PostgreSQLOptions:database"] += _identifier; + tempConfiguration["ElasticClientOptions:Indices:Verenigingen"] += _identifier; + return tempConfiguration; + } + + private ElasticClient ConfigureElasticClient() + { + var settings = new ConnectionSettings(new Uri(_configurationRoot["ElasticClientOptions:Uri"])) + .BasicAuthentication( + _configurationRoot["ElasticClientOptions:Username"], + _configurationRoot["ElasticClientOptions:Password"]) + .DefaultMappingFor( + typeof(VerenigingDocument), + descriptor => descriptor.IndexName(VerenigingenIndexName)) + .EnableDebugMode(); + + var client = new ElasticClient(settings); + if (client.Indices.Exists(VerenigingenIndexName).Exists) + client.Indices.Delete(VerenigingenIndexName); + + client.Indices.Create( + VerenigingenIndexName, + c => c + .Map( + m => m + .AutoMap())); + + client.Indices.Refresh(Indices.All); + return client; + } + + public void Dispose() + { + GC.SuppressFinalize(this); + + _elasticClient.Indices.Delete(VerenigingenIndexName); + _elasticClient.Indices.Refresh(Indices.All); + } +} diff --git a/test/AssociationRegistry.Test/Projections.Tests/When_Saving_A_Document_To_Elastic/Given_A_Valid_VerenigingDocument.cs b/test/AssociationRegistry.Test/Projections.Tests/When_Saving_A_Document_To_Elastic/Given_A_Valid_VerenigingDocument.cs new file mode 100644 index 000000000..fb6dbc769 --- /dev/null +++ b/test/AssociationRegistry.Test/Projections.Tests/When_Saving_A_Document_To_Elastic/Given_A_Valid_VerenigingDocument.cs @@ -0,0 +1,41 @@ +namespace AssociationRegistry.Test.Projections.Tests.When_Saving_A_Document_To_Elastic; + +using AssociationRegistry.Public.Api.SearchVerenigingen; +using AutoFixture; +using Xunit; + +public class Given_A_Valid_VerenigingDocument_Fixture : ElasticRepositoryFixture +{ + public Given_A_Valid_VerenigingDocument_Fixture() : base(nameof(Given_A_Valid_VerenigingDocument_Fixture)) + { + } +} + +public class Given_A_Valid_VerenigingDocument : IClassFixture +{ + private readonly Given_A_Valid_VerenigingDocument_Fixture _classFixture; + + public Given_A_Valid_VerenigingDocument(Given_A_Valid_VerenigingDocument_Fixture classFixture) + { + _classFixture = classFixture; + } + + [Fact] + public void Then_it_does_not_throw_an_exception() + { + var fixture = new Fixture(); + + _classFixture.ElasticRepository + .Save( + new VerenigingDocument( + fixture.Create(), + fixture.Create(), + fixture.Create(), + fixture.Create(), + new[] { fixture.Create() }, + new[] { fixture.Create() }, + fixture.Create(), + new[] { fixture.Create() } + )); + } +} diff --git a/test/AssociationRegistry.Test/Public.Api.IntegrationTests/Fixtures/PublicElasticFixture.cs b/test/AssociationRegistry.Test/Public.Api.IntegrationTests/Fixtures/PublicElasticFixture.cs index a344fc1e8..0b835a2f6 100644 --- a/test/AssociationRegistry.Test/Public.Api.IntegrationTests/Fixtures/PublicElasticFixture.cs +++ b/test/AssociationRegistry.Test/Public.Api.IntegrationTests/Fixtures/PublicElasticFixture.cs @@ -145,7 +145,7 @@ private ElasticClient ConfigureElasticClient() private DocumentStore ConfigureDocumentStore() { - var esEventHandler = new ElasticEventHandler(_elasticClient, new BrolFeederStub()); + var esEventHandler = new ElasticEventHandler(new ElasticRepository(_elasticClient), new BrolFeederStub()); return DocumentStore.For( opts =>