add test that class loader is properly configured if one plugin depends on another one

GitOrigin-RevId: ef32f6f4272d0c3683eed3cc4c2ae398fb3b43cd
This commit is contained in:
Vladimir Krivosheev
2019-11-12 08:31:53 +00:00
committed by intellij-monorepo-bot
parent 21f426e155
commit af4666ea5b
4 changed files with 91 additions and 17 deletions
@@ -1133,8 +1133,10 @@ public final class PluginManagerCore {
public static List<? extends IdeaPluginDescriptor> testLoadDescriptorsFromDir(@NotNull Path dir)
throws ExecutionException, InterruptedException {
PluginLoadingResult result = new PluginLoadingResult(Collections.emptyMap());
loadDescriptorsFromDir(dir, result, true, new DescriptorListLoadingContext(0, Collections.emptySet(), result));
loadDescriptorsFromDir(dir, result, true, DescriptorListLoadingContext.createSingleDescriptorContext(Collections.emptySet()));
result.finishLoading();
initializePlugins(result, UrlClassLoader.build().get(), false, true);
return result.plugins;
}
@@ -1620,7 +1622,7 @@ public final class PluginManagerCore {
}
@ApiStatus.Internal
static void initializePlugins(@NotNull PluginLoadingResult loadResult, @NotNull ClassLoader coreLoader, boolean checkEssentialPlugins) {
static void initializePlugins(@NotNull PluginLoadingResult loadResult, @NotNull ClassLoader coreLoader, boolean checkEssentialPlugins, boolean usePluginClassLoader) {
List<String> errors = new ArrayList<>(loadResult.errors);
Map<PluginId, IdeaPluginDescriptorImpl> idMap = loadResult.idMap;
@@ -1631,7 +1633,7 @@ public final class PluginManagerCore {
}
IdeaPluginDescriptorImpl coreDescriptor = idMap.get(CORE_ID);
if (coreDescriptor == null) {
if (checkEssentialPlugins && coreDescriptor == null) {
throw new EssentialPluginMissingException(Collections.singletonList(CORE_ID + " (platform prefix: " + System.getProperty(PlatformUtils.PLATFORM_PREFIX_KEY) + ")"));
}
@@ -1674,7 +1676,7 @@ public final class PluginManagerCore {
}
mergeOptionalConfigs(enabledPlugins, idMap);
configureClassLoaders(coreLoader, graph, coreDescriptor, enabledPlugins);
configureClassLoaders(coreLoader, graph, coreDescriptor, enabledPlugins, usePluginClassLoader);
if (checkEssentialPlugins) {
checkEssentialPluginsAreAvailable(idMap);
@@ -1685,8 +1687,9 @@ public final class PluginManagerCore {
private static void configureClassLoaders(@NotNull ClassLoader coreLoader,
@NotNull CachingSemiGraph<IdeaPluginDescriptorImpl> graph,
@NotNull IdeaPluginDescriptor coreDescriptor,
@NotNull List<IdeaPluginDescriptorImpl> enabledPlugins) {
@Nullable IdeaPluginDescriptor coreDescriptor,
@NotNull List<IdeaPluginDescriptorImpl> enabledPlugins,
boolean usePluginClassLoader) {
ArrayList<ClassLoader> loaders = new ArrayList<>();
ClassLoader[] emptyClassLoaderArray = new ClassLoader[0];
for (IdeaPluginDescriptorImpl rootDescriptor : enabledPlugins) {
@@ -1695,7 +1698,7 @@ public final class PluginManagerCore {
continue;
}
if (isUnitTestMode && !ourUnitTestWithBundledPlugins) {
if (!usePluginClassLoader) {
rootDescriptor.setLoader(null);
continue;
}
@@ -1876,7 +1879,7 @@ public final class PluginManagerCore {
try {
Activity loadPluginsActivity = StartUpMeasurer.startActivity("plugin initialization");
result = loadDescriptors(isRunningFromSources());
initializePlugins(result, coreLoader, !isUnitTestMode);
initializePlugins(result, coreLoader, !isUnitTestMode, !isUnitTestMode || ourUnitTestWithBundledPlugins);
ourPlugins = result.getSortedPlugins();
if (!result.incompletePlugins.isEmpty()) {
@@ -13,8 +13,10 @@ import com.intellij.util.SmartList;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.lang.UrlClassLoader;
import gnu.trove.THashSet;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.TestOnly;
import java.awt.*;
import java.io.File;
@@ -33,7 +35,9 @@ import java.util.concurrent.atomic.AtomicLong;
*/
public final class PluginClassLoader extends UrlClassLoader {
static {
if (registerAsParallelCapable()) markParallelCapable(PluginClassLoader.class);
if (registerAsParallelCapable()) {
markParallelCapable(PluginClassLoader.class);
}
}
private final ClassLoader[] myParents;
@@ -422,4 +426,12 @@ public final class PluginClassLoader extends UrlClassLoader {
return myEnumerations[myIndex].nextElement();
}
}
@NotNull
@TestOnly
@ApiStatus.Internal
public List<ClassLoader> _getParents() {
//noinspection SSBasedInspection
return Collections.unmodifiableList(Arrays.asList(myParents));
}
}
@@ -3,6 +3,7 @@
package com.intellij.ide.plugins
import com.intellij.ide.plugins.cl.PluginClassLoader
import com.intellij.openapi.extensions.PluginId
import com.intellij.openapi.util.SystemInfo
import com.intellij.testFramework.PlatformTestUtil
@@ -15,11 +16,11 @@ import com.intellij.util.io.write
import com.intellij.util.lang.UrlClassLoader
import junit.framework.TestCase
import org.assertj.core.api.Assertions.assertThatThrownBy
import org.intellij.lang.annotations.Language
import org.junit.Assume.assumeTrue
import org.junit.Rule
import org.junit.Test
import java.io.File
import java.io.IOException
import java.net.URL
import java.net.URLClassLoader
import java.nio.file.Files
@@ -125,8 +126,7 @@ class PluginDescriptorTest {
urls.add(path.toUri().toURL())
}
}
val descriptors = PluginManagerCore.testLoadDescriptorsFromClassPath(
URLClassLoader(urls.toTypedArray(), null))
val descriptors = PluginManagerCore.testLoadDescriptorsFromClassPath(URLClassLoader(urls.toTypedArray(), null))
// core and com.intellij.workspace
assertThat(descriptors).hasSize(1)
}
@@ -135,8 +135,7 @@ class PluginDescriptorTest {
@Throws(Exception::class)
fun testProduction2() {
assumeTrue(SystemInfo.isMac && !UsefulTestCase.IS_UNDER_TEAMCITY)
val descriptors = PluginManagerCore.testLoadDescriptorsFromDir(
Paths.get("/Volumes/data/plugins"))
val descriptors = PluginManagerCore.testLoadDescriptorsFromDir(Paths.get("/Volumes/data/plugins"))
assertThat(descriptors).isNotEmpty()
}
@@ -158,7 +157,6 @@ class PluginDescriptorTest {
}
@Test
@Throws(IOException::class)
fun releaseDate() {
val pluginFile = inMemoryFs.fs.getPath("plugin/META-INF/plugin.xml")
pluginFile.write("""
@@ -173,6 +171,63 @@ class PluginDescriptorTest {
assertThat(SimpleDateFormat("yyyyMMdd", Locale.US).format(descriptor.releaseDate)).isEqualTo("20190811")
}
@Test
fun classLoader() {
val pluginDir = inMemoryFs.fs.getPath("/plugins")
writeDescriptor("foo", pluginDir, """
<idea-plugin>
<id>foo</id>
<depends>bar</depends>
<vendor>JetBrains</vendor>
</idea-plugin>""")
writeDescriptor("bar", pluginDir, """
<idea-plugin>
<id>bar</id>
<vendor>JetBrains</vendor>
</idea-plugin>""")
checkClassLoader(pluginDir)
}
@Test
fun `classLoader - optional dependency`() {
val pluginDir = inMemoryFs.fs.getPath("/plugins")
writeDescriptor("foo", pluginDir, """
<idea-plugin>
<id>foo</id>
<depends optional="true" config-file="stream-debugger.xml">bar</depends>
<vendor>JetBrains</vendor>
</idea-plugin>""")
pluginDir.resolve("foo/META-INF/stream-debugger.xml").write("""
<idea-plugin>
<actions>
</actions>
</idea-plugin>
""".trimIndent())
writeDescriptor("bar", pluginDir, """
<idea-plugin>
<id>bar</id>
<vendor>JetBrains</vendor>
</idea-plugin>""")
checkClassLoader(pluginDir)
}
private fun checkClassLoader(pluginDir: Path) {
val list = PluginManagerCore.testLoadDescriptorsFromDir(pluginDir)
assertThat(list).hasSize(2)
val bar = list[0]
assertThat(bar.pluginId.idString).isEqualTo("bar")
val foo = list[1]
assertThat(foo.pluginId.idString).isEqualTo("foo")
val fooClassLoader = foo.pluginClassLoader as PluginClassLoader
assertThat(fooClassLoader._getParents()).containsExactly(bar.pluginClassLoader)
}
@Test
fun componentConfig() {
val pluginFile = inMemoryFs.fs.getPath("/plugin/META-INF/plugin.xml")
@@ -243,4 +298,8 @@ class PluginDescriptorTest {
TestCase.assertEquals(impl1.hashCode(), impl2.hashCode())
TestCase.assertNotSame(impl1.name, impl2.name)
}
}
}
private fun writeDescriptor(id: String, pluginDir: Path, @Language("xml") data: String) {
pluginDir.resolve("$id/META-INF/plugin.xml").write(data.trimIndent())
}
@@ -122,7 +122,7 @@ public class PluginManagerTest {
private static void doPluginSortTest(@NotNull String testDataName, boolean isBundled) throws IOException, JDOMException {
PluginManagerCore.ourPluginError = null;
PluginLoadingResult loadPluginResult = loadDescriptors(testDataName + ".xml", isBundled);
PluginManagerCore.initializePlugins(loadPluginResult, PluginManagerTest.class.getClassLoader(), /* checkEssentialPlugins = */ false);
PluginManagerCore.initializePlugins(loadPluginResult, PluginManagerTest.class.getClassLoader(), /* checkEssentialPlugins = */ false, false);
String actual = StringUtil.join(loadPluginResult.getSortedPlugins(), o -> (o.isEnabled() ? "+ " : " ") + o.getPluginId().getIdString(), "\n") +
"\n\n" + StringUtil.notNullize(PluginManagerCore.ourPluginError).replace("<p/>", "\n");
PluginManagerCore.ourPluginError = null;