Browse Source

SONAR-5007 improve l10n of server exception handling

tags/4.4-RC1
Simon Brandhof 10 years ago
parent
commit
69fffe5069
44 changed files with 373 additions and 646 deletions
  1. 1
    1
      sonar-server/src/main/java/org/sonar/server/component/DefaultRubyComponentService.java
  2. 2
    1
      sonar-server/src/main/java/org/sonar/server/debt/DebtModelOperations.java
  3. 30
    114
      sonar-server/src/main/java/org/sonar/server/exceptions/BadRequestException.java
  4. 100
    0
      sonar-server/src/main/java/org/sonar/server/exceptions/Errors.java
  5. 14
    70
      sonar-server/src/main/java/org/sonar/server/exceptions/Message.java
  6. 0
    66
      sonar-server/src/main/java/org/sonar/server/exceptions/Messages.java
  7. 0
    33
      sonar-server/src/main/java/org/sonar/server/exceptions/ServerException.java
  8. 33
    0
      sonar-server/src/main/java/org/sonar/server/exceptions/Verifications.java
  9. 1
    1
      sonar-server/src/main/java/org/sonar/server/issue/InternalRubyIssueService.java
  10. 4
    4
      sonar-server/src/main/java/org/sonar/server/issue/IssueBulkChangeQuery.java
  11. 35
    47
      sonar-server/src/main/java/org/sonar/server/qualitygate/QualityGates.java
  12. 4
    10
      sonar-server/src/main/java/org/sonar/server/qualityprofile/BulkChangeResult.java
  13. 3
    2
      sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileOperations.java
  14. 6
    10
      sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileRepositoryExporter.java
  15. 2
    10
      sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileReset.java
  16. 1
    1
      sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfiles.java
  17. 6
    2
      sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/BulkRuleActivationActions.java
  18. 1
    27
      sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/QProfileRestoreBuiltInAction.java
  19. 1
    1
      sonar-server/src/main/java/org/sonar/server/rule/RuleOperations.java
  20. 1
    1
      sonar-server/src/main/java/org/sonar/server/util/BooleanTypeValidation.java
  21. 3
    2
      sonar-server/src/main/java/org/sonar/server/util/FloatTypeValidation.java
  22. 1
    1
      sonar-server/src/main/java/org/sonar/server/util/IntegerTypeValidation.java
  23. 1
    1
      sonar-server/src/main/java/org/sonar/server/util/StringListTypeValidation.java
  24. 2
    1
      sonar-server/src/main/java/org/sonar/server/util/TypeValidation.java
  25. 2
    1
      sonar-server/src/main/java/org/sonar/server/util/TypeValidations.java
  26. 2
    8
      sonar-server/src/main/java/org/sonar/server/util/Validation.java
  27. 11
    42
      sonar-server/src/main/java/org/sonar/server/ws/WebServiceEngine.java
  28. 6
    7
      sonar-server/src/test/java/org/sonar/server/debt/DebtModelOperationsTest.java
  29. 1
    78
      sonar-server/src/test/java/org/sonar/server/exceptions/BadRequestExceptionTest.java
  30. 2
    18
      sonar-server/src/test/java/org/sonar/server/exceptions/ServerExceptionTest.java
  31. 42
    0
      sonar-server/src/test/java/org/sonar/server/exceptions/VerificationsTest.java
  32. 4
    2
      sonar-server/src/test/java/org/sonar/server/issue/InternalRubyIssueServiceTest.java
  33. 2
    2
      sonar-server/src/test/java/org/sonar/server/issue/IssueBulkChangeQueryTest.java
  34. 1
    1
      sonar-server/src/test/java/org/sonar/server/qualitygate/ws/QGatesWsTest.java
  35. 6
    4
      sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileRepositoryExporterTest.java
  36. 3
    1
      sonar-server/src/test/java/org/sonar/server/qualityprofile/RuleActivatorMediumTest.java
  37. 5
    26
      sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/QProfileRestoreBuiltInActionTest.java
  38. 3
    1
      sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/QProfilesWsTest.java
  39. 1
    1
      sonar-server/src/test/java/org/sonar/server/util/BooleanTypeValidationTest.java
  40. 1
    1
      sonar-server/src/test/java/org/sonar/server/util/FloatTypeValidationTest.java
  41. 1
    1
      sonar-server/src/test/java/org/sonar/server/util/IntegerTypeValidationTest.java
  42. 2
    2
      sonar-server/src/test/java/org/sonar/server/util/StringListTypeValidationTest.java
  43. 1
    1
      sonar-server/src/test/java/org/sonar/server/util/TypeValidationsTest.java
  44. 25
    43
      sonar-server/src/test/java/org/sonar/server/ws/WebServiceEngineTest.java

+ 1
- 1
sonar-server/src/main/java/org/sonar/server/component/DefaultRubyComponentService.java View File

@@ -75,7 +75,7 @@ public class DefaultRubyComponentService implements RubyComponentService {
.setCreatedAt(new Date()));
component = (ComponentDto) resourceDao.findByKey(kee);
if (component == null) {
throw new BadRequestException(String.format("%s not created: %s", null, kee));
throw new BadRequestException(String.format("Component not created: %s", kee));
}
resourceIndexerDao.indexResource(component.getId());
return component.getId();

+ 2
- 1
sonar-server/src/main/java/org/sonar/server/debt/DebtModelOperations.java View File

@@ -41,6 +41,7 @@ import org.sonar.server.util.Validation;

import javax.annotation.CheckForNull;
import javax.annotation.Nullable;

import java.util.Date;
import java.util.List;

@@ -253,7 +254,7 @@ public class DebtModelOperations implements ServerComponent {

private void checkNotAlreadyExists(String name, SqlSession session) {
if (dbClient.debtCharacteristicDao().selectByName(name, session) != null) {
throw BadRequestException.ofL10n(Validation.IS_ALREADY_USED_MESSAGE, name);
throw new BadRequestException(Validation.IS_ALREADY_USED_MESSAGE, name);
}
}


+ 30
- 114
sonar-server/src/main/java/org/sonar/server/exceptions/BadRequestException.java View File

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

import org.apache.commons.lang.builder.ReflectionToStringBuilder;
import com.google.common.base.Objects;
import org.sonar.api.utils.ValidationMessages;

import javax.annotation.CheckForNull;
import javax.annotation.Nullable;

import java.util.Arrays;
import java.util.List;

import static com.google.common.collect.Lists.newArrayList;

/**
* Request is not valid and can not be processed.
*/
@@ -36,127 +31,48 @@ public class BadRequestException extends ServerException {

private static final int BAD_REQUEST = 400;

private final List<Message> errors;

public BadRequestException(String message) {
super(BAD_REQUEST, message);
this.errors = newArrayList();
}

public BadRequestException(String message, List<Message> errors) {
super(BAD_REQUEST, message);
this.errors = errors;
}
private final Errors errors;

public BadRequestException(@Nullable String message, @Nullable String l10nKey, @Nullable Object[] l10nParams) {
super(BAD_REQUEST, message, l10nKey, l10nParams);
this.errors = newArrayList();
public BadRequestException(String l10nKey, Object... l10nParams) {
super(BAD_REQUEST);
this.errors = new Errors().add(Message.of(l10nKey, l10nParams));
}

public BadRequestException(@Nullable String message, @Nullable String l10nKey, @Nullable Object[] l10nParams, List<Message> errors) {
super(BAD_REQUEST, message, l10nKey, l10nParams);
this.errors = errors;
public BadRequestException(List<Message> messages) {
super(BAD_REQUEST);
this.errors = new Errors().add(messages);
}

public static BadRequestException of(String message) {
return new BadRequestException(message);
public BadRequestException(Errors e) {
super(BAD_REQUEST);
this.errors = e;
}

public static BadRequestException of(String message, List<Message> errors) {
return new BadRequestException(message, errors);
public BadRequestException(ValidationMessages validationMessages) {
super(BAD_REQUEST);
this.errors = new Errors();
for (String s : validationMessages.getErrors()) {
errors.add(Message.of(s));
}
}

public static BadRequestException of(List<Message> errors) {
return new BadRequestException(null, null, null, errors);
public Errors errors() {
return errors;
}

public static BadRequestException ofL10n(String l10nKey, Object... l10nParams) {
return new BadRequestException(null, l10nKey, l10nParams);
public Message firstError() {
return errors.messages().get(0);
}

public static BadRequestException ofL10n(List<Message> errors, String l10nKey, Object... l10nParams) {
return new BadRequestException(null, l10nKey, l10nParams, errors);
@Override
public String getMessage() {
return firstError().getKey();
}

/**
* List of error messages. Empty if there are no errors.
*/
public List<Message> errors() {
return errors;
@Override
public String toString() {
return Objects.toStringHelper(this)
.add("errors", errors)
.toString();
}

public static class Message {
private final String l10nKey;
private final Object[] l10nParams;
private final String text;

private Message(@Nullable String l10nKey, @Nullable Object[] l10nParams, @Nullable String text) {
this.l10nKey = l10nKey;
this.l10nParams = l10nParams;
this.text = text;
}

public static Message of(String text) {
return new Message(null, null, text);
}

public static Message ofL10n(String l10nKey, Object... l10nParams) {
return new Message(l10nKey, l10nParams, null);
}

@CheckForNull
public String text() {
return text;
}

@CheckForNull
public String l10nKey() {
return l10nKey;
}

public Object[] l10nParams() {
if (l10nParams == null) {
return new Object[0];
} else {
return Arrays.copyOf(l10nParams, l10nParams.length);
}
}

@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Message message = (Message) o;

if (l10nKey != null ? !l10nKey.equals(message.l10nKey) : message.l10nKey != null) {
return false;
}
// Probably incorrect - comparing Object[] arrays with Arrays.equals
if (!Arrays.equals(l10nParams, message.l10nParams)) {
return false;
}
if (text != null ? !text.equals(message.text) : message.text != null) {
return false;
}
return true;
}

@Override
public int hashCode() {
int result = l10nKey != null ? l10nKey.hashCode() : 0;
result = 31 * result + (l10nParams != null ? Arrays.hashCode(l10nParams) : 0);
result = 31 * result + (text != null ? text.hashCode() : 0);
return result;
}

@Override
public String toString() {
return new ReflectionToStringBuilder(this).toString();
}
}

}

+ 100
- 0
sonar-server/src/main/java/org/sonar/server/exceptions/Errors.java View File

@@ -0,0 +1,100 @@
/*
* SonarQube, open source software quality management tool.
* Copyright (C) 2008-2014 SonarSource
* mailto:contact AT sonarsource DOT com
*
* SonarQube 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.
*
* SonarQube 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 com.google.common.base.Objects;
import com.google.common.collect.Lists;
import org.apache.commons.lang.StringUtils;
import org.sonar.api.i18n.I18n;
import org.sonar.api.utils.text.JsonWriter;

import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Locale;

public class Errors {

private final List<Message> messages = Lists.newArrayList();

public Errors() {
}

public Errors add(Errors errors) {
this.messages.addAll(errors.messages());
return this;
}

public Errors add(Collection<Message> messages) {
for (Message message : messages) {
add(message);
}
return this;
}

public Errors add(Message message, Message... others) {
messages.add(message);
Collections.addAll(messages, others);
return this;
}

public List<Message> messages() {
return messages;
}

public boolean isEmpty() {
return messages.isEmpty();
}

public boolean check(boolean expression, String l10nKey, Object... l10nParams) {
if (!expression) {
add(Message.of(l10nKey, l10nParams));
}
return expression;
}

public void writeJson(JsonWriter json, I18n i18n, Locale locale) {
writeJson(json, i18n, locale, "errors");
}

public void writeJsonAsWarnings(JsonWriter json, I18n i18n, Locale locale) {
writeJson(json, i18n, locale, "warnings");
}

private void writeJson(JsonWriter json, I18n i18n, Locale locale, String name) {
if (!messages.isEmpty()) {
json.name(name).beginArray();
for (Message message : messages) {
json.beginObject();
String text = StringUtils.defaultString(i18n.message(locale, message.getKey(), message.getKey(), message.getParams()), message.getKey());
json.prop("msg", text);
json.endObject();
}
json.endArray();
}
}

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

+ 14
- 70
sonar-server/src/main/java/org/sonar/server/exceptions/Message.java View File

@@ -20,92 +20,36 @@
package org.sonar.server.exceptions;

import com.google.common.base.Objects;

import javax.annotation.CheckForNull;
import javax.annotation.Nullable;

import java.util.Map;
import com.google.common.base.Preconditions;
import org.apache.commons.lang.StringUtils;

public class Message {

public static enum Level {
INFO, WARNING, ERROR
}

private final String code;
private String label;
private Object[] l10nParams = new Object[0];
private Level level;
private Map<String, Object> params;

private Message(String code) {
this.code = code;
}

public String getCode() {
return code;
}
@CheckForNull
public String getLabel() {
return label;
}

public Message setLabel(String s) {
this.label = s;
return this;
}

public Object[] getL10nParams() {
return l10nParams;
}
private final String key;
private final Object[] params;

public Message setL10nParams(Object[] l10nParams) {
this.l10nParams = l10nParams;
return this;
}

public Level getLevel() {
return level;
}

public Message setLevel(Level level) {
this.level = level;
return this;
}

public Map<String, Object> getParams() {
return params;
}

public Message setParams(Map<String, Object> params) {
private Message(String key, Object[] params) {
this.key = key;
this.params = params;
return this;
}

public Message setParam(String key, @Nullable Object value) {
this.params.put(key, value);
return this;
public String getKey() {
return key;
}

public static Message newError(String code) {
return new Message(code).setLevel(Level.ERROR);
}

public static Message newWarning(String code) {
return new Message(code).setLevel(Level.WARNING);
public Object[] getParams() {
return params;
}

public static Message newInfo(String code) {
return new Message(code).setLevel(Level.INFO);
public static Message of(String l10nKey, Object... l10nParams) {
Preconditions.checkArgument(StringUtils.isNotBlank(l10nKey));
return new Message(l10nKey, l10nParams);
}

@Override
public String toString() {
return Objects.toStringHelper(this)
.add("code", code)
.add("label", label)
.add("l10nParams", l10nParams)
.add("level", level)
.add("key", key)
.add("params", params)
.toString();
}

+ 0
- 66
sonar-server/src/main/java/org/sonar/server/exceptions/Messages.java View File

@@ -1,66 +0,0 @@
/*
* SonarQube, open source software quality management tool.
* Copyright (C) 2008-2014 SonarSource
* mailto:contact AT sonarsource DOT com
*
* SonarQube 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.
*
* SonarQube 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 com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ListMultimap;
import org.sonar.api.utils.text.JsonWriter;

import java.util.Collection;
import java.util.List;

public class Messages {

private ListMultimap<Message.Level, Message> messagesByLevel = ArrayListMultimap.create();

public Messages add(Message message) {
messagesByLevel.put(message.getLevel(), message);
return this;
}

public Collection<Message> all() {
return messagesByLevel.values();
}

public List<Message> getByLevel(Message.Level level) {
return messagesByLevel.get(level);
}

public boolean hasLevel(Message.Level level) {
return messagesByLevel.containsKey(level);
}

public void writeJson(JsonWriter json) {
writeJson(json, "errors", Message.Level.ERROR);
writeJson(json, "warnings", Message.Level.WARNING);
writeJson(json, "infos", Message.Level.INFO);
}

private void writeJson(JsonWriter json, String label, Message.Level level) {
List<Message> messages = messagesByLevel.get(level);
if (!messages.isEmpty()) {
json.name(label).beginArray();
for (Message message : messages) {
json.beginObject().prop("msg", message.getLabel()).endObject();
}
json.endArray();
}
}
}

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

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

import javax.annotation.CheckForNull;
import javax.annotation.Nullable;

import java.util.Arrays;

public class ServerException extends RuntimeException {
private final int httpCode;

private final String l10nKey;
private final Object[] l10nParams;

public ServerException(int httpCode) {
this.httpCode = httpCode;
this.l10nKey = null;
this.l10nParams = null;
}

public ServerException(int httpCode, String message) {
super(message);
this.httpCode = httpCode;
this.l10nKey = null;
this.l10nParams = null;
}

public ServerException(int httpCode, @Nullable String message, @Nullable String l10nKey, @Nullable Object[] l10nParams) {
super(message);
this.httpCode = httpCode;
this.l10nKey = l10nKey;
this.l10nParams = l10nParams;
}

public int httpCode() {
return httpCode;
}

@CheckForNull
public String l10nKey() {
return l10nKey;
}

@CheckForNull
public Object[] l10nParams() {
if (l10nParams == null) {
return new Object[0];
} else {
return Arrays.copyOf(l10nParams, l10nParams.length);
}
}
}

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

@@ -0,0 +1,33 @@
/*
* SonarQube, open source software quality management tool.
* Copyright (C) 2008-2014 SonarSource
* mailto:contact AT sonarsource DOT com
*
* SonarQube 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.
*
* SonarQube 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 l10nKey, Object... l10nParams) {
if (!expression) {
throw new BadRequestException(l10nKey, l10nParams);
}
}
}

+ 1
- 1
sonar-server/src/main/java/org/sonar/server/issue/InternalRubyIssueService.java View File

@@ -615,7 +615,7 @@ public class InternalRubyIssueService implements ServerComponent {

private void checkOptionalSizeParameter(String value, String paramName, Integer size) {
if (!Strings.isNullOrEmpty(value) && value.length() > size) {
throw BadRequestException.ofL10n(Validation.IS_TOO_LONG_MESSAGE, paramName, size);
throw new BadRequestException(Validation.IS_TOO_LONG_MESSAGE, paramName, size);
}
}


+ 4
- 4
sonar-server/src/main/java/org/sonar/server/issue/IssueBulkChangeQuery.java View File

@@ -62,14 +62,14 @@ public class IssueBulkChangeQuery {
parse(props, null);
}

private void parse(Map<String, Object> props, String comment) {
private void parse(Map<String, Object> props, @Nullable String comment) {
this.issues = sanitizeList(RubyUtils.toStrings(props.get("issues")));
if (issues == null || issues.isEmpty()) {
throw BadRequestException.ofL10n("issue_bulk_change.error.empty_issues");
throw new BadRequestException("issue_bulk_change.error.empty_issues");
}
actions = sanitizeList(RubyUtils.toStrings(props.get("actions")));
if (actions == null || actions.isEmpty()) {
throw BadRequestException.ofL10n("issue_bulk_change.error.need_one_action");
throw new BadRequestException("issue_bulk_change.error.need_one_action");
}
for (String action : actions) {
Map<String, Object> actionProperties = getActionProps(action, props);
@@ -83,7 +83,7 @@ public class IssueBulkChangeQuery {
}
}

private List<String> sanitizeList(List<String> list) {
private List<String> sanitizeList(@Nullable List<String> list) {
if (list == null || list.isEmpty()) {
return Collections.emptyList();
}

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

@@ -40,7 +40,8 @@ import org.sonar.core.qualitygate.db.QualityGateDao;
import org.sonar.core.qualitygate.db.QualityGateDto;
import org.sonar.server.component.persistence.ComponentDao;
import org.sonar.server.exceptions.BadRequestException;
import org.sonar.server.exceptions.BadRequestException.Message;
import org.sonar.server.exceptions.Errors;
import org.sonar.server.exceptions.Message;
import org.sonar.server.exceptions.NotFoundException;
import org.sonar.server.exceptions.ServerException;
import org.sonar.server.user.UserSession;
@@ -50,10 +51,6 @@ import javax.annotation.CheckForNull;
import javax.annotation.Nullable;

import java.util.Collection;
import java.util.Collections;
import java.util.List;

import static com.google.common.collect.Lists.newArrayList;

/**
* @since 4.3
@@ -75,7 +72,7 @@ public class QualityGates {
private final MyBatis myBatis;

public QualityGates(QualityGateDao dao, QualityGateConditionDao conditionDao, MetricFinder metricFinder, PropertiesDao propertiesDao, ComponentDao componentDao,
MyBatis myBatis) {
MyBatis myBatis) {
this.dao = dao;
this.conditionDao = conditionDao;
this.metricFinder = metricFinder;
@@ -119,10 +116,10 @@ public class QualityGates {
dao.insert(destinationGate, session);
for (QualityGateConditionDto sourceCondition : conditionDao.selectForQualityGate(sourceId, session)) {
conditionDao.insert(new QualityGateConditionDto().setQualityGateId(destinationGate.getId())
.setMetricId(sourceCondition.getMetricId()).setOperator(sourceCondition.getOperator())
.setWarningThreshold(sourceCondition.getWarningThreshold()).setErrorThreshold(sourceCondition.getErrorThreshold()).setPeriod(sourceCondition.getPeriod()),
.setMetricId(sourceCondition.getMetricId()).setOperator(sourceCondition.getOperator())
.setWarningThreshold(sourceCondition.getWarningThreshold()).setErrorThreshold(sourceCondition.getErrorThreshold()).setPeriod(sourceCondition.getPeriod()),
session
);
);
}
session.commit();
} finally {
@@ -131,7 +128,6 @@ public class QualityGates {
return destinationGate;
}


public Collection<QualityGateDto> list() {
return dao.selectAll();
}
@@ -173,7 +169,7 @@ public class QualityGates {
}

public QualityGateConditionDto createCondition(long qGateId, String metricKey, String operator,
@Nullable String warningThreshold, @Nullable String errorThreshold, @Nullable Integer period) {
@Nullable String warningThreshold, @Nullable String errorThreshold, @Nullable Integer period) {
checkPermission(UserSession.get());
getNonNullQgate(qGateId);
Metric metric = getNonNullMetric(metricKey);
@@ -186,7 +182,7 @@ public class QualityGates {
}

public QualityGateConditionDto updateCondition(long condId, String metricKey, String operator,
@Nullable String warningThreshold, @Nullable String errorThreshold, @Nullable Integer period) {
@Nullable String warningThreshold, @Nullable String errorThreshold, @Nullable Integer period) {
checkPermission(UserSession.get());
QualityGateConditionDto condition = getNonNullCondition(condId);
Metric metric = getNonNullMetric(metricKey);
@@ -257,42 +253,36 @@ public class QualityGates {
}

private void validateCondition(Metric metric, String operator, @Nullable String warningThreshold, @Nullable String errorThreshold, @Nullable Integer period) {
List<Message> validationMessages = newArrayList();
validateMetric(metric, validationMessages);
validateOperator(metric, operator, validationMessages);
validateThresholds(warningThreshold, errorThreshold, validationMessages);
validatePeriod(metric, period, validationMessages);
if (!validationMessages.isEmpty()) {
throw BadRequestException.of(validationMessages);
Errors errors = new Errors();
validateMetric(metric, errors);
checkOperator(metric, operator, errors);
checkThresholds(warningThreshold, errorThreshold, errors);
checkPeriod(metric, period, errors);
if (!errors.isEmpty()) {
throw new BadRequestException(errors);
}
}

private void validatePeriod(Metric metric, @Nullable Integer period, List<Message> validationMessages) {
private void checkPeriod(Metric metric, @Nullable Integer period, Errors errors) {
if (period == null) {
if (metric.getKey().startsWith("new_")) {
validationMessages.add(Message.of("A period must be selected for differential metrics."));
}
} else if (period < 1 || period > 5) {
validationMessages.add(Message.of("Valid periods are integers between 1 and 5 (included)."));
errors.check(!metric.getKey().startsWith("new_"), "A period must be selected for differential metrics.");

} else {
errors.check(period >= 1 && period <= 5, "Valid periods are integers between 1 and 5 (included).");
}
}

private void validateThresholds(@Nullable String warningThreshold, @Nullable String errorThreshold, List<Message> validationMessages) {
if (warningThreshold == null && errorThreshold == null) {
validationMessages.add(Message.of("At least one threshold (warning, error) must be set."));
}
private void checkThresholds(@Nullable String warningThreshold, @Nullable String errorThreshold, Errors errors) {
errors.check(warningThreshold != null || errorThreshold != null, "At least one threshold (warning, error) must be set.");
}

private void validateOperator(Metric metric, String operator, List<Message> validationMessages) {
if (!QualityGateConditionDto.isOperatorAllowed(operator, metric.getType())) {
validationMessages.add(Message.of(String.format("Operator %s is not allowed for metric type %s.", operator, metric.getType())));
}
private void checkOperator(Metric metric, String operator, Errors errors) {
errors
.check(QualityGateConditionDto.isOperatorAllowed(operator, metric.getType()), String.format("Operator %s is not allowed for metric type %s.", operator, metric.getType()));
}

private void validateMetric(Metric metric, List<Message> validationMessages) {
if (!isAlertable(metric)) {
validationMessages.add(Message.of(String.format("Metric '%s' cannot be used to define a condition.", metric.getKey())));
}
private void validateMetric(Metric metric, Errors errors) {
errors.check(isAlertable(metric), String.format("Metric '%s' cannot be used to define a condition.", metric.getKey()));
}

private boolean isAvailableForInit(Metric metric) {
@@ -355,24 +345,22 @@ public class QualityGates {
}

private void validateQualityGate(@Nullable Long updatingQgateId, @Nullable String name) {
List<BadRequestException.Message> messages = newArrayList();
Errors errors = new Errors();
if (Strings.isNullOrEmpty(name)) {
messages.add(BadRequestException.Message.ofL10n(Validation.CANT_BE_EMPTY_MESSAGE, "Name"));
errors.add(Message.of(Validation.CANT_BE_EMPTY_MESSAGE, "Name"));
} else {
messages.addAll(checkQgateNotAlreadyExists(updatingQgateId, name));
checkQgateNotAlreadyExists(updatingQgateId, name, errors);
}
if (!messages.isEmpty()) {
throw BadRequestException.of(messages);
if (!errors.isEmpty()) {
throw new BadRequestException(errors);
}
}

private Collection<BadRequestException.Message> checkQgateNotAlreadyExists(@Nullable Long updatingQgateId, String name) {
private void checkQgateNotAlreadyExists(@Nullable Long updatingQgateId, String name, Errors errors) {
QualityGateDto existingQgate = dao.selectByName(name);
boolean isModifyingCurrentQgate = updatingQgateId != null && existingQgate != null && existingQgate.getId().equals(updatingQgateId);
if (!isModifyingCurrentQgate && existingQgate != null) {
return Collections.singleton(BadRequestException.Message.ofL10n(Validation.IS_ALREADY_USED_MESSAGE, "Name"));
}
return Collections.emptySet();
errors.check(isModifyingCurrentQgate || existingQgate == null, Validation.IS_ALREADY_USED_MESSAGE, "Name");

}

private void checkPermission(UserSession userSession) {

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

@@ -20,25 +20,19 @@
package org.sonar.server.qualityprofile;

import com.google.common.collect.Lists;
import org.sonar.server.exceptions.Message;
import org.sonar.server.exceptions.Messages;
import org.sonar.server.exceptions.Errors;

import java.util.Collection;
import java.util.List;

public class BulkChangeResult {

private final Messages messages = new Messages();
private final Errors errors = new Errors();
private int succeeded = 0, failed = 0;
private final List<ActiveRuleChange> changes = Lists.newArrayList();

BulkChangeResult addMessage(Message message) {
this.messages.add(message);
return this;
}

public Messages getMessages() {
return messages;
public Errors getErrors() {
return errors;
}

public int countSucceeded() {

+ 3
- 2
sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileOperations.java View File

@@ -32,6 +32,7 @@ import org.sonar.server.exceptions.BadRequestException;
import org.sonar.server.user.UserSession;

import javax.annotation.Nullable;

import java.util.List;
import java.util.Map;

@@ -47,7 +48,7 @@ public class QProfileOperations implements ServerComponent {
private final QProfileLookup profileLookup;

public QProfileOperations(MyBatis myBatis, QualityProfileDao dao, PropertiesDao propertiesDao,
QProfileRepositoryExporter exporter, PreviewCache dryRunCache, QProfileLookup profileLookup) {
QProfileRepositoryExporter exporter, PreviewCache dryRunCache, QProfileLookup profileLookup) {
this.myBatis = myBatis;
this.dao = dao;
this.propertiesDao = propertiesDao;
@@ -128,7 +129,7 @@ public class QProfileOperations implements ServerComponent {

private void checkNotAlreadyExists(String name, String language, DbSession session) {
if (dao.selectByNameAndLanguage(name, language, session) != null) {
throw BadRequestException.ofL10n("quality_profiles.profile_x_already_exists", name);
throw new BadRequestException("quality_profiles.profile_x_already_exists", name);
}
}


+ 6
- 10
sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileRepositoryExporter.java View File

@@ -68,7 +68,7 @@ public class QProfileRepositoryExporter implements ServerComponent {
}

public QProfileRepositoryExporter(DatabaseSessionFactory sessionFactory, ActiveRuleDao activeRuleDao,
List<ProfileImporter> importers, List<ProfileExporter> exporters) {
List<ProfileImporter> importers, List<ProfileExporter> exporters) {
this.sessionFactory = sessionFactory;
this.activeRuleDao = activeRuleDao;
this.importers = importers;
@@ -89,7 +89,7 @@ public class QProfileRepositoryExporter implements ServerComponent {
DatabaseSession session = sessionFactory.getSession();
RulesProfile rulesProfile = session.getSingleResult(RulesProfile.class, "id", profile.id());
if (rulesProfile == null) {
throw new NotFoundException("This profile does not exists.");
throw new NotFoundException("This profile does not exist");
}
ProfileExporter exporter = getProfileExporter(pluginKey);
Writer writer = new StringWriter();
@@ -114,16 +114,12 @@ public class QProfileRepositoryExporter implements ServerComponent {
paramsByActiveRule.put(activeRuleDto.getId(), activeRuleParamDto);
}
}
//ruleRegistry.bulkIndexActiveRules(activeRuleDtos, paramsByActiveRule);
// TODO ruleRegistry.bulkIndexActiveRules(activeRuleDtos, paramsByActiveRule);
}

private void processValidationMessages(ValidationMessages messages, QProfileResult result) {
if (!messages.getErrors().isEmpty()) {
List<BadRequestException.Message> errors = newArrayList();
for (String error : messages.getErrors()) {
errors.add(BadRequestException.Message.of(error));
}
throw BadRequestException.of("Fail to import profile", errors);
throw new BadRequestException(messages);
}
result.addWarnings(messages.getWarnings());
result.addInfos(messages.getInfos());
@@ -154,7 +150,7 @@ public class QProfileRepositoryExporter implements ServerComponent {
return importer;
}
}
throw BadRequestException.of("No such importer : " + importerKey);
throw new BadRequestException("No such importer : " + importerKey);
}

private ProfileExporter getProfileExporter(String exporterKey) {
@@ -163,7 +159,7 @@ public class QProfileRepositoryExporter implements ServerComponent {
return exporter;
}
}
throw BadRequestException.of("No such exporter : " + exporterKey);
throw new BadRequestException("No such exporter : " + exporterKey);
}

public List<ProfileExporter> getProfileExportersForLanguage(String language) {

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

@@ -23,7 +23,6 @@ import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ListMultimap;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import org.slf4j.LoggerFactory;
import org.sonar.api.ServerComponent;
import org.sonar.api.profiles.ProfileDefinition;
import org.sonar.api.profiles.RulesProfile;
@@ -44,8 +43,6 @@ import java.util.List;
import java.util.Map;
import java.util.Set;

import static com.google.common.collect.Lists.newArrayList;

public class QProfileReset implements ServerComponent {

private final DbClient db;
@@ -121,7 +118,7 @@ public class QProfileReset implements ServerComponent {
result.addChanges(changes);
} catch (BadRequestException e) {
result.incrementFailed();
//TODOresult.addMessage()
result.getErrors().add(e.errors());
}
}

@@ -155,12 +152,7 @@ public class QProfileReset implements ServerComponent {

private void processValidationMessages(ValidationMessages messages) {
if (!messages.getErrors().isEmpty()) {
List<BadRequestException.Message> errors = newArrayList();
for (String error : messages.getErrors()) {
errors.add(BadRequestException.Message.of(error));
}
throw BadRequestException.of("Fail to restore profile", errors);
throw new BadRequestException(messages);
}
}
}


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

@@ -147,7 +147,7 @@ public class QProfiles implements ServerComponent {

private void checkProfileNameParam(String name) {
if (Strings.isNullOrEmpty(name)) {
throw BadRequestException.ofL10n("quality_profiles.please_type_profile_name");
throw new BadRequestException("quality_profiles.please_type_profile_name");
}
}


+ 6
- 2
sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/BulkRuleActivationActions.java View File

@@ -20,6 +20,7 @@
package org.sonar.server.qualityprofile.ws;

import org.sonar.api.ServerComponent;
import org.sonar.api.i18n.I18n;
import org.sonar.api.rule.Severity;
import org.sonar.api.server.ws.Request;
import org.sonar.api.server.ws.RequestHandler;
@@ -31,6 +32,7 @@ import org.sonar.server.qualityprofile.BulkChangeResult;
import org.sonar.server.qualityprofile.QProfileService;
import org.sonar.server.rule.RuleService;
import org.sonar.server.rule.ws.SearchAction;
import org.sonar.server.user.UserSession;

public class BulkRuleActivationActions implements ServerComponent {

@@ -42,10 +44,12 @@ public class BulkRuleActivationActions implements ServerComponent {

private final QProfileService profileService;
private final RuleService ruleService;
private final I18n i18n;

public BulkRuleActivationActions(QProfileService profileService, RuleService ruleService) {
public BulkRuleActivationActions(QProfileService profileService, RuleService ruleService, I18n i18n) {
this.profileService = profileService;
this.ruleService = ruleService;
this.i18n = i18n;
}

void define(WebService.NewController controller) {
@@ -117,7 +121,7 @@ public class BulkRuleActivationActions implements ServerComponent {
JsonWriter json = response.newJsonWriter().beginObject();
json.prop("succeeded", result.countSucceeded());
json.prop("failed", result.countFailed());
result.getMessages().writeJson(json);
result.getErrors().writeJsonAsWarnings(json, i18n, UserSession.get().locale());
json.endObject().close();
}


+ 1
- 27
sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/QProfileRestoreBuiltInAction.java View File

@@ -24,8 +24,6 @@ import org.sonar.api.server.ws.Request;
import org.sonar.api.server.ws.RequestHandler;
import org.sonar.api.server.ws.Response;
import org.sonar.api.server.ws.WebService;
import org.sonar.api.utils.text.JsonWriter;
import org.sonar.server.qualityprofile.QProfileResult;
import org.sonar.server.qualityprofile.QProfileService;

public class QProfileRestoreBuiltInAction implements RequestHandler {
@@ -53,31 +51,7 @@ public class QProfileRestoreBuiltInAction implements RequestHandler {
public void handle(Request request, Response response) {
String language = request.mandatoryParam("language");
service.restoreBuiltInProfilesForLanguage(language);

// TODO
QProfileResult result = new QProfileResult();

if (!result.infos().isEmpty() || !result.warnings().isEmpty()) {
JsonWriter json = response.newJsonWriter();
json.beginObject();
if (!result.infos().isEmpty()) {
json.name("infos").beginArray();
for (String info : result.infos()) {
json.value(info);
}
json.endArray();
}
if (!result.warnings().isEmpty()) {
json.name("warnings").beginArray();
for (String warning : result.warnings()) {
json.value(warning);
}
json.endArray();
}
json.endObject().close();
} else {
response.noContent();
}
response.noContent();
}

}

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

@@ -87,7 +87,7 @@ public class RuleOperations implements ServerComponent {
session.commit();
}
} catch (IllegalArgumentException e) {
throw BadRequestException.of(e.getMessage());
throw new BadRequestException(e.getMessage());
} finally {
MyBatis.closeQuietly(session);
}

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

@@ -36,7 +36,7 @@ public class BooleanTypeValidation implements TypeValidation {
@Override
public void validate(String value, List<String> options) {
if (!StringUtils.equalsIgnoreCase(value, "true") && !StringUtils.equalsIgnoreCase(value, "false")) {
throw BadRequestException.ofL10n("errors.type.notBoolean", value);
throw new BadRequestException("errors.type.notBoolean", value);
}
}


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

@@ -23,6 +23,7 @@ package org.sonar.server.util;
import org.sonar.api.PropertyType;
import org.sonar.server.exceptions.BadRequestException;

import javax.annotation.Nullable;
import java.util.List;

public class FloatTypeValidation implements TypeValidation {
@@ -33,11 +34,11 @@ public class FloatTypeValidation implements TypeValidation {
}

@Override
public void validate(String value, List<String> options) {
public void validate(String value, @Nullable List<String> options) {
try {
Double.parseDouble(value);
} catch (NumberFormatException e) {
throw BadRequestException.ofL10n("errors.type.notFloat", value);
throw new BadRequestException("errors.type.notFloat", value);
}
}


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

@@ -36,7 +36,7 @@ public class IntegerTypeValidation implements TypeValidation {
@Override
public void validate(String value, List<String> options) {
if (!NumberUtils.isDigits(value)) {
throw BadRequestException.ofL10n("errors.type.notInteger", value);
throw new BadRequestException("errors.type.notInteger", value);
}
}


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

@@ -37,7 +37,7 @@ public class StringListTypeValidation implements TypeValidation {
public void validate(String value, List<String> options) {
if (!options.contains(value)) {
String optionsAsString = StringUtils.join(options, ", ");
throw BadRequestException.ofL10n("errors.type.notInOptions", value, optionsAsString);
throw new BadRequestException("errors.type.notInOptions", value, optionsAsString);
}
}


+ 2
- 1
sonar-server/src/main/java/org/sonar/server/util/TypeValidation.java View File

@@ -22,11 +22,12 @@ package org.sonar.server.util;

import org.sonar.api.ServerComponent;

import javax.annotation.Nullable;
import java.util.List;

public interface TypeValidation extends ServerComponent {

String key();

void validate(String value, List<String> options);
void validate(String value, @Nullable List<String> options);
}

+ 2
- 1
sonar-server/src/main/java/org/sonar/server/util/TypeValidations.java View File

@@ -25,6 +25,7 @@ import com.google.common.collect.Iterables;
import org.sonar.api.ServerComponent;
import org.sonar.server.exceptions.BadRequestException;

import javax.annotation.Nullable;
import java.util.List;

public class TypeValidations implements ServerComponent {
@@ -42,7 +43,7 @@ public class TypeValidations implements ServerComponent {
}
}

public void validate(String value, String type, List<String> options) {
public void validate(String value, String type, @Nullable List<String> options) {
TypeValidation typeValidation = findByKey(type);
typeValidation.validate(value, options);
}

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

@@ -34,20 +34,14 @@ public class Validation {

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

public static void checkMandatoryParameter(Object value, String paramName) {
if (value == null) {
throw BadRequestException.ofL10n(Validation.CANT_BE_EMPTY_MESSAGE, paramName);
throw new BadRequestException(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 BadRequestException.ofL10n(Validation.IS_TOO_LONG_MESSAGE, paramName, size);
throw new BadRequestException(Validation.IS_TOO_LONG_MESSAGE, paramName, size);
}
}


+ 11
- 42
sonar-server/src/main/java/org/sonar/server/ws/WebServiceEngine.java View File

@@ -19,7 +19,6 @@
*/
package org.sonar.server.ws;

import org.elasticsearch.common.collect.Lists;
import org.picocontainer.Startable;
import org.slf4j.LoggerFactory;
import org.sonar.api.ServerComponent;
@@ -29,17 +28,16 @@ import org.sonar.api.server.ws.WebService;
import org.sonar.api.server.ws.internal.ValidatingRequest;
import org.sonar.api.utils.text.JsonWriter;
import org.sonar.server.exceptions.BadRequestException;
import org.sonar.server.exceptions.BadRequestException.Message;
import org.sonar.server.exceptions.Errors;
import org.sonar.server.exceptions.Message;
import org.sonar.server.exceptions.ServerException;
import org.sonar.server.plugins.MimeTypes;
import org.sonar.server.user.UserSession;

import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
import javax.servlet.http.HttpServletResponse;

import java.io.OutputStreamWriter;
import java.util.Collection;
import java.util.List;
import java.util.Locale;

/**
* @since 4.2
@@ -77,7 +75,7 @@ public class WebServiceEngine implements ServerComponent, Startable {
}

public void execute(ValidatingRequest request, ServletResponse response,
String controllerPath, String actionKey) {
String controllerPath, String actionKey) {
try {
WebService.Action action = getAction(controllerPath, actionKey);
request.setAction(action);
@@ -86,15 +84,15 @@ public class WebServiceEngine implements ServerComponent, Startable {

} catch (IllegalArgumentException e) {
// TODO replace by BadRequestException in Request#mandatoryParam()
sendError(400, e.getMessage(), response);
sendErrors(response, 400, new Errors().add(Message.of(e.getMessage())));
} catch (BadRequestException e) {
sendError(e, response);
sendErrors(response, 400, e.errors());
} catch (ServerException e) {
sendError(e.httpCode(), message(e.getMessage(), e.l10nKey(), e.l10nParams()), response);
sendErrors(response, e.httpCode(), new Errors().add(Message.of(e.getMessage())));
} catch (Exception e) {
// TODO implement Request.toString()
LoggerFactory.getLogger(getClass()).error("Fail to process request " + request, e);
sendError(500, e.getMessage(), response);
sendErrors(response, 500, new Errors().add(Message.of(e.getMessage())));
}
}

@@ -117,32 +115,7 @@ public class WebServiceEngine implements ServerComponent, Startable {
}
}

private void sendError(BadRequestException e, ServletResponse response) {
Collection<String> messages = Lists.newArrayList();
String exceptionMessage = message(e.getMessage(), e.l10nKey(), e.l10nParams());
if (exceptionMessage != null) {
messages.add(exceptionMessage);
}
for (Message message : e.errors()) {
messages.add(message(message.text(), message.l10nKey(), message.l10nParams()));
}
sendErrors(response, e.httpCode(), messages.toArray(new String[messages.size()]));
}

@CheckForNull
private String message(@Nullable String message, @Nullable String l10nKey, Object... l10nParams) {
if (l10nKey != null) {
return i18n.message(Locale.getDefault(), l10nKey, message, l10nParams);
} else {
return message;
}
}

private void sendError(int status, @Nullable String message, ServletResponse response) {
sendErrors(response, status, message);
}

private void sendErrors(ServletResponse response, int status, String... errors) {
private void sendErrors(ServletResponse response, int status, Errors errors) {
ServletResponse.ServletStream stream = response.stream();
stream.reset();
stream.setStatus(status);
@@ -151,11 +124,7 @@ public class WebServiceEngine implements ServerComponent, Startable {

try {
json.beginObject();
json.name("errors").beginArray();
for (String message : errors) {
json.beginObject().prop("msg", message).endObject();
}
json.endArray();
errors.writeJson(json, i18n, UserSession.get().locale());
json.endObject();
} finally {
// TODO if close() fails, the runtime exception should not hide the

+ 6
- 7
sonar-server/src/test/java/org/sonar/server/debt/DebtModelOperationsTest.java View File

@@ -151,8 +151,8 @@ public class DebtModelOperationsTest {
try {
service.create("Compilation", 1);
fail();
} catch (Exception e) {
assertThat(e).isInstanceOf(BadRequestException.class).hasMessage("A sub characteristic can not have a sub characteristic as parent.");
} catch (BadRequestException e) {
assertThat(e.firstError().getKey()).isEqualTo("A sub characteristic can not have a sub characteristic as parent.");
}
}

@@ -177,8 +177,8 @@ public class DebtModelOperationsTest {
service.create("Compilation", 1);
fail();
} catch (BadRequestException e) {
assertThat(e.l10nKey()).isEqualTo("errors.is_already_used");
assertThat(e.l10nParams()[0]).isEqualTo("Compilation");
assertThat(e.firstError().getKey()).isEqualTo("errors.is_already_used");
assertThat(e.firstError().getParams()[0]).isEqualTo("Compilation");
}
}

@@ -327,10 +327,9 @@ public class DebtModelOperationsTest {
try {
service.moveDown(10);
fail();
} catch (Exception e) {
assertThat(e).isInstanceOf(BadRequestException.class).hasMessage("Sub characteristics can not be moved.");
} catch (BadRequestException e) {
assertThat(e.firstError().getKey()).isEqualTo("Sub characteristics can not be moved.");
}

verify(dao, never()).update(any(CharacteristicDto.class), eq(session));
}


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

@@ -22,91 +22,14 @@ package org.sonar.server.exceptions;

import org.junit.Test;

import static com.google.common.collect.Lists.newArrayList;
import static org.fest.assertions.Assertions.assertThat;

public class BadRequestExceptionTest {

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

@Test
public void text_error_with_list_of_errors() throws Exception {
BadRequestException exception = BadRequestException.of("error", newArrayList(BadRequestException.Message.of("new error")));

assertThat(exception.errors()).hasSize(1);
assertThat(exception.errors().get(0).text()).isEqualTo("new error");
}

@Test
public void text_error_with_list_of_l18n_errors() throws Exception {
BadRequestException exception = BadRequestException.of("error", newArrayList(BadRequestException.Message.ofL10n("issue.error.123", "10")));

assertThat(exception.errors()).hasSize(1);
assertThat(exception.errors().get(0).l10nKey()).isEqualTo("issue.error.123");
assertThat(exception.errors().get(0).l10nParams()).containsOnly("10");
}

@Test
public void list_of_errors() throws Exception {
BadRequestException exception = BadRequestException.of(newArrayList(BadRequestException.Message.of("new error")));

assertThat(exception.errors()).hasSize(1);
assertThat(exception.errors().get(0).text()).isEqualTo("new error");
}

@Test
public void l10n_errors() throws Exception {
BadRequestException exception = BadRequestException.ofL10n("issue.error.123", "10");
assertThat(exception.getMessage()).isNull();
assertThat(exception.l10nKey()).isEqualTo("issue.error.123");
assertThat(exception.l10nParams()).containsOnly("10");
}

@Test
public void l10n_errors_with_list_of_errors() throws Exception {
BadRequestException exception = BadRequestException.ofL10n(newArrayList(BadRequestException.Message.of("new error")), "issue.error.123", "10");
assertThat(exception.getMessage()).isNull();
assertThat(exception.l10nKey()).isEqualTo("issue.error.123");
assertThat(exception.l10nParams()).containsOnly("10");
assertThat(exception.errors()).hasSize(1);
assertThat(exception.errors().get(0).text()).isEqualTo("new error");
}

@Test
public void test_equals_and_hashcode() throws Exception {
BadRequestException.Message msg = BadRequestException.Message.of("error1");
BadRequestException.Message sameMsg = BadRequestException.Message.of("error1");
BadRequestException.Message msg2 = BadRequestException.Message.of("error2");

assertThat(msg.toString()).contains("error1");
assertThat(msg).isEqualTo(sameMsg);
assertThat(msg).isEqualTo(sameMsg);
assertThat(msg.hashCode()).isEqualTo(msg.hashCode());
assertThat(msg.hashCode()).isEqualTo(sameMsg.hashCode());

assertThat(msg).isNotEqualTo(msg2);
}

@Test
public void test_equals_and_hashcode_on_l10n() throws Exception {
BadRequestException.Message msg = BadRequestException.Message.ofL10n("error.123", "10");
BadRequestException.Message sameMsg = BadRequestException.Message.ofL10n("error.123", "10");
BadRequestException.Message msg2 = BadRequestException.Message.ofL10n("error.123", "200");
BadRequestException.Message msg3 = BadRequestException.Message.ofL10n("error.50");

assertThat(msg.toString()).contains("error.123").contains("10");
assertThat(msg).isEqualTo(msg);
assertThat(msg).isEqualTo(sameMsg);
assertThat(msg.hashCode()).isEqualTo(msg.hashCode());
assertThat(msg.hashCode()).isEqualTo(sameMsg.hashCode());

assertThat(msg).isNotEqualTo(msg2);
assertThat(msg).isNotEqualTo(msg3);
assertThat(msg).isNotEqualTo("issue.error.123");
}

}

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

@@ -27,31 +27,15 @@ import static org.fest.assertions.Assertions.assertThat;
public class ServerExceptionTest {

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

@Test
public void should_create_exception_with_status_and_message(){
public void should_create_exception_with_status_and_message() {
ServerException exception = new ServerException(404, "Not found");
assertThat(exception.httpCode()).isEqualTo(404);
assertThat(exception.getMessage()).isEqualTo("Not found");
}

@Test
public void should_create_exception_with_status_and_l10n_message_with_param(){
ServerException exception = new ServerException(404, null, "key", new String[]{"value"});
assertThat(exception.httpCode()).isEqualTo(404);
assertThat(exception.l10nKey()).isEqualTo("key");
assertThat(exception.l10nParams()).containsOnly("value");
}

@Test
public void should_create_exception_with_status_and_l10n_message_without_param(){
ServerException exception = new ServerException(404, null, "key", null);
assertThat(exception.httpCode()).isEqualTo(404);
assertThat(exception.l10nKey()).isEqualTo("key");
assertThat(exception.l10nParams()).isEmpty();
}
}

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

@@ -0,0 +1,42 @@
/*
* SonarQube, open source software quality management tool.
* Copyright (C) 2008-2014 SonarSource
* mailto:contact AT sonarsource DOT com
*
* SonarQube 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.
*
* SonarQube 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.Test;

import static org.fest.assertions.Assertions.assertThat;
import static org.fest.assertions.Fail.fail;

public class VerificationsTest {

@Test
public void check() throws Exception {
// no exception
Verifications.check(true, "my.l10n.key", "foo", "bar");

try {
Verifications.check(false, "my.l10n.key", "foo", "bar");
fail();
} catch (BadRequestException e) {
assertThat(e.firstError().getKey()).isEqualTo("my.l10n.key");
assertThat(e.firstError().getParams()).containsOnly("foo", "bar");
}
}
}

+ 4
- 2
sonar-server/src/test/java/org/sonar/server/issue/InternalRubyIssueServiceTest.java View File

@@ -41,6 +41,7 @@ import org.sonar.core.resource.ResourceDao;
import org.sonar.core.resource.ResourceDto;
import org.sonar.core.resource.ResourceQuery;
import org.sonar.server.exceptions.BadRequestException;
import org.sonar.server.exceptions.Message;
import org.sonar.server.issue.actionplan.ActionPlanService;
import org.sonar.server.issue.filter.IssueFilterService;
import org.sonar.server.user.UserSession;
@@ -653,8 +654,9 @@ public class InternalRubyIssueServiceTest {

private void checkBadRequestException(Exception e, String key, Object... params) {
BadRequestException exception = (BadRequestException) e;
assertThat(exception.l10nKey()).isEqualTo(key);
assertThat(exception.l10nParams()).containsOnly(params);
Message msg = exception.errors().messages().get(0);
assertThat(msg.getKey()).isEqualTo(key);
assertThat(msg.getParams()).containsOnly(params);
}

private String createLongString(int size) {

+ 2
- 2
sonar-server/src/test/java/org/sonar/server/issue/IssueBulkChangeQueryTest.java View File

@@ -155,8 +155,8 @@ public class IssueBulkChangeQueryTest {

private void checkBadRequestException(Exception e, String key, Object... params) {
BadRequestException exception = (BadRequestException) e;
assertThat(exception.l10nKey()).isEqualTo(key);
assertThat(exception.l10nParams()).containsOnly(params);
assertThat(exception.firstError().getKey()).isEqualTo(key);
assertThat(exception.firstError().getParams()).containsOnly(params);
}

}

+ 1
- 1
sonar-server/src/test/java/org/sonar/server/qualitygate/ws/QGatesWsTest.java View File

@@ -208,7 +208,7 @@ public class QGatesWsTest {
@Test(expected = BadRequestException.class)
public void create_with_duplicate_name() throws Exception {
String name = "New QG";
when(qGates.create(name)).thenThrow(BadRequestException.of("Name is already used"));
when(qGates.create(name)).thenThrow(new BadRequestException("Name is already used"));
tester.newGetRequest("api/qualitygates", "create").setParam("name", name).execute();
}


+ 6
- 4
sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileRepositoryExporterTest.java View File

@@ -20,7 +20,6 @@

package org.sonar.server.qualityprofile;

import com.google.common.collect.Multimap;
import org.apache.ibatis.session.SqlSession;
import org.junit.Before;
import org.junit.Test;
@@ -54,9 +53,12 @@ import static com.google.common.collect.Lists.newArrayList;
import static org.fest.assertions.Assertions.assertThat;
import static org.fest.assertions.Fail.fail;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyListOf;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.*;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

@RunWith(MockitoJUnitRunner.class)
public class QProfileRepositoryExporterTest {
@@ -256,7 +258,7 @@ public class QProfileRepositoryExporterTest {
operations.exportToXml(new QProfile().setId(1), "pmd");
fail();
} catch (Exception e) {
assertThat(e).isInstanceOf(NotFoundException.class).hasMessage("This profile does not exists.");
assertThat(e).isInstanceOf(NotFoundException.class).hasMessage("This profile does not exist");
}

verify(exporter, never()).exportProfile(any(RulesProfile.class), any(Writer.class));

+ 3
- 1
sonar-server/src/test/java/org/sonar/server/qualityprofile/RuleActivatorMediumTest.java View File

@@ -34,6 +34,7 @@ import org.sonar.core.rule.RuleDto;
import org.sonar.core.rule.RuleParamDto;
import org.sonar.server.db.DbClient;
import org.sonar.server.exceptions.BadRequestException;
import org.sonar.server.exceptions.Message;
import org.sonar.server.qualityprofile.index.ActiveRuleIndex;
import org.sonar.server.rule.RuleTesting;
import org.sonar.server.rule.index.RuleIndex;
@@ -320,7 +321,8 @@ public class RuleActivatorMediumTest {
ruleActivator.activate(activation);
fail();
} catch (BadRequestException e) {
assertThat(e.l10nKey()).isEqualTo("errors.type.notInteger");
Message msg = e.errors().messages().get(0);
assertThat(msg.getKey()).isEqualTo("errors.type.notInteger");
verifyZeroActiveRules(XOO_PROFILE_KEY);
}
}

+ 5
- 26
sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/QProfileRestoreBuiltInActionTest.java View File

@@ -25,6 +25,7 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import org.sonar.api.i18n.I18n;
import org.sonar.server.qualityprofile.QProfileService;
import org.sonar.server.rule.RuleService;
import org.sonar.server.ws.WsTester;
@@ -37,6 +38,9 @@ public class QProfileRestoreBuiltInActionTest {
@Mock
QProfileService profileService;

@Mock
I18n i18n;

WsTester tester;

@Before
@@ -46,7 +50,7 @@ public class QProfileRestoreBuiltInActionTest {
tester = new WsTester(new QProfilesWs(
new QProfileRestoreBuiltInAction(this.profileService),
new RuleActivationActions(profileService),
new BulkRuleActivationActions(profileService, ruleService)));
new BulkRuleActivationActions(profileService, ruleService, i18n)));
}

@Test
@@ -56,29 +60,4 @@ public class QProfileRestoreBuiltInActionTest {
WsTester.TestRequest request = tester.newPostRequest("api/qualityprofiles", "restore_built_in").setParam("language", "java");
request.execute().assertNoContent();
}

// TODO
// @Test
// public void show_infos() throws Exception {
// when(profileService.recreateBuiltInProfilesByLanguage("java")).thenReturn(new QProfileResult().addInfos(newArrayList("Some info")));
//
// WsTester.TestRequest request = tester.newPostRequest("api/qualityprofiles", "recreate_built_in").setParam("language", "java");
// request.execute().assertJson(getClass(), "show_infos.json");
// }
//
// @Test
// public void show_warnings() throws Exception {
// when(profileService.recreateBuiltInProfilesByLanguage("java")).thenReturn(new QProfileResult().addWarnings(newArrayList("Some warning")));
//
// WsTester.TestRequest request = tester.newPostRequest("api/qualityprofiles", "recreate_built_in").setParam("language", "java");
// request.execute().assertJson(getClass(), "show_warnings.json");
// }
//
// @Test
// public void show_infos_and_warnings() throws Exception {
// when(profileService.recreateBuiltInProfilesByLanguage("java")).thenReturn(new QProfileResult().addInfos(newArrayList("Some info")).addWarnings(newArrayList("Some warning")));
//
// WsTester.TestRequest request = tester.newPostRequest("api/qualityprofiles", "recreate_built_in").setParam("language", "java");
// request.execute().assertJson(getClass(), "show_infos_and_warnings.json");
// }
}

+ 3
- 1
sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/QProfilesWsTest.java View File

@@ -22,6 +22,7 @@ package org.sonar.server.qualityprofile.ws;

import org.junit.Before;
import org.junit.Test;
import org.sonar.api.i18n.I18n;
import org.sonar.api.server.ws.WebService;
import org.sonar.server.qualityprofile.QProfileService;
import org.sonar.server.rule.RuleService;
@@ -38,10 +39,11 @@ public class QProfilesWsTest {
public void setUp() {
QProfileService profileService = mock(QProfileService.class);
RuleService ruleService = mock(RuleService.class);
I18n i18n = mock(I18n.class);
controller = new WsTester(new QProfilesWs(new QProfileRestoreBuiltInAction(
mock(QProfileService.class)),
new RuleActivationActions(profileService),
new BulkRuleActivationActions(profileService, ruleService)
new BulkRuleActivationActions(profileService, ruleService, i18n)
)).controller(QProfilesWs.API_ENDPOINT);
}


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

@@ -57,7 +57,7 @@ public class BooleanTypeValidationTest {
} catch (Exception e) {
assertThat(e).isInstanceOf(BadRequestException.class);
BadRequestException badRequestException = (BadRequestException) e;
assertThat(badRequestException.l10nParams()[0]).isEqualTo("abc");
assertThat(badRequestException.firstError().getParams()[0]).isEqualTo("abc");
}
}


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

@@ -55,7 +55,7 @@ public class FloatTypeValidationTest {
} catch (Exception e) {
assertThat(e).isInstanceOf(BadRequestException.class);
BadRequestException badRequestException = (BadRequestException) e;
assertThat(badRequestException.l10nParams()[0]).isEqualTo("abc");
assertThat(badRequestException.firstError().getParams()[0]).isEqualTo("abc");
}
}


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

@@ -54,7 +54,7 @@ public class IntegerTypeValidationTest {
} catch (Exception e) {
assertThat(e).isInstanceOf(BadRequestException.class);
BadRequestException badRequestException = (BadRequestException) e;
assertThat(badRequestException.l10nParams()[0]).isEqualTo("abc");
assertThat(badRequestException.firstError().getParams()[0]).isEqualTo("abc");
}
}


+ 2
- 2
sonar-server/src/test/java/org/sonar/server/util/StringListTypeValidationTest.java View File

@@ -55,8 +55,8 @@ public class StringListTypeValidationTest {
} catch (Exception e) {
assertThat(e).isInstanceOf(BadRequestException.class);
BadRequestException badRequestException = (BadRequestException) e;
assertThat(badRequestException.l10nParams()[0]).isEqualTo("abc");
assertThat(badRequestException.l10nParams()[1]).isEqualTo("a, b, c");
assertThat(badRequestException.firstError().getParams()[0]).isEqualTo("abc");
assertThat(badRequestException.firstError().getParams()[1]).isEqualTo("a, b, c");
}
}


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

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


+ 25
- 43
sonar-server/src/test/java/org/sonar/server/ws/WebServiceEngineTest.java View File

@@ -19,12 +19,13 @@
*/
package org.sonar.server.ws;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.apache.commons.io.IOUtils;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.sonar.api.i18n.I18n;
import org.sonar.api.server.ws.Request;
import org.sonar.api.server.ws.RequestHandler;
@@ -32,17 +33,19 @@ import org.sonar.api.server.ws.Response;
import org.sonar.api.server.ws.WebService;
import org.sonar.api.server.ws.internal.ValidatingRequest;
import org.sonar.server.exceptions.BadRequestException;
import org.sonar.server.exceptions.BadRequestException.Message;
import org.sonar.server.exceptions.ServerException;
import org.sonar.server.exceptions.Errors;
import org.sonar.server.exceptions.Message;
import org.sonar.server.plugins.MimeTypes;

import javax.annotation.Nullable;

import java.io.IOException;
import java.util.List;
import java.util.Locale;
import java.util.Map;

import static org.fest.assertions.Assertions.assertThat;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyObject;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
@@ -83,7 +86,7 @@ public class WebServiceEngineTest {
}

I18n i18n = mock(I18n.class);
WebServiceEngine engine = new WebServiceEngine(new WebService[]{new SystemWebService()}, i18n);
WebServiceEngine engine = new WebServiceEngine(new WebService[] {new SystemWebService()}, i18n);

@Before
public void start() {
@@ -230,13 +233,13 @@ public class WebServiceEngineTest {
public void bad_request_with_i18n_message() throws Exception {
ValidatingRequest request = new SimpleRequest("GET").setParam("count", "3");
ServletResponse response = new ServletResponse();
when(i18n.message(eq(Locale.getDefault()), eq("bad.request.reason"), anyString(), eq(0))).thenReturn("Bad request reason #0");
when(i18n.message(Locale.ENGLISH, "bad.request.reason", "bad.request.reason", 0)).thenReturn("reason #0");

engine.execute(request, response, "api/system", "fail_with_i18n_message");

assertThat(response.stream().outputAsString()).isEqualTo("{\"errors\":["
+ "{\"msg\":\"Bad request reason #0\"}"
+ "]}");
assertThat(response.stream().outputAsString()).isEqualTo(
"{\"errors\":[{\"msg\":\"reason #0\"}]}"
);
assertThat(response.stream().httpStatus()).isEqualTo(400);
assertThat(response.stream().mediaType()).isEqualTo(MimeTypes.JSON);
}
@@ -261,34 +264,20 @@ public class WebServiceEngineTest {
public void bad_request_with_multiple_i18n_messages() throws Exception {
ValidatingRequest request = new SimpleRequest("GET").setParam("count", "3");
ServletResponse response = new ServletResponse();
when(i18n.message(Locale.getDefault(), "bad.request.reason", null, 0)).thenReturn("Bad request reason #0");
when(i18n.message(Locale.getDefault(), "bad.request.reason", null, 1)).thenReturn("Bad request reason #1");
when(i18n.message(Locale.getDefault(), "bad.request.reason", null, 2)).thenReturn("Bad request reason #2");
when(i18n.message(Locale.ENGLISH, "bad.request.reason", "bad.request.reason", 0)).thenReturn("reason #0");
when(i18n.message(Locale.ENGLISH, "bad.request.reason", "bad.request.reason", 1)).thenReturn("reason #1");
when(i18n.message(Locale.ENGLISH, "bad.request.reason", "bad.request.reason", 2)).thenReturn("reason #2");

engine.execute(request, response, "api/system", "fail_with_multiple_i18n_messages");

assertThat(response.stream().outputAsString()).isEqualTo("{\"errors\":["
+ "{\"msg\":\"Bad request reason #0\"},"
+ "{\"msg\":\"Bad request reason #1\"},"
+ "{\"msg\":\"Bad request reason #2\"}"
+ "]}");
assertThat(response.stream().outputAsString()).isEqualTo("{\"errors\":[" +
"{\"msg\":\"reason #0\"}," +
"{\"msg\":\"reason #1\"}," +
"{\"msg\":\"reason #2\"}]}");
assertThat(response.stream().httpStatus()).isEqualTo(400);
assertThat(response.stream().mediaType()).isEqualTo(MimeTypes.JSON);
}

@Test
public void server_exception_with_i18n_message() throws Exception {
ValidatingRequest request = new SimpleRequest("GET");
ServletResponse response = new ServletResponse();
when(i18n.message(eq(Locale.getDefault()), eq("not.found"), anyString())).thenReturn("Element is not found");

engine.execute(request, response, "api/system", "server_exception_with_i18n_message");

assertThat(response.stream().outputAsString()).isEqualTo("{\"errors\":[{\"msg\":\"Element is not found\"}]}");
assertThat(response.stream().httpStatus()).isEqualTo(404);
assertThat(response.stream().mediaType()).isEqualTo(MimeTypes.JSON);
}

static class SystemWebService implements WebService {
@Override
public void define(Context context) {
@@ -327,7 +316,7 @@ public class WebServiceEngineTest {
.setHandler(new RequestHandler() {
@Override
public void handle(Request request, Response response) {
throw BadRequestException.ofL10n("bad.request.reason", 0);
throw new BadRequestException("bad.request.reason", 0);
}
});
newController.createAction("fail_with_multiple_messages")
@@ -335,11 +324,11 @@ public class WebServiceEngineTest {
.setHandler(new RequestHandler() {
@Override
public void handle(Request request, Response response) {
List<BadRequestException.Message> errors = Lists.newArrayList();
Errors errors = new Errors();
for (int count = 0; count < Integer.valueOf(request.param("count")); count++) {
errors.add(Message.of("Bad request reason #" + count));
}
throw BadRequestException.of(errors);
throw new BadRequestException(errors);
}
});
newController.createAction("fail_with_multiple_i18n_messages")
@@ -347,18 +336,11 @@ public class WebServiceEngineTest {
.setHandler(new RequestHandler() {
@Override
public void handle(Request request, Response response) {
List<BadRequestException.Message> errors = Lists.newArrayList();
Errors errors = new Errors();
for (int count = 0; count < Integer.valueOf(request.param("count")); count++) {
errors.add(Message.ofL10n("bad.request.reason", count));
errors.add(Message.of("bad.request.reason", count));
}
throw BadRequestException.of(errors);
}
});
newController.createAction("server_exception_with_i18n_message")
.setHandler(new RequestHandler() {
@Override
public void handle(Request request, Response response) {
throw new ServerException(404, null, "not.found", null);
throw new BadRequestException(errors);
}
});
newController.createAction("alive")

Loading…
Cancel
Save