3 * Copyright (C) 2009-2022 SonarSource SA
4 * mailto:info AT sonarsource DOT com
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 3 of the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 package org.sonar.server.qualityprofile.index;
22 import java.util.Collection;
23 import java.util.Collections;
24 import java.util.List;
25 import java.util.stream.Collectors;
26 import org.assertj.core.groups.Tuple;
27 import org.junit.Before;
28 import org.junit.Rule;
29 import org.junit.Test;
30 import org.sonar.api.utils.System2;
31 import org.sonar.db.DbTester;
32 import org.sonar.db.es.EsQueueDto;
33 import org.sonar.db.qualityprofile.ActiveRuleDto;
34 import org.sonar.db.qualityprofile.QProfileDto;
35 import org.sonar.db.rule.RuleDefinitionDto;
36 import org.sonar.server.es.EsTester;
37 import org.sonar.server.qualityprofile.ActiveRuleChange;
39 import static java.util.Arrays.stream;
40 import static java.util.Collections.emptySet;
41 import static java.util.Collections.singletonList;
42 import static org.assertj.core.api.Assertions.assertThat;
43 import static org.sonar.server.rule.index.RuleIndexDefinition.TYPE_ACTIVE_RULE;
45 public class ActiveRuleIndexerTest {
47 private System2 system2 = System2.INSTANCE;
50 public DbTester db = DbTester.create(system2);
53 public EsTester es = EsTester.create();
55 private ActiveRuleIndexer underTest = new ActiveRuleIndexer(db.getDbClient(), es.client());
56 private RuleDefinitionDto rule1;
57 private RuleDefinitionDto rule2;
58 private QProfileDto profile1;
59 private QProfileDto profile2;
62 public void before() {
63 rule1 = db.rules().insert();
64 rule2 = db.rules().insert();
65 profile1 = db.qualityProfiles().insert();
66 profile2 = db.qualityProfiles().insert();
70 public void getIndexTypes() {
71 assertThat(underTest.getIndexTypes()).containsExactly(TYPE_ACTIVE_RULE);
75 public void indexOnStartup_does_nothing_if_no_data() {
76 underTest.indexOnStartup(emptySet());
77 assertThat(es.countDocuments(TYPE_ACTIVE_RULE)).isZero();
81 public void indexOnStartup_indexes_all_data() {
82 ActiveRuleDto activeRule = db.qualityProfiles().activateRule(profile1, rule1);
84 underTest.indexOnStartup(emptySet());
86 List<ActiveRuleDoc> docs = es.getDocuments(TYPE_ACTIVE_RULE, ActiveRuleDoc.class);
87 assertThat(docs).hasSize(1);
88 verify(docs.get(0), profile1, activeRule);
89 assertThatEsQueueTableIsEmpty();
93 public void indexAll_indexes_all_data() {
94 ActiveRuleDto activeRule = db.qualityProfiles().activateRule(profile1, rule1);
98 List<ActiveRuleDoc> docs = es.getDocuments(TYPE_ACTIVE_RULE, ActiveRuleDoc.class);
99 assertThat(docs).hasSize(1);
100 verify(docs.get(0), profile1, activeRule);
101 assertThatEsQueueTableIsEmpty();
105 public void test_commitAndIndex() {
106 ActiveRuleDto ar1 = db.qualityProfiles().activateRule(profile1, rule1);
107 ActiveRuleDto ar2 = db.qualityProfiles().activateRule(profile2, rule1);
108 db.qualityProfiles().activateRule(profile2, rule2);
110 commitAndIndex(rule1, ar1, ar2);
112 verifyOnlyIndexed(ar1, ar2);
113 assertThatEsQueueTableIsEmpty();
117 public void commitAndIndex_empty_list() {
118 db.qualityProfiles().activateRule(profile1, rule1);
120 underTest.commitAndIndex(db.getSession(), Collections.emptyList());
122 assertThat(es.countDocuments(TYPE_ACTIVE_RULE)).isZero();
123 assertThatEsQueueTableIsEmpty();
127 public void commitAndIndex_keeps_elements_to_recover_in_ES_QUEUE_on_errors() {
128 ActiveRuleDto ar = db.qualityProfiles().activateRule(profile1, rule1);
129 es.lockWrites(TYPE_ACTIVE_RULE);
131 commitAndIndex(rule1, ar);
133 EsQueueDto expectedItem = EsQueueDto.create(TYPE_ACTIVE_RULE.format(), "ar_" + ar.getUuid(), "activeRuleUuid", ar.getRuleUuid());
134 assertThatEsQueueContainsExactly(expectedItem);
135 es.unlockWrites(TYPE_ACTIVE_RULE);
139 public void commitAndIndex_deletes_the_documents_that_dont_exist_in_database() {
140 ActiveRuleDto ar = db.qualityProfiles().activateRule(profile1, rule1);
142 assertThat(es.countDocuments(TYPE_ACTIVE_RULE)).isOne();
144 db.getDbClient().activeRuleDao().delete(db.getSession(), ar.getKey());
145 commitAndIndex(rule1, ar);
147 assertThat(es.countDocuments(TYPE_ACTIVE_RULE)).isZero();
148 assertThatEsQueueTableIsEmpty();
152 public void index_fails_and_deletes_doc_if_docIdType_is_unsupported() {
153 EsQueueDto item = EsQueueDto.create(TYPE_ACTIVE_RULE.format(), "the_id", "unsupported", "the_routing");
154 db.getDbClient().esQueueDao().insert(db.getSession(), item);
156 underTest.index(db.getSession(), singletonList(item));
158 assertThatEsQueueTableIsEmpty();
159 assertThat(es.countDocuments(TYPE_ACTIVE_RULE)).isZero();
163 public void commitDeletionOfProfiles() {
164 ActiveRuleDto ar1 = db.qualityProfiles().activateRule(profile1, rule1);
165 db.qualityProfiles().activateRule(profile2, rule1);
166 db.qualityProfiles().activateRule(profile2, rule2);
168 db.getDbClient().qualityProfileDao().deleteRulesProfilesByUuids(db.getSession(), singletonList(profile2.getRulesProfileUuid()));
170 underTest.commitDeletionOfProfiles(db.getSession(), singletonList(profile2));
172 verifyOnlyIndexed(ar1);
176 public void commitDeletionOfProfiles_does_nothing_if_profiles_are_not_indexed() {
177 db.qualityProfiles().activateRule(profile1, rule1);
179 assertThat(es.countDocuments(TYPE_ACTIVE_RULE)).isOne();
181 underTest.commitDeletionOfProfiles(db.getSession(), singletonList(profile2));
183 assertThat(es.countDocuments(TYPE_ACTIVE_RULE)).isOne();
186 private void assertThatEsQueueTableIsEmpty() {
187 assertThat(db.countRowsOfTable(db.getSession(), "es_queue")).isZero();
190 private void assertThatEsQueueContainsExactly(EsQueueDto expected) {
191 Collection<EsQueueDto> items = db.getDbClient().esQueueDao().selectForRecovery(db.getSession(), system2.now() + 1_000, 10);
193 .extracting(EsQueueDto::getDocId, EsQueueDto::getDocIdType, EsQueueDto::getDocRouting)
194 .containsExactlyInAnyOrder(Tuple.tuple(expected.getDocId(), expected.getDocIdType(), expected.getDocRouting()));
197 private void commitAndIndex(RuleDefinitionDto rule, ActiveRuleDto... ar) {
198 underTest.commitAndIndex(db.getSession(), stream(ar)
199 .map(a -> new ActiveRuleChange(ActiveRuleChange.Type.ACTIVATED, a, rule))
200 .collect(Collectors.toList()));
203 private void verifyOnlyIndexed(ActiveRuleDto... expected) {
204 List<String> docs = es.getIds(TYPE_ACTIVE_RULE);
205 assertThat(docs).hasSize(expected.length);
206 for (ActiveRuleDto activeRuleDto : expected) {
207 assertThat(docs).contains("ar_" + activeRuleDto.getUuid());
211 private void verify(ActiveRuleDoc doc1, QProfileDto profile, ActiveRuleDto activeRule) {
213 .matches(doc -> doc.getId().equals("ar_" + activeRule.getUuid()))
214 .matches(doc -> doc.getRuleProfileUuid().equals(profile.getRulesProfileUuid()))
215 .matches(doc -> doc.getSeverity().equals(activeRule.getSeverityString()));
218 private void indexAll() {
219 underTest.indexOnStartup(emptySet());