diff options
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());
+ }
+}
|