Warn on badly-formed null values for date and IP field mappers ()

In  we changed when null_value was parsed for ip and date fields. Previously,
the null value was stored as a string, and parsed into a date or InetAddress whenever
a document containing a null value was encountered. Now, the values are parsed when
the mappings are built, which means that bad values are detected up front; if you try and
add a mapping with a badly-parsed ip or date for a null_value, the mapping will be
rejected.

This causes problems for upgrades in the case when you have a badly-formed null_value
in a pre-7.9 cluster. This commit fixes the upgrade case by changing the logic to only
logging a warning on the badly formed value, replicating the earlier behaviour.

Fixes 
This commit is contained in:
Alan Woodward 2020-09-17 16:18:52 +01:00 committed by Alan Woodward
parent 4d272a2a00
commit 91e2330529
7 changed files with 109 additions and 204 deletions
server/src
main/java/org/elasticsearch/index/mapper
test/java/org/elasticsearch
test/framework/src/main/java/org/elasticsearch/index/mapper

@ -36,6 +36,7 @@ import org.elasticsearch.Version;
import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.geo.ShapeRelation;
import org.elasticsearch.common.joda.Joda;
import org.elasticsearch.common.logging.DeprecationLogger;
import org.elasticsearch.common.lucene.BytesRefs;
import org.elasticsearch.common.time.DateFormatter;
import org.elasticsearch.common.time.DateFormatters;
@ -73,6 +74,8 @@ import static org.elasticsearch.common.time.DateUtils.toLong;
/** A {@link FieldMapper} for dates. */
public final class DateFieldMapper extends ParametrizedFieldMapper {
private static final DeprecationLogger DEPRECATION_LOGGER = DeprecationLogger.getLogger(DateFieldMapper.class);
public static final String CONTENT_TYPE = "date";
public static final String DATE_NANOS_CONTENT_TYPE = "date_nanos";
public static final DateFormatter DEFAULT_DATE_TIME_FORMATTER = DateFormatter.forPattern("strict_date_optional_time||epoch_millis");
@ -205,8 +208,8 @@ public final class DateFieldMapper extends ParametrizedFieldMapper {
private final Resolution resolution;
private final Version indexCreatedVersion;
public Builder(String name, Version indexCreatedVersion, Resolution resolution,
DateFormatter dateFormatter, boolean ignoreMalformedByDefault) {
public Builder(String name, Resolution resolution, DateFormatter dateFormatter,
boolean ignoreMalformedByDefault, Version indexCreatedVersion) {
super(name);
this.resolution = resolution;
this.indexCreatedVersion = indexCreatedVersion;
@ -241,9 +244,10 @@ public final class DateFieldMapper extends ParametrizedFieldMapper {
}
try {
return fieldType.parse(nullValue.getValue());
}
catch (Exception e) {
throw new MapperParsingException("Error parsing [null_value] on field [" + name() + "]: " + e.getMessage(), e);
} catch (Exception e) {
DEPRECATION_LOGGER.deprecate("date_mapper_null_field", "Error parsing [" + nullValue.getValue()
+ "] as date in [null_value] on field [" + name() + "]); [null_value] will be ignored");
return null;
}
}
@ -254,18 +258,18 @@ public final class DateFieldMapper extends ParametrizedFieldMapper {
ft.setBoost(boost.getValue());
Long nullTimestamp = parseNullValue(ft);
return new DateFieldMapper(name, ft, multiFieldsBuilder.build(this, context),
copyTo.build(), nullTimestamp, resolution, indexCreatedVersion, this);
copyTo.build(), nullTimestamp, resolution, this);
}
}
public static final TypeParser MILLIS_PARSER = new TypeParser((n, c) -> {
boolean ignoreMalformedByDefault = IGNORE_MALFORMED_SETTING.get(c.getSettings());
return new Builder(n, c.indexVersionCreated(), Resolution.MILLISECONDS, c.getDateFormatter(), ignoreMalformedByDefault);
return new Builder(n, Resolution.MILLISECONDS, c.getDateFormatter(), ignoreMalformedByDefault, c.indexVersionCreated());
});
public static final TypeParser NANOS_PARSER = new TypeParser((n, c) -> {
boolean ignoreMalformedByDefault = IGNORE_MALFORMED_SETTING.get(c.getSettings());
return new Builder(n, c.indexVersionCreated(), Resolution.NANOSECONDS, c.getDateFormatter(), ignoreMalformedByDefault);
return new Builder(n, Resolution.NANOSECONDS, c.getDateFormatter(), ignoreMalformedByDefault, c.indexVersionCreated());
});
public static final class DateFieldType extends MappedFieldType {
@ -525,9 +529,9 @@ public final class DateFieldMapper extends ParametrizedFieldMapper {
private final Long nullValue;
private final String nullValueAsString;
private final Resolution resolution;
private final Version indexCreatedVersion;
private final boolean ignoreMalformedByDefault;
private final Version indexCreatedVersion;
private DateFieldMapper(
String simpleName,
@ -536,7 +540,6 @@ public final class DateFieldMapper extends ParametrizedFieldMapper {
CopyTo copyTo,
Long nullValue,
Resolution resolution,
Version indexCreatedVersion,
Builder builder) {
super(simpleName, mappedFieldType, multiFields, copyTo);
this.store = builder.store.getValue();
@ -548,13 +551,13 @@ public final class DateFieldMapper extends ParametrizedFieldMapper {
this.nullValueAsString = builder.nullValue.getValue();
this.nullValue = nullValue;
this.resolution = resolution;
this.indexCreatedVersion = indexCreatedVersion;
this.ignoreMalformedByDefault = builder.ignoreMalformed.getDefaultValue();
this.indexCreatedVersion = builder.indexCreatedVersion;
}
@Override
public ParametrizedFieldMapper.Builder getMergeBuilder() {
return new Builder(simpleName(), indexCreatedVersion, resolution, null, ignoreMalformedByDefault).init(this);
return new Builder(simpleName(), resolution, null, ignoreMalformedByDefault, indexCreatedVersion).init(this);
}
@Override

@ -696,9 +696,8 @@ final class DocumentParser {
= context.root().findTemplateBuilder(context, currentFieldName, dateTimeFormatter);
if (builder == null) {
boolean ignoreMalformed = IGNORE_MALFORMED_SETTING.get(context.indexSettings().getSettings());
Version indexCreatedVersion = context.indexSettings().getIndexVersionCreated();
builder = new DateFieldMapper.Builder(currentFieldName, indexCreatedVersion,
DateFieldMapper.Resolution.MILLISECONDS, dateTimeFormatter, ignoreMalformed);
builder = new DateFieldMapper.Builder(currentFieldName, DateFieldMapper.Resolution.MILLISECONDS,
dateTimeFormatter, ignoreMalformed, Version.indexCreated(context.indexSettings().getSettings()));
}
return builder;

@ -30,10 +30,11 @@ import org.apache.lucene.search.Query;
import org.apache.lucene.search.TermQuery;
import org.apache.lucene.util.ArrayUtil;
import org.apache.lucene.util.BytesRef;
import org.elasticsearch.Version;
import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.collect.Tuple;
import org.elasticsearch.common.logging.DeprecationLogger;
import org.elasticsearch.common.network.InetAddresses;
import org.elasticsearch.common.network.NetworkAddress;
import org.elasticsearch.index.fielddata.IndexFieldData;
import org.elasticsearch.index.fielddata.ScriptDocValues;
import org.elasticsearch.index.fielddata.plain.SortedSetOrdinalsIndexFieldData;
@ -55,6 +56,8 @@ import java.util.function.Supplier;
/** A {@link FieldMapper} for ip addresses. */
public class IpFieldMapper extends ParametrizedFieldMapper {
private static final DeprecationLogger DEPRECATION_LOGGER = DeprecationLogger.getLogger(IpFieldMapper.class);
public static final String CONTENT_TYPE = "ip";
private static IpFieldMapper toType(FieldMapper in) {
@ -68,36 +71,44 @@ public class IpFieldMapper extends ParametrizedFieldMapper {
private final Parameter<Boolean> stored = Parameter.storeParam(m -> toType(m).stored, false);
private final Parameter<Boolean> ignoreMalformed;
private final Parameter<InetAddress> nullValue = new Parameter<>("null_value", false, () -> null,
(n, c, o) -> o == null ? null : InetAddresses.forString(o.toString()), m -> toType(m).nullValue)
.setSerializer((b, f, v) -> {
if (v == null) {
b.nullField(f);
} else {
b.field(f, InetAddresses.toAddrString(v));
}
}, NetworkAddress::format)
.acceptsNull();
private final Parameter<String> nullValue
= Parameter.stringParam("null_value", false, m -> toType(m).nullValueAsString, null).acceptsNull();
private final Parameter<Map<String, String>> meta = Parameter.metaParam();
private final boolean ignoreMalformedByDefault;
private final Version indexCreatedVersion;
public Builder(String name, boolean ignoreMalformedByDefault) {
public Builder(String name, boolean ignoreMalformedByDefault, Version indexCreatedVersion) {
super(name);
this.ignoreMalformedByDefault = ignoreMalformedByDefault;
this.indexCreatedVersion = indexCreatedVersion;
this.ignoreMalformed
= Parameter.boolParam("ignore_malformed", true, m -> toType(m).ignoreMalformed, ignoreMalformedByDefault);
}
Builder nullValue(InetAddress nullValue) {
Builder nullValue(String nullValue) {
this.nullValue.setValue(nullValue);
return this;
}
private InetAddress parseNullValue() {
String nullValueAsString = nullValue.getValue();
if (nullValueAsString == null) {
return null;
}
try {
return InetAddresses.forString(nullValueAsString);
} catch (Exception e) {
DEPRECATION_LOGGER.deprecate("ip_mapper_null_field", "Error parsing [" + nullValue.getValue()
+ "] as IP in [null_value] on field [" + name() + "]); [null_value] will be ignored");
return null;
}
}
@Override
protected List<Parameter<?>> getParameters() {
return Arrays.asList(indexed, hasDocValues, stored, ignoreMalformed, nullValue);
return Arrays.asList(indexed, hasDocValues, stored, ignoreMalformed, nullValue, meta);
}
@Override
@ -111,7 +122,7 @@ public class IpFieldMapper extends ParametrizedFieldMapper {
public static final TypeParser PARSER = new TypeParser((n, c) -> {
boolean ignoreMalformedByDefault = IGNORE_MALFORMED_SETTING.get(c.getSettings());
return new Builder(n, ignoreMalformedByDefault);
return new Builder(n, ignoreMalformedByDefault, c.indexVersionCreated());
});
public static final class IpFieldType extends SimpleMappedFieldType {
@ -322,9 +333,12 @@ public class IpFieldMapper extends ParametrizedFieldMapper {
private final boolean hasDocValues;
private final boolean stored;
private final boolean ignoreMalformed;
private final InetAddress nullValue;
private final String nullValueAsString;
private final boolean ignoreMalformedByDefault;
private final Version indexCreatedVersion;
private IpFieldMapper(
String simpleName,
@ -338,7 +352,9 @@ public class IpFieldMapper extends ParametrizedFieldMapper {
this.hasDocValues = builder.hasDocValues.getValue();
this.stored = builder.stored.getValue();
this.ignoreMalformed = builder.ignoreMalformed.getValue();
this.nullValue = builder.nullValue.getValue();
this.nullValue = builder.parseNullValue();
this.nullValueAsString = builder.nullValue.getValue();
this.indexCreatedVersion = builder.indexCreatedVersion;
}
@Override
@ -424,6 +440,6 @@ public class IpFieldMapper extends ParametrizedFieldMapper {
@Override
public ParametrizedFieldMapper.Builder getMergeBuilder() {
return new Builder(simpleName(), ignoreMalformedByDefault).init(this);
return new Builder(simpleName(), ignoreMalformedByDefault, indexCreatedVersion).init(this);
}
}

@ -554,7 +554,7 @@ public class MetadataRolloverServiceTests extends ESTestCase {
try {
Mapper.BuilderContext builderContext = new Mapper.BuilderContext(Settings.EMPTY, new ContentPath(0));
DateFieldMapper dateFieldMapper
= new DateFieldMapper.Builder("@timestamp", Version.CURRENT, DateFieldMapper.Resolution.MILLISECONDS, null, false)
= new DateFieldMapper.Builder("@timestamp", DateFieldMapper.Resolution.MILLISECONDS, null, false, Version.CURRENT)
.build(builderContext);
MetadataFieldMapper mockedTimestampField = mock(MetadataFieldMapper.class);
when(mockedTimestampField.name()).thenReturn("_data_stream_timestamp");

@ -40,7 +40,6 @@ import java.util.HashMap;
import java.util.Map;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.notNullValue;
public class DateFieldMapperTests extends MapperTestCase {
@ -221,14 +220,10 @@ public class DateFieldMapperTests extends MapperTestCase {
assertFalse(dvField.fieldType().stored());
}
public void testBadNullValue() {
public void testBadNullValue() throws IOException {
createDocumentMapper(fieldMapping(b -> b.field("type", "date").field("null_value", "foo")));
MapperParsingException e = expectThrows(MapperParsingException.class,
() -> createDocumentMapper(fieldMapping(b -> b.field("type", "date").field("null_value", ""))));
assertThat(e.getMessage(),
equalTo("Failed to parse mapping [_doc]: Error parsing [null_value] on field [field]: cannot parse empty date"));
}
assertWarnings("Error parsing [foo] as date in [null_value] on field [field]); [null_value] will be ignored"); }
public void testNullConfigValuesFail() {
Exception e = expectThrows(MapperParsingException.class,
@ -364,7 +359,8 @@ public class DateFieldMapperTests extends MapperTestCase {
mapping.put("null_value", nullValue);
}
DateFieldMapper.Builder builder = new DateFieldMapper.Builder("field", Version.CURRENT, resolution, null, false);
DateFieldMapper.Builder builder
= new DateFieldMapper.Builder("field", resolution, null, false, Version.CURRENT);
builder.parse("field", null, mapping);
return builder.build(context);
}

@ -28,61 +28,28 @@ import org.apache.lucene.search.TermQuery;
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.network.InetAddresses;
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.termvectors.TermVectorsService;
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.net.InetAddress;
import java.util.Collection;
import static org.elasticsearch.index.mapper.FieldMapperTestCase.fetchSourceValue;
import static org.hamcrest.Matchers.containsString;
public class IpFieldMapperTests extends ESSingleNodeTestCase {
IndexService indexService;
DocumentMapperParser parser;
@Before
public void setup() {
indexService = createIndex("test");
parser = indexService.mapperService().documentMapperParser();
}
public class IpFieldMapperTests extends MapperTestCase {
@Override
protected Collection<Class<? extends Plugin>> getPlugins() {
return pluginList(InternalSettingsPlugin.class);
protected void minimalMapping(XContentBuilder b) throws IOException {
b.field("type", "ip");
}
public void testDefaults() throws Exception {
String mapping = Strings.toString(XContentFactory.jsonBuilder().startObject().startObject("type")
.startObject("properties").startObject("field").field("type", "ip").endObject().endObject()
.endObject().endObject());
DocumentMapper mapper = createDocumentMapper(fieldMapping(this::minimalMapping));
DocumentMapper mapper = parser.parse("type", new CompressedXContent(mapping));
assertEquals(mapping, mapper.mappingSource().toString());
ParsedDocument doc = mapper.parse(new SourceToParse("test", "type", "1", BytesReference
.bytes(XContentFactory.jsonBuilder()
.startObject()
.field("field", "::1")
.endObject()),
XContentType.JSON));
ParsedDocument doc = mapper.parse(source(b -> b.field("field", "::1")));
IndexableField[] fields = doc.rootDoc().getFields("field");
assertEquals(2, fields.length);
@ -98,20 +65,13 @@ public class IpFieldMapperTests extends ESSingleNodeTestCase {
}
public void testNotIndexed() throws Exception {
String mapping = Strings.toString(XContentFactory.jsonBuilder().startObject().startObject("type")
.startObject("properties").startObject("field").field("type", "ip").field("index", false).endObject().endObject()
.endObject().endObject());
DocumentMapper mapper = parser.parse("type", new CompressedXContent(mapping));
DocumentMapper mapper = createDocumentMapper(fieldMapping(b -> {
b.field("type", "ip");
b.field("index", false);
}));
assertEquals(mapping, mapper.mappingSource().toString());
ParsedDocument doc = mapper.parse(new SourceToParse("test", "type", "1", BytesReference
.bytes(XContentFactory.jsonBuilder()
.startObject()
.field("field", "::1")
.endObject()),
XContentType.JSON));
ParsedDocument doc = mapper.parse(source(b -> b.field("field", "::1")));
IndexableField[] fields = doc.rootDoc().getFields("field");
assertEquals(1, fields.length);
@ -120,20 +80,13 @@ public class IpFieldMapperTests extends ESSingleNodeTestCase {
}
public void testNoDocValues() throws Exception {
String mapping = Strings.toString(XContentFactory.jsonBuilder().startObject().startObject("type")
.startObject("properties").startObject("field").field("type", "ip").field("doc_values", false).endObject().endObject()
.endObject().endObject());
DocumentMapper mapper = parser.parse("type", new CompressedXContent(mapping));
DocumentMapper mapper = createDocumentMapper(fieldMapping(b -> {
b.field("type", "ip");
b.field("doc_values", false);
}));
assertEquals(mapping, mapper.mappingSource().toString());
ParsedDocument doc = mapper.parse(new SourceToParse("test", "type", "1", BytesReference
.bytes(XContentFactory.jsonBuilder()
.startObject()
.field("field", "::1")
.endObject()),
XContentType.JSON));
ParsedDocument doc = mapper.parse(source(b -> b.field("field", "::1")));
IndexableField[] fields = doc.rootDoc().getFields("field");
assertEquals(1, fields.length);
@ -151,20 +104,13 @@ public class IpFieldMapperTests extends ESSingleNodeTestCase {
}
public void testStore() throws Exception {
String mapping = Strings.toString(XContentFactory.jsonBuilder().startObject().startObject("type")
.startObject("properties").startObject("field").field("type", "ip").field("store", true).endObject().endObject()
.endObject().endObject());
DocumentMapper mapper = parser.parse("type", new CompressedXContent(mapping));
DocumentMapper mapper = createDocumentMapper(fieldMapping(b -> {
b.field("type", "ip");
b.field("store", true);
}));
assertEquals(mapping, mapper.mappingSource().toString());
ParsedDocument doc = mapper.parse(new SourceToParse("test", "type", "1", BytesReference
.bytes(XContentFactory.jsonBuilder()
.startObject()
.field("field", "::1")
.endObject()),
XContentType.JSON));
ParsedDocument doc = mapper.parse(source(b -> b.field("field", "::1")));
IndexableField[] fields = doc.rootDoc().getFields("field");
assertEquals(3, fields.length);
@ -179,35 +125,19 @@ public class IpFieldMapperTests extends ESSingleNodeTestCase {
}
public void testIgnoreMalformed() throws Exception {
String mapping = Strings.toString(XContentFactory.jsonBuilder().startObject().startObject("type")
.startObject("properties").startObject("field").field("type", "ip").endObject().endObject()
.endObject().endObject());
DocumentMapper mapper = parser.parse("type", new CompressedXContent(mapping));
DocumentMapper mapper = createDocumentMapper(fieldMapping(this::minimalMapping));
assertEquals(mapping, mapper.mappingSource().toString());
ThrowingRunnable runnable = () -> mapper.parse(new SourceToParse("test", "type", "1", BytesReference
.bytes(XContentFactory.jsonBuilder()
.startObject()
.field("field", ":1")
.endObject()),
XContentType.JSON));
ThrowingRunnable runnable = () -> mapper.parse(source(b -> b.field("field", ":1")));
MapperParsingException e = expectThrows(MapperParsingException.class, runnable);
assertThat(e.getCause().getMessage(), containsString("':1' is not an IP string literal"));
mapping = Strings.toString(XContentFactory.jsonBuilder().startObject().startObject("type")
.startObject("properties").startObject("field").field("type", "ip").field("ignore_malformed", true).endObject().endObject()
.endObject().endObject());
DocumentMapper mapper2 = createDocumentMapper(fieldMapping(b -> {
b.field("type", "ip");
b.field("ignore_malformed", true);
}));
DocumentMapper mapper2 = parser.parse("type", new CompressedXContent(mapping));
ParsedDocument doc = mapper2.parse(new SourceToParse("test", "type", "1", BytesReference
.bytes(XContentFactory.jsonBuilder()
.startObject()
.field("field", ":1")
.endObject()),
XContentType.JSON));
ParsedDocument doc = mapper2.parse(source(b -> b.field("field", ":1")));
IndexableField[] fields = doc.rootDoc().getFields("field");
assertEquals(0, fields.length);
@ -215,45 +145,19 @@ public class IpFieldMapperTests extends ESSingleNodeTestCase {
}
public void testNullValue() throws IOException {
String mapping = Strings.toString(XContentFactory.jsonBuilder().startObject()
.startObject("type")
.startObject("properties")
.startObject("field")
.field("type", "ip")
.endObject()
.endObject()
.endObject().endObject());
DocumentMapper mapper = parser.parse("type", new CompressedXContent(mapping));
assertEquals(mapping, mapper.mappingSource().toString());
DocumentMapper mapper = createDocumentMapper(fieldMapping(this::minimalMapping));
ParsedDocument doc = mapper.parse(new SourceToParse("test", "type", "1", BytesReference
.bytes(XContentFactory.jsonBuilder()
.startObject()
.nullField("field")
.endObject()),
XContentType.JSON));
ParsedDocument doc = mapper.parse(source(b -> b.nullField("field")));
assertArrayEquals(new IndexableField[0], doc.rootDoc().getFields("field"));
mapping = Strings.toString(XContentFactory.jsonBuilder().startObject()
.startObject("type")
.startObject("properties")
.startObject("field")
.field("type", "ip")
.field("null_value", "::1")
.endObject()
.endObject()
.endObject().endObject());
mapper = createDocumentMapper(fieldMapping(b -> {
b.field("type", "ip");
b.field("null_value", "::1");
}));
mapper = parser.parse("type", new CompressedXContent(mapping));
assertEquals(mapping, mapper.mappingSource().toString());
doc = mapper.parse(source(b -> b.nullField("field")));
doc = mapper.parse(new SourceToParse("test", "type", "1", BytesReference
.bytes(XContentFactory.jsonBuilder()
.startObject()
.nullField("field")
.endObject()),
XContentType.JSON));
IndexableField[] fields = doc.rootDoc().getFields("field");
assertEquals(2, fields.length);
IndexableField pointField = fields[0];
@ -265,46 +169,33 @@ public class IpFieldMapperTests extends ESSingleNodeTestCase {
assertEquals(DocValuesType.SORTED_SET, dvField.fieldType().docValuesType());
assertEquals(new BytesRef(InetAddressPoint.encode(InetAddresses.forString("::1"))), dvField.binaryValue());
assertFalse(dvField.fieldType().stored());
}
public void testSerializeDefaults() throws Exception {
String mapping = Strings.toString(XContentFactory.jsonBuilder().startObject().startObject("type")
.startObject("properties").startObject("field").field("type", "ip").endObject().endObject()
.endObject().endObject());
mapper = createDocumentMapper(fieldMapping(b -> {
b.field("type", "ip");
b.nullField("null_value");
}));
DocumentMapper docMapper = parser.parse("type", new CompressedXContent(mapping));
IpFieldMapper mapper = (IpFieldMapper)docMapper.root().getMapper("field");
XContentBuilder builder = XContentFactory.jsonBuilder().startObject();
mapper.doXContentBody(builder, true, ToXContent.EMPTY_PARAMS);
String got = Strings.toString(builder.endObject());
doc = mapper.parse(source(b -> b.nullField("field")));
assertArrayEquals(new IndexableField[0], doc.rootDoc().getFields("field"));
// it would be nice to check the entire serialized default mapper, but there are
// a whole lot of bogus settings right now it picks up from calling super.doXContentBody...
assertTrue(got, got.contains("\"ignore_malformed\":false"));
}
public void testEmptyName() throws IOException {
String mapping = Strings.toString(XContentFactory.jsonBuilder().startObject().startObject("type")
.startObject("properties").startObject("").field("type", "ip").endObject().endObject()
.endObject().endObject());
IllegalArgumentException e = expectThrows(IllegalArgumentException.class,
() -> parser.parse("type", new CompressedXContent(mapping))
);
assertThat(e.getMessage(), containsString("name cannot be empty string"));
createDocumentMapper(fieldMapping(b -> {
b.field("type", "ip");
b.field("null_value", ":1");
}));
assertWarnings("Error parsing [:1] as IP in [null_value] on field [field]); [null_value] will be ignored");
}
public void testFetchSourceValue() throws IOException {
Settings settings = Settings.builder().put(IndexMetadata.SETTING_VERSION_CREATED, Version.CURRENT.id).build();
Mapper.BuilderContext context = new Mapper.BuilderContext(settings, new ContentPath());
IpFieldMapper mapper = new IpFieldMapper.Builder("field", true).build(context);
IpFieldMapper mapper = new IpFieldMapper.Builder("field", true, Version.CURRENT).build(context);
assertEquals(List.of("2001:db8::2:1"), fetchSourceValue(mapper, "2001:db8::2:1"));
assertEquals(List.of("2001:db8::2:1"), fetchSourceValue(mapper, "2001:db8:0:0:0:0:2:1"));
assertEquals(List.of("::1"), fetchSourceValue(mapper, "0:0:0:0:0:0:0:1"));
IpFieldMapper nullValueMapper = new IpFieldMapper.Builder("field", true)
.nullValue(InetAddresses.forString("2001:db8:0:0:0:0:2:7"))
IpFieldMapper nullValueMapper = new IpFieldMapper.Builder("field", true, Version.CURRENT)
.nullValue("2001:db8:0:0:0:0:2:7")
.build(context);
assertEquals(List.of("2001:db8::2:7"), fetchSourceValue(nullValueMapper, null));
}

@ -102,7 +102,7 @@ public abstract class MapperServiceTestCase extends ESTestCase {
}
protected final MapperService createMapperService(XContentBuilder mappings) throws IOException {
return createMapperService(getIndexSettings(), mappings);
return createMapperService(Version.CURRENT, mappings);
}
protected final MapperService createMapperService(String type, String mappings) throws IOException {
@ -114,13 +114,13 @@ public abstract class MapperServiceTestCase extends ESTestCase {
/**
* Create a {@link MapperService} like we would for an index.
*/
protected final MapperService createMapperService(Settings settings, XContentBuilder mapping) throws IOException {
protected final MapperService createMapperService(Version version, XContentBuilder mapping) throws IOException {
IndexMetadata meta = IndexMetadata.builder("index")
.settings(Settings.builder().put("index.version.created", Version.CURRENT))
.settings(Settings.builder().put("index.version.created", version))
.numberOfReplicas(0)
.numberOfShards(1)
.build();
IndexSettings indexSettings = new IndexSettings(meta, Settings.EMPTY);
IndexSettings indexSettings = new IndexSettings(meta, getIndexSettings());
MapperRegistry mapperRegistry = new IndicesModule(
getPlugins().stream().filter(p -> p instanceof MapperPlugin).map(p -> (MapperPlugin) p).collect(toList())
).getMapperRegistry();
@ -128,7 +128,7 @@ public abstract class MapperServiceTestCase extends ESTestCase {
Settings.EMPTY,
getPlugins().stream().filter(p -> p instanceof ScriptPlugin).map(p -> (ScriptPlugin) p).collect(toList())
);
ScriptService scriptService = new ScriptService(settings, scriptModule.engines, scriptModule.contexts);
ScriptService scriptService = new ScriptService(getIndexSettings(), scriptModule.engines, scriptModule.contexts);
SimilarityService similarityService = new SimilarityService(indexSettings, scriptService, emptyMap());
MapperService mapperService = new MapperService(
indexSettings,