diff --git a/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/domain/use_cases/missions/CreateOrUpdateEnvActions.kt b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/domain/use_cases/missions/CreateOrUpdateEnvActions.kt index 3109d2fc2..51a458a3e 100644 --- a/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/domain/use_cases/missions/CreateOrUpdateEnvActions.kt +++ b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/domain/use_cases/missions/CreateOrUpdateEnvActions.kt @@ -25,7 +25,6 @@ class CreateOrUpdateEnvActions( @Throws(IllegalArgumentException::class) fun execute( - // @UseCaseValidation(validator = MissionValidator::class) mission: MissionEntity, envActions: List?, ): MissionEntity { @@ -55,6 +54,7 @@ class CreateOrUpdateEnvActions( }, ) } + ActionTypeEnum.SURVEILLANCE -> { val surveillance = it as EnvActionSurveillanceEntity val normalizedGeometry = @@ -76,6 +76,7 @@ class CreateOrUpdateEnvActions( }, ) } + ActionTypeEnum.NOTE -> { (it as EnvActionNoteEntity).copy() } diff --git a/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/domain/use_cases/missions/CreateOrUpdateMission.kt b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/domain/use_cases/missions/CreateOrUpdateMission.kt index 24afd5d09..ca828d38d 100644 --- a/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/domain/use_cases/missions/CreateOrUpdateMission.kt +++ b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/domain/use_cases/missions/CreateOrUpdateMission.kt @@ -1,12 +1,13 @@ package fr.gouv.cacem.monitorenv.domain.use_cases.missions -// import fr.gouv.cacem.monitorenv.domain.validators.mission.MissionValidator import fr.gouv.cacem.monitorenv.config.UseCase import fr.gouv.cacem.monitorenv.domain.entities.mission.MissionEntity import fr.gouv.cacem.monitorenv.domain.repositories.IFacadeAreasRepository import fr.gouv.cacem.monitorenv.domain.repositories.IMissionRepository import fr.gouv.cacem.monitorenv.domain.repositories.IPostgisFunctionRepository import fr.gouv.cacem.monitorenv.domain.use_cases.missions.events.UpdateMissionEvent +import fr.gouv.cacem.monitorenv.domain.validators.UseCaseValidation +import fr.gouv.cacem.monitorenv.domain.validators.mission.MissionValidator import org.slf4j.LoggerFactory import org.springframework.context.ApplicationEventPublisher @@ -21,7 +22,7 @@ class CreateOrUpdateMission( @Throws(IllegalArgumentException::class) fun execute( - // @UseCaseValidation(validator = MissionValidator::class) + @UseCaseValidation(validator = MissionValidator::class) mission: MissionEntity, ): MissionEntity { logger.info("Attempt to CREATE or UPDATE mission ${mission.id}") diff --git a/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/domain/use_cases/missions/CreateOrUpdateMissionWithActionsAndAttachedReporting.kt b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/domain/use_cases/missions/CreateOrUpdateMissionWithActionsAndAttachedReporting.kt index f4dfd6f92..6ee6db75e 100644 --- a/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/domain/use_cases/missions/CreateOrUpdateMissionWithActionsAndAttachedReporting.kt +++ b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/domain/use_cases/missions/CreateOrUpdateMissionWithActionsAndAttachedReporting.kt @@ -2,13 +2,14 @@ package fr.gouv.cacem.monitorenv.domain.use_cases.missions -// import fr.gouv.cacem.monitorenv.domain.validators.mission.MissionValidator import fr.gouv.cacem.monitorenv.config.UseCase import fr.gouv.cacem.monitorenv.domain.entities.mission.MissionEntity import fr.gouv.cacem.monitorenv.domain.exceptions.ReportingAlreadyAttachedException import fr.gouv.cacem.monitorenv.domain.repositories.IReportingRepository import fr.gouv.cacem.monitorenv.domain.use_cases.missions.dtos.EnvActionAttachedToReportingIds import fr.gouv.cacem.monitorenv.domain.use_cases.missions.dtos.MissionDetailsDTO +import fr.gouv.cacem.monitorenv.domain.validators.UseCaseValidation +import fr.gouv.cacem.monitorenv.domain.validators.mission.MissionWithEnvActionsValidator import org.slf4j.LoggerFactory import java.util.UUID @@ -27,7 +28,7 @@ class CreateOrUpdateMissionWithActionsAndAttachedReporting( @Throws(IllegalArgumentException::class) fun execute( - // @UseCaseValidation(validator = MissionValidator::class) + @UseCaseValidation(validator = MissionWithEnvActionsValidator::class) mission: MissionEntity, attachedReportingIds: List, envActionsAttachedToReportingIds: List, diff --git a/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/domain/validators/UseCaseValidationAspect.kt b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/domain/validators/UseCaseValidationAspect.kt index 60fcf6e5b..560c0827a 100644 --- a/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/domain/validators/UseCaseValidationAspect.kt +++ b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/domain/validators/UseCaseValidationAspect.kt @@ -4,27 +4,24 @@ import org.aspectj.lang.JoinPoint import org.aspectj.lang.annotation.Aspect import org.aspectj.lang.annotation.Before import org.aspectj.lang.reflect.MethodSignature +import org.springframework.context.ApplicationContext import org.springframework.stereotype.Component @Component @Aspect -class UseCaseValidationAspect { +class UseCaseValidationAspect(private val applicationContext: ApplicationContext) { @Before("execution(* fr.gouv.cacem.monitorenv.domain.use_cases..*.execute(..))") fun before(joinPoint: JoinPoint) { val method = (joinPoint.signature as MethodSignature).method - // Parcourir les paramètres de la méthode method.parameters.forEachIndexed { index, parameter -> val annotation = parameter.getAnnotation(UseCaseValidation::class.java) if (annotation != null) { - // Récupérer l'argument associé à ce paramètre val arg = joinPoint.args[index] - // Instancier et exécuter le validateur spécifié dans l'annotation - val validator = - annotation.validator.objectInstance - ?: annotation.validator.java.getDeclaredConstructor().newInstance() - (validator as Validator).validate(arg) // Valide l'objet + // Récupérer le validateur depuis le contexte Spring + val validator = applicationContext.getBean(annotation.validator.java) as Validator + validator.validate(arg) } } } diff --git a/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/domain/validators/mission/MissionValidator.kt b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/domain/validators/mission/MissionValidator.kt index e81c1bbe0..8a7e224db 100644 --- a/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/domain/validators/mission/MissionValidator.kt +++ b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/domain/validators/mission/MissionValidator.kt @@ -1,21 +1,11 @@ package fr.gouv.cacem.monitorenv.domain.validators.mission import fr.gouv.cacem.monitorenv.domain.entities.mission.MissionEntity -import fr.gouv.cacem.monitorenv.domain.entities.mission.envAction.ActionTypeEnum -import fr.gouv.cacem.monitorenv.domain.entities.mission.envAction.EnvActionEntity -import fr.gouv.cacem.monitorenv.domain.entities.mission.envAction.envActionControl.ActionTargetTypeEnum -import fr.gouv.cacem.monitorenv.domain.entities.mission.envAction.envActionControl.EnvActionControlEntity -import fr.gouv.cacem.monitorenv.domain.entities.mission.envAction.envActionControl.infraction.AdministrativeResponseEnum -import fr.gouv.cacem.monitorenv.domain.entities.mission.envAction.envActionControl.infraction.FormalNoticeEnum -import fr.gouv.cacem.monitorenv.domain.entities.mission.envAction.envActionControl.infraction.InfractionTypeEnum -import fr.gouv.cacem.monitorenv.domain.entities.mission.envAction.envActionControl.infraction.SeizureTypeEnum -import fr.gouv.cacem.monitorenv.domain.entities.mission.envAction.envActionSurveillance.EnvActionSurveillanceEntity import fr.gouv.cacem.monitorenv.domain.exceptions.BackendUsageErrorCode import fr.gouv.cacem.monitorenv.domain.exceptions.BackendUsageException import fr.gouv.cacem.monitorenv.domain.validators.Validator import org.slf4j.LoggerFactory import org.springframework.stereotype.Component -import java.time.ZonedDateTime private const val NB_CHAR_MAX = 3 @@ -62,203 +52,5 @@ class MissionValidator : Validator { data = "Le trigramme \"ouvert par\" doit avoir 3 lettres", ) } - validateEnvActions(mission) - } - - private fun validateEnvActions(mission: MissionEntity) { - val isMissionEnded = - mission.endDateTimeUtc != null && - ZonedDateTime.now().isAfter(mission.endDateTimeUtc) - - mission.envActions?.forEach { envAction -> - if (envAction is EnvActionControlEntity) { - validateControl(envAction, mission, isMissionEnded) - } - - if (envAction is EnvActionSurveillanceEntity) { - validateSurveillance(envAction, mission, isMissionEnded) - } - } - } - - private fun validateControl( - control: EnvActionControlEntity, - mission: MissionEntity, - isMissionEnded: Boolean, - ) { - validateEnvAction(control, mission) - - if (isMissionEnded) { - if (control.geom === null) { - throw BackendUsageException( - code = BackendUsageErrorCode.UNVALID_PROPERTY, - data = "La géométrie du contrôle est obligatoire", - ) - } - if (control.vehicleType === null && - control.actionTargetType === ActionTargetTypeEnum.VEHICLE - ) { - throw BackendUsageException( - code = BackendUsageErrorCode.UNVALID_PROPERTY, - data = "Le type de véhicule est obligatoire", - ) - } - validateControlPlan(control) - } - - validateInfractions(control, isMissionEnded) - } - - private fun validateInfractions( - control: EnvActionControlEntity, - isMissionEnded: Boolean, - ) { - val sumOfNbTarget = control.infractions?.sumOf { infraction -> infraction.nbTarget } - if (sumOfNbTarget != 0 && - sumOfNbTarget != null && - ( - control.actionNumberOfControls != null && - sumOfNbTarget > control.actionNumberOfControls - ) - ) { - throw BackendUsageException( - code = BackendUsageErrorCode.UNVALID_PROPERTY, - data = "Le nombre de cibles excède le nombre total de contrôles", - ) - } - - control.infractions?.forEach { infraction -> - if (infraction.infractionType !== InfractionTypeEnum.WAITING && - infraction.natinf?.isEmpty() == true - ) { - throw BackendUsageException( - code = BackendUsageErrorCode.UNVALID_PROPERTY, - data = - "Une infraction doit avoir une natinf si le type d'infraction n'est pas \"En attente\"", - ) - } - if (infraction.nbTarget < 1) { - throw BackendUsageException( - code = BackendUsageErrorCode.UNVALID_PROPERTY, - data = "le nombre minimum de cible est 1", - ) - } - if (isMissionEnded) { - if (infraction.infractionType === InfractionTypeEnum.WAITING) { - throw BackendUsageException( - code = BackendUsageErrorCode.UNVALID_PROPERTY, - data = "Le type d'infraction ne peut pas être \"en attente\"", - ) - } - if (infraction.seizure === SeizureTypeEnum.PENDING) { - throw BackendUsageException( - code = BackendUsageErrorCode.UNVALID_PROPERTY, - data = "L'appréhension/saisie ne peut pas être \"en attente\"", - ) - } - if (infraction.administrativeResponse === AdministrativeResponseEnum.PENDING) { - throw BackendUsageException( - code = BackendUsageErrorCode.UNVALID_PROPERTY, - data = "La réponse administrative ne peut pas être \"en attente\"", - ) - } - if (infraction.formalNotice === FormalNoticeEnum.PENDING) { - throw BackendUsageException( - code = BackendUsageErrorCode.UNVALID_PROPERTY, - data = "La mise en demeure ne peut pas être \"en attente\"", - ) - } - } - } - } - - private fun validateSurveillance( - surveillance: EnvActionSurveillanceEntity, - mission: MissionEntity, - isMissionEnded: Boolean, - ) { - validateEnvAction(surveillance, mission) - - if (surveillance.geom === null) { - throw BackendUsageException( - code = BackendUsageErrorCode.UNVALID_PROPERTY, - data = "La géométrie de la surveillance est obligatoire", - ) - } - if (surveillance.completedBy !== null && surveillance.completedBy.length != NB_CHAR_MAX) { - throw BackendUsageException( - code = BackendUsageErrorCode.UNVALID_PROPERTY, - data = "Le trigramme \"complété par\" doit avoir 3 lettres", - ) - } - if (surveillance.actionEndDateTimeUtc?.isAfter(mission.endDateTimeUtc) == true) { - logger.info("Validating mission surveillance: ${surveillance.actionEndDateTimeUtc}") - logger.info("Validating mission: ${mission.endDateTimeUtc}") - throw BackendUsageException( - code = BackendUsageErrorCode.UNVALID_PROPERTY, - data = - "La date de fin de la surveillance doit être antérieure à celle de fin de mission", - ) - } - if (surveillance.actionEndDateTimeUtc?.isBefore(mission.startDateTimeUtc) == true) { - throw BackendUsageException( - code = BackendUsageErrorCode.UNVALID_PROPERTY, - data = - "La date de fin de la surveillance doit être postérieure à celle du début de mission", - ) - } - if (isMissionEnded) { - validateControlPlan(surveillance) - } - } - - private fun validateEnvAction( - envAction: EnvActionEntity, - mission: MissionEntity, - ) { - val actionType = - if (envAction.actionType === ActionTypeEnum.CONTROL) { - "du contrôle" - } else { - "de la surveillance" - } - if (envAction.actionStartDateTimeUtc?.isBefore(mission.startDateTimeUtc) == true) { - throw BackendUsageException( - code = BackendUsageErrorCode.UNVALID_PROPERTY, - data = - "La date de début $actionType doit être postérieure à celle du début de mission", - ) - } - if (envAction.actionStartDateTimeUtc?.isAfter(mission.endDateTimeUtc) == true) { - throw BackendUsageException( - code = BackendUsageErrorCode.UNVALID_PROPERTY, - data = - "La date de début $actionType doit être antérieure à celle de fin de mission", - ) - } - if (envAction.openBy?.length != NB_CHAR_MAX) { - throw BackendUsageException( - code = BackendUsageErrorCode.UNVALID_PROPERTY, - data = "Le trigramme \"ouvert par\" doit avoir 3 lettres", - ) - } - } - - private fun validateControlPlan(envAction: EnvActionEntity) { - if (envAction.controlPlans?.isEmpty() == true) { - throw BackendUsageException( - code = BackendUsageErrorCode.UNVALID_PROPERTY, - data = "Le plan de contrôle est obligatoire", - ) - } else { - envAction.controlPlans?.forEach { controlPlan -> - if (controlPlan.subThemeIds?.isEmpty() == true) { - throw BackendUsageException( - code = BackendUsageErrorCode.UNVALID_PROPERTY, - data = "Le sous-thème du plan de contrôle est obligatoire", - ) - } - } - } } } diff --git a/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/domain/validators/mission/MissionWithEnvActionsValidator.kt b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/domain/validators/mission/MissionWithEnvActionsValidator.kt new file mode 100644 index 000000000..49ef5719a --- /dev/null +++ b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/domain/validators/mission/MissionWithEnvActionsValidator.kt @@ -0,0 +1,228 @@ +package fr.gouv.cacem.monitorenv.domain.validators.mission + +import fr.gouv.cacem.monitorenv.domain.entities.mission.MissionEntity +import fr.gouv.cacem.monitorenv.domain.entities.mission.envAction.ActionTypeEnum +import fr.gouv.cacem.monitorenv.domain.entities.mission.envAction.EnvActionEntity +import fr.gouv.cacem.monitorenv.domain.entities.mission.envAction.envActionControl.ActionTargetTypeEnum +import fr.gouv.cacem.monitorenv.domain.entities.mission.envAction.envActionControl.EnvActionControlEntity +import fr.gouv.cacem.monitorenv.domain.entities.mission.envAction.envActionControl.infraction.AdministrativeResponseEnum +import fr.gouv.cacem.monitorenv.domain.entities.mission.envAction.envActionControl.infraction.FormalNoticeEnum +import fr.gouv.cacem.monitorenv.domain.entities.mission.envAction.envActionControl.infraction.InfractionTypeEnum +import fr.gouv.cacem.monitorenv.domain.entities.mission.envAction.envActionControl.infraction.SeizureTypeEnum +import fr.gouv.cacem.monitorenv.domain.entities.mission.envAction.envActionSurveillance.EnvActionSurveillanceEntity +import fr.gouv.cacem.monitorenv.domain.exceptions.BackendUsageErrorCode +import fr.gouv.cacem.monitorenv.domain.exceptions.BackendUsageException +import fr.gouv.cacem.monitorenv.domain.validators.Validator +import org.slf4j.LoggerFactory +import org.springframework.stereotype.Component +import java.time.ZonedDateTime + +private const val NB_CHAR_MAX = 3 + +@Component +class MissionWithEnvActionsValidator(private val missionValidator: MissionValidator) : Validator { + private val logger = LoggerFactory.getLogger(MissionWithEnvActionsValidator::class.java) + + override fun validate(mission: MissionEntity) { + missionValidator.validate(mission) + + validateEnvActions(mission) + } + + private fun validateEnvActions(mission: MissionEntity) { + val isMissionEnded = + mission.endDateTimeUtc != null && + ZonedDateTime.now().isAfter(mission.endDateTimeUtc) + + mission.envActions?.forEach { envAction -> + if (envAction is EnvActionControlEntity) { + validateControl(envAction, mission, isMissionEnded) + } + + if (envAction is EnvActionSurveillanceEntity) { + validateSurveillance(envAction, mission, isMissionEnded) + } + } + } + + private fun validateControl( + control: EnvActionControlEntity, + mission: MissionEntity, + isMissionEnded: Boolean, + ) { + validateEnvAction(control, mission) + + if (isMissionEnded) { + if (control.geom === null) { + throw BackendUsageException( + code = BackendUsageErrorCode.UNVALID_PROPERTY, + data = "La géométrie du contrôle est obligatoire", + ) + } + if (control.vehicleType === null && + control.actionTargetType === ActionTargetTypeEnum.VEHICLE + ) { + throw BackendUsageException( + code = BackendUsageErrorCode.UNVALID_PROPERTY, + data = "Le type de véhicule est obligatoire", + ) + } + validateControlPlan(control) + } + + validateInfractions(control, isMissionEnded) + } + + private fun validateInfractions( + control: EnvActionControlEntity, + isMissionEnded: Boolean, + ) { + val sumOfNbTarget = control.infractions?.sumOf { infraction -> infraction.nbTarget } + if (sumOfNbTarget != 0 && + sumOfNbTarget != null && + ( + control.actionNumberOfControls != null && + sumOfNbTarget > control.actionNumberOfControls + ) + ) { + throw BackendUsageException( + code = BackendUsageErrorCode.UNVALID_PROPERTY, + data = "Le nombre de cibles excède le nombre total de contrôles", + ) + } + + control.infractions?.forEach { infraction -> + if (infraction.infractionType !== InfractionTypeEnum.WAITING && + infraction.natinf?.isEmpty() == true + ) { + throw BackendUsageException( + code = BackendUsageErrorCode.UNVALID_PROPERTY, + data = + "Une infraction doit avoir une natinf si le type d'infraction n'est pas \"En attente\"", + ) + } + if (infraction.nbTarget < 1) { + throw BackendUsageException( + code = BackendUsageErrorCode.UNVALID_PROPERTY, + data = "le nombre minimum de cible est 1", + ) + } + if (isMissionEnded) { + if (infraction.infractionType === InfractionTypeEnum.WAITING) { + throw BackendUsageException( + code = BackendUsageErrorCode.UNVALID_PROPERTY, + data = "Le type d'infraction ne peut pas être \"en attente\"", + ) + } + if (infraction.seizure === SeizureTypeEnum.PENDING) { + throw BackendUsageException( + code = BackendUsageErrorCode.UNVALID_PROPERTY, + data = "L'appréhension/saisie ne peut pas être \"en attente\"", + ) + } + if (infraction.administrativeResponse === AdministrativeResponseEnum.PENDING) { + throw BackendUsageException( + code = BackendUsageErrorCode.UNVALID_PROPERTY, + data = "La réponse administrative ne peut pas être \"en attente\"", + ) + } + if (infraction.formalNotice === FormalNoticeEnum.PENDING) { + throw BackendUsageException( + code = BackendUsageErrorCode.UNVALID_PROPERTY, + data = "La mise en demeure ne peut pas être \"en attente\"", + ) + } + } + } + } + + private fun validateSurveillance( + surveillance: EnvActionSurveillanceEntity, + mission: MissionEntity, + isMissionEnded: Boolean, + ) { + validateEnvAction(surveillance, mission) + + if (surveillance.geom === null) { + throw BackendUsageException( + code = BackendUsageErrorCode.UNVALID_PROPERTY, + data = "La géométrie de la surveillance est obligatoire", + ) + } + if (surveillance.completedBy !== null && surveillance.completedBy.length != NB_CHAR_MAX) { + throw BackendUsageException( + code = BackendUsageErrorCode.UNVALID_PROPERTY, + data = "Le trigramme \"complété par\" doit avoir 3 lettres", + ) + } + if (surveillance.actionEndDateTimeUtc?.isAfter(mission.endDateTimeUtc) == true) { + logger.info("Validating mission surveillance: ${surveillance.actionEndDateTimeUtc}") + logger.info("Validating mission: ${mission.endDateTimeUtc}") + throw BackendUsageException( + code = BackendUsageErrorCode.UNVALID_PROPERTY, + data = + "La date de fin de la surveillance doit être antérieure à celle de fin de mission", + ) + } + if (surveillance.actionEndDateTimeUtc?.isBefore(mission.startDateTimeUtc) == true) { + throw BackendUsageException( + code = BackendUsageErrorCode.UNVALID_PROPERTY, + data = + "La date de fin de la surveillance doit être postérieure à celle du début de mission", + ) + } + if (isMissionEnded) { + validateControlPlan(surveillance) + } + } + + private fun validateEnvAction( + envAction: EnvActionEntity, + mission: MissionEntity, + ) { + val actionType = + if (envAction.actionType === ActionTypeEnum.CONTROL) { + "du contrôle" + } else { + "de la surveillance" + } + if (envAction.actionStartDateTimeUtc?.isBefore(mission.startDateTimeUtc) == true) { + throw BackendUsageException( + code = BackendUsageErrorCode.UNVALID_PROPERTY, + data = + "La date de début $actionType doit être postérieure à celle du début de mission", + ) + } + if (envAction.actionStartDateTimeUtc?.isAfter(mission.endDateTimeUtc) == true) { + throw BackendUsageException( + code = BackendUsageErrorCode.UNVALID_PROPERTY, + data = + "La date de début $actionType doit être antérieure à celle de fin de mission", + ) + } + if (envAction.openBy?.length != NB_CHAR_MAX) { + throw BackendUsageException( + code = BackendUsageErrorCode.UNVALID_PROPERTY, + data = "Le trigramme \"ouvert par\" doit avoir 3 lettres", + ) + } + } + + private fun validateControlPlan(envAction: EnvActionEntity) { + if (envAction.controlPlans?.isEmpty() == true) { + throw BackendUsageException( + code = BackendUsageErrorCode.UNVALID_PROPERTY, + data = "Le plan de contrôle est obligatoire", + ) + } else { + envAction.controlPlans?.forEach { controlPlan -> + if (controlPlan.subThemeIds?.isEmpty() == true) { + throw BackendUsageException( + code = BackendUsageErrorCode.UNVALID_PROPERTY, + data = "Le sous-thème du plan de contrôle est obligatoire", + ) + } + } + } + } +} diff --git a/backend/src/test/kotlin/fr/gouv/cacem/monitorenv/domain/use_cases/missions/CreateOrUpdateMissionUTests.kt b/backend/src/test/kotlin/fr/gouv/cacem/monitorenv/domain/use_cases/missions/CreateOrUpdateMissionUTests.kt index e3ed7c243..c7ae2dfe9 100644 --- a/backend/src/test/kotlin/fr/gouv/cacem/monitorenv/domain/use_cases/missions/CreateOrUpdateMissionUTests.kt +++ b/backend/src/test/kotlin/fr/gouv/cacem/monitorenv/domain/use_cases/missions/CreateOrUpdateMissionUTests.kt @@ -1,6 +1,10 @@ package fr.gouv.cacem.monitorenv.domain.use_cases.missions -import com.nhaarman.mockitokotlin2.* +import com.nhaarman.mockitokotlin2.anyOrNull +import com.nhaarman.mockitokotlin2.argThat +import com.nhaarman.mockitokotlin2.given +import com.nhaarman.mockitokotlin2.times +import com.nhaarman.mockitokotlin2.verify import fr.gouv.cacem.monitorenv.domain.entities.mission.MissionEntity import fr.gouv.cacem.monitorenv.domain.entities.mission.MissionSourceEnum import fr.gouv.cacem.monitorenv.domain.entities.mission.MissionTypeEnum @@ -24,7 +28,7 @@ import org.springframework.boot.test.system.OutputCaptureExtension import org.springframework.context.ApplicationEventPublisher import org.springframework.test.context.junit.jupiter.SpringExtension import java.time.ZonedDateTime -import java.util.* +import java.util.UUID @ExtendWith(SpringExtension::class) @ExtendWith(OutputCaptureExtension::class) diff --git a/backend/src/test/kotlin/fr/gouv/cacem/monitorenv/domain/validators/mission/MissionValidatorUTest.kt b/backend/src/test/kotlin/fr/gouv/cacem/monitorenv/domain/validators/mission/MissionValidatorUTest.kt index fa2474319..d2a284fa0 100644 --- a/backend/src/test/kotlin/fr/gouv/cacem/monitorenv/domain/validators/mission/MissionValidatorUTest.kt +++ b/backend/src/test/kotlin/fr/gouv/cacem/monitorenv/domain/validators/mission/MissionValidatorUTest.kt @@ -1,9 +1,18 @@ package fr.gouv.cacem.monitorenv.domain.validators.mission +import fr.gouv.cacem.monitorenv.domain.exceptions.BackendUsageException +import fr.gouv.cacem.monitorenv.domain.use_cases.missions.fixtures.MissionFixture.Companion.aMissionEntity +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Assertions.assertThrows +import org.junit.jupiter.api.Test +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.ValueSource +import java.time.ZonedDateTime + class MissionValidatorUTest { private val missionValidator = MissionValidator() - /* @Test + @Test fun `validate should throw an exception if startDateTimeUtc is after endDateTimeUtc`() { val startDateTimeUtc = ZonedDateTime.parse("2020-03-04T00:00:00.000Z") val mission = @@ -13,7 +22,7 @@ class MissionValidatorUTest { ) val assertThrows = assertThrows(BackendUsageException::class.java) { missionValidator.validate(mission) } - assertThat(assertThrows.message).isEqualTo("La date de fin doit être postérieure à la date de début") + assertThat(assertThrows.data).isEqualTo("La date de fin doit être postérieure à la date de début") } @Test @@ -21,7 +30,7 @@ class MissionValidatorUTest { val mission = aMissionEntity(controlUnits = emptyList()) val assertThrows = assertThrows(BackendUsageException::class.java) { missionValidator.validate(mission) } - assertThat(assertThrows.message).isEqualTo("Une unité de contrôle est requise") + assertThat(assertThrows.data).isEqualTo("Une unité de contrôle est requise") } @Test @@ -29,7 +38,7 @@ class MissionValidatorUTest { val mission = aMissionEntity(missionTypes = emptyList()) val assertThrows = assertThrows(BackendUsageException::class.java) { missionValidator.validate(mission) } - assertThat(assertThrows.message).isEqualTo("Le type de mission est requis") + assertThat(assertThrows.data).isEqualTo("Le type de mission est requis") } @ParameterizedTest @@ -38,7 +47,7 @@ class MissionValidatorUTest { val mission = aMissionEntity(openBy = openBy) val assertThrows = assertThrows(BackendUsageException::class.java) { missionValidator.validate(mission) } - assertThat(assertThrows.message).isEqualTo("Le trigramme \"ouvert par\" doit avoir 3 lettres") + assertThat(assertThrows.data).isEqualTo("Le trigramme \"ouvert par\" doit avoir 3 lettres") } @ParameterizedTest @@ -47,330 +56,7 @@ class MissionValidatorUTest { val mission = aMissionEntity(completedBy = completedBy) val assertThrows = assertThrows(BackendUsageException::class.java) { missionValidator.validate(mission) } - assertThat(assertThrows.message).isEqualTo("Le trigramme \"complété par\" doit avoir 3 lettres") - } - - @Test - fun `validate should throw an exception if there is a control with a start date before mission starting date`() { - val startDateTimeUtc = ZonedDateTime.parse("2020-03-04T00:00:00.000Z") - val anEnvActionControl = anEnvActionControl(startTime = startDateTimeUtc.minusSeconds(1)) - val mission = aMissionEntity(startDateTimeUtc = startDateTimeUtc, envActions = listOf(anEnvActionControl)) - - val assertThrows = assertThrows(BackendUsageException::class.java) { missionValidator.validate(mission) } - assertThat( - assertThrows.message, - ).isEqualTo("La date de début du contrôle doit être postérieure à celle du début de mission") - } - - @Test - fun `validate should pass if there is a control with the same start date as mission's`() { - val startDateTimeUtc = ZonedDateTime.parse("2020-03-04T00:00:00.000Z") - val endDateTimeUtc = ZonedDateTime.parse("2021-03-04T00:00:00.000Z") - val anEnvActionControl = anEnvActionControl(startTime = startDateTimeUtc) - val mission = - aMissionEntity( - startDateTimeUtc = startDateTimeUtc, - endDateTimeUtc = endDateTimeUtc, - envActions = listOf(anEnvActionControl), - ) - - missionValidator.validate(mission) - } - - @Test - fun `validate should pass if there is a control without geometry when mission has ended`() { - val endDateTimeUtc = ZonedDateTime.now().minusSeconds(1) - val anEnvActionControl = anEnvActionControl(geom = null) - val mission = - aMissionEntity( - endDateTimeUtc = endDateTimeUtc, - envActions = listOf(anEnvActionControl), - ) - - val assertThrows = assertThrows(BackendUsageException::class.java) { missionValidator.validate(mission) } - assertThat(assertThrows.message).isEqualTo("La géométrie du contrôle est obligatoire") - } - - @ParameterizedTest - @EnumSource(value = InfractionTypeEnum::class, names = ["WAITING"], mode = EnumSource.Mode.EXCLUDE) - fun `validate should throw an exception if there is a control with infractionType other than WAITING that doesnt have a NATINF`( - infractionType: InfractionTypeEnum, - ) { - val anEnvActionControl = - anEnvActionControl(infractions = listOf(anInfraction(infractionType = infractionType, natinf = listOf()))) - val mission = aMissionEntity(envActions = listOf(anEnvActionControl)) - - val assertThrows = assertThrows(BackendUsageException::class.java) { missionValidator.validate(mission) } - assertThat( - assertThrows.message, - ).isEqualTo("Une infraction doit avoir une natinf si le type d'infraction n'est pas \"En attente\"") - } - - @Test - fun `validate should throw an exception if there is a control with infractionType is WAITING when mission has ended`() { - val endDateTimeUtc = ZonedDateTime.now().minusSeconds(1) - val anEnvActionControl = - anEnvActionControl(infractions = listOf(anInfraction(infractionType = InfractionTypeEnum.WAITING))) - val mission = aMissionEntity(endDateTimeUtc = endDateTimeUtc, envActions = listOf(anEnvActionControl)) - - val assertThrows = assertThrows(BackendUsageException::class.java) { missionValidator.validate(mission) } - assertThat( - assertThrows.message, - ).isEqualTo("Le type d'infraction ne peut pas être \"en attente\"") - } - - @Test - fun `validate should throw an exception if there is a control with administrativeResponse is WAITING when mission has ended`() { - val endDateTimeUtc = ZonedDateTime.now().minusSeconds(1) - val anEnvActionControl = - anEnvActionControl( - infractions = listOf(anInfraction(administrativeResponse = AdministrativeResponseEnum.PENDING)), - ) - val mission = aMissionEntity(endDateTimeUtc = endDateTimeUtc, envActions = listOf(anEnvActionControl)) - - val assertThrows = assertThrows(BackendUsageException::class.java) { missionValidator.validate(mission) } - assertThat( - assertThrows.message, - ).isEqualTo("La réponse administrative ne peut pas être \"en attente\"") - } - - @Test - fun `validate should throw an exception if there is a control with seizure is PENDING when mission has ended`() { - val endDateTimeUtc = ZonedDateTime.now().minusSeconds(1) - val anEnvActionControl = - anEnvActionControl(infractions = listOf(anInfraction(seizure = SeizureTypeEnum.PENDING))) - val mission = aMissionEntity(endDateTimeUtc = endDateTimeUtc, envActions = listOf(anEnvActionControl)) - - val assertThrows = assertThrows(BackendUsageException::class.java) { missionValidator.validate(mission) } - assertThat( - assertThrows.message, - ).isEqualTo("L'appréhension/saisie ne peut pas être \"en attente\"") - } - - @Test - fun `validate should throw an exception if there is a control with formalNotice is PENDING when mission has ended`() { - val endDateTimeUtc = ZonedDateTime.now().minusSeconds(1) - val anEnvActionControl = - anEnvActionControl(infractions = listOf(anInfraction(formalNotice = FormalNoticeEnum.PENDING))) - val mission = aMissionEntity(endDateTimeUtc = endDateTimeUtc, envActions = listOf(anEnvActionControl)) - - val assertThrows = assertThrows(BackendUsageException::class.java) { missionValidator.validate(mission) } - assertThat( - assertThrows.message, - ).isEqualTo("La mise en demeure ne peut pas être \"en attente\"") - } - - @Test - fun `validate should throw an exception if there is a control with infraction and nbTarget is less than 1`() { - val anEnvActionControl = anEnvActionControl(infractions = listOf(anInfraction(nbTarget = 0))) - val mission = aMissionEntity(envActions = listOf(anEnvActionControl)) - - val assertThrows = assertThrows(BackendUsageException::class.java) { missionValidator.validate(mission) } - assertThat(assertThrows.message).isEqualTo("le nombre minimum de cible est 1") - } - - @Test - fun `validate should throw an exception if there is a control with infractions that got more nbTarget than the mission actionNumberOfControls `() { - val anEnvActionControl = - anEnvActionControl( - actionNumberOfControls = 10, - infractions = listOf(anInfraction(nbTarget = 10), anInfraction(nbTarget = 5)), - ) - val mission = aMissionEntity(envActions = listOf(anEnvActionControl)) - - val assertThrows = assertThrows(BackendUsageException::class.java) { missionValidator.validate(mission) } - assertThat(assertThrows.message).isEqualTo("Le nombre de cibles excède le nombre total de contrôles") - } - - @Test - fun `validate should pass if there is a control with infractions that got less nbTarget than the mission actionNumberOfControls `() { - val anEnvActionControl = - anEnvActionControl( - actionNumberOfControls = 2, - infractions = listOf(anInfraction(nbTarget = 1)), - ) - val mission = aMissionEntity(envActions = listOf(anEnvActionControl)) - - missionValidator.validate(mission) - } - - @Test - fun `validate should pass if there is a control with infractionType = WAITING that doesnt have a NATINF`() { - val anEnvActionControl = - anEnvActionControl(infractions = listOf(anInfraction(infractionType = InfractionTypeEnum.WAITING))) - val mission = aMissionEntity(envActions = listOf(anEnvActionControl)) - - missionValidator.validate(mission) - } - - @ParameterizedTest - @ValueSource(strings = ["A", "AA", "AAAA"]) - fun `validate should throw an exception if there is a control with openBy is not a trigram`(openBy: String) { - val anEnvActionControl = anEnvActionControl(openBy = openBy) - val mission = aMissionEntity(envActions = listOf(anEnvActionControl)) - - val assertThrows = assertThrows(BackendUsageException::class.java) { missionValidator.validate(mission) } - assertThat(assertThrows.message).isEqualTo("Le trigramme \"ouvert par\" doit avoir 3 lettres") - } - - @Test - fun `validate should throw an exception if there is a control without control plans when mission has ended`() { - val endDateTimeUtc = ZonedDateTime.now().minusSeconds(1) - val anEnvActionControl = anEnvActionControl(controlPlans = listOf()) - val mission = aMissionEntity(endDateTimeUtc = endDateTimeUtc, envActions = listOf(anEnvActionControl)) - - val assertThrows = assertThrows(BackendUsageException::class.java) { missionValidator.validate(mission) } - assertThat(assertThrows.message).isEqualTo("Le plan de contrôle est obligatoire") - } - - @Test - fun `validate should throw an exception if there is a control with control plan without subtheme when mission has ended`() { - val endDateTimeUtc = ZonedDateTime.now().minusSeconds(1) - val anEnvActionControl = - anEnvActionControl(controlPlans = listOf(EnvActionControlPlanEntity(subThemeIds = listOf()))) - val mission = aMissionEntity(endDateTimeUtc = endDateTimeUtc, envActions = listOf(anEnvActionControl)) - - val assertThrows = assertThrows(BackendUsageException::class.java) { missionValidator.validate(mission) } - assertThat(assertThrows.message).isEqualTo("Le sous-thème du plan de contrôle est obligatoire") - } - - @Test - fun `validate should throw an exception if there is a control actionTargetType as VEHICULE without vehiculeType when mission has ended`() { - val endDateTimeUtc = ZonedDateTime.now().minusSeconds(1) - val anEnvActionControl = anEnvActionControl(actionTargetTypeEnum = ActionTargetTypeEnum.VEHICLE) - val mission = aMissionEntity(endDateTimeUtc = endDateTimeUtc, envActions = listOf(anEnvActionControl)) - - val assertThrows = assertThrows(BackendUsageException::class.java) { missionValidator.validate(mission) } - assertThat(assertThrows.message).isEqualTo("Le type de véhicule est obligatoire") - } - - @ParameterizedTest - @EnumSource(value = ActionTargetTypeEnum::class, names = ["VEHICLE"], mode = EnumSource.Mode.EXCLUDE) - fun `validate should pass if there is a control actionTargetType as targetType other than VEHICLE without vehiculeType when mission has ended`( - targetType: ActionTargetTypeEnum, - ) { - val endDateTimeUtc = ZonedDateTime.now().minusSeconds(1) - val anEnvActionControl = anEnvActionControl(actionTargetTypeEnum = targetType) - val mission = aMissionEntity(endDateTimeUtc = endDateTimeUtc, envActions = listOf(anEnvActionControl)) - - missionValidator.validate(mission) - } - - @Test - fun `validate should throw an exception if there is a surveillance with a start date before mission starting date`() { - val startDateTimeUtc = ZonedDateTime.parse("2020-03-04T00:00:00.000Z") - val anEnvActionSurveillance = anEnvActionSurveillance(startTime = startDateTimeUtc.minusSeconds(1)) - val mission = aMissionEntity(startDateTimeUtc = startDateTimeUtc, envActions = listOf(anEnvActionSurveillance)) - - val assertThrows = assertThrows(BackendUsageException::class.java) { missionValidator.validate(mission) } - assertThat( - assertThrows.message, - ).isEqualTo("La date de début de la surveillance doit être postérieure à celle du début de mission") - } - - @Test - fun `validate should throw an exception if there is a surveillance with a start date after mission ending date`() { - val startDateTimeUtc = ZonedDateTime.parse("2019-03-04T00:00:00.000Z") - val endDateTimeUtc = ZonedDateTime.parse("2020-03-04T00:00:00.000Z") - val anEnvActionSurveillance = anEnvActionSurveillance(endTime = endDateTimeUtc.plusSeconds(1)) - val mission = - aMissionEntity( - startDateTimeUtc = startDateTimeUtc, - endDateTimeUtc = endDateTimeUtc, - envActions = listOf(anEnvActionSurveillance), - ) - - val assertThrows = assertThrows(BackendUsageException::class.java) { missionValidator.validate(mission) } - assertThat( - assertThrows.message, - ).isEqualTo("La date de fin de la surveillance doit être antérieure à celle de fin de mission") - } - - @Test - fun `validate should throw an exception if there is a surveillance with an end date after mission ending date`() { - val startDateTimeUtc = ZonedDateTime.parse("2019-03-04T00:00:00.000Z") - val endDateTimeUtc = ZonedDateTime.parse("2020-03-04T00:00:00.000Z") - val anEnvActionSurveillance = anEnvActionSurveillance(endTime = endDateTimeUtc.plusSeconds(1)) - val mission = - aMissionEntity( - startDateTimeUtc = startDateTimeUtc, - endDateTimeUtc = endDateTimeUtc, - envActions = listOf(anEnvActionSurveillance), - ) - - val assertThrows = assertThrows(BackendUsageException::class.java) { missionValidator.validate(mission) } - assertThat( - assertThrows.message, - ).isEqualTo("La date de fin de la surveillance doit être antérieure à celle de fin de mission") - } - - @Test - fun `validate should throw an exception if there is a surveillance with an end date before mission starting date`() { - val startDateTimeUtc = ZonedDateTime.parse("2020-03-04T00:00:00.000Z") - val endDateTimeUtc = ZonedDateTime.parse("2021-03-04T00:00:00.000Z") - - val anEnvActionSurveillance = anEnvActionSurveillance(endTime = startDateTimeUtc.minusSeconds(1)) - val mission = - aMissionEntity( - startDateTimeUtc = startDateTimeUtc, - endDateTimeUtc = endDateTimeUtc, - envActions = listOf(anEnvActionSurveillance), - ) - - val assertThrows = assertThrows(BackendUsageException::class.java) { missionValidator.validate(mission) } - assertThat( - assertThrows.message, - ).isEqualTo("La date de fin de la surveillance doit être postérieure à celle du début de mission") - } - - @Test - fun `validate should pass if there is a surveillance with an date equal to mission's`() { - val startDateTimeUtc = ZonedDateTime.parse("2020-03-04T00:00:00.000Z") - val endDateTimeUtc = ZonedDateTime.parse("2020-03-04T00:00:00.000Z") - val anEnvActionSurveillance = anEnvActionSurveillance(startTime = startDateTimeUtc, endTime = endDateTimeUtc) - val mission = - aMissionEntity( - startDateTimeUtc = startDateTimeUtc, - endDateTimeUtc = endDateTimeUtc, - envActions = listOf(anEnvActionSurveillance), - ) - - missionValidator.validate(mission) - } - - @Test - fun `validate should pass if there is a surveillance without geometry`() { - val endDateTimeUtc = ZonedDateTime.now().minusSeconds(1) - val anEnvActionSurveillance = anEnvActionSurveillance(geom = null) - val mission = - aMissionEntity( - endDateTimeUtc = endDateTimeUtc, - envActions = listOf(anEnvActionSurveillance), - ) - - val assertThrows = assertThrows(BackendUsageException::class.java) { missionValidator.validate(mission) } - assertThat(assertThrows.message).isEqualTo("La géométrie de la surveillance est obligatoire") - } - - @Test - fun `validate should throw an exception if there is a surveillance without control plans when mission has ended`() { - val endDateTimeUtc = ZonedDateTime.now().minusSeconds(1) - val anEnvActionSurveillance = anEnvActionSurveillance(controlPlans = listOf()) - val mission = aMissionEntity(endDateTimeUtc = endDateTimeUtc, envActions = listOf(anEnvActionSurveillance)) - - val assertThrows = assertThrows(BackendUsageException::class.java) { missionValidator.validate(mission) } - assertThat(assertThrows.message).isEqualTo("Le plan de contrôle est obligatoire") - } - - @Test - fun `validate should throw an exception if there is a surveillance with control plan without subtheme when mission has ended`() { - val endDateTimeUtc = ZonedDateTime.now().minusSeconds(1) - val anEnvActionSurveillance = - anEnvActionSurveillance(controlPlans = listOf(EnvActionControlPlanEntity(subThemeIds = listOf()))) - val mission = aMissionEntity(endDateTimeUtc = endDateTimeUtc, envActions = listOf(anEnvActionSurveillance)) - - val assertThrows = assertThrows(BackendUsageException::class.java) { missionValidator.validate(mission) } - assertThat(assertThrows.message).isEqualTo("Le sous-thème du plan de contrôle est obligatoire") + assertThat(assertThrows.data).isEqualTo("Le trigramme \"complété par\" doit avoir 3 lettres") } @Test @@ -378,5 +64,5 @@ class MissionValidatorUTest { val mission = aMissionEntity() missionValidator.validate(mission) - } */ + } } diff --git a/backend/src/test/kotlin/fr/gouv/cacem/monitorenv/domain/validators/mission/MissionValidatorWithEnvActionsUTest.kt b/backend/src/test/kotlin/fr/gouv/cacem/monitorenv/domain/validators/mission/MissionValidatorWithEnvActionsUTest.kt new file mode 100644 index 000000000..24d0ec533 --- /dev/null +++ b/backend/src/test/kotlin/fr/gouv/cacem/monitorenv/domain/validators/mission/MissionValidatorWithEnvActionsUTest.kt @@ -0,0 +1,387 @@ +package fr.gouv.cacem.monitorenv.domain.validators.mission + +import com.nhaarman.mockitokotlin2.verify +import fr.gouv.cacem.monitorenv.domain.entities.mission.envAction.EnvActionControlPlanEntity +import fr.gouv.cacem.monitorenv.domain.entities.mission.envAction.envActionControl.ActionTargetTypeEnum +import fr.gouv.cacem.monitorenv.domain.entities.mission.envAction.envActionControl.infraction.AdministrativeResponseEnum +import fr.gouv.cacem.monitorenv.domain.entities.mission.envAction.envActionControl.infraction.FormalNoticeEnum +import fr.gouv.cacem.monitorenv.domain.entities.mission.envAction.envActionControl.infraction.InfractionTypeEnum +import fr.gouv.cacem.monitorenv.domain.entities.mission.envAction.envActionControl.infraction.SeizureTypeEnum +import fr.gouv.cacem.monitorenv.domain.exceptions.BackendUsageException +import fr.gouv.cacem.monitorenv.domain.use_cases.actions.fixtures.EnvActionFixture.Companion.anEnvActionControl +import fr.gouv.cacem.monitorenv.domain.use_cases.actions.fixtures.EnvActionFixture.Companion.anEnvActionSurveillance +import fr.gouv.cacem.monitorenv.domain.use_cases.actions.fixtures.EnvActionFixture.Companion.anInfraction +import fr.gouv.cacem.monitorenv.domain.use_cases.missions.fixtures.MissionFixture.Companion.aMissionEntity +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Assertions.assertThrows +import org.junit.jupiter.api.Test +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.EnumSource +import org.junit.jupiter.params.provider.ValueSource +import org.mockito.Mock +import org.mockito.Mockito.mock +import java.time.ZonedDateTime + +class MissionValidatorWithEnvActionsUTest { + @Mock + private val missionValidator: MissionValidator = mock() + private val missionWithEnvActionsValidator = MissionWithEnvActionsValidator(missionValidator) + + @Test + fun `validate call mission validator`() { + val mission = aMissionEntity() + + missionWithEnvActionsValidator.validate(mission) + verify(missionValidator).validate(mission) + } + + @Test + fun `validate should throw an exception if there is a control with a start date before mission starting date`() { + val startDateTimeUtc = ZonedDateTime.parse("2020-03-04T00:00:00.000Z") + val anEnvActionControl = anEnvActionControl(startTime = startDateTimeUtc.minusSeconds(1)) + val mission = aMissionEntity(startDateTimeUtc = startDateTimeUtc, envActions = listOf(anEnvActionControl)) + + val assertThrows = + assertThrows(BackendUsageException::class.java) { missionWithEnvActionsValidator.validate(mission) } + assertThat( + assertThrows.data, + ).isEqualTo("La date de début du contrôle doit être postérieure à celle du début de mission") + } + + @Test + fun `validate should pass if there is a control with the same start date as mission's`() { + val startDateTimeUtc = ZonedDateTime.parse("2020-03-04T00:00:00.000Z") + val endDateTimeUtc = ZonedDateTime.parse("2021-03-04T00:00:00.000Z") + val anEnvActionControl = anEnvActionControl(startTime = startDateTimeUtc) + val mission = + aMissionEntity( + startDateTimeUtc = startDateTimeUtc, + endDateTimeUtc = endDateTimeUtc, + envActions = listOf(anEnvActionControl), + ) + + missionWithEnvActionsValidator.validate(mission) + } + + @Test + fun `validate should pass if there is a control without geometry when mission has ended`() { + val endDateTimeUtc = ZonedDateTime.now().minusSeconds(1) + val anEnvActionControl = anEnvActionControl(geom = null) + val mission = + aMissionEntity( + endDateTimeUtc = endDateTimeUtc, + envActions = listOf(anEnvActionControl), + ) + + val assertThrows = + assertThrows(BackendUsageException::class.java) { missionWithEnvActionsValidator.validate(mission) } + assertThat(assertThrows.data).isEqualTo("La géométrie du contrôle est obligatoire") + } + + @ParameterizedTest + @EnumSource(value = InfractionTypeEnum::class, names = ["WAITING"], mode = EnumSource.Mode.EXCLUDE) + fun `validate should throw an exception if there is a control with infractionType other than WAITING that doesnt have a NATINF`( + infractionType: InfractionTypeEnum, + ) { + val anEnvActionControl = + anEnvActionControl(infractions = listOf(anInfraction(infractionType = infractionType, natinf = listOf()))) + val mission = aMissionEntity(envActions = listOf(anEnvActionControl)) + + val assertThrows = + assertThrows(BackendUsageException::class.java) { missionWithEnvActionsValidator.validate(mission) } + assertThat( + assertThrows.data, + ).isEqualTo("Une infraction doit avoir une natinf si le type d'infraction n'est pas \"En attente\"") + } + + @Test + fun `validate should throw an exception if there is a control with infractionType is WAITING when mission has ended`() { + val endDateTimeUtc = ZonedDateTime.now().minusSeconds(1) + val anEnvActionControl = + anEnvActionControl(infractions = listOf(anInfraction(infractionType = InfractionTypeEnum.WAITING))) + val mission = aMissionEntity(endDateTimeUtc = endDateTimeUtc, envActions = listOf(anEnvActionControl)) + + val assertThrows = + assertThrows(BackendUsageException::class.java) { missionWithEnvActionsValidator.validate(mission) } + assertThat( + assertThrows.data, + ).isEqualTo("Le type d'infraction ne peut pas être \"en attente\"") + } + + @Test + fun `validate should throw an exception if there is a control with administrativeResponse is WAITING when mission has ended`() { + val endDateTimeUtc = ZonedDateTime.now().minusSeconds(1) + val anEnvActionControl = + anEnvActionControl( + infractions = listOf(anInfraction(administrativeResponse = AdministrativeResponseEnum.PENDING)), + ) + val mission = aMissionEntity(endDateTimeUtc = endDateTimeUtc, envActions = listOf(anEnvActionControl)) + + val assertThrows = + assertThrows(BackendUsageException::class.java) { missionWithEnvActionsValidator.validate(mission) } + assertThat( + assertThrows.data, + ).isEqualTo("La réponse administrative ne peut pas être \"en attente\"") + } + + @Test + fun `validate should throw an exception if there is a control with seizure is PENDING when mission has ended`() { + val endDateTimeUtc = ZonedDateTime.now().minusSeconds(1) + val anEnvActionControl = + anEnvActionControl(infractions = listOf(anInfraction(seizure = SeizureTypeEnum.PENDING))) + val mission = aMissionEntity(endDateTimeUtc = endDateTimeUtc, envActions = listOf(anEnvActionControl)) + + val assertThrows = + assertThrows(BackendUsageException::class.java) { missionWithEnvActionsValidator.validate(mission) } + assertThat( + assertThrows.data, + ).isEqualTo("L'appréhension/saisie ne peut pas être \"en attente\"") + } + + @Test + fun `validate should throw an exception if there is a control with formalNotice is PENDING when mission has ended`() { + val endDateTimeUtc = ZonedDateTime.now().minusSeconds(1) + val anEnvActionControl = + anEnvActionControl(infractions = listOf(anInfraction(formalNotice = FormalNoticeEnum.PENDING))) + val mission = aMissionEntity(endDateTimeUtc = endDateTimeUtc, envActions = listOf(anEnvActionControl)) + + val assertThrows = + assertThrows(BackendUsageException::class.java) { missionWithEnvActionsValidator.validate(mission) } + assertThat( + assertThrows.data, + ).isEqualTo("La mise en demeure ne peut pas être \"en attente\"") + } + + @Test + fun `validate should throw an exception if there is a control with infraction and nbTarget is less than 1`() { + val anEnvActionControl = anEnvActionControl(infractions = listOf(anInfraction(nbTarget = 0))) + val mission = aMissionEntity(envActions = listOf(anEnvActionControl)) + + val assertThrows = + assertThrows(BackendUsageException::class.java) { missionWithEnvActionsValidator.validate(mission) } + assertThat(assertThrows.data).isEqualTo("le nombre minimum de cible est 1") + } + + @Test + fun `validate should throw an exception if there is a control with infractions that got more nbTarget than the mission actionNumberOfControls `() { + val anEnvActionControl = + anEnvActionControl( + actionNumberOfControls = 10, + infractions = listOf(anInfraction(nbTarget = 10), anInfraction(nbTarget = 5)), + ) + val mission = aMissionEntity(envActions = listOf(anEnvActionControl)) + + val assertThrows = + assertThrows(BackendUsageException::class.java) { missionWithEnvActionsValidator.validate(mission) } + assertThat(assertThrows.data).isEqualTo("Le nombre de cibles excède le nombre total de contrôles") + } + + @Test + fun `validate should pass if there is a control with infractions that got less nbTarget than the mission actionNumberOfControls `() { + val anEnvActionControl = + anEnvActionControl( + actionNumberOfControls = 2, + infractions = listOf(anInfraction(nbTarget = 1)), + ) + val mission = aMissionEntity(envActions = listOf(anEnvActionControl)) + + missionWithEnvActionsValidator.validate(mission) + } + + @Test + fun `validate should pass if there is a control with infractionType = WAITING that doesnt have a NATINF`() { + val anEnvActionControl = + anEnvActionControl(infractions = listOf(anInfraction(infractionType = InfractionTypeEnum.WAITING))) + val mission = aMissionEntity(envActions = listOf(anEnvActionControl)) + + missionWithEnvActionsValidator.validate(mission) + } + + @ParameterizedTest + @ValueSource(strings = ["A", "AA", "AAAA"]) + fun `validate should throw an exception if there is a control with openBy is not a trigram`(openBy: String) { + val anEnvActionControl = anEnvActionControl(openBy = openBy) + val mission = aMissionEntity(envActions = listOf(anEnvActionControl)) + + val assertThrows = + assertThrows(BackendUsageException::class.java) { missionWithEnvActionsValidator.validate(mission) } + assertThat(assertThrows.data).isEqualTo("Le trigramme \"ouvert par\" doit avoir 3 lettres") + } + + @Test + fun `validate should throw an exception if there is a control without control plans when mission has ended`() { + val endDateTimeUtc = ZonedDateTime.now().minusSeconds(1) + val anEnvActionControl = anEnvActionControl(controlPlans = listOf()) + val mission = aMissionEntity(endDateTimeUtc = endDateTimeUtc, envActions = listOf(anEnvActionControl)) + + val assertThrows = + assertThrows(BackendUsageException::class.java) { missionWithEnvActionsValidator.validate(mission) } + assertThat(assertThrows.data).isEqualTo("Le plan de contrôle est obligatoire") + } + + @Test + fun `validate should throw an exception if there is a control with control plan without subtheme when mission has ended`() { + val endDateTimeUtc = ZonedDateTime.now().minusSeconds(1) + val anEnvActionControl = + anEnvActionControl(controlPlans = listOf(EnvActionControlPlanEntity(subThemeIds = listOf()))) + val mission = aMissionEntity(endDateTimeUtc = endDateTimeUtc, envActions = listOf(anEnvActionControl)) + + val assertThrows = + assertThrows(BackendUsageException::class.java) { missionWithEnvActionsValidator.validate(mission) } + assertThat(assertThrows.data).isEqualTo("Le sous-thème du plan de contrôle est obligatoire") + } + + @Test + fun `validate should throw an exception if there is a control actionTargetType as VEHICULE without vehiculeType when mission has ended`() { + val endDateTimeUtc = ZonedDateTime.now().minusSeconds(1) + val anEnvActionControl = anEnvActionControl(actionTargetTypeEnum = ActionTargetTypeEnum.VEHICLE) + val mission = aMissionEntity(endDateTimeUtc = endDateTimeUtc, envActions = listOf(anEnvActionControl)) + + val assertThrows = + assertThrows(BackendUsageException::class.java) { missionWithEnvActionsValidator.validate(mission) } + assertThat(assertThrows.data).isEqualTo("Le type de véhicule est obligatoire") + } + + @ParameterizedTest + @EnumSource(value = ActionTargetTypeEnum::class, names = ["VEHICLE"], mode = EnumSource.Mode.EXCLUDE) + fun `validate should pass if there is a control actionTargetType as targetType other than VEHICLE without vehiculeType when mission has ended`( + targetType: ActionTargetTypeEnum, + ) { + val endDateTimeUtc = ZonedDateTime.now().minusSeconds(1) + val anEnvActionControl = anEnvActionControl(actionTargetTypeEnum = targetType) + val mission = aMissionEntity(endDateTimeUtc = endDateTimeUtc, envActions = listOf(anEnvActionControl)) + + missionWithEnvActionsValidator.validate(mission) + } + + @Test + fun `validate should throw an exception if there is a surveillance with a start date before mission starting date`() { + val startDateTimeUtc = ZonedDateTime.parse("2020-03-04T00:00:00.000Z") + val anEnvActionSurveillance = anEnvActionSurveillance(startTime = startDateTimeUtc.minusSeconds(1)) + val mission = aMissionEntity(startDateTimeUtc = startDateTimeUtc, envActions = listOf(anEnvActionSurveillance)) + + val assertThrows = + assertThrows(BackendUsageException::class.java) { missionWithEnvActionsValidator.validate(mission) } + assertThat( + assertThrows.data, + ).isEqualTo("La date de début de la surveillance doit être postérieure à celle du début de mission") + } + + @Test + fun `validate should throw an exception if there is a surveillance with a start date after mission ending date`() { + val startDateTimeUtc = ZonedDateTime.parse("2019-03-04T00:00:00.000Z") + val endDateTimeUtc = ZonedDateTime.parse("2020-03-04T00:00:00.000Z") + val anEnvActionSurveillance = anEnvActionSurveillance(endTime = endDateTimeUtc.plusSeconds(1)) + val mission = + aMissionEntity( + startDateTimeUtc = startDateTimeUtc, + endDateTimeUtc = endDateTimeUtc, + envActions = listOf(anEnvActionSurveillance), + ) + + val assertThrows = + assertThrows(BackendUsageException::class.java) { missionWithEnvActionsValidator.validate(mission) } + assertThat( + assertThrows.data, + ).isEqualTo("La date de fin de la surveillance doit être antérieure à celle de fin de mission") + } + + @Test + fun `validate should throw an exception if there is a surveillance with an end date after mission ending date`() { + val startDateTimeUtc = ZonedDateTime.parse("2019-03-04T00:00:00.000Z") + val endDateTimeUtc = ZonedDateTime.parse("2020-03-04T00:00:00.000Z") + val anEnvActionSurveillance = anEnvActionSurveillance(endTime = endDateTimeUtc.plusSeconds(1)) + val mission = + aMissionEntity( + startDateTimeUtc = startDateTimeUtc, + endDateTimeUtc = endDateTimeUtc, + envActions = listOf(anEnvActionSurveillance), + ) + + val assertThrows = + assertThrows(BackendUsageException::class.java) { missionWithEnvActionsValidator.validate(mission) } + assertThat( + assertThrows.data, + ).isEqualTo("La date de fin de la surveillance doit être antérieure à celle de fin de mission") + } + + @Test + fun `validate should throw an exception if there is a surveillance with an end date before mission starting date`() { + val startDateTimeUtc = ZonedDateTime.parse("2020-03-04T00:00:00.000Z") + val endDateTimeUtc = ZonedDateTime.parse("2021-03-04T00:00:00.000Z") + + val anEnvActionSurveillance = anEnvActionSurveillance(endTime = startDateTimeUtc.minusSeconds(1)) + val mission = + aMissionEntity( + startDateTimeUtc = startDateTimeUtc, + endDateTimeUtc = endDateTimeUtc, + envActions = listOf(anEnvActionSurveillance), + ) + + val assertThrows = + assertThrows(BackendUsageException::class.java) { missionWithEnvActionsValidator.validate(mission) } + assertThat( + assertThrows.data, + ).isEqualTo("La date de fin de la surveillance doit être postérieure à celle du début de mission") + } + + @Test + fun `validate should pass if there is a surveillance with an date equal to mission's`() { + val startDateTimeUtc = ZonedDateTime.parse("2020-03-04T00:00:00.000Z") + val endDateTimeUtc = ZonedDateTime.parse("2020-03-04T00:00:00.000Z") + val anEnvActionSurveillance = anEnvActionSurveillance(startTime = startDateTimeUtc, endTime = endDateTimeUtc) + val mission = + aMissionEntity( + startDateTimeUtc = startDateTimeUtc, + endDateTimeUtc = endDateTimeUtc, + envActions = listOf(anEnvActionSurveillance), + ) + + missionWithEnvActionsValidator.validate(mission) + } + + @Test + fun `validate should pass if there is a surveillance without geometry`() { + val endDateTimeUtc = ZonedDateTime.now().minusSeconds(1) + val anEnvActionSurveillance = anEnvActionSurveillance(geom = null) + val mission = + aMissionEntity( + endDateTimeUtc = endDateTimeUtc, + envActions = listOf(anEnvActionSurveillance), + ) + + val assertThrows = + assertThrows(BackendUsageException::class.java) { missionWithEnvActionsValidator.validate(mission) } + assertThat(assertThrows.data).isEqualTo("La géométrie de la surveillance est obligatoire") + } + + @Test + fun `validate should throw an exception if there is a surveillance without control plans when mission has ended`() { + val endDateTimeUtc = ZonedDateTime.now().minusSeconds(1) + val anEnvActionSurveillance = anEnvActionSurveillance(controlPlans = listOf()) + val mission = aMissionEntity(endDateTimeUtc = endDateTimeUtc, envActions = listOf(anEnvActionSurveillance)) + + val assertThrows = + assertThrows(BackendUsageException::class.java) { missionWithEnvActionsValidator.validate(mission) } + assertThat(assertThrows.data).isEqualTo("Le plan de contrôle est obligatoire") + } + + @Test + fun `validate should throw an exception if there is a surveillance with control plan without subtheme when mission has ended`() { + val endDateTimeUtc = ZonedDateTime.now().minusSeconds(1) + val anEnvActionSurveillance = + anEnvActionSurveillance(controlPlans = listOf(EnvActionControlPlanEntity(subThemeIds = listOf()))) + val mission = aMissionEntity(endDateTimeUtc = endDateTimeUtc, envActions = listOf(anEnvActionSurveillance)) + + val assertThrows = + assertThrows(BackendUsageException::class.java) { missionWithEnvActionsValidator.validate(mission) } + assertThat(assertThrows.data).isEqualTo("Le sous-thème du plan de contrôle est obligatoire") + } + + @Test + fun `validate should pass for a valid MissionEntity`() { + val mission = aMissionEntity() + + missionWithEnvActionsValidator.validate(mission) + } +}