]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-8748 BadRequestException fail when empty list or empty element
authorJulien Lancelot <julien.lancelot@sonarsource.com>
Fri, 10 Feb 2017 08:09:05 +0000 (09:09 +0100)
committerJulien Lancelot <julien.lancelot@sonarsource.com>
Fri, 10 Feb 2017 11:56:19 +0000 (12:56 +0100)
26 files changed:
server/sonar-server/src/main/java/org/sonar/server/email/ws/SendAction.java
server/sonar-server/src/main/java/org/sonar/server/exceptions/BadRequestException.java
server/sonar-server/src/main/java/org/sonar/server/exceptions/Message.java
server/sonar-server/src/main/java/org/sonar/server/exceptions/ServerException.java
server/sonar-server/src/main/java/org/sonar/server/exceptions/Verifications.java [deleted file]
server/sonar-server/src/main/java/org/sonar/server/qualitygate/QualityGateConditionsUpdater.java
server/sonar-server/src/main/java/org/sonar/server/qualitygate/QualityGateUpdater.java
server/sonar-server/src/main/java/org/sonar/server/qualitygate/QualityGates.java
server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileExporters.java
server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileFactory.java
server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileReset.java
server/sonar-server/src/main/java/org/sonar/server/rule/RuleCreator.java
server/sonar-server/src/main/java/org/sonar/server/user/UserUpdater.java
server/sonar-server/src/main/java/org/sonar/server/util/BooleanTypeValidation.java
server/sonar-server/src/main/java/org/sonar/server/util/FloatTypeValidation.java
server/sonar-server/src/main/java/org/sonar/server/util/IntegerTypeValidation.java
server/sonar-server/src/main/java/org/sonar/server/util/LongTypeValidation.java
server/sonar-server/src/main/java/org/sonar/server/util/MetricLevelTypeValidation.java
server/sonar-server/src/main/java/org/sonar/server/util/StringListTypeValidation.java
server/sonar-server/src/main/java/org/sonar/server/util/Validation.java
server/sonar-server/src/test/java/org/sonar/server/exceptions/BadRequestExceptionTest.java
server/sonar-server/src/test/java/org/sonar/server/exceptions/MessageTest.java
server/sonar-server/src/test/java/org/sonar/server/exceptions/ServerExceptionTest.java
server/sonar-server/src/test/java/org/sonar/server/exceptions/VerificationsTest.java [deleted file]
server/sonar-server/src/test/java/org/sonar/server/util/TypeValidationsTest.java
server/sonar-server/src/test/java/org/sonar/server/ws/WebServiceEngineTest.java

index 6846ba11737622069b8aaa962dc217d3d83d66ea..976321610ad8c8a7eec14b29d14db6187001214c 100644 (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);
   }
 
 }
index 3013d38438ea9116ea75d102a88770737749dfca..e280f6ba200b9e000d4e11ee26098372d2f9e7ab 100644 (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();
   }
+
 }
index b75cb64bd59fb35a97c1da7f58abd6c4c0badf0d..59589746799714b3c6c49acfe718c3d1552e04dd 100644 (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);
   }
 
index 5a568a9cfeb167d82912fa63b9f6913c8befa2da..0ea1bbee4ec7aaf84f2da3ded24f73a738335c22 100644 (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;
   }
 
diff --git a/server/sonar-server/src/main/java/org/sonar/server/exceptions/Verifications.java b/server/sonar-server/src/main/java/org/sonar/server/exceptions/Verifications.java
deleted file mode 100644 (file)
index 8ca1788..0000000
+++ /dev/null
@@ -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);
-    }
-  }
-}
index 62677ca2e1e50866aaba31de25a80911103e7fc3..2f86d056ce7a4d444c02400fa730b56030ce9707 100644 (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);
     }
   }
 
index 5eac4df76c9dcdc4cfbb454afac86fd50c3989ec..a6a7fd195916b62714003f586b8f2ba18051f56e 100644 (file)
@@ -54,7 +54,7 @@ public class QualityGateUpdater {
       checkQualityGateDoesNotAlreadyExist(qGateId, name, errors);
     }
     if (!errors.isEmpty()) {
-      throw new BadRequestException(errors);
+      throw BadRequestException.create(errors);
     }
   }
 
index 2439d41781c1923453d9986ff606966d4564cd28..2840be3f2902fb70b0912023937754449478f544 100644 (file)
@@ -233,7 +233,7 @@ public class QualityGates {
       checkQgateNotAlreadyExists(updatingQgateId, name, errors);
     }
     if (!errors.isEmpty()) {
-      throw new BadRequestException(errors);
+      throw BadRequestException.create(errors);
     }
   }
 
index 31b307d0c787228151a82829871c4fba2c125f8f..9f895999211d2380368d2d5838a2a33ebd044deb 100644 (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());
index a47a4a715c1d5fca8f720c772057ec1303677208..72090103e4b621894293f24830b3ad50bd23790c 100644 (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);
index d6c9fbdccc843f090206892f44b416dabeb821de..ff957a2d24aa2a3334778dd04d33555835493cd2 100644 (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());
     }
   }
 }
index d164307ceead2e17d138ebd83679d2d498c4f3e3..3489c4205d65b593d7fb617c0850300e64e5d405 100644 (file)
@@ -119,7 +119,7 @@ public class RuleCreator {
     }
 
     if (!errors.isEmpty()) {
-      throw new BadRequestException(errors);
+      throw BadRequestException.create(errors);
     }
   }
 
index 2d479ffd31a0916a982fb458dd8c6c49f76e97a8..8b66f04a428a5c3fa617ced47773c6b0a7e46b29 100644 (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()));
index de890541158aaab28901002e5536d260add477e9..29b278c8feec372bde86207cbfb492de58c75288 100644 (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));
     }
   }
 
index b7b65f53b921210ff1fa0a359410574aa1a97220..6c60cc47b0d740384696c5a21b91c3dce1fa213a 100644 (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));
     }
   }
 
index 58fe53ea9603d9255138808bca2ccf56a5795b5e..ebedef9aa8cbcbc8efd563416d994424f488736b 100644 (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));
     }
   }
 
index 156bdff00ab4a8e49248315b79d371265b9ea69a..e9e85fd58ebcec0da23b295af8d11de319397663 100644 (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));
     }
   }
 }
index 4b0617fd793ab229170bd56f0f0b4b56c6f5f5d0..aa63898c21575cacf46883b1866c2b3c4efc7d72 100644 (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));
     }
   }
 }
index b8132d3287a0faa022cfb21dd71e0385b65cd791..37ee95ae39236ea32f3e95b871c92123865e1800 100644 (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));
     }
   }
 
index 3fd131febb0a7f78c809748fac0ed19385e08e78..2bad85689b6e081b144c045bbd6b85c8e5035d21 100644 (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));
     }
   }
 
index 343d0725eef0583505fd63a8c4e0ea7de17d1c8d..e1666dfe906b8db3380eb3e61401a6d4489a086d 100644 (file)
  */
 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));
+  }
 }
index 7626de314eb7587da5e6ef05238d635e3ede7719..bfd9961d3a8f3d46f7c176d0615aa0bc2eaeefa9 100644 (file)
  */
 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");
index 5be018c2150d4bdd4905d26c1d3b02c15242856a..be72096ddd2413263c654a5d994d98b09dd62224 100644 (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);
   }
 
diff --git a/server/sonar-server/src/test/java/org/sonar/server/exceptions/VerificationsTest.java b/server/sonar-server/src/test/java/org/sonar/server/exceptions/VerificationsTest.java
deleted file mode 100644 (file)
index 00cbe8e..0000000
+++ /dev/null
@@ -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");
-  }
-}
index 2ed86b6964e9ce29c667ded389cb1a2c767bad03..2efbf720f6996a8521fe2d7a5d3057be0656840e 100644 (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.");
     }
   }
 
index f43bc1bd196a91b9f5781cd277ee0a52427b4401..280e53bdccddc1eaa346439f312ac76d68303cf3 100644 (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());