specifying them as node properties is not supported in ES 5.X and causes failure at startup
configureNetwork(builder);
configureCluster(builder);
configureMarvel(builder);
+ configureAction(builder);
return builder;
}
}
}
- void configureIndexDefaults(Map<String, String> builder) {
- configureIndexDefaultsForCluster(builder);
- builder.put("index.number_of_shards", "1");
- builder.put("index.refresh_interval", "30s");
- builder.put("action.auto_create_index", String.valueOf(false));
- builder.put("index.mapper.dynamic", String.valueOf(false));
- }
-
- private void configureIndexDefaultsForCluster(Map<String, String> builder) {
- builder.put("index.number_of_replicas", String.valueOf(computeReplicationFactor()));
- }
-
- private int computeReplicationFactor() {
- if (clusterEnabled) {
- return props.valueAsInt(ProcessProperties.SEARCH_REPLICAS, 1);
- }
- return 0;
- }
-
private void configureCluster(Map<String, String> builder) {
// Default value in a standalone mode, not overridable
}
}
+ private void configureAction(Map<String, String> builder) {
+ builder.put("action.auto_create_index", String.valueOf(false));
+ }
}
public class EsSettingsTest {
+ private static final boolean CLUSTER_ENABLED = true;
+ private static final boolean CLUSTER_DISABLED = false;
+
@Rule
public TemporaryFolder temp = new TemporaryFolder();
// http is disabled for security reasons
assertThat(generated.get("http.enabled")).isEqualTo("false");
- assertThat(generated.get("index.number_of_replicas")).isEqualTo("0");
assertThat(generated.get("discovery.zen.ping.unicast.hosts")).isNull();
assertThat(generated.get("discovery.zen.minimum_master_nodes")).isEqualTo("1");
assertThat(generated.get("discovery.initial_state_timeout")).isEqualTo("30s");
+
+ assertThat(generated.get("action.auto_create_index")).isEqualTo("false");
}
@Test
File dataDir = temp.newFolder();
File logDir = temp.newFolder();
File tempDir = temp.newFolder();
- Props props = minProps(false);
+ Props props = minProps(CLUSTER_DISABLED);
props.set(ProcessProperties.PATH_DATA, dataDir.getAbsolutePath());
props.set(ProcessProperties.PATH_LOGS, logDir.getAbsolutePath());
props.set(ProcessProperties.PATH_TEMP, tempDir.getAbsolutePath());
}
@Test
- public void cluster_is_enabled() throws Exception {
- Props props = minProps(true);
+ public void set_discovery_settings_if_cluster_is_enabled() throws Exception {
+ Props props = minProps(CLUSTER_ENABLED);
props.set(ProcessProperties.CLUSTER_SEARCH_HOSTS, "1.2.3.4:9000,1.2.3.5:8080");
Map<String, String> settings = new EsSettings(props).build();
- assertThat(settings.get("index.number_of_replicas")).isEqualTo("1");
assertThat(settings.get("discovery.zen.ping.unicast.hosts")).isEqualTo("1.2.3.4:9000,1.2.3.5:8080");
assertThat(settings.get("discovery.zen.minimum_master_nodes")).isEqualTo("2");
assertThat(settings.get("discovery.initial_state_timeout")).isEqualTo("120s");
@Test
public void incorrect_values_of_minimum_master_nodes() throws Exception {
- Props props = minProps(true);
+ Props props = minProps(CLUSTER_ENABLED);
props.set(ProcessProperties.SEARCH_MINIMUM_MASTER_NODES, "ꝱꝲꝳପ");
EsSettings underTest = new EsSettings(props);
@Test
public void cluster_is_enabled_with_defined_minimum_master_nodes() throws Exception {
- Props props = minProps(true);
+ Props props = minProps(CLUSTER_ENABLED);
props.set(ProcessProperties.SEARCH_MINIMUM_MASTER_NODES, "5");
Map<String, String> settings = new EsSettings(props).build();
@Test
public void cluster_is_enabled_with_defined_initialTimeout() throws Exception {
- Props props = minProps(true);
+ Props props = minProps(CLUSTER_ENABLED);
props.set(ProcessProperties.SEARCH_INITIAL_STATE_TIMEOUT, "10s");
Map<String, String> settings = new EsSettings(props).build();
@Test
public void in_standalone_initialTimeout_is_not_overridable() throws Exception {
- Props props = minProps(false);
+ Props props = minProps(CLUSTER_DISABLED);
props.set(ProcessProperties.SEARCH_INITIAL_STATE_TIMEOUT, "10s");
Map<String, String> settings = new EsSettings(props).build();
@Test
public void in_standalone_minimumMasterNodes_is_not_overridable() throws Exception {
- Props props = minProps(false);
+ Props props = minProps(CLUSTER_DISABLED);
props.set(ProcessProperties.SEARCH_MINIMUM_MASTER_NODES, "5");
Map<String, String> settings = new EsSettings(props).build();
}
- @Test
- public void in_standalone_searchReplicas_is_not_overridable() throws Exception {
- Props props = minProps(false);
- props.set(ProcessProperties.SEARCH_REPLICAS, "5");
- Map<String, String> settings = new EsSettings(props).build();
-
- assertThat(settings.get("index.number_of_replicas")).isEqualTo("0");
- }
-
- @Test
- public void cluster_is_enabled_with_defined_replicas() throws Exception {
- Props props = minProps(true);
- props.set(ProcessProperties.SEARCH_REPLICAS, "5");
- Map<String, String> settings = new EsSettings(props).build();
-
- assertThat(settings.get("index.number_of_replicas")).isEqualTo("5");
- }
-
- @Test
- public void incorrect_values_of_replicas() throws Exception {
- Props props = minProps(true);
-
- props.set(ProcessProperties.SEARCH_REPLICAS, "ꝱꝲꝳପ");
-
- EsSettings underTest = new EsSettings(props);
-
- expectedException.expect(IllegalStateException.class);
- expectedException.expectMessage("Value of property sonar.search.replicas is not an integer:");
- underTest.build();
- }
@Test
public void enable_marvel() throws Exception {
- Props props = minProps(false);
+ Props props = minProps(CLUSTER_DISABLED);
props.set("sonar.search.marvelHosts", "127.0.0.2,127.0.0.3");
Map<String, String> settings = new EsSettings(props).build();
@Test
public void enable_http_connector() throws Exception {
- Props props = minProps(false);
+ Props props = minProps(CLUSTER_DISABLED);
props.set(ProcessProperties.SEARCH_HTTP_PORT, "9010");
Map<String, String> settings = new EsSettings(props).build();
@Test
public void enable_http_connector_different_host() throws Exception {
- Props props = minProps(false);
+ Props props = minProps(CLUSTER_DISABLED);
props.set(ProcessProperties.SEARCH_HTTP_PORT, "9010");
props.set(ProcessProperties.SEARCH_HOST, "127.0.0.2");
Map<String, String> settings = new EsSettings(props).build();
import java.util.TreeSet;
import java.util.UUID;
import org.apache.commons.lang.StringUtils;
-import org.elasticsearch.cluster.metadata.IndexMetaData;
-import org.elasticsearch.common.settings.Settings;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.sonar.process.ProcessProperties;
Map<String, String> build() {
Map<String, String> builder = new HashMap<>();
configureFileSystem(builder);
- configureIndexDefaults(builder);
configureNetwork(builder);
configureCluster(builder);
configureMarvel(builder);
}
}
- private static void configureIndexDefaults(Settings.Builder builder) {
- builder
- .put("index.number_of_shards", "1")
- .put("index.refresh_interval", "30s")
- .put("action.auto_create_index", false)
- .put("index.mapper.dynamic", false)
- .put("action.auto_create_index", false);
- }
-
private void configureCluster(Map<String, String> builder) {
// Default value in a standalone mode, not overridable
int replicationFactor = 0;
import static org.sonar.server.es.DefaultIndexSettingsElement.SEARCH_PREFIX_ANALYZER;
import static org.sonar.server.es.DefaultIndexSettingsElement.SEARCH_PREFIX_CASE_INSENSITIVE_ANALYZER;
import static org.sonar.server.es.DefaultIndexSettingsElement.SORTABLE_ANALYZER;
+import static org.sonar.server.es.NewIndex.SettingsConfiguration.MANUAL_REFRESH_INTERVAL;
+import static org.sonar.server.es.NewIndex.SettingsConfiguration.newBuilder;
public class ComponentIndexDefinition implements IndexDefinition {
@Override
public void define(IndexDefinitionContext context) {
- NewIndex index = context.create(INDEX_TYPE_COMPONENT.getIndex());
- index.refreshHandledByIndexer();
- index.configureShards(config, DEFAULT_NUMBER_OF_SHARDS);
+ NewIndex index = context.create(
+ INDEX_TYPE_COMPONENT.getIndex(),
+ newBuilder(config)
+ .setRefreshInterval(MANUAL_REFRESH_INTERVAL)
+ .setDefaultNbOfShards(DEFAULT_NUMBER_OF_SHARDS)
+ .build());
NewIndex.NewIndexType mapping = index.createType(INDEX_TYPE_COMPONENT.getType())
.requireProjectAuthorization();
class IndexDefinitionContext {
private final Map<String, NewIndex> byKey = Maps.newHashMap();
- public NewIndex create(String key) {
+ public NewIndex create(String key, NewIndex.SettingsConfiguration settingsConfiguration) {
Preconditions.checkArgument(!byKey.containsKey(key), String.format("Index already exists: %s", key));
- NewIndex index = new NewIndex(key);
+ NewIndex index = new NewIndex(key, settingsConfiguration);
byKey.put(key, index);
return index;
}
*/
package org.sonar.server.es;
-import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSortedMap;
import com.google.common.collect.Maps;
import static com.google.common.base.Preconditions.checkArgument;
import static java.lang.String.format;
+import static java.lang.String.valueOf;
+import static java.util.Objects.requireNonNull;
import static org.sonar.server.es.DefaultIndexSettings.ANALYZER;
import static org.sonar.server.es.DefaultIndexSettings.FIELDDATA_ENABLED;
import static org.sonar.server.es.DefaultIndexSettings.FIELD_FIELDDATA;
private final Settings.Builder settings = DefaultIndexSettings.defaults();
private final Map<String, NewIndexType> types = new LinkedHashMap<>();
- NewIndex(String indexName) {
- Preconditions.checkArgument(StringUtils.isAllLowerCase(indexName), "Index name must be lower-case: " + indexName);
+ NewIndex(String indexName, SettingsConfiguration settingsConfiguration) {
+ checkArgument(StringUtils.isAllLowerCase(indexName), "Index name must be lower-case: " + indexName);
this.indexName = indexName;
+ applySettingsConfiguration(settingsConfiguration);
}
- public void refreshHandledByIndexer() {
- getSettings().put("index.refresh_interval", "-1");
+ private void applySettingsConfiguration(SettingsConfiguration settingsConfiguration) {
+ settings.put("index.mapper.dynamic", valueOf(false));
+ settings.put("index.refresh_interval", refreshInterval(settingsConfiguration));
+
+ Configuration config = settingsConfiguration.getConfiguration();
+ boolean clusterMode = config.getBoolean(ProcessProperties.CLUSTER_ENABLED).orElse(false);
+ int shards = config.getInt(format("sonar.search.%s.shards", indexName))
+ .orElse(settingsConfiguration.getDefaultNbOfShards());
+ int replicas = clusterMode ? config.getInt(ProcessProperties.SEARCH_REPLICAS).orElse(1) : 0;
+
+ settings.put(IndexMetaData.SETTING_NUMBER_OF_SHARDS, shards);
+ settings.put(IndexMetaData.SETTING_NUMBER_OF_REPLICAS, replicas);
+ }
+
+ private static String refreshInterval(SettingsConfiguration settingsConfiguration) {
+ int refreshInterval = settingsConfiguration.getRefreshInterval();
+ if (refreshInterval == -1) {
+ return "-1";
+ }
+ return refreshInterval + "s";
+ }
+
+ public static class SettingsConfiguration {
+ public static final int MANUAL_REFRESH_INTERVAL = -1;
+
+ private final Configuration configuration;
+ private final int defaultNbOfShards;
+ private final int refreshInterval;
+
+ private SettingsConfiguration(Builder builder) {
+ this.configuration = builder.configuration;
+ this.defaultNbOfShards = builder.defaultNbOfShards;
+ this.refreshInterval = builder.refreshInterval;
+ }
+
+ public static Builder newBuilder(Configuration configuration) {
+ return new Builder(configuration);
+ }
+
+ public Configuration getConfiguration() {
+ return configuration;
+ }
+
+ public int getDefaultNbOfShards() {
+ return defaultNbOfShards;
+ }
+
+ public int getRefreshInterval() {
+ return refreshInterval;
+ }
+
+ public static class Builder {
+ private final Configuration configuration;
+ private int defaultNbOfShards = 1;
+ private int refreshInterval = 30;
+
+ public Builder(Configuration configuration) {
+ this.configuration = requireNonNull(configuration, "configuration can't be null");
+ }
+
+ public Builder setDefaultNbOfShards(int defaultNbOfShards) {
+ checkArgument(defaultNbOfShards >= 1, "defaultNbOfShards must be >= 1");
+ this.defaultNbOfShards = defaultNbOfShards;
+ return this;
+ }
+
+ public Builder setRefreshInterval(int refreshInterval) {
+ checkArgument(refreshInterval == -1 || refreshInterval > 0,
+ "refreshInterval must be either -1 or strictly positive");
+ this.refreshInterval = refreshInterval;
+ return this;
+ }
+
+ public SettingsConfiguration build() {
+ return new SettingsConfiguration(this);
+ }
+ }
+
}
public String getName() {
return types;
}
- public void configureShards(Configuration config, int defaultNbOfShards) {
- boolean clusterMode = config.getBoolean(ProcessProperties.CLUSTER_ENABLED).orElse(false);
- int shards = config.getInt(format("sonar.search.%s.shards", indexName)).orElse(defaultNbOfShards);
-
- int replicas = config.getInt(ProcessProperties.SEARCH_REPLICAS).orElse(clusterMode ? 1 : 0);
-
- getSettings().put(IndexMetaData.SETTING_NUMBER_OF_SHARDS, shards);
- getSettings().put(IndexMetaData.SETTING_NUMBER_OF_REPLICAS, replicas);
- }
-
public static class NewIndexType {
private final NewIndex index;
private final String name;
hash.putAll(ImmutableMap.of(
"type", getFieldType(),
"index", disableSearch ? INDEX_NOT_SEARCHABLE : INDEX_SEARCHABLE,
- "norms", String.valueOf(!disableNorms),
- "store", String.valueOf(store)));
+ "norms", valueOf(!disableNorms),
+ "store", valueOf(store)));
if (getFieldData()) {
hash.put(FIELD_FIELDDATA, FIELDDATA_ENABLED);
}
"type", getFieldType(),
"index", INDEX_SEARCHABLE,
"norms", "false",
- "store", String.valueOf(store)));
+ "store", valueOf(store)));
hash.put("fields", multiFields);
}
import org.sonar.server.es.IndexType;
import org.sonar.server.es.NewIndex;
+import static org.sonar.server.es.NewIndex.SettingsConfiguration.MANUAL_REFRESH_INTERVAL;
+import static org.sonar.server.es.NewIndex.SettingsConfiguration.newBuilder;
+
public class MetadataIndexDefinition {
public static final IndexType INDEX_TYPE_METADATA = new IndexType("metadatas", "metadata");
}
public void define(IndexDefinitionContext context) {
- NewIndex index = context.create(INDEX_TYPE_METADATA.getIndex());
- index.refreshHandledByIndexer();
- index.configureShards(configuration, DEFAULT_NUMBER_OF_SHARDS);
+ NewIndex index = context.create(
+ INDEX_TYPE_METADATA.getIndex(),
+ newBuilder(configuration)
+ .setRefreshInterval(MANUAL_REFRESH_INTERVAL)
+ .setDefaultNbOfShards(DEFAULT_NUMBER_OF_SHARDS)
+ .build());
NewIndex.NewIndexType mapping = index.createType(INDEX_TYPE_METADATA.getType());
import org.sonar.server.es.NewIndex;
import static org.sonar.server.es.DefaultIndexSettingsElement.SORTABLE_ANALYZER;
+import static org.sonar.server.es.NewIndex.SettingsConfiguration.MANUAL_REFRESH_INTERVAL;
+import static org.sonar.server.es.NewIndex.SettingsConfiguration.newBuilder;
/**
* Definition of ES index "issues", including settings and fields.
@Override
public void define(IndexDefinitionContext context) {
- NewIndex index = context.create(INDEX_TYPE_ISSUE.getIndex());
-
- index.refreshHandledByIndexer();
- index.configureShards(config, 5);
+ NewIndex index = context.create(
+ INDEX_TYPE_ISSUE.getIndex(),
+ newBuilder(config)
+ .setRefreshInterval(MANUAL_REFRESH_INTERVAL)
+ .setDefaultNbOfShards(5)
+ .build());
NewIndex.NewIndexType type = index.createType(INDEX_TYPE_ISSUE.getType());
type.requireProjectAuthorization();
import static org.sonar.server.es.DefaultIndexSettingsElement.SEARCH_GRAMS_ANALYZER;
import static org.sonar.server.es.DefaultIndexSettingsElement.SORTABLE_ANALYZER;
+import static org.sonar.server.es.NewIndex.SettingsConfiguration.MANUAL_REFRESH_INTERVAL;
+import static org.sonar.server.es.NewIndex.SettingsConfiguration.newBuilder;
public class ProjectMeasuresIndexDefinition implements IndexDefinition {
@Override
public void define(IndexDefinitionContext context) {
- NewIndex index = context.create(INDEX_TYPE_PROJECT_MEASURES.getIndex());
- index.refreshHandledByIndexer();
- index.configureShards(config, 5);
+ NewIndex index = context.create(
+ INDEX_TYPE_PROJECT_MEASURES.getIndex(),
+ newBuilder(config)
+ .setRefreshInterval(MANUAL_REFRESH_INTERVAL)
+ .setDefaultNbOfShards(5)
+ .build());
NewIndex.NewIndexType mapping = index.createType(INDEX_TYPE_PROJECT_MEASURES.getType())
.requireProjectAuthorization();
import static org.sonar.server.es.DefaultIndexSettingsElement.ENGLISH_HTML_ANALYZER;
import static org.sonar.server.es.DefaultIndexSettingsElement.SEARCH_WORDS_ANALYZER;
import static org.sonar.server.es.DefaultIndexSettingsElement.SORTABLE_ANALYZER;
+import static org.sonar.server.es.NewIndex.SettingsConfiguration.MANUAL_REFRESH_INTERVAL;
+import static org.sonar.server.es.NewIndex.SettingsConfiguration.newBuilder;
/**
* Definition of ES index "rules", including settings and fields.
@Override
public void define(IndexDefinitionContext context) {
- NewIndex index = context.create(INDEX_TYPE_RULE.getIndex());
-
- index.refreshHandledByIndexer();
- // Default nb of shards should be greater than 1 in order to
- // easily detect routing misconfiguration.
- // See https://jira.sonarsource.com/browse/SONAR-9489
- index.configureShards(config, 2);
+ NewIndex index = context.create(
+ INDEX_TYPE_RULE.getIndex(),
+ newBuilder(config)
+ .setRefreshInterval(MANUAL_REFRESH_INTERVAL)
+ // Default nb of shards should be greater than 1 in order to
+ // easily detect routing misconfiguration.
+ // See https://jira.sonarsource.com/browse/SONAR-9489
+ .setDefaultNbOfShards(2)
+ .build());
// Active rule type
NewIndex.NewIndexType activeRuleMapping = index.createType(INDEX_TYPE_ACTIVE_RULE.getType());
import static org.sonar.server.es.DefaultIndexSettings.FIELD_TYPE_KEYWORD;
import static org.sonar.server.es.DefaultIndexSettings.INDEX_SEARCHABLE;
+import static org.sonar.server.es.NewIndex.SettingsConfiguration.MANUAL_REFRESH_INTERVAL;
+import static org.sonar.server.es.NewIndex.SettingsConfiguration.newBuilder;
public class TestIndexDefinition implements IndexDefinition {
@Override
public void define(IndexDefinitionContext context) {
- NewIndex index = context.create(INDEX_TYPE_TEST.getIndex());
-
- index.refreshHandledByIndexer();
- index.configureShards(config, 5);
+ NewIndex index = context.create(
+ INDEX_TYPE_TEST.getIndex(),
+ newBuilder(config)
+ .setRefreshInterval(MANUAL_REFRESH_INTERVAL)
+ .setDefaultNbOfShards(5)
+ .build());
NewIndex.NewIndexType mapping = index.createType(INDEX_TYPE_TEST.getType());
mapping.setAttribute("_routing", ImmutableMap.of("required", true));
import static org.sonar.server.es.DefaultIndexSettingsElement.SORTABLE_ANALYZER;
import static org.sonar.server.es.DefaultIndexSettingsElement.USER_SEARCH_GRAMS_ANALYZER;
+import static org.sonar.server.es.NewIndex.SettingsConfiguration.newBuilder;
/**
* Definition of ES index "users", including settings and fields.
@Override
public void define(IndexDefinitionContext context) {
- NewIndex index = context.create(INDEX_TYPE_USER.getIndex());
-
- index.configureShards(config, 1);
+ NewIndex index = context.create(INDEX_TYPE_USER.getIndex(),
+ newBuilder(config)
+ .setDefaultNbOfShards(1)
+ .build());
// type "user"
NewIndex.NewIndexType mapping = index.createType(INDEX_TYPE_USER.getType());
import org.sonar.server.es.IndexType;
import org.sonar.server.es.NewIndex;
+import static org.sonar.server.es.NewIndex.SettingsConfiguration.newBuilder;
+
/**
* Definition of ES index "views", including settings and fields.
*/
@Override
public void define(IndexDefinitionContext context) {
- NewIndex index = context.create(INDEX_TYPE_VIEW.getIndex());
-
- index.configureShards(config, 5);
+ NewIndex index = context.create(
+ INDEX_TYPE_VIEW.getIndex(),
+ newBuilder(config)
+ .setDefaultNbOfShards(5)
+ .build());
// type "view"
NewIndex.NewIndexType mapping = index.createType(INDEX_TYPE_VIEW.getType());
package org.sonar.server.es;
import org.elasticsearch.cluster.metadata.IndexMetaData;
+import org.sonar.api.config.internal.MapSettings;
+
+import static org.sonar.server.es.NewIndex.SettingsConfiguration.newBuilder;
public class FakeIndexDefinition implements IndexDefinition {
@Override
public void define(IndexDefinitionContext context) {
- NewIndex index = context.create(INDEX);
+ NewIndex index = context.create(INDEX, newBuilder(new MapSettings().asConfig()).build());
index.getSettings().put(IndexMetaData.SETTING_NUMBER_OF_REPLICAS, replicas);
index.getSettings().put("index.refresh_interval", "-1");
NewIndex.NewIndexType type = index.createType(INDEX_TYPE_FAKE.getType());
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.sonar.server.es.NewIndex.SettingsConfiguration.newBuilder;
public class IndexCreatorTest {
+ private static final NewIndex.SettingsConfiguration settingsConfiguration = newBuilder(new MapSettings().asConfig()).build();
+
@Rule
public EsTester es = new EsTester();
+
private MetadataIndexDefinition metadataIndexDefinition = new MetadataIndexDefinition(new MapSettings().asConfig());
private MetadataIndex metadataIndex = new MetadataIndex(es.client());
public void mark_all_non_existing_index_types_as_uninitialized() throws Exception {
MetadataIndex metadataIndexMock = mock(MetadataIndex.class);
IndexDefinitions registry = new IndexDefinitions(new IndexDefinition[] {context -> {
- NewIndex i = context.create("i");
+
+ NewIndex i = context.create("i", settingsConfiguration);
i.createType("t1");
i.createType("t2");
}}, new MapSettings().asConfig());
public static class FakeIndexDefinition implements IndexDefinition {
@Override
public void define(IndexDefinitionContext context) {
- NewIndex index = context.create("fakes");
+ NewIndex index = context.create("fakes", settingsConfiguration);
NewIndex.NewIndexType mapping = index.createType("fake");
mapping.keywordFieldBuilder("key").build();
mapping.createDateTimeField("updatedAt");
public static class FakeIndexDefinitionV2 implements IndexDefinition {
@Override
public void define(IndexDefinitionContext context) {
- NewIndex index = context.create("fakes");
+ NewIndex index = context.create("fakes", settingsConfiguration);
NewIndex.NewIndexType mapping = index.createType("fake");
mapping.keywordFieldBuilder("key").build();
mapping.createDateTimeField("updatedAt");
package org.sonar.server.es;
import org.junit.Test;
+import org.sonar.api.config.internal.MapSettings;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.fail;
+import static org.sonar.server.es.NewIndex.SettingsConfiguration.newBuilder;
public class IndexDefinitionContextTest {
+ private NewIndex.SettingsConfiguration emptySettingsConfiguration = newBuilder(new MapSettings().asConfig()).build();
@Test
public void create_indices() {
IndexDefinition.IndexDefinitionContext context = new IndexDefinition.IndexDefinitionContext();
- context.create("issues");
- context.create("measures");
+ context.create("issues", emptySettingsConfiguration);
+ context.create("measures", emptySettingsConfiguration);
assertThat(context.getIndices().keySet()).containsOnly("issues", "measures");
}
public void fail_to_create_twice_the_same_index() {
IndexDefinition.IndexDefinitionContext context = new IndexDefinition.IndexDefinitionContext();
- context.create("issues");
+ context.create("issues", emptySettingsConfiguration);
try {
- context.create("issues");
+ context.create("issues", emptySettingsConfiguration);
fail();
} catch (IllegalArgumentException ok) {
assertThat(ok).hasMessage("Index already exists: issues");
import org.junit.Test;
import java.util.Arrays;
+import org.sonar.api.config.internal.MapSettings;
import static org.assertj.core.api.Assertions.assertThat;
+import static org.sonar.server.es.NewIndex.SettingsConfiguration.newBuilder;
public class IndexDefinitionHashTest {
}
private NewIndex createIndex() {
- NewIndex newIndex = new NewIndex("fakes");
+ NewIndex newIndex = new NewIndex("fakes", newBuilder(new MapSettings().asConfig()).build());
NewIndex.NewIndexType mapping = newIndex.createType("fake");
mapping.setAttribute("list_attr", Arrays.asList("foo", "bar"));
mapping.keywordFieldBuilder("key").build();
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.es;
+
+import java.util.Random;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.sonar.api.config.Configuration;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.sonar.server.es.NewIndex.SettingsConfiguration.newBuilder;
+
+public class NewIndexSettingsConfigurationTest {
+ @Rule
+ public ExpectedException expectedException = ExpectedException.none();
+
+ private Configuration mockConfiguration = mock(Configuration.class);
+
+ @Test
+ public void newBuilder_fails_with_NPE_when_Configuration_is_null() {
+ expectedException.expect(NullPointerException.class);
+ expectedException.expectMessage("configuration can't be null");
+
+ newBuilder(null);
+ }
+
+ @Test
+ public void setDefaultNbOfShards_fails_with_IAE_if_argument_is_zero() {
+ NewIndex.SettingsConfiguration.Builder underTest = newBuilder(mockConfiguration);
+
+ expectedException.expect(IllegalArgumentException.class);
+ expectedException.expectMessage("defaultNbOfShards must be >= 1");
+
+ underTest.setDefaultNbOfShards(0);
+ }
+
+ @Test
+ public void setDefaultNbOfShards_fails_with_IAE_if_argument_is_less_than_zero() {
+ NewIndex.SettingsConfiguration.Builder underTest = newBuilder(mockConfiguration);
+
+ expectedException.expect(IllegalArgumentException.class);
+ expectedException.expectMessage("defaultNbOfShards must be >= 1");
+
+ underTest.setDefaultNbOfShards(-1 - new Random().nextInt(10));
+ }
+
+ @Test
+ public void setDefaultNbOfShards_accepts_1() {
+ NewIndex.SettingsConfiguration.Builder underTest = newBuilder(mockConfiguration);
+
+ assertThat(underTest.setDefaultNbOfShards(1).build().getDefaultNbOfShards()).isEqualTo(1);
+ }
+
+ @Test
+ public void setDefaultNbOfShards_accepts_any_int_greater_than_1() {
+ NewIndex.SettingsConfiguration.Builder underTest = newBuilder(mockConfiguration);
+
+ int value = 1 + new Random().nextInt(200);
+
+ assertThat(underTest.setDefaultNbOfShards(value).build().getDefaultNbOfShards()).isEqualTo(value);
+ }
+
+ @Test
+ public void getDefaultNbOfShards_returns_1_when_not_explicitly_set() {
+ assertThat(newBuilder(mockConfiguration).build().getDefaultNbOfShards()).isEqualTo(1);
+ }
+
+ @Test
+ public void setRefreshInterval_fails_with_IAE_if_argument_is_zero() {
+ NewIndex.SettingsConfiguration.Builder underTest = newBuilder(mockConfiguration);
+
+ expectedException.expect(IllegalArgumentException.class);
+ expectedException.expectMessage("refreshInterval must be either -1 or strictly positive");
+
+ underTest.setRefreshInterval(0);
+ }
+
+ @Test
+ public void setRefreshInterval_fails_with_IAE_if_argument_is_less_than_minus_1() {
+ NewIndex.SettingsConfiguration.Builder underTest = newBuilder(mockConfiguration);
+
+ expectedException.expect(IllegalArgumentException.class);
+ expectedException.expectMessage("refreshInterval must be either -1 or strictly positive");
+
+ underTest.setRefreshInterval(-2 - new Random().nextInt(10));
+ }
+
+ @Test
+ public void setRefreshInterval_accepts_minus_1() {
+ NewIndex.SettingsConfiguration.Builder underTest = newBuilder(mockConfiguration);
+
+ assertThat(underTest.setRefreshInterval(-1).build().getRefreshInterval()).isEqualTo(-1);
+ }
+
+ @Test
+ public void setRefreshInterval_accepts_any_int_greater_than_1() {
+ NewIndex.SettingsConfiguration.Builder underTest = newBuilder(mockConfiguration);
+
+ int value = 1 + new Random().nextInt(200);
+
+ assertThat(underTest.setRefreshInterval(value).build().getRefreshInterval()).isEqualTo(value);
+ }
+
+ @Test
+ public void getRefreshInterval_returns_30_when_not_explicitly_set() {
+ assertThat(newBuilder(mockConfiguration).build().getRefreshInterval()).isEqualTo(30);
+ }
+}
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.data.MapEntry.entry;
import static org.junit.Assert.fail;
+import static org.sonar.process.ProcessProperties.CLUSTER_ENABLED;
+import static org.sonar.server.es.NewIndex.SettingsConfiguration.newBuilder;
public class NewIndexTest {
@Rule
public ExpectedException expectedException = ExpectedException.none();
+ private MapSettings settings = new MapSettings();
+ private NewIndex.SettingsConfiguration defaultSettingsConfiguration = newBuilder(settings.asConfig()).build();
+
+ @Test
+ public void getName_returns_constructor_argument() {
+ assertThat(new NewIndex("foo", defaultSettingsConfiguration).getName()).isEqualTo("foo");
+ }
+
+ @Test
+ public void no_types_of_none_are_specified() {
+ assertThat(new NewIndex("foo", defaultSettingsConfiguration).getTypes()).isEmpty();
+ }
+
@Test
- public void most_basic_index() {
- NewIndex index = new NewIndex("issues");
- assertThat(index.getName()).isEqualTo("issues");
- assertThat(index.getTypes()).isEmpty();
- Settings settings = index.getSettings().build();
- // test some basic settings
- assertThat(settings.get("index.number_of_shards")).isNotEmpty();
+ public void verify_default_index_settings_in_standalone() {
+ Settings underTest = new NewIndex("issues", defaultSettingsConfiguration).getSettings().build();
+
+ assertThat(underTest.get("index.number_of_shards")).isNotEmpty();
+ assertThat(underTest.get("index.mapper.dynamic")).isEqualTo("false");
+ assertThat(underTest.get("index.refresh_interval")).isEqualTo("30s");
+ assertThat(underTest.get("index.number_of_shards")).isEqualTo("1");
+ assertThat(underTest.get("index.number_of_replicas")).isEqualTo("0");
+ }
+
+ @Test
+ public void verify_default_index_settings_in_cluster() {
+ settings.setProperty(CLUSTER_ENABLED, "true");
+ Settings underTest = new NewIndex("issues", defaultSettingsConfiguration).getSettings().build();
+
+ assertThat(underTest.get("index.number_of_shards")).isNotEmpty();
+ assertThat(underTest.get("index.mapper.dynamic")).isEqualTo("false");
+ assertThat(underTest.get("index.refresh_interval")).isEqualTo("30s");
+ assertThat(underTest.get("index.number_of_shards")).isEqualTo("1");
+ assertThat(underTest.get("index.number_of_replicas")).isEqualTo("1");
}
@Test
public void index_name_is_lower_case() {
try {
- new NewIndex("Issues");
+ new NewIndex("Issues", defaultSettingsConfiguration);
fail();
} catch (IllegalArgumentException e) {
assertThat(e).hasMessage("Index name must be lower-case: Issues");
@Test
public void define_fields() {
- NewIndex index = new NewIndex("issues");
+ NewIndex index = new NewIndex("issues", defaultSettingsConfiguration);
NewIndex.NewIndexType mapping = index.createType("issue");
mapping.setAttribute("dynamic", "true");
mapping.setProperty("foo_field", ImmutableMap.of("type", "keyword"));
@Test
public void define_string_field() {
- NewIndex index = new NewIndex("issues");
+ NewIndex index = new NewIndex("issues", defaultSettingsConfiguration);
NewIndex.NewIndexType mapping = index.createType("issue");
mapping.keywordFieldBuilder("basic_field").build();
mapping.keywordFieldBuilder("not_searchable_field").disableSearch().build();
@Test
public void define_nested_field() {
- NewIndex index = new NewIndex("projectmeasures");
+ NewIndex index = new NewIndex("projectmeasures", defaultSettingsConfiguration);
NewIndex.NewIndexType mapping = index.createType("projectmeasures");
mapping.nestedFieldBuilder("measures")
expectedException.expect(IllegalArgumentException.class);
expectedException.expectMessage("At least one sub-field must be declared in nested property 'measures'");
- NewIndex index = new NewIndex("projectmeasures");
+ NewIndex index = new NewIndex("projectmeasures", defaultSettingsConfiguration);
NewIndex.NewIndexType mapping = index.createType("project_measures");
mapping.nestedFieldBuilder("measures").build();
@Test
public void use_default_doc_values() {
- NewIndex index = new NewIndex("issues");
+ NewIndex index = new NewIndex("issues", defaultSettingsConfiguration);
NewIndex.NewIndexType mapping = index.createType("issue");
mapping.keywordFieldBuilder("the_doc_value").build();
@Test
public void default_shards_and_replicas() {
- NewIndex index = new NewIndex("issues");
- index.configureShards(new MapSettings().asConfig(), 5);
+ NewIndex index = new NewIndex("issues", newBuilder(settings.asConfig()).setDefaultNbOfShards(5).build());
+
assertThat(index.getSettings().get(IndexMetaData.SETTING_NUMBER_OF_SHARDS)).isEqualTo("5");
assertThat(index.getSettings().get(IndexMetaData.SETTING_NUMBER_OF_REPLICAS)).isEqualTo("0");
}
@Test
public void five_shards_and_one_replica_by_default_on_cluster() {
- NewIndex index = new NewIndex("issues");
- MapSettings settings = new MapSettings();
- settings.setProperty(ProcessProperties.CLUSTER_ENABLED, "true");
- index.configureShards(settings.asConfig(), 5);
+ settings.setProperty(CLUSTER_ENABLED, "true");
+ NewIndex index = new NewIndex("issues", newBuilder(settings.asConfig()).setDefaultNbOfShards(5).build());
+
assertThat(index.getSettings().get(IndexMetaData.SETTING_NUMBER_OF_SHARDS)).isEqualTo("5");
assertThat(index.getSettings().get(IndexMetaData.SETTING_NUMBER_OF_REPLICAS)).isEqualTo("1");
}
@Test
public void customize_number_of_shards() {
- NewIndex index = new NewIndex("issues");
- MapSettings settings = new MapSettings();
settings.setProperty("sonar.search.issues.shards", "3");
- index.configureShards(settings.asConfig(), 5);
+ NewIndex index = new NewIndex("issues", newBuilder(settings.asConfig()).setDefaultNbOfShards(5).build());
+
assertThat(index.getSettings().get(IndexMetaData.SETTING_NUMBER_OF_SHARDS)).isEqualTo("3");
// keep default value
assertThat(index.getSettings().get(IndexMetaData.SETTING_NUMBER_OF_REPLICAS)).isEqualTo("0");
@Test
public void default_number_of_replicas_on_standalone_instance_must_be_0() {
- NewIndex index = new NewIndex("issues");
- MapSettings settings = new MapSettings();
- index.configureShards(settings.asConfig(), 5);
+ NewIndex index = new NewIndex("issues", newBuilder(settings.asConfig()).setDefaultNbOfShards(5).build());
+
assertThat(index.getSettings().get(IndexMetaData.SETTING_NUMBER_OF_REPLICAS)).isEqualTo("0");
}
@Test
public void default_number_of_replicas_on_non_enabled_cluster_must_be_0() {
- NewIndex index = new NewIndex("issues");
- MapSettings settings = new MapSettings();
- settings.setProperty(ProcessProperties.CLUSTER_ENABLED, "false");
- index.configureShards(settings.asConfig(), 5);
+ settings.setProperty(CLUSTER_ENABLED, "false");
+ NewIndex index = new NewIndex("issues", newBuilder(settings.asConfig()).setDefaultNbOfShards(5).build());
+
assertThat(index.getSettings().get(IndexMetaData.SETTING_NUMBER_OF_REPLICAS)).isEqualTo("0");
}
@Test
public void default_number_of_replicas_on_cluster_instance_must_be_1() {
- NewIndex index = new NewIndex("issues");
- MapSettings settings = new MapSettings();
- settings.setProperty(ProcessProperties.CLUSTER_ENABLED, "true");
- index.configureShards(settings.asConfig(), 5);
+ settings.setProperty(CLUSTER_ENABLED, "true");
+ NewIndex index = new NewIndex("issues", newBuilder(settings.asConfig()).setDefaultNbOfShards(5).build());
+
assertThat(index.getSettings().get(IndexMetaData.SETTING_NUMBER_OF_REPLICAS)).isEqualTo("1");
}
@Test
public void when_number_of_replicas_on_cluster_is_specified_to_zero_default_value_must_not_be_used() {
- NewIndex index = new NewIndex("issues");
- MapSettings settings = new MapSettings();
- settings.setProperty(ProcessProperties.CLUSTER_ENABLED, "true");
+ settings.setProperty(CLUSTER_ENABLED, "true");
settings.setProperty(ProcessProperties.SEARCH_REPLICAS, "0");
- index.configureShards(settings.asConfig(), 5);
+ NewIndex index = new NewIndex("issues", newBuilder(settings.asConfig()).setDefaultNbOfShards(5).build());
+
assertThat(index.getSettings().get(IndexMetaData.SETTING_NUMBER_OF_REPLICAS)).isEqualTo("0");
}
@Test
- public void customize_number_of_replicas() {
- NewIndex index = new NewIndex("issues");
- MapSettings settings = new MapSettings();
+ public void index_defined_with_specified_number_of_replicas_when_cluster_enabled() {
+ settings.setProperty(CLUSTER_ENABLED, "true");
settings.setProperty(ProcessProperties.SEARCH_REPLICAS, "3");
- index.configureShards(settings.asConfig(), 5);
+ NewIndex index = new NewIndex("issues", newBuilder(settings.asConfig()).setDefaultNbOfShards(5).build());
+
assertThat(index.getSettings().get(IndexMetaData.SETTING_NUMBER_OF_REPLICAS)).isEqualTo("3");
}
+ @Test
+ public void fail_when_replica_customization_cant_be_parsed() throws Exception {
+ settings.setProperty(CLUSTER_ENABLED, "true");
+ settings.setProperty(ProcessProperties.SEARCH_REPLICAS, "ꝱꝲꝳପ");
+ NewIndex.SettingsConfiguration settingsConfiguration = newBuilder(settings.asConfig()).setDefaultNbOfShards(5).build();
+
+ expectedException.expect(IllegalStateException.class);
+ expectedException.expectMessage("The property 'sonar.search.replicas' is not an int value: For input string: \"ꝱꝲꝳପ\"");
+
+ new NewIndex("issues", settingsConfiguration);
+ }
+
+ @Test
+ public void in_standalone_searchReplicas_is_not_overridable() throws Exception {
+ settings.setProperty(ProcessProperties.SEARCH_REPLICAS, "5");
+ NewIndex index = new NewIndex("issues", defaultSettingsConfiguration);
+
+ assertThat(index.getSettings().get("index.number_of_replicas")).isEqualTo("0");
+ }
+
@Test
public void index_with_source() {
- NewIndex index = new NewIndex("issues");
+ NewIndex index = new NewIndex("issues", defaultSettingsConfiguration);
NewIndex.NewIndexType mapping = index.createType("issue");
mapping.setEnableSource(true);
@Test
public void index_without_source() {
- NewIndex index = new NewIndex("issues");
+ NewIndex index = new NewIndex("issues", defaultSettingsConfiguration);
NewIndex.NewIndexType mapping = index.createType("issue");
mapping.setEnableSource(false);
@Test
public void index_requires_project_authorization() {
- NewIndex index = new NewIndex("issues");
+ NewIndex index = new NewIndex("issues", defaultSettingsConfiguration);
index.createType("issue")
// creates a second type "authorization" and configures _parent and _routing fields
.requireProjectAuthorization();
*/
package org.sonar.server.permission.index;
+import org.sonar.api.config.internal.MapSettings;
import org.sonar.server.es.IndexDefinition;
import org.sonar.server.es.IndexType;
import org.sonar.server.es.NewIndex;
+import static org.sonar.server.es.NewIndex.SettingsConfiguration.MANUAL_REFRESH_INTERVAL;
+import static org.sonar.server.es.NewIndex.SettingsConfiguration.newBuilder;
+
public class FooIndexDefinition implements IndexDefinition {
public static final String FOO_INDEX = "foos";
@Override
public void define(IndexDefinitionContext context) {
- NewIndex index = context.create(FOO_INDEX);
- index.refreshHandledByIndexer();
+ NewIndex index = context.create(FOO_INDEX, newBuilder(new MapSettings().asConfig()).setRefreshInterval(MANUAL_REFRESH_INTERVAL).build());
NewIndex.NewIndexType type = index.createType(FOO_TYPE)
.requireProjectAuthorization();