diff --git a/docs/src/features/basisdaten-service/index.md b/docs/src/features/basisdaten-service/index.md index 4c396f926..4d643bbe7 100644 --- a/docs/src/features/basisdaten-service/index.md +++ b/docs/src/features/basisdaten-service/index.md @@ -18,6 +18,28 @@ Folgende Services werden zum Betrieb benötigt: - EAI-Service - Infomanagement-Service +## Datenmodell + +```mermaid + +classDiagram + Wahltermindaten + Wahlbezirk + Wahlvorschläge + Referendumvorlagen + Kopfdaten + + Wahltermindaten --> Wahlbezirk : uses + Wahltermindaten --> Kopfdaten : uses + Wahltermindaten --> Wahlvorschläge : uses + Wahltermindaten --> Referendumvorlagen : uses + + class Wahltermindaten { + <> + LocalDate wahltag + } +``` + ## Handbuch In dem Service werden Handbücher verwaltet. Je Wahl und Wahlbezirkart kann ein Handbuch hinterlegt werden. @@ -29,6 +51,51 @@ Bei dem Handbuch soll es sich um ein PDF-Dokument handeln. Für Wahltage können Listen mit ungültigen Wahlscheinen verwaltet werden. Die Übermittlung der Daten erfolgt im csv-Format. Dieses umfasst eine Headerzeile, gefolgt von den Daten in den Spalten Name, Vorname und Nummer. +## Wahltermindaten + +Wahltermindaten sind eine virtuelle Zusammenfassung von Daten zu einem Wahltermin. + +Über den Service können diese Daten für einen Wahltag erstellt und gelöscht werden. Die zu erstellenden Daten +werden von dem EAI-Service importiert. + +### Ablauf des Imports + +```mermaid + +sequenceDiagram + + box BasisdatenService + participant WahltermindatenService + participant WahltagService + participant AsyncWahltermindatenService + end + box EAIService + participant Basisdaten + participant Wahlvorschlaege + participant Referendumvorlagen + end + + WahltermindatenService ->>+ WahltagService: request für Wahltag mit ID + WahltagService -->>- WahltermindatenService: Wahltag + + WahltermindatenService ->>+ Basisdaten : request Basisdaten für Wahltag + Basisdaten -->>- WahltermindatenService : Basisdaten + + WahltermindatenService ->> WahltermindatenService : Speichere Wahlen aus Basisdaten + WahltermindatenService ->> WahltermindatenService : Speicher Wahlbezirke der Basisdaten + WahltermindatenService ->> WahltermindatenService : Speicher Kopfdaten der Basisdaten + + WahltermindatenService -->> AsyncWahltermindatenService : Starte Initialisierung der
Wahlvorschläge und Referendumvorlagen + + AsyncWahltermindatenService ->>+ Wahlvorschlaege : lade request Wahlvorschläge für Bezirke der Wahlen + Wahlvorschlaege -->>- AsyncWahltermindatenService : Wahlvorschläge + AsyncWahltermindatenService ->> AsyncWahltermindatenService : speichere Wahlvorschläge + + AsyncWahltermindatenService ->>+ Referendumvorlagen : request Referendumvorlagen für Bezirke der Wahlen + Referendumvorlagen -->>- AsyncWahltermindatenService : Referendumvorlagen + AsyncWahltermindatenService ->> AsyncWahltermindatenService : speichere Referendumvorlagen +``` + ## Konfigurationsparameter Alle Konfigurationsparameter beginnen mit `service.config` @@ -36,4 +103,8 @@ Alle Konfigurationsparameter beginnen mit `service.config` | Name | Beschreibung | Default | | ---- |---------------------------------------------------| ------- | | ungueltigewahlscheine.filenamesuffix | Dateinamenssuffix für die ungueltigen Wahlscheine | Ungueltigews.csv | -| manual.filenamesuffix | Dateinamenssuffix für das Handbuch | Handbuch.pdf | \ No newline at end of file +| manual.filenamesuffix | Dateinamenssuffix für das Handbuch | Handbuch.pdf | +| async.corePoolSize | core Poolsize von ThreadPoolTaskExecutor | 2 | +| async.maxPoolSize | max Poolsize von ThreadPoolTaskExecutor | 2 | +| async.queueCapacity | Kapazität für Queue von ThreadPoolTaskExecutor | 500 | +| async.threadNamePrefix | Prefix für Threads von ThreadPoolTaskExecutor | taskExecutor- | \ No newline at end of file diff --git a/stack/keycloak/migration/add-authorities-basisdaten-wahltermindaten.yml b/stack/keycloak/migration/add-authorities-basisdaten-wahltermindaten.yml new file mode 100644 index 000000000..880d04d95 --- /dev/null +++ b/stack/keycloak/migration/add-authorities-basisdaten-wahltermindaten.yml @@ -0,0 +1,21 @@ +id: add authorities basisdaten wahltermindaten +author: MrSebastian +realm: ${SSO_REALM} +changes: + - addRole: + name: Basisdaten_BUSINESSACTION_PutWahltermindaten + clientRole: true + clientId: ${SSO_CLIENT_ID} + - assignRoleToGroup: + group: allBasisdatenAuthorities + role: Basisdaten_BUSINESSACTION_PutWahltermindaten + clientId: ${SSO_CLIENT_ID} + + - addRole: + name: Basisdaten_BUSINESSACTION_DeleteWahltermindaten + clientRole: true + clientId: ${SSO_CLIENT_ID} + - assignRoleToGroup: + group: allBasisdatenAuthorities + role: Basisdaten_BUSINESSACTION_DeleteWahltermindaten + clientId: ${SSO_CLIENT_ID} \ No newline at end of file diff --git a/stack/keycloak/migration/keycloak-changelog.yml b/stack/keycloak/migration/keycloak-changelog.yml index 5c6ebe284..27ee19839 100644 --- a/stack/keycloak/migration/keycloak-changelog.yml +++ b/stack/keycloak/migration/keycloak-changelog.yml @@ -43,3 +43,4 @@ includes: - path: create-group-all-vorfaelleundvorkommnisse-authorities.yml - path: add-authorities-vorfaelleundvorkommnisse.yml - path: add-authorities-eai-ergebnismeldung.yml + - path: add-authorities-basisdaten-wahltermindaten.yml diff --git a/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/clients/DummyClientImpl.java b/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/clients/DummyClientImpl.java index 9db72eb6a..cb620195a 100644 --- a/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/clients/DummyClientImpl.java +++ b/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/clients/DummyClientImpl.java @@ -9,6 +9,7 @@ import de.muenchen.oss.wahllokalsystem.basisdatenservice.domain.wahlen.Wahlart; import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.common.StimmzettelgebietsartModel; import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.common.WahlbezirkArtModel; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.common.WahltagWithNummer; import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.kopfdaten.BasisdatenModel; import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.kopfdaten.BasisstrukturdatenModel; import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.kopfdaten.KonfigurierterWahltagClient; @@ -24,7 +25,6 @@ import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.wahlbezirke.WahlbezirkeClient; import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.wahlen.WahlModel; import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.wahlen.WahlenClient; -import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.wahlen.WahltagWithNummer; import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.wahltag.WahltagModel; import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.wahltag.WahltageClient; import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.wahlvorschlag.KandidatModel; @@ -77,9 +77,11 @@ public List getWahlen(final WahltagWithNummer wahltagWithNummer) thro @Override public ReferendumvorlagenModel getReferendumvorlagen(ReferendumvorlagenReferenceModel referendumvorlagenReferenceModel) { return new ReferendumvorlagenModel("stimmzettelgebietID", Set.of(new ReferendumvorlageModel("wahlvorschlagID1", 1L, "kurzname1", "frage1", - Set.of(new ReferendumoptionModel("optionID11", "option11", 1L), new ReferendumoptionModel("optionID12", "option12", 2L))), + Set.of(new ReferendumoptionModel("optionID11" + UUID.randomUUID(), "option11", 1L), + new ReferendumoptionModel("optionID12" + UUID.randomUUID(), "option12", 2L))), new ReferendumvorlageModel("wahlvorschlagID2", 2L, "kurzname2", "frage2", - Set.of(new ReferendumoptionModel("optionID21", "option21", 1L), new ReferendumoptionModel("optionID22", "option22", 2L))))); + Set.of(new ReferendumoptionModel("optionID21" + UUID.randomUUID(), "option21", 1L), + new ReferendumoptionModel("optionID22" + UUID.randomUUID(), "option22", 2L))))); } @Override diff --git a/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/clients/WahldatenClientImpl.java b/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/clients/WahldatenClientImpl.java index 9db35c2d2..22465b569 100644 --- a/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/clients/WahldatenClientImpl.java +++ b/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/clients/WahldatenClientImpl.java @@ -4,9 +4,9 @@ import de.muenchen.oss.wahllokalsystem.basisdatenservice.eai.aou.client.WahldatenControllerApi; import de.muenchen.oss.wahllokalsystem.basisdatenservice.eai.aou.model.BasisdatenDTO; import de.muenchen.oss.wahllokalsystem.basisdatenservice.exception.ExceptionConstants; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.common.WahltagWithNummer; import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.kopfdaten.BasisdatenModel; import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.kopfdaten.WahldatenClient; -import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.wahlen.WahltagWithNummer; import de.muenchen.oss.wahllokalsystem.wls.common.exception.WlsException; import de.muenchen.oss.wahllokalsystem.wls.common.exception.util.ExceptionFactory; import lombok.RequiredArgsConstructor; diff --git a/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/clients/WahlenClientImpl.java b/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/clients/WahlenClientImpl.java index fc1e771f2..cff30cf59 100644 --- a/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/clients/WahlenClientImpl.java +++ b/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/clients/WahlenClientImpl.java @@ -4,9 +4,9 @@ import de.muenchen.oss.wahllokalsystem.basisdatenservice.eai.aou.client.WahldatenControllerApi; import de.muenchen.oss.wahllokalsystem.basisdatenservice.eai.aou.model.WahlDTO; import de.muenchen.oss.wahllokalsystem.basisdatenservice.exception.ExceptionConstants; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.common.WahltagWithNummer; import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.wahlen.WahlModel; import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.wahlen.WahlenClient; -import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.wahlen.WahltagWithNummer; import de.muenchen.oss.wahllokalsystem.wls.common.exception.util.ExceptionFactory; import java.util.List; import java.util.Set; diff --git a/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/configuration/AsyncConfiguration.java b/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/configuration/AsyncConfiguration.java new file mode 100644 index 000000000..c62cb7b1e --- /dev/null +++ b/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/configuration/AsyncConfiguration.java @@ -0,0 +1,42 @@ +package de.muenchen.oss.wahllokalsystem.basisdatenservice.configuration; + +import lombok.val; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.annotation.EnableAsync; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; +import org.springframework.security.task.DelegatingSecurityContextAsyncTaskExecutor; + +@EnableAsync +@Configuration +public class AsyncConfiguration { + + @Value("${app.async.corePoolSize}") + public int corePoolSize; + + @Value("${app.async.maxPoolSize}") + public int maxPoolSize; + + @Value("${app.async.queueCapacity}") + public int queueCapacity; + + @Value("${app.async.threadNamePrefix}") + public String threadNamePrefix; + + @Bean + public ThreadPoolTaskExecutor threadPoolTaskExecutor() { + val executor = new ThreadPoolTaskExecutor(); + executor.setCorePoolSize(corePoolSize); + executor.setMaxPoolSize(maxPoolSize); + executor.setQueueCapacity(queueCapacity); + executor.setThreadNamePrefix(threadNamePrefix); + executor.initialize(); + return executor; + } + + @Bean + public DelegatingSecurityContextAsyncTaskExecutor taskExecutor(final ThreadPoolTaskExecutor threadPoolTaskExecutor) { + return new DelegatingSecurityContextAsyncTaskExecutor(threadPoolTaskExecutor); + } +} diff --git a/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/domain/referendumvorlagen/ReferendumvorlagenRepository.java b/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/domain/referendumvorlagen/ReferendumvorlagenRepository.java index 9c1abe933..adc12bc79 100644 --- a/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/domain/referendumvorlagen/ReferendumvorlagenRepository.java +++ b/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/domain/referendumvorlagen/ReferendumvorlagenRepository.java @@ -48,4 +48,7 @@ public interface ReferendumvorlagenRepository extends CrudRepository { - initKopfdata(basisstrukturdaten.wahlID(), basisstrukturdaten.wahlbezirkID(), basisdatenModel); - }); + public List initKopfdaten(BasisdatenModel basisdatenModel) { + return basisdatenModel.basisstrukturdaten() + .stream().map(basisstrukturdaten -> initKopfdata(basisstrukturdaten.wahlID(), basisstrukturdaten.wahlbezirkID(), basisdatenModel)) + .toList(); } protected KopfdatenModel initKopfdata(String wahlID, String wahlbezirkID, BasisdatenModel basisdaten) { diff --git a/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/services/kopfdaten/KopfdatenService.java b/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/services/kopfdaten/KopfdatenService.java index 7e11a3628..e8e8617c6 100644 --- a/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/services/kopfdaten/KopfdatenService.java +++ b/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/services/kopfdaten/KopfdatenService.java @@ -1,7 +1,7 @@ package de.muenchen.oss.wahllokalsystem.basisdatenservice.services.kopfdaten; import de.muenchen.oss.wahllokalsystem.basisdatenservice.domain.kopfdaten.KopfdatenRepository; -import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.wahlen.WahltagWithNummer; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.common.WahltagWithNummer; import de.muenchen.oss.wahllokalsystem.wls.common.security.domain.BezirkUndWahlID; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -20,7 +20,7 @@ public class KopfdatenService { private final WahldatenClient wahldatenClient; private final KopfdatenRepository kopfdatenRepository; private final KopfdatenModelMapper kopfdatenModelMapper; - private final InitializeKopfdaten kopfDataInitializer; + private final KopfdatenMapper kopfDataInitializer; @PreAuthorize("hasAuthority('Basisdaten_BUSINESSACTION_GetKopfdaten')") @Transactional diff --git a/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/services/kopfdaten/WahldatenClient.java b/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/services/kopfdaten/WahldatenClient.java index f47f60ff6..09309980c 100644 --- a/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/services/kopfdaten/WahldatenClient.java +++ b/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/services/kopfdaten/WahldatenClient.java @@ -1,6 +1,6 @@ package de.muenchen.oss.wahllokalsystem.basisdatenservice.services.kopfdaten; -import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.wahlen.WahltagWithNummer; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.common.WahltagWithNummer; import de.muenchen.oss.wahllokalsystem.wls.common.exception.WlsException; public interface WahldatenClient { diff --git a/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/services/wahlen/WahlenClient.java b/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/services/wahlen/WahlenClient.java index 9895c7e21..8feb22e8e 100644 --- a/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/services/wahlen/WahlenClient.java +++ b/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/services/wahlen/WahlenClient.java @@ -1,5 +1,6 @@ package de.muenchen.oss.wahllokalsystem.basisdatenservice.services.wahlen; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.common.WahltagWithNummer; import de.muenchen.oss.wahllokalsystem.wls.common.exception.WlsException; import java.util.List; diff --git a/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/services/wahlen/WahlenService.java b/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/services/wahlen/WahlenService.java index b0814cff6..b789045f5 100644 --- a/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/services/wahlen/WahlenService.java +++ b/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/services/wahlen/WahlenService.java @@ -4,6 +4,7 @@ import de.muenchen.oss.wahllokalsystem.basisdatenservice.domain.wahlen.Wahl; import de.muenchen.oss.wahllokalsystem.basisdatenservice.domain.wahlen.WahlRepository; import de.muenchen.oss.wahllokalsystem.basisdatenservice.exception.ExceptionConstants; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.common.WahltagWithNummer; import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.wahltag.WahltageService; import de.muenchen.oss.wahllokalsystem.wls.common.exception.util.ExceptionFactory; import java.util.List; diff --git a/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/services/wahltermindaten/AsyncProgress.java b/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/services/wahltermindaten/AsyncProgress.java new file mode 100644 index 000000000..a17a328b0 --- /dev/null +++ b/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/services/wahltermindaten/AsyncProgress.java @@ -0,0 +1,70 @@ +package de.muenchen.oss.wahllokalsystem.basisdatenservice.services.wahltermindaten; + +import java.time.LocalDate; +import java.time.LocalDateTime; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + +@Component +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class AsyncProgress { + + public static final Logger LOG = LoggerFactory.getLogger(AsyncProgress.class); + + private LocalDate forWahltag; + private String wahlNummer = ""; + private LocalDateTime lastStartTime; + private LocalDateTime lastFinishTime = LocalDateTime.now(); + private boolean wahlvorschlaegeLoadingActive = false; + private int wahlvorschlaegeTotal = 0; + private int wahlvorschlageFinished = 0; + private String wahlvorschlaegeNext = ""; + private boolean referendumLoadingActive = false; + private int referendumVorlagenTotal = 0; + private int referendumVorlagenFinished = 0; + private String referendumVorlagenNext = ""; + + public synchronized void incWahlvorschlaegeFinished() { + wahlvorschlageFinished++; + LOG.info("#incWahlvorschlaegeFinished: {}", wahlvorschlageFinished); + if (wahlvorschlageFinished >= getWahlvorschlaegeTotal()) { + this.setWahlvorschlaegeLoadingActive(false); + if (!this.isReferendumLoadingActive()) { + this.setLastFinishTime(LocalDateTime.now()); + } + } + } + + public synchronized void incReferendumVorlagenFinished() { + referendumVorlagenFinished++; + LOG.info("#incReferendumVorlagenFinished: {}", referendumVorlagenFinished); + if (getReferendumVorlagenFinished() >= getReferendumVorlagenTotal()) { + this.setReferendumLoadingActive(false); + if (!this.isWahlvorschlaegeLoadingActive()) { + this.setLastFinishTime(LocalDateTime.now()); + } + } + } + + public void reset(LocalDate forWahltag, String wahlNummer) { + this.forWahltag = forWahltag; + this.wahlNummer = wahlNummer; + lastStartTime = LocalDateTime.now(); + lastFinishTime = null; + wahlvorschlageFinished = 0; + wahlvorschlaegeTotal = 0; + wahlvorschlaegeLoadingActive = false; + referendumVorlagenFinished = 0; + referendumVorlagenTotal = 0; + referendumLoadingActive = false; + } + +} diff --git a/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/services/wahltermindaten/AsyncWahltermindatenService.java b/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/services/wahltermindaten/AsyncWahltermindatenService.java new file mode 100644 index 000000000..20c6577a7 --- /dev/null +++ b/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/services/wahltermindaten/AsyncWahltermindatenService.java @@ -0,0 +1,109 @@ +package de.muenchen.oss.wahllokalsystem.basisdatenservice.services.wahltermindaten; + +import de.muenchen.oss.wahllokalsystem.basisdatenservice.domain.referendumvorlagen.ReferendumvorlagenRepository; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.domain.wahlen.Wahlart; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.domain.wahlvorschlag.WahlvorschlaegeRepository; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.common.WahltagWithNummer; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.kopfdaten.BasisdatenModel; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.referendumvorlagen.ReferendumvorlagenClient; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.referendumvorlagen.ReferendumvorlagenModelMapper; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.referendumvorlagen.ReferendumvorlagenReferenceModel; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.wahlvorschlag.WahlvorschlaegeClient; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.wahlvorschlag.WahlvorschlaegeModelMapper; +import de.muenchen.oss.wahllokalsystem.wls.common.security.domain.BezirkUndWahlID; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import lombok.val; +import org.springframework.scheduling.annotation.Async; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.stereotype.Service; + +@Service +@RequiredArgsConstructor +@Slf4j +public class AsyncWahltermindatenService { + + private final AsyncProgress asyncProgress; + + private final WahlvorschlaegeClient wahlvorschlaegeClient; + private final ReferendumvorlagenClient referendumvorlagenClient; + + private final WahlvorschlaegeRepository wahlvorschlaegeRepository; + private final ReferendumvorlagenRepository referendumvorlagenRepository; + + private final WahlvorschlaegeModelMapper wahlvorschlaegeModelMapper; + private final ReferendumvorlagenModelMapper referendumvorlagenModelMapper; + + @Async + public void initVorlagenAndVorschlaege(final WahltagWithNummer wahltagWithNummer, final BasisdatenModel basisdaten) { + asyncProgress.reset(wahltagWithNummer.wahltag(), wahltagWithNummer.wahltagNummer()); + initWahlvorschlaege(basisdaten); + initReferendumvorlagen(basisdaten); + } + + private void initWahlvorschlaege(final BasisdatenModel basisdaten) { + asyncProgress.setWahlvorschlaegeTotal(basisdaten.wahlen().size() * basisdaten.wahlbezirke().size()); + asyncProgress.setWahlvorschlaegeLoadingActive(true); + + val currentAuthentication = SecurityContextHolder.getContext().getAuthentication(); + + basisdaten.wahlen().parallelStream() + .filter(wahl -> !Wahlart.VE.equals(wahl.wahlart()) && !Wahlart.BEB.equals(wahl.wahlart())) + .forEach(wahl -> basisdaten.wahlbezirke().parallelStream() + .forEach(wahlbezirk -> { + if (wahl.wahlID().equals(wahlbezirk.wahlID())) { + SecurityContextHolder.getContext().setAuthentication(currentAuthentication); + loadAndPersistWahlvorschlaege(wahl.wahlID(), wahlbezirk.wahlbezirkID(), wahlbezirk.nummer()); + SecurityContextHolder.getContext().setAuthentication(null); + } + })); + } + + private void loadAndPersistWahlvorschlaege(String wahlID, String wahlbezirk, String nummer) { + try { + log.info("#initWahlvorschlag von Wahlbezirk {}", nummer); + asyncProgress.setWahlvorschlaegeNext(nummer); + val wahlvorschlaege = wahlvorschlaegeClient.getWahlvorschlaege(new BezirkUndWahlID(wahlID, wahlbezirk)); + val wahlvorschlaegeEntity = wahlvorschlaegeModelMapper.toEntity(wahlvorschlaege); + wahlvorschlaegeRepository.save(wahlvorschlaegeEntity); + } catch (final Exception e) { + log.info("#initReferendumvorlage: Fehler bei initReferendumvortage -> möglicherweise richtiges Verhalten; Fehler:", e); + } finally { + asyncProgress.incWahlvorschlaegeFinished(); + } + } + + private void initReferendumvorlagen(final BasisdatenModel basisdaten) { + if (basisdaten.wahlen().stream().anyMatch(wahl -> Wahlart.VE.equals(wahl.wahlart()) || Wahlart.BEB.equals(wahl.wahlart()))) { + asyncProgress.setReferendumVorlagenTotal(basisdaten.wahlen().size() * basisdaten.wahlbezirke().size()); + asyncProgress.setReferendumLoadingActive(true); + } + + val currentAuthentication = SecurityContextHolder.getContext().getAuthentication(); + + basisdaten.wahlen().parallelStream() + .filter(wahl -> Wahlart.VE.equals(wahl.wahlart()) || Wahlart.BEB.equals(wahl.wahlart())) + .forEach(wahl -> basisdaten.wahlbezirke().parallelStream() + .forEach(wahlbezirk -> { + if (wahl.wahlID().equals(wahlbezirk.wahlID())) { + SecurityContextHolder.getContext().setAuthentication(currentAuthentication); + loadAndPersistReferendumvorlagen(wahl.wahlID(), wahlbezirk.wahlbezirkID(), wahlbezirk.nummer()); + SecurityContextHolder.getContext().setAuthentication(null); + } + })); + } + + private void loadAndPersistReferendumvorlagen(String wahlID, String wahlbezirk, String nummer) { + try { + log.info("#initReferendumvorlage von Wahlbezirk {}", nummer); + asyncProgress.setReferendumVorlagenNext(nummer); + val referendumvorlagen = referendumvorlagenClient.getReferendumvorlagen(new ReferendumvorlagenReferenceModel(wahlID, wahlbezirk)); + val referendumvorlagenEntity = referendumvorlagenModelMapper.toEntity(referendumvorlagen, new BezirkUndWahlID(wahlID, wahlbezirk)); + referendumvorlagenRepository.save(referendumvorlagenEntity); + } catch (final Exception e) { + log.info("#initReferendumvorlage: Fehler bei initReferendumvorlage -> möglicherweise richtiges Verhalten; Fehler:", e); + } finally { + asyncProgress.incReferendumVorlagenFinished(); + } + } +} diff --git a/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/services/wahltermindaten/WahltermindatenService.java b/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/services/wahltermindaten/WahltermindatenService.java new file mode 100644 index 000000000..637da1df1 --- /dev/null +++ b/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/services/wahltermindaten/WahltermindatenService.java @@ -0,0 +1,127 @@ +package de.muenchen.oss.wahllokalsystem.basisdatenservice.services.wahltermindaten; + +import de.muenchen.oss.wahllokalsystem.basisdatenservice.domain.kopfdaten.KopfdatenRepository; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.domain.referendumvorlagen.ReferendumvorlagenRepository; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.domain.wahlbezirke.Wahlbezirk; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.domain.wahlbezirke.WahlbezirkRepository; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.domain.wahlen.WahlRepository; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.domain.wahlvorschlag.WahlvorschlaegeRepository; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.exception.ExceptionConstants; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.common.WahltagWithNummer; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.kopfdaten.BasisstrukturdatenModel; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.kopfdaten.KopfdatenMapper; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.kopfdaten.KopfdatenModel; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.kopfdaten.KopfdatenModelMapper; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.kopfdaten.WahldatenClient; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.wahlbezirke.WahlbezirkModel; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.wahlbezirke.WahlbezirkModelMapper; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.wahlen.WahlModel; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.wahlen.WahlModelMapper; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.wahltag.WahltagModel; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.wahltag.WahltageService; +import de.muenchen.oss.wahllokalsystem.wls.common.exception.FachlicheWlsException; +import de.muenchen.oss.wahllokalsystem.wls.common.exception.util.ExceptionFactory; +import java.util.Collection; +import java.util.List; +import java.util.function.Supplier; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import lombok.val; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@RequiredArgsConstructor +@Slf4j +public class WahltermindatenService { + + private final WahltermindatenValidator wahltermindatenValidator; + private final WahltageService wahltageService; + private final WahldatenClient wahldatenClient; + + private final WahlModelMapper wahlModelMapper; + private final WahlbezirkModelMapper wahlbezirkModelMapper; + private final KopfdatenModelMapper kopfdatenModelMapper; + + private final WahlRepository wahlRepository; + private final WahlbezirkRepository wahlbezirkRepository; + private final KopfdatenRepository kopfdatenRepository; + private final WahlvorschlaegeRepository wahlvorschlaegeRepository; + private final ReferendumvorlagenRepository referendumvorlagenRepository; + private final KopfdatenMapper kopfDataInitializer; + + private final AsyncWahltermindatenService asyncWahltermindatenService; + + private final ExceptionFactory exceptionFactory; + + @PreAuthorize("hasAuthority('Basisdaten_BUSINESSACTION_PutWahltermindaten')") + @Transactional + public void putWahltermindaten(final String wahltagID) { + log.info("#putWahltermindaten"); + wahltermindatenValidator.validateParameterToInitWahltermindaten(wahltagID); + val wahltagModel = getWahltagByIdOrThrow(wahltagID, + () -> exceptionFactory.createFachlicheWlsException(ExceptionConstants.CODE_PUTWAHLTERMINDATEN_NO_WAHLTAG)); + val wahltagWithNummer = new WahltagWithNummer(wahltagModel.wahltag(), wahltagModel.nummer()); + val basisdatenModel = wahldatenClient.loadBasisdaten(wahltagWithNummer); + if (null == basisdatenModel) { + throw exceptionFactory.createFachlicheWlsException(ExceptionConstants.GET_BASISDATEN_NO_DATA); + } + + persistWahlen(basisdatenModel.wahlen().stream().toList()); + persistWahlbezirke(basisdatenModel.wahlbezirke(), basisdatenModel.wahlen()); + persistKopfdaten(kopfDataInitializer.initKopfdaten(basisdatenModel)); + + asyncWahltermindatenService.initVorlagenAndVorschlaege(wahltagWithNummer, basisdatenModel); + } + + @PreAuthorize("hasAuthority('Basisdaten_BUSINESSACTION_DeleteWahltermindaten')") + @Transactional + public void deleteWahltermindaten(final String wahltagID) { + log.info("#deleteWahltermindaten"); + wahltermindatenValidator.validateParameterToDeleteWahltermindaten(wahltagID); + val wahltag = getWahltagByIdOrThrow(wahltagID, + () -> exceptionFactory.createFachlicheWlsException(ExceptionConstants.CODE_DELETEWAHLTERMINDATEN_PARAMETER_UNVOLLSTAENDIG)); + + val basisstrukturdaten = wahldatenClient.loadBasisdaten(new WahltagWithNummer(wahltag.wahltag(), wahltag.nummer())).basisstrukturdaten(); + val wahlIDs = basisstrukturdaten.stream().map(BasisstrukturdatenModel::wahlID).toList(); + + wahlbezirkRepository.deleteByWahltag(wahltag.wahltag()); + wahlIDs.forEach((wahlID) -> { + kopfdatenRepository.deleteAllByBezirkUndWahlID_WahlID(wahlID); + wahlRepository.deleteById(wahlID); + wahlvorschlaegeRepository.deleteAllByBezirkUndWahlID_WahlID(wahlID); + referendumvorlagenRepository.deleteAllByBezirkUndWahlID_WahlID(wahlID); + }); + } + + private WahltagModel getWahltagByIdOrThrow(final String wahltagID, final Supplier wlsExceptionSupplier) { + val wahltagModel = wahltageService.getWahltage().stream() + .filter(w -> w.wahltagID().equals(wahltagID)) + .findAny(); + return wahltagModel.orElseThrow(wlsExceptionSupplier); + } + + private void persistKopfdaten(List kopfdatenModels) { + val kopfdatenEntities = kopfdatenModels.stream().map(kopfdatenModelMapper::toEntity).toList(); + kopfdatenRepository.saveAll(kopfdatenEntities); + } + + private void persistWahlen(final List wahlModelIterable) { + val wahlenEntities = wahlModelMapper.fromListOfWahlModeltoListOfWahlEntities(wahlModelIterable); + wahlRepository.saveAll(wahlenEntities); + } + + private void persistWahlbezirke(Collection wahlbezirkModelIterable, Collection wahlModels) { + val wahlbezirke = wahlbezirkModelMapper.fromListOfWahlbezirkModeltoListOfWahlbezirkEntities(wahlbezirkModelIterable); + wahlbezirke.forEach(wahlbezirkEntity -> linkFirstMatchingWahl(wahlbezirkEntity, wahlModels)); + wahlbezirkRepository.saveAll(wahlbezirke); + } + + private void linkFirstMatchingWahl(final Wahlbezirk wahlbezirk, final Collection wahlen) { + val searchedWahl = wahlen.stream().filter(wahl -> wahlbezirk.getWahlnummer().equals(wahl.nummer())).findFirst().orElse(null); + if (null != searchedWahl) { + wahlbezirk.setWahlID(searchedWahl.wahlID()); + } + } +} diff --git a/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/services/wahltermindaten/WahltermindatenValidator.java b/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/services/wahltermindaten/WahltermindatenValidator.java new file mode 100644 index 000000000..3e4f66559 --- /dev/null +++ b/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/services/wahltermindaten/WahltermindatenValidator.java @@ -0,0 +1,27 @@ +package de.muenchen.oss.wahllokalsystem.basisdatenservice.services.wahltermindaten; + +import de.muenchen.oss.wahllokalsystem.basisdatenservice.exception.ExceptionConstants; +import de.muenchen.oss.wahllokalsystem.wls.common.exception.util.ExceptionFactory; +import lombok.RequiredArgsConstructor; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Component; + +@Component +@RequiredArgsConstructor +public class WahltermindatenValidator { + + private final ExceptionFactory exceptionFactory; + + public void validateParameterToInitWahltermindaten(final String wahltagID) { + if (StringUtils.isBlank(wahltagID)) { + throw exceptionFactory.createFachlicheWlsException(ExceptionConstants.CODE_PUTWAHLTERMINDATEN_PARAMETER_UNVOLLSTAENDIG); + } + } + + public void validateParameterToDeleteWahltermindaten(final String wahltagID) { + if (StringUtils.isBlank(wahltagID)) { + throw exceptionFactory.createFachlicheWlsException(ExceptionConstants.CODE_DELETEWAHLTERMINDATEN_PARAMETER_UNVOLLSTAENDIG); + } + } + +} diff --git a/wls-basisdaten-service/src/main/resources/application.yml b/wls-basisdaten-service/src/main/resources/application.yml index 01d33e9a9..cadc2d4d5 100644 --- a/wls-basisdaten-service/src/main/resources/application.yml +++ b/wls-basisdaten-service/src/main/resources/application.yml @@ -64,6 +64,11 @@ info.application.name: @project.artifactId@ info.application.version: @project.version@ app: + async: + corePoolSize: 2 + maxPoolSize: 2 + queueCapacity: 500 + threadNamePrefix: "taskExecutor-" clients: eai: basePath: http://localhost:39146 diff --git a/wls-basisdaten-service/src/test/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/clients/DummyClientImplTest.java b/wls-basisdaten-service/src/test/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/clients/DummyClientImplTest.java index 081b99a9c..fee226728 100644 --- a/wls-basisdaten-service/src/test/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/clients/DummyClientImplTest.java +++ b/wls-basisdaten-service/src/test/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/clients/DummyClientImplTest.java @@ -1,7 +1,7 @@ package de.muenchen.oss.wahllokalsystem.basisdatenservice.clients; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.common.WahltagWithNummer; import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.kopfdaten.StimmzettelgebietModel; -import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.wahlen.WahltagWithNummer; import de.muenchen.oss.wahllokalsystem.wls.common.security.domain.BezirkUndWahlID; import java.time.LocalDate; import lombok.val; diff --git a/wls-basisdaten-service/src/test/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/clients/WahldatenClientImplTest.java b/wls-basisdaten-service/src/test/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/clients/WahldatenClientImplTest.java index 1fc1a3f9d..ac004525e 100644 --- a/wls-basisdaten-service/src/test/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/clients/WahldatenClientImplTest.java +++ b/wls-basisdaten-service/src/test/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/clients/WahldatenClientImplTest.java @@ -4,8 +4,8 @@ import de.muenchen.oss.wahllokalsystem.basisdatenservice.eai.aou.client.WahldatenControllerApi; import de.muenchen.oss.wahllokalsystem.basisdatenservice.exception.ExceptionConstants; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.common.WahltagWithNummer; import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.kopfdaten.BasisdatenModel; -import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.wahlen.WahltagWithNummer; import de.muenchen.oss.wahllokalsystem.basisdatenservice.utils.MockDataFactory; import de.muenchen.oss.wahllokalsystem.wls.common.exception.FachlicheWlsException; import de.muenchen.oss.wahllokalsystem.wls.common.exception.TechnischeWlsException; diff --git a/wls-basisdaten-service/src/test/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/clients/WahlenClientImplTest.java b/wls-basisdaten-service/src/test/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/clients/WahlenClientImplTest.java index d3ee3cb2b..fc87369da 100644 --- a/wls-basisdaten-service/src/test/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/clients/WahlenClientImplTest.java +++ b/wls-basisdaten-service/src/test/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/clients/WahlenClientImplTest.java @@ -5,8 +5,8 @@ import de.muenchen.oss.wahllokalsystem.basisdatenservice.eai.aou.client.WahldatenControllerApi; import de.muenchen.oss.wahllokalsystem.basisdatenservice.eai.aou.model.WahlDTO; import de.muenchen.oss.wahllokalsystem.basisdatenservice.exception.ExceptionConstants; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.common.WahltagWithNummer; import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.wahlen.WahlModel; -import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.wahlen.WahltagWithNummer; import de.muenchen.oss.wahllokalsystem.wls.common.exception.FachlicheWlsException; import de.muenchen.oss.wahllokalsystem.wls.common.exception.TechnischeWlsException; import de.muenchen.oss.wahllokalsystem.wls.common.exception.util.ExceptionFactory; diff --git a/wls-basisdaten-service/src/test/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/domain/ReferendumvorlagenRepositoryTest.java b/wls-basisdaten-service/src/test/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/domain/ReferendumvorlagenRepositoryTest.java new file mode 100644 index 000000000..6bcf330a9 --- /dev/null +++ b/wls-basisdaten-service/src/test/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/domain/ReferendumvorlagenRepositoryTest.java @@ -0,0 +1,97 @@ +package de.muenchen.oss.wahllokalsystem.basisdatenservice.domain; + +import static de.muenchen.oss.wahllokalsystem.basisdatenservice.TestConstants.SPRING_NO_SECURITY_PROFILE; +import static de.muenchen.oss.wahllokalsystem.basisdatenservice.TestConstants.SPRING_TEST_PROFILE; + +import de.muenchen.oss.wahllokalsystem.basisdatenservice.MicroServiceApplication; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.domain.referendumvorlagen.Referendumoption; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.domain.referendumvorlagen.Referendumvorlage; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.domain.referendumvorlagen.ReferendumvorlageRepository; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.domain.referendumvorlagen.Referendumvorlagen; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.domain.referendumvorlagen.ReferendumvorlagenRepository; +import de.muenchen.oss.wahllokalsystem.wls.common.security.domain.BezirkUndWahlID; +import java.util.HashSet; +import java.util.UUID; +import lombok.extern.slf4j.Slf4j; +import lombok.val; +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.transaction.support.TransactionTemplate; + +@SpringBootTest( + classes = { MicroServiceApplication.class }, + webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT +) +@ActiveProfiles(profiles = { SPRING_TEST_PROFILE, SPRING_NO_SECURITY_PROFILE }) +@Slf4j +class ReferendumvorlagenRepositoryTest { + + @Autowired + private ReferendumvorlagenRepository referendumvorlagenRepository; + + @Autowired + private ReferendumvorlageRepository referendumvorlageRepository; + + @Autowired + private TransactionTemplate transactionTemplate; + + @AfterEach + void tearDown() { + referendumvorlageRepository.deleteAll(); + referendumvorlagenRepository.deleteAll(); + } + + @Nested + class DeleteAllByBezirkUndWahlID_WahlID { + + @Test + void should_removeReferendumvorlagenAndChildren_when_wahlIdMatches() { + val wahlIDToDelete = "wahlID"; + + val referendumvorlagenToKeep = transactionTemplate.execute(status -> { + referendumvorlagenRepository.save(createReferendumvorlagenWithBezirkAndWahlID("wahlbezirk1", wahlIDToDelete)); + referendumvorlagenRepository.save(createReferendumvorlagenWithBezirkAndWahlID("wahlbezirk2", wahlIDToDelete)); + + return referendumvorlagenRepository.save(createReferendumvorlagenWithBezirkAndWahlID("wahlbezirk1", "wahlIDToKeep")); + }); + + transactionTemplate.executeWithoutResult(status -> referendumvorlagenRepository.deleteAllByBezirkUndWahlID_WahlID(wahlIDToDelete)); + + Assertions.assertThat(referendumvorlagenRepository.count()).isEqualTo(1); + Assertions.assertThat(referendumvorlagenRepository.existsById(referendumvorlagenToKeep.getId())).isTrue(); + + Assertions.assertThat(referendumvorlageRepository.count()).isEqualTo(referendumvorlagenToKeep.getReferendumvorlagen().size()); + referendumvorlagenToKeep.getReferendumvorlagen() + .forEach(referendumvorlage -> Assertions.assertThat(referendumvorlageRepository.existsById(referendumvorlage.getId())).isTrue()); + } + + private Referendumvorlagen createReferendumvorlagenWithBezirkAndWahlID(final String wahlbezirkID, final String wahlID) { + val referendumvorlagen = new Referendumvorlagen(); + + referendumvorlagen.setBezirkUndWahlID(new BezirkUndWahlID(wahlID, wahlbezirkID)); + referendumvorlagen.setStimmzettelgebietID(wahlID); + + referendumvorlagen.setReferendumvorlagen(new HashSet<>()); + val referendumvorlage1 = new Referendumvorlage(null, null, UUID.randomUUID().toString(), 1L, "", "", new HashSet<>()); + referendumvorlagen.addReferendumvorlage(referendumvorlage1); + val referendumvorlage2 = new Referendumvorlage(null, null, UUID.randomUUID().toString(), 1L, "", "", new HashSet<>()); + referendumvorlagen.addReferendumvorlage(referendumvorlage2); + + val referendumoption1Vorlage1 = new Referendumoption(UUID.randomUUID().toString(), "", null); + referendumvorlage1.getReferendumoptionen().add(referendumoption1Vorlage1); + val referendumoption2Vorlage1 = new Referendumoption(UUID.randomUUID().toString(), "", null); + referendumvorlage1.getReferendumoptionen().add(referendumoption2Vorlage1); + val referendumoption1Vorlage2 = new Referendumoption(UUID.randomUUID().toString(), "", null); + referendumvorlage2.getReferendumoptionen().add(referendumoption1Vorlage2); + val referendumoption2Vorlage2 = new Referendumoption(UUID.randomUUID().toString(), "", null); + referendumvorlage2.getReferendumoptionen().add(referendumoption2Vorlage2); + + return referendumvorlagen; + } + } +} diff --git a/wls-basisdaten-service/src/test/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/domain/WahlvorschlaegeRepositoryTest.java b/wls-basisdaten-service/src/test/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/domain/WahlvorschlaegeRepositoryTest.java new file mode 100644 index 000000000..6cce1f5f6 --- /dev/null +++ b/wls-basisdaten-service/src/test/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/domain/WahlvorschlaegeRepositoryTest.java @@ -0,0 +1,109 @@ +package de.muenchen.oss.wahllokalsystem.basisdatenservice.domain; + +import static de.muenchen.oss.wahllokalsystem.basisdatenservice.TestConstants.SPRING_NO_SECURITY_PROFILE; +import static de.muenchen.oss.wahllokalsystem.basisdatenservice.TestConstants.SPRING_TEST_PROFILE; + +import de.muenchen.oss.wahllokalsystem.basisdatenservice.MicroServiceApplication; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.domain.wahlvorschlag.Kandidat; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.domain.wahlvorschlag.KandidatRepository; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.domain.wahlvorschlag.Wahlvorschlaege; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.domain.wahlvorschlag.WahlvorschlaegeRepository; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.domain.wahlvorschlag.Wahlvorschlag; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.domain.wahlvorschlag.WahlvorschlagRepository; +import de.muenchen.oss.wahllokalsystem.wls.common.security.domain.BezirkUndWahlID; +import java.util.HashSet; +import lombok.extern.slf4j.Slf4j; +import lombok.val; +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.transaction.support.TransactionTemplate; + +@SpringBootTest( + classes = { MicroServiceApplication.class }, + webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT +) +@ActiveProfiles(profiles = { SPRING_TEST_PROFILE, SPRING_NO_SECURITY_PROFILE }) +@Slf4j +class WahlvorschlaegeRepositoryTest { + + @Autowired + private WahlvorschlaegeRepository wahlvorschlaegeRepository; + + @Autowired + private WahlvorschlagRepository wahlvorschlagRepository; + + @Autowired + private KandidatRepository kandidatRepository; + + @Autowired + private TransactionTemplate transactionTemplate; + + @AfterEach + void tearDown() { + kandidatRepository.deleteAll(); + wahlvorschlagRepository.deleteAll(); + wahlvorschlaegeRepository.deleteAll(); + } + + @Nested + class DeleteAllByBezirkUndWahlID_WahlID { + + @Test + void should_removeWahlvorschlaegeAndChildren_when_wahlIdMatches() { + val wahlIDToDelete = "wahlID"; + + val wahlvorschlaegeToKeep = transactionTemplate.execute(status -> { + wahlvorschlaegeRepository.save(createWahlvorschlaegeWithKandidatenWithBezirkAndWahlID("wahlbezirk1", wahlIDToDelete)); + wahlvorschlaegeRepository.save(createWahlvorschlaegeWithKandidatenWithBezirkAndWahlID("wahlbezirk2", wahlIDToDelete)); + + return wahlvorschlaegeRepository.save(createWahlvorschlaegeWithKandidatenWithBezirkAndWahlID("wahlbezirk1", "wahlIDToKeep")); + }); + + wahlvorschlaegeRepository.deleteAllByBezirkUndWahlID_WahlID(wahlIDToDelete); + + Assertions.assertThat(wahlvorschlaegeRepository.count()).isEqualTo(1); + Assertions.assertThat(wahlvorschlaegeRepository.existsById(wahlvorschlaegeToKeep.getId())).isTrue(); + + Assertions.assertThat(wahlvorschlagRepository.count()).isEqualTo(wahlvorschlaegeToKeep.getWahlvorschlaege().size()); + wahlvorschlaegeToKeep.getWahlvorschlaege() + .forEach(wahlvorschlag -> Assertions.assertThat(wahlvorschlagRepository.existsById(wahlvorschlag.getId())).isTrue()); + + val expectedCountKandidaten = wahlvorschlaegeToKeep.getWahlvorschlaege().stream() + .map(wahlvorschlag -> wahlvorschlag.getKandidaten().size()) + .mapToLong(Integer::longValue) + .sum(); + Assertions.assertThat(kandidatRepository.count()).isEqualTo(expectedCountKandidaten); + wahlvorschlaegeToKeep.getWahlvorschlaege().stream().flatMap(wahlvorschlag -> wahlvorschlag.getKandidaten().stream()) + .forEach(kandidat -> Assertions.assertThat(kandidatRepository.existsById(kandidat.getId())).isTrue()); + } + + private Wahlvorschlaege createWahlvorschlaegeWithKandidatenWithBezirkAndWahlID(final String wahlbezirkID, final String wahlID) { + val wahlvorschlaege = new Wahlvorschlaege(); + + wahlvorschlaege.setBezirkUndWahlID(new BezirkUndWahlID(wahlID, wahlbezirkID)); + wahlvorschlaege.setStimmzettelgebietID(wahlID); + + wahlvorschlaege.setWahlvorschlaege(new HashSet<>()); + val wahlvorschlag1 = new Wahlvorschlag(null, wahlbezirkID + "_" + wahlID + "_1", null, 1L, wahlID + "_1", true, new HashSet<>()); + wahlvorschlaege.addWahlvorschlag(wahlvorschlag1); + val wahlvorschlag2 = new Wahlvorschlag(null, wahlbezirkID + "_" + wahlID + "_2", null, 1L, wahlID + "_2", true, new HashSet<>()); + wahlvorschlaege.addWahlvorschlag(wahlvorschlag2); + + val kandidat1Vorschlag1 = new Kandidat(null, wahlvorschlag1.getIdentifikator() + "_1", null, "kandidat", 1L, true, 1L, true); + wahlvorschlag1.addKandidat(kandidat1Vorschlag1); + val kandidat2Vorschlag1 = new Kandidat(null, wahlvorschlag1.getIdentifikator() + "_2", null, "kandidat", 1L, true, 1L, true); + wahlvorschlag1.addKandidat(kandidat2Vorschlag1); + val kandidat1Vorschlag2 = new Kandidat(null, wahlvorschlag2.getIdentifikator() + "_1", null, "kandidat", 1L, true, 1L, true); + wahlvorschlag2.addKandidat(kandidat1Vorschlag2); + val kandidat2Vorschlag2 = new Kandidat(null, wahlvorschlag2.getIdentifikator() + "_2", null, "kandidat", 1L, true, 1L, true); + wahlvorschlag2.addKandidat(kandidat2Vorschlag2); + + return wahlvorschlaege; + } + } +} diff --git a/wls-basisdaten-service/src/test/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/rest/wahltermindaten/WahltermindatenControllerIntegrationTest.java b/wls-basisdaten-service/src/test/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/rest/wahltermindaten/WahltermindatenControllerIntegrationTest.java new file mode 100644 index 000000000..540f40e62 --- /dev/null +++ b/wls-basisdaten-service/src/test/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/rest/wahltermindaten/WahltermindatenControllerIntegrationTest.java @@ -0,0 +1,446 @@ +package de.muenchen.oss.wahllokalsystem.basisdatenservice.rest.wahltermindaten; + +import static de.muenchen.oss.wahllokalsystem.basisdatenservice.TestConstants.SPRING_NO_SECURITY_PROFILE; +import static de.muenchen.oss.wahllokalsystem.basisdatenservice.TestConstants.SPRING_TEST_PROFILE; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.github.tomakehurst.wiremock.client.WireMock; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.MicroServiceApplication; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.clients.WahldatenClientMapper; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.domain.common.WahlbezirkArt; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.domain.kopfdaten.Kopfdaten; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.domain.kopfdaten.KopfdatenRepository; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.domain.kopfdaten.Stimmzettelgebietsart; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.domain.referendumvorlagen.Referendumoption; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.domain.referendumvorlagen.Referendumvorlage; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.domain.referendumvorlagen.ReferendumvorlageRepository; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.domain.referendumvorlagen.Referendumvorlagen; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.domain.referendumvorlagen.ReferendumvorlagenRepository; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.domain.wahlbezirke.Wahlbezirk; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.domain.wahlbezirke.WahlbezirkRepository; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.domain.wahlen.Wahl; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.domain.wahlen.WahlRepository; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.domain.wahlen.Wahlart; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.domain.wahltag.Wahltag; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.domain.wahltag.WahltagRepository; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.domain.wahlvorschlag.Kandidat; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.domain.wahlvorschlag.KandidatRepository; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.domain.wahlvorschlag.Wahlvorschlaege; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.domain.wahlvorschlag.WahlvorschlaegeRepository; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.domain.wahlvorschlag.Wahlvorschlag; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.domain.wahlvorschlag.WahlvorschlagRepository; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.eai.aou.model.BasisdatenDTO; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.eai.aou.model.BasisstrukturdatenDTO; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.eai.aou.model.StimmzettelgebietDTO; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.eai.aou.model.WahlDTO; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.eai.aou.model.WahlbezirkDTO; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.eai.aou.model.WahltagDTO; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.common.WahltagWithNummer; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.wahltermindaten.AsyncWahltermindatenService; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.utils.Authorities; +import de.muenchen.oss.wahllokalsystem.wls.common.security.domain.BezirkUndWahlID; +import de.muenchen.oss.wahllokalsystem.wls.common.testing.SecurityUtils; +import java.time.LocalDate; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.UUID; +import lombok.val; +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.SpyBean; +import org.springframework.cloud.contract.wiremock.AutoConfigureWireMock; +import org.springframework.http.HttpStatus; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; + +@SpringBootTest(classes = MicroServiceApplication.class) +@AutoConfigureMockMvc +@AutoConfigureWireMock +@ActiveProfiles(profiles = { SPRING_TEST_PROFILE, SPRING_NO_SECURITY_PROFILE }) +public class WahltermindatenControllerIntegrationTest { + + @Autowired + MockMvc mockMvc; + + @Autowired + ObjectMapper objectMapper; + + @SpyBean + WahlvorschlaegeRepository wahlvorschlaegeRepository; + @Autowired + WahlvorschlagRepository wahlvorschlagRepository; + @Autowired + KandidatRepository kandidatRepository; + + @SpyBean + ReferendumvorlagenRepository referendumvorlagenRepository; + @Autowired + ReferendumvorlageRepository referendumvorlageRepository; + + @SpyBean + WahlRepository wahlRepository; + @SpyBean + WahlbezirkRepository wahlbezirkRepository; + @SpyBean + KopfdatenRepository kopfdatenRepository; + + @SpyBean + AsyncWahltermindatenService asyncWahltermindatenService; + + @Autowired + private WahltagRepository wahltagRepository; + + @Autowired + WahldatenClientMapper wahldatenClientMapper; + + @AfterEach + void tearDown() { + SecurityUtils.runWith(Authorities.REPOSITORY_DELETE_REFERENDUMVORLAGEN, Authorities.REPOSITORY_DELETE_WAHLVORSCHLAEGE, + Authorities.REPOSITORY_DELETE_WAHL, Authorities.REPOSITORY_DELETE_WAHLBEZIRK); + wahlvorschlaegeRepository.deleteAll(); + referendumvorlagenRepository.deleteAll(); + wahlbezirkRepository.deleteAll(); + wahlRepository.deleteAll(); + kopfdatenRepository.deleteAll(); + } + + @Nested + class DeleteWahltermindaten { + + private String dateStringForDelete; + private LocalDate localDateForDelete; + private Wahltag wahltagForDelete; + private Wahl wahlToDelete1; + private Wahl wahlToDelete2; + private Collection wahlbezirkeToDelete; + private Collection kopfdatenToDelete; + private Collection wahlvorschlaegeToDelete; + private Collection referendumvorlagenToDelete; + + @BeforeEach + void setup() throws Exception { + //Data that should be deleted after call + dateStringForDelete = "2013-01-01"; + localDateForDelete = LocalDate.parse(dateStringForDelete); + wahltagForDelete = wahltagRepository.save(new Wahltag("wahltagForDelete", LocalDate.parse(dateStringForDelete), null, "12")); + + wahlToDelete1 = createWahlToDelete("wahlToDelete1", localDateForDelete); + wahlToDelete2 = createWahlToDelete("wahlToDelete2", localDateForDelete); + wahlbezirkeToDelete = createWahlbezirkeToDelete(localDateForDelete, wahlToDelete1.getWahlID(), wahlToDelete2.getWahlID()); + kopfdatenToDelete = createKopfdatenToDelete(wahlbezirkeToDelete); + wahlvorschlaegeToDelete = createWahlvorschlaegeToDelete(wahlbezirkeToDelete); + referendumvorlagenToDelete = createReferendumvorlagenToDelete(wahlbezirkeToDelete); + + setupWireMockForWahltagClient(wahltagForDelete); + + setupWireMockForWahlClient(wahlToDelete1.getWahlID(), wahlToDelete2.getWahlID()); + } + + @Test + void should_deleteWahlenAndWahlbezirkeOnWahlenOfWahltag_when_wahltagIDIsGiven() throws Exception { + //Data that should be kept after the call + val localDateForDataToKeep = LocalDate.parse("2024-10-07"); + val wahlToKeep = wahlRepository.save(new Wahl(UUID.randomUUID().toString(), "wahlToKeep", 1, 1, localDateForDataToKeep, Wahlart.BTW, null, "1")); + val wahlbezirkToKeep = wahlbezirkRepository.save( + new Wahlbezirk("wahlbezirkToKeep", localDateForDataToKeep, "1", WahlbezirkArt.UWB, "1", wahlToKeep.getWahlID())); + val wahlvorschlaegeToKeep = createWahlvorschlaege(wahlToKeep.getWahlID(), wahlbezirkToKeep.getWahlbezirkID(), "3"); + val referendumvorlagenToKeep = createReferendunvorlagen(wahlToKeep.getWahlID(), wahlbezirkToKeep.getWahlbezirkID(), "3"); + val kopfdatenToKeep = kopfdatenRepository.save( + new Kopfdaten(new BezirkUndWahlID(wahlToKeep.getWahlID(), wahlbezirkToKeep.getWahlbezirkID()), "LHM", Stimmzettelgebietsart.WK, "3", + "SHZ to keep", wahlToKeep.getName(), wahlbezirkToKeep.getNummer())); + + val request = MockMvcRequestBuilders.delete("/businessActions/wahltermindaten/" + wahltagForDelete.getWahltagID()); + mockMvc.perform(request).andExpect(status().isOk()); + + //verify data to keep are not deleted + Assertions.assertThat(wahlRepository.findById(wahlToKeep.getWahlID())).isPresent(); + Assertions.assertThat(wahlbezirkRepository.findById(wahlbezirkToKeep.getWahlbezirkID())).isPresent(); + Assertions.assertThat(wahlvorschlaegeRepository.findById(wahlvorschlaegeToKeep.getId())).isPresent(); + Assertions.assertThat(referendumvorlagenRepository.findById(referendumvorlagenToKeep.getId())).isPresent(); + Assertions.assertThat(kopfdatenRepository.findById(kopfdatenToKeep.getBezirkUndWahlID())).isPresent(); + + //verify no additional data exists + val expectedCountWahlvorschlaeg = wahlvorschlaegeToKeep.getWahlvorschlaege().size(); + val expectedCountKandidaten = (Long) wahlvorschlaegeToKeep.getWahlvorschlaege().stream() + .map(vorschlag -> vorschlag.getKandidaten().size()) + .mapToLong(Integer::longValue).sum(); + val expectedCountReferendumvorlage = referendumvorlagenToKeep.getReferendumvorlagen().size(); + Assertions.assertThat(wahlRepository.count()).isEqualTo(1); + Assertions.assertThat(wahlbezirkRepository.count()).isEqualTo(1); + Assertions.assertThat(wahlvorschlaegeRepository.count()).isEqualTo(1); + Assertions.assertThat(wahlvorschlagRepository.count()).isEqualTo(expectedCountWahlvorschlaeg); + Assertions.assertThat(kandidatRepository.count()).isEqualTo(expectedCountKandidaten); + Assertions.assertThat(referendumvorlagenRepository.count()).isEqualTo(1); + Assertions.assertThat(referendumvorlageRepository.count()).isEqualTo(expectedCountReferendumvorlage); + Assertions.assertThat(kopfdatenRepository.count()).isEqualTo(1); + } + + @Test + void should_keepAllExistingData_when_deleteOfWahlbezirkeFailed() throws Exception { + Mockito.doThrow(new RuntimeException("test transactional")).when(wahlbezirkRepository).deleteByWahltag(any()); + + val request = MockMvcRequestBuilders.delete("/businessActions/wahltermindaten/" + wahltagForDelete.getWahltagID()); + mockMvc.perform(request).andExpect(status().isInternalServerError()); + + verifyNoDataForDeletionIsDeleted(wahlvorschlaegeToDelete, referendumvorlagenToDelete, wahlbezirkeToDelete, kopfdatenToDelete); + } + + @Test + void should_keepAllExistingData_when_deleteOfKopfdatenFailed() throws Exception { + Mockito.doThrow(new RuntimeException("test transactional")).when(kopfdatenRepository).deleteAllByBezirkUndWahlID_WahlID(any()); + + val request = MockMvcRequestBuilders.delete("/businessActions/wahltermindaten/" + wahltagForDelete.getWahltagID()); + mockMvc.perform(request).andExpect(status().isInternalServerError()); + + verifyNoDataForDeletionIsDeleted(wahlvorschlaegeToDelete, referendumvorlagenToDelete, wahlbezirkeToDelete, kopfdatenToDelete); + } + + @Test + void should_keepAllExistingData_when_deleteOfWahlenFailed() throws Exception { + Mockito.doThrow(new RuntimeException("test transactional")).when(wahlRepository).deleteById(any()); + + val request = MockMvcRequestBuilders.delete("/businessActions/wahltermindaten/" + wahltagForDelete.getWahltagID()); + mockMvc.perform(request).andExpect(status().isInternalServerError()); + + verifyNoDataForDeletionIsDeleted(wahlvorschlaegeToDelete, referendumvorlagenToDelete, wahlbezirkeToDelete, kopfdatenToDelete); + } + + @Test + void should_keepAllExistingData_when_deleteOfWahlvorschlaegeFailed() throws Exception { + Mockito.doThrow(new RuntimeException("test transactional")).when(wahlvorschlaegeRepository).deleteAllByBezirkUndWahlID_WahlID(any()); + + val request = MockMvcRequestBuilders.delete("/businessActions/wahltermindaten/" + wahltagForDelete.getWahltagID()); + mockMvc.perform(request).andExpect(status().isInternalServerError()); + + verifyNoDataForDeletionIsDeleted(wahlvorschlaegeToDelete, referendumvorlagenToDelete, wahlbezirkeToDelete, kopfdatenToDelete); + } + + @Test + void should_keepAllExistingData_when_deleteOfReferendumvorlagenFailed() throws Exception { + Mockito.doThrow(new RuntimeException("test transactional")).when(referendumvorlagenRepository).deleteAllByBezirkUndWahlID_WahlID(any()); + + val request = MockMvcRequestBuilders.delete("/businessActions/wahltermindaten/" + wahltagForDelete.getWahltagID()); + mockMvc.perform(request).andExpect(status().isInternalServerError()); + + verifyNoDataForDeletionIsDeleted(wahlvorschlaegeToDelete, referendumvorlagenToDelete, wahlbezirkeToDelete, kopfdatenToDelete); + } + + private void verifyNoDataForDeletionIsDeleted(Collection wahlvorschlaegeToDelete, + Collection referendumvorlagenToDelete, + Collection wahlbezirkeToDelete, Collection kopfdatenToDelete) { + val expectedCountWahlvorschlaeg = wahlvorschlaegeToDelete.stream().map(wahlvorschlaege -> wahlvorschlaege.getWahlvorschlaege().size()) + .mapToLong(Integer::longValue) + .sum(); + val expectedCountKandidaten = wahlvorschlaegeToDelete.stream() + .flatMap(wahlvorschlaege -> wahlvorschlaege.getWahlvorschlaege().stream()) + .mapToLong(wahlvorschlag -> wahlvorschlag.getKandidaten().size()) + .sum(); + val expectedCountReferendumvorlage = referendumvorlagenToDelete.stream() + .mapToLong(referendumvorlagen -> referendumvorlagen.getReferendumvorlagen().size()) + .sum(); + Assertions.assertThat(wahlRepository.count()).isEqualTo(2); + Assertions.assertThat(wahlbezirkRepository.count()).isEqualTo(wahlbezirkeToDelete.size()); + Assertions.assertThat(wahlvorschlaegeRepository.count()).isEqualTo(wahlvorschlaegeToDelete.size()); + Assertions.assertThat(wahlvorschlagRepository.count()).isEqualTo(expectedCountWahlvorschlaeg); + Assertions.assertThat(kandidatRepository.count()).isEqualTo(expectedCountKandidaten); + Assertions.assertThat(referendumvorlagenRepository.count()).isEqualTo(referendumvorlagenToDelete.size()); + Assertions.assertThat(referendumvorlageRepository.count()).isEqualTo(expectedCountReferendumvorlage); + Assertions.assertThat(kopfdatenRepository.count()).isEqualTo(kopfdatenToDelete.size()); + } + + private void setupWireMockForWahlClient(String wahlToDeleteID1, String wahlToDeleteID2) + throws JsonProcessingException { + val wahlclientResponse = new BasisdatenDTO().basisstrukturdaten( + Set.of(new BasisstrukturdatenDTO().wahlID(wahlToDeleteID1), new BasisstrukturdatenDTO().wahlID(wahlToDeleteID2))); + WireMock.stubFor(WireMock.get(WireMock.urlPathMatching("/wahldaten/basisdaten")) + .willReturn(WireMock.aResponse() + .withHeader("Content-Type", "application/json") + .withBody(objectMapper.writeValueAsString(wahlclientResponse)) + .withStatus(HttpStatus.OK.value()))); + } + + private Wahl createWahlToDelete(final String wahlID, final LocalDate wahltag) { + return wahlRepository.save(new Wahl(wahlID, wahlID, 1, 1, wahltag, Wahlart.BTW, null, "1")); + } + + private Collection createWahlbezirkeToDelete(final LocalDate wahltagDate, final String wahlToDeleteID1, final String wahlToDeleteID2) { + val wahlbezirk1ToDeleteWahl1 = wahlbezirkRepository.save( + new Wahlbezirk("wbz1_1", wahltagDate, "1", WahlbezirkArt.UWB, "1", wahlToDeleteID1)); + val wahlbezirk2ToDeleteWahl1 = wahlbezirkRepository.save( + new Wahlbezirk("wbz1_2", wahltagDate, "2", WahlbezirkArt.UWB, "1", wahlToDeleteID1)); + val wahlbezirk1ToDeleteWahl2 = wahlbezirkRepository.save( + new Wahlbezirk("wbz2_1", wahltagDate, "1", WahlbezirkArt.UWB, "2", wahlToDeleteID2)); + val wahlbezirk2ToDeleteWahl2 = wahlbezirkRepository.save( + new Wahlbezirk("wbz2_2", wahltagDate, "2", WahlbezirkArt.UWB, "2", wahlToDeleteID2)); + + return List.of(wahlbezirk1ToDeleteWahl1, wahlbezirk2ToDeleteWahl1, wahlbezirk1ToDeleteWahl2, wahlbezirk2ToDeleteWahl2); + } + + private Collection createKopfdatenToDelete(final Collection wahlbezirke) { + return wahlbezirke.stream() + .map(wahlbezirk -> kopfdatenRepository.save( + new Kopfdaten(new BezirkUndWahlID(wahlbezirk.getWahlID(), wahlbezirk.getWahlbezirkID()), "LHM", Stimmzettelgebietsart.WK, "1", + "SGZ 1_1", wahlbezirk.getWahlID(), wahlbezirk.getWahlbezirkID()))) + .toList(); + } + + private Collection createWahlvorschlaegeToDelete(final Collection wahlbezirke) { + return wahlbezirke.stream() + .map(wahlbezirk -> createWahlvorschlaege(wahlbezirk.getWahlID(), wahlbezirk.getWahlbezirkID(), wahlbezirk.getNummer())) + .toList(); + } + + private Collection createReferendumvorlagenToDelete(final Collection wahlbezirke) { + return wahlbezirke.stream() + .map(wahlbezirk -> createReferendunvorlagen(wahlbezirk.getWahlID(), wahlbezirk.getWahlbezirkID(), wahlbezirk.getNummer())) + .toList(); + } + + private Wahlvorschlaege createWahlvorschlaege(final String wahlID, final String wahlbezirkID, final String stimmzettelgebietID) { + val wahlvorschlaege = new Wahlvorschlaege(null, new BezirkUndWahlID(wahlID, wahlbezirkID), stimmzettelgebietID, new HashSet<>()); + + val wahlvorschlag1 = new Wahlvorschlag(null, UUID.randomUUID().toString(), wahlvorschlaege, 1L, wahlID + wahlbezirkID, true, + new HashSet<>()); + wahlvorschlaege.addWahlvorschlag(wahlvorschlag1); + val kandidat1Vorschlag1 = new Kandidat(null, UUID.randomUUID().toString(), wahlvorschlag1, "kandidat1", 1, false, 1L, false); + wahlvorschlag1.addKandidat(kandidat1Vorschlag1); + val kandidat2Vorschlag1 = new Kandidat(null, UUID.randomUUID().toString(), wahlvorschlag1, "kandidat1", 1, false, 1L, false); + wahlvorschlag1.addKandidat(kandidat2Vorschlag1); + + val wahlvorschlag2 = new Wahlvorschlag(null, UUID.randomUUID().toString(), wahlvorschlaege, 1L, wahlID + wahlbezirkID, true, + new HashSet<>()); + wahlvorschlaege.addWahlvorschlag(wahlvorschlag2); + val kandidat1Vorschlag2 = new Kandidat(null, UUID.randomUUID().toString(), wahlvorschlag2, "kandidat1", 1, false, 1L, false); + wahlvorschlag2.addKandidat(kandidat1Vorschlag2); + val kandidat2Vorschlag2 = new Kandidat(null, UUID.randomUUID().toString(), wahlvorschlag2, "kandidat1", 1, false, 1L, false); + wahlvorschlag2.addKandidat(kandidat2Vorschlag2); + + return wahlvorschlaegeRepository.save(wahlvorschlaege); + } + + private Referendumvorlagen createReferendunvorlagen(final String wahlID, final String wahlbezirkID, final String stimmzettelgebietID) { + val referendumvorlagen = new Referendumvorlagen(null, new BezirkUndWahlID(wahlID, wahlbezirkID), stimmzettelgebietID, new HashSet<>()); + + val referendumvorlage1 = new Referendumvorlage(null, referendumvorlagen, "1", 1L, wahlID + wahlbezirkID, "Frage 1", new HashSet<>()); + referendumvorlagen.addReferendumvorlage(referendumvorlage1); + val referendumOption1Vorlage1 = new Referendumoption(UUID.randomUUID().toString(), "Option 1", 1L); + referendumvorlage1.getReferendumoptionen().add(referendumOption1Vorlage1); + val referendumOption2Vorlage1 = new Referendumoption(UUID.randomUUID().toString(), "Option 2", 1L); + referendumvorlage1.getReferendumoptionen().add(referendumOption2Vorlage1); + + val referendumvorlage2 = new Referendumvorlage(null, referendumvorlagen, "1", 1L, wahlID + wahlbezirkID, "Frage 1", new HashSet<>()); + referendumvorlagen.addReferendumvorlage(referendumvorlage2); + val referendumOption1Vorlage2 = new Referendumoption(UUID.randomUUID().toString(), "Option 1", 1L); + referendumvorlage1.getReferendumoptionen().add(referendumOption1Vorlage2); + val referendumOption2Vorlage2 = new Referendumoption(UUID.randomUUID().toString(), "Option 2", 1L); + referendumvorlage1.getReferendumoptionen().add(referendumOption2Vorlage2); + + return referendumvorlagenRepository.save(referendumvorlagen); + } + } + + @Nested + class PutWahltermindaten { + + @Test + void should_persistImportedData_when_wahltagIDIsValidWahltag() throws Exception { + val localDateOfWahltag = LocalDate.parse("2024-08-26"); + val wahltagToGetWahltermindaten = new Wahltag("wahltagID", localDateOfWahltag, "", "1"); + + setupWireMockForWahltagClient(wahltagToGetWahltermindaten); + + val basisstrukturdatenToImport = createBasisdatenDTO(localDateOfWahltag); + + WireMock.stubFor(WireMock.get(WireMock.urlPathMatching("/wahldaten/basisdaten")) + .willReturn(WireMock.aResponse() + .withHeader("Content-Type", "application/json") + .withBody(objectMapper.writeValueAsString(basisstrukturdatenToImport)) + .withStatus(HttpStatus.OK.value()))); + + val request = MockMvcRequestBuilders.put("/businessActions/wahltermindaten/" + wahltagToGetWahltermindaten.getWahltagID()); + mockMvc.perform(request).andExpect(status().isOk()); + + Assertions.assertThat(kopfdatenRepository.count()).isEqualTo(5); + Assertions.assertThat(wahlbezirkRepository.count()).isEqualTo(5); + Assertions.assertThat(wahlRepository.count()).isEqualTo(2); + + val expectedBasisdatenModel = wahldatenClientMapper.fromRemoteClientDTOToModel(basisstrukturdatenToImport); + Mockito.verify(asyncWahltermindatenService) + .initVorlagenAndVorschlaege(eq(new WahltagWithNummer(wahltagToGetWahltermindaten.getWahltag(), wahltagToGetWahltermindaten.getNummer())), + eq(expectedBasisdatenModel)); + } + + private static BasisdatenDTO createBasisdatenDTO(LocalDate localDateOfWahltag) { + return new BasisdatenDTO() + .basisstrukturdaten( + Set.of( + new BasisstrukturdatenDTO().wahlID("wahlID1").wahltag(localDateOfWahltag).wahlbezirkID("wahlbezirkID1_1") + .stimmzettelgebietID("sgzID1"), + new BasisstrukturdatenDTO().wahlID("wahlID1").wahltag(localDateOfWahltag).wahlbezirkID("wahlbezirkID1_2") + .stimmzettelgebietID("sgzID1"), + new BasisstrukturdatenDTO().wahlID("wahlID1").wahltag(localDateOfWahltag).wahlbezirkID("wahlbezirkID1_3") + .stimmzettelgebietID("sgzID1"), + new BasisstrukturdatenDTO().wahlID("wahlID2").wahltag(localDateOfWahltag).wahlbezirkID("wahlbezirkID2_1") + .stimmzettelgebietID("sgzID2"), + new BasisstrukturdatenDTO().wahlID("wahlID2").wahltag(localDateOfWahltag).wahlbezirkID("wahlbezirkID2_2") + .stimmzettelgebietID("sgzID2"))) + .stimmzettelgebiete( + Set.of( + new StimmzettelgebietDTO().wahltag(localDateOfWahltag).name("sgz1").identifikator("sgzID1").nummer("1") + .stimmzettelgebietsart( + StimmzettelgebietDTO.StimmzettelgebietsartEnum.WK), + new StimmzettelgebietDTO().wahltag(localDateOfWahltag).name("sgz2").identifikator("sgzID2").nummer("2") + .stimmzettelgebietsart( + StimmzettelgebietDTO.StimmzettelgebietsartEnum.WK) + + )) + .wahlen( + Set.of( + new WahlDTO().name("wahl 1").wahltag(localDateOfWahltag).identifikator("wahlID1").wahlart(WahlDTO.WahlartEnum.BTW) + .nummer("1"), + new WahlDTO().name("wahl 2").wahltag(localDateOfWahltag).identifikator("wahlID2").wahlart(WahlDTO.WahlartEnum.BTW) + .nummer("2"))) + .wahlbezirke( + Set.of( + new WahlbezirkDTO().wahltag(localDateOfWahltag).wahlID("wahlID1").identifikator("wahlbezirkID1_1").nummer("1_1") + .wahlnummer("1").wahlbezirkArt( + WahlbezirkDTO.WahlbezirkArtEnum.UWB), + new WahlbezirkDTO().wahltag(localDateOfWahltag).wahlID("wahlID1").identifikator("wahlbezirkID1_2").nummer("1_2") + .wahlnummer("1").wahlbezirkArt( + WahlbezirkDTO.WahlbezirkArtEnum.UWB), + new WahlbezirkDTO().wahltag(localDateOfWahltag).wahlID("wahlID1").identifikator("wahlbezirkID1_3").nummer("1_3") + .wahlnummer("1").wahlbezirkArt( + WahlbezirkDTO.WahlbezirkArtEnum.UWB), + new WahlbezirkDTO().wahltag(localDateOfWahltag).wahlID("wahlID2").identifikator("wahlbezirkID2_1").nummer("2_1") + .wahlnummer("2").wahlbezirkArt( + WahlbezirkDTO.WahlbezirkArtEnum.UWB), + new WahlbezirkDTO().wahltag(localDateOfWahltag).wahlID("wahlID2").identifikator("wahlbezirkID2_2").nummer("2_2") + .wahlnummer("2").wahlbezirkArt( + WahlbezirkDTO.WahlbezirkArtEnum.UWB))); + } + } + + private void setupWireMockForWahltagClient(Wahltag wahltag) throws JsonProcessingException { + val wahltagClientResponse = Set.of(new WahltagDTO().identifikator(wahltag.getWahltagID()).tag(wahltag.getWahltag()) + .nummer(wahltag.getNummer())); + WireMock.stubFor(WireMock.get(WireMock.urlPathMatching("/wahldaten/wahltage")) + .willReturn(WireMock.aResponse() + .withHeader("Content-Type", "application/json") + .withBody(objectMapper.writeValueAsString(wahltagClientResponse)) + .withStatus(HttpStatus.OK.value()))); + } +} diff --git a/wls-basisdaten-service/src/test/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/rest/wahltermindaten/WahltermindatenControllerTest.java b/wls-basisdaten-service/src/test/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/rest/wahltermindaten/WahltermindatenControllerTest.java new file mode 100644 index 000000000..99922cc92 --- /dev/null +++ b/wls-basisdaten-service/src/test/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/rest/wahltermindaten/WahltermindatenControllerTest.java @@ -0,0 +1,49 @@ +package de.muenchen.oss.wahllokalsystem.basisdatenservice.rest.wahltermindaten; + +import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.wahltermindaten.WahltermindatenService; +import lombok.val; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.jupiter.MockitoExtension; + +@ExtendWith(MockitoExtension.class) +class WahltermindatenControllerTest { + + @Mock + WahltermindatenService wahltermindatenService; + + @InjectMocks + WahltermindatenController unitUnderTest; + + @Nested + class PutWahltermindaten { + + @Test + void should_callServiceWithWahltagID_when_givenWahltagID() { + val wahltagID = "wahltagID"; + + unitUnderTest.putWahltermindaten(wahltagID); + + Mockito.verify(wahltermindatenService).putWahltermindaten(wahltagID); + } + } + + @Nested + class DeleteWahltermindaten { + + @Test + void should_callServiceWahltagID_when_givenWahltagID() { + val wahltagID = "wahltagID"; + + unitUnderTest.deleteWahltermindaten(wahltagID); + + Mockito.verify(wahltermindatenService).deleteWahltermindaten(wahltagID); + } + + } + +} diff --git a/wls-basisdaten-service/src/test/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/services/kopfdaten/KopfdatenServiceTest.java b/wls-basisdaten-service/src/test/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/services/kopfdaten/KopfdatenServiceTest.java index 9931338a7..c62099993 100644 --- a/wls-basisdaten-service/src/test/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/services/kopfdaten/KopfdatenServiceTest.java +++ b/wls-basisdaten-service/src/test/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/services/kopfdaten/KopfdatenServiceTest.java @@ -5,7 +5,7 @@ import de.muenchen.oss.wahllokalsystem.basisdatenservice.domain.kopfdaten.KopfdatenRepository; import de.muenchen.oss.wahllokalsystem.basisdatenservice.domain.kopfdaten.Stimmzettelgebietsart; import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.common.StimmzettelgebietsartModel; -import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.wahlen.WahltagWithNummer; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.common.WahltagWithNummer; import de.muenchen.oss.wahllokalsystem.basisdatenservice.utils.MockDataFactory; import de.muenchen.oss.wahllokalsystem.wls.common.security.domain.BezirkUndWahlID; import java.time.LocalDate; @@ -33,7 +33,7 @@ class KopfdatenServiceTest { KopfdatenValidator kopfdatenValidator; @Mock - InitializeKopfdaten initializeKopfdaten; + KopfdatenMapper kopfdatenMapper; @Mock WahldatenClient wahldatenClient; @@ -64,7 +64,7 @@ void dataIsLoadedFromRemoteIfNotExistingInRepo() { Mockito.when(wahldatenClient.loadBasisdaten( new WahltagWithNummer(mockedKonfigurierterWahltagFromClient.wahltag(), mockedKonfigurierterWahltagFromClient.nummer()))) .thenReturn(mockedBasisdatenModelFromClient); - Mockito.when(initializeKopfdaten.initKopfdata(wahlID, wahlbezrkID, mockedBasisdatenModelFromClient)).thenReturn(mockedKopfdatenModelByInitializer); + Mockito.when(kopfdatenMapper.initKopfdata(wahlID, wahlbezrkID, mockedBasisdatenModelFromClient)).thenReturn(mockedKopfdatenModelByInitializer); val result = unitUnderTest.getKopfdaten(bezirkUndWahlId); Assertions.assertThat(result).isEqualTo(mockedKopfdatenModelByInitializer); diff --git a/wls-basisdaten-service/src/test/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/services/wahlen/WahlenServiceTest.java b/wls-basisdaten-service/src/test/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/services/wahlen/WahlenServiceTest.java index dbd816dee..cbfb7b209 100644 --- a/wls-basisdaten-service/src/test/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/services/wahlen/WahlenServiceTest.java +++ b/wls-basisdaten-service/src/test/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/services/wahlen/WahlenServiceTest.java @@ -5,6 +5,7 @@ import de.muenchen.oss.wahllokalsystem.basisdatenservice.domain.wahlen.WahlRepository; import de.muenchen.oss.wahllokalsystem.basisdatenservice.domain.wahlen.Wahlart; import de.muenchen.oss.wahllokalsystem.basisdatenservice.exception.ExceptionConstants; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.common.WahltagWithNummer; import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.wahltag.WahltagModel; import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.wahltag.WahltageService; import de.muenchen.oss.wahllokalsystem.wls.common.exception.TechnischeWlsException; diff --git a/wls-basisdaten-service/src/test/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/services/wahltermindaten/AsyncProgressTest.java b/wls-basisdaten-service/src/test/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/services/wahltermindaten/AsyncProgressTest.java new file mode 100644 index 000000000..f4cc31673 --- /dev/null +++ b/wls-basisdaten-service/src/test/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/services/wahltermindaten/AsyncProgressTest.java @@ -0,0 +1,107 @@ +package de.muenchen.oss.wahllokalsystem.basisdatenservice.services.wahltermindaten; + +import lombok.val; +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +class AsyncProgressTest { + + AsyncProgress unitUnderTest = new AsyncProgress(); + + @Nested + class IncWahlvorschlaegeFinished { + + @Test + void should_increaseNumberOfFinishedWahlvorschlaege_when_called() { + val numberOfFinisheBeforeCall = unitUnderTest.getWahlvorschlageFinished(); + unitUnderTest.incWahlvorschlaegeFinished(); + val numberOfFinishedAfterCall = unitUnderTest.getWahlvorschlageFinished(); + + Assertions.assertThat(numberOfFinishedAfterCall).isEqualTo(numberOfFinisheBeforeCall + 1); + } + + @Test + void should_keepWahlvorschlaegeActiveTrue_when_finishedIsBelowTotal() { + unitUnderTest.setWahlvorschlaegeLoadingActive(true); + unitUnderTest.setWahlvorschlaegeTotal(10); + + unitUnderTest.incWahlvorschlaegeFinished(); + + Assertions.assertThat(unitUnderTest.isWahlvorschlaegeLoadingActive()).isTrue(); + } + + @Test + void should_setWahlvorschlaegeFinishedToFalse_when_totalIsReached() { + unitUnderTest.setWahlvorschlaegeLoadingActive(true); + unitUnderTest.setWahlvorschlaegeTotal(1); + + unitUnderTest.incWahlvorschlaegeFinished(); + + Assertions.assertThat(unitUnderTest.isWahlvorschlaegeLoadingActive()).isFalse(); + } + + @Test + void should_setLastFinishTime_when_wahlvorschlaegeAndReferendumvorlagenAreDone() { + unitUnderTest.setWahlvorschlaegeLoadingActive(true); + unitUnderTest.setReferendumLoadingActive(false); + unitUnderTest.setWahlvorschlaegeTotal(1); + unitUnderTest.setLastFinishTime(null); + + unitUnderTest.incWahlvorschlaegeFinished(); + + Assertions.assertThat(unitUnderTest.getLastFinishTime()).isNotNull(); + } + } + + @Nested + class IncReferendumVorlagenFinished { + + @Test + void should_increaseNumberOfFinishedReferendumvorlagen_when_called() { + val numberOfFinisheBeforeCall = unitUnderTest.getReferendumVorlagenFinished(); + unitUnderTest.incReferendumVorlagenFinished(); + val numberOfFinishedAfterCall = unitUnderTest.getReferendumVorlagenFinished(); + + Assertions.assertThat(numberOfFinishedAfterCall).isEqualTo(numberOfFinisheBeforeCall + 1); + } + + @Test + void should_keepReferndumvorlagenFinishedActiveTrue_when_finishedIsBelowTotal() { + unitUnderTest.setReferendumLoadingActive(true); + unitUnderTest.setReferendumVorlagenTotal(10); + + unitUnderTest.incReferendumVorlagenFinished(); + + Assertions.assertThat(unitUnderTest.isReferendumLoadingActive()).isTrue(); + } + + @Test + void should_setReferndumvorlagenFinishedToFalse_when_totalIsReached() { + unitUnderTest.setReferendumLoadingActive(true); + unitUnderTest.setReferendumVorlagenTotal(1); + + unitUnderTest.incReferendumVorlagenFinished(); + + Assertions.assertThat(unitUnderTest.isReferendumLoadingActive()).isFalse(); + } + + @Test + void should_setLastFinishTime_when_wahlvorschlaegeAndReferendumvorlagenAreDone() { + unitUnderTest.setWahlvorschlaegeLoadingActive(false); + unitUnderTest.setReferendumLoadingActive(true); + unitUnderTest.setWahlvorschlaegeTotal(1); + unitUnderTest.setLastFinishTime(null); + + unitUnderTest.incReferendumVorlagenFinished(); + + Assertions.assertThat(unitUnderTest.getLastFinishTime()).isNotNull(); + } + } + + @Nested + class Reset { + + } + +} diff --git a/wls-basisdaten-service/src/test/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/services/wahltermindaten/AsyncWahltermindatenServiceTest.java b/wls-basisdaten-service/src/test/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/services/wahltermindaten/AsyncWahltermindatenServiceTest.java new file mode 100644 index 000000000..59b4571d8 --- /dev/null +++ b/wls-basisdaten-service/src/test/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/services/wahltermindaten/AsyncWahltermindatenServiceTest.java @@ -0,0 +1,207 @@ +package de.muenchen.oss.wahllokalsystem.basisdatenservice.services.wahltermindaten; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.times; + +import de.muenchen.oss.wahllokalsystem.basisdatenservice.domain.referendumvorlagen.Referendumvorlagen; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.domain.referendumvorlagen.ReferendumvorlagenRepository; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.domain.wahlen.Wahlart; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.domain.wahlvorschlag.Wahlvorschlaege; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.domain.wahlvorschlag.WahlvorschlaegeRepository; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.common.WahlbezirkArtModel; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.common.WahltagWithNummer; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.kopfdaten.BasisdatenModel; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.referendumvorlagen.ReferendumvorlagenClient; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.referendumvorlagen.ReferendumvorlagenModel; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.referendumvorlagen.ReferendumvorlagenModelMapper; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.wahlbezirke.WahlbezirkModel; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.wahlen.WahlModel; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.wahlvorschlag.WahlvorschlaegeClient; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.wahlvorschlag.WahlvorschlaegeModel; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.wahlvorschlag.WahlvorschlaegeModelMapper; +import java.time.LocalDate; +import java.util.Collections; +import java.util.Set; +import lombok.val; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.jupiter.MockitoExtension; + +@ExtendWith(MockitoExtension.class) +class AsyncWahltermindatenServiceTest { + + @Mock + AsyncProgress asyncProgress; + + @Mock + WahlvorschlaegeClient wahlvorschlaegeClient; + @Mock + ReferendumvorlagenClient referendumvorlagenClient; + + @Mock + WahlvorschlaegeRepository wahlvorschlaegeRepository; + @Mock + ReferendumvorlagenRepository referendumvorlagenRepository; + + @Mock + WahlvorschlaegeModelMapper wahlvorschlaegeModelMapper; + @Mock + ReferendumvorlagenModelMapper referendumvorlagenModelMapper; + + @InjectMocks + AsyncWahltermindatenService unitUnderTest; + + @Nested + class InitVorlagenAndVorschlaege { + + @Test + void should_resetProgress_when_methodIsCalled() { + val wahltagDate = LocalDate.now(); + val wahltagNummer = "wahltagNummer"; + val basisdatenModel = createEmptyBasisdatenModel(); + + unitUnderTest.initVorlagenAndVorschlaege(new WahltagWithNummer(wahltagDate, wahltagNummer), basisdatenModel); + + Mockito.verify(asyncProgress).reset(wahltagDate, wahltagNummer); + } + + @Test + void should_persistWahlvorschlaege_when_basisdatenAreDelivered() { + val wahltagDate = LocalDate.now(); + val wahltagNummer = "wahltagNummer"; + val basisdatenModel = createBasisdatenModelWith2WahlenAnd2WahlbezirkeForEachWahl(wahltagDate, Wahlart.BTW); + + val mockedWahlvorschlaegeClientResponse = WahlvorschlaegeModel.builder().build(); + val mockedWahlvorschlaegeModelMappedAsEntity = new Wahlvorschlaege(); + + Mockito.when(wahlvorschlaegeClient.getWahlvorschlaege(any())).thenReturn(mockedWahlvorschlaegeClientResponse); + Mockito.when(wahlvorschlaegeModelMapper.toEntity(mockedWahlvorschlaegeClientResponse)).thenReturn(mockedWahlvorschlaegeModelMappedAsEntity); + + unitUnderTest.initVorlagenAndVorschlaege(new WahltagWithNummer(wahltagDate, wahltagNummer), basisdatenModel); + + Mockito.verify(wahlvorschlaegeRepository, times(4)).save(mockedWahlvorschlaegeModelMappedAsEntity); + Mockito.verify(asyncProgress, times(4)).incWahlvorschlaegeFinished(); + Mockito.verify(asyncProgress, times(4)).setWahlvorschlaegeNext(any()); + } + + @Test + void should_increaseWahlvorstandProgressEven_when_savingFailed() { + val wahltagDate = LocalDate.now(); + val wahltagNummer = "wahltagNummer"; + val basisdatenModel = createBasisdatenModelWith2WahlenAnd2WahlbezirkeForEachWahl(wahltagDate, Wahlart.BTW); + + val mockedWahlvorschlaegeClientResponse = WahlvorschlaegeModel.builder().build(); + val mockedWahlvorschlaegeModelMappedAsEntity = new Wahlvorschlaege(); + + Mockito.when(wahlvorschlaegeClient.getWahlvorschlaege(any())).thenReturn(mockedWahlvorschlaegeClientResponse); + Mockito.when(wahlvorschlaegeModelMapper.toEntity(mockedWahlvorschlaegeClientResponse)).thenReturn(mockedWahlvorschlaegeModelMappedAsEntity); + Mockito.doThrow(new RuntimeException("saving failed")).when(wahlvorschlaegeRepository).save(mockedWahlvorschlaegeModelMappedAsEntity); + + unitUnderTest.initVorlagenAndVorschlaege(new WahltagWithNummer(wahltagDate, wahltagNummer), basisdatenModel); + + Mockito.verify(asyncProgress, times(4)).incWahlvorschlaegeFinished(); + Mockito.verify(asyncProgress, times(4)).setWahlvorschlaegeNext(any()); + } + + @Test + void should_increaseWahlvorstandProgressEven_when_loadingWahlvorschlaegeFromClientFailed() { + val wahltagDate = LocalDate.now(); + val wahltagNummer = "wahltagNummer"; + val basisdatenModel = createBasisdatenModelWith2WahlenAnd2WahlbezirkeForEachWahl(wahltagDate, Wahlart.BTW); + + Mockito.doThrow(new RuntimeException("getting data from client failed")).when(wahlvorschlaegeClient).getWahlvorschlaege(any()); + + unitUnderTest.initVorlagenAndVorschlaege(new WahltagWithNummer(wahltagDate, wahltagNummer), basisdatenModel); + + Mockito.verify(asyncProgress, times(4)).incWahlvorschlaegeFinished(); + Mockito.verify(asyncProgress, times(4)).setWahlvorschlaegeNext(any()); + } + + @Test + void should_persistReferendumvorlagen_when_basisdatenAreDelivered() { + val wahltagDate = LocalDate.now(); + val wahltagNummer = "wahltagNummer"; + val basisdatenModel = createBasisdatenModelWith2WahlenAnd2WahlbezirkeForEachWahl(wahltagDate, Wahlart.BEB); + + val mockedReferendumvorlagenClientResponse = createEmptyReferendumvorlagenModel(); + val mockedReferendumvorlagenModelMappedAsEntity = new Referendumvorlagen(); + + Mockito.when(referendumvorlagenClient.getReferendumvorlagen(any())).thenReturn(mockedReferendumvorlagenClientResponse); + Mockito.when(referendumvorlagenModelMapper.toEntity(eq(mockedReferendumvorlagenClientResponse), any())) + .thenReturn(mockedReferendumvorlagenModelMappedAsEntity); + + unitUnderTest.initVorlagenAndVorschlaege(new WahltagWithNummer(wahltagDate, wahltagNummer), basisdatenModel); + + Mockito.verify(referendumvorlagenRepository, times(4)).save(mockedReferendumvorlagenModelMappedAsEntity); + Mockito.verify(asyncProgress, times(4)).incReferendumVorlagenFinished(); + Mockito.verify(asyncProgress, times(4)).setReferendumVorlagenNext(any()); + } + + @Test + void should_increaseReferendumvorlagenProgressEven_when_savingFailed() { + val wahltagDate = LocalDate.now(); + val wahltagNummer = "wahltagNummer"; + val basisdatenModel = createBasisdatenModelWith2WahlenAnd2WahlbezirkeForEachWahl(wahltagDate, Wahlart.BEB); + + val mockedReferendumvorlagenClientResponse = createEmptyReferendumvorlagenModel(); + val mockedReferendumvorlagenModelMappedAsEntity = new Referendumvorlagen(); + + Mockito.when(referendumvorlagenClient.getReferendumvorlagen(any())).thenReturn(mockedReferendumvorlagenClientResponse); + Mockito.when(referendumvorlagenModelMapper.toEntity(eq(mockedReferendumvorlagenClientResponse), any())) + .thenReturn(mockedReferendumvorlagenModelMappedAsEntity); + Mockito.doThrow(new RuntimeException("saving failed")).when(referendumvorlagenRepository).save(any()); + + unitUnderTest.initVorlagenAndVorschlaege(new WahltagWithNummer(wahltagDate, wahltagNummer), basisdatenModel); + + Mockito.verify(asyncProgress, times(4)).incReferendumVorlagenFinished(); + Mockito.verify(asyncProgress, times(4)).setReferendumVorlagenNext(any()); + } + + @Test + void should_increaseReferendumvorlagenProgressEven_when_loadingReferendumvorlagenFromClientFailed() { + val wahltagDate = LocalDate.now(); + val wahltagNummer = "wahltagNummer"; + val basisdatenModel = createBasisdatenModelWith2WahlenAnd2WahlbezirkeForEachWahl(wahltagDate, Wahlart.BEB); + + Mockito.doThrow(new RuntimeException("getting data from client failed")).when(referendumvorlagenClient).getReferendumvorlagen(any()); + + unitUnderTest.initVorlagenAndVorschlaege(new WahltagWithNummer(wahltagDate, wahltagNummer), basisdatenModel); + + Mockito.verify(asyncProgress, times(4)).incReferendumVorlagenFinished(); + Mockito.verify(asyncProgress, times(4)).setReferendumVorlagenNext(any()); + } + + @Test + void should_propagateAuthentication_when_repositioriesAreCalled() { + + } + + private ReferendumvorlagenModel createEmptyReferendumvorlagenModel() { + return new ReferendumvorlagenModel("sgzid", Collections.emptySet()); + } + + private BasisdatenModel createEmptyBasisdatenModel() { + return new BasisdatenModel(Collections.emptySet(), Collections.emptySet(), Collections.emptySet(), Collections.emptySet()); + } + + private BasisdatenModel createBasisdatenModelWith2WahlenAnd2WahlbezirkeForEachWahl(final LocalDate wahltagDate, final Wahlart wahlArt) { + val wahlenModels = Set.of( + new WahlModel("wahlID1", "wahl1", 1L, 1L, wahltagDate, wahlArt, null, "1"), + new WahlModel("wahlID2", "wahl2", 2L, 2L, wahltagDate, wahlArt, null, "2")); + + val wahlbezirkeModels = Set.of( + new WahlbezirkModel("wahlbezirkID1", WahlbezirkArtModel.UWB, "1", wahltagDate, "1", "wahlID1"), + new WahlbezirkModel("wahlbezirkID2", WahlbezirkArtModel.UWB, "2", wahltagDate, "1", "wahlID1"), + new WahlbezirkModel("wahlbezirkID3", WahlbezirkArtModel.UWB, "3", wahltagDate, "2", "wahlID2"), + new WahlbezirkModel("wahlbezirkID4", WahlbezirkArtModel.UWB, "4", wahltagDate, "2", "wahlID2")); + + return new BasisdatenModel(Collections.emptySet(), wahlenModels, wahlbezirkeModels, Collections.emptySet()); + } + } + +} diff --git a/wls-basisdaten-service/src/test/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/services/wahltermindaten/WahltermindatenServiceSecurityTest.java b/wls-basisdaten-service/src/test/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/services/wahltermindaten/WahltermindatenServiceSecurityTest.java new file mode 100644 index 000000000..46c09dcbd --- /dev/null +++ b/wls-basisdaten-service/src/test/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/services/wahltermindaten/WahltermindatenServiceSecurityTest.java @@ -0,0 +1,288 @@ +package de.muenchen.oss.wahllokalsystem.basisdatenservice.services.wahltermindaten; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.github.tomakehurst.wiremock.client.WireMock; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.MicroServiceApplication; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.TestConstants; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.domain.kopfdaten.KopfdatenRepository; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.domain.referendumvorlagen.ReferendumvorlagenRepository; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.domain.wahlbezirke.WahlbezirkRepository; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.domain.wahlen.WahlRepository; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.domain.wahltag.WahltagRepository; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.domain.wahlvorschlag.WahlvorschlaegeRepository; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.eai.aou.model.BasisdatenDTO; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.eai.aou.model.BasisstrukturdatenDTO; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.eai.aou.model.KandidatDTO; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.eai.aou.model.ReferendumoptionDTO; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.eai.aou.model.ReferendumvorlageDTO; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.eai.aou.model.ReferendumvorlagenDTO; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.eai.aou.model.StimmzettelgebietDTO; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.eai.aou.model.WahlDTO; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.eai.aou.model.WahlbezirkDTO; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.eai.aou.model.WahltagDTO; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.eai.aou.model.WahlvorschlaegeDTO; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.eai.aou.model.WahlvorschlagDTO; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.utils.Authorities; +import de.muenchen.oss.wahllokalsystem.wls.common.testing.SecurityUtils; +import java.time.LocalDate; +import java.util.Set; +import java.util.UUID; +import java.util.stream.Stream; +import lombok.val; +import org.apache.commons.lang3.ArrayUtils; +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.aggregator.ArgumentsAccessor; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.cloud.contract.wiremock.AutoConfigureWireMock; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; +import org.springframework.core.task.SyncTaskExecutor; +import org.springframework.http.HttpStatus; +import org.springframework.security.access.AccessDeniedException; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.test.context.ActiveProfiles; + +@SpringBootTest(classes = { MicroServiceApplication.class, WahltermindatenServiceSecurityTest.TestConfiguration.class }) +@ActiveProfiles({ TestConstants.SPRING_TEST_PROFILE }) +@AutoConfigureWireMock +public class WahltermindatenServiceSecurityTest { + + @Configuration + static class TestConfiguration { + + @Bean + @Primary + public SyncTaskExecutor syncTaskExecutor() { + return new SyncTaskExecutor(); + } + } + + @Autowired + WahltermindatenService unitUnderTest; + + @Autowired + ObjectMapper objectMapper; + + @Autowired + WahlvorschlaegeRepository wahlvorschlaegeRepository; + + @Autowired + ReferendumvorlagenRepository referendumvorlagenRepository; + + @Autowired + KopfdatenRepository kopfdatenRepository; + + @Autowired + WahltagRepository wahltagRepository; + + @Autowired + WahlRepository wahlRepository; + + @Autowired + WahlbezirkRepository wahlbezirkRepository; + + @BeforeEach + void setup() { + SecurityContextHolder.clearContext(); + } + + @AfterEach + void teardown() { + SecurityUtils.runWith(Authorities.REPOSITORY_DELETE_WAHLTAG, Authorities.REPOSITORY_DELETE_WAHL, Authorities.REPOSITORY_DELETE_KOPFDATEN, + Authorities.REPOSITORY_DELETE_WAHLBEZIRK, + Authorities.REPOSITORY_DELETE_WAHLVORSCHLAEGE, + Authorities.REPOSITORY_DELETE_REFERENDUMVORLAGEN); + wahlvorschlaegeRepository.deleteAll(); + referendumvorlagenRepository.deleteAll(); + kopfdatenRepository.deleteAll(); + wahltagRepository.deleteAll(); + wahlRepository.deleteAll(); + wahlbezirkRepository.deleteAll(); + } + + @Nested + class PutWahltermindaten { + + @Test + void should_throwNoException_when_allRequiredAuthoritiesArePresent() throws Exception { + SecurityUtils.runWith(ArrayUtils.addAll(Authorities.ALL_AUTHORITIES_PUT_WAHLTERMINDATEN_THAT_GOT_CATCHED_ON_MISSING, + Authorities.ALL_AUTHORITIES_PUT_WAHLTERMINDATEN_THAT_GOT_NOT_CATCHED_ON_MISSING)); + + val wahltagID = "wahltagID"; + val stimmzettelgebietID = "sgzID"; + + //WireMock für getWahltag + setupWireMockForWahltagClient(wahltagID); + val wahlbezirkID = "wahlbezirkID"; + //WireMock für getBasisdaten + final String wahlID = "wahlID"; + setupWireMockForWahldatenClient(wahlID, wahlbezirkID, stimmzettelgebietID); + + //WireMock für getWahlvorschlaege + setupWireMockForWahlvorschlaege(wahlID, wahlbezirkID, stimmzettelgebietID); + //WireMock für getReferendumvorlagen + setupWireMockForReferendumvorlagen(wahlID); + + Assertions.assertThatNoException().isThrownBy(() -> unitUnderTest.putWahltermindaten(wahltagID)); + } + + @ParameterizedTest(name = "{index} - {1} missing") + @MethodSource("getMissingAuthoritiesVariationsWithUncatchedException") + void should_throwAccessDeniedException_when_oneRequiredAuthorityIsMissing(final ArgumentsAccessor argumentsAccessor) throws Exception { + SecurityUtils.runWith( + ArrayUtils.addAll(Authorities.ALL_AUTHORITIES_PUT_WAHLTERMINDATEN_THAT_GOT_CATCHED_ON_MISSING, argumentsAccessor.get(0, String[].class))); + + val wahltagID = "wahltagID"; + val wahlID = "wahlID"; + val stimmzettelgebietID = "sgzID"; + val wahlbezirkID = "wahlbezirkID"; + + setupWireMockForWahltagClient(wahltagID); + setupWireMockForWahldatenClient(wahlID, wahlbezirkID, stimmzettelgebietID); + setupWireMockForWahlvorschlaege(wahlID, wahlbezirkID, stimmzettelgebietID); + setupWireMockForReferendumvorlagen(wahlID); + + Assertions.assertThatThrownBy(() -> unitUnderTest.putWahltermindaten(wahltagID)) + .isInstanceOf(AccessDeniedException.class); + } + + @ParameterizedTest(name = "{index} - {1} missing") + @MethodSource("getMissingAuthoritiesVariationsWithCatchedException") + void should_notThrowAccessDeniedException_when_oneRequiredAuthorityIsMissingThatGotCatched(final ArgumentsAccessor argumentsAccessor) throws Exception { + SecurityUtils.runWith( + ArrayUtils.addAll(Authorities.ALL_AUTHORITIES_PUT_WAHLTERMINDATEN_THAT_GOT_NOT_CATCHED_ON_MISSING, + argumentsAccessor.get(0, String[].class))); + + val wahltagID = "wahltagID"; + val wahlID = "wahlID"; + val stimmzettelgebietID = "sgzID"; + val wahlbezirkID = "wahlbezirkID"; + + setupWireMockForWahltagClient(wahltagID); + setupWireMockForWahldatenClient(wahlID, wahlbezirkID, stimmzettelgebietID); + setupWireMockForWahlvorschlaege(wahlID, wahlbezirkID, stimmzettelgebietID); + setupWireMockForReferendumvorlagen(wahlID); + + Assertions.assertThatNoException().isThrownBy(() -> unitUnderTest.putWahltermindaten(wahltagID)); + } + + public static Stream getMissingAuthoritiesVariationsWithUncatchedException() { + return SecurityUtils.buildArgumentsForMissingAuthoritiesVariations(Authorities.ALL_AUTHORITIES_PUT_WAHLTERMINDATEN_THAT_GOT_NOT_CATCHED_ON_MISSING); + } + + public static Stream getMissingAuthoritiesVariationsWithCatchedException() { + return SecurityUtils.buildArgumentsForMissingAuthoritiesVariations(Authorities.ALL_AUTHORITIES_PUT_WAHLTERMINDATEN_THAT_GOT_CATCHED_ON_MISSING); + } + + } + + @Nested + class DeleteWahltermindaten { + + @Test + void should_throwNoException_when_allRequiredAuthoritiesArePresent() throws Exception { + SecurityUtils.runWith(Authorities.ALL_AUTHORITIES_DELETE_WAHLTERMINDTEN); + + val wahltagID = "wahltagID"; + val wahlID = "wahlID"; + val stimmzettelgebietID = "sgzID"; + val wahlbezirkID = "wahlbezirkID"; + + setupWireMockForWahltagClient(wahltagID); + setupWireMockForWahldatenClient(wahlID, wahlbezirkID, stimmzettelgebietID); + + Assertions.assertThatNoException().isThrownBy(() -> unitUnderTest.deleteWahltermindaten(wahltagID)); + } + + @ParameterizedTest(name = "{index} - {1} missing") + @MethodSource("getMissingAuthoritiesVariationsWithUncatchedException") + void should_throwAccessDeniedException_when_oneRequiredAuthorityIsMissing(final ArgumentsAccessor argumentsAccessor) throws Exception { + SecurityUtils.runWith( + ArrayUtils.addAll(Authorities.ALL_AUTHORITIES_PUT_WAHLTERMINDATEN_THAT_GOT_CATCHED_ON_MISSING, argumentsAccessor.get(0, String[].class))); + + val wahltagID = "wahltagID"; + val wahlID = "wahlID"; + val stimmzettelgebietID = "sgzID"; + val wahlbezirkID = "wahlbezirkID"; + + setupWireMockForWahltagClient(wahltagID); + setupWireMockForWahldatenClient(wahlID, wahlbezirkID, stimmzettelgebietID); + setupWireMockForWahlvorschlaege(wahlID, wahlbezirkID, stimmzettelgebietID); + setupWireMockForReferendumvorlagen(wahlID); + + Assertions.assertThatThrownBy(() -> unitUnderTest.putWahltermindaten(wahltagID)) + .isInstanceOf(AccessDeniedException.class); + } + + public static Stream getMissingAuthoritiesVariationsWithUncatchedException() { + return SecurityUtils.buildArgumentsForMissingAuthoritiesVariations(Authorities.ALL_AUTHORITIES_DELETE_WAHLTERMINDTEN); + } + + } + + private void setupWireMockForWahltagClient(final String wahltagID) throws JsonProcessingException { + val wahltagClientResponse = Set.of(new WahltagDTO().identifikator(wahltagID).tag(LocalDate.now()) + .nummer("0")); + WireMock.stubFor(WireMock.get(WireMock.urlPathMatching("/wahldaten/wahltage")) + .willReturn(WireMock.aResponse() + .withHeader("Content-Type", "application/json") + .withBody(objectMapper.writeValueAsString(wahltagClientResponse)) + .withStatus(HttpStatus.OK.value()))); + } + + private void setupWireMockForWahldatenClient(final String wahlID, final String wahlbezirkID, final String stimmzettelgebietID) + throws JsonProcessingException { + val wahltagDate = LocalDate.now(); + val wahlclientResponse = new BasisdatenDTO().basisstrukturdaten( + Set.of(new BasisstrukturdatenDTO().wahlID(wahlID).wahlbezirkID(wahlbezirkID).stimmzettelgebietID(stimmzettelgebietID))) + .wahlbezirke(Set.of(new WahlbezirkDTO().identifikator(wahlbezirkID).wahltag(wahltagDate).wahlID(wahlID) + .wahlbezirkArt(WahlbezirkDTO.WahlbezirkArtEnum.UWB).nummer("0") + .wahlnummer("0"))) + .wahlen(Set.of(new WahlDTO().nummer("0").wahltag(wahltagDate).name("wahl").wahlart(WahlDTO.WahlartEnum.BTW).identifikator(wahlID))) + .stimmzettelgebiete( + Set.of(new StimmzettelgebietDTO().stimmzettelgebietsart(StimmzettelgebietDTO.StimmzettelgebietsartEnum.WK).wahltag(wahltagDate) + .nummer("0").identifikator(stimmzettelgebietID).name("name"))); + WireMock.stubFor(WireMock.get(WireMock.urlPathMatching("/wahldaten/basisdaten")) + .willReturn(WireMock.aResponse() + .withHeader("Content-Type", "application/json") + .withBody(objectMapper.writeValueAsString(wahlclientResponse)) + .withStatus(HttpStatus.OK.value()))); + } + + private void setupWireMockForWahlvorschlaege(final String wahlID, final String wahlbezirkID, final String stimmzettelgebietID) + throws JsonProcessingException { + val wahlvorschlaege = new WahlvorschlaegeDTO().wahlID(wahlID) + .stimmzettelgebietID(stimmzettelgebietID) + .wahlbezirkID(wahlbezirkID) + .wahlvorschlaege(Set.of(new WahlvorschlagDTO().identifikator(UUID.randomUUID().toString()) + .kurzname("kurzname") + .addKandidatenItem(new KandidatDTO().identifikator(UUID.randomUUID().toString()).name("kandidat").direktkandidat(true)))); + WireMock.stubFor(WireMock.get(WireMock.urlPathMatching("/vorschlaege/wahl/.*/.*")) + .willReturn(WireMock.aResponse() + .withHeader("Content-Type", "application/json") + .withBody(objectMapper.writeValueAsString(wahlvorschlaege)) + .withStatus(HttpStatus.OK.value()))); + } + + private void setupWireMockForReferendumvorlagen(final String stimmzettelgebietID) throws JsonProcessingException { + val referendumvorlagen = new ReferendumvorlagenDTO().stimmzettelgebietID(stimmzettelgebietID) + .referendumvorlagen( + Set.of(new ReferendumvorlageDTO().frage("frage") + .addReferendumoptionenItem(new ReferendumoptionDTO().id(UUID.randomUUID().toString()).name("option")))); + WireMock.stubFor(WireMock.get(WireMock.urlPathMatching("/vorschlaege/referendum/.*/.*")) + .willReturn(WireMock.aResponse() + .withHeader("Content-Type", "application/json") + .withBody(objectMapper.writeValueAsString(referendumvorlagen)) + .withStatus(HttpStatus.OK.value()))); + } +} diff --git a/wls-basisdaten-service/src/test/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/services/wahltermindaten/WahltermindatenServiceTest.java b/wls-basisdaten-service/src/test/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/services/wahltermindaten/WahltermindatenServiceTest.java new file mode 100644 index 000000000..277534411 --- /dev/null +++ b/wls-basisdaten-service/src/test/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/services/wahltermindaten/WahltermindatenServiceTest.java @@ -0,0 +1,263 @@ +package de.muenchen.oss.wahllokalsystem.basisdatenservice.services.wahltermindaten; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; + +import de.muenchen.oss.wahllokalsystem.basisdatenservice.domain.kopfdaten.Kopfdaten; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.domain.kopfdaten.KopfdatenRepository; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.domain.referendumvorlagen.ReferendumvorlagenRepository; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.domain.wahlbezirke.Wahlbezirk; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.domain.wahlbezirke.WahlbezirkRepository; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.domain.wahlen.Wahl; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.domain.wahlen.WahlRepository; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.domain.wahlen.Wahlart; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.domain.wahlvorschlag.WahlvorschlaegeRepository; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.exception.ExceptionConstants; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.common.WahlbezirkArtModel; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.common.WahltagWithNummer; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.kopfdaten.BasisdatenModel; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.kopfdaten.BasisstrukturdatenModel; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.kopfdaten.KopfdatenMapper; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.kopfdaten.KopfdatenModel; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.kopfdaten.KopfdatenModelMapper; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.kopfdaten.WahldatenClient; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.wahlbezirke.WahlbezirkModel; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.wahlbezirke.WahlbezirkModelMapper; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.wahlen.WahlModel; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.wahlen.WahlModelMapper; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.wahltag.WahltagModel; +import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.wahltag.WahltageService; +import de.muenchen.oss.wahllokalsystem.wls.common.exception.FachlicheWlsException; +import de.muenchen.oss.wahllokalsystem.wls.common.exception.util.ExceptionFactory; +import java.time.LocalDate; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Set; +import lombok.val; +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.jupiter.MockitoExtension; + +@ExtendWith(MockitoExtension.class) +class WahltermindatenServiceTest { + + @Mock + WahltermindatenValidator wahltermindatenValidator; + + @Mock + WahltageService wahltageService; + + @Mock + WahldatenClient wahldatenClient; + + @Mock + WahlModelMapper wahlModelMapper; + + @Mock + WahlbezirkModelMapper wahlbezirkModelMapper; + + @Mock + KopfdatenModelMapper kopfdatenModelMapper; + + @Mock + WahlRepository wahlRepository; + + @Mock + WahlbezirkRepository wahlbezirkRepository; + + @Mock + KopfdatenRepository kopfdatenRepository; + + @Mock + WahlvorschlaegeRepository wahlvorschlaegeRepository; + + @Mock + ReferendumvorlagenRepository referendumvorlagenRepository; + + @Mock + KopfdatenMapper kopfDataInitializer; + + @Mock + ExceptionFactory exceptionFactory; + + @Mock + AsyncWahltermindatenService asyncWahltermindatenService; + + @InjectMocks + WahltermindatenService unitUnderTest; + + @Nested + class PutWahltermindaten { + + @Captor + ArgumentCaptor> wahlbezirkEntitiesCaptor; + + @Test + void should_throwException_when_wahltagIDIsInvalid() { + val wahltagID = "wahltagID"; + + val mockedValidationException = FachlicheWlsException.withCode("000").buildWithMessage("validation failed"); + + Mockito.doThrow(mockedValidationException).when(wahltermindatenValidator).validateParameterToInitWahltermindaten(wahltagID); + + Assertions.assertThatThrownBy(() -> unitUnderTest.putWahltermindaten(wahltagID)).isSameAs(mockedValidationException); + } + + @Test + void should_throwException_when_wahltagWithIDDoesNotExist() { + val wahltagID = "wahltagID"; + + val mockedWlsException = FachlicheWlsException.withCode("000").buildWithMessage("message"); + val mockedWahltageServiceResponse = List.of(new WahltagModel("otherWahltagID", LocalDate.now(), "", "")); + + Mockito.when(wahltageService.getWahltage()).thenReturn(mockedWahltageServiceResponse); + Mockito.when(exceptionFactory.createFachlicheWlsException(ExceptionConstants.CODE_PUTWAHLTERMINDATEN_NO_WAHLTAG)).thenReturn(mockedWlsException); + + Assertions.assertThatThrownBy(() -> unitUnderTest.putWahltermindaten(wahltagID)).isSameAs(mockedWlsException); + } + + @Test + void should_throwException_when_noBasisdatenWhereFound() { + val wahltagID = "wahltagID"; + + val mockedMatchingWahltag = new WahltagModel(wahltagID, LocalDate.now(), "", "nummer"); + val mockedWahltageServiceResponse = List.of(mockedMatchingWahltag); + val mockedWlsException = FachlicheWlsException.withCode("000").buildWithMessage("message"); + + Mockito.when(wahltageService.getWahltage()).thenReturn(mockedWahltageServiceResponse); + Mockito.when(wahldatenClient.loadBasisdaten(new WahltagWithNummer(mockedMatchingWahltag.wahltag(), mockedMatchingWahltag.nummer()))) + .thenReturn(null); + Mockito.when(exceptionFactory.createFachlicheWlsException(ExceptionConstants.GET_BASISDATEN_NO_DATA)).thenReturn(mockedWlsException); + + Assertions.assertThatThrownBy(() -> unitUnderTest.putWahltermindaten(wahltagID)).isSameAs(mockedWlsException); + } + + @Test + void should_persistData_when_gettingBasisdaten() { + val wahltagID = "wahltagID"; + + val mockedDataWahltag = LocalDate.now(); + + val mockedMatchingWahltag = new WahltagModel(wahltagID, mockedDataWahltag, "", "nummer"); + val mockedWahltageServiceResponse = List.of(mockedMatchingWahltag); + val mockedWahldatenClientResponse = createMockedBasisdatenModel(mockedDataWahltag); + val mockedWahlenMappedAsEntity = List.of(createWahlWithNummer("1"), createWahlWithNummer("2")); + val mockedWahlbezirkeMappedAsEntity = Set.of(createWahlbezirkWithWahlnummer("1"), createWahlbezirkWithWahlnummer("2")); + val mockedKopfdatenListen = List.of(KopfdatenModel.builder().build(), KopfdatenModel.builder().build()); + val mockedKopfdatenMappedAsEntity = new Kopfdaten(); + + Mockito.when(wahltageService.getWahltage()).thenReturn(mockedWahltageServiceResponse); + Mockito.when(wahldatenClient.loadBasisdaten(new WahltagWithNummer(mockedMatchingWahltag.wahltag(), mockedMatchingWahltag.nummer()))) + .thenReturn(mockedWahldatenClientResponse); + Mockito.when(wahlModelMapper.fromListOfWahlModeltoListOfWahlEntities(any())).thenReturn(mockedWahlenMappedAsEntity); + Mockito.when(wahlbezirkModelMapper.fromListOfWahlbezirkModeltoListOfWahlbezirkEntities(any())).thenReturn(mockedWahlbezirkeMappedAsEntity); + Mockito.when(kopfDataInitializer.initKopfdaten(mockedWahldatenClientResponse)).thenReturn(mockedKopfdatenListen); + Mockito.when(kopfdatenModelMapper.toEntity(any())).thenReturn(mockedKopfdatenMappedAsEntity); + + unitUnderTest.putWahltermindaten(wahltagID); + + Mockito.verify(wahlRepository).saveAll(mockedWahlenMappedAsEntity); + Mockito.verify(wahlbezirkRepository).saveAll(wahlbezirkEntitiesCaptor.capture()); + Mockito.verify(asyncWahltermindatenService) + .initVorlagenAndVorschlaege(eq(new WahltagWithNummer(mockedMatchingWahltag.wahltag(), mockedMatchingWahltag.nummer())), + eq(mockedWahldatenClientResponse)); + Mockito.verify(kopfdatenRepository).saveAll(List.of(mockedKopfdatenMappedAsEntity, mockedKopfdatenMappedAsEntity)); + + Assertions.assertThat(wahlbezirkEntitiesCaptor.getAllValues().size()).isEqualTo(1); + Assertions.assertThat(wahlbezirkEntitiesCaptor.getValue()).containsOnly( + new Wahlbezirk(null, null, null, null, "1", "wahlID1"), + new Wahlbezirk(null, null, null, null, "2", "wahlID2")); + } + + private static BasisdatenModel createMockedBasisdatenModel(LocalDate wahltagDate) { + val mockedWahldatenWahlen = Set.of(new WahlModel("wahlID1", "wahl 1", 1L, 1L, wahltagDate, Wahlart.BTW, null, "1"), + new WahlModel("wahlID2", "wahl 2", 1L, 1L, wahltagDate, Wahlart.BTW, null, "2")); + val mockedWahldatenWahlbezirke = Set.of(new WahlbezirkModel("wbz1", WahlbezirkArtModel.UWB, "1", wahltagDate, "1", "1"), + new WahlbezirkModel("wbz2", WahlbezirkArtModel.UWB, "1", wahltagDate, "2", "2")); + return new BasisdatenModel(Collections.emptySet(), mockedWahldatenWahlen, mockedWahldatenWahlbezirke, + Collections.emptySet()); + } + + private Wahl createWahlWithNummer(final String nummer) { + val wahl = new Wahl(); + wahl.setNummer(nummer); + + return wahl; + } + + private Wahlbezirk createWahlbezirkWithWahlnummer(final String wahlnummer) { + val wahlbezirk = new Wahlbezirk(); + wahlbezirk.setWahlnummer(wahlnummer); + + return wahlbezirk; + } + } + + @Nested + class DeleteWahltermindaten { + + @Test + void should_throwException_when_wahltagIDIsNotValid() { + val wahltagID = "wahltagID"; + + val mockedValidationException = FachlicheWlsException.withCode("000").buildWithMessage("validation failed"); + + Mockito.doThrow(mockedValidationException).when(wahltermindatenValidator).validateParameterToDeleteWahltermindaten(wahltagID); + + Assertions.assertThatThrownBy(() -> unitUnderTest.deleteWahltermindaten(wahltagID)).isSameAs(mockedValidationException); + } + + @Test + void should_throwException_when_wahltagOfIDDoesNotExist() { + val wahltagID = "wahltagID"; + + val mockedFachlicheWlsException = FachlicheWlsException.withCode("000").buildWithMessage("fachlicheWlsException"); + + Mockito.when(exceptionFactory.createFachlicheWlsException(ExceptionConstants.CODE_DELETEWAHLTERMINDATEN_PARAMETER_UNVOLLSTAENDIG)) + .thenReturn(mockedFachlicheWlsException); + Mockito.when(wahltageService.getWahltage()).thenReturn(Collections.emptyList()); + + Assertions.assertThatThrownBy(() -> unitUnderTest.deleteWahltermindaten(wahltagID)).isSameAs(mockedFachlicheWlsException); + } + + @Test + void should_deleteDataInReposOfWahlen_when_wahltagIdHasWahltagWithBasisdaten() { + val wahltagID = "wahltagID"; + + val mockedDataWahltagDate = LocalDate.now(); + val mockedMatchingWahltag = new WahltagModel(wahltagID, mockedDataWahltagDate, "", "nummer"); + val mockedWahltageServiceResponse = List.of(mockedMatchingWahltag); + val mockedBasisstrukturdatenModels = Set.of(createBasisstrukturdatenModelWithWahlID("wahlID1"), createBasisstrukturdatenModelWithWahlID("wahlID2")); + val mockedWahldatenClientResponse = new BasisdatenModel(mockedBasisstrukturdatenModels, null, null, null); + + Mockito.when(wahltageService.getWahltage()).thenReturn(mockedWahltageServiceResponse); + Mockito.when(wahldatenClient.loadBasisdaten(new WahltagWithNummer(mockedDataWahltagDate, mockedMatchingWahltag.nummer()))) + .thenReturn(mockedWahldatenClientResponse); + + unitUnderTest.deleteWahltermindaten(wahltagID); + + Mockito.verify(wahlbezirkRepository).deleteByWahltag(mockedDataWahltagDate); + Mockito.verify(kopfdatenRepository).deleteAllByBezirkUndWahlID_WahlID("wahlID1"); + Mockito.verify(kopfdatenRepository).deleteAllByBezirkUndWahlID_WahlID("wahlID2"); + Mockito.verify(wahlRepository).deleteById("wahlID1"); + Mockito.verify(wahlRepository).deleteById("wahlID2"); + Mockito.verify(wahlvorschlaegeRepository).deleteAllByBezirkUndWahlID_WahlID("wahlID1"); + Mockito.verify(wahlvorschlaegeRepository).deleteAllByBezirkUndWahlID_WahlID("wahlID2"); + Mockito.verify(referendumvorlagenRepository).deleteAllByBezirkUndWahlID_WahlID("wahlID1"); + Mockito.verify(referendumvorlagenRepository).deleteAllByBezirkUndWahlID_WahlID("wahlID2"); + } + + private BasisstrukturdatenModel createBasisstrukturdatenModelWithWahlID(String wahlID) { + return new BasisstrukturdatenModel(wahlID, null, null, null); + } + } + +} diff --git a/wls-basisdaten-service/src/test/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/services/wahltermindaten/WahltermindatenValidatorTest.java b/wls-basisdaten-service/src/test/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/services/wahltermindaten/WahltermindatenValidatorTest.java new file mode 100644 index 000000000..f369696b3 --- /dev/null +++ b/wls-basisdaten-service/src/test/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/services/wahltermindaten/WahltermindatenValidatorTest.java @@ -0,0 +1,99 @@ +package de.muenchen.oss.wahllokalsystem.basisdatenservice.services.wahltermindaten; + +import de.muenchen.oss.wahllokalsystem.basisdatenservice.exception.ExceptionConstants; +import de.muenchen.oss.wahllokalsystem.wls.common.exception.FachlicheWlsException; +import de.muenchen.oss.wahllokalsystem.wls.common.exception.util.ExceptionFactory; +import lombok.val; +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.jupiter.MockitoExtension; + +@ExtendWith(MockitoExtension.class) +class WahltermindatenValidatorTest { + + @Mock + ExceptionFactory exceptionFactory; + + @InjectMocks + WahltermindatenValidator unitUnderTest; + + @Nested + class ValidateParameterToInitWahltermindaten { + + final FachlicheWlsException mockedWlsException = FachlicheWlsException.withCode("000").buildWithMessage("mocked wls exception"); + + @Test + void should_throwNoException_when_wahltagIDIsValid() { + val wahltagID = "wahltagID"; + + unitUnderTest.validateParameterToInitWahltermindaten(wahltagID); + } + + @Test + void should_throwException_when_wahltagIDIsNull() { + Mockito.when(exceptionFactory.createFachlicheWlsException(ExceptionConstants.CODE_PUTWAHLTERMINDATEN_PARAMETER_UNVOLLSTAENDIG)) + .thenReturn(mockedWlsException); + + Assertions.assertThatThrownBy(() -> unitUnderTest.validateParameterToInitWahltermindaten(null)).isSameAs(mockedWlsException); + } + + @Test + void should_throwException_when_wahltagIDIsEmpty() { + Mockito.when(exceptionFactory.createFachlicheWlsException(ExceptionConstants.CODE_PUTWAHLTERMINDATEN_PARAMETER_UNVOLLSTAENDIG)) + .thenReturn(mockedWlsException); + + Assertions.assertThatThrownBy(() -> unitUnderTest.validateParameterToInitWahltermindaten("")).isSameAs(mockedWlsException); + } + + @Test + void should_throwException_when_wahltagIDIsBlank() { + Mockito.when(exceptionFactory.createFachlicheWlsException(ExceptionConstants.CODE_PUTWAHLTERMINDATEN_PARAMETER_UNVOLLSTAENDIG)) + .thenReturn(mockedWlsException); + + Assertions.assertThatThrownBy(() -> unitUnderTest.validateParameterToInitWahltermindaten(" ")).isSameAs(mockedWlsException); + } + } + + @Nested + class ValidateParameterToDeleteWahltermindaten { + + final FachlicheWlsException mockedWlsException = FachlicheWlsException.withCode("000").buildWithMessage("mocked wls exception"); + + @Test + void should_throwNoException_when_wahltagIDIsValid() { + val wahltagID = "wahltagID"; + + unitUnderTest.validateParameterToDeleteWahltermindaten(wahltagID); + } + + @Test + void should_throwException_when_wahltagIDIsNull() { + Mockito.when(exceptionFactory.createFachlicheWlsException(ExceptionConstants.CODE_DELETEWAHLTERMINDATEN_PARAMETER_UNVOLLSTAENDIG)) + .thenReturn(mockedWlsException); + + Assertions.assertThatThrownBy(() -> unitUnderTest.validateParameterToDeleteWahltermindaten(null)).isSameAs(mockedWlsException); + } + + @Test + void should_throwException_when_wahltagIDIsEmpty() { + Mockito.when(exceptionFactory.createFachlicheWlsException(ExceptionConstants.CODE_DELETEWAHLTERMINDATEN_PARAMETER_UNVOLLSTAENDIG)) + .thenReturn(mockedWlsException); + + Assertions.assertThatThrownBy(() -> unitUnderTest.validateParameterToDeleteWahltermindaten("")).isSameAs(mockedWlsException); + } + + @Test + void should_throwException_when_wahltagIDIsBlank() { + Mockito.when(exceptionFactory.createFachlicheWlsException(ExceptionConstants.CODE_DELETEWAHLTERMINDATEN_PARAMETER_UNVOLLSTAENDIG)) + .thenReturn(mockedWlsException); + + Assertions.assertThatThrownBy(() -> unitUnderTest.validateParameterToDeleteWahltermindaten(" ")).isSameAs(mockedWlsException); + } + } + +} diff --git a/wls-basisdaten-service/src/test/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/utils/Authorities.java b/wls-basisdaten-service/src/test/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/utils/Authorities.java index 59e059af2..62d598a3e 100644 --- a/wls-basisdaten-service/src/test/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/utils/Authorities.java +++ b/wls-basisdaten-service/src/test/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/utils/Authorities.java @@ -26,6 +26,9 @@ public class Authorities { public static final String SERVICE_GET_WAHLBEZIRKE = "Basisdaten_BUSINESSACTION_GetWahlbezirke"; + public static final String SERVICE_PUT_WAHLTERMINDATEN = "Basisdaten_BUSINESSACTION_PutWahltermindaten"; + public static final String SERVICE_DELETE_WAHLTERMINDATEN = "Basisdaten_BUSINESSACTION_DeleteWahltermindaten"; + public static final String REPOSITORY_READ_WAHLVORSCHLAEGE = "Basisdaten_READ_WLSWahlvorschlaege"; public static final String REPOSITORY_DELETE_WAHLVORSCHLAEGE = "Basisdaten_DELETE_WLSWahlvorschlaege"; public static final String REPOSITORY_WRITE_WAHLVORSCHLAEGE = "Basisdaten_WRITE_WLSWahlvorschlaege"; @@ -195,4 +198,35 @@ public class Authorities { REPOSITORY_READ_WAHLBEZIRK, REPOSITORY_WRITE_WAHLBEZIRK, }; + + public static final String[] ALL_AUTHORITIES_PUT_WAHLTERMINDATEN_THAT_GOT_NOT_CATCHED_ON_MISSING = { + SERVICE_PUT_WAHLTERMINDATEN, + + SERVICE_GET_WAHLTAGE, + REPOSITORY_WRITE_WAHLTAG, + REPOSITORY_READ_WAHLTAG, + + REPOSITORY_WRITE_WAHL, + REPOSITORY_WRITE_WAHLBEZIRK, + REPOSITORY_READ_KOPFDATEN + }; + + public static final String[] ALL_AUTHORITIES_PUT_WAHLTERMINDATEN_THAT_GOT_CATCHED_ON_MISSING = { + REPOSITORY_WRITE_WAHLVORSCHLAEGE, + REPOSITORY_WRITE_REFERENDUMVORLAGEN + }; + + public static final String[] ALL_AUTHORITIES_DELETE_WAHLTERMINDTEN = { + SERVICE_DELETE_WAHLTERMINDATEN, + + SERVICE_GET_WAHLTAGE, + REPOSITORY_WRITE_WAHLTAG, + REPOSITORY_READ_WAHLTAG, + + REPOSITORY_DELETE_WAHLBEZIRK, + REPOSITORY_DELETE_WAHL, + REPOSITORY_DELETE_KOPFDATEN, + REPOSITORY_DELETE_WAHLVORSCHLAEGE, + REPOSITORY_DELETE_REFERENDUMVORLAGEN + }; } diff --git a/wls-basisdaten-service/src/test/resources/http-client.env.json b/wls-basisdaten-service/src/test/resources/http-client.env.json index 5efb2e017..28b176a15 100644 --- a/wls-basisdaten-service/src/test/resources/http-client.env.json +++ b/wls-basisdaten-service/src/test/resources/http-client.env.json @@ -1,5 +1,7 @@ { "nonDocker": { + "token_type": "", + "auth_token": "", "WLS_BASISDATEN_SERVICE_URL": "http://localhost:39151", "SSO_URL": "http://kubernetes.docker.internal:8100" } diff --git a/wls-basisdaten-service/src/test/resources/wahltermindaten.http b/wls-basisdaten-service/src/test/resources/wahltermindaten.http new file mode 100644 index 000000000..c03c36ce0 --- /dev/null +++ b/wls-basisdaten-service/src/test/resources/wahltermindaten.http @@ -0,0 +1,34 @@ +### Get token wls_all +POST {{ SSO_URL }}/auth/realms/wls_realm/protocol/openid-connect/token +Content-Type: application/x-www-form-urlencoded + +password = test & +grant_type = password & +client_secret = top-secret & +client_id = wls & +username = wls_all + +> {% + client.global.set("auth_token", response.body.access_token); + client.global.set("token_type", response.body.token_type); +%} + +### get userinfo with auth_token +GET {{ SSO_URL }}/auth/realms/wls_realm/protocol/openid-connect/userinfo +Authorization: {{ token_type }} {{ auth_token }} + +### Put Wahltermindaten +PUT {{ WLS_BASISDATEN_SERVICE_URL }}/businessActions/wahltermindaten/wahltagID1 +Authorization: {{ token_type }} {{ auth_token }} + +### Put Wahltermindaten - failed cause wahltagID does not exist +PUT {{ WLS_BASISDATEN_SERVICE_URL }}/businessActions/wahltermindaten/wahltagIDThatDoesNotExist +Authorization: {{ token_type }} {{ auth_token }} + +### Delete Wahltermindaten +DELETE {{ WLS_BASISDATEN_SERVICE_URL }}/businessActions/wahltermindaten/wahltagID1 +Authorization: {{ token_type }} {{ auth_token }} + +### Delete Wahltermindaten - failed cause wahltagID does not exist +DELETE {{ WLS_BASISDATEN_SERVICE_URL }}/businessActions/wahltermindaten/wahltagIDThatDoesNotExist +Authorization: {{ token_type }} {{ auth_token }} \ No newline at end of file