Skip to content

Transfer Spring application data from dialog processor to Engine #1816

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 6 commits into from
Feb 17, 2023
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 @@ -55,6 +55,7 @@ import java.io.File
import kotlin.contracts.ExperimentalContracts
import kotlin.contracts.contract
import org.utbot.common.isAbstract
import org.utbot.framework.plugin.api.util.utContext

const val SYMBOLIC_NULL_ADDR: Int = 0

Expand Down Expand Up @@ -1147,6 +1148,25 @@ open class TypeParameters(val parameters: List<ClassId> = emptyList())

class WildcardTypeParameter : TypeParameters(emptyList())

/**
* Additional data describing user project.
*/
interface ApplicationContext

/**
* Data we get from Spring application context
* to manage engine and code generator behaviour.
*
* @param beanQualifiedNames describes fqn of injected classes
*/
data class SpringApplicationContext(
val beanQualifiedNames: List<String> = emptyList(),
): ApplicationContext {
private val springInjectedClasses: List<ClassId> by lazy {
beanQualifiedNames.map { fqn -> utContext.classLoader.loadClass(fqn).id }
}
}

interface CodeGenerationSettingItem {
val id: String
val displayName: String
Expand Down
5 changes: 5 additions & 0 deletions utbot-framework/src/main/kotlin/org/utbot/engine/Traverser.kt
Original file line number Diff line number Diff line change
Expand Up @@ -116,10 +116,12 @@ import org.utbot.framework.UtSettings
import org.utbot.framework.UtSettings.maximizeCoverageUsingReflection
import org.utbot.framework.UtSettings.preferredCexOption
import org.utbot.framework.UtSettings.substituteStaticsWithSymbolicVariable
import org.utbot.framework.plugin.api.ApplicationContext
import org.utbot.framework.plugin.api.ClassId
import org.utbot.framework.plugin.api.ExecutableId
import org.utbot.framework.plugin.api.FieldId
import org.utbot.framework.plugin.api.MethodId
import org.utbot.framework.plugin.api.SpringApplicationContext
import org.utbot.framework.plugin.api.classId
import org.utbot.framework.plugin.api.id
import org.utbot.framework.plugin.api.util.executable
Expand Down Expand Up @@ -237,6 +239,7 @@ class Traverser(
internal val typeResolver: TypeResolver,
private val globalGraph: InterProceduralUnitGraph,
private val mocker: Mocker,
private val applicationContext: ApplicationContext?,
) : UtContextInitializer() {

private val visitedStmts: MutableSet<Stmt> = mutableSetOf()
Expand Down Expand Up @@ -273,6 +276,8 @@ class Traverser(

internal val objectCounter = ObjectCounter(TypeRegistry.objectCounterInitialValue)



private fun findNewAddr(insideStaticInitializer: Boolean): UtAddrExpression {
val newAddr = objectCounter.createNewAddr()
// return negative address for objects created inside static initializer
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ class UtBotSymbolicEngine(
dependencyPaths: String,
val mockStrategy: MockStrategy = NO_MOCKS,
chosenClassesToMockAlways: Set<ClassId>,
applicationContext: ApplicationContext?,
private val solverTimeoutInMillis: Int = checkSolverTimeoutMillis
) : UtContextInitializer() {
private val graph = methodUnderTest.sootMethod.jimpleBody().apply {
Expand Down Expand Up @@ -144,6 +145,7 @@ class UtBotSymbolicEngine(
typeResolver,
globalGraph,
mocker,
applicationContext,
)

//HACK (long strings)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ open class TestCaseGenerator(
val engineActions: MutableList<(UtBotSymbolicEngine) -> Unit> = mutableListOf(),
val isCanceled: () -> Boolean = { false },
val forceSootReload: Boolean = true,
val applicationContext: ApplicationContext? = null,
) {
private val logger: KLogger = KotlinLogging.logger {}
private val timeoutLogger: KLogger = KotlinLogging.logger(logger.name + ".timeout")
Expand Down Expand Up @@ -112,7 +113,14 @@ open class TestCaseGenerator(
executionTimeEstimator: ExecutionTimeEstimator = ExecutionTimeEstimator(utBotGenerationTimeoutInMillis, 1)
): Flow<UtResult> {
try {
val engine = createSymbolicEngine(controller, method, mockStrategy, chosenClassesToMockAlways, executionTimeEstimator)
val engine = createSymbolicEngine(
controller,
method,
mockStrategy,
chosenClassesToMockAlways,
applicationContext = null,
executionTimeEstimator,
)
engineActions.map { engine.apply(it) }
engineActions.clear()
return defaultTestFlow(engine, executionTimeEstimator.userTimeout)
Expand Down Expand Up @@ -159,6 +167,7 @@ open class TestCaseGenerator(
method,
mockStrategy,
chosenClassesToMockAlways,
applicationContext,
executionTimeEstimator
)

Expand Down Expand Up @@ -248,6 +257,7 @@ open class TestCaseGenerator(
method: ExecutableId,
mockStrategyApi: MockStrategyApi,
chosenClassesToMockAlways: Set<ClassId>,
applicationContext: ApplicationContext?,
executionTimeEstimator: ExecutionTimeEstimator
): UtBotSymbolicEngine {
logger.debug("Starting symbolic execution for $method --$mockStrategyApi--")
Expand All @@ -258,6 +268,7 @@ open class TestCaseGenerator(
dependencyPaths = dependencyPaths,
mockStrategy = mockStrategyApi.toModel(),
chosenClassesToMockAlways = chosenClassesToMockAlways,
applicationContext = applicationContext,
solverTimeoutInMillis = executionTimeEstimator.updatedSolverCheckTimeoutMillis
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,16 @@ fun defaultTestFlow(timeout: Long) = testFlow {
}
}

/**
* Creates default flow for Spring application.
*/
fun defaultSpringFlow(timeout: Long) = testFlow {
isSymbolicEngineEnabled = true
generationTimeout = timeout
isFuzzingEnabled = false
fuzzingValue = 0.0
}

/**
* Creates default flow that uses [UtSettings] for customization.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,10 +83,13 @@ private fun EngineProcessModel.setup(kryoHelper: KryoHelper, watchdog: IdleWatch
watchdog.measureTimeForActiveCall(createTestGenerator, "Creating Test Generator") { params ->
AnalyticsConfigureUtil.configureML()
Instrumenter.adapter = RdInstrumenter(realProtocol.rdInstrumenterAdapter)
val applicationContext: ApplicationContext = kryoHelper.readObject(params.applicationContext)

testGenerator = TestCaseGenerator(buildDirs = params.buildDir.map { Paths.get(it) },
classpath = params.classpath,
dependencyPaths = params.dependencyPaths,
jdkInfo = JdkInfo(Paths.get(params.jdkInfo.path), params.jdkInfo.version),
applicationContext = applicationContext,
isCanceled = {
runBlocking {
model.isCancelled.startSuspending(Unit)
Expand All @@ -105,16 +108,24 @@ private fun EngineProcessModel.setup(kryoHelper: KryoHelper, watchdog: IdleWatch
if (!staticsMockingConfigured) {
ForceStaticMockListener.create(testGenerator, conflictTriggers, cancelJob = true)
}
val result = testGenerator.generate(methods,
MockStrategyApi.valueOf(params.mockStrategy),
kryoHelper.readObject(params.chosenClassesToMockAlways),
params.timeout,
generate = testFlow {

val generateFlow = when (testGenerator.applicationContext) {
is SpringApplicationContext -> defaultSpringFlow(params.generationTimeout)
else -> testFlow {
generationTimeout = params.generationTimeout
isSymbolicEngineEnabled = params.isSymbolicEngineEnabled
isFuzzingEnabled = params.isFuzzingEnabled
fuzzingValue = params.fuzzingValue
})
}
}

val result = testGenerator.generate(
methods,
MockStrategyApi.valueOf(params.mockStrategy),
kryoHelper.readObject(params.chosenClassesToMockAlways),
params.timeout,
generate = generateFlow,
)
.summarizeAll(Paths.get(params.searchDirectory), null)
.filterNot { it.executions.isEmpty() && it.errors.isEmpty() }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ class EngineProcessModel private constructor(
}


const val serializationHash = 5025678608993948804L
const val serializationHash = -4839464828913070560L

}
override val serializersOwner: ISerializersOwner get() = EngineProcessModel
Expand Down Expand Up @@ -173,7 +173,7 @@ val IProtocol.engineProcessModel get() = getOrCreateExtension(EngineProcessModel


/**
* #### Generated from [EngineProcessModel.kt:101]
* #### Generated from [EngineProcessModel.kt:102]
*/
data class FindMethodParamNamesArguments (
val classId: ByteArray,
Expand Down Expand Up @@ -236,7 +236,7 @@ data class FindMethodParamNamesArguments (


/**
* #### Generated from [EngineProcessModel.kt:105]
* #### Generated from [EngineProcessModel.kt:106]
*/
data class FindMethodParamNamesResult (
val paramNames: ByteArray
Expand Down Expand Up @@ -293,7 +293,7 @@ data class FindMethodParamNamesResult (


/**
* #### Generated from [EngineProcessModel.kt:94]
* #### Generated from [EngineProcessModel.kt:95]
*/
data class FindMethodsInClassMatchingSelectedArguments (
val classId: ByteArray,
Expand Down Expand Up @@ -356,7 +356,7 @@ data class FindMethodsInClassMatchingSelectedArguments (


/**
* #### Generated from [EngineProcessModel.kt:98]
* #### Generated from [EngineProcessModel.kt:99]
*/
data class FindMethodsInClassMatchingSelectedResult (
val executableIds: ByteArray
Expand Down Expand Up @@ -413,7 +413,7 @@ data class FindMethodsInClassMatchingSelectedResult (


/**
* #### Generated from [EngineProcessModel.kt:43]
* #### Generated from [EngineProcessModel.kt:44]
*/
data class GenerateParams (
val mockInstalled: Boolean,
Expand Down Expand Up @@ -536,7 +536,7 @@ data class GenerateParams (


/**
* #### Generated from [EngineProcessModel.kt:61]
* #### Generated from [EngineProcessModel.kt:62]
*/
data class GenerateResult (
val notEmptyCases: Int,
Expand Down Expand Up @@ -599,7 +599,7 @@ data class GenerateResult (


/**
* #### Generated from [EngineProcessModel.kt:113]
* #### Generated from [EngineProcessModel.kt:114]
*/
data class GenerateTestReportArgs (
val eventLogMessage: String?,
Expand Down Expand Up @@ -692,7 +692,7 @@ data class GenerateTestReportArgs (


/**
* #### Generated from [EngineProcessModel.kt:122]
* #### Generated from [EngineProcessModel.kt:123]
*/
data class GenerateTestReportResult (
val notifyMessage: String,
Expand Down Expand Up @@ -824,7 +824,7 @@ data class JdkInfo (


/**
* #### Generated from [EngineProcessModel.kt:89]
* #### Generated from [EngineProcessModel.kt:90]
*/
data class MethodDescription (
val name: String,
Expand Down Expand Up @@ -893,7 +893,7 @@ data class MethodDescription (


/**
* #### Generated from [EngineProcessModel.kt:65]
* #### Generated from [EngineProcessModel.kt:66]
*/
data class RenderParams (
val testSetsId: Long,
Expand Down Expand Up @@ -1034,7 +1034,7 @@ data class RenderParams (


/**
* #### Generated from [EngineProcessModel.kt:82]
* #### Generated from [EngineProcessModel.kt:83]
*/
data class RenderResult (
val generatedCode: String,
Expand Down Expand Up @@ -1097,7 +1097,7 @@ data class RenderResult (


/**
* #### Generated from [EngineProcessModel.kt:86]
* #### Generated from [EngineProcessModel.kt:87]
*/
data class SetupContextParams (
val classpathForUrlsClassloader: List<String>
Expand Down Expand Up @@ -1160,7 +1160,8 @@ data class TestGeneratorParams (
val buildDir: Array<String>,
val classpath: String?,
val dependencyPaths: String,
val jdkInfo: JdkInfo
val jdkInfo: JdkInfo,
val applicationContext: ByteArray
) : IPrintable {
//companion

Expand All @@ -1173,14 +1174,16 @@ data class TestGeneratorParams (
val classpath = buffer.readNullable { buffer.readString() }
val dependencyPaths = buffer.readString()
val jdkInfo = JdkInfo.read(ctx, buffer)
return TestGeneratorParams(buildDir, classpath, dependencyPaths, jdkInfo)
val applicationContext = buffer.readByteArray()
return TestGeneratorParams(buildDir, classpath, dependencyPaths, jdkInfo, applicationContext)
}

override fun write(ctx: SerializationCtx, buffer: AbstractBuffer, value: TestGeneratorParams) {
buffer.writeArray(value.buildDir) { buffer.writeString(it) }
buffer.writeNullable(value.classpath) { buffer.writeString(it) }
buffer.writeString(value.dependencyPaths)
JdkInfo.write(ctx, buffer, value.jdkInfo)
buffer.writeByteArray(value.applicationContext)
}


Expand All @@ -1200,6 +1203,7 @@ data class TestGeneratorParams (
if (classpath != other.classpath) return false
if (dependencyPaths != other.dependencyPaths) return false
if (jdkInfo != other.jdkInfo) return false
if (!(applicationContext contentEquals other.applicationContext)) return false

return true
}
Expand All @@ -1210,6 +1214,7 @@ data class TestGeneratorParams (
__r = __r*31 + if (classpath != null) classpath.hashCode() else 0
__r = __r*31 + dependencyPaths.hashCode()
__r = __r*31 + jdkInfo.hashCode()
__r = __r*31 + applicationContext.contentHashCode()
return __r
}
//pretty print
Expand All @@ -1220,6 +1225,7 @@ data class TestGeneratorParams (
print("classpath = "); classpath.print(printer); println()
print("dependencyPaths = "); dependencyPaths.print(printer); println()
print("jdkInfo = "); jdkInfo.print(printer); println()
print("applicationContext = "); applicationContext.print(printer); println()
}
printer.print(")")
}
Expand All @@ -1229,7 +1235,7 @@ data class TestGeneratorParams (


/**
* #### Generated from [EngineProcessModel.kt:108]
* #### Generated from [EngineProcessModel.kt:109]
*/
data class WriteSarifReportArguments (
val testSetsId: Long,
Expand Down
Loading