Skip to content

Improve test generation cancellation #1458

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Dec 6, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -500,6 +500,11 @@ object UtSettings : AbstractSettings(logger, defaultKeyForSettingsPath, defaultS
* It is used to do not encode big type storages due to significand performance degradation.
*/
var maxNumberOfTypesToEncode by getIntProperty(512)

/**
* The behaviour of further analysis if tests generation cancellation is requested.
*/
var cancellationStrategyType by getEnumProperty(CancellationStrategyType.SAVE_PROCESSED_RESULTS)
}

/**
Expand Down Expand Up @@ -564,6 +569,26 @@ enum class TestSelectionStrategyType {
COVERAGE_STRATEGY
}

/**
* Describes the behaviour if test generation is canceled.
*/
enum class CancellationStrategyType {
/**
* Do not react on cancellation
*/
NONE,

/**
* Clear all generated test classes
*/
CANCEL_EVERYTHING,

/**
* Show already processed test classes
*/
SAVE_PROCESSED_RESULTS
}

/**
* Enum to specify [MLSelector], see implementations for more details
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import com.intellij.ide.fileTemplates.FileTemplateUtil
import com.intellij.ide.fileTemplates.JavaTemplateUtil
import com.intellij.ide.highlighter.JavaFileType
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.application.readAction
import com.intellij.openapi.application.runReadAction
import com.intellij.openapi.application.runWriteAction
import com.intellij.openapi.command.WriteCommandAction.runWriteCommandAction
Expand Down Expand Up @@ -42,18 +41,13 @@ import com.intellij.psi.codeStyle.JavaCodeStyleManager.DO_NOT_ADD_IMPORTS
import com.intellij.psi.search.GlobalSearchScopesCore
import com.intellij.testIntegration.TestIntegrationUtils
import com.siyeh.ig.psiutils.ImportUtils
import java.nio.file.Path
import java.util.concurrent.CancellationException
import java.util.concurrent.CountDownLatch
import java.util.concurrent.TimeUnit
import mu.KotlinLogging
import org.jetbrains.kotlin.asJava.classes.KtUltraLightClass
import org.jetbrains.kotlin.idea.KotlinFileType
import org.jetbrains.kotlin.idea.core.ShortenReferences
import org.jetbrains.kotlin.idea.core.getPackage
import org.jetbrains.kotlin.idea.core.util.toPsiDirectory
import org.jetbrains.kotlin.idea.util.ImportInsertHelperImpl
import org.jetbrains.kotlin.idea.util.projectStructure.allModules
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.KtClass
import org.jetbrains.kotlin.psi.KtNamedFunction
Expand All @@ -64,6 +58,9 @@ import org.jetbrains.kotlin.psi.psiUtil.startOffset
import org.utbot.common.FileUtil
import org.utbot.common.HTML_LINE_SEPARATOR
import org.utbot.common.PathUtil.toHtmlLinkTag
import org.utbot.framework.CancellationStrategyType.CANCEL_EVERYTHING
import org.utbot.framework.CancellationStrategyType.NONE
import org.utbot.framework.CancellationStrategyType.SAVE_PROCESSED_RESULTS
import org.utbot.framework.UtSettings
import org.utbot.framework.codegen.domain.Import
import org.utbot.framework.codegen.domain.ParametrizedTestSource
Expand Down Expand Up @@ -98,6 +95,10 @@ import org.utbot.intellij.plugin.util.assertIsWriteThread
import org.utbot.intellij.plugin.util.extractClassMethodsIncludingNested
import org.utbot.sarif.Sarif
import org.utbot.sarif.SarifReport
import java.nio.file.Path
import java.util.concurrent.CancellationException
import java.util.concurrent.CountDownLatch
import java.util.concurrent.TimeUnit

object CodeGenerationController {
private val logger = KotlinLogging.logger {}
Expand All @@ -114,7 +115,7 @@ object CodeGenerationController {
model: GenerateTestsModel,
classesWithTests: Map<PsiClass, RdTestGenerationResult>,
psi2KClass: Map<PsiClass, ClassId>,
proccess: EngineProcess,
process: EngineProcess,
indicator: ProgressIndicator
) {
assertIsDispatchThread()
Expand All @@ -127,7 +128,14 @@ object CodeGenerationController {
val utilClassListener = UtilClassListener()
var index = 0
for ((srcClass, generateResult) in classesWithTests) {
if (indicator.isCanceled) return
if (indicator.isCanceled) {
when (UtSettings.cancellationStrategyType) {
NONE,
SAVE_PROCESSED_RESULTS -> {}
CANCEL_EVERYTHING -> break
}
}

val (count, testSetsId) = generateResult
if (count <= 0) {
latch.countDown()
Expand All @@ -143,7 +151,7 @@ object CodeGenerationController {
val cut = psi2KClass[srcClass] ?: error("Didn't find KClass instance for class ${srcClass.name}")
runWriteCommandAction(model.project, "Generate tests with UtBot", null, {
generateCodeAndReport(
proccess,
process,
testSetsId,
srcClass,
cut,
Expand All @@ -170,9 +178,9 @@ object CodeGenerationController {
waitForCountDown(latch, indicator = indicator) {
run(EDT_LATER, indicator,"Go to EDT for utility class creation") {
run(WRITE_ACTION, indicator, "Need write action for utility class creation") {
createUtilityClassIfNeed(utilClassListener, model, baseTestDirectory, indicator)
createUtilityClassIfNeeded(utilClassListener, model, baseTestDirectory, indicator)
run(THREAD_POOL, indicator, "Generate summary Sarif report") {
proceedTestReport(proccess, model)
proceedTestReport(process, model)
val sarifReportsPath =
model.testModule.getOrCreateSarifReportsPath(model.testSourceRoot)
UtTestsDialogProcessor.updateIndicator(indicator, UtTestsDialogProcessor.ProgressRange.SARIF, "Merge Sarif reports", 0.75)
Expand All @@ -181,7 +189,7 @@ object CodeGenerationController {
UtTestsDialogProcessor.updateIndicator(indicator, UtTestsDialogProcessor.ProgressRange.SARIF, "Start tests with coverage", 0.95)
RunConfigurationHelper.runTestsWithCoverage(model, testFilesPointers)
}
proccess.terminate()
process.terminate()
UtTestsDialogProcessor.updateIndicator(indicator, UtTestsDialogProcessor.ProgressRange.SARIF, "Generation finished", 1.0)

run(EDT_LATER, null, "Run sarif-based inspections") {
Expand Down Expand Up @@ -232,7 +240,7 @@ object CodeGenerationController {
)
}
}
private fun createUtilityClassIfNeed(
private fun createUtilityClassIfNeeded(
utilClassListener: UtilClassListener,
model: GenerateTestsModel,
baseTestDirectory: PsiDirectory,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,13 @@ import com.intellij.util.containers.nullize
import com.intellij.util.io.exists
import mu.KotlinLogging
import org.jetbrains.kotlin.idea.util.module
import org.utbot.framework.CancellationStrategyType.CANCEL_EVERYTHING
import org.utbot.framework.CancellationStrategyType.NONE
import org.utbot.framework.CancellationStrategyType.SAVE_PROCESSED_RESULTS
import org.utbot.framework.UtSettings
import org.utbot.framework.plugin.api.ClassId
import org.utbot.framework.plugin.api.JavaDocCommentStyle
import org.utbot.framework.plugin.api.util.LockFile
import org.utbot.framework.plugin.api.util.withStaticsSubstitutionRequired
import org.utbot.framework.plugin.services.JdkInfoService
import org.utbot.framework.plugin.services.WorkingDirService
Expand All @@ -37,17 +41,20 @@ import org.utbot.intellij.plugin.process.EngineProcess
import org.utbot.intellij.plugin.process.RdTestGenerationResult
import org.utbot.intellij.plugin.settings.Settings
import org.utbot.intellij.plugin.ui.GenerateTestsDialogWindow
import org.utbot.intellij.plugin.ui.utils.isBuildWithGradle
import org.utbot.intellij.plugin.ui.utils.showErrorDialogLater
import org.utbot.intellij.plugin.ui.utils.testModules
import org.utbot.intellij.plugin.util.*
import org.utbot.intellij.plugin.util.IntelliJApiHelper
import org.utbot.intellij.plugin.util.PluginJdkInfoProvider
import org.utbot.intellij.plugin.util.PluginWorkingDirProvider
import org.utbot.intellij.plugin.util.assertIsNonDispatchThread
import org.utbot.intellij.plugin.util.extractClassMethodsIncludingNested
import org.utbot.rd.terminateOnException
import java.io.File
import java.nio.file.Path
import java.nio.file.Paths
import java.util.concurrent.TimeUnit
import kotlin.io.path.pathString
import org.utbot.framework.plugin.api.util.LockFile
import org.utbot.intellij.plugin.ui.utils.isBuildWithGradle
import org.utbot.rd.terminateOnException
import java.time.LocalDateTime
import java.time.format.DateTimeFormatter

Expand Down Expand Up @@ -176,6 +183,14 @@ object UtTestsDialogProcessor {


for (srcClass in model.srcClasses) {
if (indicator.isCanceled) {
when (UtSettings.cancellationStrategyType) {
NONE -> {}
SAVE_PROCESSED_RESULTS,
CANCEL_EVERYTHING -> break
}
}

val (methods, className) = DumbService.getInstance(project)
.runReadActionInSmartMode(Computable {
val canonicalName = srcClass.canonicalName
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ import com.intellij.util.PlatformUtils
import com.intellij.util.ReflectionUtil
import com.intellij.util.concurrency.AppExecutorUtil
import mu.KotlinLogging
import org.jetbrains.kotlin.idea.util.application.invokeLater
import org.utbot.framework.CancellationStrategyType.*
import org.utbot.framework.UtSettings

/**
* This object is required to encapsulate Android API usage and grant safe access to it.
Expand All @@ -24,10 +25,18 @@ object IntelliJApiHelper {
fun run(target: Target, indicator: ProgressIndicator? = null, logMessage : String, runnable: Runnable) {
logger.info { "[${target}]: " + logMessage +
if (indicator != null) ", indicator[${indicator.text}; ${(indicator.fraction * 100).toInt()}%]" else "" }
if (indicator != null && indicator.isCanceled) {
logger.error { "Indicator is already cancelled" }
return

if (indicator?.isCanceled == true) {
when (UtSettings.cancellationStrategyType) {
NONE,
SAVE_PROCESSED_RESULTS -> {}
CANCEL_EVERYTHING -> {
logger.info { "Indicator is already cancelled" }
return
}
}
}

val wrapper = Runnable {
try {
runnable.run()
Expand Down