Skip to content

Commit 19cb36d

Browse files
committed
Revert "Refactor ConcreteExecutionContext interface, to avoid whens by ApplicationContext type"
This reverts commit 5672783.
1 parent 5672783 commit 19cb36d

File tree

15 files changed

+245
-357
lines changed

15 files changed

+245
-357
lines changed

utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/api/Api.kt

Lines changed: 6 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1319,7 +1319,7 @@ interface CodeGenerationContext
13191319
interface SpringCodeGenerationContext : CodeGenerationContext {
13201320
val springTestType: SpringTestType
13211321
val springSettings: SpringSettings
1322-
val concreteContextLoadingResult: ConcreteContextLoadingResult?
1322+
val springContextLoadingResult: SpringContextLoadingResult?
13231323
}
13241324

13251325
sealed class SpringConfiguration(val fullDisplayName: String) {
@@ -1345,35 +1345,14 @@ sealed interface SpringSettings {
13451345
}
13461346

13471347
/**
1348-
* Result of loading concrete execution context (e.g. Spring application context).
1349-
*
1350-
* [contextLoaded] can be `true` while [exceptions] is not empty. For example, we may fail
1351-
* to load context with most specific SpringApi available (e.g. SpringBoot),
1352-
* but successfully fall back to less specific SpringApi (e.g. PureSpring).
1348+
* [contextLoaded] can be `true` while [exceptions] is not empty,
1349+
* if we failed to use most specific SpringApi available (e.g. SpringBoot), but
1350+
* were able to successfully fall back to less specific SpringApi (e.g. PureSpring).
13531351
*/
1354-
class ConcreteContextLoadingResult(
1352+
class SpringContextLoadingResult(
13551353
val contextLoaded: Boolean,
13561354
val exceptions: List<Throwable>
1357-
) {
1358-
val utErrors: List<UtError> get() =
1359-
exceptions.map { UtError(it.message ?: "Concrete context loading failed", it) }
1360-
1361-
fun andThen(onSuccess: () -> ConcreteContextLoadingResult) =
1362-
if (contextLoaded) {
1363-
val otherResult = onSuccess()
1364-
ConcreteContextLoadingResult(
1365-
contextLoaded = otherResult.contextLoaded,
1366-
exceptions = exceptions + otherResult.exceptions
1367-
)
1368-
} else this
1369-
1370-
companion object {
1371-
fun successWithoutExceptions() = ConcreteContextLoadingResult(
1372-
contextLoaded = true,
1373-
exceptions = emptyList()
1374-
)
1375-
}
1376-
}
1355+
)
13771356

13781357
enum class SpringTestType(
13791358
override val id: String,

utbot-framework/src/main/kotlin/org/utbot/engine/UtBotSymbolicEngine.kt

Lines changed: 58 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import org.utbot.analytics.Predictors
1010
import org.utbot.api.exception.UtMockAssumptionViolatedException
1111
import org.utbot.common.debug
1212
import org.utbot.common.measureTime
13+
import org.utbot.common.tryLoadClass
1314
import org.utbot.engine.MockStrategy.NO_MOCKS
1415
import org.utbot.engine.pc.*
1516
import org.utbot.engine.selectors.*
@@ -33,7 +34,7 @@ import org.utbot.framework.UtSettings.pathSelectorType
3334
import org.utbot.framework.UtSettings.processUnknownStatesDuringConcreteExecution
3435
import org.utbot.framework.UtSettings.useDebugVisualization
3536
import org.utbot.framework.context.ApplicationContext
36-
import org.utbot.framework.context.ConcreteExecutionContext
37+
import org.utbot.framework.context.spring.SpringApplicationContext
3738
import org.utbot.framework.plugin.api.*
3839
import org.utbot.framework.plugin.api.Step
3940
import org.utbot.framework.plugin.api.util.*
@@ -43,11 +44,17 @@ import org.utbot.framework.util.graph
4344
import org.utbot.framework.util.sootMethod
4445
import org.utbot.fuzzer.*
4546
import org.utbot.fuzzing.*
47+
import org.utbot.fuzzing.providers.FieldValueProvider
48+
import org.utbot.fuzzing.providers.ObjectValueProvider
49+
import org.utbot.fuzzing.spring.SavedEntityValueProvider
50+
import org.utbot.fuzzing.spring.SpringBeanValueProvider
4651
import org.utbot.fuzzing.utils.Trie
4752
import org.utbot.instrumentation.ConcreteExecutor
53+
import org.utbot.instrumentation.getRelevantSpringRepositories
4854
import org.utbot.instrumentation.instrumentation.Instrumentation
4955
import org.utbot.instrumentation.instrumentation.execution.UtConcreteExecutionData
5056
import org.utbot.instrumentation.instrumentation.execution.UtConcreteExecutionResult
57+
import org.utbot.instrumentation.instrumentation.execution.UtExecutionInstrumentation
5158
import org.utbot.taint.*
5259
import org.utbot.taint.model.TaintConfiguration
5360
import soot.jimple.Stmt
@@ -111,7 +118,7 @@ class UtBotSymbolicEngine(
111118
val mockStrategy: MockStrategy = NO_MOCKS,
112119
chosenClassesToMockAlways: Set<ClassId>,
113120
val applicationContext: ApplicationContext,
114-
val concreteExecutionContext: ConcreteExecutionContext,
121+
executionInstrumentationFactory: UtExecutionInstrumentation.Factory<*>,
115122
userTaintConfigurationProvider: TaintConfigurationProvider? = null,
116123
private val solverTimeoutInMillis: Int = checkSolverTimeoutMillis,
117124
) : UtContextInitializer() {
@@ -184,7 +191,7 @@ class UtBotSymbolicEngine(
184191

185192
private val concreteExecutor =
186193
ConcreteExecutor(
187-
concreteExecutionContext.instrumentationFactory,
194+
executionInstrumentationFactory,
188195
classpath,
189196
).apply { this.classLoader = utContext.classLoader }
190197

@@ -386,15 +393,57 @@ class UtBotSymbolicEngine(
386393
val names = graph.body.method.tags.filterIsInstance<ParamNamesTag>().firstOrNull()?.names ?: emptyList()
387394
var testEmittedByFuzzer = 0
388395

389-
val valueProviders = try {
390-
concreteExecutionContext.tryCreateValueProvider(concreteExecutor, classUnderTest, defaultIdGenerator)
391-
} catch (e: Exception) {
392-
emit(UtError(e.message ?: "Failed to create ValueProvider", e))
396+
if (applicationContext is SpringApplicationContext &&
397+
applicationContext.springTestType == SpringTestType.INTEGRATION_TEST &&
398+
applicationContext.getBeansAssignableTo(methodUnderTest.classId).isEmpty()) {
399+
val fullConfigDisplayName = (applicationContext.springSettings as? SpringSettings.PresentSpringSettings)
400+
?.configuration?.fullDisplayName
401+
val errorDescription = "No beans of type ${methodUnderTest.classId.name} are found. " +
402+
"Try choosing different Spring configuration or adding beans to $fullConfigDisplayName"
403+
emit(UtError(
404+
errorDescription,
405+
IllegalStateException(errorDescription)
406+
))
393407
return@flow
394-
}.let(transform)
408+
}
395409

396-
val coverageToMinStateBeforeSize = mutableMapOf<Trie.Node<Instruction>, Int>()
410+
val valueProviders = ValueProvider.of(defaultValueProviders(defaultIdGenerator))
411+
.letIf(applicationContext is SpringApplicationContext
412+
&& applicationContext.springTestType == SpringTestType.INTEGRATION_TEST
413+
) { provider ->
414+
val relevantRepositories = concreteExecutor.getRelevantSpringRepositories(methodUnderTest.classId)
415+
logger.info { "Detected relevant repositories for class ${methodUnderTest.classId}: $relevantRepositories" }
397416

417+
val generatedValueAnnotationClasses = SpringModelUtils.generatedValueClassIds.mapNotNull {
418+
@Suppress("UNCHECKED_CAST") // type system fails to understand that GeneratedValue is indeed an annotation
419+
utContext.classLoader.tryLoadClass(it.name) as Class<out Annotation>?
420+
}
421+
422+
val generatedValueFieldIds =
423+
relevantRepositories
424+
.map { it.entityClassId.jClass }
425+
.flatMap { entityClass -> generateSequence(entityClass) { it.superclass } }
426+
.flatMap { it.declaredFields.toList() }
427+
.filter { field -> generatedValueAnnotationClasses.any { field.isAnnotationPresent(it) } }
428+
.map { it.fieldId }
429+
logger.info { "Detected @GeneratedValue fields: $generatedValueFieldIds" }
430+
431+
// spring should try to generate bean values, but if it fails, then object value provider is used for it
432+
val springBeanValueProvider = SpringBeanValueProvider(
433+
defaultIdGenerator,
434+
beanNameProvider = { classId ->
435+
(applicationContext as SpringApplicationContext).getBeansAssignableTo(classId)
436+
.map { it.beanName }
437+
},
438+
relevantRepositories = relevantRepositories
439+
).withFallback(ObjectValueProvider(defaultIdGenerator))
440+
provider
441+
.except { p -> p is ObjectValueProvider }
442+
.with(springBeanValueProvider)
443+
.with(ValueProvider.of(relevantRepositories.map { SavedEntityValueProvider(defaultIdGenerator, it) }))
444+
.with(ValueProvider.of(generatedValueFieldIds.map { FieldValueProvider(defaultIdGenerator, it) }))
445+
}.let(transform)
446+
val coverageToMinStateBeforeSize = mutableMapOf<Trie.Node<Instruction>, Int>()
398447
runJavaFuzzing(
399448
defaultIdGenerator,
400449
methodUnderTest,

utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/CgSpringIntegrationTestClassConstructor.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ class CgSpringIntegrationTestClassConstructor(
5858
)
5959

6060
private fun constructContextLoadsMethod() : CgTestMethod {
61-
val contextLoadingResult = springCodeGenerationContext.concreteContextLoadingResult
61+
val contextLoadingResult = springCodeGenerationContext.springContextLoadingResult
6262
if (contextLoadingResult == null)
6363
logger.error { "Missing contextLoadingResult" }
6464
val exception = contextLoadingResult?.exceptions?.firstOrNull()
Lines changed: 8 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,15 @@
11
package org.utbot.framework.context
22

3-
import org.utbot.framework.plugin.api.ClassId
4-
import org.utbot.framework.plugin.api.ConcreteContextLoadingResult
5-
import org.utbot.framework.plugin.api.UtExecution
6-
import org.utbot.fuzzer.IdentityPreservingIdGenerator
7-
import org.utbot.fuzzing.JavaValueProvider
8-
import org.utbot.instrumentation.ConcreteExecutor
9-
import org.utbot.instrumentation.instrumentation.execution.UtConcreteExecutionResult
10-
import org.utbot.instrumentation.instrumentation.execution.UtExecutionInstrumentation
3+
import org.utbot.framework.plugin.api.UtError
114

125
interface ConcreteExecutionContext {
13-
val instrumentationFactory: UtExecutionInstrumentation.Factory<*>
6+
fun preventsFurtherTestGeneration(): Boolean
147

15-
fun loadContext(
16-
concreteExecutor: ConcreteExecutor<UtConcreteExecutionResult, UtExecutionInstrumentation>,
17-
): ConcreteContextLoadingResult
8+
fun getErrors(): List<UtError>
189

19-
fun transformExecutionsBeforeMinimization(
20-
executions: List<UtExecution>,
21-
classUnderTestId: ClassId
22-
): List<UtExecution>
23-
24-
fun tryCreateValueProvider(
25-
concreteExecutor: ConcreteExecutor<UtConcreteExecutionResult, UtExecutionInstrumentation>,
26-
classUnderTest: ClassId,
27-
idGenerator: IdentityPreservingIdGenerator<Int>,
28-
): JavaValueProvider
10+
// TODO refactor, so this interface only includes the following:
11+
// val instrumentationFactory: UtExecutionInstrumentation.Factory<*>
12+
// fun createValueProviderOrThrow(classUnderTest: ClassId, idGenerator: IdentityPreservingIdGenerator<Int>): JavaValueProvider
13+
// fun loadContext(): ContextLoadingResult
14+
// fun Coverage.filterCoveredInstructions(classUnderTestId: ClassId): Coverage
2915
}

utbot-framework/src/main/kotlin/org/utbot/framework/context/custom/CoverageFilteringConcreteExecutionContext.kt

Lines changed: 0 additions & 93 deletions
This file was deleted.

utbot-framework/src/main/kotlin/org/utbot/framework/context/simple/SimpleApplicationContext.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,5 +17,5 @@ class SimpleApplicationContext(
1717
override fun createConcreteExecutionContext(
1818
fullClasspath: String,
1919
classpathWithoutDependencies: String
20-
): ConcreteExecutionContext = SimpleConcreteExecutionContext(fullClasspath)
20+
): ConcreteExecutionContext = SimpleConcreteExecutionContext(fullClasspath, classpathWithoutDependencies)
2121
}
Lines changed: 8 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,14 @@
11
package org.utbot.framework.context.simple
22

33
import org.utbot.framework.context.ConcreteExecutionContext
4-
import org.utbot.framework.plugin.api.ClassId
5-
import org.utbot.framework.plugin.api.ConcreteContextLoadingResult
6-
import org.utbot.framework.plugin.api.UtExecution
7-
import org.utbot.fuzzer.IdentityPreservingIdGenerator
8-
import org.utbot.fuzzing.JavaValueProvider
9-
import org.utbot.fuzzing.ValueProvider
10-
import org.utbot.fuzzing.defaultValueProviders
11-
import org.utbot.instrumentation.ConcreteExecutor
12-
import org.utbot.instrumentation.instrumentation.execution.SimpleUtExecutionInstrumentation
13-
import org.utbot.instrumentation.instrumentation.execution.UtConcreteExecutionResult
14-
import org.utbot.instrumentation.instrumentation.execution.UtExecutionInstrumentation
15-
import java.io.File
4+
import org.utbot.framework.plugin.api.UtError
165

17-
class SimpleConcreteExecutionContext(fullClassPath: String) : ConcreteExecutionContext {
18-
override val instrumentationFactory: UtExecutionInstrumentation.Factory<*> =
19-
SimpleUtExecutionInstrumentation.Factory(fullClassPath.split(File.pathSeparator).toSet())
6+
class SimpleConcreteExecutionContext(
7+
// TODO these properties will be used later (to fulfill TODO in ConcreteExecutionContext)
8+
val fullClassPath: String,
9+
val classpathWithoutDependencies: String
10+
) : ConcreteExecutionContext {
11+
override fun preventsFurtherTestGeneration(): Boolean = false
2012

21-
override fun loadContext(
22-
concreteExecutor: ConcreteExecutor<UtConcreteExecutionResult, UtExecutionInstrumentation>,
23-
): ConcreteContextLoadingResult = ConcreteContextLoadingResult.successWithoutExceptions()
24-
25-
override fun transformExecutionsBeforeMinimization(
26-
executions: List<UtExecution>,
27-
classUnderTestId: ClassId
28-
): List<UtExecution> = executions
29-
30-
override fun tryCreateValueProvider(
31-
concreteExecutor: ConcreteExecutor<UtConcreteExecutionResult, UtExecutionInstrumentation>,
32-
classUnderTest: ClassId,
33-
idGenerator: IdentityPreservingIdGenerator<Int>
34-
): JavaValueProvider = ValueProvider.of(defaultValueProviders(idGenerator))
13+
override fun getErrors(): List<UtError> = emptyList()
3514
}

utbot-framework/src/main/kotlin/org/utbot/framework/context/spring/SpringApplicationContext.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import org.utbot.framework.context.ApplicationContext
44
import org.utbot.framework.plugin.api.BeanDefinitionData
55
import org.utbot.framework.plugin.api.ClassId
66
import org.utbot.framework.plugin.api.SpringCodeGenerationContext
7-
import org.utbot.framework.plugin.api.ConcreteContextLoadingResult
7+
import org.utbot.framework.plugin.api.SpringContextLoadingResult
88

99
/**
1010
* Data we get from Spring application context
@@ -19,6 +19,6 @@ interface SpringApplicationContext : ApplicationContext, SpringCodeGenerationCon
1919
val injectedTypes: Set<ClassId>
2020
val allInjectedSuperTypes: Set<ClassId>
2121

22-
override var concreteContextLoadingResult: ConcreteContextLoadingResult?
22+
override var springContextLoadingResult: SpringContextLoadingResult?
2323
fun getBeansAssignableTo(classId: ClassId): List<BeanDefinitionData>
2424
}

0 commit comments

Comments
 (0)