Use async profiler for perfTests if it presents in env variable; Add kt project copy-n-paste perfTests
This commit is contained in:
@@ -201,7 +201,7 @@ projectTest(taskName = "performanceTest") {
|
||||
dependsOn(performanceTestRuntime)
|
||||
|
||||
testClassesDirs = sourceSets["performanceTest"].output.classesDirs
|
||||
classpath = performanceTestRuntime
|
||||
classpath = performanceTestRuntime + files("${System.getenv("ASYNC_PROFILER_HOME")}/build/async-profiler.jar")
|
||||
workingDir = rootDir
|
||||
|
||||
jvmArgs?.removeAll { it.startsWith("-Xmx") }
|
||||
|
||||
+111
-22
@@ -13,6 +13,7 @@ import com.intellij.codeInsight.lookup.LookupElement
|
||||
import com.intellij.ide.highlighter.ModuleFileType
|
||||
import com.intellij.ide.startup.impl.StartupManagerImpl
|
||||
import com.intellij.idea.IdeaTestApplication
|
||||
import com.intellij.openapi.actionSystem.IdeActions
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.application.runWriteAction
|
||||
import com.intellij.openapi.editor.EditorFactory
|
||||
@@ -102,6 +103,7 @@ abstract class AbstractPerformanceProjectsTest : UsefulTestCase() {
|
||||
assertTrue("kotlin project has been not imported properly", perfHighlightFile.isNotEmpty())
|
||||
} finally {
|
||||
closeProject(project)
|
||||
myApplication.setDataProvider(null)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -112,9 +114,10 @@ abstract class AbstractPerformanceProjectsTest : UsefulTestCase() {
|
||||
ThrowableRunnable {
|
||||
if (myProject != null) {
|
||||
DaemonCodeAnalyzerSettings.getInstance().isImportHintEnabled = true // return default value to avoid unnecessary save
|
||||
(StartupManager.getInstance(myProject!!) as StartupManagerImpl).checkCleared()
|
||||
(DaemonCodeAnalyzer.getInstance(myProject!!) as DaemonCodeAnalyzerImpl).cleanupAfterTest()
|
||||
closeProject(myProject!!)
|
||||
(StartupManager.getInstance(project()) as StartupManagerImpl).checkCleared()
|
||||
(DaemonCodeAnalyzer.getInstance(project()) as DaemonCodeAnalyzerImpl).cleanupAfterTest()
|
||||
closeProject(project())
|
||||
myApplication.setDataProvider(null)
|
||||
myProject = null
|
||||
}
|
||||
}).run()
|
||||
@@ -230,6 +233,7 @@ abstract class AbstractPerformanceProjectsTest : UsefulTestCase() {
|
||||
// close all project but last - we're going to return and use it further
|
||||
if (counter < warmUpIterations + iterations - 1) {
|
||||
closeProject(project)
|
||||
myApplication.setDataProvider(null)
|
||||
}
|
||||
counter++
|
||||
}
|
||||
@@ -253,6 +257,8 @@ abstract class AbstractPerformanceProjectsTest : UsefulTestCase() {
|
||||
dispatchAllInvocationEvents()
|
||||
|
||||
Fixture.enableAnnotatorsAndLoadDefinitions(project)
|
||||
|
||||
myApplication.setDataProvider(TestDataProvider(project))
|
||||
}
|
||||
|
||||
return lastProject ?: error("unable to open project $name at $path")
|
||||
@@ -265,7 +271,6 @@ abstract class AbstractPerformanceProjectsTest : UsefulTestCase() {
|
||||
|
||||
refreshGradleProject(projectPath, project)
|
||||
|
||||
//ExternalProjectsManagerImpl.getInstance(project).setStoreExternally(false)
|
||||
dispatchAllInvocationEvents()
|
||||
|
||||
// WARNING: [VD] DO NOT SAVE PROJECT AS IT COULD PERSIST WRONG MODULES INFO
|
||||
@@ -286,7 +291,7 @@ abstract class AbstractPerformanceProjectsTest : UsefulTestCase() {
|
||||
revertChangesAtTheEnd: Boolean = true,
|
||||
note: String = ""
|
||||
) = perfTypeAndAutocomplete(
|
||||
myProject!!, stats, fileName, marker, insertString, surroundItems,
|
||||
project(), stats, fileName, marker, insertString, surroundItems,
|
||||
lookupElements = lookupElements, typeAfterMarker = typeAfterMarker,
|
||||
revertChangesAtTheEnd = revertChangesAtTheEnd, note = note
|
||||
)
|
||||
@@ -313,11 +318,7 @@ abstract class AbstractPerformanceProjectsTest : UsefulTestCase() {
|
||||
val editor = fixture.editor
|
||||
|
||||
val initialText = editor.document.text
|
||||
if (isAKotlinScriptFile(fileName)) {
|
||||
runAndMeasure("update script dependencies for $fileName") {
|
||||
ScriptConfigurationManager.updateScriptDependenciesSynchronously(fixture.psiFile, project)
|
||||
}
|
||||
}
|
||||
updateScriptDependenciesIfNeeded(fileName, fixture, project)
|
||||
|
||||
val tasksIdx = editor.document.text.indexOf(marker)
|
||||
assertTrue("marker '$marker' not found in $fileName", tasksIdx > 0)
|
||||
@@ -360,7 +361,8 @@ abstract class AbstractPerformanceProjectsTest : UsefulTestCase() {
|
||||
}
|
||||
commitAllDocuments()
|
||||
}
|
||||
}
|
||||
},
|
||||
profileEnabled = true
|
||||
)
|
||||
}
|
||||
|
||||
@@ -374,7 +376,7 @@ abstract class AbstractPerformanceProjectsTest : UsefulTestCase() {
|
||||
revertChangesAtTheEnd: Boolean = true,
|
||||
note: String = ""
|
||||
) = perfTypeAndHighlight(
|
||||
myProject!!, stats, fileName, marker, insertString, surroundItems,
|
||||
project(), stats, fileName, marker, insertString, surroundItems,
|
||||
typeAfterMarker = typeAfterMarker,
|
||||
revertChangesAtTheEnd = revertChangesAtTheEnd, note = note
|
||||
)
|
||||
@@ -399,11 +401,7 @@ abstract class AbstractPerformanceProjectsTest : UsefulTestCase() {
|
||||
val editor = fixture.editor
|
||||
|
||||
val initialText = editor.document.text
|
||||
if (isAKotlinScriptFile(fileName)) {
|
||||
runAndMeasure("update script dependencies for $fileName") {
|
||||
ScriptConfigurationManager.updateScriptDependenciesSynchronously(fixture.psiFile, project)
|
||||
}
|
||||
}
|
||||
updateScriptDependenciesIfNeeded(fileName, fixture, project)
|
||||
|
||||
val tasksIdx = editor.document.text.indexOf(marker)
|
||||
assertTrue("marker '$marker' not found in $fileName", tasksIdx > 0)
|
||||
@@ -442,10 +440,97 @@ abstract class AbstractPerformanceProjectsTest : UsefulTestCase() {
|
||||
pair.second.revertChanges(revertChangesAtTheEnd, pair.first)
|
||||
}
|
||||
commitAllDocuments()
|
||||
}
|
||||
},
|
||||
profileEnabled = true
|
||||
)
|
||||
}
|
||||
|
||||
fun perfCopyAndPaste(
|
||||
stats: Stats,
|
||||
sourceFileName: String,
|
||||
sourceInitialMarker: String? = null,
|
||||
sourceFinalMarker: String? = null,
|
||||
targetFileName: String,
|
||||
targetInitialMarker: String? = null,
|
||||
targetFinalMarker: String? = null,
|
||||
note: String = ""
|
||||
) = perfCopyAndPaste(
|
||||
project(), stats,
|
||||
sourceFileName, sourceInitialMarker, sourceFinalMarker,
|
||||
targetFileName, targetInitialMarker, targetFinalMarker,
|
||||
note
|
||||
)
|
||||
|
||||
fun perfCopyAndPaste(
|
||||
project: Project,
|
||||
stats: Stats,
|
||||
sourceFileName: String,
|
||||
sourceInitialMarker: String? = null,
|
||||
sourceFinalMarker: String? = null,
|
||||
targetFileName: String,
|
||||
targetInitialMarker: String? = null,
|
||||
targetFinalMarker: String? = null,
|
||||
note: String = ""
|
||||
) {
|
||||
stats.perfTest<Pair<Array<Fixture>, String>, Boolean>(
|
||||
warmUpIterations = 8,
|
||||
iterations = 15,
|
||||
testName = "${notePrefix(note)}$sourceFileName",
|
||||
setUp = {
|
||||
val fixture1 = openFixture(project, sourceFileName)
|
||||
val fixture2 = openFixture(project, targetFileName)
|
||||
|
||||
val initialText2 = fixture2.document.text
|
||||
|
||||
updateScriptDependenciesIfNeeded(sourceFileName, fixture1, project)
|
||||
updateScriptDependenciesIfNeeded(sourceFileName, fixture2, project)
|
||||
|
||||
fixture1.selectMarkers(sourceInitialMarker, sourceFinalMarker)
|
||||
fixture2.selectMarkers(targetInitialMarker, targetFinalMarker)
|
||||
|
||||
it.setUpValue = Pair(arrayOf(fixture1, fixture2), initialText2)
|
||||
},
|
||||
test = {
|
||||
it.setUpValue?.let { setUpValue ->
|
||||
val fixture1 = setUpValue.first[0]
|
||||
val fixture2 = setUpValue.first[1]
|
||||
it.value = fixture1.performEditorAction(IdeActions.ACTION_COPY) &&
|
||||
fixture2.performEditorAction(IdeActions.ACTION_PASTE)
|
||||
}
|
||||
},
|
||||
tearDown = {
|
||||
try {
|
||||
commitAllDocuments()
|
||||
it.value?.let { performed ->
|
||||
assertTrue("copy-n-paste has not performed well", performed)
|
||||
// files could be different due to spaces
|
||||
//assertEquals(it.setUpValue!!.first.document.text, it.setUpValue!!.second.document.text)
|
||||
}
|
||||
} finally {
|
||||
it.setUpValue?.let { setUpValue ->
|
||||
// pair.second.performEditorAction(IdeActions.ACTION_UNDO)
|
||||
val fixture2 = setUpValue.first[1]
|
||||
fixture2.applyText(setUpValue.second)
|
||||
}
|
||||
commitAllDocuments()
|
||||
}
|
||||
},
|
||||
profileEnabled = true
|
||||
)
|
||||
}
|
||||
|
||||
private fun updateScriptDependenciesIfNeeded(
|
||||
fileName: String,
|
||||
fixture: Fixture,
|
||||
project: Project
|
||||
) {
|
||||
if (isAKotlinScriptFile(fileName)) {
|
||||
runAndMeasure("update script dependencies for $fileName") {
|
||||
ScriptConfigurationManager.updateScriptDependenciesSynchronously(fixture.psiFile, project)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun initKotlinProject(
|
||||
project: Project,
|
||||
projectPath: String,
|
||||
@@ -468,7 +553,7 @@ abstract class AbstractPerformanceProjectsTest : UsefulTestCase() {
|
||||
}
|
||||
|
||||
protected fun perfHighlightFile(name: String, stats: Stats): List<HighlightInfo> =
|
||||
perfHighlightFile(myProject!!, name, stats)
|
||||
perfHighlightFile(project(), name, stats)
|
||||
|
||||
protected fun perfHighlightFile(
|
||||
project: Project,
|
||||
@@ -495,7 +580,8 @@ abstract class AbstractPerformanceProjectsTest : UsefulTestCase() {
|
||||
commitAllDocuments()
|
||||
FileEditorManager.getInstance(project).closeFile(it.setUpValue!!.psiFile.virtualFile)
|
||||
PsiManager.getInstance(project).dropPsiCaches()
|
||||
}
|
||||
},
|
||||
profileEnabled = !isWarmUp
|
||||
)
|
||||
highlightInfos
|
||||
}
|
||||
@@ -517,7 +603,9 @@ abstract class AbstractPerformanceProjectsTest : UsefulTestCase() {
|
||||
}
|
||||
|
||||
protected fun perfScriptDependencies(name: String, stats: Stats, note: String = "") =
|
||||
perfScriptDependencies(myProject!!, name, stats, note = note)
|
||||
perfScriptDependencies(project(), name, stats, note = note)
|
||||
|
||||
private fun project() = myProject ?: error("project has not been initialized")
|
||||
|
||||
private fun perfScriptDependencies(
|
||||
project: Project,
|
||||
@@ -536,7 +624,8 @@ abstract class AbstractPerformanceProjectsTest : UsefulTestCase() {
|
||||
tearDown = {
|
||||
it.setUpValue?.let { ef -> cleanupCaches(project, ef.psiFile.virtualFile) }
|
||||
it.value?.let { v -> assertNotNull(v) }
|
||||
}
|
||||
},
|
||||
profileEnabled = true
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
-551
@@ -1,551 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.perf
|
||||
|
||||
import com.intellij.codeInsight.daemon.*
|
||||
import com.intellij.codeInsight.daemon.impl.DaemonCodeAnalyzerImpl
|
||||
import com.intellij.codeInsight.daemon.impl.HighlightInfo
|
||||
import com.intellij.codeInsight.daemon.impl.IdentifierHighlighterPassFactory
|
||||
import com.intellij.codeInsight.lookup.LookupElement
|
||||
import com.intellij.ide.highlighter.ModuleFileType
|
||||
import com.intellij.ide.startup.impl.StartupManagerImpl
|
||||
import com.intellij.idea.IdeaTestApplication
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.application.runWriteAction
|
||||
import com.intellij.openapi.editor.EditorFactory
|
||||
import com.intellij.openapi.externalSystem.service.project.manage.ExternalProjectsManagerImpl
|
||||
import com.intellij.openapi.fileEditor.FileDocumentManager
|
||||
import com.intellij.openapi.fileEditor.FileEditorManager
|
||||
import com.intellij.openapi.fileEditor.impl.FileEditorManagerImpl
|
||||
import com.intellij.openapi.module.ModuleManager
|
||||
import com.intellij.openapi.module.ModuleTypeId
|
||||
import com.intellij.openapi.project.DumbService
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.project.ex.ProjectManagerEx
|
||||
import com.intellij.openapi.project.impl.ProjectImpl
|
||||
import com.intellij.openapi.projectRoots.JavaSdk
|
||||
import com.intellij.openapi.projectRoots.ProjectJdkTable
|
||||
import com.intellij.openapi.projectRoots.Sdk
|
||||
import com.intellij.openapi.projectRoots.impl.JavaAwareProjectJdkTableImpl
|
||||
import com.intellij.openapi.roots.ProjectRootManager
|
||||
import com.intellij.openapi.roots.ex.ProjectRootManagerEx
|
||||
import com.intellij.openapi.startup.StartupManager
|
||||
import com.intellij.openapi.vcs.changes.ChangeListManager
|
||||
import com.intellij.openapi.vcs.changes.ChangeListManagerImpl
|
||||
import com.intellij.openapi.vfs.LocalFileSystem
|
||||
import com.intellij.openapi.vfs.VirtualFileManager
|
||||
import com.intellij.psi.PsiDocumentManager
|
||||
import com.intellij.psi.PsiFile
|
||||
import com.intellij.psi.PsiManager
|
||||
import com.intellij.testFramework.*
|
||||
import com.intellij.testFramework.fixtures.impl.CodeInsightTestFixtureImpl
|
||||
import com.intellij.util.ArrayUtilRt
|
||||
import com.intellij.util.ThrowableRunnable
|
||||
import com.intellij.util.indexing.UnindexedFilesUpdater
|
||||
import com.intellij.util.io.exists
|
||||
import org.jetbrains.kotlin.idea.configuration.getModulesWithKotlinFiles
|
||||
import org.jetbrains.kotlin.idea.core.script.ScriptConfigurationManager
|
||||
import org.jetbrains.kotlin.idea.framework.KotlinSdkType
|
||||
import org.jetbrains.kotlin.idea.perf.Stats.Companion.WARM_UP
|
||||
import org.jetbrains.kotlin.idea.perf.Stats.Companion.runAndMeasure
|
||||
import org.jetbrains.kotlin.idea.project.getAndCacheLanguageLevelByDependencies
|
||||
import org.jetbrains.kotlin.idea.test.ConfigLibraryUtil
|
||||
import org.jetbrains.kotlin.idea.test.invalidateLibraryCache
|
||||
import org.jetbrains.kotlin.idea.testFramework.*
|
||||
import org.jetbrains.kotlin.idea.testFramework.Fixture.Companion.cleanupCaches
|
||||
import org.jetbrains.kotlin.idea.testFramework.Fixture.Companion.isAKotlinScriptFile
|
||||
import org.jetbrains.kotlin.idea.testFramework.Fixture.Companion.openFileInEditor
|
||||
import org.jetbrains.kotlin.idea.testFramework.Fixture.Companion.openFixture
|
||||
import java.io.File
|
||||
import java.nio.file.Paths
|
||||
|
||||
abstract class AbstractPerformanceProjectsTest : UsefulTestCase() {
|
||||
|
||||
// myProject is not required for all potential perf test cases
|
||||
protected var myProject: Project? = null
|
||||
private lateinit var jdk18: Sdk
|
||||
private lateinit var myApplication: IdeaTestApplication
|
||||
|
||||
override fun isStressTest(): Boolean = true
|
||||
|
||||
override fun isPerformanceTest(): Boolean = false
|
||||
|
||||
override fun setUp() {
|
||||
super.setUp()
|
||||
|
||||
myApplication = IdeaTestApplication.getInstance()
|
||||
runWriteAction {
|
||||
val jdkTableImpl = JavaAwareProjectJdkTableImpl.getInstanceEx()
|
||||
val homePath = if (jdkTableImpl.internalJdk.homeDirectory!!.name == "jre") {
|
||||
jdkTableImpl.internalJdk.homeDirectory!!.parent.path
|
||||
} else {
|
||||
jdkTableImpl.internalJdk.homePath!!
|
||||
}
|
||||
|
||||
val javaSdk = JavaSdk.getInstance()
|
||||
jdk18 = javaSdk.createJdk("1.8", homePath)
|
||||
val internal = javaSdk.createJdk("IDEA jdk", homePath)
|
||||
|
||||
val jdkTable = ProjectJdkTable.getInstance()
|
||||
jdkTable.addJdk(jdk18, testRootDisposable)
|
||||
jdkTable.addJdk(internal, testRootDisposable)
|
||||
KotlinSdkType.setUpIfNeeded()
|
||||
}
|
||||
}
|
||||
|
||||
protected fun warmUpProject(stats: Stats) {
|
||||
val project = perfOpenHelloWorld(stats, WARM_UP)
|
||||
try {
|
||||
val perfHighlightFile = perfHighlightFile(project, "src/HelloMain.kt", stats, WARM_UP)
|
||||
assertTrue("kotlin project has been not imported properly", perfHighlightFile.isNotEmpty())
|
||||
} finally {
|
||||
closeProject(project)
|
||||
}
|
||||
}
|
||||
|
||||
override fun tearDown() {
|
||||
commitAllDocuments()
|
||||
RunAll(
|
||||
ThrowableRunnable { super.tearDown() },
|
||||
ThrowableRunnable {
|
||||
if (myProject != null) {
|
||||
DaemonCodeAnalyzerSettings.getInstance().isImportHintEnabled = true // return default value to avoid unnecessary save
|
||||
(StartupManager.getInstance(myProject!!) as StartupManagerImpl).checkCleared()
|
||||
(DaemonCodeAnalyzer.getInstance(myProject!!) as DaemonCodeAnalyzerImpl).cleanupAfterTest()
|
||||
closeProject(myProject!!)
|
||||
myProject = null
|
||||
}
|
||||
}).run()
|
||||
}
|
||||
|
||||
fun simpleFilename(fileName: String): String {
|
||||
val lastIndexOf = fileName.lastIndexOf('/')
|
||||
return if (lastIndexOf >= 0) fileName.substring(lastIndexOf + 1) else fileName
|
||||
}
|
||||
|
||||
protected fun perfOpenKotlinProjectFast(stats: Stats) =
|
||||
perfOpenKotlinProject(stats, fast = true)
|
||||
|
||||
protected fun perfOpenKotlinProject(stats: Stats, fast: Boolean = false) {
|
||||
myProject = innerPerfOpenProject("kotlin", stats = stats, path = "../perfTestProject", note = "", fast = fast)
|
||||
}
|
||||
|
||||
protected fun perfOpenHelloWorld(stats: Stats, note: String = ""): Project =
|
||||
innerPerfOpenProject("helloKotlin", stats, note, path = "idea/testData/perfTest/helloKotlin", simpleModule = true)
|
||||
|
||||
protected fun innerPerfOpenProject(
|
||||
name: String,
|
||||
stats: Stats,
|
||||
note: String,
|
||||
path: String,
|
||||
simpleModule: Boolean = false,
|
||||
fast: Boolean = false
|
||||
): Project {
|
||||
val projectPath = File(path).canonicalPath
|
||||
|
||||
assertTrue("path $path does not exist, check README.md", File(projectPath).exists())
|
||||
|
||||
val warmUpIterations = if (fast) 0 else 1
|
||||
val iterations = if (fast) 1 else 3
|
||||
val projectManagerEx = ProjectManagerEx.getInstanceEx()
|
||||
|
||||
var lastProject: Project? = null
|
||||
var counter = 0
|
||||
|
||||
stats.perfTest<Unit, Project>(
|
||||
warmUpIterations = warmUpIterations,
|
||||
iterations = iterations,
|
||||
testName = "open project${if (note.isNotEmpty()) " $note" else ""}",
|
||||
test = {
|
||||
val project = if (!simpleModule) {
|
||||
val project = projectManagerEx.loadProject(Paths.get(path), name)
|
||||
assertNotNull("project $name at $path is not loaded", project)
|
||||
val projectRootManager = ProjectRootManager.getInstance(project!!)
|
||||
|
||||
runWriteAction {
|
||||
with(projectRootManager) {
|
||||
projectSdk = jdk18
|
||||
}
|
||||
}
|
||||
assertTrue("project $name at $path is not opened", projectManagerEx.openProject(project))
|
||||
project
|
||||
} else {
|
||||
val project = projectManagerEx.loadAndOpenProject(projectPath)!!
|
||||
initKotlinProject(project, projectPath, name)
|
||||
project
|
||||
}
|
||||
|
||||
(project as ProjectImpl).registerComponentImplementation(
|
||||
FileEditorManager::class.java,
|
||||
FileEditorManagerImpl::class.java
|
||||
)
|
||||
|
||||
dispatchAllInvocationEvents()
|
||||
|
||||
with(StartupManager.getInstance(project) as StartupManagerImpl) {
|
||||
ProjectRootManagerEx.getInstanceEx(project).markRootsForRefresh()
|
||||
VirtualFileManager.getInstance().syncRefresh()
|
||||
|
||||
runStartupActivities()
|
||||
runPostStartupActivities()
|
||||
}
|
||||
|
||||
logMessage { "project $name is ${if (project.isInitialized) "initialized" else "not initialized"}" }
|
||||
|
||||
with(ChangeListManager.getInstance(project) as ChangeListManagerImpl) {
|
||||
waitUntilRefreshed()
|
||||
}
|
||||
|
||||
it.value = project
|
||||
},
|
||||
tearDown = {
|
||||
it.value?.let { project ->
|
||||
|
||||
runAndMeasure("refresh gradle project $name") {
|
||||
refreshGradleProjectIfNeeded(projectPath, project)
|
||||
}
|
||||
|
||||
ApplicationManager.getApplication().executeOnPooledThread {
|
||||
DumbService.getInstance(project).waitForSmartMode()
|
||||
|
||||
for (module in getModulesWithKotlinFiles(project)) {
|
||||
module.getAndCacheLanguageLevelByDependencies()
|
||||
}
|
||||
}.get()
|
||||
|
||||
val modules = ModuleManager.getInstance(project).modules
|
||||
assertTrue("project has to have at least one module", modules.isNotEmpty())
|
||||
|
||||
logMessage { "modules of $name: ${modules.map { m -> m.name }}" }
|
||||
|
||||
lastProject = project
|
||||
VirtualFileManager.getInstance().syncRefresh()
|
||||
|
||||
runWriteAction {
|
||||
project.save()
|
||||
}
|
||||
|
||||
logMessage { "project '$name' successfully opened" }
|
||||
|
||||
// close all project but last - we're going to return and use it further
|
||||
if (counter < warmUpIterations + iterations - 1) {
|
||||
closeProject(project)
|
||||
}
|
||||
counter++
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
// indexing
|
||||
lastProject?.let { project ->
|
||||
invalidateLibraryCache(project)
|
||||
|
||||
CodeInsightTestFixtureImpl.ensureIndexesUpToDate(project)
|
||||
|
||||
dispatchAllInvocationEvents()
|
||||
|
||||
logMessage { "project $name is ${if (project.isInitialized) "initialized" else "not initialized"}" }
|
||||
|
||||
with(DumbService.getInstance(project)) {
|
||||
queueTask(UnindexedFilesUpdater(project))
|
||||
completeJustSubmittedTasks()
|
||||
}
|
||||
dispatchAllInvocationEvents()
|
||||
|
||||
Fixture.enableAnnotatorsAndLoadDefinitions(project)
|
||||
}
|
||||
|
||||
return lastProject ?: error("unable to open project $name at $path")
|
||||
}
|
||||
|
||||
private fun refreshGradleProjectIfNeeded(projectPath: String, project: Project) {
|
||||
if (listOf("build.gradle.kts", "build.gradle").map { name -> Paths.get(projectPath, name).exists() }.find { e -> e } != true) return
|
||||
|
||||
ExternalProjectsManagerImpl.getInstance(project).setStoreExternally(true)
|
||||
|
||||
refreshGradleProject(projectPath, project)
|
||||
|
||||
//ExternalProjectsManagerImpl.getInstance(project).setStoreExternally(false)
|
||||
dispatchAllInvocationEvents()
|
||||
|
||||
// WARNING: [VD] DO NOT SAVE PROJECT AS IT COULD PERSIST WRONG MODULES INFO
|
||||
|
||||
// runInEdtAndWait {
|
||||
// PlatformTestUtil.saveProject(project)
|
||||
// }
|
||||
}
|
||||
|
||||
fun perfTypeAndAutocomplete(
|
||||
stats: Stats,
|
||||
fileName: String,
|
||||
marker: String,
|
||||
insertString: String,
|
||||
surroundItems: String = "\n",
|
||||
lookupElements: List<String>,
|
||||
typeAfterMarker: Boolean = true,
|
||||
revertChangesAtTheEnd: Boolean = true,
|
||||
note: String = ""
|
||||
) = perfTypeAndAutocomplete(
|
||||
myProject!!, stats, fileName, marker, insertString, surroundItems,
|
||||
lookupElements = lookupElements, typeAfterMarker = typeAfterMarker,
|
||||
revertChangesAtTheEnd = revertChangesAtTheEnd, note = note
|
||||
)
|
||||
|
||||
fun perfTypeAndAutocomplete(
|
||||
project: Project,
|
||||
stats: Stats,
|
||||
fileName: String,
|
||||
marker: String,
|
||||
insertString: String,
|
||||
surroundItems: String = "\n",
|
||||
lookupElements: List<String>,
|
||||
typeAfterMarker: Boolean = true,
|
||||
revertChangesAtTheEnd: Boolean = true,
|
||||
note: String = ""
|
||||
) {
|
||||
assertTrue("lookupElements has to be not empty", lookupElements.isNotEmpty())
|
||||
stats.perfTest<Pair<String, Fixture>, Array<LookupElement>>(
|
||||
warmUpIterations = 8,
|
||||
iterations = 15,
|
||||
testName = "typeAndAutocomplete ${notePrefix(note)}$fileName",
|
||||
setUp = {
|
||||
val fixture = openFixture(project, fileName)
|
||||
val editor = fixture.editor
|
||||
|
||||
val initialText = editor.document.text
|
||||
if (isAKotlinScriptFile(fileName)) {
|
||||
runAndMeasure("update script dependencies for $fileName") {
|
||||
ScriptConfigurationManager.updateScriptDependenciesSynchronously(fixture.psiFile, project)
|
||||
}
|
||||
}
|
||||
|
||||
val tasksIdx = editor.document.text.indexOf(marker)
|
||||
assertTrue("marker '$marker' not found in $fileName", tasksIdx > 0)
|
||||
if (typeAfterMarker) {
|
||||
editor.caretModel.moveToOffset(tasksIdx + marker.length + 1)
|
||||
} else {
|
||||
editor.caretModel.moveToOffset(tasksIdx - 1)
|
||||
}
|
||||
|
||||
for (surroundItem in surroundItems) {
|
||||
EditorTestUtil.performTypingAction(editor, surroundItem)
|
||||
}
|
||||
|
||||
editor.caretModel.moveToOffset(editor.caretModel.offset - if (typeAfterMarker) 1 else 2)
|
||||
|
||||
if (!typeAfterMarker) {
|
||||
for (surroundItem in surroundItems) {
|
||||
EditorTestUtil.performTypingAction(editor, surroundItem)
|
||||
}
|
||||
editor.caretModel.moveToOffset(editor.caretModel.offset - 2)
|
||||
}
|
||||
|
||||
fixture.type(insertString)
|
||||
|
||||
it.setUpValue = Pair(initialText, fixture)
|
||||
},
|
||||
test = {
|
||||
val fixture = it.setUpValue!!.second
|
||||
it.value = fixture.complete()
|
||||
},
|
||||
tearDown = {
|
||||
val items = it.value?.map { e -> e.lookupString }?.toList() ?: emptyList()
|
||||
try {
|
||||
for (lookupElement in lookupElements) {
|
||||
assertTrue("'$lookupElement' has to be present in items", items.contains(lookupElement))
|
||||
}
|
||||
} finally {
|
||||
it.setUpValue?.let { pair ->
|
||||
pair.second.revertChanges(revertChangesAtTheEnd, pair.first)
|
||||
}
|
||||
commitAllDocuments()
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
fun perfTypeAndHighlight(
|
||||
stats: Stats,
|
||||
fileName: String,
|
||||
marker: String,
|
||||
insertString: String,
|
||||
surroundItems: String = "\n",
|
||||
typeAfterMarker: Boolean = true,
|
||||
revertChangesAtTheEnd: Boolean = true,
|
||||
note: String = ""
|
||||
) = perfTypeAndHighlight(
|
||||
myProject!!, stats, fileName, marker, insertString, surroundItems,
|
||||
typeAfterMarker = typeAfterMarker,
|
||||
revertChangesAtTheEnd = revertChangesAtTheEnd, note = note
|
||||
)
|
||||
|
||||
fun perfTypeAndHighlight(
|
||||
project: Project,
|
||||
stats: Stats,
|
||||
fileName: String,
|
||||
marker: String,
|
||||
insertString: String,
|
||||
surroundItems: String = "\n",
|
||||
typeAfterMarker: Boolean = true,
|
||||
revertChangesAtTheEnd: Boolean = true,
|
||||
note: String = ""
|
||||
) {
|
||||
stats.perfTest<Pair<String, Fixture>, List<HighlightInfo>>(
|
||||
warmUpIterations = 8,
|
||||
iterations = 15,
|
||||
testName = "typeAndHighlight ${notePrefix(note)}$fileName",
|
||||
setUp = {
|
||||
val fixture = openFixture(project, fileName)
|
||||
val editor = fixture.editor
|
||||
|
||||
val initialText = editor.document.text
|
||||
if (isAKotlinScriptFile(fileName)) {
|
||||
runAndMeasure("update script dependencies for $fileName") {
|
||||
ScriptConfigurationManager.updateScriptDependenciesSynchronously(fixture.psiFile, project)
|
||||
}
|
||||
}
|
||||
|
||||
val tasksIdx = editor.document.text.indexOf(marker)
|
||||
assertTrue("marker '$marker' not found in $fileName", tasksIdx > 0)
|
||||
if (typeAfterMarker) {
|
||||
editor.caretModel.moveToOffset(tasksIdx + marker.length + 1)
|
||||
} else {
|
||||
editor.caretModel.moveToOffset(tasksIdx - 1)
|
||||
}
|
||||
|
||||
for (surroundItem in surroundItems) {
|
||||
EditorTestUtil.performTypingAction(editor, surroundItem)
|
||||
}
|
||||
|
||||
editor.caretModel.moveToOffset(editor.caretModel.offset - if (typeAfterMarker) 1 else 2)
|
||||
|
||||
if (!typeAfterMarker) {
|
||||
for (surroundItem in surroundItems) {
|
||||
EditorTestUtil.performTypingAction(editor, surroundItem)
|
||||
}
|
||||
editor.caretModel.moveToOffset(editor.caretModel.offset - 2)
|
||||
}
|
||||
|
||||
fixture.type(insertString)
|
||||
|
||||
it.setUpValue = Pair(initialText, fixture)
|
||||
},
|
||||
test = {
|
||||
val fixture = it.setUpValue!!.second
|
||||
it.value = fixture.doHighlighting()
|
||||
},
|
||||
tearDown = {
|
||||
it.value?.let { list ->
|
||||
assertNotEmpty(list)
|
||||
}
|
||||
it.setUpValue?.let { pair ->
|
||||
pair.second.revertChanges(revertChangesAtTheEnd, pair.first)
|
||||
}
|
||||
commitAllDocuments()
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
private fun initKotlinProject(
|
||||
project: Project,
|
||||
projectPath: String,
|
||||
name: String
|
||||
) {
|
||||
val modulePath = "$projectPath/$name${ModuleFileType.DOT_DEFAULT_EXTENSION}"
|
||||
val projectFile = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(File(projectPath))!!
|
||||
val srcFile = projectFile.findChild("src")!!
|
||||
val module = runWriteAction {
|
||||
val projectRootManager = ProjectRootManager.getInstance(project)
|
||||
with(projectRootManager) {
|
||||
projectSdk = jdk18
|
||||
}
|
||||
val moduleManager = ModuleManager.getInstance(project)
|
||||
val module = moduleManager.newModule(modulePath, ModuleTypeId.JAVA_MODULE)
|
||||
PsiTestUtil.addSourceRoot(module, srcFile)
|
||||
module
|
||||
}
|
||||
ConfigLibraryUtil.configureKotlinRuntimeAndSdk(module, jdk18)
|
||||
}
|
||||
|
||||
protected fun perfHighlightFile(name: String, stats: Stats): List<HighlightInfo> =
|
||||
perfHighlightFile(myProject!!, name, stats)
|
||||
|
||||
protected fun perfHighlightFile(
|
||||
project: Project,
|
||||
fileName: String,
|
||||
stats: Stats,
|
||||
note: String = ""
|
||||
): List<HighlightInfo> {
|
||||
return highlightFile {
|
||||
val isWarmUp = note == WARM_UP
|
||||
var highlightInfos: List<HighlightInfo> = emptyList()
|
||||
stats.perfTest<EditorFile, List<HighlightInfo>>(
|
||||
warmUpIterations = if (isWarmUp) 1 else 3,
|
||||
iterations = if (isWarmUp) 2 else 10,
|
||||
testName = "highlighting ${notePrefix(note)}${simpleFilename(fileName)}",
|
||||
setUp = {
|
||||
it.setUpValue = openFileInEditor(project, fileName)
|
||||
},
|
||||
test = {
|
||||
val file = it.setUpValue
|
||||
it.value = highlightFile(project, file!!.psiFile)
|
||||
},
|
||||
tearDown = {
|
||||
highlightInfos = it.value ?: emptyList()
|
||||
commitAllDocuments()
|
||||
FileEditorManager.getInstance(project).closeFile(it.setUpValue!!.psiFile.virtualFile)
|
||||
PsiManager.getInstance(project).dropPsiCaches()
|
||||
}
|
||||
)
|
||||
highlightInfos
|
||||
}
|
||||
}
|
||||
|
||||
fun <T> highlightFile(block: () -> T): T {
|
||||
var value: T? = null
|
||||
IdentifierHighlighterPassFactory.doWithHighlightingEnabled {
|
||||
value = block()
|
||||
}
|
||||
return value!!
|
||||
}
|
||||
|
||||
private fun highlightFile(project: Project, psiFile: PsiFile): List<HighlightInfo> {
|
||||
val document = FileDocumentManager.getInstance().getDocument(psiFile.virtualFile)!!
|
||||
val editor = EditorFactory.getInstance().getEditors(document).first()
|
||||
PsiDocumentManager.getInstance(project).commitAllDocuments()
|
||||
return CodeInsightTestFixtureImpl.instantiateAndRun(psiFile, editor, ArrayUtilRt.EMPTY_INT_ARRAY, true)
|
||||
}
|
||||
|
||||
protected fun perfScriptDependencies(name: String, stats: Stats, note: String = "") =
|
||||
perfScriptDependencies(myProject!!, name, stats, note = note)
|
||||
|
||||
private fun perfScriptDependencies(
|
||||
project: Project,
|
||||
fileName: String,
|
||||
stats: Stats,
|
||||
note: String = ""
|
||||
) {
|
||||
if (!isAKotlinScriptFile(fileName)) return
|
||||
stats.perfTest<EditorFile, EditorFile>(
|
||||
testName = "updateScriptDependencies ${notePrefix(note)}${simpleFilename(fileName)}",
|
||||
setUp = { it.setUpValue = openFileInEditor(project, fileName) },
|
||||
test = {
|
||||
ScriptConfigurationManager.updateScriptDependenciesSynchronously(it.setUpValue!!.psiFile, project)
|
||||
it.value = it.setUpValue
|
||||
},
|
||||
tearDown = {
|
||||
it.setUpValue?.let { ef -> cleanupCaches(project, ef.psiFile.virtualFile) }
|
||||
it.value?.let { v -> assertNotNull(v) }
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
fun notePrefix(note: String) = if (note.isNotEmpty()) {
|
||||
if (note.endsWith("/")) note else "$note "
|
||||
} else ""
|
||||
|
||||
|
||||
}
|
||||
@@ -102,6 +102,21 @@ class PerformanceProjectsTest : AbstractPerformanceProjectsTest() {
|
||||
}
|
||||
}
|
||||
|
||||
fun testKotlinProjectCopyAndPaste() {
|
||||
tcSuite("Kotlin copy-and-paste") {
|
||||
val stats = Stats("Kotlin copy-and-paste")
|
||||
stats.use { stat ->
|
||||
perfOpenKotlinProjectFast(stat)
|
||||
|
||||
perfCopyAndPaste(
|
||||
stat,
|
||||
sourceFileName = "compiler/psi/src/org/jetbrains/kotlin/psi/KtFile.kt",
|
||||
targetFileName = "compiler/psi/src/org/jetbrains/kotlin/psi/KtImportInfo.kt"
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun testKotlinProjectCompletionKtFile() {
|
||||
tcSuite("Kotlin completion ktFile") {
|
||||
val stats = Stats("Kotlin completion ktFile")
|
||||
@@ -239,7 +254,8 @@ class PerformanceProjectsTest : AbstractPerformanceProjectsTest() {
|
||||
testName = testName,
|
||||
setUp = perfKtsFileAnalysisSetUp(project, fileName),
|
||||
test = perfKtsFileAnalysisTest(),
|
||||
tearDown = perfKtsFileAnalysisTearDown(extraTimingsNs, project)
|
||||
tearDown = perfKtsFileAnalysisTearDown(extraTimingsNs, project),
|
||||
profileEnabled = true
|
||||
)
|
||||
|
||||
extraStats.printWarmUpTimings(
|
||||
|
||||
@@ -6,8 +6,7 @@
|
||||
package org.jetbrains.kotlin.idea.perf
|
||||
|
||||
import org.jetbrains.kotlin.idea.perf.WholeProjectPerformanceTest.Companion.nsToMs
|
||||
import org.jetbrains.kotlin.idea.perf.profilers.async.DummyProfilerHandler
|
||||
import org.jetbrains.kotlin.idea.perf.profilers.async.ProfilerHandler
|
||||
import org.jetbrains.kotlin.idea.perf.profilers.*
|
||||
import org.jetbrains.kotlin.idea.testFramework.logMessage
|
||||
import org.jetbrains.kotlin.util.PerformanceCounter
|
||||
import java.io.*
|
||||
@@ -19,7 +18,11 @@ import kotlin.test.assertEquals
|
||||
|
||||
typealias StatInfos = Map<String, Any>?
|
||||
|
||||
class Stats(val name: String = "", val header: Array<String> = arrayOf("Name", "ValueMS", "StdDev")) : Closeable {
|
||||
class Stats(
|
||||
val name: String = "",
|
||||
val header: Array<String> = arrayOf("Name", "ValueMS", "StdDev"),
|
||||
val acceptanceStabilityLevel: Int = 25
|
||||
) : Closeable {
|
||||
|
||||
private val perfTestRawDataMs = mutableListOf<Long>()
|
||||
|
||||
@@ -49,7 +52,7 @@ class Stats(val name: String = "", val header: Array<String> = arrayOf("Name", "
|
||||
for (v in listOf(
|
||||
Triple("mean", "", calcMean.mean.toLong()),
|
||||
Triple("stdDev", " stdDev", calcMean.stdDev.toLong()),
|
||||
Triple("geomMean", "geomMean", calcMean.geomMean.toLong())
|
||||
Triple("geomMean", " geomMean", calcMean.geomMean.toLong())
|
||||
)) {
|
||||
val n = "$id : ${v.first}"
|
||||
|
||||
@@ -63,7 +66,7 @@ class Stats(val name: String = "", val header: Array<String> = arrayOf("Name", "
|
||||
.fold(mutableSetOf<String>(), { acc, keys -> acc.addAll(keys); acc })
|
||||
.filter { it != TEST_KEY && it != ERROR_KEY }
|
||||
.sorted().forEach { perfCounterName ->
|
||||
val values = statInfosArray.map { (it?.get(perfCounterName) as Long) }.toLongArray()
|
||||
val values = statInfosArray.map { (it?.get(perfCounterName) as? Long) ?: 0L }.toLongArray()
|
||||
val statInfoMean = calcMean(values)
|
||||
|
||||
val n = "$id : $perfCounterName"
|
||||
@@ -147,6 +150,23 @@ class Stats(val name: String = "", val header: Array<String> = arrayOf("Name", "
|
||||
assertEquals(iterations, statInfoArray.size)
|
||||
if (testName != WARM_UP) {
|
||||
appendTimings(testName, statInfoArray)
|
||||
|
||||
// do not estimate stability for warm-up
|
||||
if (!testName.contains(WARM_UP)) {
|
||||
val calcMean = calcMean(statInfoArray)
|
||||
val stabilityPercentage = round(calcMean.stdDev * 100.0 / calcMean.mean).toInt()
|
||||
logMessage { "$testName stability is $stabilityPercentage %" }
|
||||
val stabilityName = "$name: $testName stability"
|
||||
|
||||
val stable = stabilityPercentage <= acceptanceStabilityLevel
|
||||
printTestStarted(stabilityName)
|
||||
printStatValue(stabilityName, stabilityPercentage)
|
||||
if (stable) {
|
||||
printTestFinished(stabilityName)
|
||||
} else {
|
||||
printTestFailed(stabilityName, "stability above $stabilityPercentage %")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -202,19 +222,8 @@ class Stats(val name: String = "", val header: Array<String> = arrayOf("Name", "
|
||||
warmUpStatInfosArray.filterNotNull().map { it[ERROR_KEY] as? Exception }.firstOrNull()?.let { throw it }
|
||||
}
|
||||
|
||||
private fun <SV, TV> mainPhase(phaseData: PhaseData<SV, TV>): Array<StatInfos> {
|
||||
val statInfosArray = phase(phaseData, "")
|
||||
|
||||
// do not estimate stability for warm-up
|
||||
if (!phaseData.testName.contains(WARM_UP)) {
|
||||
val calcMean = calcMean(statInfosArray)
|
||||
val stabilityPercentage = round(calcMean.stdDev * 100.0 / calcMean.mean).toInt()
|
||||
logMessage { "${phaseData.testName} stability is $stabilityPercentage %" }
|
||||
check(stabilityPercentage <= 10) { "${phaseData.testName} is not stable: stability above $stabilityPercentage %" }
|
||||
}
|
||||
|
||||
return statInfosArray
|
||||
}
|
||||
private fun <SV, TV> mainPhase(phaseData: PhaseData<SV, TV>): Array<StatInfos> =
|
||||
phase(phaseData, "")
|
||||
|
||||
private fun <SV, TV> phase(phaseData: PhaseData<SV, TV>, phaseName: String): Array<StatInfos> {
|
||||
val statInfosArray = Array<StatInfos>(phaseData.iterations) { null }
|
||||
@@ -275,13 +284,13 @@ class Stats(val name: String = "", val header: Array<String> = arrayOf("Name", "
|
||||
val profilerHandler = if (phaseData.profileEnabled) ProfilerHandler.getInstance() else DummyProfilerHandler
|
||||
|
||||
return if (profilerHandler != DummyProfilerHandler) {
|
||||
val profilerPath = pathToResource("profile/${plainname()}/")
|
||||
val profilerPath = pathToResource("profile/${plainname()}")
|
||||
check(with(File(profilerPath)) { exists() || mkdirs() }) { "unable to mkdirs $profilerPath for ${phaseData.testName}" }
|
||||
val activityName = "${phaseData.testName}-${if (phaseName.isEmpty()) "" else "$phaseName-"}$attempt"
|
||||
|
||||
ActualPhaseProfiler(activityName, profilerPath, profilerHandler)
|
||||
} else {
|
||||
dummyPhaseProfiler
|
||||
DummyPhaseProfiler
|
||||
}
|
||||
}
|
||||
|
||||
@@ -313,11 +322,6 @@ class Stats(val name: String = "", val header: Array<String> = arrayOf("Name", "
|
||||
|
||||
const val WARM_UP = "warm-up"
|
||||
|
||||
private val dummyPhaseProfiler = object : PhaseProfiler {
|
||||
override fun start() {}
|
||||
override fun stop() {}
|
||||
}
|
||||
|
||||
inline fun runAndMeasure(note: String, block: () -> Unit) {
|
||||
val openProjectMillis = measureTimeMillis {
|
||||
block()
|
||||
@@ -329,6 +333,14 @@ class Stats(val name: String = "", val header: Array<String> = arrayOf("Name", "
|
||||
println("##teamcity[testStarted name='$testName' captureStandardOutput='true']")
|
||||
}
|
||||
|
||||
fun printStatValue(name: String, value: Any) {
|
||||
println("##teamcity[buildStatisticValue key='$name' value='$value']")
|
||||
}
|
||||
|
||||
private fun printTestFinished(testName: String) {
|
||||
println("##teamcity[testFinished name='$testName']")
|
||||
}
|
||||
|
||||
fun printTestFinished(testName: String, spentMs: Long, includeStatValue: Boolean = true) {
|
||||
if (includeStatValue) {
|
||||
printStatValue(testName, spentMs)
|
||||
@@ -336,16 +348,15 @@ class Stats(val name: String = "", val header: Array<String> = arrayOf("Name", "
|
||||
println("##teamcity[testFinished name='$testName' duration='$spentMs']")
|
||||
}
|
||||
|
||||
fun printStatValue(name: String, value: Any) {
|
||||
println("##teamcity[buildStatisticValue key='$name' value='$value']")
|
||||
}
|
||||
|
||||
fun printTestFinished(testName: String, error: Throwable) {
|
||||
println("error at $testName:")
|
||||
tcPrintErrors(testName, listOf(error))
|
||||
|
||||
printStatValue(testName, -1)
|
||||
println("##teamcity[testFinished name='$testName']")
|
||||
tcPrintErrors(testName, listOf(error))
|
||||
//printTestFinished(testName)
|
||||
}
|
||||
|
||||
private fun printTestFailed(testName: String, details: String) {
|
||||
println("##teamcity[testFailed name='$testName' message='Exceptions reported' details='${tcEscape(details)}']")
|
||||
}
|
||||
|
||||
inline fun tcSuite(name: String, block: () -> Unit) {
|
||||
@@ -361,7 +372,7 @@ class Stats(val name: String = "", val header: Array<String> = arrayOf("Name", "
|
||||
printTestStarted(name)
|
||||
val (time, errors) = block()
|
||||
tcPrintErrors(name, errors)
|
||||
printTestFinished(name, time, includeStatValue = false)
|
||||
//printTestFinished(name, time, includeStatValue = false)
|
||||
}
|
||||
|
||||
private fun tcEscape(s: String) = s.replace("|", "||")
|
||||
@@ -381,27 +392,11 @@ class Stats(val name: String = "", val header: Array<String> = arrayOf("Name", "
|
||||
}
|
||||
errorDetailsPrintWriter.close()
|
||||
val details = detailsWriter.toString()
|
||||
println("##teamcity[testFailed name='$name' message='Exceptions reported' details='${tcEscape(details)}']")
|
||||
printTestFailed(name, details)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private interface PhaseProfiler {
|
||||
fun start()
|
||||
|
||||
fun stop()
|
||||
}
|
||||
|
||||
private class ActualPhaseProfiler(val activityName: String, val profilerPath: String, val profilerHandler: ProfilerHandler) :
|
||||
PhaseProfiler {
|
||||
override fun start() {
|
||||
profilerHandler.startProfiling(activityName)
|
||||
}
|
||||
|
||||
override fun stop() {
|
||||
profilerHandler.stopProfiling(profilerPath, activityName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data class PhaseData<SV, TV>(
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.perf.profilers
|
||||
|
||||
interface PhaseProfiler {
|
||||
fun start()
|
||||
|
||||
fun stop()
|
||||
}
|
||||
|
||||
object DummyPhaseProfiler : PhaseProfiler {
|
||||
override fun start() {}
|
||||
override fun stop() {}
|
||||
}
|
||||
|
||||
class ActualPhaseProfiler(
|
||||
private val activityName: String,
|
||||
private val profilerPath: String,
|
||||
private val profilerHandler: ProfilerHandler
|
||||
) :
|
||||
PhaseProfiler {
|
||||
override fun start() {
|
||||
profilerHandler.startProfiling(activityName)
|
||||
}
|
||||
|
||||
override fun stop() {
|
||||
profilerHandler.stopProfiling(profilerPath, activityName)
|
||||
}
|
||||
}
|
||||
+2
-1
@@ -3,9 +3,10 @@
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.perf.profilers.async
|
||||
package org.jetbrains.kotlin.idea.perf.profilers
|
||||
|
||||
import com.intellij.openapi.util.SystemInfo
|
||||
import org.jetbrains.kotlin.idea.perf.profilers.async.AsyncProfilerHandler
|
||||
import org.jetbrains.kotlin.idea.testFramework.logMessage
|
||||
|
||||
interface ProfilerHandler {
|
||||
+4
-2
@@ -8,8 +8,8 @@ package org.jetbrains.kotlin.idea.perf.profilers.async
|
||||
import com.intellij.openapi.util.SystemInfo
|
||||
import com.intellij.openapi.util.io.FileUtil
|
||||
import com.intellij.util.containers.ContainerUtil
|
||||
import org.jetbrains.kotlin.idea.perf.profilers.ProfilerHandler
|
||||
import org.jetbrains.kotlin.idea.testFramework.logMessage
|
||||
//import one.profiler.AsyncProfiler
|
||||
import java.io.File
|
||||
import java.nio.file.Files
|
||||
import java.nio.file.StandardCopyOption
|
||||
@@ -33,6 +33,7 @@ internal class AsyncProfilerHandler : ProfilerHandler {
|
||||
}
|
||||
|
||||
private fun execute(command: String) {
|
||||
logMessage { "asyncProfiler command: '$command'" }
|
||||
executeMethod.invoke(asyncProfiler, command)
|
||||
}
|
||||
|
||||
@@ -49,7 +50,8 @@ internal class AsyncProfilerHandler : ProfilerHandler {
|
||||
override fun stopProfiling(snapshotsPath: String, activityName: String, options: List<String>) {
|
||||
val combinedOptions = ArrayList(options)
|
||||
val commandBuilder = AsyncProfilerCommandBuilder(snapshotsPath)
|
||||
val stopAndDumpCommands = commandBuilder.buildStopAndDumpCommands(activityName, combinedOptions)
|
||||
val name = activityName.replace(' ', '_').replace('/', '_')
|
||||
val stopAndDumpCommands = commandBuilder.buildStopAndDumpCommands(name, combinedOptions)
|
||||
for (stopCommand in stopAndDumpCommands) {
|
||||
execute(stopCommand)
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import com.intellij.openapi.editor.Editor
|
||||
import com.intellij.openapi.editor.EditorFactory
|
||||
import com.intellij.openapi.fileEditor.FileDocumentManager
|
||||
import com.intellij.openapi.fileEditor.FileEditorManager
|
||||
import com.intellij.openapi.fileEditor.ex.FileEditorManagerEx
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.project.guessProjectDir
|
||||
import com.intellij.openapi.roots.FileIndexFacade
|
||||
@@ -35,10 +36,10 @@ import com.intellij.psi.search.FilenameIndex
|
||||
import com.intellij.psi.search.GlobalSearchScope
|
||||
import com.intellij.psi.xml.XmlFileNSInfoProvider
|
||||
import com.intellij.testFramework.EditorTestUtil
|
||||
import com.intellij.testFramework.UsefulTestCase
|
||||
import com.intellij.testFramework.fixtures.EditorTestFixture
|
||||
import com.intellij.testFramework.runInEdtAndWait
|
||||
import com.intellij.xml.XmlSchemaProvider
|
||||
import junit.framework.TestCase.*
|
||||
import org.jetbrains.kotlin.idea.KotlinLanguage
|
||||
import org.jetbrains.kotlin.idea.core.script.ScriptConfigurationManager
|
||||
import org.jetbrains.kotlin.idea.core.script.ScriptDefinitionsManager
|
||||
@@ -48,7 +49,7 @@ import org.jetbrains.kotlin.parsing.KotlinParserDefinition
|
||||
|
||||
|
||||
class Fixture(val project: Project, val editor: Editor, val psiFile: PsiFile, val vFile: VirtualFile = psiFile.virtualFile) {
|
||||
private val delegate = EditorTestFixture(project, editor, vFile)
|
||||
private var delegate = EditorTestFixture(project, editor, vFile)
|
||||
|
||||
val document: Document
|
||||
get() = editor.document
|
||||
@@ -59,26 +60,49 @@ class Fixture(val project: Project, val editor: Editor, val psiFile: PsiFile, va
|
||||
delegate.type(s)
|
||||
}
|
||||
|
||||
fun performEditorAction(actionId: String): Boolean {
|
||||
selectEditor()
|
||||
return delegate.performEditorAction(actionId)
|
||||
}
|
||||
|
||||
fun complete(type: CompletionType = CompletionType.BASIC, invocationCount: Int = 1): Array<LookupElement> =
|
||||
delegate.complete(type, invocationCount) ?: emptyArray()
|
||||
|
||||
fun revertChanges(revertChangesAtTheEnd: Boolean, text: String) {
|
||||
try {
|
||||
if (revertChangesAtTheEnd) {
|
||||
runWriteAction {
|
||||
// TODO: [VD] revert ?
|
||||
//editorFixture.performEditorAction(IdeActions.SELECTED_CHANGES_ROLLBACK)
|
||||
document.setText(text)
|
||||
saveDocument(document)
|
||||
commitDocument(project, document)
|
||||
}
|
||||
dispatchAllInvocationEvents()
|
||||
// TODO: [VD] revert ?
|
||||
//editorFixture.performEditorAction(IdeActions.SELECTED_CHANGES_ROLLBACK)
|
||||
applyText(text)
|
||||
}
|
||||
} finally {
|
||||
cleanupCaches(project, vFile)
|
||||
}
|
||||
}
|
||||
|
||||
fun selectMarkers(initialMarker: String?, finalMarker: String?) {
|
||||
selectEditor()
|
||||
val text = editor.document.text
|
||||
editor.selectionModel.setSelection(
|
||||
initialMarker?.let { marker -> text.indexOf(marker) } ?: 0,
|
||||
finalMarker?.let { marker -> text.indexOf(marker) } ?: text.length)
|
||||
}
|
||||
|
||||
private fun selectEditor() {
|
||||
val fileEditorManagerEx = FileEditorManagerEx.getInstanceEx(project)
|
||||
fileEditorManagerEx.openFile(vFile, true)
|
||||
check(fileEditorManagerEx.selectedEditor?.file == vFile) { "unable to open $vFile" }
|
||||
}
|
||||
|
||||
fun applyText(text: String) {
|
||||
runWriteAction {
|
||||
document.setText(text)
|
||||
saveDocument(document)
|
||||
commitDocument(project, document)
|
||||
}
|
||||
dispatchAllInvocationEvents()
|
||||
}
|
||||
|
||||
companion object {
|
||||
// quite simple impl - good so far
|
||||
fun isAKotlinScriptFile(fileName: String) = fileName.endsWith(KotlinParserDefinition.STD_SCRIPT_EXT)
|
||||
@@ -112,15 +136,16 @@ class Fixture(val project: Project, val editor: Editor, val psiFile: PsiFile, va
|
||||
scriptDefinitionsManager.getAllDefinitions()
|
||||
dispatchAllInvocationEvents()
|
||||
|
||||
UsefulTestCase.assertTrue(scriptDefinitionsManager.isReady())
|
||||
UsefulTestCase.assertFalse(KotlinScriptingSettings.getInstance(project).isAutoReloadEnabled)
|
||||
assertTrue(scriptDefinitionsManager.isReady())
|
||||
assertFalse(KotlinScriptingSettings.getInstance(project).isAutoReloadEnabled)
|
||||
}
|
||||
|
||||
|
||||
fun openFixture(project: Project, fileName: String): Fixture {
|
||||
val fileInEditor = openFileInEditor(project, fileName)
|
||||
val file = fileInEditor.psiFile
|
||||
val editor = EditorFactory.getInstance().getEditors(fileInEditor.document, project)[0]
|
||||
val editorFactory = EditorFactory.getInstance()
|
||||
val editor = editorFactory.getEditors(fileInEditor.document, project)[0]
|
||||
|
||||
return Fixture(project, editor, file)
|
||||
}
|
||||
@@ -148,7 +173,7 @@ class Fixture(val project: Project, val editor: Editor, val psiFile: PsiFile, va
|
||||
)
|
||||
.filter { it.canonicalPath?.contains("/$projectBaseName/$name") ?: false }.toList()
|
||||
|
||||
UsefulTestCase.assertEquals(
|
||||
assertEquals(
|
||||
"expected the only file with name '$name'\n, it were: [${virtualFiles.map { it.canonicalPath }.joinToString("\n")}]",
|
||||
1,
|
||||
virtualFiles.size
|
||||
@@ -163,18 +188,18 @@ class Fixture(val project: Project, val editor: Editor, val psiFile: PsiFile, va
|
||||
val psiFile = projectFileByName(project, name)
|
||||
val vFile = psiFile.virtualFile
|
||||
|
||||
UsefulTestCase.assertTrue("file $vFile is not indexed yet", FileIndexFacade.getInstance(project).isInContent(vFile))
|
||||
assertTrue("file $vFile is not indexed yet", FileIndexFacade.getInstance(project).isInContent(vFile))
|
||||
|
||||
runInEdtAndWait {
|
||||
fileEditorManager.openFile(vFile, true)
|
||||
}
|
||||
val document = fileDocumentManager.getDocument(vFile)!!
|
||||
val document = fileDocumentManager.getDocument(vFile) ?: error("no document for $vFile found")
|
||||
|
||||
UsefulTestCase.assertNotNull("doc not found for $vFile", EditorFactory.getInstance().getEditors(document))
|
||||
UsefulTestCase.assertTrue("expected non empty doc", document.text.isNotEmpty())
|
||||
assertNotNull("doc not found for $vFile", EditorFactory.getInstance().getEditors(document))
|
||||
assertTrue("expected non empty doc", document.text.isNotEmpty())
|
||||
|
||||
val offset = psiFile.textOffset
|
||||
UsefulTestCase.assertTrue("side effect: to load the text", offset >= 0)
|
||||
assertTrue("side effect: to load the text", offset >= 0)
|
||||
|
||||
waitForAllEditorsFinallyLoaded(project)
|
||||
|
||||
@@ -204,7 +229,7 @@ class Fixture(val project: Project, val editor: Editor, val psiFile: PsiFile, va
|
||||
}
|
||||
|
||||
val tasksIdx = fileInEditor.document.text.indexOf(marker)
|
||||
UsefulTestCase.assertTrue(tasksIdx > 0)
|
||||
assertTrue(tasksIdx > 0)
|
||||
editor.caretModel.moveToOffset(tasksIdx + marker.length + 1)
|
||||
|
||||
for (surroundItem in surroundItems) {
|
||||
@@ -218,7 +243,7 @@ class Fixture(val project: Project, val editor: Editor, val psiFile: PsiFile, va
|
||||
val elements = fixture.complete()
|
||||
val items = elements.map { it.lookupString }.toList()
|
||||
for (lookupElement in lookupElements) {
|
||||
UsefulTestCase.assertTrue("'$lookupElement' has to be present in items", items.contains(lookupElement))
|
||||
assertTrue("'$lookupElement' has to be present in items", items.contains(lookupElement))
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
|
||||
Reference in New Issue
Block a user