/*
* 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.common.settings;
import org.elasticsearch.Version;
import org.elasticsearch.common.Booleans;
import org.elasticsearch.common.logging.DeprecationLogger;
import org.elasticsearch.common.logging.ESLoggerFactory;
import org.elasticsearch.common.settings.loader.YamlSettingsLoader;
import org.elasticsearch.test.ESTestCase;
import org.hamcrest.Matchers;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
import static org.hamcrest.Matchers.allOf;
import static org.hamcrest.Matchers.arrayContaining;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.hasToString;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.notNullValue;
import static org.hamcrest.Matchers.nullValue;
public class SettingsTests extends ESTestCase {
public void testReplacePropertiesPlaceholderSystemProperty() {
String value = System.getProperty("java.home");
assertFalse(value.isEmpty());
Settings settings = Settings.builder()
.put("property.placeholder", value)
.put("setting1", "${property.placeholder}")
.replacePropertyPlaceholders()
.build();
assertThat(settings.get("setting1"), equalTo(value));
}
public void testReplacePropertiesPlaceholderSystemVariablesHaveNoEffect() {
final String value = System.getProperty("java.home");
assertNotNull(value);
final IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () -> Settings.builder()
.put("setting1", "${java.home}")
.replacePropertyPlaceholders()
.build());
assertThat(e, hasToString(containsString("Could not resolve placeholder 'java.home'")));
}
public void testReplacePropertiesPlaceholderByEnvironmentVariables() {
final String hostname = randomAlphaOfLength(16);
final Settings implicitEnvSettings = Settings.builder()
.put("setting1", "${HOSTNAME}")
.replacePropertyPlaceholders(name -> "HOSTNAME".equals(name) ? hostname : null)
.build();
assertThat(implicitEnvSettings.get("setting1"), equalTo(hostname));
}
public void testReplacePropertiesPlaceholderIgnoresPrompt() {
Settings settings = Settings.builder()
.put("setting1", "${prompt.text}")
.put("setting2", "${prompt.secret}")
.replacePropertyPlaceholders()
.build();
assertThat(settings.get("setting1"), is("${prompt.text}"));
assertThat(settings.get("setting2"), is("${prompt.secret}"));
}
public void testUnFlattenedSettings() {
Settings settings = Settings.builder()
.put("foo", "abc")
.put("bar", "def")
.put("baz.foo", "ghi")
.put("baz.bar", "jkl")
.putArray("baz.arr", "a", "b", "c")
.build();
Map<String, Object> map = settings.getAsStructuredMap();
assertThat(map.keySet(), Matchers.<String>hasSize(3));
assertThat(map, allOf(
Matchers.<String, Object>hasEntry("foo", "abc"),
Matchers.<String, Object>hasEntry("bar", "def")));
@SuppressWarnings("unchecked") Map<String, Object> bazMap = (Map<String, Object>) map.get("baz");
assertThat(bazMap.keySet(), Matchers.<String>hasSize(3));
assertThat(bazMap, allOf(
Matchers.<String, Object>hasEntry("foo", "ghi"),
Matchers.<String, Object>hasEntry("bar", "jkl")));
@SuppressWarnings("unchecked") List<String> bazArr = (List<String>) bazMap.get("arr");
assertThat(bazArr, contains("a", "b", "c"));
}
public void testFallbackToFlattenedSettings() {
Settings settings = Settings.builder()
.put("foo", "abc")
.put("foo.bar", "def")
.put("foo.baz", "ghi").build();
Map<String, Object> map = settings.getAsStructuredMap();
assertThat(map.keySet(), Matchers.<String>hasSize(3));
assertThat(map, allOf(
Matchers.<String, Object>hasEntry("foo", "abc"),
Matchers.<String, Object>hasEntry("foo.bar", "def"),
Matchers.<String, Object>hasEntry("foo.baz", "ghi")));
settings = Settings.builder()
.put("foo.bar", "def")
.put("foo", "abc")
.put("foo.baz", "ghi")
.build();
map = settings.getAsStructuredMap();
assertThat(map.keySet(), Matchers.<String>hasSize(3));
assertThat(map, allOf(
Matchers.<String, Object>hasEntry("foo", "abc"),
Matchers.<String, Object>hasEntry("foo.bar", "def"),
Matchers.<String, Object>hasEntry("foo.baz", "ghi")));
}
public void testGetAsSettings() {
Settings settings = Settings.builder()
.put("bar", "hello world")
.put("foo", "abc")
.put("foo.bar", "def")
.put("foo.baz", "ghi").build();
Settings fooSettings = settings.getAsSettings("foo");
assertFalse(fooSettings.isEmpty());
assertEquals(2, fooSettings.size());
assertThat(fooSettings.get("bar"), equalTo("def"));
assertThat(fooSettings.get("baz"), equalTo("ghi"));
}
@SuppressWarnings("deprecation") //#getAsBooleanLenientForPreEs6Indices is the test subject
public void testLenientBooleanForPreEs6Index() throws IOException {
// time to say goodbye?
assertTrue(
"It's time to implement #22298. Please delete this test and Settings#getAsBooleanLenientForPreEs6Indices().",
Version.CURRENT.minimumCompatibilityVersion().before(Version.V_6_0_0_alpha1_UNRELEASED));
String falsy = randomFrom("false", "off", "no", "0");
String truthy = randomFrom("true", "on", "yes", "1");
Settings settings = Settings.builder()
.put("foo", falsy)
.put("bar", truthy).build();
final DeprecationLogger deprecationLogger = new DeprecationLogger(ESLoggerFactory.getLogger("testLenientBooleanForPreEs6Index"));
assertFalse(settings.getAsBooleanLenientForPreEs6Indices(Version.V_5_0_0, "foo", null, deprecationLogger));
assertTrue(settings.getAsBooleanLenientForPreEs6Indices(Version.V_5_0_0, "bar", null, deprecationLogger));
assertTrue(settings.getAsBooleanLenientForPreEs6Indices(Version.V_5_0_0, "baz", true, deprecationLogger));
List<String> expectedDeprecationWarnings = new ArrayList<>();
if (Booleans.isBoolean(falsy) == false) {
expectedDeprecationWarnings.add(
"The value [" + falsy + "] of setting [foo] is not coerced into boolean anymore. Please change this value to [false].");
}
if (Booleans.isBoolean(truthy) == false) {
expectedDeprecationWarnings.add(
"The value [" + truthy + "] of setting [bar] is not coerced into boolean anymore. Please change this value to [true].");
}
if (expectedDeprecationWarnings.isEmpty() == false) {
assertWarnings(expectedDeprecationWarnings.toArray(new String[1]));
}
}
@SuppressWarnings("deprecation") //#getAsBooleanLenientForPreEs6Indices is the test subject
public void testInvalidLenientBooleanForCurrentIndexVersion() {
String falsy = randomFrom("off", "no", "0");
String truthy = randomFrom("on", "yes", "1");
Settings settings = Settings.builder()
.put("foo", falsy)
.put("bar", truthy).build();
final DeprecationLogger deprecationLogger =
new DeprecationLogger(ESLoggerFactory.getLogger("testInvalidLenientBooleanForCurrentIndexVersion"));
expectThrows(IllegalArgumentException.class,
() -> settings.getAsBooleanLenientForPreEs6Indices(Version.CURRENT, "foo", null, deprecationLogger));
expectThrows(IllegalArgumentException.class,
() -> settings.getAsBooleanLenientForPreEs6Indices(Version.CURRENT, "bar", null, deprecationLogger));
}
@SuppressWarnings("deprecation") //#getAsBooleanLenientForPreEs6Indices is the test subject
public void testValidLenientBooleanForCurrentIndexVersion() {
Settings settings = Settings.builder()
.put("foo", "false")
.put("bar", "true").build();
final DeprecationLogger deprecationLogger =
new DeprecationLogger(ESLoggerFactory.getLogger("testValidLenientBooleanForCurrentIndexVersion"));
assertFalse(settings.getAsBooleanLenientForPreEs6Indices(Version.CURRENT, "foo", null, deprecationLogger));
assertTrue(settings.getAsBooleanLenientForPreEs6Indices(Version.CURRENT, "bar", null, deprecationLogger));
assertTrue(settings.getAsBooleanLenientForPreEs6Indices(Version.CURRENT, "baz", true, deprecationLogger));
}
public void testMultLevelGetPrefix() {
Settings settings = Settings.builder()
.put("1.2.3", "hello world")
.put("1.2.3.4", "abc")
.put("2.3.4", "def")
.put("3.4", "ghi").build();
Settings firstLevelSettings = settings.getByPrefix("1.");
assertFalse(firstLevelSettings.isEmpty());
assertEquals(2, firstLevelSettings.size());
assertThat(firstLevelSettings.get("2.3.4"), equalTo("abc"));
assertThat(firstLevelSettings.get("2.3"), equalTo("hello world"));
Settings secondLevelSetting = firstLevelSettings.getByPrefix("2.");
assertFalse(secondLevelSetting.isEmpty());
assertEquals(2, secondLevelSetting.size());
assertNull(secondLevelSetting.get("2.3.4"));
assertNull(secondLevelSetting.get("1.2.3.4"));
assertNull(secondLevelSetting.get("1.2.3"));
assertThat(secondLevelSetting.get("3.4"), equalTo("abc"));
assertThat(secondLevelSetting.get("3"), equalTo("hello world"));
Settings thirdLevelSetting = secondLevelSetting.getByPrefix("3.");
assertFalse(thirdLevelSetting.isEmpty());
assertEquals(1, thirdLevelSetting.size());
assertNull(thirdLevelSetting.get("2.3.4"));
assertNull(thirdLevelSetting.get("3.4"));
assertNull(thirdLevelSetting.get("1.2.3"));
assertThat(thirdLevelSetting.get("4"), equalTo("abc"));
}
public void testNames() {
Settings settings = Settings.builder()
.put("bar", "baz")
.put("foo", "abc")
.put("foo.bar", "def")
.put("foo.baz", "ghi").build();
Set<String> names = settings.names();
assertThat(names.size(), equalTo(2));
assertTrue(names.contains("bar"));
assertTrue(names.contains("foo"));
Settings fooSettings = settings.getAsSettings("foo");
names = fooSettings.names();
assertThat(names.size(), equalTo(2));
assertTrue(names.contains("bar"));
assertTrue(names.contains("baz"));
}
public void testThatArraysAreOverriddenCorrectly() throws IOException {
// overriding a single value with an array
Settings settings = Settings.builder()
.put(Settings.builder().putArray("value", "1").build())
.put(Settings.builder().putArray("value", "2", "3").build())
.build();
assertThat(settings.getAsArray("value"), arrayContaining("2", "3"));
settings = Settings.builder()
.put(Settings.builder().put("value", "1").build())
.put(Settings.builder().putArray("value", "2", "3").build())
.build();
assertThat(settings.getAsArray("value"), arrayContaining("2", "3"));
settings = Settings.builder()
.put(new YamlSettingsLoader(false).load("value: 1"))
.put(new YamlSettingsLoader(false).load("value: [ 2, 3 ]"))
.build();
assertThat(settings.getAsArray("value"), arrayContaining("2", "3"));
settings = Settings.builder()
.put(Settings.builder().put("value.with.deep.key", "1").build())
.put(Settings.builder().putArray("value.with.deep.key", "2", "3").build())
.build();
assertThat(settings.getAsArray("value.with.deep.key"), arrayContaining("2", "3"));
// overriding an array with a shorter array
settings = Settings.builder()
.put(Settings.builder().putArray("value", "1", "2").build())
.put(Settings.builder().putArray("value", "3").build())
.build();
assertThat(settings.getAsArray("value"), arrayContaining("3"));
settings = Settings.builder()
.put(Settings.builder().putArray("value", "1", "2", "3").build())
.put(Settings.builder().putArray("value", "4", "5").build())
.build();
assertThat(settings.getAsArray("value"), arrayContaining("4", "5"));
settings = Settings.builder()
.put(Settings.builder().putArray("value.deep.key", "1", "2", "3").build())
.put(Settings.builder().putArray("value.deep.key", "4", "5").build())
.build();
assertThat(settings.getAsArray("value.deep.key"), arrayContaining("4", "5"));
// overriding an array with a longer array
settings = Settings.builder()
.put(Settings.builder().putArray("value", "1", "2").build())
.put(Settings.builder().putArray("value", "3", "4", "5").build())
.build();
assertThat(settings.getAsArray("value"), arrayContaining("3", "4", "5"));
settings = Settings.builder()
.put(Settings.builder().putArray("value.deep.key", "1", "2", "3").build())
.put(Settings.builder().putArray("value.deep.key", "4", "5").build())
.build();
assertThat(settings.getAsArray("value.deep.key"), arrayContaining("4", "5"));
// overriding an array with a single value
settings = Settings.builder()
.put(Settings.builder().putArray("value", "1", "2").build())
.put(Settings.builder().put("value", "3").build())
.build();
assertThat(settings.getAsArray("value"), arrayContaining("3"));
settings = Settings.builder()
.put(Settings.builder().putArray("value.deep.key", "1", "2").build())
.put(Settings.builder().put("value.deep.key", "3").build())
.build();
assertThat(settings.getAsArray("value.deep.key"), arrayContaining("3"));
// test that other arrays are not overridden
settings = Settings.builder()
.put(Settings.builder().putArray("value", "1", "2", "3").putArray("a", "b", "c").build())
.put(Settings.builder().putArray("value", "4", "5").putArray("d", "e", "f").build())
.build();
assertThat(settings.getAsArray("value"), arrayContaining("4", "5"));
assertThat(settings.getAsArray("a"), arrayContaining("b", "c"));
assertThat(settings.getAsArray("d"), arrayContaining("e", "f"));
settings = Settings.builder()
.put(Settings.builder().putArray("value.deep.key", "1", "2", "3").putArray("a", "b", "c").build())
.put(Settings.builder().putArray("value.deep.key", "4", "5").putArray("d", "e", "f").build())
.build();
assertThat(settings.getAsArray("value.deep.key"), arrayContaining("4", "5"));
assertThat(settings.getAsArray("a"), notNullValue());
assertThat(settings.getAsArray("d"), notNullValue());
// overriding a deeper structure with an array
settings = Settings.builder()
.put(Settings.builder().put("value.data", "1").build())
.put(Settings.builder().putArray("value", "4", "5").build())
.build();
assertThat(settings.getAsArray("value"), arrayContaining("4", "5"));
// overriding an array with a deeper structure
settings = Settings.builder()
.put(Settings.builder().putArray("value", "4", "5").build())
.put(Settings.builder().put("value.data", "1").build())
.build();
assertThat(settings.get("value.data"), is("1"));
assertThat(settings.get("value"), is(nullValue()));
}
public void testPrefixNormalization() {
Settings settings = Settings.builder().normalizePrefix("foo.").build();
assertThat(settings.names().size(), equalTo(0));
settings = Settings.builder()
.put("bar", "baz")
.normalizePrefix("foo.")
.build();
assertThat(settings.size(), equalTo(1));
assertThat(settings.get("bar"), nullValue());
assertThat(settings.get("foo.bar"), equalTo("baz"));
settings = Settings.builder()
.put("bar", "baz")
.put("foo.test", "test")
.normalizePrefix("foo.")
.build();
assertThat(settings.size(), equalTo(2));
assertThat(settings.get("bar"), nullValue());
assertThat(settings.get("foo.bar"), equalTo("baz"));
assertThat(settings.get("foo.test"), equalTo("test"));
settings = Settings.builder()
.put("foo.test", "test")
.normalizePrefix("foo.")
.build();
assertThat(settings.size(), equalTo(1));
assertThat(settings.get("foo.test"), equalTo("test"));
}
public void testFilteredMap() {
Settings.Builder builder = Settings.builder();
builder.put("a", "a1");
builder.put("a.b", "ab1");
builder.put("a.b.c", "ab2");
builder.put("a.c", "ac1");
builder.put("a.b.c.d", "ab3");
Map<String, String> fiteredMap = builder.build().filter((k) -> k.startsWith("a.b")).getAsMap();
assertEquals(3, fiteredMap.size());
int numKeys = 0;
for (String k : fiteredMap.keySet()) {
numKeys++;
assertTrue(k.startsWith("a.b"));
}
assertEquals(3, numKeys);
int numValues = 0;
for (String v : fiteredMap.values()) {
numValues++;
assertTrue(v.startsWith("ab"));
}
assertEquals(3, numValues);
assertFalse(fiteredMap.containsKey("a.c"));
assertFalse(fiteredMap.containsKey("a"));
assertTrue(fiteredMap.containsKey("a.b"));
assertTrue(fiteredMap.containsKey("a.b.c"));
assertTrue(fiteredMap.containsKey("a.b.c.d"));
expectThrows(UnsupportedOperationException.class, () ->
fiteredMap.remove("a.b"));
assertEquals("ab1", fiteredMap.get("a.b"));
assertEquals("ab2", fiteredMap.get("a.b.c"));
assertEquals("ab3", fiteredMap.get("a.b.c.d"));
Iterator<String> iterator = fiteredMap.keySet().iterator();
for (int i = 0; i < 10; i++) {
assertTrue(iterator.hasNext());
}
assertEquals("a.b", iterator.next());
if (randomBoolean()) {
assertTrue(iterator.hasNext());
}
assertEquals("a.b.c", iterator.next());
if (randomBoolean()) {
assertTrue(iterator.hasNext());
}
assertEquals("a.b.c.d", iterator.next());
assertFalse(iterator.hasNext());
expectThrows(NoSuchElementException.class, () -> iterator.next());
}
public void testPrefixMap() {
Settings.Builder builder = Settings.builder();
builder.put("a", "a1");
builder.put("a.b", "ab1");
builder.put("a.b.c", "ab2");
builder.put("a.c", "ac1");
builder.put("a.b.c.d", "ab3");
Map<String, String> prefixMap = builder.build().getByPrefix("a.").getAsMap();
assertEquals(4, prefixMap.size());
int numKeys = 0;
for (String k : prefixMap.keySet()) {
numKeys++;
assertTrue(k, k.startsWith("b") || k.startsWith("c"));
}
assertEquals(4, numKeys);
int numValues = 0;
for (String v : prefixMap.values()) {
numValues++;
assertTrue(v, v.startsWith("ab") || v.startsWith("ac"));
}
assertEquals(4, numValues);
assertFalse(prefixMap.containsKey("a"));
assertTrue(prefixMap.containsKey("c"));
assertTrue(prefixMap.containsKey("b"));
assertTrue(prefixMap.containsKey("b.c"));
assertTrue(prefixMap.containsKey("b.c.d"));
expectThrows(UnsupportedOperationException.class, () ->
prefixMap.remove("a.b"));
assertEquals("ab1", prefixMap.get("b"));
assertEquals("ab2", prefixMap.get("b.c"));
assertEquals("ab3", prefixMap.get("b.c.d"));
Iterator<String> prefixIterator = prefixMap.keySet().iterator();
for (int i = 0; i < 10; i++) {
assertTrue(prefixIterator.hasNext());
}
assertEquals("b", prefixIterator.next());
if (randomBoolean()) {
assertTrue(prefixIterator.hasNext());
}
assertEquals("b.c", prefixIterator.next());
if (randomBoolean()) {
assertTrue(prefixIterator.hasNext());
}
assertEquals("b.c.d", prefixIterator.next());
if (randomBoolean()) {
assertTrue(prefixIterator.hasNext());
}
assertEquals("c", prefixIterator.next());
assertFalse(prefixIterator.hasNext());
expectThrows(NoSuchElementException.class, () -> prefixIterator.next());
}
public void testEmptyFilterMap() {
Settings.Builder builder = Settings.builder();
builder.put("a", "a1");
builder.put("a.b", "ab1");
builder.put("a.b.c", "ab2");
builder.put("a.c", "ac1");
builder.put("a.b.c.d", "ab3");
Map<String, String> fiteredMap = builder.build().filter((k) -> false).getAsMap();
assertEquals(0, fiteredMap.size());
for (String k : fiteredMap.keySet()) {
fail("no element");
}
for (String v : fiteredMap.values()) {
fail("no element");
}
assertFalse(fiteredMap.containsKey("a.c"));
assertFalse(fiteredMap.containsKey("a"));
assertFalse(fiteredMap.containsKey("a.b"));
assertFalse(fiteredMap.containsKey("a.b.c"));
assertFalse(fiteredMap.containsKey("a.b.c.d"));
expectThrows(UnsupportedOperationException.class, () ->
fiteredMap.remove("a.b"));
assertNull(fiteredMap.get("a.b"));
assertNull(fiteredMap.get("a.b.c"));
assertNull(fiteredMap.get("a.b.c.d"));
Iterator<String> iterator = fiteredMap.keySet().iterator();
for (int i = 0; i < 10; i++) {
assertFalse(iterator.hasNext());
}
expectThrows(NoSuchElementException.class, () -> iterator.next());
}
public void testEmpty() {
assertTrue(Settings.EMPTY.isEmpty());
MockSecureSettings secureSettings = new MockSecureSettings();
assertTrue(Settings.builder().setSecureSettings(secureSettings).build().isEmpty());
}
public void testSecureSettingConflict() {
Setting<SecureString> setting = SecureSetting.secureString("something.secure", null);
Settings settings = Settings.builder().put("something.secure", "notreallysecure").build();
IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () -> setting.get(settings));
assertTrue(e.getMessage().contains("must be stored inside the Elasticsearch keystore"));
}
public void testGetAsArrayFailsOnDuplicates() {
final Settings settings =
Settings.builder()
.put("foobar.0", "bar")
.put("foobar.1", "baz")
.put("foobar", "foo")
.build();
final IllegalStateException e = expectThrows(IllegalStateException.class, () -> settings.getAsArray("foobar"));
assertThat(e, hasToString(containsString("settings object contains values for [foobar=foo] and [foobar.0=bar]")));
}
}