Skip to content

Commit 9b22a39

Browse files
Transfer Spring application data from UI to Engine (#1816)
1 parent 91001ef commit 9b22a39

File tree

10 files changed

+101
-26
lines changed

10 files changed

+101
-26
lines changed

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

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ import java.io.File
5555
import kotlin.contracts.ExperimentalContracts
5656
import kotlin.contracts.contract
5757
import org.utbot.common.isAbstract
58+
import org.utbot.framework.plugin.api.util.utContext
5859

5960
const val SYMBOLIC_NULL_ADDR: Int = 0
6061

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

11481149
class WildcardTypeParameter : TypeParameters(emptyList())
11491150

1151+
/**
1152+
* Additional data describing user project.
1153+
*/
1154+
interface ApplicationContext
1155+
1156+
/**
1157+
* Data we get from Spring application context
1158+
* to manage engine and code generator behaviour.
1159+
*
1160+
* @param beanQualifiedNames describes fqn of injected classes
1161+
*/
1162+
data class SpringApplicationContext(
1163+
val beanQualifiedNames: List<String> = emptyList(),
1164+
): ApplicationContext {
1165+
private val springInjectedClasses: List<ClassId> by lazy {
1166+
beanQualifiedNames.map { fqn -> utContext.classLoader.loadClass(fqn).id }
1167+
}
1168+
}
1169+
11501170
interface CodeGenerationSettingItem {
11511171
val id: String
11521172
val displayName: String

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,10 +116,12 @@ import org.utbot.framework.UtSettings
116116
import org.utbot.framework.UtSettings.maximizeCoverageUsingReflection
117117
import org.utbot.framework.UtSettings.preferredCexOption
118118
import org.utbot.framework.UtSettings.substituteStaticsWithSymbolicVariable
119+
import org.utbot.framework.plugin.api.ApplicationContext
119120
import org.utbot.framework.plugin.api.ClassId
120121
import org.utbot.framework.plugin.api.ExecutableId
121122
import org.utbot.framework.plugin.api.FieldId
122123
import org.utbot.framework.plugin.api.MethodId
124+
import org.utbot.framework.plugin.api.SpringApplicationContext
123125
import org.utbot.framework.plugin.api.classId
124126
import org.utbot.framework.plugin.api.id
125127
import org.utbot.framework.plugin.api.util.executable
@@ -237,6 +239,7 @@ class Traverser(
237239
internal val typeResolver: TypeResolver,
238240
private val globalGraph: InterProceduralUnitGraph,
239241
private val mocker: Mocker,
242+
private val applicationContext: ApplicationContext?,
240243
) : UtContextInitializer() {
241244

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

274277
internal val objectCounter = ObjectCounter(TypeRegistry.objectCounterInitialValue)
275278

279+
280+
276281
private fun findNewAddr(insideStaticInitializer: Boolean): UtAddrExpression {
277282
val newAddr = objectCounter.createNewAddr()
278283
// return negative address for objects created inside static initializer

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ class UtBotSymbolicEngine(
105105
dependencyPaths: String,
106106
val mockStrategy: MockStrategy = NO_MOCKS,
107107
chosenClassesToMockAlways: Set<ClassId>,
108+
applicationContext: ApplicationContext?,
108109
private val solverTimeoutInMillis: Int = checkSolverTimeoutMillis
109110
) : UtContextInitializer() {
110111
private val graph = methodUnderTest.sootMethod.jimpleBody().apply {
@@ -144,6 +145,7 @@ class UtBotSymbolicEngine(
144145
typeResolver,
145146
globalGraph,
146147
mocker,
148+
applicationContext,
147149
)
148150

149151
//HACK (long strings)

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

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ open class TestCaseGenerator(
6161
val engineActions: MutableList<(UtBotSymbolicEngine) -> Unit> = mutableListOf(),
6262
val isCanceled: () -> Boolean = { false },
6363
val forceSootReload: Boolean = true,
64+
val applicationContext: ApplicationContext? = null,
6465
) {
6566
private val logger: KLogger = KotlinLogging.logger {}
6667
private val timeoutLogger: KLogger = KotlinLogging.logger(logger.name + ".timeout")
@@ -112,7 +113,14 @@ open class TestCaseGenerator(
112113
executionTimeEstimator: ExecutionTimeEstimator = ExecutionTimeEstimator(utBotGenerationTimeoutInMillis, 1)
113114
): Flow<UtResult> {
114115
try {
115-
val engine = createSymbolicEngine(controller, method, mockStrategy, chosenClassesToMockAlways, executionTimeEstimator)
116+
val engine = createSymbolicEngine(
117+
controller,
118+
method,
119+
mockStrategy,
120+
chosenClassesToMockAlways,
121+
applicationContext = null,
122+
executionTimeEstimator,
123+
)
116124
engineActions.map { engine.apply(it) }
117125
engineActions.clear()
118126
return defaultTestFlow(engine, executionTimeEstimator.userTimeout)
@@ -159,6 +167,7 @@ open class TestCaseGenerator(
159167
method,
160168
mockStrategy,
161169
chosenClassesToMockAlways,
170+
applicationContext,
162171
executionTimeEstimator
163172
)
164173

@@ -248,6 +257,7 @@ open class TestCaseGenerator(
248257
method: ExecutableId,
249258
mockStrategyApi: MockStrategyApi,
250259
chosenClassesToMockAlways: Set<ClassId>,
260+
applicationContext: ApplicationContext?,
251261
executionTimeEstimator: ExecutionTimeEstimator
252262
): UtBotSymbolicEngine {
253263
logger.debug("Starting symbolic execution for $method --$mockStrategyApi--")
@@ -258,6 +268,7 @@ open class TestCaseGenerator(
258268
dependencyPaths = dependencyPaths,
259269
mockStrategy = mockStrategyApi.toModel(),
260270
chosenClassesToMockAlways = chosenClassesToMockAlways,
271+
applicationContext = applicationContext,
261272
solverTimeoutInMillis = executionTimeEstimator.updatedSolverCheckTimeoutMillis
262273
)
263274
}

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,16 @@ fun defaultTestFlow(timeout: Long) = testFlow {
2424
}
2525
}
2626

27+
/**
28+
* Creates default flow for Spring application.
29+
*/
30+
fun defaultSpringFlow(timeout: Long) = testFlow {
31+
isSymbolicEngineEnabled = true
32+
generationTimeout = timeout
33+
isFuzzingEnabled = false
34+
fuzzingValue = 0.0
35+
}
36+
2737
/**
2838
* Creates default flow that uses [UtSettings] for customization.
2939
*/

utbot-framework/src/main/kotlin/org/utbot/framework/process/EngineProcessMain.kt

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -83,10 +83,13 @@ private fun EngineProcessModel.setup(kryoHelper: KryoHelper, watchdog: IdleWatch
8383
watchdog.measureTimeForActiveCall(createTestGenerator, "Creating Test Generator") { params ->
8484
AnalyticsConfigureUtil.configureML()
8585
Instrumenter.adapter = RdInstrumenter(realProtocol.rdInstrumenterAdapter)
86+
val applicationContext: ApplicationContext = kryoHelper.readObject(params.applicationContext)
87+
8688
testGenerator = TestCaseGenerator(buildDirs = params.buildDir.map { Paths.get(it) },
8789
classpath = params.classpath,
8890
dependencyPaths = params.dependencyPaths,
8991
jdkInfo = JdkInfo(Paths.get(params.jdkInfo.path), params.jdkInfo.version),
92+
applicationContext = applicationContext,
9093
isCanceled = {
9194
runBlocking {
9295
model.isCancelled.startSuspending(Unit)
@@ -105,16 +108,24 @@ private fun EngineProcessModel.setup(kryoHelper: KryoHelper, watchdog: IdleWatch
105108
if (!staticsMockingConfigured) {
106109
ForceStaticMockListener.create(testGenerator, conflictTriggers, cancelJob = true)
107110
}
108-
val result = testGenerator.generate(methods,
109-
MockStrategyApi.valueOf(params.mockStrategy),
110-
kryoHelper.readObject(params.chosenClassesToMockAlways),
111-
params.timeout,
112-
generate = testFlow {
111+
112+
val generateFlow = when (testGenerator.applicationContext) {
113+
is SpringApplicationContext -> defaultSpringFlow(params.generationTimeout)
114+
else -> testFlow {
113115
generationTimeout = params.generationTimeout
114116
isSymbolicEngineEnabled = params.isSymbolicEngineEnabled
115117
isFuzzingEnabled = params.isFuzzingEnabled
116118
fuzzingValue = params.fuzzingValue
117-
})
119+
}
120+
}
121+
122+
val result = testGenerator.generate(
123+
methods,
124+
MockStrategyApi.valueOf(params.mockStrategy),
125+
kryoHelper.readObject(params.chosenClassesToMockAlways),
126+
params.timeout,
127+
generate = generateFlow,
128+
)
118129
.summarizeAll(Paths.get(params.searchDirectory), null)
119130
.filterNot { it.executions.isEmpty() && it.errors.isEmpty() }
120131

utbot-framework/src/main/kotlin/org/utbot/framework/process/generated/EngineProcessModel.Generated.kt

Lines changed: 22 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ class EngineProcessModel private constructor(
7272
}
7373

7474

75-
const val serializationHash = 5025678608993948804L
75+
const val serializationHash = -4839464828913070560L
7676

7777
}
7878
override val serializersOwner: ISerializersOwner get() = EngineProcessModel
@@ -173,7 +173,7 @@ val IProtocol.engineProcessModel get() = getOrCreateExtension(EngineProcessModel
173173

174174

175175
/**
176-
* #### Generated from [EngineProcessModel.kt:101]
176+
* #### Generated from [EngineProcessModel.kt:102]
177177
*/
178178
data class FindMethodParamNamesArguments (
179179
val classId: ByteArray,
@@ -236,7 +236,7 @@ data class FindMethodParamNamesArguments (
236236

237237

238238
/**
239-
* #### Generated from [EngineProcessModel.kt:105]
239+
* #### Generated from [EngineProcessModel.kt:106]
240240
*/
241241
data class FindMethodParamNamesResult (
242242
val paramNames: ByteArray
@@ -293,7 +293,7 @@ data class FindMethodParamNamesResult (
293293

294294

295295
/**
296-
* #### Generated from [EngineProcessModel.kt:94]
296+
* #### Generated from [EngineProcessModel.kt:95]
297297
*/
298298
data class FindMethodsInClassMatchingSelectedArguments (
299299
val classId: ByteArray,
@@ -356,7 +356,7 @@ data class FindMethodsInClassMatchingSelectedArguments (
356356

357357

358358
/**
359-
* #### Generated from [EngineProcessModel.kt:98]
359+
* #### Generated from [EngineProcessModel.kt:99]
360360
*/
361361
data class FindMethodsInClassMatchingSelectedResult (
362362
val executableIds: ByteArray
@@ -413,7 +413,7 @@ data class FindMethodsInClassMatchingSelectedResult (
413413

414414

415415
/**
416-
* #### Generated from [EngineProcessModel.kt:43]
416+
* #### Generated from [EngineProcessModel.kt:44]
417417
*/
418418
data class GenerateParams (
419419
val mockInstalled: Boolean,
@@ -536,7 +536,7 @@ data class GenerateParams (
536536

537537

538538
/**
539-
* #### Generated from [EngineProcessModel.kt:61]
539+
* #### Generated from [EngineProcessModel.kt:62]
540540
*/
541541
data class GenerateResult (
542542
val notEmptyCases: Int,
@@ -599,7 +599,7 @@ data class GenerateResult (
599599

600600

601601
/**
602-
* #### Generated from [EngineProcessModel.kt:113]
602+
* #### Generated from [EngineProcessModel.kt:114]
603603
*/
604604
data class GenerateTestReportArgs (
605605
val eventLogMessage: String?,
@@ -692,7 +692,7 @@ data class GenerateTestReportArgs (
692692

693693

694694
/**
695-
* #### Generated from [EngineProcessModel.kt:122]
695+
* #### Generated from [EngineProcessModel.kt:123]
696696
*/
697697
data class GenerateTestReportResult (
698698
val notifyMessage: String,
@@ -824,7 +824,7 @@ data class JdkInfo (
824824

825825

826826
/**
827-
* #### Generated from [EngineProcessModel.kt:89]
827+
* #### Generated from [EngineProcessModel.kt:90]
828828
*/
829829
data class MethodDescription (
830830
val name: String,
@@ -893,7 +893,7 @@ data class MethodDescription (
893893

894894

895895
/**
896-
* #### Generated from [EngineProcessModel.kt:65]
896+
* #### Generated from [EngineProcessModel.kt:66]
897897
*/
898898
data class RenderParams (
899899
val testSetsId: Long,
@@ -1034,7 +1034,7 @@ data class RenderParams (
10341034

10351035

10361036
/**
1037-
* #### Generated from [EngineProcessModel.kt:82]
1037+
* #### Generated from [EngineProcessModel.kt:83]
10381038
*/
10391039
data class RenderResult (
10401040
val generatedCode: String,
@@ -1097,7 +1097,7 @@ data class RenderResult (
10971097

10981098

10991099
/**
1100-
* #### Generated from [EngineProcessModel.kt:86]
1100+
* #### Generated from [EngineProcessModel.kt:87]
11011101
*/
11021102
data class SetupContextParams (
11031103
val classpathForUrlsClassloader: List<String>
@@ -1160,7 +1160,8 @@ data class TestGeneratorParams (
11601160
val buildDir: Array<String>,
11611161
val classpath: String?,
11621162
val dependencyPaths: String,
1163-
val jdkInfo: JdkInfo
1163+
val jdkInfo: JdkInfo,
1164+
val applicationContext: ByteArray
11641165
) : IPrintable {
11651166
//companion
11661167

@@ -1173,14 +1174,16 @@ data class TestGeneratorParams (
11731174
val classpath = buffer.readNullable { buffer.readString() }
11741175
val dependencyPaths = buffer.readString()
11751176
val jdkInfo = JdkInfo.read(ctx, buffer)
1176-
return TestGeneratorParams(buildDir, classpath, dependencyPaths, jdkInfo)
1177+
val applicationContext = buffer.readByteArray()
1178+
return TestGeneratorParams(buildDir, classpath, dependencyPaths, jdkInfo, applicationContext)
11771179
}
11781180

11791181
override fun write(ctx: SerializationCtx, buffer: AbstractBuffer, value: TestGeneratorParams) {
11801182
buffer.writeArray(value.buildDir) { buffer.writeString(it) }
11811183
buffer.writeNullable(value.classpath) { buffer.writeString(it) }
11821184
buffer.writeString(value.dependencyPaths)
11831185
JdkInfo.write(ctx, buffer, value.jdkInfo)
1186+
buffer.writeByteArray(value.applicationContext)
11841187
}
11851188

11861189

@@ -1200,6 +1203,7 @@ data class TestGeneratorParams (
12001203
if (classpath != other.classpath) return false
12011204
if (dependencyPaths != other.dependencyPaths) return false
12021205
if (jdkInfo != other.jdkInfo) return false
1206+
if (!(applicationContext contentEquals other.applicationContext)) return false
12031207

12041208
return true
12051209
}
@@ -1210,6 +1214,7 @@ data class TestGeneratorParams (
12101214
__r = __r*31 + if (classpath != null) classpath.hashCode() else 0
12111215
__r = __r*31 + dependencyPaths.hashCode()
12121216
__r = __r*31 + jdkInfo.hashCode()
1217+
__r = __r*31 + applicationContext.contentHashCode()
12131218
return __r
12141219
}
12151220
//pretty print
@@ -1220,6 +1225,7 @@ data class TestGeneratorParams (
12201225
print("classpath = "); classpath.print(printer); println()
12211226
print("dependencyPaths = "); dependencyPaths.print(printer); println()
12221227
print("jdkInfo = "); jdkInfo.print(printer); println()
1228+
print("applicationContext = "); applicationContext.print(printer); println()
12231229
}
12241230
printer.print(")")
12251231
}
@@ -1229,7 +1235,7 @@ data class TestGeneratorParams (
12291235

12301236

12311237
/**
1232-
* #### Generated from [EngineProcessModel.kt:108]
1238+
* #### Generated from [EngineProcessModel.kt:109]
12331239
*/
12341240
data class WriteSarifReportArguments (
12351241
val testSetsId: Long,

0 commit comments

Comments
 (0)