/* * 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 com.google.common.collect.Iterators; import org.elasticsearch.Version; import org.elasticsearch.cluster.metadata.IndexMetaData; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.test.ESTestCase; import java.io.IOException; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Iterator; import java.util.List; import static org.hamcrest.Matchers.containsString; public class FieldTypeLookupTests extends ESTestCase { public void testEmpty() { FieldTypeLookup lookup = new FieldTypeLookup(); assertNull(lookup.get("foo")); assertNull(lookup.getByIndexName("foo")); assertEquals(Collections.emptySet(), lookup.getTypes("foo")); assertEquals(Collections.emptySet(), lookup.getTypesByIndexName("foo")); Collection<String> names = lookup.simpleMatchToFullName("foo"); assertNotNull(names); assertTrue(names.isEmpty()); names = lookup.simpleMatchToIndexNames("foo"); assertNotNull(names); assertTrue(names.isEmpty()); Iterator<MappedFieldType> itr = lookup.iterator(); assertNotNull(itr); assertFalse(itr.hasNext()); } public void testDefaultMapping() { FieldTypeLookup lookup = new FieldTypeLookup(); try { lookup.copyAndAddAll(MapperService.DEFAULT_MAPPING, Collections.<FieldMapper>emptyList(), randomBoolean()); fail(); } catch (IllegalArgumentException expected) { assertEquals("Default mappings should not be added to the lookup", expected.getMessage()); } } public void testAddNewField() { FieldTypeLookup lookup = new FieldTypeLookup(); FakeFieldMapper f = new FakeFieldMapper("foo", "bar"); FieldTypeLookup lookup2 = lookup.copyAndAddAll("type", newList(f), randomBoolean()); assertNull(lookup.get("foo")); assertNull(lookup.get("bar")); assertNull(lookup.getByIndexName("foo")); assertNull(lookup.getByIndexName("bar")); assertEquals(f.fieldType(), lookup2.get("foo")); assertNull(lookup.get("bar")); assertEquals(f.fieldType(), lookup2.getByIndexName("bar")); assertNull(lookup.getByIndexName("foo")); assertEquals(Collections.emptySet(), lookup.getTypes("foo")); assertEquals(Collections.emptySet(), lookup.getTypesByIndexName("foo")); assertEquals(Collections.emptySet(), lookup.getTypes("bar")); assertEquals(Collections.emptySet(), lookup.getTypesByIndexName("bar")); assertEquals(Collections.singleton("type"), lookup2.getTypes("foo")); assertEquals(Collections.emptySet(), lookup2.getTypesByIndexName("foo")); assertEquals(Collections.emptySet(), lookup2.getTypes("bar")); assertEquals(Collections.singleton("type"), lookup2.getTypesByIndexName("bar")); assertEquals(1, Iterators.size(lookup2.iterator())); } public void testAddExistingField() { FakeFieldMapper f = new FakeFieldMapper("foo", "foo"); FakeFieldMapper f2 = new FakeFieldMapper("foo", "foo"); FieldTypeLookup lookup = new FieldTypeLookup(); lookup = lookup.copyAndAddAll("type1", newList(f), randomBoolean()); FieldTypeLookup lookup2 = lookup.copyAndAddAll("type2", newList(f2), randomBoolean()); assertSame(f2.fieldType(), lookup2.get("foo")); assertSame(f2.fieldType(), lookup2.getByIndexName("foo")); assertEquals(1, Iterators.size(lookup2.iterator())); } public void testAddExistingIndexName() { FakeFieldMapper f = new FakeFieldMapper("foo", "foo"); FakeFieldMapper f2 = new FakeFieldMapper("bar", "foo"); FieldTypeLookup lookup = new FieldTypeLookup(); lookup = lookup.copyAndAddAll("type1", newList(f), randomBoolean()); FieldTypeLookup lookup2 = lookup.copyAndAddAll("type2", newList(f2), randomBoolean()); assertSame(f.fieldType(), lookup2.get("foo")); assertSame(f2.fieldType(), lookup2.get("bar")); assertSame(f2.fieldType(), lookup2.getByIndexName("foo")); assertEquals(2, Iterators.size(lookup2.iterator())); } public void testAddExistingFullName() { FakeFieldMapper f = new FakeFieldMapper("foo", "foo"); FakeFieldMapper f2 = new FakeFieldMapper("foo", "bar"); FieldTypeLookup lookup = new FieldTypeLookup(); lookup = lookup.copyAndAddAll("type1", newList(f), randomBoolean()); try { lookup.copyAndAddAll("type2", newList(f2), randomBoolean()); } catch (IllegalArgumentException e) { assertThat(e.getMessage(), containsString("mapper [foo] has different [index_name]")); } } public void testAddExistingBridgeName() { FakeFieldMapper f = new FakeFieldMapper("foo", "foo"); FakeFieldMapper f2 = new FakeFieldMapper("bar", "bar"); FieldTypeLookup lookup = new FieldTypeLookup(); lookup = lookup.copyAndAddAll("type1", newList(f, f2), randomBoolean()); try { FakeFieldMapper f3 = new FakeFieldMapper("foo", "bar"); lookup.copyAndAddAll("type2", newList(f3), randomBoolean()); } catch (IllegalStateException e) { assertTrue(e.getMessage().contains("insane mappings")); } try { FakeFieldMapper f3 = new FakeFieldMapper("bar", "foo"); lookup.copyAndAddAll("type2", newList(f3), randomBoolean()); } catch (IllegalStateException e) { assertTrue(e.getMessage().contains("insane mappings")); } } public void testCheckCompatibilityMismatchedTypes() { FieldMapper f1 = new FakeFieldMapper("foo", "bar"); FieldTypeLookup lookup = new FieldTypeLookup(); lookup = lookup.copyAndAddAll("type", newList(f1), randomBoolean()); MappedFieldType ft2 = FakeFieldMapper.makeOtherFieldType("foo", "foo"); FieldMapper f2 = new FakeFieldMapper("foo", ft2); try { lookup.copyAndAddAll("type2", newList(f2), false); fail("expected type mismatch"); } catch (IllegalArgumentException e) { assertTrue(e.getMessage().contains("cannot be changed from type [faketype] to [otherfaketype]")); } // fails even if updateAllTypes == true try { lookup.copyAndAddAll("type2", newList(f2), true); fail("expected type mismatch"); } catch (IllegalArgumentException e) { assertTrue(e.getMessage().contains("cannot be changed from type [faketype] to [otherfaketype]")); } } public void testCheckCompatibilityConflict() { FieldMapper f1 = new FakeFieldMapper("foo", "bar"); FieldTypeLookup lookup = new FieldTypeLookup(); lookup = lookup.copyAndAddAll("type", newList(f1), randomBoolean()); MappedFieldType ft2 = FakeFieldMapper.makeFieldType("foo", "bar"); ft2.setBoost(2.0f); FieldMapper f2 = new FakeFieldMapper("foo", ft2); try { // different type lookup.copyAndAddAll("type2", newList(f2), false); fail("expected conflict"); } catch (IllegalArgumentException e) { assertTrue(e.getMessage().contains("to update [boost] across all types")); } lookup.copyAndAddAll("type", newList(f2), false); // boost is updateable, so ok since we are implicitly updating all types lookup.copyAndAddAll("type2", newList(f2), true); // boost is updateable, so ok if forcing // now with a non changeable setting MappedFieldType ft3 = FakeFieldMapper.makeFieldType("foo", "bar"); ft3.setStored(true); FieldMapper f3 = new FakeFieldMapper("foo", ft3); try { lookup.copyAndAddAll("type2", newList(f3), false); fail("expected conflict"); } catch (IllegalArgumentException e) { assertTrue(e.getMessage().contains("has different [store] values")); } // even with updateAllTypes == true, incompatible try { lookup.copyAndAddAll("type2", newList(f3), true); fail("expected conflict"); } catch (IllegalArgumentException e) { assertTrue(e.getMessage().contains("has different [store] values")); } } public void testSimpleMatchIndexNames() { FakeFieldMapper f1 = new FakeFieldMapper("foo", "baz"); FakeFieldMapper f2 = new FakeFieldMapper("bar", "boo"); FieldTypeLookup lookup = new FieldTypeLookup(); lookup = lookup.copyAndAddAll("type", newList(f1, f2), randomBoolean()); Collection<String> names = lookup.simpleMatchToIndexNames("b*"); assertTrue(names.contains("baz")); assertTrue(names.contains("boo")); } public void testSimpleMatchFullNames() { FakeFieldMapper f1 = new FakeFieldMapper("foo", "baz"); FakeFieldMapper f2 = new FakeFieldMapper("bar", "boo"); FieldTypeLookup lookup = new FieldTypeLookup(); lookup = lookup.copyAndAddAll("type", newList(f1, f2), randomBoolean()); Collection<String> names = lookup.simpleMatchToFullName("b*"); assertTrue(names.contains("foo")); assertTrue(names.contains("bar")); } public void testIteratorImmutable() { FakeFieldMapper f1 = new FakeFieldMapper("foo", "bar"); FieldTypeLookup lookup = new FieldTypeLookup(); lookup = lookup.copyAndAddAll("type", newList(f1), randomBoolean()); try { Iterator<MappedFieldType> itr = lookup.iterator(); assertTrue(itr.hasNext()); assertEquals(f1.fieldType(), itr.next()); itr.remove(); fail("remove should have failed"); } catch (UnsupportedOperationException e) { // expected } } static List<FieldMapper> newList(FieldMapper... mapper) { return Arrays.asList(mapper); } // this sucks how much must be overridden just do get a dummy field mapper... static class FakeFieldMapper extends FieldMapper { static Settings dummySettings = Settings.builder().put(IndexMetaData.SETTING_VERSION_CREATED, Version.CURRENT.id).build(); public FakeFieldMapper(String fullName, String indexName) { super(fullName, makeFieldType(fullName, indexName), makeFieldType(fullName, indexName), dummySettings, null, null); } public FakeFieldMapper(String fullName, MappedFieldType fieldType) { super(fullName, fieldType, fieldType, dummySettings, null, null); } static MappedFieldType makeFieldType(String fullName, String indexName) { FakeFieldType fieldType = new FakeFieldType(); fieldType.setNames(new MappedFieldType.Names(indexName, indexName, fullName)); return fieldType; } static MappedFieldType makeOtherFieldType(String fullName, String indexName) { OtherFakeFieldType fieldType = new OtherFakeFieldType(); fieldType.setNames(new MappedFieldType.Names(indexName, indexName, fullName)); return fieldType; } static class FakeFieldType extends MappedFieldType { public FakeFieldType() {} protected FakeFieldType(FakeFieldType ref) { super(ref); } @Override public MappedFieldType clone() { return new FakeFieldType(this); } @Override public String typeName() { return "faketype"; } } static class OtherFakeFieldType extends MappedFieldType { public OtherFakeFieldType() {} protected OtherFakeFieldType(OtherFakeFieldType ref) { super(ref); } @Override public MappedFieldType clone() { return new OtherFakeFieldType(this); } @Override public String typeName() { return "otherfaketype"; } } @Override protected String contentType() { return null; } @Override protected void parseCreateField(ParseContext context, List list) throws IOException {} } }