/*
* 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.update;
import org.elasticsearch.action.admin.indices.mapping.get.GetMappingsResponse;
import org.elasticsearch.action.admin.indices.mapping.put.PutMappingResponse;
import org.elasticsearch.client.Client;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.index.mapper.MapperParsingException;
import org.elasticsearch.index.mapper.MergeMappingException;
import org.elasticsearch.test.ESIntegTestCase;
import org.junit.Test;
import java.util.HashMap;
import static org.elasticsearch.test.StreamsUtils.copyToStringFromClasspath;
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.equalTo;
public class UpdateMappingOnClusterIT extends ESIntegTestCase {
private static final String INDEX = "index";
private static final String TYPE = "type";
@Test
public void test_all_enabled() throws Exception {
XContentBuilder mapping = jsonBuilder().startObject().startObject("mappings").startObject(TYPE).startObject("_all").field("enabled", "false").endObject().endObject().endObject().endObject();
XContentBuilder mappingUpdate = jsonBuilder().startObject().startObject("_all").field("enabled", "true").endObject().startObject("properties").startObject("text").field("type", "string").endObject().endObject().endObject();
String errorMessage = "[_all] enabled is false now encountering true";
testConflict(mapping.string(), mappingUpdate.string(), errorMessage);
}
@Test
public void test_all_conflicts() throws Exception {
String mapping = copyToStringFromClasspath("/org/elasticsearch/index/mapper/update/all_mapping_create_index.json");
String mappingUpdate = copyToStringFromClasspath("/org/elasticsearch/index/mapper/update/all_mapping_update_with_conflicts.json");
String[] errorMessage = {
"[_all] has different [omit_norms] values",
"[_all] has different [store] values",
"[_all] has different [store_term_vector] values",
"[_all] has different [store_term_vector_offsets] values",
"[_all] has different [store_term_vector_positions] values",
"[_all] has different [store_term_vector_payloads] values",
"[_all] has different [analyzer]",
"[_all] has different [similarity]"};
// fielddata and search_analyzer should not report conflict
testConflict(mapping, mappingUpdate, errorMessage);
}
public void testAllDisabled() throws Exception {
XContentBuilder mapping = jsonBuilder().startObject().startObject("mappings").startObject(TYPE).startObject("_all").field("enabled", true).endObject().endObject().endObject().endObject();
XContentBuilder mappingUpdate = jsonBuilder().startObject().startObject("_all").field("enabled", false).endObject().startObject("properties").startObject("text").field("type", "string").endObject().endObject().endObject();
String errorMessage = "[_all] enabled is true now encountering false";
testConflict(mapping.string(), mappingUpdate.string(), errorMessage);
}
public void testAllWithDefault() throws Exception {
String defaultMapping = jsonBuilder().startObject().startObject("_default_")
.startObject("_all")
.field("enabled", false)
.endObject()
.endObject().endObject().string();
client().admin().indices().prepareCreate("index").addMapping("_default_", defaultMapping).get();
String docMapping = jsonBuilder().startObject()
.startObject("doc")
.endObject()
.endObject().string();
PutMappingResponse response = client().admin().indices().preparePutMapping("index").setType("doc").setSource(docMapping).get();
assertTrue(response.isAcknowledged());
String docMappingUpdate = jsonBuilder().startObject().startObject("doc")
.startObject("properties")
.startObject("text")
.field("type", "string")
.endObject()
.endObject()
.endObject()
.endObject().string();
response = client().admin().indices().preparePutMapping("index").setType("doc").setSource(docMappingUpdate).get();
assertTrue(response.isAcknowledged());
String docMappingAllExplicitEnabled = jsonBuilder().startObject()
.startObject("doc_all_enabled")
.startObject("_all")
.field("enabled", true)
.endObject()
.endObject()
.endObject().string();
response = client().admin().indices().preparePutMapping("index").setType("doc_all_enabled").setSource(docMappingAllExplicitEnabled).get();
assertTrue(response.isAcknowledged());
GetMappingsResponse mapping = client().admin().indices().prepareGetMappings("index").get();
HashMap props = (HashMap)mapping.getMappings().get("index").get("doc").getSourceAsMap().get("_all");
assertThat((Boolean)props.get("enabled"), equalTo(false));
props = (HashMap)mapping.getMappings().get("index").get("doc").getSourceAsMap().get("properties");
assertNotNull(props);
assertNotNull(props.get("text"));
props = (HashMap)mapping.getMappings().get("index").get("doc_all_enabled").getSourceAsMap().get("_all");
assertThat((Boolean)props.get("enabled"), equalTo(true));
props = (HashMap)mapping.getMappings().get("index").get("_default_").getSourceAsMap().get("_all");
assertThat((Boolean)props.get("enabled"), equalTo(false));
}
@Test
public void test_doc_valuesInvalidMapping() throws Exception {
String mapping = jsonBuilder().startObject().startObject("mappings").startObject(TYPE).startObject("_all").startObject("fielddata").field("format", "doc_values").endObject().endObject().endObject().endObject().endObject().string();
try {
prepareCreate(INDEX).setSource(mapping).get();
fail();
} catch (MapperParsingException e) {
assertThat(e.getDetailedMessage(), containsString("[_all] is always tokenized and cannot have doc values"));
}
}
@Test
public void test_doc_valuesInvalidMappingOnUpdate() throws Exception {
String mapping = jsonBuilder().startObject().startObject(TYPE).startObject("properties").startObject("text").field("type", "string").endObject().endObject().endObject().string();
prepareCreate(INDEX).addMapping(TYPE, mapping).get();
String mappingUpdate = jsonBuilder().startObject().startObject(TYPE).startObject("_all").startObject("fielddata").field("format", "doc_values").endObject().endObject().endObject().endObject().string();
GetMappingsResponse mappingsBeforeUpdateResponse = client().admin().indices().prepareGetMappings(INDEX).addTypes(TYPE).get();
try {
client().admin().indices().preparePutMapping(INDEX).setType(TYPE).setSource(mappingUpdate).get();
fail();
} catch (MapperParsingException e) {
assertThat(e.getDetailedMessage(), containsString("[_all] is always tokenized and cannot have doc values"));
}
// make sure all nodes have same cluster state
compareMappingOnNodes(mappingsBeforeUpdateResponse);
}
// checks if the setting for timestamp and size are kept even if disabled
@Test
public void testDisabledSizeTimestampIndexDoNotLooseMappings() throws Exception {
String mapping = copyToStringFromClasspath("/org/elasticsearch/index/mapper/update/default_mapping_with_disabled_root_types.json");
prepareCreate(INDEX).addMapping(TYPE, mapping).get();
GetMappingsResponse mappingsBeforeGreen = client().admin().indices().prepareGetMappings(INDEX).addTypes(TYPE).get();
ensureGreen(INDEX);
// make sure all nodes have same cluster state
compareMappingOnNodes(mappingsBeforeGreen);
}
protected void testConflict(String mapping, String mappingUpdate, String... errorMessages) throws InterruptedException {
assertAcked(prepareCreate(INDEX).setSource(mapping).get());
ensureGreen(INDEX);
GetMappingsResponse mappingsBeforeUpdateResponse = client().admin().indices().prepareGetMappings(INDEX).addTypes(TYPE).get();
try {
client().admin().indices().preparePutMapping(INDEX).setType(TYPE).setSource(mappingUpdate).get();
fail();
} catch (MergeMappingException|IllegalArgumentException e) {
for (String errorMessage : errorMessages) {
assertThat(e.getMessage(), containsString(errorMessage));
}
}
compareMappingOnNodes(mappingsBeforeUpdateResponse);
}
private void compareMappingOnNodes(GetMappingsResponse previousMapping) {
// make sure all nodes have same cluster state
for (Client client : cluster()) {
GetMappingsResponse currentMapping = client.admin().indices().prepareGetMappings(INDEX).addTypes(TYPE).setLocal(true).get();
assertThat(previousMapping.getMappings().get(INDEX).get(TYPE).source(), equalTo(currentMapping.getMappings().get(INDEX).get(TYPE).source()));
}
}
}