[CALCITE-2347] running ElasticSearch in embedded mode for unit tests of ES adapter...
[calcite.git] / elasticsearch2 / src / test / java / org / apache / calcite / adapter / elasticsearch2 / EmbeddedElasticNode.java
1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to you under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17 package org.apache.calcite.adapter.elasticsearch2;
18
19 import com.google.common.base.Preconditions;
20 import com.google.common.io.Files;
21
22 import org.elasticsearch.Version;
23 import org.elasticsearch.action.admin.cluster.node.info.NodeInfo;
24 import org.elasticsearch.action.admin.cluster.node.info.NodesInfoResponse;
25 import org.elasticsearch.client.Client;
26 import org.elasticsearch.common.settings.Settings;
27 import org.elasticsearch.common.transport.TransportAddress;
28 import org.elasticsearch.node.Node;
29 import org.elasticsearch.node.internal.InternalSettingsPreparer;
30 import org.elasticsearch.plugins.Plugin;
31 import org.elasticsearch.script.groovy.GroovyPlugin;
32
33 import java.io.File;
34 import java.util.Arrays;
35 import java.util.Collection;
36 import java.util.Collections;
37
38 /**
39 * Represents a single elastic search node which can run embedded in a java application.
40 * Intended for unit and integration tests. Settings and plugins are crafted for Calcite.
41 */
42 class EmbeddedElasticNode implements AutoCloseable {
43
44 private final LocalNode node;
45 private volatile boolean isStarted;
46
47 private EmbeddedElasticNode(LocalNode node) {
48 this.node = Preconditions.checkNotNull(node, "node");
49 }
50
51 /**
52 * Having separate class to expose (protected) constructor which allows to install
53 * different plugins. In our case it is {@code GroovyPlugin} for scripted fields like
54 * {@code loc[0]} or {@code loc[1]['foo']}.
55 */
56 private static class LocalNode extends Node {
57 private LocalNode(Settings settings, Collection<Class<? extends Plugin>> classpathPlugins) {
58 super(InternalSettingsPreparer.prepareEnvironment(settings, null),
59 Version.CURRENT,
60 classpathPlugins);
61 }
62 }
63
64 /**
65 * Creates an instance with existing settings
66 */
67 private static EmbeddedElasticNode create(Settings settings) {
68 // ensure GroovyPlugin is installed or otherwise scripted fields would not work
69 LocalNode node = new LocalNode(settings, Collections.singleton(GroovyPlugin.class));
70 return new EmbeddedElasticNode(node);
71 }
72
73 /**
74 * Creates elastic node as single member of a cluster. Node will not be started
75 * unless {@link #start()} is explicitly called.
76 */
77 public static EmbeddedElasticNode create() {
78 File data = Files.createTempDir();
79 data.deleteOnExit();
80 File home = Files.createTempDir();
81 home.deleteOnExit();
82
83 Settings settings = Settings.builder()
84 .put("node.name", "fake-elastic")
85 .put("path.home", home.getAbsolutePath())
86 .put("path.data", data.getAbsolutePath())
87 .put("script.inline", true) // requires GroovyPlugin
88 .put("script.indexed", true) // requires GroovyPlugin
89 .put("cluster.routing.allocation.disk.threshold_enabled", false)
90 .put("node.local", true)
91 .put("node.data", true)
92 .put("network.host", "localhost")
93 .build();
94
95 return create(settings);
96 }
97
98 /**
99 * Starts current node
100 */
101 public void start() {
102 Preconditions.checkState(!isStarted, "already started");
103 node.start();
104 this.isStarted = true;
105 }
106
107 /**
108 * Returns current address to connect to with HTTP client.
109 */
110 public TransportAddress httpAddress() {
111 Preconditions.checkState(isStarted, "node is not started");
112
113 NodesInfoResponse response = client().admin().cluster().prepareNodesInfo()
114 .execute().actionGet();
115 if (response.getNodes().length != 1) {
116 throw new IllegalStateException("Expected single node but got "
117 + response.getNodes().length);
118 }
119 NodeInfo node = response.getNodes()[0];
120 return node.getHttp().address().boundAddresses()[0];
121 }
122
123 /**
124 * Exposes elastic
125 * <a href="https://www.elastic.co/guide/en/elasticsearch/client/java-api/current/transport-client.html">transport client</a>
126 *
127 * (use of HTTP client is preferred).
128 */
129 public Client client() {
130 Preconditions.checkState(isStarted, "node is not started");
131 return node.client();
132 }
133
134 @Override public void close() throws Exception {
135 node.close();
136 // cleanup data dirs
137 File data = new File(node.settings().get("path.data"));
138 File home = new File(node.settings().get("path.home"));
139 for (File file: Arrays.asList(data, home)) {
140 if (file.exists()) {
141 file.delete();
142 }
143 }
144 }
145 }
146
147 // End EmbeddedElasticNode.java