Browse Source

SONAR-8952 make api/rules/tags organization aware

A new elasticsearch type “ruleExtension” is added to the rules index. It stores either system tags, or tags for one, specific organization.
tags/6.4-RC1
Daniel Schwarz 7 years ago
parent
commit
0794633975
62 changed files with 1506 additions and 774 deletions
  1. 9
    0
      server/sonar-db-dao/src/main/java/org/sonar/db/rule/RuleDao.java
  2. 2
    0
      server/sonar-db-dao/src/main/java/org/sonar/db/rule/RuleMapper.java
  3. 23
    0
      server/sonar-db-dao/src/main/resources/org/sonar/db/rule/RuleMapper.xml
  4. 4
    4
      server/sonar-db-dao/src/test/java/org/sonar/db/qualityprofile/ActiveRuleDaoTest.java
  5. 15
    17
      server/sonar-db-dao/src/test/java/org/sonar/db/rule/RuleDbTester.java
  6. 71
    0
      server/sonar-db-dao/src/test/java/org/sonar/db/rule/RuleTesting.java
  7. 6
    2
      server/sonar-server/src/main/java/org/sonar/server/es/IndexerStartupTask.java
  8. 42
    6
      server/sonar-server/src/main/java/org/sonar/server/es/StickyFacetBuilder.java
  9. 19
    36
      server/sonar-server/src/main/java/org/sonar/server/issue/index/IssueIndex.java
  10. 20
    3
      server/sonar-server/src/main/java/org/sonar/server/issue/ws/TagsAction.java
  11. 0
    2
      server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java
  12. 3
    3
      server/sonar-server/src/main/java/org/sonar/server/qualityprofile/index/ActiveRuleDoc.java
  13. 4
    14
      server/sonar-server/src/main/java/org/sonar/server/rule/RegisterRules.java
  14. 1
    1
      server/sonar-server/src/main/java/org/sonar/server/rule/RuleCreator.java
  15. 1
    1
      server/sonar-server/src/main/java/org/sonar/server/rule/RuleDeleter.java
  16. 2
    6
      server/sonar-server/src/main/java/org/sonar/server/rule/RuleUpdater.java
  17. 1
    11
      server/sonar-server/src/main/java/org/sonar/server/rule/index/RuleDoc.java
  18. 11
    15
      server/sonar-server/src/main/java/org/sonar/server/rule/index/RuleDocWithSystemScope.java
  19. 94
    0
      server/sonar-server/src/main/java/org/sonar/server/rule/index/RuleExtensionDoc.java
  20. 62
    0
      server/sonar-server/src/main/java/org/sonar/server/rule/index/RuleExtensionScope.java
  21. 70
    13
      server/sonar-server/src/main/java/org/sonar/server/rule/index/RuleIndex.java
  22. 34
    20
      server/sonar-server/src/main/java/org/sonar/server/rule/index/RuleIndexDefinition.java
  23. 55
    50
      server/sonar-server/src/main/java/org/sonar/server/rule/index/RuleIndexer.java
  24. 1
    1
      server/sonar-server/src/main/java/org/sonar/server/rule/index/RuleIterator.java
  25. 3
    6
      server/sonar-server/src/main/java/org/sonar/server/rule/index/RuleIteratorForMultipleChunks.java
  26. 18
    24
      server/sonar-server/src/main/java/org/sonar/server/rule/index/RuleIteratorForSingleChunk.java
  27. 126
    0
      server/sonar-server/src/main/java/org/sonar/server/rule/index/RuleMetadataIterator.java
  28. 11
    0
      server/sonar-server/src/main/java/org/sonar/server/rule/index/RuleQuery.java
  29. 41
    6
      server/sonar-server/src/main/java/org/sonar/server/rule/ws/TagsAction.java
  30. 4
    4
      server/sonar-server/src/test/java/org/sonar/server/component/ComponentCleanerServiceTest.java
  31. 3
    3
      server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/PersistIssuesStepTest.java
  32. 8
    13
      server/sonar-server/src/test/java/org/sonar/server/issue/IssueServiceMediumTest.java
  33. 3
    4
      server/sonar-server/src/test/java/org/sonar/server/issue/RulesAggregation.java
  34. 4
    4
      server/sonar-server/src/test/java/org/sonar/server/issue/RulesAggregationTest.java
  35. 25
    25
      server/sonar-server/src/test/java/org/sonar/server/issue/index/IssueIndexTest.java
  36. 34
    22
      server/sonar-server/src/test/java/org/sonar/server/issue/ws/TagsActionTest.java
  37. 12
    10
      server/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileBackuperMediumTest.java
  38. 12
    6
      server/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileCopierMediumTest.java
  39. 2
    2
      server/sonar-server/src/test/java/org/sonar/server/qualityprofile/RuleActivatorMediumTest.java
  40. 2
    2
      server/sonar-server/src/test/java/org/sonar/server/qualityprofile/index/ActiveRuleIndexerTest.java
  41. 19
    23
      server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/ChangeParentActionTest.java
  42. 3
    3
      server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/ChangelogLoaderTest.java
  43. 2
    3
      server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/CreateActionTest.java
  44. 6
    9
      server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/InheritanceActionTest.java
  45. 8
    9
      server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/QProfilesWsMediumTest.java
  46. 3
    4
      server/sonar-server/src/test/java/org/sonar/server/rule/RegisterRulesTest.java
  47. 21
    20
      server/sonar-server/src/test/java/org/sonar/server/rule/RuleCreatorMediumTest.java
  48. 3
    3
      server/sonar-server/src/test/java/org/sonar/server/rule/RuleDeleterMediumTest.java
  49. 0
    0
      server/sonar-server/src/test/java/org/sonar/server/rule/RuleServiceMediumTest.java
  50. 17
    20
      server/sonar-server/src/test/java/org/sonar/server/rule/RuleUpdaterMediumTest.java
  51. 0
    2
      server/sonar-server/src/test/java/org/sonar/server/rule/index/RuleDocTesting.java
  52. 1
    1
      server/sonar-server/src/test/java/org/sonar/server/rule/index/RuleIndexDefinitionTest.java
  53. 388
    216
      server/sonar-server/src/test/java/org/sonar/server/rule/index/RuleIndexTest.java
  54. 6
    37
      server/sonar-server/src/test/java/org/sonar/server/rule/index/RuleIndexerTest.java
  55. 32
    26
      server/sonar-server/src/test/java/org/sonar/server/rule/index/RuleIteratorForSingleChunkTest.java
  56. 2
    2
      server/sonar-server/src/test/java/org/sonar/server/rule/ws/ListActionTest.java
  57. 1
    33
      server/sonar-server/src/test/java/org/sonar/server/rule/ws/RulesWsMediumTest.java
  58. 9
    10
      server/sonar-server/src/test/java/org/sonar/server/rule/ws/SearchActionMediumTest.java
  59. 7
    8
      server/sonar-server/src/test/java/org/sonar/server/rule/ws/ShowActionMediumTest.java
  60. 118
    0
      server/sonar-server/src/test/java/org/sonar/server/rule/ws/TagsActionTest.java
  61. 2
    1
      server/sonar-server/src/test/java/org/sonar/server/view/index/ViewIndexerTest.java
  62. 0
    8
      server/sonar-server/src/test/resources/org/sonar/server/rule/ws/RulesWsMediumTest/get_tags.json

+ 9
- 0
server/sonar-db-dao/src/main/java/org/sonar/db/rule/RuleDao.java View File

@@ -29,6 +29,7 @@ import org.sonar.api.rules.RuleQuery;
import org.sonar.db.Dao;
import org.sonar.db.DbSession;
import org.sonar.db.RowNotFoundException;
import org.sonar.db.organization.OrganizationDto;

import static com.google.common.base.Preconditions.checkNotNull;
import static org.sonar.db.DatabaseUtils.executeLargeInputs;
@@ -45,6 +46,10 @@ public class RuleDao implements Dao {
return Optional.fromNullable(mapper(session).selectDefinitionByKey(key));
}

public java.util.Optional<RuleMetadataDto> selectMetadataByKey(DbSession session, RuleKey key, OrganizationDto organization) {
return java.util.Optional.ofNullable(mapper(session).selectMetadataByKey(key, organization.getUuid()));
}

public RuleDto selectOrFailByKey(DbSession session, String organizationUuid, RuleKey key) {
RuleDto rule = mapper(session).selectByKey(organizationUuid, key);
if (rule == null) {
@@ -122,6 +127,10 @@ public class RuleDao implements Dao {
mapper(session).insertDefinition(dto);
}

public void insert(DbSession session, RuleMetadataDto dto) {
mapper(session).insertMetadata(dto);
}

public void update(DbSession session, RuleDefinitionDto dto) {
mapper(session).updateDefinition(dto);
}

+ 2
- 0
server/sonar-db-dao/src/main/java/org/sonar/db/rule/RuleMapper.java View File

@@ -45,6 +45,8 @@ public interface RuleMapper {

RuleDefinitionDto selectDefinitionByKey(RuleKey ruleKey);

RuleMetadataDto selectMetadataByKey(@Param("ruleKey") RuleKey ruleKey, @Param("organizationUuid") String organizationUuid);

List<RuleDto> selectByKeys(@Param("organizationUuid") String organizationUuid, @Param("ruleKeys") List<RuleKey> keys);

List<RuleDefinitionDto> selectDefinitionByKeys(@Param("ruleKeys") List<RuleKey> keys);

+ 23
- 0
server/sonar-db-dao/src/main/resources/org/sonar/db/rule/RuleMapper.xml View File

@@ -139,6 +139,29 @@
and r.plugin_rule_key=#{rule,jdbcType=VARCHAR}
</select>

<select id="selectMetadataByKey" parameterType="map" resultType="org.sonar.db.rule.RuleMetadataDto">
select
rm.rule_id as "ruleId",
rm.organization_uuid as "organizationUuid",
rm.note_data as "noteData",
rm.note_user_login as "noteUserLogin",
rm.note_created_at as "noteCreatedAt",
rm.note_updated_at as "noteUpdatedAt",
rm.remediation_function as "remediationFunction",
rm.remediation_gap_mult as "remediationGapMultiplier",
rm.remediation_base_effort as "remediationBaseEffort",
rm.tags as "tagsField",
rm.created_at as "createdAt",
rm.updated_at as "updatedAt"
from
rules_metadata rm
inner join rules r on rm.rule_id = r.id
where
r.plugin_name=#{ruleKey.repository,jdbcType=VARCHAR}
and r.plugin_rule_key=#{ruleKey.rule,jdbcType=VARCHAR}
and rm.organization_uuid = #{organizationUuid,jdbcType=VARCHAR}
</select>

<select id="selectByKeys" parameterType="map" resultType="Rule">
select
<include refid="selectJoinedTablesColumns"/>

+ 4
- 4
server/sonar-db-dao/src/test/java/org/sonar/db/qualityprofile/ActiveRuleDaoTest.java View File

@@ -67,9 +67,9 @@ public class ActiveRuleDaoTest {
private QualityProfileDto profile1 = QualityProfileDto.createFor("qp1").setOrganizationUuid(organization.getUuid()).setName("QProfile1");
private QualityProfileDto profile2 = QualityProfileDto.createFor("qp2").setOrganizationUuid(organization.getUuid()).setName("QProfile2");

private RuleDefinitionDto rule1 = RuleTesting.newDto(RuleTesting.XOO_X1).getDefinition();
private RuleDefinitionDto rule2 = RuleTesting.newDto(RuleTesting.XOO_X2).getDefinition();
private RuleDefinitionDto rule3 = RuleTesting.newDto(RuleTesting.XOO_X3).getDefinition();
private RuleDefinitionDto rule1 = RuleTesting.newRule(RuleTesting.XOO_X1);
private RuleDefinitionDto rule2 = RuleTesting.newRule(RuleTesting.XOO_X2);
private RuleDefinitionDto rule3 = RuleTesting.newRule(RuleTesting.XOO_X3);

private RuleParamDto rule1Param1;
private RuleParamDto rule1Param2;
@@ -200,7 +200,7 @@ public class ActiveRuleDaoTest {

@Test
public void select_by_profile_ignore_removed_rules() throws Exception {
RuleDefinitionDto removedRule = RuleTesting.newDto(RuleKey.of("removed", "rule")).setStatus(RuleStatus.REMOVED).getDefinition();
RuleDefinitionDto removedRule = RuleTesting.newRule(RuleKey.of("removed", "rule")).setStatus(RuleStatus.REMOVED);
dbTester.rules().insert(removedRule);
ActiveRuleDto activeRule = createFor(profile1, removedRule).setSeverity(BLOCKER);
underTest.insert(dbTester.getSession(), activeRule);

+ 15
- 17
server/sonar-db-dao/src/test/java/org/sonar/db/rule/RuleDbTester.java View File

@@ -27,6 +27,7 @@ import org.sonar.api.server.rule.RuleParamType;
import org.sonar.db.DbTester;
import org.sonar.db.organization.OrganizationDto;

import static org.sonar.db.rule.RuleTesting.newRule;
import static org.sonar.db.rule.RuleTesting.newRuleDto;

public class RuleDbTester {
@@ -38,21 +39,22 @@ public class RuleDbTester {
}

public RuleDefinitionDto insert() {
return insert(RuleTesting.newRule());
return insert(newRule());
}

public RuleDefinitionDto insert(RuleKey key) {
return insert(RuleTesting.newRule(key));
return insert(newRule(key));
}

public RuleDefinitionDto insert(Consumer<RuleDefinitionDto> populater) {
RuleDefinitionDto rule = RuleTesting.newRule();
populater.accept(rule);
@SafeVarargs
public final RuleDefinitionDto insert(Consumer<RuleDefinitionDto>... populaters) {
RuleDefinitionDto rule = newRule();
Arrays.asList(populaters).forEach(populater -> populater.accept(rule));
return insert(rule);
}

public RuleDefinitionDto insert(RuleKey key, Consumer<RuleDefinitionDto> populater) {
RuleDefinitionDto rule = RuleTesting.newRule(key);
RuleDefinitionDto rule = newRule(key);
populater.accept(rule);
return insert(rule);
}
@@ -63,13 +65,10 @@ public class RuleDbTester {
return rule;
}

public RuleMetadataDto insertOrUpdateMetadata(RuleDefinitionDto rule, OrganizationDto organization) {
return insertOrUpdateMetadata(rule, organization, r -> {});
}

public RuleMetadataDto insertOrUpdateMetadata(RuleDefinitionDto rule, OrganizationDto organization, Consumer<RuleMetadataDto> populater) {
@SafeVarargs
public final RuleMetadataDto insertOrUpdateMetadata(RuleDefinitionDto rule, OrganizationDto organization, Consumer<RuleMetadataDto>... populaters) {
RuleMetadataDto dto = RuleTesting.newRuleMetadata(rule, organization);
populater.accept(dto);
Arrays.asList(populaters).forEach(populater -> populater.accept(dto));
return insertOrUpdateMetadata(dto);
}

@@ -92,12 +91,10 @@ public class RuleDbTester {
}

public RuleDto insertRule(RuleDto ruleDto) {
RuleDao ruleDao = db.getDbClient().ruleDao();
ruleDao.insert(db.getSession(), ruleDto.getDefinition());
db.commit();
insert(ruleDto.getDefinition());
RuleMetadataDto metadata = ruleDto.getMetadata();
if (metadata.getOrganizationUuid() != null) {
ruleDao.insertOrUpdate(db.getSession(), metadata.setRuleId(ruleDto.getId()));
db.getDbClient().ruleDao().insertOrUpdate(db.getSession(), metadata.setRuleId(ruleDto.getId()));
db.commit();
}
return ruleDto;
@@ -111,7 +108,8 @@ public class RuleDbTester {
});
}

public RuleDto insertRule(OrganizationDto organization, Consumer<RuleDto>... populaters) {
@SafeVarargs
public final RuleDto insertRule(OrganizationDto organization, Consumer<RuleDto>... populaters) {
RuleDto ruleDto = newRuleDto(organization);
Arrays.asList(populaters).forEach(populater -> populater.accept(ruleDto));
return insertRule(ruleDto);

+ 71
- 0
server/sonar-db-dao/src/test/java/org/sonar/db/rule/RuleTesting.java View File

@@ -21,6 +21,7 @@ package org.sonar.db.rule;

import com.google.common.collect.ImmutableSet;
import java.util.Date;
import java.util.function.Consumer;
import javax.annotation.Nullable;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.rule.RuleStatus;
@@ -31,6 +32,7 @@ import org.sonar.db.organization.OrganizationDto;
import org.sonar.db.rule.RuleDto.Format;

import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.collect.ImmutableSet.copyOf;
import static com.google.common.collect.Sets.newHashSet;
import static java.util.Objects.requireNonNull;
import static org.apache.commons.lang.RandomStringUtils.randomAlphabetic;
@@ -223,6 +225,10 @@ public class RuleTesting {
.setIsTemplate(true);
}

/**
* @deprecated use {@link #newCustomRule(RuleDefinitionDto)}
*/
@Deprecated
public static RuleDto newCustomRule(RuleDto templateRule) {
checkNotNull(templateRule.getId(), "The template rule need to be persisted before creating this custom rule.");
return newDto(RuleKey.of(templateRule.getRepositoryKey(), templateRule.getRuleKey() + "_" + System.currentTimeMillis()))
@@ -231,7 +237,72 @@ public class RuleTesting {
.setType(templateRule.getType());
}

public static RuleDefinitionDto newCustomRule(RuleDefinitionDto templateRule) {
checkNotNull(templateRule.getId(), "The template rule need to be persisted before creating this custom rule.");
return newRule(RuleKey.of(templateRule.getRepositoryKey(), templateRule.getRuleKey() + "_" + System.currentTimeMillis()))
.setLanguage(templateRule.getLanguage())
.setTemplateId(templateRule.getId())
.setType(templateRule.getType());
}

public static RuleKey randomRuleKey() {
return RuleKey.of("repo_" + randomAlphanumeric(3), "rule_" + randomAlphanumeric(3));
}

public static Consumer<RuleDefinitionDto> setRepositoryKey(String repositoryKey) {
return rule -> rule.setRepositoryKey(repositoryKey);
}

public static Consumer<RuleDefinitionDto> setCreatedAt(long createdAt) {
return rule -> rule.setCreatedAt(createdAt);
}

public static Consumer<RuleDefinitionDto> setUpdatedAt(long updatedtAt) {
return rule -> rule.setUpdatedAt(updatedtAt);
}

public static Consumer<RuleDefinitionDto> setRuleKey(String ruleKey) {
return rule -> rule.setRuleKey(ruleKey);
}

public static Consumer<RuleDefinitionDto> setName(String name) {
return rule -> rule.setName(name);
}

public static Consumer<RuleDefinitionDto> setLanguage(String language) {
return rule -> rule.setLanguage(language);
}

public static Consumer<RuleDefinitionDto> setSeverity(String severity) {
return rule -> rule.setSeverity(severity);
}

public static Consumer<RuleDefinitionDto> setStatus(RuleStatus status) {
return rule -> rule.setStatus(status);
}

public static Consumer<RuleDefinitionDto> setType(RuleType type) {
return rule -> rule.setType(type);
}

public static Consumer<RuleDefinitionDto> setIsTemplate(boolean isTemplate) {
return rule -> rule.setIsTemplate(isTemplate);
}

public static Consumer<RuleDefinitionDto> setTemplateId(@Nullable Integer templateId) {
return rule -> rule.setTemplateId(templateId);
}

public static Consumer<RuleDefinitionDto> setSystemTags(String... tags) {
return rule -> rule.setSystemTags(copyOf(tags));
}

public static Consumer<RuleMetadataDto> setOrganizationUuid(String organizationUuid) {
return rule -> rule.setOrganizationUuid(organizationUuid);
}

public static Consumer<RuleMetadataDto> setTags(String... tags) {
return rule -> rule.setTags(copyOf(tags));
}

}

+ 6
- 2
server/sonar-server/src/main/java/org/sonar/server/es/IndexerStartupTask.java View File

@@ -73,10 +73,14 @@ public class IndexerStartupTask {
}

private Set<IndexType> getUninitializedTypes(StartupIndexer indexer) {
return indexer.getIndexTypes().stream().filter(this::getUninitialized).collect(toSet());
return indexer.getIndexTypes().stream().filter(this::isUninitialized).collect(toSet());
}

private boolean getUninitialized(IndexType indexType) {
private boolean isUninitialized(IndexType indexType) {
return isUninitialized(indexType, esClient);
}

public static boolean isUninitialized(IndexType indexType, EsClient esClient) {
String setting = esClient.nativeClient().admin().indices().prepareGetSettings(indexType.getIndex()).get().getSetting(indexType.getIndex(),
getInitializedSettingName(indexType));
return !"true".equals(setting);

+ 42
- 6
server/sonar-server/src/main/java/org/sonar/server/es/StickyFacetBuilder.java View File

@@ -22,6 +22,7 @@ package org.sonar.server.es;
import java.util.Arrays;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Collector;
import java.util.stream.Collectors;
import javax.annotation.Nullable;
@@ -62,12 +63,35 @@ public class StickyFacetBuilder {
}

public AggregationBuilder buildStickyFacet(String fieldName, String facetName, Object... selected) {
return buildStickyFacet(fieldName, facetName, FACET_DEFAULT_SIZE, selected);
return buildStickyFacet(fieldName, facetName, t -> t, selected);
}

/**
* Creates an aggregation, that will return the top-terms for <code>fieldName</code>.
*
* It will filter according to the filters of every of the <em>other</em> fields, but will not apply filters to <em>this</em> field (so that the user can see all terms, even
* after having chosen for one of the terms).
*
* If special filtering is required (like for nested types), additional functionality can be passed into the method in the <code>additionalAggregationFilter</code> parameter.
*
* @param fieldName the name of the field that contains the terms
* @param facetName the name of the aggregation (use this for to find the corresponding results in the response)
* @param additionalAggregationFilter additional features (like filtering using childQuery)
* @param selected the terms, that the user already has selected
* @return the (global) aggregation, that can be added on top level of the elasticsearch request
*/
public AggregationBuilder buildStickyFacet(String fieldName, String facetName, Function<TermsBuilder, AggregationBuilder<?>> additionalAggregationFilter, Object... selected) {
return buildStickyFacet(fieldName, facetName, FACET_DEFAULT_SIZE, additionalAggregationFilter, selected);
}

public AggregationBuilder buildStickyFacet(String fieldName, String facetName, int size, Object... selected) {
return buildStickyFacet(fieldName, facetName, size, t -> t, selected);
}

private AggregationBuilder buildStickyFacet(String fieldName, String facetName, int size, Function<TermsBuilder, AggregationBuilder<?>> additionalAggregationFilter,
Object... selected) {
BoolQueryBuilder facetFilter = getStickyFacetFilter(fieldName);
FilterAggregationBuilder facetTopAggregation = buildTopFacetAggregation(fieldName, facetName, facetFilter, size);
FilterAggregationBuilder facetTopAggregation = buildTopFacetAggregation(fieldName, facetName, facetFilter, size, additionalAggregationFilter);
facetTopAggregation = addSelectedItemsToFacet(fieldName, facetName, facetTopAggregation, selected);

return AggregationBuilders
@@ -86,6 +110,20 @@ public class StickyFacetBuilder {
}

public FilterAggregationBuilder buildTopFacetAggregation(String fieldName, String facetName, BoolQueryBuilder facetFilter, int size) {
return buildTopFacetAggregation(fieldName, facetName, facetFilter, size, t -> t);
}

private FilterAggregationBuilder buildTopFacetAggregation(String fieldName, String facetName, BoolQueryBuilder facetFilter, int size,
Function<TermsBuilder, AggregationBuilder<?>> additionalAggregationFilter) {
TermsBuilder termsAggregation = buildTermsFacetAggregation(fieldName, facetName, size);
AggregationBuilder<?> innerAggregation = additionalAggregationFilter.apply(termsAggregation);
return AggregationBuilders
.filter(facetName + "_filter")
.filter(facetFilter)
.subAggregation(innerAggregation);
}

private TermsBuilder buildTermsFacetAggregation(String fieldName, String facetName, int size) {
TermsBuilder termsAggregation = AggregationBuilders.terms(facetName)
.field(fieldName)
.order(order)
@@ -94,10 +132,7 @@ public class StickyFacetBuilder {
if (subAggregation != null) {
termsAggregation = termsAggregation.subAggregation(subAggregation);
}
return AggregationBuilders
.filter(facetName + "_filter")
.filter(facetFilter)
.subAggregation(termsAggregation);
return termsAggregation;
}

public FilterAggregationBuilder addSelectedItemsToFacet(String fieldName, String facetName, FilterAggregationBuilder facetTopAggregation, Object... selected) {
@@ -118,4 +153,5 @@ public class StickyFacetBuilder {
facetTopAggregation.subAggregation(selectedTerms);
return facetTopAggregation;
}

}

+ 19
- 36
server/sonar-server/src/main/java/org/sonar/server/issue/index/IssueIndex.java View File

@@ -22,9 +22,7 @@ package org.sonar.server.issue.index;
import com.google.common.base.Function;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
@@ -34,7 +32,6 @@ import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.SortedSet;
import java.util.TimeZone;
import java.util.regex.Pattern;
import javax.annotation.CheckForNull;
@@ -51,8 +48,6 @@ import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.aggregations.AggregationBuilder;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.filter.FilterAggregationBuilder;
import org.elasticsearch.search.aggregations.bucket.global.Global;
import org.elasticsearch.search.aggregations.bucket.global.GlobalBuilder;
import org.elasticsearch.search.aggregations.bucket.histogram.DateHistogramInterval;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.aggregations.bucket.terms.Terms.Order;
@@ -75,7 +70,6 @@ import org.sonar.server.es.Sorting;
import org.sonar.server.es.StickyFacetBuilder;
import org.sonar.server.issue.IssueQuery;
import org.sonar.server.permission.index.AuthorizationTypeSupport;
import org.sonar.server.rule.index.RuleIndexDefinition;
import org.sonar.server.user.UserSession;
import org.sonar.server.view.index.ViewIndexDefinition;

@@ -86,6 +80,8 @@ import static org.elasticsearch.index.query.QueryBuilders.matchAllQuery;
import static org.elasticsearch.index.query.QueryBuilders.termQuery;
import static org.elasticsearch.index.query.QueryBuilders.termsQuery;
import static org.sonar.server.es.EsUtils.escapeSpecialRegexChars;
import static org.sonar.server.issue.index.IssueIndexDefinition.FIELD_ISSUE_ORGANIZATION_UUID;
import static org.sonar.server.issue.index.IssueIndexDefinition.INDEX_TYPE_ISSUE;
import static org.sonarqube.ws.client.issue.IssuesWsParameters.DEPRECATED_FACET_MODE_DEBT;
import static org.sonarqube.ws.client.issue.IssuesWsParameters.DEPRECATED_PARAM_ACTION_PLANS;
import static org.sonarqube.ws.client.issue.IssuesWsParameters.FACET_ASSIGNED_TO_ME;
@@ -157,6 +153,7 @@ public class IssueIndex {
return new IssueDoc(input);
}
};
public static final String AGGREGATION_NAME_FOR_TAGS = "tags__issues";

private final Sorting sorting;
private final EsClient client;
@@ -169,6 +166,7 @@ public class IssueIndex {
this.system = system;
this.userSession = userSession;
this.authorizationTypeSupport = authorizationTypeSupport;

this.sorting = new Sorting();
this.sorting.add(IssueQuery.SORT_BY_ASSIGNEE, IssueIndexDefinition.FIELD_ISSUE_ASSIGNEE);
this.sorting.add(IssueQuery.SORT_BY_STATUS, IssueIndexDefinition.FIELD_ISSUE_STATUS);
@@ -192,7 +190,7 @@ public class IssueIndex {

public SearchResult<IssueDoc> search(IssueQuery query, SearchOptions options) {
SearchRequestBuilder requestBuilder = client
.prepareSearch(IssueIndexDefinition.INDEX_TYPE_ISSUE);
.prepareSearch(INDEX_TYPE_ISSUE);

configureSorting(query, requestBuilder);
configurePagination(options, requestBuilder);
@@ -478,7 +476,7 @@ public class IssueIndex {
private Optional<Long> getMinCreatedAt(Map<String, QueryBuilder> filters, QueryBuilder esQuery) {
String facetNameAndField = IssueIndexDefinition.FIELD_ISSUE_FUNC_CREATED_AT;
SearchRequestBuilder esRequest = client
.prepareSearch(IssueIndexDefinition.INDEX_TYPE_ISSUE)
.prepareSearch(INDEX_TYPE_ISSUE)
.setSize(0);
BoolQueryBuilder esFilter = boolQuery();
filters.values().stream().filter(Objects::nonNull).forEach(esFilter::must);
@@ -592,42 +590,27 @@ public class IssueIndex {
return value == null ? null : termQuery(field, value);
}

public List<String> listTags(@Nullable String textQuery, int maxNumberOfTags) {
public List<String> listTags(String organizationUuid, @Nullable String textQuery, int maxNumberOfTags) {
SearchRequestBuilder requestBuilder = client
.prepareSearch(IssueIndexDefinition.INDEX_TYPE_ISSUE, RuleIndexDefinition.INDEX_TYPE_RULE);

requestBuilder.setQuery(boolQuery().must(matchAllQuery()).filter(createBoolFilter(
IssueQuery.builder().checkAuthorization(false).build())));

GlobalBuilder topAggreg = AggregationBuilders.global("tags");
String tagsOnIssuesSubAggregation = "tags__issues";
String tagsOnRulesSubAggregation = "tags__rules";
.prepareSearch(INDEX_TYPE_ISSUE)
.setQuery(boolQuery()
.filter(termQuery(FIELD_ISSUE_ORGANIZATION_UUID, organizationUuid)))
.setSize(0);

TermsBuilder issueTags = AggregationBuilders.terms(tagsOnIssuesSubAggregation)
TermsBuilder termsAggregation = AggregationBuilders.terms(AGGREGATION_NAME_FOR_TAGS)
.field(IssueIndexDefinition.FIELD_ISSUE_TAGS)
.size(maxNumberOfTags)
.order(Terms.Order.term(true))
.minDocCount(1L);
TermsBuilder ruleTags = AggregationBuilders.terms(tagsOnRulesSubAggregation)
.field(RuleIndexDefinition.FIELD_RULE_ALL_TAGS)
.size(maxNumberOfTags)
.order(Terms.Order.term(true))
.minDocCount(1L);
if (textQuery != null) {
String escapedTextQuery = escapeSpecialRegexChars(textQuery);
issueTags.include(format(SUBSTRING_MATCH_REGEXP, escapedTextQuery));
ruleTags.include(format(SUBSTRING_MATCH_REGEXP, escapedTextQuery));
termsAggregation.include(format(SUBSTRING_MATCH_REGEXP, escapedTextQuery));
}
requestBuilder.addAggregation(termsAggregation);

SearchResponse searchResponse = requestBuilder.addAggregation(topAggreg.subAggregation(issueTags).subAggregation(ruleTags)).get();
Global allTags = searchResponse.getAggregations().get("tags");
SortedSet<String> result = Sets.newTreeSet();
Terms issuesResult = allTags.getAggregations().get(tagsOnIssuesSubAggregation);
Terms rulesResult = allTags.getAggregations().get(tagsOnRulesSubAggregation);
result.addAll(EsUtils.termsKeys(issuesResult));
result.addAll(EsUtils.termsKeys(rulesResult));
List<String> resultAsList = Lists.newArrayList(result);
return resultAsList.size() > maxNumberOfTags && maxNumberOfTags > 0 ? resultAsList.subList(0, maxNumberOfTags) : resultAsList;
SearchResponse searchResponse = requestBuilder.get();
Terms issuesResult = searchResponse.getAggregations().get(AGGREGATION_NAME_FOR_TAGS);
return EsUtils.termsKeys(issuesResult);
}

public Map<String, Long> countTags(IssueQuery query, int maxNumberOfTags) {
@@ -642,7 +625,7 @@ public class IssueIndex {

private Terms listTermsMatching(String fieldName, IssueQuery query, @Nullable String textQuery, Terms.Order termsOrder, int maxNumberOfTags) {
SearchRequestBuilder requestBuilder = client
.prepareSearch(IssueIndexDefinition.INDEX_TYPE_ISSUE)
.prepareSearch(INDEX_TYPE_ISSUE)
// Avoids returning search hits
.setSize(0);

@@ -692,7 +675,7 @@ public class IssueIndex {
}

SearchRequestBuilder requestBuilder = client
.prepareSearch(IssueIndexDefinition.INDEX_TYPE_ISSUE)
.prepareSearch(INDEX_TYPE_ISSUE)
.setSearchType(SearchType.SCAN)
.setScroll(TimeValue.timeValueMinutes(EsUtils.SCROLL_TIME_IN_MINUTES))
.setSize(10_000)

+ 20
- 3
server/sonar-server/src/main/java/org/sonar/server/issue/ws/TagsAction.java View File

@@ -19,8 +19,12 @@
*/
package org.sonar.server.issue.ws;

import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.google.common.io.Resources;
import java.util.Collection;
import java.util.List;
import java.util.SortedSet;
import javax.annotation.Nullable;
import org.sonar.api.server.ws.Request;
import org.sonar.api.server.ws.Response;
@@ -29,6 +33,8 @@ import org.sonar.api.server.ws.WebService.NewAction;
import org.sonar.api.server.ws.WebService.Param;
import org.sonar.api.utils.text.JsonWriter;
import org.sonar.server.issue.index.IssueIndex;
import org.sonar.server.organization.DefaultOrganizationProvider;
import org.sonar.server.rule.index.RuleIndex;

import static org.sonar.api.server.ws.WebService.Param.PAGE_SIZE;

@@ -39,9 +45,13 @@ import static org.sonar.api.server.ws.WebService.Param.PAGE_SIZE;
public class TagsAction implements IssuesWsAction {

private final IssueIndex issueIndex;
private final RuleIndex ruleIndex;
private final DefaultOrganizationProvider defaultOrganizationProvider;

public TagsAction(IssueIndex issueIndex) {
public TagsAction(IssueIndex issueIndex, RuleIndex ruleIndex, DefaultOrganizationProvider defaultOrganizationProvider) {
this.issueIndex = issueIndex;
this.ruleIndex = ruleIndex;
this.defaultOrganizationProvider = defaultOrganizationProvider;
}

@Override
@@ -64,12 +74,19 @@ public class TagsAction implements IssuesWsAction {
public void handle(Request request, Response response) throws Exception {
String query = request.param(Param.TEXT_QUERY);
int pageSize = request.mandatoryParamAsInt("ps");
List<String> tags = listTags(query, pageSize);
List<String> tags = listTags(query, pageSize == 0 ? Integer.MAX_VALUE : pageSize);
writeTags(response, tags);
}

private List<String> listTags(@Nullable String textQuery, int pageSize) {
return issueIndex.listTags(textQuery, pageSize);
Collection<String> issueTags = issueIndex.listTags(defaultOrganizationProvider.get().getUuid(), textQuery, pageSize);
Collection<String> ruleTags = ruleIndex.listTags(defaultOrganizationProvider.get().getUuid(), textQuery, pageSize);

SortedSet<String> result = Sets.newTreeSet();
result.addAll(issueTags);
result.addAll(ruleTags);
List<String> resultAsList = Lists.newArrayList(result);
return resultAsList.size() > pageSize && pageSize > 0 ? resultAsList.subList(0, pageSize) : resultAsList;
}

private static void writeTags(Response response, List<String> tags) {

+ 0
- 2
server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java View File

@@ -166,7 +166,6 @@ import org.sonar.server.rule.RuleDeleter;
import org.sonar.server.rule.RuleUpdater;
import org.sonar.server.rule.index.RuleIndexDefinition;
import org.sonar.server.rule.index.RuleIndexer;
import org.sonar.server.rule.index.RuleIteratorFactory;
import org.sonar.server.rule.ws.ActiveRuleCompleter;
import org.sonar.server.rule.ws.RepositoriesAction;
import org.sonar.server.rule.ws.RuleMapper;
@@ -282,7 +281,6 @@ public class PlatformLevel4 extends PlatformLevel {
// rule
RuleIndexDefinition.class,
RuleIndexer.class,
RuleIteratorFactory.class,
AnnotationRuleParser.class,
XMLRuleParser.class,
DefaultRuleFinder.class,

+ 3
- 3
server/sonar-server/src/main/java/org/sonar/server/qualityprofile/index/ActiveRuleDoc.java View File

@@ -27,7 +27,7 @@ import org.sonar.server.qualityprofile.ActiveRule;

import static com.google.common.base.Preconditions.checkNotNull;
import static org.apache.commons.lang.StringUtils.containsIgnoreCase;
import static org.sonar.server.rule.index.RuleIndexDefinition.FIELD_ACTIVE_ORGANIZATION_UUID;
import static org.sonar.server.rule.index.RuleIndexDefinition.FIELD_ACTIVE_RULE_ORGANIZATION_UUID;
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;
@@ -71,11 +71,11 @@ public class ActiveRuleDoc extends BaseDoc {
}

String organizationUuid() {
return getField(FIELD_ACTIVE_ORGANIZATION_UUID);
return getField(FIELD_ACTIVE_RULE_ORGANIZATION_UUID);
}

public ActiveRuleDoc setOrganizationUuid(String s) {
setField(FIELD_ACTIVE_ORGANIZATION_UUID, s);
setField(FIELD_ACTIVE_RULE_ORGANIZATION_UUID, s);
return this;
}


+ 4
- 14
server/sonar-server/src/main/java/org/sonar/server/rule/RegisterRules.java View File

@@ -28,6 +28,7 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import javax.annotation.Nullable;
import org.apache.commons.lang.ObjectUtils;
import org.apache.commons.lang.StringUtils;
@@ -45,14 +46,12 @@ import org.sonar.api.utils.log.Profiler;
import org.sonar.core.util.stream.MoreCollectors;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.organization.OrganizationDto;
import org.sonar.db.qualityprofile.ActiveRuleDto;
import org.sonar.db.qualityprofile.ActiveRuleParamDto;
import org.sonar.db.rule.RuleDefinitionDto;
import org.sonar.db.rule.RuleDto.Format;
import org.sonar.db.rule.RuleParamDto;
import org.sonar.db.rule.RuleRepositoryDto;
import org.sonar.server.organization.DefaultOrganizationProvider;
import org.sonar.server.qualityprofile.ActiveRuleChange;
import org.sonar.server.qualityprofile.RuleActivator;
import org.sonar.server.qualityprofile.index.ActiveRuleIndexer;
@@ -75,10 +74,9 @@ public class RegisterRules implements Startable {
private final ActiveRuleIndexer activeRuleIndexer;
private final Languages languages;
private final System2 system2;
private final DefaultOrganizationProvider defaultOrganizationProvider;

public RegisterRules(RuleDefinitionsLoader defLoader, RuleActivator ruleActivator, DbClient dbClient, RuleIndexer ruleIndexer,
ActiveRuleIndexer activeRuleIndexer, Languages languages, System2 system2, DefaultOrganizationProvider defaultOrganizationProvider) {
ActiveRuleIndexer activeRuleIndexer, Languages languages, System2 system2) {
this.defLoader = defLoader;
this.ruleActivator = ruleActivator;
this.dbClient = dbClient;
@@ -86,7 +84,6 @@ public class RegisterRules implements Startable {
this.activeRuleIndexer = activeRuleIndexer;
this.languages = languages;
this.system2 = system2;
this.defaultOrganizationProvider = defaultOrganizationProvider;
}

@Override
@@ -111,22 +108,15 @@ public class RegisterRules implements Startable {
List<RuleDefinitionDto> removedRules = processRemainingDbRules(allRules.values(), session);
List<ActiveRuleChange> changes = removeActiveRulesOnStillExistingRepositories(session, removedRules, context);
session.commit();
keysToIndex.addAll(removedRules.stream().map(RuleDefinitionDto::getKey).collect(Collectors.toList()));

persistRepositories(session, context.repositories());
ruleIndexer.delete(removedRules.stream().map(RuleDefinitionDto::getKey).collect(MoreCollectors.toList(removedRules.size())));
ruleIndexer.index(getDefaultOrganization(), keysToIndex);
ruleIndexer.indexRuleDefinitions(keysToIndex);
activeRuleIndexer.index(changes);
profiler.stopDebug();
}
}

private OrganizationDto getDefaultOrganization() {
try (DbSession dbSession = dbClient.openSession(false)) {
return dbClient.organizationDao().selectByUuid(dbSession, defaultOrganizationProvider.get().getUuid())
.orElseThrow(() -> new IllegalStateException("Cannot load default organization"));
}
}

private void persistRepositories(DbSession dbSession, List<RulesDefinition.Repository> repositories) {
dbClient.ruleRepositoryDao().truncate(dbSession);
List<RuleRepositoryDto> dtos = repositories

+ 1
- 1
server/sonar-server/src/main/java/org/sonar/server/rule/RuleCreator.java View File

@@ -88,7 +88,7 @@ public class RuleCreator {
.orElseGet(() -> createCustomRule(customRuleKey, newRule, templateRule, dbSession));

dbSession.commit();
ruleIndexer.index(defaultOrganization, customRuleKey);
ruleIndexer.indexRuleDefinition(customRuleKey);
return customRuleKey;
}


+ 1
- 1
server/sonar-server/src/main/java/org/sonar/server/rule/RuleDeleter.java View File

@@ -61,7 +61,7 @@ public class RuleDeleter {
dbClient.ruleDao().update(dbSession, rule);

dbSession.commit();
ruleIndexer.delete(ruleKey);
ruleIndexer.indexRuleDefinition(ruleKey);
}
}
}

+ 2
- 6
server/sonar-server/src/main/java/org/sonar/server/rule/RuleUpdater.java View File

@@ -39,7 +39,6 @@ import org.sonar.api.server.debt.DebtRemediationFunction;
import org.sonar.api.utils.System2;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.organization.OrganizationDto;
import org.sonar.db.qualityprofile.ActiveRuleDto;
import org.sonar.db.qualityprofile.ActiveRuleParamDto;
import org.sonar.db.rule.RuleDefinitionDto;
@@ -91,17 +90,14 @@ public class RuleUpdater {
return false;
}

String defaultOrganizationUuid = defaultOrganizationProvider.get().getUuid();
OrganizationDto organization = dbClient.organizationDao().selectByUuid(dbSession, defaultOrganizationUuid)
.orElseThrow(() -> new IllegalStateException(String.format("Could not find default organization '%s'", defaultOrganizationUuid)));

RuleDto rule = getRuleDto(update);
// validate only the changes, not all the rule fields
apply(update, rule, userSession);
update(dbSession, rule);
updateParameters(dbSession, update, rule);
dbSession.commit();
ruleIndexer.index(organization, rule.getKey());

ruleIndexer.indexRuleDefinition(rule.getKey());
return true;
}


+ 1
- 11
server/sonar-server/src/main/java/org/sonar/server/rule/index/RuleDoc.java View File

@@ -20,7 +20,6 @@
package org.sonar.server.rule.index;

import com.google.common.collect.Maps;
import java.util.Collection;
import java.util.Map;
import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
@@ -40,7 +39,7 @@ public class RuleDoc extends BaseDoc {
}

public RuleDoc() {
super(Maps.newHashMapWithExpectedSize(16));
super(Maps.newHashMapWithExpectedSize(15));
}

@Override
@@ -166,15 +165,6 @@ public class RuleDoc extends BaseDoc {
return this;
}

public Collection<String> allTags() {
return getField(RuleIndexDefinition.FIELD_RULE_ALL_TAGS);
}

public RuleDoc setAllTags(@Nullable Collection<String> l) {
setField(RuleIndexDefinition.FIELD_RULE_ALL_TAGS, l);
return this;
}

public RuleType type() {
return RuleType.valueOf(getField(RuleIndexDefinition.FIELD_RULE_TYPE));
}

server/sonar-server/src/main/java/org/sonar/server/rule/index/RuleIteratorFactory.java → server/sonar-server/src/main/java/org/sonar/server/rule/index/RuleDocWithSystemScope.java View File

@@ -17,28 +17,24 @@
* 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.rule.index;

import java.util.List;
import org.sonar.api.rule.RuleKey;
import org.sonar.db.DbClient;
import org.sonar.db.organization.OrganizationDto;

import static java.util.Arrays.asList;
package org.sonar.server.rule.index;

public class RuleIteratorFactory {
public class RuleDocWithSystemScope {

private final DbClient dbClient;
private final RuleDoc ruleDoc;
private final RuleExtensionDoc ruleExtensionDoc;

public RuleIteratorFactory(DbClient dbClient) {
this.dbClient = dbClient;
public RuleDocWithSystemScope(RuleDoc ruleDoc, RuleExtensionDoc ruleExtensionDoc) {
this.ruleDoc = ruleDoc;
this.ruleExtensionDoc = ruleExtensionDoc;
}

public RuleIterator createForKey(OrganizationDto organization, RuleKey ruleKey) {
return new RuleIteratorForSingleChunk(dbClient, organization, asList(ruleKey));
public RuleDoc getRuleDoc() {
return ruleDoc;
}

public RuleIterator createForKeys(OrganizationDto organization, List<RuleKey> ruleKeys) {
return new RuleIteratorForMultipleChunks(dbClient, organization, ruleKeys);
public RuleExtensionDoc getRuleExtensionDoc() {
return ruleExtensionDoc;
}
}

+ 94
- 0
server/sonar-server/src/main/java/org/sonar/server/rule/index/RuleExtensionDoc.java View File

@@ -0,0 +1,94 @@
/*
* SonarQube
* Copyright (C) 2009-2017 SonarSource SA
* mailto:info 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.rule.index;

import com.google.common.collect.Maps;
import java.util.Map;
import java.util.Set;
import org.apache.commons.lang.builder.ReflectionToStringBuilder;
import org.sonar.api.rule.RuleKey;
import org.sonar.db.rule.RuleMetadataDto;
import org.sonar.server.es.BaseDoc;

public class RuleExtensionDoc extends BaseDoc {

public RuleExtensionDoc(Map<String, Object> fields) {
super(fields);
}

public RuleExtensionDoc() {
super(Maps.newHashMapWithExpectedSize(4));
}

@Override
public String getId() {
// the Id is generated by elasticsearch
return null;
}

@Override
public String getRouting() {
return null;
}

@Override
public String getParent() {
return getRuleKey().toString();
}

public RuleKey getRuleKey() {
return getField(RuleIndexDefinition.FIELD_RULE_EXTENSION_RULE_KEY);
}

public RuleExtensionDoc setRuleKey(RuleKey ruleKey) {
setField(RuleIndexDefinition.FIELD_RULE_EXTENSION_RULE_KEY, ruleKey);
return this;
}

public RuleExtensionScope getScope() {
return RuleExtensionScope.parse(getField(RuleIndexDefinition.FIELD_RULE_EXTENSION_SCOPE));
}

public RuleExtensionDoc setScope(RuleExtensionScope scope) {
setField(RuleIndexDefinition.FIELD_RULE_EXTENSION_SCOPE, scope.getScope());
return this;
}

public Set<String> getTags() {
return getField(RuleIndexDefinition.FIELD_RULE_EXTENSION_TAGS);
}

public RuleExtensionDoc setTags(Set<String> tags) {
setField(RuleIndexDefinition.FIELD_RULE_EXTENSION_TAGS, tags);
return this;
}

public static RuleExtensionDoc of(RuleKey key, RuleExtensionScope scope, RuleMetadataDto ruleExtension) {
return new RuleExtensionDoc()
.setRuleKey(key)
.setScope(scope)
.setTags(ruleExtension.getTags());
}

@Override
public String toString() {
return ReflectionToStringBuilder.toString(this);
}
}

+ 62
- 0
server/sonar-server/src/main/java/org/sonar/server/rule/index/RuleExtensionScope.java View File

@@ -0,0 +1,62 @@
/*
* SonarQube
* Copyright (C) 2009-2017 SonarSource SA
* mailto:info 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.rule.index;

import java.util.Optional;
import javax.annotation.Nullable;
import org.sonar.db.organization.OrganizationDto;

import static com.google.common.base.Preconditions.checkArgument;

public class RuleExtensionScope {

private static final String FAKE_UUID_FOR_SYSTEM = "system";

private final Optional<String> organizationUuid;

private RuleExtensionScope(@Nullable String organizationUuid) {
this.organizationUuid = Optional.ofNullable(organizationUuid);
}

public static RuleExtensionScope system() {
return new RuleExtensionScope(null);
}

public static RuleExtensionScope organization(OrganizationDto organization) {
return organization(organization.getUuid());
}

public static RuleExtensionScope organization(String organizationUuid) {
checkArgument(!FAKE_UUID_FOR_SYSTEM.equals(organizationUuid), "The organization uuid '%s' is reserved for to store system tags in the rules index.", FAKE_UUID_FOR_SYSTEM);
return new RuleExtensionScope(organizationUuid);
}

public String getScope() {
return organizationUuid.orElse(FAKE_UUID_FOR_SYSTEM);
}

public static RuleExtensionScope parse(String scope) {
if (FAKE_UUID_FOR_SYSTEM.equals(scope)) {
return system();
}
return new RuleExtensionScope(scope);
}
}

+ 70
- 13
server/sonar-server/src/main/java/org/sonar/server/rule/index/RuleIndex.java View File

@@ -30,7 +30,9 @@ import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.function.Function;
import javax.annotation.Nullable;
import org.apache.commons.lang.StringUtils;
import org.elasticsearch.action.search.SearchRequestBuilder;
@@ -43,8 +45,11 @@ import org.elasticsearch.index.query.MatchQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.SimpleQueryStringBuilder;
import org.elasticsearch.index.query.TermsQueryBuilder;
import org.elasticsearch.search.aggregations.AbstractAggregationBuilder;
import org.elasticsearch.search.aggregations.AggregationBuilder;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.filter.FilterAggregationBuilder;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.aggregations.bucket.terms.TermsBuilder;
import org.elasticsearch.search.sort.FieldSortBuilder;
@@ -55,24 +60,29 @@ import org.sonar.api.rule.RuleStatus;
import org.sonar.api.rule.Severity;
import org.sonar.api.rules.RuleType;
import org.sonar.server.es.EsClient;
import org.sonar.server.es.EsUtils;
import org.sonar.server.es.SearchIdResult;
import org.sonar.server.es.SearchOptions;
import org.sonar.server.es.StickyFacetBuilder;

import static com.google.common.base.Preconditions.checkArgument;
import static org.elasticsearch.index.query.QueryBuilders.boolQuery;
import static org.elasticsearch.index.query.QueryBuilders.matchAllQuery;
import static org.elasticsearch.index.query.QueryBuilders.matchQuery;
import static org.elasticsearch.index.query.QueryBuilders.simpleQueryStringQuery;
import static org.elasticsearch.index.query.QueryBuilders.termsQuery;
import static org.sonar.server.es.DefaultIndexSettingsElement.SEARCH_WORDS_ANALYZER;
import static org.sonar.server.es.DefaultIndexSettingsElement.SORTABLE_ANALYZER;
import static org.sonar.server.es.EsUtils.SCROLL_TIME_IN_MINUTES;
import static org.sonar.server.es.EsUtils.escapeSpecialRegexChars;
import static org.sonar.server.es.EsUtils.scrollIds;
import static org.sonar.server.rule.index.RuleIndexDefinition.FIELD_ACTIVE_RULE_INHERITANCE;
import static org.sonar.server.rule.index.RuleIndexDefinition.FIELD_ACTIVE_RULE_ORGANIZATION_UUID;
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_ALL_TAGS;
import static org.sonar.server.rule.index.RuleIndexDefinition.FIELD_RULE_CREATED_AT;
import static org.sonar.server.rule.index.RuleIndexDefinition.FIELD_RULE_EXTENSION_SCOPE;
import static org.sonar.server.rule.index.RuleIndexDefinition.FIELD_RULE_EXTENSION_TAGS;
import static org.sonar.server.rule.index.RuleIndexDefinition.FIELD_RULE_HTML_DESCRIPTION;
import static org.sonar.server.rule.index.RuleIndexDefinition.FIELD_RULE_INTERNAL_KEY;
import static org.sonar.server.rule.index.RuleIndexDefinition.FIELD_RULE_IS_TEMPLATE;
@@ -88,6 +98,7 @@ import static org.sonar.server.rule.index.RuleIndexDefinition.FIELD_RULE_TYPE;
import static org.sonar.server.rule.index.RuleIndexDefinition.FIELD_RULE_UPDATED_AT;
import static org.sonar.server.rule.index.RuleIndexDefinition.INDEX_TYPE_ACTIVE_RULE;
import static org.sonar.server.rule.index.RuleIndexDefinition.INDEX_TYPE_RULE;
import static org.sonar.server.rule.index.RuleIndexDefinition.INDEX_TYPE_RULE_EXTENSION;

/**
* The unique entry-point to interact with Elasticsearch index "rules".
@@ -108,6 +119,7 @@ public class RuleIndex {
Collections2.filter(
Collections2.transform(Arrays.asList(RuleStatus.values()), RuleStatus::toString),
input -> !RuleStatus.REMOVED.toString().equals(input)));
private static final String AGGREGATION_NAME_FOR_TAGS = "tagsAggregation";
private final EsClient client;

public RuleIndex(EsClient client) {
@@ -196,13 +208,6 @@ public class RuleIndex {
.boost(boost);
}

private static QueryBuilder termAnyQuery(String field, String query, float boost) {
return QueryBuilders.multiMatchQuery(query,
field, SEARCH_WORDS_ANALYZER.subField(field))
.operator(MatchQueryBuilder.Operator.OR)
.boost(boost);
}

/* Build main filter (match based) */
private static Map<String, QueryBuilder> buildFilters(RuleQuery query) {

@@ -245,8 +250,16 @@ public class RuleIndex {
}

if (isNotEmpty(query.getTags())) {
filters.put(FIELD_RULE_ALL_TAGS,
QueryBuilders.termsQuery(FIELD_RULE_ALL_TAGS, query.getTags()));
BoolQueryBuilder q = boolQuery();
String organizationUuid = query.getOrganizationUuid();
checkArgument(organizationUuid != null, "Cannot filter on tags '%s', if no organization is specified.", query.getTags());
query.getTags().stream()
.map(tag -> boolQuery()
.filter(QueryBuilders.termQuery(FIELD_RULE_EXTENSION_TAGS, tag))
.filter(termsQuery(FIELD_RULE_EXTENSION_SCOPE, RuleExtensionScope.system().getScope(), RuleExtensionScope.organization(organizationUuid).getScope())))
.map(childQuery -> QueryBuilders.hasChildQuery(INDEX_TYPE_RULE_EXTENSION.getType(), childQuery))
.forEach(q::filter);
filters.put(FIELD_RULE_EXTENSION_TAGS, q);
}

if (isNotEmpty(query.getTypes())) {
@@ -285,6 +298,7 @@ public class RuleIndex {
addTermFilter(childrenFilter, FIELD_ACTIVE_RULE_PROFILE_KEY, query.getQProfileKey());
addTermFilter(childrenFilter, FIELD_ACTIVE_RULE_INHERITANCE, query.getInheritance());
addTermFilter(childrenFilter, FIELD_ACTIVE_RULE_SEVERITY, query.getActiveSeverities());
addTermFilter(childrenFilter, FIELD_ACTIVE_RULE_ORGANIZATION_UUID, query.getOrganizationUuid());

// ChildQuery
QueryBuilder childQuery;
@@ -294,7 +308,7 @@ public class RuleIndex {
childQuery = matchAllQuery();
}

/** Implementation of activation query */
/* Implementation of activation query */
if (Boolean.TRUE.equals(query.getActivation())) {
filters.put("activation",
QueryBuilders.hasChildQuery(INDEX_TYPE_ACTIVE_RULE.getType(),
@@ -354,8 +368,24 @@ public class RuleIndex {
}
if (options.getFacets().contains(FACET_TAGS) || options.getFacets().contains(FACET_OLD_DEFAULT)) {
Collection<String> tags = query.getTags();
String organizationUuid = query.getOrganizationUuid();
checkArgument(organizationUuid != null, "Cannot use tags facet, if no organization is specified.", query.getTags());

Function<TermsBuilder, AggregationBuilder<?>> childFeature = termsAggregation -> {

FilterAggregationBuilder scopeAggregation = AggregationBuilders.filter("scope_filter_for_" + FACET_TAGS).filter(
termsQuery(FIELD_RULE_EXTENSION_SCOPE,
RuleExtensionScope.system().getScope(),
RuleExtensionScope.organization(organizationUuid).getScope()))
.subAggregation(termsAggregation);

return AggregationBuilders.children("children_for_" + FACET_TAGS)
.childType(INDEX_TYPE_RULE_EXTENSION.getType())
.subAggregation(scopeAggregation);
};

aggregations.put(FACET_TAGS,
stickyFacetBuilder.buildStickyFacet(FIELD_RULE_ALL_TAGS, FACET_TAGS,
stickyFacetBuilder.buildStickyFacet(FIELD_RULE_EXTENSION_TAGS, FACET_TAGS, childFeature,
(tags == null) ? (new String[0]) : tags.toArray()));
}
if (options.getFacets().contains(FACET_TYPES)) {
@@ -482,7 +512,10 @@ public class RuleIndex {
.addAggregation(termsAggregation);

SearchResponse esResponse = request.get();
return extractAggregationTerms(aggregationKey, esResponse);
}

private static Set<String> extractAggregationTerms(String aggregationKey, SearchResponse esResponse) {
Set<String> terms = new HashSet<>();
Terms aggregation = esResponse.getAggregations().get(aggregationKey);
if (aggregation != null) {
@@ -491,8 +524,32 @@ public class RuleIndex {
return terms;
}

public Set<String> listTags(String organizationUuid, @Nullable String query, int size) {
TermsQueryBuilder scopeFilter = QueryBuilders.termsQuery(
FIELD_RULE_EXTENSION_SCOPE,
RuleExtensionScope.system().getScope(),
RuleExtensionScope.organization(organizationUuid).getScope());

TermsBuilder termsAggregation = AggregationBuilders.terms(AGGREGATION_NAME_FOR_TAGS)
.field(FIELD_RULE_EXTENSION_TAGS)
.size(size)
.minDocCount(1);
Optional.ofNullable(query)
.map(EsUtils::escapeSpecialRegexChars)
.map(queryString -> ".*" + queryString + ".*")
.ifPresent(termsAggregation::include);

SearchRequestBuilder request = client
.prepareSearch(INDEX_TYPE_RULE_EXTENSION)
.setQuery(boolQuery().filter(scopeFilter))
.setSize(0)
.addAggregation(termsAggregation);

SearchResponse esResponse = request.get();
return extractAggregationTerms(AGGREGATION_NAME_FOR_TAGS, esResponse);
}

private static boolean isNotEmpty(@Nullable Collection list) {
return list != null && !list.isEmpty();
}

}

+ 34
- 20
server/sonar-server/src/main/java/org/sonar/server/rule/index/RuleIndexDefinition.java View File

@@ -52,20 +52,26 @@ public class RuleIndexDefinition implements IndexDefinition {
public static final String FIELD_RULE_LANGUAGE = "lang";
public static final String FIELD_RULE_IS_TEMPLATE = "isTemplate";
public static final String FIELD_RULE_TEMPLATE_KEY = "templateKey";
public static final String FIELD_RULE_ALL_TAGS = "allTags";
public static final String FIELD_RULE_TYPE = "type";
public static final String FIELD_RULE_CREATED_AT = "createdAt";
public static final String FIELD_RULE_UPDATED_AT = "updatedAt";

public static final Set<String> SORT_FIELDS = ImmutableSet.of(
RuleIndexDefinition.FIELD_RULE_NAME,
RuleIndexDefinition.FIELD_RULE_UPDATED_AT,
RuleIndexDefinition.FIELD_RULE_CREATED_AT,
RuleIndexDefinition.FIELD_RULE_KEY);
FIELD_RULE_NAME,
FIELD_RULE_UPDATED_AT,
FIELD_RULE_CREATED_AT,
FIELD_RULE_KEY);

// Rule extension fields
public static final IndexType INDEX_TYPE_RULE_EXTENSION = new IndexType(INDEX, "ruleExtension");
/** The uuid of a {@link RuleExtensionScope} */
public static final String FIELD_RULE_EXTENSION_SCOPE = "scope";
public static final String FIELD_RULE_EXTENSION_RULE_KEY = "ruleKey";
public static final String FIELD_RULE_EXTENSION_TAGS = "tags";

// Active rule fields
public static final IndexType INDEX_TYPE_ACTIVE_RULE = new IndexType(INDEX, "activeRule");
public static final String FIELD_ACTIVE_ORGANIZATION_UUID = "organizationUuid";
public static final String FIELD_ACTIVE_RULE_ORGANIZATION_UUID = "organizationUuid";
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";
@@ -89,23 +95,32 @@ public class RuleIndexDefinition implements IndexDefinition {
index.configureShards(settings, 1);

// Active rule type
NewIndex.NewIndexType activeRuleMapping = index.createType(RuleIndexDefinition.INDEX_TYPE_ACTIVE_RULE.getType());
NewIndex.NewIndexType activeRuleMapping = index.createType(INDEX_TYPE_ACTIVE_RULE.getType());
activeRuleMapping.setEnableSource(false);
activeRuleMapping.setAttribute("_parent", ImmutableMap.of("type", RuleIndexDefinition.INDEX_TYPE_RULE.getType()));
activeRuleMapping.setAttribute("_parent", ImmutableMap.of("type", INDEX_TYPE_RULE.getType()));

activeRuleMapping.stringFieldBuilder(RuleIndexDefinition.FIELD_ACTIVE_ORGANIZATION_UUID).disableNorms().build();
activeRuleMapping.stringFieldBuilder(RuleIndexDefinition.FIELD_ACTIVE_RULE_KEY).addSubFields(SORTABLE_ANALYZER).build();
activeRuleMapping.stringFieldBuilder(RuleIndexDefinition.FIELD_ACTIVE_RULE_RULE_KEY).addSubFields(SORTABLE_ANALYZER).build();
activeRuleMapping.stringFieldBuilder(RuleIndexDefinition.FIELD_ACTIVE_RULE_REPOSITORY).build();
activeRuleMapping.stringFieldBuilder(RuleIndexDefinition.FIELD_ACTIVE_RULE_PROFILE_KEY).disableNorms().build();
activeRuleMapping.stringFieldBuilder(RuleIndexDefinition.FIELD_ACTIVE_RULE_INHERITANCE).disableNorms().build();
activeRuleMapping.stringFieldBuilder(RuleIndexDefinition.FIELD_ACTIVE_RULE_SEVERITY).disableNorms().build();
activeRuleMapping.stringFieldBuilder(FIELD_ACTIVE_RULE_ORGANIZATION_UUID).disableNorms().build();
activeRuleMapping.stringFieldBuilder(FIELD_ACTIVE_RULE_KEY).addSubFields(SORTABLE_ANALYZER).build();
activeRuleMapping.stringFieldBuilder(FIELD_ACTIVE_RULE_RULE_KEY).addSubFields(SORTABLE_ANALYZER).build();
activeRuleMapping.stringFieldBuilder(FIELD_ACTIVE_RULE_REPOSITORY).build();
activeRuleMapping.stringFieldBuilder(FIELD_ACTIVE_RULE_PROFILE_KEY).disableNorms().build();
activeRuleMapping.stringFieldBuilder(FIELD_ACTIVE_RULE_INHERITANCE).disableNorms().build();
activeRuleMapping.stringFieldBuilder(FIELD_ACTIVE_RULE_SEVERITY).disableNorms().build();

activeRuleMapping.createLongField(RuleIndexDefinition.FIELD_ACTIVE_RULE_CREATED_AT);
activeRuleMapping.createLongField(RuleIndexDefinition.FIELD_ACTIVE_RULE_UPDATED_AT);
activeRuleMapping.createLongField(FIELD_ACTIVE_RULE_CREATED_AT);
activeRuleMapping.createLongField(FIELD_ACTIVE_RULE_UPDATED_AT);

// Rule extension type
NewIndex.NewIndexType ruleExtensionType = index.createType(INDEX_TYPE_RULE_EXTENSION.getType());
ruleExtensionType.setEnableSource(false);
ruleExtensionType.setAttribute("_parent", ImmutableMap.of("type", INDEX_TYPE_RULE.getType()));

ruleExtensionType.stringFieldBuilder(FIELD_RULE_EXTENSION_SCOPE).disableNorms().build();
ruleExtensionType.stringFieldBuilder(FIELD_RULE_EXTENSION_RULE_KEY).disableNorms().build();
ruleExtensionType.stringFieldBuilder(FIELD_RULE_EXTENSION_TAGS).build();

// Rule type
NewIndex.NewIndexType ruleMapping = index.createType(RuleIndexDefinition.INDEX_TYPE_RULE.getType());
NewIndex.NewIndexType ruleMapping = index.createType(INDEX_TYPE_RULE.getType());
ruleMapping.setEnableSource(false);

ruleMapping.stringFieldBuilder(FIELD_RULE_KEY).addSubFields(SORTABLE_ANALYZER).build();
@@ -125,8 +140,7 @@ public class RuleIndexDefinition implements IndexDefinition {

ruleMapping.createBooleanField(FIELD_RULE_IS_TEMPLATE);
ruleMapping.stringFieldBuilder(FIELD_RULE_TEMPLATE_KEY).disableNorms().build();

ruleMapping.stringFieldBuilder(FIELD_RULE_ALL_TAGS).addSubFields(SEARCH_WORDS_ANALYZER).build();
ruleMapping.stringFieldBuilder(FIELD_RULE_TYPE).disableNorms().build();

ruleMapping.createLongField(FIELD_RULE_CREATED_AT);

+ 55
- 50
server/sonar-server/src/main/java/org/sonar/server/rule/index/RuleIndexer.java View File

@@ -19,8 +19,8 @@
*/
package org.sonar.server.rule.index;

import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableSet;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
@@ -34,98 +34,103 @@ import org.sonar.server.es.BulkIndexer.Size;
import org.sonar.server.es.EsClient;
import org.sonar.server.es.IndexType;
import org.sonar.server.es.StartupIndexer;
import org.sonar.server.organization.DefaultOrganizationProvider;

import static java.util.Collections.singletonList;
import static org.sonar.server.rule.index.RuleIndexDefinition.INDEX_TYPE_RULE;
import static org.sonar.server.rule.index.RuleIndexDefinition.INDEX_TYPE_RULE_EXTENSION;

public class RuleIndexer implements StartupIndexer {

private final EsClient esClient;
private final DbClient dbClient;
private final RuleIteratorFactory ruleIteratorFactory;
private final DefaultOrganizationProvider defaultOrganizationProvider;

public RuleIndexer(EsClient esClient, DbClient dbClient, RuleIteratorFactory ruleIteratorFactory, DefaultOrganizationProvider defaultOrganizationProvider) {
public RuleIndexer(EsClient esClient, DbClient dbClient) {
this.esClient = esClient;
this.dbClient = dbClient;
this.ruleIteratorFactory = ruleIteratorFactory;
this.defaultOrganizationProvider = defaultOrganizationProvider;
}

@Override
public Set<IndexType> getIndexTypes() {
return ImmutableSet.of(INDEX_TYPE_RULE);
return ImmutableSet.of(INDEX_TYPE_RULE, INDEX_TYPE_RULE_EXTENSION);
}

@Override
public void indexOnStartup(Set<IndexType> uninitializedIndexTypes) {
BulkIndexer bulk = new BulkIndexer(esClient, RuleIndexDefinition.INDEX).setSize(Size.LARGE);
bulk.start();

// index all definitions and system extensions
if (uninitializedIndexTypes.contains(INDEX_TYPE_RULE)) {
try(DbSession dbSession = dbClient.openSession(false)) {

String defaultOrganizationUuid = defaultOrganizationProvider.get().getUuid();
OrganizationDto defaultOrganization = dbClient.organizationDao().selectByUuid(dbSession, defaultOrganizationUuid)
.orElseThrow(() -> new IllegalStateException(String.format("Cannot load default organization for uuid '%s'", defaultOrganizationUuid)));
try (RuleIterator rules = new RuleIteratorForSingleChunk(dbClient, null)) {
doIndexRuleDefinitions(rules, bulk);
}
}

try (RuleIterator rules = new RuleIteratorForSingleChunk(dbClient, defaultOrganization, null)) {
doIndex(bulk, rules);
}
// index all organization extensions
if (uninitializedIndexTypes.contains(INDEX_TYPE_RULE_EXTENSION)) {
try (RuleMetadataIterator metadatas = new RuleMetadataIterator(dbClient)) {
doIndexRuleExtensions(metadatas, bulk);
}
}

bulk.stop();
}

public void index(OrganizationDto organization, RuleKey ruleKey) {
BulkIndexer bulk = createBulkIndexer(Size.REGULAR);
try (RuleIterator rules = ruleIteratorFactory.createForKey(organization, ruleKey)) {
doIndex(bulk, rules);
}
public void indexRuleDefinition(RuleKey ruleKey) {
indexRuleDefinitions(singletonList(ruleKey));
}

public void index(OrganizationDto organization, List<RuleKey> ruleKeys) {
BulkIndexer bulk = createBulkIndexer(Size.REGULAR);
try (RuleIterator rules = ruleIteratorFactory.createForKeys(organization, ruleKeys)) {
doIndex(bulk, rules);
public void indexRuleDefinitions(List<RuleKey> ruleKeys) {
BulkIndexer bulk = new BulkIndexer(esClient, RuleIndexDefinition.INDEX).setSize(Size.REGULAR);
bulk.start();

try (RuleIterator rules = new RuleIteratorForMultipleChunks(dbClient, ruleKeys)) {
doIndexRuleDefinitions(rules, bulk);
}

bulk.stop();
}

@VisibleForTesting
public void index(Iterator<RuleDoc> rules) {
doIndex(createBulkIndexer(Size.REGULAR), rules);
public void indexRuleExtension(OrganizationDto organization, RuleKey ruleKey) {
try (DbSession dbSession = dbClient.openSession(false)) {
dbClient.ruleDao()
.selectMetadataByKey(dbSession, ruleKey, organization)
.map(ruleExtension -> RuleExtensionDoc.of(ruleKey, RuleExtensionScope.organization(organization), ruleExtension))
.map(Arrays::asList)
.map(List::iterator)
.ifPresent(metadatas -> {
BulkIndexer bulk = new BulkIndexer(esClient, RuleIndexDefinition.INDEX).setSize(Size.REGULAR);
bulk.start();

doIndexRuleExtensions(metadatas, bulk);

bulk.stop();
});
}
}

private static void doIndex(BulkIndexer bulk, Iterator<RuleDoc> rules) {
bulk.start();
private static void doIndexRuleDefinitions(Iterator<RuleDocWithSystemScope> rules, BulkIndexer bulk) {
while (rules.hasNext()) {
RuleDoc rule = rules.next();
bulk.add(newIndexRequest(rule));
RuleDocWithSystemScope ruleWithExtension = rules.next();
bulk.add(newIndexRequest(ruleWithExtension.getRuleDoc()));
bulk.add(newIndexRequest(ruleWithExtension.getRuleExtensionDoc()));
}
bulk.stop();
}

private BulkIndexer createBulkIndexer(Size size) {
BulkIndexer bulk = new BulkIndexer(esClient, INDEX_TYPE_RULE.getIndex());
bulk.setSize(size);
return bulk;
private static void doIndexRuleExtensions(Iterator<RuleExtensionDoc> metadatas, BulkIndexer bulk) {
while (metadatas.hasNext()) {
RuleExtensionDoc metadata = metadatas.next();
bulk.add(newIndexRequest(metadata));
}
}

private static IndexRequest newIndexRequest(RuleDoc rule) {
return new IndexRequest(INDEX_TYPE_RULE.getIndex(), INDEX_TYPE_RULE.getType(), rule.key().toString()).source(rule.getFields());
}

public void delete(RuleKey ruleKey) {
esClient.prepareDelete(INDEX_TYPE_RULE, ruleKey.toString())
.setRefresh(true)
.get();
}

public void delete(List<RuleKey> rules) {
BulkIndexer bulk = createBulkIndexer(Size.REGULAR);
bulk.start();
for (RuleKey rule : rules) {
bulk.addDeletion(INDEX_TYPE_RULE, rule.toString());
}
bulk.stop();
private static IndexRequest newIndexRequest(RuleExtensionDoc ruleExtension) {
return new IndexRequest(INDEX_TYPE_RULE_EXTENSION.getIndex(), INDEX_TYPE_RULE_EXTENSION.getType())
.source(ruleExtension.getFields())
.parent(ruleExtension.getParent());
}
}

+ 1
- 1
server/sonar-server/src/main/java/org/sonar/server/rule/index/RuleIterator.java View File

@@ -21,7 +21,7 @@ package org.sonar.server.rule.index;

import java.util.Iterator;

public interface RuleIterator extends Iterator<RuleDoc>, AutoCloseable {
public interface RuleIterator extends Iterator<RuleDocWithSystemScope>, AutoCloseable {

@Override
void close();

+ 3
- 6
server/sonar-server/src/main/java/org/sonar/server/rule/index/RuleIteratorForMultipleChunks.java View File

@@ -26,20 +26,17 @@ import java.util.NoSuchElementException;
import org.sonar.api.rule.RuleKey;
import org.sonar.db.DatabaseUtils;
import org.sonar.db.DbClient;
import org.sonar.db.organization.OrganizationDto;

import static java.util.Optional.ofNullable;

public class RuleIteratorForMultipleChunks implements RuleIterator {

private final DbClient dbClient;
private final OrganizationDto organization;
private final Iterator<List<RuleKey>> iteratorOverChunks;
private RuleIteratorForSingleChunk currentChunk;

public RuleIteratorForMultipleChunks(DbClient dbClient, OrganizationDto organization, Collection<RuleKey> keys) {
public RuleIteratorForMultipleChunks(DbClient dbClient, Collection<RuleKey> keys) {
this.dbClient = dbClient;
this.organization = organization;
iteratorOverChunks = DatabaseUtils.toUniqueAndSortedPartitions(keys).iterator();
}

@@ -58,7 +55,7 @@ public class RuleIteratorForMultipleChunks implements RuleIterator {
}

@Override
public RuleDoc next() {
public RuleDocWithSystemScope next() {
for (;;) {
if (currentChunk != null && currentChunk.hasNext()) {
return currentChunk.next();
@@ -73,7 +70,7 @@ public class RuleIteratorForMultipleChunks implements RuleIterator {

private RuleIteratorForSingleChunk nextChunk() {
List<RuleKey> nextInput = iteratorOverChunks.next();
return new RuleIteratorForSingleChunk(dbClient, organization, nextInput);
return new RuleIteratorForSingleChunk(dbClient, nextInput);
}

@Override

+ 18
- 24
server/sonar-server/src/main/java/org/sonar/server/rule/index/RuleIteratorForSingleChunk.java View File

@@ -21,7 +21,6 @@ package org.sonar.server.rule.index;

import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
@@ -36,7 +35,6 @@ import org.sonar.db.DatabaseUtils;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.ResultSetIterator;
import org.sonar.db.organization.OrganizationDto;
import org.sonar.db.rule.RuleDto;
import org.sonar.db.rule.SeverityUtil;
import org.sonar.markdown.Markdown;
@@ -59,11 +57,10 @@ public class RuleIteratorForSingleChunk implements RuleIterator {
"r.priority",
"r.status",
"r.is_template",
"rm.tags",
"r.system_tags",
"t.plugin_rule_key",

// column 11
"t.plugin_rule_key",
"t.plugin_name",
"r.plugin_config_key",
"r.language",
@@ -73,23 +70,19 @@ public class RuleIteratorForSingleChunk implements RuleIterator {
};

private static final String SQL_ALL = "SELECT " + StringUtils.join(FIELDS, ",") + " FROM rules r " +
"LEFT OUTER JOIN rules t ON t.id=r.template_id " +
"LEFT OUTER JOIN rules_metadata rm ON rm.rule_id = r.id and rm.organization_uuid=?";

"LEFT OUTER JOIN rules t ON t.id=r.template_id";
private static final Splitter TAGS_SPLITTER = Splitter.on(',').trimResults().omitEmptyStrings();

private final DbSession session;

private final OrganizationDto organization;
private final List<RuleKey> ruleKeys;

private final PreparedStatement stmt;
private final ResultSetIterator<RuleDoc> iterator;
private final ResultSetIterator<RuleDocWithSystemScope> iterator;

RuleIteratorForSingleChunk(DbClient dbClient, OrganizationDto organization, @Nullable List<RuleKey> ruleKeys) {
RuleIteratorForSingleChunk(DbClient dbClient, @Nullable List<RuleKey> ruleKeys) {
checkArgument(ruleKeys == null || ruleKeys.size() <= DatabaseUtils.PARTITION_SIZE_FOR_ORACLE,
"Cannot search for more than " + DatabaseUtils.PARTITION_SIZE_FOR_ORACLE + " rule keys at once. Please provide the keys in smaller chunks.");
this.organization = organization;
this.ruleKeys = ruleKeys;
this.session = dbClient.openSession(false);

@@ -119,7 +112,7 @@ public class RuleIteratorForSingleChunk implements RuleIterator {
}

@Override
public RuleDoc next() {
public RuleDocWithSystemScope next() {
return iterator.next();
}

@@ -137,7 +130,6 @@ public class RuleIteratorForSingleChunk implements RuleIterator {

private void setParameters(PreparedStatement stmt) throws SQLException {
AtomicInteger index = new AtomicInteger(1);
stmt.setString(index.getAndIncrement(), organization.getUuid());
if (ruleKeys != null && !ruleKeys.isEmpty()) {
for (RuleKey ruleKey : ruleKeys) {
stmt.setString(index.getAndIncrement(), ruleKey.repository());
@@ -156,19 +148,21 @@ public class RuleIteratorForSingleChunk implements RuleIterator {
}
}

private static final class RuleIteratorInternal extends ResultSetIterator<RuleDoc> {
private static final class RuleIteratorInternal extends ResultSetIterator<RuleDocWithSystemScope> {

public RuleIteratorInternal(PreparedStatement stmt) throws SQLException {
super(stmt);
}

@Override
protected RuleDoc read(ResultSet rs) throws SQLException {
protected RuleDocWithSystemScope read(ResultSet rs) throws SQLException {
RuleDoc doc = new RuleDoc();
RuleExtensionDoc extensionDoc = new RuleExtensionDoc().setScope(RuleExtensionScope.system());

String ruleKey = rs.getString(1);
String repositoryKey = rs.getString(2);
RuleKey key = RuleKey.of(repositoryKey, ruleKey);
extensionDoc.setRuleKey(key);

// all the fields must be present, even if value is null
doc.setKey(key.toString());
@@ -191,23 +185,23 @@ public class RuleIteratorForSingleChunk implements RuleIterator {
doc.setSeverity(SeverityUtil.getSeverityFromOrdinal(rs.getInt(6)));
doc.setStatus(rs.getString(7));
doc.setIsTemplate(rs.getBoolean(8));
doc.setAllTags(Sets.union(stringTagsToSet(rs.getString(9)), stringTagsToSet(rs.getString(10))));
extensionDoc.setTags(stringTagsToSet(rs.getString(9)));

String templateRuleKey = rs.getString(11);
String templateRepoKey = rs.getString(12);
String templateRuleKey = rs.getString(10);
String templateRepoKey = rs.getString(11);
if (templateRepoKey != null && templateRuleKey != null) {
doc.setTemplateKey(RuleKey.of(templateRepoKey, templateRuleKey).toString());
} else {
doc.setTemplateKey(null);
}

doc.setInternalKey(rs.getString(13));
doc.setLanguage(rs.getString(14));
doc.setType(RuleType.valueOf(rs.getInt(15)));
doc.setCreatedAt(rs.getLong(16));
doc.setUpdatedAt(rs.getLong(17));
doc.setInternalKey(rs.getString(12));
doc.setLanguage(rs.getString(13));
doc.setType(RuleType.valueOf(rs.getInt(14)));
doc.setCreatedAt(rs.getLong(15));
doc.setUpdatedAt(rs.getLong(16));

return doc;
return new RuleDocWithSystemScope(doc, extensionDoc);
}

private static Set<String> stringTagsToSet(@Nullable String tags) {

+ 126
- 0
server/sonar-server/src/main/java/org/sonar/server/rule/index/RuleMetadataIterator.java View File

@@ -0,0 +1,126 @@
/*
* SonarQube
* Copyright (C) 2009-2017 SonarSource SA
* mailto:info 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.rule.index;

import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableSet;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Iterator;
import java.util.Set;
import javax.annotation.Nullable;
import org.apache.commons.lang.StringUtils;
import org.sonar.api.rule.RuleKey;
import org.sonar.db.DatabaseUtils;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.ResultSetIterator;

/**
* Scrolls over table RULES_METADATA and reads documents to populate the rule extension index type
*/
public class RuleMetadataIterator implements Iterator<RuleExtensionDoc>, AutoCloseable {

private static final String[] FIELDS = {
"r.plugin_name",
"r.plugin_rule_key",
"rm.organization_uuid",
"rm.tags"
};

private static final String SQL_ALL = "SELECT " + StringUtils.join(FIELDS, ",") + " FROM rules r " +
"INNER JOIN rules_metadata rm ON rm.rule_id = r.id " +
"WHERE rm.tags is not null AND rm.tags != ''";
private static final Splitter TAGS_SPLITTER = Splitter.on(',').trimResults().omitEmptyStrings();

private final DbSession session;

private final PreparedStatement stmt;
private final ResultSetIterator<RuleExtensionDoc> iterator;

RuleMetadataIterator(DbClient dbClient) {
this.session = dbClient.openSession(false);

try {
String sql = SQL_ALL;
stmt = dbClient.getMyBatis().newScrollingSelectStatement(session, sql);
iterator = createIterator();
} catch (Exception e) {
session.close();
throw new IllegalStateException("Fail to prepare SQL request to select all rules", e);
}
}

private RuleMetadataIteratorInternal createIterator() {
try {
return new RuleMetadataIteratorInternal(stmt);
} catch (SQLException e) {
DatabaseUtils.closeQuietly(stmt);
throw new IllegalStateException("Fail to prepare SQL request to select all rules", e);
}
}

@Override
public boolean hasNext() {
return iterator.hasNext();
}

@Override
public RuleExtensionDoc next() {
return iterator.next();
}

@Override
public void close() {
try {
iterator.close();
} finally {
DatabaseUtils.closeQuietly(stmt);
session.close();
}
}

private static final class RuleMetadataIteratorInternal extends ResultSetIterator<RuleExtensionDoc> {

public RuleMetadataIteratorInternal(PreparedStatement stmt) throws SQLException {
super(stmt);
}

@Override
protected RuleExtensionDoc read(ResultSet rs) throws SQLException {
RuleExtensionDoc doc = new RuleExtensionDoc();

String ruleKey = rs.getString(1);
String repositoryKey = rs.getString(2);
RuleKey key = RuleKey.of(repositoryKey, ruleKey);
doc.setRuleKey(key);
doc.setScope(RuleExtensionScope.organization(rs.getString(3)));
doc.setTags(stringTagsToSet(rs.getString(4)));

return doc;
}

private static Set<String> stringTagsToSet(@Nullable String tags) {
return ImmutableSet.copyOf(TAGS_SPLITTER.split(tags == null ? "" : tags));
}
}
}

+ 11
- 0
server/sonar-server/src/main/java/org/sonar/server/rule/index/RuleQuery.java View File

@@ -50,6 +50,7 @@ public class RuleQuery {
private boolean ascendingSort = true;
private String internalKey;
private String ruleKey;
private String organizationUuid;

@CheckForNull
public String getQProfileKey() {
@@ -258,4 +259,14 @@ public class RuleQuery {
public String getRuleKey() {
return ruleKey;
}

@CheckForNull
public String getOrganizationUuid() {
return organizationUuid;
}

public RuleQuery setOrganizationUuid(@Nullable String organizationUuid) {
this.organizationUuid = organizationUuid;
return this;
}
}

+ 41
- 6
server/sonar-server/src/main/java/org/sonar/server/rule/ws/TagsAction.java View File

@@ -20,22 +20,34 @@
package org.sonar.server.rule.ws;

import com.google.common.io.Resources;
import java.util.Optional;
import java.util.Set;
import javax.annotation.Nullable;
import org.sonar.api.server.ws.Request;
import org.sonar.api.server.ws.Response;
import org.sonar.api.server.ws.WebService;
import org.sonar.api.server.ws.WebService.NewAction;
import org.sonar.api.server.ws.WebService.Param;
import org.sonar.api.utils.text.JsonWriter;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.organization.OrganizationDto;
import org.sonar.server.organization.DefaultOrganizationProvider;
import org.sonar.server.rule.index.RuleIndex;
import org.sonar.server.rule.index.RuleIndexDefinition;
import org.sonar.server.ws.WsUtils;

import static org.sonarqube.ws.client.component.ComponentsWsParameters.PARAM_ORGANIZATION;

public class TagsAction implements RulesWsAction {

private final RuleIndex ruleIndex;
private final DbClient dbClient;
private final DefaultOrganizationProvider defaultOrganizationProvider;

public TagsAction(RuleIndex ruleIndex) {
public TagsAction(RuleIndex ruleIndex, DbClient dbClient, DefaultOrganizationProvider defaultOrganizationProvider) {
this.ruleIndex = ruleIndex;
this.dbClient = dbClient;
this.defaultOrganizationProvider = defaultOrganizationProvider;
}

@Override
@@ -54,18 +66,41 @@ public class TagsAction implements RulesWsAction {
.setDescription("The size of the list to return, 0 for all tags")
.setExampleValue("25")
.setDefaultValue("0");
action
.createParam(PARAM_ORGANIZATION)
.setDescription("Organization key")
.setRequired(false)
.setInternal(true)
.setExampleValue("my-org")
.setSince("6.4");

}

@Override
public void handle(Request request, Response response) {
OrganizationDto organization = getOrganization(request.param(PARAM_ORGANIZATION));
String query = request.param(Param.TEXT_QUERY);
int pageSize = request.mandatoryParamAsInt("ps");
Set<String> tags = ruleIndex.terms(RuleIndexDefinition.FIELD_RULE_ALL_TAGS, query, pageSize);

Set<String> tags = ruleIndex.listTags(organization.getUuid(), query, pageSize == 0 ? Integer.MAX_VALUE : pageSize);

writeResponse(response, tags);
}

private OrganizationDto getOrganization(@Nullable String organizationKey) {
try (DbSession dbSession = dbClient.openSession(false)) {
String organizationOrDefaultKey = Optional.ofNullable(organizationKey)
.orElseGet(defaultOrganizationProvider.get()::getKey);
return WsUtils.checkFoundWithOptional(
dbClient.organizationDao().selectByKey(dbSession, organizationOrDefaultKey),
"No organization with key '%s'", organizationOrDefaultKey);
}
}

private static void writeResponse(Response response, Set<String> tags) {
JsonWriter json = response.newJsonWriter().beginObject();
json.name("tags").beginArray();
for (String tag : tags) {
json.value(tag);
}
tags.forEach(json::value);
json.endArray().endObject().close();
}
}

+ 4
- 4
server/sonar-server/src/test/java/org/sonar/server/component/ComponentCleanerServiceTest.java View File

@@ -35,7 +35,7 @@ import org.sonar.db.component.SnapshotDto;
import org.sonar.db.component.SnapshotTesting;
import org.sonar.db.issue.IssueDto;
import org.sonar.db.issue.IssueTesting;
import org.sonar.db.rule.RuleDto;
import org.sonar.db.rule.RuleDefinitionDto;
import org.sonar.db.rule.RuleTesting;
import org.sonar.server.es.ProjectIndexer;

@@ -131,9 +131,9 @@ public class ComponentCleanerServiceTest {
String suffix = String.valueOf(id);
ComponentDto project = newProjectDto(db.organizations().insert(), "project-uuid-" + suffix)
.setKey("project-key-" + suffix);
RuleDto rule = RuleTesting.newDto(RuleKey.of("sonarqube", "rule-" + suffix));
dbClient.ruleDao().insert(dbSession, rule.getDefinition());
IssueDto issue = IssueTesting.newDto(rule, project, project).setKee("issue-key-" + suffix).setUpdatedAt(new Date().getTime());
RuleDefinitionDto rule = RuleTesting.newRule(RuleKey.of("sonarqube", "rule-" + suffix));
dbClient.ruleDao().insert(dbSession, rule);
IssueDto issue = IssueTesting.newIssue(rule, project, project).setKee("issue-key-" + suffix).setUpdatedAt(new Date().getTime());
dbClient.componentDao().insert(dbSession, project);
SnapshotDto snapshot = dbClient.snapshotDao().insert(dbSession, SnapshotTesting.newAnalysis(project));
dbClient.issueDao().insert(dbSession, issue);

+ 3
- 3
server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/PersistIssuesStepTest.java View File

@@ -39,7 +39,7 @@ import org.sonar.db.component.ComponentDto;
import org.sonar.db.component.ComponentTesting;
import org.sonar.db.issue.IssueDto;
import org.sonar.db.organization.OrganizationDto;
import org.sonar.db.rule.RuleDto;
import org.sonar.db.rule.RuleDefinitionDto;
import org.sonar.db.rule.RuleTesting;
import org.sonar.scanner.protocol.output.ScannerReport;
import org.sonar.server.computation.task.projectanalysis.analysis.AnalysisMetadataHolderRule;
@@ -95,8 +95,8 @@ public class PersistIssuesStepTest extends BaseStepTest {

@Test
public void insert_new_issue() {
RuleDto rule = RuleTesting.newDto(RuleKey.of("xoo", "S01"));
dbTester.rules().insertRule(rule);
RuleDefinitionDto rule = RuleTesting.newRule(RuleKey.of("xoo", "S01"));
dbTester.rules().insert(rule);
OrganizationDto organizationDto = dbTester.organizations().insert();
ComponentDto project = ComponentTesting.newProjectDto(organizationDto);
dbClient.componentDao().insert(session, project);

+ 8
- 13
server/sonar-server/src/test/java/org/sonar/server/issue/IssueServiceMediumTest.java View File

@@ -47,7 +47,6 @@ import org.sonar.server.es.SearchResult;
import org.sonar.server.issue.index.IssueDoc;
import org.sonar.server.issue.index.IssueIndex;
import org.sonar.server.issue.index.IssueIndexer;
import org.sonar.server.organization.DefaultOrganizationProvider;
import org.sonar.server.permission.GroupPermissionChange;
import org.sonar.server.permission.PermissionChange;
import org.sonar.server.permission.PermissionUpdater;
@@ -74,7 +73,6 @@ public class IssueServiceMediumTest {
private DbSession session;
private IssueService service;
private RuleIndexer ruleIndexer;
private OrganizationDto defaultOrganization;

@Before
public void setUp() {
@@ -83,9 +81,6 @@ public class IssueServiceMediumTest {
session = db.openSession(false);
service = tester.get(IssueService.class);
ruleIndexer = tester.get(RuleIndexer.class);
String defaultOrganizationUuid = tester.get(DefaultOrganizationProvider.class).get().getUuid();
defaultOrganization = db.organizationDao().selectByUuid(session, defaultOrganizationUuid)
.orElseThrow(() -> new IllegalStateException(String.format("Could not find defautl organization '%s'", defaultOrganizationUuid)));
}

@After
@@ -95,7 +90,7 @@ public class IssueServiceMediumTest {

@Test
public void set_tags() {
RuleDto rule = newRule(defaultOrganization);
RuleDto rule = newRule();
ComponentDto project = newProject();
ComponentDto file = newFile(project);
userSessionRule.logIn("john").addProjectUuidPermissions(UserRole.USER, project.uuid());
@@ -130,7 +125,7 @@ public class IssueServiceMediumTest {

@Test
public void list_component_tags() {
RuleDto rule = newRule(defaultOrganization);
RuleDto rule = newRule();
ComponentDto project = newProject();
ComponentDto file = newFile(project);
saveIssue(IssueTesting.newDto(rule, file, project).setTags(ImmutableSet.of("convention", "java8", "bug")));
@@ -150,7 +145,7 @@ public class IssueServiceMediumTest {

@Test
public void test_listAuthors() {
RuleDto rule = newRule(defaultOrganization);
RuleDto rule = newRule();
ComponentDto project = newProject();
ComponentDto file = newFile(project);
saveIssue(IssueTesting.newDto(rule, file, project).setAuthorLogin("luke.skywalker"));
@@ -167,7 +162,7 @@ public class IssueServiceMediumTest {

@Test
public void listAuthors_escapes_regexp_special_characters() {
saveIssue(IssueTesting.newDto(newRule(defaultOrganization), newFile(newProject()), newProject()).setAuthorLogin("name++"));
saveIssue(IssueTesting.newDto(newRule(), newFile(newProject()), newProject()).setAuthorLogin("name++"));

assertThat(service.listAuthors("invalidRegexp[", 5)).isEmpty();
assertThat(service.listAuthors("nam+", 5)).isEmpty();
@@ -175,18 +170,18 @@ public class IssueServiceMediumTest {
assertThat(service.listAuthors(".*", 5)).isEmpty();
}

private RuleDto newRule(OrganizationDto organization) {
return newRule(organization, RuleTesting.newXooX1());
private RuleDto newRule() {
return newRule(RuleTesting.newXooX1());
}

private RuleDto newRule(OrganizationDto organization, RuleDto rule) {
private RuleDto newRule(RuleDto rule) {
RuleDao ruleDao = tester.get(RuleDao.class);
ruleDao.insert(session, rule.getDefinition());
if (rule.getOrganizationUuid() != null) {
ruleDao.insertOrUpdate(session, rule.getMetadata().setRuleId(rule.getId()));
}
session.commit();
ruleIndexer.index(organization, rule.getKey());
ruleIndexer.indexRuleDefinition(rule.getDefinition().getKey());
return rule;
}


server/sonar-server/src/main/java/org/sonar/server/issue/RulesAggregation.java → server/sonar-server/src/test/java/org/sonar/server/issue/RulesAggregation.java View File

@@ -21,10 +21,9 @@ package org.sonar.server.issue;

import com.google.common.collect.HashMultiset;
import com.google.common.collect.Multiset;
import org.sonar.api.rule.RuleKey;
import org.sonar.db.rule.RuleDto;

import java.util.Collection;
import org.sonar.api.rule.RuleKey;
import org.sonar.db.rule.RuleDefinitionDto;

public class RulesAggregation {

@@ -34,7 +33,7 @@ public class RulesAggregation {
this.rules = HashMultiset.create();
}

public RulesAggregation add(RuleDto ruleDto) {
public RulesAggregation add(RuleDefinitionDto ruleDto) {
rules.add(new Rule(ruleDto.getKey(), ruleDto.getName()));
return this;
}

+ 4
- 4
server/sonar-server/src/test/java/org/sonar/server/issue/RulesAggregationTest.java View File

@@ -21,7 +21,7 @@ package org.sonar.server.issue;

import org.junit.Test;
import org.sonar.api.rule.RuleKey;
import org.sonar.db.rule.RuleDto;
import org.sonar.db.rule.RuleDefinitionDto;
import org.sonar.db.rule.RuleTesting;

import static org.assertj.core.api.Assertions.assertThat;
@@ -38,7 +38,7 @@ public class RulesAggregationTest {
public void count_rules() {
RulesAggregation rulesAggregation = new RulesAggregation();
RuleKey ruleKey = RuleKey.of("xoo", "S001");
RuleDto ruleDto = RuleTesting.newDto(ruleKey).setName("Rule name");
RuleDefinitionDto ruleDto = RuleTesting.newRule(ruleKey).setName("Rule name");
rulesAggregation.add(ruleDto);
rulesAggregation.add(ruleDto);

@@ -53,10 +53,10 @@ public class RulesAggregationTest {
public void count_rules_with_different_rules() {
RulesAggregation rulesAggregation = new RulesAggregation();

RuleDto ruleDto = RuleTesting.newDto(RuleKey.of("xoo", "S001")).setName("Rule name 1");
RuleDefinitionDto ruleDto = RuleTesting.newRule(RuleKey.of("xoo", "S001")).setName("Rule name 1");
rulesAggregation.add(ruleDto);
rulesAggregation.add(ruleDto);
rulesAggregation.add(RuleTesting.newDto(RuleKey.of("xoo", "S002")).setName("Rule name 2"));
rulesAggregation.add(RuleTesting.newRule(RuleKey.of("xoo", "S002")).setName("Rule name 2"));

assertThat(rulesAggregation.rules()).hasSize(2);
}

+ 25
- 25
server/sonar-server/src/test/java/org/sonar/server/issue/index/IssueIndexTest.java View File

@@ -20,7 +20,6 @@
package org.sonar.server.issue.index;

import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterators;
import com.google.common.collect.Lists;
import java.util.Date;
@@ -40,9 +39,11 @@ import org.sonar.api.rule.Severity;
import org.sonar.api.utils.Duration;
import org.sonar.api.utils.KeyValueFormat;
import org.sonar.api.utils.System2;
import org.sonar.db.DbTester;
import org.sonar.db.component.ComponentDto;
import org.sonar.db.component.ComponentTesting;
import org.sonar.db.organization.OrganizationDto;
import org.sonar.db.rule.RuleDefinitionDto;
import org.sonar.db.user.GroupDto;
import org.sonar.db.user.UserDto;
import org.sonar.server.es.EsTester;
@@ -52,8 +53,6 @@ import org.sonar.server.issue.IssueQuery;
import org.sonar.server.permission.index.AuthorizationTypeSupport;
import org.sonar.server.permission.index.PermissionIndexerDao;
import org.sonar.server.permission.index.PermissionIndexerTester;
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.tester.UserSessionRule;
@@ -61,6 +60,7 @@ import org.sonar.server.view.index.ViewDoc;
import org.sonar.server.view.index.ViewIndexDefinition;
import org.sonar.server.view.index.ViewIndexer;

import static com.google.common.collect.ImmutableSet.of;
import static com.google.common.collect.Lists.newArrayList;
import static java.util.Arrays.asList;
import static org.assertj.core.api.Assertions.assertThat;
@@ -73,8 +73,6 @@ import static org.sonar.api.utils.DateUtils.parseDateTime;
import static org.sonar.db.component.ComponentTesting.newFileDto;
import static org.sonar.db.component.ComponentTesting.newProjectDto;
import static org.sonar.db.organization.OrganizationTesting.newOrganizationDto;
import static org.sonar.db.rule.RuleTesting.XOO_X1;
import static org.sonar.db.rule.RuleTesting.XOO_X2;
import static org.sonar.db.user.GroupTesting.newGroupDto;
import static org.sonar.db.user.UserTesting.newUserDto;
import static org.sonar.server.issue.IssueDocTesting.newDoc;
@@ -89,16 +87,19 @@ public class IssueIndexTest {
new ViewIndexDefinition(new MapSettings()),
new RuleIndexDefinition(new MapSettings()));
@Rule
public DbTester db = DbTester.create(system2);
@Rule
public UserSessionRule userSessionRule = UserSessionRule.standalone();
@Rule
public ExpectedException expectedException = ExpectedException.none();

private IssueIndexer issueIndexer = new IssueIndexer(tester.client(), new IssueIteratorFactory(null));
private ViewIndexer viewIndexer = new ViewIndexer(null, tester.client());
private RuleIndexer ruleIndexer = new RuleIndexer(tester.client(), null, null, null);
private RuleIndexer ruleIndexer = new RuleIndexer(tester.client(), db.getDbClient());
private PermissionIndexerTester authorizationIndexerTester = new PermissionIndexerTester(tester, issueIndexer);

private IssueIndex underTest = new IssueIndex(tester.client(), system2, userSessionRule, new AuthorizationTypeSupport(userSessionRule));
private IssueIndex underTest = new IssueIndex(tester.client(), system2, userSessionRule, new AuthorizationTypeSupport(userSessionRule)
);

@Before
public void setUp() {
@@ -1326,24 +1327,27 @@ public class IssueIndexTest {

@Test
public void list_tags() {
indexRules(
RuleDocTesting.newDoc(XOO_X1).setAllTags(asList("tag1", "systag1")),
RuleDocTesting.newDoc(XOO_X2).setAllTags(asList("tag2", "systag2")));
RuleDefinitionDto r1 = db.rules().insert();
ruleIndexer.indexRuleDefinition(r1.getKey());

RuleDefinitionDto r2 = db.rules().insert();
ruleIndexer.indexRuleDefinition(r2.getKey());

OrganizationDto org = db.organizations().insert();
ComponentDto project = newProjectDto(newOrganizationDto());
ComponentDto file = newFileDto(project, null);
indexIssues(
newDoc("ISSUE1", file).setRuleKey(XOO_X1.toString()).setTags(ImmutableSet.of("convention", "java8", "bug")),
newDoc("ISSUE2", file).setRuleKey(XOO_X1.toString()).setTags(ImmutableSet.of("convention", "bug")),
newDoc("ISSUE3", file).setRuleKey(XOO_X2.toString()),
newDoc("ISSUE4", file).setRuleKey(XOO_X1.toString()).setTags(ImmutableSet.of("convention")));
newDoc("ISSUE1", file).setOrganizationUuid(org.getUuid()).setRuleKey(r1.getKey().toString()).setTags(of("convention", "java8", "bug")),
newDoc("ISSUE2", file).setOrganizationUuid(org.getUuid()).setRuleKey(r1.getKey().toString()).setTags(of("convention", "bug")),
newDoc("ISSUE3", file).setOrganizationUuid(org.getUuid()).setRuleKey(r2.getKey().toString()),
newDoc("ISSUE4", file).setOrganizationUuid(org.getUuid()).setRuleKey(r1.getKey().toString()).setTags(of("convention")));

assertThat(underTest.listTags(null, 5)).containsOnly("convention", "java8", "bug", "systag1", "systag2");
assertThat(underTest.listTags(null, 2)).containsOnly("bug", "convention");
assertThat(underTest.listTags("vent", 5)).containsOnly("convention");
assertThat(underTest.listTags("sys", 5)).containsOnly("systag1", "systag2");
assertThat(underTest.listTags(null, 1)).containsOnly("bug");
assertThat(underTest.listTags(null, Integer.MAX_VALUE)).containsOnly("convention", "java8", "bug", "systag1", "systag2", "tag1", "tag2");
assertThat(underTest.listTags("invalidRegexp[", 5)).isEmpty();
assertThat(underTest.listTags(org.getUuid(), null, Integer.MAX_VALUE)).containsOnly("convention", "java8", "bug");
assertThat(underTest.listTags(org.getUuid(), null, 2)).containsOnly("bug", "convention");
assertThat(underTest.listTags(org.getUuid(), "vent", Integer.MAX_VALUE)).containsOnly("convention");
assertThat(underTest.listTags(org.getUuid(), null, 1)).containsOnly("bug");
assertThat(underTest.listTags(org.getUuid(), null, Integer.MAX_VALUE)).containsOnly("convention", "java8", "bug");
assertThat(underTest.listTags(org.getUuid(), "invalidRegexp[", Integer.MAX_VALUE)).isEmpty();
}

@Test
@@ -1405,8 +1409,4 @@ public class IssueIndexTest {
private void indexView(String viewUuid, List<String> projects) {
viewIndexer.index(new ViewDoc().setUuid(viewUuid).setProjects(projects));
}

private void indexRules(RuleDoc... rules) {
ruleIndexer.index(asList(rules).iterator());
}
}

+ 34
- 22
server/sonar-server/src/test/java/org/sonar/server/issue/ws/TagsActionTest.java View File

@@ -19,7 +19,6 @@
*/
package org.sonar.server.issue.ws;

import com.google.common.collect.ImmutableSet;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -32,25 +31,26 @@ import org.sonar.db.component.ComponentDto;
import org.sonar.db.issue.IssueDto;
import org.sonar.db.issue.IssueTesting;
import org.sonar.db.organization.OrganizationDto;
import org.sonar.db.rule.RuleDto;
import org.sonar.db.rule.RuleDefinitionDto;
import org.sonar.server.es.EsTester;
import org.sonar.server.issue.index.IssueIndex;
import org.sonar.server.issue.index.IssueIndexDefinition;
import org.sonar.server.issue.index.IssueIndexer;
import org.sonar.server.issue.index.IssueIteratorFactory;
import org.sonar.server.organization.TestDefaultOrganizationProvider;
import org.sonar.server.permission.index.AuthorizationTypeSupport;
import org.sonar.server.rule.index.RuleIndex;
import org.sonar.server.rule.index.RuleIndexDefinition;
import org.sonar.server.rule.index.RuleIndexer;
import org.sonar.server.rule.index.RuleIteratorFactory;
import org.sonar.server.tester.UserSessionRule;
import org.sonar.server.ws.WsActionTester;

import static java.util.Arrays.asList;
import static java.util.Collections.emptySet;
import static org.assertj.core.api.Assertions.assertThat;
import static org.sonar.api.web.UserRole.USER;
import static org.sonar.db.component.ComponentTesting.newFileDto;
import static org.sonar.db.rule.RuleTesting.newRuleDto;
import static org.sonar.db.rule.RuleTesting.setSystemTags;
import static org.sonar.db.rule.RuleTesting.setTags;
import static org.sonar.test.JsonAssert.assertJson;

public class TagsActionTest {
@@ -63,10 +63,11 @@ public class TagsActionTest {
public EsTester es = new EsTester(new IssueIndexDefinition(new MapSettings()), new RuleIndexDefinition(new MapSettings()));

private IssueIndexer issueIndexer = new IssueIndexer(es.client(), new IssueIteratorFactory(db.getDbClient()));
private RuleIndexer ruleIndexer = new RuleIndexer(es.client(), null, new RuleIteratorFactory(db.getDbClient()), null);
private RuleIndexer ruleIndexer = new RuleIndexer(es.client(), db.getDbClient());
private IssueIndex issueIndex = new IssueIndex(es.client(), System2.INSTANCE, userSession, new AuthorizationTypeSupport(userSession));
private RuleIndex ruleIndex = new RuleIndex(es.client());

private WsActionTester tester = new WsActionTester(new TagsAction(issueIndex));
private WsActionTester tester = new WsActionTester(new TagsAction(issueIndex, ruleIndex, TestDefaultOrganizationProvider.from(db)));
private OrganizationDto organization;

@Before
@@ -86,10 +87,15 @@ public class TagsActionTest {

@Test
public void return_tags_from_rules() throws Exception {
RuleDto r = db.rules().insertRule(organization, rule -> rule.setSystemTags(ImmutableSet.of("tag1")), rule -> rule.setTags(ImmutableSet.of("tag2")));
RuleDto r2 = db.rules().insertRule(organization, rule -> rule.setSystemTags(ImmutableSet.of("tag3")), rule -> rule.setTags(ImmutableSet.of("tag4", "tag5")));
db.commit();
ruleIndexer.index(organization, asList(r.getKey(), r2.getKey()));
RuleDefinitionDto r = db.rules().insert(setSystemTags("tag1"));
ruleIndexer.indexRuleDefinition(r.getKey());
db.rules().insertOrUpdateMetadata(r, organization, setTags("tag2"));
ruleIndexer.indexRuleExtension(organization, r.getKey());

RuleDefinitionDto r2 = db.rules().insert(setSystemTags("tag3"));
ruleIndexer.indexRuleDefinition(r2.getKey());
db.rules().insertOrUpdateMetadata(r2, organization, setTags("tag4", "tag5"));
ruleIndexer.indexRuleExtension(organization, r2.getKey());

String result = tester.newRequest().execute().getInput();
assertJson(result).isSimilarTo("{\"tags\":[\"tag1\", \"tag2\", \"tag3\", \"tag4\", \"tag5\"]}");
@@ -100,8 +106,11 @@ public class TagsActionTest {
insertIssueWithBrowsePermission(insertRuleWithoutTags(), "tag1", "tag2");
insertIssueWithBrowsePermission(insertRuleWithoutTags(), "tag3", "tag4", "tag5");
issueIndexer.indexOnStartup(null);
RuleDto r = db.rules().insertRule(db.getDefaultOrganization(), rule -> rule.setSystemTags(ImmutableSet.of("tag6")).setTags(ImmutableSet.of("tag7")));
ruleIndexer.index(organization, r.getKey());

RuleDefinitionDto r = db.rules().insert(setSystemTags("tag6"));
ruleIndexer.indexRuleDefinition(r.getKey());
db.rules().insertOrUpdateMetadata(r, organization, setTags("tag7"));
ruleIndexer.indexRuleExtension(organization, r.getKey());

String result = tester.newRequest().execute().getInput();
assertJson(result).isSimilarTo("{\"tags\":[\"tag1\", \"tag2\", \"tag3\", \"tag4\", \"tag5\", \"tag6\", \"tag7\"]}");
@@ -137,8 +146,11 @@ public class TagsActionTest {
public void test_example() throws Exception {
insertIssueWithBrowsePermission(insertRuleWithoutTags(), "convention");
issueIndexer.indexOnStartup(null);
RuleDto r = db.rules().insertRule(db.getDefaultOrganization(), rule -> rule.setSystemTags(ImmutableSet.of("cwe")).setTags(ImmutableSet.of("security")));
ruleIndexer.index(organization, r.getKey());

RuleDefinitionDto r = db.rules().insert(setSystemTags("cwe"));
ruleIndexer.indexRuleDefinition(r.getKey());
db.rules().insertOrUpdateMetadata(r, organization, setTags("security"));
ruleIndexer.indexRuleExtension(organization, r.getKey());

String result = tester.newRequest().execute().getInput();
assertJson(result).isSimilarTo(tester.getDef().responseExampleAsString());
@@ -154,27 +166,27 @@ public class TagsActionTest {
assertThat(action.params()).hasSize(2);

Param query = action.param("q");
assertThat(query).isNotNull();
assertThat(query.isRequired()).isFalse();
assertThat(query.description()).isNotEmpty();
assertThat(query.exampleValue()).isNotEmpty();

Param pageSize = action.param("ps");
assertThat(pageSize).isNotNull();
assertThat(pageSize.isRequired()).isFalse();
assertThat(pageSize.defaultValue()).isEqualTo("10");
assertThat(pageSize.description()).isNotEmpty();
assertThat(pageSize.exampleValue()).isNotEmpty();
}

private RuleDto insertRuleWithoutTags() {
RuleDto ruleDto = newRuleDto(db.getDefaultOrganization()).setTags(emptySet()).setSystemTags(emptySet());
db.rules().insertRule(ruleDto);
return ruleDto;
private RuleDefinitionDto insertRuleWithoutTags() {
return db.rules().insert(setSystemTags());
}

private IssueDto insertIssue(RuleDto rule, String... tags) {
private IssueDto insertIssue(RuleDefinitionDto rule, String... tags) {
ComponentDto project = db.components().insertProject(organization);
ComponentDto file = db.components().insertComponent(newFileDto(project));
IssueDto issueDto = IssueTesting.newDto(rule, file, project).setTags(asList(tags));
IssueDto issueDto = IssueTesting.newIssue(rule, file, project).setTags(asList(tags));
return db.issues().insertIssue(issueDto);
}

@@ -182,7 +194,7 @@ public class TagsActionTest {
userSession.logIn("john").addProjectUuidPermissions(USER, issue.getProjectUuid());
}

private IssueDto insertIssueWithBrowsePermission(RuleDto rule, String... tags) {
private IssueDto insertIssueWithBrowsePermission(RuleDefinitionDto rule, String... tags) {
IssueDto issue = insertIssue(rule, tags);
setUserWithBrowsePermission(issue);
return issue;

+ 12
- 10
server/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileBackuperMediumTest.java View File

@@ -42,6 +42,7 @@ import org.sonar.db.qualityprofile.ActiveRuleDao;
import org.sonar.db.qualityprofile.ActiveRuleDto;
import org.sonar.db.qualityprofile.ActiveRuleParamDto;
import org.sonar.db.qualityprofile.QualityProfileDto;
import org.sonar.db.rule.RuleDefinitionDto;
import org.sonar.db.rule.RuleDto;
import org.sonar.db.rule.RuleParamDto;
import org.sonar.server.qualityprofile.index.ActiveRuleIndexer;
@@ -51,14 +52,13 @@ import org.sonar.server.rule.index.RuleQuery;
import org.sonar.server.tester.ServerTester;
import org.sonar.server.tester.UserSessionRule;

import static java.util.Arrays.asList;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.fail;
import static org.sonar.db.qualityprofile.ActiveRuleDto.INHERITED;
import static org.sonar.db.qualityprofile.ActiveRuleDto.OVERRIDES;
import static org.sonar.db.rule.RuleTesting.XOO_X1;
import static org.sonar.db.rule.RuleTesting.XOO_X2;
import static org.sonar.db.rule.RuleTesting.newDto;
import static org.sonar.db.rule.RuleTesting.newRule;
import static org.sonar.db.rule.RuleTesting.newXooX1;
import static org.sonar.db.rule.RuleTesting.newXooX2;
import static org.sonar.server.qualityprofile.QProfileTesting.XOO_P1_KEY;
@@ -94,16 +94,19 @@ public class QProfileBackuperMediumTest {

// create pre-defined rules
RuleDto xooRule1 = newXooX1().setSeverity("MINOR").setLanguage("xoo");
RuleDto xooRule2 = newXooX2().setSeverity("MAJOR").setLanguage("xoo");
db.ruleDao().insert(dbSession, xooRule1.getDefinition());
db.ruleDao().insert(dbSession, xooRule2.getDefinition());
db.ruleDao().insertRuleParam(dbSession, xooRule1.getDefinition(), RuleParamDto.createFor(xooRule1.getDefinition())
.setName("max").setDefaultValue("10").setType(RuleParamType.INTEGER.type()));
dbSession.commit();
dbSession.clearCache();
ruleIndexer.indexRuleDefinition(xooRule1.getDefinition().getKey());

RuleDto xooRule2 = newXooX2().setSeverity("MAJOR").setLanguage("xoo");
db.ruleDao().insert(dbSession, xooRule2.getDefinition());
dbSession.commit();
ruleIndexer.indexRuleDefinition(xooRule2.getDefinition().getKey());

this.organization = OrganizationTesting.newOrganizationDto();
db.organizationDao().insert(dbSession, organization);
ruleIndexer.index(organization, asList(xooRule1.getKey(), xooRule2.getKey()));
}

@After
@@ -114,11 +117,10 @@ public class QProfileBackuperMediumTest {
@Test
public void backup() throws Exception {
RuleKey blahRuleKey = RuleKey.of("blah", "my-rule");
RuleDto blahRule = newDto(blahRuleKey).setSeverity("INFO").setLanguage("xoo");
db.ruleDao().insert(dbSession, blahRule.getDefinition());
RuleDefinitionDto blahRule = newRule(blahRuleKey).setSeverity("INFO").setLanguage("xoo");
db.ruleDao().insert(dbSession, blahRule);
dbSession.commit();
dbSession.clearCache();
ruleIndexer.index(organization, blahRuleKey);
ruleIndexer.indexRuleDefinition(blahRule.getKey());

// create profile P1 with rules x2 and x1 activated
QualityProfileDto profile = newXooP1(organization);

+ 12
- 6
server/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileCopierMediumTest.java View File

@@ -36,6 +36,7 @@ import org.sonar.db.organization.OrganizationDto;
import org.sonar.db.qualityprofile.ActiveRuleDto;
import org.sonar.db.qualityprofile.ActiveRuleParamDto;
import org.sonar.db.qualityprofile.QualityProfileDto;
import org.sonar.db.rule.RuleDefinitionDto;
import org.sonar.db.rule.RuleDto;
import org.sonar.db.rule.RuleParamDto;
import org.sonar.db.rule.RuleTesting;
@@ -46,7 +47,6 @@ import org.sonar.server.rule.index.RuleQuery;
import org.sonar.server.tester.ServerTester;
import org.sonar.server.tester.UserSessionRule;

import static java.util.Arrays.asList;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.fail;
import static org.sonar.server.qualityprofile.QProfileTesting.getDefaultOrganization;
@@ -80,17 +80,23 @@ public class QProfileCopierMediumTest {

// create pre-defined rules
RuleDto xooRule1 = RuleTesting.newXooX1().setSeverity("MINOR");
RuleDto xooRule2 = RuleTesting.newXooX2().setSeverity("MAJOR");
db.ruleDao().insert(dbSession, xooRule1.getDefinition());
db.ruleDao().insert(dbSession, xooRule2.getDefinition());
db.ruleDao().insertRuleParam(dbSession, xooRule1.getDefinition(), RuleParamDto.createFor(xooRule1.getDefinition())
RuleDefinitionDto xooRule1Definition = xooRule1.getDefinition();
db.ruleDao().insert(dbSession, xooRule1Definition);
db.ruleDao().insertRuleParam(dbSession, xooRule1Definition, RuleParamDto.createFor(xooRule1Definition)
.setName("max").setDefaultValue("10").setType(RuleParamType.INTEGER.type()));
dbSession.commit();
ruleIndexer.indexRuleDefinition(xooRule1Definition.getKey());

RuleDto xooRule2 = RuleTesting.newXooX2().setSeverity("MAJOR");
RuleDefinitionDto xooRule2Definition = xooRule2.getDefinition();
db.ruleDao().insert(dbSession, xooRule2Definition);
dbSession.commit();
ruleIndexer.indexRuleDefinition(xooRule2Definition.getKey());

// create pre-defined profile
sourceProfile = QProfileTesting.newXooP1(organization);
db.qualityProfileDao().insert(dbSession, sourceProfile);
dbSession.commit();
ruleIndexer.index(organization, asList(xooRule1.getKey(), xooRule2.getKey()));
}

@After

+ 2
- 2
server/sonar-server/src/test/java/org/sonar/server/qualityprofile/RuleActivatorMediumTest.java View File

@@ -146,7 +146,7 @@ public class RuleActivatorMediumTest {

// index all rules
dbSession.commit();
ruleIndexer.index(organization, asList(javaRule, xooRule1, xooRule2, xooTemplateRule1, xooCustomRule1).stream().map(RuleDto::getKey).collect(Collectors.toList()));
ruleIndexer.indexRuleDefinitions(asList(javaRule, xooRule1, xooRule2, xooTemplateRule1, xooCustomRule1).stream().map(RuleDto::getKey).collect(Collectors.toList()));
}

@After
@@ -914,7 +914,7 @@ public class RuleActivatorMediumTest {
keys.add(ruleDefinitionDto.getKey());
}
dbSession.commit();
ruleIndexer.index(organization, keys);
ruleIndexer.indexRuleDefinitions(keys);

// 0. No active rules so far (base case) and plenty rules available
verifyZeroActiveRules(XOO_P1_KEY);

+ 2
- 2
server/sonar-server/src/test/java/org/sonar/server/qualityprofile/index/ActiveRuleIndexerTest.java View File

@@ -142,7 +142,7 @@ public class ActiveRuleIndexerTest {
long now = 2000000L;

// Index one active rule
RuleDefinitionDto rule = RuleTesting.newDto(RULE_KEY_1).getDefinition();
RuleDefinitionDto rule = RuleTesting.newRule(RULE_KEY_1);
dbTester.rules().insert(rule);
QualityProfileDto profile = QualityProfileDto.createFor("qp")
.setOrganizationUuid(organization.getUuid())
@@ -159,7 +159,7 @@ public class ActiveRuleIndexerTest {
assertThat(esTester.getIds(INDEX_TYPE_ACTIVE_RULE)).containsOnly(activeRule.getKey().toString());

// Index another active rule
RuleDefinitionDto rule2 = RuleTesting.newDto(RULE_KEY_2).getDefinition();
RuleDefinitionDto rule2 = RuleTesting.newRule(RULE_KEY_2);
dbTester.rules().insert(rule2);
ActiveRuleDto activeRule2 = ActiveRuleDto.createFor(profile, rule2).setSeverity(Severity.CRITICAL)
.setCreatedAt(now).setUpdatedAt(now);

+ 19
- 23
server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/ChangeParentActionTest.java View File

@@ -42,7 +42,7 @@ import org.sonar.db.organization.OrganizationDto;
import org.sonar.db.qualityprofile.ActiveRuleDto;
import org.sonar.db.qualityprofile.QualityProfileDto;
import org.sonar.db.qualityprofile.QualityProfileTesting;
import org.sonar.db.rule.RuleDto;
import org.sonar.db.rule.RuleDefinitionDto;
import org.sonar.db.rule.RuleTesting;
import org.sonar.server.es.EsClient;
import org.sonar.server.es.EsTester;
@@ -56,7 +56,6 @@ import org.sonar.server.qualityprofile.index.ActiveRuleIndexer;
import org.sonar.server.rule.index.RuleIndex;
import org.sonar.server.rule.index.RuleIndexDefinition;
import org.sonar.server.rule.index.RuleIndexer;
import org.sonar.server.rule.index.RuleIteratorFactory;
import org.sonar.server.rule.index.RuleQuery;
import org.sonar.server.tester.UserSessionRule;
import org.sonar.server.util.TypeValidations;
@@ -105,10 +104,7 @@ public class ChangeParentActionTest {
TestDefaultOrganizationProvider defaultOrganizationProvider = TestDefaultOrganizationProvider.from(dbTester);
ruleIndexer = new RuleIndexer(
esClient,
null,
new RuleIteratorFactory(dbClient),
null
);
dbClient);
activeRuleIndexer = new ActiveRuleIndexer(
System2.INSTANCE,
dbClient,
@@ -160,9 +156,9 @@ public class ChangeParentActionTest {
QualityProfileDto parent1 = createProfile();
QualityProfileDto child = createProfile();

RuleDto rule1 = createRule();
RuleDefinitionDto rule1 = createRule();
createActiveRule(rule1, parent1);
ruleIndexer.index(organization, rule1.getKey());
ruleIndexer.indexRuleDefinition(rule1.getKey());
activeRuleIndexer.index();

assertThat(dbClient.activeRuleDao().selectByProfileKey(dbSession, child.getKey())).isEmpty();
@@ -188,11 +184,11 @@ public class ChangeParentActionTest {
QualityProfileDto parent2 = createProfile();
QualityProfileDto child = createProfile();

RuleDto rule1 = createRule();
RuleDto rule2 = createRule();
RuleDefinitionDto rule1 = createRule();
RuleDefinitionDto rule2 = createRule();
createActiveRule(rule1, parent1);
createActiveRule(rule2, parent2);
ruleIndexer.index(organization, Stream.of(rule1, rule2).map(RuleDto::getKey).collect(MoreCollectors.toList()));
ruleIndexer.indexRuleDefinitions(Stream.of(rule1, rule2).map(RuleDefinitionDto::getKey).collect(MoreCollectors.toList()));
activeRuleIndexer.index();

// Set parent 1
@@ -218,9 +214,9 @@ public class ChangeParentActionTest {
QualityProfileDto parent = createProfile();
QualityProfileDto child = createProfile();

RuleDto rule1 = createRule();
RuleDefinitionDto rule1 = createRule();
createActiveRule(rule1, parent);
ruleIndexer.index(organization, rule1.getKey());
ruleIndexer.indexRuleDefinition(rule1.getKey());
activeRuleIndexer.index();

// Set parent
@@ -245,11 +241,11 @@ public class ChangeParentActionTest {
QualityProfileDto parent2 = createProfile();
QualityProfileDto child = createProfile();

RuleDto rule1 = createRule();
RuleDto rule2 = createRule();
RuleDefinitionDto rule1 = createRule();
RuleDefinitionDto rule2 = createRule();
createActiveRule(rule1, parent1);
createActiveRule(rule2, parent2);
ruleIndexer.index(organization, rule1.getKey());
ruleIndexer.indexRuleDefinition(rule1.getKey());
activeRuleIndexer.index();

assertThat(dbClient.activeRuleDao().selectByProfileKey(dbSession, child.getKey())).isEmpty();
@@ -306,9 +302,9 @@ public class ChangeParentActionTest {
QualityProfileDto parent = createProfile();
QualityProfileDto child = createProfile();

RuleDto rule1 = createRule();
RuleDefinitionDto rule1 = createRule();
createActiveRule(rule1, parent);
ruleIndexer.index(organization, rule1.getKey());
ruleIndexer.indexRuleDefinition(rule1.getKey());
activeRuleIndexer.index();

assertThat(dbClient.activeRuleDao().selectByProfileKey(dbSession, child.getKey())).isEmpty();
@@ -404,18 +400,18 @@ public class ChangeParentActionTest {
return profile;
}

private RuleDto createRule() {
RuleDto rule = RuleTesting.newDto(RuleKey.of(ruleRepository, randomAlphanumeric(5)))
private RuleDefinitionDto createRule() {
RuleDefinitionDto rule = RuleTesting.newRule(RuleKey.of(ruleRepository, randomAlphanumeric(5)))
.setLanguage(language.getKey())
.setSeverity(Severity.BLOCKER)
.setStatus(RuleStatus.READY);
dbClient.ruleDao().insert(dbSession, rule.getDefinition());
dbClient.ruleDao().insert(dbSession, rule);
dbSession.commit();
return rule;
}

private ActiveRuleDto createActiveRule(RuleDto rule, QualityProfileDto profile) {
ActiveRuleDto activeRule = ActiveRuleDto.createFor(profile, rule.getDefinition())
private ActiveRuleDto createActiveRule(RuleDefinitionDto rule, QualityProfileDto profile) {
ActiveRuleDto activeRule = ActiveRuleDto.createFor(profile, rule)
.setSeverity(rule.getSeverityString());
dbClient.activeRuleDao().insert(dbSession, activeRule);
dbSession.commit();

+ 3
- 3
server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/ChangelogLoaderTest.java View File

@@ -31,7 +31,7 @@ import org.sonar.db.DbTester;
import org.sonar.db.qualityprofile.QProfileChangeDto;
import org.sonar.db.qualityprofile.QProfileChangeQuery;
import org.sonar.db.qualityprofile.QualityProfileTesting;
import org.sonar.db.rule.RuleDto;
import org.sonar.db.rule.RuleDefinitionDto;
import org.sonar.db.rule.RuleTesting;
import org.sonar.db.user.UserDto;
import org.sonar.db.user.UserTesting;
@@ -159,8 +159,8 @@ public class ChangelogLoaderTest {
}

private void insertRule(RuleKey key, String name) {
RuleDto dto = RuleTesting.newDto(key).setName(name);
dbTester.rules().insertRule(dto);
RuleDefinitionDto dto = RuleTesting.newRule(key).setName(name);
dbTester.rules().insert(dto);
dbTester.getSession().commit();
}


+ 2
- 3
server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/CreateActionTest.java View File

@@ -55,7 +55,6 @@ import org.sonar.server.qualityprofile.index.ActiveRuleIndexer;
import org.sonar.server.rule.index.RuleIndex;
import org.sonar.server.rule.index.RuleIndexDefinition;
import org.sonar.server.rule.index.RuleIndexer;
import org.sonar.server.rule.index.RuleIteratorFactory;
import org.sonar.server.rule.index.RuleQuery;
import org.sonar.server.tester.UserSessionRule;
import org.sonar.server.ws.TestRequest;
@@ -94,7 +93,7 @@ public class CreateActionTest {
private DbSession dbSession = dbTester.getSession();
private RuleIndex ruleIndex = new RuleIndex(esTester.client());
private DefaultOrganizationProvider defaultOrganizationProvider = TestDefaultOrganizationProvider.from(dbTester);
private RuleIndexer ruleIndexer = new RuleIndexer(esTester.client(), null, new RuleIteratorFactory(dbClient), null);
private RuleIndexer ruleIndexer = new RuleIndexer(esTester.client(), dbClient);
private ActiveRuleIndexer activeRuleIndexer = new ActiveRuleIndexer(system2, dbClient, esTester.client());
private ProfileImporter[] profileImporters = createImporters();
private QProfileExporters qProfileExporters = new QProfileExporters(dbClient, null,
@@ -243,7 +242,7 @@ public class CreateActionTest {
private void insertRule(RuleDefinitionDto ruleDto) {
dbClient.ruleDao().insert(dbSession, ruleDto);
dbSession.commit();
ruleIndexer.index(organization, ruleDto.getKey());
ruleIndexer.indexRuleDefinition(ruleDto.getKey());
}

private CreateWsResponse executeRequest(String name, String language) {

+ 6
- 9
server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/InheritanceActionTest.java View File

@@ -37,7 +37,6 @@ import org.sonar.db.organization.OrganizationDto;
import org.sonar.db.qualityprofile.ActiveRuleDto;
import org.sonar.db.qualityprofile.QualityProfileDto;
import org.sonar.db.rule.RuleDefinitionDto;
import org.sonar.db.rule.RuleDto;
import org.sonar.db.rule.RuleTesting;
import org.sonar.server.es.EsClient;
import org.sonar.server.es.EsTester;
@@ -53,14 +52,11 @@ import org.sonar.server.qualityprofile.index.ActiveRuleIndexer;
import org.sonar.server.rule.index.RuleIndex;
import org.sonar.server.rule.index.RuleIndexDefinition;
import org.sonar.server.rule.index.RuleIndexer;
import org.sonar.server.rule.index.RuleIteratorFactory;
import org.sonar.server.tester.UserSessionRule;
import org.sonar.server.util.TypeValidations;
import org.sonar.server.ws.WsActionTester;
import org.sonar.test.JsonAssert;

import static java.util.Arrays.asList;

public class InheritanceActionTest {

@Rule
@@ -85,7 +81,7 @@ public class InheritanceActionTest {
dbClient = dbTester.getDbClient();
dbSession = dbTester.getSession();
esClient = esTester.client();
ruleIndexer = new RuleIndexer(esClient, null, new RuleIteratorFactory(dbClient), null);
ruleIndexer = new RuleIndexer(esClient, dbClient);
activeRuleIndexer = new ActiveRuleIndexer(System2.INSTANCE, dbClient, esClient);
TestDefaultOrganizationProvider defaultOrganizationProvider = TestDefaultOrganizationProvider.from(dbTester);
underTest = new InheritanceAction(
@@ -119,7 +115,6 @@ public class InheritanceActionTest {
createActiveRule(rule2, groupWide);

dbSession.commit();
ruleIndexer.index(organization, asList(rule1.getKey(), rule2.getKey(), rule3.getKey()));
activeRuleIndexer.index();

QualityProfileDto companyWide = createProfile("xoo", "My Company Profile", "xoo-my-company-profile-12345");
@@ -181,14 +176,16 @@ public class InheritanceActionTest {

private RuleDefinitionDto createRule(String lang, String id) {
long now = new Date().getTime();
RuleDto rule = RuleTesting.newDto(RuleKey.of("blah", id))
RuleDefinitionDto rule = RuleTesting.newRule(RuleKey.of("blah", id))
.setLanguage(lang)
.setSeverity(Severity.BLOCKER)
.setStatus(RuleStatus.READY)
.setUpdatedAt(now)
.setCreatedAt(now);
dbClient.ruleDao().insert(dbSession, rule.getDefinition());
return rule.getDefinition();
dbClient.ruleDao().insert(dbSession, rule);
dbSession.commit();
ruleIndexer.indexRuleDefinition(rule.getKey());
return rule;
}

private ActiveRuleDto createActiveRule(RuleDefinitionDto rule, QualityProfileDto profile) {

+ 8
- 9
server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/QProfilesWsMediumTest.java View File

@@ -39,7 +39,6 @@ import org.sonar.db.qualityprofile.ActiveRuleDto;
import org.sonar.db.qualityprofile.ActiveRuleKey;
import org.sonar.db.qualityprofile.QualityProfileDto;
import org.sonar.db.rule.RuleDefinitionDto;
import org.sonar.db.rule.RuleDto;
import org.sonar.db.rule.RuleTesting;
import org.sonar.server.es.SearchOptions;
import org.sonar.server.exceptions.BadRequestException;
@@ -103,7 +102,7 @@ public class QProfilesWsMediumTest {
RuleDefinitionDto rule = createRule(profile.getLanguage(), "toto");
createActiveRule(rule, profile);
session.commit();
ruleIndexer.index(organization, rule.getKey());
ruleIndexer.indexRuleDefinition(rule.getKey());
activeRuIndexer.index();

// 0. Assert No Active Rule for profile
@@ -203,7 +202,7 @@ public class QProfilesWsMediumTest {
QualityProfileDto profile = createProfile("java");
RuleDefinitionDto rule = createRule(profile.getLanguage(), "toto");
session.commit();
ruleIndexer.index(organization, rule.getKey());
ruleIndexer.indexRuleDefinition(rule.getKey());

// 0. Assert No Active Rule for profile
assertThat(db.activeRuleDao().selectByProfileKey(session, profile.getKey())).isEmpty();
@@ -224,7 +223,7 @@ public class QProfilesWsMediumTest {
QualityProfileDto profile = createProfile("java");
RuleDefinitionDto rule = createRule("php", "toto");
session.commit();
ruleIndexer.index(organization, rule.getKey());
ruleIndexer.indexRuleDefinition(rule.getKey());

// 0. Assert No Active Rule for profile
assertThat(db.activeRuleDao().selectByProfileKey(session, profile.getKey())).isEmpty();
@@ -247,7 +246,7 @@ public class QProfilesWsMediumTest {
QualityProfileDto profile = createProfile("java");
RuleDefinitionDto rule = createRule(profile.getLanguage(), "toto");
session.commit();
ruleIndexer.index(organization, rule.getKey());
ruleIndexer.indexRuleDefinition(rule.getKey());

// 0. Assert No Active Rule for profile
assertThat(db.activeRuleDao().selectByProfileKey(session, profile.getKey())).isEmpty();
@@ -439,14 +438,14 @@ public class QProfilesWsMediumTest {
}

private RuleDefinitionDto createRule(String lang, String id) {
RuleDto rule = RuleTesting.newDto(RuleKey.of("blah", id))
RuleDefinitionDto rule = RuleTesting.newRule(RuleKey.of("blah", id))
.setLanguage(lang)
.setSeverity(Severity.BLOCKER)
.setStatus(RuleStatus.READY);
db.ruleDao().insert(session, rule.getDefinition());
db.ruleDao().insert(session, rule);
session.commit();
ruleIndexer.index(organization, rule.getKey());
return rule.getDefinition();
ruleIndexer.indexRuleDefinition(rule.getKey());
return rule;
}

private ActiveRuleDto createActiveRule(RuleDefinitionDto rule, QualityProfileDto profile) {

+ 3
- 4
server/sonar-server/src/test/java/org/sonar/server/rule/RegisterRulesTest.java View File

@@ -42,13 +42,11 @@ import org.sonar.db.rule.RuleParamDto;
import org.sonar.db.rule.RuleRepositoryDto;
import org.sonar.server.es.EsTester;
import org.sonar.server.es.SearchOptions;
import org.sonar.server.organization.TestDefaultOrganizationProvider;
import org.sonar.server.qualityprofile.RuleActivator;
import org.sonar.server.qualityprofile.index.ActiveRuleIndexer;
import org.sonar.server.rule.index.RuleIndex;
import org.sonar.server.rule.index.RuleIndexDefinition;
import org.sonar.server.rule.index.RuleIndexer;
import org.sonar.server.rule.index.RuleIteratorFactory;
import org.sonar.server.rule.index.RuleQuery;

import static com.google.common.collect.Sets.newHashSet;
@@ -86,7 +84,7 @@ public class RegisterRulesTest {
@Before
public void before() {
when(system.now()).thenReturn(DATE1.getTime());
ruleIndexer = new RuleIndexer(esTester.client(), null, new RuleIteratorFactory(dbClient), null);
ruleIndexer = new RuleIndexer(esTester.client(), dbClient);
ruleIndex = new RuleIndex(esTester.client());
activeRuleIndexer = new ActiveRuleIndexer(system, dbClient, esTester.client());
}
@@ -124,6 +122,7 @@ public class RegisterRulesTest {
// verify repositories
assertThat(dbClient.ruleRepositoryDao().selectAll(dbTester.getSession())).extracting(RuleRepositoryDto::getKey).containsOnly("fake");
}

@Test
public void insert_then_remove_rule() {
String ruleKey = randomAlphanumeric(5);
@@ -457,7 +456,7 @@ public class RegisterRulesTest {
Languages languages = mock(Languages.class);
when(languages.get("java")).thenReturn(mock(Language.class));

RegisterRules task = new RegisterRules(loader, ruleActivator, dbClient, ruleIndexer, activeRuleIndexer, languages, system, TestDefaultOrganizationProvider.from(dbTester));
RegisterRules task = new RegisterRules(loader, ruleActivator, dbClient, ruleIndexer, activeRuleIndexer, languages, system);
task.start();
// Execute a commit to refresh session state as the task is using its own session
dbTester.getSession().commit();

+ 21
- 20
server/sonar-server/src/test/java/org/sonar/server/rule/RuleCreatorMediumTest.java View File

@@ -52,6 +52,7 @@ import org.sonar.server.tester.UserSessionRule;

import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.fail;
import static org.sonar.db.rule.RuleTesting.newRule;

// TODO replace ServerTester by EsTester / DbTester
public class RuleCreatorMediumTest {
@@ -160,7 +161,7 @@ public class RuleCreatorMediumTest {
@Test
public void create_custom_rule_with_no_parameter_value() {
// insert template rule
RuleDto templateRule = createTemplateRuleWithIntArrayParam();
RuleDefinitionDto templateRule = createTemplateRuleWithIntArrayParam();

NewCustomRule newRule = NewCustomRule.createForCustomRule("CUSTOM_RULE", templateRule.getKey())
.setName("My custom")
@@ -184,7 +185,7 @@ public class RuleCreatorMediumTest {
@Test
public void create_custom_rule_with_multiple_parameter_values() {
// insert template rule
RuleDto templateRule = createTemplateRuleWithIntArrayParam();
RuleDefinitionDto templateRule = createTemplateRuleWithIntArrayParam();

NewCustomRule newRule = NewCustomRule.createForCustomRule("CUSTOM_RULE", templateRule.getKey())
.setName("My custom")
@@ -209,7 +210,7 @@ public class RuleCreatorMediumTest {
@Test
public void create_custom_rule_with_invalid_parameter() {
// insert template rule
RuleDto templateRule = createTemplateRuleWithIntArrayParam();
RuleDefinitionDto templateRule = createTemplateRuleWithIntArrayParam();

// Create custom rule
NewCustomRule newRule = NewCustomRule.createForCustomRule("CUSTOM_RULE", templateRule.getKey())
@@ -231,7 +232,7 @@ public class RuleCreatorMediumTest {
@Test
public void create_custom_rule_with_invalid_parameters() {
// insert template rule
RuleDto templateRule = createTemplateRuleWithTwoIntParams();
RuleDefinitionDto templateRule = createTemplateRuleWithTwoIntParams();

// Create custom rule
NewCustomRule newRule = NewCustomRule.createForCustomRule("CUSTOM_RULE", templateRule.getKey())
@@ -481,8 +482,8 @@ public class RuleCreatorMediumTest {
@Test
public void fail_to_create_custom_rule_when_wrong_rule_template() {
// insert rule
RuleDto rule = RuleTesting.newDto(RuleKey.of("java", "S001")).setIsTemplate(false);
dao.insert(dbSession, rule.getDefinition());
RuleDefinitionDto rule = newRule(RuleKey.of("java", "S001")).setIsTemplate(false);
dao.insert(dbSession, rule);
dbSession.commit();

// Create custom rule with unknown template rule
@@ -519,12 +520,12 @@ public class RuleCreatorMediumTest {
RuleParamDto ruleParamDto = RuleParamDto.createFor(templateRule.getDefinition()).setName("regex").setType("STRING").setDescription("Reg ex").setDefaultValue(".*");
dao.insertRuleParam(dbSession, templateRule.getDefinition(), ruleParamDto);
dbSession.commit();
ruleIndexer.index(defaultOrganization, templateRule.getKey());
ruleIndexer.indexRuleDefinition(templateRule.getDefinition().getKey());
return templateRule;
}

private RuleDto createTemplateRuleWithIntArrayParam() {
RuleDto templateRule = RuleTesting.newDto(RuleKey.of("java", "S002"))
private RuleDefinitionDto createTemplateRuleWithIntArrayParam() {
RuleDefinitionDto templateRule = newRule(RuleKey.of("java", "S002"))
.setIsTemplate(true)
.setLanguage("java")
.setConfigKey("S002")
@@ -534,17 +535,17 @@ public class RuleCreatorMediumTest {
.setGapDescription("desc")
.setCreatedAt(new Date().getTime())
.setUpdatedAt(new Date().getTime());
dao.insert(dbSession, templateRule.getDefinition());
RuleParamDto ruleParamDto = RuleParamDto.createFor(templateRule.getDefinition())
dao.insert(dbSession, templateRule);
RuleParamDto ruleParamDto = RuleParamDto.createFor(templateRule)
.setName("myIntegers").setType("INTEGER,multiple=true,values=1;2;3").setDescription("My Integers").setDefaultValue("1");
dao.insertRuleParam(dbSession, templateRule.getDefinition(), ruleParamDto);
dao.insertRuleParam(dbSession, templateRule, ruleParamDto);
dbSession.commit();
ruleIndexer.index(defaultOrganization, templateRule.getKey());
ruleIndexer.indexRuleDefinition(templateRule.getKey());
return templateRule;
}

private RuleDto createTemplateRuleWithTwoIntParams() {
RuleDto templateRule = RuleTesting.newDto(RuleKey.of("java", "S003"))
private RuleDefinitionDto createTemplateRuleWithTwoIntParams() {
RuleDefinitionDto templateRule = newRule(RuleKey.of("java", "S003"))
.setIsTemplate(true)
.setLanguage("java")
.setConfigKey("S003")
@@ -554,13 +555,13 @@ public class RuleCreatorMediumTest {
.setGapDescription("desc")
.setCreatedAt(new Date().getTime())
.setUpdatedAt(new Date().getTime());
dao.insert(dbSession, templateRule.getDefinition());
RuleParamDto ruleParam1Dto = RuleParamDto.createFor(templateRule.getDefinition())
dao.insert(dbSession, templateRule);
RuleParamDto ruleParam1Dto = RuleParamDto.createFor(templateRule)
.setName("first").setType("INTEGER").setDescription("First integer").setDefaultValue("0");
dao.insertRuleParam(dbSession, templateRule.getDefinition(), ruleParam1Dto);
RuleParamDto ruleParam2Dto = RuleParamDto.createFor(templateRule.getDefinition())
dao.insertRuleParam(dbSession, templateRule, ruleParam1Dto);
RuleParamDto ruleParam2Dto = RuleParamDto.createFor(templateRule)
.setName("second").setType("INTEGER").setDescription("Second integer").setDefaultValue("0");
dao.insertRuleParam(dbSession, templateRule.getDefinition(), ruleParam2Dto);
dao.insertRuleParam(dbSession, templateRule, ruleParam2Dto);
dbSession.commit();
return templateRule;
}

+ 3
- 3
server/sonar-server/src/test/java/org/sonar/server/rule/RuleDeleterMediumTest.java View File

@@ -88,7 +88,7 @@ public class RuleDeleterMediumTest {
.setUpdatedAt(PAST);
dao.insert(dbSession, templateRule.getDefinition());
dbSession.commit();
ruleIndexer.index(organization, templateRule.getKey());
ruleIndexer.indexRuleDefinition(templateRule.getDefinition().getKey());

// Verify in index
assertThat(index.searchAll(new RuleQuery())).containsOnly(templateRule.getKey());
@@ -100,7 +100,7 @@ public class RuleDeleterMediumTest {
.setUpdatedAt(PAST);
dao.insert(dbSession, customRule.getDefinition());
dbSession.commit();
ruleIndexer.index(organization, customRule.getKey());
ruleIndexer.indexRuleDefinition(customRule.getDefinition().getKey());

// Verify in index
assertThat(index.searchAll(new RuleQuery())).containsOnly(templateRule.getKey(), customRule.getKey());
@@ -134,7 +134,7 @@ public class RuleDeleterMediumTest {
public void fail_to_delete_if_not_custom() {
// Create rule
RuleKey ruleKey = RuleKey.of("java", "S001");
dao.insert(dbSession, RuleTesting.newDto(ruleKey).getDefinition());
dao.insert(dbSession, RuleTesting.newRule(ruleKey));
dbSession.commit();

try {

+ 0
- 0
server/sonar-server/src/test/java/org/sonar/server/rule/RuleServiceMediumTest.java View File


+ 17
- 20
server/sonar-server/src/test/java/org/sonar/server/rule/RuleUpdaterMediumTest.java View File

@@ -31,6 +31,7 @@ import javax.annotation.Nonnull;
import org.junit.After;
import org.junit.Before;
import org.junit.ClassRule;
import org.junit.Ignore;
import org.junit.Test;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.rule.RuleStatus;
@@ -55,7 +56,6 @@ import org.sonar.server.qualityprofile.QProfileTesting;
import org.sonar.server.qualityprofile.RuleActivation;
import org.sonar.server.qualityprofile.RuleActivator;
import org.sonar.server.rule.index.RuleIndex;
import org.sonar.server.rule.index.RuleIndexDefinition;
import org.sonar.server.rule.index.RuleQuery;
import org.sonar.server.tester.ServerTester;
import org.sonar.server.tester.UserSessionRule;
@@ -96,7 +96,7 @@ public class RuleUpdaterMediumTest {

@Test
public void do_not_update_rule_with_removed_status() {
ruleDao.insert(dbSession, RuleTesting.newDto(RULE_KEY).setStatus(RuleStatus.REMOVED).getDefinition());
ruleDao.insert(dbSession, RuleTesting.newRule(RULE_KEY).setStatus(RuleStatus.REMOVED));
dbSession.commit();

RuleUpdate update = RuleUpdate.createForPluginRule(RULE_KEY).setTags(Sets.newHashSet("java9"));
@@ -190,6 +190,7 @@ public class RuleUpdaterMediumTest {
assertThat(rule.getNoteUpdatedAt()).isNull();
}

@Ignore
@Test
public void set_tags() {
// insert db
@@ -202,13 +203,12 @@ public class RuleUpdaterMediumTest {
RuleUpdate update = RuleUpdate.createForPluginRule(RULE_KEY).setTags(Sets.newHashSet("bug", "java8"));
underTest.update(update, userSessionRule);

dbSession.clearCache();
RuleDto rule = ruleDao.selectOrFailByKey(dbSession, defaultOrganization.getUuid(), RULE_KEY);
assertThat(rule.getTags()).containsOnly("bug");
assertThat(rule.getSystemTags()).containsOnly("java8", "javadoc");

// verify that tags are indexed in index
Set<String> tags = tester.get(RuleIndex.class).terms(RuleIndexDefinition.FIELD_RULE_ALL_TAGS);
Set<String> tags = ruleIndex.listTags(defaultOrganization.getUuid(), null, 10);
assertThat(tags).containsOnly("bug", "java8", "javadoc");
}

@@ -230,17 +230,16 @@ public class RuleUpdaterMediumTest {
assertThat(rule.getSystemTags()).containsOnly("java8", "javadoc");

// verify that tags are indexed in index
Set<String> tags = tester.get(RuleIndex.class).terms(RuleIndexDefinition.FIELD_RULE_ALL_TAGS);
Set<String> tags = ruleIndex.listTags(defaultOrganization.getUuid(), null, 10);
assertThat(tags).containsOnly("java8", "javadoc");
}

@Test
public void override_debt() {
ruleDao.insert(dbSession, RuleTesting.newDto(RULE_KEY)
ruleDao.insert(dbSession, RuleTesting.newRule(RULE_KEY)
.setDefRemediationFunction(DebtRemediationFunction.Type.LINEAR_OFFSET.name())
.setDefRemediationGapMultiplier("1d")
.setDefRemediationBaseEffort("5min")
.getDefinition());
.setDefRemediationBaseEffort("5min"));
dbSession.commit();

DefaultDebtRemediationFunction fn = new DefaultDebtRemediationFunction(DebtRemediationFunction.Type.CONSTANT_ISSUE, null, "1min");
@@ -262,11 +261,10 @@ public class RuleUpdaterMediumTest {

@Test
public void override_debt_only_offset() {
ruleDao.insert(dbSession, RuleTesting.newDto(RULE_KEY)
ruleDao.insert(dbSession, RuleTesting.newRule(RULE_KEY)
.setDefRemediationFunction(DebtRemediationFunction.Type.LINEAR.name())
.setDefRemediationGapMultiplier("1d")
.setDefRemediationBaseEffort(null)
.getDefinition());
.setDefRemediationBaseEffort(null));
dbSession.commit();

RuleUpdate update = RuleUpdate.createForPluginRule(RULE_KEY)
@@ -287,11 +285,10 @@ public class RuleUpdaterMediumTest {

@Test
public void override_debt_from_linear_with_offset_to_constant() {
ruleDao.insert(dbSession, RuleTesting.newDto(RULE_KEY)
ruleDao.insert(dbSession, RuleTesting.newRule(RULE_KEY)
.setDefRemediationFunction(DebtRemediationFunction.Type.LINEAR_OFFSET.name())
.setDefRemediationGapMultiplier("1d")
.setDefRemediationBaseEffort("5min")
.getDefinition());
.setDefRemediationBaseEffort("5min"));
dbSession.commit();

RuleUpdate update = RuleUpdate.createForPluginRule(RULE_KEY)
@@ -546,8 +543,8 @@ public class RuleUpdaterMediumTest {
@Test
public void fail_to_update_plugin_rule_if_name_is_set() {
// Create rule rule
RuleDto ruleDto = RuleTesting.newDto(RuleKey.of("squid", "S01"));
ruleDao.insert(dbSession, ruleDto.getDefinition());
RuleDefinitionDto ruleDto = RuleTesting.newRule(RuleKey.of("squid", "S01"));
ruleDao.insert(dbSession, ruleDto);

dbSession.commit();

@@ -564,8 +561,8 @@ public class RuleUpdaterMediumTest {
@Test
public void fail_to_update_plugin_rule_if_description_is_set() {
// Create rule rule
RuleDto ruleDto = RuleTesting.newDto(RuleKey.of("squid", "S01"));
ruleDao.insert(dbSession, ruleDto.getDefinition());
RuleDefinitionDto ruleDto = RuleTesting.newRule(RuleKey.of("squid", "S01"));
ruleDao.insert(dbSession, ruleDto);

dbSession.commit();

@@ -582,8 +579,8 @@ public class RuleUpdaterMediumTest {
@Test
public void fail_to_update_plugin_rule_if_severity_is_set() {
// Create rule rule
RuleDto ruleDto = RuleTesting.newDto(RuleKey.of("squid", "S01"));
ruleDao.insert(dbSession, ruleDto.getDefinition());
RuleDefinitionDto ruleDto = RuleTesting.newRule(RuleKey.of("squid", "S01"));
ruleDao.insert(dbSession, ruleDto);

dbSession.commit();


+ 0
- 2
server/sonar-server/src/test/java/org/sonar/server/rule/index/RuleDocTesting.java View File

@@ -20,7 +20,6 @@
package org.sonar.server.rule.index;

import com.google.common.collect.Maps;
import java.util.Arrays;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.rule.RuleStatus;
import org.sonar.api.rule.Severity;
@@ -44,7 +43,6 @@ public class RuleDocTesting {
.setStatus(RuleStatus.READY.name())
.setLanguage("xoo")
.setIsTemplate(false)
.setAllTags(Arrays.asList("spring", "performance"))
.setType(RuleType.CODE_SMELL)
.setCreatedAt(1_500_000_000L)
.setUpdatedAt(1_600_000_000L);

+ 1
- 1
server/sonar-server/src/test/java/org/sonar/server/rule/index/RuleIndexDefinitionTest.java View File

@@ -54,7 +54,7 @@ public class RuleIndexDefinitionTest {
assertThat(context.getIndices()).hasSize(1);
NewIndex ruleIndex = context.getIndices().get("rules");
assertThat(ruleIndex).isNotNull();
assertThat(ruleIndex.getTypes().keySet()).containsOnly("rule", "activeRule");
assertThat(ruleIndex.getTypes().keySet()).containsOnly("activeRule", "ruleExtension", "rule");

// no cluster by default
assertThat(ruleIndex.getSettings().get("index.number_of_shards")).isEqualTo("1");

+ 388
- 216
server/sonar-server/src/test/java/org/sonar/server/rule/index/RuleIndexTest.java
File diff suppressed because it is too large
View File


+ 6
- 37
server/sonar-server/src/test/java/org/sonar/server/rule/index/RuleIndexerTest.java View File

@@ -19,18 +19,15 @@
*/
package org.sonar.server.rule.index;

import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.sonar.api.config.MapSettings;
import org.sonar.api.rule.RuleStatus;
import org.sonar.api.rule.Severity;
import org.sonar.api.rules.RuleType;
import org.sonar.api.utils.System2;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.DbTester;
import org.sonar.db.organization.OrganizationDto;
import org.sonar.db.rule.RuleDefinitionDto;
import org.sonar.db.rule.RuleDto;
import org.sonar.server.es.EsTester;
@@ -41,15 +38,14 @@ import static org.assertj.core.api.Assertions.assertThat;

public class RuleIndexerTest {

private System2 system2 = System2.INSTANCE;

@Rule
public EsTester esTester = new EsTester(new RuleIndexDefinition(new MapSettings()));

@Rule
public DbTester dbTester = DbTester.create(system2);
public DbTester dbTester = DbTester.create();

private DbClient dbClient = dbTester.getDbClient();
private final RuleIndexer underTest = new RuleIndexer(esTester.client(), dbClient);
private DbSession dbSession = dbTester.getSession();
private RuleDefinitionDto rule = new RuleDefinitionDto()
.setRuleKey("S001")
@@ -66,17 +62,10 @@ public class RuleIndexerTest {
.setType(RuleType.BUG)
.setCreatedAt(1500000000000L)
.setUpdatedAt(1600000000000L);
private OrganizationDto organization;

@Before
public void before() {
organization = dbTester.getDefaultOrganization();
}

@Test
public void index_nothing() {
RuleIndexer indexer = createIndexer();
// indexer.index(Iterators.emptyIterator());
// underTest.index(Iterators.emptyIterator());
assertThat(esTester.countDocuments(RuleIndexDefinition.INDEX_TYPE_RULE)).isEqualTo(0L);
}

@@ -85,44 +74,24 @@ public class RuleIndexerTest {
dbClient.ruleDao().insert(dbSession, rule);
dbSession.commit();

RuleIndexer indexer = createIndexer();
indexer.index(organization, rule.getKey());
underTest.indexRuleDefinition(rule.getKey());

assertThat(esTester.countDocuments(RuleIndexDefinition.INDEX_TYPE_RULE)).isEqualTo(1);
}

@Test
public void removed_rule_is_not_removed_from_index() {
RuleIndexer indexer = createIndexer();

// Create and Index rule
dbClient.ruleDao().insert(dbSession, rule.setStatus(RuleStatus.READY));
dbSession.commit();
indexer.index(organization, rule.getKey());
underTest.indexRuleDefinition(rule.getKey());
assertThat(esTester.countDocuments(RuleIndexDefinition.INDEX_TYPE_RULE)).isEqualTo(1);

// Remove rule
dbTester.getDbClient().ruleDao().update(dbTester.getSession(), rule.setStatus(RuleStatus.READY).setUpdatedAt(2000000000000L));
dbTester.getSession().commit();
indexer.index(organization, rule.getKey());

assertThat(esTester.countDocuments(RuleIndexDefinition.INDEX_TYPE_RULE)).isEqualTo(1);
}

@Test
public void index_on_startup() {
RuleIndexer indexer = createIndexer();

// Create and Index rule
dbClient.ruleDao().insert(dbSession, rule.setStatus(RuleStatus.READY));
dbSession.commit();
underTest.indexRuleDefinition(rule.getKey());

indexer.indexOnStartup(indexer.getIndexTypes());
assertThat(esTester.countDocuments(RuleIndexDefinition.INDEX_TYPE_RULE)).isEqualTo(1);
}

private RuleIndexer createIndexer() {
return new RuleIndexer(esTester.client(), dbClient, new RuleIteratorFactory(dbTester.getDbClient()), TestDefaultOrganizationProvider.from(dbTester));
}

}

+ 32
- 26
server/sonar-server/src/test/java/org/sonar/server/rule/index/RuleIteratorForSingleChunkTest.java View File

@@ -46,12 +46,12 @@ public class RuleIteratorForSingleChunkTest {

private DbClient dbClient = dbTester.getDbClient();
private DbSession dbSession = dbTester.getSession();
private RuleDto templateRule;
private RuleDefinitionDto templateRule;
private RuleDefinitionDto customRule;

@Before
public void setUp() throws Exception {
templateRule = new RuleDto()
templateRule = new RuleDefinitionDto()
.setRuleKey("S001")
.setRepositoryKey("xoo")
.setConfigKey("S1")
@@ -65,9 +65,7 @@ public class RuleIteratorForSingleChunkTest {
.setSystemTags(newHashSet("cwe"))
.setType(RuleType.BUG)
.setCreatedAt(1500000000000L)
.setUpdatedAt(1600000000000L)
.setOrganizationUuid(dbTester.getDefaultOrganization().getUuid())
.setTags(newHashSet("performance"));
.setUpdatedAt(1600000000000L);

customRule = new RuleDefinitionDto()
.setRuleKey("S002")
@@ -87,13 +85,15 @@ public class RuleIteratorForSingleChunkTest {

@Test
public void iterator_over_one_rule() {
dbTester.rules().insertRule(templateRule);
dbTester.rules().insert(templateRule);

List<RuleDoc> results = getResults();
List<RuleDocWithSystemScope> results = getResults();

assertThat(results).hasSize(1);

RuleDoc templateDoc = getRuleDoc(results, templateRule.getRuleKey());
RuleDocWithSystemScope ruleDocWithSystemScope = getRuleDoc(results, templateRule.getRuleKey());
RuleDoc templateDoc = ruleDocWithSystemScope.getRuleDoc();
RuleExtensionDoc templateExtensionDoc = ruleDocWithSystemScope.getRuleExtensionDoc();
assertThat(templateDoc).isNotNull();
assertThat(templateDoc.key()).isEqualTo(RuleKey.of("xoo", "S001"));
assertThat(templateDoc.ruleKey()).isEqualTo("S001");
@@ -105,22 +105,24 @@ public class RuleIteratorForSingleChunkTest {
assertThat(templateDoc.severity()).isEqualTo(Severity.BLOCKER);
assertThat(templateDoc.status()).isEqualTo(RuleStatus.READY);
assertThat(templateDoc.isTemplate()).isTrue();
assertThat(templateDoc.allTags()).containsOnly("performance", "cwe");
assertThat(templateExtensionDoc.getTags()).containsOnly("cwe");
assertThat(templateDoc.createdAt()).isEqualTo(1500000000000L);
assertThat(templateDoc.updatedAt()).isEqualTo(1600000000000L);
}

@Test
public void iterator_over_rules() {
dbTester.rules().insertRule(templateRule);
dbTester.rules().insert(templateRule);
dbClient.ruleDao().insert(dbSession, customRule);
dbSession.commit();

List<RuleDoc> results = getResults();
List<RuleDocWithSystemScope> results = getResults();

assertThat(results).hasSize(2);

RuleDoc templateDoc = getRuleDoc(results, templateRule.getRuleKey());
RuleDocWithSystemScope templateDocWithSystemScope = getRuleDoc(results, templateRule.getRuleKey());
RuleDoc templateDoc = templateDocWithSystemScope.getRuleDoc();
RuleExtensionDoc templateExtensionDoc = templateDocWithSystemScope.getRuleExtensionDoc();
assertThat(templateDoc.key()).isEqualTo(RuleKey.of("xoo", "S001"));
assertThat(templateDoc.ruleKey()).isEqualTo("S001");
assertThat(templateDoc.repository()).isEqualTo("xoo");
@@ -131,11 +133,13 @@ public class RuleIteratorForSingleChunkTest {
assertThat(templateDoc.severity()).isEqualTo(Severity.BLOCKER);
assertThat(templateDoc.status()).isEqualTo(RuleStatus.READY);
assertThat(templateDoc.isTemplate()).isTrue();
assertThat(templateDoc.allTags()).containsOnly("performance", "cwe");
assertThat(templateExtensionDoc.getTags()).containsOnly("cwe");
assertThat(templateDoc.createdAt()).isEqualTo(1500000000000L);
assertThat(templateDoc.updatedAt()).isEqualTo(1600000000000L);

RuleDoc customDoc = getRuleDoc(results, customRule.getRuleKey());
RuleDocWithSystemScope customDocWithSystemScope = getRuleDoc(results, customRule.getRuleKey());
RuleDoc customDoc = customDocWithSystemScope.getRuleDoc();
RuleExtensionDoc customExtensionDoc = customDocWithSystemScope.getRuleExtensionDoc();
assertThat(customDoc.key()).isEqualTo(RuleKey.of("xoo", "S002"));
assertThat(customDoc.ruleKey()).isEqualTo("S002");
assertThat(customDoc.repository()).isEqualTo("xoo");
@@ -146,48 +150,50 @@ public class RuleIteratorForSingleChunkTest {
assertThat(customDoc.severity()).isEqualTo(Severity.MAJOR);
assertThat(customDoc.status()).isEqualTo(RuleStatus.BETA);
assertThat(customDoc.isTemplate()).isFalse();
assertThat(customDoc.allTags()).isEmpty();
assertThat(customExtensionDoc.getTags()).isEmpty();
assertThat(customDoc.createdAt()).isEqualTo(2000000000000L);
assertThat(customDoc.updatedAt()).isEqualTo(2100000000000L);
}

@Test
public void custom_rule() {
dbTester.rules().insertRule(templateRule);
dbTester.rules().insert(templateRule);
dbClient.ruleDao().insert(dbSession, customRule.setTemplateId(templateRule.getId()));
dbSession.commit();

List<RuleDoc> results = getResults();
List<RuleDocWithSystemScope> results = getResults();

assertThat(results).hasSize(2);

RuleDoc templateDoc = getRuleDoc(results, templateRule.getRuleKey());
RuleDocWithSystemScope templateDocWithSystemScope = getRuleDoc(results, templateRule.getRuleKey());
RuleDoc templateDoc = templateDocWithSystemScope.getRuleDoc();
assertThat(templateDoc.isTemplate()).isTrue();
assertThat(templateDoc.templateKey()).isNull();

RuleDoc customDoc = getRuleDoc(results, customRule.getRuleKey());
RuleDocWithSystemScope customDocWithSystemScope = getRuleDoc(results, customRule.getRuleKey());
RuleDoc customDoc = customDocWithSystemScope.getRuleDoc();
assertThat(customDoc.isTemplate()).isFalse();
assertThat(customDoc.templateKey()).isEqualTo(RuleKey.of("xoo", "S001"));
}

@Test
public void removed_rule_is_returned() {
dbTester.rules().insertRule(templateRule.setStatus(RuleStatus.REMOVED));
dbTester.rules().insert(templateRule.setStatus(RuleStatus.REMOVED));
dbSession.commit();

List<RuleDoc> results = getResults();
List<RuleDocWithSystemScope> results = getResults();

assertThat(results).hasSize(1);
}

private List<RuleDoc> getResults() {
return Lists.newArrayList(new RuleIteratorForSingleChunk(dbTester.getDbClient(), dbTester.getDefaultOrganization(), null));
private List<RuleDocWithSystemScope> getResults() {
return Lists.newArrayList(new RuleIteratorForSingleChunk(dbTester.getDbClient(), null));
}

private RuleDoc getRuleDoc(List<RuleDoc> results, String ruleKey) {
RuleDoc rule;
private RuleDocWithSystemScope getRuleDoc(List<RuleDocWithSystemScope> results, String ruleKey) {
RuleDocWithSystemScope rule;
rule = results.stream()
.filter(r -> ruleKey.equals(r.key().rule()))
.filter(r -> ruleKey.equals(r.getRuleDoc().key().rule()))
.findAny()
.orElseThrow(() -> new NotFoundException("Rule not found in results"));
return rule;

+ 2
- 2
server/sonar-server/src/test/java/org/sonar/server/rule/ws/ListActionTest.java View File

@@ -50,8 +50,8 @@ public class ListActionTest {

@Test
public void return_rules_in_protobuf() throws Exception {
dbTester.rules().insertRule(RuleTesting.newDto(RuleKey.of("java", "S001")).setConfigKey(null).setName(null));
dbTester.rules().insertRule(RuleTesting.newDto(RuleKey.of("java", "S002")).setConfigKey("I002").setName("Rule Two"));
dbTester.rules().insert(RuleTesting.newRule(RuleKey.of("java", "S001")).setConfigKey(null).setName(null));
dbTester.rules().insert(RuleTesting.newRule(RuleKey.of("java", "S002")).setConfigKey("I002").setName("Rule Two"));
dbTester.getSession().commit();

TestResponse response = tester.newRequest()

+ 1
- 33
server/sonar-server/src/test/java/org/sonar/server/rule/ws/RulesWsMediumTest.java View File

@@ -19,16 +19,12 @@
*/
package org.sonar.server.rule.ws;

import com.google.common.collect.ImmutableSet;
import java.util.Collections;
import java.util.stream.Stream;
import org.junit.After;
import org.junit.Before;
import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.Test;
import org.sonar.api.server.ws.WebService;
import org.sonar.core.util.stream.MoreCollectors;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.organization.OrganizationDto;
@@ -120,7 +116,7 @@ public class RulesWsMediumTest {
tester.get(ActiveRuleDao.class).insert(session, activeRuleDto);

session.commit();
ruleIndexer.index(defaultOrganization, rule.getKey());
ruleIndexer.indexRuleDefinition(rule.getDefinition().getKey());
activeRuleIndexer.index();

// 1. With Activation
@@ -136,32 +132,4 @@ public class RulesWsMediumTest {
result = request.execute();
result.assertJson(this.getClass(), "show_rule_no_active.json");
}

@Test
public void get_tags() throws Exception {
QualityProfileDto profile = QProfileTesting.newXooP1(defaultOrganization);
tester.get(QualityProfileDao.class).insert(session, profile);

RuleDto rule = RuleTesting.newXooX1(defaultOrganization)
.setTags(ImmutableSet.of("hello", "world"))
.setSystemTags(Collections.<String>emptySet());
ruleDao.insert(session, rule.getDefinition());
ruleDao.insertOrUpdate(session, rule.getMetadata().setRuleId(rule.getId()));

RuleDto rule2 = RuleTesting.newXooX2(defaultOrganization)
.setTags(ImmutableSet.of("hello", "java"))
.setSystemTags(ImmutableSet.of("sys1"));
ruleDao.insert(session, rule2.getDefinition());
ruleDao.insertOrUpdate(session, rule2.getMetadata().setRuleId(rule2.getId()));

session.commit();
ruleIndexer.index(defaultOrganization, Stream.of(rule, rule2).map(RuleDto::getKey).collect(MoreCollectors.toList()));

tester.wsTester().newGetRequest(API_ENDPOINT, API_TAGS_METHOD).execute().assertJson(this.getClass(), "get_tags.json");
tester.wsTester().newGetRequest(API_ENDPOINT, API_TAGS_METHOD)
.setParam("ps", "1").execute().assertJson(this.getClass(), "get_tags_limited.json");
tester.wsTester().newGetRequest(API_ENDPOINT, API_TAGS_METHOD)
.setParam("q", "ll").execute().assertJson(this.getClass(), "get_tags_filtered.json");
}

}

+ 9
- 10
server/sonar-server/src/test/java/org/sonar/server/rule/ws/SearchActionMediumTest.java View File

@@ -24,6 +24,7 @@ import java.util.Date;
import org.junit.After;
import org.junit.Before;
import org.junit.ClassRule;
import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.sonar.api.rule.RuleKey;
@@ -56,6 +57,7 @@ import org.sonar.server.tester.ServerTester;
import org.sonar.server.tester.UserSessionRule;
import org.sonar.server.ws.WsTester;

import static java.util.Arrays.asList;
import static org.assertj.core.api.Assertions.assertThat;
import static org.sonarqube.ws.client.rule.RulesWsParameters.PARAM_ACTIVATION;
import static org.sonarqube.ws.client.rule.RulesWsParameters.PARAM_AVAILABLE_SINCE;
@@ -208,7 +210,7 @@ public class SearchActionMediumTest {

@Test
public void return_lang_key_field_when_language_name_is_not_available() throws Exception {
insertRule(RuleTesting.newDto(RuleKey.of("other", "rule")).setLanguage("unknown").getDefinition());
insertRule(RuleTesting.newRule(RuleKey.of("other", "rule")).setLanguage("unknown"));
dbSession.commit();

WsTester.TestRequest request = tester.wsTester().newGetRequest(API_ENDPOINT, API_SEARCH_METHOD).setParam(WebService.Param.FIELDS, "langName");
@@ -496,16 +498,13 @@ public class SearchActionMediumTest {
result.assertJson(this.getClass(), "get_note_as_markdown_and_html.json");
}

@Ignore
@Test
public void filter_by_tags() throws Exception {
insertRule(RuleTesting.newXooX1()
.setSystemTags(ImmutableSet.of("tag1"))
.getDefinition());
insertRule(RuleTesting.newXooX2()
.setSystemTags(ImmutableSet.of("tag2"))
.getDefinition());

dbSession.commit();
insertRule(RuleTesting.newRule()
.setSystemTags(ImmutableSet.of("tag1")));
insertRule(RuleTesting.newRule()
.setSystemTags(ImmutableSet.of("tag2")));

activeRuleIndexer.index();

@@ -640,6 +639,6 @@ public class SearchActionMediumTest {
private void insertRule(RuleDefinitionDto definition) {
ruleDao.insert(dbSession, definition);
dbSession.commit();
ruleIndexer.index(defaultOrganizationDto, definition.getKey());
ruleIndexer.indexRuleDefinition(definition.getKey());
}
}

+ 7
- 8
server/sonar-server/src/test/java/org/sonar/server/rule/ws/ShowActionMediumTest.java View File

@@ -192,7 +192,7 @@ public class ShowActionMediumTest {

@Test
public void show_rule_with_no_default_and_no_overridden_debt() throws Exception {
RuleDto ruleDto = RuleTesting.newDto(RuleKey.of("java", "S001"))
RuleDefinitionDto ruleDto = RuleTesting.newRule(RuleKey.of("java", "S001"))
.setName("Rule S001")
.setDescription("Rule S001 <b>description</b>")
.setDescriptionFormat(Format.HTML)
@@ -203,7 +203,7 @@ public class ShowActionMediumTest {
.setDefRemediationFunction(null)
.setDefRemediationGapMultiplier(null)
.setDefRemediationBaseEffort(null);
ruleDao.insert(session, ruleDto.getDefinition());
ruleDao.insert(session, ruleDto);
session.commit();
session.clearCache();

@@ -259,7 +259,7 @@ public class ShowActionMediumTest {

@Test
public void show_rule_when_activated() throws Exception {
RuleDto ruleDto = RuleTesting.newDto(RuleKey.of("java", "S001"))
RuleDefinitionDto ruleDto = RuleTesting.newRule(RuleKey.of("java", "S001"))
.setName("Rule S001")
.setDescription("Rule S001 <b>description</b>")
.setDescriptionFormat(Format.HTML)
@@ -269,12 +269,11 @@ public class ShowActionMediumTest {
.setType(RuleType.BUG)
.setCreatedAt(new Date().getTime())
.setUpdatedAt(new Date().getTime());
RuleDefinitionDto definition = ruleDto.getDefinition();
ruleDao.insert(session, definition);
ruleDao.insert(session, ruleDto);
session.commit();
ruleIndexer.index(defaultOrganization, definition.getKey());
RuleParamDto regexParam = RuleParamDto.createFor(definition).setName("regex").setType("STRING").setDescription("Reg *exp*").setDefaultValue(".*");
ruleDao.insertRuleParam(session, definition, regexParam);
ruleIndexer.indexRuleDefinition(ruleDto.getKey());
RuleParamDto regexParam = RuleParamDto.createFor(ruleDto).setName("regex").setType("STRING").setDescription("Reg *exp*").setDefaultValue(".*");
ruleDao.insertRuleParam(session, ruleDto, regexParam);

QualityProfileDto profile = QualityProfileDto.createFor("profile")
.setOrganizationUuid(defaultOrganizationProvider.get().getUuid())

+ 118
- 0
server/sonar-server/src/test/java/org/sonar/server/rule/ws/TagsActionTest.java View File

@@ -0,0 +1,118 @@
/*
* SonarQube
* Copyright (C) 2009-2017 SonarSource SA
* mailto:info 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.rule.ws;

import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.sonar.api.config.MapSettings;
import org.sonar.api.server.ws.WebService;
import org.sonar.db.DbClient;
import org.sonar.db.DbTester;
import org.sonar.db.organization.OrganizationDto;
import org.sonar.db.rule.RuleDefinitionDto;
import org.sonar.server.es.EsClient;
import org.sonar.server.es.EsTester;
import org.sonar.server.organization.TestDefaultOrganizationProvider;
import org.sonar.server.rule.index.RuleIndex;
import org.sonar.server.rule.index.RuleIndexDefinition;
import org.sonar.server.rule.index.RuleIndexer;
import org.sonar.server.tester.UserSessionRule;
import org.sonar.server.ws.WsActionTester;

import static org.assertj.core.api.Assertions.assertThat;
import static org.sonar.db.rule.RuleTesting.setSystemTags;
import static org.sonar.db.rule.RuleTesting.setTags;
import static org.sonar.test.JsonAssert.assertJson;

public class TagsActionTest {

@Rule
public UserSessionRule userSession = UserSessionRule.standalone();
@Rule
public DbTester dbTester = DbTester.create();
@Rule
public EsTester esTester = new EsTester(new RuleIndexDefinition(new MapSettings()));

private DbClient dbClient = dbTester.getDbClient();
private EsClient esClient = esTester.client();
private RuleIndex ruleIndex = new RuleIndex(esClient);
private RuleIndexer ruleIndexer = new RuleIndexer(esClient, dbClient);

private WsActionTester tester = new WsActionTester(new org.sonar.server.rule.ws.TagsAction(ruleIndex, dbClient, TestDefaultOrganizationProvider.from(dbTester)));
private OrganizationDto organization;

@Before
public void before() {
organization = dbTester.organizations().insert();
}

@Test
public void test_definition() {
WebService.Action action = tester.getDef();
assertThat(action.description()).isNotEmpty();
assertThat(action.responseExampleAsString()).isNotEmpty();
assertThat(action.isPost()).isFalse();
assertThat(action.isInternal()).isFalse();
assertThat(action.params()).hasSize(3);

WebService.Param query = action.param("q");
assertThat(query).isNotNull();
assertThat(query.isRequired()).isFalse();
assertThat(query.description()).isNotEmpty();
assertThat(query.exampleValue()).isNotEmpty();

WebService.Param pageSize = action.param("ps");
assertThat(pageSize).isNotNull();
assertThat(pageSize.isRequired()).isFalse();
assertThat(pageSize.defaultValue()).isEqualTo("0");
assertThat(pageSize.description()).isNotEmpty();
assertThat(pageSize.exampleValue()).isNotEmpty();

WebService.Param organization = action.param("organization");
assertThat(organization).isNotNull();
assertThat(organization.isRequired()).isFalse();
assertThat(organization.isInternal()).isTrue();
assertThat(organization.description()).isNotEmpty();
assertThat(organization.exampleValue()).isNotEmpty();
assertThat(organization.since()).isEqualTo("6.4");
}

@Test
public void return_system_tag() throws Exception {
RuleDefinitionDto r = dbTester.rules().insert(setSystemTags("tag"));
ruleIndexer.indexRuleDefinition(r.getKey());

String result = tester.newRequest().execute().getInput();
assertJson(result).isSimilarTo("{\"tags\":[\"tag\"]}");
}

@Test
public void return_tag() throws Exception {
RuleDefinitionDto r = dbTester.rules().insert(setSystemTags());
ruleIndexer.indexRuleDefinition(r.getKey());
dbTester.rules().insertOrUpdateMetadata(r, organization, setTags("tag"));
ruleIndexer.indexRuleExtension(organization, r.getKey());

String result = tester.newRequest().setParam("organization", organization.getKey()).execute().getInput();
assertJson(result).isSimilarTo("{\"tags\":[\"tag\"]}");
}
}

+ 2
- 1
server/sonar-server/src/test/java/org/sonar/server/view/index/ViewIndexerTest.java View File

@@ -125,7 +125,8 @@ public class ViewIndexerTest {

@Test
public void clear_views_lookup_cache_on_index_view_uuid() {
IssueIndex issueIndex = new IssueIndex(esTester.client(), System2.INSTANCE, userSessionRule, new AuthorizationTypeSupport(userSessionRule));
IssueIndex issueIndex = new IssueIndex(esTester.client(), System2.INSTANCE, userSessionRule, new AuthorizationTypeSupport(userSessionRule)
);
IssueIndexer issueIndexer = new IssueIndexer(esTester.client(), new IssueIteratorFactory(dbClient));

String viewUuid = "ABCD";

+ 0
- 8
server/sonar-server/src/test/resources/org/sonar/server/rule/ws/RulesWsMediumTest/get_tags.json View File

@@ -1,8 +0,0 @@
{
"tags": [
"sys1",
"java",
"world",
"hello"
]
}

Loading…
Cancel
Save