Merge branch 'stable-2.14' into stable-2.15
* stable-2.14: ElasticReindexIT: Add tests against Elasticsearch version 5 Elasticsearch: Add tests for queries against version 5 MatchQueryBuilder: Don't use deprecated "match" query Elasticsearch: Add an adapter to support V5 Add Bazel version check Change-Id: I72f7ce2f87061f1799abc1a73f57b93a2859b6b6
This commit is contained in:
		
							
								
								
									
										11
									
								
								WORKSPACE
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								WORKSPACE
									
									
									
									
									
								
							| @@ -4,6 +4,13 @@ load("//tools/bzl:maven_jar.bzl", "maven_jar", "GERRIT", "MAVEN_LOCAL") | |||||||
| load("//lib/codemirror:cm.bzl", "CM_VERSION", "DIFF_MATCH_PATCH_VERSION") | load("//lib/codemirror:cm.bzl", "CM_VERSION", "DIFF_MATCH_PATCH_VERSION") | ||||||
| load("//plugins:external_plugin_deps.bzl", "external_plugin_deps") | load("//plugins:external_plugin_deps.bzl", "external_plugin_deps") | ||||||
|  |  | ||||||
|  | http_archive( | ||||||
|  |     name = "bazel_skylib", | ||||||
|  |     sha256 = "bbccf674aa441c266df9894182d80de104cabd19be98be002f6d478aaa31574d", | ||||||
|  |     strip_prefix = "bazel-skylib-2169ae1c374aab4a09aa90e65efe1a3aad4e279b", | ||||||
|  |     urls = ["https://github.com/bazelbuild/bazel-skylib/archive/2169ae1c374aab4a09aa90e65efe1a3aad4e279b.tar.gz"], | ||||||
|  | ) | ||||||
|  |  | ||||||
| http_archive( | http_archive( | ||||||
|     name = "io_bazel_rules_closure", |     name = "io_bazel_rules_closure", | ||||||
|     sha256 = "6691c58a2cd30a86776dd9bb34898b041e37136f2dc7e24cadaeaf599c95c657", |     sha256 = "6691c58a2cd30a86776dd9bb34898b041e37136f2dc7e24cadaeaf599c95c657", | ||||||
| @@ -20,6 +27,10 @@ http_file( | |||||||
|     url = "https://raw.githubusercontent.com/google/closure-compiler/775609aad61e14aef289ebec4bfc09ad88877f9e/contrib/externs/polymer-1.0.js", |     url = "https://raw.githubusercontent.com/google/closure-compiler/775609aad61e14aef289ebec4bfc09ad88877f9e/contrib/externs/polymer-1.0.js", | ||||||
| ) | ) | ||||||
|  |  | ||||||
|  | load("@bazel_skylib//:lib.bzl", "versions") | ||||||
|  |  | ||||||
|  | versions.check(minimum_bazel_version = "0.7.0") | ||||||
|  |  | ||||||
| load("@io_bazel_rules_closure//closure:defs.bzl", "closure_repositories") | load("@io_bazel_rules_closure//closure:defs.bzl", "closure_repositories") | ||||||
|  |  | ||||||
| # Prevent redundant loading of dependencies. | # Prevent redundant loading of dependencies. | ||||||
|   | |||||||
| @@ -50,7 +50,6 @@ import org.elasticsearch.client.Response; | |||||||
|  |  | ||||||
| abstract class AbstractElasticIndex<K, V> implements Index<K, V> { | abstract class AbstractElasticIndex<K, V> implements Index<K, V> { | ||||||
|   protected static final String BULK = "_bulk"; |   protected static final String BULK = "_bulk"; | ||||||
|   protected static final String IGNORE_UNMAPPED = "ignore_unmapped"; |  | ||||||
|   protected static final String ORDER = "order"; |   protected static final String ORDER = "order"; | ||||||
|   protected static final String SEARCH = "_search"; |   protected static final String SEARCH = "_search"; | ||||||
|  |  | ||||||
| @@ -80,8 +79,8 @@ abstract class AbstractElasticIndex<K, V> implements Index<K, V> { | |||||||
|   private final Schema<V> schema; |   private final Schema<V> schema; | ||||||
|   private final SitePaths sitePaths; |   private final SitePaths sitePaths; | ||||||
|   private final String indexNameRaw; |   private final String indexNameRaw; | ||||||
|   private final ElasticRestClientProvider client; |  | ||||||
|  |  | ||||||
|  |   protected final ElasticRestClientProvider client; | ||||||
|   protected final String indexName; |   protected final String indexName; | ||||||
|   protected final Gson gson; |   protected final Gson gson; | ||||||
|   protected final ElasticQueryBuilder queryBuilder; |   protected final ElasticQueryBuilder queryBuilder; | ||||||
| @@ -130,7 +129,8 @@ abstract class AbstractElasticIndex<K, V> implements Index<K, V> { | |||||||
|   @Override |   @Override | ||||||
|   public void deleteAll() throws IOException { |   public void deleteAll() throws IOException { | ||||||
|     // Delete the index, if it exists. |     // Delete the index, if it exists. | ||||||
|     Response response = client.get().performRequest("HEAD", indexName); |     String endpoint = indexName + client.adapter().indicesExistParam(); | ||||||
|  |     Response response = client.get().performRequest("HEAD", endpoint); | ||||||
|     int statusCode = response.getStatusLine().getStatusCode(); |     int statusCode = response.getStatusLine().getStatusCode(); | ||||||
|     if (statusCode == HttpStatus.SC_OK) { |     if (statusCode == HttpStatus.SC_OK) { | ||||||
|       response = client.get().performRequest("DELETE", indexName); |       response = client.get().performRequest("DELETE", indexName); | ||||||
| @@ -182,7 +182,7 @@ abstract class AbstractElasticIndex<K, V> implements Index<K, V> { | |||||||
|   protected JsonArray getSortArray(String idFieldName) { |   protected JsonArray getSortArray(String idFieldName) { | ||||||
|     JsonObject properties = new JsonObject(); |     JsonObject properties = new JsonObject(); | ||||||
|     properties.addProperty(ORDER, "asc"); |     properties.addProperty(ORDER, "asc"); | ||||||
|     properties.addProperty(IGNORE_UNMAPPED, true); |     client.adapter().setIgnoreUnmapped(properties); | ||||||
|  |  | ||||||
|     JsonArray sortArray = new JsonArray(); |     JsonArray sortArray = new JsonArray(); | ||||||
|     addNamedElement(idFieldName, properties, sortArray); |     addNamedElement(idFieldName, properties, sortArray); | ||||||
|   | |||||||
| @@ -61,8 +61,8 @@ public class ElasticAccountIndex extends AbstractElasticIndex<Account.Id, Accoun | |||||||
|   public static class AccountMapping { |   public static class AccountMapping { | ||||||
|     MappingProperties accounts; |     MappingProperties accounts; | ||||||
|  |  | ||||||
|     public AccountMapping(Schema<AccountState> schema) { |     public AccountMapping(Schema<AccountState> schema, ElasticQueryAdapter adapter) { | ||||||
|       this.accounts = ElasticMapping.createMapping(schema); |       this.accounts = ElasticMapping.createMapping(schema, adapter); | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
| @@ -83,7 +83,7 @@ public class ElasticAccountIndex extends AbstractElasticIndex<Account.Id, Accoun | |||||||
|       @Assisted Schema<AccountState> schema) { |       @Assisted Schema<AccountState> schema) { | ||||||
|     super(cfg, sitePaths, schema, client, ACCOUNTS); |     super(cfg, sitePaths, schema, client, ACCOUNTS); | ||||||
|     this.accountCache = accountCache; |     this.accountCache = accountCache; | ||||||
|     this.mapping = new AccountMapping(schema); |     this.mapping = new AccountMapping(schema, client.adapter()); | ||||||
|     this.schema = schema; |     this.schema = schema; | ||||||
|   } |   } | ||||||
|  |  | ||||||
| @@ -133,7 +133,7 @@ public class ElasticAccountIndex extends AbstractElasticIndex<Account.Id, Accoun | |||||||
|       QueryBuilder qb = queryBuilder.toQueryBuilder(p); |       QueryBuilder qb = queryBuilder.toQueryBuilder(p); | ||||||
|       fields = IndexUtils.accountFields(opts); |       fields = IndexUtils.accountFields(opts); | ||||||
|       SearchSourceBuilder searchSource = |       SearchSourceBuilder searchSource = | ||||||
|           new SearchSourceBuilder() |           new SearchSourceBuilder(client.adapter()) | ||||||
|               .query(qb) |               .query(qb) | ||||||
|               .from(opts.start()) |               .from(opts.start()) | ||||||
|               .size(opts.limit()) |               .size(opts.limit()) | ||||||
|   | |||||||
| @@ -87,8 +87,8 @@ class ElasticChangeIndex extends AbstractElasticIndex<Change.Id, ChangeData> | |||||||
|     MappingProperties openChanges; |     MappingProperties openChanges; | ||||||
|     MappingProperties closedChanges; |     MappingProperties closedChanges; | ||||||
|  |  | ||||||
|     ChangeMapping(Schema<ChangeData> schema) { |     ChangeMapping(Schema<ChangeData> schema, ElasticQueryAdapter adapter) { | ||||||
|       MappingProperties mapping = ElasticMapping.createMapping(schema); |       MappingProperties mapping = ElasticMapping.createMapping(schema, adapter); | ||||||
|       this.openChanges = mapping; |       this.openChanges = mapping; | ||||||
|       this.closedChanges = mapping; |       this.closedChanges = mapping; | ||||||
|     } |     } | ||||||
| @@ -115,7 +115,7 @@ class ElasticChangeIndex extends AbstractElasticIndex<Change.Id, ChangeData> | |||||||
|     this.db = db; |     this.db = db; | ||||||
|     this.changeDataFactory = changeDataFactory; |     this.changeDataFactory = changeDataFactory; | ||||||
|     this.schema = schema; |     this.schema = schema; | ||||||
|     mapping = new ChangeMapping(schema); |     this.mapping = new ChangeMapping(schema, client.adapter()); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   @Override |   @Override | ||||||
| @@ -189,7 +189,7 @@ class ElasticChangeIndex extends AbstractElasticIndex<Change.Id, ChangeData> | |||||||
|       QueryBuilder qb = queryBuilder.toQueryBuilder(p); |       QueryBuilder qb = queryBuilder.toQueryBuilder(p); | ||||||
|       fields = IndexUtils.changeFields(opts); |       fields = IndexUtils.changeFields(opts); | ||||||
|       SearchSourceBuilder searchSource = |       SearchSourceBuilder searchSource = | ||||||
|           new SearchSourceBuilder() |           new SearchSourceBuilder(client.adapter()) | ||||||
|               .query(qb) |               .query(qb) | ||||||
|               .from(opts.start()) |               .from(opts.start()) | ||||||
|               .size(opts.limit()) |               .size(opts.limit()) | ||||||
| @@ -431,7 +431,7 @@ class ElasticChangeIndex extends AbstractElasticIndex<Change.Id, ChangeData> | |||||||
|     private JsonArray getSortArray() { |     private JsonArray getSortArray() { | ||||||
|       JsonObject properties = new JsonObject(); |       JsonObject properties = new JsonObject(); | ||||||
|       properties.addProperty(ORDER, "desc"); |       properties.addProperty(ORDER, "desc"); | ||||||
|       properties.addProperty(IGNORE_UNMAPPED, true); |       client.adapter().setIgnoreUnmapped(properties); | ||||||
|  |  | ||||||
|       JsonArray sortArray = new JsonArray(); |       JsonArray sortArray = new JsonArray(); | ||||||
|       addNamedElement(ChangeField.UPDATED.getName(), properties, sortArray); |       addNamedElement(ChangeField.UPDATED.getName(), properties, sortArray); | ||||||
|   | |||||||
| @@ -60,8 +60,8 @@ public class ElasticGroupIndex extends AbstractElasticIndex<AccountGroup.UUID, I | |||||||
|   static class GroupMapping { |   static class GroupMapping { | ||||||
|     MappingProperties groups; |     MappingProperties groups; | ||||||
|  |  | ||||||
|     GroupMapping(Schema<InternalGroup> schema) { |     GroupMapping(Schema<InternalGroup> schema, ElasticQueryAdapter adapter) { | ||||||
|       this.groups = ElasticMapping.createMapping(schema); |       this.groups = ElasticMapping.createMapping(schema, adapter); | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
| @@ -82,7 +82,7 @@ public class ElasticGroupIndex extends AbstractElasticIndex<AccountGroup.UUID, I | |||||||
|       @Assisted Schema<InternalGroup> schema) { |       @Assisted Schema<InternalGroup> schema) { | ||||||
|     super(cfg, sitePaths, schema, client, GROUPS); |     super(cfg, sitePaths, schema, client, GROUPS); | ||||||
|     this.groupCache = groupCache; |     this.groupCache = groupCache; | ||||||
|     this.mapping = new GroupMapping(schema); |     this.mapping = new GroupMapping(schema, client.adapter()); | ||||||
|     this.schema = schema; |     this.schema = schema; | ||||||
|   } |   } | ||||||
|  |  | ||||||
| @@ -132,7 +132,7 @@ public class ElasticGroupIndex extends AbstractElasticIndex<AccountGroup.UUID, I | |||||||
|       QueryBuilder qb = queryBuilder.toQueryBuilder(p); |       QueryBuilder qb = queryBuilder.toQueryBuilder(p); | ||||||
|       fields = IndexUtils.groupFields(opts); |       fields = IndexUtils.groupFields(opts); | ||||||
|       SearchSourceBuilder searchSource = |       SearchSourceBuilder searchSource = | ||||||
|           new SearchSourceBuilder() |           new SearchSourceBuilder(client.adapter()) | ||||||
|               .query(qb) |               .query(qb) | ||||||
|               .from(opts.start()) |               .from(opts.start()) | ||||||
|               .size(opts.limit()) |               .size(opts.limit()) | ||||||
|   | |||||||
| @@ -21,13 +21,15 @@ import com.google.gerrit.index.Schema; | |||||||
| import java.util.Map; | import java.util.Map; | ||||||
|  |  | ||||||
| class ElasticMapping { | class ElasticMapping { | ||||||
|   static MappingProperties createMapping(Schema<?> schema) { |   static MappingProperties createMapping(Schema<?> schema, ElasticQueryAdapter adapter) { | ||||||
|     ElasticMapping.Builder mapping = new ElasticMapping.Builder(); |     ElasticMapping.Builder mapping = new ElasticMapping.Builder(adapter); | ||||||
|     for (FieldDef<?, ?> field : schema.getFields().values()) { |     for (FieldDef<?, ?> field : schema.getFields().values()) { | ||||||
|       String name = field.getName(); |       String name = field.getName(); | ||||||
|       FieldType<?> fieldType = field.getType(); |       FieldType<?> fieldType = field.getType(); | ||||||
|       if (fieldType == FieldType.EXACT || fieldType == FieldType.KEYWORD) { |       if (fieldType == FieldType.EXACT) { | ||||||
|         mapping.addExactField(name); |         mapping.addExactField(name); | ||||||
|  |       } else if (fieldType == FieldType.KEYWORD) { | ||||||
|  |         mapping.addKeywordField(name); | ||||||
|       } else if (fieldType == FieldType.TIMESTAMP) { |       } else if (fieldType == FieldType.TIMESTAMP) { | ||||||
|         mapping.addTimestamp(name); |         mapping.addTimestamp(name); | ||||||
|       } else if (fieldType == FieldType.INTEGER |       } else if (fieldType == FieldType.INTEGER | ||||||
| @@ -46,9 +48,14 @@ class ElasticMapping { | |||||||
|   } |   } | ||||||
|  |  | ||||||
|   static class Builder { |   static class Builder { | ||||||
|  |     private final ElasticQueryAdapter adapter; | ||||||
|     private final ImmutableMap.Builder<String, FieldProperties> fields = |     private final ImmutableMap.Builder<String, FieldProperties> fields = | ||||||
|         new ImmutableMap.Builder<>(); |         new ImmutableMap.Builder<>(); | ||||||
|  |  | ||||||
|  |     Builder(ElasticQueryAdapter adapter) { | ||||||
|  |       this.adapter = adapter; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     MappingProperties build() { |     MappingProperties build() { | ||||||
|       MappingProperties properties = new MappingProperties(); |       MappingProperties properties = new MappingProperties(); | ||||||
|       properties.properties = fields.build(); |       properties.properties = fields.build(); | ||||||
| @@ -56,9 +63,20 @@ class ElasticMapping { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     Builder addExactField(String name) { |     Builder addExactField(String name) { | ||||||
|       FieldProperties key = new FieldProperties("string"); |       FieldProperties key = new FieldProperties(adapter.keywordFieldType()); | ||||||
|       key.index = "not_analyzed"; |       key.index = adapter.indexProperty(); | ||||||
|       FieldProperties properties = new FieldProperties("string"); |       FieldProperties properties; | ||||||
|  |       properties = new FieldProperties(adapter.stringFieldType()); | ||||||
|  |       properties.fields = ImmutableMap.of("key", key); | ||||||
|  |       fields.put(name, properties); | ||||||
|  |       return this; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     Builder addKeywordField(String name) { | ||||||
|  |       FieldProperties key = new FieldProperties(adapter.keywordFieldType()); | ||||||
|  |       key.index = adapter.indexProperty(); | ||||||
|  |       FieldProperties properties; | ||||||
|  |       properties = new FieldProperties(adapter.keywordFieldType()); | ||||||
|       properties.fields = ImmutableMap.of("key", key); |       properties.fields = ImmutableMap.of("key", key); | ||||||
|       fields.put(name, properties); |       fields.put(name, properties); | ||||||
|       return this; |       return this; | ||||||
| @@ -78,7 +96,7 @@ class ElasticMapping { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     Builder addString(String name) { |     Builder addString(String name) { | ||||||
|       fields.put(name, new FieldProperties("string")); |       fields.put(name, new FieldProperties(adapter.stringFieldType())); | ||||||
|       return this; |       return this; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -0,0 +1,74 @@ | |||||||
|  | // Copyright (C) 2018 The Android Open Source Project | ||||||
|  | // | ||||||
|  | // Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  | // you may not use this file except in compliance with the License. | ||||||
|  | // You may obtain a copy of the License at | ||||||
|  | // | ||||||
|  | // http://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  | // | ||||||
|  | // Unless required by applicable law or agreed to in writing, software | ||||||
|  | // distributed under the License is distributed on an "AS IS" BASIS, | ||||||
|  | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
|  | // See the License for the specific language governing permissions and | ||||||
|  | // limitations under the License. | ||||||
|  |  | ||||||
|  | package com.google.gerrit.elasticsearch; | ||||||
|  |  | ||||||
|  | import com.google.gson.JsonObject; | ||||||
|  |  | ||||||
|  | public class ElasticQueryAdapter { | ||||||
|  |   private final boolean ignoreUnmapped; | ||||||
|  |   private final String searchFilteringName; | ||||||
|  |   private final String indicesExistParam; | ||||||
|  |   private final String keywordFieldType; | ||||||
|  |   private final String stringFieldType; | ||||||
|  |   private final String indexProperty; | ||||||
|  |  | ||||||
|  |   ElasticQueryAdapter(ElasticVersion version) { | ||||||
|  |     this.ignoreUnmapped = version == ElasticVersion.V2_4; | ||||||
|  |     switch (version) { | ||||||
|  |       case V5_6: | ||||||
|  |       case V6_2: | ||||||
|  |         this.searchFilteringName = "_source"; | ||||||
|  |         this.indicesExistParam = "?allow_no_indices=false"; | ||||||
|  |         this.keywordFieldType = "keyword"; | ||||||
|  |         this.stringFieldType = "text"; | ||||||
|  |         this.indexProperty = "true"; | ||||||
|  |         break; | ||||||
|  |       case V2_4: | ||||||
|  |       default: | ||||||
|  |         this.searchFilteringName = "fields"; | ||||||
|  |         this.indicesExistParam = ""; | ||||||
|  |         this.keywordFieldType = "string"; | ||||||
|  |         this.stringFieldType = "string"; | ||||||
|  |         this.indexProperty = "not_analyzed"; | ||||||
|  |         break; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   void setIgnoreUnmapped(JsonObject properties) { | ||||||
|  |     if (ignoreUnmapped) { | ||||||
|  |       properties.addProperty("ignore_unmapped", true); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public String searchFilteringName() { | ||||||
|  |     return searchFilteringName; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   String indicesExistParam() { | ||||||
|  |     return indicesExistParam; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   String keywordFieldType() { | ||||||
|  |     return keywordFieldType; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   String stringFieldType() { | ||||||
|  |     return stringFieldType; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   String indexProperty() { | ||||||
|  |     return indexProperty; | ||||||
|  |   } | ||||||
|  | } | ||||||
| @@ -44,6 +44,7 @@ class ElasticRestClientProvider implements Provider<RestClient>, LifecycleListen | |||||||
|   private final String password; |   private final String password; | ||||||
|  |  | ||||||
|   private RestClient client; |   private RestClient client; | ||||||
|  |   private ElasticQueryAdapter adapter; | ||||||
|  |  | ||||||
|   @Inject |   @Inject | ||||||
|   ElasticRestClientProvider(ElasticConfiguration cfg) { |   ElasticRestClientProvider(ElasticConfiguration cfg) { | ||||||
| @@ -69,6 +70,7 @@ class ElasticRestClientProvider implements Provider<RestClient>, LifecycleListen | |||||||
|           client = build(); |           client = build(); | ||||||
|           ElasticVersion version = getVersion(); |           ElasticVersion version = getVersion(); | ||||||
|           log.info("Elasticsearch integration version {}", version); |           log.info("Elasticsearch integration version {}", version); | ||||||
|  |           adapter = new ElasticQueryAdapter(version); | ||||||
|         } |         } | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
| @@ -89,6 +91,11 @@ class ElasticRestClientProvider implements Provider<RestClient>, LifecycleListen | |||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   ElasticQueryAdapter adapter() { | ||||||
|  |     get(); // Make sure we're connected | ||||||
|  |     return adapter; | ||||||
|  |   } | ||||||
|  |  | ||||||
|   public static class FailedToGetVersion extends ElasticException { |   public static class FailedToGetVersion extends ElasticException { | ||||||
|     private static final long serialVersionUID = 1L; |     private static final long serialVersionUID = 1L; | ||||||
|     private static final String MESSAGE = "Failed to get Elasticsearch version"; |     private static final String MESSAGE = "Failed to get Elasticsearch version"; | ||||||
|   | |||||||
| @@ -27,9 +27,14 @@ class MatchQueryBuilder extends QueryBuilder { | |||||||
|  |  | ||||||
|   enum Type { |   enum Type { | ||||||
|     /** The text is analyzed and used as a phrase query. */ |     /** The text is analyzed and used as a phrase query. */ | ||||||
|     PHRASE, |     MATCH_PHRASE, | ||||||
|     /** The text is analyzed and used in a phrase query, with the last term acting as a prefix. */ |     /** The text is analyzed and used in a phrase query, with the last term acting as a prefix. */ | ||||||
|     PHRASE_PREFIX |     MATCH_PHRASE_PREFIX; | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public String toString() { | ||||||
|  |       return name().toLowerCase(Locale.US); | ||||||
|  |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   private final String name; |   private final String name; | ||||||
| @@ -52,14 +57,6 @@ class MatchQueryBuilder extends QueryBuilder { | |||||||
|  |  | ||||||
|   @Override |   @Override | ||||||
|   protected void doXContent(XContentBuilder builder) throws IOException { |   protected void doXContent(XContentBuilder builder) throws IOException { | ||||||
|     builder.startObject("match"); |     builder.startObject(type.toString()).field(name, text).endObject(); | ||||||
|     builder.startObject(name); |  | ||||||
|  |  | ||||||
|     builder.field("query", text); |  | ||||||
|     if (type != null) { |  | ||||||
|       builder.field("type", type.toString().toLowerCase(Locale.ENGLISH)); |  | ||||||
|     } |  | ||||||
|     builder.endObject(); |  | ||||||
|     builder.endObject(); |  | ||||||
|   } |   } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -33,7 +33,7 @@ public abstract class QueryBuilders { | |||||||
|    * @param text The query text (to be analyzed). |    * @param text The query text (to be analyzed). | ||||||
|    */ |    */ | ||||||
|   public static MatchQueryBuilder matchPhraseQuery(String name, Object text) { |   public static MatchQueryBuilder matchPhraseQuery(String name, Object text) { | ||||||
|     return new MatchQueryBuilder(name, text).type(MatchQueryBuilder.Type.PHRASE); |     return new MatchQueryBuilder(name, text).type(MatchQueryBuilder.Type.MATCH_PHRASE); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   /** |   /** | ||||||
| @@ -43,7 +43,7 @@ public abstract class QueryBuilders { | |||||||
|    * @param text The query text (to be analyzed). |    * @param text The query text (to be analyzed). | ||||||
|    */ |    */ | ||||||
|   public static MatchQueryBuilder matchPhrasePrefixQuery(String name, Object text) { |   public static MatchQueryBuilder matchPhrasePrefixQuery(String name, Object text) { | ||||||
|     return new MatchQueryBuilder(name, text).type(MatchQueryBuilder.Type.PHRASE_PREFIX); |     return new MatchQueryBuilder(name, text).type(MatchQueryBuilder.Type.MATCH_PHRASE_PREFIX); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   /** |   /** | ||||||
|   | |||||||
| @@ -14,6 +14,7 @@ | |||||||
|  |  | ||||||
| package com.google.gerrit.elasticsearch.builders; | package com.google.gerrit.elasticsearch.builders; | ||||||
|  |  | ||||||
|  | import com.google.gerrit.elasticsearch.ElasticQueryAdapter; | ||||||
| import java.io.IOException; | import java.io.IOException; | ||||||
| import java.util.List; | import java.util.List; | ||||||
|  |  | ||||||
| @@ -23,6 +24,7 @@ import java.util.List; | |||||||
|  * <p>A trimmed down and modified version of org.elasticsearch.search.builder.SearchSourceBuilder. |  * <p>A trimmed down and modified version of org.elasticsearch.search.builder.SearchSourceBuilder. | ||||||
|  */ |  */ | ||||||
| public class SearchSourceBuilder { | public class SearchSourceBuilder { | ||||||
|  |   private final ElasticQueryAdapter adapter; | ||||||
|  |  | ||||||
|   private QuerySourceBuilder querySourceBuilder; |   private QuerySourceBuilder querySourceBuilder; | ||||||
|  |  | ||||||
| @@ -33,7 +35,9 @@ public class SearchSourceBuilder { | |||||||
|   private List<String> fieldNames; |   private List<String> fieldNames; | ||||||
|  |  | ||||||
|   /** Constructs a new search source builder. */ |   /** Constructs a new search source builder. */ | ||||||
|   public SearchSourceBuilder() {} |   public SearchSourceBuilder(ElasticQueryAdapter adapter) { | ||||||
|  |     this.adapter = adapter; | ||||||
|  |   } | ||||||
|  |  | ||||||
|   /** Constructs a new search source builder with a search query. */ |   /** Constructs a new search source builder with a search query. */ | ||||||
|   public SearchSourceBuilder query(QueryBuilder query) { |   public SearchSourceBuilder query(QueryBuilder query) { | ||||||
| @@ -95,9 +99,9 @@ public class SearchSourceBuilder { | |||||||
|  |  | ||||||
|     if (fieldNames != null) { |     if (fieldNames != null) { | ||||||
|       if (fieldNames.size() == 1) { |       if (fieldNames.size() == 1) { | ||||||
|         builder.field("fields", fieldNames.get(0)); |         builder.field(adapter.searchFilteringName(), fieldNames.get(0)); | ||||||
|       } else { |       } else { | ||||||
|         builder.startArray("fields"); |         builder.startArray(adapter.searchFilteringName()); | ||||||
|         for (String fieldName : fieldNames) { |         for (String fieldName : fieldNames) { | ||||||
|           builder.value(fieldName); |           builder.value(fieldName); | ||||||
|         } |         } | ||||||
|   | |||||||
| @@ -15,7 +15,6 @@ | |||||||
| package com.google.gerrit.elasticsearch; | package com.google.gerrit.elasticsearch; | ||||||
|  |  | ||||||
| import com.google.common.collect.ImmutableSet; | import com.google.common.collect.ImmutableSet; | ||||||
| import com.google.gerrit.elasticsearch.ElasticVersion; |  | ||||||
| import java.util.Set; | import java.util.Set; | ||||||
| import org.apache.http.HttpHost; | import org.apache.http.HttpHost; | ||||||
| import org.junit.internal.AssumptionViolatedException; | import org.junit.internal.AssumptionViolatedException; | ||||||
|   | |||||||
| @@ -17,14 +17,11 @@ package com.google.gerrit.elasticsearch; | |||||||
| import com.google.gerrit.elasticsearch.ElasticTestUtils.ElasticNodeInfo; | import com.google.gerrit.elasticsearch.ElasticTestUtils.ElasticNodeInfo; | ||||||
| import com.google.gerrit.server.query.change.AbstractQueryChangesTest; | import com.google.gerrit.server.query.change.AbstractQueryChangesTest; | ||||||
| import com.google.gerrit.testutil.InMemoryModule; | import com.google.gerrit.testutil.InMemoryModule; | ||||||
| import com.google.gerrit.testutil.InMemoryRepositoryManager.Repo; |  | ||||||
| import com.google.inject.Guice; | import com.google.inject.Guice; | ||||||
| import com.google.inject.Injector; | import com.google.inject.Injector; | ||||||
| import org.eclipse.jgit.junit.TestRepository; |  | ||||||
| import org.eclipse.jgit.lib.Config; | import org.eclipse.jgit.lib.Config; | ||||||
| import org.junit.AfterClass; | import org.junit.AfterClass; | ||||||
| import org.junit.BeforeClass; | import org.junit.BeforeClass; | ||||||
| import org.junit.Test; |  | ||||||
|  |  | ||||||
| public class ElasticQueryChangesTest extends AbstractQueryChangesTest { | public class ElasticQueryChangesTest extends AbstractQueryChangesTest { | ||||||
|   private static ElasticNodeInfo nodeInfo; |   private static ElasticNodeInfo nodeInfo; | ||||||
| @@ -66,12 +63,4 @@ public class ElasticQueryChangesTest extends AbstractQueryChangesTest { | |||||||
|     ElasticTestUtils.configure(elasticsearchConfig, nodeInfo.port, indicesPrefix); |     ElasticTestUtils.configure(elasticsearchConfig, nodeInfo.port, indicesPrefix); | ||||||
|     return Guice.createInjector(new InMemoryModule(elasticsearchConfig, notesMigration)); |     return Guice.createInjector(new InMemoryModule(elasticsearchConfig, notesMigration)); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   @Test |  | ||||||
|   public void byOwnerInvalidQuery() throws Exception { |  | ||||||
|     TestRepository<Repo> repo = createProject("repo"); |  | ||||||
|     insert(repo, newChange(repo), userId); |  | ||||||
|     String nameEmail = user.asIdentifiedUser().getNameEmail(); |  | ||||||
|     assertQuery("owner: \"" + nameEmail + "\"\\"); |  | ||||||
|   } |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -0,0 +1,66 @@ | |||||||
|  | // Copyright (C) 2018 The Android Open Source Project | ||||||
|  | // | ||||||
|  | // Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  | // you may not use this file except in compliance with the License. | ||||||
|  | // You may obtain a copy of the License at | ||||||
|  | // | ||||||
|  | // http://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  | // | ||||||
|  | // Unless required by applicable law or agreed to in writing, software | ||||||
|  | // distributed under the License is distributed on an "AS IS" BASIS, | ||||||
|  | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
|  | // See the License for the specific language governing permissions and | ||||||
|  | // limitations under the License. | ||||||
|  |  | ||||||
|  | package com.google.gerrit.elasticsearch; | ||||||
|  |  | ||||||
|  | import com.google.gerrit.elasticsearch.ElasticTestUtils.ElasticNodeInfo; | ||||||
|  | import com.google.gerrit.server.query.account.AbstractQueryAccountsTest; | ||||||
|  | import com.google.gerrit.testutil.InMemoryModule; | ||||||
|  | import com.google.inject.Guice; | ||||||
|  | import com.google.inject.Injector; | ||||||
|  | import org.eclipse.jgit.lib.Config; | ||||||
|  | import org.junit.AfterClass; | ||||||
|  | import org.junit.BeforeClass; | ||||||
|  |  | ||||||
|  | public class ElasticV5QueryAccountsTest extends AbstractQueryAccountsTest { | ||||||
|  |   private static ElasticNodeInfo nodeInfo; | ||||||
|  |   private static ElasticContainer<?> container; | ||||||
|  |  | ||||||
|  |   @BeforeClass | ||||||
|  |   public static void startIndexService() { | ||||||
|  |     if (nodeInfo != null) { | ||||||
|  |       // do not start Elasticsearch twice | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     container = ElasticContainer.createAndStart(ElasticVersion.V5_6); | ||||||
|  |     nodeInfo = new ElasticNodeInfo(container.getHttpHost().getPort()); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @AfterClass | ||||||
|  |   public static void stopElasticsearchServer() { | ||||||
|  |     if (container != null) { | ||||||
|  |       container.stop(); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   private String testName() { | ||||||
|  |     return testName.getMethodName().toLowerCase() + "_"; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @Override | ||||||
|  |   protected void initAfterLifecycleStart() throws Exception { | ||||||
|  |     super.initAfterLifecycleStart(); | ||||||
|  |     ElasticTestUtils.createAllIndexes(injector); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @Override | ||||||
|  |   protected Injector createInjector() { | ||||||
|  |     Config elasticsearchConfig = new Config(config); | ||||||
|  |     InMemoryModule.setDefaults(elasticsearchConfig); | ||||||
|  |     String indicesPrefix = testName(); | ||||||
|  |     ElasticTestUtils.configure(elasticsearchConfig, nodeInfo.port, indicesPrefix); | ||||||
|  |     return Guice.createInjector(new InMemoryModule(elasticsearchConfig, notesMigration)); | ||||||
|  |   } | ||||||
|  | } | ||||||
| @@ -0,0 +1,66 @@ | |||||||
|  | // Copyright (C) 2018 The Android Open Source Project | ||||||
|  | // | ||||||
|  | // Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  | // you may not use this file except in compliance with the License. | ||||||
|  | // You may obtain a copy of the License at | ||||||
|  | // | ||||||
|  | // http://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  | // | ||||||
|  | // Unless required by applicable law or agreed to in writing, software | ||||||
|  | // distributed under the License is distributed on an "AS IS" BASIS, | ||||||
|  | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
|  | // See the License for the specific language governing permissions and | ||||||
|  | // limitations under the License. | ||||||
|  |  | ||||||
|  | package com.google.gerrit.elasticsearch; | ||||||
|  |  | ||||||
|  | import com.google.gerrit.elasticsearch.ElasticTestUtils.ElasticNodeInfo; | ||||||
|  | import com.google.gerrit.server.query.change.AbstractQueryChangesTest; | ||||||
|  | import com.google.gerrit.testutil.InMemoryModule; | ||||||
|  | import com.google.inject.Guice; | ||||||
|  | import com.google.inject.Injector; | ||||||
|  | import org.eclipse.jgit.lib.Config; | ||||||
|  | import org.junit.AfterClass; | ||||||
|  | import org.junit.BeforeClass; | ||||||
|  |  | ||||||
|  | public class ElasticV5QueryChangesTest extends AbstractQueryChangesTest { | ||||||
|  |   private static ElasticNodeInfo nodeInfo; | ||||||
|  |   private static ElasticContainer<?> container; | ||||||
|  |  | ||||||
|  |   @BeforeClass | ||||||
|  |   public static void startIndexService() { | ||||||
|  |     if (nodeInfo != null) { | ||||||
|  |       // do not start Elasticsearch twice | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     container = ElasticContainer.createAndStart(ElasticVersion.V5_6); | ||||||
|  |     nodeInfo = new ElasticNodeInfo(container.getHttpHost().getPort()); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @AfterClass | ||||||
|  |   public static void stopElasticsearchServer() { | ||||||
|  |     if (container != null) { | ||||||
|  |       container.stop(); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   private String testName() { | ||||||
|  |     return testName.getMethodName().toLowerCase() + "_"; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @Override | ||||||
|  |   protected void initAfterLifecycleStart() throws Exception { | ||||||
|  |     super.initAfterLifecycleStart(); | ||||||
|  |     ElasticTestUtils.createAllIndexes(injector); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @Override | ||||||
|  |   protected Injector createInjector() { | ||||||
|  |     Config elasticsearchConfig = new Config(config); | ||||||
|  |     InMemoryModule.setDefaults(elasticsearchConfig); | ||||||
|  |     String indicesPrefix = testName(); | ||||||
|  |     ElasticTestUtils.configure(elasticsearchConfig, nodeInfo.port, indicesPrefix); | ||||||
|  |     return Guice.createInjector(new InMemoryModule(elasticsearchConfig, notesMigration)); | ||||||
|  |   } | ||||||
|  | } | ||||||
| @@ -0,0 +1,66 @@ | |||||||
|  | // Copyright (C) 2018 The Android Open Source Project | ||||||
|  | // | ||||||
|  | // Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  | // you may not use this file except in compliance with the License. | ||||||
|  | // You may obtain a copy of the License at | ||||||
|  | // | ||||||
|  | // http://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  | // | ||||||
|  | // Unless required by applicable law or agreed to in writing, software | ||||||
|  | // distributed under the License is distributed on an "AS IS" BASIS, | ||||||
|  | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
|  | // See the License for the specific language governing permissions and | ||||||
|  | // limitations under the License. | ||||||
|  |  | ||||||
|  | package com.google.gerrit.elasticsearch; | ||||||
|  |  | ||||||
|  | import com.google.gerrit.elasticsearch.ElasticTestUtils.ElasticNodeInfo; | ||||||
|  | import com.google.gerrit.server.query.group.AbstractQueryGroupsTest; | ||||||
|  | import com.google.gerrit.testutil.InMemoryModule; | ||||||
|  | import com.google.inject.Guice; | ||||||
|  | import com.google.inject.Injector; | ||||||
|  | import org.eclipse.jgit.lib.Config; | ||||||
|  | import org.junit.AfterClass; | ||||||
|  | import org.junit.BeforeClass; | ||||||
|  |  | ||||||
|  | public class ElasticV5QueryGroupsTest extends AbstractQueryGroupsTest { | ||||||
|  |   private static ElasticNodeInfo nodeInfo; | ||||||
|  |   private static ElasticContainer<?> container; | ||||||
|  |  | ||||||
|  |   @BeforeClass | ||||||
|  |   public static void startIndexService() { | ||||||
|  |     if (nodeInfo != null) { | ||||||
|  |       // do not start Elasticsearch twice | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     container = ElasticContainer.createAndStart(ElasticVersion.V5_6); | ||||||
|  |     nodeInfo = new ElasticNodeInfo(container.getHttpHost().getPort()); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @AfterClass | ||||||
|  |   public static void stopElasticsearchServer() { | ||||||
|  |     if (container != null) { | ||||||
|  |       container.stop(); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   private String testName() { | ||||||
|  |     return testName.getMethodName().toLowerCase() + "_"; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @Override | ||||||
|  |   protected void initAfterLifecycleStart() throws Exception { | ||||||
|  |     super.initAfterLifecycleStart(); | ||||||
|  |     ElasticTestUtils.createAllIndexes(injector); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @Override | ||||||
|  |   protected Injector createInjector() { | ||||||
|  |     Config elasticsearchConfig = new Config(config); | ||||||
|  |     InMemoryModule.setDefaults(elasticsearchConfig); | ||||||
|  |     String indicesPrefix = testName(); | ||||||
|  |     ElasticTestUtils.configure(elasticsearchConfig, nodeInfo.port, indicesPrefix); | ||||||
|  |     return Guice.createInjector(new InMemoryModule(elasticsearchConfig, notesMigration)); | ||||||
|  |   } | ||||||
|  | } | ||||||
| @@ -2593,6 +2593,14 @@ public abstract class AbstractQueryChangesTest extends GerritServerTests { | |||||||
|     assertQuery("query:query4"); |     assertQuery("query:query4"); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   @Test | ||||||
|  |   public void byOwnerInvalidQuery() throws Exception { | ||||||
|  |     TestRepository<Repo> repo = createProject("repo"); | ||||||
|  |     insert(repo, newChange(repo), userId); | ||||||
|  |     String nameEmail = user.asIdentifiedUser().getNameEmail(); | ||||||
|  |     assertQuery("owner: \"" + nameEmail + "\"\\"); | ||||||
|  |   } | ||||||
|  |  | ||||||
|   protected ChangeInserter newChange(TestRepository<Repo> repo) throws Exception { |   protected ChangeInserter newChange(TestRepository<Repo> repo) throws Exception { | ||||||
|     return newChange(repo, null, null, null, null, false); |     return newChange(repo, null, null, null, null, false); | ||||||
|   } |   } | ||||||
|   | |||||||
| @@ -64,6 +64,7 @@ public class LuceneQueryChangesTest extends AbstractQueryChangesTest { | |||||||
|   } |   } | ||||||
|  |  | ||||||
|   @Test |   @Test | ||||||
|  |   @Override | ||||||
|   public void byOwnerInvalidQuery() throws Exception { |   public void byOwnerInvalidQuery() throws Exception { | ||||||
|     TestRepository<Repo> repo = createProject("repo"); |     TestRepository<Repo> repo = createProject("repo"); | ||||||
|     Change change1 = insert(repo, newChange(repo), userId); |     Change change1 = insert(repo, newChange(repo), userId); | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 David Pursehouse
					David Pursehouse