Nicer performance tests suite dsl
This commit is contained in:
committed by
Vladimir Dolzhenko
parent
2cee82a348
commit
1ae7f693c5
+92
-146
@@ -5,25 +5,17 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.idea.perf
|
package org.jetbrains.kotlin.idea.perf
|
||||||
|
|
||||||
import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer
|
|
||||||
import com.intellij.codeInsight.daemon.DaemonCodeAnalyzerSettings
|
|
||||||
import com.intellij.codeInsight.daemon.impl.DaemonCodeAnalyzerImpl
|
|
||||||
import com.intellij.codeInsight.daemon.impl.HighlightInfo
|
import com.intellij.codeInsight.daemon.impl.HighlightInfo
|
||||||
import com.intellij.codeInsight.daemon.impl.IdentifierHighlighterPassFactory
|
import com.intellij.codeInsight.daemon.impl.IdentifierHighlighterPassFactory
|
||||||
import com.intellij.codeInsight.lookup.LookupElement
|
import com.intellij.codeInsight.lookup.LookupElement
|
||||||
import com.intellij.codeInspection.InspectionProfileEntry
|
import com.intellij.codeInspection.InspectionProfileEntry
|
||||||
import com.intellij.ide.startup.impl.StartupManagerImpl
|
|
||||||
import com.intellij.openapi.actionSystem.IdeActions
|
import com.intellij.openapi.actionSystem.IdeActions
|
||||||
import com.intellij.openapi.application.runWriteAction
|
|
||||||
import com.intellij.openapi.editor.EditorFactory
|
import com.intellij.openapi.editor.EditorFactory
|
||||||
import com.intellij.openapi.fileEditor.FileDocumentManager
|
import com.intellij.openapi.fileEditor.FileDocumentManager
|
||||||
import com.intellij.openapi.fileEditor.FileEditorManager
|
import com.intellij.openapi.fileEditor.FileEditorManager
|
||||||
import com.intellij.openapi.project.DumbService
|
import com.intellij.openapi.project.DumbService
|
||||||
import com.intellij.openapi.project.Project
|
import com.intellij.openapi.project.Project
|
||||||
import com.intellij.openapi.projectRoots.JavaSdk
|
|
||||||
import com.intellij.openapi.projectRoots.Sdk
|
import com.intellij.openapi.projectRoots.Sdk
|
||||||
import com.intellij.openapi.projectRoots.impl.JavaAwareProjectJdkTableImpl
|
|
||||||
import com.intellij.openapi.startup.StartupManager
|
|
||||||
import com.intellij.profile.codeInspection.ProjectInspectionProfileManager
|
import com.intellij.profile.codeInspection.ProjectInspectionProfileManager
|
||||||
import com.intellij.psi.PsiDocumentManager
|
import com.intellij.psi.PsiDocumentManager
|
||||||
import com.intellij.psi.PsiFile
|
import com.intellij.psi.PsiFile
|
||||||
@@ -35,18 +27,20 @@ import com.intellij.util.ThrowableRunnable
|
|||||||
import com.intellij.util.indexing.UnindexedFilesUpdater
|
import com.intellij.util.indexing.UnindexedFilesUpdater
|
||||||
import com.intellij.util.ui.UIUtil
|
import com.intellij.util.ui.UIUtil
|
||||||
import org.jetbrains.kotlin.idea.core.script.ScriptConfigurationManager
|
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.WARM_UP
|
||||||
import org.jetbrains.kotlin.idea.perf.Stats.Companion.runAndMeasure
|
import org.jetbrains.kotlin.idea.perf.Stats.Companion.runAndMeasure
|
||||||
|
import org.jetbrains.kotlin.idea.perf.util.PerformanceSuite.ApplicationScope.Companion.initApp
|
||||||
|
import org.jetbrains.kotlin.idea.perf.util.PerformanceSuite.ApplicationScope.Companion.initSdk
|
||||||
|
import org.jetbrains.kotlin.idea.perf.util.ProfileTools.Companion.initDefaultProfile
|
||||||
|
import org.jetbrains.kotlin.idea.perf.util.logMessage
|
||||||
import org.jetbrains.kotlin.idea.test.invalidateLibraryCache
|
import org.jetbrains.kotlin.idea.test.invalidateLibraryCache
|
||||||
import org.jetbrains.kotlin.idea.testFramework.*
|
import org.jetbrains.kotlin.idea.testFramework.*
|
||||||
|
import org.jetbrains.kotlin.idea.testFramework.TestApplicationManager
|
||||||
import org.jetbrains.kotlin.idea.testFramework.Fixture.Companion.cleanupCaches
|
import org.jetbrains.kotlin.idea.testFramework.Fixture.Companion.cleanupCaches
|
||||||
import org.jetbrains.kotlin.idea.testFramework.Fixture.Companion.close
|
import org.jetbrains.kotlin.idea.testFramework.Fixture.Companion.close
|
||||||
import org.jetbrains.kotlin.idea.testFramework.Fixture.Companion.isAKotlinScriptFile
|
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.openFileInEditor
|
||||||
import org.jetbrains.kotlin.idea.testFramework.Fixture.Companion.openFixture
|
import org.jetbrains.kotlin.idea.testFramework.Fixture.Companion.openFixture
|
||||||
import org.jetbrains.kotlin.idea.testFramework.ProjectOpenAction.SIMPLE_JAVA_MODULE
|
|
||||||
import org.jetbrains.kotlin.idea.util.getProjectJdkTableSafe
|
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
abstract class AbstractPerformanceProjectsTest : UsefulTestCase() {
|
abstract class AbstractPerformanceProjectsTest : UsefulTestCase() {
|
||||||
@@ -63,29 +57,11 @@ abstract class AbstractPerformanceProjectsTest : UsefulTestCase() {
|
|||||||
override fun setUp() {
|
override fun setUp() {
|
||||||
super.setUp()
|
super.setUp()
|
||||||
|
|
||||||
myApplication = TestApplicationManager.getInstance()
|
myApplication = initApp(testRootDisposable)
|
||||||
runWriteAction {
|
initSdk(testRootDisposable)
|
||||||
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 = getProjectJdkTableSafe()
|
|
||||||
jdkTable.addJdk(jdk18, testRootDisposable)
|
|
||||||
jdkTable.addJdk(internal, testRootDisposable)
|
|
||||||
KotlinSdkType.setUpIfNeeded()
|
|
||||||
}
|
|
||||||
|
|
||||||
GradleProcessOutputInterceptor.install(testRootDisposable)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected fun warmUpProject(stats: Stats, vararg filesToHighlight: String, openProject: () -> Project) {
|
internal fun warmUpProject(stats: Stats, vararg filesToHighlight: String, openProject: () -> Project) {
|
||||||
assertTrue(filesToHighlight.isNotEmpty())
|
assertTrue(filesToHighlight.isNotEmpty())
|
||||||
|
|
||||||
val project = openProject()
|
val project = openProject()
|
||||||
@@ -96,7 +72,6 @@ abstract class AbstractPerformanceProjectsTest : UsefulTestCase() {
|
|||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
closeProject(project)
|
closeProject(project)
|
||||||
myApplication.setDataProvider(null)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -105,15 +80,9 @@ abstract class AbstractPerformanceProjectsTest : UsefulTestCase() {
|
|||||||
RunAll(
|
RunAll(
|
||||||
ThrowableRunnable { super.tearDown() },
|
ThrowableRunnable { super.tearDown() },
|
||||||
ThrowableRunnable {
|
ThrowableRunnable {
|
||||||
if (myProject != null) {
|
myProject?.let { project ->
|
||||||
logMessage { "myProject is about to be closed" }
|
closeProject(project)
|
||||||
DaemonCodeAnalyzerSettings.getInstance().isImportHintEnabled = true // return default value to avoid unnecessary save
|
|
||||||
(StartupManager.getInstance(project()) as StartupManagerImpl).checkCleared()
|
|
||||||
(DaemonCodeAnalyzer.getInstance(project()) as DaemonCodeAnalyzerImpl).cleanupAfterTest()
|
|
||||||
closeProject(project())
|
|
||||||
myApplication.setDataProvider(null)
|
|
||||||
myProject = null
|
myProject = null
|
||||||
logMessage { "myProject is closed" }
|
|
||||||
}
|
}
|
||||||
}).run()
|
}).run()
|
||||||
}
|
}
|
||||||
@@ -123,14 +92,72 @@ abstract class AbstractPerformanceProjectsTest : UsefulTestCase() {
|
|||||||
return if (lastIndexOf >= 0) fileName.substring(lastIndexOf + 1) else fileName
|
return if (lastIndexOf >= 0) fileName.substring(lastIndexOf + 1) else fileName
|
||||||
}
|
}
|
||||||
|
|
||||||
protected fun perfOpenHelloWorld(stats: Stats, note: String = ""): Project =
|
private fun closeProject(project: Project) = myApplication.closeProject(project)
|
||||||
perfOpenProject(
|
|
||||||
name = "helloKotlin",
|
protected fun perfOpenProject(
|
||||||
stats = stats,
|
stats: Stats,
|
||||||
note = note,
|
note: String = "",
|
||||||
path = "idea/testData/perfTest/helloKotlin",
|
fast: Boolean = false,
|
||||||
openAction = SIMPLE_JAVA_MODULE
|
initializer: ProjectBuilder.() -> Unit,
|
||||||
)
|
): Project {
|
||||||
|
val projectBuilder = ProjectBuilder().apply(initializer)
|
||||||
|
val name = projectBuilder.name
|
||||||
|
val openProjectOperation = projectBuilder.openProjectOperation()
|
||||||
|
|
||||||
|
val warmUpIterations = if (fast) 0 else 5
|
||||||
|
val iterations = if (fast) 1 else 5
|
||||||
|
|
||||||
|
var lastProject: Project? = null
|
||||||
|
var counter = 0
|
||||||
|
|
||||||
|
performanceTest<Unit, Project> {
|
||||||
|
name("open project $name${if (note.isNotEmpty()) " $note" else ""}")
|
||||||
|
stats(stats)
|
||||||
|
warmUpIterations(warmUpIterations)
|
||||||
|
iterations(iterations)
|
||||||
|
checkStability(!fast)
|
||||||
|
test {
|
||||||
|
it.value = openProjectOperation.openProject()
|
||||||
|
}
|
||||||
|
tearDown {
|
||||||
|
it.value?.let { project ->
|
||||||
|
lastProject = project
|
||||||
|
openProjectOperation.postOpenProject(project)
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
myApplication.setDataProvider(TestDataProvider(project))
|
||||||
|
}
|
||||||
|
|
||||||
|
return lastProject ?: error("unable to open project $name")
|
||||||
|
}
|
||||||
|
|
||||||
protected fun perfOpenProject(
|
protected fun perfOpenProject(
|
||||||
name: String,
|
name: String,
|
||||||
@@ -170,16 +197,13 @@ abstract class AbstractPerformanceProjectsTest : UsefulTestCase() {
|
|||||||
it.value?.let { project ->
|
it.value?.let { project ->
|
||||||
lastProject = project
|
lastProject = project
|
||||||
openAction.postOpenProject(openProject = openProject, project = project)
|
openAction.postOpenProject(openProject = openProject, project = project)
|
||||||
openAction.initDefaultProfile(project)
|
project.initDefaultProfile()
|
||||||
|
|
||||||
logMessage { "project '$name' successfully opened" }
|
logMessage { "project '$name' successfully opened" }
|
||||||
|
|
||||||
// close all project but last - we're going to return and use it further
|
// close all project but last - we're going to return and use it further
|
||||||
if (counter < warmUpIterations + iterations - 1) {
|
if (counter < warmUpIterations + iterations - 1) {
|
||||||
myApplication.setDataProvider(null)
|
myApplication.closeProject(project)
|
||||||
logMessage { "project '$name' is about to be closed" }
|
|
||||||
closeProject(project)
|
|
||||||
logMessage { "project '$name' successfully closed" }
|
|
||||||
}
|
}
|
||||||
counter++
|
counter++
|
||||||
}
|
}
|
||||||
@@ -448,92 +472,6 @@ abstract class AbstractPerformanceProjectsTest : UsefulTestCase() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun perfType(
|
|
||||||
stats: Stats,
|
|
||||||
fileName: String,
|
|
||||||
marker: String,
|
|
||||||
insertString: String,
|
|
||||||
surroundItems: String = "\n",
|
|
||||||
typeAfterMarker: Boolean = true,
|
|
||||||
revertChangesAtTheEnd: Boolean = true,
|
|
||||||
note: String = "",
|
|
||||||
delay: Long? = null
|
|
||||||
) = perfType(
|
|
||||||
project(), stats, fileName, marker, insertString, surroundItems,
|
|
||||||
typeAfterMarker = typeAfterMarker,
|
|
||||||
revertChangesAtTheEnd = revertChangesAtTheEnd,
|
|
||||||
note = note,
|
|
||||||
delay = delay
|
|
||||||
)
|
|
||||||
|
|
||||||
fun perfType(
|
|
||||||
project: Project,
|
|
||||||
stats: Stats,
|
|
||||||
fileName: String,
|
|
||||||
marker: String,
|
|
||||||
insertString: String,
|
|
||||||
surroundItems: String = "\n",
|
|
||||||
typeAfterMarker: Boolean = true,
|
|
||||||
revertChangesAtTheEnd: Boolean = true,
|
|
||||||
note: String = "",
|
|
||||||
delay: Long? = null
|
|
||||||
) {
|
|
||||||
performanceTest<Pair<String, Fixture>, List<HighlightInfo>> {
|
|
||||||
name("type ${notePrefix(note)}$fileName")
|
|
||||||
stats(stats)
|
|
||||||
warmUpIterations(8)
|
|
||||||
iterations(15)
|
|
||||||
setUp {
|
|
||||||
val fixture = openFixture(project, fileName)
|
|
||||||
val editor = fixture.editor
|
|
||||||
|
|
||||||
val initialText = editor.document.text
|
|
||||||
updateScriptDependenciesIfNeeded(fileName, fixture)
|
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
|
|
||||||
it.setUpValue = Pair(initialText, fixture)
|
|
||||||
}
|
|
||||||
test {
|
|
||||||
val fixture = it.setUpValue!!.second
|
|
||||||
for (i in insertString.indices) {
|
|
||||||
fixture.type(insertString[i])
|
|
||||||
delay?.let { d -> Thread.sleep(d) }
|
|
||||||
}
|
|
||||||
it.value = fixture.doHighlighting()
|
|
||||||
}
|
|
||||||
tearDown {
|
|
||||||
it.value?.let { list ->
|
|
||||||
assertNotEmpty(list)
|
|
||||||
}
|
|
||||||
it.setUpValue?.let { pair ->
|
|
||||||
pair.second.revertChanges(revertChangesAtTheEnd, pair.first)
|
|
||||||
}
|
|
||||||
commitAllDocuments()
|
|
||||||
}
|
|
||||||
profilerEnabled(true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun perfCopyAndPaste(
|
fun perfCopyAndPaste(
|
||||||
stats: Stats,
|
stats: Stats,
|
||||||
sourceFileName: String,
|
sourceFileName: String,
|
||||||
@@ -630,12 +568,16 @@ abstract class AbstractPerformanceProjectsTest : UsefulTestCase() {
|
|||||||
protected fun perfHighlightFileEmptyProfile(name: String, stats: Stats): List<HighlightInfo> =
|
protected fun perfHighlightFileEmptyProfile(name: String, stats: Stats): List<HighlightInfo> =
|
||||||
perfHighlightFile(project(), name, stats, tools = emptyArray(), note = "empty profile")
|
perfHighlightFile(project(), name, stats, tools = emptyArray(), note = "empty profile")
|
||||||
|
|
||||||
private fun perfHighlightFile(
|
protected fun perfHighlightFile(
|
||||||
project: Project,
|
project: Project,
|
||||||
fileName: String,
|
fileName: String,
|
||||||
stats: Stats,
|
stats: Stats,
|
||||||
tools: Array<InspectionProfileEntry>? = null,
|
tools: Array<InspectionProfileEntry>? = null,
|
||||||
note: String = ""
|
note: String = "",
|
||||||
|
warmUpIterations: Int = 3,
|
||||||
|
iterations: Int = 10,
|
||||||
|
checkStability: Boolean = true,
|
||||||
|
filenameSimplifier: (String) -> String = ::simpleFilename
|
||||||
): List<HighlightInfo> {
|
): List<HighlightInfo> {
|
||||||
val profileManager = ProjectInspectionProfileManager.getInstance(project)
|
val profileManager = ProjectInspectionProfileManager.getInstance(project)
|
||||||
val currentProfile = profileManager.currentProfile
|
val currentProfile = profileManager.currentProfile
|
||||||
@@ -647,10 +589,11 @@ abstract class AbstractPerformanceProjectsTest : UsefulTestCase() {
|
|||||||
val isWarmUp = note == WARM_UP
|
val isWarmUp = note == WARM_UP
|
||||||
var highlightInfos: List<HighlightInfo> = emptyList()
|
var highlightInfos: List<HighlightInfo> = emptyList()
|
||||||
performanceTest<EditorFile, List<HighlightInfo>> {
|
performanceTest<EditorFile, List<HighlightInfo>> {
|
||||||
name("highlighting ${notePrefix(note)}${simpleFilename(fileName)}")
|
name("highlighting ${notePrefix(note)}${filenameSimplifier(fileName)}")
|
||||||
stats(stats)
|
stats(stats)
|
||||||
warmUpIterations(if (isWarmUp) 1 else 3)
|
warmUpIterations(if (isWarmUp) 1 else warmUpIterations)
|
||||||
iterations(if (isWarmUp) 2 else 10)
|
iterations(if (isWarmUp) 2 else iterations)
|
||||||
|
checkStability(checkStability)
|
||||||
setUp {
|
setUp {
|
||||||
it.setUpValue = openFileInEditor(project, fileName)
|
it.setUpValue = openFileInEditor(project, fileName)
|
||||||
}
|
}
|
||||||
@@ -661,7 +604,10 @@ abstract class AbstractPerformanceProjectsTest : UsefulTestCase() {
|
|||||||
tearDown {
|
tearDown {
|
||||||
highlightInfos = it.value ?: emptyList()
|
highlightInfos = it.value ?: emptyList()
|
||||||
commitAllDocuments()
|
commitAllDocuments()
|
||||||
FileEditorManager.getInstance(project).closeFile(it.setUpValue!!.psiFile.virtualFile)
|
it.setUpValue?.let { editorFile ->
|
||||||
|
val fileEditorManager = FileEditorManager.getInstance(project)
|
||||||
|
fileEditorManager.closeFile(editorFile.psiFile.virtualFile)
|
||||||
|
}
|
||||||
PsiManager.getInstance(project).dropPsiCaches()
|
PsiManager.getInstance(project).dropPsiCaches()
|
||||||
}
|
}
|
||||||
profilerEnabled(!isWarmUp)
|
profilerEnabled(!isWarmUp)
|
||||||
|
|||||||
@@ -1,14 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2010-2020 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 java.nio.file.*
|
|
||||||
|
|
||||||
fun Path.copyRecursively(targetDirectory: Path) {
|
|
||||||
val src = this
|
|
||||||
Files.walk(src)
|
|
||||||
.forEach { source -> Files.copy(source, targetDirectory.resolve(src.relativize(source)), StandardCopyOption.REPLACE_EXISTING) }
|
|
||||||
}
|
|
||||||
+3
-3
@@ -25,9 +25,9 @@ import org.jetbrains.kotlin.idea.framework.detectLibraryKind
|
|||||||
import org.jetbrains.kotlin.idea.perf.PerformanceNativeProjectsTest.TestProject.*
|
import org.jetbrains.kotlin.idea.perf.PerformanceNativeProjectsTest.TestProject.*
|
||||||
import org.jetbrains.kotlin.idea.perf.PerformanceNativeProjectsTest.TestTarget.*
|
import org.jetbrains.kotlin.idea.perf.PerformanceNativeProjectsTest.TestTarget.*
|
||||||
import org.jetbrains.kotlin.idea.perf.Stats.Companion.WARM_UP
|
import org.jetbrains.kotlin.idea.perf.Stats.Companion.WARM_UP
|
||||||
import org.jetbrains.kotlin.idea.perf.Stats.Companion.tcSuite
|
import org.jetbrains.kotlin.idea.perf.util.TeamCity.suite
|
||||||
|
import org.jetbrains.kotlin.idea.perf.util.logMessage
|
||||||
import org.jetbrains.kotlin.idea.testFramework.ProjectOpenAction.GRADLE_PROJECT
|
import org.jetbrains.kotlin.idea.testFramework.ProjectOpenAction.GRADLE_PROJECT
|
||||||
import org.jetbrains.kotlin.idea.testFramework.logMessage
|
|
||||||
import org.jetbrains.kotlin.idea.testFramework.suggestOsNeutralFileName
|
import org.jetbrains.kotlin.idea.testFramework.suggestOsNeutralFileName
|
||||||
import org.jetbrains.kotlin.idea.util.projectStructure.allModules
|
import org.jetbrains.kotlin.idea.util.projectStructure.allModules
|
||||||
import org.jetbrains.kotlin.library.KOTLIN_STDLIB_NAME
|
import org.jetbrains.kotlin.library.KOTLIN_STDLIB_NAME
|
||||||
@@ -157,7 +157,7 @@ class PerformanceNativeProjectsTest : AbstractPerformanceProjectsTest() {
|
|||||||
assertTrue("Target $testTarget is not allowed on your host OS", testTarget.enabled)
|
assertTrue("Target $testTarget is not allowed on your host OS", testTarget.enabled)
|
||||||
|
|
||||||
val projectName = projectName(testTarget, testProject, enableCommonizer)
|
val projectName = projectName(testTarget, testProject, enableCommonizer)
|
||||||
tcSuite(projectName) {
|
suite(projectName) {
|
||||||
Stats(projectName).use { stats ->
|
Stats(projectName).use { stats ->
|
||||||
myProject = perfOpenTemplateGradleProject(stats, testTarget, testProject, enableCommonizer)
|
myProject = perfOpenTemplateGradleProject(stats, testTarget, testProject, enableCommonizer)
|
||||||
|
|
||||||
|
|||||||
+37
-34
@@ -8,15 +8,13 @@ package org.jetbrains.kotlin.idea.perf
|
|||||||
import com.intellij.codeInsight.daemon.impl.HighlightInfo
|
import com.intellij.codeInsight.daemon.impl.HighlightInfo
|
||||||
import com.intellij.lang.annotation.AnnotationHolder
|
import com.intellij.lang.annotation.AnnotationHolder
|
||||||
import com.intellij.openapi.project.Project
|
import com.intellij.openapi.project.Project
|
||||||
import com.intellij.openapi.util.Disposer
|
|
||||||
import com.intellij.psi.PsiElement
|
import com.intellij.psi.PsiElement
|
||||||
import org.jetbrains.kotlin.idea.core.script.ScriptConfigurationManager
|
import org.jetbrains.kotlin.idea.core.script.ScriptConfigurationManager
|
||||||
import org.jetbrains.kotlin.idea.highlighter.KotlinPsiChecker
|
import org.jetbrains.kotlin.idea.highlighter.KotlinPsiChecker
|
||||||
import org.jetbrains.kotlin.idea.highlighter.KotlinPsiCheckerAndHighlightingUpdater
|
import org.jetbrains.kotlin.idea.highlighter.KotlinPsiCheckerAndHighlightingUpdater
|
||||||
import org.jetbrains.kotlin.idea.perf.Stats.Companion.TEST_KEY
|
import org.jetbrains.kotlin.idea.perf.Stats.Companion.TEST_KEY
|
||||||
import org.jetbrains.kotlin.idea.perf.Stats.Companion.WARM_UP
|
|
||||||
import org.jetbrains.kotlin.idea.perf.Stats.Companion.runAndMeasure
|
import org.jetbrains.kotlin.idea.perf.Stats.Companion.runAndMeasure
|
||||||
import org.jetbrains.kotlin.idea.perf.Stats.Companion.tcSuite
|
import org.jetbrains.kotlin.idea.perf.util.TeamCity.suite
|
||||||
import org.jetbrains.kotlin.idea.testFramework.Fixture
|
import org.jetbrains.kotlin.idea.testFramework.Fixture
|
||||||
import org.jetbrains.kotlin.idea.testFramework.Fixture.Companion.cleanupCaches
|
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.isAKotlinScriptFile
|
||||||
@@ -29,10 +27,10 @@ class PerformanceProjectsTest : AbstractPerformanceProjectsTest() {
|
|||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
var warmedUp: Boolean = false
|
val hwStats: Stats = Stats("helloWorld project")
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
val hwStats: Stats = Stats("helloWorld project")
|
val warmUp = WarmUpProject(hwStats)
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
val timer: AtomicLong = AtomicLong()
|
val timer: AtomicLong = AtomicLong()
|
||||||
@@ -53,17 +51,28 @@ class PerformanceProjectsTest : AbstractPerformanceProjectsTest() {
|
|||||||
|
|
||||||
override fun setUp() {
|
override fun setUp() {
|
||||||
super.setUp()
|
super.setUp()
|
||||||
// warm up: open simple small project
|
warmUp.warmUp(this)
|
||||||
if (!warmedUp) {
|
|
||||||
warmUpProject(hwStats, "src/HelloMain.kt") { perfOpenHelloWorld(hwStats, WARM_UP) }
|
|
||||||
warmedUp = true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun testHelloWorldProject() {
|
fun testHelloWorldProject() {
|
||||||
|
suite("Hello world project") {
|
||||||
|
myProject = perfOpenProject(stats = hwStats) {
|
||||||
|
name("helloKotlin")
|
||||||
|
|
||||||
tcSuite("Hello world project") {
|
kotlinFile("HelloMain") {
|
||||||
myProject = perfOpenHelloWorld(hwStats)
|
topFunction("main") {
|
||||||
|
param("args", "Array<String>")
|
||||||
|
body("""println("Hello World!")""")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
kotlinFile("HelloMain2") {
|
||||||
|
topFunction("main") {
|
||||||
|
param("args", "Array<String>")
|
||||||
|
body("""println("Hello World!")""")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// highlight
|
// highlight
|
||||||
perfHighlightFile("src/HelloMain.kt", hwStats)
|
perfHighlightFile("src/HelloMain.kt", hwStats)
|
||||||
@@ -72,9 +81,8 @@ class PerformanceProjectsTest : AbstractPerformanceProjectsTest() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun testKotlinProject() {
|
fun testKotlinProject() {
|
||||||
tcSuite("Kotlin project") {
|
suite("Kotlin project") {
|
||||||
val stats = Stats("kotlin project")
|
Stats("kotlin project").use {
|
||||||
stats.use {
|
|
||||||
perfOpenKotlinProject(it)
|
perfOpenKotlinProject(it)
|
||||||
|
|
||||||
val filesToHighlight = arrayOf(
|
val filesToHighlight = arrayOf(
|
||||||
@@ -114,9 +122,8 @@ class PerformanceProjectsTest : AbstractPerformanceProjectsTest() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun testKotlinProjectCopyAndPaste() {
|
fun testKotlinProjectCopyAndPaste() {
|
||||||
tcSuite("Kotlin copy-and-paste") {
|
suite("Kotlin copy-and-paste") {
|
||||||
val stats = Stats("Kotlin copy-and-paste")
|
Stats("Kotlin copy-and-paste").use { stat ->
|
||||||
stats.use { stat ->
|
|
||||||
perfOpenKotlinProjectFast(stat)
|
perfOpenKotlinProjectFast(stat)
|
||||||
|
|
||||||
perfCopyAndPaste(
|
perfCopyAndPaste(
|
||||||
@@ -129,9 +136,8 @@ class PerformanceProjectsTest : AbstractPerformanceProjectsTest() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun testKotlinProjectCompletionKtFile() {
|
fun testKotlinProjectCompletionKtFile() {
|
||||||
tcSuite("Kotlin completion ktFile") {
|
suite("Kotlin completion ktFile") {
|
||||||
val stats = Stats("Kotlin completion ktFile")
|
Stats("Kotlin completion ktFile").use { stat ->
|
||||||
stats.use { stat ->
|
|
||||||
perfOpenKotlinProjectFast(stat)
|
perfOpenKotlinProjectFast(stat)
|
||||||
|
|
||||||
perfTypeAndAutocomplete(
|
perfTypeAndAutocomplete(
|
||||||
@@ -157,9 +163,8 @@ class PerformanceProjectsTest : AbstractPerformanceProjectsTest() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun testKotlinProjectCompletionBuildGradle() {
|
fun testKotlinProjectCompletionBuildGradle() {
|
||||||
tcSuite("Kotlin completion gradle.kts") {
|
suite("Kotlin completion gradle.kts") {
|
||||||
val stats = Stats("kotlin completion gradle.kts")
|
Stats("kotlin completion gradle.kts").use { stat ->
|
||||||
stats.use { stat ->
|
|
||||||
runAndMeasure("open kotlin project") {
|
runAndMeasure("open kotlin project") {
|
||||||
perfOpenKotlinProjectFast(stat)
|
perfOpenKotlinProjectFast(stat)
|
||||||
}
|
}
|
||||||
@@ -191,9 +196,8 @@ class PerformanceProjectsTest : AbstractPerformanceProjectsTest() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun testKotlinProjectScriptDependenciesBuildGradle() {
|
fun testKotlinProjectScriptDependenciesBuildGradle() {
|
||||||
tcSuite("Kotlin scriptDependencies gradle.kts") {
|
suite("Kotlin scriptDependencies gradle.kts") {
|
||||||
val stats = Stats("kotlin scriptDependencies gradle.kts")
|
Stats("kotlin scriptDependencies gradle.kts").use { stat ->
|
||||||
stats.use { stat ->
|
|
||||||
perfOpenKotlinProjectFast(stat)
|
perfOpenKotlinProjectFast(stat)
|
||||||
|
|
||||||
perfScriptDependenciesBuildGradleKts(stat)
|
perfScriptDependenciesBuildGradleKts(stat)
|
||||||
@@ -205,9 +209,8 @@ class PerformanceProjectsTest : AbstractPerformanceProjectsTest() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun testKotlinProjectBuildGradle() {
|
fun testKotlinProjectBuildGradle() {
|
||||||
tcSuite("Kotlin gradle.kts") {
|
suite("Kotlin gradle.kts") {
|
||||||
val stats = Stats("kotlin gradle.kts")
|
Stats("kotlin gradle.kts").use { stat ->
|
||||||
stats.use { stat ->
|
|
||||||
perfOpenKotlinProjectFast(stat)
|
perfOpenKotlinProjectFast(stat)
|
||||||
|
|
||||||
perfFileAnalysisBuildGradleKts(stat)
|
perfFileAnalysisBuildGradleKts(stat)
|
||||||
@@ -280,14 +283,14 @@ class PerformanceProjectsTest : AbstractPerformanceProjectsTest() {
|
|||||||
val extraStats = Stats("${stats.name} $testName")
|
val extraStats = Stats("${stats.name} $testName")
|
||||||
val extraTimingsNs = mutableListOf<Map<String, Any>?>()
|
val extraTimingsNs = mutableListOf<Map<String, Any>?>()
|
||||||
|
|
||||||
val warmUpIterations = 20
|
val warmUpIterations = 30
|
||||||
val iterations = 30
|
val iterations = 50
|
||||||
|
|
||||||
performanceTest<Fixture, Pair<Long, List<HighlightInfo>>> {
|
performanceTest<Fixture, Pair<Long, List<HighlightInfo>>> {
|
||||||
name(testName)
|
name(testName)
|
||||||
stats(stats)
|
stats(stats)
|
||||||
warmUpIterations(30)
|
warmUpIterations(warmUpIterations)
|
||||||
iterations(50)
|
iterations(iterations)
|
||||||
setUp(perfKtsFileAnalysisSetUp(project, fileName))
|
setUp(perfKtsFileAnalysisSetUp(project, fileName))
|
||||||
test(perfKtsFileAnalysisTest())
|
test(perfKtsFileAnalysisTest())
|
||||||
tearDown(perfKtsFileAnalysisTearDown(extraTimingsNs, project))
|
tearDown(perfKtsFileAnalysisTearDown(extraTimingsNs, project))
|
||||||
|
|||||||
+70
-74
@@ -5,95 +5,91 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.idea.perf
|
package org.jetbrains.kotlin.idea.perf
|
||||||
|
|
||||||
import org.jetbrains.kotlin.idea.perf.Stats.Companion.tcSuite
|
import com.intellij.codeInsight.daemon.impl.HighlightInfo
|
||||||
|
import com.intellij.testFramework.UsefulTestCase
|
||||||
|
import org.jetbrains.kotlin.idea.perf.util.DefaultProfile
|
||||||
|
import org.jetbrains.kotlin.idea.perf.util.PerformanceSuite
|
||||||
|
import org.jetbrains.kotlin.idea.perf.util.PerformanceSuite.TypingConfig
|
||||||
|
import org.jetbrains.kotlin.idea.perf.util.ProjectProfile
|
||||||
|
import org.jetbrains.kotlin.idea.perf.util.suite
|
||||||
|
import org.jetbrains.kotlin.idea.testFramework.commitAllDocuments
|
||||||
|
import org.jetbrains.kotlin.test.JUnit3RunnerWithInners
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
|
||||||
class PerformanceStressTest : AbstractPerformanceProjectsTest() {
|
@RunWith(JUnit3RunnerWithInners::class)
|
||||||
|
class PerformanceStressTest : UsefulTestCase() {
|
||||||
companion object {
|
|
||||||
|
|
||||||
@JvmStatic
|
|
||||||
var warmedUp: Boolean = false
|
|
||||||
|
|
||||||
@JvmStatic
|
|
||||||
val hwStats: Stats = Stats("helloWorld project")
|
|
||||||
|
|
||||||
init {
|
|
||||||
// there is no @AfterClass for junit3.8
|
|
||||||
Runtime.getRuntime().addShutdownHook(Thread { hwStats.close() })
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun setUp() {
|
|
||||||
super.setUp()
|
|
||||||
// warm up: open simple small project
|
|
||||||
if (!warmedUp) {
|
|
||||||
warmUpProject(hwStats, "src/HelloMain.kt") {
|
|
||||||
openProject {
|
|
||||||
name("helloWorld")
|
|
||||||
|
|
||||||
kotlinFile("HelloMain") {
|
|
||||||
topFunction("main") {
|
|
||||||
param("args", "Array<String>")
|
|
||||||
body("""println("Hello World!")""")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
warmedUp = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun testLotsOfOverloadedMethods() {
|
fun testLotsOfOverloadedMethods() {
|
||||||
// KT-35135
|
// KT-35135
|
||||||
val generatedTypes = mutableListOf(listOf<String>())
|
val generatedTypes = mutableListOf(listOf<String>())
|
||||||
generateTypes(arrayOf("Int", "String", "Long", "List<Int>", "Array<Int>"), generatedTypes)
|
generateTypes(arrayOf("Int", "String", "Long", "List<Int>", "Array<Int>"), generatedTypes)
|
||||||
|
|
||||||
tcSuite("Lots of overloaded method project") {
|
suite(
|
||||||
myProject = openProject {
|
suiteName = "Lots of overloaded method project",
|
||||||
name("kt-35135")
|
config = PerformanceSuite.StatsScopeConfig(name = "kt-35135 project", warmup = 8, iterations = 15)
|
||||||
buildGradle("idea/testData/perfTest/simpleTemplate/")
|
) {
|
||||||
|
app {
|
||||||
|
warmUpProject()
|
||||||
|
|
||||||
kotlinFile("OverloadX") {
|
project {
|
||||||
pkg("pkg")
|
descriptor {
|
||||||
|
name("kt-35135")
|
||||||
|
buildGradle("idea/testData/perfTest/simpleTemplate/")
|
||||||
|
|
||||||
topClass("OverloadX") {
|
kotlinFile("OverloadX") {
|
||||||
openClass()
|
pkg("pkg")
|
||||||
|
|
||||||
for (types in generatedTypes) {
|
topClass("OverloadX") {
|
||||||
function("foo") {
|
openClass()
|
||||||
openFunction()
|
|
||||||
returnType("String")
|
for (types in generatedTypes) {
|
||||||
for ((index, type) in types.withIndex()) {
|
function("foo") {
|
||||||
param("arg$index", type)
|
openFunction()
|
||||||
|
returnType("String")
|
||||||
|
for ((index, type) in types.withIndex()) {
|
||||||
|
param("arg$index", type)
|
||||||
|
}
|
||||||
|
body("TODO()")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
body("TODO()")
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
kotlinFile("SomeClass") {
|
||||||
|
pkg("pkg")
|
||||||
|
|
||||||
|
topClass("SomeClass") {
|
||||||
|
superClass("OverloadX")
|
||||||
|
|
||||||
|
body("ov")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
profile(DefaultProfile)
|
||||||
|
|
||||||
|
fixture("src/main/java/pkg/SomeClass.kt").use { fixture ->
|
||||||
|
val typingConfig = TypingConfig(
|
||||||
|
fixture,
|
||||||
|
marker = "ov",
|
||||||
|
insertString = "override fun foo(): String = TODO()",
|
||||||
|
delayMs = 50
|
||||||
|
)
|
||||||
|
|
||||||
|
measure<List<HighlightInfo>>("type override fun foo()", fixture = fixture) {
|
||||||
|
before = {
|
||||||
|
moveCursor(typingConfig)
|
||||||
|
}
|
||||||
|
test = {
|
||||||
|
typeAndHighlight(typingConfig)
|
||||||
|
}
|
||||||
|
after = {
|
||||||
|
fixture.restoreText()
|
||||||
|
commitAllDocuments()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
kotlinFile("SomeClass") {
|
|
||||||
pkg("pkg")
|
|
||||||
|
|
||||||
topClass("SomeClass") {
|
|
||||||
superClass("OverloadX")
|
|
||||||
|
|
||||||
body("ov")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val stats = Stats("kt-35135 project")
|
|
||||||
stats.use { stats ->
|
|
||||||
perfType(
|
|
||||||
stats,
|
|
||||||
"src/main/java/pkg/SomeClass.kt",
|
|
||||||
"ov",
|
|
||||||
"override fun foo(): String = TODO()",
|
|
||||||
note = "override fun foo()",
|
|
||||||
delay = 50
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ import com.intellij.openapi.project.Project
|
|||||||
import com.intellij.openapi.projectRoots.JavaSdk
|
import com.intellij.openapi.projectRoots.JavaSdk
|
||||||
import com.intellij.openapi.projectRoots.impl.JavaAwareProjectJdkTableImpl
|
import com.intellij.openapi.projectRoots.impl.JavaAwareProjectJdkTableImpl
|
||||||
import com.intellij.util.io.*
|
import com.intellij.util.io.*
|
||||||
|
import org.jetbrains.kotlin.idea.perf.util.ProfileTools.Companion.initDefaultProfile
|
||||||
|
import org.jetbrains.kotlin.idea.testFramework.GRADLE_JDK_NAME
|
||||||
import org.jetbrains.kotlin.idea.testFramework.OpenProject
|
import org.jetbrains.kotlin.idea.testFramework.OpenProject
|
||||||
import org.jetbrains.kotlin.idea.testFramework.ProjectOpenAction
|
import org.jetbrains.kotlin.idea.testFramework.ProjectOpenAction
|
||||||
import java.nio.file.Files
|
import java.nio.file.Files
|
||||||
@@ -209,31 +211,54 @@ class ProjectBuilder {
|
|||||||
//
|
//
|
||||||
return targetDirectory.toAbsolutePath().toFile().absolutePath
|
return targetDirectory.toAbsolutePath().toFile().absolutePath
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun openProjectOperation(): OpenProjectOperation {
|
||||||
|
val builder = this
|
||||||
|
val projectPath = generateFiles()
|
||||||
|
|
||||||
|
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()
|
||||||
|
val jdk18 = javaSdk.createJdk("1.8", homePath)
|
||||||
|
|
||||||
|
val openAction = if (buildGradle != null) ProjectOpenAction.GRADLE_PROJECT else ProjectOpenAction.SIMPLE_JAVA_MODULE
|
||||||
|
val openProject = OpenProject(
|
||||||
|
projectPath = projectPath,
|
||||||
|
projectName = name,
|
||||||
|
jdk = jdk18,
|
||||||
|
projectOpenAction = openAction
|
||||||
|
)
|
||||||
|
|
||||||
|
return object : OpenProjectOperation {
|
||||||
|
|
||||||
|
override fun openProject() = ProjectOpenAction.openProject(openProject)
|
||||||
|
|
||||||
|
override fun postOpenProject(project: Project) {
|
||||||
|
openAction.postOpenProject(project = project, openProject = openProject)
|
||||||
|
if (builder.initDefaultProfile) {
|
||||||
|
project.initDefaultProfile()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface OpenProjectOperation {
|
||||||
|
fun openProject(): Project
|
||||||
|
|
||||||
|
fun postOpenProject(project: Project)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun openProject(initializer: ProjectBuilder.() -> Unit): Project {
|
fun openProject(initializer: ProjectBuilder.() -> Unit): Project {
|
||||||
val projectBuilder = ProjectBuilder().apply(initializer)
|
val projectBuilder = ProjectBuilder().apply(initializer)
|
||||||
val projectPath = projectBuilder.generateFiles()
|
val openProject = projectBuilder.openProjectOperation()
|
||||||
|
|
||||||
val jdkTableImpl = JavaAwareProjectJdkTableImpl.getInstanceEx()
|
return openProject.openProject().also {
|
||||||
val homePath = if (jdkTableImpl.internalJdk.homeDirectory!!.name == "jre") {
|
openProject.postOpenProject(it)
|
||||||
jdkTableImpl.internalJdk.homeDirectory!!.parent.path
|
|
||||||
} else {
|
|
||||||
jdkTableImpl.internalJdk.homePath!!
|
|
||||||
}
|
}
|
||||||
val javaSdk = JavaSdk.getInstance()
|
|
||||||
val jdk18 = javaSdk.createJdk("1.8", homePath)
|
|
||||||
val openAction = if (projectBuilder.buildGradle != null) ProjectOpenAction.GRADLE_PROJECT else ProjectOpenAction.SIMPLE_JAVA_MODULE
|
|
||||||
val openProject = OpenProject(
|
|
||||||
projectPath = projectPath,
|
|
||||||
projectName = projectBuilder.name,
|
|
||||||
jdk = jdk18,
|
|
||||||
projectOpenAction = openAction
|
|
||||||
)
|
|
||||||
val project = ProjectOpenAction.openProject(openProject)
|
|
||||||
openAction.postOpenProject(project = project, openProject = openProject)
|
|
||||||
if (projectBuilder.initDefaultProfile) {
|
|
||||||
openAction.initDefaultProfile(project)
|
|
||||||
}
|
|
||||||
return project
|
|
||||||
}
|
}
|
||||||
@@ -7,7 +7,8 @@ package org.jetbrains.kotlin.idea.perf
|
|||||||
|
|
||||||
import org.jetbrains.kotlin.idea.perf.WholeProjectPerformanceTest.Companion.nsToMs
|
import org.jetbrains.kotlin.idea.perf.WholeProjectPerformanceTest.Companion.nsToMs
|
||||||
import org.jetbrains.kotlin.idea.perf.profilers.*
|
import org.jetbrains.kotlin.idea.perf.profilers.*
|
||||||
import org.jetbrains.kotlin.idea.testFramework.logMessage
|
import org.jetbrains.kotlin.idea.perf.util.TeamCity
|
||||||
|
import org.jetbrains.kotlin.idea.perf.util.logMessage
|
||||||
import org.jetbrains.kotlin.idea.testFramework.suggestOsNeutralFileName
|
import org.jetbrains.kotlin.idea.testFramework.suggestOsNeutralFileName
|
||||||
import org.jetbrains.kotlin.util.PerformanceCounter
|
import org.jetbrains.kotlin.util.PerformanceCounter
|
||||||
import java.io.*
|
import java.io.*
|
||||||
@@ -57,9 +58,9 @@ class Stats(
|
|||||||
)) {
|
)) {
|
||||||
val n = "$id : ${v.first}"
|
val n = "$id : ${v.first}"
|
||||||
|
|
||||||
printTestStarted(n)
|
TeamCity.test(n, durationMs = v.third) {
|
||||||
printStatValue("$id${v.second}", v.third)
|
TeamCity.statValue("$id${v.second}", v.third)
|
||||||
printTestFinished(n, v.third, includeStatValue = false)
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
statInfosArray.filterNotNull()
|
statInfosArray.filterNotNull()
|
||||||
@@ -75,9 +76,11 @@ class Stats(
|
|||||||
|
|
||||||
val shortName = if (perfCounterName.endsWith(": time")) n.removeSuffix(": time") else null
|
val shortName = if (perfCounterName.endsWith(": time")) n.removeSuffix(": time") else null
|
||||||
|
|
||||||
shortName?.let { printTestStarted(it) }
|
shortName?.let {
|
||||||
printStatValue(n, mean)
|
TeamCity.test(it, durationMs = mean) {
|
||||||
shortName?.let { printTestFinished(it, mean, includeStatValue = false) }
|
TeamCity.statValue(it, mean)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
perfTestRawDataMs.addAll(timingsMs.toList())
|
perfTestRawDataMs.addAll(timingsMs.toList())
|
||||||
@@ -161,15 +164,15 @@ class Stats(
|
|||||||
val stabilityName = "$name: $testName stability"
|
val stabilityName = "$name: $testName stability"
|
||||||
|
|
||||||
val stable = stabilityPercentage <= acceptanceStabilityLevel
|
val stable = stabilityPercentage <= acceptanceStabilityLevel
|
||||||
printTestStarted(stabilityName)
|
|
||||||
printStatValue(stabilityName, stabilityPercentage)
|
val error = if (stable or !checkStability) {
|
||||||
if (stable or !checkStability) {
|
null
|
||||||
printTestFinished(stabilityName)
|
|
||||||
} else {
|
} else {
|
||||||
printTestFailed(
|
"$testName stability is $stabilityPercentage %, above accepted level of $acceptanceStabilityLevel %"
|
||||||
stabilityName,
|
}
|
||||||
"$testName stability is $stabilityPercentage %, above accepted level of $acceptanceStabilityLevel %"
|
|
||||||
)
|
TeamCity.test(stabilityName, errorDetails = error) {
|
||||||
|
TeamCity.statValue(stabilityName, stabilityPercentage)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -178,7 +181,7 @@ class Stats(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (testName != WARM_UP) {
|
if (testName != WARM_UP) {
|
||||||
tcSuite(testName, block)
|
TeamCity.suite(testName, block)
|
||||||
} else {
|
} else {
|
||||||
block()
|
block()
|
||||||
}
|
}
|
||||||
@@ -197,19 +200,17 @@ class Stats(
|
|||||||
|
|
||||||
val t = statInfo[ERROR_KEY] as? Throwable
|
val t = statInfo[ERROR_KEY] as? Throwable
|
||||||
if (t != null) {
|
if (t != null) {
|
||||||
printTestStarted(n)
|
TeamCity.test(n, errors = listOf(t)) {}
|
||||||
printTestFinished(n, t)
|
|
||||||
} else if (!printOnlyErrors) {
|
} else if (!printOnlyErrors) {
|
||||||
printTestStarted(n)
|
TeamCity.test(n, durationMs = (statInfo[TEST_KEY] as Long).nsToMs) {
|
||||||
for ((k, v) in statInfo) {
|
for ((k, v) in statInfo) {
|
||||||
if (k == TEST_KEY) continue
|
if (k == TEST_KEY) continue
|
||||||
printStatValue("$n $k", v)
|
TeamCity.statValue("$n $k", v)
|
||||||
(v as? Number)?.let {
|
(v as? Number)?.let {
|
||||||
printTestMetadata(n, k, it)
|
TeamCity.testMetadata(n, k, it)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
printTestFinished(n, (statInfo[TEST_KEY] as Long).nsToMs)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -245,7 +246,14 @@ class Stats(
|
|||||||
|
|
||||||
private fun <SV, TV> mainPhase(phaseData: PhaseData<SV, TV>): Array<StatInfos> {
|
private fun <SV, TV> mainPhase(phaseData: PhaseData<SV, TV>): Array<StatInfos> {
|
||||||
val statInfosArray = phase(phaseData, "")
|
val statInfosArray = phase(phaseData, "")
|
||||||
statInfosArray.filterNotNull().map { it[ERROR_KEY] as? Throwable }.firstOrNull()?.let { throw it }
|
statInfosArray.filterNotNull().map { it[ERROR_KEY] as? Throwable }.firstOrNull()?.let {
|
||||||
|
printTimings(
|
||||||
|
phaseData.testName,
|
||||||
|
printOnlyErrors = true,
|
||||||
|
statInfoArray = statInfosArray
|
||||||
|
)
|
||||||
|
throw it
|
||||||
|
}
|
||||||
return statInfosArray
|
return statInfosArray
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -300,7 +308,7 @@ class Stats(
|
|||||||
}
|
}
|
||||||
} catch (t: Throwable) {
|
} catch (t: Throwable) {
|
||||||
logMessage(t) { "error at ${phaseData.testName}" }
|
logMessage(t) { "error at ${phaseData.testName}" }
|
||||||
tcPrintErrors(phaseData.testName, listOf(t))
|
TeamCity.testFailed(name, error = t)
|
||||||
}
|
}
|
||||||
return statInfosArray
|
return statInfosArray
|
||||||
}
|
}
|
||||||
@@ -338,7 +346,7 @@ class Stats(
|
|||||||
override fun close() {
|
override fun close() {
|
||||||
if (perfTestRawDataMs.isNotEmpty()) {
|
if (perfTestRawDataMs.isNotEmpty()) {
|
||||||
val geomMeanMs = geomMean(perfTestRawDataMs.toList()).toLong()
|
val geomMeanMs = geomMean(perfTestRawDataMs.toList()).toLong()
|
||||||
printStatValue("$name geomMean", geomMeanMs)
|
TeamCity.statValue("$name geomMean", geomMeanMs)
|
||||||
append(arrayOf("$name geomMean", geomMeanMs, 0))
|
append(arrayOf("$name geomMean", geomMeanMs, 0))
|
||||||
}
|
}
|
||||||
statsOutput.flush()
|
statsOutput.flush()
|
||||||
@@ -357,75 +365,6 @@ class Stats(
|
|||||||
}
|
}
|
||||||
logMessage { "$note took $openProjectMillis ms" }
|
logMessage { "$note took $openProjectMillis ms" }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun printTestStarted(testName: String) {
|
|
||||||
println("##teamcity[testStarted name='$testName' captureStandardOutput='true']")
|
|
||||||
}
|
|
||||||
|
|
||||||
fun printStatValue(name: String, value: Any) {
|
|
||||||
println("##teamcity[buildStatisticValue key='$name' value='$value']")
|
|
||||||
}
|
|
||||||
|
|
||||||
fun printTestMetadata(testName: String, name: String, value: Number) {
|
|
||||||
println("##teamcity[testMetadata testName='$testName' name='$name' type='number' 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)
|
|
||||||
}
|
|
||||||
println("##teamcity[testFinished name='$testName' duration='$spentMs']")
|
|
||||||
}
|
|
||||||
|
|
||||||
fun printTestFinished(testName: String, error: Throwable) {
|
|
||||||
println("error at $testName:")
|
|
||||||
printStatValue(testName, -1)
|
|
||||||
tcPrintErrors(testName, listOf(error))
|
|
||||||
}
|
|
||||||
|
|
||||||
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) {
|
|
||||||
println("##teamcity[testSuiteStarted name='$name']")
|
|
||||||
try {
|
|
||||||
block()
|
|
||||||
} finally {
|
|
||||||
println("##teamcity[testSuiteFinished name='$name']")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inline fun tcTest(name: String, block: () -> Pair<Long, List<Throwable>>) {
|
|
||||||
printTestStarted(name)
|
|
||||||
val (time, errors) = block()
|
|
||||||
tcPrintErrors(name, errors)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun tcEscape(s: String) = s.replace("|", "||")
|
|
||||||
.replace("[", "|[")
|
|
||||||
.replace("]", "|]")
|
|
||||||
.replace("\r", "|r")
|
|
||||||
.replace("\n", "|n")
|
|
||||||
.replace("'", "|'")
|
|
||||||
|
|
||||||
fun tcPrintErrors(name: String, errors: List<Throwable>) {
|
|
||||||
if (errors.isNotEmpty()) {
|
|
||||||
val detailsWriter = StringWriter()
|
|
||||||
val errorDetailsPrintWriter = PrintWriter(detailsWriter)
|
|
||||||
errors.forEach {
|
|
||||||
it.printStackTrace(errorDetailsPrintWriter)
|
|
||||||
errorDetailsPrintWriter.println()
|
|
||||||
}
|
|
||||||
errorDetailsPrintWriter.close()
|
|
||||||
val details = detailsWriter.toString()
|
|
||||||
printTestFailed(name, details)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2020 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
|
||||||
|
|
||||||
|
/**
|
||||||
|
* warm up: open simple `hello world` project
|
||||||
|
*/
|
||||||
|
class WarmUpProject(private val stats: Stats) {
|
||||||
|
private var warmedUp: Boolean = false
|
||||||
|
|
||||||
|
fun warmUp(test: AbstractPerformanceProjectsTest) {
|
||||||
|
if (warmedUp) return
|
||||||
|
test.warmUpProject(stats, "src/HelloMain.kt") {
|
||||||
|
openProject {
|
||||||
|
name("helloWorld")
|
||||||
|
|
||||||
|
kotlinFile("HelloMain") {
|
||||||
|
topFunction("main") {
|
||||||
|
param("args", "Array<String>")
|
||||||
|
body("""println("Hello World!")""")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
warmedUp = true
|
||||||
|
}
|
||||||
|
}
|
||||||
+10
-5
@@ -28,8 +28,8 @@ import com.intellij.psi.impl.source.resolve.reference.ReferenceProvidersRegistry
|
|||||||
import com.intellij.psi.xml.XmlFileNSInfoProvider
|
import com.intellij.psi.xml.XmlFileNSInfoProvider
|
||||||
import com.intellij.xml.XmlSchemaProvider
|
import com.intellij.xml.XmlSchemaProvider
|
||||||
import org.jetbrains.kotlin.idea.framework.KotlinSdkType
|
import org.jetbrains.kotlin.idea.framework.KotlinSdkType
|
||||||
import org.jetbrains.kotlin.idea.perf.Stats.Companion.tcSuite
|
import org.jetbrains.kotlin.idea.perf.util.TeamCity
|
||||||
import org.jetbrains.kotlin.idea.perf.Stats.Companion.tcTest
|
import org.jetbrains.kotlin.idea.testFramework.TestApplicationManager
|
||||||
import org.jetbrains.kotlin.idea.util.getProjectJdkTableSafe
|
import org.jetbrains.kotlin.idea.util.getProjectJdkTableSafe
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
@@ -95,7 +95,7 @@ abstract class WholeProjectPerformanceTest : DaemonAnalyzerTestCase(), WholeProj
|
|||||||
|
|
||||||
fun testWholeProjectPerformance() {
|
fun testWholeProjectPerformance() {
|
||||||
|
|
||||||
tcSuite(this::class.simpleName ?: "Unknown") {
|
TeamCity.suite(this::class.simpleName ?: "Unknown") {
|
||||||
val totals = mutableMapOf<String, Long>()
|
val totals = mutableMapOf<String, Long>()
|
||||||
|
|
||||||
fun appendInspectionResult(file: String, id: String, nanoTime: Long) {
|
fun appendInspectionResult(file: String, id: String, nanoTime: Long) {
|
||||||
@@ -104,7 +104,7 @@ abstract class WholeProjectPerformanceTest : DaemonAnalyzerTestCase(), WholeProj
|
|||||||
perfStats.append(file, id, nanoTime)
|
perfStats.append(file, id, nanoTime)
|
||||||
}
|
}
|
||||||
|
|
||||||
tcSuite("TotalPerFile") {
|
TeamCity.suite("TotalPerFile") {
|
||||||
// TODO: [VD] temp to limit number of files (and total time to run)
|
// TODO: [VD] temp to limit number of files (and total time to run)
|
||||||
val files = provideFiles(project).sortedBy { it.name }.take(10)
|
val files = provideFiles(project).sortedBy { it.name }.take(10)
|
||||||
|
|
||||||
@@ -120,7 +120,7 @@ abstract class WholeProjectPerformanceTest : DaemonAnalyzerTestCase(), WholeProj
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tcSuite("Total") {
|
TeamCity.suite("Total") {
|
||||||
totals.forEach { (k, v) ->
|
totals.forEach { (k, v) ->
|
||||||
tcTest(k) {
|
tcTest(k) {
|
||||||
v.nsToMs to emptyList()
|
v.nsToMs to emptyList()
|
||||||
@@ -139,6 +139,11 @@ abstract class WholeProjectPerformanceTest : DaemonAnalyzerTestCase(), WholeProj
|
|||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
val Long.nsToMs get() = (this * 1e-6).toLong()
|
val Long.nsToMs get() = (this * 1e-6).toLong()
|
||||||
|
|
||||||
|
inline fun tcTest(name: String, block: () -> Pair<Long, List<Throwable>>) {
|
||||||
|
val (time, errors) = block()
|
||||||
|
TeamCity.test(name, time, errors = errors) {}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2010-2020 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
@file:Suppress("UNUSED_PARAMETER")
|
|
||||||
|
|
||||||
package org.jetbrains.kotlin.idea.perf
|
|
||||||
|
|
||||||
import com.intellij.openapi.Disposable
|
|
||||||
import com.intellij.openapi.project.Project
|
|
||||||
import com.intellij.testFramework.propertyBased.MadTestingUtil
|
|
||||||
|
|
||||||
// BUNCH: 193
|
|
||||||
fun enableAllInspectionsCompat(project: Project, disposable: Disposable) {
|
|
||||||
MadTestingUtil.enableAllInspections(project, disposable)
|
|
||||||
}
|
|
||||||
|
|
||||||
// BUNCH: 193
|
|
||||||
typealias TestApplicationManager = com.intellij.idea.IdeaTestApplication
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2010-2020 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
@file:Suppress("UNUSED_PARAMETER")
|
|
||||||
|
|
||||||
package org.jetbrains.kotlin.idea.perf
|
|
||||||
|
|
||||||
import com.intellij.openapi.Disposable
|
|
||||||
import com.intellij.openapi.project.Project
|
|
||||||
import com.intellij.testFramework.propertyBased.MadTestingUtil
|
|
||||||
|
|
||||||
// BUNCH: 193
|
|
||||||
fun enableAllInspectionsCompat(project: Project, disposable: Disposable) {
|
|
||||||
MadTestingUtil.enableAllInspections(project)
|
|
||||||
}
|
|
||||||
|
|
||||||
// BUNCH: 193
|
|
||||||
typealias TestApplicationManager = com.intellij.testFramework.TestApplicationManager
|
|
||||||
+1
-1
@@ -7,7 +7,7 @@ package org.jetbrains.kotlin.idea.perf.profilers
|
|||||||
|
|
||||||
import org.jetbrains.kotlin.idea.perf.profilers.async.AsyncProfilerHandler
|
import org.jetbrains.kotlin.idea.perf.profilers.async.AsyncProfilerHandler
|
||||||
import org.jetbrains.kotlin.idea.perf.profilers.yk.YKProfilerHandler
|
import org.jetbrains.kotlin.idea.perf.profilers.yk.YKProfilerHandler
|
||||||
import org.jetbrains.kotlin.idea.testFramework.logMessage
|
import org.jetbrains.kotlin.idea.perf.util.logMessage
|
||||||
|
|
||||||
interface ProfilerHandler {
|
interface ProfilerHandler {
|
||||||
fun startProfiling(activityName: String, options: List<String> = emptyList())
|
fun startProfiling(activityName: String, options: List<String> = emptyList())
|
||||||
|
|||||||
+1
-1
@@ -10,7 +10,7 @@ import com.intellij.openapi.util.io.FileUtil
|
|||||||
import com.intellij.util.containers.ContainerUtil
|
import com.intellij.util.containers.ContainerUtil
|
||||||
import org.jetbrains.kotlin.idea.perf.profilers.ProfilerHandler
|
import org.jetbrains.kotlin.idea.perf.profilers.ProfilerHandler
|
||||||
import org.jetbrains.kotlin.idea.perf.profilers.doOrThrow
|
import org.jetbrains.kotlin.idea.perf.profilers.doOrThrow
|
||||||
import org.jetbrains.kotlin.idea.testFramework.logMessage
|
import org.jetbrains.kotlin.idea.perf.util.logMessage
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.lang.reflect.Method
|
import java.lang.reflect.Method
|
||||||
import java.nio.file.Files
|
import java.nio.file.Files
|
||||||
|
|||||||
+1
-1
@@ -7,7 +7,7 @@ package org.jetbrains.kotlin.idea.perf.profilers.yk
|
|||||||
|
|
||||||
import org.jetbrains.kotlin.idea.perf.profilers.ProfilerHandler
|
import org.jetbrains.kotlin.idea.perf.profilers.ProfilerHandler
|
||||||
import org.jetbrains.kotlin.idea.perf.profilers.doOrThrow
|
import org.jetbrains.kotlin.idea.perf.profilers.doOrThrow
|
||||||
import org.jetbrains.kotlin.idea.testFramework.logMessage
|
import org.jetbrains.kotlin.idea.perf.util.logMessage
|
||||||
import java.lang.management.ManagementFactory
|
import java.lang.management.ManagementFactory
|
||||||
import java.lang.reflect.Method
|
import java.lang.reflect.Method
|
||||||
import java.nio.file.Files
|
import java.nio.file.Files
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2020 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.util
|
||||||
|
|
||||||
|
import com.intellij.util.io.exists
|
||||||
|
import java.io.File
|
||||||
|
import java.nio.file.Files
|
||||||
|
import java.nio.file.Path
|
||||||
|
import java.nio.file.Paths
|
||||||
|
import java.nio.file.StandardCopyOption
|
||||||
|
|
||||||
|
fun String.lastPathSegment() =
|
||||||
|
Paths.get(this).last().toString()
|
||||||
|
|
||||||
|
fun exists(path: String, vararg paths: String) =
|
||||||
|
Paths.get(path, *paths).toAbsolutePath().exists()
|
||||||
|
|
||||||
|
fun Path.copyRecursively(targetDirectory: Path) {
|
||||||
|
val src = this
|
||||||
|
Files.walk(src)
|
||||||
|
.forEach { source -> Files.copy(source, targetDirectory.resolve(src.relativize(source)), StandardCopyOption.REPLACE_EXISTING) }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun File.allFilesWithExtension(ext: String): Iterable<File> =
|
||||||
|
walk().filter { it.isFile && it.extension.equals(ext, ignoreCase = true) }.toList()
|
||||||
@@ -0,0 +1,99 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2020 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.util
|
||||||
|
|
||||||
|
import java.io.PrintWriter
|
||||||
|
import java.io.StringWriter
|
||||||
|
|
||||||
|
inline fun gradleMessage(block: () -> String) {
|
||||||
|
print("#gradle ${block()}")
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun logMessage(message: () -> String) {
|
||||||
|
println("-- ${message()}")
|
||||||
|
}
|
||||||
|
|
||||||
|
fun logMessage(t: Throwable, message: () -> String) {
|
||||||
|
val writer = StringWriter()
|
||||||
|
PrintWriter(writer).use {
|
||||||
|
t.printStackTrace(it)
|
||||||
|
}
|
||||||
|
println("-- ${message()}:\n$writer")
|
||||||
|
}
|
||||||
|
|
||||||
|
object TeamCity {
|
||||||
|
inline fun message(block: () -> String) {
|
||||||
|
println("##teamcity[${block()}]")
|
||||||
|
}
|
||||||
|
|
||||||
|
fun suite(name: String, block: () -> Unit) {
|
||||||
|
message { "testSuiteStarted name='$name'" }
|
||||||
|
try {
|
||||||
|
block()
|
||||||
|
} finally {
|
||||||
|
message { "testSuiteFinished name='$name'" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun test(name: String, durationMs: Long? = null, errors: List<Throwable>, block: () -> Unit) {
|
||||||
|
test(name, durationMs, if (errors.isNotEmpty()) toDetails(errors) else null, block)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun test(name: String, durationMs: Long? = null, errorDetails: String? = null, block: () -> Unit) {
|
||||||
|
testStarted(name)
|
||||||
|
try {
|
||||||
|
block()
|
||||||
|
} finally {
|
||||||
|
if (errorDetails != null) {
|
||||||
|
statValue(name, -1)
|
||||||
|
testFailed(name, errorDetails)
|
||||||
|
} else {
|
||||||
|
testFinished(name, durationMs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun statValue(name: String, value: Any) {
|
||||||
|
message { "buildStatisticValue key='$name' value='$value'" }
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun testStarted(testName: String) {
|
||||||
|
message { "testStarted name='$testName'" }
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun testMetadata(testName: String, name: String, value: Number) {
|
||||||
|
message { "testMetadata testName='$testName' name='$name' type='number' value='$value'" }
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun testFinished(testName: String, durationMs: Long? = null) {
|
||||||
|
message { "testFinished name='$testName'${durationMs?.let { " duration='$durationMs'" }}" }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun testFailed(testName: String, error: Throwable) = testFailed(testName, toDetails(listOf(error))!!)
|
||||||
|
|
||||||
|
fun testFailed(testName: String, details: String) {
|
||||||
|
message { "testFailed name='$testName' message='Exceptions reported' details='${escape(details)}'" }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun escape(s: String) = s.replace("|", "||")
|
||||||
|
.replace("[", "|[")
|
||||||
|
.replace("]", "|]")
|
||||||
|
.replace("\r", "|r")
|
||||||
|
.replace("\n", "|n")
|
||||||
|
.replace("'", "|'")
|
||||||
|
|
||||||
|
private fun toDetails(errors: List<Throwable>): String? {
|
||||||
|
if (errors.isEmpty()) return null
|
||||||
|
val detailsWriter = StringWriter()
|
||||||
|
val errorDetailsPrintWriter = PrintWriter(detailsWriter)
|
||||||
|
errors.forEach {
|
||||||
|
it.printStackTrace(errorDetailsPrintWriter)
|
||||||
|
errorDetailsPrintWriter.println()
|
||||||
|
}
|
||||||
|
errorDetailsPrintWriter.close()
|
||||||
|
return detailsWriter.toString()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,416 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2020 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.util
|
||||||
|
|
||||||
|
import com.intellij.codeInsight.daemon.impl.HighlightInfo
|
||||||
|
import com.intellij.openapi.Disposable
|
||||||
|
import com.intellij.openapi.application.runWriteAction
|
||||||
|
import com.intellij.openapi.editor.EditorFactory
|
||||||
|
import com.intellij.openapi.fileEditor.FileDocumentManager
|
||||||
|
import com.intellij.openapi.fileEditor.FileEditorManager
|
||||||
|
import com.intellij.openapi.project.DumbService
|
||||||
|
import com.intellij.openapi.project.Project
|
||||||
|
import com.intellij.openapi.project.ex.ProjectManagerEx
|
||||||
|
import com.intellij.openapi.projectRoots.JavaSdk
|
||||||
|
import com.intellij.openapi.projectRoots.Sdk
|
||||||
|
import com.intellij.openapi.projectRoots.impl.JavaAwareProjectJdkTableImpl
|
||||||
|
import com.intellij.openapi.vfs.VirtualFile
|
||||||
|
import com.intellij.psi.PsiDocumentManager
|
||||||
|
import com.intellij.psi.PsiFile
|
||||||
|
import com.intellij.psi.PsiManager
|
||||||
|
import com.intellij.psi.impl.PsiDocumentManagerBase
|
||||||
|
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.containers.toArray
|
||||||
|
import com.intellij.util.indexing.UnindexedFilesUpdater
|
||||||
|
import org.jetbrains.kotlin.idea.core.script.ScriptConfigurationManager
|
||||||
|
import org.jetbrains.kotlin.idea.framework.KotlinSdkType
|
||||||
|
import org.jetbrains.kotlin.idea.perf.ProjectBuilder
|
||||||
|
import org.jetbrains.kotlin.idea.perf.Stats
|
||||||
|
import org.jetbrains.kotlin.idea.perf.Stats.Companion.runAndMeasure
|
||||||
|
import org.jetbrains.kotlin.idea.perf.performanceTest
|
||||||
|
import org.jetbrains.kotlin.idea.perf.util.ProfileTools.Companion.disableAllInspections
|
||||||
|
import org.jetbrains.kotlin.idea.perf.util.ProfileTools.Companion.enableAllInspections
|
||||||
|
import org.jetbrains.kotlin.idea.perf.util.ProfileTools.Companion.enableInspections
|
||||||
|
import org.jetbrains.kotlin.idea.perf.util.ProfileTools.Companion.enableSingleInspection
|
||||||
|
import org.jetbrains.kotlin.idea.perf.util.ProfileTools.Companion.initDefaultProfile
|
||||||
|
import org.jetbrains.kotlin.idea.test.invalidateLibraryCache
|
||||||
|
import org.jetbrains.kotlin.idea.testFramework.*
|
||||||
|
import org.jetbrains.kotlin.idea.testFramework.TestApplicationManager
|
||||||
|
import org.jetbrains.kotlin.idea.util.getProjectJdkTableSafe
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Vladimir Ilmov
|
||||||
|
*/
|
||||||
|
class PerformanceSuite {
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
fun suite(
|
||||||
|
name: String,
|
||||||
|
stats: StatsScope,
|
||||||
|
block: (StatsScope) -> Unit
|
||||||
|
) {
|
||||||
|
TeamCity.suite(name) {
|
||||||
|
stats.stats.use {
|
||||||
|
block(stats)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun PsiFile.highlightFile(): List<HighlightInfo> {
|
||||||
|
val document = FileDocumentManager.getInstance().getDocument(virtualFile)!!
|
||||||
|
val editor = EditorFactory.getInstance().getEditors(document).first()
|
||||||
|
PsiDocumentManager.getInstance(project).commitAllDocuments()
|
||||||
|
return CodeInsightTestFixtureImpl.instantiateAndRun(this, editor, ArrayUtilRt.EMPTY_INT_ARRAY, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun rollbackChanges(vararg file: VirtualFile) {
|
||||||
|
val fileDocumentManager = FileDocumentManager.getInstance()
|
||||||
|
runInEdtAndWait {
|
||||||
|
fileDocumentManager.reloadFiles(*file)
|
||||||
|
}
|
||||||
|
|
||||||
|
ProjectManagerEx.getInstanceEx().openProjects.forEach { project ->
|
||||||
|
val psiDocumentManagerBase = PsiDocumentManager.getInstance(project) as PsiDocumentManagerBase
|
||||||
|
|
||||||
|
runInEdtAndWait {
|
||||||
|
psiDocumentManagerBase.clearUncommittedDocuments()
|
||||||
|
psiDocumentManagerBase.commitAllDocuments()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class StatsScope(val config: StatsScopeConfig, val stats: Stats, val rootDisposable: Disposable) {
|
||||||
|
fun app(f: ApplicationScope.() -> Unit) = ApplicationScope(rootDisposable, this).use(f)
|
||||||
|
|
||||||
|
fun <T> measure(name: String, f: MeasurementScope<T>.() -> Unit): List<T?> =
|
||||||
|
MeasurementScope<T>(name, stats, config).apply(f).run()
|
||||||
|
|
||||||
|
fun <T> measure(name: String, f: MeasurementScope<T>.() -> Unit, after: (() -> Unit)?): List<T?> =
|
||||||
|
MeasurementScope<T>(name, stats, config, after = after).apply(f).run()
|
||||||
|
|
||||||
|
fun logStatValue(name: String, value: Any) {
|
||||||
|
logMessage { "buildStatisticValue key='${stats.name}: $name' value='$value'" }
|
||||||
|
TeamCity.statValue("${stats.name}: $name", value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data class TypingConfig(
|
||||||
|
val fixture: Fixture,
|
||||||
|
val marker: String,
|
||||||
|
val insertString: String,
|
||||||
|
val surroundItems: String = "\n",
|
||||||
|
val typeAfterMarker: Boolean = true,
|
||||||
|
val note: String = "",
|
||||||
|
val delayMs: Long? = null
|
||||||
|
) : AutoCloseable {
|
||||||
|
override fun close() {
|
||||||
|
fixture.close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class MeasurementScope<T>(
|
||||||
|
val name: String,
|
||||||
|
val stats: Stats,
|
||||||
|
val config: StatsScopeConfig,
|
||||||
|
var before: () -> Unit = {},
|
||||||
|
var test: (() -> T?)? = null,
|
||||||
|
var after: (() -> Unit)? = null
|
||||||
|
) {
|
||||||
|
fun run(): List<T?> {
|
||||||
|
val t = test ?: error("test procedure isn't set")
|
||||||
|
val value = mutableListOf<T?>()
|
||||||
|
performanceTest<Unit, T> {
|
||||||
|
name(name)
|
||||||
|
stats(stats)
|
||||||
|
warmUpIterations(config.warmup)
|
||||||
|
iterations(config.iterations)
|
||||||
|
setUp {
|
||||||
|
before()
|
||||||
|
}
|
||||||
|
test {
|
||||||
|
value.add(t.invoke())
|
||||||
|
}
|
||||||
|
tearDown {
|
||||||
|
after?.invoke()
|
||||||
|
}
|
||||||
|
profilerEnabled(config.profile)
|
||||||
|
}
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ApplicationScope(val rootDisposable: Disposable, val stats: StatsScope) : AutoCloseable {
|
||||||
|
val application = initApp(rootDisposable)
|
||||||
|
val jdk: Sdk = initSdk(rootDisposable)
|
||||||
|
|
||||||
|
fun project(externalProject: ExternalProject, refresh: Boolean = false, block: ProjectScope.() -> Unit) =
|
||||||
|
ProjectScope(ProjectScopeConfig(externalProject, refresh), this).use(block)
|
||||||
|
|
||||||
|
fun project(block: ProjectWithDescriptorScope.() -> Unit) =
|
||||||
|
ProjectWithDescriptorScope(this).use(block)
|
||||||
|
|
||||||
|
fun project(path: String, openWith: ProjectOpenAction = ProjectOpenAction.EXISTING_IDEA_PROJECT, block: ProjectScope.() -> Unit) =
|
||||||
|
ProjectScope(ProjectScopeConfig(path, openWith), this).use(block)
|
||||||
|
|
||||||
|
fun gradleProject(path: String, refresh: Boolean = false, block: ProjectScope.() -> Unit) =
|
||||||
|
ProjectScope(ProjectScopeConfig(path, ProjectOpenAction.GRADLE_PROJECT, refresh), this).use(block)
|
||||||
|
|
||||||
|
fun warmUpProject() = project {
|
||||||
|
descriptor {
|
||||||
|
name("helloWorld")
|
||||||
|
|
||||||
|
kotlinFile("HelloMain") {
|
||||||
|
topFunction("main") {
|
||||||
|
param("args", "Array<String>")
|
||||||
|
body("""println("Hello World!")""")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fixture("src/HelloMain.kt").use {
|
||||||
|
highlight(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun close() {
|
||||||
|
application?.setDataProvider(null)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun initApp(rootDisposable: Disposable): TestApplicationManager {
|
||||||
|
val application = TestApplicationManager.getInstance()
|
||||||
|
GradleProcessOutputInterceptor.install(rootDisposable)
|
||||||
|
return application
|
||||||
|
}
|
||||||
|
|
||||||
|
fun initSdk(rootDisposable: Disposable): Sdk {
|
||||||
|
return 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()
|
||||||
|
val jdk = javaSdk.createJdk("1.8", homePath)
|
||||||
|
val internal = javaSdk.createJdk("IDEA jdk", homePath)
|
||||||
|
val gradle = javaSdk.createJdk(GRADLE_JDK_NAME, homePath)
|
||||||
|
|
||||||
|
val jdkTable = getProjectJdkTableSafe()
|
||||||
|
jdkTable.addJdk(jdk, rootDisposable)
|
||||||
|
jdkTable.addJdk(internal, rootDisposable)
|
||||||
|
jdkTable.addJdk(gradle, rootDisposable)
|
||||||
|
KotlinSdkType.setUpIfNeeded()
|
||||||
|
jdk
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class StatsScopeConfig(var name: String? = null, var warmup: Int = 2, var iterations: Int = 5, var profile: Boolean = false)
|
||||||
|
|
||||||
|
class ProjectScopeConfig(val path: String, val openWith: ProjectOpenAction, val refresh: Boolean = false) {
|
||||||
|
val name: String = path.lastPathSegment()
|
||||||
|
|
||||||
|
constructor(externalProject: ExternalProject, refresh: Boolean) : this(externalProject.path, externalProject.openWith, refresh)
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class AbstractProjectScope(val app: ApplicationScope) : AutoCloseable {
|
||||||
|
abstract val project: Project
|
||||||
|
val openFiles = mutableListOf<VirtualFile>()
|
||||||
|
|
||||||
|
fun profile(profile: ProjectProfile) {
|
||||||
|
when (profile) {
|
||||||
|
EmptyProfile -> project.disableAllInspections()
|
||||||
|
DefaultProfile -> project.initDefaultProfile()
|
||||||
|
FullProfile -> project.enableAllInspections()
|
||||||
|
is CustomProfile -> project.enableInspections(*profile.inspectionNames.toArray(emptyArray()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun highlight(fixture: Fixture) = highlight(fixture.psiFile)
|
||||||
|
|
||||||
|
fun highlight(editorFile: PsiFile?) =
|
||||||
|
editorFile?.let {
|
||||||
|
it.highlightFile()
|
||||||
|
} ?: error("editor isn't ready for highlight")
|
||||||
|
|
||||||
|
fun moveCursor(config: TypingConfig) {
|
||||||
|
val fixture = config.fixture
|
||||||
|
val editor = fixture.editor
|
||||||
|
updateScriptDependenciesIfNeeded(fixture)
|
||||||
|
|
||||||
|
val marker = config.marker
|
||||||
|
val tasksIdx = fixture.text.indexOf(marker)
|
||||||
|
check(tasksIdx > 0) {
|
||||||
|
"marker '$marker' not found in ${fixture.fileName}"
|
||||||
|
}
|
||||||
|
if (config.typeAfterMarker) {
|
||||||
|
editor.caretModel.moveToOffset(tasksIdx + marker.length + 1)
|
||||||
|
} else {
|
||||||
|
editor.caretModel.moveToOffset(tasksIdx - 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
for (surroundItem in config.surroundItems) {
|
||||||
|
EditorTestUtil.performTypingAction(editor, surroundItem)
|
||||||
|
}
|
||||||
|
|
||||||
|
editor.caretModel.moveToOffset(editor.caretModel.offset - if (config.typeAfterMarker) 1 else 2)
|
||||||
|
|
||||||
|
if (!config.typeAfterMarker) {
|
||||||
|
for (surroundItem in config.surroundItems) {
|
||||||
|
EditorTestUtil.performTypingAction(editor, surroundItem)
|
||||||
|
}
|
||||||
|
editor.caretModel.moveToOffset(editor.caretModel.offset - 2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun typeAndHighlight(config: TypingConfig): List<HighlightInfo> {
|
||||||
|
val string = config.insertString
|
||||||
|
for (i in string.indices) {
|
||||||
|
config.fixture.type(string[i])
|
||||||
|
config.delayMs?.let { d -> Thread.sleep(d) }
|
||||||
|
}
|
||||||
|
return config.fixture.doHighlighting()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun updateScriptDependenciesIfNeeded(fixture: Fixture) {
|
||||||
|
val path = fixture.vFile.path
|
||||||
|
if (Fixture.isAKotlinScriptFile(path)) {
|
||||||
|
runAndMeasure("update script dependencies for $path") {
|
||||||
|
ScriptConfigurationManager.updateScriptDependenciesSynchronously(fixture.psiFile)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun enableSingleInspection(inspectionName: String) =
|
||||||
|
this.project.enableSingleInspection(inspectionName)
|
||||||
|
|
||||||
|
fun enableAllInspections() =
|
||||||
|
this.project.enableAllInspections()
|
||||||
|
|
||||||
|
fun editor(path: String) =
|
||||||
|
Fixture.openFileInEditor(project, path).psiFile.also { openFiles.add(it.virtualFile) }
|
||||||
|
|
||||||
|
fun fixture(path: String): Fixture {
|
||||||
|
val fixture = Fixture.openFixture(project, path)
|
||||||
|
openFiles.add(fixture.vFile)
|
||||||
|
if (Fixture.isAKotlinScriptFile(path)) {
|
||||||
|
ScriptConfigurationManager.updateScriptDependenciesSynchronously(fixture.psiFile)
|
||||||
|
}
|
||||||
|
return fixture
|
||||||
|
}
|
||||||
|
|
||||||
|
fun rollbackChanges() =
|
||||||
|
rollbackChanges(*openFiles.toTypedArray())
|
||||||
|
|
||||||
|
fun close(editorFile: PsiFile?) {
|
||||||
|
commitAllDocuments()
|
||||||
|
editorFile?.virtualFile?.let {
|
||||||
|
FileEditorManager.getInstance(project).closeFile(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <T> measure(vararg name: String, f: MeasurementScope<T>.() -> Unit): List<T?> {
|
||||||
|
val after = { PsiManager.getInstance(project).dropPsiCaches() }
|
||||||
|
return app.stats.measure("${name.joinToString("-")}", f, after)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <T> measure(vararg name: String, fixture: Fixture, f: MeasurementScope<T>.() -> Unit): List<T?> =
|
||||||
|
measure("${name.joinToString("-")} ${fixture.fileName}", f = f)
|
||||||
|
|
||||||
|
override fun close() {
|
||||||
|
RunAll(
|
||||||
|
ThrowableRunnable {
|
||||||
|
project?.let { prj ->
|
||||||
|
app.application?.closeProject(prj)
|
||||||
|
}
|
||||||
|
}).run()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ProjectWithDescriptorScope(app: ApplicationScope) : AbstractProjectScope(app) {
|
||||||
|
private var descriptor: ProjectBuilder? = null
|
||||||
|
override val project: Project by lazy {
|
||||||
|
val builder = descriptor ?: error("project is not configured")
|
||||||
|
val openProject = builder.openProjectOperation()
|
||||||
|
|
||||||
|
openProject.openProject().also {
|
||||||
|
openProject.postOpenProject(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun descriptor(descriptor: ProjectBuilder.() -> Unit) {
|
||||||
|
this.descriptor = ProjectBuilder().apply(descriptor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ProjectScope(config: ProjectScopeConfig, app: ApplicationScope) : AbstractProjectScope(app) {
|
||||||
|
override val project: Project = initProject(config, app)
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun initProject(config: ProjectScopeConfig, app: ApplicationScope): Project {
|
||||||
|
val projectPath = File(config.path).canonicalPath
|
||||||
|
|
||||||
|
UsefulTestCase.assertTrue("path ${config.path} does not exist, check README.md", File(projectPath).exists())
|
||||||
|
|
||||||
|
val openProject = OpenProject(
|
||||||
|
projectPath = projectPath,
|
||||||
|
projectName = config.name,
|
||||||
|
jdk = app.jdk,
|
||||||
|
projectOpenAction = config.openWith
|
||||||
|
)
|
||||||
|
val project = ProjectOpenAction.openProject(openProject)
|
||||||
|
openProject.projectOpenAction.postOpenProject(project, openProject)
|
||||||
|
|
||||||
|
// indexing
|
||||||
|
if (config.refresh) {
|
||||||
|
invalidateLibraryCache(project)
|
||||||
|
}
|
||||||
|
|
||||||
|
CodeInsightTestFixtureImpl.ensureIndexesUpToDate(project)
|
||||||
|
|
||||||
|
dispatchAllInvocationEvents()
|
||||||
|
with(DumbService.getInstance(project)) {
|
||||||
|
queueTask(UnindexedFilesUpdater(project))
|
||||||
|
completeJustSubmittedTasks()
|
||||||
|
}
|
||||||
|
dispatchAllInvocationEvents()
|
||||||
|
|
||||||
|
Fixture.enableAnnotatorsAndLoadDefinitions(project)
|
||||||
|
|
||||||
|
app.application?.setDataProvider(TestDataProvider(project))
|
||||||
|
|
||||||
|
return project
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sealed class ProjectProfile
|
||||||
|
object EmptyProfile : ProjectProfile()
|
||||||
|
object DefaultProfile : ProjectProfile()
|
||||||
|
object FullProfile : ProjectProfile()
|
||||||
|
data class CustomProfile(val inspectionNames: List<String>) : ProjectProfile()
|
||||||
|
|
||||||
|
fun UsefulTestCase.suite(
|
||||||
|
suiteName: String? = null,
|
||||||
|
config: PerformanceSuite.StatsScopeConfig = PerformanceSuite.StatsScopeConfig(),
|
||||||
|
block: PerformanceSuite.StatsScope.() -> Unit
|
||||||
|
) {
|
||||||
|
PerformanceSuite.suite(
|
||||||
|
suiteName ?: this.javaClass.name,
|
||||||
|
PerformanceSuite.StatsScope(config, Stats(config.name ?: suiteName ?: name), testRootDisposable),
|
||||||
|
block
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1,96 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2020 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.util
|
||||||
|
|
||||||
|
import com.intellij.codeInspection.ex.InspectionProfileImpl
|
||||||
|
import com.intellij.codeInspection.ex.Tools
|
||||||
|
import com.intellij.openapi.project.Project
|
||||||
|
import com.intellij.openapi.util.Disposer
|
||||||
|
import com.intellij.profile.codeInspection.InspectionProjectProfileManager
|
||||||
|
import com.intellij.profile.codeInspection.ProjectInspectionProfileManager
|
||||||
|
|
||||||
|
class ProfileTools {
|
||||||
|
companion object {
|
||||||
|
internal fun Project.enableAllInspections() {
|
||||||
|
InspectionProfileImpl.INIT_INSPECTIONS = true
|
||||||
|
val profile = InspectionProfileImpl("all-inspections")
|
||||||
|
profile.enableAllTools(this)
|
||||||
|
replaceProfile(profile)
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun Project.disableAllInspections() {
|
||||||
|
InspectionProfileImpl.INIT_INSPECTIONS = true
|
||||||
|
val profile = InspectionProfileImpl("no-inspections")
|
||||||
|
profile.disableAllTools(this)
|
||||||
|
replaceProfile(profile)
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun Project.initDefaultProfile() {
|
||||||
|
val projectInspectionProfileManager = ProjectInspectionProfileManager.getInstance(this)
|
||||||
|
projectInspectionProfileManager.forceLoadSchemes()
|
||||||
|
|
||||||
|
val projectProfile = projectInspectionProfileManager.projectProfile ?: error("project has to have non null profile name")
|
||||||
|
val profile = projectInspectionProfileManager.getProfile(projectProfile)
|
||||||
|
InspectionProfileImpl.INIT_INSPECTIONS = true
|
||||||
|
profile.initInspectionTools(this)
|
||||||
|
// disable some known `bad` inspections
|
||||||
|
profile.disableInspection(this, "SSBasedInspection")
|
||||||
|
|
||||||
|
val enabledTools = profile.getAllEnabledInspectionTools(this)
|
||||||
|
check(enabledTools.isNotEmpty()) {
|
||||||
|
"project $name has to have at least one enabled inspection in profile"
|
||||||
|
}
|
||||||
|
InspectionProfileImpl.INIT_INSPECTIONS = false
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun Project.enableSingleInspection(inspectionName: String) {
|
||||||
|
InspectionProfileImpl.INIT_INSPECTIONS = true
|
||||||
|
val profile = InspectionProfileImpl("$inspectionName-only")
|
||||||
|
profile.disableAllTools(this)
|
||||||
|
profile.enableTool(inspectionName, this)
|
||||||
|
|
||||||
|
replaceProfile(profile)
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun Project.enableInspections(vararg inspectionNames: String) {
|
||||||
|
InspectionProfileImpl.INIT_INSPECTIONS = true
|
||||||
|
val profile = InspectionProfileImpl("custom")
|
||||||
|
profile.disableAllTools(this)
|
||||||
|
inspectionNames.forEach {
|
||||||
|
profile.enableTool(it, this)
|
||||||
|
}
|
||||||
|
|
||||||
|
replaceProfile(profile)
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun InspectionProfileImpl.disableInspection(project: Project, vararg shortIds: String) {
|
||||||
|
shortIds.forEach { shortId ->
|
||||||
|
this.getToolsOrNull(shortId, project)?.let { it.isEnabled = false }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun Project.replaceProfile(profile: InspectionProfileImpl) {
|
||||||
|
preloadProfileTools(profile, this)
|
||||||
|
val manager = InspectionProjectProfileManager.getInstance(this) as ProjectInspectionProfileManager
|
||||||
|
manager.addProfile(profile)
|
||||||
|
val prev = manager.currentProfile
|
||||||
|
manager.setCurrentProfile(profile)
|
||||||
|
Disposer.register(this, {
|
||||||
|
InspectionProfileImpl.INIT_INSPECTIONS = false
|
||||||
|
manager.setCurrentProfile(prev)
|
||||||
|
manager.deleteProfile(profile)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun preloadProfileTools(
|
||||||
|
profile: InspectionProfileImpl,
|
||||||
|
project: Project
|
||||||
|
) {
|
||||||
|
// instantiate all tools to avoid extension loading in inconvenient moment
|
||||||
|
profile.getAllEnabledInspectionTools(project).forEach { state: Tools -> state.tool.getTool() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2020 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.util
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.idea.testFramework.ProjectOpenAction
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Vladimir Ilmov
|
||||||
|
*/
|
||||||
|
class ExternalProject(val path: String, val openWith: ProjectOpenAction) {
|
||||||
|
companion object {
|
||||||
|
const val KOTLIN_PROJECT_PATH = "../perfTestProject"
|
||||||
|
|
||||||
|
val KOTLIN_GRADLE = ExternalProject(KOTLIN_PROJECT_PATH, ProjectOpenAction.GRADLE_PROJECT)
|
||||||
|
val KOTLIN_JPS = ExternalProject(KOTLIN_PROJECT_PATH, ProjectOpenAction.EXISTING_IDEA_PROJECT)
|
||||||
|
val KOTLIN_AUTO = ExternalProject(KOTLIN_PROJECT_PATH, autoOpenAction(KOTLIN_PROJECT_PATH))
|
||||||
|
|
||||||
|
fun autoOpenAction(path: String): ProjectOpenAction {
|
||||||
|
return if (exists(path, ".idea", "modules.xml"))
|
||||||
|
ProjectOpenAction.EXISTING_IDEA_PROJECT.apply { println("Opening $path in iml mode.") }
|
||||||
|
else
|
||||||
|
ProjectOpenAction.GRADLE_PROJECT.apply { println("Opening $path in Gradle mode.") }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -13,9 +13,9 @@ import com.intellij.codeInsight.daemon.impl.HighlightInfo
|
|||||||
import com.intellij.codeInsight.lookup.LookupElement
|
import com.intellij.codeInsight.lookup.LookupElement
|
||||||
import com.intellij.lang.ExternalAnnotatorsFilter
|
import com.intellij.lang.ExternalAnnotatorsFilter
|
||||||
import com.intellij.lang.LanguageAnnotators
|
import com.intellij.lang.LanguageAnnotators
|
||||||
import com.intellij.lang.StdLanguages
|
|
||||||
import com.intellij.lang.injection.InjectedLanguageManager
|
import com.intellij.lang.injection.InjectedLanguageManager
|
||||||
import com.intellij.lang.java.JavaLanguage
|
import com.intellij.lang.java.JavaLanguage
|
||||||
|
import com.intellij.lang.xml.XMLLanguage
|
||||||
import com.intellij.openapi.application.runWriteAction
|
import com.intellij.openapi.application.runWriteAction
|
||||||
import com.intellij.openapi.editor.Document
|
import com.intellij.openapi.editor.Document
|
||||||
import com.intellij.openapi.editor.Editor
|
import com.intellij.openapi.editor.Editor
|
||||||
@@ -43,18 +43,30 @@ import junit.framework.TestCase.*
|
|||||||
import org.jetbrains.kotlin.idea.KotlinLanguage
|
import org.jetbrains.kotlin.idea.KotlinLanguage
|
||||||
import org.jetbrains.kotlin.idea.core.script.ScriptConfigurationManager
|
import org.jetbrains.kotlin.idea.core.script.ScriptConfigurationManager
|
||||||
import org.jetbrains.kotlin.idea.core.script.ScriptDefinitionsManager
|
import org.jetbrains.kotlin.idea.core.script.ScriptDefinitionsManager
|
||||||
import org.jetbrains.kotlin.idea.core.script.settings.KotlinScriptingSettings
|
|
||||||
import org.jetbrains.kotlin.idea.core.util.toPsiFile
|
import org.jetbrains.kotlin.idea.core.util.toPsiFile
|
||||||
import org.jetbrains.kotlin.parsing.KotlinParserDefinition
|
import org.jetbrains.kotlin.parsing.KotlinParserDefinition
|
||||||
import java.io.Closeable
|
|
||||||
|
|
||||||
|
class Fixture(
|
||||||
class Fixture(val project: Project, val editor: Editor, val psiFile: PsiFile, val vFile: VirtualFile = psiFile.virtualFile) : Closeable {
|
val fileName: String,
|
||||||
|
val project: Project,
|
||||||
|
val editor: Editor,
|
||||||
|
val psiFile: PsiFile,
|
||||||
|
val vFile: VirtualFile = psiFile.virtualFile
|
||||||
|
) : AutoCloseable {
|
||||||
private var delegate = EditorTestFixture(project, editor, vFile)
|
private var delegate = EditorTestFixture(project, editor, vFile)
|
||||||
|
|
||||||
|
private var savedText: String? = null
|
||||||
|
|
||||||
val document: Document
|
val document: Document
|
||||||
get() = editor.document
|
get() = editor.document
|
||||||
|
|
||||||
|
val text: String
|
||||||
|
get() = document.text
|
||||||
|
|
||||||
|
init {
|
||||||
|
storeText()
|
||||||
|
}
|
||||||
|
|
||||||
fun doHighlighting(): List<HighlightInfo> = delegate.doHighlighting() ?: emptyList()
|
fun doHighlighting(): List<HighlightInfo> = delegate.doHighlighting() ?: emptyList()
|
||||||
|
|
||||||
fun type(s: String) {
|
fun type(s: String) {
|
||||||
@@ -73,7 +85,21 @@ class Fixture(val project: Project, val editor: Editor, val psiFile: PsiFile, va
|
|||||||
fun complete(type: CompletionType = CompletionType.BASIC, invocationCount: Int = 1): Array<LookupElement> =
|
fun complete(type: CompletionType = CompletionType.BASIC, invocationCount: Int = 1): Array<LookupElement> =
|
||||||
delegate.complete(type, invocationCount) ?: emptyArray()
|
delegate.complete(type, invocationCount) ?: emptyArray()
|
||||||
|
|
||||||
fun revertChanges(revertChangesAtTheEnd: Boolean, text: String) {
|
fun storeText() {
|
||||||
|
savedText = text
|
||||||
|
}
|
||||||
|
|
||||||
|
fun restoreText() {
|
||||||
|
savedText?.let {
|
||||||
|
try {
|
||||||
|
applyText(it)
|
||||||
|
} finally {
|
||||||
|
cleanupCaches(project)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun revertChanges(revertChangesAtTheEnd: Boolean = true, text: String) {
|
||||||
try {
|
try {
|
||||||
if (revertChangesAtTheEnd) {
|
if (revertChangesAtTheEnd) {
|
||||||
// TODO: [VD] revert ?
|
// TODO: [VD] revert ?
|
||||||
@@ -108,7 +134,10 @@ class Fixture(val project: Project, val editor: Editor, val psiFile: PsiFile, va
|
|||||||
dispatchAllInvocationEvents()
|
dispatchAllInvocationEvents()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun close() = close(project, vFile)
|
override fun close() {
|
||||||
|
savedText = null
|
||||||
|
close(project, vFile)
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
// quite simple impl - good so far
|
// quite simple impl - good so far
|
||||||
@@ -128,7 +157,7 @@ class Fixture(val project: Project, val editor: Editor, val psiFile: PsiFile, va
|
|||||||
InjectedLanguageManager.getInstance(project) // zillion of Dom Sem classes
|
InjectedLanguageManager.getInstance(project) // zillion of Dom Sem classes
|
||||||
with(LanguageAnnotators.INSTANCE) {
|
with(LanguageAnnotators.INSTANCE) {
|
||||||
allForLanguage(JavaLanguage.INSTANCE) // pile of annotator classes loads
|
allForLanguage(JavaLanguage.INSTANCE) // pile of annotator classes loads
|
||||||
allForLanguage(StdLanguages.XML)
|
allForLanguage(XMLLanguage.INSTANCE)
|
||||||
allForLanguage(KotlinLanguage.INSTANCE)
|
allForLanguage(KotlinLanguage.INSTANCE)
|
||||||
}
|
}
|
||||||
DaemonAnalyzerTestCase.assertTrue(
|
DaemonAnalyzerTestCase.assertTrue(
|
||||||
@@ -147,7 +176,7 @@ class Fixture(val project: Project, val editor: Editor, val psiFile: PsiFile, va
|
|||||||
dispatchAllInvocationEvents()
|
dispatchAllInvocationEvents()
|
||||||
|
|
||||||
assertTrue(scriptDefinitionsManager.isReady())
|
assertTrue(scriptDefinitionsManager.isReady())
|
||||||
assertFalse(KotlinScriptingSettings.getInstance(project).isAutoReloadEnabled)
|
//assertFalse(KotlinScriptingSettings.getInstance(project).isAutoReloadEnabled)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -157,7 +186,7 @@ class Fixture(val project: Project, val editor: Editor, val psiFile: PsiFile, va
|
|||||||
val editorFactory = EditorFactory.getInstance()
|
val editorFactory = EditorFactory.getInstance()
|
||||||
val editor = editorFactory.getEditors(fileInEditor.document, project)[0]
|
val editor = editorFactory.getEditors(fileInEditor.document, project)[0]
|
||||||
|
|
||||||
return Fixture(project, editor, file)
|
return Fixture(fileName, project, editor, file)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun baseName(name: String): String {
|
private fun baseName(name: String): String {
|
||||||
@@ -177,10 +206,10 @@ class Fixture(val project: Project, val editor: Editor, val psiFile: PsiFile, va
|
|||||||
val projectBaseName = baseName(project.name)
|
val projectBaseName = baseName(project.name)
|
||||||
|
|
||||||
val virtualFiles = FilenameIndex.getVirtualFilesByName(
|
val virtualFiles = FilenameIndex.getVirtualFilesByName(
|
||||||
project,
|
project,
|
||||||
baseFileName, true,
|
baseFileName, true,
|
||||||
GlobalSearchScope.projectScope(project)
|
GlobalSearchScope.projectScope(project)
|
||||||
)
|
)
|
||||||
.filter { it.canonicalPath?.contains("/$projectBaseName/$name") ?: false }.toList()
|
.filter { it.canonicalPath?.contains("/$projectBaseName/$name") ?: false }.toList()
|
||||||
|
|
||||||
assertEquals(
|
assertEquals(
|
||||||
@@ -230,7 +259,7 @@ class Fixture(val project: Project, val editor: Editor, val psiFile: PsiFile, va
|
|||||||
) {
|
) {
|
||||||
val fileInEditor = openFileInEditor(project, fileName)
|
val fileInEditor = openFileInEditor(project, fileName)
|
||||||
val editor = EditorFactory.getInstance().getEditors(fileInEditor.document, project)[0]
|
val editor = EditorFactory.getInstance().getEditors(fileInEditor.document, project)[0]
|
||||||
val fixture = Fixture(project, editor, fileInEditor.psiFile)
|
val fixture = Fixture(fileName, project, editor, fileInEditor.psiFile)
|
||||||
|
|
||||||
val initialText = editor.document.text
|
val initialText = editor.document.text
|
||||||
try {
|
try {
|
||||||
|
|||||||
+4
-1
@@ -12,6 +12,7 @@ import com.intellij.openapi.externalSystem.model.task.ExternalSystemTaskNotifica
|
|||||||
import com.intellij.openapi.externalSystem.model.task.ExternalSystemTaskNotificationListener.EP_NAME as EP
|
import com.intellij.openapi.externalSystem.model.task.ExternalSystemTaskNotificationListener.EP_NAME as EP
|
||||||
import com.intellij.testFramework.ExtensionTestUtil.maskExtensions
|
import com.intellij.testFramework.ExtensionTestUtil.maskExtensions
|
||||||
import org.jetbrains.kotlin.idea.framework.GRADLE_SYSTEM_ID
|
import org.jetbrains.kotlin.idea.framework.GRADLE_SYSTEM_ID
|
||||||
|
import org.jetbrains.kotlin.idea.perf.util.gradleMessage
|
||||||
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
|
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
|
||||||
import java.lang.Exception
|
import java.lang.Exception
|
||||||
import kotlin.test.assertNull
|
import kotlin.test.assertNull
|
||||||
@@ -44,8 +45,10 @@ private class GradleProcessOutputInterceptorImpl : GradleProcessOutputIntercepto
|
|||||||
private val buffer = StringBuilder()
|
private val buffer = StringBuilder()
|
||||||
|
|
||||||
override fun onTaskOutput(id: ExternalSystemTaskId, text: String, stdOut: Boolean) {
|
override fun onTaskOutput(id: ExternalSystemTaskId, text: String, stdOut: Boolean) {
|
||||||
if (id.projectSystemId == GRADLE_SYSTEM_ID && text.isNotEmpty())
|
if (id.projectSystemId == GRADLE_SYSTEM_ID && text.isNotEmpty()) {
|
||||||
|
gradleMessage { text }
|
||||||
buffer.append(text)
|
buffer.append(text)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun reset() = buffer.setLength(0)
|
override fun reset() = buffer.setLength(0)
|
||||||
|
|||||||
+1
-25
@@ -5,7 +5,6 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.idea.testFramework
|
package org.jetbrains.kotlin.idea.testFramework
|
||||||
|
|
||||||
import com.intellij.codeInspection.ex.InspectionProfileImpl
|
|
||||||
import com.intellij.ide.highlighter.ModuleFileType
|
import com.intellij.ide.highlighter.ModuleFileType
|
||||||
import com.intellij.openapi.application.ApplicationManager
|
import com.intellij.openapi.application.ApplicationManager
|
||||||
import com.intellij.openapi.application.runWriteAction
|
import com.intellij.openapi.application.runWriteAction
|
||||||
@@ -17,18 +16,16 @@ import com.intellij.openapi.project.Project
|
|||||||
import com.intellij.openapi.project.ex.ProjectManagerEx
|
import com.intellij.openapi.project.ex.ProjectManagerEx
|
||||||
import com.intellij.openapi.projectRoots.Sdk
|
import com.intellij.openapi.projectRoots.Sdk
|
||||||
import com.intellij.openapi.roots.ProjectRootManager
|
import com.intellij.openapi.roots.ProjectRootManager
|
||||||
import com.intellij.openapi.util.Disposer
|
|
||||||
import com.intellij.openapi.vcs.changes.ChangeListManager
|
import com.intellij.openapi.vcs.changes.ChangeListManager
|
||||||
import com.intellij.openapi.vcs.changes.ChangeListManagerImpl
|
import com.intellij.openapi.vcs.changes.ChangeListManagerImpl
|
||||||
import com.intellij.openapi.vfs.LocalFileSystem
|
import com.intellij.openapi.vfs.LocalFileSystem
|
||||||
import com.intellij.openapi.vfs.VirtualFileManager
|
import com.intellij.openapi.vfs.VirtualFileManager
|
||||||
import com.intellij.profile.codeInspection.ProjectInspectionProfileManager
|
|
||||||
import com.intellij.testFramework.PsiTestUtil
|
import com.intellij.testFramework.PsiTestUtil
|
||||||
import com.intellij.testFramework.UsefulTestCase.assertTrue
|
import com.intellij.testFramework.UsefulTestCase.assertTrue
|
||||||
import com.intellij.util.io.exists
|
import com.intellij.util.io.exists
|
||||||
import org.jetbrains.kotlin.idea.configuration.getModulesWithKotlinFiles
|
import org.jetbrains.kotlin.idea.configuration.getModulesWithKotlinFiles
|
||||||
import org.jetbrains.kotlin.idea.perf.Stats.Companion.runAndMeasure
|
import org.jetbrains.kotlin.idea.perf.Stats.Companion.runAndMeasure
|
||||||
import org.jetbrains.kotlin.idea.perf.enableAllInspectionsCompat
|
import org.jetbrains.kotlin.idea.perf.util.logMessage
|
||||||
import org.jetbrains.kotlin.idea.project.getAndCacheLanguageLevelByDependencies
|
import org.jetbrains.kotlin.idea.project.getAndCacheLanguageLevelByDependencies
|
||||||
import org.jetbrains.kotlin.idea.test.ConfigLibraryUtil
|
import org.jetbrains.kotlin.idea.test.ConfigLibraryUtil
|
||||||
import java.io.File
|
import java.io.File
|
||||||
@@ -89,11 +86,6 @@ enum class ProjectOpenAction {
|
|||||||
|
|
||||||
refreshGradleProject(projectPath, project)
|
refreshGradleProject(projectPath, project)
|
||||||
|
|
||||||
assertTrue(
|
|
||||||
ModuleManager.getInstance(project).modules.isNotEmpty(),
|
|
||||||
"Gradle project $projectName at $projectPath has to have at least one module"
|
|
||||||
)
|
|
||||||
|
|
||||||
return project
|
return project
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -144,22 +136,6 @@ enum class ProjectOpenAction {
|
|||||||
//runWriteAction { project.save() }
|
//runWriteAction { project.save() }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun initDefaultProfile(project: Project) {
|
|
||||||
val projectInspectionProfileManager = ProjectInspectionProfileManager.getInstance(project)
|
|
||||||
projectInspectionProfileManager.forceLoadSchemes()
|
|
||||||
|
|
||||||
val projectProfile = projectInspectionProfileManager.projectProfile ?: error("project has to have non null profile name")
|
|
||||||
val profile = projectInspectionProfileManager.getProfile(projectProfile)
|
|
||||||
InspectionProfileImpl.INIT_INSPECTIONS = true
|
|
||||||
profile.initInspectionTools(project)
|
|
||||||
val enabledTools = profile.getAllEnabledInspectionTools(project)
|
|
||||||
assertTrue(
|
|
||||||
"project ${project.name} has to have at least one enabled inspection in profile",
|
|
||||||
enabledTools.isNotEmpty()
|
|
||||||
)
|
|
||||||
InspectionProfileImpl.INIT_INSPECTIONS = false
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun openProject(openProject: OpenProject): Project {
|
fun openProject(openProject: OpenProject): Project {
|
||||||
val project = openProject.projectOpenAction.openProject(
|
val project = openProject.projectOpenAction.openProject(
|
||||||
|
|||||||
@@ -13,3 +13,6 @@ fun ProjectManagerEx.forceCloseProjectEx(project: Project, dispose: Boolean): Bo
|
|||||||
if (!dispose) error("dispose should be true")
|
if (!dispose) error("dispose should be true")
|
||||||
return this.forceCloseProject(project, true)
|
return this.forceCloseProject(project, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// BUNCH: 193
|
||||||
|
typealias TestApplicationManager = com.intellij.idea.IdeaTestApplication
|
||||||
|
|||||||
@@ -13,3 +13,6 @@ fun ProjectManagerEx.forceCloseProjectEx(project: Project, dispose: Boolean): Bo
|
|||||||
if (!dispose) error("dispose should be true")
|
if (!dispose) error("dispose should be true")
|
||||||
return this.forceCloseProject(project)
|
return this.forceCloseProject(project)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// BUNCH: 193
|
||||||
|
typealias TestApplicationManager = com.intellij.testFramework.TestApplicationManager
|
||||||
@@ -15,6 +15,7 @@ import com.intellij.openapi.project.Project
|
|||||||
import com.intellij.openapi.roots.ProjectRootManager
|
import com.intellij.openapi.roots.ProjectRootManager
|
||||||
import org.jetbrains.plugins.gradle.service.project.open.setupGradleSettings
|
import org.jetbrains.plugins.gradle.service.project.open.setupGradleSettings
|
||||||
import org.jetbrains.plugins.gradle.settings.GradleProjectSettings
|
import org.jetbrains.plugins.gradle.settings.GradleProjectSettings
|
||||||
|
import org.jetbrains.plugins.gradle.settings.GradleSettings
|
||||||
import org.jetbrains.plugins.gradle.util.GradleConstants
|
import org.jetbrains.plugins.gradle.util.GradleConstants
|
||||||
import org.jetbrains.plugins.gradle.util.GradleLog
|
import org.jetbrains.plugins.gradle.util.GradleLog
|
||||||
import java.io.File
|
import java.io.File
|
||||||
@@ -26,6 +27,8 @@ fun refreshGradleProject(projectPath: String, project: Project) {
|
|||||||
dispatchAllInvocationEvents()
|
dispatchAllInvocationEvents()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const val GRADLE_JDK_NAME = "Gradle JDK"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* inspired by org.jetbrains.plugins.gradle.service.project.open.importProject(projectDirectory, project)
|
* inspired by org.jetbrains.plugins.gradle.service.project.open.importProject(projectDirectory, project)
|
||||||
*/
|
*/
|
||||||
@@ -34,7 +37,16 @@ private fun _importProject(projectPath: String, project: Project) {
|
|||||||
val projectSdk = ProjectRootManager.getInstance(project).projectSdk
|
val projectSdk = ProjectRootManager.getInstance(project).projectSdk
|
||||||
assertNotNull(projectSdk, "project SDK not found for ${project.name} at $projectPath")
|
assertNotNull(projectSdk, "project SDK not found for ${project.name} at $projectPath")
|
||||||
val gradleProjectSettings = GradleProjectSettings()
|
val gradleProjectSettings = GradleProjectSettings()
|
||||||
|
|
||||||
|
GradleSettings.getInstance(project).gradleVmOptions =
|
||||||
|
"-Xmx2048m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=${System.getProperty("user.dir")}"
|
||||||
|
|
||||||
setupGradleSettings(gradleProjectSettings, projectPath, project, projectSdk)
|
setupGradleSettings(gradleProjectSettings, projectPath, project, projectSdk)
|
||||||
|
gradleProjectSettings.gradleJvm = GRADLE_JDK_NAME
|
||||||
|
|
||||||
|
GradleSettings.getInstance(project).getLinkedProjectSettings(projectPath)?.let { linkedProjectSettings ->
|
||||||
|
linkedProjectSettings.gradleJvm = GRADLE_JDK_NAME
|
||||||
|
}
|
||||||
|
|
||||||
_attachGradleProjectAndRefresh(gradleProjectSettings, project)
|
_attachGradleProjectAndRefresh(gradleProjectSettings, project)
|
||||||
}
|
}
|
||||||
|
|||||||
+12
@@ -15,6 +15,7 @@ import com.intellij.openapi.project.Project
|
|||||||
import com.intellij.openapi.roots.ProjectRootManager
|
import com.intellij.openapi.roots.ProjectRootManager
|
||||||
import org.jetbrains.plugins.gradle.service.project.open.setupGradleSettings
|
import org.jetbrains.plugins.gradle.service.project.open.setupGradleSettings
|
||||||
import org.jetbrains.plugins.gradle.settings.GradleProjectSettings
|
import org.jetbrains.plugins.gradle.settings.GradleProjectSettings
|
||||||
|
import org.jetbrains.plugins.gradle.settings.GradleSettings
|
||||||
import org.jetbrains.plugins.gradle.util.GradleConstants
|
import org.jetbrains.plugins.gradle.util.GradleConstants
|
||||||
import org.jetbrains.plugins.gradle.util.GradleLog
|
import org.jetbrains.plugins.gradle.util.GradleLog
|
||||||
import java.io.File
|
import java.io.File
|
||||||
@@ -26,6 +27,8 @@ fun refreshGradleProject(projectPath: String, project: Project) {
|
|||||||
dispatchAllInvocationEvents()
|
dispatchAllInvocationEvents()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const val GRADLE_JDK_NAME = "Gradle JDK"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* inspired by org.jetbrains.plugins.gradle.service.project.open.importProject(projectDirectory, project)
|
* inspired by org.jetbrains.plugins.gradle.service.project.open.importProject(projectDirectory, project)
|
||||||
*/
|
*/
|
||||||
@@ -34,7 +37,16 @@ private fun _importProject(projectPath: String, project: Project) {
|
|||||||
val projectSdk = ProjectRootManager.getInstance(project).projectSdk
|
val projectSdk = ProjectRootManager.getInstance(project).projectSdk
|
||||||
assertNotNull(projectSdk, "project SDK not found for ${project.name} at $projectPath")
|
assertNotNull(projectSdk, "project SDK not found for ${project.name} at $projectPath")
|
||||||
val gradleProjectSettings = GradleProjectSettings()
|
val gradleProjectSettings = GradleProjectSettings()
|
||||||
|
|
||||||
|
GradleSettings.getInstance(project).gradleVmOptions =
|
||||||
|
"-Xmx2048m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=${System.getProperty("user.dir")}"
|
||||||
|
|
||||||
setupGradleSettings(gradleProjectSettings, projectPath, project, projectSdk)
|
setupGradleSettings(gradleProjectSettings, projectPath, project, projectSdk)
|
||||||
|
gradleProjectSettings.gradleJvm = GRADLE_JDK_NAME
|
||||||
|
|
||||||
|
GradleSettings.getInstance(project).getLinkedProjectSettings(projectPath)?.let { linkedProjectSettings ->
|
||||||
|
linkedProjectSettings.gradleJvm = GRADLE_JDK_NAME
|
||||||
|
}
|
||||||
|
|
||||||
_attachGradleProjectAndRefresh(gradleProjectSettings, project)
|
_attachGradleProjectAndRefresh(gradleProjectSettings, project)
|
||||||
}
|
}
|
||||||
|
|||||||
+18
-15
@@ -5,6 +5,9 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.idea.testFramework
|
package org.jetbrains.kotlin.idea.testFramework
|
||||||
|
|
||||||
|
import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer
|
||||||
|
import com.intellij.codeInsight.daemon.DaemonCodeAnalyzerSettings
|
||||||
|
import com.intellij.codeInsight.daemon.impl.DaemonCodeAnalyzerImpl
|
||||||
import com.intellij.ide.startup.impl.StartupManagerImpl
|
import com.intellij.ide.startup.impl.StartupManagerImpl
|
||||||
import com.intellij.lang.LanguageAnnotators
|
import com.intellij.lang.LanguageAnnotators
|
||||||
import com.intellij.lang.LanguageExtensionPoint
|
import com.intellij.lang.LanguageExtensionPoint
|
||||||
@@ -22,9 +25,8 @@ import com.intellij.testFramework.ExtensionTestUtil
|
|||||||
import com.intellij.testFramework.runInEdtAndWait
|
import com.intellij.testFramework.runInEdtAndWait
|
||||||
import com.intellij.util.ui.UIUtil
|
import com.intellij.util.ui.UIUtil
|
||||||
import org.jetbrains.kotlin.idea.parameterInfo.HintType
|
import org.jetbrains.kotlin.idea.parameterInfo.HintType
|
||||||
|
import org.jetbrains.kotlin.idea.perf.util.logMessage
|
||||||
import org.jetbrains.kotlin.idea.test.runPostStartupActivitiesOnce
|
import org.jetbrains.kotlin.idea.test.runPostStartupActivitiesOnce
|
||||||
import java.io.PrintWriter
|
|
||||||
import java.io.StringWriter
|
|
||||||
import java.nio.file.Paths
|
import java.nio.file.Paths
|
||||||
|
|
||||||
fun commitAllDocuments() {
|
fun commitAllDocuments() {
|
||||||
@@ -70,10 +72,23 @@ fun dispatchAllInvocationEvents() {
|
|||||||
fun loadProjectWithName(path: String, name: String): Project? =
|
fun loadProjectWithName(path: String, name: String): Project? =
|
||||||
ProjectManagerEx.getInstanceEx().loadProject(Paths.get(path), name)
|
ProjectManagerEx.getInstanceEx().loadProject(Paths.get(path), name)
|
||||||
|
|
||||||
fun closeProject(project: Project) {
|
fun TestApplicationManager.closeProject(project: Project) {
|
||||||
|
val name = project.name
|
||||||
|
val startupManagerImpl = StartupManager.getInstance(project) as StartupManagerImpl
|
||||||
|
val daemonCodeAnalyzerSettings = DaemonCodeAnalyzerSettings.getInstance()
|
||||||
|
val daemonCodeAnalyzerImpl = DaemonCodeAnalyzer.getInstance(project) as DaemonCodeAnalyzerImpl
|
||||||
|
|
||||||
|
setDataProvider(null)
|
||||||
|
daemonCodeAnalyzerSettings.isImportHintEnabled = true // return default value to avoid unnecessary save
|
||||||
|
startupManagerImpl.checkCleared()
|
||||||
|
daemonCodeAnalyzerImpl.cleanupAfterTest()
|
||||||
|
|
||||||
|
logMessage { "project '$name' is about to be closed" }
|
||||||
dispatchAllInvocationEvents()
|
dispatchAllInvocationEvents()
|
||||||
val projectManagerEx = ProjectManagerEx.getInstanceEx()
|
val projectManagerEx = ProjectManagerEx.getInstanceEx()
|
||||||
projectManagerEx.forceCloseProjectEx(project, true)
|
projectManagerEx.forceCloseProjectEx(project, true)
|
||||||
|
|
||||||
|
logMessage { "project '$name' successfully closed" }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun runStartupActivities(project: Project) {
|
fun runStartupActivities(project: Project) {
|
||||||
@@ -105,15 +120,3 @@ fun replaceWithCustomHighlighter(parentDisposable: Disposable, fromImplementatio
|
|||||||
ExtensionTestUtil.maskExtensions(pointName, filteredExtensions + listOf(point), parentDisposable)
|
ExtensionTestUtil.maskExtensions(pointName, filteredExtensions + listOf(point), parentDisposable)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun logMessage(message: () -> String) {
|
|
||||||
println("-- ${message()}")
|
|
||||||
}
|
|
||||||
|
|
||||||
fun logMessage(t: Throwable, message: () -> String) {
|
|
||||||
val writer = StringWriter()
|
|
||||||
PrintWriter(writer).use {
|
|
||||||
t.printStackTrace(it)
|
|
||||||
}
|
|
||||||
println("-- ${message()}:\n$writer")
|
|
||||||
}
|
|
||||||
+2
-13
@@ -25,6 +25,7 @@ import com.intellij.testFramework.PlatformTestUtil
|
|||||||
import com.intellij.testFramework.runInEdtAndWait
|
import com.intellij.testFramework.runInEdtAndWait
|
||||||
import com.intellij.util.ui.UIUtil
|
import com.intellij.util.ui.UIUtil
|
||||||
import org.jetbrains.kotlin.idea.parameterInfo.HintType
|
import org.jetbrains.kotlin.idea.parameterInfo.HintType
|
||||||
|
import org.jetbrains.kotlin.idea.perf.TestApplicationManager
|
||||||
import org.jetbrains.kotlin.idea.test.runPostStartupActivitiesOnce
|
import org.jetbrains.kotlin.idea.test.runPostStartupActivitiesOnce
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
import java.util.concurrent.TimeoutException
|
import java.util.concurrent.TimeoutException
|
||||||
@@ -74,7 +75,7 @@ fun dispatchAllInvocationEvents() {
|
|||||||
fun loadProjectWithName(path: String, name: String): Project? =
|
fun loadProjectWithName(path: String, name: String): Project? =
|
||||||
ProjectManagerEx.getInstanceEx().loadProject(name, path)
|
ProjectManagerEx.getInstanceEx().loadProject(name, path)
|
||||||
|
|
||||||
fun closeProject(project: Project) {
|
fun TestApplicationManager.closeProject(project: Project) {
|
||||||
dispatchAllInvocationEvents()
|
dispatchAllInvocationEvents()
|
||||||
val projectManagerEx = ProjectManagerEx.getInstanceEx()
|
val projectManagerEx = ProjectManagerEx.getInstanceEx()
|
||||||
projectManagerEx.forceCloseProjectEx(project, true)
|
projectManagerEx.forceCloseProjectEx(project, true)
|
||||||
@@ -133,15 +134,3 @@ fun replaceWithCustomHighlighter(parentDisposable: Disposable, fromImplementatio
|
|||||||
PlatformTestUtil.maskExtensions(pointName, filteredExtensions + listOf(point), parentDisposable)
|
PlatformTestUtil.maskExtensions(pointName, filteredExtensions + listOf(point), parentDisposable)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun logMessage(message: () -> String) {
|
|
||||||
println("-- ${message()}")
|
|
||||||
}
|
|
||||||
|
|
||||||
fun logMessage(t: Throwable, message: () -> String) {
|
|
||||||
val writer = StringWriter()
|
|
||||||
PrintWriter(writer).use {
|
|
||||||
t.printStackTrace(it)
|
|
||||||
}
|
|
||||||
println("-- ${message()}:\n$writer")
|
|
||||||
}
|
|
||||||
+2
-13
@@ -23,6 +23,7 @@ import com.intellij.testFramework.runInEdtAndWait
|
|||||||
import com.intellij.util.ui.UIUtil
|
import com.intellij.util.ui.UIUtil
|
||||||
import org.jetbrains.kotlin.idea.parameterInfo.HintType
|
import org.jetbrains.kotlin.idea.parameterInfo.HintType
|
||||||
import org.jetbrains.kotlin.idea.test.runPostStartupActivitiesOnce
|
import org.jetbrains.kotlin.idea.test.runPostStartupActivitiesOnce
|
||||||
|
import org.jetbrains.kotlin.idea.perf.TestApplicationManager
|
||||||
import java.io.PrintWriter
|
import java.io.PrintWriter
|
||||||
import java.io.StringWriter
|
import java.io.StringWriter
|
||||||
|
|
||||||
@@ -69,7 +70,7 @@ fun dispatchAllInvocationEvents() {
|
|||||||
fun loadProjectWithName(path: String, name: String): Project? =
|
fun loadProjectWithName(path: String, name: String): Project? =
|
||||||
ProjectManagerEx.getInstanceEx().loadProject(name, path)
|
ProjectManagerEx.getInstanceEx().loadProject(name, path)
|
||||||
|
|
||||||
fun closeProject(project: Project) {
|
fun TestApplicationManager.closeProject(project: Project) {
|
||||||
dispatchAllInvocationEvents()
|
dispatchAllInvocationEvents()
|
||||||
val projectManagerEx = ProjectManagerEx.getInstanceEx()
|
val projectManagerEx = ProjectManagerEx.getInstanceEx()
|
||||||
projectManagerEx.forceCloseProjectEx(project, true)
|
projectManagerEx.forceCloseProjectEx(project, true)
|
||||||
@@ -104,15 +105,3 @@ fun replaceWithCustomHighlighter(parentDisposable: Disposable, fromImplementatio
|
|||||||
PlatformTestUtil.maskExtensions(pointName, filteredExtensions + listOf(point), parentDisposable)
|
PlatformTestUtil.maskExtensions(pointName, filteredExtensions + listOf(point), parentDisposable)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun logMessage(message: () -> String) {
|
|
||||||
println("-- ${message()}")
|
|
||||||
}
|
|
||||||
|
|
||||||
fun logMessage(t: Throwable, message: () -> String) {
|
|
||||||
val writer = StringWriter()
|
|
||||||
PrintWriter(writer).use {
|
|
||||||
t.printStackTrace(it)
|
|
||||||
}
|
|
||||||
println("-- ${message()}:\n$writer")
|
|
||||||
}
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
|
|
||||||
fun main(args: Array<String>) {
|
|
||||||
println("Hello World!")
|
|
||||||
}
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
|
|
||||||
fun main(args: Array<String>) {
|
|
||||||
println("Hello World!")
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user