|
@@ -0,0 +1,179 @@
|
|
|
+/*
|
|
|
+ * Licensed to Elasticsearch under one or more contributor
|
|
|
+ * license agreements. See the NOTICE file distributed with
|
|
|
+ * this work for additional information regarding copyright
|
|
|
+ * ownership. Elasticsearch licenses this file to you 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 org.elasticsearch.index.mapper;
|
|
|
+
|
|
|
+import org.apache.lucene.analysis.standard.StandardAnalyzer;
|
|
|
+import org.apache.lucene.index.IndexReader;
|
|
|
+import org.apache.lucene.index.IndexWriterConfig;
|
|
|
+import org.apache.lucene.index.RandomIndexWriter;
|
|
|
+import org.apache.lucene.store.Directory;
|
|
|
+import org.elasticsearch.Version;
|
|
|
+import org.elasticsearch.cluster.metadata.IndexMetadata;
|
|
|
+import org.elasticsearch.common.CheckedConsumer;
|
|
|
+import org.elasticsearch.common.bytes.BytesReference;
|
|
|
+import org.elasticsearch.common.compress.CompressedXContent;
|
|
|
+import org.elasticsearch.common.settings.Settings;
|
|
|
+import org.elasticsearch.common.xcontent.XContentBuilder;
|
|
|
+import org.elasticsearch.common.xcontent.XContentFactory;
|
|
|
+import org.elasticsearch.common.xcontent.XContentType;
|
|
|
+import org.elasticsearch.common.xcontent.json.JsonXContent;
|
|
|
+import org.elasticsearch.index.IndexSettings;
|
|
|
+import org.elasticsearch.index.analysis.AnalyzerScope;
|
|
|
+import org.elasticsearch.index.analysis.IndexAnalyzers;
|
|
|
+import org.elasticsearch.index.analysis.NamedAnalyzer;
|
|
|
+import org.elasticsearch.index.query.QueryShardContext;
|
|
|
+import org.elasticsearch.index.similarity.SimilarityService;
|
|
|
+import org.elasticsearch.indices.IndicesModule;
|
|
|
+import org.elasticsearch.indices.mapper.MapperRegistry;
|
|
|
+import org.elasticsearch.plugins.MapperPlugin;
|
|
|
+import org.elasticsearch.plugins.Plugin;
|
|
|
+import org.elasticsearch.script.ScriptService;
|
|
|
+import org.elasticsearch.test.ESTestCase;
|
|
|
+
|
|
|
+import java.io.IOException;
|
|
|
+import java.util.Collection;
|
|
|
+import java.util.Map;
|
|
|
+
|
|
|
+import static java.util.Collections.emptyList;
|
|
|
+import static java.util.Collections.emptyMap;
|
|
|
+import static java.util.stream.Collectors.toList;
|
|
|
+import static org.mockito.Matchers.anyObject;
|
|
|
+import static org.mockito.Matchers.anyString;
|
|
|
+import static org.mockito.Mockito.mock;
|
|
|
+import static org.mockito.Mockito.when;
|
|
|
+
|
|
|
+public abstract class MapperServiceTestCase extends ESTestCase {
|
|
|
+
|
|
|
+ protected static final Settings SETTINGS = Settings.builder().put("index.version.created", Version.CURRENT).build();
|
|
|
+
|
|
|
+ protected Collection<? extends Plugin> getPlugins() {
|
|
|
+ return emptyList();
|
|
|
+ }
|
|
|
+
|
|
|
+ protected Settings getIndexSettings() {
|
|
|
+ return SETTINGS;
|
|
|
+ }
|
|
|
+
|
|
|
+ protected IndexAnalyzers createIndexAnalyzers(IndexSettings indexSettings) {
|
|
|
+ return new IndexAnalyzers(
|
|
|
+ Map.of("default", new NamedAnalyzer("default", AnalyzerScope.INDEX, new StandardAnalyzer())),
|
|
|
+ Map.of(),
|
|
|
+ Map.of()
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+ protected final String randomIndexOptions() {
|
|
|
+ return randomFrom("docs", "freqs", "positions", "offsets");
|
|
|
+ }
|
|
|
+
|
|
|
+ protected final DocumentMapper createDocumentMapper(XContentBuilder mappings) throws IOException {
|
|
|
+ return createMapperService(mappings).documentMapper();
|
|
|
+ }
|
|
|
+
|
|
|
+ protected final MapperService createMapperService(XContentBuilder mappings) throws IOException {
|
|
|
+ return createMapperService(getIndexSettings(), mappings);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Create a {@link MapperService} like we would for an index.
|
|
|
+ */
|
|
|
+ protected final MapperService createMapperService(Settings settings, XContentBuilder mapping) throws IOException {
|
|
|
+ IndexMetadata meta = IndexMetadata.builder("index")
|
|
|
+ .settings(Settings.builder().put("index.version.created", Version.CURRENT))
|
|
|
+ .numberOfReplicas(0)
|
|
|
+ .numberOfShards(1)
|
|
|
+ .build();
|
|
|
+ IndexSettings indexSettings = new IndexSettings(meta, settings);
|
|
|
+ MapperRegistry mapperRegistry = new IndicesModule(
|
|
|
+ getPlugins().stream().filter(p -> p instanceof MapperPlugin).map(p -> (MapperPlugin) p).collect(toList())
|
|
|
+ ).getMapperRegistry();
|
|
|
+ ScriptService scriptService = new ScriptService(settings, emptyMap(), emptyMap());
|
|
|
+ SimilarityService similarityService = new SimilarityService(indexSettings, scriptService, Map.of());
|
|
|
+ MapperService mapperService = new MapperService(
|
|
|
+ indexSettings,
|
|
|
+ createIndexAnalyzers(indexSettings),
|
|
|
+ xContentRegistry(),
|
|
|
+ similarityService,
|
|
|
+ mapperRegistry,
|
|
|
+ () -> { throw new UnsupportedOperationException(); },
|
|
|
+ () -> true
|
|
|
+ );
|
|
|
+ merge(mapperService, mapping);
|
|
|
+ return mapperService;
|
|
|
+ }
|
|
|
+
|
|
|
+ protected final void withLuceneIndex(
|
|
|
+ MapperService mapperService,
|
|
|
+ CheckedConsumer<RandomIndexWriter, IOException> builder,
|
|
|
+ CheckedConsumer<IndexReader, IOException> test
|
|
|
+ ) throws IOException {
|
|
|
+ try (
|
|
|
+ Directory dir = newDirectory();
|
|
|
+ RandomIndexWriter iw = new RandomIndexWriter(random(), dir, new IndexWriterConfig(mapperService.indexAnalyzer()))
|
|
|
+ ) {
|
|
|
+ builder.accept(iw);
|
|
|
+ try (IndexReader reader = iw.getReader()) {
|
|
|
+ test.accept(reader);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ protected final SourceToParse source(CheckedConsumer<XContentBuilder, IOException> build) throws IOException {
|
|
|
+ XContentBuilder builder = JsonXContent.contentBuilder().startObject();
|
|
|
+ build.accept(builder);
|
|
|
+ builder.endObject();
|
|
|
+ return new SourceToParse("test", "1", BytesReference.bytes(builder), XContentType.JSON);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Merge a new mapping into the one in the provided {@link MapperService}.
|
|
|
+ */
|
|
|
+ protected final void merge(MapperService mapperService, XContentBuilder mapping) throws IOException {
|
|
|
+ mapperService.merge(null, new CompressedXContent(BytesReference.bytes(mapping)), MapperService.MergeReason.MAPPING_UPDATE);
|
|
|
+ }
|
|
|
+
|
|
|
+ protected final XContentBuilder mapping(CheckedConsumer<XContentBuilder, IOException> buildFields) throws IOException {
|
|
|
+ XContentBuilder builder = XContentFactory.jsonBuilder().startObject().startObject("_doc").startObject("properties");
|
|
|
+ buildFields.accept(builder);
|
|
|
+ return builder.endObject().endObject().endObject();
|
|
|
+ }
|
|
|
+
|
|
|
+ protected final XContentBuilder fieldMapping(CheckedConsumer<XContentBuilder, IOException> buildField) throws IOException {
|
|
|
+ return mapping(b -> {
|
|
|
+ b.startObject("field");
|
|
|
+ buildField.accept(b);
|
|
|
+ b.endObject();
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ QueryShardContext createQueryShardContext(MapperService mapperService) {
|
|
|
+ QueryShardContext queryShardContext = mock(QueryShardContext.class);
|
|
|
+ when(queryShardContext.getMapperService()).thenReturn(mapperService);
|
|
|
+ when(queryShardContext.fieldMapper(anyString())).thenAnswer(inv -> mapperService.fieldType(inv.getArguments()[0].toString()));
|
|
|
+ when(queryShardContext.getIndexAnalyzers()).thenReturn(mapperService.getIndexAnalyzers());
|
|
|
+ when(queryShardContext.getSearchQuoteAnalyzer(anyObject())).thenCallRealMethod();
|
|
|
+ when(queryShardContext.getSearchAnalyzer(anyObject())).thenCallRealMethod();
|
|
|
+ when(queryShardContext.getIndexSettings()).thenReturn(mapperService.getIndexSettings());
|
|
|
+ when(queryShardContext.simpleMatchToIndexNames(anyObject())).thenAnswer(
|
|
|
+ inv -> mapperService.simpleMatchToFullName(inv.getArguments()[0].toString())
|
|
|
+ );
|
|
|
+ return queryShardContext;
|
|
|
+ }
|
|
|
+}
|