From c7c06d7ae381d87a37fb4d9eaeb7fe38ce29de8a Mon Sep 17 00:00:00 2001 From: Julien Lancelot Date: Tue, 21 Feb 2017 11:38:19 +0100 Subject: [PATCH] SONAR-8795 Extract text search feature in a dedicated class --- .../component/index/ComponentIndex.java | 30 ++--- .../ComponentTextSearchFeature.java} | 54 ++++----- .../ComponentTextSearchQueryFactory.java | 114 ++++++++++++++++++ .../server/es/textsearch/package-info.java | 24 ++++ .../index/ComponentIndexFeatureKeyTest.java | 3 +- .../ComponentIndexFeaturePartialTest.java | 3 +- .../ComponentIndexFeaturePrefixTest.java | 7 +- .../ComponentIndexMultipleWordsTest.java | 5 +- .../index/ComponentIndexScoreTest.java | 3 +- .../component/index/ComponentIndexTest.java | 3 +- .../ComponentTextSearchFeatureRule.java} | 12 +- .../ComponentTextSearchQueryFactoryTest.java | 89 ++++++++++++++ 12 files changed, 289 insertions(+), 58 deletions(-) rename server/sonar-server/src/main/java/org/sonar/server/{component/index/ComponentIndexSearchFeature.java => es/textsearch/ComponentTextSearchFeature.java} (62%) create mode 100644 server/sonar-server/src/main/java/org/sonar/server/es/textsearch/ComponentTextSearchQueryFactory.java create mode 100644 server/sonar-server/src/main/java/org/sonar/server/es/textsearch/package-info.java rename server/sonar-server/src/test/java/org/sonar/server/{component/index/ComponentIndexSearchFeatureRule.java => es/textsearch/ComponentTextSearchFeatureRule.java} (75%) create mode 100644 server/sonar-server/src/test/java/org/sonar/server/es/textsearch/ComponentTextSearchQueryFactoryTest.java diff --git a/server/sonar-server/src/main/java/org/sonar/server/component/index/ComponentIndex.java b/server/sonar-server/src/main/java/org/sonar/server/component/index/ComponentIndex.java index 6c891e0554c..65ceb1af541 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/component/index/ComponentIndex.java +++ b/server/sonar-server/src/main/java/org/sonar/server/component/index/ComponentIndex.java @@ -38,10 +38,15 @@ import org.elasticsearch.search.aggregations.metrics.tophits.InternalTopHits; import org.elasticsearch.search.aggregations.metrics.tophits.TopHitsBuilder; import org.sonar.core.util.stream.Collectors; import org.sonar.server.es.EsClient; +import org.sonar.server.es.textsearch.ComponentTextSearchFeature; +import org.sonar.server.es.textsearch.ComponentTextSearchQueryFactory; +import org.sonar.server.es.textsearch.ComponentTextSearchQueryFactory.ComponentTextSearchQuery; import org.sonar.server.permission.index.AuthorizationTypeSupport; import static org.elasticsearch.index.query.QueryBuilders.boolQuery; import static org.elasticsearch.index.query.QueryBuilders.termQuery; +import static org.sonar.server.component.index.ComponentIndexDefinition.FIELD_KEY; +import static org.sonar.server.component.index.ComponentIndexDefinition.FIELD_NAME; import static org.sonar.server.component.index.ComponentIndexDefinition.FIELD_QUALIFIER; import static org.sonar.server.component.index.ComponentIndexDefinition.INDEX_COMPONENTS; import static org.sonar.server.component.index.ComponentIndexDefinition.TYPE_COMPONENT; @@ -60,11 +65,11 @@ public class ComponentIndex { } public List search(ComponentIndexQuery query) { - return search(query, ComponentIndexSearchFeature.values()); + return search(query, ComponentTextSearchFeature.values()); } @VisibleForTesting - List search(ComponentIndexQuery query, ComponentIndexSearchFeature... features) { + List search(ComponentIndexQuery query, ComponentTextSearchFeature... features) { Collection qualifiers = query.getQualifiers(); if (qualifiers.isEmpty()) { return Collections.emptyList(); @@ -87,10 +92,7 @@ public class ComponentIndex { private static FiltersAggregationBuilder createAggregation(ComponentIndexQuery query) { FiltersAggregationBuilder filtersAggregation = AggregationBuilders.filters(FILTERS_AGGREGATION_NAME) .subAggregation(createSubAggregation(query)); - - query.getQualifiers().stream() - .forEach(q -> filtersAggregation.filter(q, termQuery(FIELD_QUALIFIER, q))); - + query.getQualifiers().forEach(q -> filtersAggregation.filter(q, termQuery(FIELD_QUALIFIER, q))); return filtersAggregation; } @@ -100,17 +102,15 @@ public class ComponentIndex { return sub.setFetchSource(false); } - private QueryBuilder createQuery(ComponentIndexQuery query, ComponentIndexSearchFeature... features) { + private QueryBuilder createQuery(ComponentIndexQuery query, ComponentTextSearchFeature... features) { BoolQueryBuilder esQuery = boolQuery(); esQuery.filter(authorizationTypeSupport.createQueryFilter()); - - BoolQueryBuilder featureQuery = boolQuery(); - - Arrays.stream(features) - .map(f -> f.getQuery(query.getQuery())) - .forEach(featureQuery::should); - - return esQuery.must(featureQuery); + ComponentTextSearchQuery componentTextSearchQuery = ComponentTextSearchQuery.builder() + .setQueryText(query.getQuery()) + .setFieldKey(FIELD_KEY) + .setFieldName(FIELD_NAME) + .build(); + return esQuery.must(ComponentTextSearchQueryFactory.createQuery(componentTextSearchQuery, features)); } private static List aggregationsToQualifiers(SearchResponse response) { diff --git a/server/sonar-server/src/main/java/org/sonar/server/component/index/ComponentIndexSearchFeature.java b/server/sonar-server/src/main/java/org/sonar/server/es/textsearch/ComponentTextSearchFeature.java similarity index 62% rename from server/sonar-server/src/main/java/org/sonar/server/component/index/ComponentIndexSearchFeature.java rename to server/sonar-server/src/main/java/org/sonar/server/es/textsearch/ComponentTextSearchFeature.java index 603224b04cd..5410a7a4eea 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/component/index/ComponentIndexSearchFeature.java +++ b/server/sonar-server/src/main/java/org/sonar/server/es/textsearch/ComponentTextSearchFeature.java @@ -17,7 +17,7 @@ * 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.component.index; +package org.sonar.server.es.textsearch; import java.util.Arrays; import java.util.Locale; @@ -28,59 +28,58 @@ import org.elasticsearch.index.query.BoolQueryBuilder; import org.elasticsearch.index.query.MatchQueryBuilder; import org.elasticsearch.index.query.QueryBuilder; import org.sonar.server.es.DefaultIndexSettings; +import org.sonar.server.es.textsearch.ComponentTextSearchQueryFactory.ComponentTextSearchQuery; import static org.elasticsearch.index.query.QueryBuilders.boolQuery; import static org.elasticsearch.index.query.QueryBuilders.matchQuery; import static org.elasticsearch.index.query.QueryBuilders.prefixQuery; -import static org.sonar.server.component.index.ComponentIndexDefinition.FIELD_KEY; -import static org.sonar.server.component.index.ComponentIndexDefinition.FIELD_NAME; import static org.sonar.server.es.DefaultIndexSettingsElement.SEARCH_GRAMS_ANALYZER; import static org.sonar.server.es.DefaultIndexSettingsElement.SORTABLE_ANALYZER; -public enum ComponentIndexSearchFeature { +public enum ComponentTextSearchFeature { EXACT_IGNORE_CASE { @Override - public QueryBuilder getQuery(String queryText) { - return matchQuery(SORTABLE_ANALYZER.subField(FIELD_NAME), queryText) + public QueryBuilder getQuery(ComponentTextSearchQuery query) { + return matchQuery(SORTABLE_ANALYZER.subField(query.getFieldName()), query.getQueryText()) .boost(2.5f); } }, PREFIX { @Override - public QueryBuilder getQuery(String queryText) { - return prefixAndPartialQuery(queryText, FIELD_NAME) + public QueryBuilder getQuery(ComponentTextSearchQuery query) { + return prefixAndPartialQuery(query.getQueryText(), query.getFieldName(), query.getFieldName()) .boost(2f); } }, PREFIX_IGNORE_CASE { @Override - public QueryBuilder getQuery(String queryText) { - String lowerCaseQueryText = queryText.toLowerCase(Locale.getDefault()); - return prefixAndPartialQuery(lowerCaseQueryText, SORTABLE_ANALYZER.subField(FIELD_NAME)) + public QueryBuilder getQuery(ComponentTextSearchQuery query) { + String lowerCaseQueryText = query.getQueryText().toLowerCase(Locale.getDefault()); + return prefixAndPartialQuery(lowerCaseQueryText, SORTABLE_ANALYZER.subField(query.getFieldName()), query.getFieldName()) .boost(3f); } }, PARTIAL { @Override - public QueryBuilder getQuery(String queryText) { - BoolQueryBuilder query = boolQuery(); - split(queryText) - .map(this::partialTermQuery) - .forEach(query::must); - return query + public QueryBuilder getQuery(ComponentTextSearchQuery query) { + BoolQueryBuilder queryBuilder = boolQuery(); + split(query.getQueryText()) + .map(text -> partialTermQuery(text, query.getFieldName())) + .forEach(queryBuilder::must); + return queryBuilder .boost(0.5f); } }, KEY { @Override - public QueryBuilder getQuery(String queryText) { - return matchQuery(SORTABLE_ANALYZER.subField(FIELD_KEY), queryText) + public QueryBuilder getQuery(ComponentTextSearchQuery query) { + return matchQuery(SORTABLE_ANALYZER.subField(query.getFieldKey()), query.getQueryText()) .boost(50f); } }; - public abstract QueryBuilder getQuery(String queryText); + public abstract QueryBuilder getQuery(ComponentTextSearchQuery query); protected Stream split(String queryText) { return Arrays.stream( @@ -88,8 +87,8 @@ public enum ComponentIndexSearchFeature { .filter(StringUtils::isNotEmpty); } - protected BoolQueryBuilder prefixAndPartialQuery(String queryText, String fieldName) { - BoolQueryBuilder query = boolQuery(); + protected BoolQueryBuilder prefixAndPartialQuery(String queryText, String fieldName, String originalFieldName) { + BoolQueryBuilder queryBuilder = boolQuery(); AtomicBoolean first = new AtomicBoolean(true); split(queryText) @@ -99,17 +98,16 @@ public enum ComponentIndexSearchFeature { return prefixQuery(fieldName, queryTerm); } - return partialTermQuery(queryTerm); + return partialTermQuery(queryTerm, originalFieldName); }) - .forEach(query::must); - return query; + .forEach(queryBuilder::must); + return queryBuilder; } - protected MatchQueryBuilder partialTermQuery(String queryTerm) { + protected MatchQueryBuilder partialTermQuery(String queryTerm, String fieldName) { // We will truncate the search to the maximum length of nGrams in the index. // Otherwise the search would for sure not find any results. String truncatedQuery = StringUtils.left(queryTerm, DefaultIndexSettings.MAXIMUM_NGRAM_LENGTH); - - return matchQuery(SEARCH_GRAMS_ANALYZER.subField(FIELD_NAME), truncatedQuery); + return matchQuery(SEARCH_GRAMS_ANALYZER.subField(fieldName), truncatedQuery); } } diff --git a/server/sonar-server/src/main/java/org/sonar/server/es/textsearch/ComponentTextSearchQueryFactory.java b/server/sonar-server/src/main/java/org/sonar/server/es/textsearch/ComponentTextSearchQueryFactory.java new file mode 100644 index 00000000000..81e85881041 --- /dev/null +++ b/server/sonar-server/src/main/java/org/sonar/server/es/textsearch/ComponentTextSearchQueryFactory.java @@ -0,0 +1,114 @@ +/* + * 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.es.textsearch; + +import java.util.Arrays; +import org.elasticsearch.index.query.BoolQueryBuilder; +import org.elasticsearch.index.query.QueryBuilder; + +import static com.google.common.base.Preconditions.checkArgument; +import static java.util.Objects.requireNonNull; +import static org.elasticsearch.index.query.QueryBuilders.boolQuery; + +/** + * This class is used in order to do some advanced full text search in an index on component key and component name + * + * The index must contains at least one field for the component key and one field for the component name + */ +public class ComponentTextSearchQueryFactory { + + private ComponentTextSearchQueryFactory() { + // Only static methods + } + + public static QueryBuilder createQuery(ComponentTextSearchQuery query, ComponentTextSearchFeature... features) { + checkArgument(features.length > 0, "features cannot be empty"); + BoolQueryBuilder featureQuery = boolQuery(); + Arrays.stream(features) + .map(f -> f.getQuery(query)) + .forEach(featureQuery::should); + return featureQuery; + } + + public static class ComponentTextSearchQuery { + private final String queryText; + private final String fieldKey; + private final String fieldName; + + private ComponentTextSearchQuery(Builder builder) { + this.queryText = builder.queryText; + this.fieldKey = builder.fieldKey; + this.fieldName = builder.fieldName; + } + + public String getQueryText() { + return queryText; + } + + public String getFieldKey() { + return fieldKey; + } + + public String getFieldName() { + return fieldName; + } + + public static Builder builder() { + return new Builder(); + } + + public static class Builder { + private String queryText; + private String fieldKey; + private String fieldName; + + /** + * The text search query + */ + public Builder setQueryText(String queryText) { + this.queryText = queryText; + return this; + } + + /** + * The index field that contains the component key + */ + public Builder setFieldKey(String fieldKey) { + this.fieldKey = fieldKey; + return this; + } + + /** + * The index field that contains the component name + */ + public Builder setFieldName(String fieldName) { + this.fieldName = fieldName; + return this; + } + + public ComponentTextSearchQuery build() { + this.queryText = requireNonNull(queryText, "query text cannot be null"); + this.fieldKey = requireNonNull(fieldKey, "field key cannot be null"); + this.fieldName = requireNonNull(fieldName, "field name cannot be null"); + return new ComponentTextSearchQuery(this); + } + } + } +} diff --git a/server/sonar-server/src/main/java/org/sonar/server/es/textsearch/package-info.java b/server/sonar-server/src/main/java/org/sonar/server/es/textsearch/package-info.java new file mode 100644 index 00000000000..9439c3b6d07 --- /dev/null +++ b/server/sonar-server/src/main/java/org/sonar/server/es/textsearch/package-info.java @@ -0,0 +1,24 @@ +/* + * 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. + */ +@ParametersAreNonnullByDefault +package org.sonar.server.es.textsearch; + +import javax.annotation.ParametersAreNonnullByDefault; + diff --git a/server/sonar-server/src/test/java/org/sonar/server/component/index/ComponentIndexFeatureKeyTest.java b/server/sonar-server/src/test/java/org/sonar/server/component/index/ComponentIndexFeatureKeyTest.java index 51912fc6c35..cd8e6fc557f 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/component/index/ComponentIndexFeatureKeyTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/component/index/ComponentIndexFeatureKeyTest.java @@ -22,12 +22,13 @@ package org.sonar.server.component.index; import org.junit.Before; import org.junit.Test; import org.sonar.db.component.ComponentDto; +import org.sonar.server.es.textsearch.ComponentTextSearchFeature; public class ComponentIndexFeatureKeyTest extends ComponentIndexTest { @Before public void before() { - features.set(ComponentIndexSearchFeature.KEY); + features.set(ComponentTextSearchFeature.KEY); } @Test diff --git a/server/sonar-server/src/test/java/org/sonar/server/component/index/ComponentIndexFeaturePartialTest.java b/server/sonar-server/src/test/java/org/sonar/server/component/index/ComponentIndexFeaturePartialTest.java index 471db3b6ebe..5cdeff81d81 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/component/index/ComponentIndexFeaturePartialTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/component/index/ComponentIndexFeaturePartialTest.java @@ -22,12 +22,13 @@ package org.sonar.server.component.index; import org.junit.Before; import org.junit.Test; import org.sonar.db.component.ComponentDto; +import org.sonar.server.es.textsearch.ComponentTextSearchFeature; public class ComponentIndexFeaturePartialTest extends ComponentIndexTest { @Before public void before() { - features.set(ComponentIndexSearchFeature.PARTIAL); + features.set(ComponentTextSearchFeature.PARTIAL); } @Test diff --git a/server/sonar-server/src/test/java/org/sonar/server/component/index/ComponentIndexFeaturePrefixTest.java b/server/sonar-server/src/test/java/org/sonar/server/component/index/ComponentIndexFeaturePrefixTest.java index bb2c4f735b4..55b8fe0d235 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/component/index/ComponentIndexFeaturePrefixTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/component/index/ComponentIndexFeaturePrefixTest.java @@ -21,12 +21,13 @@ package org.sonar.server.component.index; import org.junit.Before; import org.junit.Test; +import org.sonar.server.es.textsearch.ComponentTextSearchFeature; public class ComponentIndexFeaturePrefixTest extends ComponentIndexTest { @Before public void before() { - features.set(ComponentIndexSearchFeature.PREFIX, ComponentIndexSearchFeature.PREFIX_IGNORE_CASE); + features.set(ComponentTextSearchFeature.PREFIX, ComponentTextSearchFeature.PREFIX_IGNORE_CASE); } @Test @@ -41,13 +42,13 @@ public class ComponentIndexFeaturePrefixTest extends ComponentIndexTest { @Test public void should_be_able_to_ignore_case() { - features.set(ComponentIndexSearchFeature.PREFIX_IGNORE_CASE); + features.set(ComponentTextSearchFeature.PREFIX_IGNORE_CASE); assertResultOrder("cOmPoNeNt.Js", "CoMpOnEnT.jS"); } @Test public void should_be_able_to_match_case() { - features.set(ComponentIndexSearchFeature.PREFIX); + features.set(ComponentTextSearchFeature.PREFIX); assertNoFileMatches("cOmPoNeNt.Js", "CoMpOnEnT.jS"); } diff --git a/server/sonar-server/src/test/java/org/sonar/server/component/index/ComponentIndexMultipleWordsTest.java b/server/sonar-server/src/test/java/org/sonar/server/component/index/ComponentIndexMultipleWordsTest.java index f621db542d8..76f49b40309 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/component/index/ComponentIndexMultipleWordsTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/component/index/ComponentIndexMultipleWordsTest.java @@ -20,6 +20,7 @@ package org.sonar.server.component.index; import org.junit.Test; +import org.sonar.server.es.textsearch.ComponentTextSearchFeature; public class ComponentIndexMultipleWordsTest extends ComponentIndexTest { @@ -31,7 +32,7 @@ public class ComponentIndexMultipleWordsTest extends ComponentIndexTest { @Test public void should_find_partial_match() { - features.set(ComponentIndexSearchFeature.PARTIAL); + features.set(ComponentTextSearchFeature.PARTIAL); assertResultOrder("struts java", "Xstrutsx.Xjavax"); } @@ -86,7 +87,7 @@ public class ComponentIndexMultipleWordsTest extends ComponentIndexTest { @Test public void should_require_all_words_to_match_for_partial() { - features.set(ComponentIndexSearchFeature.PARTIAL); + features.set(ComponentTextSearchFeature.PARTIAL); assertNoFileMatches("struts java", "Struts"); } diff --git a/server/sonar-server/src/test/java/org/sonar/server/component/index/ComponentIndexScoreTest.java b/server/sonar-server/src/test/java/org/sonar/server/component/index/ComponentIndexScoreTest.java index 13ebac31f0c..2851892cc03 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/component/index/ComponentIndexScoreTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/component/index/ComponentIndexScoreTest.java @@ -22,6 +22,7 @@ package org.sonar.server.component.index; import org.junit.Test; import org.sonar.db.component.ComponentDto; import org.sonar.db.component.ComponentTesting; +import org.sonar.server.es.textsearch.ComponentTextSearchFeature; public class ComponentIndexScoreTest extends ComponentIndexTest { @@ -103,7 +104,7 @@ public class ComponentIndexScoreTest extends ComponentIndexTest { @Test public void scoring_test_DbTester() { - features.set(ComponentIndexSearchFeature.PARTIAL); + features.set(ComponentTextSearchFeature.PARTIAL); ComponentDto project = indexProject("key-1", "Quality Product"); diff --git a/server/sonar-server/src/test/java/org/sonar/server/component/index/ComponentIndexTest.java b/server/sonar-server/src/test/java/org/sonar/server/component/index/ComponentIndexTest.java index 0f2b8628d04..40508ff39a3 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/component/index/ComponentIndexTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/component/index/ComponentIndexTest.java @@ -34,6 +34,7 @@ import org.sonar.db.component.ComponentTesting; import org.sonar.db.organization.OrganizationDto; import org.sonar.db.organization.OrganizationTesting; import org.sonar.server.es.EsTester; +import org.sonar.server.es.textsearch.ComponentTextSearchFeatureRule; import org.sonar.server.permission.index.AuthorizationTypeSupport; import org.sonar.server.permission.index.PermissionIndexerTester; import org.sonar.server.tester.UserSessionRule; @@ -56,7 +57,7 @@ public abstract class ComponentIndexTest { public UserSessionRule userSession = UserSessionRule.standalone(); @Rule - public ComponentIndexSearchFeatureRule features = new ComponentIndexSearchFeatureRule(); + public ComponentTextSearchFeatureRule features = new ComponentTextSearchFeatureRule(); protected ComponentIndexer indexer = new ComponentIndexer(db.getDbClient(), es.client()); diff --git a/server/sonar-server/src/test/java/org/sonar/server/component/index/ComponentIndexSearchFeatureRule.java b/server/sonar-server/src/test/java/org/sonar/server/es/textsearch/ComponentTextSearchFeatureRule.java similarity index 75% rename from server/sonar-server/src/test/java/org/sonar/server/component/index/ComponentIndexSearchFeatureRule.java rename to server/sonar-server/src/test/java/org/sonar/server/es/textsearch/ComponentTextSearchFeatureRule.java index 2f05501b18e..c49cf8033cf 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/component/index/ComponentIndexSearchFeatureRule.java +++ b/server/sonar-server/src/test/java/org/sonar/server/es/textsearch/ComponentTextSearchFeatureRule.java @@ -17,24 +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.component.index; +package org.sonar.server.es.textsearch; import org.junit.rules.ExternalResource; -public class ComponentIndexSearchFeatureRule extends ExternalResource { +public class ComponentTextSearchFeatureRule extends ExternalResource { - private ComponentIndexSearchFeature[] features; + private ComponentTextSearchFeature[] features; @Override protected void before() throws Throwable { - features = ComponentIndexSearchFeature.values(); + features = ComponentTextSearchFeature.values(); } - public ComponentIndexSearchFeature[] get() { + public ComponentTextSearchFeature[] get() { return features; } - public void set(ComponentIndexSearchFeature... features) { + public void set(ComponentTextSearchFeature... features) { this.features = features; } } diff --git a/server/sonar-server/src/test/java/org/sonar/server/es/textsearch/ComponentTextSearchQueryFactoryTest.java b/server/sonar-server/src/test/java/org/sonar/server/es/textsearch/ComponentTextSearchQueryFactoryTest.java new file mode 100644 index 00000000000..dbf143f1bfa --- /dev/null +++ b/server/sonar-server/src/test/java/org/sonar/server/es/textsearch/ComponentTextSearchQueryFactoryTest.java @@ -0,0 +1,89 @@ +/* + * 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.es.textsearch; + +import org.elasticsearch.index.query.QueryBuilder; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.sonar.server.es.textsearch.ComponentTextSearchQueryFactory.ComponentTextSearchQuery; + +import static org.sonar.server.es.textsearch.ComponentTextSearchQueryFactory.createQuery; +import static org.sonar.test.JsonAssert.assertJson; + +public class ComponentTextSearchQueryFactoryTest { + + @Rule + public ExpectedException expectedException = ExpectedException.none(); + + @Test + public void create_query() throws Exception { + QueryBuilder result = createQuery(ComponentTextSearchQuery.builder() + .setQueryText("SonarQube").setFieldKey("key").setFieldName("name").build(), + ComponentTextSearchFeature.KEY); + + assertJson(result.toString()).isSimilarTo("{" + + " \"bool\" : {" + + " \"should\" : {" + + " \"match\" : {" + + " \"key.sortable_analyzer\" : {" + + " \"query\" : \"SonarQube\"," + + " \"type\" : \"boolean\"," + + " \"boost\" : 50.0\n" + + " }" + + " }" + + " }" + + " }" + + "}"); + } + + @Test + public void fail_to_create_query_when_no_feature() throws Exception { + expectedException.expect(IllegalArgumentException.class); + expectedException.expectMessage("features cannot be empty"); + + createQuery(ComponentTextSearchQuery.builder() + .setQueryText("SonarQube").setFieldKey("key").setFieldName("name").build()); + } + + @Test + public void fail_to_create_query_when_no_query_text() throws Exception { + expectedException.expect(NullPointerException.class); + expectedException.expectMessage("query text cannot be null"); + + ComponentTextSearchQuery.builder().setFieldKey("key").setFieldName("name").build(); + } + + @Test + public void fail_to_create_query_when_no_field_key() throws Exception { + expectedException.expect(NullPointerException.class); + expectedException.expectMessage("field key cannot be null"); + + ComponentTextSearchQuery.builder().setQueryText("SonarQube").setFieldName("name").build(); + } + + @Test + public void fail_to_create_query_when_no_field_name() throws Exception { + expectedException.expect(NullPointerException.class); + expectedException.expectMessage("field name cannot be null"); + + ComponentTextSearchQuery.builder().setQueryText("SonarQube").setFieldKey("key").build(); + } +} -- 2.39.5