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;
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
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;
--- /dev/null
+/*
+ * 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;
+ }
+}
--- /dev/null
+/*
+ * 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());
+ }
+
+ }
+}
--- /dev/null
+/*
+ * 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);
+ }
+}
--- /dev/null
+/*
+ * 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());
+ }
+}
--- /dev/null
+/*
+ * 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;
+ }
+ }
+}
--- /dev/null
+/*
+ * 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;
+ }
+}
--- /dev/null
+/*
+ * 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);
+ }
+}
--- /dev/null
+/*
+ * 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;
UpdateKeyAction.class,
BulkUpdateKeyAction.class,
SearchProjectsAction.class,
- SearchProjectsQueryBuilderValidator.class);
+ ProjectMeasuresQueryValidator.class);
}
}
--- /dev/null
+/*
+ * 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));
+ }
+
+}
--- /dev/null
+/*
+ * 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));
+ }
+}
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;
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;
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
action
.createParam(PARAM_FILTER)
- .setDescription("TODO")
- .setSince("6.2");
+ .setDescription("TODO");
}
@Override
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()));
}
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> {
+++ /dev/null
-/*
- * 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;
- }
- }
- }
-
-}
+++ /dev/null
-/*
- * 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));
- }
-}
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 {
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;
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;
+++ /dev/null
-/*
- * 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;
- }
-}
+++ /dev/null
-/*
- * 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());
- }
-
- }
-}
+++ /dev/null
-/*
- * 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);
- }
-}
+++ /dev/null
-/*
- * 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());
- }
-}
+++ /dev/null
-/*
- * 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;
- }
-}
+++ /dev/null
-/*
- * 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);
- }
-}
+++ /dev/null
-/*
- * 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;
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;
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;
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 {
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;
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 {
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;
--- /dev/null
+/*
+ * 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);
+ }
+}
--- /dev/null
+/*
+ * 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());
+ }
+}
--- /dev/null
+/*
+ * 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();
+ }
+
+}
--- /dev/null
+/*
+ * 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);
+ }
+}
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;
--- /dev/null
+/*
+ * 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();
+ }
+}
--- /dev/null
+/*
+ * 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));
+ }
+}
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;
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;
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
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() {
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);
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());
}
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);
+ }
}
+++ /dev/null
-/*
- * 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 >=");
- }
-}
+++ /dev/null
-/*
- * 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));
- }
-}
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;
+++ /dev/null
-/*
- * 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);
- }
-}
+++ /dev/null
-/*
- * 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());
- }
-}
+++ /dev/null
-/*
- * 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();
- }
-
-}
+++ /dev/null
-/*
- * 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);
- }
-}
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;
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;
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;
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);