mirror of
https://gitflic.ru/project/openide/openide.git
synced 2025-12-15 11:53:49 +07:00
[Jar Repository] [IDEA-328006] LibrarySynchronizationQueue now works properly with disposed libs
The library may be disposed from the moment it got into the queue till the moment it's processed GitOrigin-RevId: fe8a580766a267db11fb095ca71b589d17a34bbc
This commit is contained in:
committed by
intellij-monorepo-bot
parent
d99d8bd0ea
commit
c8930055a8
@@ -21,5 +21,6 @@
|
||||
<orderEntry type="module" module-name="intellij.platform.workspace.jps" scope="TEST" />
|
||||
<orderEntry type="module" module-name="intellij.platform.backend.workspace" scope="TEST" />
|
||||
<orderEntry type="module" module-name="intellij.platform.testFramework.junit5" scope="TEST" />
|
||||
<orderEntry type="library" name="kotlin-test" level="project" />
|
||||
</component>
|
||||
</module>
|
||||
@@ -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<Request>(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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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")
|
||||
|
||||
Reference in New Issue
Block a user