]> source.dussan.org Git - sonarqube.git/blob
56d1732dec60a514242b2c82a0f12b578103b860
[sonarqube.git] /
1 /*
2  * SonarQube
3  * Copyright (C) 2009-2022 SonarSource SA
4  * mailto:info AT sonarsource DOT com
5  *
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.
10  *
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.
15  *
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.
19  */
20 package org.sonar.server.measure.index;
21
22 import com.google.common.collect.ImmutableMap;
23 import java.util.List;
24 import java.util.Map;
25 import org.junit.Rule;
26 import org.junit.Test;
27 import org.sonar.api.utils.System2;
28 import org.sonar.db.component.ComponentDto;
29 import org.sonar.server.es.EsTester;
30 import org.sonar.server.es.Facets;
31 import org.sonar.server.es.SearchOptions;
32 import org.sonar.server.measure.index.ProjectMeasuresQuery.MetricCriterion;
33 import org.sonar.server.permission.index.IndexPermissions;
34 import org.sonar.server.permission.index.PermissionIndexerTester;
35 import org.sonar.server.permission.index.WebAuthorizationTypeSupport;
36 import org.sonar.server.tester.UserSessionRule;
37
38 import static com.google.common.base.Preconditions.checkArgument;
39 import static com.google.common.collect.Lists.newArrayList;
40 import static java.util.Arrays.stream;
41 import static java.util.stream.Collectors.toList;
42 import static org.assertj.core.api.Assertions.assertThat;
43 import static org.assertj.core.api.Assertions.entry;
44 import static org.sonar.api.resources.Qualifiers.PROJECT;
45 import static org.sonar.db.component.ComponentTesting.newPrivateProjectDto;
46 import static org.sonar.server.measure.index.ProjectMeasuresIndexDefinition.TYPE_PROJECT_MEASURES;
47 import static org.sonar.server.measure.index.ProjectMeasuresQuery.Operator.GT;
48 import static org.sonar.server.measure.index.ProjectMeasuresQuery.Operator.LT;
49
50 public class ProjectMeasuresIndexTextSearchTest {
51
52   private static final String NCLOC = "ncloc";
53
54   @Rule
55   public EsTester es = EsTester.create();
56   @Rule
57   public UserSessionRule userSession = UserSessionRule.standalone();
58
59   private ProjectMeasuresIndexer projectMeasureIndexer = new ProjectMeasuresIndexer(null, es.client());
60   private PermissionIndexerTester authorizationIndexer = new PermissionIndexerTester(es, projectMeasureIndexer);
61   private ProjectMeasuresIndex underTest = new ProjectMeasuresIndex(es.client(), new WebAuthorizationTypeSupport(userSession), System2.INSTANCE);
62
63   @Test
64   public void search_partial_text_from_project_key() {
65     index(
66       newDoc(newPrivateProjectDto().setUuid("struts").setName("Apache Struts").setDbKey("org.apache.commons.structs")),
67       newDoc(newPrivateProjectDto().setUuid("sonarqube").setName("SonarQube").setDbKey("org.sonar.sonarqube")));
68
69     assertTextQueryResults("apache", "struts");
70     assertTextQueryResults("apache.comm", "struts");
71     assertTextQueryResults("org.apache.commons.structs", "struts");
72     assertTextQueryResults("org.", "struts", "sonarqube");
73   }
74
75   @Test
76   public void match_exact_case_insensitive_name() {
77     index(
78       newDoc(newPrivateProjectDto().setUuid("struts").setName("Apache Struts")),
79       newDoc(newPrivateProjectDto().setUuid("sonarqube").setName("SonarQube")));
80
81     assertTextQueryResults("Apache Struts", "struts");
82     assertTextQueryResults("APACHE STRUTS", "struts");
83     assertTextQueryResults("APACHE struTS", "struts");
84   }
85
86   @Test
87   public void match_from_sub_name() {
88     index(newDoc(newPrivateProjectDto().setUuid("struts").setName("Apache Struts")));
89
90     assertTextQueryResults("truts", "struts");
91     assertTextQueryResults("pache", "struts");
92     assertTextQueryResults("apach", "struts");
93     assertTextQueryResults("che stru", "struts");
94   }
95
96   @Test
97   public void match_name_with_dot() {
98     index(newDoc(newPrivateProjectDto().setUuid("struts").setName("Apache.Struts")));
99
100     assertTextQueryResults("apache struts", "struts");
101   }
102
103   @Test
104   public void match_partial_name() {
105     index(newDoc(newPrivateProjectDto().setUuid("struts").setName("XstrutsxXjavax")));
106
107     assertTextQueryResults("struts java", "struts");
108   }
109
110   @Test
111   public void match_partial_name_prefix_word1() {
112     index(newDoc(newPrivateProjectDto().setUuid("struts").setName("MyStruts.java")));
113
114     assertTextQueryResults("struts java", "struts");
115   }
116
117   @Test
118   public void match_partial_name_suffix_word1() {
119     index(newDoc(newPrivateProjectDto().setUuid("struts").setName("StrutsObject.java")));
120
121     assertTextQueryResults("struts java", "struts");
122   }
123
124   @Test
125   public void match_partial_name_prefix_word2() {
126     index(newDoc(newPrivateProjectDto().setUuid("struts").setName("MyStruts.xjava")));
127
128     assertTextQueryResults("struts java", "struts");
129   }
130
131   @Test
132   public void match_partial_name_suffix_word2() {
133     index(newDoc(newPrivateProjectDto().setUuid("struts").setName("MyStrutsObject.xjavax")));
134
135     assertTextQueryResults("struts java", "struts");
136   }
137
138   @Test
139   public void match_subset_of_document_terms() {
140     index(newDoc(newPrivateProjectDto().setUuid("struts").setName("Some.Struts.Project.java.old")));
141
142     assertTextQueryResults("struts java", "struts");
143   }
144
145   @Test
146   public void match_partial_match_prefix_and_suffix_everywhere() {
147     index(newDoc(newPrivateProjectDto().setUuid("struts").setName("MyStruts.javax")));
148
149     assertTextQueryResults("struts java", "struts");
150   }
151
152   @Test
153   public void ignore_empty_words() {
154     index(newDoc(newPrivateProjectDto().setUuid("struts").setName("Struts")));
155
156     assertTextQueryResults("            struts   \n     \n\n", "struts");
157   }
158
159   @Test
160   public void match_name_from_prefix() {
161     index(newDoc(newPrivateProjectDto().setUuid("struts").setName("Apache Struts")));
162
163     assertTextQueryResults("apach", "struts");
164     assertTextQueryResults("ApA", "struts");
165     assertTextQueryResults("AP", "struts");
166   }
167
168   @Test
169   public void match_name_from_two_words() {
170     index(newDoc(newPrivateProjectDto().setUuid("project").setName("ApacheStrutsFoundation")));
171
172     assertTextQueryResults("apache struts", "project");
173     assertTextQueryResults("struts apache", "project");
174     // Only one word is matching
175     assertNoResults("apache plugin");
176     assertNoResults("project struts");
177   }
178
179   @Test
180   public void match_long_name() {
181     index(
182       newDoc(newPrivateProjectDto().setUuid("project1").setName("LongNameLongNameLongNameLongNameSonarQube")),
183       newDoc(newPrivateProjectDto().setUuid("project2").setName("LongNameLongNameLongNameLongNameSonarQubeX")));
184
185     assertTextQueryResults("LongNameLongNameLongNameLongNameSonarQube", "project1", "project2");
186   }
187
188   @Test
189   public void match_name_with_two_characters() {
190     index(newDoc(newPrivateProjectDto().setUuid("struts").setName("Apache Struts")));
191
192     assertTextQueryResults("st", "struts");
193     assertTextQueryResults("tr", "struts");
194   }
195
196   @Test
197   public void match_exact_case_insensitive_key() {
198     index(
199       newDoc(newPrivateProjectDto().setUuid("project1").setName("Windows").setDbKey("project1")),
200       newDoc(newPrivateProjectDto().setUuid("project2").setName("apachee").setDbKey("project2")));
201
202     assertTextQueryResults("project1", "project1");
203     assertTextQueryResults("PROJECT1", "project1");
204     assertTextQueryResults("pRoJecT1", "project1");
205   }
206
207   @Test
208   public void match_key_with_dot() {
209     index(
210       newDoc(newPrivateProjectDto().setUuid("sonarqube").setName("SonarQube").setDbKey("org.sonarqube")),
211       newDoc(newPrivateProjectDto().setUuid("sq").setName("SQ").setDbKey("sonarqube")));
212
213     assertTextQueryResults("org.sonarqube", "sonarqube");
214     assertNoResults("orgsonarqube");
215     assertNoResults("org-sonarqube");
216     assertNoResults("org:sonarqube");
217     assertNoResults("org sonarqube");
218   }
219
220   @Test
221   public void match_key_with_dash() {
222     index(
223       newDoc(newPrivateProjectDto().setUuid("sonarqube").setName("SonarQube").setDbKey("org-sonarqube")),
224       newDoc(newPrivateProjectDto().setUuid("sq").setName("SQ").setDbKey("sonarqube")));
225
226     assertTextQueryResults("org-sonarqube", "sonarqube");
227     assertNoResults("orgsonarqube");
228     assertNoResults("org.sonarqube");
229     assertNoResults("org:sonarqube");
230     assertNoResults("org sonarqube");
231   }
232
233   @Test
234   public void match_key_with_colon() {
235     index(
236       newDoc(newPrivateProjectDto().setUuid("sonarqube").setName("SonarQube").setDbKey("org:sonarqube")),
237       newDoc(newPrivateProjectDto().setUuid("sq").setName("SQ").setDbKey("sonarqube")));
238
239     assertTextQueryResults("org:sonarqube", "sonarqube");
240     assertNoResults("orgsonarqube");
241     assertNoResults("org-sonarqube");
242     assertNoResults("org_sonarqube");
243     assertNoResults("org sonarqube");
244   }
245
246   @Test
247   public void match_key_having_all_special_characters() {
248     index(newDoc(newPrivateProjectDto().setUuid("sonarqube").setName("SonarQube").setDbKey("org.sonarqube:sonar-sérvèr_ç")));
249
250     assertTextQueryResults("org.sonarqube:sonar-sérvèr_ç", "sonarqube");
251   }
252
253   @Test
254   public void facets_take_into_account_text_search() {
255     index(
256       // docs with ncloc<1K
257       newDoc(newPrivateProjectDto().setName("Windows").setDbKey("project1"), NCLOC, 0d),
258       newDoc(newPrivateProjectDto().setName("apachee").setDbKey("project2"), NCLOC, 999d),
259       // docs with ncloc>=1K and ncloc<10K
260       newDoc(newPrivateProjectDto().setName("Apache").setDbKey("project3"), NCLOC, 1_000d),
261       // docs with ncloc>=100K and ncloc<500K
262       newDoc(newPrivateProjectDto().setName("Apache Foundation").setDbKey("project4"), NCLOC, 100_000d));
263
264     assertNclocFacet(new ProjectMeasuresQuery().setQueryText("apache"), 1L, 1L, 0L, 1L, 0L);
265     assertNclocFacet(new ProjectMeasuresQuery().setQueryText("PAch"), 1L, 1L, 0L, 1L, 0L);
266     assertNclocFacet(new ProjectMeasuresQuery().setQueryText("apache foundation"), 0L, 0L, 0L, 1L, 0L);
267     assertNclocFacet(new ProjectMeasuresQuery().setQueryText("project3"), 0L, 1L, 0L, 0L, 0L);
268     assertNclocFacet(new ProjectMeasuresQuery().setQueryText("project"), 2L, 1L, 0L, 1L, 0L);
269   }
270
271   @Test
272   public void filter_by_metric_take_into_account_text_search() {
273     index(
274       newDoc(newPrivateProjectDto().setUuid("project1").setName("Windows").setDbKey("project1"), NCLOC, 30_000d),
275       newDoc(newPrivateProjectDto().setUuid("project2").setName("apachee").setDbKey("project2"), NCLOC, 40_000d),
276       newDoc(newPrivateProjectDto().setUuid("project3").setName("Apache").setDbKey("project3"), NCLOC, 50_000d),
277       newDoc(newPrivateProjectDto().setUuid("project4").setName("Apache").setDbKey("project4"), NCLOC, 60_000d));
278
279     assertResults(new ProjectMeasuresQuery().setQueryText("apache").addMetricCriterion(MetricCriterion.create(NCLOC, GT, 20_000d)), "project3", "project4", "project2");
280     assertResults(new ProjectMeasuresQuery().setQueryText("apache").addMetricCriterion(MetricCriterion.create(NCLOC, LT, 55_000d)), "project3", "project2");
281     assertResults(new ProjectMeasuresQuery().setQueryText("PAC").addMetricCriterion(MetricCriterion.create(NCLOC, LT, 55_000d)), "project3", "project2");
282     assertResults(new ProjectMeasuresQuery().setQueryText("apachee").addMetricCriterion(MetricCriterion.create(NCLOC, GT, 30_000d)), "project2");
283     assertResults(new ProjectMeasuresQuery().setQueryText("unknown").addMetricCriterion(MetricCriterion.create(NCLOC, GT, 20_000d)));
284   }
285
286   private void index(ProjectMeasuresDoc... docs) {
287     es.putDocuments(TYPE_PROJECT_MEASURES, docs);
288     authorizationIndexer.allow(stream(docs).map(doc -> new IndexPermissions(doc.getId(), PROJECT).allowAnyone()).collect(toList()));
289   }
290
291   private static ProjectMeasuresDoc newDoc(ComponentDto project) {
292     return new ProjectMeasuresDoc()
293       .setId(project.uuid())
294       .setKey(project.getDbKey())
295       .setName(project.name())
296       .setQualifier(project.qualifier());
297   }
298
299   private static ProjectMeasuresDoc newDoc(ComponentDto project, String metric1, Object value1) {
300     return newDoc(project).setMeasures(newArrayList(newMeasure(metric1, value1)));
301   }
302
303   private static Map<String, Object> newMeasure(String key, Object value) {
304     return ImmutableMap.of("key", key, "value", value);
305   }
306
307   private void assertResults(ProjectMeasuresQuery query, String... expectedProjectUuids) {
308     List<String> result = underTest.search(query, new SearchOptions()).getUuids();
309     assertThat(result).containsExactly(expectedProjectUuids);
310   }
311
312   private void assertTextQueryResults(String queryText, String... expectedProjectUuids) {
313     assertResults(new ProjectMeasuresQuery().setQueryText(queryText), expectedProjectUuids);
314   }
315
316   private void assertNoResults(String queryText) {
317     assertTextQueryResults(queryText);
318   }
319
320   private void assertNclocFacet(ProjectMeasuresQuery query, Long... facetExpectedValues) {
321     checkArgument(facetExpectedValues.length == 5, "5 facet values is required");
322     Facets facets = underTest.search(query, new SearchOptions().addFacets(NCLOC)).getFacets();
323     assertThat(facets.get(NCLOC)).containsExactly(
324       entry("*-1000.0", facetExpectedValues[0]),
325       entry("1000.0-10000.0", facetExpectedValues[1]),
326       entry("10000.0-100000.0", facetExpectedValues[2]),
327       entry("100000.0-500000.0", facetExpectedValues[3]),
328       entry("500000.0-*", facetExpectedValues[4]));
329   }
330 }