/*
* Licensed to Crate under one or more contributor license agreements.
* See the NOTICE file distributed with this work for additional
* information regarding copyright ownership. Crate 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.
*
* However, if you have executed another commercial license agreement
* with Crate these terms will supersede the license and you may use the
* software solely pursuant to the terms of the relevant commercial
* agreement.
*/
package io.crate.plugin;
import io.crate.test.CauseMatcher;
import org.elasticsearch.cluster.service.ClusterService;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.plugins.PluginsService;
import org.elasticsearch.test.ESIntegTestCase;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import java.io.File;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import static org.elasticsearch.client.Requests.clusterHealthRequest;
import static org.hamcrest.Matchers.is;
@ESIntegTestCase.ClusterScope(scope = ESIntegTestCase.Scope.TEST, numDataNodes = 0, numClientNodes = 0)
public class PluginLoaderTest extends ESIntegTestCase {
@Rule
public ExpectedException expectedException = ExpectedException.none();
@Override
protected Collection<Class<? extends Plugin>> nodePlugins() {
return Collections.singletonList(PluginLoaderPlugin.class);
}
@Test
public void testLoadPlugin() throws Exception {
String node = startNodeWithPlugins("/io/crate/plugin/simple_plugin");
PluginsService pluginsService = internalCluster().getInstance(PluginsService.class, node);
PluginLoaderPlugin corePlugin = getCratePlugin(pluginsService);
PluginLoader pluginLoader = corePlugin.pluginLoader;
assertThat(pluginLoader.plugins.size(), is(1));
assertThat(pluginLoader.plugins.get(0).getClass().getCanonicalName(), is("io.crate.plugin.ExamplePlugin"));
}
@Test
public void testPluginWithCrateSettings() throws Exception {
String node = startNodeWithPlugins("/io/crate/plugin/plugin_with_crate_settings");
PluginsService pluginsService = internalCluster().getInstance(PluginsService.class, node);
PluginLoaderPlugin corePlugin = getCratePlugin(pluginsService);
Settings settings = corePlugin.settings;
assertThat(settings.get("setting.for.crate"), is("foo"));
}
@Test
public void testLoadPluginWithAlreadyLoadedClass() throws Exception {
// test that JarHell is used and plugin is not loaded because it contains an already loaded class
expectedException.expect(CauseMatcher.causeOfCause(RuntimeException.class));
startNodeWithPlugins("/io/crate/plugin/plugin_with_already_loaded_class");
}
@Test
public void testDuplicates() throws Exception {
// test that node will die due to jarHell (same plugin jar loaded twice)
expectedException.expect(CauseMatcher.causeOfCause(RuntimeException.class));
startNodeWithPlugins("/io/crate/plugin/duplicates");
}
@Test
public void testInvalidPluginEmptyDirectory() throws Exception {
// test that node will die because of an invalid plugin (in this case, just an empty directory)
expectedException.expect(CauseMatcher.causeOfCause(RuntimeException.class));
startNodeWithPlugins("/io/crate/plugin/invalid");
}
private static String startNodeWithPlugins(String pluginDir) throws URISyntaxException {
URL resource = PluginLoaderTest.class.getResource(pluginDir);
Settings.Builder settings = Settings.builder();
if (resource != null) {
settings.put(PluginLoader.SETTING_CRATE_PLUGINS_PATH.getKey(), new File(resource.toURI()).getAbsolutePath());
}
String nodeName = internalCluster().startNode(settings);
// We wait for a Green status
client().admin().cluster().health(clusterHealthRequest().waitForGreenStatus()).actionGet();
return internalCluster().getInstance(ClusterService.class, nodeName).state().nodes().getLocalNode().getName();
}
private PluginLoaderPlugin getCratePlugin(PluginsService pluginsService) {
// find the PluginLoaderPlugin, should be the only one loaded
List<PluginLoaderPlugin> pluginLoaderPlugins = pluginsService.filterPlugins(PluginLoaderPlugin.class);
if (pluginLoaderPlugins.isEmpty()) {
throw new IllegalStateException("Couldn't find PluginLoaderPlugin");
}
return pluginLoaderPlugins.get(0);
}
}