Convert completion, binary, boolean tests to MapperTestCase (#62004)

Also fixes a metadata serialization bug in CompletionFieldMapper.
This commit is contained in:
Alan Woodward 2020-09-07 10:10:44 +01:00 committed by Alan Woodward
parent 7e566ddd06
commit 1799c0c583
4 changed files with 453 additions and 837 deletions

View File

@ -188,6 +188,9 @@ public class CompletionFieldMapper extends ParametrizedFieldMapper {
this.contexts.getValue().toXContent(builder, ToXContent.EMPTY_PARAMS);
builder.endArray();
}
if (this.meta.getValue().isEmpty() == false) {
builder.field(this.meta.name, this.meta.getValue());
}
}
@Override

View File

@ -20,65 +20,40 @@
package org.elasticsearch.index.mapper;
import org.apache.lucene.util.BytesRef;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.bytes.BytesArray;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.compress.CompressedXContent;
import org.elasticsearch.common.compress.CompressorFactory;
import org.elasticsearch.common.io.stream.BytesStreamOutput;
import org.elasticsearch.common.io.stream.StreamOutput;
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.plugins.Plugin;
import org.elasticsearch.test.ESSingleNodeTestCase;
import org.elasticsearch.test.InternalSettingsPlugin;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collection;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.instanceOf;
public class BinaryFieldMapperTests extends ESSingleNodeTestCase {
public class BinaryFieldMapperTests extends MapperTestCase {
@Override
protected Collection<Class<? extends Plugin>> getPlugins() {
return pluginList(InternalSettingsPlugin.class);
protected void minimalMapping(XContentBuilder b) throws IOException {
b.field("type", "binary");
}
public void testDefaultMapping() throws Exception {
XContentBuilder mapping = XContentFactory.jsonBuilder().startObject().startObject("type")
.startObject("properties")
.startObject("field")
.field("type", "binary")
.endObject()
.endObject()
.endObject().endObject();
MapperService mapperService = createIndex("test", Settings.EMPTY, "type", mapping).mapperService();
MapperService mapperService = createMapperService(fieldMapping(this::minimalMapping));
FieldMapper mapper = (FieldMapper) mapperService.documentMapper().mappers().getMapper("field");
assertThat(mapper, instanceOf(BinaryFieldMapper.class));
assertThat(mapper.fieldType.stored(), equalTo(false));
assertEquals(Strings.toString(mapping), Strings.toString(mapperService.documentMapper()));
}
public void testStoredValue() throws IOException {
XContentBuilder mapping = XContentFactory.jsonBuilder().startObject().startObject("type")
.startObject("properties")
.startObject("field")
.field("type", "binary")
.field("store", true)
.endObject()
.endObject()
.endObject().endObject();
MapperService mapperService = createIndex("test", Settings.EMPTY, "type", mapping).mapperService();
MapperService mapperService = createMapperService(fieldMapping(b -> {
minimalMapping(b);
b.field("store", "true");
}));
// case 1: a simple binary value
final byte[] binaryValue1 = new byte[100];
@ -93,9 +68,7 @@ public class BinaryFieldMapperTests extends ESSingleNodeTestCase {
assertTrue(CompressorFactory.isCompressed(new BytesArray(binaryValue2)));
for (byte[] value : Arrays.asList(binaryValue1, binaryValue2)) {
ParsedDocument doc = mapperService.documentMapper().parse(new SourceToParse("test", "type", "id",
BytesReference.bytes(XContentFactory.jsonBuilder().startObject().field("field", value).endObject()),
XContentType.JSON));
ParsedDocument doc = mapperService.documentMapper().parse(source(b -> b.field("field", value)));
BytesRef indexedValue = doc.rootDoc().getBinaryValue("field");
assertEquals(new BytesRef(value), indexedValue);
@ -104,16 +77,4 @@ public class BinaryFieldMapperTests extends ESSingleNodeTestCase {
assertEquals(new BytesArray(value), originalValue);
}
}
public void testEmptyName() throws IOException {
// after 5.x
String mapping = Strings.toString(XContentFactory.jsonBuilder().startObject().startObject("type")
.startObject("properties").startObject("").field("type", "binary").endObject().endObject()
.endObject().endObject());
IllegalArgumentException e = expectThrows(IllegalArgumentException.class,
() -> createIndex("test").mapperService().documentMapperParser().parse("type", new CompressedXContent(mapping))
);
assertThat(e.getMessage(), containsString("name cannot be empty string"));
}
}

View File

@ -19,100 +19,55 @@
package org.elasticsearch.index.mapper;
import org.apache.lucene.analysis.MockAnalyzer;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.DocValuesType;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.index.IndexableField;
import org.apache.lucene.index.LeafReader;
import org.apache.lucene.index.SortedNumericDocValues;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.BoostQuery;
import org.apache.lucene.search.TermQuery;
import org.apache.lucene.store.ByteBuffersDirectory;
import org.apache.lucene.store.Directory;
import org.apache.lucene.util.BytesRef;
import org.elasticsearch.Version;
import org.elasticsearch.cluster.metadata.IndexMetadata;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.collect.List;
import org.elasticsearch.common.compress.CompressedXContent;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.IndexService;
import org.elasticsearch.index.mapper.MapperService.MergeReason;
import org.elasticsearch.index.mapper.ParseContext.Document;
import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.test.ESSingleNodeTestCase;
import org.elasticsearch.test.InternalSettingsPlugin;
import org.junit.Before;
import java.io.IOException;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import static org.elasticsearch.index.mapper.FieldMapperTestCase.fetchSourceValue;
import static org.hamcrest.Matchers.containsString;
public class BooleanFieldMapperTests extends ESSingleNodeTestCase {
private IndexService indexService;
private DocumentMapperParser parser;
@Before
public void setup() {
indexService = createIndex("test");
parser = indexService.mapperService().documentMapperParser();
}
public class BooleanFieldMapperTests extends MapperTestCase {
@Override
protected Collection<Class<? extends Plugin>> getPlugins() {
return pluginList(InternalSettingsPlugin.class);
protected void minimalMapping(XContentBuilder b) throws IOException {
b.field("type", "boolean");
}
public void testDefaults() throws IOException {
String mapping = Strings.toString(XContentFactory.jsonBuilder().startObject().startObject("type")
.startObject("properties").startObject("field").field("type", "boolean").endObject().endObject()
.endObject().endObject());
DocumentMapper defaultMapper = parser.parse("type", new CompressedXContent(mapping));
MapperService mapperService = createMapperService(fieldMapping(this::minimalMapping));
ParsedDocument doc = mapperService.documentMapper().parse(source(b -> b.field("field", true)));
ParsedDocument doc = defaultMapper.parse(new SourceToParse("test", "type", "1", BytesReference
.bytes(XContentFactory.jsonBuilder()
.startObject()
.field("field", true)
.endObject()),
XContentType.JSON));
try (Directory dir = new ByteBuffersDirectory();
IndexWriter w = new IndexWriter(dir, new IndexWriterConfig(new MockAnalyzer(random())))) {
w.addDocuments(doc.docs());
try (DirectoryReader reader = DirectoryReader.open(w)) {
final LeafReader leaf = reader.leaves().get(0).reader();
// boolean fields are indexed and have doc values by default
assertEquals(new BytesRef("T"), leaf.terms("field").iterator().next());
SortedNumericDocValues values = leaf.getSortedNumericDocValues("field");
assertNotNull(values);
assertTrue(values.advanceExact(0));
assertEquals(1, values.docValueCount());
assertEquals(1, values.nextValue());
}
}
withLuceneIndex(mapperService, iw -> iw.addDocument(doc.rootDoc()), reader -> {
final LeafReader leaf = reader.leaves().get(0).reader();
// boolean fields are indexed and have doc values by default
assertEquals(new BytesRef("T"), leaf.terms("field").iterator().next());
SortedNumericDocValues values = leaf.getSortedNumericDocValues("field");
assertNotNull(values);
assertTrue(values.advanceExact(0));
assertEquals(1, values.docValueCount());
assertEquals(1, values.nextValue());
});
}
public void testSerialization() throws IOException {
String mapping = Strings.toString(XContentFactory.jsonBuilder().startObject().startObject("type")
.startObject("properties").startObject("field").field("type", "boolean").endObject().endObject()
.endObject().endObject());
DocumentMapper defaultMapper = parser.parse("type", new CompressedXContent(mapping));
DocumentMapper defaultMapper = createDocumentMapper(fieldMapping(this::minimalMapping));
Mapper mapper = defaultMapper.mappers().getMapper("field");
XContentBuilder builder = XContentFactory.jsonBuilder().startObject();
mapper.toXContent(builder, ToXContent.EMPTY_PARAMS);
@ -120,15 +75,11 @@ public class BooleanFieldMapperTests extends ESSingleNodeTestCase {
assertEquals("{\"field\":{\"type\":\"boolean\"}}", Strings.toString(builder));
// now change some parameters
mapping = Strings.toString(XContentFactory.jsonBuilder().startObject().startObject("type")
.startObject("properties").startObject("field")
.field("type", "boolean")
.field("doc_values", "false")
.field("null_value", true)
.endObject().endObject()
.endObject().endObject());
defaultMapper = parser.parse("type", new CompressedXContent(mapping));
defaultMapper = createDocumentMapper(fieldMapping(b -> {
b.field("type", "boolean");
b.field("doc_values", false);
b.field("null_value", true);
}));
mapper = defaultMapper.mappers().getMapper("field");
builder = XContentFactory.jsonBuilder().startObject();
mapper.toXContent(builder, ToXContent.EMPTY_PARAMS);
@ -137,109 +88,67 @@ public class BooleanFieldMapperTests extends ESSingleNodeTestCase {
}
public void testParsesBooleansStrict() throws IOException {
String mapping = Strings.toString(XContentFactory.jsonBuilder()
.startObject()
.startObject("type")
.startObject("properties")
.startObject("field")
.field("type", "boolean")
.endObject()
.endObject()
.endObject()
.endObject());
DocumentMapper defaultMapper = parser.parse("type", new CompressedXContent(mapping));
DocumentMapper defaultMapper = createDocumentMapper(fieldMapping(this::minimalMapping));
// omit "false"/"true" here as they should still be parsed correctly
String randomValue = randomFrom("off", "no", "0", "on", "yes", "1");
BytesReference source = BytesReference.bytes(XContentFactory.jsonBuilder()
.startObject()
.field("field", randomValue)
.endObject());
MapperParsingException ex = expectThrows(MapperParsingException.class,
() -> defaultMapper.parse(new SourceToParse("test", "type", "1", source, XContentType.JSON)));
assertEquals("failed to parse field [field] of type [boolean] in document with id '1'. " +
"Preview of field's value: '" + randomValue + "'", ex.getMessage());
for (String value : new String[]{"off", "no", "0", "on", "yes", "1"}) {
MapperParsingException ex = expectThrows(MapperParsingException.class,
() -> defaultMapper.parse(source(b -> b.field("field", value))));
assertEquals("failed to parse field [field] of type [boolean] in document with id '1'. " +
"Preview of field's value: '" + value + "'", ex.getMessage());
}
}
public void testParsesBooleansNestedStrict() throws IOException {
String mapping = Strings.toString(XContentFactory.jsonBuilder()
.startObject()
.startObject("type")
.startObject("properties")
.startObject("field")
.field("type", "boolean")
.endObject()
.endObject()
.endObject()
.endObject());
DocumentMapper defaultMapper = parser.parse("type", new CompressedXContent(mapping));
// omit "false"/"true" here as they should still be parsed correctly
String randomValue = "no";
BytesReference source = BytesReference.bytes(XContentFactory.jsonBuilder()
.startObject()
.startObject("field")
.field("inner_field", randomValue)
.endObject()
.endObject());
DocumentMapper defaultMapper = createDocumentMapper(fieldMapping(this::minimalMapping));
MapperParsingException ex = expectThrows(MapperParsingException.class,
() -> defaultMapper.parse(new SourceToParse("test", "type", "1", source, XContentType.JSON)));
() -> defaultMapper.parse(source(b -> {
b.startObject("field");
{
b.field("inner_field", "no");
}
b.endObject();
})));
assertEquals("failed to parse field [field] of type [boolean] in document with id '1'. " +
"Preview of field's value: '{inner_field=" + randomValue + "}'", ex.getMessage());
"Preview of field's value: '{inner_field=no}'", ex.getMessage());
}
public void testMultiFields() throws IOException {
String mapping = Strings.toString(XContentFactory.jsonBuilder().startObject().startObject("type")
.startObject("properties")
.startObject("field")
.field("type", "boolean")
.startObject("fields")
.startObject("as_string")
.field("type", "keyword")
.endObject()
.endObject()
.endObject().endObject()
.endObject().endObject());
DocumentMapper mapper = indexService.mapperService()
.merge("type", new CompressedXContent(mapping), MapperService.MergeReason.MAPPING_UPDATE);
assertEquals(mapping, mapper.mappingSource().toString());
BytesReference source = BytesReference.bytes(XContentFactory.jsonBuilder()
.startObject()
.field("field", false)
.endObject());
ParsedDocument doc = mapper.parse(new SourceToParse("test", "type", "1", source, XContentType.JSON));
DocumentMapper mapper = createDocumentMapper(fieldMapping(b -> {
b.field("type", "boolean");
b.startObject("fields");
{
b.startObject("as_string").field("type", "keyword").endObject();
}
b.endObject();
}));
ParsedDocument doc = mapper.parse(source(b -> b.field("field", false)));
assertNotNull(doc.rootDoc().getField("field.as_string"));
}
public void testDocValues() throws Exception {
String mapping = Strings.toString(XContentFactory.jsonBuilder().startObject().startObject("type")
.startObject("properties")
.startObject("bool1")
.field("type", "boolean")
.endObject()
.startObject("bool2")
.field("type", "boolean")
.field("index", false)
.endObject()
.startObject("bool3")
.field("type", "boolean")
.field("index", true)
.endObject()
.endObject()
.endObject().endObject());
DocumentMapper defaultMapper = indexService.mapperService().documentMapperParser().parse("type", new CompressedXContent(mapping));
DocumentMapper defaultMapper = createDocumentMapper(mapping(b -> {
b.startObject("bool1").field("type", "boolean").endObject();
b.startObject("bool2");
{
b.field("type", "boolean");
b.field("index", false);
}
b.endObject();
b.startObject("bool3");
{
b.field("type", "boolean");
b.field("index", true);
}
b.endObject();
}));
ParsedDocument parsedDoc = defaultMapper.parse(source(b -> {
b.field("bool1", true);
b.field("bool2", true);
b.field("bool3", true);
}));
ParsedDocument parsedDoc = defaultMapper.parse(new SourceToParse("test", "type", "1", BytesReference
.bytes(XContentFactory.jsonBuilder()
.startObject()
.field("bool1", true)
.field("bool2", true)
.field("bool3", true)
.endObject()),
XContentType.JSON));
Document doc = parsedDoc.rootDoc();
IndexableField[] fields = doc.getFields("bool1");
assertEquals(2, fields.length);
@ -253,50 +162,13 @@ public class BooleanFieldMapperTests extends ESSingleNodeTestCase {
assertEquals(DocValuesType.SORTED_NUMERIC, fields[1].fieldType().docValuesType());
}
public void testEmptyName() throws IOException {
// after 5.x
String mapping = Strings.toString(XContentFactory.jsonBuilder().startObject().startObject("type")
.startObject("properties").startObject("").field("type", "boolean").endObject().endObject()
.endObject().endObject());
IllegalArgumentException e = expectThrows(IllegalArgumentException.class,
() -> parser.parse("type", new CompressedXContent(mapping))
);
assertThat(e.getMessage(), containsString("name cannot be empty string"));
}
public void testMeta() throws Exception {
String mapping = Strings.toString(XContentFactory.jsonBuilder().startObject().startObject("_doc")
.startObject("properties").startObject("field").field("type", "boolean")
.field("meta", Collections.singletonMap("foo", "bar"))
.endObject().endObject().endObject().endObject());
DocumentMapper mapper = indexService.mapperService().merge("_doc",
new CompressedXContent(mapping), MergeReason.MAPPING_UPDATE);
assertEquals(mapping, mapper.mappingSource().toString());
String mapping2 = Strings.toString(XContentFactory.jsonBuilder().startObject().startObject("_doc")
.startObject("properties").startObject("field").field("type", "boolean")
.endObject().endObject().endObject().endObject());
mapper = indexService.mapperService().merge("_doc",
new CompressedXContent(mapping2), MergeReason.MAPPING_UPDATE);
assertEquals(mapping2, mapper.mappingSource().toString());
String mapping3 = Strings.toString(XContentFactory.jsonBuilder().startObject().startObject("_doc")
.startObject("properties").startObject("field").field("type", "boolean")
.field("meta", Collections.singletonMap("baz", "quux"))
.endObject().endObject().endObject().endObject());
mapper = indexService.mapperService().merge("_doc",
new CompressedXContent(mapping3), MergeReason.MAPPING_UPDATE);
assertEquals(mapping3, mapper.mappingSource().toString());
}
public void testBoosts() throws Exception {
String mapping = "{\"_doc\":{\"properties\":{\"field\":{\"type\":\"boolean\",\"boost\":2.0}}}}";
DocumentMapper mapper = indexService.mapperService().merge("_doc", new CompressedXContent(mapping), MergeReason.MAPPING_UPDATE);
assertEquals(mapping, mapper.mappingSource().toString());
MapperService mapperService = createMapperService(fieldMapping(b -> {
minimalMapping(b);
b.field("boost", 2.0);
}));
MappedFieldType ft = indexService.mapperService().fieldType("field");
MappedFieldType ft = mapperService.fieldType("field");
assertEquals(new BoostQuery(new TermQuery(new Term("field", "T")), 2.0f), ft.termQuery("true", null));
}