From 2745d5de301f3fbb775d3989477a6b001c171ee3 Mon Sep 17 00:00:00 2001 From: Eric Hartmann Date: Fri, 9 Feb 2018 16:17:21 +0100 Subject: [PATCH] SONAR-10407 Fix upgrade of too long permision_templates keys --- ...ultPermTemplateColumnsOfOrganizations.java | 30 ++++- ...ermTemplateColumnsOfOrganizationsTest.java | 108 ++++++++++++++++-- .../properties_and_organizations.sql | 11 ++ 3 files changed, 137 insertions(+), 12 deletions(-) diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v63/PopulateDefaultPermTemplateColumnsOfOrganizations.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v63/PopulateDefaultPermTemplateColumnsOfOrganizations.java index f39e51601ff..6987e11e768 100644 --- a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v63/PopulateDefaultPermTemplateColumnsOfOrganizations.java +++ b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v63/PopulateDefaultPermTemplateColumnsOfOrganizations.java @@ -22,8 +22,11 @@ package org.sonar.server.platform.db.migration.version.v63; import java.sql.SQLException; import java.util.HashMap; import java.util.Map; +import javax.annotation.Nullable; import org.sonar.api.utils.log.Loggers; +import org.sonar.core.util.UuidFactory; import org.sonar.db.Database; +import org.sonar.server.platform.db.migration.def.VarcharColumnDef; import org.sonar.server.platform.db.migration.step.DataChange; import static com.google.common.base.MoreObjects.firstNonNull; @@ -49,10 +52,12 @@ public class PopulateDefaultPermTemplateColumnsOfOrganizations extends DataChang private static final String DEFAULT_DEV_TEMPLATE_PROPERTY = "sonar.permission.template.DEV.default"; private final DefaultOrganizationUuidProvider defaultOrganizationUuid; + private final UuidFactory uuidFactory; - public PopulateDefaultPermTemplateColumnsOfOrganizations(Database db, DefaultOrganizationUuidProvider defaultOrganizationUuid) { + public PopulateDefaultPermTemplateColumnsOfOrganizations(Database db, DefaultOrganizationUuidProvider defaultOrganizationUuid, UuidFactory uuidFactory) { super(db); this.defaultOrganizationUuid = defaultOrganizationUuid; + this.uuidFactory = uuidFactory; } @Override @@ -67,8 +72,10 @@ public class PopulateDefaultPermTemplateColumnsOfOrganizations extends DataChang // DB has just been created, default template of default organization will be populated by a startup task return; } - String projectDefaultTemplate = firstNonNull(defaultTemplateProperties.get(DEFAULT_PROJECT_TEMPLATE_PROPERTY), globalDefaultTemplate); - String viewDefaultTemplate = defaultTemplateProperties.get(DEFAULT_VIEW_TEMPLATE_PROPERTY); + String projectDefaultTemplate = updateKeeIfRequired(context, + firstNonNull(defaultTemplateProperties.get(DEFAULT_PROJECT_TEMPLATE_PROPERTY), globalDefaultTemplate)); + String viewDefaultTemplate = updateKeeIfRequired(context, + defaultTemplateProperties.get(DEFAULT_VIEW_TEMPLATE_PROPERTY)); Loggers.get(PopulateDefaultPermTemplateColumnsOfOrganizations.class) .debug("Setting default templates on default organization '{}': project='{}', view='{}'", @@ -95,6 +102,23 @@ public class PopulateDefaultPermTemplateColumnsOfOrganizations extends DataChang .commit(); } + /** + * SONAR-10407 Ensure that the kee length is not greater than 40 + * In this case, we must update the kee to a UUID + */ + private String updateKeeIfRequired(Context context, @Nullable String kee) throws SQLException { + if (kee == null || kee.length() <= VarcharColumnDef.UUID_SIZE) { + return kee; + } + + String newKee = uuidFactory.create(); + context.prepareUpsert("update permission_templates set kee=? where kee=?") + .setString(1, newKee) + .setString(2, kee) + .execute(); + return newKee; + } + private static void ensureOnlyDefaultOrganizationExists(Context context, String defaultOrganizationUuid) throws SQLException { Integer otherOrganizationCount = context.prepareSelect("select count(*) from organizations where uuid <> ?") .setString(1, defaultOrganizationUuid) diff --git a/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v63/PopulateDefaultPermTemplateColumnsOfOrganizationsTest.java b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v63/PopulateDefaultPermTemplateColumnsOfOrganizationsTest.java index 9b37b2ebf36..fc60ca1d117 100644 --- a/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v63/PopulateDefaultPermTemplateColumnsOfOrganizationsTest.java +++ b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v63/PopulateDefaultPermTemplateColumnsOfOrganizationsTest.java @@ -19,14 +19,22 @@ */ package org.sonar.server.platform.db.migration.version.v63; +import com.google.common.collect.ImmutableList; import java.sql.SQLException; +import java.sql.Timestamp; +import java.util.ArrayList; +import java.util.List; import java.util.Map; import javax.annotation.Nullable; +import org.junit.After; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; +import org.sonar.core.util.UuidFactory; +import org.sonar.core.util.UuidFactoryFast; import org.sonar.db.CoreDbTester; +import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric; import static org.assertj.core.api.Assertions.assertThat; public class PopulateDefaultPermTemplateColumnsOfOrganizationsTest { @@ -41,8 +49,14 @@ public class PopulateDefaultPermTemplateColumnsOfOrganizationsTest { @Rule public ExpectedException expectedException = ExpectedException.none(); + private RecordingUuidFactory recordingUuidFactory = new RecordingUuidFactory(); private PopulateDefaultPermTemplateColumnsOfOrganizations underTest = new PopulateDefaultPermTemplateColumnsOfOrganizations(dbTester.database(), - new DefaultOrganizationUuidProviderImpl()); + new DefaultOrganizationUuidProviderImpl(), recordingUuidFactory); + + @After + public void clearRecordingUuidFactory() { + recordingUuidFactory.clear(); + } @Test public void fails_with_ISE_when_no_default_organization_is_set() throws SQLException { @@ -120,6 +134,44 @@ public class PopulateDefaultPermTemplateColumnsOfOrganizationsTest { verifyPropertiesDoNotExist(); } + @Test + public void execute_should_update_kee_when_old_kee_is_too_long() throws SQLException { + setupDefaultOrganization(); + insertProperty(DEFAULT_TEMPLATE_PROPERTY, insertPermissionTemplates(randomAlphanumeric(100))); + insertProperty(DEFAULT_VIEW_TEMPLATE_PROPERTY, insertPermissionTemplates(randomAlphanumeric(100))); + insertProperty(DEFAULT_PROJECT_TEMPLATE_PROPERTY, insertPermissionTemplates(randomAlphanumeric(100))); + insertProperty(DEFAULT_DEV_TEMPLATE_PROPERTY, insertPermissionTemplates(randomAlphanumeric(100))); + + underTest.execute(); + + verifyTemplateColumns(recordingUuidFactory.getRecordedUuids().get(0), recordingUuidFactory.getRecordedUuids().get(1)); + verifyPropertiesDoNotExist(); + verifyExistenceOfPermissionTemplate(recordingUuidFactory.getRecordedUuids().get(0)); + verifyExistenceOfPermissionTemplate(recordingUuidFactory.getRecordedUuids().get(1)); + } + + @Test + public void execute_should_update_kee_only_when_old_kee_length_is_41_or_more() throws SQLException { + setupDefaultOrganization(); + insertProperty(DEFAULT_TEMPLATE_PROPERTY, insertPermissionTemplates(randomAlphanumeric(40))); + insertProperty(DEFAULT_VIEW_TEMPLATE_PROPERTY, insertPermissionTemplates(randomAlphanumeric(40))); + insertProperty(DEFAULT_PROJECT_TEMPLATE_PROPERTY, insertPermissionTemplates(randomAlphanumeric(40))); + insertProperty(DEFAULT_DEV_TEMPLATE_PROPERTY, insertPermissionTemplates(randomAlphanumeric(40))); + + underTest.execute(); + + assertThat(recordingUuidFactory.getRecordedUuids()).isEmpty(); + + insertProperty(DEFAULT_TEMPLATE_PROPERTY, insertPermissionTemplates(randomAlphanumeric(41))); + insertProperty(DEFAULT_VIEW_TEMPLATE_PROPERTY, insertPermissionTemplates(randomAlphanumeric(41))); + insertProperty(DEFAULT_PROJECT_TEMPLATE_PROPERTY, insertPermissionTemplates(randomAlphanumeric(41))); + insertProperty(DEFAULT_DEV_TEMPLATE_PROPERTY, insertPermissionTemplates(randomAlphanumeric(41))); + + underTest.execute(); + + assertThat(recordingUuidFactory.getRecordedUuids()).hasSize(2); + } + @Test public void execute_sets_project_from_project_property_and_view_from_view_property_when_all_properties_are_defined() throws SQLException { setupDefaultOrganization(); @@ -153,6 +205,16 @@ public class PopulateDefaultPermTemplateColumnsOfOrganizationsTest { assertThat(row.get("viewDefaultPermTemplate")).isEqualTo(view); } + @Test + public void migration_is_reentrant() throws SQLException { + setupDefaultOrganization(); + insertProperty(DEFAULT_TEMPLATE_PROPERTY, "foo"); + + underTest.execute(); + + underTest.execute(); + } + private void verifyPropertiesDoNotExist() { verifyPropertyDoesNotExist(DEFAULT_TEMPLATE_PROPERTY); verifyPropertyDoesNotExist(DEFAULT_PROJECT_TEMPLATE_PROPERTY); @@ -165,14 +227,8 @@ public class PopulateDefaultPermTemplateColumnsOfOrganizationsTest { .isEqualTo(0); } - @Test - public void migration_is_reentrant() throws SQLException { - setupDefaultOrganization(); - insertProperty(DEFAULT_TEMPLATE_PROPERTY, "foo"); - - underTest.execute(); - - underTest.execute(); + private void verifyExistenceOfPermissionTemplate(String kee) { + assertThat(dbTester.countSql("select count(kee) from permission_templates where kee='" + kee +"'")).isEqualTo(1); } private void setupDefaultOrganization() { @@ -190,6 +246,20 @@ public class PopulateDefaultPermTemplateColumnsOfOrganizationsTest { "UPDATED_AT", "1000"); } + private String insertPermissionTemplates(String kee) { + dbTester.executeInsert( + "PERMISSION_TEMPLATES", + "ORGANIZATION_UUID", DEFAULT_ORGANIZATION_UUID, + "NAME", randomAlphanumeric(50), + "KEE", kee, + "DESCRIPTION", randomAlphanumeric(500), + "KEY_PATTERN", "", + "CREATED_AT", new Timestamp(1000L), + "UPDATED_AT", new Timestamp(1000L)); + + return kee; + } + private void insertDefaultOrganizationUuid(String defaultOrganizationUuid) { dbTester.executeInsert( "INTERNAL_PROPERTIES", @@ -205,4 +275,24 @@ public class PopulateDefaultPermTemplateColumnsOfOrganizationsTest { "IS_EMPTY", String.valueOf(value == null), "TEXT_VALUE", value); } + + private static final class RecordingUuidFactory implements UuidFactory { + private final List generatedUuids = new ArrayList<>(); + private final UuidFactory uuidFactory = UuidFactoryFast.getInstance(); + + @Override + public String create() { + String uuid = uuidFactory.create(); + generatedUuids.add(uuid); + return uuid; + } + + public void clear() { + generatedUuids.clear(); + } + + public List getRecordedUuids() { + return ImmutableList.copyOf(generatedUuids); + } + } } diff --git a/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v63/PopulateDefaultPermTemplateColumnsOfOrganizationsTest/properties_and_organizations.sql b/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v63/PopulateDefaultPermTemplateColumnsOfOrganizationsTest/properties_and_organizations.sql index 056ce7cd9ef..d6b052f42e2 100644 --- a/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v63/PopulateDefaultPermTemplateColumnsOfOrganizationsTest/properties_and_organizations.sql +++ b/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v63/PopulateDefaultPermTemplateColumnsOfOrganizationsTest/properties_and_organizations.sql @@ -34,3 +34,14 @@ CREATE TABLE "INTERNAL_PROPERTIES" ( "CREATED_AT" BIGINT ); CREATE UNIQUE INDEX "UNIQ_INTERNAL_PROPERTIES" ON "INTERNAL_PROPERTIES" ("KEE"); + +CREATE TABLE "PERMISSION_TEMPLATES" ( + "ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1), + "ORGANIZATION_UUID" VARCHAR(40) NOT NULL, + "NAME" VARCHAR(100) NOT NULL, + "KEE" VARCHAR(100) NOT NULL, + "DESCRIPTION" VARCHAR(4000), + "KEY_PATTERN" VARCHAR(500), + "CREATED_AT" TIMESTAMP, + "UPDATED_AT" TIMESTAMP +); -- 2.39.5