/*
 * 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.test;

import org.elasticsearch.action.admin.cluster.health.ClusterHealthResponse;
import org.elasticsearch.action.admin.cluster.health.ClusterHealthStatus;
import org.elasticsearch.client.Requests;
import org.elasticsearch.cluster.ClusterName;
import org.elasticsearch.cluster.metadata.IndexMetaData;
import org.elasticsearch.cluster.metadata.MetaData;
import org.elasticsearch.common.Priority;
import org.elasticsearch.common.settings.ImmutableSettings;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.concurrent.EsExecutors;
import org.elasticsearch.index.service.IndexService;
import org.elasticsearch.indices.IndicesService;
import org.elasticsearch.node.Node;
import org.elasticsearch.node.NodeBuilder;
import org.elasticsearch.node.internal.InternalNode;
import org.junit.After;

import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.lessThanOrEqualTo;

/**
 * A test that keep a single node started for all tests that can be used to get
 * references to Guice injectors in unit tests.
 */
public class ElasticsearchSingleNodeTest extends ElasticsearchTestCase {

    private static final Node node = node();

    @After
    public void after() {
        node.client().admin().indices().prepareDelete("*").get();
        MetaData metaData = node.client().admin().cluster().prepareState().get().getState().getMetaData();
        assertThat("test leaves persistent cluster metadata behind: " + metaData.persistentSettings().getAsMap(),
                metaData.persistentSettings().getAsMap().size(), equalTo(0));
        assertThat("test leaves transient cluster metadata behind: " + metaData.transientSettings().getAsMap(),
                metaData.transientSettings().getAsMap().size(), equalTo(0));
    }

    /**
     * Same as {@link #node(Settings) node(ImmutableSettings.EMPTY)}.
     */
    public static Node node() {
        return node(ImmutableSettings.EMPTY);
    }

    public static Node node(Settings settings) {
        return NodeBuilder.nodeBuilder().local(true).data(true).settings(ImmutableSettings.builder()
                .put(ClusterName.SETTING, ElasticsearchSingleNodeTest.class.getName())
                .put("node.name", ElasticsearchSingleNodeTest.class.getName())
                .put(IndexMetaData.SETTING_NUMBER_OF_SHARDS, 1)
                .put(IndexMetaData.SETTING_NUMBER_OF_REPLICAS, 0)
                .put(settings)
                .put(EsExecutors.PROCESSORS, 1) // limit the number of threads created
                .put("http.enabled", false)
                .put("index.store.type", "ram")
                .put("gateway.type", "none")).build().start();
    }

    public static <T> T getInstanceFromNode(Class<T> clazz, Node node) {
        return ((InternalNode) node).injector().getInstance(clazz);
    }

    public static IndexService createIndex(String index) {
        return createIndex(index, ImmutableSettings.EMPTY);
    }

    public static IndexService createIndex(String index, Settings settings) {
        node.client().admin().indices().prepareCreate(index).setSettings(settings).get();
        // Wait for the index to be allocated so that cluster state updates don't override
        // changes that would have been done locally
        ClusterHealthResponse health = node.client().admin().cluster()
                .health(Requests.clusterHealthRequest(index).waitForYellowStatus().waitForEvents(Priority.LANGUID).waitForRelocatingShards(0)).actionGet();
        assertThat(health.getStatus(), lessThanOrEqualTo(ClusterHealthStatus.YELLOW));
        IndicesService instanceFromNode = getInstanceFromNode(IndicesService.class, node);
        return instanceFromNode.indexService(index);
    }
}

@@ -1154,32 +1154,85 @@
 adata.MetaData;%0A
+import org.elasticsearch.cluster.node.DiscoveryNode;%0A
 import org.elast
@@ -1691,52 +1691,115 @@
 er;%0A
-%0Aimport static org.hamcrest.Matchers.equalTo
+import org.junit.Ignore;%0A%0Aimport static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked
 ;%0Aim
@@ -1832,33 +1832,17 @@
 atchers.
-lessThanOrEqualTo
+*
 ;%0A%0A/**%0A 
@@ -1972,22 +1972,39 @@
 ts.%0A */%0A
-public
+@Ignore%0Apublic abstract
  class E
@@ -2794,29 +2794,30 @@
     */%0A    p
-ublic
+rivate
  static Node
@@ -2876,37 +2876,38 @@
 Y);%0A    %7D%0A%0A    p
-ublic
+rivate
  static Node nod
@@ -2937,22 +2937,28 @@
         
-return
+Node build =
  NodeBui
@@ -3568,47 +3568,254 @@
 ut(%22
-gateway.type%22, %22none%22)).build().start()
+config.ignore_system_properties%22, true) // make sure we get what we set :)%0A                .put(%22gateway.type%22, %22none%22)).build();%0A        build.start();%0A        assertThat(DiscoveryNode.localNode(build.settings()), is(true));%0A        return build
 ;%0A  
@@ -4171,32 +4171,44 @@
 ings) %7B%0A        
+assertAcked(
 node.client().ad
@@ -4267,24 +4267,25 @@
 tings).get()
+)
 ;%0A        //
@@ -4728,24 +4728,128 @@
 s.YELLOW));%0A
+        assertThat(%22Cluster must be a single node cluster%22, health.getNumberOfDataNodes(), equalTo(1));%0A
         Indi
@@ -4971,16 +4971,20 @@
 xService
+Safe
 (index);
@@ -4990,10 +4990,12 @@
 ;%0A    %7D%0A
+%0A%0A
 %7D%0A

Enforce provided settings in test base classes