Browse Source

SONAR-8172 add WS /api/organizations/update

tags/6.2-RC1
Sébastien Lesaint 7 years ago
parent
commit
7b33b0a132

+ 11
- 47
server/sonar-server/src/main/java/org/sonar/server/organization/ws/CreateAction.java View File

@@ -36,19 +36,16 @@ import org.sonarqube.ws.Organizations.CreateWsResponse;
import static com.google.common.base.Preconditions.checkArgument;
import static java.lang.Math.min;
import static org.sonar.core.util.Slug.slugify;
import static org.sonar.server.organization.ws.OrganizationsWsSupport.KEY_MAX_LENGTH;
import static org.sonar.server.organization.ws.OrganizationsWsSupport.KEY_MIN_LENGTH;
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_URL;
import static org.sonar.server.ws.WsUtils.writeProtobuf;

public class CreateAction implements OrganizationsAction {
private static final String ACTION = "create";
private static final String PARAM_NAME = "name";
private static final String PARAM_KEY = "key";
private static final String PARAM_DESCRIPTION = "description";
private static final String PARAM_URL = "url";
private static final String PARAM_AVATAR_URL = "avatar";
private static final int NAME_MIN_LENGTH = 2;
private static final int NAME_MAX_LENGTH = 64;
private static final int KEY_MIN_LENGTH = 2;
private static final int KEY_MAX_LENGTH = 32;

private final UserSession userSession;
private final DbClient dbClient;
@@ -74,12 +71,6 @@ public class CreateAction implements OrganizationsAction {
.setSince("6.2")
.setHandler(this);

action.createParam(PARAM_NAME)
.setRequired(true)
.setDescription("Name of the organization. <br />" +
"It must be between 2 and 64 chars longs.")
.setExampleValue("Foo Company");

action.createParam(PARAM_KEY)
.setRequired(false)
.setDescription("Key of the organization. <br />" +
@@ -88,32 +79,19 @@ public class CreateAction implements OrganizationsAction {
"Otherwise, it must be between 2 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)")
.setExampleValue("foo-company");

action.createParam(PARAM_DESCRIPTION)
.setRequired(false)
.setDescription("Description of the organization.<br/> It must be less than 256 chars long.")
.setExampleValue("The Foo company produces quality software for Bar.");

action.createParam(PARAM_URL)
.setRequired(false)
.setDescription("URL of the organization.<br/> It must be less than 256 chars long.")
.setExampleValue("https://www.foo.com");

action.createParam(PARAM_AVATAR_URL)
.setRequired(false)
.setDescription("URL of the organization avatar.<br/> It must be less than 256 chars long.")
.setExampleValue("https://www.foo.com/foo.png");
wsSupport.addOrganizationDetailsParams(action);
}

@Override
public void handle(Request request, Response response) throws Exception {
userSession.checkPermission(GlobalPermissions.SYSTEM_ADMIN);

String name = getAndCheckName(request);
String name = wsSupport.getAndCheckName(request);
String requestKey = getAndCheckKey(request);
String key = useOrGenerateKey(requestKey, name);
checkParamMaxLength(request, PARAM_DESCRIPTION, 256);
checkParamMaxLength(request, PARAM_URL, 256);
checkParamMaxLength(request, PARAM_AVATAR_URL, 256);
wsSupport.getAndCheckDescription(request);
wsSupport.getAndCheckUrl(request);
wsSupport.getAndCheckAvatar(request);

try (DbSession dbSession = dbClient.openSession(false)) {
checkKeyIsNotUsed(dbSession, key, requestKey, name);
@@ -126,20 +104,6 @@ public class CreateAction implements OrganizationsAction {
}
}

private static void checkParamMaxLength(Request request, String key, int maxLength) {
String value = request.param(key);
if (value != null) {
checkArgument(value.length() <= maxLength, "%s '%s' must be at most %s chars long", key, value, maxLength);
}
}

private static String getAndCheckName(Request request) {
String name = request.mandatoryParam(PARAM_NAME);
checkArgument(name.length() >= NAME_MIN_LENGTH, "Name '%s' must be at least %s chars long", name, NAME_MIN_LENGTH);
checkArgument(name.length() <= NAME_MAX_LENGTH, "Name '%s' must be at most %s chars long", name, NAME_MAX_LENGTH);
return name;
}

@CheckForNull
private static String getAndCheckKey(Request request) {
String rqstKey = request.param(PARAM_KEY);

+ 2
- 1
server/sonar-server/src/main/java/org/sonar/server/organization/ws/OrganizationsWsModule.java View File

@@ -30,7 +30,8 @@ public class OrganizationsWsModule extends Module {
OrganizationsWsSupport.class,
// actions
CreateAction.class,
SearchAction.class);
SearchAction.class,
UpdateAction.class);
}

}

+ 75
- 0
server/sonar-server/src/main/java/org/sonar/server/organization/ws/OrganizationsWsSupport.java View File

@@ -19,10 +19,85 @@
*/
package org.sonar.server.organization.ws;

import javax.annotation.CheckForNull;
import org.sonar.api.server.ws.Request;
import org.sonar.api.server.ws.WebService;
import org.sonar.db.organization.OrganizationDto;
import org.sonarqube.ws.Organizations;

import static com.google.common.base.Preconditions.checkArgument;

/**
* Factorizes code and constants between Organization WS's actions.
*/
public class OrganizationsWsSupport {
static final String PARAM_ID = "id";
static final String PARAM_KEY = "key";
static final String PARAM_NAME = "name";
static final String PARAM_DESCRIPTION = "description";
static final String PARAM_URL = "url";
static final String PARAM_AVATAR_URL = "avatar";
static final int KEY_MIN_LENGTH = 2;
static final int KEY_MAX_LENGTH = 32;
static final int NAME_MIN_LENGTH = 2;
static final int NAME_MAX_LENGTH = 64;
static final int DESCRIPTION_MAX_LENGTH = 256;
static final int URL_MAX_LENGTH = 256;

String getAndCheckName(Request request) {
String name = request.mandatoryParam(PARAM_NAME);
checkArgument(name.length() >= NAME_MIN_LENGTH, "Name '%s' must be at least %s chars long", name, NAME_MIN_LENGTH);
checkArgument(name.length() <= NAME_MAX_LENGTH, "Name '%s' must be at most %s chars long", name, NAME_MAX_LENGTH);
return name;
}

@CheckForNull
String getAndCheckAvatar(Request request) {
return getAndCheckParamMaxLength(request, PARAM_AVATAR_URL, URL_MAX_LENGTH);
}

@CheckForNull
String getAndCheckUrl(Request request) {
return getAndCheckParamMaxLength(request, PARAM_URL, URL_MAX_LENGTH);
}

@CheckForNull
String getAndCheckDescription(Request request) {
return getAndCheckParamMaxLength(request, PARAM_DESCRIPTION, DESCRIPTION_MAX_LENGTH);
}

@CheckForNull
private static String getAndCheckParamMaxLength(Request request, String key, int maxLength) {
String value = request.param(key);
if (value != null) {
checkArgument(value.length() <= maxLength, "%s '%s' must be at most %s chars long", key, value, maxLength);
}
return value;
}

void addOrganizationDetailsParams(WebService.NewAction action) {
action.createParam(PARAM_NAME)
.setRequired(true)
.setDescription("Name of the organization. <br />" +
"It must be between 2 and 64 chars longs.")
.setExampleValue("Foo Company");

action.createParam(PARAM_DESCRIPTION)
.setRequired(false)
.setDescription("Description of the organization.<br/> It must be less than 256 chars long.")
.setExampleValue("The Foo company produces quality software for Bar.");

action.createParam(PARAM_URL)
.setRequired(false)
.setDescription("URL of the organization.<br/> It must be less than 256 chars long.")
.setExampleValue("https://www.foo.com");

action.createParam(PARAM_AVATAR_URL)
.setRequired(false)
.setDescription("URL of the organization avatar.<br/> It must be less than 256 chars long.")
.setExampleValue("https://www.foo.com/foo.png");
}

Organizations.Organization toOrganization(OrganizationDto dto) {
return toOrganization(Organizations.Organization.newBuilder(), dto);
}

+ 135
- 0
server/sonar-server/src/main/java/org/sonar/server/organization/ws/UpdateAction.java View File

@@ -0,0 +1,135 @@
/*
* SonarQube
* Copyright (C) 2009-2016 SonarSource SA
* mailto:contact 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.organization.ws;

import java.util.Optional;
import javax.annotation.Nullable;
import org.sonar.api.server.ws.Request;
import org.sonar.api.server.ws.Response;
import org.sonar.api.server.ws.WebService;
import org.sonar.api.utils.System2;
import org.sonar.core.permission.GlobalPermissions;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.organization.OrganizationDto;
import org.sonar.server.exceptions.NotFoundException;
import org.sonar.server.user.UserSession;
import org.sonarqube.ws.Organizations;

import static com.google.common.base.Preconditions.checkArgument;
import static java.lang.String.format;
import static org.sonar.core.util.Uuids.UUID_EXAMPLE_03;
import static org.sonar.server.organization.ws.OrganizationsWsSupport.PARAM_KEY;
import static org.sonar.server.organization.ws.OrganizationsWsSupport.PARAM_ID;
import static org.sonar.server.ws.WsUtils.writeProtobuf;

public class UpdateAction implements OrganizationsAction {
private static final String ACTION = "update";

private final UserSession userSession;
private final OrganizationsWsSupport wsSupport;
private final DbClient dbClient;
private final System2 system2;

public UpdateAction(UserSession userSession, OrganizationsWsSupport wsSupport, DbClient dbClient, System2 system2) {
this.userSession = userSession;
this.wsSupport = wsSupport;
this.dbClient = dbClient;
this.system2 = system2;
}

@Override
public void define(WebService.NewController context) {
WebService.NewAction action = context.createAction(ACTION)
.setPost(true)
.setDescription(
format("Update an organization.<br/>" +
"The '%s' or '%s' must be provided.<br/>" +
"Require 'Administer System' permission.",
PARAM_ID, PARAM_KEY))
.setInternal(true)
.setSince("6.2")
.setHandler(this);

action.createParam(PARAM_ID)
.setRequired(false)
.setDescription("Organization id")
.setExampleValue(UUID_EXAMPLE_03);

action.createParam(PARAM_KEY)
.setRequired(false)
.setDescription("Organization key")
.setExampleValue("foo-company");

wsSupport.addOrganizationDetailsParams(action);
}

@Override
public void handle(Request request, Response response) throws Exception {
userSession.checkPermission(GlobalPermissions.SYSTEM_ADMIN);

String uuid = request.param(PARAM_ID);
String key = request.param(PARAM_KEY);
checkKeyOrUuid(uuid, key);
String name = wsSupport.getAndCheckName(request);
String description = wsSupport.getAndCheckDescription(request);
String url = wsSupport.getAndCheckUrl(request);
String avatar = wsSupport.getAndCheckAvatar(request);

try (DbSession dbSession = dbClient.openSession(false)) {
OrganizationDto dto = getDto(dbSession, uuid, key);
dto.setName(name)
.setDescription(description)
.setUrl(url)
.setAvatarUrl(avatar)
.setUpdatedAt(system2.now());
dbClient.organizationDao().update(dbSession, dto);
dbSession.commit();

writeResponse(request, response, dto);
}
}

private static void checkKeyOrUuid(@Nullable String uuid, @Nullable String key) {
checkArgument(uuid != null ^ key != null, "Either '%s' or '%s' must be provided, not both", PARAM_ID, PARAM_KEY);
}

private OrganizationDto getDto(DbSession dbSession, @Nullable String uuid, @Nullable String key) {
if (uuid != null) {
return failIfEmpty(dbClient.organizationDao().selectByUuid(dbSession, uuid), "Organization not found for uuid '%s'", uuid);
} else {
return failIfEmpty(dbClient.organizationDao().selectByKey(dbSession, key), "Organization not found for key '%s'", key);
}
}

private static OrganizationDto failIfEmpty(Optional<OrganizationDto> organizationDto, String msg, Object argument) {
if (!organizationDto.isPresent()) {
throw new NotFoundException(format(msg, argument));
}
return organizationDto.get();
}

private void writeResponse(Request request, Response response, OrganizationDto dto) {
writeProtobuf(
Organizations.UpdateWsResponse.newBuilder().setOrganization(wsSupport.toOrganization(dto)).build(),
request,
response);
}
}

+ 7
- 13
server/sonar-server/src/test/java/org/sonar/server/organization/ws/CreateActionTest.java View File

@@ -44,13 +44,13 @@ import org.sonarqube.ws.Organizations.Organization;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static org.sonar.server.organization.ws.OrganizationsWsTestSupport.STRING_257_CHARS_LONG;
import static org.sonar.server.organization.ws.OrganizationsWsTestSupport.STRING_65_CHARS_LONG;
import static org.sonar.test.JsonAssert.assertJson;

public class CreateActionTest {
private static final String SOME_UUID = "uuid";
private static final long SOME_DATE = 1_200_000L;
private static final String STRING_65_CHARS_LONG = "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz1234567890-ab";
private static final String STRING_257_CHARS_LONG = String.format("%1$257.257s", "a").replace(" ", "a");

@Rule
public UserSessionRule userSession = UserSessionRule.standalone();
@@ -401,17 +401,11 @@ public class CreateActionTest {

private static void populateRequest(@Nullable String name, @Nullable String key, @Nullable String description, @Nullable String url, @Nullable String avatar,
TestRequest request) {
setParam(request, "name", name);
setParam(request, "key", key);
setParam(request, "description", description);
setParam(request, "url", url);
setParam(request, "avatar", avatar);
}

private static void setParam(TestRequest request, String param, @Nullable String value) {
if (value != null) {
request.setParam(param, value);
}
OrganizationsWsTestSupport.setParam(request, "name", name);
OrganizationsWsTestSupport.setParam(request, "key", key);
OrganizationsWsTestSupport.setParam(request, "description", description);
OrganizationsWsTestSupport.setParam(request, "url", url);
OrganizationsWsTestSupport.setParam(request, "avatar", avatar);
}

private void verifyResponseAndDb(CreateWsResponse response,

+ 1
- 1
server/sonar-server/src/test/java/org/sonar/server/organization/ws/OrganizationsWsModuleTest.java View File

@@ -34,7 +34,7 @@ public class OrganizationsWsModuleTest {
public void verify_component_count() {
ComponentContainer container = new ComponentContainer();
underTest.configure(container);
assertThat(container.getPicoContainer().getComponentAdapters()).hasSize(CONTAINER_ITSELF + PROPERTY_DEFINITION + 4);
assertThat(container.getPicoContainer().getComponentAdapters()).hasSize(CONTAINER_ITSELF + PROPERTY_DEFINITION + 5);
}

}

+ 35
- 0
server/sonar-server/src/test/java/org/sonar/server/organization/ws/OrganizationsWsTestSupport.java View File

@@ -0,0 +1,35 @@
/*
* SonarQube
* Copyright (C) 2009-2016 SonarSource SA
* mailto:contact 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.organization.ws;

import javax.annotation.Nullable;
import org.sonar.server.ws.TestRequest;

public class OrganizationsWsTestSupport {

static final String STRING_65_CHARS_LONG = "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz1234567890-ab";
static final String STRING_257_CHARS_LONG = String.format("%1$257.257s", "a").replace(" ", "a");

static void setParam(TestRequest request, String param, @Nullable String value) {
if (value != null) {
request.setParam(param, value);
}
}
}

+ 481
- 0
server/sonar-server/src/test/java/org/sonar/server/organization/ws/UpdateActionTest.java View File

@@ -0,0 +1,481 @@
/*
* SonarQube
* Copyright (C) 2009-2016 SonarSource SA
* mailto:contact 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.organization.ws;

import java.io.IOException;
import javax.annotation.Nullable;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.sonar.api.server.ws.WebService;
import org.sonar.api.utils.System2;
import org.sonar.core.permission.GlobalPermissions;
import org.sonar.db.DbTester;
import org.sonar.db.organization.OrganizationDto;
import org.sonar.server.exceptions.ForbiddenException;
import org.sonar.server.tester.UserSessionRule;
import org.sonar.server.ws.TestRequest;
import org.sonar.server.ws.WsActionTester;
import org.sonarqube.ws.MediaTypes;
import org.sonarqube.ws.Organizations;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static org.sonar.core.util.Uuids.UUID_EXAMPLE_03;
import static org.sonar.server.organization.ws.OrganizationsWsTestSupport.STRING_257_CHARS_LONG;
import static org.sonar.server.organization.ws.OrganizationsWsTestSupport.STRING_65_CHARS_LONG;
import static org.sonar.server.organization.ws.OrganizationsWsTestSupport.setParam;

public class UpdateActionTest {
private static final String SOME_UUID = "uuid";
private static final String SOME_KEY = "key";
private static final long SOME_DATE = 1_200_000L;

@Rule
public DbTester dbTester = DbTester.create(System2.INSTANCE);
@Rule
public UserSessionRule userSession = UserSessionRule.standalone();
@Rule
public ExpectedException expectedException = ExpectedException.none();

private System2 system2 = mock(System2.class);
private UpdateAction underTest = new UpdateAction(userSession, new OrganizationsWsSupport(), dbTester.getDbClient(), system2);
private WsActionTester wsTester = new WsActionTester(underTest);

@Test
public void verify_define() {
WebService.Action action = wsTester.getDef();
assertThat(action.key()).isEqualTo("update");
assertThat(action.isPost()).isTrue();
assertThat(action.description()).isEqualTo("Update an organization.<br/>" +
"The 'id' or 'key' must be provided.<br/>" +
"Require 'Administer System' permission.");
assertThat(action.isInternal()).isTrue();
assertThat(action.since()).isEqualTo("6.2");
assertThat(action.handler()).isEqualTo(underTest);
assertThat(action.params()).hasSize(6);
assertThat(action.responseExample()).isNull();

assertThat(action.param("id"))
.matches(param -> !param.isRequired())
.matches(param -> UUID_EXAMPLE_03.equals(param.exampleValue()))
.matches(param -> "Organization id".equals(param.description()));
assertThat(action.param("key"))
.matches(param -> !param.isRequired())
.matches(param -> "foo-company".equals(param.exampleValue()))
.matches(param -> "Organization key".equals(param.description()));
assertThat(action.param("name"))
.matches(WebService.Param::isRequired)
.matches(param -> "Foo Company".equals(param.exampleValue()))
.matches(param -> param.description() != null);
assertThat(action.param("description"))
.matches(param -> !param.isRequired())
.matches(param -> "The Foo company produces quality software for Bar.".equals(param.exampleValue()))
.matches(param -> param.description() != null);
assertThat(action.param("url"))
.matches(param -> !param.isRequired())
.matches(param -> "https://www.foo.com".equals(param.exampleValue()))
.matches(param -> param.description() != null);
assertThat(action.param("avatar"))
.matches(param -> !param.isRequired())
.matches(param -> "https://www.foo.com/foo.png".equals(param.exampleValue()))
.matches(param -> param.description() != null);
}

@Test
public void request_fails_if_user_does_not_have_SYSTEM_ADMIN_permission() {
expectedException.expect(ForbiddenException.class);
expectedException.expectMessage("Insufficient privileges");

executeIdRequest("uuid", "name");
}

@Test
public void request_fails_if_both_uuid_and_key_are_missing() {
giveUserSystemAdminPermission();

expectUuidAndKeySetOrMissingIAE();

executeRequest(null, null, "name", "description", "url", "avatar");
}

@Test
public void request_fails_if_both_uuid_and_key_are_provided() {
giveUserSystemAdminPermission();

expectUuidAndKeySetOrMissingIAE();

executeRequest("uuid", "key", "name", "description", "url", "avatar");
}

private void expectUuidAndKeySetOrMissingIAE() {
expectedException.expect(IllegalArgumentException.class);
expectedException.expectMessage("Either 'id' or 'key' must be provided, not both");
}

@Test
public void request_fails_if_name_param_is_missing_when_uuid_is_provided() {
giveUserSystemAdminPermission();

expectMissingNameIAE();

executeIdRequest("uuid", null);
}

@Test
public void request_fails_if_name_param_is_missing_when_key_is_provided() {
giveUserSystemAdminPermission();

expectMissingNameIAE();

executeKeyRequest("key", null);
}

private void expectMissingNameIAE() {
expectedException.expect(IllegalArgumentException.class);
expectedException.expectMessage("The 'name' parameter is missing");
}

@Test
public void request_fails_if_name_is_one_char_long_when_uuid_is_provided() {
giveUserSystemAdminPermission();

expectNameTooShortIAE();

executeIdRequest(SOME_UUID, "a");
}

@Test
public void request_fails_if_name_is_one_char_long_when_key_is_provided() {
giveUserSystemAdminPermission();

expectNameTooShortIAE();

executeKeyRequest(SOME_KEY, "a");
}

private void expectNameTooShortIAE() {
expectedException.expect(IllegalArgumentException.class);
expectedException.expectMessage("Name 'a' must be at least 2 chars long");
}

@Test
public void request_succeeds_if_name_is_two_chars_long_when_uuid_is_provided() {
giveUserSystemAdminPermission();
OrganizationDto dto = mockForSuccessfulUpdate(SOME_UUID, SOME_DATE);

verifyResponseAndDb(executeIdRequest(SOME_UUID, "ab"), dto, "ab", SOME_DATE);
}

@Test
public void request_succeeds_if_name_is_two_chars_long_when_key_is_provided() {
giveUserSystemAdminPermission();
OrganizationDto dto = mockForSuccessfulUpdate(SOME_UUID, SOME_DATE);

verifyResponseAndDb(executeKeyRequest(dto.getKey(), "ab"), dto, "ab", SOME_DATE);
}

@Test
public void request_fails_if_name_is_65_chars_long_when_uuid_is_provided() {
giveUserSystemAdminPermission();

expectedException.expect(IllegalArgumentException.class);
expectedException.expectMessage("Name '" + STRING_65_CHARS_LONG + "' must be at most 64 chars long");

executeIdRequest(SOME_UUID, STRING_65_CHARS_LONG);
}

@Test
public void request_fails_if_name_is_65_chars_long_when_key_is_provided() {
giveUserSystemAdminPermission();

expectedException.expect(IllegalArgumentException.class);
expectedException.expectMessage("Name '" + STRING_65_CHARS_LONG + "' must be at most 64 chars long");

executeKeyRequest(SOME_KEY, STRING_65_CHARS_LONG);
}

@Test
public void request_succeeds_if_name_is_64_char_long_when_uuid_is_provided() {
giveUserSystemAdminPermission();
OrganizationDto dto = mockForSuccessfulUpdate(SOME_UUID, SOME_DATE);

String name = STRING_65_CHARS_LONG.substring(0, 64);

verifyResponseAndDb(executeIdRequest(SOME_UUID, name), dto, name, SOME_DATE);
}

@Test
public void request_succeeds_if_description_url_and_avatar_are_not_specified_when_uuid_is_specified() {
giveUserSystemAdminPermission();
OrganizationDto dto = mockForSuccessfulUpdate(SOME_UUID, SOME_DATE);

Organizations.UpdateWsResponse response = executeIdRequest(SOME_UUID, "bar", null, null, null);
verifyResponseAndDb(response, dto, "bar", null, null, null, SOME_DATE);
}

@Test
public void request_succeeds_if_description_url_and_avatar_are_not_specified_when_key_is_specified() {
giveUserSystemAdminPermission();
OrganizationDto dto = mockForSuccessfulUpdate(SOME_UUID, SOME_DATE);

Organizations.UpdateWsResponse response = executeKeyRequest(dto.getKey(), "bar", null, null, null);
verifyResponseAndDb(response, dto, "bar", null, null, null, SOME_DATE);
}

@Test
public void request_succeeds_if_description_url_and_avatar_are_specified_when_uuid_is_specified() {
giveUserSystemAdminPermission();
OrganizationDto dto = mockForSuccessfulUpdate(SOME_UUID, SOME_DATE);

Organizations.UpdateWsResponse response = executeIdRequest(SOME_UUID, "bar", "moo", "doo", "boo");
verifyResponseAndDb(response, dto, "bar", "moo", "doo", "boo", SOME_DATE);
}

@Test
public void request_succeeds_if_description_url_and_avatar_are_specified_when_key_is_specified() {
giveUserSystemAdminPermission();
OrganizationDto dto = mockForSuccessfulUpdate(SOME_UUID, SOME_DATE);

Organizations.UpdateWsResponse response = executeKeyRequest(dto.getKey(), "bar", "moo", "doo", "boo");
verifyResponseAndDb(response, dto, "bar", "moo", "doo", "boo", SOME_DATE);
}

@Test
public void request_fails_if_description_is_257_chars_long_when_uuid_is_specified() {
giveUserSystemAdminPermission();

expectedException.expect(IllegalArgumentException.class);
expectedException.expectMessage("description '" + STRING_257_CHARS_LONG + "' must be at most 256 chars long");

executeIdRequest(SOME_UUID, "bar", STRING_257_CHARS_LONG, null, null);
}

@Test
public void request_fails_if_description_is_257_chars_long_when_key_is_specified() {
giveUserSystemAdminPermission();

expectedException.expect(IllegalArgumentException.class);
expectedException.expectMessage("description '" + STRING_257_CHARS_LONG + "' must be at most 256 chars long");

executeKeyRequest(SOME_KEY, "bar", STRING_257_CHARS_LONG, null, null);
}

@Test
public void request_succeeds_if_description_is_256_chars_long_when_uuid_is_specified() {
giveUserSystemAdminPermission();
OrganizationDto dto = mockForSuccessfulUpdate(SOME_UUID, SOME_DATE);
String description = STRING_257_CHARS_LONG.substring(0, 256);

Organizations.UpdateWsResponse response = executeIdRequest(SOME_UUID, "bar", description, null, null);
verifyResponseAndDb(response, dto, "bar", description, null, null, SOME_DATE);
}

@Test
public void request_succeeds_if_description_is_256_chars_long_when_key_is_specified() {
giveUserSystemAdminPermission();
OrganizationDto dto = mockForSuccessfulUpdate(SOME_UUID, SOME_DATE);
String description = STRING_257_CHARS_LONG.substring(0, 256);

Organizations.UpdateWsResponse response = executeKeyRequest(dto.getKey(), "bar", description, null, null);
verifyResponseAndDb(response, dto, "bar", description, null, null, SOME_DATE);
}

@Test
public void request_fails_if_url_is_257_chars_long_when_uuid_is_specified() {
giveUserSystemAdminPermission();

expectedException.expect(IllegalArgumentException.class);
expectedException.expectMessage("url '" + STRING_257_CHARS_LONG + "' must be at most 256 chars long");

executeIdRequest(SOME_UUID, "bar", null, STRING_257_CHARS_LONG, null);
}

@Test
public void request_fails_if_url_is_257_chars_long_when_key_is_specified() {
giveUserSystemAdminPermission();

expectedException.expect(IllegalArgumentException.class);
expectedException.expectMessage("url '" + STRING_257_CHARS_LONG + "' must be at most 256 chars long");

executeKeyRequest(SOME_KEY, "bar", null, STRING_257_CHARS_LONG, null);
}

@Test
public void request_succeeds_if_url_is_256_chars_long_when_uuid_is_specified() {
giveUserSystemAdminPermission();
OrganizationDto dto = mockForSuccessfulUpdate(SOME_UUID, SOME_DATE);
String url = STRING_257_CHARS_LONG.substring(0, 256);

Organizations.UpdateWsResponse response = executeIdRequest(SOME_UUID, "bar", null, url, null);
verifyResponseAndDb(response, dto, "bar", null, url, null, SOME_DATE);
}

@Test
public void request_succeeds_if_url_is_256_chars_long_when_key_is_specified() {
giveUserSystemAdminPermission();
OrganizationDto dto = mockForSuccessfulUpdate(SOME_UUID, SOME_DATE);
String url = STRING_257_CHARS_LONG.substring(0, 256);

Organizations.UpdateWsResponse response = executeKeyRequest(dto.getKey(), "bar", null, url, null);
verifyResponseAndDb(response, dto, "bar", null, url, null, SOME_DATE);
}

@Test
public void request_fails_if_avatar_is_257_chars_long_when_uuid_is_specified() {
giveUserSystemAdminPermission();

expectedException.expect(IllegalArgumentException.class);
expectedException.expectMessage("avatar '" + STRING_257_CHARS_LONG + "' must be at most 256 chars long");

executeIdRequest(SOME_UUID, "bar", null, null, STRING_257_CHARS_LONG);
}

@Test
public void request_fails_if_avatar_is_257_chars_long_when_key_is_specified() {
giveUserSystemAdminPermission();

expectedException.expect(IllegalArgumentException.class);
expectedException.expectMessage("avatar '" + STRING_257_CHARS_LONG + "' must be at most 256 chars long");

executeKeyRequest(SOME_KEY, "bar", null, null, STRING_257_CHARS_LONG);
}

@Test
public void request_succeeds_if_avatar_is_256_chars_long_when_uuid_is_specified() {
giveUserSystemAdminPermission();
OrganizationDto dto = mockForSuccessfulUpdate(SOME_UUID, SOME_DATE);
String avatar = STRING_257_CHARS_LONG.substring(0, 256);

Organizations.UpdateWsResponse response = executeIdRequest(SOME_UUID, "bar", null, null, avatar);
verifyResponseAndDb(response, dto, "bar", null, null, avatar, SOME_DATE);
}

@Test
public void request_succeeds_if_avatar_is_256_chars_long_when_key_is_specified() {
giveUserSystemAdminPermission();
OrganizationDto dto = mockForSuccessfulUpdate(SOME_UUID, SOME_DATE);
String avatar = STRING_257_CHARS_LONG.substring(0, 256);

Organizations.UpdateWsResponse response = executeKeyRequest(dto.getKey(), "bar", null, null, avatar);
verifyResponseAndDb(response, dto, "bar", null, null, avatar, SOME_DATE);
}

private void giveUserSystemAdminPermission() {
userSession.setGlobalPermissions(GlobalPermissions.SYSTEM_ADMIN);
}

private OrganizationDto mockForSuccessfulUpdate(String uuid, long nextNow) {
OrganizationDto dto = insertOrganization(uuid);
when(system2.now()).thenReturn(nextNow);
return dto;
}

private OrganizationDto insertOrganization(String uuid) {
OrganizationDto dto = new OrganizationDto()
.setUuid(uuid)
.setKey(uuid + "_key")
.setName(uuid + "_name")
.setDescription(uuid + "_description")
.setUrl(uuid + "_url")
.setAvatarUrl(uuid + "_avatar_url")
.setCreatedAt((long) uuid.hashCode())
.setUpdatedAt((long) uuid.hashCode());
dbTester.getDbClient().organizationDao().insert(dbTester.getSession(), dto);
dbTester.commit();
return dto;
}

private Organizations.UpdateWsResponse executeIdRequest(String uuid, @Nullable String name) {
return executeRequest(uuid, null, name, null, null, null);
}

private Organizations.UpdateWsResponse executeIdRequest(String id, @Nullable String name,
@Nullable String description, @Nullable String url, @Nullable String avatar) {
return executeRequest(id, null, name, description, url, avatar);
}

private Organizations.UpdateWsResponse executeKeyRequest(String key, @Nullable String name) {
return executeRequest(null, key, name, null, null, null);
}

private Organizations.UpdateWsResponse executeKeyRequest(String key, @Nullable String name,
@Nullable String description, @Nullable String url, @Nullable String avatar) {
return executeRequest(null, key, name, description, url, avatar);
}

private Organizations.UpdateWsResponse executeRequest(@Nullable String id, @Nullable String key,
@Nullable String name, @Nullable String description, @Nullable String url, @Nullable String avatar) {
TestRequest request = wsTester.newRequest()
.setMediaType(MediaTypes.PROTOBUF);
setParam(request, "id", id);
setParam(request, "key", key);
setParam(request, "name", name);
setParam(request, "description", description);
setParam(request, "url", url);
setParam(request, "avatar", avatar);
try {
return Organizations.UpdateWsResponse.parseFrom(request.execute().getInputStream());
} catch (IOException e) {
throw new IllegalStateException(e);
}
}

private void verifyResponseAndDb(Organizations.UpdateWsResponse response, OrganizationDto dto, String name, long updateAt) {
verifyResponseAndDb(response, dto, name, null, null, null, updateAt);
}

private void verifyResponseAndDb(Organizations.UpdateWsResponse response,
OrganizationDto dto, String name,
@Nullable String description, @Nullable String url, @Nullable String avatar,
long updateAt) {
Organizations.Organization organization = response.getOrganization();
assertThat(organization.getId()).isEqualTo(dto.getUuid());
assertThat(organization.getName()).isEqualTo(name);
assertThat(organization.getKey()).isEqualTo(dto.getKey());
if (description == null) {
assertThat(organization.hasDescription()).isFalse();
} else {
assertThat(organization.getDescription()).isEqualTo(description);
}
if (url == null) {
assertThat(organization.hasUrl()).isFalse();
} else {
assertThat(organization.getUrl()).isEqualTo(url);
}
if (avatar == null) {
assertThat(organization.hasAvatar()).isFalse();
} else {
assertThat(organization.getAvatar()).isEqualTo(avatar);
}

OrganizationDto newDto = dbTester.getDbClient().organizationDao().selectByUuid(dbTester.getSession(), dto.getUuid()).get();
assertThat(newDto.getUuid()).isEqualTo(newDto.getUuid());
assertThat(newDto.getKey()).isEqualTo(newDto.getKey());
assertThat(newDto.getName()).isEqualTo(name);
assertThat(newDto.getDescription()).isEqualTo(description);
assertThat(newDto.getUrl()).isEqualTo(url);
assertThat(newDto.getAvatarUrl()).isEqualTo(avatar);
assertThat(newDto.getCreatedAt()).isEqualTo(newDto.getCreatedAt());
assertThat(newDto.getUpdatedAt()).isEqualTo(updateAt);
}

}

+ 5
- 0
sonar-ws/src/main/protobuf/ws-organizations.proto View File

@@ -29,6 +29,11 @@ message CreateWsResponse {
optional Organization organization = 1;
}

// WS api/organizations/update
message UpdateWsResponse {
optional Organization organization = 1;
}

// WS api/organizations/search
message SearchWsResponse {
repeated Organization organizations = 1;

Loading…
Cancel
Save