aboutsummaryrefslogtreecommitdiffstats
path: root/server
diff options
context:
space:
mode:
authorDaniel Schwarz <daniel.schwarz@sonarsource.com>2017-05-10 15:54:47 +0200
committerDaniel Schwarz <bartfastiel@users.noreply.github.com>2017-05-11 09:31:11 +0200
commit2fc84f863e47cdd5c833d4804a640a214bb60920 (patch)
tree66c7b634e01bea9ed3c99fdabd43b2cab67755e6 /server
parent044686172e636433f6c1eb0af0f687e7442974f2 (diff)
downloadsonarqube-2fc84f863e47cdd5c833d4804a640a214bb60920.tar.gz
sonarqube-2fc84f863e47cdd5c833d4804a640a214bb60920.zip
SONAR-9075 “more” skips first 6 results, in api/components/suggestions
Diffstat (limited to 'server')
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/component/index/ComponentHitsPerQualifier.java4
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/component/index/ComponentIndex.java5
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/component/index/ComponentIndexQuery.java18
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/component/ws/SuggestionsAction.java44
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/component/index/ComponentIndexQueryTest.java3
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/component/ws/SuggestionsActionTest.java69
6 files changed, 88 insertions, 55 deletions
diff --git a/server/sonar-server/src/main/java/org/sonar/server/component/index/ComponentHitsPerQualifier.java b/server/sonar-server/src/main/java/org/sonar/server/component/index/ComponentHitsPerQualifier.java
index 6576b7fdac9..45069a2506c 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/component/index/ComponentHitsPerQualifier.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/component/index/ComponentHitsPerQualifier.java
@@ -44,8 +44,4 @@ public class ComponentHitsPerQualifier {
public long getTotalHits() {
return totalHits;
}
-
- public long getNumberOfFurtherResults() {
- return Math.max(totalHits - hits.size(), 0L);
- }
}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/component/index/ComponentIndex.java b/server/sonar-server/src/main/java/org/sonar/server/component/index/ComponentIndex.java
index 60d288028a9..d03b2220fb3 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/component/index/ComponentIndex.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/component/index/ComponentIndex.java
@@ -114,8 +114,9 @@ public class ComponentIndex {
.setHighlighterEncoder("html")
.setHighlighterPreTags("<mark>")
.setHighlighterPostTags("</mark>")
- .addHighlightedField(createHighlighter());
- query.getLimit().ifPresent(sub::setSize);
+ .addHighlightedField(createHighlighter())
+ .setFrom(query.getSkip())
+ .setSize(query.getLimit());
return sub.setFetchSource(false);
}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/component/index/ComponentIndexQuery.java b/server/sonar-server/src/main/java/org/sonar/server/component/index/ComponentIndexQuery.java
index 74a62b04677..e314afce4db 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/component/index/ComponentIndexQuery.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/component/index/ComponentIndexQuery.java
@@ -21,7 +21,6 @@ package org.sonar.server.component.index;
import java.util.Collection;
import java.util.Collections;
-import java.util.Optional;
import java.util.Set;
import static com.google.common.base.Preconditions.checkArgument;
@@ -35,6 +34,7 @@ public class ComponentIndexQuery {
private final Collection<String> qualifiers;
private final Set<String> recentlyBrowsedKeys;
private final Set<String> favoriteKeys;
+ private final int skip;
private final int limit;
private ComponentIndexQuery(Builder builder) {
@@ -42,6 +42,7 @@ public class ComponentIndexQuery {
this.qualifiers = requireNonNull(builder.qualifiers);
this.recentlyBrowsedKeys = requireNonNull(builder.recentlyBrowsedKeys);
this.favoriteKeys = requireNonNull(builder.favoriteKeys);
+ this.skip = builder.skip;
this.limit = builder.limit;
}
@@ -57,8 +58,12 @@ public class ComponentIndexQuery {
return recentlyBrowsedKeys;
}
- public Optional<Integer> getLimit() {
- return Optional.ofNullable(limit);
+ public int getSkip() {
+ return skip;
+ }
+
+ public int getLimit() {
+ return limit;
}
public static Builder builder() {
@@ -74,6 +79,7 @@ public class ComponentIndexQuery {
private Collection<String> qualifiers = Collections.emptyList();
private Set<String> recentlyBrowsedKeys = Collections.emptySet();
private Set<String> favoriteKeys = Collections.emptySet();
+ private int skip = 0;
private int limit = DEFAULT_LIMIT;
private Builder() {
@@ -100,6 +106,12 @@ public class ComponentIndexQuery {
return this;
}
+ public Builder setSkip(int skip) {
+ checkArgument(limit > 0, "Skip has to be strictly positive: %s", limit);
+ this.skip = skip;
+ return this;
+ }
+
public Builder setLimit(int limit) {
checkArgument(limit > 0, "Limit has to be strictly positive: %s", limit);
this.limit = limit;
diff --git a/server/sonar-server/src/main/java/org/sonar/server/component/ws/SuggestionsAction.java b/server/sonar-server/src/main/java/org/sonar/server/component/ws/SuggestionsAction.java
index 12328d0f655..8c4ea02e2c9 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/component/ws/SuggestionsAction.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/component/ws/SuggestionsAction.java
@@ -63,6 +63,7 @@ import static java.util.Optional.ofNullable;
import static org.sonar.api.web.UserRole.USER;
import static org.sonar.core.util.stream.MoreCollectors.toList;
import static org.sonar.core.util.stream.MoreCollectors.toSet;
+import static org.sonar.server.component.index.ComponentIndexQuery.DEFAULT_LIMIT;
import static org.sonar.server.es.DefaultIndexSettings.MINIMUM_NGRAM_LENGTH;
import static org.sonar.server.ws.WsUtils.writeProtobuf;
import static org.sonarqube.ws.WsComponents.SuggestionsWsResponse.Organization;
@@ -77,7 +78,7 @@ public class SuggestionsAction implements ComponentsWsAction {
static final String SHORT_INPUT_WARNING = "short_input";
private static final int MAXIMUM_RECENTLY_BROWSED = 50;
- static final int EXTENDED_LIMIT = 20;
+ private static final int EXTENDED_LIMIT = 20;
private final ComponentIndex index;
private final FavoriteFinder favoriteFinder;
@@ -117,7 +118,7 @@ public class SuggestionsAction implements ComponentsWsAction {
.setExampleValue("sonar");
action.createParam(PARAM_MORE)
- .setDescription("Category, for which to display " + EXTENDED_LIMIT + " instead of " + ComponentIndexQuery.DEFAULT_LIMIT + " results")
+ .setDescription("Category, for which to display the next " + EXTENDED_LIMIT + " results (skipping the first " + DEFAULT_LIMIT + " results)")
.setPossibleValues(stream(SuggestionCategory.values()).map(SuggestionCategory::getName).toArray(String[]::new))
.setSince("6.4");
@@ -136,7 +137,9 @@ public class SuggestionsAction implements ComponentsWsAction {
String more = wsRequest.param(PARAM_MORE);
Set<String> recentlyBrowsedKeys = getRecentlyBrowsedKeys(wsRequest);
List<String> qualifiers = getQualifiers(more);
- SuggestionsWsResponse searchWsResponse = loadSuggestions(query, more, recentlyBrowsedKeys, qualifiers);
+ int skip = more == null ? 0 : DEFAULT_LIMIT;
+ int limit = more == null ? DEFAULT_LIMIT : EXTENDED_LIMIT;
+ SuggestionsWsResponse searchWsResponse = loadSuggestions(query, skip, limit, recentlyBrowsedKeys, qualifiers);
writeProtobuf(searchWsResponse, wsRequest, wsResponse);
}
@@ -148,17 +151,17 @@ public class SuggestionsAction implements ComponentsWsAction {
return new HashSet<>(recentlyBrowsedParam);
}
- private SuggestionsWsResponse loadSuggestions(@Nullable String query, String more, Set<String> recentlyBrowsedKeys, List<String> qualifiers) {
+ private SuggestionsWsResponse loadSuggestions(@Nullable String query, int skip, int limit, Set<String> recentlyBrowsedKeys, List<String> qualifiers) {
if (query == null) {
- return loadSuggestionsWithoutSearch(more, recentlyBrowsedKeys, qualifiers);
+ return loadSuggestionsWithoutSearch(skip, limit, recentlyBrowsedKeys, qualifiers);
}
- return loadSuggestionsWithSearch(query, more, recentlyBrowsedKeys, qualifiers);
+ return loadSuggestionsWithSearch(query, skip, limit, recentlyBrowsedKeys, qualifiers);
}
/**
* we are generating suggestions, by using (1) favorites and (2) recently browsed components (without searchin in Elasticsearch)
*/
- private SuggestionsWsResponse loadSuggestionsWithoutSearch(@Nullable String more, Set<String> recentlyBrowsedKeys, List<String> qualifiers) {
+ private SuggestionsWsResponse loadSuggestionsWithoutSearch(int skip, int limit, Set<String> recentlyBrowsedKeys, List<String> qualifiers) {
List<ComponentDto> favoriteDtos = favoriteFinder.list();
if (favoriteDtos.isEmpty() && recentlyBrowsedKeys.isEmpty()) {
return newBuilder().build();
@@ -179,12 +182,12 @@ public class SuggestionsAction implements ComponentsWsAction {
Comparator<ComponentDto> favoriteComparator = Comparator.comparing(c -> favoriteUuids.contains(c.uuid()) ? -1 : +1);
Comparator<ComponentDto> comparator = favoriteComparator.thenComparing(ComponentDto::name);
- int limit = more == null ? ComponentIndexQuery.DEFAULT_LIMIT : EXTENDED_LIMIT;
ComponentIndexResults componentsPerQualifiers = ComponentIndexResults.newBuilder().setQualifiers(
qualifiers.stream().map(q -> {
List<ComponentHit> hits = componentsPerQualifier.get(q)
.stream()
.sorted(comparator)
+ .skip(skip)
.limit(limit)
.map(ComponentDto::uuid)
.map(ComponentHit::new)
@@ -192,21 +195,20 @@ public class SuggestionsAction implements ComponentsWsAction {
int totalHits = componentsPerQualifier.size();
return new ComponentHitsPerQualifier(q, hits, totalHits);
})).build();
- return buildResponse(recentlyBrowsedKeys, favoriteUuids, componentsPerQualifiers, dbSession, componentDtos.stream()).build();
+ return buildResponse(recentlyBrowsedKeys, favoriteUuids, componentsPerQualifiers, dbSession, componentDtos.stream(), skip + limit).build();
}
}
- private SuggestionsWsResponse loadSuggestionsWithSearch(String query, @Nullable String more, Set<String> recentlyBrowsedKeys, List<String> qualifiers) {
+ private SuggestionsWsResponse loadSuggestionsWithSearch(String query, int skip, int limit, Set<String> recentlyBrowsedKeys, List<String> qualifiers) {
List<ComponentDto> favorites = favoriteFinder.list();
Set<String> favoriteKeys = favorites.stream().map(ComponentDto::getKey).collect(MoreCollectors.toSet(favorites.size()));
ComponentIndexQuery.Builder queryBuilder = ComponentIndexQuery.builder()
.setQuery(query)
.setRecentlyBrowsedKeys(recentlyBrowsedKeys)
.setFavoriteKeys(favoriteKeys)
- .setQualifiers(qualifiers);
- if (more != null) {
- queryBuilder.setLimit(EXTENDED_LIMIT);
- }
+ .setQualifiers(qualifiers)
+ .setSkip(skip)
+ .setLimit(limit);
ComponentIndexResults componentsPerQualifiers = searchInIndex(queryBuilder.build());
if (componentsPerQualifiers.isEmpty()) {
return newBuilder().build();
@@ -219,7 +221,7 @@ public class SuggestionsAction implements ComponentsWsAction {
.collect(toSet());
Stream<ComponentDto> componentDtoStream = dbClient.componentDao().selectByUuids(dbSession, componentUuids).stream();
Set<String> favoriteUuids = favorites.stream().map(ComponentDto::uuid).collect(MoreCollectors.toSet(favorites.size()));
- SuggestionsWsResponse.Builder searchWsResponse = buildResponse(recentlyBrowsedKeys, favoriteUuids, componentsPerQualifiers, dbSession, componentDtoStream);
+ SuggestionsWsResponse.Builder searchWsResponse = buildResponse(recentlyBrowsedKeys, favoriteUuids, componentsPerQualifiers, dbSession, componentDtoStream, skip + limit);
getWarning(query).ifPresent(searchWsResponse::setWarning);
return searchWsResponse.build();
}
@@ -241,12 +243,12 @@ public class SuggestionsAction implements ComponentsWsAction {
}
private SuggestionsWsResponse.Builder buildResponse(Set<String> recentlyBrowsedKeys, Set<String> favoriteUuids, ComponentIndexResults componentsPerQualifiers,
- DbSession dbSession, Stream<ComponentDto> stream) {
+ DbSession dbSession, Stream<ComponentDto> stream, int coveredItems) {
Map<String, ComponentDto> componentsByUuids = stream
.collect(MoreCollectors.uniqueIndex(ComponentDto::uuid));
Map<String, OrganizationDto> organizationsByUuids = loadOrganizations(dbSession, componentsByUuids.values());
Map<String, ComponentDto> projectsByUuids = loadProjects(dbSession, componentsByUuids.values());
- return toResponse(componentsPerQualifiers, recentlyBrowsedKeys, favoriteUuids, organizationsByUuids, componentsByUuids, projectsByUuids);
+ return toResponse(componentsPerQualifiers, recentlyBrowsedKeys, favoriteUuids, organizationsByUuids, componentsByUuids, projectsByUuids, coveredItems);
}
private Map<String, ComponentDto> loadProjects(DbSession dbSession, Collection<ComponentDto> components) {
@@ -271,18 +273,18 @@ public class SuggestionsAction implements ComponentsWsAction {
}
private static SuggestionsWsResponse.Builder toResponse(ComponentIndexResults componentsPerQualifiers, Set<String> recentlyBrowsedKeys, Set<String> favoriteUuids,
- Map<String, OrganizationDto> organizationsByUuids, Map<String, ComponentDto> componentsByUuids, Map<String, ComponentDto> projectsByUuids) {
+ Map<String, OrganizationDto> organizationsByUuids, Map<String, ComponentDto> componentsByUuids, Map<String, ComponentDto> projectsByUuids, int coveredItems) {
if (componentsPerQualifiers.isEmpty()) {
return newBuilder();
}
return newBuilder()
- .addAllResults(toCategories(componentsPerQualifiers, recentlyBrowsedKeys, favoriteUuids, componentsByUuids, organizationsByUuids, projectsByUuids))
+ .addAllResults(toCategories(componentsPerQualifiers, recentlyBrowsedKeys, favoriteUuids, componentsByUuids, organizationsByUuids, projectsByUuids, coveredItems))
.addAllOrganizations(toOrganizations(organizationsByUuids))
.addAllProjects(toProjects(projectsByUuids));
}
private static List<Category> toCategories(ComponentIndexResults componentsPerQualifiers, Set<String> recentlyBrowsedKeys, Set<String> favoriteUuids,
- Map<String, ComponentDto> componentsByUuids, Map<String, OrganizationDto> organizationByUuids, Map<String, ComponentDto> projectsByUuids) {
+ Map<String, ComponentDto> componentsByUuids, Map<String, OrganizationDto> organizationByUuids, Map<String, ComponentDto> projectsByUuids, int coveredItems) {
return componentsPerQualifiers.getQualifiers().map(qualifier -> {
List<Suggestion> suggestions = qualifier.getHits().stream()
@@ -291,7 +293,7 @@ public class SuggestionsAction implements ComponentsWsAction {
return Category.newBuilder()
.setQ(qualifier.getQualifier())
- .setMore(qualifier.getNumberOfFurtherResults())
+ .setMore(Math.max(0, qualifier.getTotalHits() - coveredItems))
.addAllItems(suggestions)
.build();
}).collect(toList());
diff --git a/server/sonar-server/src/test/java/org/sonar/server/component/index/ComponentIndexQueryTest.java b/server/sonar-server/src/test/java/org/sonar/server/component/index/ComponentIndexQueryTest.java
index d1f51eaaaec..7192e929fc8 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/component/index/ComponentIndexQueryTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/component/index/ComponentIndexQueryTest.java
@@ -19,7 +19,6 @@
*/
package org.sonar.server.component.index;
-import java.util.Optional;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
@@ -79,6 +78,6 @@ public class ComponentIndexQueryTest {
ComponentIndexQuery query = ComponentIndexQuery.builder().setQuery("ab")
.setLimit(1).build();
- assertThat(query.getLimit()).isEqualTo(Optional.of(1));
+ assertThat(query.getLimit()).isEqualTo(1);
}
}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/component/ws/SuggestionsActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/component/ws/SuggestionsActionTest.java
index 2ffdd06bdf3..9247f5cb0ef 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/component/ws/SuggestionsActionTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/component/ws/SuggestionsActionTest.java
@@ -63,8 +63,6 @@ import static org.mockito.Mockito.mock;
import static org.sonar.api.web.UserRole.USER;
import static org.sonar.db.component.ComponentTesting.newModuleDto;
import static org.sonar.db.component.ComponentTesting.newPrivateProjectDto;
-import static org.sonar.server.component.index.ComponentIndexQuery.DEFAULT_LIMIT;
-import static org.sonar.server.component.ws.SuggestionsAction.EXTENDED_LIMIT;
import static org.sonar.server.component.ws.SuggestionsAction.PARAM_MORE;
import static org.sonar.server.component.ws.SuggestionsAction.PARAM_QUERY;
import static org.sonar.server.component.ws.SuggestionsAction.PARAM_RECENTLY_BROWSED;
@@ -274,8 +272,7 @@ public class SuggestionsActionTest {
tuple("Bravo", true, false),
tuple("Delta", true, false),
tuple("Alpha", false, true),
- tuple("Charlie", false, true)
- );
+ tuple("Charlie", false, true));
}
@Test
@@ -475,26 +472,52 @@ public class SuggestionsActionTest {
}
@Test
- public void should_propose_to_show_more_results_if_7_projects_are_found() throws Exception {
- check_proposal_to_show_more_results(7, DEFAULT_LIMIT, 1L, null);
+ public void should_not_propose_to_show_more_results_if_0_projects_are_found() throws Exception {
+ check_proposal_to_show_more_results(0, 0, 0L, null);
+ }
+
+ @Test
+ public void should_not_propose_to_show_more_results_if_5_projects_are_found() throws Exception {
+ check_proposal_to_show_more_results(5, 5, 0L, null);
}
@Test
public void should_not_propose_to_show_more_results_if_6_projects_are_found() throws Exception {
- check_proposal_to_show_more_results(6, DEFAULT_LIMIT, 0L, null);
+ check_proposal_to_show_more_results(6, 6, 0L, null);
}
@Test
- public void should_not_propose_to_show_more_results_if_5_projects_are_found() throws Exception {
- check_proposal_to_show_more_results(5, DEFAULT_LIMIT, 0L, null);
+ public void should_propose_to_show_more_results_if_7_projects_are_found() throws Exception {
+ check_proposal_to_show_more_results(7, 6, 1L, null);
}
@Test
- public void show_show_more_results_if_requested() throws Exception {
- check_proposal_to_show_more_results(21, EXTENDED_LIMIT, 1L, SuggestionCategory.PROJECT);
+ public void show_more_results_if_requested_and_5_projects_are_found() throws Exception {
+ check_proposal_to_show_more_results(5, 0, 0L, SuggestionCategory.PROJECT);
}
- private void check_proposal_to_show_more_results(int numberOfProjects, int results, long numberOfMoreResults, @Nullable SuggestionCategory more) throws Exception {
+ @Test
+ public void show_more_results_if_requested_and_6_projects_are_found() throws Exception {
+ check_proposal_to_show_more_results(6, 0, 0L, SuggestionCategory.PROJECT);
+ }
+
+ @Test
+ public void show_more_results_if_requested_and_7_projects_are_found() throws Exception {
+ check_proposal_to_show_more_results(7, 1, 0L, SuggestionCategory.PROJECT);
+ }
+
+ @Test
+ public void show_more_results_if_requested_and_26_projects_are_found() throws Exception {
+ check_proposal_to_show_more_results(26, 20, 0L, SuggestionCategory.PROJECT);
+ }
+
+ @Test
+ public void show_more_results_if_requested_and_27_projects_are_found() throws Exception {
+ check_proposal_to_show_more_results(27, 20, 1L, SuggestionCategory.PROJECT);
+ }
+
+ private void check_proposal_to_show_more_results(int numberOfProjects, int expectedNumberOfResults, long expectedNumberOfMoreResults, @Nullable SuggestionCategory more)
+ throws Exception {
String namePrefix = "MyProject";
List<ComponentDto> projects = range(0, numberOfProjects)
@@ -511,21 +534,21 @@ public class SuggestionsActionTest {
SuggestionsWsResponse response = request
.executeProtobuf(SuggestionsWsResponse.class);
- // assert match in qualifier "TRK"
- assertThat(response.getResultsList())
- .filteredOn(q -> q.getItemsCount() > 0)
- .extracting(Category::getQ)
- .containsExactly(Qualifiers.PROJECT);
-
// include limited number of results in the response
assertThat(response.getResultsList())
.flatExtracting(Category::getItemsList)
- .hasSize(Math.min(results, numberOfProjects));
+ .hasSize(expectedNumberOfResults);
// indicate, that there are more results
- assertThat(response.getResultsList())
- .filteredOn(q -> q.getItemsCount() > 0)
- .extracting(Category::getMore)
- .containsExactly(numberOfMoreResults);
+ if (expectedNumberOfResults == 0 && expectedNumberOfMoreResults == 0) {
+ assertThat(response.getResultsList())
+ .filteredOn(q -> q.getItemsCount() > 0)
+ .isEmpty();
+ } else {
+ assertThat(response.getResultsList())
+ .filteredOn(q -> q.getItemsCount() > 0)
+ .extracting(Category::getMore)
+ .containsExactly(expectedNumberOfMoreResults);
+ }
}
}