> plugins() {
@@ -494,22 +498,87 @@ public class PluginsService extends AbstractComponent {
try {
Class extends Plugin> pluginClass = (Class extends Plugin>) settings.getClassLoader().loadClass(className);
Plugin plugin;
- try {
- plugin = pluginClass.getConstructor(Settings.class).newInstance(settings);
- } catch (NoSuchMethodException e) {
+
+ if (!checkLucene || checkLuceneCompatibility(pluginClass, settings, logger)) {
try {
- plugin = pluginClass.getConstructor().newInstance();
- } catch (NoSuchMethodException e1) {
- throw new ElasticsearchException("No constructor for [" + pluginClass + "]. A plugin class must " +
- "have either an empty default constructor or a single argument constructor accepting a " +
- "Settings instance");
+ plugin = pluginClass.getConstructor(Settings.class).newInstance(settings);
+ } catch (NoSuchMethodException e) {
+ try {
+ plugin = pluginClass.getConstructor().newInstance();
+ } catch (NoSuchMethodException e1) {
+ throw new ElasticsearchException("No constructor for [" + pluginClass + "]. A plugin class must " +
+ "have either an empty default constructor or a single argument constructor accepting a " +
+ "Settings instance");
+ }
}
+ } else {
+ throw new ElasticsearchException("Plugin is incompatible with the current node");
}
+
return plugin;
} catch (Throwable e) {
throw new ElasticsearchException("Failed to load plugin class [" + className + "]", e);
}
}
+
+ /**
+ * Check that a plugin is Lucene compatible with the current running node using `lucene` property
+ * in `es-plugin.properties` file.
+ * If plugin does not provide `lucene` property, we consider that the plugin is compatible.
+ * If plugin provides `lucene` property, we try to load related Enum org.apache.lucene.util.Version. If this
+ * fails, it means that the node is too "old" comparing to the Lucene version the plugin was built for.
+ * We compare then two first digits of current node lucene version against two first digits of plugin Lucene
+ * version. If not equal, it means that the plugin is too "old" for the current node.
+ *
+ * @param pluginClass Plugin class we are checking
+ * @return true if the plugin is Lucene compatible
+ */
+ public static boolean checkLuceneCompatibility(Class extends Plugin> pluginClass, Settings settings, ESLogger logger) {
+ String luceneVersion = null;
+ try {
+ // We try to read the es-plugin.properties file
+ // But as we can have several plugins in the same classloader,
+ // we have to find the right es-plugin.properties file
+ Enumeration pluginUrls = settings.getClassLoader().getResources(PluginsService.ES_PLUGIN_PROPERTIES);
+
+ while (pluginUrls.hasMoreElements()) {
+ URL pluginUrl = pluginUrls.nextElement();
+ try (InputStream is = pluginUrl.openStream()) {
+ Properties pluginProps = new Properties();
+ pluginProps.load(is);
+ String plugin = pluginProps.getProperty("plugin");
+ // If we don't have the expected plugin, let's continue to the next one
+ if (pluginClass.getName().equals(plugin)) {
+ luceneVersion = pluginProps.getProperty("lucene");
+ break;
+ }
+ logger.debug("skipping [{}]", pluginUrl);
+ }
+ }
+
+ if (luceneVersion != null) {
+ // We only keep the first two parts
+ String parts[] = luceneVersion.split("\\.");
+
+ // Should fail if the running node is too old!
+ org.apache.lucene.util.Version luceneExpectedVersion = org.apache.lucene.util.Version.parseLeniently(parts[0]+"."+parts[1]);
+
+ if (Version.CURRENT.luceneVersion.equals(luceneExpectedVersion)) {
+ logger.debug("starting analysis plugin for Lucene [{}].", luceneExpectedVersion);
+ return true;
+ }
+ } else {
+ logger.debug("lucene property is not set in plugin {} file. Skipping test.", PluginsService.ES_PLUGIN_PROPERTIES);
+ return true;
+ }
+ } catch (Throwable t) {
+ // We don't have the expected version... Let's fail after.
+ logger.debug("exception raised while checking plugin Lucene version.", t);
+ }
+ logger.error("cannot start plugin due to incorrect Lucene version: plugin [{}], node [{}].",
+ luceneVersion, Constants.LUCENE_MAIN_VERSION);
+ return false;
+ }
}
diff --git a/src/test/java/org/elasticsearch/nodesinfo/SimpleNodesInfoTests.java b/src/test/java/org/elasticsearch/nodesinfo/SimpleNodesInfoTests.java
index 983af06b16b..f7c68889d67 100644
--- a/src/test/java/org/elasticsearch/nodesinfo/SimpleNodesInfoTests.java
+++ b/src/test/java/org/elasticsearch/nodesinfo/SimpleNodesInfoTests.java
@@ -19,22 +19,18 @@
package org.elasticsearch.nodesinfo;
-import com.google.common.base.Function;
-import com.google.common.base.Predicate;
-import com.google.common.base.Predicates;
-import com.google.common.collect.FluentIterable;
-import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import org.elasticsearch.action.admin.cluster.health.ClusterHealthResponse;
import org.elasticsearch.action.admin.cluster.node.info.NodesInfoResponse;
import org.elasticsearch.action.admin.cluster.node.info.PluginInfo;
-import org.elasticsearch.action.admin.cluster.node.info.PluginsInfo;
import org.elasticsearch.cluster.ClusterService;
import org.elasticsearch.common.settings.ImmutableSettings;
+import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.nodesinfo.plugin.dummy1.TestPlugin;
import org.elasticsearch.nodesinfo.plugin.dummy2.TestNoVersionPlugin;
import org.elasticsearch.test.ElasticsearchIntegrationTest;
import org.elasticsearch.test.ElasticsearchIntegrationTest.ClusterScope;
+import org.elasticsearch.test.hamcrest.ElasticsearchAssertions;
import org.junit.Test;
import java.io.File;
@@ -43,8 +39,6 @@ import java.net.URL;
import java.util.Collections;
import java.util.List;
-import static com.google.common.base.Predicates.and;
-import static com.google.common.base.Predicates.isNull;
import static org.elasticsearch.client.Requests.clusterHealthRequest;
import static org.elasticsearch.client.Requests.nodesInfoRequest;
import static org.elasticsearch.common.settings.ImmutableSettings.settingsBuilder;
@@ -133,23 +127,23 @@ public class SimpleNodesInfoTests extends ElasticsearchIntegrationTest {
NodesInfoResponse response = client().admin().cluster().prepareNodesInfo().clear().setPlugins(true).execute().actionGet();
logger.info("--> full json answer, status " + response.toString());
- assertNodeContainsPlugins(response, server1NodeId,
+ ElasticsearchAssertions.assertNodeContainsPlugins(response, server1NodeId,
Collections.EMPTY_LIST, Collections.EMPTY_LIST, Collections.EMPTY_LIST, // No JVM Plugin
Collections.EMPTY_LIST, Collections.EMPTY_LIST, Collections.EMPTY_LIST);// No Site Plugin
- assertNodeContainsPlugins(response, server2NodeId,
+ ElasticsearchAssertions.assertNodeContainsPlugins(response, server2NodeId,
Collections.EMPTY_LIST, Collections.EMPTY_LIST, Collections.EMPTY_LIST, // No JVM Plugin
Lists.newArrayList(Fields.SITE_PLUGIN), // Site Plugin
Lists.newArrayList(Fields.SITE_PLUGIN_DESCRIPTION),
Lists.newArrayList(Fields.SITE_PLUGIN_VERSION));
- assertNodeContainsPlugins(response, server3NodeId,
+ ElasticsearchAssertions.assertNodeContainsPlugins(response, server3NodeId,
Lists.newArrayList(TestPlugin.Fields.NAME), // JVM Plugin
Lists.newArrayList(TestPlugin.Fields.DESCRIPTION),
Lists.newArrayList(PluginInfo.VERSION_NOT_AVAILABLE),
Collections.EMPTY_LIST, Collections.EMPTY_LIST, Collections.EMPTY_LIST);// No site Plugin
- assertNodeContainsPlugins(response, server4NodeId,
+ ElasticsearchAssertions.assertNodeContainsPlugins(response, server4NodeId,
Lists.newArrayList(TestNoVersionPlugin.Fields.NAME), // JVM Plugin
Lists.newArrayList(TestNoVersionPlugin.Fields.DESCRIPTION),
Lists.newArrayList(PluginInfo.VERSION_NOT_AVAILABLE),
@@ -158,63 +152,14 @@ public class SimpleNodesInfoTests extends ElasticsearchIntegrationTest {
Lists.newArrayList(PluginInfo.VERSION_NOT_AVAILABLE));
}
- private void assertNodeContainsPlugins(NodesInfoResponse response, String nodeId,
- List expectedJvmPluginNames,
- List expectedJvmPluginDescriptions,
- List expectedJvmVersions,
- List expectedSitePluginNames,
- List expectedSitePluginDescriptions,
- List expectedSiteVersions) {
-
- assertThat(response.getNodesMap().get(nodeId), notNullValue());
-
- PluginsInfo plugins = response.getNodesMap().get(nodeId).getPlugins();
- assertThat(plugins, notNullValue());
-
- List pluginNames = FluentIterable.from(plugins.getInfos()).filter(jvmPluginPredicate).transform(nameFunction).toList();
- for (String expectedJvmPluginName : expectedJvmPluginNames) {
- assertThat(pluginNames, hasItem(expectedJvmPluginName));
- }
-
- List pluginDescriptions = FluentIterable.from(plugins.getInfos()).filter(jvmPluginPredicate).transform(descriptionFunction).toList();
- for (String expectedJvmPluginDescription : expectedJvmPluginDescriptions) {
- assertThat(pluginDescriptions, hasItem(expectedJvmPluginDescription));
- }
-
- List jvmPluginVersions = FluentIterable.from(plugins.getInfos()).filter(jvmPluginPredicate).transform(versionFunction).toList();
- for (String pluginVersion : expectedJvmVersions) {
- assertThat(jvmPluginVersions, hasItem(pluginVersion));
- }
-
- FluentIterable jvmUrls = FluentIterable.from(plugins.getInfos())
- .filter(and(jvmPluginPredicate, Predicates.not(sitePluginPredicate)))
- .filter(isNull())
- .transform(urlFunction);
- assertThat(Iterables.size(jvmUrls), is(0));
-
- List sitePluginNames = FluentIterable.from(plugins.getInfos()).filter(sitePluginPredicate).transform(nameFunction).toList();
- for (String expectedSitePluginName : expectedSitePluginNames) {
- assertThat(sitePluginNames, hasItem(expectedSitePluginName));
- }
-
- List sitePluginDescriptions = FluentIterable.from(plugins.getInfos()).filter(sitePluginPredicate).transform(descriptionFunction).toList();
- for (String sitePluginDescription : expectedSitePluginDescriptions) {
- assertThat(sitePluginDescriptions, hasItem(sitePluginDescription));
- }
-
- List sitePluginUrls = FluentIterable.from(plugins.getInfos()).filter(sitePluginPredicate).transform(urlFunction).toList();
- assertThat(sitePluginUrls, not(contains(nullValue())));
-
-
- List sitePluginVersions = FluentIterable.from(plugins.getInfos()).filter(sitePluginPredicate).transform(versionFunction).toList();
- for (String pluginVersion : expectedSiteVersions) {
- assertThat(sitePluginVersions, hasItem(pluginVersion));
- }
+ public static String startNodeWithPlugins(int nodeId, String ... pluginClassNames) throws URISyntaxException {
+ return startNodeWithPlugins(ImmutableSettings.EMPTY, "/org/elasticsearch/nodesinfo/node" + Integer.toString(nodeId) + "/", pluginClassNames);
}
- private String startNodeWithPlugins(int nodeId, String ... pluginClassNames) throws URISyntaxException {
- URL resource = SimpleNodesInfoTests.class.getResource("/org/elasticsearch/nodesinfo/node" + Integer.toString(nodeId) + "/");
+ public static String startNodeWithPlugins(Settings nodeSettings, String pluginDir, String ... pluginClassNames) throws URISyntaxException {
+ URL resource = SimpleNodesInfoTests.class.getResource(pluginDir);
ImmutableSettings.Builder settings = settingsBuilder();
+ settings.put(nodeSettings);
if (resource != null) {
settings.put("path.plugins", new File(resource.toURI()).getAbsolutePath());
}
@@ -228,45 +173,8 @@ public class SimpleNodesInfoTests extends ElasticsearchIntegrationTest {
// We wait for a Green status
client().admin().cluster().health(clusterHealthRequest().waitForGreenStatus()).actionGet();
- String serverNodeId = cluster().getInstance(ClusterService.class, nodeName).state().nodes().localNodeId();
- logger.debug("--> server {} started" + serverNodeId);
- return serverNodeId;
+ return cluster().getInstance(ClusterService.class, nodeName).state().nodes().localNodeId();
}
- private Predicate jvmPluginPredicate = new Predicate() {
- public boolean apply(PluginInfo pluginInfo) {
- return pluginInfo.isJvm();
- }
- };
-
- private Predicate sitePluginPredicate = new Predicate() {
- public boolean apply(PluginInfo pluginInfo) {
- return pluginInfo.isSite();
- }
- };
-
- private Function nameFunction = new Function() {
- public String apply(PluginInfo pluginInfo) {
- return pluginInfo.getName();
- }
- };
-
- private Function descriptionFunction = new Function() {
- public String apply(PluginInfo pluginInfo) {
- return pluginInfo.getDescription();
- }
- };
-
- private Function urlFunction = new Function() {
- public String apply(PluginInfo pluginInfo) {
- return pluginInfo.getUrl();
- }
- };
-
- private Function versionFunction = new Function() {
- public String apply(PluginInfo pluginInfo) {
- return pluginInfo.getVersion();
- }
- };
}
diff --git a/src/test/java/org/elasticsearch/plugin/PluginLuceneCheckerTests.java b/src/test/java/org/elasticsearch/plugin/PluginLuceneCheckerTests.java
new file mode 100644
index 00000000000..45bda11b0f2
--- /dev/null
+++ b/src/test/java/org/elasticsearch/plugin/PluginLuceneCheckerTests.java
@@ -0,0 +1,82 @@
+/*
+ * 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.plugin;
+
+import com.google.common.collect.Lists;
+import org.elasticsearch.action.admin.cluster.node.info.NodesInfoResponse;
+import org.elasticsearch.nodesinfo.SimpleNodesInfoTests;
+import org.elasticsearch.test.ElasticsearchIntegrationTest;
+import org.elasticsearch.test.ElasticsearchIntegrationTest.ClusterScope;
+import org.elasticsearch.test.hamcrest.ElasticsearchAssertions;
+import org.junit.Test;
+
+import java.net.URISyntaxException;
+import java.util.Collections;
+
+import static org.elasticsearch.common.settings.ImmutableSettings.settingsBuilder;
+
+/**
+ *
+ */
+@ClusterScope(scope= ElasticsearchIntegrationTest.Scope.TEST, numDataNodes=0, transportClientRatio = 0)
+public class PluginLuceneCheckerTests extends ElasticsearchIntegrationTest {
+
+ /**
+ * We check that no Lucene version checking is done
+ * when we set `"plugins.check_lucene":false`
+ */
+ @Test
+ public void testDisableLuceneVersionCheckingPlugin() throws URISyntaxException {
+ String serverNodeId = SimpleNodesInfoTests.startNodeWithPlugins(
+ settingsBuilder().put("plugins.check_lucene", false).build(),
+ "/org/elasticsearch/plugin/lucene/");
+ logger.info("--> server {} started" + serverNodeId);
+
+ NodesInfoResponse response = client().admin().cluster().prepareNodesInfo().clear().setPlugins(true).execute().actionGet();
+ logger.info("--> full json answer, status " + response.toString());
+
+ ElasticsearchAssertions.assertNodeContainsPlugins(response, serverNodeId,
+ Lists.newArrayList("old-lucene"), Lists.newArrayList("old"), Lists.newArrayList("1.0.0"), // JVM Plugin
+ Collections.EMPTY_LIST, Collections.EMPTY_LIST, Collections.EMPTY_LIST);// No Site Plugin
+ }
+
+ /**
+ * We check that with an old plugin (built on an old Lucene version)
+ * plugin is not loaded
+ * We check that with a recent plugin (built on current Lucene version)
+ * plugin is loaded
+ * We check that with a too recent plugin (built on an unknown Lucene version)
+ * plugin is not loaded
+ */
+ @Test
+ public void testEnableLuceneVersionCheckingPlugin() throws URISyntaxException {
+ String serverNodeId = SimpleNodesInfoTests.startNodeWithPlugins(
+ settingsBuilder().put("plugins.check_lucene", true).build(),
+ "/org/elasticsearch/plugin/lucene/");
+ logger.info("--> server {} started" + serverNodeId);
+
+ NodesInfoResponse response = client().admin().cluster().prepareNodesInfo().clear().setPlugins(true).execute().actionGet();
+ logger.info("--> full json answer, status " + response.toString());
+
+ ElasticsearchAssertions.assertNodeContainsPlugins(response, serverNodeId,
+ Lists.newArrayList("current-lucene"), Lists.newArrayList("current"), Lists.newArrayList("2.0.0"), // JVM Plugin
+ Collections.EMPTY_LIST, Collections.EMPTY_LIST, Collections.EMPTY_LIST);// No Site Plugin
+ }
+}
diff --git a/src/test/java/org/elasticsearch/plugin/PluginManagerTests.java b/src/test/java/org/elasticsearch/plugin/PluginManagerTests.java
index 1d038f9c1b5..c20701cc6de 100644
--- a/src/test/java/org/elasticsearch/plugin/PluginManagerTests.java
+++ b/src/test/java/org/elasticsearch/plugin/PluginManagerTests.java
@@ -22,6 +22,7 @@ import com.google.common.base.Predicate;
import org.elasticsearch.ElasticsearchIllegalArgumentException;
import org.elasticsearch.ElasticsearchTimeoutException;
import org.elasticsearch.action.admin.cluster.node.info.NodesInfoResponse;
+import org.elasticsearch.action.admin.cluster.node.info.PluginInfo;
import org.elasticsearch.common.collect.Tuple;
import org.elasticsearch.common.io.FileSystemUtils;
import org.elasticsearch.common.settings.ImmutableSettings;
@@ -46,8 +47,9 @@ import java.io.IOException;
import java.net.URI;
import java.util.concurrent.TimeUnit;
-import static org.elasticsearch.test.ElasticsearchIntegrationTest.*;
+import static org.elasticsearch.test.ElasticsearchIntegrationTest.Scope;
import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.notNullValue;
@@ -150,9 +152,18 @@ public class PluginManagerTests extends ElasticsearchIntegrationTest {
NodesInfoResponse nodesInfoResponse = client().admin().cluster().prepareNodesInfo().clear().setPlugins(true).get();
assertThat(nodesInfoResponse.getNodes().length, equalTo(1));
assertThat(nodesInfoResponse.getNodes()[0].getPlugins().getInfos(), notNullValue());
- assertThat(nodesInfoResponse.getNodes()[0].getPlugins().getInfos().size(), equalTo(1));
- assertThat(nodesInfoResponse.getNodes()[0].getPlugins().getInfos().get(0).getName(), equalTo(pluginName));
- assertThat(nodesInfoResponse.getNodes()[0].getPlugins().getInfos().get(0).isSite(), equalTo(true));
+ assertThat(nodesInfoResponse.getNodes()[0].getPlugins().getInfos().size(), not(0));
+
+ boolean pluginFound = false;
+
+ for (PluginInfo pluginInfo : nodesInfoResponse.getNodes()[0].getPlugins().getInfos()) {
+ if (pluginInfo.getName().equals(pluginName)) {
+ pluginFound = true;
+ break;
+ }
+ }
+
+ assertThat(pluginFound, is(true));
}
private void assertPluginAvailable(String pluginName) throws InterruptedException {
diff --git a/src/test/java/org/elasticsearch/plugin/lucene/current/CurrentLucenePlugin.java b/src/test/java/org/elasticsearch/plugin/lucene/current/CurrentLucenePlugin.java
new file mode 100644
index 00000000000..848fd2ebe24
--- /dev/null
+++ b/src/test/java/org/elasticsearch/plugin/lucene/current/CurrentLucenePlugin.java
@@ -0,0 +1,40 @@
+/*
+ * 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.plugin.lucene.current;
+
+import org.elasticsearch.plugins.AbstractPlugin;
+
+public class CurrentLucenePlugin extends AbstractPlugin {
+ /**
+ * The name of the plugin.
+ */
+ @Override
+ public String name() {
+ return "current-lucene";
+ }
+
+ /**
+ * The description of the plugin.
+ */
+ @Override
+ public String description() {
+ return "current";
+ }
+}
diff --git a/src/test/java/org/elasticsearch/plugin/lucene/current/es-plugin.properties b/src/test/java/org/elasticsearch/plugin/lucene/current/es-plugin.properties
new file mode 100644
index 00000000000..fb009c621a1
--- /dev/null
+++ b/src/test/java/org/elasticsearch/plugin/lucene/current/es-plugin.properties
@@ -0,0 +1,21 @@
+################################################################
+# 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.
+################################################################
+plugin=org.elasticsearch.plugin.lucene.current.CurrentLucenePlugin
+version=2.0.0
+lucene=${lucene.version}
diff --git a/src/test/java/org/elasticsearch/plugin/lucene/newer/NewerLucenePlugin.java b/src/test/java/org/elasticsearch/plugin/lucene/newer/NewerLucenePlugin.java
new file mode 100644
index 00000000000..7ceaec320d7
--- /dev/null
+++ b/src/test/java/org/elasticsearch/plugin/lucene/newer/NewerLucenePlugin.java
@@ -0,0 +1,40 @@
+/*
+ * 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.plugin.lucene.newer;
+
+import org.elasticsearch.plugins.AbstractPlugin;
+
+public class NewerLucenePlugin extends AbstractPlugin {
+ /**
+ * The name of the plugin.
+ */
+ @Override
+ public String name() {
+ return "newer-lucene";
+ }
+
+ /**
+ * The description of the plugin.
+ */
+ @Override
+ public String description() {
+ return "newer";
+ }
+}
diff --git a/src/test/java/org/elasticsearch/plugin/lucene/newer/es-plugin.properties b/src/test/java/org/elasticsearch/plugin/lucene/newer/es-plugin.properties
new file mode 100644
index 00000000000..1e41549909b
--- /dev/null
+++ b/src/test/java/org/elasticsearch/plugin/lucene/newer/es-plugin.properties
@@ -0,0 +1,21 @@
+################################################################
+# 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.
+################################################################
+plugin=org.elasticsearch.plugin.lucene.newer.NewerLucenePlugin
+version=3.0.0
+lucene=99.0.0
diff --git a/src/test/java/org/elasticsearch/plugin/lucene/old/OldLucenePlugin.java b/src/test/java/org/elasticsearch/plugin/lucene/old/OldLucenePlugin.java
new file mode 100644
index 00000000000..7e01f466854
--- /dev/null
+++ b/src/test/java/org/elasticsearch/plugin/lucene/old/OldLucenePlugin.java
@@ -0,0 +1,40 @@
+/*
+ * 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.plugin.lucene.old;
+
+import org.elasticsearch.plugins.AbstractPlugin;
+
+public class OldLucenePlugin extends AbstractPlugin {
+ /**
+ * The name of the plugin.
+ */
+ @Override
+ public String name() {
+ return "old-lucene";
+ }
+
+ /**
+ * The description of the plugin.
+ */
+ @Override
+ public String description() {
+ return "old";
+ }
+}
diff --git a/src/test/java/org/elasticsearch/plugin/lucene/old/es-plugin.properties b/src/test/java/org/elasticsearch/plugin/lucene/old/es-plugin.properties
new file mode 100644
index 00000000000..8344e919e8d
--- /dev/null
+++ b/src/test/java/org/elasticsearch/plugin/lucene/old/es-plugin.properties
@@ -0,0 +1,21 @@
+################################################################
+# 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.
+################################################################
+plugin=org.elasticsearch.plugin.lucene.old.OldLucenePlugin
+version=1.0.0
+lucene=3.0.0
diff --git a/src/test/java/org/elasticsearch/test/hamcrest/ElasticsearchAssertions.java b/src/test/java/org/elasticsearch/test/hamcrest/ElasticsearchAssertions.java
index f247fd2b77b..63418df7d84 100644
--- a/src/test/java/org/elasticsearch/test/hamcrest/ElasticsearchAssertions.java
+++ b/src/test/java/org/elasticsearch/test/hamcrest/ElasticsearchAssertions.java
@@ -18,7 +18,11 @@
*/
package org.elasticsearch.test.hamcrest;
+import com.google.common.base.Function;
import com.google.common.base.Predicate;
+import com.google.common.base.Predicates;
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.Iterables;
import org.apache.lucene.search.BooleanQuery;
import org.apache.lucene.search.Query;
import org.elasticsearch.ElasticsearchException;
@@ -31,6 +35,9 @@ import org.elasticsearch.action.ActionRequestBuilder;
import org.elasticsearch.action.ShardOperationFailedException;
import org.elasticsearch.action.admin.cluster.health.ClusterHealthRequestBuilder;
import org.elasticsearch.action.admin.cluster.health.ClusterHealthResponse;
+import org.elasticsearch.action.admin.cluster.node.info.NodesInfoResponse;
+import org.elasticsearch.action.admin.cluster.node.info.PluginInfo;
+import org.elasticsearch.action.admin.cluster.node.info.PluginsInfo;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequestBuilder;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexResponse;
import org.elasticsearch.action.admin.indices.template.get.GetIndexTemplatesResponse;
@@ -58,6 +65,7 @@ import org.elasticsearch.test.engine.MockInternalEngine;
import org.elasticsearch.test.store.MockDirectoryHelper;
import org.hamcrest.Matcher;
import org.hamcrest.Matchers;
+import org.junit.Assert;
import java.io.IOException;
import java.lang.reflect.Constructor;
@@ -65,6 +73,7 @@ import java.lang.reflect.InvocationTargetException;
import java.util.*;
import java.util.concurrent.TimeUnit;
+import static com.google.common.base.Predicates.isNull;
import static org.elasticsearch.test.ElasticsearchTestCase.*;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.*;
@@ -575,4 +584,96 @@ public class ElasticsearchAssertions {
}
}
+ public static void assertNodeContainsPlugins(NodesInfoResponse response, String nodeId,
+ List expectedJvmPluginNames,
+ List expectedJvmPluginDescriptions,
+ List expectedJvmVersions,
+ List expectedSitePluginNames,
+ List expectedSitePluginDescriptions,
+ List expectedSiteVersions) {
+
+ Assert.assertThat(response.getNodesMap().get(nodeId), notNullValue());
+
+ PluginsInfo plugins = response.getNodesMap().get(nodeId).getPlugins();
+ Assert.assertThat(plugins, notNullValue());
+
+ List pluginNames = FluentIterable.from(plugins.getInfos()).filter(jvmPluginPredicate).transform(nameFunction).toList();
+ for (String expectedJvmPluginName : expectedJvmPluginNames) {
+ Assert.assertThat(pluginNames, hasItem(expectedJvmPluginName));
+ }
+
+ List pluginDescriptions = FluentIterable.from(plugins.getInfos()).filter(jvmPluginPredicate).transform(descriptionFunction).toList();
+ for (String expectedJvmPluginDescription : expectedJvmPluginDescriptions) {
+ Assert.assertThat(pluginDescriptions, hasItem(expectedJvmPluginDescription));
+ }
+
+ List jvmPluginVersions = FluentIterable.from(plugins.getInfos()).filter(jvmPluginPredicate).transform(versionFunction).toList();
+ for (String pluginVersion : expectedJvmVersions) {
+ Assert.assertThat(jvmPluginVersions, hasItem(pluginVersion));
+ }
+
+ FluentIterable jvmUrls = FluentIterable.from(plugins.getInfos())
+ .filter(Predicates.and(jvmPluginPredicate, Predicates.not(sitePluginPredicate)))
+ .filter(isNull())
+ .transform(urlFunction);
+ Assert.assertThat(Iterables.size(jvmUrls), is(0));
+
+ List sitePluginNames = FluentIterable.from(plugins.getInfos()).filter(sitePluginPredicate).transform(nameFunction).toList();
+ Assert.assertThat(sitePluginNames.isEmpty(), is(expectedSitePluginNames.isEmpty()));
+ for (String expectedSitePluginName : expectedSitePluginNames) {
+ Assert.assertThat(sitePluginNames, hasItem(expectedSitePluginName));
+ }
+
+ List sitePluginDescriptions = FluentIterable.from(plugins.getInfos()).filter(sitePluginPredicate).transform(descriptionFunction).toList();
+ Assert.assertThat(sitePluginDescriptions.isEmpty(), is(expectedSitePluginDescriptions.isEmpty()));
+ for (String sitePluginDescription : expectedSitePluginDescriptions) {
+ Assert.assertThat(sitePluginDescriptions, hasItem(sitePluginDescription));
+ }
+
+ List sitePluginUrls = FluentIterable.from(plugins.getInfos()).filter(sitePluginPredicate).transform(urlFunction).toList();
+ Assert.assertThat(sitePluginUrls, not(contains(nullValue())));
+
+
+ List sitePluginVersions = FluentIterable.from(plugins.getInfos()).filter(sitePluginPredicate).transform(versionFunction).toList();
+ Assert.assertThat(sitePluginVersions.isEmpty(), is(expectedSiteVersions.isEmpty()));
+ for (String pluginVersion : expectedSiteVersions) {
+ Assert.assertThat(sitePluginVersions, hasItem(pluginVersion));
+ }
+ }
+
+ private static Predicate jvmPluginPredicate = new Predicate() {
+ public boolean apply(PluginInfo pluginInfo) {
+ return pluginInfo.isJvm();
+ }
+ };
+
+ private static Predicate sitePluginPredicate = new Predicate() {
+ public boolean apply(PluginInfo pluginInfo) {
+ return pluginInfo.isSite();
+ }
+ };
+
+ private static Function nameFunction = new Function() {
+ public String apply(PluginInfo pluginInfo) {
+ return pluginInfo.getName();
+ }
+ };
+
+ private static Function descriptionFunction = new Function() {
+ public String apply(PluginInfo pluginInfo) {
+ return pluginInfo.getDescription();
+ }
+ };
+
+ private static Function urlFunction = new Function() {
+ public String apply(PluginInfo pluginInfo) {
+ return pluginInfo.getUrl();
+ }
+ };
+
+ private static Function versionFunction = new Function() {
+ public String apply(PluginInfo pluginInfo) {
+ return pluginInfo.getVersion();
+ }
+ };
}