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