diff --git a/java/idea-ui/intellij.java.ui.tests.iml b/java/idea-ui/intellij.java.ui.tests.iml
index ad172adfd097..3faf05d01266 100644
--- a/java/idea-ui/intellij.java.ui.tests.iml
+++ b/java/idea-ui/intellij.java.ui.tests.iml
@@ -21,5 +21,6 @@
+
\ No newline at end of file
diff --git a/java/idea-ui/src/com/intellij/jarRepository/LibrarySynchronizationQueue.kt b/java/idea-ui/src/com/intellij/jarRepository/LibrarySynchronizationQueue.kt
index fc1cf9e92244..c6f9b2201206 100644
--- a/java/idea-ui/src/com/intellij/jarRepository/LibrarySynchronizationQueue.kt
+++ b/java/idea-ui/src/com/intellij/jarRepository/LibrarySynchronizationQueue.kt
@@ -17,7 +17,7 @@ import org.jetbrains.idea.maven.utils.library.RepositoryUtils
import kotlin.coroutines.coroutineContext
@Service(Service.Level.PROJECT)
-internal class LibrarySynchronizationQueue(private val project: Project, private val scope: CoroutineScope) {
+class LibrarySynchronizationQueue(private val project: Project, private val scope: CoroutineScope) {
private val synchronizationRequests = Channel(capacity = Channel.UNLIMITED).apply {
scope.coroutineContext.job.invokeOnCompletion {
close()
@@ -84,7 +84,11 @@ internal class LibrarySynchronizationQueue(private val project: Project, private
if (!coroutineContext.isActive) {
return
}
- if (readAction { library.needToReload() }) {
+ val needToReload = readAction {
+ if (library.isDisposed) return@readAction false
+ library.needToReload()
+ }
+ if (needToReload) {
RepositoryUtils.reloadDependencies(project, library)
}
}
diff --git a/java/idea-ui/testSrc/com/intellij/jarRepository/RepositoryLibraryTest.kt b/java/idea-ui/testSrc/com/intellij/jarRepository/RepositoryLibraryTest.kt
index 6019b424bf74..b6305741b531 100644
--- a/java/idea-ui/testSrc/com/intellij/jarRepository/RepositoryLibraryTest.kt
+++ b/java/idea-ui/testSrc/com/intellij/jarRepository/RepositoryLibraryTest.kt
@@ -2,53 +2,64 @@
package com.intellij.jarRepository
import com.intellij.java.library.getMavenCoordinates
+import com.intellij.openapi.Disposable
import com.intellij.openapi.application.runWriteActionAndWait
import com.intellij.openapi.roots.OrderRootType
import com.intellij.openapi.roots.impl.libraries.LibraryEx
import com.intellij.openapi.roots.libraries.Library
import com.intellij.openapi.roots.libraries.LibraryTablesRegistrar
+import com.intellij.openapi.util.Disposer
import com.intellij.openapi.vfs.VfsUtil
import com.intellij.platform.backend.workspace.WorkspaceModel
import com.intellij.platform.backend.workspace.impl.internal
-import com.intellij.testFramework.ApplicationRule
-import com.intellij.testFramework.DisposableRule
-import com.intellij.testFramework.RuleChain
-import com.intellij.testFramework.rules.ProjectModelRule
-import com.intellij.testFramework.rules.TempDirectory
+import com.intellij.testFramework.junit5.TestApplication
+import com.intellij.testFramework.junit5.TestDisposable
+import com.intellij.testFramework.rules.ProjectModelExtension
+import com.intellij.testFramework.rules.TempDirectoryExtension
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.runBlocking
import org.jetbrains.idea.maven.utils.library.RepositoryLibraryProperties
import org.jetbrains.idea.maven.utils.library.RepositoryUtils
-import org.junit.Assert.*
-import org.junit.Before
-import org.junit.ClassRule
-import org.junit.Rule
-import org.junit.Test
+import org.junit.jupiter.api.Assertions.assertFalse
+import org.junit.jupiter.api.BeforeEach
+import org.junit.jupiter.api.Test
+import org.junit.jupiter.api.assertDoesNotThrow
+import org.junit.jupiter.api.extension.RegisterExtension
import java.util.concurrent.TimeUnit
import kotlin.io.path.exists
+import kotlin.test.assertEquals
+import kotlin.test.assertNotNull
+import kotlin.test.assertNull
+import kotlin.test.assertTrue
+@TestApplication
class RepositoryLibraryTest {
- companion object {
- @JvmStatic
- @get:ClassRule
- val applicationRule = ApplicationRule()
- }
+ @TestDisposable
+ lateinit var disposable: Disposable
- private val disposableRule = DisposableRule()
- private val projectRule = ProjectModelRule()
- private val mavenRepo = TempDirectory()
- private val localMavenCache = TempDirectory()
- @get:Rule
- val rulesChain = RuleChain(localMavenCache, mavenRepo, projectRule, disposableRule)
+ @JvmField
+ @RegisterExtension
+ val projectRule: ProjectModelExtension = ProjectModelExtension()
+
+ @JvmField
+ @RegisterExtension
+ val mavenRepo = TempDirectoryExtension()
+
+ @JvmField
+ @RegisterExtension
+ val localMavenCache = TempDirectoryExtension()
private val ARTIFACT_NAME = "myArtifact"
private val GROUP_NAME = "myGroup"
private val LIBRARY_NAME = "NewLibrary"
- @Before
+ @BeforeEach
fun setUp() {
JarRepositoryManager.setLocalRepositoryPath(localMavenCache.root)
MavenRepoFixture(mavenRepo.root).apply {
addLibraryArtifact(group = GROUP_NAME, artifact = ARTIFACT_NAME, version = "1.0")
+ addLibraryArtifact(group = GROUP_NAME, artifact = ARTIFACT_NAME, version = "1.0-SNAPSHOT")
generateMavenMetadata(GROUP_NAME, ARTIFACT_NAME)
}
@@ -57,17 +68,21 @@ class RepositoryLibraryTest {
)
}
- private fun createLibrary(block: (LibraryEx.ModifiableModelEx) -> Unit = {}): Library {
+ private fun createLibrary(version: String = "1.0", libraryName: String = LIBRARY_NAME, block: (LibraryEx.ModifiableModelEx) -> Unit = {}): Library {
val libraryTable = LibraryTablesRegistrar.getInstance().getLibraryTable(projectRule.project)
val library = runWriteActionAndWait {
- projectRule.addProjectLevelLibrary(LIBRARY_NAME) {
+ projectRule.addProjectLevelLibrary(libraryName) {
it.kind = RepositoryLibraryType.REPOSITORY_LIBRARY_KIND
- it.properties = RepositoryLibraryProperties(GROUP_NAME, ARTIFACT_NAME, "1.0", false, emptyList())
+ it.properties = RepositoryLibraryProperties(GROUP_NAME, ARTIFACT_NAME, version, false, emptyList())
block(it)
}
}
- disposableRule.register {
- runWriteActionAndWait { libraryTable.removeLibrary(library) }
+ Disposer.register(disposable) {
+ runWriteActionAndWait {
+ if (!library.isDisposed) {
+ libraryTable.removeLibrary(library)
+ }
+ }
}
return library
}
@@ -105,6 +120,24 @@ class RepositoryLibraryTest {
assertTrue(workspaceVersion() > modelVersionBefore)
}
+ @Test
+ fun testSynchronizationQueueDoesWorkWithDisposedLibs() = runBlocking {
+ localMavenCache.rootPath.resolve(GROUP_NAME).resolve(ARTIFACT_NAME).resolve("1.0").resolve("$ARTIFACT_NAME-1.0.jar")
+
+ repeat(1) {
+ val library = createLibrary(version = "1.0-SNAPSHOT", libraryName = "Lib$it")
+ assertEquals(0, getLibraryRoots(library).size)
+ assertDoesNotThrow {
+ val deferred = launch {
+ LibrarySynchronizationQueue.getInstance(projectRule.project).requestSynchronization(library as LibraryEx)
+ LibrarySynchronizationQueue.getInstance(projectRule.project).flush()
+ }
+ Disposer.dispose(library)
+ deferred.join()
+ }
+ }
+ }
+
@Test
fun libraryNoUpdateProjectModel() {
val jar = localMavenCache.rootPath.resolve(GROUP_NAME).resolve(ARTIFACT_NAME).resolve("1.0").resolve("$ARTIFACT_NAME-1.0.jar")