mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-03-22 15:19:59 +07:00
[AutoSync] cleanup: migrated auto-sync test MockProjectAware on the platform operation wait system
GitOrigin-RevId: ba019de3fd61bf5965716ad730580a6d0cc301dc
This commit is contained in:
committed by
intellij-monorepo-bot
parent
5937b20901
commit
b4aeb3fa31
@@ -32,5 +32,6 @@
|
||||
<orderEntry type="module" module-name="intellij.platform.testFramework.junit5" scope="TEST" />
|
||||
<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.backend.observation" scope="TEST" />
|
||||
</component>
|
||||
</module>
|
||||
@@ -1,6 +1,7 @@
|
||||
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.openapi.externalSystem.autoimport
|
||||
|
||||
import com.intellij.openapi.application.invokeAndWaitIfNeeded
|
||||
import com.intellij.openapi.externalSystem.autoimport.ExternalSystemModificationType.*
|
||||
import com.intellij.openapi.externalSystem.autoimport.ExternalSystemProjectTrackerSettings.AutoReloadType.*
|
||||
import com.intellij.openapi.externalSystem.autoimport.ExternalSystemRefreshStatus.FAILURE
|
||||
@@ -10,6 +11,8 @@ import com.intellij.openapi.externalSystem.autoimport.ExternalSystemSettingsFile
|
||||
import com.intellij.openapi.externalSystem.autoimport.MockProjectAware.ReloadCollisionPassType
|
||||
import com.intellij.openapi.externalSystem.model.ProjectSystemId
|
||||
import com.intellij.openapi.externalSystem.util.Parallel.Companion.parallel
|
||||
import com.intellij.openapi.externalSystem.util.runReadAction
|
||||
import com.intellij.openapi.externalSystem.util.runWriteActionAndWait
|
||||
import com.intellij.openapi.util.Ref
|
||||
import com.intellij.testFramework.PlatformTestUtil
|
||||
import com.intellij.testFramework.refreshVfs
|
||||
@@ -473,7 +476,9 @@ class AutoReloadTest : AutoReloadTestCase() {
|
||||
|
||||
fun `test document changes between save`() {
|
||||
test { settingsFile ->
|
||||
val settingsDocument = settingsFile.getDocument()
|
||||
val settingsDocument = runReadAction {
|
||||
settingsFile.getDocument()
|
||||
}
|
||||
|
||||
settingsDocument.replaceContent("println 'hello'")
|
||||
assertStateAndReset(numReload = 0, notified = true, event = "change")
|
||||
@@ -643,11 +648,11 @@ class AutoReloadTest : AutoReloadTestCase() {
|
||||
assertActivationStatus(projectId1, projectId2, event = "refresh project")
|
||||
}
|
||||
|
||||
fun `test merging of refreshes with different nature`() {
|
||||
fun `test merging of refreshes with different nature (parallel)`() {
|
||||
test { settingsFile ->
|
||||
enableAsyncExecution()
|
||||
|
||||
waitForProjectReloadFinish {
|
||||
waitForAllProjectReloads {
|
||||
parallel {
|
||||
thread {
|
||||
settingsFile.modify(EXTERNAL)
|
||||
@@ -930,10 +935,16 @@ class AutoReloadTest : AutoReloadTestCase() {
|
||||
|
||||
fun `test settings file modification by document before sync`() {
|
||||
test { settingsFile ->
|
||||
val settingsDocument = settingsFile.getDocument()
|
||||
val settingsDocument = runReadAction {
|
||||
settingsFile.getDocument()
|
||||
}
|
||||
|
||||
settingsDocument.appendString(SAMPLE_TEXT + "\n")
|
||||
onceWhenReloading { settingsDocument.saveToDisk() }
|
||||
onceWhenReloading {
|
||||
runWriteActionAndWait {
|
||||
settingsDocument.saveToDisk()
|
||||
}
|
||||
}
|
||||
forceReloadProject()
|
||||
assertStateAndReset(numReload = 1, notified = false, event = "settings file modified by document before sync")
|
||||
}
|
||||
@@ -944,9 +955,7 @@ class AutoReloadTest : AutoReloadTestCase() {
|
||||
whenReloading(1) {
|
||||
settingsFile.modify(EXTERNAL)
|
||||
}
|
||||
waitForProjectReloadFinish(2) {
|
||||
settingsFile.modify(EXTERNAL)
|
||||
}
|
||||
settingsFile.modify(EXTERNAL)
|
||||
assertStateAndReset(numReload = 2, notified = false, event = "settings file modified during sync")
|
||||
}
|
||||
}
|
||||
@@ -956,9 +965,7 @@ class AutoReloadTest : AutoReloadTestCase() {
|
||||
whenReloadStarted(1) {
|
||||
forceReloadProject()
|
||||
}
|
||||
waitForProjectReloadFinish(2) {
|
||||
forceReloadProject()
|
||||
}
|
||||
forceReloadProject()
|
||||
assertStateAndReset(numReload = 2, notified = false, event = "test force sync action during sync")
|
||||
}
|
||||
}
|
||||
@@ -976,7 +983,7 @@ class AutoReloadTest : AutoReloadTestCase() {
|
||||
whenReloadStarted(expectedRefreshes - 1) {
|
||||
forceReloadProject()
|
||||
}
|
||||
waitForProjectReloadFinish(expectedRefreshes) {
|
||||
waitForAllProjectReloads {
|
||||
forceReloadProject()
|
||||
}
|
||||
assertStateAndReset(numReload = expectedRefreshes, notified = false, event = "reloads")
|
||||
@@ -998,7 +1005,7 @@ class AutoReloadTest : AutoReloadTestCase() {
|
||||
whenReloading(expectedRefreshes - 1) {
|
||||
settingsFile.modify(EXTERNAL)
|
||||
}
|
||||
waitForProjectReloadFinish(expectedRefreshes) {
|
||||
waitForAllProjectReloads {
|
||||
settingsFile.modify(EXTERNAL)
|
||||
}
|
||||
assertStateAndReset(numReload = expectedRefreshes, notified = false, event = "reloads")
|
||||
@@ -1026,24 +1033,28 @@ class AutoReloadTest : AutoReloadTestCase() {
|
||||
}
|
||||
}
|
||||
|
||||
fun `test merge project reloads`() {
|
||||
fun `test merge project reloads (parallel)`() {
|
||||
test { settingsFile ->
|
||||
enableAsyncExecution()
|
||||
setDispatcherMergingSpan(100)
|
||||
val alarm = Alarm()
|
||||
// see AutoImportProjectTracker.scheduleDelayedSmartProjectReload
|
||||
setDispatcherMergingSpan(100) // total merging delay 1000ms
|
||||
|
||||
val alarm = Alarm(Alarm.ThreadToUse.POOLED_THREAD, testDisposable)
|
||||
repeat(10) {
|
||||
val promise = AsyncPromise<Unit>()
|
||||
alarm.addRequest({
|
||||
waitForProjectReloadFinish {
|
||||
markDirty()
|
||||
scheduleProjectReload()
|
||||
}
|
||||
promise.setResult(Unit)
|
||||
}, 500)
|
||||
waitForProjectReloadFinish {
|
||||
alarm.addRequest(Runnable {
|
||||
waitForAllProjectReloads {
|
||||
markDirty()
|
||||
scheduleProjectReload()
|
||||
}
|
||||
promise.setResult(Unit)
|
||||
}, 500)
|
||||
waitForAllProjectReloads {
|
||||
settingsFile.modify(EXTERNAL)
|
||||
}
|
||||
PlatformTestUtil.waitForPromise(promise, TimeUnit.SECONDS.toMillis(10))
|
||||
invokeAndWaitIfNeeded {
|
||||
PlatformTestUtil.waitForPromise(promise, TimeUnit.SECONDS.toMillis(10))
|
||||
}
|
||||
assertStateAndReset(numReload = 1, notified = false, event = "project reload")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ package com.intellij.openapi.externalSystem.autoimport
|
||||
|
||||
import com.intellij.ide.file.BatchFileChangeListener
|
||||
import com.intellij.openapi.Disposable
|
||||
import com.intellij.openapi.application.invokeAndWaitIfNeeded
|
||||
import com.intellij.openapi.command.WriteCommandAction
|
||||
import com.intellij.openapi.components.ComponentManager
|
||||
import com.intellij.openapi.editor.Document
|
||||
@@ -15,19 +14,19 @@ import com.intellij.openapi.externalSystem.autoimport.ExternalSystemProjectTrack
|
||||
import com.intellij.openapi.externalSystem.autoimport.MockProjectAware.ReloadCollisionPassType
|
||||
import com.intellij.openapi.externalSystem.importing.ProjectResolverPolicy
|
||||
import com.intellij.openapi.externalSystem.service.project.autoimport.ProjectAware
|
||||
import com.intellij.openapi.util.io.*
|
||||
import com.intellij.openapi.progress.util.BackgroundTaskUtil
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.util.Computable
|
||||
import com.intellij.openapi.util.Disposer
|
||||
import com.intellij.openapi.util.Ref
|
||||
import com.intellij.openapi.util.io.getResolvedPath
|
||||
import com.intellij.openapi.util.io.toCanonicalPath
|
||||
import com.intellij.openapi.util.use
|
||||
import com.intellij.openapi.vfs.*
|
||||
import com.intellij.platform.externalSystem.testFramework.ExternalSystemTestCase
|
||||
import com.intellij.platform.externalSystem.testFramework.ExternalSystemTestUtil.TEST_EXTERNAL_SYSTEM_ID
|
||||
import com.intellij.platform.externalSystem.testFramework.TestExternalSystemManager
|
||||
import com.intellij.testFramework.ExtensionTestUtil
|
||||
import com.intellij.testFramework.PlatformTestUtil
|
||||
import com.intellij.testFramework.refreshVfs
|
||||
import com.intellij.testFramework.replaceService
|
||||
import com.intellij.testFramework.utils.editor.saveToDisk
|
||||
@@ -37,16 +36,16 @@ import com.intellij.testFramework.utils.vfs.createFile
|
||||
import com.intellij.testFramework.utils.vfs.deleteRecursively
|
||||
import com.intellij.testFramework.utils.vfs.getFile
|
||||
import com.intellij.testFramework.utils.vfs.refreshAndGetVirtualFile
|
||||
import org.jetbrains.concurrency.AsyncPromise
|
||||
import java.nio.file.Path
|
||||
import java.util.concurrent.TimeUnit
|
||||
import java.util.concurrent.atomic.AtomicInteger
|
||||
import kotlin.io.path.appendText
|
||||
import kotlin.io.path.readText
|
||||
import kotlin.io.path.writeText
|
||||
|
||||
@Suppress("unused", "MemberVisibilityCanBePrivate", "SameParameterValue")
|
||||
abstract class AutoReloadTestCase : ExternalSystemTestCase() {
|
||||
|
||||
override fun runInDispatchThread() = false
|
||||
|
||||
override fun getTestsTempDir() = "tmp${System.currentTimeMillis()}"
|
||||
|
||||
override fun getExternalSystemConfigFileName() = throw UnsupportedOperationException()
|
||||
@@ -238,12 +237,14 @@ abstract class AutoReloadTestCase : ExternalSystemTestCase() {
|
||||
projectTrackerSettings.loadState(state.second)
|
||||
}
|
||||
|
||||
protected fun assertProjectAware(projectAware: MockProjectAware,
|
||||
numReload: Int? = null,
|
||||
numSettingsAccess: Int? = null,
|
||||
numSubscribing: Int? = null,
|
||||
numUnsubscribing: Int? = null,
|
||||
event: String) {
|
||||
protected fun assertProjectAware(
|
||||
projectAware: MockProjectAware,
|
||||
numReload: Int? = null,
|
||||
numSettingsAccess: Int? = null,
|
||||
numSubscribing: Int? = null,
|
||||
numUnsubscribing: Int? = null,
|
||||
event: String,
|
||||
) {
|
||||
if (numReload != null) assertCountEvent(numReload, projectAware.reloadCounter.get(), "project reload", event)
|
||||
if (numSettingsAccess != null) assertCountEvent(numSettingsAccess, projectAware.settingsAccessCounter.get(), "access to settings",
|
||||
event)
|
||||
@@ -320,7 +321,7 @@ abstract class AutoReloadTestCase : ExternalSystemTestCase() {
|
||||
|
||||
protected fun testWithDummyExternalSystem(
|
||||
autoImportAwareCondition: Ref<Boolean>? = null,
|
||||
test: DummyExternalSystemTestBench.(VirtualFile) -> Unit
|
||||
test: DummyExternalSystemTestBench.(VirtualFile) -> Unit,
|
||||
) {
|
||||
val externalSystemManagers = ExternalSystemManager.EP_NAME.extensionList + TestExternalSystemManager(myProject)
|
||||
ExtensionTestUtil.maskExtensions(ExternalSystemManager.EP_NAME, externalSystemManagers, testRootDisposable)
|
||||
@@ -354,7 +355,7 @@ abstract class AutoReloadTestCase : ExternalSystemTestCase() {
|
||||
fun withProjectTracker(
|
||||
state: Pair<AutoImportProjectTracker.State, AutoImportProjectTrackerSettings.State> =
|
||||
AutoImportProjectTracker.State() to AutoImportProjectTrackerSettings.State(),
|
||||
test: (Disposable) -> Unit
|
||||
test: (Disposable) -> Unit,
|
||||
): Pair<AutoImportProjectTracker.State, AutoImportProjectTrackerSettings.State> {
|
||||
return myProject.replaceService(ExternalSystemProjectTrackerSettings::class.java, AutoImportProjectTrackerSettings()) {
|
||||
myProject.replaceService(ExternalSystemProjectTracker::class.java, AutoImportProjectTracker(myProject)) {
|
||||
@@ -372,7 +373,7 @@ abstract class AutoReloadTestCase : ExternalSystemTestCase() {
|
||||
projectAware: MockProjectAware,
|
||||
state: Pair<AutoImportProjectTracker.State, AutoImportProjectTrackerSettings.State> =
|
||||
AutoImportProjectTracker.State() to AutoImportProjectTrackerSettings.State(),
|
||||
test: SimpleTestBench.() -> Unit
|
||||
test: SimpleTestBench.() -> Unit,
|
||||
): Pair<AutoImportProjectTracker.State, AutoImportProjectTrackerSettings.State> {
|
||||
return withProjectTracker(state) {
|
||||
register(projectAware, parentDisposable = it)
|
||||
@@ -409,7 +410,7 @@ abstract class AutoReloadTestCase : ExternalSystemTestCase() {
|
||||
}
|
||||
|
||||
protected fun mockProjectAware(projectId: ExternalSystemProjectId = ExternalSystemProjectId(TEST_EXTERNAL_SYSTEM_ID, projectPath)) =
|
||||
MockProjectAware(projectId, testDisposable)
|
||||
MockProjectAware(projectId, myProject, testDisposable)
|
||||
|
||||
protected inner class SimpleTestBench(val projectAware: MockProjectAware) {
|
||||
|
||||
@@ -499,21 +500,8 @@ abstract class AutoReloadTestCase : ExternalSystemTestCase() {
|
||||
projectAware.resetAssertionCounters()
|
||||
}
|
||||
|
||||
fun waitForProjectReloadFinish(numExpectedReloads: Int = 1, action: () -> Unit) {
|
||||
require(numExpectedReloads > 0)
|
||||
Disposer.newDisposable(testDisposable, "waitForProjectReloadFinish").use { parentDisposable ->
|
||||
val promise = AsyncPromise<ExternalSystemRefreshStatus>()
|
||||
val uncompletedReloads = AtomicInteger(numExpectedReloads)
|
||||
whenReloadFinished(parentDisposable) { status ->
|
||||
if (uncompletedReloads.decrementAndGet() == 0) {
|
||||
promise.setResult(status)
|
||||
}
|
||||
}
|
||||
action()
|
||||
invokeAndWaitIfNeeded {
|
||||
PlatformTestUtil.waitForPromise(promise, TimeUnit.SECONDS.toMillis(10))
|
||||
}
|
||||
}
|
||||
fun waitForAllProjectReloads(action: () -> Unit) {
|
||||
projectAware.waitForAllProjectReloads(action)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -534,13 +522,15 @@ abstract class AutoReloadTestCase : ExternalSystemTestCase() {
|
||||
resetAssertionCounters()
|
||||
}
|
||||
|
||||
fun assertState(numReload: Int? = null,
|
||||
numReloadStarted: Int? = null,
|
||||
numReloadFinished: Int? = null,
|
||||
numSubscribing: Int? = null,
|
||||
numUnsubscribing: Int? = null,
|
||||
autoReloadType: AutoReloadType = SELECTIVE,
|
||||
event: String) {
|
||||
fun assertState(
|
||||
numReload: Int? = null,
|
||||
numReloadStarted: Int? = null,
|
||||
numReloadFinished: Int? = null,
|
||||
numSubscribing: Int? = null,
|
||||
numUnsubscribing: Int? = null,
|
||||
autoReloadType: AutoReloadType = SELECTIVE,
|
||||
event: String,
|
||||
) {
|
||||
if (numReload != null) assertCountEvent(numReload, projectAware.reloadCounter.get(), "project reload", event)
|
||||
if (numReloadStarted != null) assertCountEvent(numReloadStarted, projectAware.startReloadCounter.get(), "project before reload", event)
|
||||
if (numReloadFinished != null) assertCountEvent(numReloadFinished, projectAware.finishReloadCounter.get(), "project after reload", event)
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
package com.intellij.openapi.externalSystem.autoimport
|
||||
|
||||
import com.intellij.openapi.Disposable
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.application.invokeAndWaitIfNeeded
|
||||
import com.intellij.openapi.externalSystem.autoimport.ExternalSystemRefreshStatus.SUCCESS
|
||||
import com.intellij.openapi.externalSystem.autoimport.MockProjectAware.ReloadCollisionPassType.*
|
||||
@@ -11,17 +12,24 @@ import com.intellij.openapi.observable.operation.core.AtomicOperationTrace
|
||||
import com.intellij.openapi.observable.operation.core.isOperationInProgress
|
||||
import com.intellij.openapi.observable.operation.core.traceRun
|
||||
import com.intellij.openapi.observable.operation.core.withCompletedOperation
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.util.Disposer
|
||||
import com.intellij.openapi.util.io.toCanonicalPath
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.platform.backend.observation.ActivityKey
|
||||
import com.intellij.platform.backend.observation.Observation
|
||||
import com.intellij.platform.backend.observation.trackActivityBlocking
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlinx.coroutines.withTimeout
|
||||
import java.nio.file.Path
|
||||
import java.util.concurrent.atomic.AtomicInteger
|
||||
import java.util.concurrent.atomic.AtomicReference
|
||||
import kotlin.concurrent.thread
|
||||
import kotlin.time.Duration.Companion.seconds
|
||||
|
||||
class MockProjectAware(
|
||||
override val projectId: ExternalSystemProjectId,
|
||||
private val parentDisposable: Disposable
|
||||
private val project: Project,
|
||||
private val parentDisposable: Disposable,
|
||||
) : ExternalSystemProjectAware {
|
||||
|
||||
val subscribeCounter = AtomicInteger(0)
|
||||
@@ -145,12 +153,29 @@ class MockProjectAware(
|
||||
|
||||
private fun background(action: () -> Unit) {
|
||||
if (AutoImportProjectTracker.isAsyncChangesProcessing) {
|
||||
thread(block = action)
|
||||
ApplicationManager.getApplication().executeOnPooledThread(action)
|
||||
}
|
||||
else {
|
||||
action()
|
||||
}
|
||||
}
|
||||
|
||||
fun <R> waitForAllProjectReloads(action: () -> R): R {
|
||||
return project.trackActivityBlocking(MockProjectReloadActivityKey, action)
|
||||
.also {
|
||||
runBlocking {
|
||||
withTimeout(10.seconds) {
|
||||
Observation.awaitConfiguration(project) { message ->
|
||||
println(message)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private object MockProjectReloadActivityKey : ActivityKey {
|
||||
override val presentableName: String = "mock project reload"
|
||||
}
|
||||
|
||||
enum class ReloadCollisionPassType { DUPLICATE, CANCEL, IGNORE }
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.openapi.externalSystem.autoimport
|
||||
|
||||
import com.intellij.openapi.externalSystem.autoimport.ExternalSystemModificationType.EXTERNAL
|
||||
import com.intellij.openapi.externalSystem.util.Parallel.Companion.parallel
|
||||
|
||||
// Test for the mock auto-sync test infrastructure
|
||||
class MockProjectAwareTest : AutoReloadTestCase() {
|
||||
|
||||
fun `test wait for single mock reload function (parallel)`() {
|
||||
test {
|
||||
enableAsyncExecution()
|
||||
|
||||
waitForAllProjectReloads {
|
||||
forceReloadProject()
|
||||
}
|
||||
assertStateAndReset(numReload = 1, notified = false, event = "project reload")
|
||||
}
|
||||
}
|
||||
|
||||
fun `test wait for mock reload function (parallel)`() {
|
||||
test {
|
||||
enableAsyncExecution()
|
||||
|
||||
val expectedReloads = 10
|
||||
parallel {
|
||||
repeat(expectedReloads) {
|
||||
thread {
|
||||
waitForAllProjectReloads {
|
||||
forceReloadProject()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
assertStateAndReset(numReload = expectedReloads, notified = false, event = "$expectedReloads parallel project reloads")
|
||||
}
|
||||
}
|
||||
|
||||
fun `test wait for indirect mock reload function (parallel)`() {
|
||||
test { settingsFile ->
|
||||
enableAsyncExecution()
|
||||
|
||||
waitForAllProjectReloads {
|
||||
settingsFile.modify(EXTERNAL)
|
||||
}
|
||||
assertStateAndReset(numReload = 1, notified = false, event = "project reload")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.openapi.externalSystem.util
|
||||
|
||||
import com.intellij.openapi.application.invokeAndWaitIfNeeded
|
||||
import com.intellij.testFramework.PlatformTestUtil
|
||||
import org.jetbrains.concurrency.AsyncPromise
|
||||
import java.util.concurrent.CountDownLatch
|
||||
@@ -32,7 +33,9 @@ class Parallel private constructor() {
|
||||
pool.configure()
|
||||
pool.start.countDown()
|
||||
for (promise in pool.promises) {
|
||||
PlatformTestUtil.waitForPromise(promise)
|
||||
invokeAndWaitIfNeeded {
|
||||
PlatformTestUtil.waitForPromise(promise)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user