Browse Source

SONAR-8748 BadRequestException fail when empty list or empty element

tags/6.3-RC1
Julien Lancelot 7 years ago
parent
commit
71c8b01163
26 changed files with 162 additions and 158 deletions
  1. 3
    4
      server/sonar-server/src/main/java/org/sonar/server/email/ws/SendAction.java
  2. 14
    25
      server/sonar-server/src/main/java/org/sonar/server/exceptions/BadRequestException.java
  3. 4
    0
      server/sonar-server/src/main/java/org/sonar/server/exceptions/Message.java
  4. 3
    1
      server/sonar-server/src/main/java/org/sonar/server/exceptions/ServerException.java
  5. 0
    33
      server/sonar-server/src/main/java/org/sonar/server/exceptions/Verifications.java
  6. 1
    1
      server/sonar-server/src/main/java/org/sonar/server/qualitygate/QualityGateConditionsUpdater.java
  7. 1
    1
      server/sonar-server/src/main/java/org/sonar/server/qualitygate/QualityGateUpdater.java
  8. 1
    1
      server/sonar-server/src/main/java/org/sonar/server/qualitygate/QualityGates.java
  9. 1
    1
      server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileExporters.java
  10. 4
    4
      server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileFactory.java
  11. 1
    1
      server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileReset.java
  12. 1
    1
      server/sonar-server/src/main/java/org/sonar/server/rule/RuleCreator.java
  13. 27
    27
      server/sonar-server/src/main/java/org/sonar/server/user/UserUpdater.java
  14. 3
    1
      server/sonar-server/src/main/java/org/sonar/server/util/BooleanTypeValidation.java
  15. 3
    1
      server/sonar-server/src/main/java/org/sonar/server/util/FloatTypeValidation.java
  16. 3
    1
      server/sonar-server/src/main/java/org/sonar/server/util/IntegerTypeValidation.java
  17. 3
    1
      server/sonar-server/src/main/java/org/sonar/server/util/LongTypeValidation.java
  18. 3
    1
      server/sonar-server/src/main/java/org/sonar/server/util/MetricLevelTypeValidation.java
  19. 3
    1
      server/sonar-server/src/main/java/org/sonar/server/util/StringListTypeValidation.java
  20. 4
    2
      server/sonar-server/src/main/java/org/sonar/server/util/Validation.java
  21. 52
    0
      server/sonar-server/src/test/java/org/sonar/server/exceptions/BadRequestExceptionTest.java
  22. 19
    0
      server/sonar-server/src/test/java/org/sonar/server/exceptions/MessageTest.java
  23. 1
    1
      server/sonar-server/src/test/java/org/sonar/server/exceptions/ServerExceptionTest.java
  24. 0
    44
      server/sonar-server/src/test/java/org/sonar/server/exceptions/VerificationsTest.java
  25. 1
    1
      server/sonar-server/src/test/java/org/sonar/server/util/TypeValidationsTest.java
  26. 6
    4
      server/sonar-server/src/test/java/org/sonar/server/ws/WebServiceEngineTest.java

+ 3
- 4
server/sonar-server/src/main/java/org/sonar/server/email/ws/SendAction.java View File

@@ -29,7 +29,6 @@ import org.sonar.api.server.ws.Request;
import org.sonar.api.server.ws.Response;
import org.sonar.api.server.ws.WebService;
import org.sonar.server.exceptions.BadRequestException;
import org.sonar.server.exceptions.Message;
import org.sonar.server.notification.email.EmailNotificationChannel;
import org.sonar.server.user.UserSession;

@@ -83,12 +82,12 @@ public class SendAction implements EmailsWsAction {
}

private static BadRequestException createBadRequestException(EmailException emailException) {
List<Message> messages = Throwables.getCausalChain(emailException)
List<String> messages = Throwables.getCausalChain(emailException)
.stream()
.map(e -> Message.of(e.getMessage()))
.map(Throwable::getMessage)
.collect(Collectors.toList());
Collections.reverse(messages);
return new BadRequestException(messages);
return BadRequestException.create(messages);
}

}

+ 14
- 25
server/sonar-server/src/main/java/org/sonar/server/exceptions/BadRequestException.java View File

@@ -21,8 +21,9 @@ package org.sonar.server.exceptions;

import com.google.common.base.MoreObjects;
import java.util.List;
import org.sonar.api.utils.ValidationMessages;
import java.util.stream.Collectors;

import static com.google.common.base.Preconditions.checkArgument;
import static java.net.HttpURLConnection.HTTP_BAD_REQUEST;

/**
@@ -32,46 +33,34 @@ public class BadRequestException extends ServerException {

private final transient Errors errors;

public BadRequestException(String format, Object... arguments) {
super(HTTP_BAD_REQUEST);
this.errors = new Errors().add(Message.of(format, arguments));
public BadRequestException(String message) {
super(HTTP_BAD_REQUEST, message);
this.errors = new Errors().add(Message.of(message));
}

public BadRequestException(List<Message> messages) {
super(HTTP_BAD_REQUEST);
this.errors = new Errors().add(messages);
private BadRequestException(Errors e) {
super(HTTP_BAD_REQUEST, e.messages().get(0).getMessage());
this.errors = e;
}

public BadRequestException(Errors e) {
super(HTTP_BAD_REQUEST);
this.errors = e;
public static BadRequestException create(List<String> errorMessages) {
return create(new Errors().add(errorMessages.stream().map(Message::of).collect(Collectors.toList())));
}

public BadRequestException(ValidationMessages validationMessages) {
super(HTTP_BAD_REQUEST);
this.errors = new Errors();
for (String s : validationMessages.getErrors()) {
errors.add(Message.of(s));
}
public static BadRequestException create(Errors e) {
checkArgument(!e.messages().isEmpty(), "At least one error message is required");
return new BadRequestException(e);
}

public Errors errors() {
return errors;
}

public Message firstError() {
return errors.messages().get(0);
}

@Override
public String getMessage() {
return firstError().getMessage();
}

@Override
public String toString() {
return MoreObjects.toStringHelper(this)
.add("errors", errors)
.toString();
}

}

+ 4
- 0
server/sonar-server/src/main/java/org/sonar/server/exceptions/Message.java View File

@@ -19,6 +19,9 @@
*/
package org.sonar.server.exceptions;

import com.google.common.base.Preconditions;

import static com.google.common.base.Strings.isNullOrEmpty;
import static java.lang.String.format;

public class Message {
@@ -26,6 +29,7 @@ public class Message {
private final String msg;

private Message(String format, Object... params) {
Preconditions.checkArgument(!isNullOrEmpty(format), "Message cannot be empty");
this.msg = format(format, params);
}


+ 3
- 1
server/sonar-server/src/main/java/org/sonar/server/exceptions/ServerException.java View File

@@ -19,6 +19,8 @@
*/
package org.sonar.server.exceptions;

import static java.util.Objects.requireNonNull;

public class ServerException extends RuntimeException {
private final int httpCode;

@@ -27,7 +29,7 @@ public class ServerException extends RuntimeException {
}

public ServerException(int httpCode, String message) {
super(message);
super(requireNonNull(message, "Error message cannot be null"));
this.httpCode = httpCode;
}


+ 0
- 33
server/sonar-server/src/main/java/org/sonar/server/exceptions/Verifications.java View File

@@ -1,33 +0,0 @@
/*
* 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.exceptions;

public class Verifications {

private Verifications() {
// only static stuff
}

public static void check(boolean expression, String format, Object... arguments) {
if (!expression) {
throw new BadRequestException(format, arguments);
}
}
}

+ 1
- 1
server/sonar-server/src/main/java/org/sonar/server/qualitygate/QualityGateConditionsUpdater.java View File

@@ -137,7 +137,7 @@ public class QualityGateConditionsUpdater {
checkPeriod(metric, period, errors);
checkRatingMetric(metric, warningThreshold, errorThreshold, period, errors);
if (!errors.isEmpty()) {
throw new BadRequestException(errors);
throw BadRequestException.create(errors);
}
}


+ 1
- 1
server/sonar-server/src/main/java/org/sonar/server/qualitygate/QualityGateUpdater.java View File

@@ -54,7 +54,7 @@ public class QualityGateUpdater {
checkQualityGateDoesNotAlreadyExist(qGateId, name, errors);
}
if (!errors.isEmpty()) {
throw new BadRequestException(errors);
throw BadRequestException.create(errors);
}
}


+ 1
- 1
server/sonar-server/src/main/java/org/sonar/server/qualitygate/QualityGates.java View File

@@ -233,7 +233,7 @@ public class QualityGates {
checkQgateNotAlreadyExists(updatingQgateId, name, errors);
}
if (!errors.isEmpty()) {
throw new BadRequestException(errors);
throw BadRequestException.create(errors);
}
}


+ 1
- 1
server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileExporters.java View File

@@ -172,7 +172,7 @@ public class QProfileExporters {

private static void processValidationMessages(ValidationMessages messages, QProfileResult result) {
if (!messages.getErrors().isEmpty()) {
throw new BadRequestException(messages);
throw BadRequestException.create(messages.getErrors());
}
result.addWarnings(messages.getWarnings());
result.addInfos(messages.getInfos());

+ 4
- 4
server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileFactory.java View File

@@ -35,10 +35,10 @@ import org.sonar.db.qualityprofile.ActiveRuleDto;
import org.sonar.db.qualityprofile.QualityProfileDto;
import org.sonar.server.exceptions.BadRequestException;
import org.sonar.server.exceptions.NotFoundException;
import org.sonar.server.exceptions.Verifications;

import static org.sonar.server.qualityprofile.ActiveRuleChange.Type.DEACTIVATED;
import static org.sonar.server.ws.WsUtils.checkFound;
import static org.sonar.server.ws.WsUtils.checkRequest;

/**
* Create, delete, rename and set as default profile.
@@ -140,7 +140,7 @@ public class QProfileFactory {
}

void setDefault(DbSession dbSession, String profileKey) {
Verifications.check(StringUtils.isNotBlank(profileKey), "Profile key must be set");
checkRequest(StringUtils.isNotBlank(profileKey), "Profile key must be set");
QualityProfileDto profile = db.qualityProfileDao().selectByKey(dbSession, profileKey);
if (profile == null) {
throw new NotFoundException("Quality profile not found: " + profileKey);
@@ -198,8 +198,8 @@ public class QProfileFactory {
// ------------- RENAME

public boolean rename(String key, String newName) {
Verifications.check(StringUtils.isNotBlank(newName), "Name must be set");
Verifications.check(newName.length() < 100, String.format("Name is too long (>%d characters)", 100));
checkRequest(StringUtils.isNotBlank(newName), "Name must be set");
checkRequest(newName.length() < 100, String.format("Name is too long (>%d characters)", 100));
DbSession dbSession = db.openSession(false);
try {
QualityProfileDto profile = db.qualityProfileDao().selectByKey(dbSession, key);

+ 1
- 1
server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileReset.java View File

@@ -172,7 +172,7 @@ public class QProfileReset {

private void processValidationMessages(ValidationMessages messages) {
if (!messages.getErrors().isEmpty()) {
throw new BadRequestException(messages);
throw BadRequestException.create(messages.getErrors());
}
}
}

+ 1
- 1
server/sonar-server/src/main/java/org/sonar/server/rule/RuleCreator.java View File

@@ -119,7 +119,7 @@ public class RuleCreator {
}

if (!errors.isEmpty()) {
throw new BadRequestException(errors);
throw BadRequestException.create(errors);
}
}


+ 27
- 27
server/sonar-server/src/main/java/org/sonar/server/user/UserUpdater.java View File

@@ -42,7 +42,6 @@ import org.sonar.db.user.GroupDto;
import org.sonar.db.user.UserDto;
import org.sonar.db.user.UserGroupDto;
import org.sonar.server.exceptions.BadRequestException;
import org.sonar.server.exceptions.Message;
import org.sonar.server.exceptions.ServerException;
import org.sonar.server.organization.DefaultOrganizationProvider;
import org.sonar.server.user.index.UserIndexer;
@@ -51,6 +50,7 @@ import org.sonar.server.util.Validation;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Strings.isNullOrEmpty;
import static com.google.common.collect.Lists.newArrayList;
import static java.lang.String.format;
import static org.sonar.db.user.UserDto.encryptPassword;
import static org.sonar.server.ws.WsUtils.checkFound;

@@ -140,7 +140,7 @@ public class UserUpdater {

private UserDto createNewUserDto(DbSession dbSession, NewUser newUser) {
UserDto userDto = new UserDto();
List<Message> messages = newArrayList();
List<String> messages = newArrayList();

String login = newUser.login();
if (validateLoginFormat(login, messages)) {
@@ -170,25 +170,25 @@ public class UserUpdater {
setExternalIdentity(userDto, newUser.externalIdentity());

if (!messages.isEmpty()) {
throw new BadRequestException(messages);
throw BadRequestException.create(messages);
}
return userDto;
}

private boolean updateUserDto(DbSession dbSession, UpdateUser updateUser, UserDto userDto) {
List<Message> messages = newArrayList();
List<String> messages = newArrayList();
boolean changed = updateName(updateUser, userDto, messages);
changed |= updateEmail(updateUser, userDto, messages);
changed |= updateExternalIdentity(updateUser, userDto);
changed |= updatePassword(updateUser, userDto, messages);
changed |= updateScmAccounts(dbSession, updateUser, userDto, messages);
if (!messages.isEmpty()) {
throw new BadRequestException(messages);
throw BadRequestException.create(messages);
}
return changed;
}

private static boolean updateName(UpdateUser updateUser, UserDto userDto, List<Message> messages) {
private static boolean updateName(UpdateUser updateUser, UserDto userDto, List<String> messages) {
String name = updateUser.name();
if (updateUser.isNameChanged() && validateNameFormat(name, messages) && !Objects.equals(userDto.getName(), name)) {
userDto.setName(name);
@@ -197,7 +197,7 @@ public class UserUpdater {
return false;
}

private static boolean updateEmail(UpdateUser updateUser, UserDto userDto, List<Message> messages) {
private static boolean updateEmail(UpdateUser updateUser, UserDto userDto, List<String> messages) {
String email = updateUser.email();
if (updateUser.isEmailChanged() && validateEmailFormat(email, messages) && !Objects.equals(userDto.getEmail(), email)) {
userDto.setEmail(email);
@@ -217,7 +217,7 @@ public class UserUpdater {
return false;
}

private static boolean updatePassword(UpdateUser updateUser, UserDto userDto, List<Message> messages) {
private static boolean updatePassword(UpdateUser updateUser, UserDto userDto, List<String> messages) {
String password = updateUser.password();
if (!updateUser.isExternalIdentityChanged() && updateUser.isPasswordChanged() && validatePasswords(password, messages) && checkPasswordChangeAllowed(userDto, messages)) {
setEncryptedPassWord(password, userDto);
@@ -226,7 +226,7 @@ public class UserUpdater {
return false;
}

private boolean updateScmAccounts(DbSession dbSession, UpdateUser updateUser, UserDto userDto, List<Message> messages) {
private boolean updateScmAccounts(DbSession dbSession, UpdateUser updateUser, UserDto userDto, List<String> messages) {
String email = updateUser.email();
List<String> scmAccounts = sanitizeScmAccounts(updateUser.scmAccounts());
List<String> existingScmAccounts = userDto.getScmAccountsAsList();
@@ -263,70 +263,70 @@ public class UserUpdater {
}
}

private static boolean checkNotEmptyParam(@Nullable String value, String param, List<Message> messages) {
private static boolean checkNotEmptyParam(@Nullable String value, String param, List<String> messages) {
if (isNullOrEmpty(value)) {
messages.add(Message.of(Validation.CANT_BE_EMPTY_MESSAGE, param));
messages.add(format(Validation.CANT_BE_EMPTY_MESSAGE, param));
return false;
}
return true;
}

private static boolean validateLoginFormat(@Nullable String login, List<Message> messages) {
private static boolean validateLoginFormat(@Nullable String login, List<String> messages) {
boolean isValid = checkNotEmptyParam(login, LOGIN_PARAM, messages);
if (!isNullOrEmpty(login)) {
if (login.length() < LOGIN_MIN_LENGTH) {
messages.add(Message.of(Validation.IS_TOO_SHORT_MESSAGE, LOGIN_PARAM, LOGIN_MIN_LENGTH));
messages.add(format(Validation.IS_TOO_SHORT_MESSAGE, LOGIN_PARAM, LOGIN_MIN_LENGTH));
return false;
} else if (login.length() > LOGIN_MAX_LENGTH) {
messages.add(Message.of(Validation.IS_TOO_LONG_MESSAGE, LOGIN_PARAM, LOGIN_MAX_LENGTH));
messages.add(format(Validation.IS_TOO_LONG_MESSAGE, LOGIN_PARAM, LOGIN_MAX_LENGTH));
return false;
} else if (!login.matches("\\A\\w[\\w\\.\\-_@]+\\z")) {
messages.add(Message.of("Use only letters, numbers, and .-_@ please."));
messages.add("Use only letters, numbers, and .-_@ please.");
return false;
}
}
return isValid;
}

private static boolean validateNameFormat(@Nullable String name, List<Message> messages) {
private static boolean validateNameFormat(@Nullable String name, List<String> messages) {
boolean isValid = checkNotEmptyParam(name, NAME_PARAM, messages);
if (name != null && name.length() > NAME_MAX_LENGTH) {
messages.add(Message.of(Validation.IS_TOO_LONG_MESSAGE, NAME_PARAM, 200));
messages.add(format(Validation.IS_TOO_LONG_MESSAGE, NAME_PARAM, 200));
return false;
}
return isValid;
}

private static boolean validateEmailFormat(@Nullable String email, List<Message> messages) {
private static boolean validateEmailFormat(@Nullable String email, List<String> messages) {
if (email != null && email.length() > EMAIL_MAX_LENGTH) {
messages.add(Message.of(Validation.IS_TOO_LONG_MESSAGE, EMAIL_PARAM, 100));
messages.add(format(Validation.IS_TOO_LONG_MESSAGE, EMAIL_PARAM, 100));
return false;
}
return true;
}

private static boolean checkPasswordChangeAllowed(UserDto userDto, List<Message> messages) {
private static boolean checkPasswordChangeAllowed(UserDto userDto, List<String> messages) {
if (!userDto.isLocal()) {
messages.add(Message.of("Password cannot be changed when external authentication is used"));
messages.add("Password cannot be changed when external authentication is used");
return false;
}
return true;
}

private static boolean validatePasswords(@Nullable String password, List<Message> messages) {
private static boolean validatePasswords(@Nullable String password, List<String> messages) {
if (password == null || password.length() == 0) {
messages.add(Message.of(Validation.CANT_BE_EMPTY_MESSAGE, PASSWORD_PARAM));
messages.add(format(Validation.CANT_BE_EMPTY_MESSAGE, PASSWORD_PARAM));
return false;
}
return true;
}

private boolean validateScmAccounts(DbSession dbSession, List<String> scmAccounts, @Nullable String login, @Nullable String email, @Nullable UserDto existingUser,
List<Message> messages) {
List<String> messages) {
boolean isValid = true;
for (String scmAccount : scmAccounts) {
if (scmAccount.equals(login) || scmAccount.equals(email)) {
messages.add(Message.of("Login and email are automatically considered as SCM accounts"));
messages.add("Login and email are automatically considered as SCM accounts");
isValid = false;
} else {
List<UserDto> matchingUsers = dbClient.userDao().selectByScmAccountOrLoginOrEmail(dbSession, scmAccount);
@@ -338,7 +338,7 @@ public class UserUpdater {
matchingUsersWithoutExistingUser.add(matchingUser.getName() + " (" + matchingUser.getLogin() + ")");
}
if (!matchingUsersWithoutExistingUser.isEmpty()) {
messages.add(Message.of("The scm account '%s' is already used by user(s) : '%s'", scmAccount, Joiner.on(", ").join(matchingUsersWithoutExistingUser)));
messages.add(format("The scm account '%s' is already used by user(s) : '%s'", scmAccount, Joiner.on(", ").join(matchingUsersWithoutExistingUser)));
isValid = false;
}
}
@@ -399,7 +399,7 @@ public class UserUpdater {
Optional<GroupDto> groupDto = dbClient.groupDao().selectByName(dbSession, defOrgUuid, defaultGroupName);
if (!groupDto.isPresent()) {
throw new ServerException(HttpURLConnection.HTTP_INTERNAL_ERROR,
String.format("The default group '%s' for new users does not exist. Please update the general security settings to fix this issue.",
format("The default group '%s' for new users does not exist. Please update the general security settings to fix this issue.",
defaultGroupName));
}
dbClient.userGroupDao().insert(dbSession, new UserGroupDto().setUserId(userDto.getId()).setGroupId(groupDto.get().getId()));

+ 3
- 1
server/sonar-server/src/main/java/org/sonar/server/util/BooleanTypeValidation.java View File

@@ -25,6 +25,8 @@ import org.apache.commons.lang.StringUtils;
import org.sonar.api.PropertyType;
import org.sonar.server.exceptions.BadRequestException;

import static java.lang.String.format;

public class BooleanTypeValidation implements TypeValidation {

@Override
@@ -35,7 +37,7 @@ public class BooleanTypeValidation implements TypeValidation {
@Override
public void validate(String value, @Nullable List<String> options) {
if (!StringUtils.equalsIgnoreCase(value, "true") && !StringUtils.equalsIgnoreCase(value, "false")) {
throw new BadRequestException("Value '%s' must be one of \"true\" or \"false\".", value);
throw new BadRequestException(format("Value '%s' must be one of \"true\" or \"false\".", value));
}
}


+ 3
- 1
server/sonar-server/src/main/java/org/sonar/server/util/FloatTypeValidation.java View File

@@ -24,6 +24,8 @@ import javax.annotation.Nullable;
import org.sonar.api.PropertyType;
import org.sonar.server.exceptions.BadRequestException;

import static java.lang.String.format;

public class FloatTypeValidation implements TypeValidation {

@Override
@@ -36,7 +38,7 @@ public class FloatTypeValidation implements TypeValidation {
try {
Double.parseDouble(value);
} catch (NumberFormatException e) {
throw new BadRequestException("Value '%s' must be an floating point number.", value);
throw new BadRequestException(format("Value '%s' must be an floating point number.", value));
}
}


+ 3
- 1
server/sonar-server/src/main/java/org/sonar/server/util/IntegerTypeValidation.java View File

@@ -24,6 +24,8 @@ import javax.annotation.Nullable;
import org.sonar.api.PropertyType;
import org.sonar.server.exceptions.BadRequestException;

import static java.lang.String.format;

public class IntegerTypeValidation implements TypeValidation {

@Override
@@ -36,7 +38,7 @@ public class IntegerTypeValidation implements TypeValidation {
try {
Integer.parseInt(value);
} catch (NumberFormatException e) {
throw new BadRequestException("Value '%s' must be an integer.", value);
throw new BadRequestException(format("Value '%s' must be an integer.", value));
}
}


+ 3
- 1
server/sonar-server/src/main/java/org/sonar/server/util/LongTypeValidation.java View File

@@ -24,6 +24,8 @@ import javax.annotation.Nullable;
import org.sonar.api.PropertyType;
import org.sonar.server.exceptions.BadRequestException;

import static java.lang.String.format;

public class LongTypeValidation implements TypeValidation {
@Override
public String key() {
@@ -35,7 +37,7 @@ public class LongTypeValidation implements TypeValidation {
try {
Long.parseLong(value);
} catch (NumberFormatException e) {
throw new BadRequestException("Value '%s' must be a long.", value);
throw new BadRequestException(format("Value '%s' must be a long.", value));
}
}
}

+ 3
- 1
server/sonar-server/src/main/java/org/sonar/server/util/MetricLevelTypeValidation.java View File

@@ -25,6 +25,8 @@ import org.sonar.api.PropertyType;
import org.sonar.api.measures.Metric;
import org.sonar.server.exceptions.BadRequestException;

import static java.lang.String.format;

public class MetricLevelTypeValidation implements TypeValidation {
@Override
public String key() {
@@ -36,7 +38,7 @@ public class MetricLevelTypeValidation implements TypeValidation {
try {
Metric.Level.valueOf(value);
} catch (IllegalArgumentException e) {
throw new BadRequestException("Value '%s' must be one of \"OK\", \"WARN\", \"ERROR\".", value);
throw new BadRequestException(format("Value '%s' must be one of \"OK\", \"WARN\", \"ERROR\".", value));
}
}
}

+ 3
- 1
server/sonar-server/src/main/java/org/sonar/server/util/StringListTypeValidation.java View File

@@ -25,6 +25,8 @@ import org.apache.commons.lang.StringUtils;
import org.sonar.api.PropertyType;
import org.sonar.server.exceptions.BadRequestException;

import static java.lang.String.format;

public class StringListTypeValidation implements TypeValidation {

@Override
@@ -36,7 +38,7 @@ public class StringListTypeValidation implements TypeValidation {
public void validate(String value, @Nullable List<String> options) {
if (options != null && !options.contains(value)) {
String optionsAsString = StringUtils.join(options, ", ");
throw new BadRequestException("Value '%s' must be one of : %s.", value, optionsAsString);
throw new BadRequestException(format("Value '%s' must be one of : %s.", value, optionsAsString));
}
}


+ 4
- 2
server/sonar-server/src/main/java/org/sonar/server/util/Validation.java View File

@@ -22,6 +22,8 @@ package org.sonar.server.util;
import com.google.common.base.Strings;
import org.sonar.server.exceptions.BadRequestException;

import static java.lang.String.format;

public class Validation {

public static final String CANT_BE_EMPTY_MESSAGE = "%s can't be empty";
@@ -35,14 +37,14 @@ public class Validation {

public static void checkMandatoryParameter(String value, String paramName) {
if (Strings.isNullOrEmpty(value)) {
throw new BadRequestException(Validation.CANT_BE_EMPTY_MESSAGE, paramName);
throw new BadRequestException(format(Validation.CANT_BE_EMPTY_MESSAGE, paramName));
}
}

public static void checkMandatorySizeParameter(String value, String paramName, Integer size) {
checkMandatoryParameter(value, paramName);
if (!Strings.isNullOrEmpty(value) && value.length() > size) {
throw new BadRequestException(Validation.IS_TOO_LONG_MESSAGE, paramName, size);
throw new BadRequestException(format(Validation.IS_TOO_LONG_MESSAGE, paramName, size));
}
}


+ 52
- 0
server/sonar-server/src/test/java/org/sonar/server/exceptions/BadRequestExceptionTest.java View File

@@ -19,16 +19,68 @@
*/
package org.sonar.server.exceptions;

import java.util.Collections;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;

import static java.util.Arrays.asList;
import static org.assertj.core.api.Assertions.assertThat;

public class BadRequestExceptionTest {

@Rule
public ExpectedException expectedException = ExpectedException.none();

@Test
public void text_error() {
BadRequestException exception = new BadRequestException("error");
assertThat(exception.getMessage()).isEqualTo("error");
}

@Test
public void create_exception_from_list() throws Exception {
BadRequestException underTest = BadRequestException.create(asList("error1", "error2"));

assertThat(underTest.errors().messages().stream().map(Message::getMessage)).containsOnly("error1", "error2");
}

@Test
public void create_exception_from_errors() throws Exception {
Errors errors = new Errors().add(Message.of("error1"), Message.of("error2"));
BadRequestException underTest = BadRequestException.create(errors);

assertThat(underTest.errors().messages().stream().map(Message::getMessage)).containsOnly("error1", "error2");
}

@Test
public void getMessage_return_first_error() throws Exception {
BadRequestException underTest = BadRequestException.create(asList("error1", "error2"));

assertThat(underTest.getMessage()).isEqualTo("error1");
}

@Test
public void fail_when_creating_exception_with_empty_list() throws Exception {
expectedException.expect(IllegalArgumentException.class);
expectedException.expectMessage("At least one error message is required");

BadRequestException.create(Collections.emptyList());
}

@Test
public void fail_when_creating_exception_with_one_empty_element() throws Exception {
expectedException.expect(IllegalArgumentException.class);
expectedException.expectMessage("Message cannot be empty");

BadRequestException.create(asList("error", ""));
}

@Test
public void fail_when_creating_exception_with_one_null_element() throws Exception {
expectedException.expect(IllegalArgumentException.class);
expectedException.expectMessage("Message cannot be empty");

BadRequestException.create(asList("error", null));
}
}

+ 19
- 0
server/sonar-server/src/test/java/org/sonar/server/exceptions/MessageTest.java View File

@@ -19,12 +19,17 @@
*/
package org.sonar.server.exceptions;

import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;

import static org.assertj.core.api.Assertions.assertThat;

public class MessageTest {

@Rule
public ExpectedException expectedException = ExpectedException.none();

@Test
public void create_message() {
Message message = Message.of("key1 %s", "param1");
@@ -37,6 +42,20 @@ public class MessageTest {
assertThat(message.getMessage()).isEqualTo("key1");
}

@Test
public void fail_when_message_is_null() throws Exception {
expectedException.expect(IllegalArgumentException.class);

Message.of(null);
}

@Test
public void fail_when_message_is_empty() throws Exception {
expectedException.expect(IllegalArgumentException.class);

Message.of("");
}

@Test
public void test_equals_and_hashcode() throws Exception {
Message message1 = Message.of("key1%s", "param1");

+ 1
- 1
server/sonar-server/src/test/java/org/sonar/server/exceptions/ServerExceptionTest.java View File

@@ -27,7 +27,7 @@ public class ServerExceptionTest {

@Test
public void should_create_exception_with_status() {
ServerException exception = new ServerException(400);
ServerException exception = new ServerException(400, "error!");
assertThat(exception.httpCode()).isEqualTo(400);
}


+ 0
- 44
server/sonar-server/src/test/java/org/sonar/server/exceptions/VerificationsTest.java View File

@@ -1,44 +0,0 @@
/*
* 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.exceptions;

import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;

public class VerificationsTest {

@Rule
public ExpectedException expectedException = ExpectedException.none();

@Test
public void check() {
// no exception
Verifications.check(true, "Error on %s and %s", "foo", "bar");
}

@Test
public void fail() throws Exception {
expectedException.expect(BadRequestException.class);
expectedException.expectMessage("Error on foo and bar");

Verifications.check(false, "Error on %s and %s", "foo", "bar");
}
}

+ 1
- 1
server/sonar-server/src/test/java/org/sonar/server/util/TypeValidationsTest.java View File

@@ -65,7 +65,7 @@ public class TypeValidationsTest {
} catch (Exception e) {
assertThat(e).isInstanceOf(BadRequestException.class);
BadRequestException badRequestException = (BadRequestException) e;
assertThat(badRequestException.firstError().getMessage()).isEqualTo("Type 'Unknown' is not valid.");
assertThat(badRequestException.getMessage()).isEqualTo("Type 'Unknown' is not valid.");
}
}


+ 6
- 4
server/sonar-server/src/test/java/org/sonar/server/ws/WebServiceEngineTest.java View File

@@ -39,6 +39,7 @@ import org.sonar.server.exceptions.Errors;
import org.sonar.server.exceptions.Message;
import org.sonarqube.ws.MediaTypes;

import static java.util.Collections.singletonList;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.doThrow;
@@ -291,7 +292,7 @@ public class WebServiceEngineTest {
DumbResponse response = new DumbResponse();

expectedException.expect(IllegalArgumentException.class);
expectedException.expectMessage("Error!");
expectedException.expectMessage("error writing json");
underTest.execute(request, response);
}

@@ -355,14 +356,15 @@ public class WebServiceEngineTest {
for (int count = 0; count < Integer.valueOf(request.param("count")); count++) {
errors.add(Message.of("Bad request reason #" + count));
}
throw new BadRequestException(errors);
throw BadRequestException.create(errors);
});
createNewDefaultAction(newController, "fail_to_write_errors")
.setHandler((request, response) -> {
Errors errors = mock(Errors.class);
when(errors.messages()).thenReturn(singletonList(Message.of("invalid argument")));
// Try to simulate an error when generating JSON errors
doThrow(new IllegalArgumentException("Error!")).when(errors).writeJson(any(JsonWriter.class));
throw new BadRequestException(errors);
doThrow(new IllegalArgumentException("error writing json")).when(errors).writeJson(any(JsonWriter.class));
throw BadRequestException.create(errors);
});
createNewDefaultAction(newController, "alive")
.setHandler((request, response) -> response.noContent());

Loading…
Cancel
Save