From 105831419ee487a9d1ab1f8a9338d275e5be82fd Mon Sep 17 00:00:00 2001 From: Teryk Bellahsene Date: Fri, 12 Aug 2016 10:39:32 +0200 Subject: [PATCH] SONAR-7930 WS api/components/bulk_update_key dry run fails when invalid key --- .../component/ws/BulkUpdateKeyActionTest.java | 10 +++++ .../sonar/core/component/ComponentKeys.java | 11 +++++ .../core/component/ComponentKeysTest.java | 40 ++++++++++++++++++- .../db/component/ComponentKeyUpdaterDao.java | 7 +++- .../component/ComponentKeyUpdaterDaoTest.java | 11 +++++ 5 files changed, 77 insertions(+), 2 deletions(-) diff --git a/server/sonar-server/src/test/java/org/sonar/server/component/ws/BulkUpdateKeyActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/component/ws/BulkUpdateKeyActionTest.java index 5260f86e683..1851c88fb95 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/component/ws/BulkUpdateKeyActionTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/component/ws/BulkUpdateKeyActionTest.java @@ -168,6 +168,16 @@ public class BulkUpdateKeyActionTest { callByKey(MY_PROJECT_KEY, FROM, "my?"); } + @Test + public void fail_to_dry_bulk_update_with_invalid_new_key() { + insertMyProject(); + + expectedException.expect(IllegalArgumentException.class); + expectedException.expectMessage("Malformed key for 'my?project'. Allowed characters are alphanumeric, '-', '_', '.' and ':', with at least one non-digit."); + + callDryRunByKey(MY_PROJECT_KEY, FROM, "my?"); + } + @Test public void fail_to_bulk_update_if_not_project_or_module() { ComponentDto project = insertMyProject(); diff --git a/sonar-core/src/main/java/org/sonar/core/component/ComponentKeys.java b/sonar-core/src/main/java/org/sonar/core/component/ComponentKeys.java index defab7e80a0..c018516ffe3 100644 --- a/sonar-core/src/main/java/org/sonar/core/component/ComponentKeys.java +++ b/sonar-core/src/main/java/org/sonar/core/component/ComponentKeys.java @@ -26,6 +26,8 @@ import org.sonar.api.resources.Project; import org.sonar.api.resources.Resource; import org.sonar.api.resources.Scopes; +import static com.google.common.base.Preconditions.checkArgument; + public final class ComponentKeys { public static final int MAX_COMPONENT_KEY_LENGTH = 400; @@ -96,6 +98,15 @@ public final class ComponentKeys { return keyCandidate.matches(VALID_MODULE_KEY_REGEXP); } + /** + * Checks if given parameter is valid for a project/module following {@link #isValidModuleKey(String)} contract. + * + * @throws IllegalArgumentException if the format is incorrect + */ + public static void checkModuleKey(String keyCandidate) { + checkArgument(isValidModuleKey(keyCandidate), "Malformed key for '%s'. Allowed characters are alphanumeric, '-', '_', '.' and ':', with at least one non-digit.", keyCandidate); + } + /** * Same as {@link #isValidModuleKey(String)}, but allows additionally '/'. */ diff --git a/sonar-core/src/test/java/org/sonar/core/component/ComponentKeysTest.java b/sonar-core/src/test/java/org/sonar/core/component/ComponentKeysTest.java index 56048b1c97e..e9818a55d37 100644 --- a/sonar-core/src/test/java/org/sonar/core/component/ComponentKeysTest.java +++ b/sonar-core/src/test/java/org/sonar/core/component/ComponentKeysTest.java @@ -19,7 +19,9 @@ */ package org.sonar.core.component; +import org.junit.Rule; import org.junit.Test; +import org.junit.rules.ExpectedException; import org.sonar.api.batch.fs.InputFile; import org.sonar.api.batch.fs.internal.DefaultInputFile; import org.sonar.api.resources.Directory; @@ -28,6 +30,8 @@ import org.sonar.api.resources.Project; import static org.assertj.core.api.Assertions.assertThat; public class ComponentKeysTest { + @Rule + public ExpectedException expectedException = ExpectedException.none(); @Test public void create_effective_key() { @@ -57,7 +61,7 @@ public class ComponentKeysTest { assertThat(ComponentKeys.isValidModuleKey("ab_12")).isTrue(); assertThat(ComponentKeys.isValidModuleKey("ab/12")).isFalse(); } - + @Test public void isValidModuleKeyIssuesMode() { assertThat(ComponentKeys.isValidModuleKeyIssuesMode("")).isFalse(); @@ -80,4 +84,38 @@ public class ComponentKeysTest { assertThat(ComponentKeys.isValidBranch("ab\n")).isFalse(); } + @Test + public void checkModuleKey_with_correct_keys() { + ComponentKeys.checkModuleKey("abc"); + ComponentKeys.checkModuleKey("a-b_1.:2"); + } + + @Test + public void checkModuleKey_fail_if_only_digit() { + expectedException.expect(IllegalArgumentException.class); + expectedException.expectMessage("Malformed key for '0123'. Allowed characters are alphanumeric, '-', '_', '.' and ':', with at least one non-digit."); + + ComponentKeys.checkModuleKey("0123"); + } + + @Test + public void checkModuleKey_fail_if_key_is_empty() { + expectedException.expect(IllegalArgumentException.class); + + ComponentKeys.checkModuleKey(""); + } + + @Test + public void checkModuleKey_fail_if_space() { + expectedException.expect(IllegalArgumentException.class); + + ComponentKeys.checkModuleKey("ab 12"); + } + + @Test + public void checkModuleKey_fail_if_special_characters_not_allowed() { + expectedException.expect(IllegalArgumentException.class); + + ComponentKeys.checkModuleKey("ab/12"); + } } diff --git a/sonar-db/src/main/java/org/sonar/db/component/ComponentKeyUpdaterDao.java b/sonar-db/src/main/java/org/sonar/db/component/ComponentKeyUpdaterDao.java index 1eb408af1f1..4248788692d 100644 --- a/sonar-db/src/main/java/org/sonar/db/component/ComponentKeyUpdaterDao.java +++ b/sonar-db/src/main/java/org/sonar/db/component/ComponentKeyUpdaterDao.java @@ -37,6 +37,7 @@ import org.sonar.db.DbSession; import org.sonar.db.MyBatis; import static com.google.common.base.Preconditions.checkArgument; +import static org.sonar.core.component.ComponentKeys.checkModuleKey; import static org.sonar.core.component.ComponentKeys.isValidModuleKey; /** @@ -109,7 +110,11 @@ public class ComponentKeyUpdaterDao implements Dao { .stream() .collect(Collectors.toMap( ResourceDto::getKey, - component -> computeNewKey(component.getKey(), stringToReplace, replacementString))); + component -> { + String newKey = computeNewKey(component.getKey(), stringToReplace, replacementString); + checkModuleKey(newKey); + return newKey; + })); } /** diff --git a/sonar-db/src/test/java/org/sonar/db/component/ComponentKeyUpdaterDaoTest.java b/sonar-db/src/test/java/org/sonar/db/component/ComponentKeyUpdaterDaoTest.java index eb74073d6b7..10621fe5a77 100644 --- a/sonar-db/src/test/java/org/sonar/db/component/ComponentKeyUpdaterDaoTest.java +++ b/sonar-db/src/test/java/org/sonar/db/component/ComponentKeyUpdaterDaoTest.java @@ -221,6 +221,17 @@ public class ComponentKeyUpdaterDaoTest { .containsOnly(entry("project", "new-project"), entry("project:enabled-module", "new-project:enabled-module")); } + @Test + public void simulate_bulk_update_key_fails_if_invalid_componentKey() { + ComponentDto project = componentDb.insertComponent(newProjectDto("A").setKey("project")); + componentDb.insertComponent(newModuleDto(project).setKey("project:enabled-module")); + componentDb.insertComponent(newModuleDto(project).setKey("project:disabled-module").setEnabled(false)); + + thrown.expect(IllegalArgumentException.class); + + underTest.simulateBulkUpdateKey(dbSession, "A", "project", "project?"); + } + @Test public void compute_new_key() { assertThat(computeNewKey("my_project", "my_", "your_")).isEqualTo("your_project"); -- 2.39.5