From 1edfd3243c8bc69ad3ff296d24e6a9441160811b Mon Sep 17 00:00:00 2001 From: philippe tcheriatinsky <philippe.tcherniatinsky@inrae.fr> Date: Mon, 24 Feb 2025 14:01:42 +0100 Subject: [PATCH 1/6] Correction #13 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ajout d'un vérificateur et envoie d'une error --- .../configuration/ConfigurationException.java | 2 +- .../configuration/builder/DataBuilder.java | 63 ++++++++++++++++--- .../oresing/rest/TestReferencesErrors.java | 23 ++++--- 3 files changed, 70 insertions(+), 18 deletions(-) diff --git a/src/main/java/fr/inra/oresing/domain/exceptions/configuration/ConfigurationException.java b/src/main/java/fr/inra/oresing/domain/exceptions/configuration/ConfigurationException.java index a664cab..9ffbd3a 100644 --- a/src/main/java/fr/inra/oresing/domain/exceptions/configuration/ConfigurationException.java +++ b/src/main/java/fr/inra/oresing/domain/exceptions/configuration/ConfigurationException.java @@ -227,7 +227,7 @@ public enum ConfigurationException { INVALID_CONFIGURATION_FILE, ADDING_AUTHORIZATION_SCOPE_ATTRIBUTES_ERROR, REMOVING_AUTHORIZATION_SCOPE_ATTRIBUTES_ERROR, - + MISSING_COMPONENT_FOR_DISPLAY_PATTERN, /* jackson parse exeption */ diff --git a/src/main/java/fr/inra/oresing/rest/model/configuration/builder/DataBuilder.java b/src/main/java/fr/inra/oresing/rest/model/configuration/builder/DataBuilder.java index 0bf0cbf..11d1a87 100644 --- a/src/main/java/fr/inra/oresing/rest/model/configuration/builder/DataBuilder.java +++ b/src/main/java/fr/inra/oresing/rest/model/configuration/builder/DataBuilder.java @@ -11,10 +11,14 @@ import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.collections4.MapUtils; import java.util.*; +import java.util.function.Predicate; +import java.util.regex.Pattern; import java.util.stream.Collectors; public record DataBuilder(RootBuilder rootBuilder) { + public static final Pattern DISPLAY_MATCHING_GROUP = Pattern.compile("\\{([^}]+)\\}"); + Parsing<StandardDataDescription> build(final String path, final String dataKey, final JsonNode jsonNode, I18n i18n) { final Set<Tag> tags = buildAndTestDomainTags(path, jsonNode); @@ -71,8 +75,8 @@ public record DataBuilder(RootBuilder rootBuilder) { final List<String> listComponentKeys = rootBuilder.getListComponentKeys(dataKey); final Map<String, Map> localizationDisplay = rootBuilder.getMapper().convertValue( - jsonNode.findPath(ConfigurationSchemaNode.OA_I_18_N_DISPLAY_PATTERN) - .findPath(ConfigurationSchemaNode.OA_PATTERN), Map.class); + jsonNode.findPath(ConfigurationSchemaNode.OA_I_18_N_DISPLAY_PATTERN), Map.class); + testLocalizationDisplay(localizationDisplay, listComponentKeys, path); try { i18n = i18n.add( NodeSchemaValidator.joinI18nPath( @@ -103,9 +107,9 @@ public record DataBuilder(RootBuilder rootBuilder) { entry -> entry.getValue().importHeader() )).entrySet().stream() .filter(entry -> entry.getValue().size() > 1) - .filter(entry->!(entry.getValue().stream().allMatch(value-> (value.getValue() instanceof PatternComponentQualifiers) || (value.getValue() instanceof PatternComponentAdjacents)))) + .filter(entry -> !(entry.getValue().stream().allMatch(value -> (value.getValue() instanceof PatternComponentQualifiers) || (value.getValue() instanceof PatternComponentAdjacents)))) .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); - if (MapUtils.isNotEmpty(duplicatedImportHeader)){ + if (MapUtils.isNotEmpty(duplicatedImportHeader)) { duplicatedImportHeader.forEach((key, value) -> rootBuilder.buildError(ConfigurationException.DUPLICATED_COMPONENT_HEADER, Map.of( "data", dataKey, @@ -124,10 +128,10 @@ public record DataBuilder(RootBuilder rootBuilder) { Map<CheckerDescription.CheckerDescriptionType, List<String>> componentValidationsByType = getComponentValidationsByType(validations); HashMap<String, ComponentDescription> localComponentDescription = new HashMap<>(componentDescriptions); final Parsing<Submission> submissionParsing = rootBuilder.getSubmissionBuilder().buildSubmission(i18n, dataKey, jsonNode, localComponentDescription); - if( + if ( tags.stream().noneMatch(Tag.DataTag.class::isInstance) && Optional.of(submissionParsing).map(Parsing::result).map(Submission::strategy).filter(SubmissionType.OA_VERSIONING::equals).isPresent() - ){ + ) { rootBuilder.buildError(ConfigurationException.UNEXPECTED_SUBMISSION, Map.of() , path); @@ -167,6 +171,51 @@ public record DataBuilder(RootBuilder rootBuilder) { )); } + private boolean testLocalizationDisplay(Map<String, Map> localizationDisplay, List<String> listComponentKeys, String path) { + if (MapUtils.isEmpty(localizationDisplay)) { + return true; + } + for (String group : List.of(ConfigurationSchemaNode.OA_TITLE, ConfigurationSchemaNode.OA_DESCRIPTION)) { + if (localizationDisplay.containsKey(group)) { + for (Object language : localizationDisplay.get(group).keySet()) { + boolean test = testLocalizationDisplay( + localizationDisplay.get(group).get(language).toString(), + listComponentKeys, + path, + group, + language.toString()); + if (!test) { + return test; + } + } + } + } + return true; + } + + private boolean testLocalizationDisplay(String matchingGroup, List<String> listComponentKeys, String path, String group, String language) { + Pattern pattern = DISPLAY_MATCHING_GROUP; + List<String> list = pattern.matcher(matchingGroup) + .results() + .map(m -> m.group(1)) + .filter(Predicate.not(listComponentKeys::contains)) + .toList(); + list.stream().forEach( + badGroup -> rootBuilder.buildError(ConfigurationException.MISSING_COMPONENT_FOR_DISPLAY_PATTERN, + Map.of( + "badGroup", badGroup, + "expectedComponent", listComponentKeys + ), + NodeSchemaValidator.joinPath( + path, + group, + language + ) + ) + ); + return list.isEmpty(); + } + private Map<CheckerDescription.CheckerDescriptionType, List<String>> getComponentValidationsByType(ImmutableMap<String, ValidationDescription> validations) { Map<CheckerDescription.CheckerDescriptionType, List<String>> componentValidationByType = new HashMap<>(); for (ValidationDescription validation : validations.values()) { @@ -185,7 +234,7 @@ public record DataBuilder(RootBuilder rootBuilder) { private Set<Tag> buildAndTestDomainTags(final String path, final JsonNode jsonNode) { - if(jsonNode.get(ConfigurationSchemaNode.OA_TAGS)==null){ + if (jsonNode.get(ConfigurationSchemaNode.OA_TAGS) == null) { return Collections.emptySet(); } final Set<String> domainTagNames = rootBuilder.getDomainTags().stream() diff --git a/src/test/java/fr/inra/oresing/rest/TestReferencesErrors.java b/src/test/java/fr/inra/oresing/rest/TestReferencesErrors.java index 31cb2f2..e0e4de3 100644 --- a/src/test/java/fr/inra/oresing/rest/TestReferencesErrors.java +++ b/src/test/java/fr/inra/oresing/rest/TestReferencesErrors.java @@ -60,6 +60,9 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. public class TestReferencesErrors { public static final Map<String, String> responses = new HashMap<>(); + public static final String LOGIN = "poussinreferenceserrors"; + public static final String PASSWORD = "xxxxxxxx"; + public static final String EMAIL = "poussinreferenceserrors@inrae.fr"; @Autowired private ObjectMapper objectMapper; @Autowired @@ -86,13 +89,13 @@ public class TestReferencesErrors { @BeforeEach public void createUser() throws Exception { - CreateUserResult authUser = authenticationService.createUser("poussin", "xxxxxxxx", "poussin@inrae.fr"); + CreateUserResult authUser = authenticationService.createUser(LOGIN, PASSWORD, EMAIL); final UUID userId = authUser.userId(); setToActive(userId); - final CreateUserResult lambdaUser = authenticationService.createUser("lambda", "xxxxxxxx", "lamnda@inrae.fr"); + final CreateUserResult lambdaUser = authenticationService.createUser("lambda", PASSWORD, "lamnda@inrae.fr"); authCookie = mockMvc.perform(post("/api/v1/login") - .param("login", "poussin") - .param("password", "xxxxxxxx")) + .param("login", LOGIN) + .param("password", PASSWORD)) .andReturn().getResponse().getCookie(AuthHelper.JWT_COOKIE_NAME); addRoleAdmin(authUser); } @@ -140,13 +143,13 @@ public class TestReferencesErrors { try (final InputStream in = Objects.requireNonNull(resource).openStream()) { final MockMultipartFile configuration = new MockMultipartFile("file", "recursivity.yaml", "text/plain", in); //définition de l'application - CreateUserResult recursivityUser = authenticationService.createUser("recursivity", "xxxxxxxx", "recursivity@inrae.fr"); + CreateUserResult recursivityUser = authenticationService.createUser("recursivity", PASSWORD, "recursivity@inrae.fr"); setToActive(recursivityUser.userId()); final UUID recursivityUserId = recursivityUser.userId(); addUserRightCreateApplication(recursivityUserId, "recursivite"); recursivityCookie = mockMvc.perform(post("/api/v1/login") .param("login", "recursivity") - .param("password", "xxxxxxxx")) + .param("password", PASSWORD)) .andReturn().getResponse().getCookie(AuthHelper.JWT_COOKIE_NAME); final String id = fixtures.getIdFromApplicationResult(fixtures.loadApplication(configuration, recursivityCookie, "recursivite", "")); final String response = mockMvc.perform(MockMvcRequestBuilders.get("/api/v1/applications/recursivite") @@ -267,13 +270,13 @@ public class TestReferencesErrors { final Cookie repeatedColumnCookie; try (final InputStream in = Objects.requireNonNull(resource).openStream()) { final MockMultipartFile configuration = new MockMultipartFile("file", "repeatedcolumns.yaml", "text/plain", in); - CreateUserResult recursivityUser = authenticationService.createUser("repeatedcolumns", "xxxxxxxx", "repeatedcolumns@inrae.fr"); + CreateUserResult recursivityUser = authenticationService.createUser("repeatedcolumns", PASSWORD, "repeatedcolumns@inrae.fr"); setToActive(recursivityUser.userId()); final UUID recursivityUserId = recursivityUser.userId(); addUserRightCreateApplication(recursivityUserId, "repeatedcolumns"); repeatedColumnCookie = mockMvc.perform(post("/api/v1/login") .param("login", "repeatedcolumns") - .param("password", "xxxxxxxx")) + .param("password", PASSWORD)) .andReturn().getResponse().getCookie(AuthHelper.JWT_COOKIE_NAME); final String id = fixtures.getIdFromApplicationResult(fixtures.loadApplication(configuration, repeatedColumnCookie, "repeatedcolumns", "")); @@ -344,13 +347,13 @@ public class TestReferencesErrors { final Cookie repeatedColumnsCookie; try (final InputStream in = Objects.requireNonNull(resource).openStream()) { final MockMultipartFile configuration = new MockMultipartFile("file", "repeatedcolumns.yaml", "text/plain", in); - CreateUserResult recursivityUser = authenticationService.createUser("repeatedcolumns", "xxxxxxxx", "repeatedcolumns@inrae.fr"); + CreateUserResult recursivityUser = authenticationService.createUser("repeatedcolumns", PASSWORD, "repeatedcolumns@inrae.fr"); setToActive(recursivityUser.userId()); final UUID recursivityUserId = recursivityUser.userId(); addUserRightCreateApplication(recursivityUserId, "repeatedcolumns"); repeatedColumnsCookie = mockMvc.perform(post("/api/v1/login") .param("login", "repeatedcolumns") - .param("password", "xxxxxxxx")) + .param("password", PASSWORD)) .andReturn().getResponse().getCookie(AuthHelper.JWT_COOKIE_NAME); final String id = fixtures.getIdFromApplicationResult(fixtures.loadApplication(configuration, repeatedColumnsCookie, "repeatedcolumns", "")); final String response = mockMvc.perform(MockMvcRequestBuilders.get("/api/v1/applications/repeatedcolumns") -- GitLab From 89a8ddc64cd90b9a901c481ee0db487b2046e99c Mon Sep 17 00:00:00 2001 From: philippe tcheriatinsky <philippe.tcherniatinsky@inrae.fr> Date: Mon, 24 Feb 2025 14:05:42 +0100 Subject: [PATCH 2/6] Renvoie de outes les erreurs --- .../rest/model/configuration/builder/DataBuilder.java | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/main/java/fr/inra/oresing/rest/model/configuration/builder/DataBuilder.java b/src/main/java/fr/inra/oresing/rest/model/configuration/builder/DataBuilder.java index 11d1a87..3c54eb0 100644 --- a/src/main/java/fr/inra/oresing/rest/model/configuration/builder/DataBuilder.java +++ b/src/main/java/fr/inra/oresing/rest/model/configuration/builder/DataBuilder.java @@ -175,22 +175,20 @@ public record DataBuilder(RootBuilder rootBuilder) { if (MapUtils.isEmpty(localizationDisplay)) { return true; } + boolean isValid = true; for (String group : List.of(ConfigurationSchemaNode.OA_TITLE, ConfigurationSchemaNode.OA_DESCRIPTION)) { if (localizationDisplay.containsKey(group)) { for (Object language : localizationDisplay.get(group).keySet()) { - boolean test = testLocalizationDisplay( + isValid = isValid && testLocalizationDisplay( localizationDisplay.get(group).get(language).toString(), listComponentKeys, path, group, language.toString()); - if (!test) { - return test; - } } } } - return true; + return isValid; } private boolean testLocalizationDisplay(String matchingGroup, List<String> listComponentKeys, String path, String group, String language) { -- GitLab From f4826fe333467bcd2d8c92a7a4f653b138f5b748 Mon Sep 17 00:00:00 2001 From: philippe tcheriatinsky <philippe.tcherniatinsky@inrae.fr> Date: Mon, 24 Feb 2025 14:52:19 +0100 Subject: [PATCH 3/6] L'erreur met en exergue un test avec une fichier de configuration invalide --- .../rest/model/configuration/builder/DataBuilder.java | 3 ++- .../resources/data/configuration/configuration.yaml | 10 +++++----- .../data/configuration/localization.result.json | 10 +++++----- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/src/main/java/fr/inra/oresing/rest/model/configuration/builder/DataBuilder.java b/src/main/java/fr/inra/oresing/rest/model/configuration/builder/DataBuilder.java index 3c54eb0..d6ccec3 100644 --- a/src/main/java/fr/inra/oresing/rest/model/configuration/builder/DataBuilder.java +++ b/src/main/java/fr/inra/oresing/rest/model/configuration/builder/DataBuilder.java @@ -198,7 +198,8 @@ public record DataBuilder(RootBuilder rootBuilder) { .map(m -> m.group(1)) .filter(Predicate.not(listComponentKeys::contains)) .toList(); - list.stream().forEach( + list.stream() + .forEach( badGroup -> rootBuilder.buildError(ConfigurationException.MISSING_COMPONENT_FOR_DISPLAY_PATTERN, Map.of( "badGroup", badGroup, diff --git a/src/test/resources/data/configuration/configuration.yaml b/src/test/resources/data/configuration/configuration.yaml index 06c4e7a..a8a1481 100644 --- a/src/test/resources/data/configuration/configuration.yaml +++ b/src/test/resources/data/configuration/configuration.yaml @@ -97,7 +97,7 @@ OA_data: en: Sites list OA_i18nDisplayPattern: OA_title: - fr: '{zet_nom_fry}' + fr: '{zet_nom_fr}' en: '{zet_nom_en}' OA_description: fr: '{zet_description_fr}' @@ -820,11 +820,11 @@ OA_data: en: remote sensing data plot OA_i18nDisplayPattern: # attention : avec un S ici car peut concerner plusieurs referentiels OA_title: - fr: "<em>[data display]</em>: {sit_code} ({sit_label_fr})" - en: "<em>[data display]</em>: {sit_code} ({sit_label_en})" + fr: "<em>[data display]</em>: {tel_experimental_site} ({tel_experimental_plot})" + en: "<em>[data display]</em>: {tel_experimental_site} ({tel_experimental_plot})" OA_description: - fr: "<em>[data display]</em>: {sit_code} ({sit_label_fr})" - en: "<em>[data display]</em>: {sit_code} ({sit_label_en})" + fr: "<em>[data display]</em>: {tel_experimental_site} ({tel_experimental_plot})" + en: "<em>[data display]</em>: {tel_experimental_site} ({tel_experimental_plot})" OA_naturalKey: # clé d'unicité pour chaque ligne de données - tel_experimental_plot - tel_experimental_site diff --git a/src/test/resources/data/configuration/localization.result.json b/src/test/resources/data/configuration/localization.result.json index eb9cabf..05c0d0e 100644 --- a/src/test/resources/data/configuration/localization.result.json +++ b/src/test/resources/data/configuration/localization.result.json @@ -218,7 +218,7 @@ "i18nDisplayPattern" : { "title" : { "en" : "{zet_nom_en}", - "fr" : "{zet_nom_fry}" + "fr" : "{zet_nom_fr}" }, "description" : { "en" : "{zet_description_en}", @@ -379,12 +379,12 @@ }, "i18nDisplayPattern" : { "title" : { - "en" : "<em>[data display]</em>: {sit_code} ({sit_label_en})", - "fr" : "<em>[data display]</em>: {sit_code} ({sit_label_fr})" + "en" : "<em>[data display]</em>: {tel_experimental_site} ({tel_experimental_plot})", + "fr" : "<em>[data display]</em>: {tel_experimental_site} ({tel_experimental_plot})" }, "description" : { - "en" : "<em>[data display]</em>: {sit_code} ({sit_label_en})", - "fr" : "<em>[data display]</em>: {sit_code} ({sit_label_fr})" + "en" : "<em>[data display]</em>: {tel_experimental_site} ({tel_experimental_plot})", + "fr" : "<em>[data display]</em>: {tel_experimental_site} ({tel_experimental_plot})" } }, "i18n" : { -- GitLab From 983e6d5e3ba9f02b7527297bc3e76eafd2f3c3f6 Mon Sep 17 00:00:00 2001 From: lucile varloteaux <lucile.varloteaux@inrae.fr> Date: Wed, 26 Feb 2025 10:02:49 +0100 Subject: [PATCH 4/6] test backend fait pour MISSING_COMPONENT_FOR_DISPLAY_PATTERN --- .../ApplicationConfigurationServiceTest.java | 33 ++++++++++++++++--- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/src/test/java/fr/inra/oresing/rest/ApplicationConfigurationServiceTest.java b/src/test/java/fr/inra/oresing/rest/ApplicationConfigurationServiceTest.java index 30b034e..b3915ab 100644 --- a/src/test/java/fr/inra/oresing/rest/ApplicationConfigurationServiceTest.java +++ b/src/test/java/fr/inra/oresing/rest/ApplicationConfigurationServiceTest.java @@ -1357,8 +1357,8 @@ public class ApplicationConfigurationServiceTest { } @Test - public void testduplicatedHeader() { - CONFIGURATION_INSTANCE.builder("testUnsuportedI18nKeyLanguageInValidation") + public void testDuplicatedHeader() { + CONFIGURATION_INSTANCE.builder("testDuplicatedHeader") .withReplace("OA_headerName: \"Nom de la clé du site\"", "OA_headerName: \"zet_chemin_parent\"") .test(errors -> { @@ -1376,8 +1376,8 @@ public class ApplicationConfigurationServiceTest { } @Test - public void testduplicatedComponent() { - CONFIGURATION_INSTANCE.builder("testUnsuportedI18nKeyLanguageInValidation") + public void testDuplicatedComponent() { + CONFIGURATION_INSTANCE.builder("testDuplicatedComponent") .withReplace("tel_value", "tel_experimental_site") .test(errors -> { @@ -1392,6 +1392,31 @@ public class ApplicationConfigurationServiceTest { }); } + @Test + public void testMissingComponentForDisplayPattern() { + CONFIGURATION_INSTANCE.builder("testMissingComponentForDisplayPattern") + .withReplace(" OA_i18nDisplayPattern:\n" + + " OA_title:\n" + + " fr: \"{esp_nom}\"\n" + + " en: \"{esp_nom}\"", + " OA_i18nDisplayPattern:\n" + + " OA_title:\n" + + " fr: \"{esp_invalid_nom}\"\n" + + " en: \"{esp_nom}\"") + .test(errors -> { + assertEquals(1, errors.size()); + final ValidationError validationError = errors.getFirst(); + assertEquals(ConfigurationException.MISSING_COMPONENT_FOR_DISPLAY_PATTERN.getMessage(), validationError.getMessage()); + + final Set<String> expected = Arrays.stream(new String[]{"colonne_homonyme_entre_referentiels", "my_computed_column", "esp_definition_en", "esp_definition_fr", "esp_nom"}) + .collect(Collectors.toCollection(TreeSet::new)); + final Set<String> given = new TreeSet<>((Collection<? extends String>) validationError.getParam("expectedComponent")); + assertEquals(expected, given); + assertEquals("esp_invalid_nom", validationError.getParam("badGroup")); + assertEquals("OA_data > especes > OA_title > fr", validationError.getParam("path")); + }); + } + @Test public void testduplicatedComponentInPatternComponent() { CONFIGURATION_INSTANCE.builder("testduplicatedComponentInPatternComponent") -- GitLab From f2479f48bbaf5d4e6e52dacde89f2175216f35b1 Mon Sep 17 00:00:00 2001 From: philippe tcheriatinsky <philippe.tcherniatinsky@inrae.fr> Date: Fri, 28 Feb 2025 11:14:13 +0100 Subject: [PATCH 5/6] Jout d'un test sur les Handlers --- .../InvalidDatasetContentException.java | 2 +- .../BadApplicationConfigurationException.java | 2 +- .../configuration/ConfigurationException.java | 1 + .../ApplicationConfigurationServiceTest.java | 5 +- .../exceptions/OreExceptionHandlerTest.java | 217 ++++++++++++++++++ 5 files changed, 221 insertions(+), 6 deletions(-) create mode 100644 src/test/java/fr/inra/oresing/rest/exceptions/OreExceptionHandlerTest.java diff --git a/src/main/java/fr/inra/oresing/domain/checker/InvalidDatasetContentException.java b/src/main/java/fr/inra/oresing/domain/checker/InvalidDatasetContentException.java index 8e1faec..7991c62 100644 --- a/src/main/java/fr/inra/oresing/domain/checker/InvalidDatasetContentException.java +++ b/src/main/java/fr/inra/oresing/domain/checker/InvalidDatasetContentException.java @@ -27,7 +27,7 @@ public class InvalidDatasetContentException extends OreSiTechnicalException { private final List<CsvRowValidationCheckResult> errors; - private InvalidDatasetContentException(final List<CsvRowValidationCheckResult> errors) { + public InvalidDatasetContentException(final List<CsvRowValidationCheckResult> errors) { super("Erreurs rencontrées à l'import du fichier"); this.errors = errors; } diff --git a/src/main/java/fr/inra/oresing/domain/exceptions/configuration/BadApplicationConfigurationException.java b/src/main/java/fr/inra/oresing/domain/exceptions/configuration/BadApplicationConfigurationException.java index 4279f32..4959a36 100644 --- a/src/main/java/fr/inra/oresing/domain/exceptions/configuration/BadApplicationConfigurationException.java +++ b/src/main/java/fr/inra/oresing/domain/exceptions/configuration/BadApplicationConfigurationException.java @@ -8,7 +8,7 @@ public class BadApplicationConfigurationException extends OreSiTechnicalExceptio private final ConfigurationException configurationException; - private BadApplicationConfigurationException(final String message, final ConfigurationException configurationException) { + public BadApplicationConfigurationException(final String message, final ConfigurationException configurationException) { super(message); this.configurationException = configurationException; } diff --git a/src/main/java/fr/inra/oresing/domain/exceptions/configuration/ConfigurationException.java b/src/main/java/fr/inra/oresing/domain/exceptions/configuration/ConfigurationException.java index 9ffbd3a..17cac12 100644 --- a/src/main/java/fr/inra/oresing/domain/exceptions/configuration/ConfigurationException.java +++ b/src/main/java/fr/inra/oresing/domain/exceptions/configuration/ConfigurationException.java @@ -225,6 +225,7 @@ public enum ConfigurationException { DUPLICATED_COMPONENT_HEADER, DUPLICATED_COMPONENT_HEADER_IN_PATTERN_COMPONENT, INVALID_CONFIGURATION_FILE, + IO_EXCEPTION, ADDING_AUTHORIZATION_SCOPE_ATTRIBUTES_ERROR, REMOVING_AUTHORIZATION_SCOPE_ATTRIBUTES_ERROR, MISSING_COMPONENT_FOR_DISPLAY_PATTERN, diff --git a/src/test/java/fr/inra/oresing/rest/ApplicationConfigurationServiceTest.java b/src/test/java/fr/inra/oresing/rest/ApplicationConfigurationServiceTest.java index b3915ab..d0ca91f 100644 --- a/src/test/java/fr/inra/oresing/rest/ApplicationConfigurationServiceTest.java +++ b/src/test/java/fr/inra/oresing/rest/ApplicationConfigurationServiceTest.java @@ -16,7 +16,6 @@ import fr.inra.oresing.rest.services.ApplicationConfigurationService; import lombok.extern.slf4j.Slf4j; import org.apache.commons.io.IOUtils; import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -1529,9 +1528,7 @@ public class ApplicationConfigurationServiceTest { default -> log.info("test terminé"); } } catch (final IOException e) { - throw new OreSiTechnicalException("impossible de lire le fichier de test", e); - } catch (final BadApplicationConfigurationException e) { - //errors.put(methodName, e); + throw new BadApplicationConfigurationException("impossible de lire le fichier de test", ConfigurationException.IO_EXCEPTION); } } diff --git a/src/test/java/fr/inra/oresing/rest/exceptions/OreExceptionHandlerTest.java b/src/test/java/fr/inra/oresing/rest/exceptions/OreExceptionHandlerTest.java new file mode 100644 index 0000000..dce92a3 --- /dev/null +++ b/src/test/java/fr/inra/oresing/rest/exceptions/OreExceptionHandlerTest.java @@ -0,0 +1,217 @@ +package fr.inra.oresing.rest.exceptions; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.common.collect.ImmutableMap; +import fr.inra.oresing.ValidationLevel; +import fr.inra.oresing.domain.OreSiUser; +import fr.inra.oresing.domain.authorization.privilegeassessor.exception.DisconnectedException; +import fr.inra.oresing.domain.checker.InvalidDatasetContentException; +import fr.inra.oresing.domain.checker.type.BooleanType; +import fr.inra.oresing.domain.data.deposit.validation.CsvRowValidationCheckResult; +import fr.inra.oresing.domain.data.deposit.validation.validationcheckresults.BooleanValidationCheckResult; +import fr.inra.oresing.domain.exceptions.OreSiTechnicalException; +import fr.inra.oresing.domain.exceptions.SiOreIllegalArgumentException; +import fr.inra.oresing.domain.exceptions.application.NoSuchApplicationException; +import fr.inra.oresing.domain.exceptions.binaryfile.binaryfile.BadFileOrUUIDQuery; +import fr.inra.oresing.domain.exceptions.configuration.BadApplicationConfigurationException; +import fr.inra.oresing.domain.exceptions.configuration.ConfigurationException; +import fr.inra.oresing.domain.exceptions.data.data.BadBinaryFileDatasetQuery; +import fr.inra.oresing.domain.exceptions.data.data.BadDownloadDatasetQuery; +import fr.inra.oresing.persistence.AuthenticationFailure; +import fr.inra.oresing.rest.model.configuration.ValidationError; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.postgresql.util.PSQLException; +import org.springframework.http.ResponseEntity; +import org.springframework.jdbc.BadSqlGrammarException; +import org.springframework.validation.ObjectError; +import org.springframework.web.bind.support.WebExchangeBindException; + +import java.util.List; +import java.util.Map; +import java.util.UUID; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.when; + +class OreExceptionHandlerTest { + private OreExceptionHandler exceptionHandler; + private ObjectMapper objectMapper; + + @Mock + private WebExchangeBindException webExchangeBindException; + + @Mock + private BadSqlGrammarException badSqlGrammarException; + + @Mock + private PSQLException psqlException; + + @BeforeEach + public void setUp() { + MockitoAnnotations.openMocks(this); + exceptionHandler = new OreExceptionHandler(); + objectMapper = new ObjectMapper(); + + // Configuration des mocks + when(webExchangeBindException.getAllErrors()).thenReturn(List.of(new ObjectError("test", "message"))); + when(badSqlGrammarException.getMessage()).thenReturn("SQL error"); + } + + @Test + public void testValidationErrorSerializability() { + ValidationError error = new ValidationError("Test error"); + ResponseEntity<ValidationError> response = exceptionHandler.handle(error); + + assertDoesNotThrow(() -> objectMapper.writeValueAsString(response.getBody())); + } + + @Test + public void testDisconnectedExceptionSerializability() { + DisconnectedException exception = new DisconnectedException("User disconnected"); + ResponseEntity<DisconnectedException> response = exceptionHandler.handle(exception); + + assertDoesNotThrow(() -> objectMapper.writeValueAsString(response.getBody())); + } + + @Test + public void testSiOreIllegalArgumentExceptionSerializability() { + SiOreIllegalArgumentException exception = new SiOreIllegalArgumentException("Illegal argument", Map.of("param", "param")); + ResponseEntity<SiOreIllegalArgumentException> response = exceptionHandler.handle(exception); + + assertDoesNotThrow(() -> objectMapper.writeValueAsString(response.getBody())); + } + + @Test + public void testAuthenticationFailureSerializability() { + // Tester différents cas de AuthenticationFailure + testAuthFailureCase("INACTIVE_ACCOUNT"); + testAuthFailureCase("EXISTING_LOGIN"); + testAuthFailureCase("BAD_LOGIN_PASSWORD"); + testAuthFailureCase("BAD_PASSWORDS"); + testAuthFailureCase("BAD_VALIDATION_KEY"); + testAuthFailureCase("DEFAULT_CASE"); + } + + private void testAuthFailureCase(String message) { + OreSiUser oreSiUser = new OreSiUser(); + oreSiUser.setId( UUID.randomUUID()); + oreSiUser.setLogin("testuser"); + oreSiUser.setEmail("test@example.com"); + oreSiUser.setAccountstate(OreSiUser.OreSiUserStates.active); + + AuthenticationFailure failure = new AuthenticationFailure(message, + oreSiUser + ); + ResponseEntity<AuthenticationFailure> response = exceptionHandler.handle(failure); + + assertDoesNotThrow(() -> objectMapper.writeValueAsString(response.getBody())); + } + + @Test + public void testWebExchangeBindExceptionSerializability() { + List<ObjectError> errors = exceptionHandler.exception(webExchangeBindException); + + assertDoesNotThrow(() -> objectMapper.writeValueAsString(errors)); + } + + @Test + public void testBadSqlGrammarExceptionSerializability() { + when(badSqlGrammarException.getCause()).thenReturn(psqlException); + when(psqlException.getMessage()).thenReturn("permission denied"); + + ResponseEntity<String> response = exceptionHandler.handle(badSqlGrammarException); + + assertDoesNotThrow(() -> objectMapper.writeValueAsString(response.getBody())); + } + + @Test + public void testNoSuchApplicationExceptionSerializability() { + NoSuchApplicationException exception = new NoSuchApplicationException("Application not found"); + ResponseEntity<String> response = exceptionHandler.handle(exception); + + assertDoesNotThrow(() -> objectMapper.writeValueAsString(response.getBody())); + } + + @Test + public void testBadApplicationConfigurationExceptionSerializability() { + ConfigurationException configException = ConfigurationException.IO_EXCEPTION; + BadApplicationConfigurationException exception = new BadApplicationConfigurationException("Configuration error", configException); + ResponseEntity<ConfigurationException> response = exceptionHandler.handle(exception); + + assertDoesNotThrow(() -> objectMapper.writeValueAsString(response.getBody())); + } + + @Test + public void testOreSiTechnicalExceptionSerializability() { + // Cas d'autorisation + OreSiTechnicalException authException = new OreSiTechnicalException("Auth error") { + public String getPackageName() { + return "fr.inra.oresing.domain.authorization.privilegeassessor.exception"; + } + }; + ResponseEntity<OreSiTechnicalException> authResponse = exceptionHandler.handle(authException); + assertDoesNotThrow(() -> objectMapper.writeValueAsString(authResponse.getBody())); + + // Cas technique général + OreSiTechnicalException techException = new OreSiTechnicalException("Technical error"); + ResponseEntity<OreSiTechnicalException> techResponse = exceptionHandler.handle(techException); + assertDoesNotThrow(() -> objectMapper.writeValueAsString(techResponse.getBody())); + } + + @Test + public void testInvalidDatasetContentExceptionSerializability() { + List<CsvRowValidationCheckResult> errors = List.of( + new CsvRowValidationCheckResult( + new BooleanValidationCheckResult( + ValidationLevel.ERROR, + "Error in row 1", + Map.of("totot", "toto"), + null, + BooleanType.forExpression("return true", ImmutableMap.of()) + ), + 1 + ), + new CsvRowValidationCheckResult( + new BooleanValidationCheckResult( + ValidationLevel.ERROR, + "Error in row 2", + Map.of("totot", "toto2"), + null, + BooleanType.forExpression("return false", ImmutableMap.of()) + ), + 2 + ) + ); + InvalidDatasetContentException exception = new InvalidDatasetContentException(errors); + ResponseEntity<List<CsvRowValidationCheckResult>> response = exceptionHandler.handle(exception); + + assertDoesNotThrow(() -> objectMapper.writeValueAsString(response.getBody())); + } + + @Test + public void testBadBinaryFileDatasetQuerySerializability() { + BadBinaryFileDatasetQuery exception = new BadBinaryFileDatasetQuery("Bad binary file query"); + ResponseEntity<String> response = exceptionHandler.handle(exception); + + assertDoesNotThrow(() -> objectMapper.writeValueAsString(response.getBody())); + } + + @Test + public void testBadDownloadDatasetQuerySerializability() { + BadDownloadDatasetQuery exception = new BadDownloadDatasetQuery("Bad download query"); + ResponseEntity<String> response = exceptionHandler.handle(exception); + + assertDoesNotThrow(() -> objectMapper.writeValueAsString(response.getBody())); + } + + @Test + public void testBadFileOrUUIDQuerySerializability() { + BadFileOrUUIDQuery exception = new BadFileOrUUIDQuery("Bad file or UUID"); + ResponseEntity<String> response = exceptionHandler.handle(exception); + + assertDoesNotThrow(() -> objectMapper.writeValueAsString(response.getBody())); + } +} \ No newline at end of file -- GitLab From 3638d7f363fe3d18455023d464fa0d2153035e59 Mon Sep 17 00:00:00 2001 From: philippe tcheriatinsky <philippe.tcherniatinsky@inrae.fr> Date: Fri, 28 Feb 2025 11:34:54 +0100 Subject: [PATCH 6/6] Correction test --- src/test/java/fr/inra/oresing/rest/TestReferencesErrors.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/test/java/fr/inra/oresing/rest/TestReferencesErrors.java b/src/test/java/fr/inra/oresing/rest/TestReferencesErrors.java index e25d4b6..d7cee3a 100644 --- a/src/test/java/fr/inra/oresing/rest/TestReferencesErrors.java +++ b/src/test/java/fr/inra/oresing/rest/TestReferencesErrors.java @@ -75,6 +75,8 @@ public class TestReferencesErrors { @Autowired private NamedParameterJdbcTemplate namedParameterJdbcTemplate; private Cookie authCookie; + private static CreateUserResult authUser = null; + private static UUID userId; @AfterAll public static void registerErrors() throws IOException { String errorsAsString = new ObjectMapper().writeValueAsString(responses); @@ -88,7 +90,7 @@ public class TestReferencesErrors { @BeforeEach public void createUser() throws Exception { try { - authUser = authenticationService.createUser("poussin", "xxxxxxxx", "poussin@inrae.fr"); + authUser = authenticationService.createUser(LOGIN, PASSWORD, EMAIL); userId = authUser.userId(); setToActive(authUser.userId()); } catch (AuthenticationFailure e) { -- GitLab