]> source.dussan.org Git - sonarqube.git/commitdiff
Refactor the way to load QProfiles from WS
authorSimon Brandhof <simon.brandhof@sonarsource.com>
Mon, 12 Sep 2016 15:16:51 +0000 (17:16 +0200)
committerSimon Brandhof <simon.brandhof@sonarsource.com>
Tue, 13 Sep 2016 14:02:02 +0000 (16:02 +0200)
17 files changed:
server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java
server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileFactory.java
server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileRef.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/BackupAction.java
server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/ChangeParentAction.java
server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/ChangelogAction.java
server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/DeleteAction.java
server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/InheritanceAction.java
server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/QProfileFinder.java [deleted file]
server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/QProfileIdentificationParamUtils.java [deleted file]
server/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileFactoryTest.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/BackupActionTest.java
server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/ChangeParentActionMediumTest.java
server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/ChangelogActionTest.java
server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/QProfileFactoryTest.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/QProfileRefTest.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/QProfilesWsTest.java

index 4d959dd5f1c17cf0d7c4f27a4416d8a6d65ca48b..156110ecde094731215a088e9a39af06e2a54df7 100644 (file)
@@ -210,7 +210,6 @@ import org.sonar.server.qualityprofile.ws.OldRestoreAction;
 import org.sonar.server.qualityprofile.ws.ProfilesWs;
 import org.sonar.server.qualityprofile.ws.ProjectAssociationActions;
 import org.sonar.server.qualityprofile.ws.ProjectsAction;
-import org.sonar.server.qualityprofile.ws.QProfileFinder;
 import org.sonar.server.qualityprofile.ws.QProfilesWs;
 import org.sonar.server.qualityprofile.ws.RenameAction;
 import org.sonar.server.qualityprofile.ws.RestoreAction;
@@ -372,7 +371,6 @@ public class PlatformLevel4 extends PlatformLevel {
       InheritanceAction.class,
       ChangeParentAction.class,
       ChangelogAction.class,
-      QProfileFinder.class,
       ChangelogLoader.class,
       CompareAction.class,
       ExportAction.class,
index f2e9ff6b6a0ecee9335662f130463f860a34bd4c..4b0e60b2d69d5547f36e8a4755c8983d0606abde 100644 (file)
@@ -38,6 +38,7 @@ 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;
 
 /**
  * Create, delete, rename and set as default profile.
@@ -171,6 +172,31 @@ public class QProfileFactory {
     db.qualityProfileDao().update(session, profile.setDefault(true));
   }
 
+  public QualityProfileDto find(QProfileRef ref) {
+    try (DbSession dbSession = db.openSession(false)) {
+      return find(ref, dbSession);
+    }
+  }
+
+  public QualityProfileDto find(QProfileRef ref, DbSession dbSession) {
+    if (ref.hasKey()) {
+      return findByKey(dbSession, ref.getKey());
+    }
+    return findByName(dbSession, ref.getLanguage(), ref.getName());
+  }
+
+  private QualityProfileDto findByKey(DbSession dbSession, String profileKey) {
+    QualityProfileDto profile;
+    profile = db.qualityProfileDao().selectByKey(dbSession, profileKey);
+    return checkFound(profile, "Unable to find a profile for with key '%s'", profileKey);
+  }
+
+  private QualityProfileDto findByName(DbSession dbSession, String language, String profileName) {
+    QualityProfileDto profile;
+    profile = db.qualityProfileDao().selectByNameAndLanguage(profileName, language, dbSession);
+    return checkFound(profile, "Unable to find a profile for language '%s' with name '%s'", language, profileName);
+  }
+
   QualityProfileDto getByProjectAndLanguage(String projectKey, String language) {
     DbSession dbSession = db.openSession(false);
     try {
diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileRef.java b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileRef.java
new file mode 100644 (file)
index 0000000..9dca9c5
--- /dev/null
@@ -0,0 +1,155 @@
+/*
+ * 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.qualityprofile;
+
+import javax.annotation.Nullable;
+import org.sonar.api.resources.Languages;
+import org.sonar.api.server.ws.Request;
+import org.sonar.api.server.ws.WebService;
+import org.sonar.server.component.ws.LanguageParamUtils;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkState;
+import static java.util.Objects.requireNonNull;
+import static org.apache.commons.lang.StringUtils.isEmpty;
+
+/**
+ * Reference to a Quality profile. The two exclusive options to reference a profile are:
+ * <ul>
+ *   <li>by its key</li>
+ *   <li>by the couple {language, name}</li>
+ * </ul>
+ */
+public class QProfileRef {
+
+  public static final String PARAM_LANGUAGE = "language";
+  public static final String PARAM_PROFILE_NAME = "profileName";
+  public static final String PARAM_PROFILE_KEY = "profileKey";
+
+  private final String key;
+  private final String language;
+  private final String name;
+
+  private QProfileRef(@Nullable String key, @Nullable String language, @Nullable String name) {
+    this.key = key;
+    this.language = language;
+    this.name = name;
+  }
+
+  /**
+   * @return {@code true} if key is defined and {@link #getKey()} can be called. If {@code false}, then
+   *   the couple {language, name} is defined and the methods {@link #getLanguage()}/{@link #getName()}
+   *   can be called.
+   */
+  public boolean hasKey() {
+    return this.key != null;
+  }
+
+  /**
+   * @return non-null key
+   * @throws IllegalStateException if {@link #hasKey()} does not return {@code true}
+   */
+  public String getKey() {
+    checkState(key != null, "Key is not present. Please call hasKey().");
+    return key;
+  }
+
+  /**
+   * @return non-null language
+   * @throws IllegalStateException if {@link #hasKey()} does not return {@code false}
+   */
+  public String getLanguage() {
+    checkState(language != null, "Language is not present. Please call hasKey().");
+    return language;
+  }
+
+  /**
+   * @return non-null name
+   * @throws IllegalStateException if {@link #hasKey()} does not return {@code false}
+   */
+  public String getName() {
+    checkState(name != null, "Name is not present. Please call hasKey().");
+    return name;
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (this == o) {
+      return true;
+    }
+    if (o == null || getClass() != o.getClass()) {
+      return false;
+    }
+    QProfileRef that = (QProfileRef) o;
+    if (key != null ? !key.equals(that.key) : that.key != null) {
+      return false;
+    }
+    if (language != null ? !language.equals(that.language) : that.language != null) {
+      return false;
+    }
+    return name != null ? name.equals(that.name) : that.name == null;
+
+  }
+
+  @Override
+  public int hashCode() {
+    int result = key != null ? key.hashCode() : 0;
+    result = 31 * result + (language != null ? language.hashCode() : 0);
+    result = 31 * result + (name != null ? name.hashCode() : 0);
+    return result;
+  }
+
+  public static QProfileRef from(Request request) {
+    String key = request.param(PARAM_PROFILE_KEY);
+    String lang = request.param(PARAM_LANGUAGE);
+    String name = request.param(PARAM_PROFILE_NAME);
+    return from(key, lang, name);
+  }
+
+  public static QProfileRef from(@Nullable String key, @Nullable String lang, @Nullable String name) {
+    if (key != null) {
+      checkArgument(isEmpty(lang) && isEmpty(name), "Either key or couple language/name must be set");
+      return fromKey(key);
+    }
+    checkArgument(!isEmpty(lang) && !isEmpty(name), "Both profile language and name must be set");
+    return fromName(lang, name);
+  }
+
+  public static QProfileRef fromKey(String key) {
+    return new QProfileRef(requireNonNull(key), null, null);
+  }
+
+  public static QProfileRef fromName(String lang, String name) {
+    return new QProfileRef(null, requireNonNull(lang), requireNonNull(name));
+  }
+
+  public static void defineParams(WebService.NewAction action, Languages languages) {
+    action.createParam(PARAM_PROFILE_KEY)
+      .setDescription("A quality profile key. Either this parameter, or a combination of profileName + language must be set.")
+      .setExampleValue("sonar-way-java-12345");
+    action.createParam(PARAM_PROFILE_NAME)
+      .setDescription("A quality profile name. If this parameter is set, profileKey must not be set and language must be set to disambiguate.")
+      .setExampleValue("Sonar way");
+    action.createParam(PARAM_LANGUAGE)
+      .setDescription("A quality profile language. If this parameter is set, profileKey must not be set and profileName must be set to disambiguate.")
+      .setPossibleValues(LanguageParamUtils.getLanguageKeys(languages))
+      .setExampleValue("js");
+  }
+}
index faf3405a1c4d46b120762f6d299b73a907c089a6..a422f83967adc1168df2e65db10e28e417bed5f5 100644 (file)
@@ -21,32 +21,26 @@ package org.sonar.server.qualityprofile.ws;
 
 import java.io.OutputStreamWriter;
 import java.nio.charset.StandardCharsets;
-import org.apache.commons.io.IOUtils;
 import org.sonar.api.resources.Languages;
 import org.sonar.api.server.ws.Request;
 import org.sonar.api.server.ws.Response;
 import org.sonar.api.server.ws.Response.Stream;
 import org.sonar.api.server.ws.WebService;
 import org.sonar.api.server.ws.WebService.NewAction;
-import org.sonar.db.DbClient;
-import org.sonar.db.DbSession;
+import org.sonar.db.qualityprofile.QualityProfileDto;
 import org.sonar.server.qualityprofile.QProfileBackuper;
 import org.sonar.server.qualityprofile.QProfileFactory;
+import org.sonar.server.qualityprofile.QProfileRef;
 import org.sonarqube.ws.MediaTypes;
 
 public class BackupAction implements QProfileWsAction {
 
   private final QProfileBackuper backuper;
-
-  private final DbClient dbClient;
-
-  private QProfileFactory profileFactory;
-
+  private final QProfileFactory profileFactory;
   private final Languages languages;
 
-  public BackupAction(QProfileBackuper backuper, DbClient dbClient, QProfileFactory profileFactory, Languages languages) {
+  public BackupAction(QProfileBackuper backuper, QProfileFactory profileFactory, Languages languages) {
     this.backuper = backuper;
-    this.dbClient = dbClient;
     this.profileFactory = profileFactory;
     this.languages = languages;
   }
@@ -59,23 +53,17 @@ public class BackupAction implements QProfileWsAction {
       .setResponseExample(getClass().getResource("backup-example.xml"))
       .setHandler(this);
 
-    QProfileIdentificationParamUtils.defineProfileParams(backup, languages);
+    QProfileRef.defineParams(backup, languages);
   }
 
   @Override
   public void handle(Request request, Response response) throws Exception {
     Stream stream = response.stream();
     stream.setMediaType(MediaTypes.XML);
-    DbSession dbSession = dbClient.openSession(false);
-    OutputStreamWriter writer = new OutputStreamWriter(stream.output(), StandardCharsets.UTF_8);
-    try {
-      String profileKey = QProfileIdentificationParamUtils.getProfileKeyFromParameters(request, profileFactory, dbSession);
-      response.setHeader("Content-Disposition", String.format("attachment; filename=%s.xml", profileKey));
-      backuper.backup(profileKey, writer);
-    } finally {
-      dbSession.close();
-      IOUtils.closeQuietly(writer);
+    try (OutputStreamWriter writer = new OutputStreamWriter(stream.output(), StandardCharsets.UTF_8)) {
+      QualityProfileDto profile = profileFactory.find(QProfileRef.from(request));
+      response.setHeader("Content-Disposition", String.format("attachment; filename=%s.xml", profile.getKee()));
+      backuper.backup(profile.getKee(), writer);
     }
   }
-
 }
index c9758089dc4b7a66a512088f4b29d43ce579db8a..4ea28a6e67dea6441260a8f4cbee4c40b1724ed0 100644 (file)
  */
 package org.sonar.server.qualityprofile.ws;
 
-import com.google.common.base.Preconditions;
 import org.sonar.api.resources.Languages;
 import org.sonar.api.server.ws.Request;
 import org.sonar.api.server.ws.Response;
 import org.sonar.api.server.ws.WebService.NewAction;
 import org.sonar.api.server.ws.WebService.NewController;
 import org.sonar.core.permission.GlobalPermissions;
-import org.sonar.db.DbClient;
-import org.sonar.db.DbSession;
+import org.sonar.db.qualityprofile.QualityProfileDto;
 import org.sonar.server.qualityprofile.QProfileFactory;
+import org.sonar.server.qualityprofile.QProfileRef;
 import org.sonar.server.qualityprofile.RuleActivator;
 import org.sonar.server.user.UserSession;
 
@@ -37,20 +36,14 @@ import static org.apache.commons.lang.StringUtils.isEmpty;
 public class ChangeParentAction implements QProfileWsAction {
 
   private static final String PARAM_PARENT_KEY = "parentKey";
-
   private static final String PARAM_PARENT_NAME = "parentName";
 
-  private final DbClient dbClient;
-
   private final RuleActivator ruleActivator;
-
   private final QProfileFactory profileFactory;
-
   private final Languages languages;
   private final UserSession userSession;
 
-  public ChangeParentAction(DbClient dbClient, RuleActivator ruleActivator, QProfileFactory profileFactory, Languages languages, UserSession userSession) {
-    this.dbClient = dbClient;
+  public ChangeParentAction(RuleActivator ruleActivator, QProfileFactory profileFactory, Languages languages, UserSession userSession) {
     this.ruleActivator = ruleActivator;
     this.profileFactory = profileFactory;
     this.languages = languages;
@@ -65,7 +58,7 @@ public class ChangeParentAction implements QProfileWsAction {
       .setDescription("Change a quality profile's parent.")
       .setHandler(this);
 
-    QProfileIdentificationParamUtils.defineProfileParams(inheritance, languages);
+    QProfileRef.defineParams(inheritance, languages);
 
     inheritance.createParam(PARAM_PARENT_KEY)
       .setDescription("The key of the new parent profile. If this parameter is set, parentName must not be set. " +
@@ -82,36 +75,15 @@ public class ChangeParentAction implements QProfileWsAction {
   public void handle(Request request, Response response) throws Exception {
     userSession.checkLoggedIn().checkPermission(GlobalPermissions.QUALITY_PROFILE_ADMIN);
 
-    DbSession session = dbClient.openSession(false);
-    try {
-      String profileKey = QProfileIdentificationParamUtils.getProfileKeyFromParameters(request, profileFactory, session);
-      String parentKey = getParentKeyFromParameters(request, profileFactory, session);
-
-      ruleActivator.setParent(profileKey, parentKey);
-
-      response.noContent();
-    } finally {
-      session.close();
-    }
-  }
-
-  private static String getParentKeyFromParameters(Request request, QProfileFactory profileFactory, DbSession session) {
-    String language = request.param(QProfileIdentificationParamUtils.PARAM_LANGUAGE);
-    String parentName = request.param(PARAM_PARENT_NAME);
+    QualityProfileDto profile = profileFactory.find(QProfileRef.from(request));
     String parentKey = request.param(PARAM_PARENT_KEY);
-
-    Preconditions.checkArgument(
-      isEmpty(parentName) || isEmpty(parentKey), "parentKey and parentName cannot be used simultaneously");
-
-    if (isEmpty(parentKey)) {
-      if (!isEmpty(parentName)) {
-        parentKey = QProfileIdentificationParamUtils.getProfileKeyFromLanguageAndName(language, parentName, profileFactory, session);
-      } else {
-        // Empty parent key is treated as "no more parent"
-        parentKey = null;
-      }
+    String parentName = request.param(PARAM_PARENT_NAME);
+    if (isEmpty(parentKey) && isEmpty(parentName)) {
+      ruleActivator.setParent(profile.getKey(), null);
+    } else {
+      QualityProfileDto parent = profileFactory.find(QProfileRef.from(parentKey, request.param(QProfileRef.PARAM_LANGUAGE), parentName));
+      ruleActivator.setParent(profile.getKey(), parent.getKey());
     }
-
-    return parentKey;
+    response.noContent();
   }
 }
index 968259448d928b4d65802d2a291b686516c675d4..e430c9081556cf5b38a602b1ca13cf82f620c3d3 100644 (file)
@@ -21,6 +21,7 @@ package org.sonar.server.qualityprofile.ws;
 
 import java.util.Date;
 import java.util.Map;
+import org.sonar.api.resources.Languages;
 import org.sonar.api.server.ws.Request;
 import org.sonar.api.server.ws.Response;
 import org.sonar.api.server.ws.WebService.NewAction;
@@ -30,6 +31,8 @@ import org.sonar.api.utils.DateUtils;
 import org.sonar.api.utils.text.JsonWriter;
 import org.sonar.db.qualityprofile.QProfileChangeQuery;
 import org.sonar.db.qualityprofile.QualityProfileDto;
+import org.sonar.server.qualityprofile.QProfileFactory;
+import org.sonar.server.qualityprofile.QProfileRef;
 
 import static org.sonar.server.es.SearchOptions.MAX_LIMIT;
 
@@ -39,11 +42,13 @@ public class ChangelogAction implements QProfileWsAction {
   private static final String PARAM_TO = "to";
 
   private final ChangelogLoader changelogLoader;
-  private final QProfileFinder profileFinder;
+  private final QProfileFactory profileFactory;
+  private final Languages languages;
 
-  public ChangelogAction(ChangelogLoader changelogLoader, QProfileFinder profileFinder) {
+  public ChangelogAction(ChangelogLoader changelogLoader, QProfileFactory profileFactory, Languages languages) {
     this.changelogLoader = changelogLoader;
-    this.profileFinder = profileFinder;
+    this.profileFactory = profileFactory;
+    this.languages = languages;
   }
 
   @Override
@@ -55,7 +60,7 @@ public class ChangelogAction implements QProfileWsAction {
       .setHandler(this)
       .setResponseExample(getClass().getResource("example-changelog.json"));
 
-    profileFinder.defineProfileParams(wsAction);
+    QProfileRef.defineParams(wsAction, languages);
 
     wsAction.addPagingParams(50, MAX_LIMIT);
 
@@ -70,7 +75,7 @@ public class ChangelogAction implements QProfileWsAction {
 
   @Override
   public void handle(Request request, Response response) throws Exception {
-    QualityProfileDto profile = profileFinder.find(request);
+    QualityProfileDto profile = profileFactory.find(QProfileRef.from(request));
 
     QProfileChangeQuery query = new QProfileChangeQuery(profile.getKey());
     Date since = request.paramAsDateTime(PARAM_SINCE);
index 75ddc8cb8ae34694811395c899d629f25f2cfdaf..999c9446126ce305e801fd65fa621eeadfaaf635 100644 (file)
@@ -27,7 +27,9 @@ import org.sonar.api.server.ws.WebService.NewController;
 import org.sonar.core.permission.GlobalPermissions;
 import org.sonar.db.DbClient;
 import org.sonar.db.DbSession;
+import org.sonar.db.qualityprofile.QualityProfileDto;
 import org.sonar.server.qualityprofile.QProfileFactory;
+import org.sonar.server.qualityprofile.QProfileRef;
 import org.sonar.server.user.UserSession;
 
 public class DeleteAction implements QProfileWsAction {
@@ -53,7 +55,7 @@ public class DeleteAction implements QProfileWsAction {
       .setPost(true)
       .setHandler(this);
 
-    QProfileIdentificationParamUtils.defineProfileParams(action, languages);
+    QProfileRef.defineParams(action, languages);
   }
 
   @Override
@@ -61,14 +63,10 @@ public class DeleteAction implements QProfileWsAction {
     userSession.checkLoggedIn();
     userSession.checkPermission(GlobalPermissions.QUALITY_PROFILE_ADMIN);
 
-    DbSession session = dbClient.openSession(false);
-    try {
-      String profileKey = QProfileIdentificationParamUtils.getProfileKeyFromParameters(request, profileFactory, session);
-      profileFactory.delete(session, profileKey, false);
-
-      session.commit();
-    } finally {
-      session.close();
+    try (DbSession dbSession = dbClient.openSession(false)) {
+      QualityProfileDto profile = profileFactory.find(QProfileRef.from(request), dbSession);
+      profileFactory.delete(dbSession, profile.getKey(), false);
+      dbSession.commit();
     }
 
     response.noContent();
index a6e38d3a11355bda7e0f46544fd457d752cf95c9..324a862265ee45ee5098615de9b4ae8d123b62bf 100644 (file)
@@ -32,11 +32,11 @@ import org.sonar.api.utils.text.JsonWriter;
 import org.sonar.db.DbClient;
 import org.sonar.db.DbSession;
 import org.sonar.db.qualityprofile.QualityProfileDto;
-import org.sonar.server.exceptions.NotFoundException;
 import org.sonar.server.qualityprofile.QProfile;
 import org.sonar.server.qualityprofile.QProfileFactory;
 import org.sonar.server.qualityprofile.QProfileLoader;
 import org.sonar.server.qualityprofile.QProfileLookup;
+import org.sonar.server.qualityprofile.QProfileRef;
 import org.sonar.server.rule.index.RuleIndexDefinition;
 import org.sonar.server.search.FacetValue;
 
@@ -45,13 +45,9 @@ import static org.sonar.server.qualityprofile.index.ActiveRuleIndex.COUNT_ACTIVE
 public class InheritanceAction implements QProfileWsAction {
 
   private final DbClient dbClient;
-
   private final QProfileLookup profileLookup;
-
   private final QProfileLoader profileLoader;
-
   private final QProfileFactory profileFactory;
-
   private final Languages languages;
 
   public InheritanceAction(DbClient dbClient, QProfileLookup profileLookup, QProfileLoader profileLoader, QProfileFactory profileFactory, Languages languages) {
@@ -70,26 +66,21 @@ public class InheritanceAction implements QProfileWsAction {
       .setHandler(this)
       .setResponseExample(getClass().getResource("example-inheritance.json"));
 
-    QProfileIdentificationParamUtils.defineProfileParams(inheritance, languages);
+    QProfileRef.defineParams(inheritance, languages);
   }
 
   @Override
   public void handle(Request request, Response response) throws Exception {
-    DbSession session = dbClient.openSession(false);
+    DbSession dbSession = dbClient.openSession(false);
     try {
-      String profileKey = QProfileIdentificationParamUtils.getProfileKeyFromParameters(request, profileFactory, session);
-      QualityProfileDto profile = dbClient.qualityProfileDao().selectByKey(session, profileKey);
-      if (profile == null) {
-        throw new NotFoundException(String.format("Could not find a quality profile with key %s", profileKey));
-      }
-
-      List<QProfile> ancestors = profileLookup.ancestors(profile, session);
-      List<QualityProfileDto> children = dbClient.qualityProfileDao().selectChildren(session, profileKey);
+      QualityProfileDto profile = profileFactory.find(QProfileRef.from(request), dbSession);
+      List<QProfile> ancestors = profileLookup.ancestors(profile, dbSession);
+      List<QualityProfileDto> children = dbClient.qualityProfileDao().selectChildren(dbSession, profile.getKey());
       Map<String, Multimap<String, FacetValue>> profileStats = profileLoader.getAllProfileStats();
 
       writeResponse(response.newJsonWriter(), profile, ancestors, children, profileStats);
     } finally {
-      session.close();
+      dbSession.close();
     }
   }
 
diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/QProfileFinder.java b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/QProfileFinder.java
deleted file mode 100644 (file)
index b2bd1b2..0000000
+++ /dev/null
@@ -1,95 +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.qualityprofile.ws;
-
-import org.sonar.api.resources.Languages;
-import org.sonar.api.server.ws.Request;
-import org.sonar.api.server.ws.WebService;
-import org.sonar.db.DbClient;
-import org.sonar.db.DbSession;
-import org.sonar.db.qualityprofile.QualityProfileDto;
-import org.sonar.server.exceptions.NotFoundException;
-import org.sonar.server.util.LanguageParamUtils;
-
-import static com.google.common.base.Preconditions.checkArgument;
-import static java.lang.String.format;
-import static org.apache.commons.lang.StringUtils.isEmpty;
-
-public class QProfileFinder {
-
-  private final DbClient dbClient;
-  private final Languages languages;
-
-  public QProfileFinder(DbClient dbClient, Languages languages) {
-    this.dbClient = dbClient;
-    this.languages = languages;
-  }
-
-  public void defineProfileParams(WebService.NewAction action) {
-    action.createParam(QProfileIdentificationParamUtils.PARAM_PROFILE_KEY)
-      .setDescription("A quality profile key. Either this parameter, or a combination of profileName + language must be set.")
-      .setExampleValue("sonar-way-java-12345");
-    action.createParam(QProfileIdentificationParamUtils.PARAM_PROFILE_NAME)
-      .setDescription("A quality profile name. If this parameter is set, profileKey must not be set and language must be set to disambiguate.")
-      .setExampleValue("Sonar way");
-    action.createParam(QProfileIdentificationParamUtils.PARAM_LANGUAGE)
-      .setDescription("A quality profile language. If this parameter is set, profileKey must not be set and profileName must be set to disambiguate.")
-      .setPossibleValues(LanguageParamUtils.getLanguageKeys(languages))
-      .setExampleValue("js");
-  }
-
-  public QualityProfileDto find(Request request) {
-    try (DbSession dbSession = dbClient.openSession(false)) {
-      return find(request, dbSession);
-    }
-  }
-
-  public QualityProfileDto find(Request request, DbSession dbSession) {
-    String language = request.param(QProfileIdentificationParamUtils.PARAM_LANGUAGE);
-    String profileName = request.param(QProfileIdentificationParamUtils.PARAM_PROFILE_NAME);
-    String profileKey = request.param(QProfileIdentificationParamUtils.PARAM_PROFILE_KEY);
-
-    checkArgument(
-      (!isEmpty(language) && !isEmpty(profileName)) ^ !isEmpty(profileKey), "Either profileKey or profileName + language must be set");
-
-    if (profileKey != null) {
-      return findByKey(dbSession, profileKey);
-    }
-    return findByName(dbSession, language, profileName);
-  }
-
-  private QualityProfileDto findByKey(DbSession dbSession, String profileKey) {
-    QualityProfileDto profile;
-    profile = dbClient.qualityProfileDao().selectByKey(dbSession, profileKey);
-    if (profile == null) {
-      throw new NotFoundException(format("Unable to find a profile for with key '%s'", profileKey));
-    }
-    return profile;
-  }
-
-  private QualityProfileDto findByName(DbSession dbSession, String language, String profileName) {
-    QualityProfileDto profile;
-    profile = dbClient.qualityProfileDao().selectByNameAndLanguage(profileName, language, dbSession);
-    if (profile == null) {
-      throw new NotFoundException(format("Unable to find a profile for language '%s' with name '%s'", language, profileName));
-    }
-    return profile;
-  }
-}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/QProfileIdentificationParamUtils.java b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/QProfileIdentificationParamUtils.java
deleted file mode 100644 (file)
index 0a4452c..0000000
+++ /dev/null
@@ -1,79 +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.qualityprofile.ws;
-
-import com.google.common.base.Preconditions;
-import org.sonar.api.resources.Languages;
-import org.sonar.api.server.ws.Request;
-import org.sonar.api.server.ws.WebService.NewAction;
-import org.sonar.db.DbSession;
-import org.sonar.db.qualityprofile.QualityProfileDto;
-import org.sonar.server.exceptions.NotFoundException;
-import org.sonar.server.qualityprofile.QProfileFactory;
-import org.sonar.server.util.LanguageParamUtils;
-
-import static org.apache.commons.lang.StringUtils.isEmpty;
-
-public class QProfileIdentificationParamUtils {
-
-  public static final String PARAM_LANGUAGE = "language";
-  public static final String PARAM_PROFILE_NAME = "profileName";
-  public static final String PARAM_PROFILE_KEY = "profileKey";
-
-  private QProfileIdentificationParamUtils() {
-    // Utility class
-  }
-
-  public static void defineProfileParams(NewAction action, Languages languages) {
-    action.createParam(PARAM_PROFILE_KEY)
-      .setDescription("A quality profile key. Either this parameter, or a combination of profileName + language must be set.")
-      .setExampleValue("sonar-way-java-12345");
-    action.createParam(PARAM_PROFILE_NAME)
-      .setDescription("A quality profile name. If this parameter is set, profileKey must not be set and language must be set to disambiguate.")
-      .setExampleValue("Sonar way");
-    action.createParam(PARAM_LANGUAGE)
-      .setDescription("A quality profile language. If this parameter is set, profileKey must not be set and profileName must be set to disambiguate.")
-      .setPossibleValues(LanguageParamUtils.getLanguageKeys(languages))
-      .setExampleValue("js");
-  }
-
-  public static String getProfileKeyFromParameters(Request request, QProfileFactory profileFactory, DbSession session) {
-    String language = request.param(PARAM_LANGUAGE);
-    String profileName = request.param(PARAM_PROFILE_NAME);
-    String profileKey = request.param(PARAM_PROFILE_KEY);
-
-    Preconditions.checkArgument(
-      (!isEmpty(language) && !isEmpty(profileName)) ^ !isEmpty(profileKey), "Either profileKey or profileName + language must be set");
-
-    if (profileKey == null) {
-      profileKey = getProfileKeyFromLanguageAndName(language, profileName, profileFactory, session);
-    }
-    return profileKey;
-  }
-
-  public static String getProfileKeyFromLanguageAndName(String language, String profileName, QProfileFactory profileFactory, DbSession session) {
-    QualityProfileDto profile = profileFactory.getByNameAndLanguage(session, profileName, language);
-    if (profile == null) {
-      throw new NotFoundException(String.format("Unable to find a profile for language '%s' with name '%s'", language, profileName));
-    }
-    return profile.getKey();
-  }
-
-}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileFactoryTest.java b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileFactoryTest.java
new file mode 100644 (file)
index 0000000..89ab1c1
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * 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.qualityprofile;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.sonar.api.utils.System2;
+import org.sonar.db.DbTester;
+import org.sonar.db.qualityprofile.QualityProfileDto;
+import org.sonar.db.qualityprofile.QualityProfileTesting;
+import org.sonar.server.exceptions.NotFoundException;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class QProfileFactoryTest {
+
+  @Rule
+  public DbTester dbTester = DbTester.create(System2.INSTANCE);
+
+  @Rule
+  public ExpectedException expectedException = ExpectedException.none();
+
+  private QProfileFactory underTest = new QProfileFactory(dbTester.getDbClient());
+
+  @Before
+  public void setUp() throws Exception {
+    QualityProfileDto dto = QualityProfileTesting.newQualityProfileDto().setKey("sw").setName("Sonar way").setLanguage("js");
+    dbTester.getDbClient().qualityProfileDao().insert(dbTester.getSession(), dto);
+    dbTester.commit();
+  }
+
+  @Test
+  public void find_profile_by_key() {
+    QualityProfileDto profile = underTest.find(QProfileRef.fromKey("sw"));
+    assertThat(profile.getKey()).isEqualTo("sw");
+    assertThat(profile.getLanguage()).isEqualTo("js");
+    assertThat(profile.getName()).isEqualTo("Sonar way");
+  }
+
+  @Test
+  public void find_profile_by_name() {
+    QualityProfileDto profile = underTest.find(QProfileRef.fromName("js", "Sonar way"));
+    assertThat(profile.getKey()).isEqualTo("sw");
+    assertThat(profile.getLanguage()).isEqualTo("js");
+    assertThat(profile.getName()).isEqualTo("Sonar way");
+  }
+
+  @Test
+  public void throw_NFE_if_profile_key_does_not_exist() {
+    expectedException.expect(NotFoundException.class);
+
+    underTest.find(QProfileRef.fromKey("missing"));
+  }
+
+  @Test
+  public void throw_NFE_if_profile_name_does_not_exist() {
+    expectedException.expect(NotFoundException.class);
+
+    underTest.find(QProfileRef.fromName("js", "Missing"));
+  }
+
+}
index a8cadafaa6e4be877c6ea5f6ceadf0b9b6514ed5..c60f27fee7372e10d5fd25a0351592134398e2f4 100644 (file)
@@ -21,20 +21,16 @@ package org.sonar.server.qualityprofile.ws;
 
 import java.io.PrintWriter;
 import java.io.Writer;
-import org.junit.Before;
-import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.mockito.Mock;
 import org.mockito.invocation.InvocationOnMock;
 import org.mockito.runners.MockitoJUnitRunner;
 import org.mockito.stubbing.Answer;
-import org.sonar.api.utils.System2;
-import org.sonar.db.DbClient;
-import org.sonar.db.DbTester;
+import org.sonar.db.qualityprofile.QualityProfileTesting;
 import org.sonar.server.language.LanguageTesting;
 import org.sonar.server.qualityprofile.QProfileBackuper;
 import org.sonar.server.qualityprofile.QProfileFactory;
+import org.sonar.server.qualityprofile.QProfileRef;
 import org.sonar.server.ws.WsTester;
 import org.sonar.server.ws.WsTester.Result;
 
@@ -43,33 +39,24 @@ import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
 
 @RunWith(MockitoJUnitRunner.class)
 public class BackupActionTest {
 
-  @Rule
-  public DbTester db = DbTester.create(System2.INSTANCE);
+  private static final String SOME_PROFILE_KEY = "polop-palap-xoo-12345";
 
-  // TODO Replace with proper DbTester + EsTester medium test once DaoV2 is removed
-  @Mock
-  private QProfileBackuper backuper;
-
-  private WsTester tester;
-
-  @Before
-  public void setUp() {
-    DbClient dbClient = new DbClient(db.database(), db.myBatis());
-
-    tester = new WsTester(new QProfilesWs(
-      mock(RuleActivationActions.class),
-      mock(BulkRuleActivationActions.class),
-      mock(ProjectAssociationActions.class),
-      new BackupAction(backuper, dbClient, new QProfileFactory(dbClient), LanguageTesting.newLanguages("xoo"))));
-  }
+  private QProfileBackuper backuper = mock(QProfileBackuper.class);
+  private QProfileFactory profileFactory = mock(QProfileFactory.class);
+  private WsTester tester = new WsTester(new QProfilesWs(
+    mock(RuleActivationActions.class),
+    mock(BulkRuleActivationActions.class),
+    mock(ProjectAssociationActions.class),
+    new BackupAction(backuper, profileFactory, LanguageTesting.newLanguages("xoo"))));
 
   @Test
   public void backup_profile() throws Exception {
-    String profileKey = "polop-palap-xoo-12345";
+    when(profileFactory.find(QProfileRef.fromKey(SOME_PROFILE_KEY))).thenReturn(QualityProfileTesting.newQualityProfileDto().setKey(SOME_PROFILE_KEY));
 
     final String response = "<polop><palap/></polop>";
     doAnswer(new Answer<Void>() {
@@ -80,11 +67,11 @@ public class BackupActionTest {
         w.close();
         return null;
       }
-    }).when(backuper).backup(eq(profileKey), any(Writer.class));
+    }).when(backuper).backup(eq(SOME_PROFILE_KEY), any(Writer.class));
 
-    Result result = tester.newGetRequest("api/qualityprofiles", "backup").setParam("profileKey", profileKey).execute();
+    Result result = tester.newGetRequest("api/qualityprofiles", "backup").setParam(QProfileRef.PARAM_PROFILE_KEY, SOME_PROFILE_KEY).execute();
     assertThat(result.outputAsString()).isEqualTo(response);
-    result.assertHeader("Content-Disposition", "attachment; filename=polop-palap-xoo-12345.xml");
+    result.assertHeader("Content-Disposition", "attachment; filename=" + SOME_PROFILE_KEY + ".xml");
   }
 
   @Test(expected = IllegalArgumentException.class)
index bc0019df2e037dfbd26cb6ed273f3cbcaa39fe74..79f3f866b381591efbbb9f8564fd5541c93455cb 100644 (file)
@@ -31,7 +31,6 @@ import org.sonar.api.rule.Severity;
 import org.sonar.core.permission.GlobalPermissions;
 import org.sonar.db.DbClient;
 import org.sonar.db.DbSession;
-import org.sonar.db.RowNotFoundException;
 import org.sonar.db.qualityprofile.ActiveRuleDto;
 import org.sonar.db.qualityprofile.QualityProfileDto;
 import org.sonar.db.rule.RuleDto;
@@ -39,6 +38,7 @@ import org.sonar.db.rule.RuleTesting;
 import org.sonar.server.es.SearchOptions;
 import org.sonar.server.exceptions.ForbiddenException;
 import org.sonar.server.qualityprofile.QProfileName;
+import org.sonar.server.qualityprofile.QProfileRef;
 import org.sonar.server.qualityprofile.QProfileTesting;
 import org.sonar.server.qualityprofile.RuleActivator;
 import org.sonar.server.qualityprofile.index.ActiveRuleIndexer;
@@ -100,7 +100,7 @@ public class ChangeParentActionMediumTest {
 
     // Set parent
     wsTester.newPostRequest(QProfilesWs.API_ENDPOINT, "change_parent")
-      .setParam(QProfileIdentificationParamUtils.PARAM_PROFILE_KEY, child.getKey())
+      .setParam(QProfileRef.PARAM_PROFILE_KEY, child.getKey())
       .setParam("parentKey", parent1.getKey())
       .execute();
     session.clearCache();
@@ -133,7 +133,7 @@ public class ChangeParentActionMediumTest {
 
     // Set parent 2 through WS
     wsTester.newPostRequest(QProfilesWs.API_ENDPOINT, "change_parent")
-      .setParam(QProfileIdentificationParamUtils.PARAM_PROFILE_KEY, child.getKey())
+      .setParam(QProfileRef.PARAM_PROFILE_KEY, child.getKey())
       .setParam("parentKey", parent2.getKey())
       .execute();
     session.clearCache();
@@ -163,7 +163,7 @@ public class ChangeParentActionMediumTest {
 
     // Remove parent through WS
     wsTester.newPostRequest(QProfilesWs.API_ENDPOINT, "change_parent")
-      .setParam(QProfileIdentificationParamUtils.PARAM_PROFILE_KEY, child.getKey())
+      .setParam(QProfileRef.PARAM_PROFILE_KEY, child.getKey())
       .execute();
     session.clearCache();
 
@@ -192,8 +192,8 @@ public class ChangeParentActionMediumTest {
 
     // 1. Set parent 1
     wsTester.newPostRequest(QProfilesWs.API_ENDPOINT, "change_parent")
-      .setParam(QProfileIdentificationParamUtils.PARAM_LANGUAGE, "xoo")
-      .setParam(QProfileIdentificationParamUtils.PARAM_PROFILE_NAME, child.getName())
+      .setParam(QProfileRef.PARAM_LANGUAGE, "xoo")
+      .setParam(QProfileRef.PARAM_PROFILE_NAME, child.getName())
       .setParam("parentName", parent1.getName())
       .execute();
     session.clearCache();
@@ -206,8 +206,8 @@ public class ChangeParentActionMediumTest {
 
     // 2. Set parent 2
     wsTester.newPostRequest(QProfilesWs.API_ENDPOINT, "change_parent")
-      .setParam(QProfileIdentificationParamUtils.PARAM_LANGUAGE, "xoo")
-      .setParam(QProfileIdentificationParamUtils.PARAM_PROFILE_NAME, child.getName())
+      .setParam(QProfileRef.PARAM_LANGUAGE, "xoo")
+      .setParam(QProfileRef.PARAM_PROFILE_NAME, child.getName())
       .setParam("parentName", parent2.getName())
       .execute();
     session.clearCache();
@@ -219,8 +219,8 @@ public class ChangeParentActionMediumTest {
 
     // 3. Remove parent
     wsTester.newPostRequest(QProfilesWs.API_ENDPOINT, "change_parent")
-      .setParam(QProfileIdentificationParamUtils.PARAM_LANGUAGE, "xoo")
-      .setParam(QProfileIdentificationParamUtils.PARAM_PROFILE_NAME, child.getName())
+      .setParam(QProfileRef.PARAM_LANGUAGE, "xoo")
+      .setParam(QProfileRef.PARAM_PROFILE_NAME, child.getName())
       .setParam("parentName", "")
       .execute();
     session.clearCache();
@@ -250,7 +250,7 @@ public class ChangeParentActionMediumTest {
 
     // Remove parent
     wsTester.newPostRequest(QProfilesWs.API_ENDPOINT, "change_parent")
-      .setParam(QProfileIdentificationParamUtils.PARAM_PROFILE_KEY, child.getKey())
+      .setParam(QProfileRef.PARAM_PROFILE_KEY, child.getKey())
       .setParam("parentKey", "")
       .execute();
     session.clearCache();
@@ -270,13 +270,13 @@ public class ChangeParentActionMediumTest {
     assertThat(ruleIndex.search(new RuleQuery().setActivation(true).setQProfileKey(child.getKey()), new SearchOptions()).getIds()).isEmpty();
 
     wsTester.newPostRequest(QProfilesWs.API_ENDPOINT, "change_parent")
-      .setParam(QProfileIdentificationParamUtils.PARAM_PROFILE_KEY, child.getKee())
+      .setParam(QProfileRef.PARAM_PROFILE_KEY, child.getKee())
       .setParam("parentName", "polop")
       .setParam("parentKey", "palap")
       .execute();
   }
 
-  @Test(expected = RowNotFoundException.class)
+  @Test(expected = IllegalArgumentException.class)
   public void fail_if_profile_key_and_name_both_set() throws Exception {
     QualityProfileDto child = createProfile("xoo", "Child");
     session.commit();
@@ -285,8 +285,8 @@ public class ChangeParentActionMediumTest {
     assertThat(ruleIndex.search(new RuleQuery().setActivation(true).setQProfileKey(child.getKey()), new SearchOptions()).getIds()).isEmpty();
 
     wsTester.newPostRequest(QProfilesWs.API_ENDPOINT, "change_parent")
-      .setParam(QProfileIdentificationParamUtils.PARAM_PROFILE_KEY, child.getKee())
-      .setParam(QProfileIdentificationParamUtils.PARAM_PROFILE_NAME, child.getName())
+      .setParam(QProfileRef.PARAM_PROFILE_KEY, child.getKee())
+      .setParam(QProfileRef.PARAM_PROFILE_NAME, child.getName())
       .setParam("parentKey", "palap")
       .execute();
   }
@@ -295,7 +295,7 @@ public class ChangeParentActionMediumTest {
   public void fail_if_missing_permission() throws Exception {
     userSessionRule.login("anakin");
     wsTester.newPostRequest(QProfilesWs.API_ENDPOINT, "change_parent")
-      .setParam(QProfileIdentificationParamUtils.PARAM_PROFILE_KEY, "polop")
+      .setParam(QProfileRef.PARAM_PROFILE_KEY, "polop")
       .setParam("parentKey", "pulup")
       .execute();
   }
index c67888895c19c1e027687f6d1a7afd7329d4ca34..254d01004af57967238670d44be17e39b2429ab6 100644 (file)
@@ -24,19 +24,23 @@ import java.util.List;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
-import org.sonar.api.server.ws.Request;
+import org.sonar.api.resources.Languages;
 import org.sonar.api.utils.System2;
 import org.sonar.db.DbTester;
 import org.sonar.db.qualityprofile.QProfileChangeQuery;
 import org.sonar.db.rule.RuleTesting;
 import org.sonar.server.exceptions.NotFoundException;
+import org.sonar.server.qualityprofile.QProfileFactory;
+import org.sonar.server.qualityprofile.QProfileRef;
 import org.sonar.server.qualityprofile.QProfileTesting;
 import org.sonar.server.ws.WsTester;
 
 import static java.util.Arrays.asList;
 import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
+import static org.sonar.server.qualityprofile.QProfileRef.PARAM_PROFILE_KEY;
 import static org.sonar.server.qualityprofile.QProfileTesting.XOO_P1_KEY;
 
 public class ChangelogActionTest {
@@ -48,52 +52,52 @@ public class ChangelogActionTest {
 
   private WsTester wsTester;
   private ChangelogLoader changelogLoader = mock(ChangelogLoader.class);
-  private QProfileFinder profileFinder = mock(QProfileFinder.class);
+  private QProfileFactory profileFactory = mock(QProfileFactory.class);
 
   @Before
   public void before() {
     wsTester = new WsTester(new QProfilesWs(mock(RuleActivationActions.class), mock(BulkRuleActivationActions.class), mock(ProjectAssociationActions.class),
-      new ChangelogAction(changelogLoader, profileFinder)));
+      new ChangelogAction(changelogLoader, profileFactory, new Languages())));
   }
 
   @Test
   public void changelog_empty() throws Exception {
-    when(profileFinder.find(any(Request.class))).thenReturn(QProfileTesting.newXooP1());
+    when(profileFactory.find(eq(QProfileRef.fromKey(XOO_P1_KEY)))).thenReturn(QProfileTesting.newXooP1());
     when(changelogLoader.load(any(QProfileChangeQuery.class))).thenReturn(new ChangelogLoader.Changelog(0, Collections.emptyList()));
 
-    wsTester.newGetRequest(QProfilesWs.API_ENDPOINT, "changelog").setParam("profileKey", XOO_P1_KEY)
+    wsTester.newGetRequest(QProfilesWs.API_ENDPOINT, "changelog").setParam(PARAM_PROFILE_KEY, XOO_P1_KEY)
       .execute().assertJson(getClass(), "changelog_empty.json");
   }
 
   @Test
   public void changelog_nominal() throws Exception {
-    when(profileFinder.find(any(Request.class))).thenReturn(QProfileTesting.newXooP1());
+    when(profileFactory.find(eq(QProfileRef.fromKey(XOO_P1_KEY)))).thenReturn(QProfileTesting.newXooP1());
     ChangelogLoader.Change change1 = new ChangelogLoader.Change("C1", "ACTIVATED", A_DATE, null, null, null, null, null, null);
     ChangelogLoader.Change change2 = new ChangelogLoader.Change("C2", "ACTIVATED", A_DATE + 10, null, null, null, null, null, null);
     List<ChangelogLoader.Change> changes = asList(change1, change2);
     when(changelogLoader.load(any(QProfileChangeQuery.class))).thenReturn(new ChangelogLoader.Changelog(10, changes));
 
-    wsTester.newGetRequest(QProfilesWs.API_ENDPOINT, "changelog").setParam("profileKey", XOO_P1_KEY)
+    wsTester.newGetRequest(QProfilesWs.API_ENDPOINT, "changelog").setParam(PARAM_PROFILE_KEY, XOO_P1_KEY)
       .execute().assertJson(getClass(), "changelog_nominal.json");
   }
 
   @Test
   public void changelog_with_all_fields() throws Exception {
-    when(profileFinder.find(any(Request.class))).thenReturn(QProfileTesting.newXooP1());
+    when(profileFactory.find(eq(QProfileRef.fromKey(XOO_P1_KEY)))).thenReturn(QProfileTesting.newXooP1());
     ChangelogLoader.Change change1 = new ChangelogLoader.Change("C1", "ACTIVATED", A_DATE, "MAJOR", "marcel", "Marcel", "INHERITED", RuleTesting.XOO_X1, "X One");
     change1.getParams().put("foo", "foo_value");
     change1.getParams().put("bar", "bar_value");
     List<ChangelogLoader.Change> changes = asList(change1);
     when(changelogLoader.load(any(QProfileChangeQuery.class))).thenReturn(new ChangelogLoader.Changelog(10, changes));
 
-    wsTester.newGetRequest(QProfilesWs.API_ENDPOINT, "changelog").setParam("profileKey", XOO_P1_KEY)
+    wsTester.newGetRequest(QProfilesWs.API_ENDPOINT, "changelog").setParam(PARAM_PROFILE_KEY, XOO_P1_KEY)
       .execute().assertJson(getClass(), "changelog_full.json");
   }
 
   @Test(expected = NotFoundException.class)
   public void fail_on_unknown_profile() throws Exception {
-    when(profileFinder.find(any(Request.class))).thenThrow(new NotFoundException("Profile not found"));
+    when(profileFactory.find(eq(QProfileRef.fromKey(XOO_P1_KEY)))).thenThrow(new NotFoundException("Profile not found"));
 
-    wsTester.newGetRequest(QProfilesWs.API_ENDPOINT, "changelog").setParam("profileKey", "unknown-profile").execute();
+    wsTester.newGetRequest(QProfilesWs.API_ENDPOINT, "changelog").setParam(PARAM_PROFILE_KEY, XOO_P1_KEY).execute();
   }
 }
diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/QProfileFactoryTest.java b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/QProfileFactoryTest.java
new file mode 100644 (file)
index 0000000..e59d6df
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * 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.qualityprofile.ws;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.sonar.api.utils.System2;
+import org.sonar.db.DbTester;
+import org.sonar.db.qualityprofile.QualityProfileDto;
+import org.sonar.db.qualityprofile.QualityProfileTesting;
+import org.sonar.server.exceptions.NotFoundException;
+import org.sonar.server.qualityprofile.QProfileFactory;
+import org.sonar.server.qualityprofile.QProfileRef;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class QProfileFactoryTest {
+
+  @Rule
+  public DbTester dbTester = DbTester.create(System2.INSTANCE);
+
+  @Rule
+  public ExpectedException expectedException = ExpectedException.none();
+
+  private QProfileFactory underTest = new QProfileFactory(dbTester.getDbClient());
+
+  @Before
+  public void setUp() throws Exception {
+    QualityProfileDto dto = QualityProfileTesting.newQualityProfileDto().setKey("sw").setName("Sonar way").setLanguage("js");
+    dbTester.getDbClient().qualityProfileDao().insert(dbTester.getSession(), dto);
+    dbTester.commit();
+  }
+
+  @Test
+  public void find_profile_by_key() {
+    QualityProfileDto profile = underTest.find(QProfileRef.fromKey("sw"));
+    assertThat(profile.getKey()).isEqualTo("sw");
+    assertThat(profile.getLanguage()).isEqualTo("js");
+    assertThat(profile.getName()).isEqualTo("Sonar way");
+  }
+
+  @Test
+  public void find_profile_by_name() {
+    QualityProfileDto profile = underTest.find(QProfileRef.fromName("js", "Sonar way"));
+    assertThat(profile.getKey()).isEqualTo("sw");
+    assertThat(profile.getLanguage()).isEqualTo("js");
+    assertThat(profile.getName()).isEqualTo("Sonar way");
+  }
+
+  @Test
+  public void throw_NFE_if_profile_key_does_not_exist() {
+    expectedException.expect(NotFoundException.class);
+
+    underTest.find(QProfileRef.fromKey("missing"));
+  }
+
+  @Test
+  public void throw_NFE_if_profile_name_does_not_exist() {
+    expectedException.expect(NotFoundException.class);
+
+    underTest.find(QProfileRef.fromName("js", "Missing"));
+  }
+}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/QProfileRefTest.java b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/QProfileRefTest.java
new file mode 100644 (file)
index 0000000..afde17a
--- /dev/null
@@ -0,0 +1,192 @@
+/*
+ * 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.qualityprofile.ws;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.sonar.api.resources.Language;
+import org.sonar.api.resources.Languages;
+import org.sonar.api.server.ws.WebService;
+import org.sonar.api.server.ws.internal.SimpleGetRequest;
+import org.sonar.server.qualityprofile.QProfileRef;
+import org.sonar.server.ws.WsTester;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+
+public class QProfileRefTest {
+
+  @Rule
+  public ExpectedException expectedException = ExpectedException.none();
+
+  @Test
+  public void create_ref_by_key() {
+    QProfileRef ref = QProfileRef.fromKey("foo");
+    assertThat(ref.hasKey()).isTrue();
+    assertThat(ref.getKey()).isEqualTo("foo");
+  }
+
+  @Test
+  public void getLanguage_throws_ISE_if_key_ref() {
+    QProfileRef ref = QProfileRef.fromKey("foo");
+
+    expectedException.expect(IllegalStateException.class);
+    ref.getLanguage();
+  }
+
+  @Test
+  public void getName_throws_ISE_if_key_ref() {
+    QProfileRef ref = QProfileRef.fromKey("foo");
+
+    expectedException.expect(IllegalStateException.class);
+    ref.getName();
+  }
+
+  @Test
+  public void create_ref_by_name() {
+    QProfileRef ref = QProfileRef.fromName("js", "Sonar way");
+    assertThat(ref.hasKey()).isFalse();
+    assertThat(ref.getLanguage()).isEqualTo("js");
+    assertThat(ref.getName()).isEqualTo("Sonar way");
+  }
+
+  @Test
+  public void getKey_throws_ISE_if_name_ref() {
+    QProfileRef ref = QProfileRef.fromName("js", "Sonar way");
+
+    expectedException.expect(IllegalStateException.class);
+    ref.getKey();
+  }
+
+
+  @Test
+  public void create_key_ref_from_ws_request() {
+    SimpleGetRequest req = new SimpleGetRequest();
+    req.setParam("profileKey", "foo");
+
+    QProfileRef ref = QProfileRef.from(req);
+    assertThat(ref.getKey()).isEqualTo("foo");
+  }
+
+  @Test
+  public void create_name_ref_from_ws_request() {
+    SimpleGetRequest req = new SimpleGetRequest();
+    req.setParam("language", "js");
+    req.setParam("profileName", "Sonar way");
+
+    QProfileRef ref = QProfileRef.from(req);
+    assertThat(ref.getLanguage()).isEqualTo("js");
+    assertThat(ref.getName()).isEqualTo("Sonar way");
+  }
+
+  @Test
+  public void create_name_ref_throws_IAE_if_language_is_missing() {
+    SimpleGetRequest req = new SimpleGetRequest();
+    req.setParam(QProfileRef.PARAM_PROFILE_KEY, "the key");
+    req.setParam(QProfileRef.PARAM_PROFILE_NAME, "the name");
+
+    expectedException.expect(IllegalArgumentException.class);
+    QProfileRef.from(req);
+  }
+
+  @Test
+  public void throw_IAE_if_request_does_not_define_ref() {
+    SimpleGetRequest req = new SimpleGetRequest();
+
+    expectedException.expect(IllegalArgumentException.class);
+    QProfileRef.from(req);
+  }
+
+  @Test
+  public void define_ws_parameters() {
+    WsTester wsTester = new WsTester();
+    WebService.NewController controller = wsTester.context().createController("api/qualityprofiles");
+    WebService.NewAction newAction = controller.createAction("do").setHandler((request, response) -> {
+    });
+
+    Languages languages = new Languages(new FakeLanguage("java"), new FakeLanguage("js"));
+    QProfileRef.defineParams(newAction, languages);
+
+    controller.done();
+    WebService.Action action = wsTester.controller("api/qualityprofiles").action("do");
+    assertThat(action.param("language")).isNotNull();
+    assertThat(action.param("language").possibleValues()).containsOnly("java", "js");
+    assertThat(action.param("profileKey")).isNotNull();
+    assertThat(action.param("profileName")).isNotNull();
+  }
+
+  @Test
+  public void test_equals_and_hashCode_of_key_ref() {
+    QProfileRef key1 = QProfileRef.fromKey("one");
+    QProfileRef key1bis = QProfileRef.fromKey("one");
+    QProfileRef key2 = QProfileRef.fromKey("two");
+    QProfileRef name = QProfileRef.fromName("js", "one");
+
+    assertThat(key1.equals(key1)).isTrue();
+    assertThat(key1.equals(key1bis)).isTrue();
+    assertThat(key1.equals(key2)).isFalse();
+    assertThat(key1.equals(name)).isFalse();
+
+    assertThat(key1.hashCode()).isEqualTo(key1.hashCode());
+    assertThat(key1.hashCode()).isEqualTo(key1bis.hashCode());
+  }
+
+  @Test
+  public void test_equals_and_hashCode_of_name_ref() {
+    QProfileRef name1 = QProfileRef.fromName("js", "one");
+    QProfileRef name1bis = QProfileRef.fromName("js", "one");
+    QProfileRef name2 = QProfileRef.fromName("js", "two");
+    QProfileRef name1OtherLang = QProfileRef.fromName("java", "one");
+    QProfileRef key = QProfileRef.fromKey("one");
+
+    assertThat(name1.equals(name1)).isTrue();
+    assertThat(name1.equals(name1bis)).isTrue();
+    assertThat(name1.equals(name2)).isFalse();
+    assertThat(name1.equals(name1OtherLang)).isFalse();
+    assertThat(name1.equals(key)).isFalse();
+
+    assertThat(name1.hashCode()).isEqualTo(name1.hashCode());
+    assertThat(name1.hashCode()).isEqualTo(name1bis.hashCode());
+  }
+
+  private static class FakeLanguage implements Language {
+    private final String key;
+
+    public FakeLanguage(String key) {
+      this.key = key;
+    }
+
+    @Override
+    public String getKey() {
+      return key;
+    }
+
+    @Override
+    public String getName() {
+      return key;
+    }
+
+    @Override
+    public String[] getFileSuffixes() {
+      throw new UnsupportedOperationException();
+    }
+  }
+}
index 3ddc714390ba90d8b560e859fc490c35af541863..0bc7bdff46cd573879002219cec606cb6553f54a 100644 (file)
@@ -32,6 +32,7 @@ import org.sonar.api.server.ws.WebService;
 import org.sonar.api.utils.ValidationMessages;
 import org.sonar.server.language.LanguageTesting;
 import org.sonar.server.qualityprofile.QProfileExporters;
+import org.sonar.server.qualityprofile.QProfileFactory;
 import org.sonar.server.qualityprofile.QProfileService;
 import org.sonar.server.tester.UserSessionRule;
 import org.sonar.server.ws.WsTester;
@@ -67,10 +68,10 @@ public class QProfilesWsTest {
       new SearchAction(null, languages),
       new SetDefaultAction(languages, null, null, userSessionRule),
       new ProjectsAction(null, userSessionRule),
-      new BackupAction(null, null, null, languages),
+      new BackupAction(null, null, languages),
       new RestoreAction(null, languages, userSessionRule),
-      new ChangelogAction(null, mock(QProfileFinder.class)),
-      new ChangeParentAction(null, null, null, languages, userSessionRule),
+      new ChangelogAction(null, mock(QProfileFactory.class), languages),
+      new ChangeParentAction(null, null, languages, userSessionRule),
       new CompareAction(null, null, null, languages),
       new CopyAction(null, languages, userSessionRule),
       new DeleteAction(languages, null, null, userSessionRule),