diff --git a/pluto-server/pom.xml b/pluto-server/pom.xml index 472a9ccd57fa97f6155baf01fcffa0ceb24ec2e0..d9f7b12ec1baaf19ab3e0742ee73b480a16a5e8a 100644 --- a/pluto-server/pom.xml +++ b/pluto-server/pom.xml @@ -29,6 +29,7 @@ <mongodb.testcontainer.version>1.15.3</mongodb.testcontainer.version> <solr.testcontainer.version>1.16.2</solr.testcontainer.version> + <elasticsearch.testcontainer.version>1.17.3</elasticsearch.testcontainer.version> </properties> <dependencies> @@ -89,6 +90,11 @@ <groupId>org.springframework.security</groupId> <artifactId>spring-security-core</artifactId> </dependency> + + <dependency> + <groupId>org.springframework.data</groupId> + <artifactId>spring-data-elasticsearch</artifactId> + </dependency> <!-- aspectJ --> <dependency> @@ -219,6 +225,12 @@ <version>${solr.testcontainer.version}</version> <scope>test</scope> </dependency> + <dependency> + <groupId>org.testcontainers</groupId> + <artifactId>elasticsearch</artifactId> + <version>${elasticsearch.testcontainer.version}</version> + <scope>test</scope> + </dependency> <!-- mongock --> <dependency> diff --git a/pluto-server/src/main/java/de/itvsh/ozg/pluto/common/elastic/ElasticsearchEventListener.java b/pluto-server/src/main/java/de/itvsh/ozg/pluto/common/elastic/ElasticsearchEventListener.java new file mode 100644 index 0000000000000000000000000000000000000000..ff485e5bae34338e2bf5361751aa86cc208c2d11 --- /dev/null +++ b/pluto-server/src/main/java/de/itvsh/ozg/pluto/common/elastic/ElasticsearchEventListener.java @@ -0,0 +1,56 @@ +package de.itvsh.ozg.pluto.common.elastic; + +import java.text.MessageFormat; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.springframework.context.event.EventListener; +import org.springframework.stereotype.Component; + +import co.elastic.clients.elasticsearch.ElasticsearchClient; +import de.itvsh.ozg.pluto.command.Command; +import de.itvsh.ozg.pluto.command.CommandService; +import de.itvsh.ozg.pluto.command.VorgangCreatedEvent; +import de.itvsh.ozg.pluto.vorgang.StatusChangedEvent; +import de.itvsh.ozg.pluto.vorgang.VorgangAssignedEvent; +import de.itvsh.ozg.pluto.vorgang.VorgangService; + +@Component +@ConditionalOnBean(ElasticsearchClient.class) +public class ElasticsearchEventListener { + @Autowired + private ElasticsearchService elasticsearchService; + + @Autowired + private CommandService commandService; + + @Autowired + private VorgangService vorgangService; + + @EventListener + public void onNewVorgang(VorgangCreatedEvent vorgangCreatedEvent) { + elasticsearchService.addVorgang(vorgangService.getById(vorgangCreatedEvent.getSource())); + + } + + @EventListener + public void onVorgangAssigned(VorgangAssignedEvent vorgangAssignedEvent) { + updateVorgang(vorgangAssignedEvent.getCommand()); + } + + @EventListener + public void onVorgangStatusChanged(StatusChangedEvent event) { + updateVorgangById(event.getSource()); + } + + private void updateVorgangById(String commandId) { + commandService.findCommand(commandId).ifPresentOrElse(this::updateVorgang, () -> { + throw new IllegalStateException(MessageFormat.format("Kein Command mit der ID {0} gefunden", commandId)); + }); + } + + void updateVorgang(Command command) { + elasticsearchService.updateVorgang(vorgangService.getById(command.getVorgangId())); + } + +} diff --git a/pluto-server/src/main/java/de/itvsh/ozg/pluto/common/elastic/ElasticsearchService.java b/pluto-server/src/main/java/de/itvsh/ozg/pluto/common/elastic/ElasticsearchService.java new file mode 100644 index 0000000000000000000000000000000000000000..9c77e47fa2fda768ab775cc5e0293e415d19286b --- /dev/null +++ b/pluto-server/src/main/java/de/itvsh/ozg/pluto/common/elastic/ElasticsearchService.java @@ -0,0 +1,21 @@ +package de.itvsh.ozg.pluto.common.elastic; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import de.itvsh.ozg.pluto.vorgang.Vorgang; + +@Service +public class ElasticsearchService { + @Autowired + private ElasticsearchVorgangRepostitory vorgangRepostitory; + + public void addVorgang(Vorgang vorgang) { + vorgangRepostitory.save(vorgang); + } + + public void updateVorgang(Vorgang vorgang) { + vorgangRepostitory.save(vorgang); + } + +} diff --git a/pluto-server/src/main/java/de/itvsh/ozg/pluto/common/elastic/ElasticsearchVorgangRepostitory.java b/pluto-server/src/main/java/de/itvsh/ozg/pluto/common/elastic/ElasticsearchVorgangRepostitory.java new file mode 100644 index 0000000000000000000000000000000000000000..4b1bf2d96004196187280f4dc32a866c1059dae2 --- /dev/null +++ b/pluto-server/src/main/java/de/itvsh/ozg/pluto/common/elastic/ElasticsearchVorgangRepostitory.java @@ -0,0 +1,11 @@ +package de.itvsh.ozg.pluto.common.elastic; + +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.elasticsearch.repository.ElasticsearchRepository; + +import de.itvsh.ozg.pluto.vorgang.Vorgang; + +interface ElasticsearchVorgangRepostitory extends ElasticsearchRepository<Vorgang, String> { + Page<Vorgang> findByAktenzeichen(String aktenzeichen, Pageable pageable); +} diff --git a/pluto-server/src/test/java/de/itvsh/ozg/pluto/common/elastic/ElasticsearchEventListenerTest.java b/pluto-server/src/test/java/de/itvsh/ozg/pluto/common/elastic/ElasticsearchEventListenerTest.java new file mode 100644 index 0000000000000000000000000000000000000000..8dd93df468bae6c75839b5c8d00f5d4a5e18fd87 --- /dev/null +++ b/pluto-server/src/test/java/de/itvsh/ozg/pluto/common/elastic/ElasticsearchEventListenerTest.java @@ -0,0 +1,103 @@ +package de.itvsh.ozg.pluto.common.elastic; + +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.*; + +import java.util.Optional; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; + +import de.itvsh.ozg.pluto.command.Command; +import de.itvsh.ozg.pluto.command.CommandService; +import de.itvsh.ozg.pluto.command.CommandTestFactory; +import de.itvsh.ozg.pluto.command.VorgangCreatedEvent; +import de.itvsh.ozg.pluto.vorgang.StatusChangedEvent; +import de.itvsh.ozg.pluto.vorgang.Vorgang; +import de.itvsh.ozg.pluto.vorgang.VorgangAssignedEvent; +import de.itvsh.ozg.pluto.vorgang.VorgangService; +import de.itvsh.ozg.pluto.vorgang.VorgangTestFactory; + +class ElasticsearchEventListenerTest { + + @InjectMocks + private ElasticsearchEventListener eventListener; + + @Mock + private ElasticsearchService elasticsearchService; + + @Mock + private CommandService commandService; + + @Mock + private VorgangService vorgangService; + + private Vorgang vorgang; + + @BeforeEach + void init() { + vorgang = VorgangTestFactory.create(); + } + + @Nested + class TestOnNewVorgang { + @Mock + private VorgangCreatedEvent vorgangCreatedEvent; + + @Test + void onNewVorgangTest() { + when(vorgangCreatedEvent.getSource()).thenReturn(VorgangTestFactory.ID); + when(vorgangService.getById(anyString())).thenReturn(vorgang); + + eventListener.onNewVorgang(vorgangCreatedEvent); + + verify(elasticsearchService).addVorgang(any()); + } + } + + @Nested + class TestOnVorgangAssigned { + @Mock + private VorgangAssignedEvent vorgangAssignedEvent; + + @BeforeEach + void init() { + Command command = CommandTestFactory.create(); + when(vorgangAssignedEvent.getCommand()).thenReturn(command); + + when(vorgangService.getById(anyString())).thenReturn(vorgang); + } + + @Test + void shouldUpdateVorgang() { + eventListener.onVorgangAssigned(vorgangAssignedEvent); + + verify(elasticsearchService).updateVorgang(any()); + } + } + + @Nested + class TestOnUpdatedVorgang { + @Mock + private StatusChangedEvent vorgangUpdatedEvent; + + @BeforeEach + void init() { + when(vorgangUpdatedEvent.getSource()).thenReturn("commandId"); + Command command = CommandTestFactory.create(); + when(commandService.findCommand(anyString())).thenReturn(Optional.of(command)); + + when(vorgangService.getById(anyString())).thenReturn(vorgang); + } + + @Test + void shouldUpdateVorgangInSolr() { + eventListener.onVorgangStatusChanged(vorgangUpdatedEvent); + + verify(elasticsearchService).updateVorgang(any()); + } + } +} diff --git a/pluto-server/src/test/java/de/itvsh/ozg/pluto/common/elastic/ElasticsearchIndexerEnabledInitializer.java b/pluto-server/src/test/java/de/itvsh/ozg/pluto/common/elastic/ElasticsearchIndexerEnabledInitializer.java new file mode 100644 index 0000000000000000000000000000000000000000..a8024d2e5cd6f395b19758c019423d7f7614aa2a --- /dev/null +++ b/pluto-server/src/test/java/de/itvsh/ozg/pluto/common/elastic/ElasticsearchIndexerEnabledInitializer.java @@ -0,0 +1,14 @@ +package de.itvsh.ozg.pluto.common.elastic; + +import org.springframework.boot.test.util.TestPropertyValues; +import org.springframework.context.ConfigurableApplicationContext; +import org.testcontainers.elasticsearch.ElasticsearchContainer; + +public class ElasticsearchIndexerEnabledInitializer extends ElasticsearchInitializer { + @Override + protected void setProperties(ElasticsearchContainer container, ConfigurableApplicationContext applicationContext) { + super.setProperties(container, applicationContext); + + TestPropertyValues.of("kop.elasticsearch.initEnabled=true"); + } +} diff --git a/pluto-server/src/test/java/de/itvsh/ozg/pluto/common/elastic/ElasticsearchInitializer.java b/pluto-server/src/test/java/de/itvsh/ozg/pluto/common/elastic/ElasticsearchInitializer.java new file mode 100644 index 0000000000000000000000000000000000000000..b8ed48af0743c0bbe9fdef40b657842350dd13bb --- /dev/null +++ b/pluto-server/src/test/java/de/itvsh/ozg/pluto/common/elastic/ElasticsearchInitializer.java @@ -0,0 +1,31 @@ +package de.itvsh.ozg.pluto.common.elastic; + +import org.springframework.boot.test.util.TestPropertyValues; +import org.springframework.context.ApplicationContextInitializer; +import org.springframework.context.ConfigurableApplicationContext; +import org.testcontainers.elasticsearch.ElasticsearchContainer; + +import lombok.AccessLevel; +import lombok.Getter; + +public class ElasticsearchInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> { + private static final String ELASTICSEARCH_VERSIION = "docker.elastic.co/elasticsearch/elasticsearch:8.3.2"; + @Getter(value = AccessLevel.PROTECTED) + private ElasticsearchContainer elasticsearchContainer; + + @Override + public void initialize(ConfigurableApplicationContext applicationContext) { + elasticsearchContainer = new ElasticsearchContainer(ELASTICSEARCH_VERSIION); + elasticsearchContainer.start(); + + setProperties(elasticsearchContainer, applicationContext); + } + + protected void setProperties(ElasticsearchContainer container, ConfigurableApplicationContext applicationContext) { + TestPropertyValues.of( + "kop.elasticsearch.host=" + container.getHttpHostAddress(), + "kop.elasticsearch.initEnabled=false", + "kop.elasticsearch.collectionName=test"); + } + +} diff --git a/pluto-server/src/test/java/de/itvsh/ozg/pluto/common/elastic/ElasticsearchServiceTest.java b/pluto-server/src/test/java/de/itvsh/ozg/pluto/common/elastic/ElasticsearchServiceTest.java new file mode 100644 index 0000000000000000000000000000000000000000..20973280e421d09ef644bbd7b2796fa421a8de88 --- /dev/null +++ b/pluto-server/src/test/java/de/itvsh/ozg/pluto/common/elastic/ElasticsearchServiceTest.java @@ -0,0 +1,43 @@ +package de.itvsh.ozg.pluto.common.elastic; + +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.*; + +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; + +import de.itvsh.ozg.pluto.vorgang.VorgangTestFactory; + +class ElasticsearchServiceTest { + + @InjectMocks + private ElasticsearchService elasticsearchService; + + @Mock + private ElasticsearchVorgangRepostitory repostitory; + + @Nested + class TestAddVorgang { + + @Test + void shouldCallRepository() { + elasticsearchService.addVorgang(VorgangTestFactory.create()); + + verify(repostitory).save(any()); + } + } + + @Nested + class TestUpdateVorgang { + + @Test + void shouldCallRepository() { + elasticsearchService.updateVorgang(VorgangTestFactory.create()); + + verify(repostitory).save(any()); + } + } + +}