As login can be automatically generated from name, size of the personal organization key might be higher than current value (32)tags/7.5
@@ -1,7 +1,7 @@ | |||
CREATE TABLE "ORGANIZATIONS" ( | |||
"UUID" VARCHAR(40) NOT NULL, | |||
"KEE" VARCHAR(32) NOT NULL, | |||
"NAME" VARCHAR(64) NOT NULL, | |||
"KEE" VARCHAR(300) NOT NULL, | |||
"NAME" VARCHAR(300) NOT NULL, | |||
"DESCRIPTION" VARCHAR(256), | |||
"URL" VARCHAR(256), | |||
"AVATAR_URL" VARCHAR(256), |
@@ -1,43 +0,0 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2018 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.db.organization; | |||
public class OrganizationCount { | |||
private String organizationUuid; | |||
private int memberCount; | |||
public String getOrganizationUuid() { | |||
return organizationUuid; | |||
} | |||
public OrganizationCount setOrganizationUuid(String organizationUuid) { | |||
this.organizationUuid = organizationUuid; | |||
return this; | |||
} | |||
public int getMemberCount() { | |||
return memberCount; | |||
} | |||
public OrganizationCount setMemberCount(int memberCount) { | |||
this.memberCount = memberCount; | |||
return this; | |||
} | |||
} |
@@ -22,6 +22,7 @@ package org.sonar.db.organization; | |||
import java.util.Objects; | |||
import javax.annotation.CheckForNull; | |||
import javax.annotation.Nullable; | |||
import org.sonar.api.server.authentication.UserIdentity; | |||
public class OrganizationDto { | |||
@@ -44,10 +45,25 @@ public class OrganizationDto { | |||
/** Technical unique identifier, can't be null */ | |||
private String uuid; | |||
/** Functional unique identifier, can't be null */ | |||
/** | |||
* Functional unique identifier, can't be null. | |||
* | |||
* On personal organization (created the first time the user authenticates), the key can have the following format : | |||
* - When {@link UserIdentity#getLogin()} is not null, it's a slug of the login | |||
* - When {@link UserIdentity#getLogin()} is null, it's a slug of the name appended to a random number | |||
* | |||
* Length is set to 300 (As login length is 255, the size must be higher than 255). | |||
*/ | |||
private String key; | |||
/** Name, can't be null */ | |||
/** | |||
* Name, can't be null. | |||
* | |||
* Length is set to 300, as it's generated from the key when no name is provided. | |||
*/ | |||
private String name; | |||
/** description can't be null */ | |||
private String description; | |||
/** url can be null */ |
@@ -41,6 +41,7 @@ public class DbVersion74 implements DbVersion { | |||
.add(2318, "Finalize CE_QUEUE.MAIN_COMPONENT_UUID 3/3", FinalizeMainComponentUuidColumnsToCeActivity.class) | |||
.add(2319, "Finalize CE_ACTIVITY.MAIN_COMPONENT_UUID 3/3", FinalizeMainComponentUuidColumnsToCeQueue.class) | |||
.add(2320, "Finalize CE_ACTIVITY.MAIN_LAST_KEY 3/3", FinalizeMainLastKeyColumnsToCeActivity.class) | |||
.add(2321, "Increase organization key and name length", IncreaseOrganizationsKeeAndNameLength.class) | |||
; | |||
} | |||
} |
@@ -0,0 +1,56 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2018 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.server.platform.db.migration.version.v74; | |||
import java.sql.SQLException; | |||
import org.sonar.db.Database; | |||
import org.sonar.server.platform.db.migration.SupportsBlueGreen; | |||
import org.sonar.server.platform.db.migration.sql.AlterColumnsBuilder; | |||
import org.sonar.server.platform.db.migration.step.DdlChange; | |||
import static org.sonar.server.platform.db.migration.def.VarcharColumnDef.newVarcharColumnDefBuilder; | |||
@SupportsBlueGreen | |||
public class IncreaseOrganizationsKeeAndNameLength extends DdlChange { | |||
public static final String ORGANIZATIONS_TABLE = "organizations"; | |||
public IncreaseOrganizationsKeeAndNameLength(Database db) { | |||
super(db); | |||
} | |||
@Override | |||
public void execute(Context context) throws SQLException { | |||
context.execute(new AlterColumnsBuilder(getDialect(), ORGANIZATIONS_TABLE) | |||
.updateColumn(newVarcharColumnDefBuilder() | |||
.setColumnName("kee") | |||
.setLimit(300) | |||
.setIsNullable(false) | |||
.build()) | |||
.build()); | |||
context.execute(new AlterColumnsBuilder(getDialect(), ORGANIZATIONS_TABLE) | |||
.updateColumn(newVarcharColumnDefBuilder() | |||
.setColumnName("name") | |||
.setLimit(300) | |||
.setIsNullable(false) | |||
.build()) | |||
.build()); | |||
} | |||
} |
@@ -35,6 +35,6 @@ public class DbVersion74Test { | |||
@Test | |||
public void verify_migration_count() { | |||
verifyMigrationCount(underTest, 14); | |||
verifyMigrationCount(underTest, 15); | |||
} | |||
} |
@@ -0,0 +1,55 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2018 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.server.platform.db.migration.version.v74; | |||
import java.sql.SQLException; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.junit.rules.ExpectedException; | |||
import org.sonar.db.CoreDbTester; | |||
import static java.sql.Types.VARCHAR; | |||
public class IncreaseOrganizationsKeeAndNameLengthTest { | |||
@Rule | |||
public final CoreDbTester db = CoreDbTester.createForSchema(IncreaseOrganizationsKeeAndNameLengthTest.class, "organizations.sql"); | |||
@Rule | |||
public ExpectedException expectedException = ExpectedException.none(); | |||
private IncreaseOrganizationsKeeAndNameLength underTest = new IncreaseOrganizationsKeeAndNameLength(db.database()); | |||
@Test | |||
public void column_is_updated() throws SQLException { | |||
underTest.execute(); | |||
db.assertColumnDefinition("organizations", "kee", VARCHAR, 300, false); | |||
db.assertColumnDefinition("organizations", "name", VARCHAR, 300, false); | |||
} | |||
@Test | |||
public void migration_is_reentrant() throws SQLException { | |||
underTest.execute(); | |||
underTest.execute(); | |||
} | |||
} |
@@ -0,0 +1,20 @@ | |||
CREATE TABLE "ORGANIZATIONS" ( | |||
"UUID" VARCHAR(40) NOT NULL, | |||
"KEE" VARCHAR(32) NOT NULL, | |||
"NAME" VARCHAR(64) NOT NULL, | |||
"DESCRIPTION" VARCHAR(256), | |||
"URL" VARCHAR(256), | |||
"AVATAR_URL" VARCHAR(256), | |||
"GUARDED" BOOLEAN NOT NULL, | |||
"DEFAULT_PERM_TEMPLATE_PROJECT" VARCHAR(40), | |||
"DEFAULT_PERM_TEMPLATE_VIEW" VARCHAR(40), | |||
"DEFAULT_GROUP_ID" INTEGER, | |||
"DEFAULT_QUALITY_GATE_UUID" VARCHAR(40) NOT NULL, | |||
"NEW_PROJECT_PRIVATE" BOOLEAN NOT NULL, | |||
"SUBSCRIPTION" VARCHAR(40) NOT NULL, | |||
"CREATED_AT" BIGINT NOT NULL, | |||
"UPDATED_AT" BIGINT NOT NULL, | |||
CONSTRAINT "PK_ORGANIZATIONS" PRIMARY KEY ("UUID") | |||
); | |||
CREATE UNIQUE INDEX "ORGANIZATION_KEY" ON "ORGANIZATIONS" ("KEE"); |
@@ -24,16 +24,16 @@ import javax.annotation.Nullable; | |||
public interface OrganizationValidation { | |||
int KEY_MIN_LENGTH = 1; | |||
int KEY_MAX_LENGTH = 32; | |||
int KEY_MAX_LENGTH = 300; | |||
int NAME_MIN_LENGTH = 1; | |||
int NAME_MAX_LENGTH = 64; | |||
int NAME_MAX_LENGTH = 300; | |||
int DESCRIPTION_MAX_LENGTH = 256; | |||
int URL_MAX_LENGTH = 256; | |||
/** | |||
* Ensures the specified argument is a valid key by failing with an exception if it is not so. | |||
* <p> | |||
* A valid key is non null and its length is between {@link #KEY_MIN_LENGTH 2} and {@link #KEY_MAX_LENGTH 32}. | |||
* A valid key is non null and its length is between {@link #KEY_MIN_LENGTH} and {@link #KEY_MAX_LENGTH}. | |||
* </p> | |||
* | |||
* @return the argument | |||
@@ -46,7 +46,7 @@ public interface OrganizationValidation { | |||
/** | |||
* Ensures the specified argument is a valid name by failing with an exception if it is not so. | |||
* <p> | |||
* A valid name is non null and its length is between {@link #NAME_MIN_LENGTH 2} and {@link #NAME_MAX_LENGTH 64}. | |||
* A valid name is non null and its length is between {@link #NAME_MIN_LENGTH} and {@link #NAME_MAX_LENGTH}. | |||
* </p> | |||
* | |||
* @return the argument |
@@ -23,7 +23,6 @@ import javax.annotation.CheckForNull; | |||
import javax.annotation.Nullable; | |||
import static com.google.common.base.Preconditions.checkArgument; | |||
import static java.lang.Math.min; | |||
import static java.util.Objects.requireNonNull; | |||
import static org.sonar.core.util.Slug.slugify; | |||
@@ -79,6 +78,6 @@ public class OrganizationValidationImpl implements OrganizationValidation { | |||
@Override | |||
public String generateKeyFrom(String source) { | |||
return slugify(source.substring(0, min(source.length(), KEY_MAX_LENGTH))); | |||
return slugify(source); | |||
} | |||
} |
@@ -40,6 +40,7 @@ import org.sonarqube.ws.Organizations.CreateWsResponse; | |||
import static com.google.common.base.Preconditions.checkArgument; | |||
import static org.sonar.server.organization.OrganizationUpdater.NewOrganization.newOrganizationBuilder; | |||
import static org.sonar.server.organization.OrganizationValidation.KEY_MAX_LENGTH; | |||
import static org.sonar.server.organization.OrganizationValidation.KEY_MIN_LENGTH; | |||
import static org.sonar.server.organization.ws.OrganizationsWsSupport.PARAM_KEY; | |||
import static org.sonar.server.ws.WsUtils.writeProtobuf; | |||
@@ -74,16 +75,20 @@ public class CreateAction implements OrganizationsWsAction { | |||
.setResponseExample(getClass().getResource("create-example.json")) | |||
.setInternal(true) | |||
.setSince("6.2") | |||
.setChangelog(new Change("7.2", "Minimal number of character of name and key is one character")) | |||
.setChangelog( | |||
new Change("7.4", "Maximal number of character of name and key is 300 characters"), | |||
new Change("7.2", "Minimal number of character of name and key is one character") | |||
) | |||
.setHandler(this); | |||
action.createParam(PARAM_KEY) | |||
.setRequired(false) | |||
.setMinimumLength(KEY_MIN_LENGTH) | |||
.setMaximumLength(KEY_MAX_LENGTH) | |||
.setDescription("Key of the organization. <br />" + | |||
"The key is unique to the whole SonarQube. <br/>" + | |||
"When not specified, the key is computed from the name. <br />" + | |||
"Otherwise, it must be between 1 and 32 chars long. All chars must be lower-case letters (a to z), digits or dash (but dash can neither be trailing nor heading)") | |||
"All chars must be lower-case letters (a to z), digits or dash (but dash can neither be trailing nor heading)") | |||
.setExampleValue("foo-company"); | |||
wsSupport.addOrganizationDetailsParams(action, true); |
@@ -29,6 +29,7 @@ import org.sonarqube.ws.Organizations.Organization; | |||
import static org.sonar.core.util.Protobuf.setNullable; | |||
import static org.sonar.server.organization.OrganizationValidation.DESCRIPTION_MAX_LENGTH; | |||
import static org.sonar.server.organization.OrganizationValidation.NAME_MAX_LENGTH; | |||
import static org.sonar.server.organization.OrganizationValidation.NAME_MIN_LENGTH; | |||
import static org.sonar.server.organization.OrganizationValidation.URL_MAX_LENGTH; | |||
/** | |||
@@ -83,9 +84,9 @@ public class OrganizationsWsSupport { | |||
void addOrganizationDetailsParams(WebService.NewAction action, boolean isNameRequired) { | |||
action.createParam(PARAM_NAME) | |||
.setRequired(isNameRequired) | |||
.setMinimumLength(NAME_MIN_LENGTH) | |||
.setMaximumLength(NAME_MAX_LENGTH) | |||
.setDescription("Name of the organization. <br />" + | |||
"It must be between 2 and 64 chars longs.") | |||
.setDescription("Name of the organization") | |||
.setExampleValue("Foo Company"); | |||
action.createParam(PARAM_DESCRIPTION) |
@@ -22,6 +22,7 @@ package org.sonar.server.organization.ws; | |||
import java.util.Optional; | |||
import javax.annotation.CheckForNull; | |||
import javax.annotation.Nullable; | |||
import org.sonar.api.server.ws.Change; | |||
import org.sonar.api.server.ws.Request; | |||
import org.sonar.api.server.ws.Response; | |||
import org.sonar.api.server.ws.WebService; | |||
@@ -34,12 +35,12 @@ import org.sonar.server.user.UserSession; | |||
import org.sonarqube.ws.Organizations; | |||
import static java.lang.String.format; | |||
import static org.sonar.db.permission.OrganizationPermission.ADMINISTER; | |||
import static org.sonar.server.organization.ws.OrganizationsWsSupport.PARAM_AVATAR_URL; | |||
import static org.sonar.server.organization.ws.OrganizationsWsSupport.PARAM_DESCRIPTION; | |||
import static org.sonar.server.organization.ws.OrganizationsWsSupport.PARAM_KEY; | |||
import static org.sonar.server.organization.ws.OrganizationsWsSupport.PARAM_NAME; | |||
import static org.sonar.server.organization.ws.OrganizationsWsSupport.PARAM_URL; | |||
import static org.sonar.db.permission.OrganizationPermission.ADMINISTER; | |||
import static org.sonar.server.ws.WsUtils.writeProtobuf; | |||
public class UpdateAction implements OrganizationsWsAction { | |||
@@ -66,6 +67,7 @@ public class UpdateAction implements OrganizationsWsAction { | |||
"Require 'Administer System' permission. Organization support must be enabled.") | |||
.setInternal(true) | |||
.setSince("6.2") | |||
.setChangelog(new Change("7.4", "Maximal number of character of name is 300 characters")) | |||
.setHandler(this); | |||
action.createParam(PARAM_KEY) |
@@ -73,7 +73,6 @@ public class OrganizationUpdaterImplTest { | |||
private static final long A_DATE = 12893434L; | |||
private static final String A_LOGIN = "a-login"; | |||
private static final String SLUG_OF_A_LOGIN = "slug-of-a-login"; | |||
private static final String STRING_64_CHARS = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; | |||
private static final String A_NAME = "a name"; | |||
private OrganizationUpdater.NewOrganization FULL_POPULATED_NEW_ORGANIZATION = newOrganizationBuilder() | |||
@@ -191,7 +190,8 @@ public class OrganizationUpdaterImplTest { | |||
assertThat(dbClient.permissionTemplateDao().selectGroupPermissionsByTemplateId(dbSession, defaultTemplate.getId())) | |||
.extracting(PermissionTemplateGroupDto::getGroupId, PermissionTemplateGroupDto::getPermission) | |||
.containsOnly( | |||
tuple(ownersGroup.getId(), UserRole.ADMIN), tuple(ownersGroup.getId(), UserRole.ISSUE_ADMIN), tuple(ownersGroup.getId(), UserRole.SECURITYHOTSPOT_ADMIN), tuple(ownersGroup.getId(), GlobalPermissions.SCAN_EXECUTION), | |||
tuple(ownersGroup.getId(), UserRole.ADMIN), tuple(ownersGroup.getId(), UserRole.ISSUE_ADMIN), tuple(ownersGroup.getId(), UserRole.SECURITYHOTSPOT_ADMIN), | |||
tuple(ownersGroup.getId(), GlobalPermissions.SCAN_EXECUTION), | |||
tuple(defaultGroupId, UserRole.USER), tuple(defaultGroupId, UserRole.CODEVIEWER)); | |||
} | |||
@@ -425,54 +425,6 @@ public class OrganizationUpdaterImplTest { | |||
assertThat(dbClient.organizationMemberDao().select(dbSession, organization.getUuid(), user.getId())).isPresent(); | |||
} | |||
@Test | |||
public void createForUser_does_not_fail_if_name_is_too_long_for_an_organization_name() { | |||
String nameTooLong = STRING_64_CHARS + "b"; | |||
UserDto user = db.users().insertUser(dto -> dto.setName(nameTooLong).setLogin(A_LOGIN)); | |||
when(organizationValidation.generateKeyFrom(A_LOGIN)).thenReturn(SLUG_OF_A_LOGIN); | |||
enableCreatePersonalOrg(true); | |||
builtInQProfileRepositoryRule.initialize(); | |||
db.qualityGates().insertBuiltInQualityGate(); | |||
underTest.createForUser(dbSession, user); | |||
OrganizationDto organization = dbClient.organizationDao().selectByKey(dbSession, SLUG_OF_A_LOGIN).get(); | |||
assertThat(organization.getName()).isEqualTo(STRING_64_CHARS); | |||
assertThat(organization.getDescription()).isEqualTo(nameTooLong + "'s personal organization"); | |||
} | |||
@Test | |||
public void createForUser_does_not_fail_if_name_is_empty_and_login_is_too_long_for_an_organization_name() { | |||
String login = STRING_64_CHARS + "b"; | |||
UserDto user = db.users().insertUser(dto -> dto.setName("").setLogin(login)); | |||
when(organizationValidation.generateKeyFrom(login)).thenReturn(SLUG_OF_A_LOGIN); | |||
enableCreatePersonalOrg(true); | |||
builtInQProfileRepositoryRule.initialize(); | |||
db.qualityGates().insertBuiltInQualityGate(); | |||
underTest.createForUser(dbSession, user); | |||
OrganizationDto organization = dbClient.organizationDao().selectByKey(dbSession, SLUG_OF_A_LOGIN).get(); | |||
assertThat(organization.getName()).isEqualTo(STRING_64_CHARS); | |||
assertThat(organization.getDescription()).isEqualTo(login + "'s personal organization"); | |||
} | |||
@Test | |||
public void createForUser_does_not_fail_if_name_is_null_and_login_is_too_long_for_an_organization_name() { | |||
String login = STRING_64_CHARS + "b"; | |||
UserDto user = db.users().insertUser(dto -> dto.setName(null).setLogin(login)); | |||
when(organizationValidation.generateKeyFrom(login)).thenReturn(SLUG_OF_A_LOGIN); | |||
enableCreatePersonalOrg(true); | |||
builtInQProfileRepositoryRule.initialize(); | |||
db.qualityGates().insertBuiltInQualityGate(); | |||
underTest.createForUser(dbSession, user); | |||
OrganizationDto organization = dbClient.organizationDao().selectByKey(dbSession, SLUG_OF_A_LOGIN).get(); | |||
assertThat(organization.getName()).isEqualTo(STRING_64_CHARS); | |||
assertThat(organization.getDescription()).isEqualTo(login + "'s personal organization"); | |||
} | |||
@Test | |||
public void createForUser_associates_to_built_in_quality_profiles() { | |||
UserDto user = db.users().insertUser(A_LOGIN); | |||
@@ -536,7 +488,6 @@ public class OrganizationUpdaterImplTest { | |||
assertThat(db.countRowsOfTable("perm_templates_groups")).isEqualTo(0); | |||
} | |||
@Test | |||
public void update_personal_organization() { | |||
OrganizationDto organization = db.organizations().insert(o -> o.setKey("old login")); |
@@ -19,6 +19,7 @@ | |||
*/ | |||
package org.sonar.server.organization; | |||
import com.google.common.base.Strings; | |||
import java.util.Random; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
@@ -32,6 +33,8 @@ public class OrganizationValidationImplTest { | |||
private static final String STRING_64_CHARS = STRING_32_CHARS + STRING_32_CHARS; | |||
private static final String STRING_256_CHARS = STRING_64_CHARS + STRING_64_CHARS + STRING_64_CHARS + STRING_64_CHARS; | |||
private static final String STRING_300_CHARS = Strings.repeat("a", 300); | |||
@Rule | |||
public ExpectedException expectedException = ExpectedException.none(); | |||
@@ -62,27 +65,22 @@ public class OrganizationValidationImplTest { | |||
} | |||
@Test | |||
public void checkValidKey_does_not_fail_if_arg_is_2_to_32_chars_long() { | |||
String str = "aa"; | |||
for (int i = 0; i < 31; i++) { | |||
public void checkValidKey_does_not_fail_if_arg_is_1_to_300_chars_long() { | |||
String str = "a"; | |||
for (int i = 0; i < 299; i++) { | |||
underTest.checkKey(str); | |||
str += "a"; | |||
} | |||
} | |||
@Test | |||
public void checkValidKey_throws_IAE_if_arg_is_33_or_more_chars_long() { | |||
String str = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; | |||
underTest.checkKey(str); | |||
for (int i = 0; i < 5 + Math.abs(new Random().nextInt(10)); i++) { | |||
str += "c"; | |||
try { | |||
underTest.checkKey(str); | |||
fail("A IllegalArgumentException should have been thrown"); | |||
} catch (IllegalArgumentException e) { | |||
assertThat(e).hasMessage("Key '" + str + "' must be at most 32 chars long"); | |||
} | |||
} | |||
public void checkValidKey_throws_IAE_when_more_than_300_characters() { | |||
String key = STRING_300_CHARS + "b"; | |||
expectedException.expect(IllegalArgumentException.class); | |||
expectedException.expectMessage("Key '" + key + "' must be at most 300 chars long"); | |||
underTest.checkKey(key); | |||
} | |||
@Test | |||
@@ -117,27 +115,22 @@ public class OrganizationValidationImplTest { | |||
} | |||
@Test | |||
public void checkValidName_does_not_fail_if_arg_is_2_to_32_chars_long() { | |||
String str = "aa"; | |||
for (int i = 0; i < 63; i++) { | |||
public void checkValidName_does_not_fail_if_arg_is_1_to_300_chars_long() { | |||
String str = "a"; | |||
for (int i = 0; i < 299; i++) { | |||
underTest.checkName(str); | |||
str += "a"; | |||
} | |||
} | |||
@Test | |||
public void checkValidName_throws_IAE_if_arg_is_65_or_more_chars_long() { | |||
String str = STRING_64_CHARS; | |||
public void checkValidName_throws_IAE_when_more_than_300_characters() { | |||
String str = STRING_300_CHARS + "b"; | |||
expectedException.expect(IllegalArgumentException.class); | |||
expectedException.expectMessage("Name '" + str + "' must be at most 300 chars long"); | |||
underTest.checkName(str); | |||
for (int i = 0; i < 5 + Math.abs(new Random().nextInt(10)); i++) { | |||
str += "c"; | |||
try { | |||
underTest.checkName(str); | |||
fail("A IllegalArgumentException should have been thrown"); | |||
} catch (IllegalArgumentException e) { | |||
assertThat(e).hasMessage("Name '" + str + "' must be at most 64 chars long"); | |||
} | |||
} | |||
} | |||
@Test | |||
@@ -244,10 +237,4 @@ public class OrganizationValidationImplTest { | |||
assertThat(underTest.generateKeyFrom("<\"foo:\">")).isEqualTo("foo"); | |||
} | |||
@Test | |||
public void generateKeyFrom_truncate_arg_to_32_chars() { | |||
assertThat(underTest.generateKeyFrom(STRING_64_CHARS)) | |||
.isEqualTo(underTest.generateKeyFrom(STRING_256_CHARS)) | |||
.isEqualTo(underTest.generateKeyFrom(STRING_32_CHARS)); | |||
} | |||
} |
@@ -69,7 +69,6 @@ import static org.elasticsearch.index.query.QueryBuilders.boolQuery; | |||
import static org.elasticsearch.index.query.QueryBuilders.termQuery; | |||
import static org.mockito.Mockito.mock; | |||
import static org.sonar.core.config.CorePropertyDefinitions.ORGANIZATIONS_ANYONE_CAN_CREATE; | |||
import static org.sonar.server.organization.ws.OrganizationsWsSupport.PARAM_KEY; | |||
import static org.sonar.server.organization.ws.OrganizationsWsSupport.PARAM_NAME; | |||
import static org.sonar.server.organization.ws.OrganizationsWsTestSupport.STRING_257_CHARS_LONG; | |||
import static org.sonar.server.organization.ws.OrganizationsWsTestSupport.STRING_65_CHARS_LONG; | |||
@@ -280,16 +279,6 @@ public class CreateActionTest { | |||
verifyResponseAndDb(executeRequest("ab"), "ab", "ab", NOW); | |||
} | |||
@Test | |||
public void request_succeeds_if_name_is_64_char_long() { | |||
createUserAndLogInAsSystemAdministrator(); | |||
db.qualityGates().insertBuiltInQualityGate(); | |||
String name = STRING_65_CHARS_LONG.substring(0, 64); | |||
verifyResponseAndDb(executeRequest(name), name, name.substring(0, 32), NOW); | |||
} | |||
@Test | |||
public void request_succeeds_if_key_is_2_chars_long() { | |||
createUserAndLogInAsSystemAdministrator(); | |||
@@ -327,17 +316,6 @@ public class CreateActionTest { | |||
verifyResponseAndDb(response, "foo", "bar", "moo", "doo", "boo", NOW); | |||
} | |||
@Test | |||
public void request_succeeds_to_generate_key_from_name_more_then_32_chars_long() { | |||
createUserAndLogInAsSystemAdministrator(); | |||
db.qualityGates().insertBuiltInQualityGate(); | |||
String name = STRING_65_CHARS_LONG.substring(0, 33); | |||
CreateWsResponse response = executeRequest(name); | |||
verifyResponseAndDb(response, name, name.substring(0, 32), NOW); | |||
} | |||
@Test | |||
public void request_generates_key_ignoring_multiple_following_spaces() { | |||
createUserAndLogInAsSystemAdministrator(); | |||
@@ -389,40 +367,6 @@ public class CreateActionTest { | |||
executeRequest(null); | |||
} | |||
@Test | |||
public void request_fails_if_name_is_empty() { | |||
createUserAndLogInAsSystemAdministrator(); | |||
expectedException.expect(IllegalArgumentException.class); | |||
expectedException.expectMessage("Name must not be empty"); | |||
wsTester.newRequest() | |||
.setParam(PARAM_NAME, "") | |||
.execute(); | |||
} | |||
@Test | |||
public void request_fails_if_name_is_65_chars_long() { | |||
createUserAndLogInAsSystemAdministrator(); | |||
expectedException.expect(IllegalArgumentException.class); | |||
expectedException.expectMessage("'name' length (65) is longer than the maximum authorized (64)"); | |||
executeRequest(STRING_65_CHARS_LONG); | |||
} | |||
@Test | |||
public void request_fails_if_key_is_33_chars_long() { | |||
createUserAndLogInAsSystemAdministrator(); | |||
String key = STRING_65_CHARS_LONG.substring(0, 33); | |||
expectedException.expect(IllegalArgumentException.class); | |||
expectedException.expectMessage("'key' length (33) is longer than the maximum authorized (32)"); | |||
executeRequest("foo", key); | |||
} | |||
@Test | |||
public void requests_fails_if_key_contains_non_ascii_chars_but_dash() { | |||
createUserAndLogInAsSystemAdministrator(); | |||
@@ -463,19 +407,6 @@ public class CreateActionTest { | |||
executeRequest("foo", "a b"); | |||
} | |||
@Test | |||
public void request_fails_if_key_is_empty() { | |||
createUserAndLogInAsSystemAdministrator(); | |||
expectedException.expect(IllegalArgumentException.class); | |||
expectedException.expectMessage("Key must not be empty"); | |||
wsTester.newRequest() | |||
.setParam(PARAM_KEY, "") | |||
.setParam(PARAM_NAME, "foo") | |||
.execute(); | |||
} | |||
@Test | |||
public void request_fails_if_key_is_specified_and_already_exists_in_DB() { | |||
createUserAndLogInAsSystemAdministrator(); | |||
@@ -490,9 +421,9 @@ public class CreateActionTest { | |||
@Test | |||
public void request_fails_if_key_computed_from_name_already_exists_in_DB() { | |||
createUserAndLogInAsSystemAdministrator(); | |||
String key = STRING_65_CHARS_LONG.substring(0, 32); | |||
String key = "key"; | |||
db.organizations().insert(o -> o.setKey(key)); | |||
String name = STRING_65_CHARS_LONG.substring(0, 64); | |||
String name = "Key"; | |||
expectedException.expect(IllegalArgumentException.class); | |||
expectedException.expectMessage("Key '" + key + "' generated from name '" + name + "' is already used. Specify one."); | |||
@@ -584,13 +515,18 @@ public class CreateActionTest { | |||
assertThat(action.handler()).isNotNull(); | |||
assertThat(action.params()).hasSize(5); | |||
assertThat(action.responseExample()).isEqualTo(getClass().getResource("create-example.json")); | |||
assertThat(action.param("name")) | |||
.matches(WebService.Param::isRequired) | |||
.matches(param -> "Foo Company".equals(param.exampleValue())) | |||
.matches(param -> param.minimumLength().equals(1)) | |||
.matches(param -> param.maximumLength().equals(300)) | |||
.matches(param -> param.description() != null); | |||
assertThat(action.param("key")) | |||
.matches(param -> !param.isRequired()) | |||
.matches(param -> "foo-company".equals(param.exampleValue())) | |||
.matches(param -> param.minimumLength().equals(1)) | |||
.matches(param -> param.maximumLength().equals(300)) | |||
.matches(param -> param.description() != null); | |||
assertThat(action.param("description")) | |||
.matches(param -> !param.isRequired()) |
@@ -82,6 +82,8 @@ public class UpdateActionTest { | |||
assertThat(action.param("name")) | |||
.matches(param -> !param.isRequired()) | |||
.matches(param -> "Foo Company".equals(param.exampleValue())) | |||
.matches(param -> param.minimumLength().equals(1)) | |||
.matches(param -> param.maximumLength().equals(300)) | |||
.matches(param -> param.description() != null); | |||
assertThat(action.param("description")) | |||
.matches(param -> !param.isRequired()) | |||
@@ -172,16 +174,6 @@ public class UpdateActionTest { | |||
verifyResponseAndDb(executeKeyRequest(org.getKey(), null), org, org.getName(), DATE_2); | |||
} | |||
@Test | |||
public void request_fails_if_name_is_empty() { | |||
userSession.logIn(); | |||
expectedException.expect(IllegalArgumentException.class); | |||
expectedException.expectMessage("Name must not be empty"); | |||
executeKeyRequest(SOME_KEY, ""); | |||
} | |||
@Test | |||
public void request_succeeds_if_name_is_two_chars_long() { | |||
OrganizationDto org = mockForSuccessfulUpdate(DATE_1, DATE_2); | |||
@@ -190,17 +182,6 @@ public class UpdateActionTest { | |||
verifyResponseAndDb(executeKeyRequest(org.getKey(), "ab"), org, "ab", DATE_2); | |||
} | |||
@Test | |||
public void request_fails_if_name_is_65_chars_long() { | |||
userSession.logIn(); | |||
expectedException.expect(IllegalArgumentException.class); | |||
expectedException.expectMessage("'name' length (65) is longer than the maximum authorized (64)"); | |||
executeKeyRequest(SOME_KEY, STRING_65_CHARS_LONG); | |||
} | |||
@Test | |||
public void request_succeeds_if_name_is_64_char_long() { | |||
OrganizationDto org = mockForSuccessfulUpdate(DATE_1, DATE_2); |