aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwolframhaussig <13997737+wolframhaussig@users.noreply.github.com>2021-06-13 11:10:35 +0200
committerGitHub <noreply@github.com>2021-06-13 12:10:35 +0300
commitdac4edb5f3fbfd5e5aae81ae4eb3c4dad2e7f732 (patch)
treec74da91c793d21f5184cb1912cf2ae4b5d0a2c0e
parent575abd034fd3bfbeff60f1ddbd9deb88c6b741e6 (diff)
downloadpf4j-dac4edb5f3fbfd5e5aae81ae4eb3c4dad2e7f732.tar.gz
pf4j-dac4edb5f3fbfd5e5aae81ae4eb3c4dad2e7f732.zip
Add secure wrapper to plugin manager (#450)
-rw-r--r--pf4j/src/main/java/org/pf4j/AbstractPluginManager.java18
-rw-r--r--pf4j/src/main/java/org/pf4j/PluginClassLoader.java2
-rw-r--r--pf4j/src/main/java/org/pf4j/SecurePluginManagerWrapper.java305
-rw-r--r--pf4j/src/test/java/org/pf4j/SecurePluginManagerWrapperTest.java272
4 files changed, 592 insertions, 5 deletions
diff --git a/pf4j/src/main/java/org/pf4j/AbstractPluginManager.java b/pf4j/src/main/java/org/pf4j/AbstractPluginManager.java
index 9562257..2374b56 100644
--- a/pf4j/src/main/java/org/pf4j/AbstractPluginManager.java
+++ b/pf4j/src/main/java/org/pf4j/AbstractPluginManager.java
@@ -860,10 +860,7 @@ public abstract class AbstractPluginManager implements PluginManager {
ClassLoader pluginClassLoader = getPluginLoader().loadPlugin(pluginPath, pluginDescriptor);
log.debug("Loaded plugin '{}' with class loader '{}'", pluginPath, pluginClassLoader);
- // create the plugin wrapper
- log.debug("Creating wrapper for plugin '{}'", pluginPath);
- PluginWrapper pluginWrapper = new PluginWrapper(this, pluginDescriptor, pluginPath, pluginClassLoader);
- pluginWrapper.setPluginFactory(getPluginFactory());
+ PluginWrapper pluginWrapper = createPluginWrapper(pluginDescriptor, pluginPath, pluginClassLoader);
// test for disabled plugin
if (isPluginDisabled(pluginDescriptor.getPluginId())) {
@@ -890,6 +887,19 @@ public abstract class AbstractPluginManager implements PluginManager {
return pluginWrapper;
}
+
+ /**
+ * creates the plugin wrapper. override this if you want to prevent plugins having full access to the plugin manager
+ *
+ * @return
+ */
+ protected PluginWrapper createPluginWrapper(PluginDescriptor pluginDescriptor, Path pluginPath, ClassLoader pluginClassLoader) {
+ // create the plugin wrapper
+ log.debug("Creating wrapper for plugin '{}'", pluginPath);
+ PluginWrapper pluginWrapper = new PluginWrapper(this, pluginDescriptor, pluginPath, pluginClassLoader);
+ pluginWrapper.setPluginFactory(getPluginFactory());
+ return pluginWrapper;
+ }
/**
* Tests for already loaded plugins on given path.
diff --git a/pf4j/src/main/java/org/pf4j/PluginClassLoader.java b/pf4j/src/main/java/org/pf4j/PluginClassLoader.java
index 4dbcb6a..d22dd55 100644
--- a/pf4j/src/main/java/org/pf4j/PluginClassLoader.java
+++ b/pf4j/src/main/java/org/pf4j/PluginClassLoader.java
@@ -103,7 +103,7 @@ public class PluginClassLoader extends URLClassLoader {
}
// if the class is part of the plugin engine use parent class loader
- if (className.startsWith(PLUGIN_PACKAGE_PREFIX) && !className.startsWith("org.pf4j.demo")) {
+ if (className.startsWith(PLUGIN_PACKAGE_PREFIX) && !className.startsWith("org.pf4j.demo") && !className.startsWith("org.pf4j.test")) {
// log.trace("Delegate the loading of PF4J class '{}' to parent", className);
return getParent().loadClass(className);
}
diff --git a/pf4j/src/main/java/org/pf4j/SecurePluginManagerWrapper.java b/pf4j/src/main/java/org/pf4j/SecurePluginManagerWrapper.java
new file mode 100644
index 0000000..f55b1e6
--- /dev/null
+++ b/pf4j/src/main/java/org/pf4j/SecurePluginManagerWrapper.java
@@ -0,0 +1,305 @@
+package org.pf4j;
+
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+/**
+ * Use this class to wrap the original plugin manager to prevent full access from within plugins.
+ * Override AbstractPluginManager.createPluginWrapper to use this class
+ * @author Wolfram Haussig
+ *
+ */
+public class SecurePluginManagerWrapper implements PluginManager {
+
+ private static final String PLUGIN_PREFIX = "Plugin ";
+ /**
+ * the current plugin
+ */
+ private String currentPluginId;
+ /**
+ * the original plugin manager
+ */
+ private PluginManager original;
+
+ /**
+ * The registered {@link PluginStateListener}s.
+ */
+ protected List<PluginStateListener> pluginStateListeners = new ArrayList<>();
+ /**
+ * wrapper for pluginStateListeners
+ */
+ private PluginStateListenerWrapper listenerWrapper = new PluginStateListenerWrapper();
+
+ /**
+ * constructor
+ * @param original the original plugin manager
+ * @param currentPlugin the current pluginId
+ */
+ public SecurePluginManagerWrapper(PluginManager original, String currentPluginId) {
+ this.original = original;
+ this.currentPluginId = currentPluginId;
+ }
+
+ @Override
+ public boolean isDevelopment() {
+ return original.isDevelopment();
+ }
+
+ @Override
+ public boolean isNotDevelopment() {
+ return original.isNotDevelopment();
+ }
+
+ @Override
+ public List<PluginWrapper> getPlugins() {
+ return Arrays.asList(getPlugin(currentPluginId));
+ }
+
+ @Override
+ public List<PluginWrapper> getPlugins(PluginState pluginState) {
+ return getPlugins().stream().filter(p -> p.getPluginState() == pluginState).collect(Collectors.toList());
+ }
+
+ @Override
+ public List<PluginWrapper> getResolvedPlugins() {
+ return getPlugins().stream().filter(p -> p.getPluginState().ordinal() >= PluginState.RESOLVED.ordinal()).collect(Collectors.toList());
+ }
+
+ @Override
+ public List<PluginWrapper> getUnresolvedPlugins() {
+ return Collections.emptyList();
+ }
+
+ @Override
+ public List<PluginWrapper> getStartedPlugins() {
+ return getPlugins(PluginState.STARTED);
+ }
+
+ @Override
+ public PluginWrapper getPlugin(String pluginId) {
+ if (currentPluginId.equals(pluginId)) {
+ return original.getPlugin(pluginId);
+ } else {
+ throw new IllegalAccessError(PLUGIN_PREFIX + currentPluginId + " tried to execute getPlugin for foreign pluginId!");
+ }
+ }
+
+ @Override
+ public void loadPlugins() {
+ throw new IllegalAccessError(PLUGIN_PREFIX + currentPluginId + " tried to execute loadPlugins!");
+ }
+
+ @Override
+ public String loadPlugin(Path pluginPath) {
+ throw new IllegalAccessError(PLUGIN_PREFIX + currentPluginId + " tried to execute loadPlugin!");
+ }
+
+ @Override
+ public void startPlugins() {
+ throw new IllegalAccessError(PLUGIN_PREFIX + currentPluginId + " tried to execute startPlugins!");
+ }
+
+ @Override
+ public PluginState startPlugin(String pluginId) {
+ throw new IllegalAccessError(PLUGIN_PREFIX + currentPluginId + " tried to execute startPlugin!");
+ }
+
+ @Override
+ public void stopPlugins() {
+ throw new IllegalAccessError(PLUGIN_PREFIX + currentPluginId + " tried to execute stopPlugins!");
+ }
+
+ @Override
+ public PluginState stopPlugin(String pluginId) {
+ if (currentPluginId.equals(pluginId)) {
+ return original.stopPlugin(pluginId);
+ } else {
+ throw new IllegalAccessError(PLUGIN_PREFIX + currentPluginId + " tried to execute stopPlugin for foreign pluginId!");
+ }
+ }
+
+ @Override
+ public void unloadPlugins() {
+ throw new IllegalAccessError(PLUGIN_PREFIX + currentPluginId + " tried to execute unloadPlugins!");
+ }
+
+ @Override
+ public boolean unloadPlugin(String pluginId) {
+ if (currentPluginId.equals(pluginId)) {
+ return original.unloadPlugin(pluginId);
+ } else {
+ throw new IllegalAccessError(PLUGIN_PREFIX + currentPluginId + " tried to execute unloadPlugin for foreign pluginId!");
+ }
+ }
+
+ @Override
+ public boolean disablePlugin(String pluginId) {
+ if (currentPluginId.equals(pluginId)) {
+ return original.disablePlugin(pluginId);
+ } else {
+ throw new IllegalAccessError(PLUGIN_PREFIX + currentPluginId + " tried to execute disablePlugin for foreign pluginId!");
+ }
+ }
+
+ @Override
+ public boolean enablePlugin(String pluginId) {
+ throw new IllegalAccessError(PLUGIN_PREFIX + currentPluginId + " tried to execute enablePlugin!");
+ }
+
+ @Override
+ public boolean deletePlugin(String pluginId) {
+ if (currentPluginId.equals(pluginId)) {
+ return original.deletePlugin(pluginId);
+ } else {
+ throw new IllegalAccessError(PLUGIN_PREFIX + currentPluginId + " tried to execute deletePlugin for foreign pluginId!");
+ }
+ }
+
+ @Override
+ public ClassLoader getPluginClassLoader(String pluginId) {
+ if (currentPluginId.equals(pluginId)) {
+ return original.getPluginClassLoader(pluginId);
+ } else {
+ throw new IllegalAccessError(PLUGIN_PREFIX + currentPluginId + " tried to execute getPluginClassLoader for foreign pluginId!");
+ }
+ }
+
+ @Override
+ public List<Class<?>> getExtensionClasses(String pluginId) {
+ if (currentPluginId.equals(pluginId)) {
+ return original.getExtensionClasses(pluginId);
+ } else {
+ throw new IllegalAccessError(PLUGIN_PREFIX + currentPluginId + " tried to execute getExtensionClasses for foreign pluginId!");
+ }
+ }
+
+ @Override
+ public <T> List<Class<? extends T>> getExtensionClasses(Class<T> type) {
+ return getExtensionClasses(type, currentPluginId);
+ }
+
+ @Override
+ public <T> List<Class<? extends T>> getExtensionClasses(Class<T> type, String pluginId) {
+ if (currentPluginId.equals(pluginId)) {
+ return original.getExtensionClasses(type, pluginId);
+ } else {
+ throw new IllegalAccessError(PLUGIN_PREFIX + currentPluginId + " tried to execute getExtensionClasses for foreign pluginId!");
+ }
+ }
+
+ @Override
+ public <T> List<T> getExtensions(Class<T> type) {
+ return getExtensions(type, currentPluginId);
+ }
+
+ @Override
+ public <T> List<T> getExtensions(Class<T> type, String pluginId) {
+ if (currentPluginId.equals(pluginId)) {
+ return original.getExtensions(type, pluginId);
+ } else {
+ throw new IllegalAccessError(PLUGIN_PREFIX + currentPluginId + " tried to execute getExtensions for foreign pluginId!");
+ }
+ }
+
+ @Override
+ public List<?> getExtensions(String pluginId) {
+ if (currentPluginId.equals(pluginId)) {
+ return original.getExtensions(pluginId);
+ } else {
+ throw new IllegalAccessError(PLUGIN_PREFIX + currentPluginId + " tried to execute getExtensions for foreign pluginId!");
+ }
+ }
+
+ @Override
+ public Set<String> getExtensionClassNames(String pluginId) {
+ if (currentPluginId.equals(pluginId)) {
+ return original.getExtensionClassNames(pluginId);
+ } else {
+ throw new IllegalAccessError(PLUGIN_PREFIX + currentPluginId + " tried to execute getExtensionClassNames for foreign pluginId!");
+ }
+ }
+
+ @Override
+ public ExtensionFactory getExtensionFactory() {
+ return original.getExtensionFactory();
+ }
+
+ @Override
+ public RuntimeMode getRuntimeMode() {
+ return original.getRuntimeMode();
+ }
+
+ @Override
+ public PluginWrapper whichPlugin(Class<?> clazz) {
+ ClassLoader classLoader = clazz.getClassLoader();
+ PluginWrapper plugin = getPlugin(currentPluginId);
+ if (plugin.getPluginClassLoader() == classLoader) {
+ return plugin;
+ }
+ return null;
+ }
+
+ @Override
+ public void addPluginStateListener(PluginStateListener listener) {
+ if (pluginStateListeners.isEmpty()) {
+ this.original.addPluginStateListener(listenerWrapper);
+ }
+ pluginStateListeners.add(listener);
+ }
+
+ @Override
+ public void removePluginStateListener(PluginStateListener listener) {
+ pluginStateListeners.remove(listener);
+ if (pluginStateListeners.isEmpty()) {
+ this.original.removePluginStateListener(listenerWrapper);
+ }
+ }
+
+ @Override
+ public void setSystemVersion(String version) {
+ throw new IllegalAccessError(PLUGIN_PREFIX + currentPluginId + " tried to execute setSystemVersion!");
+ }
+
+ @Override
+ public String getSystemVersion() {
+ return original.getSystemVersion();
+ }
+
+ @Override
+ public Path getPluginsRoot() {
+ throw new IllegalAccessError(PLUGIN_PREFIX + currentPluginId + " tried to execute getPluginsRoot!");
+ }
+
+ @Override
+ public List<Path> getPluginsRoots() {
+ throw new IllegalAccessError(PLUGIN_PREFIX + currentPluginId + " tried to execute getPluginsRoots!");
+ }
+
+ @Override
+ public VersionManager getVersionManager() {
+ return original.getVersionManager();
+ }
+
+ /**
+ * Wrapper for PluginStateListener events. will only propagate events if they match the current pluginId
+ * @author Wolfram Haussig
+ *
+ */
+ private class PluginStateListenerWrapper implements PluginStateListener {
+
+ @Override
+ public void pluginStateChanged(PluginStateEvent event) {
+ if (event.getPlugin().getPluginId().equals(currentPluginId)) {
+ for (PluginStateListener listener : pluginStateListeners) {
+ listener.pluginStateChanged(event);
+ }
+ }
+ }
+
+ }
+}
diff --git a/pf4j/src/test/java/org/pf4j/SecurePluginManagerWrapperTest.java b/pf4j/src/test/java/org/pf4j/SecurePluginManagerWrapperTest.java
new file mode 100644
index 0000000..f42d83e
--- /dev/null
+++ b/pf4j/src/test/java/org/pf4j/SecurePluginManagerWrapperTest.java
@@ -0,0 +1,272 @@
+package org.pf4j;
+
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import java.io.IOException;
+import java.nio.file.Path;
+import java.util.List;
+
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.io.TempDir;
+import org.pf4j.test.PluginJar;
+import org.pf4j.test.TestExtension;
+import org.pf4j.test.TestExtensionPoint;
+import org.pf4j.test.TestPlugin;
+
+public class SecurePluginManagerWrapperTest {
+
+ private static final String OTHER_PLUGIN_ID = "test-plugin-2";
+ private static final String THIS_PLUGIN_ID = "test-plugin-1";
+ private PluginJar thisPlugin;
+ private PluginJar otherPlugin;
+ private PluginManager pluginManager;
+ private PluginManager wrappedPluginManager;
+ private int pluginManagerEvents = 0;
+ private int wrappedPluginManagerEvents = 0;
+
+ @TempDir
+ Path pluginsPath;
+
+ @BeforeEach
+ public void setUp() throws IOException {
+ pluginManagerEvents = 0;
+ wrappedPluginManagerEvents = 0;
+ thisPlugin = new PluginJar.Builder(pluginsPath.resolve("test-plugin1.jar"), THIS_PLUGIN_ID).pluginClass(TestPlugin.class.getName()).pluginVersion("1.2.3").extension(TestExtension.class.getName()).build();
+ otherPlugin = new PluginJar.Builder(pluginsPath.resolve("test-plugin2.jar"), OTHER_PLUGIN_ID).pluginClass(TestPlugin.class.getName()).pluginVersion("1.2.3").extension(TestExtension.class.getName()).build();
+
+ pluginManager = new JarPluginManager(pluginsPath);
+ wrappedPluginManager = new SecurePluginManagerWrapper(pluginManager, THIS_PLUGIN_ID);
+ }
+
+ @AfterEach
+ public void tearDown() {
+ pluginManager.unloadPlugins();
+
+ thisPlugin = null;
+ otherPlugin = null;
+ pluginManager = null;
+ }
+
+ @Test
+ public void pluginStateListeners() {
+ pluginManager.addPluginStateListener(new PluginStateListener() {
+ @Override
+ public void pluginStateChanged(PluginStateEvent event) {
+ pluginManagerEvents++;
+ }
+ });
+ wrappedPluginManager.addPluginStateListener(new PluginStateListener() {
+ @Override
+ public void pluginStateChanged(PluginStateEvent event) {
+ wrappedPluginManagerEvents++;
+ }
+ });
+ pluginManager.loadPlugins();
+ pluginManager.startPlugins();
+ assertEquals(4, pluginManagerEvents);
+ assertEquals(2, wrappedPluginManagerEvents);
+ }
+
+ @Test
+ public void deletePlugin() {
+ pluginManager.loadPlugins();
+ assertThrows(IllegalAccessError.class, () -> wrappedPluginManager.deletePlugin(OTHER_PLUGIN_ID));
+ assertTrue(wrappedPluginManager.deletePlugin(THIS_PLUGIN_ID));
+ }
+
+ @Test
+ public void disablePlugin() {
+ pluginManager.loadPlugins();
+ assertThrows(IllegalAccessError.class, () -> wrappedPluginManager.disablePlugin(OTHER_PLUGIN_ID));
+ assertTrue(wrappedPluginManager.disablePlugin(THIS_PLUGIN_ID));
+ }
+
+ @Test
+ public void enablePlugin() {
+ pluginManager.loadPlugins();
+ assertThrows(IllegalAccessError.class, () -> wrappedPluginManager.enablePlugin(OTHER_PLUGIN_ID));
+ assertThrows(IllegalAccessError.class, () -> wrappedPluginManager.enablePlugin(THIS_PLUGIN_ID));
+ }
+
+ @Test
+ public void getExtensionClasses() {
+ pluginManager.loadPlugins();
+ pluginManager.startPlugins();
+ assertEquals(1, wrappedPluginManager.getExtensionClasses(TestExtensionPoint.class).size());
+
+ assertThrows(IllegalAccessError.class, () -> wrappedPluginManager.getExtensionClasses(TestExtensionPoint.class, OTHER_PLUGIN_ID));
+ assertEquals(1, wrappedPluginManager.getExtensionClasses(TestExtensionPoint.class, THIS_PLUGIN_ID).size());
+
+ assertThrows(IllegalAccessError.class, () -> wrappedPluginManager.getExtensionClasses(OTHER_PLUGIN_ID));
+ assertEquals(1, wrappedPluginManager.getExtensionClasses(THIS_PLUGIN_ID).size());
+ }
+
+ @Test
+ public void getExtensionClassNames() {
+ pluginManager.loadPlugins();
+ assertThrows(IllegalAccessError.class, () -> wrappedPluginManager.getExtensionClassNames(OTHER_PLUGIN_ID));
+ assertEquals(1, wrappedPluginManager.getExtensionClassNames(THIS_PLUGIN_ID).size());
+ }
+
+ @Test
+ public void getExtensionFactory() {
+ pluginManager.loadPlugins();
+ assertEquals(pluginManager.getExtensionFactory(), wrappedPluginManager.getExtensionFactory());
+ }
+
+ @Test
+ public void getExtensions() {
+ pluginManager.loadPlugins();
+ pluginManager.startPlugins();
+ assertEquals(1, wrappedPluginManager.getExtensions(TestExtensionPoint.class).size());
+
+ assertThrows(IllegalAccessError.class, () -> wrappedPluginManager.getExtensions(TestExtensionPoint.class, OTHER_PLUGIN_ID));
+ assertEquals(1, wrappedPluginManager.getExtensions(TestExtensionPoint.class, THIS_PLUGIN_ID).size());
+
+ assertThrows(IllegalAccessError.class, () -> wrappedPluginManager.getExtensions(OTHER_PLUGIN_ID));
+ assertEquals(1, wrappedPluginManager.getExtensions(THIS_PLUGIN_ID).size());
+ }
+
+ @Test
+ public void getPlugin() {
+ pluginManager.loadPlugins();
+ assertThrows(IllegalAccessError.class, () -> wrappedPluginManager.getPlugin(OTHER_PLUGIN_ID));
+ assertEquals(THIS_PLUGIN_ID, wrappedPluginManager.getPlugin(THIS_PLUGIN_ID).getPluginId());
+ }
+
+ @Test
+ public void getPluginClassLoader() {
+ pluginManager.loadPlugins();
+ assertThrows(IllegalAccessError.class, () -> wrappedPluginManager.getPluginClassLoader(OTHER_PLUGIN_ID));
+ assertNotNull(wrappedPluginManager.getPluginClassLoader(THIS_PLUGIN_ID));
+ }
+
+ @Test
+ public void getPlugins() {
+ pluginManager.loadPlugins();
+ assertEquals(2, pluginManager.getPlugins().size());
+ assertEquals(1, wrappedPluginManager.getPlugins().size());
+ }
+
+ @Test
+ public void getPluginsRoot() {
+ assertThrows(IllegalAccessError.class, () -> wrappedPluginManager.getPluginsRoot());
+ }
+
+ @Test
+ public void getPluginsRoots() {
+ assertThrows(IllegalAccessError.class, () -> wrappedPluginManager.getPluginsRoots());
+ }
+
+ @Test
+ public void getResolvedPlugins() {
+ pluginManager.loadPlugins();
+ assertEquals(2, pluginManager.getResolvedPlugins().size());
+ assertEquals(1, wrappedPluginManager.getResolvedPlugins().size());
+ }
+
+ @Test
+ public void getRuntimeMode() {
+ assertEquals(pluginManager.getRuntimeMode(), wrappedPluginManager.getRuntimeMode());
+ }
+
+ @Test
+ public void getStartedPlugins() {
+ pluginManager.loadPlugins();
+ pluginManager.startPlugins();
+ assertEquals(2, pluginManager.getStartedPlugins().size());
+ assertEquals(1, wrappedPluginManager.getStartedPlugins().size());
+ }
+
+ @Test
+ public void getSystemVersion() {
+ assertEquals(pluginManager.getSystemVersion(), wrappedPluginManager.getSystemVersion());
+ }
+
+ @Test
+ public void getUnresolvedPlugins() {
+ assertNotNull(wrappedPluginManager);
+ assertNotNull(wrappedPluginManager.getUnresolvedPlugins());
+ assertTrue(wrappedPluginManager.getUnresolvedPlugins().isEmpty());
+ }
+
+ @Test
+ public void getVersionManager() {
+ assertEquals(pluginManager.getVersionManager(), wrappedPluginManager.getVersionManager());
+ }
+
+ @Test
+ public void isDevelopment() {
+ assertEquals(pluginManager.isDevelopment(), wrappedPluginManager.isDevelopment());
+ }
+
+ @Test
+ public void isNotDevelopment() {
+ assertEquals(pluginManager.isNotDevelopment(), wrappedPluginManager.isNotDevelopment());
+ }
+
+ @Test
+ public void loadPlugin() {
+ assertThrows(IllegalAccessError.class, () -> wrappedPluginManager.loadPlugin(thisPlugin.path()));
+ }
+
+ @Test
+ public void loadPlugins() {
+ assertThrows(IllegalAccessError.class, () -> wrappedPluginManager.loadPlugins());
+ }
+
+ @Test
+ public void setSystemVersion() {
+ assertThrows(IllegalAccessError.class, () -> wrappedPluginManager.setSystemVersion("1.0.0"));
+ }
+
+ @Test
+ public void startPlugin() {
+ pluginManager.loadPlugins();
+ assertThrows(IllegalAccessError.class, () -> wrappedPluginManager.startPlugin(OTHER_PLUGIN_ID));
+ assertThrows(IllegalAccessError.class, () -> wrappedPluginManager.startPlugin(THIS_PLUGIN_ID));
+ }
+
+ @Test
+ public void startPlugins() {
+ assertThrows(IllegalAccessError.class, () -> wrappedPluginManager.startPlugins());
+ }
+
+ @Test
+ public void stopPlugin() {
+ pluginManager.loadPlugins();
+ pluginManager.startPlugins();
+ assertThrows(IllegalAccessError.class, () -> wrappedPluginManager.stopPlugin(OTHER_PLUGIN_ID));
+ assertEquals(PluginState.STOPPED, wrappedPluginManager.stopPlugin(THIS_PLUGIN_ID));
+ }
+
+ @Test
+ public void stopPlugins() {
+ assertThrows(IllegalAccessError.class, () -> wrappedPluginManager.stopPlugins());
+ }
+
+ @Test
+ public void unloadPlugin() {
+ pluginManager.loadPlugins();
+ assertThrows(IllegalAccessError.class, () -> wrappedPluginManager.unloadPlugin(OTHER_PLUGIN_ID));
+ assertTrue(wrappedPluginManager.unloadPlugin(THIS_PLUGIN_ID));
+ }
+
+ @Test
+ public void unloadPlugins() {
+ assertThrows(IllegalAccessError.class, () -> wrappedPluginManager.unloadPlugins());
+ }
+
+ @Test
+ public void whichPlugin() {
+ pluginManager.loadPlugins();
+ pluginManager.startPlugins();
+ assertEquals(null, wrappedPluginManager.whichPlugin(pluginManager.getExtensionClasses(OTHER_PLUGIN_ID).get(0)));
+ assertEquals(THIS_PLUGIN_ID, wrappedPluginManager.whichPlugin(pluginManager.getExtensionClasses(THIS_PLUGIN_ID).get(0)).getPluginId());
+ }
+}