]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-8287 Refactor project measures index and WS domain
authorTeryk Bellahsene <teryk.bellahsene@sonarsource.com>
Tue, 18 Oct 2016 08:51:04 +0000 (10:51 +0200)
committerTeryk Bellahsene <teryk.bellahsene@sonarsource.com>
Tue, 18 Oct 2016 15:01:46 +0000 (17:01 +0200)
50 files changed:
server/sonar-ce/src/main/java/org/sonar/ce/container/ComputeEngineContainerImpl.java
server/sonar-server/src/main/java/org/sonar/server/component/ComponentCleanerService.java
server/sonar-server/src/main/java/org/sonar/server/component/ComponentService.java
server/sonar-server/src/main/java/org/sonar/server/component/es/ProjectMeasuresDoc.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/component/es/ProjectMeasuresIndex.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/component/es/ProjectMeasuresIndexDefinition.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/component/es/ProjectMeasuresIndexer.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/component/es/ProjectMeasuresQuery.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/component/es/ProjectMeasuresResultSetIterator.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/component/es/ProjectsEsModule.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/component/es/package-info.java [new file with mode: 0644]
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 [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/component/ws/ProjectMeasuresQueryValidator.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/component/ws/SearchProjectsAction.java
server/sonar-server/src/main/java/org/sonar/server/component/ws/SearchProjectsQueryBuilder.java [deleted file]
server/sonar-server/src/main/java/org/sonar/server/component/ws/SearchProjectsQueryBuilderValidator.java [deleted file]
server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/IndexProjectMeasuresStep.java
server/sonar-server/src/main/java/org/sonar/server/es/IndexerStartupTask.java
server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java
server/sonar-server/src/main/java/org/sonar/server/project/es/ProjectMeasuresDoc.java [deleted file]
server/sonar-server/src/main/java/org/sonar/server/project/es/ProjectMeasuresIndex.java [deleted file]
server/sonar-server/src/main/java/org/sonar/server/project/es/ProjectMeasuresIndexDefinition.java [deleted file]
server/sonar-server/src/main/java/org/sonar/server/project/es/ProjectMeasuresIndexer.java [deleted file]
server/sonar-server/src/main/java/org/sonar/server/project/es/ProjectMeasuresResultSetIterator.java [deleted file]
server/sonar-server/src/main/java/org/sonar/server/project/es/ProjectsEsModule.java [deleted file]
server/sonar-server/src/main/java/org/sonar/server/project/es/package-info.java [deleted file]
server/sonar-server/src/test/java/org/sonar/server/component/ComponentCleanerServiceTest.java
server/sonar-server/src/test/java/org/sonar/server/component/ComponentServiceTest.java
server/sonar-server/src/test/java/org/sonar/server/component/ComponentServiceUpdateKeyTest.java
server/sonar-server/src/test/java/org/sonar/server/component/DefaultRubyComponentServiceTest.java
server/sonar-server/src/test/java/org/sonar/server/component/es/ProjectMeasuresIndexTest.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/component/es/ProjectMeasuresIndexerTest.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/component/es/ProjectMeasuresResultSetIteratorTest.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/component/es/ProjectsEsModuleTest.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/component/ws/BulkUpdateKeyActionTest.java
server/sonar-server/src/test/java/org/sonar/server/component/ws/ProjectMeasuresQueryFactoryTest.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/component/ws/ProjectMeasuresQueryFactoryValidatorTest.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/component/ws/SearchProjectsActionTest.java
server/sonar-server/src/test/java/org/sonar/server/component/ws/SearchProjectsQueryBuilderTest.java [deleted file]
server/sonar-server/src/test/java/org/sonar/server/component/ws/SearchProjectsQueryBuilderValidatorTest.java [deleted file]
server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/IndexProjectMeasuresStepTest.java
server/sonar-server/src/test/java/org/sonar/server/project/es/ProjectMeasuresIndexTest.java [deleted file]
server/sonar-server/src/test/java/org/sonar/server/project/es/ProjectMeasuresIndexerTest.java [deleted file]
server/sonar-server/src/test/java/org/sonar/server/project/es/ProjectMeasuresResultSetIteratorTest.java [deleted file]
server/sonar-server/src/test/java/org/sonar/server/project/es/ProjectsEsModuleTest.java [deleted file]
server/sonar-server/src/test/java/org/sonar/server/project/ws/BulkDeleteActionTest.java
server/sonar-server/src/test/java/org/sonar/server/project/ws/DeleteActionTest.java
server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/AddProjectActionTest.java
sonar-ws/src/main/java/org/sonarqube/ws/client/component/SearchProjectsRequest.java

index 4394911e903a9be6684d4ef22947f988317f8003..6dbda3f2f7375ea6fda3124b502547d60ea60a06 100644 (file)
@@ -116,7 +116,7 @@ import org.sonar.server.plugins.InstalledPluginReferentialFactory;
 import org.sonar.server.plugins.ServerExtensionInstaller;
 import org.sonar.server.plugins.privileged.PrivilegedPluginsBootstraper;
 import org.sonar.server.plugins.privileged.PrivilegedPluginsStopper;
-import org.sonar.server.project.es.ProjectMeasuresIndexer;
+import org.sonar.server.component.es.ProjectMeasuresIndexer;
 import org.sonar.server.property.InternalPropertiesImpl;
 import org.sonar.server.qualityprofile.QProfileLookup;
 import org.sonar.server.qualityprofile.QProfileProjectOperations;
index 11153d2bbb4d898739523fe36ac8167877f479dc..2ad193b9ccf03c4600d8d67bde4ba74a07c26d13 100644 (file)
@@ -31,7 +31,7 @@ import org.sonar.db.MyBatis;
 import org.sonar.db.component.ComponentDto;
 import org.sonar.server.issue.index.IssueAuthorizationIndexer;
 import org.sonar.server.issue.index.IssueIndexer;
-import org.sonar.server.project.es.ProjectMeasuresIndexer;
+import org.sonar.server.component.es.ProjectMeasuresIndexer;
 import org.sonar.server.test.index.TestIndexer;
 
 @ServerSide
index 184a7b8ed37c645e1d9864b9c8305f5d05687b28..1e713c826256b79344ab3d26dc7490e849a98295 100644 (file)
@@ -42,9 +42,9 @@ import org.sonar.core.util.Uuids;
 import org.sonar.db.DbClient;
 import org.sonar.db.DbSession;
 import org.sonar.db.component.ComponentDto;
+import org.sonar.server.component.es.ProjectMeasuresIndexer;
 import org.sonar.server.exceptions.BadRequestException;
 import org.sonar.server.exceptions.NotFoundException;
-import org.sonar.server.project.es.ProjectMeasuresIndexer;
 import org.sonar.server.user.UserSession;
 
 import static com.google.common.collect.Lists.newArrayList;
diff --git a/server/sonar-server/src/main/java/org/sonar/server/component/es/ProjectMeasuresDoc.java b/server/sonar-server/src/main/java/org/sonar/server/component/es/ProjectMeasuresDoc.java
new file mode 100644 (file)
index 0000000..a844c81
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * 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.component.es;
+
+import java.util.Collection;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
+import org.sonar.server.es.BaseDoc;
+
+import static org.sonar.server.component.es.ProjectMeasuresIndexDefinition.FIELD_MEASURES;
+
+public class ProjectMeasuresDoc extends BaseDoc {
+
+  public ProjectMeasuresDoc() {
+    super(new HashMap<>(4));
+  }
+
+  @Override
+  public String getId() {
+    return getField("_id");
+  }
+
+  @Override
+  public String getRouting() {
+    return null;
+  }
+
+  @Override
+  public String getParent() {
+    return null;
+  }
+
+  public ProjectMeasuresDoc setId(String s) {
+    setField("_id", s);
+    return this;
+  }
+
+  public String getKey() {
+    return getField(ProjectMeasuresIndexDefinition.FIELD_KEY);
+  }
+
+  public ProjectMeasuresDoc setKey(String s) {
+    setField(ProjectMeasuresIndexDefinition.FIELD_KEY, s);
+    return this;
+  }
+
+  public String getName() {
+    return getField(ProjectMeasuresIndexDefinition.FIELD_NAME);
+  }
+
+  public ProjectMeasuresDoc setName(String s) {
+    setField(ProjectMeasuresIndexDefinition.FIELD_NAME, s);
+    return this;
+  }
+
+  @CheckForNull
+  public Date getAnalysedAt() {
+    return getNullableField(ProjectMeasuresIndexDefinition.FIELD_ANALYSED_AT);
+  }
+
+  public ProjectMeasuresDoc setAnalysedAt(@Nullable Date d) {
+    setField(ProjectMeasuresIndexDefinition.FIELD_ANALYSED_AT, d);
+    return this;
+  }
+
+  public Collection<Map<String, Object>> getMeasures() {
+    return getField(FIELD_MEASURES);
+  }
+
+  public ProjectMeasuresDoc setMeasures(Collection<Map<String, Object>> measures) {
+    setField(FIELD_MEASURES, measures);
+    return this;
+  }
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/component/es/ProjectMeasuresIndex.java b/server/sonar-server/src/main/java/org/sonar/server/component/es/ProjectMeasuresIndex.java
new file mode 100644 (file)
index 0000000..dd24c4a
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * 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.component.es;
+
+import org.elasticsearch.action.search.SearchRequestBuilder;
+import org.elasticsearch.index.query.BoolQueryBuilder;
+import org.elasticsearch.index.query.QueryBuilder;
+import org.elasticsearch.search.sort.SortOrder;
+import org.sonar.server.component.es.ProjectMeasuresQuery.MetricCriteria;
+import org.sonar.server.es.BaseIndex;
+import org.sonar.server.es.EsClient;
+import org.sonar.server.es.SearchIdResult;
+import org.sonar.server.es.SearchOptions;
+
+import static org.elasticsearch.index.query.QueryBuilders.boolQuery;
+import static org.elasticsearch.index.query.QueryBuilders.matchAllQuery;
+import static org.elasticsearch.index.query.QueryBuilders.nestedQuery;
+import static org.elasticsearch.index.query.QueryBuilders.rangeQuery;
+import static org.elasticsearch.index.query.QueryBuilders.termQuery;
+import static org.sonar.server.component.es.ProjectMeasuresIndexDefinition.FIELD_MEASURES;
+import static org.sonar.server.component.es.ProjectMeasuresIndexDefinition.FIELD_MEASURES_KEY;
+import static org.sonar.server.component.es.ProjectMeasuresIndexDefinition.FIELD_MEASURES_VALUE;
+import static org.sonar.server.component.es.ProjectMeasuresIndexDefinition.FIELD_NAME;
+import static org.sonar.server.component.es.ProjectMeasuresIndexDefinition.INDEX_PROJECT_MEASURES;
+import static org.sonar.server.component.es.ProjectMeasuresIndexDefinition.TYPE_PROJECT_MEASURES;
+
+public class ProjectMeasuresIndex extends BaseIndex {
+
+  private static final String FIELD_KEY = FIELD_MEASURES + "." + FIELD_MEASURES_KEY;
+  private static final String FIELD_VALUE = FIELD_MEASURES + "." + FIELD_MEASURES_VALUE;
+
+  public ProjectMeasuresIndex(EsClient client) {
+    super(client);
+  }
+
+  public SearchIdResult<String> search(ProjectMeasuresQuery query, SearchOptions searchOptions) {
+    BoolQueryBuilder metricFilters = boolQuery();
+    query.getMetricCriteria().stream()
+      .map(criteria -> nestedQuery(FIELD_MEASURES, boolQuery()
+        .filter(termQuery(FIELD_KEY, criteria.getMetricKey()))
+        .filter(toValueQuery(criteria))))
+      .forEach(metricFilters::filter);
+    QueryBuilder esQuery = query.getMetricCriteria().isEmpty() ? matchAllQuery() : metricFilters;
+
+    SearchRequestBuilder request = getClient()
+      .prepareSearch(INDEX_PROJECT_MEASURES)
+      .setTypes(TYPE_PROJECT_MEASURES)
+      .setFetchSource(false)
+      .setQuery(esQuery)
+      .setFrom(searchOptions.getOffset())
+      .setSize(searchOptions.getLimit())
+      .addSort(FIELD_NAME + "." + SORT_SUFFIX, SortOrder.ASC);
+
+    return new SearchIdResult<>(request.get(), id -> id);
+  }
+
+  private static QueryBuilder toValueQuery(MetricCriteria criteria) {
+    String fieldName = FIELD_VALUE;
+
+    switch (criteria.getOperator()) {
+      case GT:
+        return rangeQuery(fieldName).gt(criteria.getValue());
+      case LTE:
+        return rangeQuery(fieldName).lte(criteria.getValue());
+      default:
+        throw new IllegalStateException("Metric criteria non supported: " + criteria.getOperator().name());
+    }
+
+  }
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/component/es/ProjectMeasuresIndexDefinition.java b/server/sonar-server/src/main/java/org/sonar/server/component/es/ProjectMeasuresIndexDefinition.java
new file mode 100644 (file)
index 0000000..6fab7e6
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * 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.component.es;
+
+import org.sonar.api.config.Settings;
+import org.sonar.server.es.IndexDefinition;
+import org.sonar.server.es.NewIndex;
+
+public class ProjectMeasuresIndexDefinition implements IndexDefinition {
+
+  public static final String INDEX_PROJECT_MEASURES = "projectmeasures";
+  public static final String TYPE_PROJECT_MEASURES = "projectmeasures";
+  public static final String FIELD_KEY = "key";
+  public static final String FIELD_NAME = "name";
+  public static final String FIELD_ANALYSED_AT = "analysedAt";
+  public static final String FIELD_MEASURES = "measures";
+  public static final String FIELD_MEASURES_KEY = "key";
+  public static final String FIELD_MEASURES_VALUE = "value";
+
+  private final Settings settings;
+
+  public ProjectMeasuresIndexDefinition(Settings settings) {
+    this.settings = settings;
+  }
+
+  @Override
+  public void define(IndexDefinitionContext context) {
+    NewIndex index = context.create(INDEX_PROJECT_MEASURES);
+    index.refreshHandledByIndexer();
+    index.configureShards(settings, 5);
+
+    NewIndex.NewIndexType mapping = index.createType(TYPE_PROJECT_MEASURES);
+    mapping.stringFieldBuilder(FIELD_KEY).disableNorms().build();
+    mapping.stringFieldBuilder(FIELD_NAME).enableSorting().enableGramSearch().build();
+    mapping.createDateTimeField(FIELD_ANALYSED_AT);
+    mapping.nestedFieldBuilder(FIELD_MEASURES)
+      .addStringFied(FIELD_MEASURES_KEY)
+      .addStringFied(FIELD_MEASURES_VALUE)
+      .build();
+
+    // do not store document but only indexation of information
+    mapping.setEnableSource(false);
+  }
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/component/es/ProjectMeasuresIndexer.java b/server/sonar-server/src/main/java/org/sonar/server/component/es/ProjectMeasuresIndexer.java
new file mode 100644 (file)
index 0000000..b6b91e6
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * 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.component.es;
+
+import java.util.Date;
+import java.util.Iterator;
+import javax.annotation.Nullable;
+import org.elasticsearch.action.index.IndexRequest;
+import org.sonar.db.DbClient;
+import org.sonar.db.DbSession;
+import org.sonar.server.es.BaseIndexer;
+import org.sonar.server.es.BulkIndexer;
+import org.sonar.server.es.EsClient;
+
+import static org.sonar.server.component.es.ProjectMeasuresIndexDefinition.FIELD_ANALYSED_AT;
+import static org.sonar.server.component.es.ProjectMeasuresIndexDefinition.INDEX_PROJECT_MEASURES;
+import static org.sonar.server.component.es.ProjectMeasuresIndexDefinition.TYPE_PROJECT_MEASURES;
+
+public class ProjectMeasuresIndexer extends BaseIndexer {
+
+  private final DbClient dbClient;
+
+  public ProjectMeasuresIndexer(DbClient dbClient, EsClient esClient) {
+    super(esClient, 300, INDEX_PROJECT_MEASURES, TYPE_PROJECT_MEASURES, FIELD_ANALYSED_AT);
+    this.dbClient = dbClient;
+  }
+
+  @Override
+  protected long doIndex(long lastUpdatedAt) {
+    return doIndex(createBulkIndexer(false), lastUpdatedAt, null);
+  }
+
+  public void index(String projectUuid) {
+    doIndex(createBulkIndexer(false), 0L, projectUuid);
+  }
+
+  public void deleteProject(String uuid) {
+    esClient
+      .prepareDelete(INDEX_PROJECT_MEASURES, TYPE_PROJECT_MEASURES, uuid)
+      .setRefresh(true)
+      .get();
+  }
+
+  private long doIndex(BulkIndexer bulk, long lastUpdatedAt, @Nullable String projectUuid) {
+    try (DbSession dbSession = dbClient.openSession(false)) {
+      ProjectMeasuresResultSetIterator rowIt = ProjectMeasuresResultSetIterator.create(dbClient, dbSession, lastUpdatedAt, projectUuid);
+      long maxDate = doIndex(bulk, rowIt);
+      rowIt.close();
+      return maxDate;
+    }
+  }
+
+  private static long doIndex(BulkIndexer bulk, Iterator<ProjectMeasuresDoc> docs) {
+    bulk.start();
+    long maxDate = 0L;
+    while (docs.hasNext()) {
+      ProjectMeasuresDoc doc = docs.next();
+      bulk.add(newIndexRequest(doc));
+
+      Date analysisDate = doc.getAnalysedAt();
+      // it's more efficient to sort programmatically than in SQL on some databases (MySQL for instance)
+      maxDate = Math.max(maxDate, analysisDate == null ? 0L : analysisDate.getTime());
+    }
+    bulk.stop();
+    return maxDate;
+  }
+
+  private BulkIndexer createBulkIndexer(boolean large) {
+    BulkIndexer bulk = new BulkIndexer(esClient, INDEX_PROJECT_MEASURES);
+    bulk.setLarge(large);
+    return bulk;
+  }
+
+  private static IndexRequest newIndexRequest(ProjectMeasuresDoc doc) {
+    return new IndexRequest(INDEX_PROJECT_MEASURES, TYPE_PROJECT_MEASURES, doc.getId())
+      .source(doc.getFields());
+  }
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/component/es/ProjectMeasuresQuery.java b/server/sonar-server/src/main/java/org/sonar/server/component/es/ProjectMeasuresQuery.java
new file mode 100644 (file)
index 0000000..0c152ed
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * 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.component.es;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static java.lang.String.format;
+import static java.util.Arrays.stream;
+
+public class ProjectMeasuresQuery {
+  private List<MetricCriteria> metricCriteria = new ArrayList<>();
+
+  public ProjectMeasuresQuery addMetricCriterion(MetricCriteria metricCriteria) {
+    this.metricCriteria.add(metricCriteria);
+    return this;
+  }
+
+  public List<MetricCriteria> getMetricCriteria() {
+    return metricCriteria;
+  }
+
+  public enum Operator {
+    LTE("<="), GT(">");
+
+    String value;
+
+    Operator(String value) {
+      this.value = value;
+    }
+
+    String getValue() {
+      return value;
+    }
+
+    public static Operator getByValue(String value) {
+      return stream(Operator.values())
+        .filter(operator -> operator.getValue().equals(value))
+        .findFirst()
+        .orElseThrow(() -> new IllegalArgumentException(format("Unknown operator '%s'", value)));
+    }
+  }
+
+  public static class MetricCriteria {
+    private final String metricKey;
+    private final Operator operator;
+    private final double value;
+
+    public MetricCriteria(String metricKey, Operator operator, double value) {
+      this.metricKey = metricKey;
+      this.operator = operator;
+      this.value = value;
+    }
+
+    public String getMetricKey() {
+      return metricKey;
+    }
+
+    public Operator getOperator() {
+      return operator;
+    }
+
+    public double getValue() {
+      return value;
+    }
+  }
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/component/es/ProjectMeasuresResultSetIterator.java b/server/sonar-server/src/main/java/org/sonar/server/component/es/ProjectMeasuresResultSetIterator.java
new file mode 100644 (file)
index 0000000..72d8bbb
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * 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.component.es;
+
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.Date;
+import javax.annotation.Nullable;
+import org.apache.commons.lang.StringUtils;
+import org.sonar.api.resources.Qualifiers;
+import org.sonar.api.resources.Scopes;
+import org.sonar.db.DbClient;
+import org.sonar.db.DbSession;
+import org.sonar.db.ResultSetIterator;
+
+public class ProjectMeasuresResultSetIterator extends ResultSetIterator<ProjectMeasuresDoc> {
+
+  private static final String[] FIELDS = {
+    "p.uuid",
+    "p.kee",
+    "p.name",
+    "s.created_at"
+  };
+
+  private static final String SQL_ALL = "SELECT " + StringUtils.join(FIELDS, ",") + " FROM projects p " +
+    "LEFT OUTER JOIN snapshots s ON s.component_uuid=p.uuid AND s.islast=? " +
+    "WHERE p.enabled=? AND p.scope=? AND p.qualifier=?";
+
+  private static final String DATE_FILTER = " AND s.created_at>?";
+
+  private static final String PROJECT_FILTER = " AND p.uuid=?";
+
+  private ProjectMeasuresResultSetIterator(PreparedStatement stmt) throws SQLException {
+    super(stmt);
+  }
+
+  static ProjectMeasuresResultSetIterator create(DbClient dbClient, DbSession session, long afterDate, @Nullable String projectUuid) {
+    try {
+      String sql = SQL_ALL;
+      sql += afterDate <= 0L ? "" : DATE_FILTER;
+      sql += projectUuid == null ? "" : PROJECT_FILTER;
+      PreparedStatement stmt = dbClient.getMyBatis().newScrollingSelectStatement(session, sql);
+      stmt.setBoolean(1, true);
+      stmt.setBoolean(2, true);
+      stmt.setString(3, Scopes.PROJECT);
+      stmt.setString(4, Qualifiers.PROJECT);
+      int index = 5;
+      if (afterDate > 0L) {
+        stmt.setLong(index, afterDate);
+        index++;
+      }
+      if (projectUuid != null) {
+        stmt.setString(index, projectUuid);
+      }
+      return new ProjectMeasuresResultSetIterator(stmt);
+    } catch (SQLException e) {
+      throw new IllegalStateException("Fail to prepare SQL request to select all project measures", e);
+    }
+  }
+
+  @Override
+  protected ProjectMeasuresDoc read(ResultSet rs) throws SQLException {
+    ProjectMeasuresDoc doc = new ProjectMeasuresDoc()
+      .setId(rs.getString(1))
+      .setKey(rs.getString(2))
+      .setName(rs.getString(3));
+    long analysisDate = rs.getLong(4);
+    doc.setAnalysedAt(rs.wasNull() ? null : new Date(analysisDate));
+    return doc;
+  }
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/component/es/ProjectsEsModule.java b/server/sonar-server/src/main/java/org/sonar/server/component/es/ProjectsEsModule.java
new file mode 100644 (file)
index 0000000..90433cf
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * 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.component.es;
+
+import org.sonar.core.platform.Module;
+
+public class ProjectsEsModule extends Module {
+  @Override
+  protected void configureModule() {
+    add(
+      ProjectMeasuresIndexDefinition.class,
+      ProjectMeasuresIndex.class,
+      ProjectMeasuresIndexer.class);
+  }
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/component/es/package-info.java b/server/sonar-server/src/main/java/org/sonar/server/component/es/package-info.java
new file mode 100644 (file)
index 0000000..0119283
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * 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.
+ */
+@ParametersAreNonnullByDefault
+package org.sonar.server.component.es;
+
+import javax.annotation.ParametersAreNonnullByDefault;
index c1b7e4f463afc5b0e88923f6ca291db8e4d2c385..76933a91e208ebdcbe91183e3bae725775fc558a 100644 (file)
@@ -37,6 +37,6 @@ public class ComponentsWsModule extends Module {
       UpdateKeyAction.class,
       BulkUpdateKeyAction.class,
       SearchProjectsAction.class,
-      SearchProjectsQueryBuilderValidator.class);
+      ProjectMeasuresQueryValidator.class);
   }
 }
diff --git a/server/sonar-server/src/main/java/org/sonar/server/component/ws/ProjectMeasuresQueryFactory.java b/server/sonar-server/src/main/java/org/sonar/server/component/ws/ProjectMeasuresQueryFactory.java
new file mode 100644 (file)
index 0000000..76d9303
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * 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.component.ws;
+
+import com.google.common.base.Splitter;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import org.apache.commons.lang.StringUtils;
+import org.sonar.server.component.es.ProjectMeasuresQuery;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static java.util.Locale.ENGLISH;
+import static org.sonar.server.component.es.ProjectMeasuresQuery.MetricCriteria;
+import static org.sonar.server.component.es.ProjectMeasuresQuery.Operator;
+
+class ProjectMeasuresQueryFactory {
+
+  private static final Splitter CRITERIA_SPLITTER = Splitter.on("and");
+  private static final Pattern CRITERIA_PATTERN = Pattern.compile("(\\w+)\\s*([<>][=]?)\\s*(\\w+)");
+
+  private ProjectMeasuresQueryFactory() {
+    // Only static methods
+  }
+
+  static ProjectMeasuresQuery newProjectMeasuresQuery(String filter) {
+    if (StringUtils.isBlank(filter)) {
+      return new ProjectMeasuresQuery();
+    }
+
+    ProjectMeasuresQuery query = new ProjectMeasuresQuery();
+
+    CRITERIA_SPLITTER.split(filter.toLowerCase(ENGLISH))
+      .forEach(criteria -> processCriteria(criteria, query));
+    return query;
+  }
+
+  private static void processCriteria(String criteria, ProjectMeasuresQuery query) {
+    Matcher matcher = CRITERIA_PATTERN.matcher(criteria);
+    checkArgument(matcher.find() && matcher.groupCount() == 3, "Invalid criterion '%s'", criteria);
+    String metric = matcher.group(1);
+    Operator operator = Operator.getByValue(matcher.group(2));
+    Double value = Double.parseDouble(matcher.group(3));
+    query.addMetricCriterion(new MetricCriteria(metric, operator, value));
+  }
+
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/component/ws/ProjectMeasuresQueryValidator.java b/server/sonar-server/src/main/java/org/sonar/server/component/ws/ProjectMeasuresQueryValidator.java
new file mode 100644 (file)
index 0000000..d6dc330
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * 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.component.ws;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+import org.sonar.core.util.stream.Collectors;
+import org.sonar.db.DbClient;
+import org.sonar.db.DbSession;
+import org.sonar.db.metric.MetricDto;
+import org.sonar.server.component.es.ProjectMeasuresQuery;
+
+import static org.sonar.server.component.es.ProjectMeasuresQuery.MetricCriteria;
+
+public class ProjectMeasuresQueryValidator {
+
+  private final DbClient dbClient;
+
+  public ProjectMeasuresQueryValidator(DbClient dbClient) {
+    this.dbClient = dbClient;
+  }
+
+  public void validate(DbSession dbSession, ProjectMeasuresQuery query) {
+    List<String> metricKeys = new ArrayList<>(query.getMetricCriteria().stream().map(MetricCriteria::getMetricKey).collect(Collectors.toSet()));
+    List<MetricDto> dbMetrics = dbClient.metricDao().selectByKeys(dbSession, metricKeys);
+    if (dbMetrics.size() == metricKeys.size()) {
+      return;
+    }
+    List<String> metricDtoKeys = dbMetrics.stream().map(MetricDto::getKey).collect(Collectors.toList());
+    Set<String> unknownKeys = metricKeys.stream().filter(metricKey -> !metricDtoKeys.contains(metricKey)).collect(Collectors.toSet());
+    throw new IllegalArgumentException(String.format("Unknown metric(s) %s", unknownKeys));
+  }
+}
index 10b3c78a5ba71857112707d31388a603d553badb..d4566f8a2007e59b6725d541239ba32b61ce7ecd 100644 (file)
@@ -23,6 +23,7 @@ package org.sonar.server.component.ws;
 import com.google.common.collect.Ordering;
 import java.util.List;
 import java.util.function.Function;
+import java.util.stream.Stream;
 import org.sonar.api.server.ws.Request;
 import org.sonar.api.server.ws.Response;
 import org.sonar.api.server.ws.WebService;
@@ -30,17 +31,17 @@ import org.sonar.api.server.ws.WebService.Param;
 import org.sonar.db.DbClient;
 import org.sonar.db.DbSession;
 import org.sonar.db.component.ComponentDto;
+import org.sonar.server.component.es.ProjectMeasuresIndex;
+import org.sonar.server.component.es.ProjectMeasuresQuery;
 import org.sonar.server.es.SearchIdResult;
 import org.sonar.server.es.SearchOptions;
-import org.sonar.server.project.es.ProjectMeasuresIndex;
 import org.sonarqube.ws.Common;
 import org.sonarqube.ws.WsComponents.Component;
 import org.sonarqube.ws.WsComponents.SearchProjectsWsResponse;
 import org.sonarqube.ws.client.component.SearchProjectsRequest;
 
 import static com.google.common.base.MoreObjects.firstNonNull;
-import static org.sonar.server.component.ws.SearchProjectsQueryBuilder.SearchProjectsCriteriaQuery;
-import static org.sonar.server.component.ws.SearchProjectsQueryBuilder.build;
+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;
@@ -49,12 +50,12 @@ 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 SearchProjectsQueryBuilderValidator searchProjectsQueryBuilderValidator;
+  private final ProjectMeasuresQueryValidator projectMeasuresQueryValidator;
 
-  public SearchProjectsAction(DbClient dbClient, ProjectMeasuresIndex index, SearchProjectsQueryBuilderValidator searchProjectsQueryBuilderValidator) {
+  public SearchProjectsAction(DbClient dbClient, ProjectMeasuresIndex index, ProjectMeasuresQueryValidator projectMeasuresQueryValidator) {
     this.dbClient = dbClient;
     this.index = index;
-    this.searchProjectsQueryBuilderValidator = searchProjectsQueryBuilderValidator;
+    this.projectMeasuresQueryValidator = projectMeasuresQueryValidator;
   }
 
   @Override
@@ -69,8 +70,7 @@ public class SearchProjectsAction implements ComponentsWsAction {
 
     action
       .createParam(PARAM_FILTER)
-      .setDescription("TODO")
-      .setSince("6.2");
+      .setDescription("TODO");
   }
 
   @Override
@@ -90,8 +90,8 @@ public class SearchProjectsAction implements ComponentsWsAction {
 
   private SearchResults searchProjects(DbSession dbSession, SearchProjectsRequest request) {
     String filter = firstNonNull(request.getFilter(), "");
-    SearchProjectsCriteriaQuery query = build(filter);
-    searchProjectsQueryBuilderValidator.validate(dbSession, query);
+    ProjectMeasuresQuery query = newProjectMeasuresQuery(filter);
+    projectMeasuresQueryValidator.validate(dbSession, query);
 
     SearchIdResult<String> searchResult = index.search(query, new SearchOptions().setPage(request.getPage(), request.getPageSize()));
 
@@ -110,21 +110,22 @@ public class SearchProjectsAction implements ComponentsWsAction {
   }
 
   private static SearchProjectsWsResponse buildResponse(SearchProjectsRequest request, SearchResults searchResults) {
-    SearchProjectsWsResponse.Builder response = SearchProjectsWsResponse.newBuilder();
-
-    response.setPaging(Common.Paging.newBuilder()
-      .setPageIndex(request.getPage())
-      .setPageSize(request.getPageSize())
-      .setTotal(searchResults.total));
-
     Function<ComponentDto, Component> dbToWsComponent = new DbToWsComponent();
 
-    searchResults.projects
-      .stream()
-      .map(dbToWsComponent)
-      .forEach(response::addComponents);
-
-    return response.build();
+    return Stream.of(SearchProjectsWsResponse.newBuilder())
+      .map(response -> response.setPaging(Common.Paging.newBuilder()
+        .setPageIndex(request.getPage())
+        .setPageSize(request.getPageSize())
+        .setTotal(searchResults.total)))
+      .map(response -> {
+        searchResults.projects.stream()
+          .map(dbToWsComponent)
+          .forEach(response::addComponents);
+        return response;
+      })
+      .map(SearchProjectsWsResponse.Builder::build)
+      .findFirst()
+      .orElseThrow(() -> new IllegalStateException("SearchProjectsWsResponse not built"));
   }
 
   private static class DbToWsComponent implements Function<ComponentDto, Component> {
diff --git a/server/sonar-server/src/main/java/org/sonar/server/component/ws/SearchProjectsQueryBuilder.java b/server/sonar-server/src/main/java/org/sonar/server/component/ws/SearchProjectsQueryBuilder.java
deleted file mode 100644 (file)
index 085ad84..0000000
+++ /dev/null
@@ -1,125 +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.component.ws;
-
-import com.google.common.base.Splitter;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-import org.apache.commons.lang.StringUtils;
-
-import static com.google.common.base.Preconditions.checkArgument;
-import static java.lang.String.format;
-import static java.util.Arrays.stream;
-import static java.util.Locale.ENGLISH;
-import static org.sonar.server.component.ws.SearchProjectsQueryBuilder.SearchProjectsCriteriaQuery.MetricCriteria;
-import static org.sonar.server.component.ws.SearchProjectsQueryBuilder.SearchProjectsCriteriaQuery.Operator;
-
-public class SearchProjectsQueryBuilder {
-
-  private static final Splitter CRITERIA_SPLITTER = Splitter.on("and");
-  private static final Pattern CRITERIA_PATTERN = Pattern.compile("(\\w+)\\s*([<>][=]?)\\s*(\\w+)");
-
-  private SearchProjectsQueryBuilder() {
-    // Only static methods
-  }
-
-  public static SearchProjectsCriteriaQuery build(String filter) {
-    if (StringUtils.isBlank(filter)) {
-      return new SearchProjectsCriteriaQuery();
-    }
-
-    SearchProjectsCriteriaQuery query = new SearchProjectsCriteriaQuery();
-
-    CRITERIA_SPLITTER.split(filter.toLowerCase(ENGLISH))
-      .forEach(criteria -> processCriteria(criteria, query));
-    return query;
-  }
-
-  private static void processCriteria(String criteria, SearchProjectsCriteriaQuery query) {
-    Matcher matcher = CRITERIA_PATTERN.matcher(criteria);
-    checkArgument(matcher.find() && matcher.groupCount() == 3, "Invalid criteria '%s'", criteria);
-    String metric = matcher.group(1);
-    Operator operator = Operator.create(matcher.group(2));
-    Double value = Double.parseDouble(matcher.group(3));
-    query.addMetricCriteria(new MetricCriteria(metric, operator, value));
-  }
-
-  public static class SearchProjectsCriteriaQuery {
-    public enum Operator {
-      LTE("<="), GT(">"), EQ("=");
-
-      String value;
-
-      Operator(String value) {
-        this.value = value;
-      }
-
-      String getValue() {
-        return value;
-      }
-
-      public static Operator create(String value) {
-        return stream(Operator.values())
-          .filter(operator -> operator.getValue().equals(value))
-          .findFirst()
-          .orElseThrow(() -> new IllegalArgumentException(format("Unknown operator '%s'", value)));
-      }
-    }
-
-    private List<MetricCriteria> metricCriterias = new ArrayList<>();
-
-    public SearchProjectsCriteriaQuery addMetricCriteria(MetricCriteria metricCriteria) {
-      metricCriterias.add(metricCriteria);
-      return this;
-    }
-
-    public List<MetricCriteria> getMetricCriterias() {
-      return metricCriterias;
-    }
-
-    public static class MetricCriteria {
-      private final String metricKey;
-      private final Operator operator;
-      private final double value;
-
-      public MetricCriteria(String metricKey, Operator operator, double value) {
-        this.metricKey = metricKey;
-        this.operator = operator;
-        this.value = value;
-      }
-
-      public String getMetricKey() {
-        return metricKey;
-      }
-
-      public Operator getOperator() {
-        return operator;
-      }
-
-      public double getValue() {
-        return value;
-      }
-    }
-  }
-
-}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/component/ws/SearchProjectsQueryBuilderValidator.java b/server/sonar-server/src/main/java/org/sonar/server/component/ws/SearchProjectsQueryBuilderValidator.java
deleted file mode 100644 (file)
index 6148b30..0000000
+++ /dev/null
@@ -1,52 +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.component.ws;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Set;
-import org.sonar.core.util.stream.Collectors;
-import org.sonar.db.DbClient;
-import org.sonar.db.DbSession;
-import org.sonar.db.metric.MetricDto;
-import org.sonar.server.component.ws.SearchProjectsQueryBuilder.SearchProjectsCriteriaQuery;
-
-import static org.sonar.server.component.ws.SearchProjectsQueryBuilder.SearchProjectsCriteriaQuery.MetricCriteria;
-
-public class SearchProjectsQueryBuilderValidator {
-
-  private final DbClient dbClient;
-
-  public SearchProjectsQueryBuilderValidator(DbClient dbClient) {
-    this.dbClient = dbClient;
-  }
-
-  public void validate(DbSession dbSession, SearchProjectsCriteriaQuery query) {
-    List<String> metricKeys = new ArrayList<>(query.getMetricCriterias().stream().map(MetricCriteria::getMetricKey).collect(Collectors.toSet()));
-    List<MetricDto> metricDtos = dbClient.metricDao().selectByKeys(dbSession, metricKeys);
-    if (metricDtos.size() == metricKeys.size()) {
-      return;
-    }
-    List<String> metricDtoKeys = metricDtos.stream().map(MetricDto::getKey).collect(Collectors.toList());
-    Set<String> unknownKeys = metricKeys.stream().filter(metricKey -> !metricDtoKeys.contains(metricKey)).collect(Collectors.toSet());
-    throw new IllegalArgumentException(String.format("Unknown metric(s) %s", unknownKeys));
-  }
-}
index 3250a46d62d16b7d197a9a63f5b19898175a004d..98febe3c30ff48ac97c0b63a61b0349ae88f9a14 100644 (file)
@@ -21,7 +21,7 @@ package org.sonar.server.computation.task.projectanalysis.step;
 
 import org.sonar.server.computation.task.projectanalysis.component.TreeRootHolder;
 import org.sonar.server.computation.task.step.ComputationStep;
-import org.sonar.server.project.es.ProjectMeasuresIndexer;
+import org.sonar.server.component.es.ProjectMeasuresIndexer;
 
 public class IndexProjectMeasuresStep implements ComputationStep {
 
index f5fa57db35beaefa70938bfa587c93e7b91bf0b8..4285b9b612835747d8e9d5552674390b6ed7a289 100644 (file)
@@ -24,7 +24,7 @@ import org.sonar.api.utils.log.Logger;
 import org.sonar.api.utils.log.Loggers;
 import org.sonar.server.issue.index.IssueAuthorizationIndexer;
 import org.sonar.server.issue.index.IssueIndexer;
-import org.sonar.server.project.es.ProjectMeasuresIndexer;
+import org.sonar.server.component.es.ProjectMeasuresIndexer;
 import org.sonar.server.test.index.TestIndexer;
 import org.sonar.server.user.index.UserIndexer;
 import org.sonar.server.view.index.ViewIndexer;
index fd4ff65f9c5cc5dc7084cd31bd9581e566d003e4..134897cf4110e133af4222ae59ada3073adca9f4 100644 (file)
@@ -177,7 +177,7 @@ import org.sonar.server.plugins.ws.PluginWSCommons;
 import org.sonar.server.plugins.ws.PluginsWs;
 import org.sonar.server.plugins.ws.UninstallAction;
 import org.sonar.server.plugins.ws.UpdatesAction;
-import org.sonar.server.project.es.ProjectsEsModule;
+import org.sonar.server.component.es.ProjectsEsModule;
 import org.sonar.server.project.ws.ProjectsWsModule;
 import org.sonar.server.projectlink.ws.ProjectLinksModule;
 import org.sonar.server.property.InternalPropertiesImpl;
diff --git a/server/sonar-server/src/main/java/org/sonar/server/project/es/ProjectMeasuresDoc.java b/server/sonar-server/src/main/java/org/sonar/server/project/es/ProjectMeasuresDoc.java
deleted file mode 100644 (file)
index 284a8be..0000000
+++ /dev/null
@@ -1,94 +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.project.es;
-
-import java.util.Collection;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.Map;
-import javax.annotation.CheckForNull;
-import javax.annotation.Nullable;
-import org.sonar.server.es.BaseDoc;
-
-import static org.sonar.server.project.es.ProjectMeasuresIndexDefinition.FIELD_MEASURES;
-
-public class ProjectMeasuresDoc extends BaseDoc {
-
-  public ProjectMeasuresDoc() {
-    super(new HashMap<>(4));
-  }
-
-  @Override
-  public String getId() {
-    return getField("_id");
-  }
-
-  @Override
-  public String getRouting() {
-    return null;
-  }
-
-  @Override
-  public String getParent() {
-    return null;
-  }
-
-  public ProjectMeasuresDoc setId(String s) {
-    setField("_id", s);
-    return this;
-  }
-
-  public String getKey() {
-    return getField(ProjectMeasuresIndexDefinition.FIELD_KEY);
-  }
-
-  public ProjectMeasuresDoc setKey(String s) {
-    setField(ProjectMeasuresIndexDefinition.FIELD_KEY, s);
-    return this;
-  }
-
-  public String getName() {
-    return getField(ProjectMeasuresIndexDefinition.FIELD_NAME);
-  }
-
-  public ProjectMeasuresDoc setName(String s) {
-    setField(ProjectMeasuresIndexDefinition.FIELD_NAME, s);
-    return this;
-  }
-
-  @CheckForNull
-  public Date getAnalysedAt() {
-    return getNullableField(ProjectMeasuresIndexDefinition.FIELD_ANALYSED_AT);
-  }
-
-  public ProjectMeasuresDoc setAnalysedAt(@Nullable Date d) {
-    setField(ProjectMeasuresIndexDefinition.FIELD_ANALYSED_AT, d);
-    return this;
-  }
-
-  public Collection<Map<String, Object>> getMeasures() {
-    return getField(FIELD_MEASURES);
-  }
-
-  public ProjectMeasuresDoc setMeasures(Collection<Map<String, Object>> measures) {
-    setField(FIELD_MEASURES, measures);
-    return this;
-  }
-}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/project/es/ProjectMeasuresIndex.java b/server/sonar-server/src/main/java/org/sonar/server/project/es/ProjectMeasuresIndex.java
deleted file mode 100644 (file)
index 6eeef11..0000000
+++ /dev/null
@@ -1,90 +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.project.es;
-
-import org.elasticsearch.action.search.SearchRequestBuilder;
-import org.elasticsearch.index.query.BoolQueryBuilder;
-import org.elasticsearch.index.query.QueryBuilder;
-import org.elasticsearch.search.sort.SortOrder;
-import org.sonar.server.component.ws.SearchProjectsQueryBuilder.SearchProjectsCriteriaQuery;
-import org.sonar.server.component.ws.SearchProjectsQueryBuilder.SearchProjectsCriteriaQuery.MetricCriteria;
-import org.sonar.server.es.BaseIndex;
-import org.sonar.server.es.EsClient;
-import org.sonar.server.es.SearchIdResult;
-import org.sonar.server.es.SearchOptions;
-
-import static org.elasticsearch.index.query.QueryBuilders.boolQuery;
-import static org.elasticsearch.index.query.QueryBuilders.matchAllQuery;
-import static org.elasticsearch.index.query.QueryBuilders.nestedQuery;
-import static org.elasticsearch.index.query.QueryBuilders.rangeQuery;
-import static org.elasticsearch.index.query.QueryBuilders.termQuery;
-import static org.sonar.server.project.es.ProjectMeasuresIndexDefinition.FIELD_MEASURES;
-import static org.sonar.server.project.es.ProjectMeasuresIndexDefinition.FIELD_MEASURES_KEY;
-import static org.sonar.server.project.es.ProjectMeasuresIndexDefinition.FIELD_MEASURES_VALUE;
-import static org.sonar.server.project.es.ProjectMeasuresIndexDefinition.FIELD_NAME;
-import static org.sonar.server.project.es.ProjectMeasuresIndexDefinition.INDEX_PROJECT_MEASURES;
-import static org.sonar.server.project.es.ProjectMeasuresIndexDefinition.TYPE_PROJECT_MEASURES;
-
-public class ProjectMeasuresIndex extends BaseIndex {
-
-  private static final String FIELD_KEY = FIELD_MEASURES + "." + FIELD_MEASURES_KEY;
-  private static final String FIELD_VALUE = FIELD_MEASURES + "." + FIELD_MEASURES_VALUE;
-
-  public ProjectMeasuresIndex(EsClient client) {
-    super(client);
-  }
-
-  public SearchIdResult<String> search(SearchProjectsCriteriaQuery query, SearchOptions searchOptions) {
-    BoolQueryBuilder metricFilters = boolQuery();
-    query.getMetricCriterias().stream()
-      .map(criteria -> nestedQuery(FIELD_MEASURES, boolQuery()
-        .filter(termQuery(FIELD_KEY, criteria.getMetricKey()))
-        .filter(toValueQuery(criteria))))
-      .forEach(metricFilters::filter);
-    QueryBuilder esQuery = query.getMetricCriterias().isEmpty() ? matchAllQuery() : metricFilters;
-
-    SearchRequestBuilder request = getClient()
-      .prepareSearch(INDEX_PROJECT_MEASURES)
-      .setTypes(TYPE_PROJECT_MEASURES)
-      .setFetchSource(false)
-      .setQuery(esQuery)
-      .setFrom(searchOptions.getOffset())
-      .setSize(searchOptions.getLimit())
-      .addSort(FIELD_NAME + "." + SORT_SUFFIX, SortOrder.ASC);
-
-    return new SearchIdResult<>(request.get(), id -> id);
-  }
-
-  private static QueryBuilder toValueQuery(MetricCriteria criteria) {
-    String fieldName = FIELD_VALUE;
-
-    switch (criteria.getOperator()) {
-      case EQ:
-        return termQuery(fieldName, criteria.getValue());
-      case GT:
-        return rangeQuery(fieldName).gt(criteria.getValue());
-      case LTE:
-        return rangeQuery(fieldName).lte(criteria.getValue());
-      default:
-        throw new IllegalStateException("Metric criteria non supported: " + criteria.getOperator().name());
-    }
-
-  }
-}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/project/es/ProjectMeasuresIndexDefinition.java b/server/sonar-server/src/main/java/org/sonar/server/project/es/ProjectMeasuresIndexDefinition.java
deleted file mode 100644 (file)
index 61eefd1..0000000
+++ /dev/null
@@ -1,61 +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.project.es;
-
-import org.sonar.api.config.Settings;
-import org.sonar.server.es.IndexDefinition;
-import org.sonar.server.es.NewIndex;
-
-public class ProjectMeasuresIndexDefinition implements IndexDefinition {
-
-  public static final String INDEX_PROJECT_MEASURES = "projectmeasures";
-  public static final String TYPE_PROJECT_MEASURES = "projectmeasures";
-  public static final String FIELD_KEY = "key";
-  public static final String FIELD_NAME = "name";
-  public static final String FIELD_ANALYSED_AT = "analysedAt";
-  public static final String FIELD_MEASURES = "measures";
-  public static final String FIELD_MEASURES_KEY = "key";
-  public static final String FIELD_MEASURES_VALUE = "value";
-
-  private final Settings settings;
-
-  public ProjectMeasuresIndexDefinition(Settings settings) {
-    this.settings = settings;
-  }
-
-  @Override
-  public void define(IndexDefinitionContext context) {
-    NewIndex index = context.create(INDEX_PROJECT_MEASURES);
-    index.refreshHandledByIndexer();
-    index.configureShards(settings, 5);
-
-    NewIndex.NewIndexType mapping = index.createType(TYPE_PROJECT_MEASURES);
-    mapping.stringFieldBuilder(FIELD_KEY).disableNorms().build();
-    mapping.stringFieldBuilder(FIELD_NAME).enableSorting().enableGramSearch().build();
-    mapping.createDateTimeField(FIELD_ANALYSED_AT);
-    mapping.nestedFieldBuilder(FIELD_MEASURES)
-      .addStringFied(FIELD_MEASURES_KEY)
-      .addStringFied(FIELD_MEASURES_VALUE)
-      .build();
-
-    // do not store document but only indexation of information
-    mapping.setEnableSource(false);
-  }
-}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/project/es/ProjectMeasuresIndexer.java b/server/sonar-server/src/main/java/org/sonar/server/project/es/ProjectMeasuresIndexer.java
deleted file mode 100644 (file)
index 8aa7252..0000000
+++ /dev/null
@@ -1,96 +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.project.es;
-
-import java.util.Date;
-import java.util.Iterator;
-import javax.annotation.Nullable;
-import org.elasticsearch.action.index.IndexRequest;
-import org.sonar.db.DbClient;
-import org.sonar.db.DbSession;
-import org.sonar.server.es.BaseIndexer;
-import org.sonar.server.es.BulkIndexer;
-import org.sonar.server.es.EsClient;
-
-import static org.sonar.server.project.es.ProjectMeasuresIndexDefinition.FIELD_ANALYSED_AT;
-import static org.sonar.server.project.es.ProjectMeasuresIndexDefinition.INDEX_PROJECT_MEASURES;
-import static org.sonar.server.project.es.ProjectMeasuresIndexDefinition.TYPE_PROJECT_MEASURES;
-
-public class ProjectMeasuresIndexer extends BaseIndexer {
-
-  private final DbClient dbClient;
-
-  public ProjectMeasuresIndexer(DbClient dbClient, EsClient esClient) {
-    super(esClient, 300, INDEX_PROJECT_MEASURES, TYPE_PROJECT_MEASURES, FIELD_ANALYSED_AT);
-    this.dbClient = dbClient;
-  }
-
-  @Override
-  protected long doIndex(long lastUpdatedAt) {
-    return doIndex(createBulkIndexer(false), lastUpdatedAt, null);
-  }
-
-  public void index(String projectUuid) {
-    doIndex(createBulkIndexer(false), 0L, projectUuid);
-  }
-
-  public void deleteProject(String uuid) {
-    esClient
-      .prepareDelete(INDEX_PROJECT_MEASURES, TYPE_PROJECT_MEASURES, uuid)
-      .setRefresh(true)
-      .get();
-  }
-
-  private long doIndex(BulkIndexer bulk, long lastUpdatedAt, @Nullable String projectUuid) {
-    try (DbSession dbSession = dbClient.openSession(false)) {
-      ProjectMeasuresResultSetIterator rowIt = ProjectMeasuresResultSetIterator.create(dbClient, dbSession, lastUpdatedAt, projectUuid);
-      long maxDate = doIndex(bulk, rowIt);
-      rowIt.close();
-      return maxDate;
-    }
-  }
-
-  private static long doIndex(BulkIndexer bulk, Iterator<ProjectMeasuresDoc> docs) {
-    bulk.start();
-    long maxDate = 0L;
-    while (docs.hasNext()) {
-      ProjectMeasuresDoc doc = docs.next();
-      bulk.add(newIndexRequest(doc));
-
-      Date analysisDate = doc.getAnalysedAt();
-      // it's more efficient to sort programmatically than in SQL on some databases (MySQL for instance)
-      maxDate = Math.max(maxDate, analysisDate == null ? 0L : analysisDate.getTime());
-    }
-    bulk.stop();
-    return maxDate;
-  }
-
-  private BulkIndexer createBulkIndexer(boolean large) {
-    BulkIndexer bulk = new BulkIndexer(esClient, INDEX_PROJECT_MEASURES);
-    bulk.setLarge(large);
-    return bulk;
-  }
-
-  private static IndexRequest newIndexRequest(ProjectMeasuresDoc doc) {
-    return new IndexRequest(INDEX_PROJECT_MEASURES, TYPE_PROJECT_MEASURES, doc.getId())
-      .source(doc.getFields());
-  }
-}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/project/es/ProjectMeasuresResultSetIterator.java b/server/sonar-server/src/main/java/org/sonar/server/project/es/ProjectMeasuresResultSetIterator.java
deleted file mode 100644 (file)
index 1cf84b6..0000000
+++ /dev/null
@@ -1,90 +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.project.es;
-
-import java.sql.PreparedStatement;
-import java.sql.ResultSet;
-import java.sql.SQLException;
-import java.util.Date;
-import javax.annotation.Nullable;
-import org.apache.commons.lang.StringUtils;
-import org.sonar.api.resources.Qualifiers;
-import org.sonar.api.resources.Scopes;
-import org.sonar.db.DbClient;
-import org.sonar.db.DbSession;
-import org.sonar.db.ResultSetIterator;
-
-public class ProjectMeasuresResultSetIterator extends ResultSetIterator<ProjectMeasuresDoc> {
-
-  private static final String[] FIELDS = {
-    "p.uuid",
-    "p.kee",
-    "p.name",
-    "s.created_at"
-  };
-
-  private static final String SQL_ALL = "SELECT " + StringUtils.join(FIELDS, ",") + " FROM projects p " +
-    "LEFT OUTER JOIN snapshots s ON s.component_uuid=p.uuid AND s.islast=? " +
-    "WHERE p.enabled=? AND p.scope=? AND p.qualifier=?";
-
-  private static final String DATE_FILTER = " AND s.created_at>?";
-
-  private static final String PROJECT_FILTER = " AND p.uuid=?";
-
-  private ProjectMeasuresResultSetIterator(PreparedStatement stmt) throws SQLException {
-    super(stmt);
-  }
-
-  static ProjectMeasuresResultSetIterator create(DbClient dbClient, DbSession session, long afterDate, @Nullable String projectUuid) {
-    try {
-      String sql = SQL_ALL;
-      sql += afterDate <= 0L ? "" : DATE_FILTER;
-      sql += projectUuid == null ? "" : PROJECT_FILTER;
-      PreparedStatement stmt = dbClient.getMyBatis().newScrollingSelectStatement(session, sql);
-      stmt.setBoolean(1, true);
-      stmt.setBoolean(2, true);
-      stmt.setString(3, Scopes.PROJECT);
-      stmt.setString(4, Qualifiers.PROJECT);
-      int index = 5;
-      if (afterDate > 0L) {
-        stmt.setLong(index, afterDate);
-        index++;
-      }
-      if (projectUuid != null) {
-        stmt.setString(index, projectUuid);
-      }
-      return new ProjectMeasuresResultSetIterator(stmt);
-    } catch (SQLException e) {
-      throw new IllegalStateException("Fail to prepare SQL request to select all project measures", e);
-    }
-  }
-
-  @Override
-  protected ProjectMeasuresDoc read(ResultSet rs) throws SQLException {
-    ProjectMeasuresDoc doc = new ProjectMeasuresDoc()
-      .setId(rs.getString(1))
-      .setKey(rs.getString(2))
-      .setName(rs.getString(3));
-    long analysisDate = rs.getLong(4);
-    doc.setAnalysedAt(rs.wasNull() ? null : new Date(analysisDate));
-    return doc;
-  }
-}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/project/es/ProjectsEsModule.java b/server/sonar-server/src/main/java/org/sonar/server/project/es/ProjectsEsModule.java
deleted file mode 100644 (file)
index fef8452..0000000
+++ /dev/null
@@ -1,33 +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.project.es;
-
-import org.sonar.core.platform.Module;
-
-public class ProjectsEsModule extends Module {
-  @Override
-  protected void configureModule() {
-    add(
-      ProjectMeasuresIndexDefinition.class,
-      ProjectMeasuresIndex.class,
-      ProjectMeasuresIndexer.class);
-  }
-}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/project/es/package-info.java b/server/sonar-server/src/main/java/org/sonar/server/project/es/package-info.java
deleted file mode 100644 (file)
index 53f33d2..0000000
+++ /dev/null
@@ -1,23 +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.
- */
-@ParametersAreNonnullByDefault
-package org.sonar.server.project.es;
-
-import javax.annotation.ParametersAreNonnullByDefault;
index ea9676adf31c441debca440050d11a7a58cd50ff..b534beadc487c973dd65b5d13413f18cc262e84c 100644 (file)
@@ -45,8 +45,8 @@ import org.sonar.server.issue.index.IssueAuthorizationDoc;
 import org.sonar.server.issue.index.IssueAuthorizationIndexer;
 import org.sonar.server.issue.index.IssueIndexDefinition;
 import org.sonar.server.issue.index.IssueIndexer;
-import org.sonar.server.project.es.ProjectMeasuresIndexDefinition;
-import org.sonar.server.project.es.ProjectMeasuresIndexer;
+import org.sonar.server.component.es.ProjectMeasuresIndexDefinition;
+import org.sonar.server.component.es.ProjectMeasuresIndexer;
 import org.sonar.server.test.index.TestDoc;
 import org.sonar.server.test.index.TestIndexDefinition;
 import org.sonar.server.test.index.TestIndexer;
index 05c52930a891cd4461ba81ed8911aa73a502ac4c..9e38c293e7233fdf64cb6ecd4c656d38734d7ada 100644 (file)
@@ -37,12 +37,12 @@ import org.sonar.db.component.ComponentDbTester;
 import org.sonar.db.component.ComponentDto;
 import org.sonar.db.component.ComponentTesting;
 import org.sonar.db.component.ResourceIndexDao;
+import org.sonar.server.component.es.ProjectMeasuresIndexDefinition;
+import org.sonar.server.component.es.ProjectMeasuresIndexer;
 import org.sonar.server.es.EsTester;
 import org.sonar.server.exceptions.BadRequestException;
 import org.sonar.server.exceptions.NotFoundException;
 import org.sonar.server.i18n.I18nRule;
-import org.sonar.server.project.es.ProjectMeasuresIndexDefinition;
-import org.sonar.server.project.es.ProjectMeasuresIndexer;
 import org.sonar.server.tester.UserSessionRule;
 
 import static com.google.common.collect.Lists.newArrayList;
@@ -58,8 +58,8 @@ import static org.sonar.core.permission.GlobalPermissions.PROVISIONING;
 import static org.sonar.db.component.ComponentTesting.newFileDto;
 import static org.sonar.db.component.ComponentTesting.newModuleDto;
 import static org.sonar.db.component.ComponentTesting.newProjectDto;
-import static org.sonar.server.project.es.ProjectMeasuresIndexDefinition.INDEX_PROJECT_MEASURES;
-import static org.sonar.server.project.es.ProjectMeasuresIndexDefinition.TYPE_PROJECT_MEASURES;
+import static org.sonar.server.component.es.ProjectMeasuresIndexDefinition.INDEX_PROJECT_MEASURES;
+import static org.sonar.server.component.es.ProjectMeasuresIndexDefinition.TYPE_PROJECT_MEASURES;
 
 public class ComponentServiceTest {
 
index ff63771f9f775a9c5cefe064ab18c072e990cfb6..1b8b843e24ddcc7c3d5cc1ca17bfe4cb2dad3f35 100644 (file)
@@ -35,12 +35,12 @@ import org.sonar.db.DbTester;
 import org.sonar.db.component.ComponentDbTester;
 import org.sonar.db.component.ComponentDto;
 import org.sonar.db.component.ComponentTesting;
+import org.sonar.server.component.es.ProjectMeasuresIndexDefinition;
+import org.sonar.server.component.es.ProjectMeasuresIndexer;
 import org.sonar.server.es.EsTester;
 import org.sonar.server.exceptions.BadRequestException;
 import org.sonar.server.exceptions.ForbiddenException;
 import org.sonar.server.i18n.I18nRule;
-import org.sonar.server.project.es.ProjectMeasuresIndexDefinition;
-import org.sonar.server.project.es.ProjectMeasuresIndexer;
 import org.sonar.server.tester.UserSessionRule;
 
 import static org.assertj.core.api.Assertions.assertThat;
@@ -51,8 +51,8 @@ import static org.elasticsearch.index.query.QueryBuilders.termQuery;
 import static org.sonar.db.component.ComponentTesting.newFileDto;
 import static org.sonar.db.component.ComponentTesting.newModuleDto;
 import static org.sonar.db.component.ComponentTesting.newProjectDto;
-import static org.sonar.server.project.es.ProjectMeasuresIndexDefinition.INDEX_PROJECT_MEASURES;
-import static org.sonar.server.project.es.ProjectMeasuresIndexDefinition.TYPE_PROJECT_MEASURES;
+import static org.sonar.server.component.es.ProjectMeasuresIndexDefinition.INDEX_PROJECT_MEASURES;
+import static org.sonar.server.component.es.ProjectMeasuresIndexDefinition.TYPE_PROJECT_MEASURES;
 
 public class ComponentServiceUpdateKeyTest {
 
index 4529ce165235f11db0e36141c99ec7ab9d67c9f7..edfd797db251ec93eed8e240a381efec3e93a475 100644 (file)
@@ -33,12 +33,12 @@ import org.sonar.db.component.ComponentDbTester;
 import org.sonar.db.component.ComponentDto;
 import org.sonar.db.component.ResourceDao;
 import org.sonar.db.component.ResourceDto;
+import org.sonar.server.component.es.ProjectMeasuresIndexDefinition;
+import org.sonar.server.component.es.ProjectMeasuresIndexer;
 import org.sonar.server.es.EsTester;
 import org.sonar.server.exceptions.BadRequestException;
 import org.sonar.server.i18n.I18nRule;
 import org.sonar.server.permission.PermissionService;
-import org.sonar.server.project.es.ProjectMeasuresIndexDefinition;
-import org.sonar.server.project.es.ProjectMeasuresIndexer;
 import org.sonar.server.tester.UserSessionRule;
 
 import static com.google.common.collect.Lists.newArrayList;
diff --git a/server/sonar-server/src/test/java/org/sonar/server/component/es/ProjectMeasuresIndexTest.java b/server/sonar-server/src/test/java/org/sonar/server/component/es/ProjectMeasuresIndexTest.java
new file mode 100644 (file)
index 0000000..b47e583
--- /dev/null
@@ -0,0 +1,140 @@
+/*
+ * 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.component.es;
+
+import com.google.common.base.Throwables;
+import com.google.common.collect.ImmutableMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.IntStream;
+import org.junit.Rule;
+import org.junit.Test;
+import org.sonar.api.config.MapSettings;
+import org.sonar.server.component.es.ProjectMeasuresQuery.MetricCriteria;
+import org.sonar.server.component.es.ProjectMeasuresQuery.Operator;
+import org.sonar.server.es.EsTester;
+import org.sonar.server.es.SearchIdResult;
+import org.sonar.server.es.SearchOptions;
+
+import static com.google.common.collect.Lists.newArrayList;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.sonar.server.component.es.ProjectMeasuresIndexDefinition.INDEX_PROJECT_MEASURES;
+import static org.sonar.server.component.es.ProjectMeasuresIndexDefinition.TYPE_PROJECT_MEASURES;
+
+public class ProjectMeasuresIndexTest {
+
+  private static final String COVERAGE = "coverage";
+  private static final String NCLOC = "ncloc";
+  @Rule
+  public EsTester es = new EsTester(new ProjectMeasuresIndexDefinition(new MapSettings()));
+
+  private ProjectMeasuresIndex underTest = new ProjectMeasuresIndex(es.client());
+
+  @Test
+  public void empty_search() {
+    List<String> result = underTest.search(new ProjectMeasuresQuery(), new SearchOptions()).getIds();
+
+    assertThat(result).isEmpty();
+  }
+
+  @Test
+  public void search_sort_by_name_case_insensitive() {
+    addDocs(newDoc("P1", "K1", "Windows"),
+      newDoc("P3", "K3", "apachee"),
+      newDoc("P2", "K2", "Apache"));
+
+    List<String> result = underTest.search(new ProjectMeasuresQuery(), new SearchOptions()).getIds();
+
+    assertThat(result).containsExactly("P2", "P3", "P1");
+  }
+
+  @Test
+  public void search_paginate_results() {
+    IntStream.rangeClosed(1, 9)
+      .forEach(i -> addDocs(newDoc("P" + i, "K" + i, "P" + i)));
+
+    SearchIdResult<String> result = underTest.search(new ProjectMeasuresQuery(), new SearchOptions().setPage(2, 3));
+
+    assertThat(result.getIds()).containsExactly("P4", "P5", "P6");
+    assertThat(result.getTotal()).isEqualTo(9);
+  }
+
+  @Test
+  public void filter_with_lower_than_or_equals() {
+    addDocs(
+      newDoc("P1", "K1", "N1").setMeasures(newArrayList(newMeasure(COVERAGE, 79d), newMeasure(NCLOC, 10_000d))),
+      newDoc("P2", "K2", "N2").setMeasures(newArrayList(newMeasure(COVERAGE, 80d), newMeasure(NCLOC, 10_000d))),
+      newDoc("P3", "K3", "N3").setMeasures(newArrayList(newMeasure(COVERAGE, 81d), newMeasure(NCLOC, 10_000d))));
+
+    ProjectMeasuresQuery esQuery = new ProjectMeasuresQuery()
+      .addMetricCriterion(new MetricCriteria(COVERAGE, Operator.LTE, 80d));
+    List<String> result = underTest.search(esQuery, new SearchOptions()).getIds();
+
+    assertThat(result).containsExactly("P1", "P2");
+  }
+
+  @Test
+  public void filter_with_greater_than() {
+    addDocs(
+      newDoc("P1", "K1", "N1").setMeasures(newArrayList(newMeasure(COVERAGE, 80d), newMeasure(NCLOC, 10_000d))),
+      newDoc("P2", "K2", "N2").setMeasures(newArrayList(newMeasure(COVERAGE, 80d), newMeasure(NCLOC, 10_001d))),
+      newDoc("P3", "K3", "N3").setMeasures(newArrayList(newMeasure(COVERAGE, 80d), newMeasure(NCLOC, 10_001d))));
+
+    ProjectMeasuresQuery esQuery = new ProjectMeasuresQuery()
+      .addMetricCriterion(new MetricCriteria(NCLOC, Operator.GT, 10_000d));
+    List<String> result = underTest.search(esQuery, new SearchOptions()).getIds();
+
+    assertThat(result).containsExactly("P2", "P3");
+  }
+
+  @Test
+  public void filter_on_several_metrics() {
+    addDocs(
+      newDoc("P1", "K1", "N1").setMeasures(newArrayList(newMeasure(COVERAGE, 81d), newMeasure(NCLOC, 10_001d))),
+      newDoc("P2", "K2", "N2").setMeasures(newArrayList(newMeasure(COVERAGE, 80d), newMeasure(NCLOC, 10_001d))),
+      newDoc("P3", "K3", "N3").setMeasures(newArrayList(newMeasure(COVERAGE, 79d), newMeasure(NCLOC, 10_000d))));
+
+    ProjectMeasuresQuery esQuery = new ProjectMeasuresQuery()
+      .addMetricCriterion(new MetricCriteria(COVERAGE, Operator.LTE, 80d))
+      .addMetricCriterion(new MetricCriteria(NCLOC, Operator.GT, 10_000d));
+    List<String> result = underTest.search(esQuery, new SearchOptions()).getIds();
+
+    assertThat(result).containsExactly("P2");
+  }
+
+  private void addDocs(ProjectMeasuresDoc... docs) {
+    try {
+      es.putDocuments(INDEX_PROJECT_MEASURES, TYPE_PROJECT_MEASURES, docs);
+    } catch (Exception e) {
+      Throwables.propagate(e);
+    }
+  }
+
+  private static ProjectMeasuresDoc newDoc(String uuid, String key, String name) {
+    return new ProjectMeasuresDoc()
+      .setId(uuid)
+      .setKey(key)
+      .setName(name);
+  }
+
+  private Map<String, Object> newMeasure(String key, double value) {
+    return ImmutableMap.of("key", key, "value", value);
+  }
+}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/component/es/ProjectMeasuresIndexerTest.java b/server/sonar-server/src/test/java/org/sonar/server/component/es/ProjectMeasuresIndexerTest.java
new file mode 100644 (file)
index 0000000..6e05050
--- /dev/null
@@ -0,0 +1,144 @@
+/*
+ * 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.component.es;
+
+import java.util.Date;
+import org.elasticsearch.action.search.SearchRequestBuilder;
+import org.junit.Rule;
+import org.junit.Test;
+import org.sonar.api.config.MapSettings;
+import org.sonar.api.utils.System2;
+import org.sonar.db.DbTester;
+import org.sonar.db.component.ComponentDbTester;
+import org.sonar.db.component.ComponentDto;
+import org.sonar.db.component.SnapshotDto;
+import org.sonar.server.es.EsTester;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.elasticsearch.index.query.QueryBuilders.boolQuery;
+import static org.elasticsearch.index.query.QueryBuilders.matchAllQuery;
+import static org.elasticsearch.index.query.QueryBuilders.termQuery;
+import static org.sonar.db.component.ComponentTesting.newProjectDto;
+import static org.sonar.server.component.es.ProjectMeasuresIndexDefinition.INDEX_PROJECT_MEASURES;
+import static org.sonar.server.component.es.ProjectMeasuresIndexDefinition.TYPE_PROJECT_MEASURES;
+
+public class ProjectMeasuresIndexerTest {
+
+  @Rule
+  public EsTester esTester = new EsTester(new ProjectMeasuresIndexDefinition(new MapSettings()));
+
+  @Rule
+  public DbTester dbTester = DbTester.create(System2.INSTANCE);
+
+  ComponentDbTester componentDbTester = new ComponentDbTester(dbTester);
+
+  ProjectMeasuresIndexer underTest = new ProjectMeasuresIndexer(dbTester.getDbClient(), esTester.client());
+
+  @Test
+  public void index_nothing() {
+    underTest.index();
+
+    assertThat(esTester.countDocuments(INDEX_PROJECT_MEASURES, TYPE_PROJECT_MEASURES)).isZero();
+  }
+
+  @Test
+  public void index_all_project() {
+    componentDbTester.insertProjectAndSnapshot(newProjectDto());
+    componentDbTester.insertProjectAndSnapshot(newProjectDto());
+    componentDbTester.insertProjectAndSnapshot(newProjectDto());
+
+    underTest.index();
+
+    assertThat(esTester.countDocuments(INDEX_PROJECT_MEASURES, TYPE_PROJECT_MEASURES)).isEqualTo(3);
+  }
+
+  @Test
+  public void index_projects_even_when_no_analysis() {
+    ComponentDto project = componentDbTester.insertProject();
+
+    underTest.index();
+
+    assertThat(esTester.getIds(INDEX_PROJECT_MEASURES, TYPE_PROJECT_MEASURES)).containsOnly(project.uuid());
+  }
+
+  @Test
+  public void index_one_project() throws Exception {
+    ComponentDto project = newProjectDto();
+    componentDbTester.insertProjectAndSnapshot(project);
+    componentDbTester.insertProjectAndSnapshot(newProjectDto());
+
+    underTest.index(project.uuid());
+
+    assertThat(esTester.getIds(INDEX_PROJECT_MEASURES, TYPE_PROJECT_MEASURES)).containsOnly(project.uuid());
+  }
+
+  @Test
+  public void update_existing_document_when_indexing_one_project() throws Exception {
+    String uuid = "PROJECT-UUID";
+    esTester.putDocuments(INDEX_PROJECT_MEASURES, TYPE_PROJECT_MEASURES, new ProjectMeasuresDoc()
+      .setId(uuid)
+      .setKey("Old Key")
+      .setName("Old Name")
+      .setAnalysedAt(new Date(1_000_000L)));
+    ComponentDto project = newProjectDto(uuid).setKey("New key").setName("New name");
+    SnapshotDto analysis = componentDbTester.insertProjectAndSnapshot(project);
+
+    underTest.index(project.uuid());
+
+    assertThat(esTester.getIds(INDEX_PROJECT_MEASURES, TYPE_PROJECT_MEASURES)).containsOnly(uuid);
+    SearchRequestBuilder request = esTester.client()
+      .prepareSearch(INDEX_PROJECT_MEASURES)
+      .setTypes(TYPE_PROJECT_MEASURES)
+      .setQuery(boolQuery().must(matchAllQuery()).filter(
+        boolQuery()
+          .must(termQuery("_id", uuid))
+          .must(termQuery(ProjectMeasuresIndexDefinition.FIELD_KEY, "New key"))
+          .must(termQuery(ProjectMeasuresIndexDefinition.FIELD_NAME, "New name"))
+          .must(termQuery(ProjectMeasuresIndexDefinition.FIELD_ANALYSED_AT, new Date(analysis.getCreatedAt())))));
+    assertThat(request.get().getHits()).hasSize(1);
+  }
+
+  @Test
+  public void delete_project() {
+    ComponentDto project1 = newProjectDto();
+    componentDbTester.insertProjectAndSnapshot(project1);
+    ComponentDto project2 = newProjectDto();
+    componentDbTester.insertProjectAndSnapshot(project2);
+    ComponentDto project3 = newProjectDto();
+    componentDbTester.insertProjectAndSnapshot(project3);
+    underTest.index();
+
+    underTest.deleteProject(project1.uuid());
+
+    assertThat(esTester.getIds(INDEX_PROJECT_MEASURES, TYPE_PROJECT_MEASURES)).containsOnly(project2.uuid(), project3.uuid());
+  }
+
+  @Test
+  public void does_nothing_when_deleting_unknown_project() throws Exception {
+    ComponentDto project = newProjectDto();
+    componentDbTester.insertProjectAndSnapshot(project);
+    underTest.index();
+
+    underTest.deleteProject("UNKNOWN");
+
+    assertThat(esTester.getIds(INDEX_PROJECT_MEASURES, TYPE_PROJECT_MEASURES)).containsOnly(project.uuid());
+  }
+}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/component/es/ProjectMeasuresResultSetIteratorTest.java b/server/sonar-server/src/test/java/org/sonar/server/component/es/ProjectMeasuresResultSetIteratorTest.java
new file mode 100644 (file)
index 0000000..ce436bf
--- /dev/null
@@ -0,0 +1,168 @@
+/*
+ * 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.component.es;
+
+import com.google.common.collect.Maps;
+import java.util.Date;
+import java.util.Map;
+import javax.annotation.Nullable;
+import org.junit.Rule;
+import org.junit.Test;
+import org.sonar.api.utils.System2;
+import org.sonar.db.DbClient;
+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.component.SnapshotDto;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.sonar.db.component.ComponentTesting.newDeveloper;
+import static org.sonar.db.component.ComponentTesting.newProjectDto;
+import static org.sonar.db.component.ComponentTesting.newView;
+import static org.sonar.db.component.SnapshotTesting.newAnalysis;
+
+public class ProjectMeasuresResultSetIteratorTest {
+
+  @Rule
+  public DbTester dbTester = DbTester.create(System2.INSTANCE);
+
+  DbClient dbClient = dbTester.getDbClient();
+  DbSession dbSession = dbTester.getSession();
+
+  ComponentDbTester componentDbTester = new ComponentDbTester(dbTester);
+
+  @Test
+  public void return_one_project_measure() {
+    ComponentDto project = newProjectDto().setKey("Project-Key").setName("Project Name");
+    SnapshotDto analysis = componentDbTester.insertProjectAndSnapshot(project);
+
+    Map<String, ProjectMeasuresDoc> docsById = createResultSetAndReturnDocsById();
+
+    assertThat(docsById).hasSize(1);
+    ProjectMeasuresDoc doc = docsById.get(project.uuid());
+    assertThat(doc).isNotNull();
+    assertThat(doc.getId()).isEqualTo(project.uuid());
+    assertThat(doc.getKey()).isEqualTo("Project-Key");
+    assertThat(doc.getName()).isEqualTo("Project Name");
+    assertThat(doc.getAnalysedAt()).isNotNull().isEqualTo(new Date(analysis.getCreatedAt()));
+  }
+
+  @Test
+  public void return_many_project_measures() {
+    componentDbTester.insertProjectAndSnapshot(newProjectDto());
+    componentDbTester.insertProjectAndSnapshot(newProjectDto());
+    componentDbTester.insertProjectAndSnapshot(newProjectDto());
+
+    assertThat(createResultSetAndReturnDocsById()).hasSize(3);
+  }
+
+  @Test
+  public void return_project_without_analysis() throws Exception {
+    ComponentDto project = componentDbTester.insertComponent(newProjectDto());
+    dbClient.snapshotDao().insert(dbSession, newAnalysis(project).setLast(false));
+    dbSession.commit();
+
+    Map<String, ProjectMeasuresDoc> docsById = createResultSetAndReturnDocsById();
+
+    assertThat(docsById).hasSize(1);
+    ProjectMeasuresDoc doc = docsById.get(project.uuid());
+    assertThat(doc.getAnalysedAt()).isNull();
+  }
+
+  @Test
+  public void does_not_return_non_active_projects() throws Exception {
+    // Disabled project
+    componentDbTester.insertProjectAndSnapshot(newProjectDto().setEnabled(false));
+    // Disabled project with analysis
+    ComponentDto project = componentDbTester.insertComponent(newProjectDto().setEnabled(false));
+    dbClient.snapshotDao().insert(dbSession, newAnalysis(project));
+
+    // A view
+    componentDbTester.insertProjectAndSnapshot(newView());
+
+    // A developer
+    componentDbTester.insertProjectAndSnapshot(newDeveloper("dev"));
+
+    dbSession.commit();
+
+    assertResultSetIsEmpty();
+  }
+
+  @Test
+  public void return_only_docs_from_given_project() throws Exception {
+    ComponentDto project = newProjectDto();
+    SnapshotDto analysis = componentDbTester.insertProjectAndSnapshot(project);
+    componentDbTester.insertProjectAndSnapshot(newProjectDto());
+    componentDbTester.insertProjectAndSnapshot(newProjectDto());
+
+    Map<String, ProjectMeasuresDoc> docsById = createResultSetAndReturnDocsById(0L, project.uuid());
+
+    assertThat(docsById).hasSize(1);
+    ProjectMeasuresDoc doc = docsById.get(project.uuid());
+    assertThat(doc).isNotNull();
+    assertThat(doc.getId()).isEqualTo(project.uuid());
+    assertThat(doc.getKey()).isNotNull().isEqualTo(project.getKey());
+    assertThat(doc.getName()).isNotNull().isEqualTo(project.name());
+    assertThat(doc.getAnalysedAt()).isNotNull().isEqualTo(new Date(analysis.getCreatedAt()));
+  }
+
+  @Test
+  public void return_only_docs_after_date() throws Exception {
+    ComponentDto project1 = newProjectDto();
+    dbClient.componentDao().insert(dbSession, project1);
+    dbClient.snapshotDao().insert(dbSession, newAnalysis(project1).setCreatedAt(1_000_000L));
+    ComponentDto project2 = newProjectDto();
+    dbClient.componentDao().insert(dbSession, project2);
+    dbClient.snapshotDao().insert(dbSession, newAnalysis(project2).setCreatedAt(2_000_000L));
+    dbSession.commit();
+
+    Map<String, ProjectMeasuresDoc> docsById = createResultSetAndReturnDocsById(1_500_000L, null);
+
+    assertThat(docsById).hasSize(1);
+    assertThat(docsById.get(project2.uuid())).isNotNull();
+  }
+
+  @Test
+  public void return_nothing_on_unknown_project() throws Exception {
+    componentDbTester.insertProjectAndSnapshot(newProjectDto());
+
+    Map<String, ProjectMeasuresDoc> docsById = createResultSetAndReturnDocsById(0L, "UNKNOWN");
+
+    assertThat(docsById).isEmpty();
+  }
+
+  private Map<String, ProjectMeasuresDoc> createResultSetAndReturnDocsById() {
+    return createResultSetAndReturnDocsById(0L, null);
+  }
+
+  private Map<String, ProjectMeasuresDoc> createResultSetAndReturnDocsById(long date, @Nullable String projectUuid) {
+    ProjectMeasuresResultSetIterator it = ProjectMeasuresResultSetIterator.create(dbTester.getDbClient(), dbTester.getSession(), date, projectUuid);
+    Map<String, ProjectMeasuresDoc> docsById = Maps.uniqueIndex(it, ProjectMeasuresDoc::getId);
+    it.close();
+    return docsById;
+  }
+
+  private void assertResultSetIsEmpty() {
+    assertThat(createResultSetAndReturnDocsById()).isEmpty();
+  }
+
+}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/component/es/ProjectsEsModuleTest.java b/server/sonar-server/src/test/java/org/sonar/server/component/es/ProjectsEsModuleTest.java
new file mode 100644 (file)
index 0000000..618e5f3
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * 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.component.es;
+
+import org.junit.Test;
+import org.sonar.core.platform.ComponentContainer;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class ProjectsEsModuleTest {
+  @Test
+  public void verify_count_of_added_components() {
+    ComponentContainer container = new ComponentContainer();
+    new ProjectsEsModule().configure(container);
+    assertThat(container.size()).isEqualTo(3 + 2);
+  }
+}
index 2625cf7967b0bb242166de5049dd247b182e784a..dc3e49866b0526f611e43a3787b96715870afca7 100644 (file)
@@ -38,12 +38,12 @@ import org.sonar.db.component.ComponentDbTester;
 import org.sonar.db.component.ComponentDto;
 import org.sonar.server.component.ComponentFinder;
 import org.sonar.server.component.ComponentService;
+import org.sonar.server.component.es.ProjectMeasuresIndexDefinition;
+import org.sonar.server.component.es.ProjectMeasuresIndexer;
 import org.sonar.server.es.EsTester;
 import org.sonar.server.exceptions.BadRequestException;
 import org.sonar.server.exceptions.ForbiddenException;
 import org.sonar.server.exceptions.NotFoundException;
-import org.sonar.server.project.es.ProjectMeasuresIndexDefinition;
-import org.sonar.server.project.es.ProjectMeasuresIndexer;
 import org.sonar.server.tester.UserSessionRule;
 import org.sonar.server.ws.TestRequest;
 import org.sonar.server.ws.WsActionTester;
diff --git a/server/sonar-server/src/test/java/org/sonar/server/component/ws/ProjectMeasuresQueryFactoryTest.java b/server/sonar-server/src/test/java/org/sonar/server/component/ws/ProjectMeasuresQueryFactoryTest.java
new file mode 100644 (file)
index 0000000..5a4014d
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ * 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.component.ws;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.sonar.server.component.es.ProjectMeasuresQuery;
+import org.sonar.test.TestUtils;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.tuple;
+import static org.sonar.server.component.es.ProjectMeasuresQuery.MetricCriteria;
+import static org.sonar.server.component.es.ProjectMeasuresQuery.Operator;
+import static org.sonar.server.component.ws.ProjectMeasuresQueryFactory.newProjectMeasuresQuery;
+
+public class ProjectMeasuresQueryFactoryTest {
+
+  @Rule
+  public ExpectedException expectedException = ExpectedException.none();
+
+  @Test
+  public void create_query() throws Exception {
+    ProjectMeasuresQuery query = newProjectMeasuresQuery("ncloc > 10 and coverage <= 80");
+
+    assertThat(query.getMetricCriteria())
+      .extracting(MetricCriteria::getMetricKey, MetricCriteria::getOperator, MetricCriteria::getValue)
+      .containsOnly(
+        tuple("ncloc", Operator.GT, 10d),
+        tuple("coverage", Operator.LTE, 80d));
+  }
+
+  @Test
+  public void convert_upper_case_to_lower_case() throws Exception {
+    assertThat(newProjectMeasuresQuery("NCLOC > 10 AND coVERage <= 80").getMetricCriteria())
+      .extracting(MetricCriteria::getMetricKey, MetricCriteria::getOperator, MetricCriteria::getValue)
+      .containsOnly(
+        tuple("ncloc", Operator.GT, 10d),
+        tuple("coverage", Operator.LTE, 80d));
+  }
+
+  @Test
+  public void ignore_white_spaces() throws Exception {
+    assertThat(newProjectMeasuresQuery("   ncloc    >    10   ").getMetricCriteria())
+      .extracting(MetricCriteria::getMetricKey, MetricCriteria::getOperator, MetricCriteria::getValue)
+      .containsOnly(tuple("ncloc", Operator.GT, 10d));
+  }
+
+  @Test
+  public void accept_empty_query() throws Exception {
+    ProjectMeasuresQuery result = newProjectMeasuresQuery("");
+
+    assertThat(result.getMetricCriteria()).isEmpty();
+  }
+
+  @Test
+  public void fail_on_unknown_operator() throws Exception {
+    expectedException.expect(IllegalArgumentException.class);
+    expectedException.expectMessage("Unknown operator '>='");
+    newProjectMeasuresQuery("ncloc >= 10");
+  }
+
+  @Test
+  public void fail_on_invalid_criteria() throws Exception {
+    expectedException.expect(IllegalArgumentException.class);
+    expectedException.expectMessage("Invalid criterion 'ncloc ? 10'");
+    newProjectMeasuresQuery("ncloc ? 10");
+  }
+
+  @Test
+  public void fail_when_no_operator() throws Exception {
+    expectedException.expect(IllegalArgumentException.class);
+    expectedException.expectMessage("Invalid criterion 'ncloc 10'");
+    newProjectMeasuresQuery("ncloc 10");
+  }
+
+  @Test
+  public void fail_when_no_key() throws Exception {
+    expectedException.expect(IllegalArgumentException.class);
+    expectedException.expectMessage("Invalid criterion '>= 10'");
+    newProjectMeasuresQuery(">= 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();
+  }
+}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/component/ws/ProjectMeasuresQueryFactoryValidatorTest.java b/server/sonar-server/src/test/java/org/sonar/server/component/ws/ProjectMeasuresQueryFactoryValidatorTest.java
new file mode 100644 (file)
index 0000000..bc3390d
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * 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.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.db.metric.MetricTesting;
+
+public class ProjectMeasuresQueryFactoryValidatorTest {
+
+  @Rule
+  public ExpectedException expectedException = ExpectedException.none();
+
+  @Rule
+  public DbTester db = DbTester.create(System2.INSTANCE);
+
+  DbClient dbClient = db.getDbClient();
+  DbSession dbSession = db.getSession();
+
+  ProjectMeasuresQueryValidator validator = new ProjectMeasuresQueryValidator(dbClient);
+
+  @Test
+  public void does_not_fail_when_metric_criteria_contains_an_existing_metric() throws Exception {
+    insertMetric("ncloc");
+
+    validator.validate(dbSession, ProjectMeasuresQueryFactory.newProjectMeasuresQuery("ncloc > 10"));
+  }
+
+  @Test
+  public void fail_when_metric_does_not_exists() throws Exception {
+    insertMetric("ncloc");
+
+    expectedException.expect(IllegalArgumentException.class);
+    expectedException.expectMessage("Unknown metric(s) [unknown]");
+    validator.validate(dbSession, ProjectMeasuresQueryFactory.newProjectMeasuresQuery("unknown > 10"));
+  }
+
+  @Test
+  public void return_all_unknown_metrics() throws Exception {
+    insertMetric("ncloc");
+
+    expectedException.expect(IllegalArgumentException.class);
+    expectedException.expectMessage("Unknown metric(s) [coverage, debt]");
+    validator.validate(dbSession, ProjectMeasuresQueryFactory.newProjectMeasuresQuery("debt > 10 AND ncloc <= 20 AND coverage > 30"));
+  }
+
+  private void insertMetric(String metricKey) {
+    dbClient.metricDao().insert(dbSession, MetricTesting.newMetricDto().setKey(metricKey));
+  }
+}
index 2210b7c17ab8dfd84875e0685f4cec14760ceac9..bfb5533b21406944121f627982b7620bb772b0d9 100644 (file)
 package org.sonar.server.component.ws;
 
 import com.google.common.base.Throwables;
+import com.google.common.collect.ImmutableMap;
 import java.io.IOException;
+import java.util.List;
+import java.util.Map;
 import java.util.stream.IntStream;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.ExpectedException;
 import org.sonar.api.config.MapSettings;
+import org.sonar.api.measures.Metric;
 import org.sonar.api.server.ws.WebService;
 import org.sonar.api.server.ws.WebService.Param;
 import org.sonar.api.utils.System2;
 import org.sonar.core.util.Uuids;
 import org.sonar.db.DbClient;
+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.server.component.es.ProjectMeasuresDoc;
+import org.sonar.server.component.es.ProjectMeasuresIndex;
+import org.sonar.server.component.es.ProjectMeasuresIndexDefinition;
 import org.sonar.server.es.EsTester;
-import org.sonar.server.project.es.ProjectMeasuresDoc;
-import org.sonar.server.project.es.ProjectMeasuresIndex;
-import org.sonar.server.project.es.ProjectMeasuresIndexDefinition;
 import org.sonar.server.ws.KeyExamples;
 import org.sonar.server.ws.TestRequest;
 import org.sonar.server.ws.WsActionTester;
@@ -48,6 +53,8 @@ import org.sonarqube.ws.WsComponents.Component;
 import org.sonarqube.ws.WsComponents.SearchProjectsWsResponse;
 import org.sonarqube.ws.client.component.SearchProjectsRequest;
 
+import static com.google.common.collect.Lists.newArrayList;
+import static java.util.Collections.emptyList;
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.sonar.db.component.ComponentTesting.newDeveloper;
 import static org.sonar.db.component.ComponentTesting.newDirectory;
@@ -55,9 +62,11 @@ import static org.sonar.db.component.ComponentTesting.newFileDto;
 import static org.sonar.db.component.ComponentTesting.newModuleDto;
 import static org.sonar.db.component.ComponentTesting.newProjectDto;
 import static org.sonar.db.component.ComponentTesting.newView;
-import static org.sonar.server.project.es.ProjectMeasuresIndexDefinition.INDEX_PROJECT_MEASURES;
-import static org.sonar.server.project.es.ProjectMeasuresIndexDefinition.TYPE_PROJECT_MEASURES;
+import static org.sonar.db.metric.MetricTesting.newMetricDto;
+import static org.sonar.server.component.es.ProjectMeasuresIndexDefinition.INDEX_PROJECT_MEASURES;
+import static org.sonar.server.component.es.ProjectMeasuresIndexDefinition.TYPE_PROJECT_MEASURES;
 import static org.sonar.test.JsonAssert.assertJson;
+import static org.sonarqube.ws.client.component.ComponentsWsParameters.PARAM_FILTER;
 
 public class SearchProjectsActionTest {
   @Rule
@@ -66,12 +75,13 @@ public class SearchProjectsActionTest {
   public EsTester es = new EsTester(new ProjectMeasuresIndexDefinition(new MapSettings()));
   @Rule
   public DbTester db = DbTester.create(System2.INSTANCE);
-  ComponentDbTester componentDb = new ComponentDbTester(db);
-  DbClient dbClient = db.getDbClient();
+  private ComponentDbTester componentDb = new ComponentDbTester(db);
+  private DbClient dbClient = db.getDbClient();
+  private DbSession dbSession = db.getSession();
 
-  WsActionTester ws = new WsActionTester(new SearchProjectsAction(dbClient, new ProjectMeasuresIndex(es.client()), new SearchProjectsQueryBuilderValidator(dbClient)));
+  private WsActionTester ws = new WsActionTester(new SearchProjectsAction(dbClient, new ProjectMeasuresIndex(es.client()), new ProjectMeasuresQueryValidator(dbClient)));
 
-  SearchProjectsRequest.Builder request = SearchProjectsRequest.builder();
+  private SearchProjectsRequest.Builder request = SearchProjectsRequest.builder();
 
   @Test
   public void json_example() {
@@ -144,6 +154,32 @@ public class SearchProjectsActionTest {
     assertThat(result.getComponents(0).getName()).isEqualTo("SonarQube");
   }
 
+  @Test
+  public void filter_projects_with_query() {
+    insertProjectInDbAndEs(newProjectDto().setName("Sonar Java"), newArrayList(newMeasure("coverage", 81), newMeasure("ncloc", 10_000d)));
+    insertProjectInDbAndEs(newProjectDto().setName("Sonar Markdown"), newArrayList(newMeasure("coverage", 80d), newMeasure("ncloc", 10_000d)));
+    insertProjectInDbAndEs(newProjectDto().setName("Sonar Qube"), newArrayList(newMeasure("coverage", 80d), newMeasure("ncloc", 10_001d)));
+    request.setFilter("coverage <= 80 and ncloc <= 10000");
+    dbClient.metricDao().insert(dbSession, newMetricDto().setKey("coverage").setValueType(Metric.ValueType.FLOAT.name()));
+    dbClient.metricDao().insert(dbSession, newMetricDto().setKey("ncloc").setValueType(Metric.ValueType.FLOAT.name()));
+    db.commit();
+
+    SearchProjectsWsResponse result = call(request);
+
+    assertThat(result.getComponentsCount()).isEqualTo(1);
+    assertThat(result.getComponents(0).getName()).isEqualTo("Sonar Markdown");
+  }
+
+  @Test
+  public void fail_if_metric_is_unknown() {
+    expectedException.expect(IllegalArgumentException.class);
+    expectedException.expectMessage("Unknown metric(s) [coverage]");
+
+    request.setFilter("coverage > 80");
+
+    call(request);
+  }
+
   @Test
   public void fail_if_page_size_greater_than_500() {
     expectedException.expect(IllegalArgumentException.class);
@@ -158,6 +194,7 @@ public class SearchProjectsActionTest {
 
     httpRequest.setParam(Param.PAGE, String.valueOf(wsRequest.getPage()));
     httpRequest.setParam(Param.PAGE_SIZE, String.valueOf(wsRequest.getPageSize()));
+    httpRequest.setParam(PARAM_FILTER, wsRequest.getFilter());
 
     try {
       return SearchProjectsWsResponse.parseFrom(httpRequest.execute().getInputStream());
@@ -178,12 +215,20 @@ public class SearchProjectsActionTest {
   }
 
   private void insertProjectInDbAndEs(ComponentDto project) {
+    insertProjectInDbAndEs(project, emptyList());
+  }
+
+  private void insertProjectInDbAndEs(ComponentDto project, List<Map<String, Object>> measures) {
     componentDb.insertComponent(project);
     try {
       es.putDocuments(INDEX_PROJECT_MEASURES, TYPE_PROJECT_MEASURES,
-        new ProjectMeasuresDoc().setId(project.uuid()).setKey(project.key()).setName(project.name()));
+        new ProjectMeasuresDoc().setId(project.uuid()).setKey(project.key()).setName(project.name()).setMeasures(measures));
     } catch (Exception e) {
       Throwables.propagate(e);
     }
   }
+
+  private static Map<String, Object> newMeasure(String key, double value) {
+    return ImmutableMap.of("key", key, "value", value);
+  }
 }
diff --git a/server/sonar-server/src/test/java/org/sonar/server/component/ws/SearchProjectsQueryBuilderTest.java b/server/sonar-server/src/test/java/org/sonar/server/component/ws/SearchProjectsQueryBuilderTest.java
deleted file mode 100644 (file)
index 36aaea3..0000000
+++ /dev/null
@@ -1,107 +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.component.ws;
-
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.tuple;
-import static org.sonar.server.component.ws.SearchProjectsQueryBuilder.SearchProjectsCriteriaQuery;
-import static org.sonar.server.component.ws.SearchProjectsQueryBuilder.build;
-import static org.sonar.server.component.ws.SearchProjectsQueryBuilder.SearchProjectsCriteriaQuery.MetricCriteria;
-import static org.sonar.server.component.ws.SearchProjectsQueryBuilder.SearchProjectsCriteriaQuery.Operator;
-
-public class SearchProjectsQueryBuilderTest {
-
-  @Rule
-  public ExpectedException expectedException = ExpectedException.none();
-
-  @Test
-  public void create_query() throws Exception {
-    SearchProjectsCriteriaQuery query = build("ncloc > 10 and coverage <= 80");
-
-    assertThat(query.getMetricCriterias())
-      .extracting(MetricCriteria::getMetricKey, MetricCriteria::getOperator, MetricCriteria::getValue)
-      .containsOnly(
-        tuple("ncloc", Operator.GT, 10d),
-        tuple("coverage", Operator.LTE, 80d));
-  }
-
-  @Test
-  public void convert_upper_case_to_lower_case() throws Exception {
-    assertThat(build("NCLOC > 10 AND coVERage <= 80").getMetricCriterias())
-      .extracting(MetricCriteria::getMetricKey, MetricCriteria::getOperator, MetricCriteria::getValue)
-      .containsOnly(
-        tuple("ncloc", Operator.GT, 10d),
-        tuple("coverage", Operator.LTE, 80d));
-  }
-
-  @Test
-  public void ignore_white_spaces() throws Exception {
-    assertThat(build("   ncloc    >    10   ").getMetricCriterias())
-      .extracting(MetricCriteria::getMetricKey, MetricCriteria::getOperator, MetricCriteria::getValue)
-      .containsOnly(tuple("ncloc", Operator.GT, 10d));
-  }
-
-  @Test
-  public void accept_empty_query() throws Exception {
-    SearchProjectsCriteriaQuery result = build("");
-
-    assertThat(result.getMetricCriterias()).isEmpty();
-  }
-
-  @Test
-  public void fail_on_unknown_operator() throws Exception {
-    expectedException.expect(IllegalArgumentException.class);
-    expectedException.expectMessage("Unknown operator '>='");
-    build("ncloc >= 10");
-  }
-
-  @Test
-  public void fail_on_invalid_criteria() throws Exception {
-    expectedException.expect(IllegalArgumentException.class);
-    expectedException.expectMessage("Invalid criteria 'ncloc ? 10'");
-    build("ncloc ? 10");
-  }
-
-  @Test
-  public void fail_when_no_operator() throws Exception {
-    expectedException.expect(IllegalArgumentException.class);
-    expectedException.expectMessage("Invalid criteria 'ncloc 10'");
-    build("ncloc 10");
-  }
-
-  @Test
-  public void fail_when_no_key() throws Exception {
-    expectedException.expect(IllegalArgumentException.class);
-    expectedException.expectMessage("Invalid criteria '>= 10'");
-    build(">= 10");
-  }
-
-  @Test
-  public void fail_when_no_value() throws Exception {
-    expectedException.expect(IllegalArgumentException.class);
-    expectedException.expectMessage("Invalid criteria 'ncloc >='");
-    build("ncloc >=");
-  }
-}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/component/ws/SearchProjectsQueryBuilderValidatorTest.java b/server/sonar-server/src/test/java/org/sonar/server/component/ws/SearchProjectsQueryBuilderValidatorTest.java
deleted file mode 100644 (file)
index 8de2d9d..0000000
+++ /dev/null
@@ -1,75 +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.component.ws;
-
-import org.junit.Ignore;
-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.db.metric.MetricTesting;
-
-@Ignore
-public class SearchProjectsQueryBuilderValidatorTest {
-
-  @Rule
-  public ExpectedException expectedException = ExpectedException.none();
-
-  @Rule
-  public DbTester db = DbTester.create(System2.INSTANCE);
-
-  DbClient dbClient = db.getDbClient();
-  DbSession dbSession = db.getSession();
-
-  SearchProjectsQueryBuilderValidator validator = new SearchProjectsQueryBuilderValidator(dbClient);
-
-  @Test
-  public void does_not_fail_when_metric_criteria_contains_an_existing_metric() throws Exception {
-    insertMetric("ncloc");
-
-    validator.validate(dbSession, SearchProjectsQueryBuilder.build("ncloc > 10"));
-  }
-
-  @Test
-  public void fail_when_metric_does_not_exists() throws Exception {
-    insertMetric("ncloc");
-
-    expectedException.expect(IllegalArgumentException.class);
-    expectedException.expectMessage("Unknown metric(s) [unknown]");
-    validator.validate(dbSession, SearchProjectsQueryBuilder.build("unknown > 10"));
-  }
-
-  @Test
-  public void return_all_unknown_metrics() throws Exception {
-    insertMetric("ncloc");
-
-    expectedException.expect(IllegalArgumentException.class);
-    expectedException.expectMessage("Unknown metric(s) [coverage, debt]");
-    validator.validate(dbSession, SearchProjectsQueryBuilder.build("debt > 10 AND ncloc <= 20 AND coverage > 30"));
-  }
-
-  private void insertMetric(String metricKey) {
-    dbClient.metricDao().insert(dbSession, MetricTesting.newMetricDto().setKey(metricKey));
-  }
-}
index bda9ddb020cdd99004f2c5489a773115310a0fe8..d8f1a2c499cd1b9630532341ede31540392ec1e8 100644 (file)
@@ -23,7 +23,7 @@ package org.sonar.server.computation.task.projectanalysis.step;
 import org.junit.Rule;
 import org.junit.Test;
 import org.sonar.server.computation.task.projectanalysis.component.TreeRootHolderRule;
-import org.sonar.server.project.es.ProjectMeasuresIndexer;
+import org.sonar.server.component.es.ProjectMeasuresIndexer;
 
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
diff --git a/server/sonar-server/src/test/java/org/sonar/server/project/es/ProjectMeasuresIndexTest.java b/server/sonar-server/src/test/java/org/sonar/server/project/es/ProjectMeasuresIndexTest.java
deleted file mode 100644 (file)
index 5dae8f3..0000000
+++ /dev/null
@@ -1,155 +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.project.es;
-
-import com.google.common.base.Throwables;
-import com.google.common.collect.ImmutableMap;
-import java.util.List;
-import java.util.Map;
-import java.util.stream.IntStream;
-import org.junit.Rule;
-import org.junit.Test;
-import org.sonar.api.config.MapSettings;
-import org.sonar.server.component.ws.SearchProjectsQueryBuilder.SearchProjectsCriteriaQuery;
-import org.sonar.server.component.ws.SearchProjectsQueryBuilder.SearchProjectsCriteriaQuery.MetricCriteria;
-import org.sonar.server.component.ws.SearchProjectsQueryBuilder.SearchProjectsCriteriaQuery.Operator;
-import org.sonar.server.es.EsTester;
-import org.sonar.server.es.SearchIdResult;
-import org.sonar.server.es.SearchOptions;
-
-import static com.google.common.collect.Lists.newArrayList;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.sonar.server.project.es.ProjectMeasuresIndexDefinition.INDEX_PROJECT_MEASURES;
-import static org.sonar.server.project.es.ProjectMeasuresIndexDefinition.TYPE_PROJECT_MEASURES;
-
-public class ProjectMeasuresIndexTest {
-
-  private static final String COVERAGE = "coverage";
-  private static final String NCLOC = "ncloc";
-  @Rule
-  public EsTester es = new EsTester(new ProjectMeasuresIndexDefinition(new MapSettings()));
-
-  private ProjectMeasuresIndex underTest = new ProjectMeasuresIndex(es.client());
-
-  @Test
-  public void empty_search() {
-    List<String> result = underTest.search(new SearchProjectsCriteriaQuery(), new SearchOptions()).getIds();
-
-    assertThat(result).isEmpty();
-  }
-
-  @Test
-  public void search_sort_by_name_case_insensitive() {
-    addDocs(newDoc("P1", "K1", "Windows"),
-      newDoc("P3", "K3", "apachee"),
-      newDoc("P2", "K2", "Apache"));
-
-    List<String> result = underTest.search(new SearchProjectsCriteriaQuery(), new SearchOptions()).getIds();
-
-    assertThat(result).containsExactly("P2", "P3", "P1");
-  }
-
-  @Test
-  public void search_paginate_results() {
-    IntStream.rangeClosed(1, 9)
-      .forEach(i -> addDocs(newDoc("P" + i, "K" + i, "P" + i)));
-
-    SearchIdResult<String> result = underTest.search(new SearchProjectsCriteriaQuery(), new SearchOptions().setPage(2, 3));
-
-    assertThat(result.getIds()).containsExactly("P4", "P5", "P6");
-    assertThat(result.getTotal()).isEqualTo(9);
-  }
-
-  @Test
-  public void filter_with_lower_than_or_equals() {
-    addDocs(
-      newDoc("P1", "K1", "N1").setMeasures(newArrayList(newMeasure(COVERAGE, 79d), newMeasure(NCLOC, 10_000d))),
-      newDoc("P2", "K2", "N2").setMeasures(newArrayList(newMeasure(COVERAGE, 80d), newMeasure(NCLOC, 10_000d))),
-      newDoc("P3", "K3", "N3").setMeasures(newArrayList(newMeasure(COVERAGE, 81d), newMeasure(NCLOC, 10_000d))));
-
-    SearchProjectsCriteriaQuery esQuery = new SearchProjectsCriteriaQuery()
-      .addMetricCriteria(new MetricCriteria(COVERAGE, Operator.LTE, 80d));
-    List<String> result = underTest.search(esQuery, new SearchOptions()).getIds();
-
-    assertThat(result).containsExactly("P1", "P2");
-  }
-
-  @Test
-  public void filter_with_greater_than() {
-    addDocs(
-      newDoc("P1", "K1", "N1").setMeasures(newArrayList(newMeasure(COVERAGE, 80d), newMeasure(NCLOC, 10_000d))),
-      newDoc("P2", "K2", "N2").setMeasures(newArrayList(newMeasure(COVERAGE, 80d), newMeasure(NCLOC, 10_001d))),
-      newDoc("P3", "K3", "N3").setMeasures(newArrayList(newMeasure(COVERAGE, 80d), newMeasure(NCLOC, 10_001d))));
-
-    SearchProjectsCriteriaQuery esQuery = new SearchProjectsCriteriaQuery()
-      .addMetricCriteria(new MetricCriteria(NCLOC, Operator.GT, 10_000d));
-    List<String> result = underTest.search(esQuery, new SearchOptions()).getIds();
-
-    assertThat(result).containsExactly("P2", "P3");
-  }
-
-  @Test
-  public void filter_with_equals() {
-    addDocs(
-      newDoc("P1", "K1", "N1").setMeasures(newArrayList(newMeasure(COVERAGE, 79d), newMeasure(NCLOC, 10_000d))),
-      newDoc("P2", "K2", "N2").setMeasures(newArrayList(newMeasure(COVERAGE, 80d), newMeasure(NCLOC, 10_000d))),
-      newDoc("P3", "K3", "N3").setMeasures(newArrayList(newMeasure(COVERAGE, 81d), newMeasure(NCLOC, 10_000d))));
-
-    SearchProjectsCriteriaQuery esQuery = new SearchProjectsCriteriaQuery()
-      .addMetricCriteria(new MetricCriteria(COVERAGE, Operator.EQ, 80d));
-    List<String> result = underTest.search(esQuery, new SearchOptions()).getIds();
-
-    assertThat(result).containsExactly("P2");
-  }
-
-  @Test
-  public void filter_on_several_metrics() {
-    addDocs(
-      newDoc("P1", "K1", "N1").setMeasures(newArrayList(newMeasure(COVERAGE, 81d), newMeasure(NCLOC, 10_001d))),
-      newDoc("P2", "K2", "N2").setMeasures(newArrayList(newMeasure(COVERAGE, 80d), newMeasure(NCLOC, 10_001d))),
-      newDoc("P3", "K3", "N3").setMeasures(newArrayList(newMeasure(COVERAGE, 79d), newMeasure(NCLOC, 10_000d))));
-
-    SearchProjectsCriteriaQuery esQuery = new SearchProjectsCriteriaQuery()
-      .addMetricCriteria(new MetricCriteria(COVERAGE, Operator.LTE, 80d))
-      .addMetricCriteria(new MetricCriteria(NCLOC, Operator.GT, 10_000d));
-    List<String> result = underTest.search(esQuery, new SearchOptions()).getIds();
-
-    assertThat(result).containsExactly("P2");
-  }
-
-  private void addDocs(ProjectMeasuresDoc... docs) {
-    try {
-      es.putDocuments(INDEX_PROJECT_MEASURES, TYPE_PROJECT_MEASURES, docs);
-    } catch (Exception e) {
-      Throwables.propagate(e);
-    }
-  }
-
-  private static ProjectMeasuresDoc newDoc(String uuid, String key, String name) {
-    return new ProjectMeasuresDoc()
-      .setId(uuid)
-      .setKey(key)
-      .setName(name);
-  }
-
-  private Map<String, Object> newMeasure(String key, double value) {
-    return ImmutableMap.of("key", key, "value", value);
-  }
-}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/project/es/ProjectMeasuresIndexerTest.java b/server/sonar-server/src/test/java/org/sonar/server/project/es/ProjectMeasuresIndexerTest.java
deleted file mode 100644 (file)
index 3d91b1b..0000000
+++ /dev/null
@@ -1,144 +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.project.es;
-
-import java.util.Date;
-import org.elasticsearch.action.search.SearchRequestBuilder;
-import org.junit.Rule;
-import org.junit.Test;
-import org.sonar.api.config.MapSettings;
-import org.sonar.api.utils.System2;
-import org.sonar.db.DbTester;
-import org.sonar.db.component.ComponentDbTester;
-import org.sonar.db.component.ComponentDto;
-import org.sonar.db.component.SnapshotDto;
-import org.sonar.server.es.EsTester;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.elasticsearch.index.query.QueryBuilders.boolQuery;
-import static org.elasticsearch.index.query.QueryBuilders.matchAllQuery;
-import static org.elasticsearch.index.query.QueryBuilders.termQuery;
-import static org.sonar.db.component.ComponentTesting.newProjectDto;
-import static org.sonar.server.project.es.ProjectMeasuresIndexDefinition.INDEX_PROJECT_MEASURES;
-import static org.sonar.server.project.es.ProjectMeasuresIndexDefinition.TYPE_PROJECT_MEASURES;
-
-public class ProjectMeasuresIndexerTest {
-
-  @Rule
-  public EsTester esTester = new EsTester(new ProjectMeasuresIndexDefinition(new MapSettings()));
-
-  @Rule
-  public DbTester dbTester = DbTester.create(System2.INSTANCE);
-
-  ComponentDbTester componentDbTester = new ComponentDbTester(dbTester);
-
-  ProjectMeasuresIndexer underTest = new ProjectMeasuresIndexer(dbTester.getDbClient(), esTester.client());
-
-  @Test
-  public void index_nothing() {
-    underTest.index();
-
-    assertThat(esTester.countDocuments(INDEX_PROJECT_MEASURES, TYPE_PROJECT_MEASURES)).isZero();
-  }
-
-  @Test
-  public void index_all_project() {
-    componentDbTester.insertProjectAndSnapshot(newProjectDto());
-    componentDbTester.insertProjectAndSnapshot(newProjectDto());
-    componentDbTester.insertProjectAndSnapshot(newProjectDto());
-
-    underTest.index();
-
-    assertThat(esTester.countDocuments(INDEX_PROJECT_MEASURES, TYPE_PROJECT_MEASURES)).isEqualTo(3);
-  }
-
-  @Test
-  public void index_projects_even_when_no_analysis() {
-    ComponentDto project = componentDbTester.insertProject();
-
-    underTest.index();
-
-    assertThat(esTester.getIds(INDEX_PROJECT_MEASURES, TYPE_PROJECT_MEASURES)).containsOnly(project.uuid());
-  }
-
-  @Test
-  public void index_one_project() throws Exception {
-    ComponentDto project = newProjectDto();
-    componentDbTester.insertProjectAndSnapshot(project);
-    componentDbTester.insertProjectAndSnapshot(newProjectDto());
-
-    underTest.index(project.uuid());
-
-    assertThat(esTester.getIds(INDEX_PROJECT_MEASURES, TYPE_PROJECT_MEASURES)).containsOnly(project.uuid());
-  }
-
-  @Test
-  public void update_existing_document_when_indexing_one_project() throws Exception {
-    String uuid = "PROJECT-UUID";
-    esTester.putDocuments(INDEX_PROJECT_MEASURES, TYPE_PROJECT_MEASURES, new ProjectMeasuresDoc()
-      .setId(uuid)
-      .setKey("Old Key")
-      .setName("Old Name")
-      .setAnalysedAt(new Date(1_000_000L)));
-    ComponentDto project = newProjectDto(uuid).setKey("New key").setName("New name");
-    SnapshotDto analysis = componentDbTester.insertProjectAndSnapshot(project);
-
-    underTest.index(project.uuid());
-
-    assertThat(esTester.getIds(INDEX_PROJECT_MEASURES, TYPE_PROJECT_MEASURES)).containsOnly(uuid);
-    SearchRequestBuilder request = esTester.client()
-      .prepareSearch(INDEX_PROJECT_MEASURES)
-      .setTypes(TYPE_PROJECT_MEASURES)
-      .setQuery(boolQuery().must(matchAllQuery()).filter(
-        boolQuery()
-          .must(termQuery("_id", uuid))
-          .must(termQuery(ProjectMeasuresIndexDefinition.FIELD_KEY, "New key"))
-          .must(termQuery(ProjectMeasuresIndexDefinition.FIELD_NAME, "New name"))
-          .must(termQuery(ProjectMeasuresIndexDefinition.FIELD_ANALYSED_AT, new Date(analysis.getCreatedAt())))));
-    assertThat(request.get().getHits()).hasSize(1);
-  }
-
-  @Test
-  public void delete_project() {
-    ComponentDto project1 = newProjectDto();
-    componentDbTester.insertProjectAndSnapshot(project1);
-    ComponentDto project2 = newProjectDto();
-    componentDbTester.insertProjectAndSnapshot(project2);
-    ComponentDto project3 = newProjectDto();
-    componentDbTester.insertProjectAndSnapshot(project3);
-    underTest.index();
-
-    underTest.deleteProject(project1.uuid());
-
-    assertThat(esTester.getIds(INDEX_PROJECT_MEASURES, TYPE_PROJECT_MEASURES)).containsOnly(project2.uuid(), project3.uuid());
-  }
-
-  @Test
-  public void does_nothing_when_deleting_unknown_project() throws Exception {
-    ComponentDto project = newProjectDto();
-    componentDbTester.insertProjectAndSnapshot(project);
-    underTest.index();
-
-    underTest.deleteProject("UNKNOWN");
-
-    assertThat(esTester.getIds(INDEX_PROJECT_MEASURES, TYPE_PROJECT_MEASURES)).containsOnly(project.uuid());
-  }
-}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/project/es/ProjectMeasuresResultSetIteratorTest.java b/server/sonar-server/src/test/java/org/sonar/server/project/es/ProjectMeasuresResultSetIteratorTest.java
deleted file mode 100644 (file)
index add4689..0000000
+++ /dev/null
@@ -1,168 +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.project.es;
-
-import com.google.common.collect.Maps;
-import java.util.Date;
-import java.util.Map;
-import javax.annotation.Nullable;
-import org.junit.Rule;
-import org.junit.Test;
-import org.sonar.api.utils.System2;
-import org.sonar.db.DbClient;
-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.component.SnapshotDto;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.sonar.db.component.ComponentTesting.newDeveloper;
-import static org.sonar.db.component.ComponentTesting.newProjectDto;
-import static org.sonar.db.component.ComponentTesting.newView;
-import static org.sonar.db.component.SnapshotTesting.newAnalysis;
-
-public class ProjectMeasuresResultSetIteratorTest {
-
-  @Rule
-  public DbTester dbTester = DbTester.create(System2.INSTANCE);
-
-  DbClient dbClient = dbTester.getDbClient();
-  DbSession dbSession = dbTester.getSession();
-
-  ComponentDbTester componentDbTester = new ComponentDbTester(dbTester);
-
-  @Test
-  public void return_one_project_measure() {
-    ComponentDto project = newProjectDto().setKey("Project-Key").setName("Project Name");
-    SnapshotDto analysis = componentDbTester.insertProjectAndSnapshot(project);
-
-    Map<String, ProjectMeasuresDoc> docsById = createResultSetAndReturnDocsById();
-
-    assertThat(docsById).hasSize(1);
-    ProjectMeasuresDoc doc = docsById.get(project.uuid());
-    assertThat(doc).isNotNull();
-    assertThat(doc.getId()).isEqualTo(project.uuid());
-    assertThat(doc.getKey()).isEqualTo("Project-Key");
-    assertThat(doc.getName()).isEqualTo("Project Name");
-    assertThat(doc.getAnalysedAt()).isNotNull().isEqualTo(new Date(analysis.getCreatedAt()));
-  }
-
-  @Test
-  public void return_many_project_measures() {
-    componentDbTester.insertProjectAndSnapshot(newProjectDto());
-    componentDbTester.insertProjectAndSnapshot(newProjectDto());
-    componentDbTester.insertProjectAndSnapshot(newProjectDto());
-
-    assertThat(createResultSetAndReturnDocsById()).hasSize(3);
-  }
-
-  @Test
-  public void return_project_without_analysis() throws Exception {
-    ComponentDto project = componentDbTester.insertComponent(newProjectDto());
-    dbClient.snapshotDao().insert(dbSession, newAnalysis(project).setLast(false));
-    dbSession.commit();
-
-    Map<String, ProjectMeasuresDoc> docsById = createResultSetAndReturnDocsById();
-
-    assertThat(docsById).hasSize(1);
-    ProjectMeasuresDoc doc = docsById.get(project.uuid());
-    assertThat(doc.getAnalysedAt()).isNull();
-  }
-
-  @Test
-  public void does_not_return_non_active_projects() throws Exception {
-    // Disabled project
-    componentDbTester.insertProjectAndSnapshot(newProjectDto().setEnabled(false));
-    // Disabled project with analysis
-    ComponentDto project = componentDbTester.insertComponent(newProjectDto().setEnabled(false));
-    dbClient.snapshotDao().insert(dbSession, newAnalysis(project));
-
-    // A view
-    componentDbTester.insertProjectAndSnapshot(newView());
-
-    // A developer
-    componentDbTester.insertProjectAndSnapshot(newDeveloper("dev"));
-
-    dbSession.commit();
-
-    assertResultSetIsEmpty();
-  }
-
-  @Test
-  public void return_only_docs_from_given_project() throws Exception {
-    ComponentDto project = newProjectDto();
-    SnapshotDto analysis = componentDbTester.insertProjectAndSnapshot(project);
-    componentDbTester.insertProjectAndSnapshot(newProjectDto());
-    componentDbTester.insertProjectAndSnapshot(newProjectDto());
-
-    Map<String, ProjectMeasuresDoc> docsById = createResultSetAndReturnDocsById(0L, project.uuid());
-
-    assertThat(docsById).hasSize(1);
-    ProjectMeasuresDoc doc = docsById.get(project.uuid());
-    assertThat(doc).isNotNull();
-    assertThat(doc.getId()).isEqualTo(project.uuid());
-    assertThat(doc.getKey()).isNotNull().isEqualTo(project.getKey());
-    assertThat(doc.getName()).isNotNull().isEqualTo(project.name());
-    assertThat(doc.getAnalysedAt()).isNotNull().isEqualTo(new Date(analysis.getCreatedAt()));
-  }
-
-  @Test
-  public void return_only_docs_after_date() throws Exception {
-    ComponentDto project1 = newProjectDto();
-    dbClient.componentDao().insert(dbSession, project1);
-    dbClient.snapshotDao().insert(dbSession, newAnalysis(project1).setCreatedAt(1_000_000L));
-    ComponentDto project2 = newProjectDto();
-    dbClient.componentDao().insert(dbSession, project2);
-    dbClient.snapshotDao().insert(dbSession, newAnalysis(project2).setCreatedAt(2_000_000L));
-    dbSession.commit();
-
-    Map<String, ProjectMeasuresDoc> docsById = createResultSetAndReturnDocsById(1_500_000L, null);
-
-    assertThat(docsById).hasSize(1);
-    assertThat(docsById.get(project2.uuid())).isNotNull();
-  }
-
-  @Test
-  public void return_nothing_on_unknown_project() throws Exception {
-    componentDbTester.insertProjectAndSnapshot(newProjectDto());
-
-    Map<String, ProjectMeasuresDoc> docsById = createResultSetAndReturnDocsById(0L, "UNKNOWN");
-
-    assertThat(docsById).isEmpty();
-  }
-
-  private Map<String, ProjectMeasuresDoc> createResultSetAndReturnDocsById() {
-    return createResultSetAndReturnDocsById(0L, null);
-  }
-
-  private Map<String, ProjectMeasuresDoc> createResultSetAndReturnDocsById(long date, @Nullable String projectUuid) {
-    ProjectMeasuresResultSetIterator it = ProjectMeasuresResultSetIterator.create(dbTester.getDbClient(), dbTester.getSession(), date, projectUuid);
-    Map<String, ProjectMeasuresDoc> docsById = Maps.uniqueIndex(it, ProjectMeasuresDoc::getId);
-    it.close();
-    return docsById;
-  }
-
-  private void assertResultSetIsEmpty() {
-    assertThat(createResultSetAndReturnDocsById()).isEmpty();
-  }
-
-}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/project/es/ProjectsEsModuleTest.java b/server/sonar-server/src/test/java/org/sonar/server/project/es/ProjectsEsModuleTest.java
deleted file mode 100644 (file)
index 38f1f5e..0000000
+++ /dev/null
@@ -1,35 +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.project.es;
-
-import org.junit.Test;
-import org.sonar.core.platform.ComponentContainer;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-public class ProjectsEsModuleTest {
-  @Test
-  public void verify_count_of_added_components() {
-    ComponentContainer container = new ComponentContainer();
-    new ProjectsEsModule().configure(container);
-    assertThat(container.size()).isEqualTo(3 + 2);
-  }
-}
index 4d7a3da3ea8956152441916b2962676811730a5d..cee5160cc17b4fe4c42447538ec269b30856936a 100644 (file)
@@ -51,7 +51,7 @@ import org.sonar.server.issue.index.IssueAuthorizationDoc;
 import org.sonar.server.issue.index.IssueAuthorizationIndexer;
 import org.sonar.server.issue.index.IssueIndexDefinition;
 import org.sonar.server.issue.index.IssueIndexer;
-import org.sonar.server.project.es.ProjectMeasuresIndexer;
+import org.sonar.server.component.es.ProjectMeasuresIndexer;
 import org.sonar.server.test.index.TestDoc;
 import org.sonar.server.test.index.TestIndexDefinition;
 import org.sonar.server.test.index.TestIndexer;
index 84275a5f714b8c5688ca7d51408b5ad5d608c462..eb8968c627727e0d092b8faefeab61c8691f711f 100644 (file)
@@ -49,7 +49,7 @@ import org.sonar.server.issue.index.IssueAuthorizationDoc;
 import org.sonar.server.issue.index.IssueAuthorizationIndexer;
 import org.sonar.server.issue.index.IssueIndexDefinition;
 import org.sonar.server.issue.index.IssueIndexer;
-import org.sonar.server.project.es.ProjectMeasuresIndexer;
+import org.sonar.server.component.es.ProjectMeasuresIndexer;
 import org.sonar.server.test.index.TestDoc;
 import org.sonar.server.test.index.TestIndexDefinition;
 import org.sonar.server.test.index.TestIndexer;
index fddb4f8bcce73cc831361bba04ccd9e59585996d..ffab7f58616a974e116b387e115e8efec9cfe8c2 100644 (file)
@@ -35,10 +35,10 @@ import org.sonar.db.qualityprofile.QualityProfileDbTester;
 import org.sonar.db.qualityprofile.QualityProfileDto;
 import org.sonar.server.component.ComponentFinder;
 import org.sonar.server.component.ComponentService;
+import org.sonar.server.component.es.ProjectMeasuresIndexDefinition;
+import org.sonar.server.component.es.ProjectMeasuresIndexer;
 import org.sonar.server.es.EsTester;
 import org.sonar.server.language.LanguageTesting;
-import org.sonar.server.project.es.ProjectMeasuresIndexDefinition;
-import org.sonar.server.project.es.ProjectMeasuresIndexer;
 import org.sonar.server.qualityprofile.QProfileLookup;
 import org.sonar.server.qualityprofile.QProfileName;
 import org.sonar.server.qualityprofile.QProfileProjectOperations;
index c8ba9187cb5729981b9051142bfdf53c8afbb8dd..b4f0d23f6e1e35a5ea78dfc5e81b6c746045bab2 100644 (file)
@@ -83,6 +83,9 @@ public class SearchProjectsRequest {
       if (pageSize == null) {
         pageSize = DEFAULT_PAGE_SIZE;
       }
+      if (filter == null) {
+        filter = "";
+      }
 
       checkArgument(pageSize <= MAX_PAGE_SIZE, "Page size must not be greater than %s", MAX_PAGE_SIZE);