From 46ea908daf0fec7dba309b358dc528c2e0c89ef7 Mon Sep 17 00:00:00 2001 From: Nikolay Lunyak Date: Mon, 19 Jun 2023 13:02:05 +0300 Subject: [PATCH] [Tests] Ensure the temporary directories are cleared This change may prevent OOMs. Context: https://jetbrains.slack.com/archives/C4U955N6B/p1685000899030279 --- .../base/AbstractAnalysisApiBasedTest.kt | 19 ++++++++++++++- .../org/jetbrains/kotlin/test/TestRunner.kt | 4 ++-- .../impl/TemporaryDirectoryManagerImpl.kt | 23 ++++++++++++++----- 3 files changed, 37 insertions(+), 9 deletions(-) diff --git a/analysis/analysis-test-framework/tests/org/jetbrains/kotlin/analysis/test/framework/base/AbstractAnalysisApiBasedTest.kt b/analysis/analysis-test-framework/tests/org/jetbrains/kotlin/analysis/test/framework/base/AbstractAnalysisApiBasedTest.kt index ae022ace03b..044ebbb4275 100644 --- a/analysis/analysis-test-framework/tests/org/jetbrains/kotlin/analysis/test/framework/base/AbstractAnalysisApiBasedTest.kt +++ b/analysis/analysis-test-framework/tests/org/jetbrains/kotlin/analysis/test/framework/base/AbstractAnalysisApiBasedTest.kt @@ -37,8 +37,10 @@ import org.jetbrains.kotlin.test.model.ResultingArtifact import org.jetbrains.kotlin.test.runners.AbstractKotlinCompilerTest import org.jetbrains.kotlin.test.services.* import org.jetbrains.kotlin.test.services.impl.TemporaryDirectoryManagerImpl +import org.junit.jupiter.api.AfterEach import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.TestInfo +import java.io.IOException import java.nio.file.Path import java.nio.file.Paths import kotlin.io.path.exists @@ -52,7 +54,13 @@ abstract class AbstractAnalysisApiBasedTest : TestWithDisposable() { protected lateinit var testDataPath: Path private set - private lateinit var testServices: TestServices + private var _testServices: TestServices? = null + + private var testServices: TestServices + get() = _testServices ?: error("`_testServices` has not been initialized") + set(value) { + _testServices = value + } protected open fun configureTest(builder: TestConfigurationBuilder) { configurator.configureTest(builder, disposable) @@ -148,6 +156,15 @@ abstract class AbstractAnalysisApiBasedTest : TestWithDisposable() { doTestByModuleStructure(moduleStructure, testServices) } + @AfterEach + fun cleanupTemporaryDirectories() { + try { + _testServices?.temporaryDirectoryManager?.cleanupTemporaryDirectories() + } catch (e: IOException) { + println("Failed to clean temporary directories: ${e.message}\n${e.stackTrace}") + } + } + private fun createTestConfiguration(): TestConfiguration { val testConfiguration = testConfiguration(testDataPath.toString(), configure) Disposer.register(disposable, testConfiguration.rootDisposable) diff --git a/compiler/test-infrastructure/tests/org/jetbrains/kotlin/test/TestRunner.kt b/compiler/test-infrastructure/tests/org/jetbrains/kotlin/test/TestRunner.kt index 77116c83e76..c08ee2d7ea3 100644 --- a/compiler/test-infrastructure/tests/org/jetbrains/kotlin/test/TestRunner.kt +++ b/compiler/test-infrastructure/tests/org/jetbrains/kotlin/test/TestRunner.kt @@ -30,8 +30,8 @@ class TestRunner(private val testConfiguration: TestConfiguration) { } finally { try { testConfiguration.testServices.temporaryDirectoryManager.cleanupTemporaryDirectories() - } catch (_: IOException) { - // ignored + } catch (e: IOException) { + println("Failed to clean temporary directories: ${e.message}\n${e.stackTrace}") } beforeDispose(testConfiguration) Disposer.dispose(testConfiguration.rootDisposable) diff --git a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/services/impl/TemporaryDirectoryManagerImpl.kt b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/services/impl/TemporaryDirectoryManagerImpl.kt index 56ebcc70ed8..aa4ac9ddceb 100644 --- a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/services/impl/TemporaryDirectoryManagerImpl.kt +++ b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/services/impl/TemporaryDirectoryManagerImpl.kt @@ -5,22 +5,23 @@ package org.jetbrains.kotlin.test.services.impl -import com.intellij.openapi.util.io.FileUtil +import com.intellij.openapi.util.io.NioFiles import org.jetbrains.kotlin.test.services.TemporaryDirectoryManager import org.jetbrains.kotlin.test.services.TestServices import org.jetbrains.kotlin.test.services.testInfo import org.jetbrains.kotlin.test.util.KtTestUtil import java.io.File +import java.nio.file.Paths import java.util.* class TemporaryDirectoryManagerImpl(testServices: TestServices) : TemporaryDirectoryManager(testServices) { private val cache = mutableMapOf() - private val rootTempDir: File = run { + private val rootTempDir = lazy { val testInfo = testServices.testInfo val className = testInfo.className val methodName = testInfo.methodName if (!onWindows && className.length + methodName.length < 255) { - return@run KtTestUtil.tmpDirForTest(className, methodName) + return@lazy KtTestUtil.tmpDirForTest(className, methodName) } // This code will simplify directory name for windows. This is needed because there can occur errors due to long name @@ -32,15 +33,25 @@ class TemporaryDirectoryManagerImpl(testServices: TestServices) : TemporaryDirec } override val rootDir: File - get() = rootTempDir + get() = rootTempDir.value override fun getOrCreateTempDirectory(name: String): File { - return cache.getOrPut(name) { KtTestUtil.tmpDir(rootTempDir, name) } + return cache.getOrPut(name) { KtTestUtil.tmpDir(rootDir, name) } } override fun cleanupTemporaryDirectories() { cache.clear() - FileUtil.delete(rootTempDir) + + if (rootTempDir.isInitialized()) { + NioFiles.deleteRecursively(Paths.get(rootDir.path)) + } + } + + @Suppress("removal") + fun finalize() { + if (rootTempDir.isInitialized() && rootDir.exists()) { + error("The temporary directory $rootDir has not been deleted by the time the corresponding ${this::class.simpleName} is finalized.") + } } companion object {