@@ -44,6 +44,7 @@ import org.sonar.server.platform.ServerSettings; | |||
import org.sonar.server.platform.TempFolderProvider; | |||
import org.sonar.server.qualityprofile.db.ActiveRuleDao; | |||
import org.sonar.server.qualityprofile.index.ActiveRuleIndex; | |||
import org.sonar.server.qualityprofile.index.ActiveRuleIndex2; | |||
import org.sonar.server.qualityprofile.index.ActiveRuleNormalizer; | |||
import org.sonar.server.ruby.PlatformRackBridge; | |||
import org.sonar.server.rule.db.RuleDao; | |||
@@ -110,6 +111,7 @@ public class PlatformLevel1 extends PlatformLevel { | |||
// rules/qprofiles | |||
RuleIndex2.class, | |||
ActiveRuleIndex2.class, | |||
RuleNormalizer.class, | |||
ActiveRuleNormalizer.class, | |||
RuleIndex.class, |
@@ -223,6 +223,7 @@ import org.sonar.server.qualityprofile.QProfileService; | |||
import org.sonar.server.qualityprofile.QProfiles; | |||
import org.sonar.server.qualityprofile.RuleActivator; | |||
import org.sonar.server.qualityprofile.RuleActivatorContextFactory; | |||
import org.sonar.server.qualityprofile.index.ActiveRuleIndexer; | |||
import org.sonar.server.qualityprofile.ws.BackupAction; | |||
import org.sonar.server.qualityprofile.ws.BulkRuleActivationActions; | |||
import org.sonar.server.qualityprofile.ws.ChangeParentAction; | |||
@@ -387,6 +388,7 @@ public class PlatformLevel4 extends PlatformLevel { | |||
UpdateCenterWs.class, | |||
// quality profile | |||
ActiveRuleIndexer.class, | |||
XMLProfileParser.class, | |||
XMLProfileSerializer.class, | |||
AnnotationProfileParser.class, |
@@ -74,7 +74,6 @@ public class PlatformLevelStartup extends PlatformLevel { | |||
DoPrivileged.execute(new DoPrivileged.Task(getComponentByType(ThreadLocalUserSession.class)) { | |||
@Override | |||
protected void doPrivileged() { | |||
getComponentByType(IndexSynchronizer.class).executeDeprecated(); | |||
PlatformLevelStartup.super.start(); | |||
getComponentByType(IndexSynchronizer.class).execute(); | |||
getComponentByType(ServerLifecycleNotifier.class).notifyStart(); |
@@ -20,16 +20,15 @@ | |||
package org.sonar.server.qualityprofile; | |||
import com.google.common.collect.ImmutableList; | |||
import org.sonar.db.qualityprofile.ActiveRuleKey; | |||
import javax.annotation.CheckForNull; | |||
import java.util.Date; | |||
import java.util.List; | |||
import java.util.Map; | |||
import javax.annotation.CheckForNull; | |||
import org.sonar.db.qualityprofile.ActiveRuleKey; | |||
public interface ActiveRule { | |||
public enum Inheritance { | |||
enum Inheritance { | |||
NONE, OVERRIDES, INHERITED; | |||
public static final List<Inheritance> ALL = ImmutableList.of(NONE, OVERRIDES, INHERITED); | |||
} |
@@ -21,26 +21,24 @@ package org.sonar.server.qualityprofile; | |||
import com.google.common.collect.Lists; | |||
import com.google.common.collect.Multimap; | |||
import org.sonar.api.server.ServerSide; | |||
import java.util.HashMap; | |||
import java.util.Iterator; | |||
import java.util.List; | |||
import java.util.Map; | |||
import javax.annotation.CheckForNull; | |||
import org.sonar.api.rule.RuleKey; | |||
import org.sonar.api.rule.RuleStatus; | |||
import org.sonar.api.server.ServerSide; | |||
import org.sonar.db.DbClient; | |||
import org.sonar.db.DbSession; | |||
import org.sonar.db.qualityprofile.ActiveRuleKey; | |||
import org.sonar.db.qualityprofile.QualityProfileDto; | |||
import org.sonar.db.DbClient; | |||
import org.sonar.server.qualityprofile.index.ActiveRuleIndex; | |||
import org.sonar.server.rule.index.RuleIndex; | |||
import org.sonar.server.rule.index.RuleQuery; | |||
import org.sonar.server.search.FacetValue; | |||
import org.sonar.server.search.IndexClient; | |||
import org.sonar.server.search.QueryContext; | |||
import javax.annotation.CheckForNull; | |||
import java.util.HashMap; | |||
import java.util.Iterator; | |||
import java.util.List; | |||
import java.util.Map; | |||
import org.sonar.server.user.UserSession; | |||
@ServerSide | |||
@@ -102,10 +100,6 @@ public class QProfileLoader { | |||
return index.get(ActiveRuleIndex.class).findByProfile(key); | |||
} | |||
public long countActiveRulesByProfile(String key) { | |||
return index.get(ActiveRuleIndex.class).countByQualityProfileKey(key); | |||
} | |||
public Map<String, Long> countAllActiveRules() { | |||
Map<String, Long> counts = new HashMap<>(); | |||
for (Map.Entry<String, Long> entry : index.get(ActiveRuleIndex.class).countAllByQualityProfileKey().entrySet()) { | |||
@@ -114,10 +108,6 @@ public class QProfileLoader { | |||
return counts; | |||
} | |||
public Multimap<String, FacetValue> getStatsByProfile(String key) { | |||
return index.get(ActiveRuleIndex.class).getStatsByProfileKey(key); | |||
} | |||
public Map<String, Multimap<String, FacetValue>> getAllProfileStats() { | |||
List<String> keys = Lists.newArrayList(); | |||
for (QualityProfileDto profile : this.findAll()) { |
@@ -22,6 +22,8 @@ package org.sonar.server.qualityprofile.db; | |||
import com.google.common.base.Function; | |||
import com.google.common.base.Optional; | |||
import com.google.common.base.Preconditions; | |||
import java.util.List; | |||
import javax.annotation.CheckForNull; | |||
import java.util.ArrayList; | |||
import java.util.List; | |||
import javax.annotation.CheckForNull; | |||
@@ -44,6 +46,7 @@ import org.sonar.server.search.IndexDefinition; | |||
import static java.util.Collections.emptyList; | |||
@Deprecated | |||
public class ActiveRuleDao extends BaseDao<ActiveRuleMapper, ActiveRuleDto, ActiveRuleKey> { | |||
private static final String QUALITY_PROFILE_IS_NOT_PERSISTED = "Quality profile is not persisted (missing id)"; |
@@ -20,16 +20,26 @@ | |||
package org.sonar.server.qualityprofile.index; | |||
import com.google.common.base.Preconditions; | |||
import com.google.common.collect.Maps; | |||
import java.util.Collections; | |||
import java.util.Date; | |||
import java.util.Map; | |||
import javax.annotation.CheckForNull; | |||
import javax.annotation.Nullable; | |||
import org.sonar.db.qualityprofile.ActiveRuleKey; | |||
import org.sonar.server.qualityprofile.ActiveRule; | |||
import org.sonar.server.search.BaseDoc; | |||
import org.sonar.server.search.IndexUtils; | |||
import javax.annotation.CheckForNull; | |||
import java.util.Date; | |||
import java.util.HashMap; | |||
import java.util.List; | |||
import java.util.Map; | |||
import static org.sonar.server.rule.index.RuleIndexDefinition.FIELD_ACTIVE_RULE_CREATED_AT; | |||
import static org.sonar.server.rule.index.RuleIndexDefinition.FIELD_ACTIVE_RULE_INHERITANCE; | |||
import static org.sonar.server.rule.index.RuleIndexDefinition.FIELD_ACTIVE_RULE_KEY; | |||
import static org.sonar.server.rule.index.RuleIndexDefinition.FIELD_ACTIVE_RULE_PARENT_KEY; | |||
import static org.sonar.server.rule.index.RuleIndexDefinition.FIELD_ACTIVE_RULE_PROFILE_KEY; | |||
import static org.sonar.server.rule.index.RuleIndexDefinition.FIELD_ACTIVE_RULE_REPOSITORY; | |||
import static org.sonar.server.rule.index.RuleIndexDefinition.FIELD_ACTIVE_RULE_RULE_KEY; | |||
import static org.sonar.server.rule.index.RuleIndexDefinition.FIELD_ACTIVE_RULE_SEVERITY; | |||
import static org.sonar.server.rule.index.RuleIndexDefinition.FIELD_ACTIVE_RULE_UPDATED_AT; | |||
public class ActiveRuleDoc extends BaseDoc implements ActiveRule { | |||
@@ -37,33 +47,38 @@ public class ActiveRuleDoc extends BaseDoc implements ActiveRule { | |||
public ActiveRuleDoc(Map<String, Object> fields) { | |||
super(fields); | |||
this.key = ActiveRuleKey.parse((String) getField(ActiveRuleNormalizer.ActiveRuleField.KEY.field())); | |||
Preconditions.checkArgument(key!=null, "Invalid ActiveRuleKey!"); | |||
this.key = ActiveRuleKey.parse((String) getField(FIELD_ACTIVE_RULE_KEY)); | |||
Preconditions.checkArgument(key != null, "ActiveRuleKey cannot be null"); | |||
} | |||
@Override | |||
public Date createdAt() { | |||
return IndexUtils.parseDateTime((String) getNullableField(ActiveRuleNormalizer.ActiveRuleField.CREATED_AT.field())); | |||
} | |||
@Override | |||
public Date updatedAt() { | |||
return IndexUtils.parseDateTime((String) getNullableField(ActiveRuleNormalizer.ActiveRuleField.UPDATED_AT.field())); | |||
public ActiveRuleDoc(ActiveRuleKey key) { | |||
super(Maps.<String, Object>newHashMapWithExpectedSize(8)); | |||
Preconditions.checkNotNull(key, "ActiveRuleKey cannot be null"); | |||
this.key = key; | |||
setField(FIELD_ACTIVE_RULE_KEY, key.toString()); | |||
setField(FIELD_ACTIVE_RULE_PROFILE_KEY, key.qProfile()); | |||
setField(FIELD_ACTIVE_RULE_RULE_KEY, key.ruleKey().toString()); | |||
setField(FIELD_ACTIVE_RULE_REPOSITORY, key.ruleKey().repository()); | |||
} | |||
@Override | |||
public ActiveRuleKey key() { | |||
return this.key; | |||
return key; | |||
} | |||
@Override | |||
public String severity() { | |||
return (String) getNullableField(ActiveRuleNormalizer.ActiveRuleField.SEVERITY.field()); | |||
return (String) getNullableField(FIELD_ACTIVE_RULE_SEVERITY); | |||
} | |||
public ActiveRuleDoc setSeverity(@Nullable String s) { | |||
setField(FIELD_ACTIVE_RULE_SEVERITY, s); | |||
return this; | |||
} | |||
@Override | |||
public ActiveRule.Inheritance inheritance() { | |||
String inheritance = getNullableField(ActiveRuleNormalizer.ActiveRuleField.INHERITANCE.field()); | |||
String inheritance = getNullableField(FIELD_ACTIVE_RULE_INHERITANCE); | |||
if (inheritance == null || inheritance.isEmpty() || | |||
inheritance.toLowerCase().contains("none")) { | |||
return Inheritance.NONE; | |||
@@ -76,26 +91,61 @@ public class ActiveRuleDoc extends BaseDoc implements ActiveRule { | |||
} | |||
} | |||
public ActiveRuleDoc setInheritance(@Nullable String s) { | |||
setField(FIELD_ACTIVE_RULE_INHERITANCE, s); | |||
return this; | |||
} | |||
@Override | |||
@CheckForNull | |||
public ActiveRuleKey parentKey() { | |||
String data = getNullableField(ActiveRuleNormalizer.ActiveRuleField.PARENT_KEY.field()); | |||
String data = getNullableField(FIELD_ACTIVE_RULE_PARENT_KEY); | |||
if (data != null && !data.isEmpty()) { | |||
return ActiveRuleKey.parse(data); | |||
} | |||
return null; | |||
} | |||
public ActiveRuleDoc setParentKey(@Nullable String s) { | |||
setField(FIELD_ACTIVE_RULE_PARENT_KEY, s); | |||
return this; | |||
} | |||
@Override | |||
@Deprecated | |||
public Map<String, String> params() { | |||
Map<String, String> params = new HashMap<>(); | |||
List<Map<String, String>> allParams = getNullableField(ActiveRuleNormalizer.ActiveRuleField.PARAMS.field()); | |||
if (allParams != null) { | |||
for (Map<String, String> param : allParams) { | |||
params.put(param.get(ActiveRuleNormalizer.ActiveRuleParamField.NAME.field()), | |||
param.get(ActiveRuleNormalizer.ActiveRuleParamField.VALUE.field())); | |||
} | |||
} | |||
return params; | |||
return Collections.emptyMap(); | |||
} | |||
@Override | |||
@Deprecated | |||
public Date createdAt() { | |||
return IndexUtils.parseDateTime((String) getNullableField(FIELD_ACTIVE_RULE_CREATED_AT)); | |||
} | |||
@CheckForNull | |||
public Long createdAtAsLong() { | |||
return (Long) getField(FIELD_ACTIVE_RULE_CREATED_AT); | |||
} | |||
public ActiveRuleDoc setCreatedAt(@Nullable Long l) { | |||
setField(FIELD_ACTIVE_RULE_CREATED_AT, l); | |||
return this; | |||
} | |||
@Override | |||
@Deprecated | |||
public Date updatedAt() { | |||
return IndexUtils.parseDateTime((String) getNullableField(FIELD_ACTIVE_RULE_UPDATED_AT)); | |||
} | |||
@CheckForNull | |||
public Long updatedAtAsLong() { | |||
return (Long) getField(FIELD_ACTIVE_RULE_UPDATED_AT); | |||
} | |||
public ActiveRuleDoc setUpdatedAt(@Nullable Long l) { | |||
setField(FIELD_ACTIVE_RULE_UPDATED_AT, l); | |||
return this; | |||
} | |||
} |
@@ -19,7 +19,6 @@ | |||
*/ | |||
package org.sonar.server.qualityprofile.index; | |||
import com.google.common.collect.ImmutableList; | |||
import com.google.common.collect.Multimap; | |||
import java.util.ArrayList; | |||
import java.util.HashMap; | |||
@@ -48,6 +47,7 @@ import org.sonar.server.search.IndexDefinition; | |||
import org.sonar.server.search.IndexField; | |||
import org.sonar.server.search.SearchClient; | |||
@Deprecated | |||
public class ActiveRuleIndex extends BaseIndex<ActiveRule, ActiveRuleDto, ActiveRuleKey> { | |||
public static final String COUNT_ACTIVE_RULES = "countActiveRules"; | |||
@@ -138,7 +138,7 @@ public class ActiveRuleIndex extends BaseIndex<ActiveRule, ActiveRuleDto, Active | |||
.setQuery(QueryBuilders.filteredQuery(QueryBuilders.matchAllQuery(), FilterBuilders.boolFilter() | |||
.must(FilterBuilders.termFilter(ActiveRuleNormalizer.ActiveRuleField.PROFILE_KEY.field(), key)) | |||
.mustNot(FilterBuilders.hasParentFilter(this.getParentType(), | |||
FilterBuilders.termFilter(RuleIndexDefinition.FIELD_STATUS, RuleStatus.REMOVED.name()))))) | |||
FilterBuilders.termFilter(RuleIndexDefinition.FIELD_RULE_STATUS, RuleStatus.REMOVED.name()))))) | |||
.setRouting(key); | |||
SearchResponse response = request.get(); | |||
@@ -153,18 +153,14 @@ public class ActiveRuleIndex extends BaseIndex<ActiveRule, ActiveRuleDto, Active | |||
return countByField(ActiveRuleNormalizer.ActiveRuleField.PROFILE_KEY, | |||
FilterBuilders.hasParentFilter(IndexDefinition.RULE.getIndexType(), | |||
FilterBuilders.notFilter( | |||
FilterBuilders.termFilter(RuleIndexDefinition.FIELD_STATUS, "REMOVED")))).get(key); | |||
FilterBuilders.termFilter(RuleIndexDefinition.FIELD_RULE_STATUS, "REMOVED")))).get(key); | |||
} | |||
public Map<String, Long> countAllByQualityProfileKey() { | |||
return countByField(ActiveRuleNormalizer.ActiveRuleField.PROFILE_KEY, | |||
FilterBuilders.hasParentFilter(IndexDefinition.RULE.getIndexType(), | |||
FilterBuilders.notFilter( | |||
FilterBuilders.termFilter(RuleIndexDefinition.FIELD_STATUS, "REMOVED")))); | |||
} | |||
public Multimap<String, FacetValue> getStatsByProfileKey(String key) { | |||
return getStatsByProfileKeys(ImmutableList.of(key)).get(key); | |||
FilterBuilders.termFilter(RuleIndexDefinition.FIELD_RULE_STATUS, "REMOVED")))); | |||
} | |||
public Map<String, Multimap<String, FacetValue>> getStatsByProfileKeys(List<String> keys) { | |||
@@ -173,7 +169,7 @@ public class ActiveRuleIndex extends BaseIndex<ActiveRule, ActiveRuleDto, Active | |||
QueryBuilders.termsQuery(ActiveRuleNormalizer.ActiveRuleField.PROFILE_KEY.field(), keys), | |||
FilterBuilders.boolFilter() | |||
.mustNot(FilterBuilders.hasParentFilter(this.getParentType(), | |||
FilterBuilders.termFilter(RuleIndexDefinition.FIELD_STATUS, RuleStatus.REMOVED.name()))))) | |||
FilterBuilders.termFilter(RuleIndexDefinition.FIELD_RULE_STATUS, RuleStatus.REMOVED.name()))))) | |||
.addAggregation(AggregationBuilders.terms(ActiveRuleNormalizer.ActiveRuleField.PROFILE_KEY.field()) | |||
.field(ActiveRuleNormalizer.ActiveRuleField.PROFILE_KEY.field()).size(0) | |||
.subAggregation(AggregationBuilders.terms(ActiveRuleNormalizer.ActiveRuleField.INHERITANCE.field()) |
@@ -0,0 +1,229 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2016 SonarSource SA | |||
* mailto:contact AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.server.qualityprofile.index; | |||
import com.google.common.base.Function; | |||
import com.google.common.collect.ArrayListMultimap; | |||
import com.google.common.collect.Multimap; | |||
import java.util.ArrayList; | |||
import java.util.HashMap; | |||
import java.util.Iterator; | |||
import java.util.List; | |||
import java.util.Map; | |||
import javax.annotation.CheckForNull; | |||
import javax.annotation.Nonnull; | |||
import org.elasticsearch.action.get.GetRequestBuilder; | |||
import org.elasticsearch.action.get.GetResponse; | |||
import org.elasticsearch.action.search.SearchRequestBuilder; | |||
import org.elasticsearch.action.search.SearchResponse; | |||
import org.elasticsearch.action.search.SearchType; | |||
import org.elasticsearch.common.unit.TimeValue; | |||
import org.elasticsearch.index.query.FilterBuilder; | |||
import org.elasticsearch.index.query.FilterBuilders; | |||
import org.elasticsearch.index.query.QueryBuilders; | |||
import org.elasticsearch.search.SearchHit; | |||
import org.elasticsearch.search.aggregations.Aggregation; | |||
import org.elasticsearch.search.aggregations.AggregationBuilders; | |||
import org.elasticsearch.search.aggregations.Aggregations; | |||
import org.elasticsearch.search.aggregations.bucket.terms.StringTerms; | |||
import org.elasticsearch.search.aggregations.bucket.terms.Terms; | |||
import org.elasticsearch.search.aggregations.metrics.valuecount.InternalValueCount; | |||
import org.sonar.api.rule.RuleKey; | |||
import org.sonar.api.rule.RuleStatus; | |||
import org.sonar.db.qualityprofile.ActiveRuleKey; | |||
import org.sonar.server.es.BaseIndex; | |||
import org.sonar.server.es.EsClient; | |||
import org.sonar.server.qualityprofile.ActiveRule; | |||
import org.sonar.server.rule.index.RuleIndexDefinition; | |||
import org.sonar.server.search.FacetValue; | |||
import static org.sonar.server.es.EsUtils.SCROLL_TIME_IN_MINUTES; | |||
import static org.sonar.server.es.EsUtils.scroll; | |||
import static org.sonar.server.rule.index.RuleIndexDefinition.FIELD_ACTIVE_RULE_INHERITANCE; | |||
import static org.sonar.server.rule.index.RuleIndexDefinition.FIELD_ACTIVE_RULE_PROFILE_KEY; | |||
import static org.sonar.server.rule.index.RuleIndexDefinition.FIELD_ACTIVE_RULE_SEVERITY; | |||
import static org.sonar.server.rule.index.RuleIndexDefinition.FIELD_RULE_STATUS; | |||
import static org.sonar.server.rule.index.RuleIndexDefinition.INDEX; | |||
import static org.sonar.server.rule.index.RuleIndexDefinition.TYPE_ACTIVE_RULE; | |||
import static org.sonar.server.rule.index.RuleIndexDefinition.TYPE_RULE; | |||
/** | |||
* The unique entry-point to interact with Elasticsearch index "active rules". | |||
* All the requests are listed here. | |||
*/ | |||
public class ActiveRuleIndex2 extends BaseIndex { | |||
public static final String COUNT_ACTIVE_RULES = "countActiveRules"; | |||
public ActiveRuleIndex2(EsClient client) { | |||
super(client); | |||
} | |||
/** | |||
* @deprecated since 5.5, use {@link org.sonar.db.qualityprofile.ActiveRuleDao instead} | |||
*/ | |||
@Deprecated | |||
@CheckForNull | |||
public ActiveRule getNullableByKey(ActiveRuleKey key) { | |||
GetRequestBuilder request = getClient().prepareGet() | |||
.setIndex(RuleIndexDefinition.INDEX) | |||
.setType(RuleIndexDefinition.TYPE_ACTIVE_RULE) | |||
.setId(key.toString()) | |||
.setFetchSource(true) | |||
.setRouting(key.ruleKey().repository()); | |||
GetResponse response = request.get(); | |||
if (response.isExists()) { | |||
return new ActiveRuleDoc(response.getSource()); | |||
} | |||
return null; | |||
} | |||
/** | |||
* @deprecated since 5.5, use {@link org.sonar.db.qualityprofile.ActiveRuleDao instead} | |||
*/ | |||
@Deprecated | |||
public List<ActiveRule> findByRule(RuleKey key) { | |||
SearchRequestBuilder request = getClient().prepareSearch(RuleIndexDefinition.INDEX) | |||
.setQuery(QueryBuilders | |||
.hasParentQuery(RuleIndexDefinition.TYPE_RULE, | |||
QueryBuilders.idsQuery(RuleIndexDefinition.TYPE_RULE) | |||
.addIds(key.toString()) | |||
)) | |||
.setRouting(key.repository()) | |||
.setSize(Integer.MAX_VALUE); | |||
SearchResponse response = request.get(); | |||
List<ActiveRule> activeRules = new ArrayList<>(); | |||
for (SearchHit hit : response.getHits()) { | |||
activeRules.add(new ActiveRuleDoc(hit.getSource())); | |||
} | |||
return activeRules; | |||
} | |||
/** | |||
* @deprecated since 5.5, use {@link org.sonar.db.qualityprofile.ActiveRuleDao instead} | |||
*/ | |||
@Deprecated | |||
public Iterator<ActiveRuleDoc> findByProfile(String key) { | |||
SearchRequestBuilder request = getClient().prepareSearch(RuleIndexDefinition.INDEX) | |||
.setTypes(RuleIndexDefinition.TYPE_ACTIVE_RULE) | |||
.setSearchType(SearchType.SCAN) | |||
.setScroll(TimeValue.timeValueMinutes(SCROLL_TIME_IN_MINUTES)) | |||
.setSize(100) | |||
.setQuery(QueryBuilders.filteredQuery(QueryBuilders.matchAllQuery(), FilterBuilders.boolFilter() | |||
.must(FilterBuilders.termFilter(RuleIndexDefinition.FIELD_ACTIVE_RULE_PROFILE_KEY, key)) | |||
.mustNot(FilterBuilders.hasParentFilter(RuleIndexDefinition.TYPE_RULE, | |||
FilterBuilders.termFilter(RuleIndexDefinition.FIELD_RULE_STATUS, RuleStatus.REMOVED.name()))))); | |||
SearchResponse response = request.get(); | |||
return scroll(getClient(), response.getScrollId(), ToDoc.INSTANCE); | |||
} | |||
public Map<String, Long> countAllByQualityProfileKey() { | |||
return countByField(FIELD_ACTIVE_RULE_PROFILE_KEY, | |||
FilterBuilders.hasParentFilter(TYPE_RULE, | |||
FilterBuilders.notFilter( | |||
FilterBuilders.termFilter(FIELD_RULE_STATUS, "REMOVED")))); | |||
} | |||
private Map<String, Long> countByField(String indexField, FilterBuilder filter) { | |||
Map<String, Long> counts = new HashMap<>(); | |||
SearchRequestBuilder request = getClient().prepareSearch(INDEX) | |||
.setTypes(TYPE_ACTIVE_RULE) | |||
.setQuery(QueryBuilders.filteredQuery( | |||
QueryBuilders.matchAllQuery(), | |||
filter)) | |||
.setSize(0) | |||
.addAggregation(AggregationBuilders | |||
.terms(indexField) | |||
.field(indexField) | |||
.order(Terms.Order.count(false)) | |||
.size(Integer.MAX_VALUE) | |||
.minDocCount(0)); | |||
SearchResponse response = request.get(); | |||
Terms values = | |||
response.getAggregations().get(indexField); | |||
for (Terms.Bucket value : values.getBuckets()) { | |||
counts.put(value.getKey(), value.getDocCount()); | |||
} | |||
return counts; | |||
} | |||
public Map<String, Multimap<String, FacetValue>> getStatsByProfileKeys(List<String> keys) { | |||
SearchRequestBuilder request = getClient().prepareSearch(INDEX) | |||
.setQuery(QueryBuilders.filteredQuery( | |||
QueryBuilders.termsQuery(FIELD_ACTIVE_RULE_PROFILE_KEY, keys), | |||
FilterBuilders.boolFilter() | |||
.mustNot(FilterBuilders.hasParentFilter(TYPE_RULE, | |||
FilterBuilders.termFilter(FIELD_RULE_STATUS, RuleStatus.REMOVED.name()))))) | |||
.addAggregation(AggregationBuilders.terms(FIELD_ACTIVE_RULE_PROFILE_KEY) | |||
.field(RuleIndexDefinition.FIELD_ACTIVE_RULE_PROFILE_KEY).size(0) | |||
.subAggregation(AggregationBuilders.terms(FIELD_ACTIVE_RULE_INHERITANCE) | |||
.field(RuleIndexDefinition.FIELD_ACTIVE_RULE_INHERITANCE)) | |||
.subAggregation(AggregationBuilders.terms(FIELD_ACTIVE_RULE_SEVERITY) | |||
.field(RuleIndexDefinition.FIELD_ACTIVE_RULE_SEVERITY)) | |||
.subAggregation(AggregationBuilders.count(COUNT_ACTIVE_RULES))) | |||
.setSize(0) | |||
.setTypes(TYPE_ACTIVE_RULE); | |||
SearchResponse response = request.get(); | |||
Map<String, Multimap<String, FacetValue>> stats = new HashMap<>(); | |||
Aggregation aggregation = response.getAggregations().get(FIELD_ACTIVE_RULE_PROFILE_KEY); | |||
for (Terms.Bucket value : ((Terms) aggregation).getBuckets()) { | |||
stats.put(value.getKey(), processAggregations(value.getAggregations())); | |||
} | |||
return stats; | |||
} | |||
private Multimap<String, FacetValue> processAggregations(Aggregations aggregations) { | |||
Multimap<String, FacetValue> stats = ArrayListMultimap.create(); | |||
if (aggregations != null) { | |||
for (Aggregation aggregation : aggregations.asList()) { | |||
if (aggregation instanceof StringTerms) { | |||
for (Terms.Bucket value : ((Terms) aggregation).getBuckets()) { | |||
FacetValue facetValue = new FacetValue(value.getKey(), value.getDocCount()); | |||
stats.put(aggregation.getName(), facetValue); | |||
} | |||
} else if (aggregation instanceof InternalValueCount) { | |||
InternalValueCount count = (InternalValueCount) aggregation; | |||
FacetValue facetValue = new FacetValue(count.getName(), count.getValue()); | |||
stats.put(count.getName(), facetValue); | |||
} | |||
} | |||
} | |||
return stats; | |||
} | |||
private enum ToDoc implements Function<Map<String, Object>, ActiveRuleDoc> { | |||
INSTANCE; | |||
@Override | |||
public ActiveRuleDoc apply(@Nonnull Map<String, Object> input) { | |||
return new ActiveRuleDoc(input); | |||
} | |||
} | |||
} |
@@ -0,0 +1,155 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2016 SonarSource SA | |||
* mailto:contact AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.server.qualityprofile.index; | |||
import com.google.common.base.Function; | |||
import com.google.common.base.Predicate; | |||
import com.google.common.collect.FluentIterable; | |||
import java.util.Iterator; | |||
import java.util.List; | |||
import javax.annotation.Nonnull; | |||
import org.elasticsearch.action.index.IndexRequest; | |||
import org.elasticsearch.action.search.SearchRequestBuilder; | |||
import org.elasticsearch.index.query.FilterBuilders; | |||
import org.elasticsearch.index.query.QueryBuilders; | |||
import org.sonar.db.DbClient; | |||
import org.sonar.db.DbSession; | |||
import org.sonar.db.qualityprofile.ActiveRuleKey; | |||
import org.sonar.server.es.BaseIndexer; | |||
import org.sonar.server.es.BulkIndexer; | |||
import org.sonar.server.es.EsClient; | |||
import org.sonar.server.qualityprofile.ActiveRuleChange; | |||
import org.sonar.server.rule.index.RuleIndexDefinition; | |||
import static org.sonar.server.rule.index.RuleIndexDefinition.FIELD_ACTIVE_RULE_UPDATED_AT; | |||
import static org.sonar.server.rule.index.RuleIndexDefinition.INDEX; | |||
import static org.sonar.server.rule.index.RuleIndexDefinition.TYPE_ACTIVE_RULE; | |||
public class ActiveRuleIndexer extends BaseIndexer { | |||
private final DbClient dbClient; | |||
public ActiveRuleIndexer(DbClient dbClient, EsClient esClient) { | |||
super(esClient, 300, INDEX, TYPE_ACTIVE_RULE, FIELD_ACTIVE_RULE_UPDATED_AT); | |||
this.dbClient = dbClient; | |||
} | |||
@Override | |||
protected long doIndex(long lastUpdatedAt) { | |||
return doIndex(createBulkIndexer(false), lastUpdatedAt); | |||
} | |||
public void index(Iterator<ActiveRuleDoc> rules) { | |||
doIndex(createBulkIndexer(false), rules); | |||
} | |||
private long doIndex(BulkIndexer bulk, long lastUpdatedAt) { | |||
DbSession dbSession = dbClient.openSession(false); | |||
long maxDate; | |||
try { | |||
ActiveRuleResultSetIterator rowIt = ActiveRuleResultSetIterator.create(dbClient, dbSession, lastUpdatedAt); | |||
maxDate = doIndex(bulk, rowIt); | |||
rowIt.close(); | |||
return maxDate; | |||
} finally { | |||
dbSession.close(); | |||
} | |||
} | |||
private long doIndex(BulkIndexer bulk, Iterator<ActiveRuleDoc> activeRules) { | |||
bulk.start(); | |||
long maxDate = 0L; | |||
while (activeRules.hasNext()) { | |||
ActiveRuleDoc activeRule = activeRules.next(); | |||
bulk.add(newIndexRequest(activeRule)); | |||
// it's more efficient to sort programmatically than in SQL on some databases (MySQL for instance) | |||
maxDate = Math.max(maxDate, activeRule.updatedAtAsLong()); | |||
} | |||
bulk.stop(); | |||
return maxDate; | |||
} | |||
public void index(List<ActiveRuleChange> changes) { | |||
deleteKeys(FluentIterable.from(changes) | |||
.filter(MatchDeactivatedRule.INSTANCE) | |||
.transform(ActiveRuleChangeToKey.INSTANCE) | |||
.toList()); | |||
index(); | |||
} | |||
public void deleteProfile(String qualityProfileKey) { | |||
BulkIndexer bulk = new BulkIndexer(esClient, INDEX); | |||
bulk.start(); | |||
SearchRequestBuilder search = esClient.prepareSearch(INDEX) | |||
.setTypes(TYPE_ACTIVE_RULE) | |||
.setQuery(QueryBuilders.filteredQuery( | |||
QueryBuilders.matchAllQuery(), | |||
FilterBuilders.boolFilter().must(FilterBuilders.termsFilter(RuleIndexDefinition.FIELD_ACTIVE_RULE_PROFILE_KEY, qualityProfileKey)) | |||
)); | |||
bulk.addDeletion(search); | |||
bulk.stop(); | |||
} | |||
private void deleteKeys(List<ActiveRuleKey> keys) { | |||
BulkIndexer bulk = new BulkIndexer(esClient, INDEX); | |||
bulk.start(); | |||
SearchRequestBuilder search = esClient.prepareSearch(INDEX) | |||
.setTypes(TYPE_ACTIVE_RULE) | |||
.setQuery(QueryBuilders.filteredQuery( | |||
QueryBuilders.matchAllQuery(), | |||
FilterBuilders.boolFilter().must(FilterBuilders.termsFilter(RuleIndexDefinition.FIELD_ACTIVE_RULE_KEY, keys)) | |||
)); | |||
bulk.addDeletion(search); | |||
bulk.stop(); | |||
} | |||
private BulkIndexer createBulkIndexer(boolean large) { | |||
BulkIndexer bulk = new BulkIndexer(esClient, INDEX); | |||
bulk.setLarge(large); | |||
return bulk; | |||
} | |||
private IndexRequest newIndexRequest(ActiveRuleDoc doc) { | |||
return new IndexRequest(INDEX, TYPE_ACTIVE_RULE, doc.key().toString()) | |||
.parent(doc.key().ruleKey().toString()) | |||
.routing(doc.key().ruleKey().repository()) | |||
.source(doc.getFields()); | |||
} | |||
private enum MatchDeactivatedRule implements Predicate<ActiveRuleChange> { | |||
INSTANCE; | |||
@Override | |||
public boolean apply(@Nonnull ActiveRuleChange input) { | |||
return input.getType().equals(ActiveRuleChange.Type.DEACTIVATED); | |||
} | |||
} | |||
private enum ActiveRuleChangeToKey implements Function<ActiveRuleChange, ActiveRuleKey> { | |||
INSTANCE; | |||
@Override | |||
public ActiveRuleKey apply(@Nonnull ActiveRuleChange input) { | |||
return input.getKey(); | |||
} | |||
} | |||
} |
@@ -112,9 +112,9 @@ public class ActiveRuleNormalizer extends BaseNormalizer<ActiveRuleDto, ActiveRu | |||
/* Creating updateRequest */ | |||
requests.add(new UpdateRequest() | |||
.id(key.toString()) | |||
.routing(key.ruleKey().toString()) | |||
.id(activeRuleDto.getKey().toString()) | |||
.parent(activeRuleDto.getKey().ruleKey().toString()) | |||
.parent(key.ruleKey().toString()) | |||
.doc(newRule) | |||
.upsert(getUpsertFor(ActiveRuleField.ALL_FIELDS, newRule))); | |||
@@ -0,0 +1,105 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2016 SonarSource SA | |||
* mailto:contact AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.server.qualityprofile.index; | |||
import java.sql.PreparedStatement; | |||
import java.sql.ResultSet; | |||
import java.sql.SQLException; | |||
import org.apache.commons.lang.StringUtils; | |||
import org.sonar.api.rule.RuleKey; | |||
import org.sonar.db.DbClient; | |||
import org.sonar.db.DbSession; | |||
import org.sonar.db.ResultSetIterator; | |||
import org.sonar.db.qualityprofile.ActiveRuleKey; | |||
import org.sonar.db.rule.SeverityUtil; | |||
import org.sonar.server.qualityprofile.ActiveRule; | |||
/** | |||
* Scrolls over table ACTIVE_RULES and reads documents to populate the active rules index | |||
*/ | |||
public class ActiveRuleResultSetIterator extends ResultSetIterator<ActiveRuleDoc> { | |||
private static final String[] FIELDS = { | |||
// column 1 | |||
"a.failure_level", | |||
"a.inheritance", | |||
"r.plugin_rule_key", | |||
"r.plugin_name", | |||
"qp.kee", | |||
"profile_parent.kee", | |||
"a.created_at_ms", | |||
"a.updated_at_ms" | |||
}; | |||
private static final String SQL_ALL = "SELECT " + StringUtils.join(FIELDS, ",") + " FROM active_rules a " + | |||
"INNER JOIN rules_profiles qp ON qp.id=a.profile_id " + | |||
"INNER JOIN rules r ON r.id = a.rule_id " + | |||
"LEFT JOIN rules_profiles profile_parent ON profile_parent.kee=qp.parent_kee "; | |||
private static final String SQL_AFTER_DATE = SQL_ALL + " WHERE a.updated_at_ms>?"; | |||
private ActiveRuleResultSetIterator(PreparedStatement stmt) throws SQLException { | |||
super(stmt); | |||
} | |||
static ActiveRuleResultSetIterator create(DbClient dbClient, DbSession session, long afterDate) { | |||
try { | |||
String sql = afterDate > 0L ? SQL_AFTER_DATE : SQL_ALL; | |||
PreparedStatement stmt = dbClient.getMyBatis().newScrollingSelectStatement(session, sql); | |||
if (afterDate > 0L) { | |||
stmt.setLong(1, afterDate); | |||
} | |||
return new ActiveRuleResultSetIterator(stmt); | |||
} catch (SQLException e) { | |||
throw new IllegalStateException("Fail to prepare SQL request to select all active rules", e); | |||
} | |||
} | |||
@Override | |||
protected ActiveRuleDoc read(ResultSet rs) throws SQLException { | |||
RuleKey ruleKey = RuleKey.of(rs.getString(4), rs.getString(3)); | |||
ActiveRuleKey activeRuleKey = ActiveRuleKey.of(rs.getString(5), ruleKey); | |||
ActiveRuleDoc doc = new ActiveRuleDoc(activeRuleKey); | |||
// all the fields must be present, even if value is null | |||
doc.setSeverity(SeverityUtil.getSeverityFromOrdinal(rs.getInt(1))); | |||
String inheritance = rs.getString(2); | |||
if (inheritance != null) { | |||
doc.setInheritance(inheritance); | |||
} else { | |||
doc.setInheritance(ActiveRule.Inheritance.NONE.name()); | |||
} | |||
String parentProfileKey = rs.getString(6); | |||
if (parentProfileKey != null) { | |||
doc.setParentKey(ActiveRuleKey.of(parentProfileKey, ruleKey).toString()); | |||
} else { | |||
doc.setParentKey(null); | |||
} | |||
doc.setCreatedAt(rs.getLong(7)); | |||
doc.setUpdatedAt(rs.getLong(8)); | |||
return doc; | |||
} | |||
} |
@@ -20,28 +20,27 @@ | |||
package org.sonar.server.qualityprofile.ws; | |||
import com.google.common.collect.Multimap; | |||
import java.util.List; | |||
import java.util.Map; | |||
import javax.annotation.Nullable; | |||
import org.sonar.api.resources.Languages; | |||
import org.sonar.api.server.ws.Request; | |||
import org.sonar.api.server.ws.Response; | |||
import org.sonar.api.server.ws.WebService.NewAction; | |||
import org.sonar.api.server.ws.WebService.NewController; | |||
import org.sonar.api.utils.text.JsonWriter; | |||
import org.sonar.db.DbClient; | |||
import org.sonar.db.DbSession; | |||
import org.sonar.db.qualityprofile.QualityProfileDto; | |||
import org.sonar.db.DbClient; | |||
import org.sonar.server.exceptions.NotFoundException; | |||
import org.sonar.server.qualityprofile.QProfile; | |||
import org.sonar.server.qualityprofile.QProfileFactory; | |||
import org.sonar.server.qualityprofile.QProfileLoader; | |||
import org.sonar.server.qualityprofile.QProfileLookup; | |||
import org.sonar.server.qualityprofile.index.ActiveRuleIndex; | |||
import org.sonar.server.qualityprofile.index.ActiveRuleNormalizer; | |||
import org.sonar.server.rule.index.RuleIndexDefinition; | |||
import org.sonar.server.search.FacetValue; | |||
import javax.annotation.Nullable; | |||
import java.util.List; | |||
import java.util.Map; | |||
import static org.sonar.server.qualityprofile.index.ActiveRuleIndex2.COUNT_ACTIVE_RULES; | |||
public class InheritanceAction implements QProfileWsAction { | |||
@@ -148,16 +147,16 @@ public class InheritanceAction implements QProfileWsAction { | |||
private Long getActiveRuleCount(Multimap<String, FacetValue> profileStats) { | |||
Long result = null; | |||
if (profileStats.containsKey(ActiveRuleIndex.COUNT_ACTIVE_RULES)) { | |||
result = profileStats.get(ActiveRuleIndex.COUNT_ACTIVE_RULES).iterator().next().getValue(); | |||
if (profileStats.containsKey(COUNT_ACTIVE_RULES)) { | |||
result = profileStats.get(COUNT_ACTIVE_RULES).iterator().next().getValue(); | |||
} | |||
return result; | |||
} | |||
private Long getOverridingRuleCount(Multimap<String, FacetValue> profileStats) { | |||
Long result = null; | |||
if (profileStats.containsKey(ActiveRuleNormalizer.ActiveRuleField.INHERITANCE.field())) { | |||
for (FacetValue value : profileStats.get(ActiveRuleNormalizer.ActiveRuleField.INHERITANCE.field())) { | |||
if (profileStats.containsKey(RuleIndexDefinition.FIELD_ACTIVE_RULE_INHERITANCE)) { | |||
for (FacetValue value : profileStats.get(RuleIndexDefinition.FIELD_ACTIVE_RULE_INHERITANCE)) { | |||
if ("OVERRIDES".equals(value.getKey())) { | |||
result = value.getValue(); | |||
} |
@@ -64,8 +64,6 @@ import org.sonar.server.es.BaseIndex; | |||
import org.sonar.server.es.EsClient; | |||
import org.sonar.server.es.SearchIdResult; | |||
import org.sonar.server.es.SearchOptions; | |||
import org.sonar.server.qualityprofile.index.ActiveRuleNormalizer; | |||
import org.sonar.server.search.IndexDefinition; | |||
import org.sonar.server.search.IndexField; | |||
import org.sonar.server.search.StickyFacetBuilder; | |||
@@ -276,9 +274,9 @@ public class RuleIndex2 extends BaseIndex { | |||
// ActiveRule Filter (profile and inheritance) | |||
BoolFilterBuilder childrenFilter = FilterBuilders.boolFilter(); | |||
this.addTermFilter(childrenFilter, ActiveRuleNormalizer.ActiveRuleField.PROFILE_KEY.field(), query.getQProfileKey()); | |||
this.addTermFilter(childrenFilter, ActiveRuleNormalizer.ActiveRuleField.INHERITANCE.field(), query.getInheritance()); | |||
this.addTermFilter(childrenFilter, ActiveRuleNormalizer.ActiveRuleField.SEVERITY.field(), query.getActiveSeverities()); | |||
addTermFilter(childrenFilter, RuleIndexDefinition.FIELD_ACTIVE_RULE_PROFILE_KEY, query.getQProfileKey()); | |||
addTermFilter(childrenFilter, RuleIndexDefinition.FIELD_ACTIVE_RULE_INHERITANCE, query.getInheritance()); | |||
addTermFilter(childrenFilter, RuleIndexDefinition.FIELD_ACTIVE_RULE_SEVERITY, query.getActiveSeverities()); | |||
// ChildQuery | |||
FilterBuilder childQuery; | |||
@@ -291,12 +289,12 @@ public class RuleIndex2 extends BaseIndex { | |||
/** Implementation of activation query */ | |||
if (Boolean.TRUE.equals(query.getActivation())) { | |||
filters.put("activation", | |||
FilterBuilders.hasChildFilter(IndexDefinition.ACTIVE_RULE.getIndexType(), | |||
FilterBuilders.hasChildFilter(RuleIndexDefinition.TYPE_ACTIVE_RULE, | |||
childQuery)); | |||
} else if (Boolean.FALSE.equals(query.getActivation())) { | |||
filters.put("activation", | |||
FilterBuilders.boolFilter().mustNot( | |||
FilterBuilders.hasChildFilter(IndexDefinition.ACTIVE_RULE.getIndexType(), | |||
FilterBuilders.hasChildFilter(RuleIndexDefinition.TYPE_ACTIVE_RULE, | |||
childQuery))); | |||
} | |||
@@ -383,13 +381,13 @@ public class RuleIndex2 extends BaseIndex { | |||
// so the rule filter has to be used as parent filter for active rules | |||
// from which we remove filters that concern active rules ("activation") | |||
HasParentFilterBuilder ruleFilter = FilterBuilders.hasParentFilter( | |||
IndexDefinition.RULE.getIndexType(), | |||
RuleIndexDefinition.TYPE_RULE, | |||
stickyFacetBuilder.getStickyFacetFilter("activation")); | |||
// Rebuilding the active rule filter without severities | |||
BoolFilterBuilder childrenFilter = FilterBuilders.boolFilter(); | |||
this.addTermFilter(childrenFilter, ActiveRuleNormalizer.ActiveRuleField.PROFILE_KEY.field(), query.getQProfileKey()); | |||
this.addTermFilter(childrenFilter, ActiveRuleNormalizer.ActiveRuleField.INHERITANCE.field(), query.getInheritance()); | |||
this.addTermFilter(childrenFilter, RuleIndexDefinition.FIELD_ACTIVE_RULE_PROFILE_KEY, query.getQProfileKey()); | |||
this.addTermFilter(childrenFilter, RuleIndexDefinition.FIELD_ACTIVE_RULE_INHERITANCE, query.getInheritance()); | |||
FilterBuilder activeRuleFilter; | |||
if (childrenFilter.hasClauses()) { | |||
activeRuleFilter = childrenFilter.must(ruleFilter); | |||
@@ -398,13 +396,13 @@ public class RuleIndex2 extends BaseIndex { | |||
} | |||
AggregationBuilder activeSeverities = AggregationBuilders.children(FACET_ACTIVE_SEVERITIES + "_children") | |||
.childType(IndexDefinition.ACTIVE_RULE.getIndexType()) | |||
.childType(RuleIndexDefinition.TYPE_ACTIVE_RULE) | |||
.subAggregation(AggregationBuilders.filter(FACET_ACTIVE_SEVERITIES + "_filter") | |||
.filter(activeRuleFilter) | |||
.subAggregation( | |||
AggregationBuilders | |||
.terms(FACET_ACTIVE_SEVERITIES) | |||
.field(ActiveRuleNormalizer.ActiveRuleField.SEVERITY.field()) | |||
.field(RuleIndexDefinition.FIELD_ACTIVE_RULE_SEVERITY) | |||
.include(Joiner.on('|').join(Severity.ALL)) | |||
.size(Severity.ALL.size()))); | |||
@@ -58,6 +58,19 @@ public class RuleIndexDefinition implements IndexDefinition { | |||
RuleIndexDefinition.FIELD_RULE_KEY | |||
); | |||
// Active rule fields | |||
public static final String TYPE_ACTIVE_RULE = "activeRule"; | |||
public static final String FIELD_ACTIVE_RULE_KEY = "key"; | |||
public static final String FIELD_ACTIVE_RULE_REPOSITORY = "repo"; | |||
public static final String FIELD_ACTIVE_RULE_INHERITANCE = "inheritance"; | |||
public static final String FIELD_ACTIVE_RULE_PROFILE_KEY = "profile"; | |||
public static final String FIELD_ACTIVE_RULE_SEVERITY = "severity"; | |||
public static final String FIELD_ACTIVE_RULE_PARENT_KEY = "parentKey"; | |||
public static final String FIELD_ACTIVE_RULE_RULE_KEY = "ruleKey"; | |||
public static final String FIELD_ACTIVE_RULE_CREATED_AT = "createdAt"; | |||
public static final String FIELD_ACTIVE_RULE_UPDATED_AT = "updatedAt"; | |||
private final Settings settings; | |||
public RuleIndexDefinition(Settings settings) { | |||
@@ -96,5 +109,22 @@ public class RuleIndexDefinition implements IndexDefinition { | |||
ruleMapping.createLongField(FIELD_RULE_CREATED_AT); | |||
ruleMapping.createLongField(FIELD_RULE_UPDATED_AT); | |||
// Active rule type | |||
NewIndex.NewIndexType activeRuleMapping = index.createType(RuleIndexDefinition.TYPE_ACTIVE_RULE); | |||
activeRuleMapping.setAttribute("_id", ImmutableMap.of("path", RuleIndexDefinition.FIELD_ACTIVE_RULE_KEY)); | |||
activeRuleMapping.setAttribute("_parent", ImmutableMap.of("type", RuleIndexDefinition.TYPE_RULE)); | |||
activeRuleMapping.setAttribute("_routing", ImmutableMap.of("required", true, "path", RuleIndexDefinition.FIELD_ACTIVE_RULE_REPOSITORY)); | |||
activeRuleMapping.stringFieldBuilder(RuleIndexDefinition.FIELD_ACTIVE_RULE_KEY).enableSorting().enableGramSearch().build(); | |||
activeRuleMapping.stringFieldBuilder(RuleIndexDefinition.FIELD_ACTIVE_RULE_RULE_KEY).disableSearch().docValues().build(); | |||
activeRuleMapping.stringFieldBuilder(RuleIndexDefinition.FIELD_ACTIVE_RULE_REPOSITORY).disableSearch().docValues().build(); | |||
activeRuleMapping.stringFieldBuilder(RuleIndexDefinition.FIELD_ACTIVE_RULE_PROFILE_KEY).docValues().build(); | |||
activeRuleMapping.stringFieldBuilder(RuleIndexDefinition.FIELD_ACTIVE_RULE_INHERITANCE).docValues().build(); | |||
activeRuleMapping.stringFieldBuilder(RuleIndexDefinition.FIELD_ACTIVE_RULE_SEVERITY).docValues().build(); | |||
activeRuleMapping.stringFieldBuilder(RuleIndexDefinition.FIELD_ACTIVE_RULE_PARENT_KEY).disableSearch().docValues().build(); | |||
activeRuleMapping.createLongField(RuleIndexDefinition.FIELD_ACTIVE_RULE_CREATED_AT); | |||
activeRuleMapping.createLongField(RuleIndexDefinition.FIELD_ACTIVE_RULE_UPDATED_AT); | |||
} | |||
} |
@@ -19,7 +19,6 @@ | |||
*/ | |||
package org.sonar.server.rule.index; | |||
import com.google.common.annotations.VisibleForTesting; | |||
import java.util.Iterator; | |||
import org.elasticsearch.action.index.IndexRequest; | |||
import org.sonar.db.DbClient; | |||
@@ -46,8 +45,7 @@ public class RuleIndexer extends BaseIndexer { | |||
return doIndex(createBulkIndexer(false), lastUpdatedAt); | |||
} | |||
@VisibleForTesting | |||
void index(Iterator<RuleDoc> rules) { | |||
public void index(Iterator<RuleDoc> rules) { | |||
doIndex(createBulkIndexer(false), rules); | |||
} | |||
@@ -70,11 +68,11 @@ public class RuleIndexer extends BaseIndexer { | |||
while (rules.hasNext()) { | |||
RuleDoc rule = rules.next(); | |||
// TODO when active rule is not more DAO v2, restore deleting of REMOVED rules and also remove active rules linked to this rule | |||
// if (rule.status() == RuleStatus.REMOVED) { | |||
// bulk.add(newDeleteRequest(rule)); | |||
// } else { | |||
// } | |||
bulk.add(newUpsertRequest(rule)); | |||
// if (rule.status() == RuleStatus.REMOVED) { | |||
// bulk.add(newDeleteRequest(rule)); | |||
// } else { | |||
// } | |||
bulk.add(newIndexRequest(rule)); | |||
// it's more efficient to sort programmatically than in SQL on some databases (MySQL for instance) | |||
maxDate = Math.max(maxDate, rule.updatedAtAtAsLong()); | |||
@@ -89,15 +87,15 @@ public class RuleIndexer extends BaseIndexer { | |||
return bulk; | |||
} | |||
private IndexRequest newUpsertRequest(RuleDoc rule) { | |||
private IndexRequest newIndexRequest(RuleDoc rule) { | |||
return new IndexRequest(INDEX, TYPE_RULE, rule.key().toString()) | |||
.routing(rule.repository()) | |||
.source(rule.getFields()); | |||
} | |||
// private DeleteRequest newDeleteRequest(RuleDoc rule) { | |||
// return new DeleteRequest(INDEX, TYPE_RULE, rule.key().toString()) | |||
// .routing(rule.repository()); | |||
// } | |||
// private DeleteRequest newDeleteRequest(RuleDoc rule) { | |||
// return new DeleteRequest(INDEX, TYPE_RULE, rule.key().toString()) | |||
// .routing(rule.repository()); | |||
// } | |||
} |
@@ -19,17 +19,12 @@ | |||
*/ | |||
package org.sonar.server.search; | |||
import java.util.Date; | |||
import org.sonar.api.config.Settings; | |||
import org.sonar.api.utils.log.Logger; | |||
import org.sonar.api.utils.log.Loggers; | |||
import org.sonar.db.DbSession; | |||
import org.sonar.server.activity.index.ActivityIndexer; | |||
import org.sonar.server.db.DbClient; | |||
import org.sonar.server.db.DeprecatedDao; | |||
import org.sonar.server.issue.index.IssueAuthorizationIndexer; | |||
import org.sonar.server.issue.index.IssueIndexer; | |||
import org.sonar.server.qualityprofile.index.ActiveRuleIndex; | |||
import org.sonar.server.test.index.TestIndexer; | |||
import org.sonar.server.user.index.UserIndexer; | |||
import org.sonar.server.view.index.ViewIndexer; | |||
@@ -38,8 +33,6 @@ public class IndexSynchronizer { | |||
private static final Logger LOG = Loggers.get(IndexSynchronizer.class); | |||
private final DbClient db; | |||
private final IndexClient index; | |||
private final TestIndexer testIndexer; | |||
private final IssueAuthorizationIndexer issueAuthorizationIndexer; | |||
private final IssueIndexer issueIndexer; | |||
@@ -53,12 +46,9 @@ public class IndexSynchronizer { | |||
* because we need {@link org.sonar.server.issue.index.IssueAuthorizationIndexer} to be executed before | |||
* {@link org.sonar.server.issue.index.IssueIndexer} | |||
*/ | |||
public IndexSynchronizer(DbClient db, IndexClient index, | |||
TestIndexer testIndexer, IssueAuthorizationIndexer issueAuthorizationIndexer, IssueIndexer issueIndexer, | |||
public IndexSynchronizer(TestIndexer testIndexer, IssueAuthorizationIndexer issueAuthorizationIndexer, IssueIndexer issueIndexer, | |||
UserIndexer userIndexer, ViewIndexer viewIndexer, ActivityIndexer activityIndexer, | |||
Settings settings) { | |||
this.db = db; | |||
this.index = index; | |||
this.testIndexer = testIndexer; | |||
this.issueAuthorizationIndexer = issueAuthorizationIndexer; | |||
this.issueIndexer = issueIndexer; | |||
@@ -68,17 +58,6 @@ public class IndexSynchronizer { | |||
this.settings = settings; | |||
} | |||
public void executeDeprecated() { | |||
DbSession session = db.openSession(false); | |||
try { | |||
// synchronize(session, db.deprecatedRuleDao(), index.get(RuleIndex.class)); | |||
synchronize(session, db.activeRuleDao(), index.get(ActiveRuleIndex.class)); | |||
session.commit(); | |||
} finally { | |||
session.close(); | |||
} | |||
} | |||
public void execute() { | |||
if (!settings.getBoolean("sonar.internal.es.disableIndexes")) { | |||
LOG.info("Index activities"); | |||
@@ -99,14 +78,4 @@ public class IndexSynchronizer { | |||
} | |||
} | |||
void synchronize(DbSession session, DeprecatedDao dao, Index index) { | |||
long count = index.getIndexStat().getDocumentCount(); | |||
Date lastSynch = index.getLastSynchronization(); | |||
LOG.info("Index {}s", index.getIndexType()); | |||
if (count <= 0) { | |||
dao.synchronizeAfter(session); | |||
} else { | |||
dao.synchronizeAfter(session, lastSynch); | |||
} | |||
} | |||
} |
@@ -222,7 +222,7 @@ public class EsTester extends ExternalResource { | |||
})); | |||
} | |||
public List<String> getIds(String indexName, String typeName){ | |||
public List<String> getIds(String indexName, String typeName) { | |||
return FluentIterable.from(getDocuments(indexName, typeName)).transform(SearchHitToId.INSTANCE).toList(); | |||
} | |||
@@ -234,7 +234,7 @@ public class EsTester extends ExternalResource { | |||
return client; | |||
} | |||
private enum SearchHitToId implements Function<SearchHit, String>{ | |||
private enum SearchHitToId implements Function<SearchHit, String> { | |||
INSTANCE; | |||
@Override |
@@ -0,0 +1,39 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2016 SonarSource SA | |||
* mailto:contact AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.server.qualityprofile.index; | |||
import org.sonar.api.rule.Severity; | |||
import org.sonar.db.qualityprofile.ActiveRuleKey; | |||
import org.sonar.db.rule.RuleTesting; | |||
public class ActiveRuleDocTesting { | |||
public static ActiveRuleDoc newDoc() { | |||
return newDoc(ActiveRuleKey.of("sonar-way", RuleTesting.XOO_X1)); | |||
} | |||
public static ActiveRuleDoc newDoc(ActiveRuleKey key) { | |||
return new ActiveRuleDoc(key) | |||
.setSeverity(Severity.CRITICAL) | |||
.setParentKey(null) | |||
.setInheritance(null).setCreatedAt(150000000L) | |||
.setUpdatedAt(160000000L); | |||
} | |||
} |
@@ -0,0 +1,242 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2016 SonarSource SA | |||
* mailto:contact AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.server.qualityprofile.index; | |||
import com.google.common.collect.ImmutableList; | |||
import com.google.common.collect.Lists; | |||
import com.google.common.collect.Multimap; | |||
import java.util.ArrayList; | |||
import java.util.List; | |||
import java.util.Map; | |||
import org.junit.Before; | |||
import org.junit.ClassRule; | |||
import org.junit.Test; | |||
import org.sonar.api.config.Settings; | |||
import org.sonar.api.rule.RuleKey; | |||
import org.sonar.api.rule.RuleStatus; | |||
import org.sonar.db.qualityprofile.ActiveRuleKey; | |||
import org.sonar.db.rule.RuleTesting; | |||
import org.sonar.server.es.EsTester; | |||
import org.sonar.server.qualityprofile.ActiveRule; | |||
import org.sonar.server.rule.index.RuleDoc; | |||
import org.sonar.server.rule.index.RuleDocTesting; | |||
import org.sonar.server.rule.index.RuleIndexDefinition; | |||
import org.sonar.server.rule.index.RuleIndexer; | |||
import org.sonar.server.search.FacetValue; | |||
import static java.util.Arrays.asList; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.assertj.core.api.Assertions.entry; | |||
import static org.sonar.api.rule.Severity.BLOCKER; | |||
import static org.sonar.api.rule.Severity.MAJOR; | |||
import static org.sonar.api.rule.Severity.MINOR; | |||
import static org.sonar.server.qualityprofile.ActiveRule.Inheritance.INHERITED; | |||
import static org.sonar.server.qualityprofile.ActiveRule.Inheritance.OVERRIDES; | |||
import static org.sonar.server.rule.index.RuleDocTesting.newDoc; | |||
import static org.sonar.server.rule.index.RuleIndexDefinition.INDEX; | |||
import static org.sonar.server.rule.index.RuleIndexDefinition.TYPE_ACTIVE_RULE; | |||
public class ActiveRuleIndex2Test { | |||
static final RuleKey RULE_KEY_1 = RuleTesting.XOO_X1; | |||
static final RuleKey RULE_KEY_2 = RuleTesting.XOO_X2; | |||
static final String QUALITY_PROFILE_KEY1 = "qp1"; | |||
static final String QUALITY_PROFILE_KEY2 = "qp2"; | |||
@ClassRule | |||
public static EsTester tester = new EsTester().addDefinitions(new RuleIndexDefinition(new Settings())); | |||
ActiveRuleIndex2 index; | |||
ActiveRuleIndexer activeRuleIndexer; | |||
RuleIndexer ruleIndexer; | |||
@Before | |||
public void setUp() { | |||
tester.truncateIndices(); | |||
activeRuleIndexer = new ActiveRuleIndexer(null, tester.client()); | |||
ruleIndexer = new RuleIndexer(null, tester.client()); | |||
index = new ActiveRuleIndex2(tester.client()); | |||
} | |||
@Test | |||
public void count_all_by_quality_profile_key() { | |||
indexRules(RuleDocTesting.newDoc(RULE_KEY_1)); | |||
indexActiveRules( | |||
ActiveRuleDocTesting.newDoc(ActiveRuleKey.of(QUALITY_PROFILE_KEY1, RULE_KEY_1)), | |||
ActiveRuleDocTesting.newDoc(ActiveRuleKey.of(QUALITY_PROFILE_KEY2, RULE_KEY_1))); | |||
// 0. Test base case | |||
assertThat(tester.countDocuments(INDEX, TYPE_ACTIVE_RULE)).isEqualTo(2); | |||
// 1. Assert by term aggregation; | |||
assertThat(index.countAllByQualityProfileKey()).containsOnly(entry(QUALITY_PROFILE_KEY1, 1L), entry(QUALITY_PROFILE_KEY2, 1L)); | |||
} | |||
@Test | |||
public void stats_for_all() { | |||
indexRules( | |||
newDoc(RULE_KEY_1), | |||
newDoc(RULE_KEY_2)); | |||
ActiveRuleKey activeRuleKey1 = ActiveRuleKey.of(QUALITY_PROFILE_KEY1, RULE_KEY_1); | |||
ActiveRuleKey activeRuleKey2 = ActiveRuleKey.of(QUALITY_PROFILE_KEY1, RULE_KEY_2); | |||
indexActiveRules( | |||
ActiveRuleDocTesting.newDoc(activeRuleKey1).setSeverity(BLOCKER), | |||
ActiveRuleDocTesting.newDoc(activeRuleKey2).setSeverity(MINOR), | |||
// Profile 2 is a child a profile 1 | |||
ActiveRuleDocTesting.newDoc(ActiveRuleKey.of(QUALITY_PROFILE_KEY2, RULE_KEY_1)).setSeverity(MAJOR) | |||
.setParentKey(activeRuleKey1.toString()).setInheritance(INHERITED.name()), | |||
ActiveRuleDocTesting.newDoc(ActiveRuleKey.of(QUALITY_PROFILE_KEY2, RULE_KEY_2)).setSeverity(BLOCKER) | |||
.setParentKey(activeRuleKey2.toString()).setInheritance(OVERRIDES.name())); | |||
// 0. Test base case | |||
assertThat(tester.countDocuments(INDEX, TYPE_ACTIVE_RULE)).isEqualTo(4); | |||
// 1. Assert by term aggregation; | |||
Map<String, Multimap<String, FacetValue>> stats = index.getStatsByProfileKeys(ImmutableList.of(QUALITY_PROFILE_KEY1, QUALITY_PROFILE_KEY2)); | |||
assertThat(stats).hasSize(2); | |||
} | |||
/** | |||
* SONAR-5844 | |||
*/ | |||
@Test | |||
public void stats_for_all_with_lof_of_profiles() { | |||
indexRules(RuleDocTesting.newDoc(RULE_KEY_1), RuleDocTesting.newDoc(RULE_KEY_2)); | |||
indexActiveRules( | |||
ActiveRuleDocTesting.newDoc(ActiveRuleKey.of(QUALITY_PROFILE_KEY1, RULE_KEY_1)), | |||
ActiveRuleDocTesting.newDoc(ActiveRuleKey.of(QUALITY_PROFILE_KEY2, RULE_KEY_1))); | |||
List<String> profileKeys = new ArrayList<>(); | |||
List<ActiveRuleDoc> docs = new ArrayList<>(); | |||
for (int i = 0; i < 30; i++) { | |||
String profileKey = "profile-" + i; | |||
profileKeys.add(profileKey); | |||
docs.add(ActiveRuleDocTesting.newDoc(ActiveRuleKey.of(profileKey, RULE_KEY_1)).setSeverity(BLOCKER)); | |||
docs.add(ActiveRuleDocTesting.newDoc(ActiveRuleKey.of(profileKey, RULE_KEY_2)).setSeverity(MAJOR)); | |||
} | |||
indexActiveRules(docs.toArray(new ActiveRuleDoc[]{})); | |||
Map<String, Multimap<String, FacetValue>> stats = index.getStatsByProfileKeys(profileKeys); | |||
assertThat(stats).hasSize(30); | |||
} | |||
@Test | |||
public void get_by_key() { | |||
indexRules(RuleDocTesting.newDoc(RULE_KEY_1)); | |||
ActiveRuleKey key = ActiveRuleKey.of(QUALITY_PROFILE_KEY1, RULE_KEY_1); | |||
indexActiveRules(ActiveRuleDocTesting.newDoc(key)); | |||
assertThat(index.getNullableByKey(key)).isNotNull(); | |||
assertThat(index.getNullableByKey(ActiveRuleKey.of(QUALITY_PROFILE_KEY1, RULE_KEY_2))).isNull(); | |||
} | |||
@Test | |||
public void find_active_rules() { | |||
indexRules( | |||
RuleDocTesting.newDoc(RULE_KEY_1), | |||
RuleDocTesting.newDoc(RULE_KEY_2), | |||
RuleDocTesting.newDoc(RuleKey.of("xoo", "removed")).setStatus(RuleStatus.REMOVED.name()) | |||
); | |||
indexActiveRules( | |||
ActiveRuleDocTesting.newDoc(ActiveRuleKey.of(QUALITY_PROFILE_KEY1, RULE_KEY_1)), | |||
ActiveRuleDocTesting.newDoc(ActiveRuleKey.of(QUALITY_PROFILE_KEY1, RULE_KEY_2)), | |||
ActiveRuleDocTesting.newDoc(ActiveRuleKey.of(QUALITY_PROFILE_KEY2, RULE_KEY_2)), | |||
// Removed rule can still be activated for instance when removing the checkstyle plugin, active rules related on checkstyle are not | |||
// removed | |||
// because if the plugin is re-install, quality profiles using these rule are not changed. | |||
ActiveRuleDocTesting.newDoc(ActiveRuleKey.of(QUALITY_PROFILE_KEY2, RuleKey.of("xoo", "removed"))) | |||
); | |||
// 1. find by rule key | |||
// in es | |||
List<ActiveRule> activeRules = index.findByRule(RULE_KEY_1); | |||
assertThat(activeRules).hasSize(1); | |||
assertThat(activeRules.get(0).key().ruleKey()).isEqualTo(RULE_KEY_1); | |||
activeRules = index.findByRule(RULE_KEY_2); | |||
assertThat(activeRules).hasSize(2); | |||
assertThat(activeRules.get(0).key().ruleKey()).isEqualTo(RULE_KEY_2); | |||
activeRules = index.findByRule(RuleKey.of("unknown", "unknown")); | |||
assertThat(activeRules).isEmpty(); | |||
// 2. find by profile | |||
List<ActiveRuleDoc> activeRuleDocs = Lists.newArrayList(index.findByProfile(QUALITY_PROFILE_KEY1)); | |||
assertThat(activeRuleDocs).hasSize(2); | |||
assertThat(activeRuleDocs.get(0).key().qProfile()).isEqualTo(QUALITY_PROFILE_KEY1); | |||
assertThat(activeRuleDocs.get(1).key().qProfile()).isEqualTo(QUALITY_PROFILE_KEY1); | |||
activeRuleDocs = Lists.newArrayList(index.findByProfile(QUALITY_PROFILE_KEY2)); | |||
assertThat(activeRuleDocs).hasSize(1); | |||
assertThat(activeRuleDocs.get(0).key().qProfile()).isEqualTo(QUALITY_PROFILE_KEY2); | |||
activeRuleDocs = Lists.newArrayList(index.findByProfile("unknown")); | |||
assertThat(activeRuleDocs).isEmpty(); | |||
} | |||
@Test | |||
public void find_many_active_rules_by_profile() { | |||
int nb = 150; | |||
RuleDoc[] ruleDocs = new RuleDoc[nb]; | |||
ActiveRuleDoc[] activeRuleDocs = new ActiveRuleDoc[nb]; | |||
for (int i = 0; i < nb; i++) { | |||
RuleKey ruleKey = RuleKey.of("xoo", "S00" + i); | |||
ruleDocs[i] = RuleDocTesting.newDoc(ruleKey); | |||
activeRuleDocs[i] = ActiveRuleDocTesting.newDoc(ActiveRuleKey.of(QUALITY_PROFILE_KEY1, ruleKey)); | |||
} | |||
indexRules(ruleDocs); | |||
indexActiveRules(activeRuleDocs); | |||
// verify index | |||
assertThat(index.findByProfile(QUALITY_PROFILE_KEY1)).hasSize(nb); | |||
} | |||
@Test | |||
public void find_many_active_rules_by_rule() { | |||
indexRules(RuleDocTesting.newDoc(RULE_KEY_1)); | |||
int nb = 150; | |||
ActiveRuleDoc[] activeRuleDocs = new ActiveRuleDoc[nb]; | |||
for (int i = 0; i < nb; i++) { | |||
activeRuleDocs[i] = ActiveRuleDocTesting.newDoc(ActiveRuleKey.of("qp" + i, RULE_KEY_1)); | |||
} | |||
indexActiveRules(activeRuleDocs); | |||
// verify index | |||
assertThat(index.findByRule(RULE_KEY_1)).hasSize(nb); | |||
} | |||
private void indexActiveRules(ActiveRuleDoc... docs) { | |||
activeRuleIndexer.index(asList(docs).iterator()); | |||
} | |||
private void indexRules(RuleDoc... rules) { | |||
ruleIndexer.index(asList(rules).iterator()); | |||
} | |||
} |
@@ -0,0 +1,188 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2016 SonarSource SA | |||
* mailto:contact AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.server.qualityprofile.index; | |||
import com.google.common.collect.Iterators; | |||
import java.util.Arrays; | |||
import org.junit.Before; | |||
import org.junit.ClassRule; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.junit.experimental.categories.Category; | |||
import org.sonar.api.config.Settings; | |||
import org.sonar.api.rule.RuleKey; | |||
import org.sonar.api.rule.Severity; | |||
import org.sonar.api.utils.System2; | |||
import org.sonar.db.DbTester; | |||
import org.sonar.db.qualityprofile.ActiveRuleDto; | |||
import org.sonar.db.qualityprofile.ActiveRuleKey; | |||
import org.sonar.db.qualityprofile.QualityProfileDto; | |||
import org.sonar.db.rule.RuleDto; | |||
import org.sonar.db.rule.RuleTesting; | |||
import org.sonar.server.es.EsTester; | |||
import org.sonar.server.qualityprofile.ActiveRuleChange; | |||
import org.sonar.server.rule.index.RuleIndexDefinition; | |||
import org.sonar.test.DbTests; | |||
import static java.util.Arrays.asList; | |||
import static java.util.Collections.singletonList; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.sonar.server.qualityprofile.ActiveRuleChange.Type.ACTIVATED; | |||
import static org.sonar.server.qualityprofile.ActiveRuleChange.Type.DEACTIVATED; | |||
import static org.sonar.server.qualityprofile.index.ActiveRuleDocTesting.newDoc; | |||
import static org.sonar.server.rule.index.RuleIndexDefinition.INDEX; | |||
import static org.sonar.server.rule.index.RuleIndexDefinition.TYPE_ACTIVE_RULE; | |||
@Category(DbTests.class) | |||
public class ActiveRuleIndexerTest { | |||
static final RuleKey RULE_KEY_1 = RuleTesting.XOO_X1; | |||
static final RuleKey RULE_KEY_2 = RuleTesting.XOO_X2; | |||
static final RuleKey RULE_KEY_3 = RuleTesting.XOO_X3; | |||
static final String QUALITY_PROFILE_KEY1 = "qp1"; | |||
static final String QUALITY_PROFILE_KEY2 = "qp2"; | |||
@ClassRule | |||
public static EsTester esTester = new EsTester().addDefinitions(new RuleIndexDefinition(new Settings())); | |||
@Rule | |||
public DbTester dbTester = DbTester.create(System2.INSTANCE); | |||
ActiveRuleIndexer indexer; | |||
@Before | |||
public void setUp() { | |||
esTester.truncateIndices(); | |||
indexer = new ActiveRuleIndexer(dbTester.getDbClient(), esTester.client()); | |||
indexer.setEnabled(true); | |||
} | |||
@Test | |||
public void index_nothing() { | |||
indexer.index(Iterators.<ActiveRuleDoc>emptyIterator()); | |||
assertThat(esTester.countDocuments(INDEX, TYPE_ACTIVE_RULE)).isZero(); | |||
} | |||
@Test | |||
public void index_nothing_if_disabled() { | |||
dbTester.prepareDbUnit(getClass(), "index.xml"); | |||
ActiveRuleIndexer indexer = new ActiveRuleIndexer(dbTester.getDbClient(), esTester.client()); | |||
indexer.setEnabled(false); | |||
indexer.index(); | |||
assertThat(esTester.countDocuments(INDEX, TYPE_ACTIVE_RULE)).isZero(); | |||
} | |||
@Test | |||
public void index() { | |||
dbTester.prepareDbUnit(getClass(), "index.xml"); | |||
indexer.index(); | |||
assertThat(esTester.countDocuments(INDEX, TYPE_ACTIVE_RULE)).isEqualTo(1); | |||
} | |||
@Test | |||
public void delete_profile() throws Exception { | |||
indexActiveRules( | |||
newDoc(ActiveRuleKey.of(QUALITY_PROFILE_KEY1, RULE_KEY_1)), | |||
newDoc(ActiveRuleKey.of(QUALITY_PROFILE_KEY1, RULE_KEY_2)), | |||
newDoc(ActiveRuleKey.of(QUALITY_PROFILE_KEY2, RULE_KEY_2)), | |||
newDoc(ActiveRuleKey.of(QUALITY_PROFILE_KEY2, RULE_KEY_3))); | |||
assertThat(esTester.getIds(INDEX, TYPE_ACTIVE_RULE)).hasSize(4); | |||
indexer.deleteProfile(QUALITY_PROFILE_KEY1); | |||
assertThat(esTester.getIds(INDEX, TYPE_ACTIVE_RULE)).containsOnly( | |||
ActiveRuleKey.of(QUALITY_PROFILE_KEY2, RULE_KEY_2).toString(), | |||
ActiveRuleKey.of(QUALITY_PROFILE_KEY2, RULE_KEY_3).toString() | |||
); | |||
} | |||
@Test | |||
public void index_from_changes_remove_deactivated_rules() throws Exception { | |||
ActiveRuleKey activeRuleKey1 = ActiveRuleKey.of(QUALITY_PROFILE_KEY1, RULE_KEY_1); | |||
ActiveRuleKey activeRuleKey2 = ActiveRuleKey.of(QUALITY_PROFILE_KEY1, RULE_KEY_2); | |||
ActiveRuleKey activeRuleKey3 = ActiveRuleKey.of(QUALITY_PROFILE_KEY2, RULE_KEY_2); | |||
ActiveRuleKey activeRuleKey4 = ActiveRuleKey.of(QUALITY_PROFILE_KEY2, RULE_KEY_3); | |||
indexActiveRules( | |||
newDoc(activeRuleKey1), | |||
newDoc(activeRuleKey2), | |||
newDoc(activeRuleKey3), | |||
newDoc(activeRuleKey4)); | |||
assertThat(esTester.getIds(INDEX, TYPE_ACTIVE_RULE)).hasSize(4); | |||
indexer.index(Arrays.asList( | |||
ActiveRuleChange.createFor(ACTIVATED, activeRuleKey1), | |||
ActiveRuleChange.createFor(DEACTIVATED, activeRuleKey2), | |||
ActiveRuleChange.createFor(DEACTIVATED, activeRuleKey3) | |||
)); | |||
assertThat(esTester.getIds(INDEX, TYPE_ACTIVE_RULE)).containsOnly( | |||
activeRuleKey1.toString(), | |||
activeRuleKey4.toString() | |||
); | |||
} | |||
@Test | |||
public void index_from_changes_index_new_active_rule() throws Exception { | |||
long yesterday = 1000000L; | |||
long now = 2000000L; | |||
// Index one active rule | |||
RuleDto rule = RuleTesting.newDto(RULE_KEY_1); | |||
dbTester.getDbClient().ruleDao().insert(dbTester.getSession(), rule); | |||
QualityProfileDto profile = QualityProfileDto.createFor("qp").setLanguage("xoo").setName("profile"); | |||
dbTester.getDbClient().qualityProfileDao().insert(dbTester.getSession(), profile); | |||
ActiveRuleDto activeRule = ActiveRuleDto.createFor(profile, rule).setSeverity(Severity.BLOCKER) | |||
.setCreatedAtInMs(yesterday).setUpdatedAtInMs(yesterday); | |||
// dbTester.getDbClient().activeRuleDao().insert(dbTester.getSession(), activeRule); | |||
dbTester.getSession().commit(); | |||
indexer.index(); | |||
assertThat(esTester.getIds(INDEX, TYPE_ACTIVE_RULE)).containsOnly(activeRule.getKey().toString()); | |||
// Index another active rule | |||
RuleDto rule2 = RuleTesting.newDto(RULE_KEY_2); | |||
dbTester.getDbClient().ruleDao().insert(dbTester.getSession(), rule2); | |||
ActiveRuleDto activeRule2 = ActiveRuleDto.createFor(profile, rule2).setSeverity(Severity.CRITICAL) | |||
.setCreatedAtInMs(now).setUpdatedAtInMs(now); | |||
// dbTester.getDbClient().activeRuleDao().insert(dbTester.getSession(), activeRule2); | |||
dbTester.getSession().commit(); | |||
indexer.index(singletonList(ActiveRuleChange.createFor(ACTIVATED, activeRule2.getKey()))); | |||
assertThat(esTester.getIds(INDEX, TYPE_ACTIVE_RULE)).containsOnly( | |||
activeRule.getKey().toString(), | |||
activeRule2.getKey().toString() | |||
); | |||
} | |||
private void indexActiveRules(ActiveRuleDoc... docs) { | |||
indexer.index(asList(docs).iterator()); | |||
} | |||
} |
@@ -0,0 +1,166 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2016 SonarSource SA | |||
* mailto:contact AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.server.qualityprofile.index; | |||
import com.google.common.base.Function; | |||
import com.google.common.collect.Maps; | |||
import java.util.Map; | |||
import javax.annotation.Nonnull; | |||
import org.junit.Before; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.junit.experimental.categories.Category; | |||
import org.sonar.api.rule.RuleKey; | |||
import org.sonar.api.utils.System2; | |||
import org.sonar.db.DbTester; | |||
import org.sonar.db.qualityprofile.ActiveRuleKey; | |||
import org.sonar.server.qualityprofile.ActiveRule; | |||
import org.sonar.test.DbTests; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.sonar.api.rule.Severity.BLOCKER; | |||
import static org.sonar.api.rule.Severity.CRITICAL; | |||
import static org.sonar.api.rule.Severity.INFO; | |||
import static org.sonar.server.qualityprofile.ActiveRule.Inheritance.INHERITED; | |||
@Category(DbTests.class) | |||
public class ActiveRuleResultSetIteratorTest { | |||
@Rule | |||
public DbTester dbTester = DbTester.create(System2.INSTANCE); | |||
@Before | |||
public void setUp() { | |||
dbTester.truncateTables(); | |||
} | |||
@Test | |||
public void iterator_over_one_active_rule() { | |||
dbTester.prepareDbUnit(getClass(), "one_active_rule.xml"); | |||
ActiveRuleResultSetIterator it = ActiveRuleResultSetIterator.create(dbTester.getDbClient(), dbTester.getSession(), 0L); | |||
Map<ActiveRuleKey, ActiveRuleDoc> activeRulesByKey = activeRulesByKey(it); | |||
it.close(); | |||
assertThat(activeRulesByKey).hasSize(1); | |||
ActiveRuleKey key = ActiveRuleKey.of("sonar-way", RuleKey.of("xoo", "S001")); | |||
ActiveRuleDoc activeRule = activeRulesByKey.get(key); | |||
assertThat(activeRule.key()).isEqualTo(key); | |||
assertThat(activeRule.severity()).isEqualTo(CRITICAL); | |||
assertThat(activeRule.inheritance()).isEqualTo(ActiveRule.Inheritance.NONE); | |||
assertThat(activeRule.parentKey()).isNull(); | |||
assertThat(activeRule.createdAtAsLong()).isEqualTo(1500000000000L); | |||
assertThat(activeRule.updatedAtAsLong()).isEqualTo(1600000000000L); | |||
} | |||
@Test | |||
public void iterator_over_active_rules() { | |||
dbTester.prepareDbUnit(getClass(), "shared.xml"); | |||
ActiveRuleResultSetIterator it = ActiveRuleResultSetIterator.create(dbTester.getDbClient(), dbTester.getSession(), 0L); | |||
Map<ActiveRuleKey, ActiveRuleDoc> activeRulesByKey = activeRulesByKey(it); | |||
it.close(); | |||
assertThat(activeRulesByKey).hasSize(3); | |||
ActiveRuleKey key = ActiveRuleKey.of("sonar-way", RuleKey.of("xoo", "S002")); | |||
ActiveRuleDoc activeRule = activeRulesByKey.get(key); | |||
assertThat(activeRule.key()).isEqualTo(key); | |||
assertThat(activeRule.severity()).isEqualTo(CRITICAL); | |||
assertThat(activeRule.inheritance()).isEqualTo(ActiveRule.Inheritance.NONE); | |||
assertThat(activeRule.parentKey()).isNull(); | |||
assertThat(activeRule.createdAtAsLong()).isEqualTo(2000000000000L); | |||
assertThat(activeRule.updatedAtAsLong()).isEqualTo(2100000000000L); | |||
key = ActiveRuleKey.of("parent", RuleKey.of("xoo", "S001")); | |||
activeRule = activeRulesByKey.get(key); | |||
assertThat(activeRule.key()).isEqualTo(key); | |||
assertThat(activeRule.severity()).isEqualTo(INFO); | |||
assertThat(activeRule.inheritance()).isEqualTo(ActiveRule.Inheritance.NONE); | |||
assertThat(activeRule.parentKey()).isNull(); | |||
assertThat(activeRule.createdAtAsLong()).isEqualTo(1700000000000L); | |||
assertThat(activeRule.updatedAtAsLong()).isEqualTo(1800000000000L); | |||
key = ActiveRuleKey.of("child", RuleKey.of("xoo", "S001")); | |||
activeRule = activeRulesByKey.get(key); | |||
assertThat(activeRule.key()).isEqualTo(key); | |||
assertThat(activeRule.severity()).isEqualTo(BLOCKER); | |||
assertThat(activeRule.inheritance()).isEqualTo(INHERITED); | |||
assertThat(activeRule.parentKey()).isEqualTo(ActiveRuleKey.of("parent", RuleKey.of("xoo", "S001"))); | |||
assertThat(activeRule.createdAtAsLong()).isEqualTo(1500000000000L); | |||
assertThat(activeRule.updatedAtAsLong()).isEqualTo(1600000000000L); | |||
} | |||
@Test | |||
public void active_rule_with_inherited_inheritance() { | |||
dbTester.prepareDbUnit(getClass(), "active_rule_with_inherited_inheritance.xml"); | |||
ActiveRuleResultSetIterator it = ActiveRuleResultSetIterator.create(dbTester.getDbClient(), dbTester.getSession(), 0L); | |||
Map<ActiveRuleKey, ActiveRuleDoc> activeRulesByKey = activeRulesByKey(it); | |||
it.close(); | |||
assertThat(activeRulesByKey).hasSize(2); | |||
ActiveRuleKey key = ActiveRuleKey.of("child", RuleKey.of("xoo", "S001")); | |||
ActiveRuleDoc activeRule = activeRulesByKey.get(key); | |||
assertThat(activeRule.inheritance()).isEqualTo(INHERITED); | |||
assertThat(activeRule.parentKey()).isEqualTo(ActiveRuleKey.of("parent", RuleKey.of("xoo", "S001"))); | |||
} | |||
@Test | |||
public void active_rule_with_overrides_inheritance() { | |||
dbTester.prepareDbUnit(getClass(), "active_rule_with_overrides_inheritance.xml"); | |||
ActiveRuleResultSetIterator it = ActiveRuleResultSetIterator.create(dbTester.getDbClient(), dbTester.getSession(), 0L); | |||
Map<ActiveRuleKey, ActiveRuleDoc> activeRulesByKey = activeRulesByKey(it); | |||
it.close(); | |||
assertThat(activeRulesByKey).hasSize(2); | |||
ActiveRuleKey key = ActiveRuleKey.of("child", RuleKey.of("xoo", "S001")); | |||
ActiveRuleDoc activeRule = activeRulesByKey.get(key); | |||
assertThat(activeRule.inheritance()).isEqualTo(ActiveRule.Inheritance.OVERRIDES); | |||
assertThat(activeRule.parentKey()).isEqualTo(ActiveRuleKey.of("parent", RuleKey.of("xoo", "S001"))); | |||
} | |||
@Test | |||
public void select_after_date() { | |||
dbTester.prepareDbUnit(getClass(), "shared.xml"); | |||
ActiveRuleResultSetIterator it = ActiveRuleResultSetIterator.create(dbTester.getDbClient(), dbTester.getSession(), 1_900_000_000_000L); | |||
assertThat(it.hasNext()).isTrue(); | |||
ActiveRuleDoc doc = it.next(); | |||
assertThat(doc.key()).isEqualTo(ActiveRuleKey.of("sonar-way", RuleKey.of("xoo", "S002"))); | |||
assertThat(it.hasNext()).isFalse(); | |||
it.close(); | |||
} | |||
private static Map<ActiveRuleKey, ActiveRuleDoc> activeRulesByKey(ActiveRuleResultSetIterator it) { | |||
return Maps.uniqueIndex(it, DocToKey.INSTANCE); | |||
} | |||
private enum DocToKey implements Function<ActiveRuleDoc, ActiveRuleKey> { | |||
INSTANCE; | |||
@Override | |||
public ActiveRuleKey apply(@Nonnull ActiveRuleDoc doc) { | |||
return doc.key(); | |||
} | |||
} | |||
} |
@@ -26,14 +26,18 @@ import java.util.List; | |||
import java.util.Map; | |||
import org.junit.Before; | |||
import org.junit.ClassRule; | |||
import org.junit.Ignore; | |||
import org.junit.Test; | |||
import org.sonar.api.config.Settings; | |||
import org.sonar.api.rule.RuleKey; | |||
import org.sonar.api.rule.RuleStatus; | |||
import org.sonar.db.qualityprofile.ActiveRuleKey; | |||
import org.sonar.db.rule.RuleTesting; | |||
import org.sonar.server.es.EsTester; | |||
import org.sonar.server.es.SearchIdResult; | |||
import org.sonar.server.es.SearchOptions; | |||
import org.sonar.server.qualityprofile.index.ActiveRuleDoc; | |||
import org.sonar.server.qualityprofile.index.ActiveRuleDocTesting; | |||
import org.sonar.server.qualityprofile.index.ActiveRuleIndexer; | |||
import static java.util.Arrays.asList; | |||
import static java.util.Collections.singleton; | |||
@@ -42,26 +46,42 @@ import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.assertj.core.data.MapEntry.entry; | |||
import static org.junit.Assert.fail; | |||
import static org.sonar.api.rule.Severity.BLOCKER; | |||
import static org.sonar.api.rule.Severity.CRITICAL; | |||
import static org.sonar.api.rule.Severity.INFO; | |||
import static org.sonar.api.rule.Severity.MAJOR; | |||
import static org.sonar.api.rule.Severity.MINOR; | |||
import static org.sonar.server.qualityprofile.ActiveRule.Inheritance.INHERITED; | |||
import static org.sonar.server.qualityprofile.ActiveRule.Inheritance.OVERRIDES; | |||
import static org.sonar.server.rule.index.RuleDocTesting.newDoc; | |||
import static org.sonar.server.rule.index.RuleIndex2.FACET_LANGUAGES; | |||
import static org.sonar.server.rule.index.RuleIndex2.FACET_REPOSITORIES; | |||
import static org.sonar.server.rule.index.RuleIndex2.FACET_TAGS; | |||
import static org.sonar.server.rule.index.RuleIndexDefinition.INDEX; | |||
import static org.sonar.server.rule.index.RuleIndexDefinition.TYPE_ACTIVE_RULE; | |||
public class RuleIndex2Test { | |||
static final RuleKey RULE_KEY_1 = RuleTesting.XOO_X1; | |||
static final RuleKey RULE_KEY_2 = RuleTesting.XOO_X2; | |||
static final RuleKey RULE_KEY_3 = RuleTesting.XOO_X3; | |||
static final RuleKey RULE_KEY_4 = RuleKey.of("xoo", "x4"); | |||
static final String QUALITY_PROFILE_KEY1 = "qp1"; | |||
static final String QUALITY_PROFILE_KEY2 = "qp2"; | |||
@ClassRule | |||
public static EsTester tester = new EsTester().addDefinitions(new RuleIndexDefinition(new Settings())); | |||
RuleIndex2 index; | |||
RuleIndexer ruleIndexer; | |||
ActiveRuleIndexer activeRuleIndexer; | |||
@Before | |||
public void setUp() { | |||
tester.truncateIndices(); | |||
ruleIndexer = new RuleIndexer(null, tester.client()); | |||
activeRuleIndexer = new ActiveRuleIndexer(null, tester.client()); | |||
index = new RuleIndex2(tester.client()); | |||
} | |||
@@ -306,7 +326,7 @@ public class RuleIndex2Test { | |||
newDoc(RuleKey.of("java", "S002")).setStatus(RuleStatus.READY.name())); | |||
RuleQuery query = new RuleQuery().setStatuses(asList(RuleStatus.DEPRECATED, RuleStatus.READY)); | |||
SearchIdResult results = index.search(query, new SearchOptions()); | |||
SearchIdResult<RuleKey> results = index.search(query, new SearchOptions()); | |||
assertThat(results.getIds()).containsOnly(RuleKey.of("java", "S002")); | |||
// no results | |||
@@ -323,194 +343,146 @@ public class RuleIndex2Test { | |||
} | |||
@Test | |||
@Ignore | |||
public void search_by_profile() { | |||
// QualityProfileDto qualityProfileDto1 = QProfileTesting.newXooP1(); | |||
// QualityProfileDto qualityProfileDto2 = QProfileTesting.newXooP2(); | |||
// db.qualityProfileDao().insert(dbSession, qualityProfileDto1, qualityProfileDto2); | |||
// | |||
// RuleDto rule1 = RuleTesting.newXooX1(); | |||
// RuleDto rule2 = RuleTesting.newXooX2(); | |||
// RuleDto rule3 = RuleTesting.newXooX3(); | |||
// dao.insert(dbSession, rule1, rule2, rule3); | |||
// | |||
// db.activeRuleDao().insert( | |||
// dbSession, | |||
// ActiveRuleDto.createFor(qualityProfileDto1, rule1).setSeverity("BLOCKER"), | |||
// ActiveRuleDto.createFor(qualityProfileDto2, rule1).setSeverity("BLOCKER"), | |||
// ActiveRuleDto.createFor(qualityProfileDto1, rule2).setSeverity("BLOCKER")); | |||
// dbSession.commit(); | |||
// dbSession.clearCache(); | |||
// | |||
// // 1. get all active rules. | |||
// Result<org.sonar.server.rule.Rule> result = index.search(new RuleQuery().setActivation(true), | |||
// new SearchOptions()); | |||
// assertThat(result.getHits()).hasSize(2); | |||
// | |||
// // 2. get all inactive rules. | |||
// result = index.search(new RuleQuery().setActivation(false), | |||
// new SearchOptions()); | |||
// assertThat(result.getHits()).hasSize(1); | |||
// assertThat(result.getHits().get(0).name()).isEqualTo(rule3.getName()); | |||
// | |||
// // 3. get all rules not active on profile | |||
// index.search(new RuleQuery().setActivation(false).setQProfileKey(qualityProfileDto2.getKey()), | |||
// new SearchOptions()); | |||
// // TODO | |||
// assertThat(result.getHits()).hasSize(1); | |||
// | |||
// // 4. get all active rules on profile | |||
// result = index.search(new RuleQuery().setActivation(true) | |||
// .setQProfileKey(qualityProfileDto2.getKey()), | |||
// new SearchOptions()); | |||
// assertThat(result.getHits()).hasSize(1); | |||
// assertThat(result.getHits().get(0).name()).isEqualTo(rule1.getName()); | |||
public void search_by_profile() throws InterruptedException { | |||
indexRules( | |||
newDoc(RULE_KEY_1), | |||
newDoc(RULE_KEY_2), | |||
newDoc(RULE_KEY_3)); | |||
indexActiveRules( | |||
ActiveRuleDocTesting.newDoc(ActiveRuleKey.of(QUALITY_PROFILE_KEY1, RULE_KEY_1)), | |||
ActiveRuleDocTesting.newDoc(ActiveRuleKey.of(QUALITY_PROFILE_KEY2, RULE_KEY_1)), | |||
ActiveRuleDocTesting.newDoc(ActiveRuleKey.of(QUALITY_PROFILE_KEY1, RULE_KEY_2))); | |||
assertThat(tester.countDocuments(INDEX, TYPE_ACTIVE_RULE)).isEqualTo(3); | |||
// 1. get all active rules. | |||
assertThat(index.search(new RuleQuery().setActivation(true), new SearchOptions()).getIds()) | |||
.containsOnly(RULE_KEY_1, RULE_KEY_2); | |||
// 2. get all inactive rules. | |||
assertThat(index.search(new RuleQuery().setActivation(false), new SearchOptions()).getIds()) | |||
.containsOnly(RULE_KEY_3); | |||
// 3. get all rules not active on profile | |||
assertThat(index.search(new RuleQuery().setActivation(false).setQProfileKey(QUALITY_PROFILE_KEY2), new SearchOptions()).getIds()) | |||
.containsOnly(RULE_KEY_2, RULE_KEY_3); | |||
// 4. get all active rules on profile | |||
assertThat(index.search(new RuleQuery().setActivation(true).setQProfileKey(QUALITY_PROFILE_KEY2), new SearchOptions()).getIds()) | |||
.containsOnly(RULE_KEY_1); | |||
} | |||
@Test | |||
@Ignore | |||
public void search_by_profile_and_inheritance() { | |||
// QualityProfileDto qualityProfileDto1 = QProfileTesting.newXooP1(); | |||
// QualityProfileDto qualityProfileDto2 = QProfileTesting.newXooP2().setParentKee(QProfileTesting.XOO_P1_KEY); | |||
// db.qualityProfileDao().insert(dbSession, qualityProfileDto1, qualityProfileDto2); | |||
// | |||
// RuleDto rule1 = RuleTesting.newDto(RuleKey.of("xoo", "S001")); | |||
// RuleDto rule2 = RuleTesting.newDto(RuleKey.of("xoo", "S002")); | |||
// RuleDto rule3 = RuleTesting.newDto(RuleKey.of("xoo", "S003")); | |||
// RuleDto rule4 = RuleTesting.newDto(RuleKey.of("xoo", "S004")); | |||
// dao.insert(dbSession, rule1, rule2, rule3, rule4); | |||
// | |||
// db.activeRuleDao().insert( | |||
// dbSession, | |||
// ActiveRuleDto.createFor(qualityProfileDto1, rule1) | |||
// .setSeverity("BLOCKER"), | |||
// ActiveRuleDto.createFor(qualityProfileDto1, rule2) | |||
// .setSeverity("BLOCKER"), | |||
// ActiveRuleDto.createFor(qualityProfileDto1, rule3) | |||
// .setSeverity("BLOCKER"), | |||
// | |||
// ActiveRuleDto.createFor(qualityProfileDto2, rule1) | |||
// .setSeverity("MINOR") | |||
// .setInheritance(ActiveRule.Inheritance.INHERITED.name()), | |||
// ActiveRuleDto.createFor(qualityProfileDto2, rule2) | |||
// .setSeverity("BLOCKER") | |||
// .setInheritance(ActiveRule.Inheritance.OVERRIDES.name()), | |||
// ActiveRuleDto.createFor(qualityProfileDto2, rule3) | |||
// .setSeverity("BLOCKER") | |||
// .setInheritance(ActiveRule.Inheritance.INHERITED.name()) | |||
// ); | |||
// | |||
// dbSession.commit(); | |||
// | |||
// // 0. get all rules | |||
// Result<org.sonar.server.rule.Rule> result = index.search(new RuleQuery(), | |||
// new SearchOptions()); | |||
// assertThat(result.getHits()).hasSize(4); | |||
// | |||
// // 1. get all active rules | |||
// result = index.search(new RuleQuery().setActivation(true), | |||
// new SearchOptions()); | |||
// assertThat(result.getHits()).hasSize(3); | |||
// | |||
// // 2. get all inactive rules. | |||
// result = index.search(new RuleQuery().setActivation(false), | |||
// new SearchOptions()); | |||
// assertThat(result.getHits()).hasSize(1); | |||
// assertThat(result.getHits().get(0).name()).isEqualTo(rule4.getName()); | |||
// | |||
// // 3. get Inherited Rules on profile1 | |||
// result = index.search(new RuleQuery().setActivation(true) | |||
// .setQProfileKey(qualityProfileDto1.getKey()) | |||
// .setInheritance(ImmutableSet.of(ActiveRule.Inheritance.INHERITED.name())), | |||
// new SearchOptions() | |||
// ); | |||
// assertThat(result.getHits()).hasSize(0); | |||
// | |||
// // 4. get Inherited Rules on profile2 | |||
// result = index.search(new RuleQuery().setActivation(true) | |||
// .setQProfileKey(qualityProfileDto2.getKey()) | |||
// .setInheritance(ImmutableSet.of(ActiveRule.Inheritance.INHERITED.name())), | |||
// new SearchOptions() | |||
// ); | |||
// assertThat(result.getHits()).hasSize(2); | |||
// | |||
// // 5. get Overridden Rules on profile1 | |||
// result = index.search(new RuleQuery().setActivation(true) | |||
// .setQProfileKey(qualityProfileDto1.getKey()) | |||
// .setInheritance(ImmutableSet.of(ActiveRule.Inheritance.OVERRIDES.name())), | |||
// new SearchOptions() | |||
// ); | |||
// assertThat(result.getHits()).hasSize(0); | |||
// | |||
// // 6. get Overridden Rules on profile2 | |||
// result = index.search(new RuleQuery().setActivation(true) | |||
// .setQProfileKey(qualityProfileDto2.getKey()) | |||
// .setInheritance(ImmutableSet.of(ActiveRule.Inheritance.OVERRIDES.name())), | |||
// new SearchOptions() | |||
// ); | |||
// assertThat(result.getHits()).hasSize(1); | |||
// | |||
// // 7. get Inherited AND Overridden Rules on profile1 | |||
// result = index.search(new RuleQuery().setActivation(true) | |||
// .setQProfileKey(qualityProfileDto1.getKey()) | |||
// .setInheritance(ImmutableSet.of( | |||
// ActiveRule.Inheritance.INHERITED.name(), ActiveRule.Inheritance.OVERRIDES.name())), | |||
// new SearchOptions() | |||
// ); | |||
// assertThat(result.getHits()).hasSize(0); | |||
// | |||
// // 8. get Inherited AND Overridden Rules on profile2 | |||
// result = index.search(new RuleQuery().setActivation(true) | |||
// .setQProfileKey(qualityProfileDto2.getKey()) | |||
// .setInheritance(ImmutableSet.of( | |||
// ActiveRule.Inheritance.INHERITED.name(), ActiveRule.Inheritance.OVERRIDES.name())), | |||
// new SearchOptions() | |||
// ); | |||
// assertThat(result.getHits()).hasSize(3); | |||
indexRules( | |||
newDoc(RULE_KEY_1), | |||
newDoc(RULE_KEY_2), | |||
newDoc(RULE_KEY_3), | |||
newDoc(RULE_KEY_4)); | |||
ActiveRuleKey activeRuleKey1 = ActiveRuleKey.of(QUALITY_PROFILE_KEY1, RULE_KEY_1); | |||
ActiveRuleKey activeRuleKey2 = ActiveRuleKey.of(QUALITY_PROFILE_KEY1, RULE_KEY_2); | |||
ActiveRuleKey activeRuleKey3 = ActiveRuleKey.of(QUALITY_PROFILE_KEY1, RULE_KEY_3); | |||
indexActiveRules( | |||
ActiveRuleDocTesting.newDoc(activeRuleKey1), | |||
ActiveRuleDocTesting.newDoc(activeRuleKey2), | |||
ActiveRuleDocTesting.newDoc(activeRuleKey3), | |||
// Profile 2 is a child a profile 1 | |||
ActiveRuleDocTesting.newDoc(ActiveRuleKey.of(QUALITY_PROFILE_KEY2, RULE_KEY_1)) | |||
.setParentKey(activeRuleKey1.toString()).setInheritance(INHERITED.name()), | |||
ActiveRuleDocTesting.newDoc(ActiveRuleKey.of(QUALITY_PROFILE_KEY2, RULE_KEY_2)) | |||
.setParentKey(activeRuleKey2.toString()).setInheritance(OVERRIDES.name()), | |||
ActiveRuleDocTesting.newDoc(ActiveRuleKey.of(QUALITY_PROFILE_KEY2, RULE_KEY_3)) | |||
.setParentKey(activeRuleKey3.toString()).setInheritance(INHERITED.name())); | |||
// 0. get all rules | |||
assertThat(index.search(new RuleQuery(), new SearchOptions()).getIds()) | |||
.hasSize(4); | |||
// 1. get all active rules | |||
assertThat(index.search(new RuleQuery() | |||
.setActivation(true), new SearchOptions()).getIds()) | |||
.hasSize(3); | |||
// 2. get all inactive rules. | |||
assertThat(index.search(new RuleQuery() | |||
.setActivation(false), new SearchOptions()).getIds()) | |||
.containsOnly(RULE_KEY_4); | |||
// 3. get Inherited Rules on profile1 | |||
assertThat(index.search(new RuleQuery().setActivation(true) | |||
.setQProfileKey(QUALITY_PROFILE_KEY1) | |||
.setInheritance(ImmutableSet.of(INHERITED.name())), | |||
new SearchOptions()).getIds()) | |||
.isEmpty(); | |||
// 4. get Inherited Rules on profile2 | |||
assertThat(index.search(new RuleQuery().setActivation(true) | |||
.setQProfileKey(QUALITY_PROFILE_KEY2) | |||
.setInheritance(ImmutableSet.of(INHERITED.name())), | |||
new SearchOptions()).getIds()) | |||
.hasSize(2); | |||
// 5. get Overridden Rules on profile1 | |||
assertThat(index.search(new RuleQuery().setActivation(true) | |||
.setQProfileKey(QUALITY_PROFILE_KEY1) | |||
.setInheritance(ImmutableSet.of(OVERRIDES.name())), | |||
new SearchOptions()).getIds()) | |||
.isEmpty(); | |||
// 6. get Overridden Rules on profile2 | |||
assertThat(index.search(new RuleQuery().setActivation(true) | |||
.setQProfileKey(QUALITY_PROFILE_KEY2) | |||
.setInheritance(ImmutableSet.of(OVERRIDES.name())), | |||
new SearchOptions()).getIds()) | |||
.hasSize(1); | |||
// 7. get Inherited AND Overridden Rules on profile1 | |||
assertThat(index.search(new RuleQuery().setActivation(true) | |||
.setQProfileKey(QUALITY_PROFILE_KEY1) | |||
.setInheritance(ImmutableSet.of(INHERITED.name(), OVERRIDES.name())), | |||
new SearchOptions()).getIds()) | |||
.isEmpty(); | |||
// 8. get Inherited AND Overridden Rules on profile2 | |||
assertThat(index.search(new RuleQuery().setActivation(true) | |||
.setQProfileKey(QUALITY_PROFILE_KEY2) | |||
.setInheritance(ImmutableSet.of(INHERITED.name(), OVERRIDES.name())), | |||
new SearchOptions()).getIds()) | |||
.hasSize(3); | |||
} | |||
@Test | |||
@Ignore | |||
public void search_by_profile_and_active_severity() { | |||
// QualityProfileDto qualityProfileDto1 = QProfileTesting.newXooP1(); | |||
// QualityProfileDto qualityProfileDto2 = QProfileTesting.newXooP2(); | |||
// db.qualityProfileDao().insert(dbSession, qualityProfileDto1, qualityProfileDto2); | |||
// | |||
// RuleDto rule1 = RuleTesting.newXooX1().setSeverity("MAJOR"); | |||
// RuleDto rule2 = RuleTesting.newXooX2().setSeverity("MINOR"); | |||
// RuleDto rule3 = RuleTesting.newXooX3().setSeverity("INFO"); | |||
// dao.insert(dbSession, rule1, rule2, rule3); | |||
// | |||
// db.activeRuleDao().insert( | |||
// dbSession, | |||
// ActiveRuleDto.createFor(qualityProfileDto1, rule1).setSeverity("BLOCKER"), | |||
// ActiveRuleDto.createFor(qualityProfileDto2, rule1).setSeverity("BLOCKER"), | |||
// ActiveRuleDto.createFor(qualityProfileDto1, rule2).setSeverity("CRITICAL")); | |||
// dbSession.commit(); | |||
// dbSession.clearCache(); | |||
// | |||
// // 1. get all active rules. | |||
// Result<org.sonar.server.rule.Rule> result = index.search(new | |||
// RuleQuery().setActivation(true).setQProfileKey(qualityProfileDto1.getKey()), | |||
// new SearchOptions()); | |||
// assertThat(result.getHits()).hasSize(2); | |||
// | |||
// // 2. get rules with active severity critical. | |||
// result = index.search(new | |||
// RuleQuery().setActivation(true).setQProfileKey(qualityProfileDto1.getKey()).setActiveSeverities(Arrays.asList("CRITICAL")), | |||
// new SearchOptions().addFacets(Arrays.asList(RuleIndex.FACET_ACTIVE_SEVERITIES))); | |||
// assertThat(result.getHits()).hasSize(1); | |||
// assertThat(result.getHits().get(0).name()).isEqualTo(rule2.getName()); | |||
// // check stickyness of active severity facet | |||
// assertThat(result.getFacetValues(RuleIndex.FACET_ACTIVE_SEVERITIES)).containsOnly(new FacetValue("BLOCKER", 1), new | |||
// FacetValue("CRITICAL", 1)); | |||
// | |||
// // 3. count activation severities of all active rules | |||
// result = index.search(new RuleQuery(), | |||
// new SearchOptions().addFacets(Arrays.asList(RuleIndex.FACET_ACTIVE_SEVERITIES))); | |||
// assertThat(result.getHits()).hasSize(3); | |||
// assertThat(result.getFacetValues(RuleIndex.FACET_ACTIVE_SEVERITIES)).containsOnly(new FacetValue("BLOCKER", 2), new | |||
// FacetValue("CRITICAL", 1)); | |||
indexRules( | |||
newDoc(RULE_KEY_1).setSeverity(MAJOR), | |||
newDoc(RULE_KEY_2).setSeverity(MINOR), | |||
newDoc(RULE_KEY_3).setSeverity(INFO)); | |||
indexActiveRules( | |||
ActiveRuleDocTesting.newDoc(ActiveRuleKey.of(QUALITY_PROFILE_KEY1, RULE_KEY_1)).setSeverity(BLOCKER), | |||
ActiveRuleDocTesting.newDoc(ActiveRuleKey.of(QUALITY_PROFILE_KEY2, RULE_KEY_1)).setSeverity(BLOCKER), | |||
ActiveRuleDocTesting.newDoc(ActiveRuleKey.of(QUALITY_PROFILE_KEY1, RULE_KEY_2)).setSeverity(CRITICAL)); | |||
// 1. get all active rules. | |||
assertThat(index.search(new RuleQuery().setActivation(true).setQProfileKey(QUALITY_PROFILE_KEY1), new SearchOptions()).getIds()) | |||
.hasSize(2); | |||
// 2. get rules with active severity critical. | |||
SearchIdResult<RuleKey> result = index.search(new RuleQuery().setActivation(true) | |||
.setQProfileKey(QUALITY_PROFILE_KEY1).setActiveSeverities(singletonList(CRITICAL)), | |||
new SearchOptions().addFacets(singletonList(RuleIndex2.FACET_ACTIVE_SEVERITIES))); | |||
assertThat(result.getIds()).containsOnly(RULE_KEY_2); | |||
// check stickyness of active severity facet | |||
assertThat(result.getFacets().get(RuleIndex2.FACET_ACTIVE_SEVERITIES)).containsOnly(entry(BLOCKER, 1L), entry(CRITICAL, 1L)); | |||
// 3. count activation severities of all active rules | |||
result = index.search(new RuleQuery(), new SearchOptions().addFacets(singletonList(RuleIndex2.FACET_ACTIVE_SEVERITIES))); | |||
assertThat(result.getIds()).hasSize(3); | |||
assertThat(result.getFacets().get(RuleIndex2.FACET_ACTIVE_SEVERITIES)).containsOnly(entry(BLOCKER, 2L), entry(CRITICAL, 1L)); | |||
} | |||
@Test | |||
@@ -724,4 +696,8 @@ public class RuleIndex2Test { | |||
private void indexRules(RuleDoc... rules) { | |||
ruleIndexer.index(asList(rules).iterator()); | |||
} | |||
private void indexActiveRules(ActiveRuleDoc... docs) { | |||
activeRuleIndexer.index(asList(docs).iterator()); | |||
} | |||
} |
@@ -38,7 +38,7 @@ public class RuleIndexDefinitionTest { | |||
assertThat(underTest.getIndices()).hasSize(1); | |||
NewIndex ruleIndex = underTest.getIndices().get("rules"); | |||
assertThat(ruleIndex).isNotNull(); | |||
assertThat(ruleIndex.getTypes().keySet()).containsOnly("rule"); | |||
assertThat(ruleIndex.getTypes().keySet()).containsOnly("rule", "activeRule"); | |||
// no cluster by default | |||
assertThat(ruleIndex.getSettings().get("index.number_of_shards")).isEqualTo(String.valueOf(NewIndex.DEFAULT_NUMBER_OF_SHARDS)); |
@@ -0,0 +1,13 @@ | |||
<dataset> | |||
<rules id="10" name="Null Pointer" plugin_name="xoo" plugin_rule_key="S001" | |||
plugin_config_key="S1" description_format="HTML" description="S001 desc" language="xoo" | |||
priority="4" status="READY" is_template="[false]" template_id="[null]" | |||
tags="bug,performance" system_tags="cwe" | |||
created_at_ms="1500000000000" updated_at_ms="1600000000000"/> | |||
<rules_profiles id="100" name="Sonar Way" kee="sonar-way" language="xoo" parent_kee="[null]" is_default="[false]"/> | |||
<active_rules id="1" profile_id="100" rule_id="10" failure_level="3" inheritance="[null]" | |||
created_at_ms="1500000000000" updated_at_ms="1600000000000"/> | |||
</dataset> |
@@ -0,0 +1,20 @@ | |||
<dataset> | |||
<rules id="10" name="Null Pointer" plugin_rule_key="S001" plugin_name="xoo" | |||
plugin_config_key="S1" description_format="HTML" description="S001 desc" language="xoo" | |||
priority="4" status="READY" is_template="[false]" template_id="[null]" | |||
tags="bug,performance" system_tags="cwe" | |||
created_at_ms="1500000000000" updated_at_ms="1600000000000"/> | |||
<rules_profiles id="1" name="Parent" kee="parent" language="xoo" parent_kee="[null]" is_default="[false]"/> | |||
<rules_profiles id="2" name="Child" kee="child" language="xoo" parent_kee="parent" is_default="[false]"/> | |||
<active_rules id="1" profile_id="2" rule_id="10" failure_level="4" inheritance="INHERITED" | |||
created_at_ms="1500000000000" updated_at_ms="1600000000000"/> | |||
<!-- Parent of Active rule 1 --> | |||
<active_rules id="2" profile_id="1" rule_id="10" failure_level="0" inheritance="[null]" | |||
created_at_ms="1500000000000" updated_at_ms="1600000000000"/> | |||
</dataset> |
@@ -0,0 +1,20 @@ | |||
<dataset> | |||
<rules id="10" name="Null Pointer" plugin_rule_key="S001" plugin_name="xoo" | |||
plugin_config_key="S1" description_format="HTML" description="S001 desc" language="xoo" | |||
priority="4" status="READY" is_template="[false]" template_id="[null]" | |||
tags="bug,performance" system_tags="cwe" | |||
created_at_ms="1500000000000" updated_at_ms="1600000000000"/> | |||
<rules_profiles id="1" name="Parent" kee="parent" language="xoo" parent_kee="[null]" is_default="[false]"/> | |||
<rules_profiles id="2" name="Child" kee="child" language="xoo" parent_kee="parent" is_default="[false]"/> | |||
<active_rules id="1" profile_id="2" rule_id="10" failure_level="2" inheritance="OVERRIDES" | |||
created_at_ms="1500000000000" updated_at_ms="1600000000000"/> | |||
<!-- Parent of Active rule 1 --> | |||
<active_rules id="2" profile_id="1" rule_id="10" failure_level="0" inheritance="[null]" | |||
created_at_ms="1500000000000" updated_at_ms="1600000000000"/> | |||
</dataset> |
@@ -0,0 +1,13 @@ | |||
<dataset> | |||
<rules id="10" name="Null Pointer" plugin_name="xoo" plugin_rule_key="S001" | |||
plugin_config_key="S1" description_format="HTML" description="S001 desc" language="xoo" | |||
priority="4" status="READY" is_template="[false]" template_id="[null]" | |||
tags="bug,performance" system_tags="cwe" | |||
created_at_ms="1500000000000" updated_at_ms="1600000000000"/> | |||
<rules_profiles id="100" name="Sonar Way" kee="sonar-way" language="xoo" parent_kee="[null]" is_default="[false]"/> | |||
<active_rules id="1" profile_id="100" rule_id="10" failure_level="3" inheritance="[null]" | |||
created_at_ms="1500000000000" updated_at_ms="1600000000000"/> | |||
</dataset> |
@@ -0,0 +1,37 @@ | |||
<dataset> | |||
<rules id="10" name="Null Pointer" plugin_rule_key="S001" | |||
plugin_config_key="S1" plugin_name="xoo" | |||
description_format="HTML" description="S001 desc" language="xoo" | |||
priority="4" status="READY" | |||
is_template="[false]" template_id="[null]" | |||
tags="bug,performance" system_tags="cwe" | |||
created_at="2014-05-10" updated_at="2014-05-11" | |||
created_at_ms="1500000000000" updated_at_ms="1600000000000"/> | |||
<rules id="11" name="Slow" plugin_rule_key="S002" | |||
plugin_config_key="S2" plugin_name="xoo" | |||
description_format="MARKDOWN" description="*S002 desc*" language="xoo" | |||
priority="3" status="BETA" | |||
is_template="[true]" template_id="[null]" | |||
tags="[null]" system_tags="[null]" | |||
created_at="2014-05-10" updated_at="2014-05-11" | |||
created_at_ms="2000000000000" updated_at_ms="2100000000000"/> | |||
<rules_profiles id="1" name="Parent" kee="parent" language="xoo" parent_kee="[null]" is_default="[false]"/> | |||
<rules_profiles id="2" name="Child" kee="child" language="xoo" parent_kee="parent" is_default="[false]"/> | |||
<active_rules id="1" profile_id="2" rule_id="10" failure_level="4" inheritance="INHERITED" | |||
created_at_ms="1500000000000" updated_at_ms="1600000000000"/> | |||
<!-- Parent of Active rule 1 --> | |||
<active_rules id="2" profile_id="1" rule_id="10" failure_level="0" inheritance="[null]" | |||
created_at_ms="1700000000000" updated_at_ms="1800000000000"/> | |||
<rules_profiles id="3" name="Sonar Way" kee="sonar-way" language="xoo" parent_kee="[null]" is_default="[false]"/> | |||
<active_rules id="3" profile_id="3" rule_id="11" failure_level="3" inheritance="[null]" | |||
created_at_ms="2000000000000" updated_at_ms="2100000000000"/> | |||
</dataset> |
@@ -0,0 +1,171 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2016 SonarSource SA | |||
* mailto:contact AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.db.qualityprofile; | |||
import com.google.common.base.Optional; | |||
import com.google.common.base.Preconditions; | |||
import java.util.List; | |||
import javax.annotation.CheckForNull; | |||
import org.sonar.db.Dao; | |||
import org.sonar.db.DbSession; | |||
import org.sonar.db.RowNotFoundException; | |||
import org.sonar.db.rule.RuleDto; | |||
public class ActiveRuleDao implements Dao { | |||
private static final String QUALITY_PROFILE_IS_NOT_PERSISTED = "Quality profile is not persisted (missing id)"; | |||
private static final String RULE_IS_NOT_PERSISTED = "Rule is not persisted"; | |||
private static final String RULE_PARAM_IS_NOT_PERSISTED = "Rule param is not persisted"; | |||
private static final String ACTIVE_RULE_KEY_CANNOT_BE_NULL = "ActiveRuleKey cannot be null"; | |||
private static final String ACTIVE_RULE_IS_NOT_PERSISTED = "ActiveRule is not persisted"; | |||
private static final String ACTIVE_RULE_IS_ALREADY_PERSISTED = "ActiveRule is already persisted"; | |||
private static final String ACTIVE_RULE_PARAM_IS_NOT_PERSISTED = "ActiveRuleParam is not persisted"; | |||
private static final String ACTIVE_RULE_PARAM_IS_ALREADY_PERSISTED = "ActiveRuleParam is already persisted"; | |||
private static final String PARAMETER_NAME_CANNOT_BE_NULL = "ParameterName cannot be null"; | |||
public Optional<ActiveRuleDto> selectByKey(DbSession session, ActiveRuleKey key) { | |||
return Optional.fromNullable(mapper(session).selectByKey(key.qProfile(), key.ruleKey().repository(), key.ruleKey().rule())); | |||
} | |||
public ActiveRuleDto selectOrFailByKey(DbSession session, ActiveRuleKey key) { | |||
Optional<ActiveRuleDto> activeRule = selectByKey(session, key); | |||
if (activeRule.isPresent()) { | |||
return activeRule.get(); | |||
} | |||
throw new RowNotFoundException(String.format("Active rule with key '%s' does not exist", key)); | |||
} | |||
public List<ActiveRuleDto> selectByRule(DbSession dbSession, RuleDto rule) { | |||
Preconditions.checkNotNull(rule.getId(), RULE_IS_NOT_PERSISTED); | |||
return mapper(dbSession).selectByRuleId(rule.getId()); | |||
} | |||
public List<ActiveRuleParamDto> selectAllParams(DbSession dbSession) { | |||
return mapper(dbSession).selectAllParams(); | |||
} | |||
public ActiveRuleDto insert(DbSession session, ActiveRuleDto item) { | |||
Preconditions.checkArgument(item.getProfileId() != null, QUALITY_PROFILE_IS_NOT_PERSISTED); | |||
Preconditions.checkArgument(item.getRuleId() != null, RULE_IS_NOT_PERSISTED); | |||
Preconditions.checkArgument(item.getId() == null, ACTIVE_RULE_IS_ALREADY_PERSISTED); | |||
mapper(session).insert(item); | |||
return item; | |||
} | |||
public ActiveRuleDto update(DbSession session, ActiveRuleDto item) { | |||
Preconditions.checkArgument(item.getProfileId() != null, QUALITY_PROFILE_IS_NOT_PERSISTED); | |||
Preconditions.checkArgument(item.getRuleId() != null, ActiveRuleDao.RULE_IS_NOT_PERSISTED); | |||
Preconditions.checkArgument(item.getId() != null, ACTIVE_RULE_IS_NOT_PERSISTED); | |||
mapper(session).update(item); | |||
return item; | |||
} | |||
public void delete(DbSession session, ActiveRuleKey key) { | |||
Optional<ActiveRuleDto> activeRule = selectByKey(session, key); | |||
if (activeRule.isPresent()) { | |||
mapper(session).deleteParameters(activeRule.get().getId()); | |||
mapper(session).delete(activeRule.get().getId()); | |||
} | |||
} | |||
/** | |||
* Nested DTO ActiveRuleParams | |||
*/ | |||
public ActiveRuleParamDto insertParam(DbSession session, ActiveRuleDto activeRule, ActiveRuleParamDto activeRuleParam) { | |||
Preconditions.checkArgument(activeRule.getId() != null, ACTIVE_RULE_IS_NOT_PERSISTED); | |||
Preconditions.checkArgument(activeRuleParam.getId() == null, ACTIVE_RULE_PARAM_IS_ALREADY_PERSISTED); | |||
Preconditions.checkNotNull(activeRuleParam.getRulesParameterId(), RULE_PARAM_IS_NOT_PERSISTED); | |||
activeRuleParam.setActiveRuleId(activeRule.getId()); | |||
mapper(session).insertParameter(activeRuleParam); | |||
return activeRuleParam; | |||
} | |||
public void deleteParamByKeyAndName(DbSession session, ActiveRuleKey key, String param) { | |||
// TODO SQL rewrite to delete by key | |||
Optional<ActiveRuleDto> activeRule = selectByKey(session, key); | |||
if (activeRule.isPresent()) { | |||
ActiveRuleParamDto activeRuleParam = mapper(session).selectParamByActiveRuleAndKey(activeRule.get().getId(), param); | |||
if (activeRuleParam != null) { | |||
mapper(session).deleteParameter(activeRuleParam.getId()); | |||
} | |||
} | |||
} | |||
public void updateParam(DbSession session, ActiveRuleDto activeRule, ActiveRuleParamDto activeRuleParam) { | |||
Preconditions.checkNotNull(activeRule.getId(), ACTIVE_RULE_IS_NOT_PERSISTED); | |||
Preconditions.checkNotNull(activeRuleParam.getId(), ACTIVE_RULE_PARAM_IS_NOT_PERSISTED); | |||
mapper(session).updateParameter(activeRuleParam); | |||
} | |||
public void deleteParam(DbSession session, ActiveRuleDto activeRule, ActiveRuleParamDto activeRuleParam) { | |||
Preconditions.checkNotNull(activeRule.getId(), ACTIVE_RULE_IS_NOT_PERSISTED); | |||
Preconditions.checkNotNull(activeRuleParam.getId(), ACTIVE_RULE_PARAM_IS_NOT_PERSISTED); | |||
mapper(session).deleteParameter(activeRuleParam.getId()); | |||
} | |||
public void deleteByProfileKey(DbSession session, String profileKey) { | |||
/** Functional cascade for params */ | |||
for (ActiveRuleDto activeRule : selectByProfileKey(session, profileKey)) { | |||
delete(session, activeRule.getKey()); | |||
} | |||
} | |||
public List<ActiveRuleDto> selectByProfileKey(DbSession session, String profileKey) { | |||
return mapper(session).selectByProfileKey(profileKey); | |||
} | |||
/** | |||
* Finder methods for ActiveRuleParams | |||
*/ | |||
public List<ActiveRuleParamDto> selectParamsByActiveRuleKey(DbSession session, ActiveRuleKey key) { | |||
Preconditions.checkNotNull(key, ACTIVE_RULE_KEY_CANNOT_BE_NULL); | |||
ActiveRuleDto activeRule = selectOrFailByKey(session, key); | |||
return mapper(session).selectParamsByActiveRuleId(activeRule.getId()); | |||
} | |||
@CheckForNull | |||
public ActiveRuleParamDto selectParamByKeyAndName(ActiveRuleKey key, String name, DbSession session) { | |||
Preconditions.checkNotNull(key, ACTIVE_RULE_KEY_CANNOT_BE_NULL); | |||
Preconditions.checkNotNull(name, PARAMETER_NAME_CANNOT_BE_NULL); | |||
Optional<ActiveRuleDto> activeRule = selectByKey(session, key); | |||
if (activeRule.isPresent()) { | |||
return mapper(session).selectParamByActiveRuleAndKey(activeRule.get().getId(), name); | |||
} | |||
return null; | |||
} | |||
public void deleteParamsByRuleParam(DbSession dbSession, RuleDto rule, String paramKey) { | |||
List<ActiveRuleDto> activeRules = selectByRule(dbSession, rule); | |||
for (ActiveRuleDto activeRule : activeRules) { | |||
for (ActiveRuleParamDto activeParam : selectParamsByActiveRuleKey(dbSession, activeRule.getKey())) { | |||
if (activeParam.getKey().equals(paramKey)) { | |||
deleteParam(dbSession, activeRule, activeParam); | |||
} | |||
} | |||
} | |||
} | |||
private ActiveRuleMapper mapper(DbSession session) { | |||
return session.getMapper(ActiveRuleMapper.class); | |||
} | |||
} |
@@ -36,17 +36,20 @@ public class ActiveRuleDto extends Dto<ActiveRuleKey> { | |||
public static final String INHERITED = ActiveRule.INHERITED; | |||
public static final String OVERRIDES = ActiveRule.OVERRIDES; | |||
private String repository; | |||
private String ruleField; | |||
private String profileKey; | |||
private Integer id; | |||
private Integer profileId; | |||
private Integer ruleId; | |||
private Integer severity; | |||
private String inheritance; | |||
//This field do not exists in db, it's only retrieve by joins | |||
private long createdAtInMs; | |||
private long updatedAtInMs; | |||
//These fields do not exists in db, it's only retrieve by joins | |||
private Integer parentId; | |||
private String repository; | |||
private String ruleField; | |||
private String profileKey; | |||
/** | |||
* @deprecated for internal use, should be private | |||
@@ -77,7 +80,6 @@ public class ActiveRuleDto extends Dto<ActiveRuleKey> { | |||
return profileId; | |||
} | |||
// TODO mark as private | |||
public ActiveRuleDto setProfileId(Integer profileId) { | |||
this.profileId = profileId; | |||
return this; | |||
@@ -87,7 +89,6 @@ public class ActiveRuleDto extends Dto<ActiveRuleKey> { | |||
return ruleId; | |||
} | |||
// TODO mark as private | |||
public ActiveRuleDto setRuleId(Integer ruleId) { | |||
this.ruleId = ruleId; | |||
return this; | |||
@@ -122,10 +123,12 @@ public class ActiveRuleDto extends Dto<ActiveRuleKey> { | |||
} | |||
@CheckForNull | |||
@Deprecated | |||
public Integer getParentId() { | |||
return parentId; | |||
} | |||
@Deprecated | |||
public ActiveRuleDto setParentId(@Nullable Integer parentId) { | |||
this.parentId = parentId; | |||
return this; | |||
@@ -139,6 +142,24 @@ public class ActiveRuleDto extends Dto<ActiveRuleKey> { | |||
return StringUtils.equals(OVERRIDES, inheritance); | |||
} | |||
public long getUpdatedAtInMs() { | |||
return updatedAtInMs; | |||
} | |||
public ActiveRuleDto setUpdatedAtInMs(long updatedAtInMs) { | |||
this.updatedAtInMs = updatedAtInMs; | |||
return this; | |||
} | |||
public long getCreatedAtInMs() { | |||
return createdAtInMs; | |||
} | |||
public ActiveRuleDto setCreatedAtInMs(long createdAtInMs) { | |||
this.createdAtInMs = createdAtInMs; | |||
return this; | |||
} | |||
public static ActiveRuleDto createFor(QualityProfileDto profileDto, RuleDto ruleDto) { | |||
Preconditions.checkNotNull(profileDto.getId(), "Profile is not persisted"); | |||
Preconditions.checkNotNull(ruleDto.getId(), "Rule is not persisted"); |
@@ -32,8 +32,8 @@ import org.sonar.api.utils.System2; | |||
import org.sonar.db.Dao; | |||
import org.sonar.db.DbSession; | |||
import org.sonar.db.MyBatis; | |||
import org.sonar.db.component.ComponentDto; | |||
import org.sonar.db.RowNotFoundException; | |||
import org.sonar.db.component.ComponentDto; | |||
@ServerSide | |||
public class QualityProfileDao implements Dao { | |||
@@ -209,21 +209,11 @@ public class QualityProfileDao implements Dao { | |||
} | |||
} | |||
/** | |||
* @deprecated Replaced by | |||
* {@link #selectByKey(DbSession, String)} | |||
*/ | |||
@Deprecated | |||
@CheckForNull | |||
public QualityProfileDto selectById(DbSession session, int id) { | |||
return mapper(session).selectById(id); | |||
} | |||
/** | |||
* @deprecated Replaced by | |||
* {@link #selectByKey(DbSession, String)} | |||
*/ | |||
@Deprecated | |||
@CheckForNull | |||
public QualityProfileDto selectById(int id) { | |||
DbSession session = mybatis.openSession(false); |
@@ -13,7 +13,9 @@ | |||
r.plugin_name as "repository", | |||
qp.kee as "profileKey", | |||
a.created_at as "createdAt", | |||
a.updated_at as "updatedAt" | |||
a.updated_at as "updatedAt", | |||
a.created_at_ms as "createdAtInMs", | |||
a.updated_at_ms as "updatedAtInMs" | |||
</sql> | |||
<sql id="activeRuleKeyJoin"> | |||
@@ -21,6 +23,7 @@ | |||
INNER JOIN rules r ON r.id = a.rule_id | |||
</sql> | |||
<!-- Should be removed when ActiveRuleDao v2 will be removed --> | |||
<sql id="activeRuleColumns"> | |||
a.id, | |||
a.profile_id as profileId, | |||
@@ -29,9 +32,12 @@ | |||
a.inheritance as inheritance, | |||
active_rule_parent.id as parentId, | |||
a.created_at as "createdAt", | |||
a.updated_at as "updatedAt" | |||
a.updated_at as "updatedAt", | |||
a.created_at_ms as "createdAtInMs", | |||
a.updated_at_ms as "updatedAtInMs" | |||
</sql> | |||
<!-- Should be removed when ActiveRuleDao v2 will be removed --> | |||
<sql id="activeRuleJoin"> | |||
INNER JOIN rules_profiles qp ON qp.id=a.profile_id | |||
LEFT JOIN rules_profiles profile_parent ON profile_parent.kee=qp.parent_kee | |||
@@ -52,8 +58,8 @@ | |||
</select> | |||
<insert id="insert" parameterType="ActiveRule" keyColumn="id" useGeneratedKeys="true" keyProperty="id"> | |||
INSERT INTO active_rules (profile_id, rule_id, failure_level, inheritance, created_at, updated_at) | |||
VALUES (#{profileId}, #{ruleId}, #{severity}, #{inheritance}, #{createdAt}, #{updatedAt}) | |||
INSERT INTO active_rules (profile_id, rule_id, failure_level, inheritance, created_at, updated_at, created_at_ms, updated_at_ms) | |||
VALUES (#{profileId}, #{ruleId}, #{severity}, #{inheritance}, #{createdAt}, #{updatedAt}, #{createdAtInMs}, #{updatedAtInMs}) | |||
</insert> | |||
<update id="update" parameterType="ActiveRule"> | |||
@@ -62,7 +68,8 @@ | |||
rule_id=#{ruleId}, | |||
failure_level=#{severity}, | |||
inheritance=#{inheritance}, | |||
updated_at=#{updatedAt} | |||
updated_at=#{updatedAt}, | |||
updated_at_ms=#{updatedAtInMs} | |||
WHERE id=#{id} | |||
</update> | |||
@@ -0,0 +1,25 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2016 SonarSource SA | |||
* mailto:contact AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.db.qualityprofile; | |||
// TODO | |||
public class ActiveRuleDaoTest { | |||
} |