+++ /dev/null
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2014 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube 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.
- *
- * SonarQube 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.core.measure;
-
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Strings;
-import com.google.common.collect.Lists;
-import org.apache.commons.lang.StringUtils;
-import org.apache.commons.lang.builder.ReflectionToStringBuilder;
-import org.sonar.api.measures.Metric;
-import org.sonar.api.resources.Qualifiers;
-
-import javax.annotation.CheckForNull;
-import javax.annotation.Nullable;
-
-import java.util.Collections;
-import java.util.Date;
-import java.util.List;
-
-public class MeasureFilter {
-
- // conditions on resources
- private String baseResourceKey;
-
- // only if baseResourceKey or baseResourceId are set
- private boolean onBaseResourceChildren = false;
-
- private List<String> resourceScopes = Collections.emptyList();
- private List<String> resourceQualifiers = Collections.emptyList();
- private String resourceKey = null;
- private String resourceName = null;
- private Date fromDate = null, toDate = null;
- private boolean userFavourites = false;
-
- // conditions on measures
- private List<MeasureFilterCondition> measureConditions = Lists.newArrayList();
-
- // sort
- private MeasureFilterSort sort = new MeasureFilterSort();
-
- public String getBaseResourceKey() {
- return baseResourceKey;
- }
-
- public MeasureFilter setBaseResourceKey(String s) {
- this.baseResourceKey = s;
- return this;
- }
-
- public MeasureFilter setOnBaseResourceChildren(boolean b) {
- this.onBaseResourceChildren = b;
- return this;
- }
-
- public boolean isOnBaseResourceChildren() {
- return onBaseResourceChildren;
- }
-
- public MeasureFilter setResourceScopes(@Nullable List<String> list) {
- this.resourceScopes = sanitize(list);
- return this;
- }
-
- public MeasureFilter setResourceQualifiers(@Nullable List<String> list) {
- this.resourceQualifiers = sanitize(list);
- if (resourceQualifiers.contains(Qualifiers.FILE)) {
- resourceQualifiers.add(Qualifiers.CLASS);
- }
- if (resourceQualifiers.contains(Qualifiers.DIRECTORY)) {
- resourceQualifiers.add(Qualifiers.PACKAGE);
- }
- return this;
- }
-
- public MeasureFilter setUserFavourites(boolean b) {
- this.userFavourites = b;
- return this;
- }
-
- public boolean isOnFavourites() {
- return userFavourites;
- }
-
- public String getResourceName() {
- return resourceName;
- }
-
- public MeasureFilter setResourceName(String s) {
- this.resourceName = s;
- return this;
- }
-
- public String getResourceKey() {
- return resourceKey;
- }
-
- public MeasureFilter setResourceKey(String s) {
- this.resourceKey = s;
- return this;
- }
-
- public MeasureFilter addCondition(MeasureFilterCondition condition) {
- this.measureConditions.add(condition);
- return this;
- }
-
- public MeasureFilter setSortOn(MeasureFilterSort.Field sortField) {
- this.sort.setField(sortField);
- return this;
- }
-
- public MeasureFilter setSortAsc(boolean b) {
- this.sort.setAsc(b);
- return this;
- }
-
- public MeasureFilter setSortOnMetric(Metric m) {
- this.sort.setField(MeasureFilterSort.Field.METRIC);
- this.sort.setMetric(m);
- return this;
- }
-
- public MeasureFilter setSortOnPeriod(int period) {
- this.sort.setPeriod(period);
- return this;
- }
-
- public MeasureFilter setFromDate(@Nullable Date d) {
- this.fromDate = d;
- return this;
- }
-
- public MeasureFilter setToDate(@Nullable Date d) {
- this.toDate = d;
- return this;
- }
-
- @CheckForNull
- public Date getFromDate() {
- return fromDate;
- }
-
- @CheckForNull
- public Date getToDate() {
- return toDate;
- }
-
- public List<String> getResourceScopes() {
- return resourceScopes;
- }
-
- public List<String> getResourceQualifiers() {
- return resourceQualifiers;
- }
-
- public List<MeasureFilterCondition> getMeasureConditions() {
- return measureConditions;
- }
-
- MeasureFilterSort sort() {
- return sort;
- }
-
- public boolean isEmpty() {
- return resourceQualifiers.isEmpty() && resourceScopes.isEmpty() && StringUtils.isEmpty(baseResourceKey) && !userFavourites;
- }
-
- @VisibleForTesting
- static List<String> sanitize(@Nullable List<String> list) {
- return isEmptyList(list) ? Collections.<String> emptyList() : Lists.newArrayList(list);
- }
-
- private static boolean isEmptyList(@Nullable List<String> list) {
- boolean blank = false;
- if (list == null || list.isEmpty() || (list.size() == 1 && Strings.isNullOrEmpty(list.get(0)))) {
- blank = true;
- }
- return blank;
- }
-
- @Override
- public String toString() {
- return ReflectionToStringBuilder.toString(this);
- }
-}
+++ /dev/null
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2014 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube 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.
- *
- * SonarQube 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.core.measure;
-
-import org.apache.commons.lang.builder.ReflectionToStringBuilder;
-import org.apache.commons.lang.builder.ToStringStyle;
-import org.sonar.api.measures.Metric;
-
-public class MeasureFilterCondition {
- public enum Operator {
- EQUALS("eq", "="), GREATER("gt", ">"), GREATER_OR_EQUALS("gte", ">="), LESS("lt", "<"), LESS_OR_EQUALS("lte", "<="), IN("in", "IN");
-
- private String code;
- private String sql;
-
- private Operator(String code, String sql) {
- this.code = code;
- this.sql = sql;
- }
-
- public String getSql() {
- return sql;
- }
-
- public static Operator fromCode(String code) {
- for (Operator operator : values()) {
- if (operator.code.equals(code)) {
- return operator;
- }
- }
- throw new IllegalArgumentException("Unknown operator code: " + code);
- }
- }
-
- private final Metric metric;
- private final Operator operator;
- private final double value;
- private final String textValue;
- private Integer period = null;
-
- public MeasureFilterCondition(Metric metric, Operator operator, double value) {
- this.metric = metric;
- this.operator = operator;
- this.value = value;
- this.textValue = null;
- }
-
- public MeasureFilterCondition(Metric metric, Operator operator, String textValue) {
- this.metric = metric;
- this.operator = operator;
- this.value = 0;
- this.textValue = textValue;
- }
-
- public MeasureFilterCondition setPeriod(Integer period) {
- this.period = period;
- return this;
- }
-
- public Metric metric() {
- return metric;
- }
-
- public Operator operator() {
- return operator;
- }
-
- public double value() {
- return value;
- }
-
- public String textValue() {
- return textValue;
- }
-
- public Integer period() {
- return period;
- }
-
- StringBuilder appendSqlColumn(StringBuilder sb, int conditionIndex) {
- sb.append("pmcond").append(conditionIndex);
- if (period != null) {
- sb.append(".variation_value_").append(period).toString();
- } else if (textValue == null) {
- sb.append(".value");
- } else {
- sb.append(".text_value");
- }
- return sb;
- }
-
- StringBuilder appendSqlCondition(StringBuilder sql, int conditionIndex) {
- String table = "pmcond" + conditionIndex;
- sql.append(" ").append(table).append(".metric_id=");
- sql.append(metric.getId());
- sql.append(" AND ");
- appendSqlColumn(sql, conditionIndex);
- sql.append(" ").append(operator.getSql()).append(" ");
- if (textValue == null) {
- sql.append(value);
- } else {
- sql.append(textValue);
- }
- sql.append(" AND ");
- sql.append(table).append(".rule_id IS NULL AND ");
- sql.append(table).append(".rule_priority IS NULL AND ");
- sql.append(table).append(".characteristic_id IS NULL AND ");
- sql.append(table).append(".person_id IS NULL ");
- return sql;
- }
-
- @Override
- public String toString() {
- return ReflectionToStringBuilder.toString(this, ToStringStyle.SIMPLE_STYLE);
- }
-}
+++ /dev/null
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2014 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube 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.
- *
- * SonarQube 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.core.measure;
-
-import org.apache.commons.lang.builder.ToStringBuilder;
-import org.apache.commons.lang.builder.ToStringStyle;
-import org.sonar.core.resource.SnapshotDto;
-
-import javax.annotation.Nullable;
-
-class MeasureFilterContext {
- private Long userId = null;
- private SnapshotDto baseSnapshot = null;
- private String sql;
- private String data;
-
- Long getUserId() {
- return userId;
- }
-
- MeasureFilterContext setUserId(@Nullable Long userId) {
- this.userId = userId;
- return this;
- }
-
- SnapshotDto getBaseSnapshot() {
- return baseSnapshot;
- }
-
- MeasureFilterContext setBaseSnapshot(@Nullable SnapshotDto baseSnapshot) {
- this.baseSnapshot = baseSnapshot;
- return this;
- }
-
- String getSql() {
- return sql;
- }
-
- MeasureFilterContext setSql(String sql) {
- this.sql = sql;
- return this;
- }
-
- String getData() {
- return data;
- }
-
- MeasureFilterContext setData(String data) {
- this.data = data;
- return this;
- }
-
- @Override
- public String toString() {
- return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE)
- .append("filter", data)
- .append("sql", sql)
- .append("user", userId)
- .toString();
- }
-}
+++ /dev/null
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2014 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube 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.
- *
- * SonarQube 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.core.measure;
-
-import com.google.common.base.Joiner;
-import org.apache.commons.lang.SystemUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.sonar.api.ServerComponent;
-import org.sonar.core.profiling.Profiling;
-import org.sonar.core.profiling.Profiling.Level;
-import org.sonar.core.profiling.StopWatch;
-
-import javax.annotation.Nullable;
-
-import java.util.List;
-import java.util.Map;
-
-public class MeasureFilterEngine implements ServerComponent {
-
- private static final Logger LOG = LoggerFactory.getLogger("org.sonar.MEASURE_FILTER");
-
- private final MeasureFilterFactory factory;
- private final MeasureFilterExecutor executor;
- private final Profiling profiling;
-
- public MeasureFilterEngine(MeasureFilterFactory factory, MeasureFilterExecutor executor, Profiling profiling) {
- this.executor = executor;
- this.factory = factory;
- this.profiling = profiling;
- }
-
- public MeasureFilterResult execute(Map<String, Object> filterMap, @Nullable Long userId) {
- StopWatch watch = profiling.start("measures", Level.BASIC);
- StopWatch sqlWatch = null;
- MeasureFilterResult result = new MeasureFilterResult();
- MeasureFilterContext context = new MeasureFilterContext();
- context.setUserId(userId);
- context.setData(String.format("{%s}", Joiner.on('|').withKeyValueSeparator("=").join(filterMap)));
- try {
- MeasureFilter filter = factory.create(filterMap);
- sqlWatch = profiling.start("sql", Level.FULL);
- List<MeasureFilterRow> rows = executor.execute(filter, context);
- result.setRows(rows);
-
- } catch (NumberFormatException e) {
- result.setError(MeasureFilterResult.Error.VALUE_SHOULD_BE_A_NUMBER);
- LOG.debug("Value selected for the metric should be a number: " + context);
- } catch (Exception e) {
- result.setError(MeasureFilterResult.Error.UNKNOWN);
- LOG.error("Fail to execute measure filter: " + context, e);
- } finally {
- if (sqlWatch != null) {
- sqlWatch.stop(context.getSql());
- }
- watch.stop(log(context, result));
- }
- return result;
- }
-
- private String log(MeasureFilterContext context, MeasureFilterResult result) {
- StringBuilder log = new StringBuilder();
- log.append(SystemUtils.LINE_SEPARATOR);
- log.append("request: ").append(context.getData()).append(SystemUtils.LINE_SEPARATOR);
- log.append(" result: ").append(result.toString());
- return log.toString();
- }
-
-}
+++ /dev/null
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2014 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube 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.
- *
- * SonarQube 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.core.measure;
-
-import com.google.common.base.Strings;
-import org.apache.commons.dbutils.DbUtils;
-import org.apache.ibatis.session.SqlSession;
-import org.sonar.api.ServerComponent;
-import org.sonar.core.persistence.Database;
-import org.sonar.core.persistence.MyBatis;
-import org.sonar.core.resource.ResourceDao;
-
-import java.sql.Connection;
-import java.sql.SQLException;
-import java.util.Collections;
-import java.util.List;
-
-public class MeasureFilterExecutor implements ServerComponent {
-
- private MyBatis mybatis;
- private Database database;
- private ResourceDao resourceDao;
-
- public MeasureFilterExecutor(MyBatis mybatis, Database database, ResourceDao resourceDao) {
- this.mybatis = mybatis;
- this.database = database;
- this.resourceDao = resourceDao;
- }
-
- public List<MeasureFilterRow> execute(MeasureFilter filter, MeasureFilterContext context) throws SQLException {
- if (filter.isEmpty()) {
- return Collections.emptyList();
- }
-
- List<MeasureFilterRow> rows;
- SqlSession session = null;
- Connection connection = null;
- try {
- session = mybatis.openSession(false);
- prepareContext(context, filter, session);
-
- if (isValid(filter, context)) {
- MeasureFilterSql sql = new MeasureFilterSql(database, filter, context);
- context.setSql(sql.sql());
- connection = session.getConnection();
- rows = sql.execute(connection);
- } else {
- rows = Collections.emptyList();
- }
- } finally {
- MyBatis.closeQuietly(session);
- // connection is supposed to be closed by the session
- DbUtils.closeQuietly(connection);
- }
-
- return rows;
- }
-
- private void prepareContext(MeasureFilterContext context, MeasureFilter filter, SqlSession session) {
- if (filter.getBaseResourceKey() != null) {
- context.setBaseSnapshot(resourceDao.getLastSnapshot(filter.getBaseResourceKey(), session));
- }
- }
-
- static boolean isValid(MeasureFilter filter, MeasureFilterContext context) {
- boolean valid = Strings.isNullOrEmpty(filter.getBaseResourceKey()) || context.getBaseSnapshot()!=null;
- valid &= !(filter.isOnBaseResourceChildren() && context.getBaseSnapshot() == null);
- valid &= !(filter.isOnFavourites() && context.getUserId() == null);
- valid &= validateMeasureConditions(filter);
- valid &= validateSort(filter);
- return valid;
- }
-
- private static boolean validateMeasureConditions(MeasureFilter filter) {
- boolean valid = true;
- for (MeasureFilterCondition condition : filter.getMeasureConditions()) {
- if (condition.period() != null && condition.period() < 1) {
- valid = false;
- }
- if (condition.metric() == null) {
- valid = false;
- }
- }
- return valid;
- }
-
- private static boolean validateSort(MeasureFilter filter) {
- boolean valid = true;
- if (filter.sort().period() != null && filter.sort().period() < 1) {
- valid = false;
- }
- if (filter.sort().onMeasures() && filter.sort().metric() == null) {
- valid = false;
- }
- return valid;
- }
-}
+++ /dev/null
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2014 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube 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.
- *
- * SonarQube 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.core.measure;
-
-import com.google.common.base.Function;
-import com.google.common.base.Joiner;
-import com.google.common.base.Strings;
-import com.google.common.collect.Lists;
-import org.apache.commons.lang.StringUtils;
-import org.sonar.api.ServerComponent;
-import org.sonar.api.measures.CoreMetrics;
-import org.sonar.api.measures.Metric;
-import org.sonar.api.measures.MetricFinder;
-import org.sonar.api.utils.DateUtils;
-import org.sonar.api.utils.System2;
-
-import javax.annotation.CheckForNull;
-import javax.annotation.Nullable;
-import java.util.Arrays;
-import java.util.Calendar;
-import java.util.Date;
-import java.util.List;
-import java.util.Map;
-
-public class MeasureFilterFactory implements ServerComponent {
-
- private final MetricFinder metricFinder;
- private final System2 system;
-
- public MeasureFilterFactory(MetricFinder metricFinder, System2 system) {
- this.metricFinder = metricFinder;
- this.system = system;
- }
-
- public MeasureFilter create(Map<String, Object> properties) {
- MeasureFilter filter = new MeasureFilter();
- filter.setBaseResourceKey((String) properties.get("base"));
- filter.setResourceScopes(toList(properties.get("scopes")));
- filter.setResourceQualifiers(toList(properties.get("qualifiers")));
- MeasureFilterCondition condition = alertToCondition(toList(properties.get("alertLevels")));
- if (condition != null) {
- filter.addCondition(condition);
- }
- String onBaseComponents = (String) properties.get("onBaseComponents");
- if (onBaseComponents != null) {
- filter.setOnBaseResourceChildren(Boolean.valueOf(onBaseComponents));
- }
- filter.setResourceName((String) properties.get("nameSearch"));
- filter.setResourceKey((String) properties.get("keySearch"));
- String onFavourites = (String) properties.get("onFavourites");
- if (onFavourites != null) {
- filter.setUserFavourites(Boolean.valueOf(onFavourites));
- }
- fillDateConditions(filter, properties);
- fillSorting(filter, properties);
- fillMeasureConditions(properties, filter);
- return filter;
- }
-
- private void fillDateConditions(MeasureFilter filter, Map<String, Object> properties) {
- String fromDate = (String) properties.get("fromDate");
- if (fromDate != null) {
- filter.setFromDate(toDate(fromDate));
- } else {
- filter.setFromDate(toDays((String) properties.get("ageMaxDays")));
- }
- String toDate = (String) properties.get("toDate");
- if (toDate != null) {
- filter.setToDate(toDate(toDate));
- } else {
- filter.setToDate(toDays((String) properties.get("ageMinDays")));
- }
- }
-
- private void fillMeasureConditions(Map<String, Object> properties, MeasureFilter filter) {
- for (int index = 1; index <= 3; index++) {
- MeasureFilterCondition condition = toCondition(properties, index);
- if (condition != null) {
- filter.addCondition(condition);
- }
- }
- }
-
- private void fillSorting(MeasureFilter filter, Map<String, Object> properties) {
- String s = (String) properties.get("sort");
- if (s != null) {
- if (StringUtils.startsWith(s, "metric:")) {
- String[] fields = StringUtils.split(s, ':');
- Metric metric = metricFinder.findByKey(fields[1]);
- if (metric != null) {
- filter.setSortOnMetric(metric);
- if (fields.length == 3) {
- filter.setSortOnPeriod(Integer.parseInt(fields[2]));
- }
- }
- } else {
- filter.setSortOn(MeasureFilterSort.Field.valueOf(s.toUpperCase()));
- }
- }
-
- if (properties.containsKey("asc")) {
- filter.setSortAsc(Boolean.valueOf((String) properties.get("asc")));
- }
- }
-
- @CheckForNull
- private MeasureFilterCondition toCondition(Map<String, Object> props, int index) {
- MeasureFilterCondition condition = null;
- String metricKey = (String) props.get("c" + index + "_metric");
- String op = (String) props.get("c" + index + "_op");
- String val = (String) props.get("c" + index + "_val");
- if (!Strings.isNullOrEmpty(metricKey) && !Strings.isNullOrEmpty(op) && !Strings.isNullOrEmpty(val)) {
- Metric metric = metricFinder.findByKey(metricKey);
- MeasureFilterCondition.Operator operator = MeasureFilterCondition.Operator.fromCode(op);
- condition = new MeasureFilterCondition(metric, operator, Double.parseDouble(val));
- String period = (String) props.get("c" + index + "_period");
- if (period != null) {
- condition.setPeriod(Integer.parseInt(period));
- }
- }
- return condition;
- }
-
- @CheckForNull
- private MeasureFilterCondition alertToCondition(List<String> alertLevels) {
- if (alertLevels == null || alertLevels.isEmpty()) {
- return null;
- }
- MeasureFilterCondition condition = null;
- String metricKey = CoreMetrics.ALERT_STATUS_KEY;
- String op = "in";
- List<String> alertLevelsUppercase = Lists.transform(alertLevels, new Function<String, String>() {
- @Override
- public String apply(String input) {
- return input != null ? input.toUpperCase() : "";
- }
- });
- String val = "('" + Joiner.on("', '").join(alertLevelsUppercase) + "')";
- if (!Strings.isNullOrEmpty(metricKey) && !Strings.isNullOrEmpty(op) && !Strings.isNullOrEmpty(val)) {
- Metric metric = metricFinder.findByKey(metricKey);
- MeasureFilterCondition.Operator operator = MeasureFilterCondition.Operator.fromCode(op);
- condition = new MeasureFilterCondition(metric, operator, val);
- }
- return condition;
- }
-
- private List<String> toList(@Nullable Object obj) {
- List<String> result = null;
- if (obj != null) {
- if (obj instanceof String) {
- result = Arrays.asList((String) obj);
- } else {
- result = (List<String>) obj;
- }
- }
- return result;
- }
-
- @CheckForNull
- private Date toDate(@Nullable String date) {
- if (date != null) {
- return DateUtils.parseDate(date);
- }
- return null;
- }
-
- @CheckForNull
- private Date toDays(@Nullable String s) {
- if (s != null) {
- int days = Integer.valueOf(s);
- Date date = org.apache.commons.lang.time.DateUtils.truncate(new Date(system.now()), Calendar.DATE);
- date = org.apache.commons.lang.time.DateUtils.addDays(date, -days);
- return date;
- }
- return null;
- }
-
-}
+++ /dev/null
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2014 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube 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.
- *
- * SonarQube 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.core.measure;
-
-import javax.annotation.Nullable;
-
-import java.util.List;
-
-public class MeasureFilterResult {
-
- public static enum Error {
- UNKNOWN, VALUE_SHOULD_BE_A_NUMBER
- }
-
- private List<MeasureFilterRow> rows = null;
- private Error error = null;
-
- MeasureFilterResult() {
- }
-
- public List<MeasureFilterRow> getRows() {
- return rows;
- }
-
- public Error getError() {
- return error;
- }
-
- MeasureFilterResult setRows(@Nullable List<MeasureFilterRow> rows) {
- this.rows = rows;
- return this;
- }
-
- MeasureFilterResult setError(@Nullable Error err) {
- this.error = err;
- return this;
- }
-
- public boolean isSuccess() {
- return error == null;
- }
-
- @Override
- public String toString() {
- StringBuilder sb = new StringBuilder();
- if (rows != null) {
- sb.append(rows.size()).append(" rows, ");
- }
- if (error != null) {
- sb.append("error=").append(error).append(", ");
- }
- return sb.toString();
- }
-}
+++ /dev/null
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2014 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube 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.
- *
- * SonarQube 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.core.measure;
-
-import org.apache.commons.lang.StringUtils;
-
-import java.sql.Timestamp;
-
-public class MeasureFilterRow {
- private final long snapshotId;
- private final long resourceId;
- private final long resourceRootId;
- private String sortText = null;
- private Timestamp sortDate = null;
- private Double sortDouble = null;
-
- MeasureFilterRow(long snapshotId, long resourceId, long resourceRootId) {
- this.snapshotId = snapshotId;
- this.resourceId = resourceId;
- this.resourceRootId = resourceRootId;
- }
-
- public long getSnapshotId() {
- return snapshotId;
- }
-
- public long getResourceId() {
- return resourceId;
- }
-
- public long getResourceRootId() {
- return resourceRootId;
- }
-
- public String getSortText() {
- return sortText;
- }
-
- void setSortText(String s) {
- this.sortText = StringUtils.defaultString(s);
- }
-
- Timestamp getSortDate() {
- return sortDate;
- }
-
- void setSortDate(Timestamp sortDate) {
- this.sortDate = sortDate;
- }
-
- Double getSortDouble() {
- return sortDouble;
- }
-
- void setSortDouble(Double sortDouble) {
- this.sortDouble = sortDouble;
- }
-}
+++ /dev/null
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2014 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube 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.
- *
- * SonarQube 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.core.measure;
-
-import org.sonar.api.measures.CoreMetrics;
-import org.sonar.api.measures.Metric;
-
-class MeasureFilterSort {
- public static enum Field {
- KEY, NAME, VERSION, METRIC, SHORT_NAME, DESCRIPTION,
- // Sort by last analysis date
- DATE,
- // Sort by project creation date
- PROJECT_CREATION_DATE
- }
-
- private Field field = Field.NAME;
- private Metric metric = null;
- private Integer period = null;
- private boolean asc = true;
-
- MeasureFilterSort() {
- }
-
- void setField(Field field) {
- this.field = field;
- }
-
- void setMetric(Metric metric) {
- this.field = Field.METRIC;
- this.metric = metric;
- }
-
- Integer period() {
- return period;
- }
-
- void setPeriod(Integer period) {
- this.period = period;
- }
-
- void setAsc(boolean asc) {
- this.asc = asc;
- }
-
- public Field field() {
- return field;
- }
-
- boolean onMeasures() {
- return field == Field.METRIC;
- }
-
- Metric metric() {
- return metric;
- }
-
- boolean isOnMeasure() {
- return metric != null;
- }
-
- boolean isOnNumericMeasure() {
- return metric != null && metric.isNumericType();
- }
-
- boolean isOnDate() {
- return Field.DATE.equals(field) || Field.PROJECT_CREATION_DATE.equals(field);
- }
-
- boolean isOnAlert() {
- return metric != null && metric.getKey().equals(CoreMetrics.ALERT_STATUS_KEY);
- }
-
- boolean isAsc() {
- return asc;
- }
-
- String column() {
- // only numeric metrics can be sorted by database, else results are sorted programmatically.
- String column;
- switch (field) {
- case KEY:
- column = "p.kee";
- break;
- case NAME:
- column = "p.long_name";
- break;
- case SHORT_NAME:
- column = "p.name";
- break;
- case DESCRIPTION:
- column = "p.description";
- break;
- case VERSION:
- column = "s.version";
- break;
- case DATE:
- column = "s.created_at";
- break;
- case PROJECT_CREATION_DATE:
- column = "p.created_at";
- break;
- case METRIC:
- column = getMetricColumn();
- break;
- default:
- throw new IllegalArgumentException("Unsupported sorting: " + field);
- }
- return column;
- }
-
- private String getMetricColumn(){
- if (metric.isNumericType()) {
- return period != null ? "pmsort.variation_value_" + period : "pmsort.value";
- } else {
- return "pmsort.text_value";
- }
- }
-}
+++ /dev/null
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2014 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube 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.
- *
- * SonarQube 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.core.measure;
-
-import com.google.common.base.Function;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Ordering;
-import org.apache.commons.dbutils.DbUtils;
-import org.apache.commons.lang.StringEscapeUtils;
-import org.apache.commons.lang.StringUtils;
-import org.sonar.core.persistence.Database;
-import org.sonar.core.persistence.dialect.MsSql;
-import org.sonar.core.persistence.dialect.Oracle;
-import org.sonar.core.resource.SnapshotDto;
-
-import javax.annotation.Nullable;
-
-import java.sql.*;
-import java.sql.Date;
-import java.util.*;
-
-class MeasureFilterSql {
-
- private final Database database;
- private final MeasureFilter filter;
- private final MeasureFilterContext context;
- private final String sql;
- private final List<Date> dateParameters = Lists.newArrayList();
-
- MeasureFilterSql(Database database, MeasureFilter filter, MeasureFilterContext context) {
- this.database = database;
- this.filter = filter;
- this.context = context;
- this.sql = generateSql();
- }
-
- List<MeasureFilterRow> execute(Connection connection) throws SQLException {
- PreparedStatement statement = connection.prepareStatement(sql);
- ResultSet rs = null;
- try {
- for (int index = 0; index < dateParameters.size(); index++) {
- statement.setDate(index + 1, dateParameters.get(index));
- }
- rs = statement.executeQuery();
- return process(rs);
-
- } finally {
- DbUtils.closeQuietly(rs);
- DbUtils.closeQuietly(statement);
- }
- }
-
- String sql() {
- return sql;
- }
-
- private String generateSql() {
- StringBuilder sb = new StringBuilder(1000);
- sb.append("SELECT s.id, s.project_id, s.root_project_id, ");
- sb.append(filter.sort().column());
- sb.append(" FROM snapshots s INNER JOIN projects p ON s.project_id=p.id ");
-
- for (int index = 0; index < filter.getMeasureConditions().size(); index++) {
- MeasureFilterCondition condition = filter.getMeasureConditions().get(index);
- sb.append(" INNER JOIN project_measures pmcond").append(index);
- sb.append(" ON s.id=pmcond").append(index).append(".snapshot_id AND ");
- condition.appendSqlCondition(sb, index);
- }
-
- if (filter.isOnFavourites()) {
- sb.append(" INNER JOIN properties props ON props.resource_id=s.project_id ");
- }
-
- if (filter.sort().isOnMeasure()) {
- sb.append(" LEFT OUTER JOIN project_measures pmsort ON s.id=pmsort.snapshot_id AND pmsort.metric_id=");
- sb.append(filter.sort().metric().getId());
- sb.append(" AND pmsort.rule_id IS NULL AND pmsort.rule_priority IS NULL AND pmsort.characteristic_id IS NULL AND pmsort.person_id IS NULL ");
- }
-
- sb.append(" WHERE ");
- appendResourceConditions(sb);
-
- for (int index = 0; index < filter.getMeasureConditions().size(); index++) {
- MeasureFilterCondition condition = filter.getMeasureConditions().get(index);
- sb.append(" AND ");
- condition.appendSqlCondition(sb, index);
- }
-
- return sb.toString();
- }
-
- private void appendResourceConditions(StringBuilder sb) {
- sb.append(" s.status='P' AND s.islast=").append(database.getDialect().getTrueSqlValue());
- if (context.getBaseSnapshot() == null) {
- sb.append(" AND p.copy_resource_id IS NULL ");
- }
- if (!filter.getResourceQualifiers().isEmpty()) {
- sb.append(" AND s.qualifier IN ");
- appendInStatement(filter.getResourceQualifiers(), sb);
- }
- if (!filter.getResourceScopes().isEmpty()) {
- sb.append(" AND s.scope IN ");
- appendInStatement(filter.getResourceScopes(), sb);
- }
- appendDateConditions(sb);
- appendFavouritesCondition(sb);
- appendResourceNameCondition(sb);
- appendResourceKeyCondition(sb);
- appendResourceBaseCondition(sb);
- }
-
- private void appendDateConditions(StringBuilder sb) {
- java.util.Date fromDate = filter.getFromDate();
- if (fromDate != null) {
- sb.append(" AND s.created_at >= ? ");
- dateParameters.add(new Date(fromDate.getTime()));
- }
- java.util.Date toDate = filter.getToDate();
- if (toDate != null) {
- sb.append(" AND s.created_at <= ? ");
- dateParameters.add(new Date(toDate.getTime()));
- }
- }
-
- private void appendFavouritesCondition(StringBuilder sb) {
- if (filter.isOnFavourites()) {
- sb.append(" AND props.prop_key='favourite' AND props.resource_id IS NOT NULL AND props.user_id=");
- sb.append(context.getUserId());
- sb.append(" ");
- }
- }
-
- private void appendResourceBaseCondition(StringBuilder sb) {
- SnapshotDto baseSnapshot = context.getBaseSnapshot();
- if (baseSnapshot != null) {
- if (filter.isOnBaseResourceChildren()) {
- sb.append(" AND s.parent_snapshot_id=").append(baseSnapshot.getId());
- } else {
- Long rootSnapshotId = baseSnapshot.getRootId() != null ? baseSnapshot.getRootId() : baseSnapshot.getId();
- sb.append(" AND s.root_snapshot_id=").append(rootSnapshotId);
- sb.append(" AND s.path LIKE '").append(StringUtils.defaultString(baseSnapshot.getPath())).append(baseSnapshot.getId()).append(".%'");
- }
- }
- }
-
- private void appendResourceKeyCondition(StringBuilder sb) {
- if (StringUtils.isNotBlank(filter.getResourceKey())) {
- sb.append(" AND UPPER(p.kee) LIKE '%");
- sb.append(escapePercentAndUnderscrore(StringEscapeUtils.escapeSql(StringUtils.upperCase(filter.getResourceKey()))));
- sb.append("%'");
- appendEscapeForSomeDb(sb);
- }
- }
-
- private void appendResourceNameCondition(StringBuilder sb) {
- if (StringUtils.isNotBlank(filter.getResourceName())) {
- sb.append(" AND s.project_id IN (SELECT rindex.resource_id FROM resource_index rindex WHERE rindex.kee LIKE '");
- sb.append(escapePercentAndUnderscrore(StringEscapeUtils.escapeSql(StringUtils.lowerCase(filter.getResourceName()))));
- sb.append("%'");
- appendEscapeForSomeDb(sb);
- if (!filter.getResourceQualifiers().isEmpty()) {
- sb.append(" AND rindex.qualifier IN ");
- appendInStatement(filter.getResourceQualifiers(), sb);
- }
- sb.append(") ");
- }
- }
-
- List<MeasureFilterRow> process(ResultSet rs) throws SQLException {
- List<MeasureFilterRow> rows = Lists.newArrayList();
- RowProcessor rowProcessor;
- if (filter.sort().isOnNumericMeasure()) {
- rowProcessor = new NumericSortRowProcessor();
- } else if (filter.sort().isOnDate()) {
- rowProcessor = new DateSortRowProcessor();
- } else if (filter.sort().isOnAlert()) {
- rowProcessor = new AlertSortRowProcessor();
- } else {
- rowProcessor = new TextSortRowProcessor();
- }
-
- while (rs.next()) {
- rows.add(rowProcessor.fetch(rs));
- }
-
- return rowProcessor.sort(rows, filter.sort().isAsc());
- }
-
- private static void appendInStatement(List<String> values, StringBuilder to) {
- to.append(" (");
- for (int i = 0; i < values.size(); i++) {
- if (i > 0) {
- to.append(",");
- }
- to.append("'");
- to.append(StringEscapeUtils.escapeSql(values.get(i)));
- to.append("'");
- }
- to.append(") ");
- }
-
- /**
- * Replace escape percent and underscore by adding a slash just before
- */
- private String escapePercentAndUnderscrore(String value){
- return value.replaceAll("%", "\\\\%").replaceAll("_", "\\\\_");
- }
-
- private void appendEscapeForSomeDb(StringBuilder sb){
- if (database.getDialect().getId().equals(Oracle.ID) || database.getDialect().getId().equals(MsSql.ID)) {
- sb.append(" ESCAPE '\\'");
- }
- }
-
- abstract static class RowProcessor {
- abstract Function sortFieldFunction();
-
- abstract Ordering sortFieldOrdering(boolean ascending);
-
- abstract MeasureFilterRow fetch(ResultSet rs) throws SQLException;
-
- final List<MeasureFilterRow> sort(List<MeasureFilterRow> rows, boolean ascending) {
- Ordering<MeasureFilterRow> ordering = sortFieldOrdering(ascending).onResultOf(sortFieldFunction());
- return ordering.immutableSortedCopy(rows);
- }
- }
-
- static class TextSortRowProcessor extends RowProcessor {
- MeasureFilterRow fetch(ResultSet rs) throws SQLException {
- MeasureFilterRow row = new MeasureFilterRow(rs.getLong(1), rs.getLong(2), rs.getLong(3));
- row.setSortText(rs.getString(4));
- return row;
- }
-
- Function sortFieldFunction() {
- return new Function<MeasureFilterRow, String>() {
- public String apply(MeasureFilterRow row) {
- return row.getSortText();
- }
- };
- }
-
- Ordering sortFieldOrdering(boolean ascending) {
- Ordering<String> ordering = Ordering.from(String.CASE_INSENSITIVE_ORDER);
- if (!ascending) {
- ordering = ordering.reverse();
- }
- return ordering;
- }
- }
-
- static class AlertSortRowProcessor extends TextSortRowProcessor {
- Function sortFieldFunction() {
- return new Function<MeasureFilterRow, Integer>() {
- public Integer apply(MeasureFilterRow row) {
- return ImmutableList.of("OK", "WARN", "ERROR").indexOf(row.getSortText());
- }
- };
- }
-
- @Override
- Ordering sortFieldOrdering(boolean ascending) {
- Ordering<Integer> ordering = Ordering.<Integer>natural().nullsLast();
- if (!ascending) {
- ordering = ordering.reverse();
- }
- return ordering;
- }
- }
-
- static class NumericSortRowProcessor extends RowProcessor {
- MeasureFilterRow fetch(ResultSet rs) throws SQLException {
- MeasureFilterRow row = new MeasureFilterRow(rs.getLong(1), rs.getLong(2), rs.getLong(3));
- double value = rs.getDouble(4);
- if (!rs.wasNull()) {
- row.setSortDouble(value);
- }
- return row;
- }
-
- Function sortFieldFunction() {
- return new Function<MeasureFilterRow, Double>() {
- public Double apply(MeasureFilterRow row) {
- return row.getSortDouble();
- }
- };
- }
-
- Ordering sortFieldOrdering(boolean ascending) {
- return ascending ? Ordering.natural().nullsLast() : Ordering.natural().reverse().nullsLast();
- }
- }
-
- static class DateSortRowProcessor extends RowProcessor {
- MeasureFilterRow fetch(ResultSet rs) throws SQLException {
- MeasureFilterRow row = new MeasureFilterRow(rs.getLong(1), rs.getLong(2), rs.getLong(3));
- row.setSortDate(rs.getTimestamp(4));
- return row;
- }
-
- Function sortFieldFunction() {
- return new Function<MeasureFilterRow, Timestamp>() {
- public Timestamp apply(MeasureFilterRow row) {
- return row.getSortDate();
- }
- };
- }
-
- Ordering sortFieldOrdering(boolean ascending) {
- return newObjectOrdering(ascending);
- }
- }
-
- private static Ordering newObjectOrdering(boolean ascending) {
- if (ascending) {
- return Ordering.from(new Comparator<Comparable>() {
- public int compare(@Nullable Comparable left, @Nullable Comparable right) {
- if (left == null) {
- return 1;
- }
- if (right == null) {
- return -1;
- }
-
- return left.compareTo(right);
- }
- });
- }
- return Ordering.from(new Comparator<Comparable>() {
- public int compare(@Nullable Comparable left, @Nullable Comparable right) {
- if (left == null) {
- return 1;
- }
- if (right == null) {
- return -1;
- }
-
- return -left.compareTo(right);
- }
- });
- }
-}
-
import org.sonar.core.dashboard.DashboardDao;
import org.sonar.core.duplication.DuplicationDao;
import org.sonar.core.graph.jdbc.GraphDao;
-import org.sonar.core.issue.db.*;
+import org.sonar.core.issue.db.ActionPlanDao;
+import org.sonar.core.issue.db.ActionPlanStatsDao;
+import org.sonar.core.issue.db.IssueChangeDao;
+import org.sonar.core.issue.db.IssueDao;
+import org.sonar.core.issue.db.IssueFilterDao;
+import org.sonar.core.issue.db.IssueFilterFavouriteDao;
+import org.sonar.core.issue.db.IssueStatsDao;
import org.sonar.core.measure.db.MeasureDao;
-import org.sonar.core.measure.db.MeasureFilterDao;
import org.sonar.core.notification.db.NotificationQueueDao;
import org.sonar.core.permission.PermissionDao;
import org.sonar.core.permission.PermissionTemplateDao;
import org.sonar.core.technicaldebt.db.CharacteristicDao;
import org.sonar.core.technicaldebt.db.RequirementDao;
import org.sonar.core.template.LoadedTemplateDao;
-import org.sonar.core.user.*;
+import org.sonar.core.user.AuthorDao;
+import org.sonar.core.user.AuthorizationDao;
+import org.sonar.core.user.GroupMembershipDao;
+import org.sonar.core.user.RoleDao;
+import org.sonar.core.user.UserDao;
import java.util.List;
public final class DaoUtils {
private DaoUtils() {
+ // only static stuff
}
@SuppressWarnings("unchecked")
IssueFilterFavouriteDao.class,
LoadedTemplateDao.class,
MeasureDao.class,
- MeasureFilterDao.class,
NotificationQueueDao.class,
PermissionDao.class,
PermissionTemplateDao.class,
+++ /dev/null
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2014 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube 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.
- *
- * SonarQube 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.core.measure;
-
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-import org.sonar.api.measures.Metric;
-
-import static org.fest.assertions.Assertions.assertThat;
-
-public class MeasureFilterConditionTest {
- @Rule
- public ExpectedException thrown = ExpectedException.none();
-
- @Test
- public void create_operator_from_code() {
- assertThat(MeasureFilterCondition.Operator.fromCode("eq")).isEqualTo(MeasureFilterCondition.Operator.EQUALS);
- assertThat(MeasureFilterCondition.Operator.fromCode("lte")).isEqualTo(MeasureFilterCondition.Operator.LESS_OR_EQUALS);
- }
-
- @Test
- public void fail_if_operator_code_not_found() {
- thrown.expect(IllegalArgumentException.class);
- MeasureFilterCondition.Operator.fromCode("xxx");
- }
-
- @Test
- public void operator_sql() {
- assertThat(MeasureFilterCondition.Operator.EQUALS.getSql()).isEqualTo("=");
- assertThat(MeasureFilterCondition.Operator.LESS_OR_EQUALS.getSql()).isEqualTo("<=");
- assertThat(MeasureFilterCondition.Operator.GREATER.getSql()).isEqualTo(">");
- }
-
- @Test
- public void value_condition() {
- Metric ncloc = new Metric.Builder("ncloc", "NCLOC", Metric.ValueType.INT).create();
- ncloc.setId(123);
- MeasureFilterCondition condition = new MeasureFilterCondition(ncloc, MeasureFilterCondition.Operator.GREATER, 10.0);
-
- assertThat(condition.metric()).isEqualTo(ncloc);
- assertThat(condition.operator()).isEqualTo(MeasureFilterCondition.Operator.GREATER);
- assertThat(condition.period()).isNull();
- assertThat(condition.value()).isEqualTo(10.0);
- assertThat(condition.textValue()).isNull();
- assertThat(condition.appendSqlColumn(new StringBuilder(), 1).toString()).isEqualTo("pmcond1.value");
- assertThat(condition.toString()).isNotEmpty();
- assertThat(condition.appendSqlCondition(new StringBuilder(), 1).toString()).isEqualTo(" pmcond1.metric_id=123 AND pmcond1.value > 10.0 AND pmcond1.rule_id IS NULL AND pmcond1.rule_priority IS NULL AND pmcond1.characteristic_id IS NULL AND pmcond1.person_id IS NULL ");
- }
-
- @Test
- public void variation_condition() {
- Metric ncloc = new Metric.Builder("ncloc", "NCLOC", Metric.ValueType.INT).create();
- ncloc.setId(123);
- MeasureFilterCondition condition = new MeasureFilterCondition(ncloc, MeasureFilterCondition.Operator.LESS_OR_EQUALS, 10.0);
- condition.setPeriod(3);
-
- assertThat(condition.metric()).isEqualTo(ncloc);
- assertThat(condition.operator()).isEqualTo(MeasureFilterCondition.Operator.LESS_OR_EQUALS);
- assertThat(condition.period()).isEqualTo(3);
- assertThat(condition.value()).isEqualTo(10.0);
- assertThat(condition.appendSqlColumn(new StringBuilder(), 2).toString()).isEqualTo("pmcond2.variation_value_3");
- assertThat(condition.toString()).isNotEmpty();
- assertThat(condition.appendSqlCondition(new StringBuilder(), 2).toString()).isEqualTo(" pmcond2.metric_id=123 AND pmcond2.variation_value_3 <= 10.0 AND pmcond2.rule_id IS NULL AND pmcond2.rule_priority IS NULL AND pmcond2.characteristic_id IS NULL AND pmcond2.person_id IS NULL ");
- }
-
- @Test
- public void text_value_condition() {
- Metric ncloc = new Metric.Builder("ncloc", "NCLOC", Metric.ValueType.INT).create();
- ncloc.setId(123);
- MeasureFilterCondition condition = new MeasureFilterCondition(ncloc, MeasureFilterCondition.Operator.EQUALS, "\"foo\"");
-
- assertThat(condition.metric()).isEqualTo(ncloc);
- assertThat(condition.operator()).isEqualTo(MeasureFilterCondition.Operator.EQUALS);
- assertThat(condition.period()).isNull();
- assertThat(condition.value()).isEqualTo(0);
- assertThat(condition.textValue()).isEqualTo("\"foo\"");
- assertThat(condition.appendSqlColumn(new StringBuilder(), 1).toString()).isEqualTo("pmcond1.text_value");
- assertThat(condition.toString()).isNotEmpty();
- assertThat(condition.appendSqlCondition(new StringBuilder(), 1).toString()).isEqualTo(" pmcond1.metric_id=123 AND pmcond1.text_value = \"foo\" AND pmcond1.rule_id IS NULL AND pmcond1.rule_priority IS NULL AND pmcond1.characteristic_id IS NULL AND pmcond1.person_id IS NULL ");
- }
-}
+++ /dev/null
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2014 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube 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.
- *
- * SonarQube 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.core.measure;
-
-import com.google.common.collect.ImmutableMap;
-import org.junit.Test;
-
-import java.util.Map;
-
-import static org.fest.assertions.Assertions.assertThat;
-
-public class MeasureFilterContextTest {
- @Test
- public void test_empty_toString() {
- MeasureFilterContext context = new MeasureFilterContext();
- assertThat(context.toString()).isNotEmpty();
- }
-
- @Test
- public void test_toString() {
- MeasureFilterContext context = new MeasureFilterContext();
- context.setData("{qualifiers=TRK}");
- context.setSql("SELECT *");
- context.setUserId(50L);
- assertThat(context.toString()).isEqualTo("MeasureFilterContext[filter={qualifiers=TRK},sql=SELECT *,user=50]");
- }
-}
+++ /dev/null
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2014 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube 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.
- *
- * SonarQube 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.core.measure;
-
-import com.google.common.collect.ImmutableMap;
-import org.hamcrest.BaseMatcher;
-import org.hamcrest.Description;
-import org.junit.Test;
-import org.sonar.api.config.Settings;
-import org.sonar.core.profiling.Profiling;
-
-import java.util.Map;
-
-import static org.fest.assertions.Assertions.assertThat;
-import static org.mockito.Matchers.argThat;
-import static org.mockito.Matchers.refEq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-public class MeasureFilterEngineTest {
-
- @Test
- public void should_create_and_execute_filter() throws Exception {
- Map<String, Object> filterMap = ImmutableMap.of("qualifiers", (Object) "TRK");
- MeasureFilterFactory factory = mock(MeasureFilterFactory.class);
- MeasureFilter filter = new MeasureFilter();
- when(factory.create(filterMap)).thenReturn(filter);
- MeasureFilterExecutor executor = mock(MeasureFilterExecutor.class);
-
- MeasureFilterEngine engine = new MeasureFilterEngine(factory, executor, new Profiling(new Settings()));
-
- final long userId = 50L;
- engine.execute(filterMap, userId);
- verify(executor).execute(refEq(filter), argThat(new BaseMatcher<MeasureFilterContext>() {
- public boolean matches(Object o) {
- MeasureFilterContext context = (MeasureFilterContext) o;
- return "{qualifiers=TRK}".equals(context.getData()) && context.getUserId() == userId;
- }
-
- public void describeTo(Description description) {
- }
- }));
- }
-
- @Test
- public void keep_error_but_do_not_fail() throws Exception {
- Map<String, Object> filterMap = ImmutableMap.of("qualifiers", (Object) "TRK");
- MeasureFilterFactory factory = mock(MeasureFilterFactory.class);
- when(factory.create(filterMap)).thenThrow(new IllegalArgumentException());
- MeasureFilterExecutor executor = mock(MeasureFilterExecutor.class);
-
- MeasureFilterEngine engine = new MeasureFilterEngine(factory, executor, new Profiling(new Settings()));
- MeasureFilterResult result = engine.execute(filterMap, 50L);
-
- assertThat(result.isSuccess()).isFalse();
- assertThat(result.getError()).isEqualTo(MeasureFilterResult.Error.UNKNOWN);
- assertThat(result.getRows()).isNull();
- }
-}
+++ /dev/null
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2014 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube 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.
- *
- * SonarQube 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.core.measure;
-
-import org.junit.Before;
-import org.junit.ClassRule;
-import org.junit.Test;
-import org.sonar.api.measures.CoreMetrics;
-import org.sonar.api.measures.Metric;
-import org.sonar.api.utils.DateUtils;
-import org.sonar.core.persistence.TestDatabase;
-import org.sonar.core.resource.ResourceDao;
-import org.sonar.core.resource.SnapshotDto;
-
-import java.sql.SQLException;
-import java.util.Arrays;
-import java.util.List;
-
-import static com.google.common.collect.Lists.newArrayList;
-import static org.fest.assertions.Assertions.assertThat;
-
-public class MeasureFilterExecutorTest {
- private static final long JAVA_PROJECT_ID = 1L;
- private static final long JAVA_FILE_BIG_ID = 3L;
- private static final long JAVA_FILE_TINY_ID = 4L;
- private static final long JAVA_PROJECT_SNAPSHOT_ID = 101L;
- private static final long JAVA_FILE_BIG_SNAPSHOT_ID = 103L;
- private static final long JAVA_FILE_TINY_SNAPSHOT_ID = 104L;
- private static final long JAVA_PACKAGE_SNAPSHOT_ID = 102L;
- private static final long PHP_PROJECT_ID = 10L;
- private static final long PHP_SNAPSHOT_ID = 110L;
- private static final Metric METRIC_LINES = new Metric.Builder("lines", "Lines", Metric.ValueType.INT).create().setId(1);
- private static final Metric METRIC_PROFILE = new Metric.Builder("profile", "Profile", Metric.ValueType.STRING).create().setId(2);
- private static final Metric METRIC_COVERAGE = new Metric.Builder("coverage", "Coverage", Metric.ValueType.FLOAT).create().setId(3);
- private static final Metric METRIC_UNKNOWN = new Metric.Builder("unknown", "Unknown", Metric.ValueType.FLOAT).create().setId(4);
-
- private MeasureFilterExecutor executor;
-
- @ClassRule
- public static TestDatabase db = new TestDatabase();
-
- @Before
- public void before() {
- executor = new MeasureFilterExecutor(db.myBatis(), db.database(), new ResourceDao(db.myBatis()));
- }
-
- @Test
- public void should_return_empty_results_if_empty_filter() throws SQLException {
- db.prepareDbUnit(getClass(), "shared.xml");
- MeasureFilter filter = new MeasureFilter();
- assertThat(filter.isEmpty()).isTrue();
-
- assertThat(executor.execute(filter, new MeasureFilterContext())).isEmpty();
- }
-
- @Test
- public void invalid_filter_should_not_return_results() throws SQLException {
- db.prepareDbUnit(getClass(), "shared.xml");
- MeasureFilter filter = new MeasureFilter().setUserFavourites(true);
- // anonymous user does not have favourites
- assertThat(executor.execute(filter, new MeasureFilterContext())).isEmpty();
- }
-
- @Test
- public void filter_is_not_valid_if_missing_base_snapshot() {
- db.prepareDbUnit(getClass(), "shared.xml");
- MeasureFilterContext context = new MeasureFilterContext();
- MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK")).setOnBaseResourceChildren(true);
- assertThat(MeasureFilterExecutor.isValid(filter, context)).isFalse();
-
- context.setBaseSnapshot(new SnapshotDto().setId(123L));
- assertThat(MeasureFilterExecutor.isValid(filter, context)).isTrue();
- }
-
- @Test
- public void filter_is_not_valid_if_condition_on_unknown_metric() {
- db.prepareDbUnit(getClass(), "shared.xml");
- MeasureFilterContext context = new MeasureFilterContext();
- MeasureFilter filter = new MeasureFilter().addCondition(new MeasureFilterCondition(null, MeasureFilterCondition.Operator.LESS, 3.0));
- assertThat(MeasureFilterExecutor.isValid(filter, context)).isFalse();
- }
-
- @Test
- public void filter_is_not_valid_if_sorting_on_unknown_metric() {
- db.prepareDbUnit(getClass(), "shared.xml");
- MeasureFilterContext context = new MeasureFilterContext();
- MeasureFilter filter = new MeasureFilter().setSortOnMetric(null);
- assertThat(MeasureFilterExecutor.isValid(filter, context)).isFalse();
- }
-
- @Test
- public void filter_is_not_valid_if_anonymous_favourites() {
- db.prepareDbUnit(getClass(), "shared.xml");
- MeasureFilterContext context = new MeasureFilterContext();
- MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK")).setUserFavourites(true);
- assertThat(MeasureFilterExecutor.isValid(filter, context)).isFalse();
-
- context.setUserId(123L);
- assertThat(MeasureFilterExecutor.isValid(filter, context)).isTrue();
- }
-
- @Test
- public void projects_without_measure_conditions() throws SQLException {
- db.prepareDbUnit(getClass(), "shared.xml");
- MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK")).setSortOn(MeasureFilterSort.Field.DATE);
- List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
-
- assertThat(rows).hasSize(2);
- verifyJavaProject(rows.get(0));
- verifyPhpProject(rows.get(1));
- }
-
- @Test
- public void should_prevent_sql_injection_through_parameters() throws SQLException {
- db.prepareDbUnit(getClass(), "shared.xml");
- MeasureFilter filter = new MeasureFilter()
- .setResourceQualifiers(Arrays.asList("'"))
- .setBaseResourceKey("'")
- .setResourceKey("'")
- .setResourceName("'")
- .setResourceName("'")
- .setResourceScopes(Arrays.asList("'"));
- List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
- // an exception would be thrown if SQL is not valid
- assertThat(rows).isEmpty();
- }
-
- @Test
- public void test_default_sort() {
- db.prepareDbUnit(getClass(), "shared.xml");
- MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("CLA"));
-
- assertThat(filter.sort().isAsc()).isTrue();
- assertThat(filter.sort().field()).isEqualTo(MeasureFilterSort.Field.NAME);
- assertThat(filter.sort().metric()).isNull();
- }
-
- @Test
- public void sort_by_ascending_resource_name() throws SQLException {
- db.prepareDbUnit(getClass(), "shared.xml");
- MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("CLA")).setSortAsc(true);
- List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
-
- // Big -> Tiny
- assertThat(rows).hasSize(2);
- verifyJavaBigFile(rows.get(0));
- verifyJavaTinyFile(rows.get(1));
- }
-
- @Test
- public void sort_by_ascending_resource_key() throws SQLException {
- db.prepareDbUnit(getClass(), "shared.xml");
- MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("CLA")).setSortAsc(true).setSortOn(MeasureFilterSort.Field.KEY);
- List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
-
- // Big -> Tiny
- assertThat(rows).hasSize(2);
- verifyJavaBigFile(rows.get(0));
- verifyJavaTinyFile(rows.get(1));
- }
-
- @Test
- public void sort_by_ascending_resource_version() throws SQLException {
- db.prepareDbUnit(getClass(), "shared.xml");
- MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK")).setSortAsc(true).setSortOn(MeasureFilterSort.Field.VERSION);
- List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
-
- // Java Project 1.0 then Php Project 3.0
- assertThat(rows).hasSize(2);
- verifyJavaProject(rows.get(0));
- verifyPhpProject(rows.get(1));
- }
-
- @Test
- public void sort_by_descending_resource_name() throws SQLException {
- db.prepareDbUnit(getClass(), "shared.xml");
- MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("CLA")).setSortAsc(false);
- List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
-
- // Tiny -> Big
- assertThat(rows).hasSize(2);
- verifyJavaTinyFile(rows.get(0));
- verifyJavaBigFile(rows.get(1));
- }
-
- @Test
- public void sort_by_ascending_text_measure() throws SQLException {
- db.prepareDbUnit(getClass(), "shared.xml");
- MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK")).setSortOnMetric(METRIC_PROFILE);
- List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
-
- assertThat(rows).hasSize(2);
- verifyPhpProject(rows.get(0));//php way
- verifyJavaProject(rows.get(1));// Sonar way
- }
-
- @Test
- public void sort_by_descending_text_measure() throws SQLException {
- db.prepareDbUnit(getClass(), "shared.xml");
- MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK")).setSortOnMetric(METRIC_PROFILE).setSortAsc(false);
- List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
-
- assertThat(rows).hasSize(2);
- verifyJavaProject(rows.get(0));// Sonar way
- verifyPhpProject(rows.get(1));//php way
- }
-
- @Test
- public void sort_by_missing_text_measure() throws SQLException {
- db.prepareDbUnit(getClass(), "shared.xml");
- // the metric 'profile' is not set on files
- MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("CLA")).setSortOnMetric(METRIC_PROFILE);
- List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
-
- assertThat(rows).hasSize(2);//2 files randomly sorted
- }
-
- @Test
- public void sort_by_ascending_numeric_measure() throws SQLException {
- db.prepareDbUnit(getClass(), "shared.xml");
- MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("CLA")).setSortOnMetric(METRIC_LINES);
- List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
-
- // Tiny -> Big
- assertThat(rows).hasSize(2);
- verifyJavaTinyFile(rows.get(0));
- verifyJavaBigFile(rows.get(1));
- }
-
- @Test
- public void sort_by_descending_numeric_measure() throws SQLException {
- db.prepareDbUnit(getClass(), "shared.xml");
- MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("CLA")).setSortOnMetric(METRIC_LINES).setSortAsc(false);
- List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
-
- // Big -> Tiny
- assertThat(rows).hasSize(2);
- verifyJavaBigFile(rows.get(0));
- verifyJavaTinyFile(rows.get(1));
- }
-
- @Test
- public void null_measures_are_ordered_after_descending_numeric_measures() throws SQLException {
- db.prepareDbUnit(getClass(), "shared.xml");
- MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK"))
- .setSortOnMetric(METRIC_COVERAGE).setSortAsc(false);
- List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
-
- // Java project has coverage but not PHP
- assertThat(rows).hasSize(2);
- verifyJavaProject(rows.get(0));
- verifyPhpProject(rows.get(1));
- }
-
- @Test
- public void null_measures_are_ordered_after_ascending_numeric_measures() throws SQLException {
- db.prepareDbUnit(getClass(), "shared.xml");
- MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK"))
- .setSortOnMetric(METRIC_COVERAGE).setSortAsc(true);
- List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
-
- // Java project has coverage but not PHP
- assertThat(rows).hasSize(2);
- verifyJavaProject(rows.get(0));
- verifyPhpProject(rows.get(1));
- }
-
- @Test
- public void sort_by_missing_numeric_measure() throws SQLException {
- db.prepareDbUnit(getClass(), "shared.xml");
- // coverage measures are not computed
- MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("CLA")).setSortOnMetric(METRIC_UNKNOWN);
- List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
-
- // 2 files, random order
- assertThat(rows).hasSize(2);
- }
-
- @Test
- public void sort_by_ascending_variation() throws SQLException {
- db.prepareDbUnit(getClass(), "shared.xml");
- MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK")).setSortOnMetric(METRIC_LINES).setSortOnPeriod(5);
- List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
-
- assertThat(rows).hasSize(2);
- verifyJavaProject(rows.get(0));// +400
- verifyPhpProject(rows.get(1));// +4900
- }
-
- @Test
- public void sort_by_descending_variation() throws SQLException {
- db.prepareDbUnit(getClass(), "shared.xml");
- MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK"))
- .setSortOnMetric(METRIC_LINES).setSortOnPeriod(5).setSortAsc(false);
- List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
-
- assertThat(rows).hasSize(2);
- verifyPhpProject(rows.get(0));// +4900
- verifyJavaProject(rows.get(1));// +400
- }
-
- @Test
- public void sort_by_ascending_date() throws SQLException {
- db.prepareDbUnit(getClass(), "shared.xml");
- MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK")).setSortOn(MeasureFilterSort.Field.DATE);
- List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
-
- verifyJavaProject(rows.get(0));// 2008
- verifyPhpProject(rows.get(1));// 2012
- }
-
- @Test
- public void sort_by_descending_date() throws SQLException {
- db.prepareDbUnit(getClass(), "shared.xml");
- MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK")).setSortOn(MeasureFilterSort.Field.DATE).setSortAsc(false);
- List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
-
- verifyPhpProject(rows.get(0));// 2012
- verifyJavaProject(rows.get(1));// 2008
- }
-
- @Test
- public void sort_by_ascending_created_at() throws SQLException {
- db.prepareDbUnit(getClass(), "shared.xml");
- MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK")).setSortOn(MeasureFilterSort.Field.PROJECT_CREATION_DATE);
- List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
-
- verifyJavaProject(rows.get(0));// 2008
- assertThat(DateUtils.formatDate(rows.get(0).getSortDate())).isEqualTo("2008-12-19");
- verifyPhpProject(rows.get(1));// 2012
- assertThat(DateUtils.formatDate(rows.get(1).getSortDate())).isEqualTo("2012-12-12");
- }
-
- @Test
- public void sort_by_descending_created_at() throws SQLException {
- db.prepareDbUnit(getClass(), "shared.xml");
- MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK")).setSortOn(MeasureFilterSort.Field.PROJECT_CREATION_DATE).setSortAsc(false);
- List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
-
- verifyPhpProject(rows.get(0));// 2012
- assertThat(DateUtils.formatDate(rows.get(0).getSortDate())).isEqualTo("2012-12-12");
- verifyJavaProject(rows.get(1));// 2008
- assertThat(DateUtils.formatDate(rows.get(1).getSortDate())).isEqualTo("2008-12-19");
- }
-
- @Test
- public void sort_by_ascending_alert() throws SQLException {
- db.prepareDbUnit(getClass(), "sort_by_alert.xml");
-
- Metric alert = new Metric.Builder(CoreMetrics.ALERT_STATUS_KEY, "Alert", Metric.ValueType.LEVEL).create().setId(5);
- MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK")).setSortOnMetric(alert);
- List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
-
- // Php Project OK, Java Project WARN then Js Project ERROR
- assertThat(rows).hasSize(3);
- verifyPhpProject(rows.get(0));
- verifyJavaProject(rows.get(1));
- verifyProject(rows.get(2), 120L, 20L, 20L);
- }
-
- @Test
- public void sort_by_descending_alert() throws SQLException {
- db.prepareDbUnit(getClass(), "sort_by_alert.xml");
-
- Metric alert = new Metric.Builder(CoreMetrics.ALERT_STATUS_KEY, "Alert", Metric.ValueType.LEVEL).create().setId(5);
- MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK")).setSortOnMetric(alert).setSortAsc(false);
- List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
-
- // Js Project ERROR, Java Project WARN, then Php Project OK
- assertThat(rows).hasSize(3);
- verifyProject(rows.get(0), 120L, 20L, 20L);
- verifyJavaProject(rows.get(1));
- verifyPhpProject(rows.get(2));
- }
-
- @Test
- public void condition_on_numeric_measure() throws SQLException {
- db.prepareDbUnit(getClass(), "shared.xml");
- MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("CLA"))
- .setSortOnMetric(METRIC_LINES)
- .addCondition(new MeasureFilterCondition(METRIC_LINES, MeasureFilterCondition.Operator.GREATER, 200));
- List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
-
- assertThat(rows).hasSize(1);
- verifyJavaBigFile(rows.get(0));
- }
-
- @Test
- public void condition_on_measure_variation() throws SQLException {
- db.prepareDbUnit(getClass(), "shared.xml");
- MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK"))
- .setSortOnMetric(METRIC_LINES)
- .addCondition(new MeasureFilterCondition(METRIC_LINES, MeasureFilterCondition.Operator.GREATER, 1000).setPeriod(5));
- List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
-
- assertThat(rows).hasSize(1);
- verifyPhpProject(rows.get(0));
- }
-
- @Test
- public void multiple_conditions_on_numeric_measures() throws SQLException {
- db.prepareDbUnit(getClass(), "shared.xml");
- MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("CLA"))
- .setSortOnMetric(METRIC_LINES)
- .addCondition(new MeasureFilterCondition(METRIC_LINES, MeasureFilterCondition.Operator.GREATER, 2))
- .addCondition(new MeasureFilterCondition(METRIC_LINES, MeasureFilterCondition.Operator.LESS_OR_EQUALS, 50));
- List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
-
- assertThat(rows).hasSize(1);
- verifyJavaTinyFile(rows.get(0));
- }
-
- @Test
- public void filter_by_min_date() throws SQLException {
- db.prepareDbUnit(getClass(), "shared.xml");
- MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK")).setFromDate(DateUtils.parseDate("2012-12-13"));
- List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
-
- // php has been analyzed in 2012-12-13, whereas java project has been analyzed in 2008
- assertThat(rows).hasSize(1);
- verifyPhpProject(rows.get(0));
- }
-
- @Test
- public void filter_by_range_of_dates() throws SQLException {
- db.prepareDbUnit(getClass(), "shared.xml");
- MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK"))
- .setFromDate(DateUtils.parseDate("2007-01-01"))
- .setToDate(DateUtils.parseDate("2010-01-01"));
- List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
-
- // php has been analyzed in 2012-12-13, whereas java project has been analyzed in 2008
- assertThat(rows).hasSize(1);
- verifyJavaProject(rows.get(0));
- }
-
- @Test
- public void filter_by_component_name() throws SQLException {
- db.prepareDbUnit(getClass(), "shared.xml");
- MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK")).setResourceName("PHP Proj");
- List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
-
- assertThat(rows).hasSize(1);
- verifyPhpProject(rows.get(0));
- }
-
- @Test
- public void filter_by_component_key() throws SQLException {
- db.prepareDbUnit(getClass(), "shared.xml");
- MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK")).setResourceKey("Va_proje");
- List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
-
- assertThat(rows).hasSize(1);
- verifyJavaProject(rows.get(0));
- }
-
- /**
- * see SONAR-4195
- */
- @Test
- public void filter_by_upper_case_component_key() throws SQLException {
- db.prepareDbUnit(getClass(), "shared.xml");
- MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("CLA")).setResourceKey("big");
- List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
-
- assertThat(rows).hasSize(1);
- verifyJavaBigFile(rows.get(0));
- }
-
- /**
- * see SONAR-4796
- */
- @Test
- public void escape_percent_and_underscore_when_filter_by_component_name_or_key() throws SQLException {
- db.prepareDbUnit(getClass(), "escape_percent_and_underscore_when_filter_by_component_name_or_key.xml");
-
- assertThat(executor.execute(
- new MeasureFilter().setResourceQualifiers(newArrayList("CLA")).setResourceKey("java_"),
- new MeasureFilterContext())).hasSize(2);
-
- assertThat(executor.execute(
- new MeasureFilter().setResourceQualifiers(newArrayList("CLA")).setResourceName("java%"),
- new MeasureFilterContext())).hasSize(2);
- }
-
- @Test
- public void filter_by_base_resource() throws SQLException {
- db.prepareDbUnit(getClass(), "shared.xml");
- MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("CLA")).setBaseResourceKey("java_project");
- List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
-
- assertThat(rows).hasSize(2);
- // default sort is on resource name
- verifyJavaBigFile(rows.get(0));
- verifyJavaTinyFile(rows.get(1));
- }
-
- @Test
- public void filter_by_parent_resource() throws SQLException {
- db.prepareDbUnit(getClass(), "shared.xml");
- MeasureFilter filter = new MeasureFilter().setBaseResourceKey("java_project").setOnBaseResourceChildren(true);
- List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
-
- assertThat(rows).hasSize(1);// the package org.sonar.foo
- assertThat(rows.get(0).getSnapshotId()).isEqualTo(JAVA_PACKAGE_SNAPSHOT_ID);
- }
-
- @Test
- public void filter_by_parent_without_children() throws Exception {
- db.prepareDbUnit(getClass(), "shared.xml");
- MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK", "PAC", "CLA")).setBaseResourceKey("java_project:org.sonar.foo.Big").setOnBaseResourceChildren(true);
- List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
-
- assertThat(rows).isEmpty();
- }
-
- @Test
- public void filter_by_user_favourites() throws Exception {
- db.prepareDbUnit(getClass(), "shared.xml");
- MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK", "FIL")).setUserFavourites(true);
- List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext().setUserId(50L));
-
- assertThat(rows).hasSize(2);
- verifyJavaBigFile(rows.get(0));
- verifyPhpProject(rows.get(1));
- }
-
- @Test
- public void ignore_person_measures_in_condition() throws Exception {
- db.prepareDbUnit(getClass(), "ignore_person_measures.xml");
- MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK")).addCondition(
- new MeasureFilterCondition(new Metric("ncloc").setId(1), MeasureFilterCondition.Operator.GREATER, 0.0)
- );
- List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext().setUserId(50L));
-
- assertThat(rows).hasSize(1);
- assertThat(rows.get(0).getSnapshotId()).isEqualTo(101L);
- }
-
- @Test
- public void ignore_person_measures_in_sort() throws Exception {
- db.prepareDbUnit(getClass(), "ignore_person_measures.xml");
- MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK")).setSortOnMetric(new Metric("ncloc").setId(1));
- List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext().setUserId(50L));
-
- assertThat(rows).hasSize(1);
- assertThat(rows.get(0).getSnapshotId()).isEqualTo(101L);
- }
-
- @Test
- public void ignore_quality_model_measures_in_condition() throws Exception {
- db.prepareDbUnit(getClass(), "ignore_quality_model_measures.xml");
- MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK")).addCondition(
- new MeasureFilterCondition(new Metric("ncloc").setId(1), MeasureFilterCondition.Operator.GREATER, 0.0)
- );
- List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext().setUserId(50L));
-
- assertThat(rows).hasSize(1);
- assertThat(rows.get(0).getSnapshotId()).isEqualTo(101L);
- }
-
- @Test
- public void ignore_quality_model_measures_in_sort() throws Exception {
- db.prepareDbUnit(getClass(), "ignore_quality_model_measures.xml");
- MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK")).setSortOnMetric(new Metric("ncloc").setId(1));
- List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext().setUserId(50L));
-
- assertThat(rows).hasSize(1);
- assertThat(rows.get(0).getSnapshotId()).isEqualTo(101L);
- }
-
-
- private void verifyJavaProject(MeasureFilterRow row) {
- verifyProject(row, JAVA_PROJECT_SNAPSHOT_ID, JAVA_PROJECT_ID, JAVA_PROJECT_ID);
- }
-
- private void verifyJavaBigFile(MeasureFilterRow row) {
- verifyProject(row, JAVA_FILE_BIG_SNAPSHOT_ID, JAVA_FILE_BIG_ID, JAVA_PROJECT_ID);
- }
-
- private void verifyJavaTinyFile(MeasureFilterRow row) {
- verifyProject(row, JAVA_FILE_TINY_SNAPSHOT_ID, JAVA_FILE_TINY_ID, JAVA_PROJECT_ID);
- }
-
- private void verifyPhpProject(MeasureFilterRow row) {
- verifyProject(row, PHP_SNAPSHOT_ID, PHP_PROJECT_ID, PHP_PROJECT_ID);
- }
-
- private void verifyProject(MeasureFilterRow row, Long snashotId, Long resourceId, Long resourceRootId) {
- assertThat(row.getSnapshotId()).isEqualTo(snashotId);
- assertThat(row.getResourceId()).isEqualTo(resourceId);
- assertThat(row.getResourceRootId()).isEqualTo(resourceRootId);
- }
-}
+++ /dev/null
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2014 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube 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.
- *
- * SonarQube 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.core.measure;
-
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Maps;
-import org.junit.Test;
-import org.mockito.invocation.InvocationOnMock;
-import org.mockito.stubbing.Answer;
-import org.sonar.api.measures.Metric;
-import org.sonar.api.measures.MetricFinder;
-import org.sonar.api.utils.DateUtils;
-import org.sonar.api.utils.System2;
-
-import java.util.Arrays;
-import java.util.List;
-import java.util.Map;
-
-import static org.fest.assertions.Assertions.assertThat;
-import static org.mockito.Matchers.anyString;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-public class MeasureFilterFactoryTest {
-
- System2 system = mock(System2.class);
-
- @Test
- public void sort_on_measure_value() {
- MeasureFilterFactory factory = new MeasureFilterFactory(newMetricFinder(), system);
- Map<String, Object> props = ImmutableMap.<String, Object>of("sort", "metric:ncloc");
- MeasureFilter filter = factory.create(props);
-
- assertThat(filter.sort().column()).isEqualTo("pmsort.value");
- assertThat(filter.sort().metric().getKey()).isEqualTo("ncloc");
- assertThat(filter.sort().period()).isNull();
- }
-
- @Test
- public void sort_on_measure_variation() {
- MeasureFilterFactory factory = new MeasureFilterFactory(newMetricFinder(), system);
- Map<String, Object> props = ImmutableMap.<String, Object>of("sort", "metric:ncloc:3");
- MeasureFilter filter = factory.create(props);
-
- assertThat(filter.sort().column()).isEqualTo("pmsort.variation_value_3");
- assertThat(filter.sort().metric().getKey()).isEqualTo("ncloc");
- assertThat(filter.sort().period()).isEqualTo(3);
- }
-
- @Test
- public void sort_on_name() {
- MeasureFilterFactory factory = new MeasureFilterFactory(newMetricFinder(), system);
- Map<String, Object> props = ImmutableMap.<String, Object>of("sort", "name");
- MeasureFilter filter = factory.create(props);
-
- assertThat(filter.sort().column()).isEqualTo("p.long_name");
- assertThat(filter.sort().metric()).isNull();
- assertThat(filter.sort().period()).isNull();
- }
-
- @Test
- public void fallback_on_name_sort_when_metric_is_unknown() {
- MetricFinder finder = mock(MetricFinder.class);
- when(finder.findByKey(anyString())).thenReturn(null);
- MeasureFilterFactory factory = new MeasureFilterFactory(finder, system);
- Map<String, Object> props = ImmutableMap.<String, Object>of("sort", "metric:sqale_index");
- MeasureFilter filter = factory.create(props);
-
- assertThat(filter.sort().column()).isEqualTo("p.long_name");
- assertThat(filter.sort().metric()).isNull();
- assertThat(filter.sort().period()).isNull();
- assertThat(filter.sort().isAsc()).isTrue();
- }
-
- @Test
- public void descending_sort() {
- MeasureFilterFactory factory = new MeasureFilterFactory(newMetricFinder(), system);
- Map<String, Object> props = ImmutableMap.<String, Object>of("asc", "false");
- MeasureFilter filter = factory.create(props);
-
- assertThat(filter.sort().column()).isEqualTo("p.long_name");
- assertThat(filter.sort().metric()).isNull();
- assertThat(filter.sort().period()).isNull();
- assertThat(filter.sort().isAsc()).isFalse();
- }
-
- @Test
- public void ascending_sort_by_default() {
- MeasureFilterFactory factory = new MeasureFilterFactory(newMetricFinder(), system);
- Map<String, Object> props = Maps.newHashMap();
- MeasureFilter filter = factory.create(props);
-
- assertThat(filter.sort().column()).isEqualTo("p.long_name");
- assertThat(filter.sort().metric()).isNull();
- assertThat(filter.sort().period()).isNull();
- assertThat(filter.sort().isAsc()).isTrue();
- }
-
- @Test
- public void date_conditions() {
- MeasureFilterFactory factory = new MeasureFilterFactory(newMetricFinder(), system);
- Map<String, Object> props = ImmutableMap.<String, Object>of(
- "fromDate", "2012-01-25",
- "toDate", "2012-02-18"
- );
- MeasureFilter filter = factory.create(props);
-
- assertThat(DateUtils.formatDate(filter.getFromDate())).isEqualTo("2012-01-25");
- assertThat(DateUtils.formatDate(filter.getToDate())).isEqualTo("2012-02-18");
- }
-
- @Test
- public void age_conditions() {
- long today = DateUtils.parseDateTime("2013-05-18T11:00:00+0000").getTime();
- when(system.now()).thenReturn(today);
-
- MeasureFilterFactory factory = new MeasureFilterFactory(newMetricFinder(), system);
- Map<String, Object> props = ImmutableMap.<String, Object>of(
- "ageMaxDays", "3",
- "ageMinDays", "1"
- );
- MeasureFilter filter = factory.create(props);
- assertThat(DateUtils.formatDate(filter.getFromDate())).isEqualTo("2013-05-15");
- assertThat(DateUtils.formatDate(filter.getToDate())).isEqualTo("2013-05-17");
- }
-
- @Test
- public void measure_value_condition() {
- MeasureFilterFactory factory = new MeasureFilterFactory(newMetricFinder(), system);
- Map<String, Object> props = ImmutableMap.<String, Object>of(
- "c1_metric", "complexity",
- "c1_op", "gte",
- "c1_val", "3.14"
- );
- MeasureFilter filter = factory.create(props);
-
- List<MeasureFilterCondition> conditions = filter.getMeasureConditions();
- assertThat(conditions).hasSize(1);
- assertThat(conditions.get(0).metric().getKey()).isEqualTo("complexity");
- assertThat(conditions.get(0).operator()).isEqualTo(MeasureFilterCondition.Operator.GREATER_OR_EQUALS);
- assertThat(conditions.get(0).value()).isEqualTo(3.14);
- assertThat(conditions.get(0).period()).isNull();
- }
-
- @Test
- public void measure_variation_condition() {
- MeasureFilterFactory factory = new MeasureFilterFactory(newMetricFinder(), system);
- Map<String, Object> props = ImmutableMap.<String, Object>of(
- "c1_metric", "complexity",
- "c1_op", "gte",
- "c1_val", "3.14",
- "c1_period", "3"
- );
- MeasureFilter filter = factory.create(props);
-
- List<MeasureFilterCondition> conditions = filter.getMeasureConditions();
- assertThat(conditions).hasSize(1);
- assertThat(conditions.get(0).metric().getKey()).isEqualTo("complexity");
- assertThat(conditions.get(0).operator()).isEqualTo(MeasureFilterCondition.Operator.GREATER_OR_EQUALS);
- assertThat(conditions.get(0).value()).isEqualTo(3.14);
- assertThat(conditions.get(0).period()).isEqualTo(3);
- }
-
- @Test
- public void alert_level_condition() {
- MeasureFilterFactory factory = new MeasureFilterFactory(newMetricFinder(), system);
- Map<String, Object> props = ImmutableMap.<String, Object>of(
- "alertLevels", Arrays.asList("error", "warn")
- );
- MeasureFilter filter = factory.create(props);
-
- List<MeasureFilterCondition> conditions = filter.getMeasureConditions();
- assertThat(conditions).hasSize(1);
- assertThat(conditions.get(0).metric().getKey()).isEqualTo("alert_status");
- assertThat(conditions.get(0).operator()).isEqualTo(MeasureFilterCondition.Operator.IN);
- assertThat(conditions.get(0).value()).isEqualTo(0);
- assertThat(conditions.get(0).textValue()).isEqualTo("('ERROR', 'WARN')");
- assertThat(conditions.get(0).period()).isNull();
- }
-
- @Test
- public void ignore_partial_measure_condition() {
- MeasureFilterFactory factory = new MeasureFilterFactory(newMetricFinder(), system);
- Map<String, Object> props = ImmutableMap.<String, Object>of(
- "c1_op", "gte",
- "c1_val", "3.14"
- );
- MeasureFilter filter = factory.create(props);
-
- List<MeasureFilterCondition> conditions = filter.getMeasureConditions();
- assertThat(conditions).isEmpty();
- }
-
- private MetricFinder newMetricFinder() {
- MetricFinder finder = mock(MetricFinder.class);
- when(finder.findByKey(anyString())).thenAnswer(new Answer<Metric>() {
- public Metric answer(InvocationOnMock invocationOnMock) throws Throwable {
- String key = (String) invocationOnMock.getArguments()[0];
- return new Metric.Builder(key, key, Metric.ValueType.INT).create();
- }
- });
- return finder;
- }
-}
+++ /dev/null
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2014 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube 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.
- *
- * SonarQube 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.core.measure;
-
-import com.google.common.collect.Lists;
-import org.junit.Test;
-
-import java.util.Arrays;
-import java.util.Collections;
-
-import static org.fest.assertions.Assertions.assertThat;
-
-public class MeasureFilterTest {
- @Test
- public void should_sanitize_list() {
- assertThat(MeasureFilter.sanitize(null)).isEmpty();
- assertThat(MeasureFilter.sanitize(Lists.<String>newArrayList())).isEmpty();
- assertThat(MeasureFilter.sanitize(Arrays.asList(""))).isEmpty();
- assertThat(MeasureFilter.sanitize(Lists.newArrayList("TRK"))).containsExactly("TRK");
- assertThat(MeasureFilter.sanitize(Lists.newArrayList("TRK", "BRC"))).containsExactly("TRK", "BRC");
- }
-
- @Test
- public void filter_is_not_empty_if_at_least_condition_on_favourites() {
- assertThat(new MeasureFilter().isEmpty()).isTrue();
- assertThat(new MeasureFilter().setUserFavourites(true).isEmpty()).isFalse();
- }
-
- @Test
- public void filter_is_not_empty_if_at_least_condition_on_qualifiers() {
- assertThat(new MeasureFilter().isEmpty()).isTrue();
- assertThat(new MeasureFilter().setResourceQualifiers(Collections.<String>emptyList()).isEmpty()).isTrue();
- assertThat(new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK")).isEmpty()).isFalse();
- }
-
- @Test
- public void filter_is_not_empty_if_at_least_condition_on_scopes() {
- assertThat(new MeasureFilter().isEmpty()).isTrue();
- assertThat(new MeasureFilter().setResourceScopes(Collections.<String>emptyList()).isEmpty()).isTrue();
- assertThat(new MeasureFilter().setResourceScopes(Arrays.asList("PRJ")).isEmpty()).isFalse();
- }
-
- @Test
- public void filter_is_not_empty_if_at_least_condition_on_root_resource() {
- assertThat(new MeasureFilter().isEmpty()).isTrue();
- assertThat(new MeasureFilter().setBaseResourceKey("foo").isEmpty()).isFalse();
- }
-}
+++ /dev/null
-<dataset>
-
- <!-- java project -->
- <projects kee="java_project:org.sonar.bar" long_name="org.sonar.bar" scope="FIL" qualifier="CLA" name="org.sonar.bar"
- id="1" root_id="[null]"
- description="[null]" enabled="[true]" language="[null]" copy_resource_id="[null]" person_id="[null]"
- created_at="2008-12-19 00:00:00.00"/>
-
- <projects kee="java_project:org.sonar.foo" scope="FIL" qualifier="CLA" long_name="org.sonar.foo" name="org.sonar.foo"
- id="2" root_id="1"
- description="[null]" enabled="[true]" language="java" copy_resource_id="[null]" person_id="[null]"
- created_at="2008-12-19 00:00:00.00"/>
-
- <projects kee="java project:org.sonar.foo.Big" scope="FIL" qualifier="CLA" long_name="org.sonar.foo.Big"
- name="Big"
- id="3" root_id="1"
- description="[null]" enabled="[true]" language="java" copy_resource_id="[null]" person_id="[null]"
- created_at="2008-12-19 00:00:00.00"/>
-
- <projects kee="java project:org.sonar.foo.Tiny" scope="FIL" qualifier="CLA" long_name="org.sonar.foo.Tiny" name="Tiny"
- id="4" root_id="1"
- description="[null]" enabled="[true]" language="java" copy_resource_id="[null]" person_id="[null]"
- created_at="2008-12-19 00:00:00.00"/>
-
- <snapshots id="101" project_id="1" root_project_id="1" root_snapshot_id="[null]" parent_snapshot_id="[null]"
- scope="FIL" qualifier="CLA" path="" depth="0"
- purge_status="[null]" period1_mode="[null]" period1_param="[null]" period1_date="[null]"
- period2_mode="[null]" period2_param="[null]" period2_date="[null]" period3_mode="[null]"
- period3_param="[null]" period3_date="[null]" period4_mode="[null]" period4_param="[null]"
- period4_date="[null]" period5_mode="[null]" period5_param="[null]" period5_date="[null]"
- created_at="2008-12-20 00:00:00.00" build_date="2008-12-20 00:00:00.00"
- version="1.0" status="P" islast="[true]"/>
-
- <snapshots id="102" project_id="2" root_project_id="1" root_snapshot_id="101" parent_snapshot_id="101"
- scope="FIL" qualifier="CLA" path="101." depth="1"
- purge_status="[null]" period1_mode="[null]" period1_param="[null]" period1_date="[null]"
- period2_mode="[null]" period2_param="[null]" period2_date="[null]" period3_mode="[null]"
- period3_param="[null]" period3_date="[null]" period4_mode="[null]" period4_param="[null]"
- period4_date="[null]" period5_mode="[null]" period5_param="[null]" period5_date="[null]"
- created_at="2008-12-20 00:00:00.00" build_date="2008-12-20 00:00:00.00"
- version="1.0" status="P" islast="[true]"/>
-
- <snapshots id="103" project_id="3" root_project_id="1" root_snapshot_id="101" parent_snapshot_id="102"
- scope="FIL" qualifier="CLA" path="101.102." depth="2"
- purge_status="[null]" period1_mode="[null]" period1_param="[null]" period1_date="[null]"
- period2_mode="[null]" period2_param="[null]" period2_date="[null]" period3_mode="[null]"
- period3_param="[null]" period3_date="[null]" period4_mode="[null]" period4_param="[null]"
- period4_date="[null]" period5_mode="[null]" period5_param="[null]" period5_date="[null]"
- created_at="2008-12-20 00:00:00.00" build_date="2008-12-20 00:00:00.00"
- version="1.0" status="P" islast="[true]"/>
-
- <snapshots id="104" project_id="4" root_project_id="1" root_snapshot_id="101" parent_snapshot_id="102"
- scope="FIL" qualifier="CLA" path="101.102." depth="2"
- purge_status="[null]" period1_mode="[null]" period1_param="[null]" period1_date="[null]"
- period2_mode="[null]" period2_param="[null]" period2_date="[null]" period3_mode="[null]"
- period3_param="[null]" period3_date="[null]" period4_mode="[null]" period4_param="[null]"
- period4_date="[null]" period5_mode="[null]" period5_param="[null]" period5_date="[null]"
- created_at="2008-12-20 00:00:00.00" build_date="2008-12-20 00:00:00.00"
- version="1.0" status="P" islast="[true]"/>
-
- <resource_index id="1" kee="java class1" position="0" name_size="12" resource_id="1" root_project_id="1" qualifier="CLA"/>
- <resource_index id="2" kee="java class2" position="1" name_size="12" resource_id="2" root_project_id="1" qualifier="CLA"/>
- <resource_index id="3" kee="java%class3" position="2" name_size="12" resource_id="3" root_project_id="1" qualifier="CLA"/>
- <resource_index id="4" kee="java%class4" position="3" name_size="12" resource_id="4" root_project_id="1" qualifier="CLA"/>
-
-
-</dataset>
+++ /dev/null
-<dataset>
- <metrics id="1" name="lines" val_type="FLOAT" description="Lines" domain="Size"
- short_name="Lines" qualitative="[false]" user_managed="[false]" enabled="[true]" origin="JAV" worst_value="[null]"
- optimized_best_value="[null]" best_value="[null]" direction="1" hidden="[false]"
- delete_historical_data="[null]"/>
-
- <projects kee="java_project" long_name="Java project" scope="PRJ" qualifier="TRK" name="Java project"
- id="1" root_id="[null]"
- description="[null]" enabled="[true]" language="[null]" copy_resource_id="[null]" person_id="[null]"/>
-
- <snapshots id="101" project_id="1" root_project_id="1" root_snapshot_id="[null]" parent_snapshot_id="[null]"
- scope="PRJ" qualifier="TRK" path="" depth="0"
- purge_status="[null]" period1_mode="[null]" period1_param="[null]" period1_date="[null]"
- period2_mode="[null]" period2_param="[null]" period2_date="[null]" period3_mode="[null]"
- period3_param="[null]" period3_date="[null]" period4_mode="[null]" period4_param="[null]"
- period4_date="[null]" period5_mode="[null]" period5_param="[null]" period5_date="[null]"
- created_at="2008-12-20 00:00:00.00" build_date="2008-12-20 00:00:00.00"
- version="1.0" status="P" islast="[true]"/>
-
-
- <!-- standard measure -->
- <project_measures id="1001" metric_id="1" value="500" snapshot_id="101" person_id="[null]"
- url="[null]" variation_value_1="[null]" variation_value_2="[null]" variation_value_3="[null]"
- variation_value_4="[null]" variation_value_5="400"
- rule_priority="[null]" alert_text="[null]" RULES_CATEGORY_ID="[null]"
- RULE_ID="[null]" text_value="[null]" tendency="[null]" measure_date="[null]" project_id="[null]"
- alert_status="[null]" description="[null]" characteristic_id="[null]"/>
-
- <!-- details of the measure by person -->
- <project_measures id="1002" metric_id="1" value="300" snapshot_id="101" person_id="30000"
- url="[null]" variation_value_1="[null]" variation_value_2="[null]" variation_value_3="[null]"
- variation_value_4="[null]" variation_value_5="400"
- rule_priority="[null]" alert_text="[null]" RULES_CATEGORY_ID="[null]"
- RULE_ID="[null]" text_value="[null]" tendency="[null]" measure_date="[null]" project_id="[null]"
- alert_status="[null]" description="[null]" characteristic_id="[null]"/>
-
- <project_measures id="1003" metric_id="1" value="200" snapshot_id="101" person_id="40000"
- url="[null]" variation_value_1="[null]" variation_value_2="[null]" variation_value_3="[null]"
- variation_value_4="[null]" variation_value_5="400"
- rule_priority="[null]" alert_text="[null]" RULES_CATEGORY_ID="[null]"
- RULE_ID="[null]" text_value="[null]" tendency="[null]" measure_date="[null]" project_id="[null]"
- alert_status="[null]" description="[null]" characteristic_id="[null]"/>
-
-</dataset>
+++ /dev/null
-<dataset>
- <metrics id="1" name="lines" val_type="FLOAT" description="Lines" domain="Size"
- short_name="Lines" qualitative="[false]" user_managed="[false]" enabled="[true]" origin="JAV" worst_value="[null]"
- optimized_best_value="[null]" best_value="[null]" direction="1" hidden="[false]"
- delete_historical_data="[null]"/>
-
- <projects kee="java_project" long_name="Java project" scope="PRJ" qualifier="TRK" name="Java project"
- id="1" root_id="[null]"
- description="[null]" enabled="[true]" language="[null]" copy_resource_id="[null]" person_id="[null]"/>
-
- <snapshots id="101" project_id="1" root_project_id="1" root_snapshot_id="[null]" parent_snapshot_id="[null]"
- scope="PRJ" qualifier="TRK" path="" depth="0"
- purge_status="[null]" period1_mode="[null]" period1_param="[null]" period1_date="[null]"
- period2_mode="[null]" period2_param="[null]" period2_date="[null]" period3_mode="[null]"
- period3_param="[null]" period3_date="[null]" period4_mode="[null]" period4_param="[null]"
- period4_date="[null]" period5_mode="[null]" period5_param="[null]" period5_date="[null]"
- created_at="2008-12-20 00:00:00.00" build_date="2008-12-20 00:00:00.00"
- version="1.0" status="P" islast="[true]"/>
-
-
- <!-- standard measure -->
- <project_measures id="1001" metric_id="1" value="500" snapshot_id="101" characteristic_id="[null]"
- url="[null]" variation_value_1="[null]" variation_value_2="[null]" variation_value_3="[null]"
- variation_value_4="[null]" variation_value_5="400"
- rule_priority="[null]" alert_text="[null]" RULES_CATEGORY_ID="[null]"
- RULE_ID="[null]" text_value="[null]" tendency="[null]" measure_date="[null]" project_id="[null]"
- alert_status="[null]" description="[null]" person_id="[null]"/>
-
- <!-- details of the measure by model characteristic -->
- <project_measures id="1002" metric_id="1" value="300" snapshot_id="101" characteristic_id="30000"
- url="[null]" variation_value_1="[null]" variation_value_2="[null]" variation_value_3="[null]"
- variation_value_4="[null]" variation_value_5="400"
- rule_priority="[null]" alert_text="[null]" RULES_CATEGORY_ID="[null]"
- RULE_ID="[null]" text_value="[null]" tendency="[null]" measure_date="[null]" project_id="[null]"
- alert_status="[null]" description="[null]" person_id="[null]"/>
-
- <project_measures id="1003" metric_id="1" value="200" snapshot_id="101" characteristic_id="40000"
- url="[null]" variation_value_1="[null]" variation_value_2="[null]" variation_value_3="[null]"
- variation_value_4="[null]" variation_value_5="400"
- rule_priority="[null]" alert_text="[null]" RULES_CATEGORY_ID="[null]"
- RULE_ID="[null]" text_value="[null]" tendency="[null]" measure_date="[null]" project_id="[null]"
- alert_status="[null]" description="[null]" person_id="[null]"/>
-
-</dataset>
+++ /dev/null
-<dataset>
- <metrics id="1" name="lines" val_type="FLOAT" description="Lines" domain="Size"
- short_name="Lines" qualitative="[false]" user_managed="[false]" enabled="[true]" origin="JAV" worst_value="[null]"
- optimized_best_value="[null]" best_value="[null]" direction="1" hidden="[false]"
- delete_historical_data="[null]"/>
-
- <metrics id="2" name="profile" val_type="STRING" description="Profile" domain="Rules"
- short_name="Profile" qualitative="[false]" user_managed="[false]" enabled="[true]" origin="JAV"
- worst_value="[null]"
- optimized_best_value="[null]" best_value="[null]" direction="0" hidden="[false]"
- delete_historical_data="[null]"/>
-
- <metrics id="3" name="coverage" val_type="FLOAT" description="Coverage" domain="Test"
- short_name="Coverage" qualitative="[true]" user_managed="[false]" enabled="[true]" origin="JAV"
- worst_value="[null]"
- optimized_best_value="[true]" best_value="100" direction="1" hidden="[false]"
- delete_historical_data="[null]"/>
-
- <metrics id="4" name="unknown" val_type="FLOAT" description="Coverage" domain="Test"
- short_name="Unknown" qualitative="[true]" user_managed="[false]" enabled="[true]" origin="JAV"
- worst_value="[null]"
- optimized_best_value="[true]" best_value="100" direction="1" hidden="[false]"
- delete_historical_data="[null]"/>
-
- <!-- java project -->
- <projects kee="java_project" long_name="Java project" scope="PRJ" qualifier="TRK" name="Java project"
- id="1" root_id="[null]"
- description="[null]" enabled="[true]" language="[null]" copy_resource_id="[null]" person_id="[null]"
- created_at="2008-12-19 00:00:00.00"/>
-
- <projects kee="java_project:org.sonar.foo" scope="DIR" qualifier="PAC" long_name="org.sonar.foo" name="org.sonar.foo"
- id="2" root_id="1"
- description="[null]" enabled="[true]" language="[null]" copy_resource_id="[null]" person_id="[null]"
- created_at="2008-12-19 00:00:00.00"/>
-
- <projects kee="java_project:org.sonar.foo.Big" scope="FIL" qualifier="CLA" long_name="org.sonar.foo.Big"
- name="Big"
- id="3" root_id="1"
- description="[null]" enabled="[true]" language="java" copy_resource_id="[null]" person_id="[null]"
- created_at="2008-12-19 00:00:00.00"/>
-
- <projects kee="java_project:org.sonar.foo.Tiny" scope="FIL" qualifier="CLA" long_name="org.sonar.foo.Tiny" name="Tiny"
- id="4" root_id="1"
- description="[null]" enabled="[true]" language="java" copy_resource_id="[null]" person_id="[null]"
- created_at="2008-12-19 00:00:00.00"/>
-
- <snapshots id="101" project_id="1" root_project_id="1" root_snapshot_id="[null]" parent_snapshot_id="[null]"
- scope="PRJ" qualifier="TRK" path="" depth="0"
- purge_status="[null]" period1_mode="[null]" period1_param="[null]" period1_date="[null]"
- period2_mode="[null]" period2_param="[null]" period2_date="[null]" period3_mode="[null]"
- period3_param="[null]" period3_date="[null]" period4_mode="[null]" period4_param="[null]"
- period4_date="[null]" period5_mode="[null]" period5_param="[null]" period5_date="[null]"
- created_at="2008-12-20 00:00:00.00" build_date="2008-12-20 00:00:00.00"
- version="1.0" status="P" islast="[true]"/>
-
- <snapshots id="102" project_id="2" root_project_id="1" root_snapshot_id="101" parent_snapshot_id="101"
- scope="DIR" qualifier="PAC" path="101." depth="1"
- purge_status="[null]" period1_mode="[null]" period1_param="[null]" period1_date="[null]"
- period2_mode="[null]" period2_param="[null]" period2_date="[null]" period3_mode="[null]"
- period3_param="[null]" period3_date="[null]" period4_mode="[null]" period4_param="[null]"
- period4_date="[null]" period5_mode="[null]" period5_param="[null]" period5_date="[null]"
- created_at="2008-12-20 00:00:00.00" build_date="2008-12-20 00:00:00.00"
- version="1.0" status="P" islast="[true]"/>
-
- <snapshots id="103" project_id="3" root_project_id="1" root_snapshot_id="101" parent_snapshot_id="102"
- scope="FIL" qualifier="CLA" path="101.102." depth="2"
- purge_status="[null]" period1_mode="[null]" period1_param="[null]" period1_date="[null]"
- period2_mode="[null]" period2_param="[null]" period2_date="[null]" period3_mode="[null]"
- period3_param="[null]" period3_date="[null]" period4_mode="[null]" period4_param="[null]"
- period4_date="[null]" period5_mode="[null]" period5_param="[null]" period5_date="[null]"
- created_at="2008-12-20 00:00:00.00" build_date="2008-12-20 00:00:00.00"
- version="1.0" status="P" islast="[true]"/>
-
- <snapshots id="104" project_id="4" root_project_id="1" root_snapshot_id="101" parent_snapshot_id="102"
- scope="FIL" qualifier="CLA" path="101.102." depth="2"
- purge_status="[null]" period1_mode="[null]" period1_param="[null]" period1_date="[null]"
- period2_mode="[null]" period2_param="[null]" period2_date="[null]" period3_mode="[null]"
- period3_param="[null]" period3_date="[null]" period4_mode="[null]" period4_param="[null]"
- period4_date="[null]" period5_mode="[null]" period5_param="[null]" period5_date="[null]"
- created_at="2008-12-20 00:00:00.00" build_date="2008-12-20 00:00:00.00"
- version="1.0" status="P" islast="[true]"/>
-
-
- <!-- lines, variation during period 5 -->
- <project_measures id="1001" metric_id="1" value="510" snapshot_id="101"
- url="[null]" variation_value_1="[null]" variation_value_2="[null]" variation_value_3="[null]"
- variation_value_4="[null]" variation_value_5="400"
- rule_priority="[null]" alert_text="[null]" RULES_CATEGORY_ID="[null]"
- RULE_ID="[null]" text_value="[null]" tendency="[null]" measure_date="[null]" project_id="[null]"
- alert_status="[null]" description="[null]" characteristic_id="[null]"/>
-
- <project_measures id="1002" metric_id="1" value="510" snapshot_id="102"
- url="[null]" variation_value_1="[null]" variation_value_2="[null]" variation_value_3="[null]"
- variation_value_4="[null]" variation_value_5="[null]"
- rule_priority="[null]" alert_text="[null]" RULES_CATEGORY_ID="[null]"
- RULE_ID="[null]" text_value="[null]" tendency="[null]" measure_date="[null]" project_id="[null]"
- alert_status="[null]" description="[null]" characteristic_id="[null]"/>
-
- <project_measures id="1003" metric_id="1" value="500" snapshot_id="103"
- url="[null]" variation_value_1="[null]" variation_value_2="[null]" variation_value_3="[null]"
- variation_value_4="[null]" variation_value_5="[null]"
- rule_priority="[null]" alert_text="[null]" RULES_CATEGORY_ID="[null]"
- RULE_ID="[null]" text_value="[null]" tendency="[null]" measure_date="[null]" project_id="[null]"
- alert_status="[null]" description="[null]" characteristic_id="[null]"/>
-
- <project_measures id="1004" metric_id="1" value="10" snapshot_id="104"
- url="[null]" variation_value_1="[null]" variation_value_2="[null]" variation_value_3="[null]"
- variation_value_4="[null]" variation_value_5="[null]"
- rule_priority="[null]" alert_text="[null]" RULES_CATEGORY_ID="[null]"
- RULE_ID="[null]" text_value="[null]" tendency="[null]" measure_date="[null]" project_id="[null]"
- alert_status="[null]" description="[null]" characteristic_id="[null]"/>
-
- <!-- profile of java project -->
- <project_measures id="1005" metric_id="2" value="[null]" snapshot_id="101"
- url="[null]" variation_value_1="[null]" variation_value_2="[null]" variation_value_3="[null]"
- variation_value_4="[null]" variation_value_5="[null]"
- rule_priority="[null]" alert_text="[null]" RULES_CATEGORY_ID="[null]"
- RULE_ID="[null]" text_value="Sonar way" tendency="[null]" measure_date="[null]" project_id="[null]"
- alert_status="[null]" description="[null]" characteristic_id="[null]"/>
-
- <!-- coverage of java project -->
- <project_measures id="1006" metric_id="3" value="12.3" snapshot_id="101"
- url="[null]" variation_value_1="[null]" variation_value_2="[null]" variation_value_3="[null]"
- variation_value_4="[null]" variation_value_5="[null]"
- rule_priority="[null]" alert_text="[null]" RULES_CATEGORY_ID="[null]"
- RULE_ID="[null]" text_value="Sonar way" tendency="[null]" measure_date="[null]" project_id="[null]"
- alert_status="[null]" description="[null]" characteristic_id="[null]"/>
-
- <!-- php project -->
- <projects kee="php_project" long_name="PHP project" scope="PRJ" qualifier="TRK" name="PHP project"
- id="10" root_id="[null]"
- description="[null]" enabled="[true]" language="[null]" copy_resource_id="[null]" person_id="[null]"
- created_at="2012-12-12 04:06:00.00"/>
-
-
- <snapshots id="110" project_id="10" root_project_id="10" root_snapshot_id="[null]" parent_snapshot_id="[null]"
- scope="PRJ" qualifier="TRK" path="" depth="0"
- purge_status="[null]" period1_mode="[null]" period1_param="[null]" period1_date="[null]"
- period2_mode="[null]" period2_param="[null]" period2_date="[null]" period3_mode="[null]"
- period3_param="[null]" period3_date="[null]" period4_mode="[null]" period4_param="[null]"
- period4_date="[null]" period5_mode="[null]" period5_param="[null]" period5_date="[null]"
- created_at="2012-12-13 04:06:00.00" build_date="2012-12-13 04:06:00.00"
- version="3.0" status="P" islast="[true]"/>
-
- <!-- lines, many new lines during period 5 -->
- <project_measures id="1010" metric_id="1" value="5000" snapshot_id="110"
- url="[null]" variation_value_1="[null]" variation_value_2="[null]" variation_value_3="[null]"
- variation_value_4="[null]" variation_value_5="4900"
- rule_priority="[null]" alert_text="[null]" RULES_CATEGORY_ID="[null]"
- RULE_ID="[null]" text_value="[null]" tendency="[null]" measure_date="[null]" project_id="[null]"
- alert_status="[null]" description="[null]" characteristic_id="[null]"/>
-
- <project_measures id="1011" metric_id="2" value="[null]" snapshot_id="110"
- url="[null]" variation_value_1="[null]" variation_value_2="[null]" variation_value_3="[null]"
- variation_value_4="[null]" variation_value_5="[null]"
- rule_priority="[null]" alert_text="[null]" RULES_CATEGORY_ID="[null]"
- RULE_ID="[null]" text_value="php way" tendency="[null]" measure_date="[null]" project_id="[null]"
- alert_status="[null]" description="[null]" characteristic_id="[null]"/>
-
-
- <resource_index id="1" kee="java project" position="0" name_size="12" resource_id="1" root_project_id="1" qualifier="TRK"/>
- <resource_index id="2" kee="java projec" position="1" name_size="12" resource_id="1" root_project_id="1" qualifier="TRK"/>
- <resource_index id="3" kee="java proje" position="2" name_size="12" resource_id="1" root_project_id="1" qualifier="TRK"/>
- <resource_index id="4" kee="java proj" position="3" name_size="12" resource_id="1" root_project_id="1" qualifier="TRK"/>
- <!-- etc -->
- <resource_index id="5" kee="php project" position="0" name_size="11" resource_id="10" root_project_id="10" qualifier="TRK"/>
- <resource_index id="6" kee="php projec" position="1" name_size="11" resource_id="10" root_project_id="10" qualifier="TRK"/>
- <resource_index id="7" kee="php proje" position="2" name_size="11" resource_id="10" root_project_id="10" qualifier="TRK"/>
- <resource_index id="8" kee="php proj" position="3" name_size="11" resource_id="10" root_project_id="10" qualifier="TRK"/>
- <!-- etc -->
-
-
- <!-- two favourites : Big.java and PHP project -->
- <properties id="1" prop_key="favourite" resource_id="3" text_value="[null]" user_id="50"/>
- <properties id="2" prop_key="favourite" resource_id="10" text_value="[null]" user_id="50"/>
-
- <!-- another properties -->
- <properties id="3" prop_key="favourite" resource_id="1" text_value="[null]" user_id="1234"/>
- <properties id="4" prop_key="sonar.profile" resource_id="1" text_value="Sonar way" user_id="[null]"/>
-
-</dataset>
+++ /dev/null
-<dataset>
- <metrics id="5" name="alert_status" val_type="LEVEL" description="Alert" domain="General"
- short_name="Alert" qualitative="[true]" user_managed="[false]" enabled="[true]" origin="JAV"
- worst_value="[null]"
- optimized_best_value="[true]" best_value="[null]" direction="1" hidden="[false]"
- delete_historical_data="[null]"/>
-
- <!-- java project -->
- <projects kee="java_project" long_name="Java project" scope="PRJ" qualifier="TRK" name="Java project"
- id="1" root_id="[null]"
- description="[null]" enabled="[true]" language="[null]" copy_resource_id="[null]" person_id="[null]"
- created_at="2008-12-19 00:00:00.00"/>
-
- <snapshots id="101" project_id="1" root_project_id="1" root_snapshot_id="[null]" parent_snapshot_id="[null]"
- scope="PRJ" qualifier="TRK" path="" depth="0"
- purge_status="[null]" period1_mode="[null]" period1_param="[null]" period1_date="[null]"
- period2_mode="[null]" period2_param="[null]" period2_date="[null]" period3_mode="[null]"
- period3_param="[null]" period3_date="[null]" period4_mode="[null]" period4_param="[null]"
- period4_date="[null]" period5_mode="[null]" period5_param="[null]" period5_date="[null]"
- created_at="2008-12-20 00:00:00.00" build_date="2008-12-20 00:00:00.00"
- version="1.0" status="P" islast="[true]"/>
-
-
- <!-- alert -->
- <project_measures id="1001" metric_id="5" value="510" snapshot_id="101"
- url="[null]" variation_value_1="[null]" variation_value_2="[null]" variation_value_3="[null]"
- variation_value_4="[null]" variation_value_5="400"
- rule_priority="[null]" alert_text="[null]" RULES_CATEGORY_ID="[null]"
- RULE_ID="[null]" text_value="WARN" tendency="[null]" measure_date="[null]" project_id="[null]"
- alert_status="[null]" description="[null]" characteristic_id="[null]"/>
-
- <!-- php project -->
- <projects kee="php_project" long_name="PHP project" scope="PRJ" qualifier="TRK" name="PHP project"
- id="10" root_id="[null]"
- description="[null]" enabled="[true]" language="[null]" copy_resource_id="[null]" person_id="[null]"
- created_at="2012-12-12 04:06:00.00"/>
-
-
- <snapshots id="110" project_id="10" root_project_id="10" root_snapshot_id="[null]" parent_snapshot_id="[null]"
- scope="PRJ" qualifier="TRK" path="" depth="0"
- purge_status="[null]" period1_mode="[null]" period1_param="[null]" period1_date="[null]"
- period2_mode="[null]" period2_param="[null]" period2_date="[null]" period3_mode="[null]"
- period3_param="[null]" period3_date="[null]" period4_mode="[null]" period4_param="[null]"
- period4_date="[null]" period5_mode="[null]" period5_param="[null]" period5_date="[null]"
- created_at="2012-12-13 04:06:00.00" build_date="2012-12-13 04:06:00.00"
- version="3.0" status="P" islast="[true]"/>
-
- <!-- alert -->
- <project_measures id="1010" metric_id="5" value="5000" snapshot_id="110"
- url="[null]" variation_value_1="[null]" variation_value_2="[null]" variation_value_3="[null]"
- variation_value_4="[null]" variation_value_5="[null]"
- rule_priority="[null]" alert_text="[null]" RULES_CATEGORY_ID="[null]"
- RULE_ID="[null]" text_value="OK" tendency="[null]" measure_date="[null]" project_id="[null]"
- alert_status="[null]" description="[null]" characteristic_id="[null]"/>
-
- <!-- js project -->
- <projects kee="js_project" long_name="JS project" scope="PRJ" qualifier="TRK" name="JS project"
- id="20" root_id="[null]"
- description="[null]" enabled="[true]" language="[null]" copy_resource_id="[null]" person_id="[null]"
- created_at="2012-12-12 04:06:00.00"/>
-
-
- <snapshots id="120" project_id="20" root_project_id="20" root_snapshot_id="[null]" parent_snapshot_id="[null]"
- scope="PRJ" qualifier="TRK" path="" depth="0"
- purge_status="[null]" period1_mode="[null]" period1_param="[null]" period1_date="[null]"
- period2_mode="[null]" period2_param="[null]" period2_date="[null]" period3_mode="[null]"
- period3_param="[null]" period3_date="[null]" period4_mode="[null]" period4_param="[null]"
- period4_date="[null]" period5_mode="[null]" period5_param="[null]" period5_date="[null]"
- created_at="2012-12-13 04:06:00.00" build_date="2012-12-13 04:06:00.00"
- version="3.0" status="P" islast="[true]"/>
-
- <!-- alert -->
- <project_measures id="1020" metric_id="5" value="5000" snapshot_id="120"
- url="[null]" variation_value_1="[null]" variation_value_2="[null]" variation_value_3="[null]"
- variation_value_4="[null]" variation_value_5="[null]"
- rule_priority="[null]" alert_text="[null]" RULES_CATEGORY_ID="[null]"
- RULE_ID="[null]" text_value="ERROR" tendency="[null]" measure_date="[null]" project_id="[null]"
- alert_status="[null]" description="[null]" characteristic_id="[null]"/>
-
-
-</dataset>
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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.measure;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Strings;
+import com.google.common.collect.Lists;
+import org.apache.commons.lang.StringUtils;
+import org.apache.commons.lang.builder.ReflectionToStringBuilder;
+import org.sonar.api.measures.Metric;
+import org.sonar.api.resources.Qualifiers;
+
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
+
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+
+public class MeasureFilter {
+
+ // conditions on resources
+ private String baseResourceKey;
+
+ // only if baseResourceKey or baseResourceId are set
+ private boolean onBaseResourceChildren = false;
+
+ private List<String> resourceScopes = Collections.emptyList();
+ private List<String> resourceQualifiers = Collections.emptyList();
+ private String resourceKey = null;
+ private String resourceName = null;
+ private Date fromDate = null, toDate = null;
+ private boolean userFavourites = false;
+
+ // conditions on measures
+ private List<MeasureFilterCondition> measureConditions = Lists.newArrayList();
+
+ // sort
+ private MeasureFilterSort sort = new MeasureFilterSort();
+
+ public String getBaseResourceKey() {
+ return baseResourceKey;
+ }
+
+ public MeasureFilter setBaseResourceKey(String s) {
+ this.baseResourceKey = s;
+ return this;
+ }
+
+ public MeasureFilter setOnBaseResourceChildren(boolean b) {
+ this.onBaseResourceChildren = b;
+ return this;
+ }
+
+ public boolean isOnBaseResourceChildren() {
+ return onBaseResourceChildren;
+ }
+
+ public MeasureFilter setResourceScopes(@Nullable List<String> list) {
+ this.resourceScopes = sanitize(list);
+ return this;
+ }
+
+ public MeasureFilter setResourceQualifiers(@Nullable List<String> list) {
+ this.resourceQualifiers = sanitize(list);
+ if (resourceQualifiers.contains(Qualifiers.FILE)) {
+ resourceQualifiers.add(Qualifiers.CLASS);
+ }
+ if (resourceQualifiers.contains(Qualifiers.DIRECTORY)) {
+ resourceQualifiers.add(Qualifiers.PACKAGE);
+ }
+ return this;
+ }
+
+ public MeasureFilter setUserFavourites(boolean b) {
+ this.userFavourites = b;
+ return this;
+ }
+
+ public boolean isOnFavourites() {
+ return userFavourites;
+ }
+
+ public String getResourceName() {
+ return resourceName;
+ }
+
+ public MeasureFilter setResourceName(String s) {
+ this.resourceName = s;
+ return this;
+ }
+
+ public String getResourceKey() {
+ return resourceKey;
+ }
+
+ public MeasureFilter setResourceKey(String s) {
+ this.resourceKey = s;
+ return this;
+ }
+
+ public MeasureFilter addCondition(MeasureFilterCondition condition) {
+ this.measureConditions.add(condition);
+ return this;
+ }
+
+ public MeasureFilter setSortOn(MeasureFilterSort.Field sortField) {
+ this.sort.setField(sortField);
+ return this;
+ }
+
+ public MeasureFilter setSortAsc(boolean b) {
+ this.sort.setAsc(b);
+ return this;
+ }
+
+ public MeasureFilter setSortOnMetric(Metric m) {
+ this.sort.setField(MeasureFilterSort.Field.METRIC);
+ this.sort.setMetric(m);
+ return this;
+ }
+
+ public MeasureFilter setSortOnPeriod(int period) {
+ this.sort.setPeriod(period);
+ return this;
+ }
+
+ public MeasureFilter setFromDate(@Nullable Date d) {
+ this.fromDate = d;
+ return this;
+ }
+
+ public MeasureFilter setToDate(@Nullable Date d) {
+ this.toDate = d;
+ return this;
+ }
+
+ @CheckForNull
+ public Date getFromDate() {
+ return fromDate;
+ }
+
+ @CheckForNull
+ public Date getToDate() {
+ return toDate;
+ }
+
+ public List<String> getResourceScopes() {
+ return resourceScopes;
+ }
+
+ public List<String> getResourceQualifiers() {
+ return resourceQualifiers;
+ }
+
+ public List<MeasureFilterCondition> getMeasureConditions() {
+ return measureConditions;
+ }
+
+ MeasureFilterSort sort() {
+ return sort;
+ }
+
+ public boolean isEmpty() {
+ return resourceQualifiers.isEmpty() && resourceScopes.isEmpty() && StringUtils.isEmpty(baseResourceKey) && !userFavourites;
+ }
+
+ @VisibleForTesting
+ static List<String> sanitize(@Nullable List<String> list) {
+ return isEmptyList(list) ? Collections.<String> emptyList() : Lists.newArrayList(list);
+ }
+
+ private static boolean isEmptyList(@Nullable List<String> list) {
+ boolean blank = false;
+ if (list == null || list.isEmpty() || (list.size() == 1 && Strings.isNullOrEmpty(list.get(0)))) {
+ blank = true;
+ }
+ return blank;
+ }
+
+ @Override
+ public String toString() {
+ return ReflectionToStringBuilder.toString(this);
+ }
+}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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.measure;
+
+import org.apache.commons.lang.builder.ReflectionToStringBuilder;
+import org.apache.commons.lang.builder.ToStringStyle;
+import org.sonar.api.measures.Metric;
+
+public class MeasureFilterCondition {
+ public enum Operator {
+ EQUALS("eq", "="), GREATER("gt", ">"), GREATER_OR_EQUALS("gte", ">="), LESS("lt", "<"), LESS_OR_EQUALS("lte", "<="), IN("in", "IN");
+
+ private String code;
+ private String sql;
+
+ private Operator(String code, String sql) {
+ this.code = code;
+ this.sql = sql;
+ }
+
+ public String getSql() {
+ return sql;
+ }
+
+ public static Operator fromCode(String code) {
+ for (Operator operator : values()) {
+ if (operator.code.equals(code)) {
+ return operator;
+ }
+ }
+ throw new IllegalArgumentException("Unknown operator code: " + code);
+ }
+ }
+
+ private final Metric metric;
+ private final Operator operator;
+ private final double value;
+ private final String textValue;
+ private Integer period = null;
+
+ public MeasureFilterCondition(Metric metric, Operator operator, double value) {
+ this.metric = metric;
+ this.operator = operator;
+ this.value = value;
+ this.textValue = null;
+ }
+
+ public MeasureFilterCondition(Metric metric, Operator operator, String textValue) {
+ this.metric = metric;
+ this.operator = operator;
+ this.value = 0;
+ this.textValue = textValue;
+ }
+
+ public MeasureFilterCondition setPeriod(Integer period) {
+ this.period = period;
+ return this;
+ }
+
+ public Metric metric() {
+ return metric;
+ }
+
+ public Operator operator() {
+ return operator;
+ }
+
+ public double value() {
+ return value;
+ }
+
+ public String textValue() {
+ return textValue;
+ }
+
+ public Integer period() {
+ return period;
+ }
+
+ StringBuilder appendSqlColumn(StringBuilder sb, int conditionIndex) {
+ sb.append("pmcond").append(conditionIndex);
+ if (period != null) {
+ sb.append(".variation_value_").append(period).toString();
+ } else if (textValue == null) {
+ sb.append(".value");
+ } else {
+ sb.append(".text_value");
+ }
+ return sb;
+ }
+
+ StringBuilder appendSqlCondition(StringBuilder sql, int conditionIndex) {
+ String table = "pmcond" + conditionIndex;
+ sql.append(" ").append(table).append(".metric_id=");
+ sql.append(metric.getId());
+ sql.append(" AND ");
+ appendSqlColumn(sql, conditionIndex);
+ sql.append(" ").append(operator.getSql()).append(" ");
+ if (textValue == null) {
+ sql.append(value);
+ } else {
+ sql.append(textValue);
+ }
+ sql.append(" AND ");
+ sql.append(table).append(".rule_id IS NULL AND ");
+ sql.append(table).append(".rule_priority IS NULL AND ");
+ sql.append(table).append(".characteristic_id IS NULL AND ");
+ sql.append(table).append(".person_id IS NULL ");
+ return sql;
+ }
+
+ @Override
+ public String toString() {
+ return ReflectionToStringBuilder.toString(this, ToStringStyle.SIMPLE_STYLE);
+ }
+}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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.measure;
+
+import org.apache.commons.lang.builder.ToStringBuilder;
+import org.apache.commons.lang.builder.ToStringStyle;
+import org.sonar.core.resource.SnapshotDto;
+
+import javax.annotation.Nullable;
+
+class MeasureFilterContext {
+ private Long userId = null;
+ private SnapshotDto baseSnapshot = null;
+ private String sql;
+ private String data;
+
+ Long getUserId() {
+ return userId;
+ }
+
+ MeasureFilterContext setUserId(@Nullable Long userId) {
+ this.userId = userId;
+ return this;
+ }
+
+ SnapshotDto getBaseSnapshot() {
+ return baseSnapshot;
+ }
+
+ MeasureFilterContext setBaseSnapshot(@Nullable SnapshotDto baseSnapshot) {
+ this.baseSnapshot = baseSnapshot;
+ return this;
+ }
+
+ String getSql() {
+ return sql;
+ }
+
+ MeasureFilterContext setSql(String sql) {
+ this.sql = sql;
+ return this;
+ }
+
+ String getData() {
+ return data;
+ }
+
+ MeasureFilterContext setData(String data) {
+ this.data = data;
+ return this;
+ }
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE)
+ .append("filter", data)
+ .append("sql", sql)
+ .append("user", userId)
+ .toString();
+ }
+}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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.measure;
+
+import com.google.common.base.Joiner;
+import org.apache.commons.lang.SystemUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.sonar.api.ServerComponent;
+import org.sonar.core.profiling.Profiling;
+import org.sonar.core.profiling.Profiling.Level;
+import org.sonar.core.profiling.StopWatch;
+
+import javax.annotation.Nullable;
+
+import java.util.List;
+import java.util.Map;
+
+public class MeasureFilterEngine implements ServerComponent {
+
+ private static final Logger LOG = LoggerFactory.getLogger("org.sonar.MEASURE_FILTER");
+
+ private final MeasureFilterFactory factory;
+ private final MeasureFilterExecutor executor;
+ private final Profiling profiling;
+
+ public MeasureFilterEngine(MeasureFilterFactory factory, MeasureFilterExecutor executor, Profiling profiling) {
+ this.executor = executor;
+ this.factory = factory;
+ this.profiling = profiling;
+ }
+
+ public MeasureFilterResult execute(Map<String, Object> filterMap, @Nullable Long userId) {
+ StopWatch watch = profiling.start("measures", Level.BASIC);
+ StopWatch sqlWatch = null;
+ MeasureFilterResult result = new MeasureFilterResult();
+ MeasureFilterContext context = new MeasureFilterContext();
+ context.setUserId(userId);
+ context.setData(String.format("{%s}", Joiner.on('|').withKeyValueSeparator("=").join(filterMap)));
+ try {
+ MeasureFilter filter = factory.create(filterMap);
+ sqlWatch = profiling.start("sql", Level.FULL);
+ List<MeasureFilterRow> rows = executor.execute(filter, context);
+ result.setRows(rows);
+
+ } catch (NumberFormatException e) {
+ result.setError(MeasureFilterResult.Error.VALUE_SHOULD_BE_A_NUMBER);
+ LOG.debug("Value selected for the metric should be a number: " + context);
+ } catch (Exception e) {
+ result.setError(MeasureFilterResult.Error.UNKNOWN);
+ LOG.error("Fail to execute measure filter: " + context, e);
+ } finally {
+ if (sqlWatch != null) {
+ sqlWatch.stop(context.getSql());
+ }
+ watch.stop(log(context, result));
+ }
+ return result;
+ }
+
+ private String log(MeasureFilterContext context, MeasureFilterResult result) {
+ StringBuilder log = new StringBuilder();
+ log.append(SystemUtils.LINE_SEPARATOR);
+ log.append("request: ").append(context.getData()).append(SystemUtils.LINE_SEPARATOR);
+ log.append(" result: ").append(result.toString());
+ return log.toString();
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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.measure;
+
+import com.google.common.base.Strings;
+import org.apache.commons.dbutils.DbUtils;
+import org.apache.ibatis.session.SqlSession;
+import org.sonar.api.ServerComponent;
+import org.sonar.core.persistence.Database;
+import org.sonar.core.persistence.MyBatis;
+import org.sonar.core.resource.ResourceDao;
+
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.util.Collections;
+import java.util.List;
+
+public class MeasureFilterExecutor implements ServerComponent {
+
+ private MyBatis mybatis;
+ private Database database;
+ private ResourceDao resourceDao;
+
+ public MeasureFilterExecutor(MyBatis mybatis, Database database, ResourceDao resourceDao) {
+ this.mybatis = mybatis;
+ this.database = database;
+ this.resourceDao = resourceDao;
+ }
+
+ public List<MeasureFilterRow> execute(MeasureFilter filter, MeasureFilterContext context) throws SQLException {
+ if (filter.isEmpty()) {
+ return Collections.emptyList();
+ }
+
+ List<MeasureFilterRow> rows;
+ SqlSession session = null;
+ Connection connection = null;
+ try {
+ session = mybatis.openSession(false);
+ prepareContext(context, filter, session);
+
+ if (isValid(filter, context)) {
+ MeasureFilterSql sql = new MeasureFilterSql(database, filter, context);
+ context.setSql(sql.sql());
+ connection = session.getConnection();
+ rows = sql.execute(connection);
+ } else {
+ rows = Collections.emptyList();
+ }
+ } finally {
+ MyBatis.closeQuietly(session);
+ // connection is supposed to be closed by the session
+ DbUtils.closeQuietly(connection);
+ }
+
+ return rows;
+ }
+
+ private void prepareContext(MeasureFilterContext context, MeasureFilter filter, SqlSession session) {
+ if (filter.getBaseResourceKey() != null) {
+ context.setBaseSnapshot(resourceDao.getLastSnapshot(filter.getBaseResourceKey(), session));
+ }
+ }
+
+ static boolean isValid(MeasureFilter filter, MeasureFilterContext context) {
+ boolean valid = Strings.isNullOrEmpty(filter.getBaseResourceKey()) || context.getBaseSnapshot()!=null;
+ valid &= !(filter.isOnBaseResourceChildren() && context.getBaseSnapshot() == null);
+ valid &= !(filter.isOnFavourites() && context.getUserId() == null);
+ valid &= validateMeasureConditions(filter);
+ valid &= validateSort(filter);
+ return valid;
+ }
+
+ private static boolean validateMeasureConditions(MeasureFilter filter) {
+ boolean valid = true;
+ for (MeasureFilterCondition condition : filter.getMeasureConditions()) {
+ if (condition.period() != null && condition.period() < 1) {
+ valid = false;
+ }
+ if (condition.metric() == null) {
+ valid = false;
+ }
+ }
+ return valid;
+ }
+
+ private static boolean validateSort(MeasureFilter filter) {
+ boolean valid = true;
+ if (filter.sort().period() != null && filter.sort().period() < 1) {
+ valid = false;
+ }
+ if (filter.sort().onMeasures() && filter.sort().metric() == null) {
+ valid = false;
+ }
+ return valid;
+ }
+}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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.measure;
+
+import com.google.common.base.Function;
+import com.google.common.base.Joiner;
+import com.google.common.base.Strings;
+import com.google.common.collect.Lists;
+import org.apache.commons.lang.StringUtils;
+import org.sonar.api.ServerComponent;
+import org.sonar.api.measures.CoreMetrics;
+import org.sonar.api.measures.Metric;
+import org.sonar.api.measures.MetricFinder;
+import org.sonar.api.utils.DateUtils;
+import org.sonar.api.utils.System2;
+
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
+import java.util.Arrays;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+
+public class MeasureFilterFactory implements ServerComponent {
+
+ private final MetricFinder metricFinder;
+ private final System2 system;
+
+ public MeasureFilterFactory(MetricFinder metricFinder, System2 system) {
+ this.metricFinder = metricFinder;
+ this.system = system;
+ }
+
+ public MeasureFilter create(Map<String, Object> properties) {
+ MeasureFilter filter = new MeasureFilter();
+ filter.setBaseResourceKey((String) properties.get("base"));
+ filter.setResourceScopes(toList(properties.get("scopes")));
+ filter.setResourceQualifiers(toList(properties.get("qualifiers")));
+ MeasureFilterCondition condition = alertToCondition(toList(properties.get("alertLevels")));
+ if (condition != null) {
+ filter.addCondition(condition);
+ }
+ String onBaseComponents = (String) properties.get("onBaseComponents");
+ if (onBaseComponents != null) {
+ filter.setOnBaseResourceChildren(Boolean.valueOf(onBaseComponents));
+ }
+ filter.setResourceName((String) properties.get("nameSearch"));
+ filter.setResourceKey((String) properties.get("keySearch"));
+ String onFavourites = (String) properties.get("onFavourites");
+ if (onFavourites != null) {
+ filter.setUserFavourites(Boolean.valueOf(onFavourites));
+ }
+ fillDateConditions(filter, properties);
+ fillSorting(filter, properties);
+ fillMeasureConditions(properties, filter);
+ return filter;
+ }
+
+ private void fillDateConditions(MeasureFilter filter, Map<String, Object> properties) {
+ String fromDate = (String) properties.get("fromDate");
+ if (fromDate != null) {
+ filter.setFromDate(toDate(fromDate));
+ } else {
+ filter.setFromDate(toDays((String) properties.get("ageMaxDays")));
+ }
+ String toDate = (String) properties.get("toDate");
+ if (toDate != null) {
+ filter.setToDate(toDate(toDate));
+ } else {
+ filter.setToDate(toDays((String) properties.get("ageMinDays")));
+ }
+ }
+
+ private void fillMeasureConditions(Map<String, Object> properties, MeasureFilter filter) {
+ for (int index = 1; index <= 3; index++) {
+ MeasureFilterCondition condition = toCondition(properties, index);
+ if (condition != null) {
+ filter.addCondition(condition);
+ }
+ }
+ }
+
+ private void fillSorting(MeasureFilter filter, Map<String, Object> properties) {
+ String s = (String) properties.get("sort");
+ if (s != null) {
+ if (StringUtils.startsWith(s, "metric:")) {
+ String[] fields = StringUtils.split(s, ':');
+ Metric metric = metricFinder.findByKey(fields[1]);
+ if (metric != null) {
+ filter.setSortOnMetric(metric);
+ if (fields.length == 3) {
+ filter.setSortOnPeriod(Integer.parseInt(fields[2]));
+ }
+ }
+ } else {
+ filter.setSortOn(MeasureFilterSort.Field.valueOf(s.toUpperCase()));
+ }
+ }
+
+ if (properties.containsKey("asc")) {
+ filter.setSortAsc(Boolean.valueOf((String) properties.get("asc")));
+ }
+ }
+
+ @CheckForNull
+ private MeasureFilterCondition toCondition(Map<String, Object> props, int index) {
+ MeasureFilterCondition condition = null;
+ String metricKey = (String) props.get("c" + index + "_metric");
+ String op = (String) props.get("c" + index + "_op");
+ String val = (String) props.get("c" + index + "_val");
+ if (!Strings.isNullOrEmpty(metricKey) && !Strings.isNullOrEmpty(op) && !Strings.isNullOrEmpty(val)) {
+ Metric metric = metricFinder.findByKey(metricKey);
+ MeasureFilterCondition.Operator operator = MeasureFilterCondition.Operator.fromCode(op);
+ condition = new MeasureFilterCondition(metric, operator, Double.parseDouble(val));
+ String period = (String) props.get("c" + index + "_period");
+ if (period != null) {
+ condition.setPeriod(Integer.parseInt(period));
+ }
+ }
+ return condition;
+ }
+
+ @CheckForNull
+ private MeasureFilterCondition alertToCondition(List<String> alertLevels) {
+ if (alertLevels == null || alertLevels.isEmpty()) {
+ return null;
+ }
+ MeasureFilterCondition condition = null;
+ String metricKey = CoreMetrics.ALERT_STATUS_KEY;
+ String op = "in";
+ List<String> alertLevelsUppercase = Lists.transform(alertLevels, new Function<String, String>() {
+ @Override
+ public String apply(String input) {
+ return input != null ? input.toUpperCase() : "";
+ }
+ });
+ String val = "('" + Joiner.on("', '").join(alertLevelsUppercase) + "')";
+ if (!Strings.isNullOrEmpty(metricKey) && !Strings.isNullOrEmpty(op) && !Strings.isNullOrEmpty(val)) {
+ Metric metric = metricFinder.findByKey(metricKey);
+ MeasureFilterCondition.Operator operator = MeasureFilterCondition.Operator.fromCode(op);
+ condition = new MeasureFilterCondition(metric, operator, val);
+ }
+ return condition;
+ }
+
+ private List<String> toList(@Nullable Object obj) {
+ List<String> result = null;
+ if (obj != null) {
+ if (obj instanceof String) {
+ result = Arrays.asList((String) obj);
+ } else {
+ result = (List<String>) obj;
+ }
+ }
+ return result;
+ }
+
+ @CheckForNull
+ private Date toDate(@Nullable String date) {
+ if (date != null) {
+ return DateUtils.parseDate(date);
+ }
+ return null;
+ }
+
+ @CheckForNull
+ private Date toDays(@Nullable String s) {
+ if (s != null) {
+ int days = Integer.valueOf(s);
+ Date date = org.apache.commons.lang.time.DateUtils.truncate(new Date(system.now()), Calendar.DATE);
+ date = org.apache.commons.lang.time.DateUtils.addDays(date, -days);
+ return date;
+ }
+ return null;
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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.measure;
+
+import javax.annotation.Nullable;
+
+import java.util.List;
+
+public class MeasureFilterResult {
+
+ public static enum Error {
+ UNKNOWN, VALUE_SHOULD_BE_A_NUMBER
+ }
+
+ private List<MeasureFilterRow> rows = null;
+ private Error error = null;
+
+ MeasureFilterResult() {
+ }
+
+ public List<MeasureFilterRow> getRows() {
+ return rows;
+ }
+
+ public Error getError() {
+ return error;
+ }
+
+ MeasureFilterResult setRows(@Nullable List<MeasureFilterRow> rows) {
+ this.rows = rows;
+ return this;
+ }
+
+ MeasureFilterResult setError(@Nullable Error err) {
+ this.error = err;
+ return this;
+ }
+
+ public boolean isSuccess() {
+ return error == null;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ if (rows != null) {
+ sb.append(rows.size()).append(" rows, ");
+ }
+ if (error != null) {
+ sb.append("error=").append(error).append(", ");
+ }
+ return sb.toString();
+ }
+}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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.measure;
+
+import org.apache.commons.lang.StringUtils;
+
+import java.sql.Timestamp;
+
+public class MeasureFilterRow {
+ private final long snapshotId;
+ private final long resourceId;
+ private final long resourceRootId;
+ private String sortText = null;
+ private Timestamp sortDate = null;
+ private Double sortDouble = null;
+
+ MeasureFilterRow(long snapshotId, long resourceId, long resourceRootId) {
+ this.snapshotId = snapshotId;
+ this.resourceId = resourceId;
+ this.resourceRootId = resourceRootId;
+ }
+
+ public long getSnapshotId() {
+ return snapshotId;
+ }
+
+ public long getResourceId() {
+ return resourceId;
+ }
+
+ public long getResourceRootId() {
+ return resourceRootId;
+ }
+
+ public String getSortText() {
+ return sortText;
+ }
+
+ void setSortText(String s) {
+ this.sortText = StringUtils.defaultString(s);
+ }
+
+ Timestamp getSortDate() {
+ return sortDate;
+ }
+
+ void setSortDate(Timestamp sortDate) {
+ this.sortDate = sortDate;
+ }
+
+ Double getSortDouble() {
+ return sortDouble;
+ }
+
+ void setSortDouble(Double sortDouble) {
+ this.sortDouble = sortDouble;
+ }
+}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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.measure;
+
+import org.sonar.api.measures.CoreMetrics;
+import org.sonar.api.measures.Metric;
+
+class MeasureFilterSort {
+ public static enum Field {
+ KEY, NAME, VERSION, METRIC, SHORT_NAME, DESCRIPTION,
+ // Sort by last analysis date
+ DATE,
+ // Sort by project creation date
+ PROJECT_CREATION_DATE
+ }
+
+ private Field field = Field.NAME;
+ private Metric metric = null;
+ private Integer period = null;
+ private boolean asc = true;
+
+ MeasureFilterSort() {
+ }
+
+ void setField(Field field) {
+ this.field = field;
+ }
+
+ void setMetric(Metric metric) {
+ this.field = Field.METRIC;
+ this.metric = metric;
+ }
+
+ Integer period() {
+ return period;
+ }
+
+ void setPeriod(Integer period) {
+ this.period = period;
+ }
+
+ void setAsc(boolean asc) {
+ this.asc = asc;
+ }
+
+ public Field field() {
+ return field;
+ }
+
+ boolean onMeasures() {
+ return field == Field.METRIC;
+ }
+
+ Metric metric() {
+ return metric;
+ }
+
+ boolean isOnMeasure() {
+ return metric != null;
+ }
+
+ boolean isOnNumericMeasure() {
+ return metric != null && metric.isNumericType();
+ }
+
+ boolean isOnDate() {
+ return Field.DATE.equals(field) || Field.PROJECT_CREATION_DATE.equals(field);
+ }
+
+ boolean isOnAlert() {
+ return metric != null && metric.getKey().equals(CoreMetrics.ALERT_STATUS_KEY);
+ }
+
+ boolean isAsc() {
+ return asc;
+ }
+
+ String column() {
+ // only numeric metrics can be sorted by database, else results are sorted programmatically.
+ String column;
+ switch (field) {
+ case KEY:
+ column = "p.kee";
+ break;
+ case NAME:
+ column = "p.long_name";
+ break;
+ case SHORT_NAME:
+ column = "p.name";
+ break;
+ case DESCRIPTION:
+ column = "p.description";
+ break;
+ case VERSION:
+ column = "s.version";
+ break;
+ case DATE:
+ column = "s.created_at";
+ break;
+ case PROJECT_CREATION_DATE:
+ column = "p.created_at";
+ break;
+ case METRIC:
+ column = getMetricColumn();
+ break;
+ default:
+ throw new IllegalArgumentException("Unsupported sorting: " + field);
+ }
+ return column;
+ }
+
+ private String getMetricColumn(){
+ if (metric.isNumericType()) {
+ return period != null ? "pmsort.variation_value_" + period : "pmsort.value";
+ } else {
+ return "pmsort.text_value";
+ }
+ }
+}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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.measure;
+
+import com.google.common.base.Function;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Ordering;
+import org.apache.commons.dbutils.DbUtils;
+import org.apache.commons.lang.StringEscapeUtils;
+import org.apache.commons.lang.StringUtils;
+import org.sonar.core.persistence.Database;
+import org.sonar.core.persistence.dialect.MsSql;
+import org.sonar.core.persistence.dialect.Oracle;
+import org.sonar.core.resource.SnapshotDto;
+
+import javax.annotation.Nullable;
+
+import java.sql.*;
+import java.sql.Date;
+import java.util.*;
+
+class MeasureFilterSql {
+
+ private final Database database;
+ private final MeasureFilter filter;
+ private final MeasureFilterContext context;
+ private final String sql;
+ private final List<Date> dateParameters = Lists.newArrayList();
+
+ MeasureFilterSql(Database database, MeasureFilter filter, MeasureFilterContext context) {
+ this.database = database;
+ this.filter = filter;
+ this.context = context;
+ this.sql = generateSql();
+ }
+
+ List<MeasureFilterRow> execute(Connection connection) throws SQLException {
+ PreparedStatement statement = connection.prepareStatement(sql);
+ ResultSet rs = null;
+ try {
+ for (int index = 0; index < dateParameters.size(); index++) {
+ statement.setDate(index + 1, dateParameters.get(index));
+ }
+ rs = statement.executeQuery();
+ return process(rs);
+
+ } finally {
+ DbUtils.closeQuietly(rs);
+ DbUtils.closeQuietly(statement);
+ }
+ }
+
+ String sql() {
+ return sql;
+ }
+
+ private String generateSql() {
+ StringBuilder sb = new StringBuilder(1000);
+ sb.append("SELECT s.id, s.project_id, s.root_project_id, ");
+ sb.append(filter.sort().column());
+ sb.append(" FROM snapshots s INNER JOIN projects p ON s.project_id=p.id ");
+
+ for (int index = 0; index < filter.getMeasureConditions().size(); index++) {
+ MeasureFilterCondition condition = filter.getMeasureConditions().get(index);
+ sb.append(" INNER JOIN project_measures pmcond").append(index);
+ sb.append(" ON s.id=pmcond").append(index).append(".snapshot_id AND ");
+ condition.appendSqlCondition(sb, index);
+ }
+
+ if (filter.isOnFavourites()) {
+ sb.append(" INNER JOIN properties props ON props.resource_id=s.project_id ");
+ }
+
+ if (filter.sort().isOnMeasure()) {
+ sb.append(" LEFT OUTER JOIN project_measures pmsort ON s.id=pmsort.snapshot_id AND pmsort.metric_id=");
+ sb.append(filter.sort().metric().getId());
+ sb.append(" AND pmsort.rule_id IS NULL AND pmsort.rule_priority IS NULL AND pmsort.characteristic_id IS NULL AND pmsort.person_id IS NULL ");
+ }
+
+ sb.append(" WHERE ");
+ appendResourceConditions(sb);
+
+ for (int index = 0; index < filter.getMeasureConditions().size(); index++) {
+ MeasureFilterCondition condition = filter.getMeasureConditions().get(index);
+ sb.append(" AND ");
+ condition.appendSqlCondition(sb, index);
+ }
+
+ return sb.toString();
+ }
+
+ private void appendResourceConditions(StringBuilder sb) {
+ sb.append(" s.status='P' AND s.islast=").append(database.getDialect().getTrueSqlValue());
+ if (context.getBaseSnapshot() == null) {
+ sb.append(" AND p.copy_resource_id IS NULL ");
+ }
+ if (!filter.getResourceQualifiers().isEmpty()) {
+ sb.append(" AND s.qualifier IN ");
+ appendInStatement(filter.getResourceQualifiers(), sb);
+ }
+ if (!filter.getResourceScopes().isEmpty()) {
+ sb.append(" AND s.scope IN ");
+ appendInStatement(filter.getResourceScopes(), sb);
+ }
+ appendDateConditions(sb);
+ appendFavouritesCondition(sb);
+ appendResourceNameCondition(sb);
+ appendResourceKeyCondition(sb);
+ appendResourceBaseCondition(sb);
+ }
+
+ private void appendDateConditions(StringBuilder sb) {
+ java.util.Date fromDate = filter.getFromDate();
+ if (fromDate != null) {
+ sb.append(" AND s.created_at >= ? ");
+ dateParameters.add(new Date(fromDate.getTime()));
+ }
+ java.util.Date toDate = filter.getToDate();
+ if (toDate != null) {
+ sb.append(" AND s.created_at <= ? ");
+ dateParameters.add(new Date(toDate.getTime()));
+ }
+ }
+
+ private void appendFavouritesCondition(StringBuilder sb) {
+ if (filter.isOnFavourites()) {
+ sb.append(" AND props.prop_key='favourite' AND props.resource_id IS NOT NULL AND props.user_id=");
+ sb.append(context.getUserId());
+ sb.append(" ");
+ }
+ }
+
+ private void appendResourceBaseCondition(StringBuilder sb) {
+ SnapshotDto baseSnapshot = context.getBaseSnapshot();
+ if (baseSnapshot != null) {
+ if (filter.isOnBaseResourceChildren()) {
+ sb.append(" AND s.parent_snapshot_id=").append(baseSnapshot.getId());
+ } else {
+ Long rootSnapshotId = baseSnapshot.getRootId() != null ? baseSnapshot.getRootId() : baseSnapshot.getId();
+ sb.append(" AND s.root_snapshot_id=").append(rootSnapshotId);
+ sb.append(" AND s.path LIKE '").append(StringUtils.defaultString(baseSnapshot.getPath())).append(baseSnapshot.getId()).append(".%'");
+ }
+ }
+ }
+
+ private void appendResourceKeyCondition(StringBuilder sb) {
+ if (StringUtils.isNotBlank(filter.getResourceKey())) {
+ sb.append(" AND UPPER(p.kee) LIKE '%");
+ sb.append(escapePercentAndUnderscrore(StringEscapeUtils.escapeSql(StringUtils.upperCase(filter.getResourceKey()))));
+ sb.append("%'");
+ appendEscapeForSomeDb(sb);
+ }
+ }
+
+ private void appendResourceNameCondition(StringBuilder sb) {
+ if (StringUtils.isNotBlank(filter.getResourceName())) {
+ sb.append(" AND s.project_id IN (SELECT rindex.resource_id FROM resource_index rindex WHERE rindex.kee LIKE '");
+ sb.append(escapePercentAndUnderscrore(StringEscapeUtils.escapeSql(StringUtils.lowerCase(filter.getResourceName()))));
+ sb.append("%'");
+ appendEscapeForSomeDb(sb);
+ if (!filter.getResourceQualifiers().isEmpty()) {
+ sb.append(" AND rindex.qualifier IN ");
+ appendInStatement(filter.getResourceQualifiers(), sb);
+ }
+ sb.append(") ");
+ }
+ }
+
+ List<MeasureFilterRow> process(ResultSet rs) throws SQLException {
+ List<MeasureFilterRow> rows = Lists.newArrayList();
+ RowProcessor rowProcessor;
+ if (filter.sort().isOnNumericMeasure()) {
+ rowProcessor = new NumericSortRowProcessor();
+ } else if (filter.sort().isOnDate()) {
+ rowProcessor = new DateSortRowProcessor();
+ } else if (filter.sort().isOnAlert()) {
+ rowProcessor = new AlertSortRowProcessor();
+ } else {
+ rowProcessor = new TextSortRowProcessor();
+ }
+
+ while (rs.next()) {
+ rows.add(rowProcessor.fetch(rs));
+ }
+
+ return rowProcessor.sort(rows, filter.sort().isAsc());
+ }
+
+ private static void appendInStatement(List<String> values, StringBuilder to) {
+ to.append(" (");
+ for (int i = 0; i < values.size(); i++) {
+ if (i > 0) {
+ to.append(",");
+ }
+ to.append("'");
+ to.append(StringEscapeUtils.escapeSql(values.get(i)));
+ to.append("'");
+ }
+ to.append(") ");
+ }
+
+ /**
+ * Replace escape percent and underscore by adding a slash just before
+ */
+ private String escapePercentAndUnderscrore(String value){
+ return value.replaceAll("%", "\\\\%").replaceAll("_", "\\\\_");
+ }
+
+ private void appendEscapeForSomeDb(StringBuilder sb){
+ if (database.getDialect().getId().equals(Oracle.ID) || database.getDialect().getId().equals(MsSql.ID)) {
+ sb.append(" ESCAPE '\\'");
+ }
+ }
+
+ abstract static class RowProcessor {
+ abstract Function sortFieldFunction();
+
+ abstract Ordering sortFieldOrdering(boolean ascending);
+
+ abstract MeasureFilterRow fetch(ResultSet rs) throws SQLException;
+
+ final List<MeasureFilterRow> sort(List<MeasureFilterRow> rows, boolean ascending) {
+ Ordering<MeasureFilterRow> ordering = sortFieldOrdering(ascending).onResultOf(sortFieldFunction());
+ return ordering.immutableSortedCopy(rows);
+ }
+ }
+
+ static class TextSortRowProcessor extends RowProcessor {
+ MeasureFilterRow fetch(ResultSet rs) throws SQLException {
+ MeasureFilterRow row = new MeasureFilterRow(rs.getLong(1), rs.getLong(2), rs.getLong(3));
+ row.setSortText(rs.getString(4));
+ return row;
+ }
+
+ Function sortFieldFunction() {
+ return new Function<MeasureFilterRow, String>() {
+ public String apply(MeasureFilterRow row) {
+ return row.getSortText();
+ }
+ };
+ }
+
+ Ordering sortFieldOrdering(boolean ascending) {
+ Ordering<String> ordering = Ordering.from(String.CASE_INSENSITIVE_ORDER);
+ if (!ascending) {
+ ordering = ordering.reverse();
+ }
+ return ordering;
+ }
+ }
+
+ static class AlertSortRowProcessor extends TextSortRowProcessor {
+ Function sortFieldFunction() {
+ return new Function<MeasureFilterRow, Integer>() {
+ public Integer apply(MeasureFilterRow row) {
+ return ImmutableList.of("OK", "WARN", "ERROR").indexOf(row.getSortText());
+ }
+ };
+ }
+
+ @Override
+ Ordering sortFieldOrdering(boolean ascending) {
+ Ordering<Integer> ordering = Ordering.<Integer>natural().nullsLast();
+ if (!ascending) {
+ ordering = ordering.reverse();
+ }
+ return ordering;
+ }
+ }
+
+ static class NumericSortRowProcessor extends RowProcessor {
+ MeasureFilterRow fetch(ResultSet rs) throws SQLException {
+ MeasureFilterRow row = new MeasureFilterRow(rs.getLong(1), rs.getLong(2), rs.getLong(3));
+ double value = rs.getDouble(4);
+ if (!rs.wasNull()) {
+ row.setSortDouble(value);
+ }
+ return row;
+ }
+
+ Function sortFieldFunction() {
+ return new Function<MeasureFilterRow, Double>() {
+ public Double apply(MeasureFilterRow row) {
+ return row.getSortDouble();
+ }
+ };
+ }
+
+ Ordering sortFieldOrdering(boolean ascending) {
+ return ascending ? Ordering.natural().nullsLast() : Ordering.natural().reverse().nullsLast();
+ }
+ }
+
+ static class DateSortRowProcessor extends RowProcessor {
+ MeasureFilterRow fetch(ResultSet rs) throws SQLException {
+ MeasureFilterRow row = new MeasureFilterRow(rs.getLong(1), rs.getLong(2), rs.getLong(3));
+ row.setSortDate(rs.getTimestamp(4));
+ return row;
+ }
+
+ Function sortFieldFunction() {
+ return new Function<MeasureFilterRow, Timestamp>() {
+ public Timestamp apply(MeasureFilterRow row) {
+ return row.getSortDate();
+ }
+ };
+ }
+
+ Ordering sortFieldOrdering(boolean ascending) {
+ return newObjectOrdering(ascending);
+ }
+ }
+
+ private static Ordering newObjectOrdering(boolean ascending) {
+ if (ascending) {
+ return Ordering.from(new Comparator<Comparable>() {
+ public int compare(@Nullable Comparable left, @Nullable Comparable right) {
+ if (left == null) {
+ return 1;
+ }
+ if (right == null) {
+ return -1;
+ }
+
+ return left.compareTo(right);
+ }
+ });
+ }
+ return Ordering.from(new Comparator<Comparable>() {
+ public int compare(@Nullable Comparable left, @Nullable Comparable right) {
+ if (left == null) {
+ return 1;
+ }
+ if (right == null) {
+ return -1;
+ }
+
+ return -left.compareTo(right);
+ }
+ });
+ }
+}
+
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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.measure;
+
+import javax.annotation.ParametersAreNonnullByDefault;
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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.measure.ws;
+
+import javax.annotation.ParametersAreNonnullByDefault;
import org.sonar.core.issue.IssueUpdater;
import org.sonar.core.issue.workflow.FunctionExecutor;
import org.sonar.core.issue.workflow.IssueWorkflow;
-import org.sonar.core.measure.MeasureFilterEngine;
-import org.sonar.core.measure.MeasureFilterExecutor;
-import org.sonar.core.measure.MeasureFilterFactory;
+import org.sonar.core.measure.db.MeasureFilterDao;
+import org.sonar.server.measure.MeasureFilterEngine;
+import org.sonar.server.measure.MeasureFilterExecutor;
+import org.sonar.server.measure.MeasureFilterFactory;
import org.sonar.core.metric.DefaultMetricFinder;
import org.sonar.core.notification.DefaultNotificationManager;
import org.sonar.core.permission.PermissionFacade;
System2.INSTANCE,
RuleDao.class,
ActiveRuleDao.class,
- DbClient.class
- ));
+ DbClient.class,
+ MeasureFilterDao.class
+ ));
components.addAll(CorePropertyDefinitions.all());
components.addAll(DatabaseMigrations.CLASSES);
components.addAll(DaoUtils.getDaoClasses());
import org.sonar.api.test.Testable;
import org.sonar.api.web.*;
import org.sonar.core.component.SnapshotPerspectives;
-import org.sonar.core.measure.MeasureFilterEngine;
-import org.sonar.core.measure.MeasureFilterResult;
+import org.sonar.server.measure.MeasureFilterEngine;
+import org.sonar.server.measure.MeasureFilterResult;
import org.sonar.core.persistence.Database;
import org.sonar.core.preview.PreviewCache;
import org.sonar.core.purge.PurgeDao;
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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.measure;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.sonar.api.measures.Metric;
+
+import static org.fest.assertions.Assertions.assertThat;
+
+public class MeasureFilterConditionTest {
+ @Rule
+ public ExpectedException thrown = ExpectedException.none();
+
+ @Test
+ public void create_operator_from_code() {
+ assertThat(MeasureFilterCondition.Operator.fromCode("eq")).isEqualTo(MeasureFilterCondition.Operator.EQUALS);
+ assertThat(MeasureFilterCondition.Operator.fromCode("lte")).isEqualTo(MeasureFilterCondition.Operator.LESS_OR_EQUALS);
+ }
+
+ @Test
+ public void fail_if_operator_code_not_found() {
+ thrown.expect(IllegalArgumentException.class);
+ MeasureFilterCondition.Operator.fromCode("xxx");
+ }
+
+ @Test
+ public void operator_sql() {
+ assertThat(MeasureFilterCondition.Operator.EQUALS.getSql()).isEqualTo("=");
+ assertThat(MeasureFilterCondition.Operator.LESS_OR_EQUALS.getSql()).isEqualTo("<=");
+ assertThat(MeasureFilterCondition.Operator.GREATER.getSql()).isEqualTo(">");
+ }
+
+ @Test
+ public void value_condition() {
+ Metric ncloc = new Metric.Builder("ncloc", "NCLOC", Metric.ValueType.INT).create();
+ ncloc.setId(123);
+ MeasureFilterCondition condition = new MeasureFilterCondition(ncloc, MeasureFilterCondition.Operator.GREATER, 10.0);
+
+ assertThat(condition.metric()).isEqualTo(ncloc);
+ assertThat(condition.operator()).isEqualTo(MeasureFilterCondition.Operator.GREATER);
+ assertThat(condition.period()).isNull();
+ assertThat(condition.value()).isEqualTo(10.0);
+ assertThat(condition.textValue()).isNull();
+ assertThat(condition.appendSqlColumn(new StringBuilder(), 1).toString()).isEqualTo("pmcond1.value");
+ assertThat(condition.toString()).isNotEmpty();
+ assertThat(condition.appendSqlCondition(new StringBuilder(), 1).toString()).isEqualTo(" pmcond1.metric_id=123 AND pmcond1.value > 10.0 AND pmcond1.rule_id IS NULL AND pmcond1.rule_priority IS NULL AND pmcond1.characteristic_id IS NULL AND pmcond1.person_id IS NULL ");
+ }
+
+ @Test
+ public void variation_condition() {
+ Metric ncloc = new Metric.Builder("ncloc", "NCLOC", Metric.ValueType.INT).create();
+ ncloc.setId(123);
+ MeasureFilterCondition condition = new MeasureFilterCondition(ncloc, MeasureFilterCondition.Operator.LESS_OR_EQUALS, 10.0);
+ condition.setPeriod(3);
+
+ assertThat(condition.metric()).isEqualTo(ncloc);
+ assertThat(condition.operator()).isEqualTo(MeasureFilterCondition.Operator.LESS_OR_EQUALS);
+ assertThat(condition.period()).isEqualTo(3);
+ assertThat(condition.value()).isEqualTo(10.0);
+ assertThat(condition.appendSqlColumn(new StringBuilder(), 2).toString()).isEqualTo("pmcond2.variation_value_3");
+ assertThat(condition.toString()).isNotEmpty();
+ assertThat(condition.appendSqlCondition(new StringBuilder(), 2).toString()).isEqualTo(" pmcond2.metric_id=123 AND pmcond2.variation_value_3 <= 10.0 AND pmcond2.rule_id IS NULL AND pmcond2.rule_priority IS NULL AND pmcond2.characteristic_id IS NULL AND pmcond2.person_id IS NULL ");
+ }
+
+ @Test
+ public void text_value_condition() {
+ Metric ncloc = new Metric.Builder("ncloc", "NCLOC", Metric.ValueType.INT).create();
+ ncloc.setId(123);
+ MeasureFilterCondition condition = new MeasureFilterCondition(ncloc, MeasureFilterCondition.Operator.EQUALS, "\"foo\"");
+
+ assertThat(condition.metric()).isEqualTo(ncloc);
+ assertThat(condition.operator()).isEqualTo(MeasureFilterCondition.Operator.EQUALS);
+ assertThat(condition.period()).isNull();
+ assertThat(condition.value()).isEqualTo(0);
+ assertThat(condition.textValue()).isEqualTo("\"foo\"");
+ assertThat(condition.appendSqlColumn(new StringBuilder(), 1).toString()).isEqualTo("pmcond1.text_value");
+ assertThat(condition.toString()).isNotEmpty();
+ assertThat(condition.appendSqlCondition(new StringBuilder(), 1).toString()).isEqualTo(" pmcond1.metric_id=123 AND pmcond1.text_value = \"foo\" AND pmcond1.rule_id IS NULL AND pmcond1.rule_priority IS NULL AND pmcond1.characteristic_id IS NULL AND pmcond1.person_id IS NULL ");
+ }
+}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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.measure;
+
+import org.junit.Test;
+
+import static org.fest.assertions.Assertions.assertThat;
+
+public class MeasureFilterContextTest {
+ @Test
+ public void test_empty_toString() {
+ MeasureFilterContext context = new MeasureFilterContext();
+ assertThat(context.toString()).isNotEmpty();
+ }
+
+ @Test
+ public void test_toString() {
+ MeasureFilterContext context = new MeasureFilterContext();
+ context.setData("{qualifiers=TRK}");
+ context.setSql("SELECT *");
+ context.setUserId(50L);
+ assertThat(context.toString()).isEqualTo("MeasureFilterContext[filter={qualifiers=TRK},sql=SELECT *,user=50]");
+ }
+}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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.measure;
+
+import com.google.common.collect.ImmutableMap;
+import org.hamcrest.BaseMatcher;
+import org.hamcrest.Description;
+import org.junit.Test;
+import org.sonar.api.config.Settings;
+import org.sonar.core.profiling.Profiling;
+
+import java.util.Map;
+
+import static org.fest.assertions.Assertions.assertThat;
+import static org.mockito.Matchers.argThat;
+import static org.mockito.Matchers.refEq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+public class MeasureFilterEngineTest {
+
+ @Test
+ public void should_create_and_execute_filter() throws Exception {
+ Map<String, Object> filterMap = ImmutableMap.of("qualifiers", (Object) "TRK");
+ MeasureFilterFactory factory = mock(MeasureFilterFactory.class);
+ MeasureFilter filter = new MeasureFilter();
+ when(factory.create(filterMap)).thenReturn(filter);
+ MeasureFilterExecutor executor = mock(MeasureFilterExecutor.class);
+
+ MeasureFilterEngine engine = new MeasureFilterEngine(factory, executor, new Profiling(new Settings()));
+
+ final long userId = 50L;
+ engine.execute(filterMap, userId);
+ verify(executor).execute(refEq(filter), argThat(new BaseMatcher<MeasureFilterContext>() {
+ public boolean matches(Object o) {
+ MeasureFilterContext context = (MeasureFilterContext) o;
+ return "{qualifiers=TRK}".equals(context.getData()) && context.getUserId() == userId;
+ }
+
+ public void describeTo(Description description) {
+ }
+ }));
+ }
+
+ @Test
+ public void keep_error_but_do_not_fail() throws Exception {
+ Map<String, Object> filterMap = ImmutableMap.of("qualifiers", (Object) "TRK");
+ MeasureFilterFactory factory = mock(MeasureFilterFactory.class);
+ when(factory.create(filterMap)).thenThrow(new IllegalArgumentException());
+ MeasureFilterExecutor executor = mock(MeasureFilterExecutor.class);
+
+ MeasureFilterEngine engine = new MeasureFilterEngine(factory, executor, new Profiling(new Settings()));
+ MeasureFilterResult result = engine.execute(filterMap, 50L);
+
+ assertThat(result.isSuccess()).isFalse();
+ assertThat(result.getError()).isEqualTo(MeasureFilterResult.Error.UNKNOWN);
+ assertThat(result.getRows()).isNull();
+ }
+}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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.measure;
+
+import org.junit.Before;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.sonar.api.measures.CoreMetrics;
+import org.sonar.api.measures.Metric;
+import org.sonar.api.utils.DateUtils;
+import org.sonar.core.persistence.TestDatabase;
+import org.sonar.core.resource.ResourceDao;
+import org.sonar.core.resource.SnapshotDto;
+
+import java.sql.SQLException;
+import java.util.Arrays;
+import java.util.List;
+
+import static com.google.common.collect.Lists.newArrayList;
+import static org.fest.assertions.Assertions.assertThat;
+
+public class MeasureFilterExecutorTest {
+ private static final long JAVA_PROJECT_ID = 1L;
+ private static final long JAVA_FILE_BIG_ID = 3L;
+ private static final long JAVA_FILE_TINY_ID = 4L;
+ private static final long JAVA_PROJECT_SNAPSHOT_ID = 101L;
+ private static final long JAVA_FILE_BIG_SNAPSHOT_ID = 103L;
+ private static final long JAVA_FILE_TINY_SNAPSHOT_ID = 104L;
+ private static final long JAVA_PACKAGE_SNAPSHOT_ID = 102L;
+ private static final long PHP_PROJECT_ID = 10L;
+ private static final long PHP_SNAPSHOT_ID = 110L;
+ private static final Metric METRIC_LINES = new Metric.Builder("lines", "Lines", Metric.ValueType.INT).create().setId(1);
+ private static final Metric METRIC_PROFILE = new Metric.Builder("profile", "Profile", Metric.ValueType.STRING).create().setId(2);
+ private static final Metric METRIC_COVERAGE = new Metric.Builder("coverage", "Coverage", Metric.ValueType.FLOAT).create().setId(3);
+ private static final Metric METRIC_UNKNOWN = new Metric.Builder("unknown", "Unknown", Metric.ValueType.FLOAT).create().setId(4);
+
+ private MeasureFilterExecutor executor;
+
+ @ClassRule
+ public static TestDatabase db = new TestDatabase();
+
+ @Before
+ public void before() {
+ executor = new MeasureFilterExecutor(db.myBatis(), db.database(), new ResourceDao(db.myBatis()));
+ }
+
+ @Test
+ public void should_return_empty_results_if_empty_filter() throws SQLException {
+ db.prepareDbUnit(getClass(), "shared.xml");
+ MeasureFilter filter = new MeasureFilter();
+ assertThat(filter.isEmpty()).isTrue();
+
+ assertThat(executor.execute(filter, new MeasureFilterContext())).isEmpty();
+ }
+
+ @Test
+ public void invalid_filter_should_not_return_results() throws SQLException {
+ db.prepareDbUnit(getClass(), "shared.xml");
+ MeasureFilter filter = new MeasureFilter().setUserFavourites(true);
+ // anonymous user does not have favourites
+ assertThat(executor.execute(filter, new MeasureFilterContext())).isEmpty();
+ }
+
+ @Test
+ public void filter_is_not_valid_if_missing_base_snapshot() {
+ db.prepareDbUnit(getClass(), "shared.xml");
+ MeasureFilterContext context = new MeasureFilterContext();
+ MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK")).setOnBaseResourceChildren(true);
+ assertThat(MeasureFilterExecutor.isValid(filter, context)).isFalse();
+
+ context.setBaseSnapshot(new SnapshotDto().setId(123L));
+ assertThat(MeasureFilterExecutor.isValid(filter, context)).isTrue();
+ }
+
+ @Test
+ public void filter_is_not_valid_if_condition_on_unknown_metric() {
+ db.prepareDbUnit(getClass(), "shared.xml");
+ MeasureFilterContext context = new MeasureFilterContext();
+ MeasureFilter filter = new MeasureFilter().addCondition(new MeasureFilterCondition(null, MeasureFilterCondition.Operator.LESS, 3.0));
+ assertThat(MeasureFilterExecutor.isValid(filter, context)).isFalse();
+ }
+
+ @Test
+ public void filter_is_not_valid_if_sorting_on_unknown_metric() {
+ db.prepareDbUnit(getClass(), "shared.xml");
+ MeasureFilterContext context = new MeasureFilterContext();
+ MeasureFilter filter = new MeasureFilter().setSortOnMetric(null);
+ assertThat(MeasureFilterExecutor.isValid(filter, context)).isFalse();
+ }
+
+ @Test
+ public void filter_is_not_valid_if_anonymous_favourites() {
+ db.prepareDbUnit(getClass(), "shared.xml");
+ MeasureFilterContext context = new MeasureFilterContext();
+ MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK")).setUserFavourites(true);
+ assertThat(MeasureFilterExecutor.isValid(filter, context)).isFalse();
+
+ context.setUserId(123L);
+ assertThat(MeasureFilterExecutor.isValid(filter, context)).isTrue();
+ }
+
+ @Test
+ public void projects_without_measure_conditions() throws SQLException {
+ db.prepareDbUnit(getClass(), "shared.xml");
+ MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK")).setSortOn(MeasureFilterSort.Field.DATE);
+ List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
+
+ assertThat(rows).hasSize(2);
+ verifyJavaProject(rows.get(0));
+ verifyPhpProject(rows.get(1));
+ }
+
+ @Test
+ public void should_prevent_sql_injection_through_parameters() throws SQLException {
+ db.prepareDbUnit(getClass(), "shared.xml");
+ MeasureFilter filter = new MeasureFilter()
+ .setResourceQualifiers(Arrays.asList("'"))
+ .setBaseResourceKey("'")
+ .setResourceKey("'")
+ .setResourceName("'")
+ .setResourceName("'")
+ .setResourceScopes(Arrays.asList("'"));
+ List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
+ // an exception would be thrown if SQL is not valid
+ assertThat(rows).isEmpty();
+ }
+
+ @Test
+ public void test_default_sort() {
+ db.prepareDbUnit(getClass(), "shared.xml");
+ MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("CLA"));
+
+ assertThat(filter.sort().isAsc()).isTrue();
+ assertThat(filter.sort().field()).isEqualTo(MeasureFilterSort.Field.NAME);
+ assertThat(filter.sort().metric()).isNull();
+ }
+
+ @Test
+ public void sort_by_ascending_resource_name() throws SQLException {
+ db.prepareDbUnit(getClass(), "shared.xml");
+ MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("CLA")).setSortAsc(true);
+ List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
+
+ // Big -> Tiny
+ assertThat(rows).hasSize(2);
+ verifyJavaBigFile(rows.get(0));
+ verifyJavaTinyFile(rows.get(1));
+ }
+
+ @Test
+ public void sort_by_ascending_resource_key() throws SQLException {
+ db.prepareDbUnit(getClass(), "shared.xml");
+ MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("CLA")).setSortAsc(true).setSortOn(MeasureFilterSort.Field.KEY);
+ List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
+
+ // Big -> Tiny
+ assertThat(rows).hasSize(2);
+ verifyJavaBigFile(rows.get(0));
+ verifyJavaTinyFile(rows.get(1));
+ }
+
+ @Test
+ public void sort_by_ascending_resource_version() throws SQLException {
+ db.prepareDbUnit(getClass(), "shared.xml");
+ MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK")).setSortAsc(true).setSortOn(MeasureFilterSort.Field.VERSION);
+ List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
+
+ // Java Project 1.0 then Php Project 3.0
+ assertThat(rows).hasSize(2);
+ verifyJavaProject(rows.get(0));
+ verifyPhpProject(rows.get(1));
+ }
+
+ @Test
+ public void sort_by_descending_resource_name() throws SQLException {
+ db.prepareDbUnit(getClass(), "shared.xml");
+ MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("CLA")).setSortAsc(false);
+ List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
+
+ // Tiny -> Big
+ assertThat(rows).hasSize(2);
+ verifyJavaTinyFile(rows.get(0));
+ verifyJavaBigFile(rows.get(1));
+ }
+
+ @Test
+ public void sort_by_ascending_text_measure() throws SQLException {
+ db.prepareDbUnit(getClass(), "shared.xml");
+ MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK")).setSortOnMetric(METRIC_PROFILE);
+ List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
+
+ assertThat(rows).hasSize(2);
+ verifyPhpProject(rows.get(0));//php way
+ verifyJavaProject(rows.get(1));// Sonar way
+ }
+
+ @Test
+ public void sort_by_descending_text_measure() throws SQLException {
+ db.prepareDbUnit(getClass(), "shared.xml");
+ MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK")).setSortOnMetric(METRIC_PROFILE).setSortAsc(false);
+ List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
+
+ assertThat(rows).hasSize(2);
+ verifyJavaProject(rows.get(0));// Sonar way
+ verifyPhpProject(rows.get(1));//php way
+ }
+
+ @Test
+ public void sort_by_missing_text_measure() throws SQLException {
+ db.prepareDbUnit(getClass(), "shared.xml");
+ // the metric 'profile' is not set on files
+ MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("CLA")).setSortOnMetric(METRIC_PROFILE);
+ List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
+
+ assertThat(rows).hasSize(2);//2 files randomly sorted
+ }
+
+ @Test
+ public void sort_by_ascending_numeric_measure() throws SQLException {
+ db.prepareDbUnit(getClass(), "shared.xml");
+ MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("CLA")).setSortOnMetric(METRIC_LINES);
+ List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
+
+ // Tiny -> Big
+ assertThat(rows).hasSize(2);
+ verifyJavaTinyFile(rows.get(0));
+ verifyJavaBigFile(rows.get(1));
+ }
+
+ @Test
+ public void sort_by_descending_numeric_measure() throws SQLException {
+ db.prepareDbUnit(getClass(), "shared.xml");
+ MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("CLA")).setSortOnMetric(METRIC_LINES).setSortAsc(false);
+ List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
+
+ // Big -> Tiny
+ assertThat(rows).hasSize(2);
+ verifyJavaBigFile(rows.get(0));
+ verifyJavaTinyFile(rows.get(1));
+ }
+
+ @Test
+ public void null_measures_are_ordered_after_descending_numeric_measures() throws SQLException {
+ db.prepareDbUnit(getClass(), "shared.xml");
+ MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK"))
+ .setSortOnMetric(METRIC_COVERAGE).setSortAsc(false);
+ List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
+
+ // Java project has coverage but not PHP
+ assertThat(rows).hasSize(2);
+ verifyJavaProject(rows.get(0));
+ verifyPhpProject(rows.get(1));
+ }
+
+ @Test
+ public void null_measures_are_ordered_after_ascending_numeric_measures() throws SQLException {
+ db.prepareDbUnit(getClass(), "shared.xml");
+ MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK"))
+ .setSortOnMetric(METRIC_COVERAGE).setSortAsc(true);
+ List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
+
+ // Java project has coverage but not PHP
+ assertThat(rows).hasSize(2);
+ verifyJavaProject(rows.get(0));
+ verifyPhpProject(rows.get(1));
+ }
+
+ @Test
+ public void sort_by_missing_numeric_measure() throws SQLException {
+ db.prepareDbUnit(getClass(), "shared.xml");
+ // coverage measures are not computed
+ MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("CLA")).setSortOnMetric(METRIC_UNKNOWN);
+ List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
+
+ // 2 files, random order
+ assertThat(rows).hasSize(2);
+ }
+
+ @Test
+ public void sort_by_ascending_variation() throws SQLException {
+ db.prepareDbUnit(getClass(), "shared.xml");
+ MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK")).setSortOnMetric(METRIC_LINES).setSortOnPeriod(5);
+ List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
+
+ assertThat(rows).hasSize(2);
+ verifyJavaProject(rows.get(0));// +400
+ verifyPhpProject(rows.get(1));// +4900
+ }
+
+ @Test
+ public void sort_by_descending_variation() throws SQLException {
+ db.prepareDbUnit(getClass(), "shared.xml");
+ MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK"))
+ .setSortOnMetric(METRIC_LINES).setSortOnPeriod(5).setSortAsc(false);
+ List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
+
+ assertThat(rows).hasSize(2);
+ verifyPhpProject(rows.get(0));// +4900
+ verifyJavaProject(rows.get(1));// +400
+ }
+
+ @Test
+ public void sort_by_ascending_date() throws SQLException {
+ db.prepareDbUnit(getClass(), "shared.xml");
+ MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK")).setSortOn(MeasureFilterSort.Field.DATE);
+ List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
+
+ verifyJavaProject(rows.get(0));// 2008
+ verifyPhpProject(rows.get(1));// 2012
+ }
+
+ @Test
+ public void sort_by_descending_date() throws SQLException {
+ db.prepareDbUnit(getClass(), "shared.xml");
+ MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK")).setSortOn(MeasureFilterSort.Field.DATE).setSortAsc(false);
+ List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
+
+ verifyPhpProject(rows.get(0));// 2012
+ verifyJavaProject(rows.get(1));// 2008
+ }
+
+ @Test
+ public void sort_by_ascending_created_at() throws SQLException {
+ db.prepareDbUnit(getClass(), "shared.xml");
+ MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK")).setSortOn(MeasureFilterSort.Field.PROJECT_CREATION_DATE);
+ List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
+
+ verifyJavaProject(rows.get(0));// 2008
+ assertThat(DateUtils.formatDate(rows.get(0).getSortDate())).isEqualTo("2008-12-19");
+ verifyPhpProject(rows.get(1));// 2012
+ assertThat(DateUtils.formatDate(rows.get(1).getSortDate())).isEqualTo("2012-12-12");
+ }
+
+ @Test
+ public void sort_by_descending_created_at() throws SQLException {
+ db.prepareDbUnit(getClass(), "shared.xml");
+ MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK")).setSortOn(MeasureFilterSort.Field.PROJECT_CREATION_DATE).setSortAsc(false);
+ List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
+
+ verifyPhpProject(rows.get(0));// 2012
+ assertThat(DateUtils.formatDate(rows.get(0).getSortDate())).isEqualTo("2012-12-12");
+ verifyJavaProject(rows.get(1));// 2008
+ assertThat(DateUtils.formatDate(rows.get(1).getSortDate())).isEqualTo("2008-12-19");
+ }
+
+ @Test
+ public void sort_by_ascending_alert() throws SQLException {
+ db.prepareDbUnit(getClass(), "sort_by_alert.xml");
+
+ Metric alert = new Metric.Builder(CoreMetrics.ALERT_STATUS_KEY, "Alert", Metric.ValueType.LEVEL).create().setId(5);
+ MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK")).setSortOnMetric(alert);
+ List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
+
+ // Php Project OK, Java Project WARN then Js Project ERROR
+ assertThat(rows).hasSize(3);
+ verifyPhpProject(rows.get(0));
+ verifyJavaProject(rows.get(1));
+ verifyProject(rows.get(2), 120L, 20L, 20L);
+ }
+
+ @Test
+ public void sort_by_descending_alert() throws SQLException {
+ db.prepareDbUnit(getClass(), "sort_by_alert.xml");
+
+ Metric alert = new Metric.Builder(CoreMetrics.ALERT_STATUS_KEY, "Alert", Metric.ValueType.LEVEL).create().setId(5);
+ MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK")).setSortOnMetric(alert).setSortAsc(false);
+ List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
+
+ // Js Project ERROR, Java Project WARN, then Php Project OK
+ assertThat(rows).hasSize(3);
+ verifyProject(rows.get(0), 120L, 20L, 20L);
+ verifyJavaProject(rows.get(1));
+ verifyPhpProject(rows.get(2));
+ }
+
+ @Test
+ public void condition_on_numeric_measure() throws SQLException {
+ db.prepareDbUnit(getClass(), "shared.xml");
+ MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("CLA"))
+ .setSortOnMetric(METRIC_LINES)
+ .addCondition(new MeasureFilterCondition(METRIC_LINES, MeasureFilterCondition.Operator.GREATER, 200));
+ List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
+
+ assertThat(rows).hasSize(1);
+ verifyJavaBigFile(rows.get(0));
+ }
+
+ @Test
+ public void condition_on_measure_variation() throws SQLException {
+ db.prepareDbUnit(getClass(), "shared.xml");
+ MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK"))
+ .setSortOnMetric(METRIC_LINES)
+ .addCondition(new MeasureFilterCondition(METRIC_LINES, MeasureFilterCondition.Operator.GREATER, 1000).setPeriod(5));
+ List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
+
+ assertThat(rows).hasSize(1);
+ verifyPhpProject(rows.get(0));
+ }
+
+ @Test
+ public void multiple_conditions_on_numeric_measures() throws SQLException {
+ db.prepareDbUnit(getClass(), "shared.xml");
+ MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("CLA"))
+ .setSortOnMetric(METRIC_LINES)
+ .addCondition(new MeasureFilterCondition(METRIC_LINES, MeasureFilterCondition.Operator.GREATER, 2))
+ .addCondition(new MeasureFilterCondition(METRIC_LINES, MeasureFilterCondition.Operator.LESS_OR_EQUALS, 50));
+ List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
+
+ assertThat(rows).hasSize(1);
+ verifyJavaTinyFile(rows.get(0));
+ }
+
+ @Test
+ public void filter_by_min_date() throws SQLException {
+ db.prepareDbUnit(getClass(), "shared.xml");
+ MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK")).setFromDate(DateUtils.parseDate("2012-12-13"));
+ List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
+
+ // php has been analyzed in 2012-12-13, whereas java project has been analyzed in 2008
+ assertThat(rows).hasSize(1);
+ verifyPhpProject(rows.get(0));
+ }
+
+ @Test
+ public void filter_by_range_of_dates() throws SQLException {
+ db.prepareDbUnit(getClass(), "shared.xml");
+ MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK"))
+ .setFromDate(DateUtils.parseDate("2007-01-01"))
+ .setToDate(DateUtils.parseDate("2010-01-01"));
+ List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
+
+ // php has been analyzed in 2012-12-13, whereas java project has been analyzed in 2008
+ assertThat(rows).hasSize(1);
+ verifyJavaProject(rows.get(0));
+ }
+
+ @Test
+ public void filter_by_component_name() throws SQLException {
+ db.prepareDbUnit(getClass(), "shared.xml");
+ MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK")).setResourceName("PHP Proj");
+ List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
+
+ assertThat(rows).hasSize(1);
+ verifyPhpProject(rows.get(0));
+ }
+
+ @Test
+ public void filter_by_component_key() throws SQLException {
+ db.prepareDbUnit(getClass(), "shared.xml");
+ MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK")).setResourceKey("Va_proje");
+ List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
+
+ assertThat(rows).hasSize(1);
+ verifyJavaProject(rows.get(0));
+ }
+
+ /**
+ * see SONAR-4195
+ */
+ @Test
+ public void filter_by_upper_case_component_key() throws SQLException {
+ db.prepareDbUnit(getClass(), "shared.xml");
+ MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("CLA")).setResourceKey("big");
+ List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
+
+ assertThat(rows).hasSize(1);
+ verifyJavaBigFile(rows.get(0));
+ }
+
+ /**
+ * see SONAR-4796
+ */
+ @Test
+ public void escape_percent_and_underscore_when_filter_by_component_name_or_key() throws SQLException {
+ db.prepareDbUnit(getClass(), "escape_percent_and_underscore_when_filter_by_component_name_or_key.xml");
+
+ assertThat(executor.execute(
+ new MeasureFilter().setResourceQualifiers(newArrayList("CLA")).setResourceKey("java_"),
+ new MeasureFilterContext())).hasSize(2);
+
+ assertThat(executor.execute(
+ new MeasureFilter().setResourceQualifiers(newArrayList("CLA")).setResourceName("java%"),
+ new MeasureFilterContext())).hasSize(2);
+ }
+
+ @Test
+ public void filter_by_base_resource() throws SQLException {
+ db.prepareDbUnit(getClass(), "shared.xml");
+ MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("CLA")).setBaseResourceKey("java_project");
+ List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
+
+ assertThat(rows).hasSize(2);
+ // default sort is on resource name
+ verifyJavaBigFile(rows.get(0));
+ verifyJavaTinyFile(rows.get(1));
+ }
+
+ @Test
+ public void filter_by_parent_resource() throws SQLException {
+ db.prepareDbUnit(getClass(), "shared.xml");
+ MeasureFilter filter = new MeasureFilter().setBaseResourceKey("java_project").setOnBaseResourceChildren(true);
+ List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
+
+ assertThat(rows).hasSize(1);// the package org.sonar.foo
+ assertThat(rows.get(0).getSnapshotId()).isEqualTo(JAVA_PACKAGE_SNAPSHOT_ID);
+ }
+
+ @Test
+ public void filter_by_parent_without_children() throws Exception {
+ db.prepareDbUnit(getClass(), "shared.xml");
+ MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK", "PAC", "CLA")).setBaseResourceKey("java_project:org.sonar.foo.Big").setOnBaseResourceChildren(true);
+ List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
+
+ assertThat(rows).isEmpty();
+ }
+
+ @Test
+ public void filter_by_user_favourites() throws Exception {
+ db.prepareDbUnit(getClass(), "shared.xml");
+ MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK", "FIL")).setUserFavourites(true);
+ List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext().setUserId(50L));
+
+ assertThat(rows).hasSize(2);
+ verifyJavaBigFile(rows.get(0));
+ verifyPhpProject(rows.get(1));
+ }
+
+ @Test
+ public void ignore_person_measures_in_condition() throws Exception {
+ db.prepareDbUnit(getClass(), "ignore_person_measures.xml");
+ MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK")).addCondition(
+ new MeasureFilterCondition(new Metric("ncloc").setId(1), MeasureFilterCondition.Operator.GREATER, 0.0)
+ );
+ List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext().setUserId(50L));
+
+ assertThat(rows).hasSize(1);
+ assertThat(rows.get(0).getSnapshotId()).isEqualTo(101L);
+ }
+
+ @Test
+ public void ignore_person_measures_in_sort() throws Exception {
+ db.prepareDbUnit(getClass(), "ignore_person_measures.xml");
+ MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK")).setSortOnMetric(new Metric("ncloc").setId(1));
+ List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext().setUserId(50L));
+
+ assertThat(rows).hasSize(1);
+ assertThat(rows.get(0).getSnapshotId()).isEqualTo(101L);
+ }
+
+ @Test
+ public void ignore_quality_model_measures_in_condition() throws Exception {
+ db.prepareDbUnit(getClass(), "ignore_quality_model_measures.xml");
+ MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK")).addCondition(
+ new MeasureFilterCondition(new Metric("ncloc").setId(1), MeasureFilterCondition.Operator.GREATER, 0.0)
+ );
+ List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext().setUserId(50L));
+
+ assertThat(rows).hasSize(1);
+ assertThat(rows.get(0).getSnapshotId()).isEqualTo(101L);
+ }
+
+ @Test
+ public void ignore_quality_model_measures_in_sort() throws Exception {
+ db.prepareDbUnit(getClass(), "ignore_quality_model_measures.xml");
+ MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK")).setSortOnMetric(new Metric("ncloc").setId(1));
+ List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext().setUserId(50L));
+
+ assertThat(rows).hasSize(1);
+ assertThat(rows.get(0).getSnapshotId()).isEqualTo(101L);
+ }
+
+
+ private void verifyJavaProject(MeasureFilterRow row) {
+ verifyProject(row, JAVA_PROJECT_SNAPSHOT_ID, JAVA_PROJECT_ID, JAVA_PROJECT_ID);
+ }
+
+ private void verifyJavaBigFile(MeasureFilterRow row) {
+ verifyProject(row, JAVA_FILE_BIG_SNAPSHOT_ID, JAVA_FILE_BIG_ID, JAVA_PROJECT_ID);
+ }
+
+ private void verifyJavaTinyFile(MeasureFilterRow row) {
+ verifyProject(row, JAVA_FILE_TINY_SNAPSHOT_ID, JAVA_FILE_TINY_ID, JAVA_PROJECT_ID);
+ }
+
+ private void verifyPhpProject(MeasureFilterRow row) {
+ verifyProject(row, PHP_SNAPSHOT_ID, PHP_PROJECT_ID, PHP_PROJECT_ID);
+ }
+
+ private void verifyProject(MeasureFilterRow row, Long snashotId, Long resourceId, Long resourceRootId) {
+ assertThat(row.getSnapshotId()).isEqualTo(snashotId);
+ assertThat(row.getResourceId()).isEqualTo(resourceId);
+ assertThat(row.getResourceRootId()).isEqualTo(resourceRootId);
+ }
+}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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.measure;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Maps;
+import org.junit.Test;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+import org.sonar.api.measures.Metric;
+import org.sonar.api.measures.MetricFinder;
+import org.sonar.api.utils.DateUtils;
+import org.sonar.api.utils.System2;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
+import static org.fest.assertions.Assertions.assertThat;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class MeasureFilterFactoryTest {
+
+ System2 system = mock(System2.class);
+
+ @Test
+ public void sort_on_measure_value() {
+ MeasureFilterFactory factory = new MeasureFilterFactory(newMetricFinder(), system);
+ Map<String, Object> props = ImmutableMap.<String, Object>of("sort", "metric:ncloc");
+ MeasureFilter filter = factory.create(props);
+
+ assertThat(filter.sort().column()).isEqualTo("pmsort.value");
+ assertThat(filter.sort().metric().getKey()).isEqualTo("ncloc");
+ assertThat(filter.sort().period()).isNull();
+ }
+
+ @Test
+ public void sort_on_measure_variation() {
+ MeasureFilterFactory factory = new MeasureFilterFactory(newMetricFinder(), system);
+ Map<String, Object> props = ImmutableMap.<String, Object>of("sort", "metric:ncloc:3");
+ MeasureFilter filter = factory.create(props);
+
+ assertThat(filter.sort().column()).isEqualTo("pmsort.variation_value_3");
+ assertThat(filter.sort().metric().getKey()).isEqualTo("ncloc");
+ assertThat(filter.sort().period()).isEqualTo(3);
+ }
+
+ @Test
+ public void sort_on_name() {
+ MeasureFilterFactory factory = new MeasureFilterFactory(newMetricFinder(), system);
+ Map<String, Object> props = ImmutableMap.<String, Object>of("sort", "name");
+ MeasureFilter filter = factory.create(props);
+
+ assertThat(filter.sort().column()).isEqualTo("p.long_name");
+ assertThat(filter.sort().metric()).isNull();
+ assertThat(filter.sort().period()).isNull();
+ }
+
+ @Test
+ public void fallback_on_name_sort_when_metric_is_unknown() {
+ MetricFinder finder = mock(MetricFinder.class);
+ when(finder.findByKey(anyString())).thenReturn(null);
+ MeasureFilterFactory factory = new MeasureFilterFactory(finder, system);
+ Map<String, Object> props = ImmutableMap.<String, Object>of("sort", "metric:sqale_index");
+ MeasureFilter filter = factory.create(props);
+
+ assertThat(filter.sort().column()).isEqualTo("p.long_name");
+ assertThat(filter.sort().metric()).isNull();
+ assertThat(filter.sort().period()).isNull();
+ assertThat(filter.sort().isAsc()).isTrue();
+ }
+
+ @Test
+ public void descending_sort() {
+ MeasureFilterFactory factory = new MeasureFilterFactory(newMetricFinder(), system);
+ Map<String, Object> props = ImmutableMap.<String, Object>of("asc", "false");
+ MeasureFilter filter = factory.create(props);
+
+ assertThat(filter.sort().column()).isEqualTo("p.long_name");
+ assertThat(filter.sort().metric()).isNull();
+ assertThat(filter.sort().period()).isNull();
+ assertThat(filter.sort().isAsc()).isFalse();
+ }
+
+ @Test
+ public void ascending_sort_by_default() {
+ MeasureFilterFactory factory = new MeasureFilterFactory(newMetricFinder(), system);
+ Map<String, Object> props = Maps.newHashMap();
+ MeasureFilter filter = factory.create(props);
+
+ assertThat(filter.sort().column()).isEqualTo("p.long_name");
+ assertThat(filter.sort().metric()).isNull();
+ assertThat(filter.sort().period()).isNull();
+ assertThat(filter.sort().isAsc()).isTrue();
+ }
+
+ @Test
+ public void date_conditions() {
+ MeasureFilterFactory factory = new MeasureFilterFactory(newMetricFinder(), system);
+ Map<String, Object> props = ImmutableMap.<String, Object>of(
+ "fromDate", "2012-01-25",
+ "toDate", "2012-02-18"
+ );
+ MeasureFilter filter = factory.create(props);
+
+ assertThat(DateUtils.formatDate(filter.getFromDate())).isEqualTo("2012-01-25");
+ assertThat(DateUtils.formatDate(filter.getToDate())).isEqualTo("2012-02-18");
+ }
+
+ @Test
+ public void age_conditions() {
+ long today = DateUtils.parseDateTime("2013-05-18T11:00:00+0000").getTime();
+ when(system.now()).thenReturn(today);
+
+ MeasureFilterFactory factory = new MeasureFilterFactory(newMetricFinder(), system);
+ Map<String, Object> props = ImmutableMap.<String, Object>of(
+ "ageMaxDays", "3",
+ "ageMinDays", "1"
+ );
+ MeasureFilter filter = factory.create(props);
+ assertThat(DateUtils.formatDate(filter.getFromDate())).isEqualTo("2013-05-15");
+ assertThat(DateUtils.formatDate(filter.getToDate())).isEqualTo("2013-05-17");
+ }
+
+ @Test
+ public void measure_value_condition() {
+ MeasureFilterFactory factory = new MeasureFilterFactory(newMetricFinder(), system);
+ Map<String, Object> props = ImmutableMap.<String, Object>of(
+ "c1_metric", "complexity",
+ "c1_op", "gte",
+ "c1_val", "3.14"
+ );
+ MeasureFilter filter = factory.create(props);
+
+ List<MeasureFilterCondition> conditions = filter.getMeasureConditions();
+ assertThat(conditions).hasSize(1);
+ assertThat(conditions.get(0).metric().getKey()).isEqualTo("complexity");
+ assertThat(conditions.get(0).operator()).isEqualTo(MeasureFilterCondition.Operator.GREATER_OR_EQUALS);
+ assertThat(conditions.get(0).value()).isEqualTo(3.14);
+ assertThat(conditions.get(0).period()).isNull();
+ }
+
+ @Test
+ public void measure_variation_condition() {
+ MeasureFilterFactory factory = new MeasureFilterFactory(newMetricFinder(), system);
+ Map<String, Object> props = ImmutableMap.<String, Object>of(
+ "c1_metric", "complexity",
+ "c1_op", "gte",
+ "c1_val", "3.14",
+ "c1_period", "3"
+ );
+ MeasureFilter filter = factory.create(props);
+
+ List<MeasureFilterCondition> conditions = filter.getMeasureConditions();
+ assertThat(conditions).hasSize(1);
+ assertThat(conditions.get(0).metric().getKey()).isEqualTo("complexity");
+ assertThat(conditions.get(0).operator()).isEqualTo(MeasureFilterCondition.Operator.GREATER_OR_EQUALS);
+ assertThat(conditions.get(0).value()).isEqualTo(3.14);
+ assertThat(conditions.get(0).period()).isEqualTo(3);
+ }
+
+ @Test
+ public void alert_level_condition() {
+ MeasureFilterFactory factory = new MeasureFilterFactory(newMetricFinder(), system);
+ Map<String, Object> props = ImmutableMap.<String, Object>of(
+ "alertLevels", Arrays.asList("error", "warn")
+ );
+ MeasureFilter filter = factory.create(props);
+
+ List<MeasureFilterCondition> conditions = filter.getMeasureConditions();
+ assertThat(conditions).hasSize(1);
+ assertThat(conditions.get(0).metric().getKey()).isEqualTo("alert_status");
+ assertThat(conditions.get(0).operator()).isEqualTo(MeasureFilterCondition.Operator.IN);
+ assertThat(conditions.get(0).value()).isEqualTo(0);
+ assertThat(conditions.get(0).textValue()).isEqualTo("('ERROR', 'WARN')");
+ assertThat(conditions.get(0).period()).isNull();
+ }
+
+ @Test
+ public void ignore_partial_measure_condition() {
+ MeasureFilterFactory factory = new MeasureFilterFactory(newMetricFinder(), system);
+ Map<String, Object> props = ImmutableMap.<String, Object>of(
+ "c1_op", "gte",
+ "c1_val", "3.14"
+ );
+ MeasureFilter filter = factory.create(props);
+
+ List<MeasureFilterCondition> conditions = filter.getMeasureConditions();
+ assertThat(conditions).isEmpty();
+ }
+
+ private MetricFinder newMetricFinder() {
+ MetricFinder finder = mock(MetricFinder.class);
+ when(finder.findByKey(anyString())).thenAnswer(new Answer<Metric>() {
+ public Metric answer(InvocationOnMock invocationOnMock) throws Throwable {
+ String key = (String) invocationOnMock.getArguments()[0];
+ return new Metric.Builder(key, key, Metric.ValueType.INT).create();
+ }
+ });
+ return finder;
+ }
+}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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.measure;
+
+import com.google.common.collect.Lists;
+import org.junit.Test;
+
+import java.util.Arrays;
+import java.util.Collections;
+
+import static org.fest.assertions.Assertions.assertThat;
+
+public class MeasureFilterTest {
+ @Test
+ public void should_sanitize_list() {
+ assertThat(MeasureFilter.sanitize(null)).isEmpty();
+ assertThat(MeasureFilter.sanitize(Lists.<String>newArrayList())).isEmpty();
+ assertThat(MeasureFilter.sanitize(Arrays.asList(""))).isEmpty();
+ assertThat(MeasureFilter.sanitize(Lists.newArrayList("TRK"))).containsExactly("TRK");
+ assertThat(MeasureFilter.sanitize(Lists.newArrayList("TRK", "BRC"))).containsExactly("TRK", "BRC");
+ }
+
+ @Test
+ public void filter_is_not_empty_if_at_least_condition_on_favourites() {
+ assertThat(new MeasureFilter().isEmpty()).isTrue();
+ assertThat(new MeasureFilter().setUserFavourites(true).isEmpty()).isFalse();
+ }
+
+ @Test
+ public void filter_is_not_empty_if_at_least_condition_on_qualifiers() {
+ assertThat(new MeasureFilter().isEmpty()).isTrue();
+ assertThat(new MeasureFilter().setResourceQualifiers(Collections.<String>emptyList()).isEmpty()).isTrue();
+ assertThat(new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK")).isEmpty()).isFalse();
+ }
+
+ @Test
+ public void filter_is_not_empty_if_at_least_condition_on_scopes() {
+ assertThat(new MeasureFilter().isEmpty()).isTrue();
+ assertThat(new MeasureFilter().setResourceScopes(Collections.<String>emptyList()).isEmpty()).isTrue();
+ assertThat(new MeasureFilter().setResourceScopes(Arrays.asList("PRJ")).isEmpty()).isFalse();
+ }
+
+ @Test
+ public void filter_is_not_empty_if_at_least_condition_on_root_resource() {
+ assertThat(new MeasureFilter().isEmpty()).isTrue();
+ assertThat(new MeasureFilter().setBaseResourceKey("foo").isEmpty()).isFalse();
+ }
+}
--- /dev/null
+<dataset>
+
+ <!-- java project -->
+ <projects kee="java_project:org.sonar.bar" long_name="org.sonar.bar" scope="FIL" qualifier="CLA" name="org.sonar.bar"
+ id="1" root_id="[null]"
+ description="[null]" enabled="[true]" language="[null]" copy_resource_id="[null]" person_id="[null]"
+ created_at="2008-12-19 00:00:00.00"/>
+
+ <projects kee="java_project:org.sonar.foo" scope="FIL" qualifier="CLA" long_name="org.sonar.foo" name="org.sonar.foo"
+ id="2" root_id="1"
+ description="[null]" enabled="[true]" language="java" copy_resource_id="[null]" person_id="[null]"
+ created_at="2008-12-19 00:00:00.00"/>
+
+ <projects kee="java project:org.sonar.foo.Big" scope="FIL" qualifier="CLA" long_name="org.sonar.foo.Big"
+ name="Big"
+ id="3" root_id="1"
+ description="[null]" enabled="[true]" language="java" copy_resource_id="[null]" person_id="[null]"
+ created_at="2008-12-19 00:00:00.00"/>
+
+ <projects kee="java project:org.sonar.foo.Tiny" scope="FIL" qualifier="CLA" long_name="org.sonar.foo.Tiny" name="Tiny"
+ id="4" root_id="1"
+ description="[null]" enabled="[true]" language="java" copy_resource_id="[null]" person_id="[null]"
+ created_at="2008-12-19 00:00:00.00"/>
+
+ <snapshots id="101" project_id="1" root_project_id="1" root_snapshot_id="[null]" parent_snapshot_id="[null]"
+ scope="FIL" qualifier="CLA" path="" depth="0"
+ purge_status="[null]" period1_mode="[null]" period1_param="[null]" period1_date="[null]"
+ period2_mode="[null]" period2_param="[null]" period2_date="[null]" period3_mode="[null]"
+ period3_param="[null]" period3_date="[null]" period4_mode="[null]" period4_param="[null]"
+ period4_date="[null]" period5_mode="[null]" period5_param="[null]" period5_date="[null]"
+ created_at="2008-12-20 00:00:00.00" build_date="2008-12-20 00:00:00.00"
+ version="1.0" status="P" islast="[true]"/>
+
+ <snapshots id="102" project_id="2" root_project_id="1" root_snapshot_id="101" parent_snapshot_id="101"
+ scope="FIL" qualifier="CLA" path="101." depth="1"
+ purge_status="[null]" period1_mode="[null]" period1_param="[null]" period1_date="[null]"
+ period2_mode="[null]" period2_param="[null]" period2_date="[null]" period3_mode="[null]"
+ period3_param="[null]" period3_date="[null]" period4_mode="[null]" period4_param="[null]"
+ period4_date="[null]" period5_mode="[null]" period5_param="[null]" period5_date="[null]"
+ created_at="2008-12-20 00:00:00.00" build_date="2008-12-20 00:00:00.00"
+ version="1.0" status="P" islast="[true]"/>
+
+ <snapshots id="103" project_id="3" root_project_id="1" root_snapshot_id="101" parent_snapshot_id="102"
+ scope="FIL" qualifier="CLA" path="101.102." depth="2"
+ purge_status="[null]" period1_mode="[null]" period1_param="[null]" period1_date="[null]"
+ period2_mode="[null]" period2_param="[null]" period2_date="[null]" period3_mode="[null]"
+ period3_param="[null]" period3_date="[null]" period4_mode="[null]" period4_param="[null]"
+ period4_date="[null]" period5_mode="[null]" period5_param="[null]" period5_date="[null]"
+ created_at="2008-12-20 00:00:00.00" build_date="2008-12-20 00:00:00.00"
+ version="1.0" status="P" islast="[true]"/>
+
+ <snapshots id="104" project_id="4" root_project_id="1" root_snapshot_id="101" parent_snapshot_id="102"
+ scope="FIL" qualifier="CLA" path="101.102." depth="2"
+ purge_status="[null]" period1_mode="[null]" period1_param="[null]" period1_date="[null]"
+ period2_mode="[null]" period2_param="[null]" period2_date="[null]" period3_mode="[null]"
+ period3_param="[null]" period3_date="[null]" period4_mode="[null]" period4_param="[null]"
+ period4_date="[null]" period5_mode="[null]" period5_param="[null]" period5_date="[null]"
+ created_at="2008-12-20 00:00:00.00" build_date="2008-12-20 00:00:00.00"
+ version="1.0" status="P" islast="[true]"/>
+
+ <resource_index id="1" kee="java class1" position="0" name_size="12" resource_id="1" root_project_id="1" qualifier="CLA"/>
+ <resource_index id="2" kee="java class2" position="1" name_size="12" resource_id="2" root_project_id="1" qualifier="CLA"/>
+ <resource_index id="3" kee="java%class3" position="2" name_size="12" resource_id="3" root_project_id="1" qualifier="CLA"/>
+ <resource_index id="4" kee="java%class4" position="3" name_size="12" resource_id="4" root_project_id="1" qualifier="CLA"/>
+
+
+</dataset>
--- /dev/null
+<dataset>
+ <metrics id="1" name="lines" val_type="FLOAT" description="Lines" domain="Size"
+ short_name="Lines" qualitative="[false]" user_managed="[false]" enabled="[true]" origin="JAV" worst_value="[null]"
+ optimized_best_value="[null]" best_value="[null]" direction="1" hidden="[false]"
+ delete_historical_data="[null]"/>
+
+ <projects kee="java_project" long_name="Java project" scope="PRJ" qualifier="TRK" name="Java project"
+ id="1" root_id="[null]"
+ description="[null]" enabled="[true]" language="[null]" copy_resource_id="[null]" person_id="[null]"/>
+
+ <snapshots id="101" project_id="1" root_project_id="1" root_snapshot_id="[null]" parent_snapshot_id="[null]"
+ scope="PRJ" qualifier="TRK" path="" depth="0"
+ purge_status="[null]" period1_mode="[null]" period1_param="[null]" period1_date="[null]"
+ period2_mode="[null]" period2_param="[null]" period2_date="[null]" period3_mode="[null]"
+ period3_param="[null]" period3_date="[null]" period4_mode="[null]" period4_param="[null]"
+ period4_date="[null]" period5_mode="[null]" period5_param="[null]" period5_date="[null]"
+ created_at="2008-12-20 00:00:00.00" build_date="2008-12-20 00:00:00.00"
+ version="1.0" status="P" islast="[true]"/>
+
+
+ <!-- standard measure -->
+ <project_measures id="1001" metric_id="1" value="500" snapshot_id="101" person_id="[null]"
+ url="[null]" variation_value_1="[null]" variation_value_2="[null]" variation_value_3="[null]"
+ variation_value_4="[null]" variation_value_5="400"
+ rule_priority="[null]" alert_text="[null]" RULES_CATEGORY_ID="[null]"
+ RULE_ID="[null]" text_value="[null]" tendency="[null]" measure_date="[null]" project_id="[null]"
+ alert_status="[null]" description="[null]" characteristic_id="[null]"/>
+
+ <!-- details of the measure by person -->
+ <project_measures id="1002" metric_id="1" value="300" snapshot_id="101" person_id="30000"
+ url="[null]" variation_value_1="[null]" variation_value_2="[null]" variation_value_3="[null]"
+ variation_value_4="[null]" variation_value_5="400"
+ rule_priority="[null]" alert_text="[null]" RULES_CATEGORY_ID="[null]"
+ RULE_ID="[null]" text_value="[null]" tendency="[null]" measure_date="[null]" project_id="[null]"
+ alert_status="[null]" description="[null]" characteristic_id="[null]"/>
+
+ <project_measures id="1003" metric_id="1" value="200" snapshot_id="101" person_id="40000"
+ url="[null]" variation_value_1="[null]" variation_value_2="[null]" variation_value_3="[null]"
+ variation_value_4="[null]" variation_value_5="400"
+ rule_priority="[null]" alert_text="[null]" RULES_CATEGORY_ID="[null]"
+ RULE_ID="[null]" text_value="[null]" tendency="[null]" measure_date="[null]" project_id="[null]"
+ alert_status="[null]" description="[null]" characteristic_id="[null]"/>
+
+</dataset>
--- /dev/null
+<dataset>
+ <metrics id="1" name="lines" val_type="FLOAT" description="Lines" domain="Size"
+ short_name="Lines" qualitative="[false]" user_managed="[false]" enabled="[true]" origin="JAV" worst_value="[null]"
+ optimized_best_value="[null]" best_value="[null]" direction="1" hidden="[false]"
+ delete_historical_data="[null]"/>
+
+ <projects kee="java_project" long_name="Java project" scope="PRJ" qualifier="TRK" name="Java project"
+ id="1" root_id="[null]"
+ description="[null]" enabled="[true]" language="[null]" copy_resource_id="[null]" person_id="[null]"/>
+
+ <snapshots id="101" project_id="1" root_project_id="1" root_snapshot_id="[null]" parent_snapshot_id="[null]"
+ scope="PRJ" qualifier="TRK" path="" depth="0"
+ purge_status="[null]" period1_mode="[null]" period1_param="[null]" period1_date="[null]"
+ period2_mode="[null]" period2_param="[null]" period2_date="[null]" period3_mode="[null]"
+ period3_param="[null]" period3_date="[null]" period4_mode="[null]" period4_param="[null]"
+ period4_date="[null]" period5_mode="[null]" period5_param="[null]" period5_date="[null]"
+ created_at="2008-12-20 00:00:00.00" build_date="2008-12-20 00:00:00.00"
+ version="1.0" status="P" islast="[true]"/>
+
+
+ <!-- standard measure -->
+ <project_measures id="1001" metric_id="1" value="500" snapshot_id="101" characteristic_id="[null]"
+ url="[null]" variation_value_1="[null]" variation_value_2="[null]" variation_value_3="[null]"
+ variation_value_4="[null]" variation_value_5="400"
+ rule_priority="[null]" alert_text="[null]" RULES_CATEGORY_ID="[null]"
+ RULE_ID="[null]" text_value="[null]" tendency="[null]" measure_date="[null]" project_id="[null]"
+ alert_status="[null]" description="[null]" person_id="[null]"/>
+
+ <!-- details of the measure by model characteristic -->
+ <project_measures id="1002" metric_id="1" value="300" snapshot_id="101" characteristic_id="30000"
+ url="[null]" variation_value_1="[null]" variation_value_2="[null]" variation_value_3="[null]"
+ variation_value_4="[null]" variation_value_5="400"
+ rule_priority="[null]" alert_text="[null]" RULES_CATEGORY_ID="[null]"
+ RULE_ID="[null]" text_value="[null]" tendency="[null]" measure_date="[null]" project_id="[null]"
+ alert_status="[null]" description="[null]" person_id="[null]"/>
+
+ <project_measures id="1003" metric_id="1" value="200" snapshot_id="101" characteristic_id="40000"
+ url="[null]" variation_value_1="[null]" variation_value_2="[null]" variation_value_3="[null]"
+ variation_value_4="[null]" variation_value_5="400"
+ rule_priority="[null]" alert_text="[null]" RULES_CATEGORY_ID="[null]"
+ RULE_ID="[null]" text_value="[null]" tendency="[null]" measure_date="[null]" project_id="[null]"
+ alert_status="[null]" description="[null]" person_id="[null]"/>
+
+</dataset>
--- /dev/null
+<dataset>
+ <metrics id="1" name="lines" val_type="FLOAT" description="Lines" domain="Size"
+ short_name="Lines" qualitative="[false]" user_managed="[false]" enabled="[true]" origin="JAV" worst_value="[null]"
+ optimized_best_value="[null]" best_value="[null]" direction="1" hidden="[false]"
+ delete_historical_data="[null]"/>
+
+ <metrics id="2" name="profile" val_type="STRING" description="Profile" domain="Rules"
+ short_name="Profile" qualitative="[false]" user_managed="[false]" enabled="[true]" origin="JAV"
+ worst_value="[null]"
+ optimized_best_value="[null]" best_value="[null]" direction="0" hidden="[false]"
+ delete_historical_data="[null]"/>
+
+ <metrics id="3" name="coverage" val_type="FLOAT" description="Coverage" domain="Test"
+ short_name="Coverage" qualitative="[true]" user_managed="[false]" enabled="[true]" origin="JAV"
+ worst_value="[null]"
+ optimized_best_value="[true]" best_value="100" direction="1" hidden="[false]"
+ delete_historical_data="[null]"/>
+
+ <metrics id="4" name="unknown" val_type="FLOAT" description="Coverage" domain="Test"
+ short_name="Unknown" qualitative="[true]" user_managed="[false]" enabled="[true]" origin="JAV"
+ worst_value="[null]"
+ optimized_best_value="[true]" best_value="100" direction="1" hidden="[false]"
+ delete_historical_data="[null]"/>
+
+ <!-- java project -->
+ <projects kee="java_project" long_name="Java project" scope="PRJ" qualifier="TRK" name="Java project"
+ id="1" root_id="[null]"
+ description="[null]" enabled="[true]" language="[null]" copy_resource_id="[null]" person_id="[null]"
+ created_at="2008-12-19 00:00:00.00"/>
+
+ <projects kee="java_project:org.sonar.foo" scope="DIR" qualifier="PAC" long_name="org.sonar.foo" name="org.sonar.foo"
+ id="2" root_id="1"
+ description="[null]" enabled="[true]" language="[null]" copy_resource_id="[null]" person_id="[null]"
+ created_at="2008-12-19 00:00:00.00"/>
+
+ <projects kee="java_project:org.sonar.foo.Big" scope="FIL" qualifier="CLA" long_name="org.sonar.foo.Big"
+ name="Big"
+ id="3" root_id="1"
+ description="[null]" enabled="[true]" language="java" copy_resource_id="[null]" person_id="[null]"
+ created_at="2008-12-19 00:00:00.00"/>
+
+ <projects kee="java_project:org.sonar.foo.Tiny" scope="FIL" qualifier="CLA" long_name="org.sonar.foo.Tiny" name="Tiny"
+ id="4" root_id="1"
+ description="[null]" enabled="[true]" language="java" copy_resource_id="[null]" person_id="[null]"
+ created_at="2008-12-19 00:00:00.00"/>
+
+ <snapshots id="101" project_id="1" root_project_id="1" root_snapshot_id="[null]" parent_snapshot_id="[null]"
+ scope="PRJ" qualifier="TRK" path="" depth="0"
+ purge_status="[null]" period1_mode="[null]" period1_param="[null]" period1_date="[null]"
+ period2_mode="[null]" period2_param="[null]" period2_date="[null]" period3_mode="[null]"
+ period3_param="[null]" period3_date="[null]" period4_mode="[null]" period4_param="[null]"
+ period4_date="[null]" period5_mode="[null]" period5_param="[null]" period5_date="[null]"
+ created_at="2008-12-20 00:00:00.00" build_date="2008-12-20 00:00:00.00"
+ version="1.0" status="P" islast="[true]"/>
+
+ <snapshots id="102" project_id="2" root_project_id="1" root_snapshot_id="101" parent_snapshot_id="101"
+ scope="DIR" qualifier="PAC" path="101." depth="1"
+ purge_status="[null]" period1_mode="[null]" period1_param="[null]" period1_date="[null]"
+ period2_mode="[null]" period2_param="[null]" period2_date="[null]" period3_mode="[null]"
+ period3_param="[null]" period3_date="[null]" period4_mode="[null]" period4_param="[null]"
+ period4_date="[null]" period5_mode="[null]" period5_param="[null]" period5_date="[null]"
+ created_at="2008-12-20 00:00:00.00" build_date="2008-12-20 00:00:00.00"
+ version="1.0" status="P" islast="[true]"/>
+
+ <snapshots id="103" project_id="3" root_project_id="1" root_snapshot_id="101" parent_snapshot_id="102"
+ scope="FIL" qualifier="CLA" path="101.102." depth="2"
+ purge_status="[null]" period1_mode="[null]" period1_param="[null]" period1_date="[null]"
+ period2_mode="[null]" period2_param="[null]" period2_date="[null]" period3_mode="[null]"
+ period3_param="[null]" period3_date="[null]" period4_mode="[null]" period4_param="[null]"
+ period4_date="[null]" period5_mode="[null]" period5_param="[null]" period5_date="[null]"
+ created_at="2008-12-20 00:00:00.00" build_date="2008-12-20 00:00:00.00"
+ version="1.0" status="P" islast="[true]"/>
+
+ <snapshots id="104" project_id="4" root_project_id="1" root_snapshot_id="101" parent_snapshot_id="102"
+ scope="FIL" qualifier="CLA" path="101.102." depth="2"
+ purge_status="[null]" period1_mode="[null]" period1_param="[null]" period1_date="[null]"
+ period2_mode="[null]" period2_param="[null]" period2_date="[null]" period3_mode="[null]"
+ period3_param="[null]" period3_date="[null]" period4_mode="[null]" period4_param="[null]"
+ period4_date="[null]" period5_mode="[null]" period5_param="[null]" period5_date="[null]"
+ created_at="2008-12-20 00:00:00.00" build_date="2008-12-20 00:00:00.00"
+ version="1.0" status="P" islast="[true]"/>
+
+
+ <!-- lines, variation during period 5 -->
+ <project_measures id="1001" metric_id="1" value="510" snapshot_id="101"
+ url="[null]" variation_value_1="[null]" variation_value_2="[null]" variation_value_3="[null]"
+ variation_value_4="[null]" variation_value_5="400"
+ rule_priority="[null]" alert_text="[null]" RULES_CATEGORY_ID="[null]"
+ RULE_ID="[null]" text_value="[null]" tendency="[null]" measure_date="[null]" project_id="[null]"
+ alert_status="[null]" description="[null]" characteristic_id="[null]"/>
+
+ <project_measures id="1002" metric_id="1" value="510" snapshot_id="102"
+ url="[null]" variation_value_1="[null]" variation_value_2="[null]" variation_value_3="[null]"
+ variation_value_4="[null]" variation_value_5="[null]"
+ rule_priority="[null]" alert_text="[null]" RULES_CATEGORY_ID="[null]"
+ RULE_ID="[null]" text_value="[null]" tendency="[null]" measure_date="[null]" project_id="[null]"
+ alert_status="[null]" description="[null]" characteristic_id="[null]"/>
+
+ <project_measures id="1003" metric_id="1" value="500" snapshot_id="103"
+ url="[null]" variation_value_1="[null]" variation_value_2="[null]" variation_value_3="[null]"
+ variation_value_4="[null]" variation_value_5="[null]"
+ rule_priority="[null]" alert_text="[null]" RULES_CATEGORY_ID="[null]"
+ RULE_ID="[null]" text_value="[null]" tendency="[null]" measure_date="[null]" project_id="[null]"
+ alert_status="[null]" description="[null]" characteristic_id="[null]"/>
+
+ <project_measures id="1004" metric_id="1" value="10" snapshot_id="104"
+ url="[null]" variation_value_1="[null]" variation_value_2="[null]" variation_value_3="[null]"
+ variation_value_4="[null]" variation_value_5="[null]"
+ rule_priority="[null]" alert_text="[null]" RULES_CATEGORY_ID="[null]"
+ RULE_ID="[null]" text_value="[null]" tendency="[null]" measure_date="[null]" project_id="[null]"
+ alert_status="[null]" description="[null]" characteristic_id="[null]"/>
+
+ <!-- profile of java project -->
+ <project_measures id="1005" metric_id="2" value="[null]" snapshot_id="101"
+ url="[null]" variation_value_1="[null]" variation_value_2="[null]" variation_value_3="[null]"
+ variation_value_4="[null]" variation_value_5="[null]"
+ rule_priority="[null]" alert_text="[null]" RULES_CATEGORY_ID="[null]"
+ RULE_ID="[null]" text_value="Sonar way" tendency="[null]" measure_date="[null]" project_id="[null]"
+ alert_status="[null]" description="[null]" characteristic_id="[null]"/>
+
+ <!-- coverage of java project -->
+ <project_measures id="1006" metric_id="3" value="12.3" snapshot_id="101"
+ url="[null]" variation_value_1="[null]" variation_value_2="[null]" variation_value_3="[null]"
+ variation_value_4="[null]" variation_value_5="[null]"
+ rule_priority="[null]" alert_text="[null]" RULES_CATEGORY_ID="[null]"
+ RULE_ID="[null]" text_value="Sonar way" tendency="[null]" measure_date="[null]" project_id="[null]"
+ alert_status="[null]" description="[null]" characteristic_id="[null]"/>
+
+ <!-- php project -->
+ <projects kee="php_project" long_name="PHP project" scope="PRJ" qualifier="TRK" name="PHP project"
+ id="10" root_id="[null]"
+ description="[null]" enabled="[true]" language="[null]" copy_resource_id="[null]" person_id="[null]"
+ created_at="2012-12-12 04:06:00.00"/>
+
+
+ <snapshots id="110" project_id="10" root_project_id="10" root_snapshot_id="[null]" parent_snapshot_id="[null]"
+ scope="PRJ" qualifier="TRK" path="" depth="0"
+ purge_status="[null]" period1_mode="[null]" period1_param="[null]" period1_date="[null]"
+ period2_mode="[null]" period2_param="[null]" period2_date="[null]" period3_mode="[null]"
+ period3_param="[null]" period3_date="[null]" period4_mode="[null]" period4_param="[null]"
+ period4_date="[null]" period5_mode="[null]" period5_param="[null]" period5_date="[null]"
+ created_at="2012-12-13 04:06:00.00" build_date="2012-12-13 04:06:00.00"
+ version="3.0" status="P" islast="[true]"/>
+
+ <!-- lines, many new lines during period 5 -->
+ <project_measures id="1010" metric_id="1" value="5000" snapshot_id="110"
+ url="[null]" variation_value_1="[null]" variation_value_2="[null]" variation_value_3="[null]"
+ variation_value_4="[null]" variation_value_5="4900"
+ rule_priority="[null]" alert_text="[null]" RULES_CATEGORY_ID="[null]"
+ RULE_ID="[null]" text_value="[null]" tendency="[null]" measure_date="[null]" project_id="[null]"
+ alert_status="[null]" description="[null]" characteristic_id="[null]"/>
+
+ <project_measures id="1011" metric_id="2" value="[null]" snapshot_id="110"
+ url="[null]" variation_value_1="[null]" variation_value_2="[null]" variation_value_3="[null]"
+ variation_value_4="[null]" variation_value_5="[null]"
+ rule_priority="[null]" alert_text="[null]" RULES_CATEGORY_ID="[null]"
+ RULE_ID="[null]" text_value="php way" tendency="[null]" measure_date="[null]" project_id="[null]"
+ alert_status="[null]" description="[null]" characteristic_id="[null]"/>
+
+
+ <resource_index id="1" kee="java project" position="0" name_size="12" resource_id="1" root_project_id="1" qualifier="TRK"/>
+ <resource_index id="2" kee="java projec" position="1" name_size="12" resource_id="1" root_project_id="1" qualifier="TRK"/>
+ <resource_index id="3" kee="java proje" position="2" name_size="12" resource_id="1" root_project_id="1" qualifier="TRK"/>
+ <resource_index id="4" kee="java proj" position="3" name_size="12" resource_id="1" root_project_id="1" qualifier="TRK"/>
+ <!-- etc -->
+ <resource_index id="5" kee="php project" position="0" name_size="11" resource_id="10" root_project_id="10" qualifier="TRK"/>
+ <resource_index id="6" kee="php projec" position="1" name_size="11" resource_id="10" root_project_id="10" qualifier="TRK"/>
+ <resource_index id="7" kee="php proje" position="2" name_size="11" resource_id="10" root_project_id="10" qualifier="TRK"/>
+ <resource_index id="8" kee="php proj" position="3" name_size="11" resource_id="10" root_project_id="10" qualifier="TRK"/>
+ <!-- etc -->
+
+
+ <!-- two favourites : Big.java and PHP project -->
+ <properties id="1" prop_key="favourite" resource_id="3" text_value="[null]" user_id="50"/>
+ <properties id="2" prop_key="favourite" resource_id="10" text_value="[null]" user_id="50"/>
+
+ <!-- another properties -->
+ <properties id="3" prop_key="favourite" resource_id="1" text_value="[null]" user_id="1234"/>
+ <properties id="4" prop_key="sonar.profile" resource_id="1" text_value="Sonar way" user_id="[null]"/>
+
+</dataset>
--- /dev/null
+<dataset>
+ <metrics id="5" name="alert_status" val_type="LEVEL" description="Alert" domain="General"
+ short_name="Alert" qualitative="[true]" user_managed="[false]" enabled="[true]" origin="JAV"
+ worst_value="[null]"
+ optimized_best_value="[true]" best_value="[null]" direction="1" hidden="[false]"
+ delete_historical_data="[null]"/>
+
+ <!-- java project -->
+ <projects kee="java_project" long_name="Java project" scope="PRJ" qualifier="TRK" name="Java project"
+ id="1" root_id="[null]"
+ description="[null]" enabled="[true]" language="[null]" copy_resource_id="[null]" person_id="[null]"
+ created_at="2008-12-19 00:00:00.00"/>
+
+ <snapshots id="101" project_id="1" root_project_id="1" root_snapshot_id="[null]" parent_snapshot_id="[null]"
+ scope="PRJ" qualifier="TRK" path="" depth="0"
+ purge_status="[null]" period1_mode="[null]" period1_param="[null]" period1_date="[null]"
+ period2_mode="[null]" period2_param="[null]" period2_date="[null]" period3_mode="[null]"
+ period3_param="[null]" period3_date="[null]" period4_mode="[null]" period4_param="[null]"
+ period4_date="[null]" period5_mode="[null]" period5_param="[null]" period5_date="[null]"
+ created_at="2008-12-20 00:00:00.00" build_date="2008-12-20 00:00:00.00"
+ version="1.0" status="P" islast="[true]"/>
+
+
+ <!-- alert -->
+ <project_measures id="1001" metric_id="5" value="510" snapshot_id="101"
+ url="[null]" variation_value_1="[null]" variation_value_2="[null]" variation_value_3="[null]"
+ variation_value_4="[null]" variation_value_5="400"
+ rule_priority="[null]" alert_text="[null]" RULES_CATEGORY_ID="[null]"
+ RULE_ID="[null]" text_value="WARN" tendency="[null]" measure_date="[null]" project_id="[null]"
+ alert_status="[null]" description="[null]" characteristic_id="[null]"/>
+
+ <!-- php project -->
+ <projects kee="php_project" long_name="PHP project" scope="PRJ" qualifier="TRK" name="PHP project"
+ id="10" root_id="[null]"
+ description="[null]" enabled="[true]" language="[null]" copy_resource_id="[null]" person_id="[null]"
+ created_at="2012-12-12 04:06:00.00"/>
+
+
+ <snapshots id="110" project_id="10" root_project_id="10" root_snapshot_id="[null]" parent_snapshot_id="[null]"
+ scope="PRJ" qualifier="TRK" path="" depth="0"
+ purge_status="[null]" period1_mode="[null]" period1_param="[null]" period1_date="[null]"
+ period2_mode="[null]" period2_param="[null]" period2_date="[null]" period3_mode="[null]"
+ period3_param="[null]" period3_date="[null]" period4_mode="[null]" period4_param="[null]"
+ period4_date="[null]" period5_mode="[null]" period5_param="[null]" period5_date="[null]"
+ created_at="2012-12-13 04:06:00.00" build_date="2012-12-13 04:06:00.00"
+ version="3.0" status="P" islast="[true]"/>
+
+ <!-- alert -->
+ <project_measures id="1010" metric_id="5" value="5000" snapshot_id="110"
+ url="[null]" variation_value_1="[null]" variation_value_2="[null]" variation_value_3="[null]"
+ variation_value_4="[null]" variation_value_5="[null]"
+ rule_priority="[null]" alert_text="[null]" RULES_CATEGORY_ID="[null]"
+ RULE_ID="[null]" text_value="OK" tendency="[null]" measure_date="[null]" project_id="[null]"
+ alert_status="[null]" description="[null]" characteristic_id="[null]"/>
+
+ <!-- js project -->
+ <projects kee="js_project" long_name="JS project" scope="PRJ" qualifier="TRK" name="JS project"
+ id="20" root_id="[null]"
+ description="[null]" enabled="[true]" language="[null]" copy_resource_id="[null]" person_id="[null]"
+ created_at="2012-12-12 04:06:00.00"/>
+
+
+ <snapshots id="120" project_id="20" root_project_id="20" root_snapshot_id="[null]" parent_snapshot_id="[null]"
+ scope="PRJ" qualifier="TRK" path="" depth="0"
+ purge_status="[null]" period1_mode="[null]" period1_param="[null]" period1_date="[null]"
+ period2_mode="[null]" period2_param="[null]" period2_date="[null]" period3_mode="[null]"
+ period3_param="[null]" period3_date="[null]" period4_mode="[null]" period4_param="[null]"
+ period4_date="[null]" period5_mode="[null]" period5_param="[null]" period5_date="[null]"
+ created_at="2012-12-13 04:06:00.00" build_date="2012-12-13 04:06:00.00"
+ version="3.0" status="P" islast="[true]"/>
+
+ <!-- alert -->
+ <project_measures id="1020" metric_id="5" value="5000" snapshot_id="120"
+ url="[null]" variation_value_1="[null]" variation_value_2="[null]" variation_value_3="[null]"
+ variation_value_4="[null]" variation_value_5="[null]"
+ rule_priority="[null]" alert_text="[null]" RULES_CATEGORY_ID="[null]"
+ RULE_ID="[null]" text_value="ERROR" tendency="[null]" measure_date="[null]" project_id="[null]"
+ alert_status="[null]" description="[null]" characteristic_id="[null]"/>
+
+
+</dataset>