]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-8288 WS api/measures/search_projects DSL handle isFavorite
authorTeryk Bellahsene <teryk.bellahsene@sonarsource.com>
Mon, 7 Nov 2016 16:40:32 +0000 (17:40 +0100)
committerTeryk Bellahsene <teryk.bellahsene@sonarsource.com>
Tue, 8 Nov 2016 16:35:46 +0000 (17:35 +0100)
server/sonar-server/src/main/java/org/sonar/server/component/es/ProjectMeasuresIndex.java
server/sonar-server/src/main/java/org/sonar/server/component/es/ProjectMeasuresQuery.java
server/sonar-server/src/main/java/org/sonar/server/component/ws/ComponentsWsModule.java
server/sonar-server/src/main/java/org/sonar/server/component/ws/ProjectMeasuresQueryFactory.java
server/sonar-server/src/main/java/org/sonar/server/component/ws/SearchProjectsAction.java
server/sonar-server/src/test/java/org/sonar/server/component/es/ProjectMeasuresIndexTest.java
server/sonar-server/src/test/java/org/sonar/server/component/ws/ComponentsWsModuleTest.java
server/sonar-server/src/test/java/org/sonar/server/component/ws/ProjectMeasuresQueryFactoryTest.java
server/sonar-server/src/test/java/org/sonar/server/component/ws/ProjectMeasuresQueryValidatorTest.java
server/sonar-server/src/test/java/org/sonar/server/component/ws/SearchProjectsActionTest.java

index 86b4385f93b22cc6dec52a6cf476326d75d330ce..83ced735a4020d66a8fd61a4cf83bb99590d12cb 100644 (file)
@@ -216,6 +216,9 @@ public class ProjectMeasuresIndex extends BaseIndex {
     if (query.hasQualityGateStatus()) {
       filters.put(ALERT_STATUS_KEY, termQuery(FIELD_QUALITY_GATE, query.getQualityGateStatus().name()));
     }
+    if (query.doesFilterOnProjectUuids()) {
+      filters.put("ids", termsQuery("_id", query.getProjectUuids()));
+    }
     return filters;
   }
 
index 6301a3c6d6fa3864c5982ef721936334ae5b04aa..ed673b2d74b49659e20d92162183a2914bcd450a 100644 (file)
@@ -32,6 +32,7 @@ import static java.util.Objects.requireNonNull;
 public class ProjectMeasuresQuery {
   private List<MetricCriterion> metricCriteria = new ArrayList<>();
   private Metric.Level qualityGateStatus;
+  private List<String> projectUuids = null;
 
   public ProjectMeasuresQuery addMetricCriterion(MetricCriterion metricCriterion) {
     this.metricCriteria.add(metricCriterion);
@@ -56,6 +57,19 @@ public class ProjectMeasuresQuery {
     return qualityGateStatus;
   }
 
+  public ProjectMeasuresQuery setProjectUuids(List<String> projectUuids) {
+    this.projectUuids = requireNonNull(projectUuids);
+    return this;
+  }
+
+  public boolean doesFilterOnProjectUuids() {
+    return projectUuids != null;
+  }
+
+  public List<String> getProjectUuids() {
+    return requireNonNull(projectUuids);
+  }
+
   public enum Operator {
     LT("<"), LTE("<="), GT(">"), GTE(">="), EQ("=");
 
index 76933a91e208ebdcbe91183e3bae725775fc558a..9e8f7b35a0f43e9267bddb8878ce67dea765ac2d 100644 (file)
@@ -37,6 +37,7 @@ public class ComponentsWsModule extends Module {
       UpdateKeyAction.class,
       BulkUpdateKeyAction.class,
       SearchProjectsAction.class,
+      ProjectMeasuresQueryFactory.class,
       ProjectMeasuresQueryValidator.class);
   }
 }
index e3ddbac901ce2d01a3f6fdb11f3cc0ed8487450b..0698c0fcd7dcbb738ff873734cd4b20b32616e47 100644 (file)
 package org.sonar.server.component.ws;
 
 import com.google.common.base.Splitter;
+import java.util.List;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 import org.apache.commons.lang.StringUtils;
 import org.sonar.api.measures.Metric.Level;
+import org.sonar.api.resources.Qualifiers;
+import org.sonar.core.util.stream.Collectors;
+import org.sonar.db.DbClient;
+import org.sonar.db.DbSession;
+import org.sonar.db.component.ComponentDto;
+import org.sonar.db.property.PropertyDto;
+import org.sonar.db.property.PropertyQuery;
 import org.sonar.server.component.es.ProjectMeasuresQuery;
+import org.sonar.server.user.UserSession;
 
 import static com.google.common.base.Preconditions.checkArgument;
 import static java.util.Locale.ENGLISH;
@@ -33,16 +42,20 @@ import static org.sonar.api.measures.CoreMetrics.ALERT_STATUS_KEY;
 import static org.sonar.server.component.es.ProjectMeasuresQuery.MetricCriterion;
 import static org.sonar.server.component.es.ProjectMeasuresQuery.Operator;
 
-class ProjectMeasuresQueryFactory {
-
+public class ProjectMeasuresQueryFactory {
   private static final Splitter CRITERIA_SPLITTER = Splitter.on(Pattern.compile("and", Pattern.CASE_INSENSITIVE));
   private static final Pattern CRITERIA_PATTERN = Pattern.compile("(\\w+)\\s*([<>]?[=]?)\\s*(\\w+)");
+  private static final String IS_FAVORITE_CRITERION = "isFavorite";
+
+  private final DbClient dbClient;
+  private final UserSession userSession;
 
-  private ProjectMeasuresQueryFactory() {
-    // Only static methods
+  public ProjectMeasuresQueryFactory(DbClient dbClient, UserSession userSession) {
+    this.dbClient = dbClient;
+    this.userSession = userSession;
   }
 
-  static ProjectMeasuresQuery newProjectMeasuresQuery(String filter) {
+  ProjectMeasuresQuery newProjectMeasuresQuery(DbSession dbSession, String filter) {
     if (StringUtils.isBlank(filter)) {
       return new ProjectMeasuresQuery();
     }
@@ -50,14 +63,21 @@ class ProjectMeasuresQueryFactory {
     ProjectMeasuresQuery query = new ProjectMeasuresQuery();
 
     CRITERIA_SPLITTER.split(filter)
-      .forEach(criteria -> processCriterion(criteria, query));
+      .forEach(criteria -> processCriterion(dbSession, criteria, query));
     return query;
   }
 
-  private static void processCriterion(String criterion, ProjectMeasuresQuery query) {
+  private void processCriterion(DbSession dbSession, String rawCriterion, ProjectMeasuresQuery query) {
+    String criterion = rawCriterion.trim();
+
     try {
+      if (IS_FAVORITE_CRITERION.equalsIgnoreCase(criterion)) {
+        query.setProjectUuids(searchFavoriteUuids(dbSession));
+        return;
+      }
+
       Matcher matcher = CRITERIA_PATTERN.matcher(criterion);
-      checkArgument(matcher.find() && matcher.groupCount() == 3, "Criterion should have a metric, an operator and a value");
+      checkArgument(matcher.find() && matcher.groupCount() == 3, "Criterion should be 'isFavourite' or criterion should have a metric, an operator and a value");
       String metric = matcher.group(1).toLowerCase(ENGLISH);
       Operator operator = Operator.getByValue(matcher.group(2));
       String value = matcher.group(3);
@@ -69,8 +89,24 @@ class ProjectMeasuresQueryFactory {
         query.addMetricCriterion(new MetricCriterion(metric, operator, doubleValue));
       }
     } catch (Exception e) {
-      throw new IllegalArgumentException(String.format("Invalid criterion '%s'", criterion.trim()), e);
+      throw new IllegalArgumentException(String.format("Invalid criterion '%s'", criterion), e);
     }
   }
 
+  private List<String> searchFavoriteUuids(DbSession dbSession) {
+    List<Long> favoriteDbIds = dbClient.propertiesDao().selectByQuery(PropertyQuery.builder()
+      .setUserId(userSession.getUserId())
+      .setKey("favourite")
+      .build(), dbSession)
+      .stream()
+      .map(PropertyDto::getResourceId)
+      .collect(Collectors.toList());
+
+    return dbClient.componentDao().selectByIds(dbSession, favoriteDbIds)
+      .stream()
+      .filter(dbComponent -> Qualifiers.PROJECT.equals(dbComponent.qualifier()))
+      .map(ComponentDto::uuid)
+      .collect(Collectors.toList());
+  }
+
 }
index d8cbb5332d68249197443997a0a3878c7129c6b5..0a6e28220a4306efb82eea82b431a062aa942f51 100644 (file)
@@ -47,7 +47,6 @@ import org.sonarqube.ws.client.component.SearchProjectsRequest;
 
 import static com.google.common.base.MoreObjects.firstNonNull;
 import static org.sonar.server.component.es.ProjectMeasuresIndex.SUPPORTED_FACETS;
-import static org.sonar.server.component.ws.ProjectMeasuresQueryFactory.newProjectMeasuresQuery;
 import static org.sonar.server.ws.WsUtils.writeProtobuf;
 import static org.sonarqube.ws.client.component.ComponentsWsParameters.PARAM_FILTER;
 import static org.sonarqube.ws.client.component.SearchProjectsRequest.DEFAULT_PAGE_SIZE;
@@ -56,12 +55,15 @@ import static org.sonarqube.ws.client.component.SearchProjectsRequest.MAX_PAGE_S
 public class SearchProjectsAction implements ComponentsWsAction {
   private final DbClient dbClient;
   private final ProjectMeasuresIndex index;
-  private final ProjectMeasuresQueryValidator projectMeasuresQueryValidator;
+  private final ProjectMeasuresQueryValidator queryValidator;
+  private final ProjectMeasuresQueryFactory queryFactory;
 
-  public SearchProjectsAction(DbClient dbClient, ProjectMeasuresIndex index, ProjectMeasuresQueryValidator projectMeasuresQueryValidator) {
+  public SearchProjectsAction(DbClient dbClient, ProjectMeasuresIndex index, ProjectMeasuresQueryFactory queryFactory,
+    ProjectMeasuresQueryValidator queryValidator) {
     this.dbClient = dbClient;
     this.index = index;
-    this.projectMeasuresQueryValidator = projectMeasuresQueryValidator;
+    this.queryFactory = queryFactory;
+    this.queryValidator = queryValidator;
   }
 
   @Override
@@ -99,8 +101,8 @@ public class SearchProjectsAction implements ComponentsWsAction {
 
   private SearchResults searchProjects(DbSession dbSession, SearchProjectsRequest request) {
     String filter = firstNonNull(request.getFilter(), "");
-    ProjectMeasuresQuery query = newProjectMeasuresQuery(filter);
-    projectMeasuresQueryValidator.validate(dbSession, query);
+    ProjectMeasuresQuery query = queryFactory.newProjectMeasuresQuery(dbSession, filter);
+    queryValidator.validate(dbSession, query);
 
     SearchIdResult<String> searchResults = index.search(query, new SearchOptions()
       .addFacets(request.getFacets())
index ecfc28f97a08ed23e9d79e516f2f0236cf9631da..ac31148d9ea8ffcaf2843af147fea2d098fc57f5 100644 (file)
@@ -21,7 +21,6 @@ package org.sonar.server.component.es;
 
 import com.google.common.base.Throwables;
 import com.google.common.collect.ImmutableMap;
-import java.util.Collections;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
@@ -40,6 +39,7 @@ import org.sonar.server.permission.index.PermissionIndexerTester;
 import org.sonar.server.tester.UserSessionRule;
 
 import static com.google.common.collect.Lists.newArrayList;
+import static java.util.Collections.emptyList;
 import static java.util.Collections.singletonList;
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.entry;
@@ -197,6 +197,19 @@ public class ProjectMeasuresIndexTest {
     assertThat(result).containsExactly("P1", "P2");
   }
 
+  @Test
+  public void filter_on_ids() {
+    addDocs(
+      newDoc("P1", "K1", "N1"),
+      newDoc("P2", "K2", "N2"),
+      newDoc("P3", "K3", "N3"));
+    ProjectMeasuresQuery esQuery = new ProjectMeasuresQuery().setProjectUuids(newArrayList("P1", "P3"));
+
+    List<String> result = underTest.search(esQuery, new SearchOptions()).getIds();
+
+    assertThat(result).containsExactly("P1", "P3");
+  }
+
   @Test
   public void return_only_projects_authorized_for_user() throws Exception {
     userSession.login("john").setUserId(10);
@@ -858,8 +871,8 @@ public class ProjectMeasuresIndexTest {
       es.putDocuments(INDEX_PROJECT_MEASURES, TYPE_PROJECT_MEASURES, docs);
       for (ProjectMeasuresDoc doc : docs) {
         authorizationIndexerTester.indexProjectPermission(doc.getId(),
-          authorizedGroup != null ? singletonList(authorizedGroup) : Collections.emptyList(),
-          authorizeUser != null ? singletonList(authorizeUser) : Collections.emptyList());
+          authorizedGroup != null ? singletonList(authorizedGroup) : emptyList(),
+          authorizeUser != null ? singletonList(authorizeUser) : emptyList());
       }
     } catch (Exception e) {
       Throwables.propagate(e);
index f8dee7ef5f4b3dc94fb2c2aea283f347cbb8aa27..01c09012ce9dc389a893ce5c13ea0c358dbae964 100644 (file)
@@ -29,6 +29,6 @@ public class ComponentsWsModuleTest {
   public void verify_count_of_added_components() {
     ComponentContainer container = new ComponentContainer();
     new ComponentsWsModule().configure(container);
-    assertThat(container.size()).isEqualTo(12 + 2);
+    assertThat(container.size()).isEqualTo(13 + 2);
   }
 }
index a36265644283875884919e7a010e78a5a4d72a07..96bddea1dcc60426a5655a8d164a3f76cc77b0f9 100644 (file)
@@ -23,24 +23,36 @@ package org.sonar.server.component.ws;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.ExpectedException;
+import org.sonar.api.utils.System2;
+import org.sonar.db.DbClient;
+import org.sonar.db.DbSession;
+import org.sonar.db.DbTester;
 import org.sonar.server.component.es.ProjectMeasuresQuery;
-import org.sonar.test.TestUtils;
+import org.sonar.server.tester.UserSessionRule;
 
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.tuple;
 import static org.sonar.server.component.es.ProjectMeasuresQuery.MetricCriterion;
 import static org.sonar.server.component.es.ProjectMeasuresQuery.Operator;
-import static org.sonar.server.component.ws.ProjectMeasuresQueryFactory.newProjectMeasuresQuery;
 import static org.sonar.server.computation.task.projectanalysis.measure.Measure.Level.OK;
 
 public class ProjectMeasuresQueryFactoryTest {
 
   @Rule
   public ExpectedException expectedException = ExpectedException.none();
+  @Rule
+  public UserSessionRule userSession = UserSessionRule.standalone();
+  @Rule
+  public DbTester db = DbTester.create(System2.INSTANCE);
+
+  private DbClient dbClient = db.getDbClient();
+  private DbSession dbSession = db.getSession();
+
+  private ProjectMeasuresQueryFactory underTest = new ProjectMeasuresQueryFactory(dbClient, userSession);
 
   @Test
   public void create_query() throws Exception {
-    ProjectMeasuresQuery query = newProjectMeasuresQuery("ncloc > 10 and coverage <= 80");
+    ProjectMeasuresQuery query = underTest.newProjectMeasuresQuery(dbSession, "ncloc > 10 and coverage <= 80");
 
     assertThat(query.getMetricCriteria())
       .extracting(MetricCriterion::getMetricKey, MetricCriterion::getOperator, MetricCriterion::getValue)
@@ -51,7 +63,7 @@ public class ProjectMeasuresQueryFactoryTest {
 
   @Test
   public void create_query_having_lesser_than_operation() throws Exception {
-    ProjectMeasuresQuery query = newProjectMeasuresQuery("ncloc < 10");
+    ProjectMeasuresQuery query = underTest.newProjectMeasuresQuery(dbSession, "ncloc < 10");
 
     assertThat(query.getMetricCriteria())
       .extracting(MetricCriterion::getMetricKey, MetricCriterion::getOperator, MetricCriterion::getValue)
@@ -60,7 +72,7 @@ public class ProjectMeasuresQueryFactoryTest {
 
   @Test
   public void create_query_having_lesser_than_or_equals_operation() throws Exception {
-    ProjectMeasuresQuery query = newProjectMeasuresQuery("ncloc <= 10");
+    ProjectMeasuresQuery query = underTest.newProjectMeasuresQuery(dbSession, "ncloc <= 10");
 
     assertThat(query.getMetricCriteria())
       .extracting(MetricCriterion::getMetricKey, MetricCriterion::getOperator, MetricCriterion::getValue)
@@ -69,7 +81,7 @@ public class ProjectMeasuresQueryFactoryTest {
 
   @Test
   public void create_query_having_greater_than_operation() throws Exception {
-    ProjectMeasuresQuery query = newProjectMeasuresQuery("ncloc > 10");
+    ProjectMeasuresQuery query = underTest.newProjectMeasuresQuery(dbSession, "ncloc > 10");
 
     assertThat(query.getMetricCriteria())
       .extracting(MetricCriterion::getMetricKey, MetricCriterion::getOperator, MetricCriterion::getValue)
@@ -78,7 +90,7 @@ public class ProjectMeasuresQueryFactoryTest {
 
   @Test
   public void create_query_having_greater_than_or_equals_operation() throws Exception {
-    ProjectMeasuresQuery query = newProjectMeasuresQuery("ncloc >= 10");
+    ProjectMeasuresQuery query = underTest.newProjectMeasuresQuery(dbSession, "ncloc >= 10");
 
     assertThat(query.getMetricCriteria())
       .extracting(MetricCriterion::getMetricKey, MetricCriterion::getOperator, MetricCriterion::getValue)
@@ -87,7 +99,7 @@ public class ProjectMeasuresQueryFactoryTest {
 
   @Test
   public void create_query_having_equal_operation() throws Exception {
-    ProjectMeasuresQuery query = newProjectMeasuresQuery("ncloc = 10");
+    ProjectMeasuresQuery query = underTest.newProjectMeasuresQuery(dbSession, "ncloc = 10");
 
     assertThat(query.getMetricCriteria())
       .extracting(MetricCriterion::getMetricKey, MetricCriterion::getOperator, MetricCriterion::getValue)
@@ -96,25 +108,39 @@ public class ProjectMeasuresQueryFactoryTest {
 
   @Test
   public void create_query_on_quality_gate() throws Exception {
-    ProjectMeasuresQuery query = newProjectMeasuresQuery("alert_status = OK");
+    ProjectMeasuresQuery query = underTest.newProjectMeasuresQuery(dbSession, "alert_status = OK");
 
     assertThat(query.getQualityGateStatus().name()).isEqualTo(OK.name());
   }
 
+  @Test
+  public void query_without_favorites_by_default() {
+    ProjectMeasuresQuery query = underTest.newProjectMeasuresQuery(dbSession, "ncloc = 10");
+
+    assertThat(query.doesFilterOnProjectUuids()).isFalse();
+  }
+
+  @Test
+  public void create_query_with_favorites() throws Exception {
+    ProjectMeasuresQuery query = underTest.newProjectMeasuresQuery(dbSession, "isFavorite");
+
+    assertThat(query.doesFilterOnProjectUuids()).isTrue();
+  }
+
   @Test
   public void fail_to_create_query_on_quality_gate_when_operator_is_not_equal() throws Exception {
     expectedException.expect(IllegalArgumentException.class);
-    newProjectMeasuresQuery("alert_status > OK");
+    underTest.newProjectMeasuresQuery(dbSession, "alert_status > OK");
   }
 
   @Test
   public void search_is_case_insensitive() throws Exception {
-    assertThat(newProjectMeasuresQuery("ncloc > 10 AnD coverage <= 80 AND debt = 10 AND issues = 20").getMetricCriteria()).hasSize(4);
+    assertThat(underTest.newProjectMeasuresQuery(dbSession, "ncloc > 10 AnD coverage <= 80 AND debt = 10 AND issues = 20").getMetricCriteria()).hasSize(4);
   }
 
   @Test
   public void convert_metric_to_lower_case() throws Exception {
-    assertThat(newProjectMeasuresQuery("NCLOC > 10 AND coVERage <= 80").getMetricCriteria())
+    assertThat(underTest.newProjectMeasuresQuery(dbSession, "NCLOC > 10 AND coVERage <= 80").getMetricCriteria())
       .extracting(MetricCriterion::getMetricKey, MetricCriterion::getOperator, MetricCriterion::getValue)
       .containsOnly(
         tuple("ncloc", Operator.GT, 10d),
@@ -123,14 +149,14 @@ public class ProjectMeasuresQueryFactoryTest {
 
   @Test
   public void ignore_white_spaces() throws Exception {
-    assertThat(newProjectMeasuresQuery("   ncloc    >    10   ").getMetricCriteria())
+    assertThat(underTest.newProjectMeasuresQuery(dbSession, "   ncloc    >    10   ").getMetricCriteria())
       .extracting(MetricCriterion::getMetricKey, MetricCriterion::getOperator, MetricCriterion::getValue)
       .containsOnly(tuple("ncloc", Operator.GT, 10d));
   }
 
   @Test
   public void accept_empty_query() throws Exception {
-    ProjectMeasuresQuery result = newProjectMeasuresQuery("");
+    ProjectMeasuresQuery result = underTest.newProjectMeasuresQuery(dbSession, "");
 
     assertThat(result.getMetricCriteria()).isEmpty();
   }
@@ -139,39 +165,42 @@ public class ProjectMeasuresQueryFactoryTest {
   public void fail_on_invalid_criteria() throws Exception {
     expectedException.expect(IllegalArgumentException.class);
     expectedException.expectMessage("Invalid criterion 'ncloc ? 10'");
-    newProjectMeasuresQuery("ncloc ? 10");
+    underTest.newProjectMeasuresQuery(dbSession, "ncloc ? 10");
+  }
+
+  @Test
+  public void fail_on_invalid_criteria_ignore_whitespaces() {
+    expectedException.expect(IllegalArgumentException.class);
+    expectedException.expectMessage("Invalid criterion 'ncloc ? 10'");
+
+    underTest.newProjectMeasuresQuery(dbSession, "    ncloc ? 10    ");
   }
 
   @Test
   public void fail_when_not_double() throws Exception {
     expectedException.expect(IllegalArgumentException.class);
     expectedException.expectMessage("Invalid criterion 'ncloc > ten'");
-    newProjectMeasuresQuery("ncloc > ten");
+    underTest.newProjectMeasuresQuery(dbSession, "ncloc > ten");
   }
 
   @Test
   public void fail_when_no_operator() throws Exception {
     expectedException.expect(IllegalArgumentException.class);
     expectedException.expectMessage("Invalid criterion 'ncloc 10'");
-    newProjectMeasuresQuery("ncloc 10");
+    underTest.newProjectMeasuresQuery(dbSession, "ncloc 10");
   }
 
   @Test
   public void fail_when_no_key() throws Exception {
     expectedException.expect(IllegalArgumentException.class);
     expectedException.expectMessage("Invalid criterion '>= 10'");
-    newProjectMeasuresQuery(">= 10");
+    underTest.newProjectMeasuresQuery(dbSession, ">= 10");
   }
 
   @Test
   public void fail_when_no_value() throws Exception {
     expectedException.expect(IllegalArgumentException.class);
     expectedException.expectMessage("Invalid criterion 'ncloc >='");
-    newProjectMeasuresQuery("ncloc >=");
-  }
-
-  @Test
-  public void private_constructor() {
-    assertThat(TestUtils.hasOnlyPrivateConstructors(ProjectMeasuresQueryFactory.class)).isTrue();
+    underTest.newProjectMeasuresQuery(dbSession, "ncloc >=");
   }
 }
index 618d8bc253203a0263bd51a11a6b93b70a78dba4..33de8438bce21abeec19d973d8581a08e3437953 100644 (file)
@@ -28,6 +28,7 @@ import org.sonar.db.DbClient;
 import org.sonar.db.DbSession;
 import org.sonar.db.DbTester;
 import org.sonar.db.metric.MetricDto;
+import org.sonar.server.tester.UserSessionRule;
 
 import static org.sonar.api.measures.Metric.ValueType.DATA;
 import static org.sonar.api.measures.Metric.ValueType.DISTRIB;
@@ -35,31 +36,34 @@ import static org.sonar.api.measures.Metric.ValueType.INT;
 import static org.sonar.api.measures.Metric.ValueType.STRING;
 import static org.sonar.api.measures.Metric.ValueType.WORK_DUR;
 import static org.sonar.db.metric.MetricTesting.newMetricDto;
-import static org.sonar.server.component.ws.ProjectMeasuresQueryFactory.newProjectMeasuresQuery;
 
 public class ProjectMeasuresQueryValidatorTest {
 
   @Rule
   public ExpectedException expectedException = ExpectedException.none();
 
+  @Rule
+  public UserSessionRule userSession = UserSessionRule.standalone();
+
   @Rule
   public DbTester db = DbTester.create(System2.INSTANCE);
 
-  DbClient dbClient = db.getDbClient();
-  DbSession dbSession = db.getSession();
+  private DbClient dbClient = db.getDbClient();
+  private DbSession dbSession = db.getSession();
+  private ProjectMeasuresQueryFactory queryFactory = new ProjectMeasuresQueryFactory(dbClient, userSession);
 
-  ProjectMeasuresQueryValidator validator = new ProjectMeasuresQueryValidator(dbClient);
+  private ProjectMeasuresQueryValidator underTest = new ProjectMeasuresQueryValidator(dbClient);
 
   @Test
   public void query_with_empty_metrics_is_valid() throws Exception {
-    validator.validate(dbSession, newProjectMeasuresQuery(""));
+    underTest.validate(dbSession, queryFactory.newProjectMeasuresQuery(dbSession, ""));
   }
 
   @Test
   public void does_not_fail_when_metric_criteria_contains_an_existing_metric() throws Exception {
     insertValidMetric("ncloc");
 
-    validator.validate(dbSession, newProjectMeasuresQuery("ncloc > 10"));
+    underTest.validate(dbSession, queryFactory.newProjectMeasuresQuery(dbSession, "ncloc > 10"));
   }
 
   @Test
@@ -72,7 +76,7 @@ public class ProjectMeasuresQueryValidatorTest {
 
     expectedException.expect(IllegalArgumentException.class);
     expectedException.expectMessage("Following metrics are not numeric : [data, distrib, string]");
-    validator.validate(dbSession, newProjectMeasuresQuery("data > 10 and distrib = 11 and ncloc <= 20 and debt < 30 and string = 40"));
+    underTest.validate(dbSession, queryFactory.newProjectMeasuresQuery(dbSession, "data > 10 and distrib = 11 and ncloc <= 20 and debt < 30 and string = 40"));
   }
 
   @Test
@@ -81,7 +85,7 @@ public class ProjectMeasuresQueryValidatorTest {
 
     expectedException.expect(IllegalArgumentException.class);
     expectedException.expectMessage("Following metrics are disabled : [ncloc]");
-    validator.validate(dbSession, newProjectMeasuresQuery("ncloc > 10"));
+    underTest.validate(dbSession, queryFactory.newProjectMeasuresQuery(dbSession, "ncloc > 10"));
   }
 
   @Test
@@ -90,7 +94,7 @@ public class ProjectMeasuresQueryValidatorTest {
 
     expectedException.expect(IllegalArgumentException.class);
     expectedException.expectMessage("Unknown metric(s) [unknown]");
-    validator.validate(dbSession, newProjectMeasuresQuery("unknown > 10"));
+    underTest.validate(dbSession, queryFactory.newProjectMeasuresQuery(dbSession, "unknown > 10"));
   }
 
   @Test
@@ -99,7 +103,7 @@ public class ProjectMeasuresQueryValidatorTest {
 
     expectedException.expect(IllegalArgumentException.class);
     expectedException.expectMessage("Unknown metric(s) [coverage, debt]");
-    validator.validate(dbSession, newProjectMeasuresQuery("debt > 10 AND ncloc <= 20 AND coverage > 30"));
+    underTest.validate(dbSession, queryFactory.newProjectMeasuresQuery(dbSession, "debt > 10 AND ncloc <= 20 AND coverage > 30"));
   }
 
   private void insertValidMetric(String metricKey) {
index d1576249ee9702d38ce9c1037531f170aae541e2..a826c026480e0a9ceccbc17295022811c5da6031 100644 (file)
@@ -42,6 +42,7 @@ import org.sonar.db.DbSession;
 import org.sonar.db.DbTester;
 import org.sonar.db.component.ComponentDbTester;
 import org.sonar.db.component.ComponentDto;
+import org.sonar.db.property.PropertyDto;
 import org.sonar.server.component.es.ProjectMeasuresDoc;
 import org.sonar.server.component.es.ProjectMeasuresIndex;
 import org.sonar.server.component.es.ProjectMeasuresIndexDefinition;
@@ -82,7 +83,7 @@ public class SearchProjectsActionTest {
   public ExpectedException expectedException = ExpectedException.none();
 
   @Rule
-  public UserSessionRule userSession = UserSessionRule.standalone();
+  public UserSessionRule userSession = UserSessionRule.standalone().login().setUserId(23);
 
   @Rule
   public EsTester es = new EsTester(new ProjectMeasuresIndexDefinition(new MapSettings()));
@@ -95,9 +96,12 @@ public class SearchProjectsActionTest {
   private DbSession dbSession = db.getSession();
 
   private PermissionIndexerTester authorizationIndexerTester = new PermissionIndexerTester(es);
+  private final ProjectMeasuresIndex index = new ProjectMeasuresIndex(es.client(), userSession);
+  private ProjectMeasuresQueryFactory queryFactory = new ProjectMeasuresQueryFactory(dbClient, userSession);
+  private final ProjectMeasuresQueryValidator queryValidator = new ProjectMeasuresQueryValidator(dbClient);
 
   private WsActionTester ws = new WsActionTester(
-    new SearchProjectsAction(dbClient, new ProjectMeasuresIndex(es.client(), userSession), new ProjectMeasuresQueryValidator(dbClient)));
+    new SearchProjectsAction(dbClient, index, queryFactory, queryValidator));
 
   private SearchProjectsRequest.Builder request = SearchProjectsRequest.builder();
 
@@ -186,6 +190,22 @@ public class SearchProjectsActionTest {
     assertThat(result.getComponents(0).getName()).isEqualTo("Sonar Markdown");
   }
 
+  @Test
+  public void filter_projects_on_favorites() {
+    long javaId = insertProjectInDbAndEs(newProjectDto("java-id").setName("Sonar Java"), newArrayList(newMeasure(COVERAGE, 81), newMeasure(NCLOC, 10_000d)));
+    long markDownId = insertProjectInDbAndEs(newProjectDto("markdown-id").setName("Sonar Markdown"), newArrayList(newMeasure(COVERAGE, 80d), newMeasure(NCLOC, 10_000d)));
+    insertProjectInDbAndEs(newProjectDto().setName("Sonar Qube"), newArrayList(newMeasure(COVERAGE, 80d), newMeasure(NCLOC, 10_001d)));
+    dbClient.propertiesDao().saveProperty(dbSession, new PropertyDto().setKey("favourite").setResourceId(javaId).setUserId(Long.valueOf(userSession.getUserId())));
+    dbClient.propertiesDao().saveProperty(dbSession, new PropertyDto().setKey("favourite").setResourceId(markDownId).setUserId(Long.valueOf(userSession.getUserId())));
+    dbSession.commit();
+    request.setFilter("isFavorite");
+
+    SearchProjectsWsResponse result = call(request);
+
+    assertThat(result.getComponentsCount()).isEqualTo(2);
+    assertThat(result.getComponentsList()).extracting(Component::getId).containsExactly("java-id", "markdown-id");
+  }
+
   @Test
   public void return_nloc_facet() {
     insertProjectInDbAndEs(newProjectDto().setName("Sonar Java"), newArrayList(newMeasure(COVERAGE, 81), newMeasure(NCLOC, 5d)));
@@ -262,7 +282,7 @@ public class SearchProjectsActionTest {
     insertProjectInDbAndEs(project, emptyList());
   }
 
-  private void insertProjectInDbAndEs(ComponentDto project, List<Map<String, Object>> measures) {
+  private long insertProjectInDbAndEs(ComponentDto project, List<Map<String, Object>> measures) {
     componentDb.insertComponent(project);
     try {
       es.putDocuments(INDEX_PROJECT_MEASURES, TYPE_PROJECT_MEASURES,
@@ -271,6 +291,8 @@ public class SearchProjectsActionTest {
     } catch (Exception e) {
       Throwables.propagate(e);
     }
+
+    return project.getId();
   }
 
   private void insertMetrics(String... metricKeys) {