Skip to content

Enables utbot-analytics module in utbot-intellij module #733

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 17 commits into from
Aug 24, 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
18,970 changes: 18,970 additions & 0 deletions models/0/nn.json

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions models/0/scaler.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
2.6720630059068036,1.0017657905428634,1.9156327155670845,9.149623402193956,28.647771666093696,3.7526096196518424,10.19303372191143,1.82985123605338,3.1600228146388725,1.5738584867331313,1.435431446698128,1.2643060286901897,1.1452401787667594
1.858559757027421,0.4865249978344985,3.162572904879665,25.21040017953888,34.48252849402906,5.320336536404879,25.362484286622546,3.722723690419032,10.46575141988185,2.489423223957629,1.8889113541845977,1.0913557664615596,0.6525565126200781
2 changes: 1 addition & 1 deletion utbot-analytics/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ test {
jvmArgs '-XX:MaxHeapSize=3072m'

useJUnitPlatform() {
excludeTags 'slow', 'IntegrationTest', 'Summary'
excludeTags 'slow', 'IntegrationTest'
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package org.utbot

import org.utbot.analytics.EngineAnalyticsContext
import org.utbot.features.FeatureExtractorFactoryImpl
import org.utbot.features.FeatureProcessorWithStatesRepetitionFactory
import org.utbot.predictors.StateRewardPredictorFactoryImpl

/**
* The basic configuration of the utbot-analytics module used in utbot-intellij and (as planned) in utbot-cli
* to implement the hidden configuration initialization to avoid direct calls of this configuration and usage of utbot-analytics imports.
*
* @see <a href="https://github.com/UnitTestBot/UTBotJava/issues/725">
* Issue: Enable utbot-analytics module in utbot-intellij module</a>
*/
object AnalyticsConfiguration {
init {
EngineAnalyticsContext.featureProcessorFactory = FeatureProcessorWithStatesRepetitionFactory()
EngineAnalyticsContext.featureExtractorFactory = FeatureExtractorFactoryImpl()
EngineAnalyticsContext.stateRewardPredictorFactory = StateRewardPredictorFactoryImpl()
}
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,11 @@ class FeatureProcessorWithRepetitionTest : UtValueTestCaseChecker(OnePath::class

/**
* Test, that we correctly add test cases and dump them into file
*
* NOTE: works only if the
* ```
* UtSettings.pathSelectorType == PathSelectorType.INHERITORS_SELECTOR
* ```
*/
@Test
fun addTestCaseTest() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,11 @@ object UtSettings {
*/
var rewardModelPath by getStringProperty("../models/0")

/**
* Full class name of the class containing the configuration for the ML models to solve path selection task.
*/
var analyticsConfigurationClassPath by getStringProperty("org.utbot.AnalyticsConfiguration")

/**
* Number of model iterations that will be used during ContestEstimator
*/
Expand Down
2 changes: 1 addition & 1 deletion utbot-intellij/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ dependencies {

implementation(project(":utbot-framework")) { exclude group: 'org.slf4j', module: 'slf4j-api' }
implementation(project(":utbot-fuzzers"))

api project(':utbot-analytics')
testImplementation 'org.mock-server:mockserver-netty:5.4.1'
testImplementation(project(":utbot-sample"))
testApi(project(":utbot-framework"))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,19 +25,25 @@ import com.intellij.testIntegration.TestIntegrationUtils
import com.intellij.util.concurrency.AppExecutorUtil
import mu.KotlinLogging
import org.jetbrains.kotlin.idea.util.module
import org.utbot.analytics.EngineAnalyticsContext
import org.utbot.analytics.Predictors
import org.utbot.common.filterWhen
import org.utbot.engine.util.mockListeners.ForceMockListener
import org.utbot.framework.plugin.services.JdkInfoService
import org.utbot.framework.UtSettings
import org.utbot.framework.plugin.api.TestCaseGenerator
import org.utbot.framework.plugin.api.UtMethod
import org.utbot.framework.plugin.api.UtMethodTestSet
import org.utbot.framework.plugin.api.testFlow
import org.utbot.framework.plugin.api.util.UtContext
import org.utbot.framework.plugin.api.util.withStaticsSubstitutionRequired
import org.utbot.framework.plugin.api.util.withUtContext
import org.utbot.intellij.plugin.generator.CodeGenerationController.generateTests
import org.utbot.intellij.plugin.models.GenerateTestsModel
import org.utbot.intellij.plugin.ui.GenerateTestsDialogWindow
import org.utbot.intellij.plugin.ui.utils.showErrorDialogLater
import org.utbot.intellij.plugin.ui.utils.suitableTestSourceRoots
import org.utbot.intellij.plugin.ui.utils.testModules
import org.utbot.intellij.plugin.util.IntelliJApiHelper
import org.utbot.intellij.plugin.util.PluginJdkInfoProvider
import org.utbot.intellij.plugin.util.signature
Expand All @@ -47,16 +53,14 @@ import java.net.URLClassLoader
import java.nio.file.Path
import java.nio.file.Paths
import java.util.concurrent.TimeUnit
import org.utbot.common.filterWhen
import org.utbot.engine.util.mockListeners.ForceStaticMockListener
import org.utbot.framework.plugin.api.testFlow
import org.utbot.framework.PathSelectorType
import org.utbot.framework.plugin.services.WorkingDirService
import org.utbot.intellij.plugin.settings.Settings
import org.utbot.intellij.plugin.ui.utils.isBuildWithGradle
import org.utbot.intellij.plugin.ui.utils.suitableTestSourceRoots
import org.utbot.intellij.plugin.util.PluginWorkingDirProvider
import org.utbot.intellij.plugin.util.isAbstract
import org.utbot.intellij.plugin.ui.utils.testModules
import kotlin.reflect.KClass
import kotlin.reflect.full.functions

Expand Down Expand Up @@ -112,7 +116,8 @@ object UtTestsDialogProcessor {
.make(
// Compile only chosen classes and their dependencies before generation.
CompositeScope(
model.srcClasses.map{ OneProjectItemCompileScope(project, it.containingFile.virtualFile) }.toTypedArray()
model.srcClasses.map { OneProjectItemCompileScope(project, it.containingFile.virtualFile) }
.toTypedArray()
)
) { aborted: Boolean, errors: Int, _: Int, _: CompileContext ->
if (!aborted && errors == 0) {
Expand Down Expand Up @@ -143,18 +148,23 @@ object UtTestsDialogProcessor {
var processedClasses = 0
val totalClasses = model.srcClasses.size

configureML()

val testCaseGenerator = TestCaseGenerator(
Paths.get(buildDir),
classpath,
pluginJarsPath.joinToString(separator = File.pathSeparator),
isCanceled = { indicator.isCanceled }
)
Paths.get(buildDir),
classpath,
pluginJarsPath.joinToString(separator = File.pathSeparator),
isCanceled = { indicator.isCanceled }
)

for (srcClass in model.srcClasses) {
val methods = ReadAction.nonBlocking<List<UtMethod<*>>> {
val clazz = classLoader.loadClass(srcClass.qualifiedName).kotlin
val srcMethods = model.selectedMethods?.toList() ?:
TestIntegrationUtils.extractClassMethods(srcClass, false)
val srcMethods =
model.selectedMethods?.toList() ?: TestIntegrationUtils.extractClassMethods(
srcClass,
false
)
.filterWhen(UtSettings.skipTestGenerationForSyntheticMethods) {
it.member !is SyntheticElement
}
Expand All @@ -172,14 +182,18 @@ object UtTestsDialogProcessor {

indicator.text = "Generate test cases for class $className"
if (totalClasses > 1) {
indicator.fraction = indicator.fraction.coerceAtLeast(0.9 * processedClasses / totalClasses)
indicator.fraction =
indicator.fraction.coerceAtLeast(0.9 * processedClasses / totalClasses)
}

// set timeout for concrete execution and for generated tests
UtSettings.concreteExecutionTimeoutInChildProcess = model.hangingTestsTimeout.timeoutMs

val searchDirectory = ReadAction
.nonBlocking<Path> { project.basePath?.let { Paths.get(it) } ?: Paths.get(srcClass.containingFile.virtualFile.parent.path) }
val searchDirectory = ReadAction
.nonBlocking<Path> {
project.basePath?.let { Paths.get(it) }
?: Paths.get(srcClass.containingFile.virtualFile.parent.path)
}
.executeSynchronously()

withStaticsSubstitutionRequired(true) {
Expand All @@ -197,17 +211,17 @@ object UtTestsDialogProcessor {
withUtContext(context) {
testCaseGenerator
.generate(
methods,
model.mockStrategy,
model.chosenClassesToMockAlways,
model.timeout,
generate = testFlow {
generationTimeout = model.timeout
isSymbolicEngineEnabled = true
isFuzzingEnabled = UtSettings.useFuzzing
fuzzingValue = project.service<Settings>().fuzzingValue
}
)
methods,
model.mockStrategy,
model.chosenClassesToMockAlways,
model.timeout,
generate = testFlow {
generationTimeout = model.timeout
isSymbolicEngineEnabled = true
isFuzzingEnabled = UtSettings.useFuzzing
fuzzingValue = project.service<Settings>().fuzzingValue
}
)
.map { it.summarize(searchDirectory) }
.filterNot { it.executions.isEmpty() && it.errors.isEmpty() }
}
Expand Down Expand Up @@ -237,7 +251,8 @@ object UtTestsDialogProcessor {
Messages.showInfoMessage(
model.project,
"No methods for test generation were found among selected items",
"No methods found")
"No methods found"
)
}
return
}
Expand All @@ -258,14 +273,47 @@ object UtTestsDialogProcessor {
}
}

/**
* Configures utbot-analytics models for the better path selection.
*
* NOTE: If analytics configuration for the NN Path Selector could not be loaded,
* it switches to the [PathSelectorType.INHERITORS_SELECTOR].
*/
private fun configureML() {
logger.info { "PathSelectorType: ${UtSettings.pathSelectorType}" }

if (UtSettings.pathSelectorType == PathSelectorType.NN_REWARD_GUIDED_SELECTOR) {
val analyticsConfigurationClassPath = UtSettings.analyticsConfigurationClassPath
try {
Class.forName(analyticsConfigurationClassPath)
Predictors.stateRewardPredictor = EngineAnalyticsContext.stateRewardPredictorFactory()

logger.info { "RewardModelPath: ${UtSettings.rewardModelPath}" }
} catch (e: ClassNotFoundException) {
logger.error {
"Configuration of the predictors from the utbot-analytics module described in the class: " +
"$analyticsConfigurationClassPath is not found!"
}

logger.info(e) {
"Error while initialization of ${UtSettings.pathSelectorType}. Changing pathSelectorType on INHERITORS_SELECTOR"
}
UtSettings.pathSelectorType = PathSelectorType.INHERITORS_SELECTOR
}
}
}

private fun errorMessage(className: String?, timeout: Long) = buildString {
appendLine("UtBot failed to generate any test cases for class $className.")
appendLine()
appendLine("Try to alter test generation configuration, e.g. enable mocking and static mocking.")
appendLine("Alternatively, you could try to increase current timeout $timeout sec for generating tests in generation dialog.")
}

private fun findMethodsInClassMatchingSelected(clazz: KClass<*>, selectedMethods: List<MemberInfo>): List<UtMethod<*>> {
private fun findMethodsInClassMatchingSelected(
clazz: KClass<*>,
selectedMethods: List<MemberInfo>
): List<UtMethod<*>> {
val selectedSignatures = selectedMethods.map { it.signature() }
return clazz.functions
.sortedWith(compareBy { selectedSignatures.indexOf(it.signature()) })
Expand Down