]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-10313 Keep the order of issues on Search
authorEric Hartmann <hartmann.eric@gmail.com>
Tue, 30 Jan 2018 11:34:11 +0000 (12:34 +0100)
committerSébastien Lesaint <sebastien.lesaint@sonarsource.com>
Thu, 8 Feb 2018 12:41:00 +0000 (13:41 +0100)
server/sonar-db-dao/src/main/java/org/sonar/db/issue/IssueDao.java
server/sonar-db-dao/src/test/java/org/sonar/db/issue/IssueDaoTest.java
server/sonar-server/src/main/java/org/sonar/server/issue/ws/SearchResponseLoader.java
server/sonar-server/src/test/java/org/sonar/server/issue/ws/SearchActionTest.java
server/sonar-server/src/test/resources/org/sonar/server/issue/ws/SearchActionTest/sort_by_updated_at.json [deleted file]
tests/src/test/java/org/sonarqube/tests/issue/IssueCreationDatePluginChangedTest.java

index 5570e5c8494d09342a5c41d5aa279021ab7581b2..482857eecfbdf452369b44aa976c302b8e6810fa 100644 (file)
  */
 package org.sonar.db.issue;
 
-import com.google.common.base.Function;
-import com.google.common.base.Predicates;
 import java.util.Collection;
-import java.util.HashMap;
 import java.util.List;
-import java.util.Map;
+import java.util.Optional;
 import java.util.Set;
-import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
 import org.apache.ibatis.session.ResultHandler;
 import org.sonar.db.Dao;
 import org.sonar.db.DbSession;
@@ -35,18 +30,17 @@ import org.sonar.db.RowNotFoundException;
 import org.sonar.db.WildcardPosition;
 import org.sonar.db.component.ComponentDto;
 
-import static com.google.common.collect.FluentIterable.from;
 import static org.sonar.db.DaoDatabaseUtils.buildLikeValue;
 import static org.sonar.db.DatabaseUtils.executeLargeInputs;
 
 public class IssueDao implements Dao {
 
-  public java.util.Optional<IssueDto> selectByKey(DbSession session, String key) {
-    return java.util.Optional.ofNullable(mapper(session).selectByKey(key));
+  public Optional<IssueDto> selectByKey(DbSession session, String key) {
+    return Optional.ofNullable(mapper(session).selectByKey(key));
   }
 
   public IssueDto selectOrFailByKey(DbSession session, String key) {
-    java.util.Optional<IssueDto> issue = selectByKey(session, key);
+    Optional<IssueDto> issue = selectByKey(session, key);
     if (!issue.isPresent()) {
       throw new RowNotFoundException(String.format("Issue with key '%s' does not exist", key));
     }
@@ -57,39 +51,12 @@ public class IssueDao implements Dao {
    * Gets a list issues by their keys. The result does NOT contain {@code null} values for issues not found, so
    * the size of result may be less than the number of keys. A single issue is returned
    * if input keys contain multiple occurrences of a key.
-   * <p>Results may be in a different order as input keys (see {@link #selectByOrderedKeys(DbSession, List)}).</p>
+   * <p>Results may be in a different order as input keys.</p>
    */
   public List<IssueDto> selectByKeys(final DbSession session, Collection<String> keys) {
     return executeLargeInputs(keys, mapper(session)::selectByKeys);
   }
 
-  /**
-   * Gets a list issues by their keys. The result does NOT contain {@code null} values for issues not found, so
-   * the size of result may be less than the number of keys. A single issue is returned
-   * if input keys contain multiple occurrences of a key.
-   * <p>Contrary to {@link #selectByKeys(DbSession, Collection)}, results are in the same order as input keys.</p>
-   */
-  public List<IssueDto> selectByOrderedKeys(DbSession session, List<String> keys) {
-    List<IssueDto> unordered = selectByKeys(session, keys);
-    return from(keys).transform(new KeyToIssue(unordered)).filter(Predicates.notNull()).toList();
-  }
-
-  private static class KeyToIssue implements Function<String, IssueDto> {
-    private final Map<String, IssueDto> map = new HashMap<>();
-
-    private KeyToIssue(Collection<IssueDto> unordered) {
-      for (IssueDto dto : unordered) {
-        map.put(dto.getKey(), dto);
-      }
-    }
-
-    @Nullable
-    @Override
-    public IssueDto apply(@Nonnull String issueKey) {
-      return map.get(issueKey);
-    }
-  }
-
   public Set<String> selectComponentUuidsOfOpenIssuesForProjectUuid(DbSession session, String projectUuid) {
     return mapper(session).selectComponentUuidsOfOpenIssuesForProjectUuid(projectUuid);
   }
index c32c54e366a94fca506bf4f2afebbe684ce96d66..9791628fc34d99e2d33f2cb74664344d12ae24d3 100644 (file)
@@ -122,18 +122,6 @@ public class IssueDaoTest {
     assertThat(issues).extracting("key").containsOnly("I1", "I2");
   }
 
-  @Test
-  public void selectByOrderedKeys() {
-    // contains I1 and I2
-    prepareTables();
-
-    Iterable<IssueDto> issues = underTest.selectByOrderedKeys(db.getSession(), asList("I1", "I2", "I3"));
-    assertThat(issues).extracting("key").containsExactly("I1", "I2");
-
-    issues = underTest.selectByOrderedKeys(db.getSession(), asList("I2", "I3", "I1"));
-    assertThat(issues).extracting("key").containsExactly("I2", "I1");
-  }
-
   @Test
   public void scrollNonClosedByComponentUuid() {
     RuleDefinitionDto rule = db.rules().insert();
index 7e03b90f08c3f6fa7bb90c66d91b6c1edeba1991..9dc3608d4d58b5839f5d246d8d3a5cd40a0f5854 100644 (file)
  */
 package org.sonar.server.issue.ws;
 
+import com.google.common.base.Function;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.MultimapBuilder;
 import com.google.common.collect.SetMultimap;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 import java.util.Set;
+import java.util.stream.Collectors;
 import javax.annotation.Nullable;
 import org.sonar.core.issue.DefaultIssue;
 import org.sonar.core.util.stream.MoreCollectors;
@@ -80,8 +84,7 @@ public class SearchResponseLoader {
   /**
    * The issue keys are given by the multi-criteria search in Elasticsearch index.
    * <p>
-   * Same as {@link #load(SearchResponseData, Collector, Facets)} but will only retrieve from DB data which is not
-   * already provided by the specified preloaded {@link SearchResponseData}.<br/>
+   * It will only retrieve from DB data which is not already provided by the specified preloaded {@link SearchResponseData}.<br/>
    * The returned {@link SearchResponseData} is <strong>not</strong> the one specified as argument.
    * </p>
    */
@@ -106,14 +109,23 @@ public class SearchResponseLoader {
   private List<IssueDto> loadIssues(SearchResponseData preloadedResponseData, Collector collector, DbSession dbSession) {
     List<IssueDto> preloadedIssues = preloadedResponseData.getIssues();
     Set<String> preloadedIssueKeys = preloadedIssues.stream().map(IssueDto::getKey).collect(MoreCollectors.toSet(preloadedIssues.size()));
-    Set<String> issueKeysToLoad = copyOf(difference(ImmutableSet.copyOf(collector.getIssueKeys()), preloadedIssueKeys));
+
+    ImmutableSet<String> issueKeys = ImmutableSet.copyOf(collector.getIssueKeys());
+    Set<String> issueKeysToLoad = copyOf(difference(issueKeys, preloadedIssueKeys));
+
     if (issueKeysToLoad.isEmpty()) {
-      return preloadedIssues;
+      return issueKeys.stream()
+        .map(new KeyToIssueFunction(preloadedIssues)::apply).filter(Objects::nonNull)
+        .collect(Collectors.toList());
     }
 
     List<IssueDto> loadedIssues = dbClient.issueDao().selectByKeys(dbSession, issueKeysToLoad);
-    return concat(preloadedIssues.stream(), loadedIssues.stream())
+    List<IssueDto> unorderedIssues = concat(preloadedIssues.stream(), loadedIssues.stream())
       .collect(toList(preloadedIssues.size() + loadedIssues.size()));
+
+    return issueKeys.stream()
+      .map(new KeyToIssueFunction(unorderedIssues)::apply).filter(Objects::nonNull)
+      .collect(Collectors.toList());
   }
 
   private void loadUsers(SearchResponseData preloadedResponseData, Collector collector, DbSession dbSession, SearchResponseData result) {
@@ -338,4 +350,20 @@ public class SearchResponseLoader {
       return projectUuids;
     }
   }
+
+  private static class KeyToIssueFunction implements Function<String, IssueDto> {
+    private final Map<String, IssueDto> map = new HashMap<>();
+
+    private KeyToIssueFunction(Collection<IssueDto> unordered) {
+      for (IssueDto dto : unordered) {
+        map.put(dto.getKey(), dto);
+      }
+    }
+
+    @Nullable
+    @Override
+    public IssueDto apply(String issueKey) {
+      return map.get(issueKey);
+    }
+  }
 }
index cf8cc73604aef01cb322eccb1fe61ef24642cb65..df3f8b2056a88aea71c5ae7b32a7693616a5453d 100644 (file)
@@ -19,6 +19,8 @@
  */
 package org.sonar.server.issue.ws;
 
+import com.google.gson.JsonElement;
+import com.google.gson.JsonParser;
 import java.time.Clock;
 import org.junit.Before;
 import org.junit.Rule;
@@ -627,11 +629,16 @@ public class SearchActionTest {
     session.commit();
     indexIssues();
 
-    ws.newRequest()
+    TestResponse response = ws.newRequest()
       .setParam("sort", IssueQuery.SORT_BY_UPDATE_DATE)
       .setParam("asc", "false")
-      .execute()
-      .assertJson(this.getClass(), "sort_by_updated_at.json");
+      .execute();
+
+    JsonElement parse = new JsonParser().parse(response.getInput());
+
+    assertThat(parse.getAsJsonObject().get("issues").getAsJsonArray())
+      .extracting(o -> o.getAsJsonObject().get("key").getAsString())
+      .containsExactly("82fd47d4-b650-4037-80bc-7b112bd4eac3", "82fd47d4-b650-4037-80bc-7b112bd4eac1", "82fd47d4-b650-4037-80bc-7b112bd4eac2");
   }
 
   @Test
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/issue/ws/SearchActionTest/sort_by_updated_at.json b/server/sonar-server/src/test/resources/org/sonar/server/issue/ws/SearchActionTest/sort_by_updated_at.json
deleted file mode 100644 (file)
index faac653..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-{
-  "issues": [
-    {
-      "organization": "my-org-2",
-      "key": "82fd47d4-b650-4037-80bc-7b112bd4eac2",
-      "component": "FILE_KEY",
-      "project": "PROJECT_KEY",
-      "rule": "xoo:x1",
-      "updateDate": "2014-11-01T00:00:00+0100"
-    },
-    {
-      "organization": "my-org-2",
-      "key": "82fd47d4-b650-4037-80bc-7b112bd4eac1",
-      "component": "FILE_KEY",
-      "project": "PROJECT_KEY",
-      "rule": "xoo:x1",
-      "updateDate": "2014-11-02T00:00:00+0100"
-    },
-    {
-      "organization": "my-org-2",
-      "key": "82fd47d4-b650-4037-80bc-7b112bd4eac3",
-      "component": "FILE_KEY",
-      "project": "PROJECT_KEY",
-      "rule": "xoo:x1",
-      "updateDate": "2014-11-03T00:00:00+0100"
-    }
-  ]
-}
index 6ad7158a0f6b1c9f15df88c0faec8e30995243cf..af2fbd1e1a6a1f1ca992f2ea65bf8875594b3c36 100644 (file)
@@ -23,12 +23,10 @@ import com.google.common.collect.ImmutableList;
 import com.sonar.orchestrator.Orchestrator;
 import com.sonar.orchestrator.build.SonarScanner;
 import java.io.File;
-import java.io.IOException;
 import java.text.ParseException;
 import java.text.SimpleDateFormat;
 import java.util.Date;
 import java.util.List;
-import javax.mail.MessagingException;
 import org.junit.AfterClass;
 import org.junit.Before;
 import org.junit.BeforeClass;
@@ -150,7 +148,9 @@ public class IssueCreationDatePluginChangedTest {
 
     // New analysis that should raise 2 new issues that will be backdated
     ORCHESTRATOR.executeBuild(scanner);
-    issues = getIssues(issueQuery().components("creation-date-sample:src/main/xoo/sample/Sample.xoo"));
+    issues = getIssues(issueQuery()
+      .components("creation-date-sample:src/main/xoo/sample/Sample.xoo")
+      .sort("FILE_LINE"));
     assertThat(issues)
       .extracting(Issue::line, Issue::creationDate)
       .containsExactly(tuple(1, dateTimeParse("2005-01-01T00:00:00+0000")),