void (Function<? super String, String> namer) { Application app = ApplicationManager.getApplication(); if (app == null) { return; } app.invokeAndWait(() -> PlatformTestUtil.cleanupAllProjects()); Map<ExtensionPointImpl<?>, Collection<WeakReference<Object>>> extensionPointToNonPlatformExtensions = collectDynamicNonPlatformExtensions(app); IdeaPluginDescriptor corePlugin = PluginManagerCore.getPlugin(PluginManagerCore.CORE_ID); assert corePlugin != null; try { // It doesn't matter what plugin to pass here. Main thing here is firing events. fireBeforePluginUnloadEvent(corePlugin); app.invokeAndWait(() -> { // obey contract that used by DynamicPluginManager - reloading of plugin is done in EDT and write action. // one write action for all - as DynamicPluginManager does (plugin unloaded in one write action) app.runWriteAction(() -> { for (ExtensionPointImpl<?> ep : extensionPointToNonPlatformExtensions.keySet()) { ep.reset(); } }); }); for (Project project : ProjectUtil.getOpenProjects()) { ((CachedValuesManagerImpl)CachedValuesManager.getManager(project)).clearCachedValues(); } } finally { firePluginUnloadedEvent(corePlugin); } GCUtil.tryGcSoftlyReachableObjects(); //noinspection CallToSystemGC System.gc(); //noinspection CallToSystemGC System.gc(); String heapDump = TestApplicationManager.publishHeapDump("dynamicExtension"); AtomicBoolean failed = new AtomicBoolean(false); extensionPointToNonPlatformExtensions.forEach((ep, references) -> { String testName = escape(namer.fun("Dynamic EP unloading " + ep.name)); System.out.printf("##teamcity[testStarted name='%s' nodeId='%s' parentNodeId='%s']%n", testName, testName, MapSerializerUtil.escapeStr("[engine:junit-vintage]/[runner:_LastInSuiteTest]/[test:testDynamicExtensions(_LastInSuiteTest)]", MapSerializerUtil.STD_ESCAPER)); System.out.flush(); List<Object> alive = ContainerUtil.mapNotNull(references, WeakReference::get); if (!alive.isEmpty()) { String aliveExtensions = StringUtil.join(alive, o -> o + " (" + o.getClass() + ")", "\n"); System.out.printf("##teamcity[%s name='%s' nodeId='%s' message='%s']%n", MapSerializerUtil.TEST_FAILED, testName, testName, escape("Not unloaded extensions:\n" + aliveExtensions + "\n\n" + "See testDynamicExtensions output to find a heapDump")); System.out.flush(); failed.set(true); } else { System.out.printf("##teamcity[testFinished name='%s' nodeId='%s']%n", testName, testName); System.out.flush(); } }); if (failed.get()) { TestCase.fail("Some of dynamic extensions have not been unloaded. See individual tests for details. Heap dump: " + heapDump); } }