Skip to content

Commit 4ad8c4a

Browse files
committed
Apply some improvements
1 parent 24d1003 commit 4ad8c4a

File tree

8 files changed

+744
-125
lines changed

8 files changed

+744
-125
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,4 +72,4 @@ fun UtInstrumentation.mapModels(mapper: UtModelMapper) = when (this) {
7272

7373
fun UtExecution.mapStateBeforeModels(mapper: UtModelMapper) = copy(
7474
stateBefore = stateBefore.mapModels(mapper)
75-
)
75+
)
Lines changed: 78 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
package org.utbot.engine
22

3-
import kotlinx.coroutines.flow.Flow
4-
import kotlinx.coroutines.flow.flow
53
import kotlinx.coroutines.runBlocking
64
import mu.KotlinLogging
75
import org.jacodb.approximation.Approximations
@@ -24,10 +22,10 @@ import org.utbot.framework.fuzzer.ReferencePreservingIntIdGenerator
2422
import org.utbot.framework.plugin.api.ExecutableId
2523
import org.utbot.framework.plugin.api.InstrumentedProcessDeathException
2624
import org.utbot.framework.plugin.api.UtConcreteExecutionFailure
25+
import org.utbot.framework.plugin.api.UtConcreteExecutionProcessedFailure
2726
import org.utbot.framework.plugin.api.UtError
2827
import org.utbot.framework.plugin.api.UtFailedExecution
2928
import org.utbot.framework.plugin.api.UtResult
30-
import org.utbot.framework.plugin.api.UtSymbolicExecution
3129
import org.utbot.framework.plugin.api.util.utContext
3230
import org.utbot.framework.plugin.services.JdkInfoService
3331
import org.utbot.instrumentation.ConcreteExecutor
@@ -36,6 +34,7 @@ import org.utbot.instrumentation.instrumentation.execution.UtExecutionInstrument
3634
import org.utbot.usvm.converter.JcToUtExecutionConverter
3735
import org.utbot.usvm.converter.SimpleInstructionIdProvider
3836
import org.utbot.usvm.converter.UtExecutionInitialState
37+
import org.utbot.usvm.converter.UtUsvmExecution
3938
import org.utbot.usvm.converter.toExecutableId
4039
import org.utbot.usvm.jc.JcContainer
4140
import org.utbot.usvm.jc.JcExecution
@@ -56,73 +55,75 @@ object UsvmSymbolicEngine {
5655
classpath: String,
5756
concreteExecutionContext: ConcreteExecutionContext,
5857
timeoutMillis: Long
59-
): Flow<Pair<ExecutableId, UtResult>> = flow {
60-
var analysisResult: AnalysisResult? = null
58+
): List<Pair<ExecutableId, UtResult>> {
6159

60+
val collectedExecutions = mutableListOf<Pair<ExecutableId, UtResult>>()
6261
val classpathFiles = classpath.split(File.pathSeparator).map { File(it) }
63-
val jcContainer = createJcContainer(classpathFiles)
6462

65-
val jcMethods = methods
66-
.mapNotNull { methodId -> jcContainer.cp.findMethodOrNull(methodId).also {
67-
if (it == null) {
68-
logger.error { "Method [$methodId] not found in jcClasspath [${jcContainer.cp}]" }
63+
createJcContainer(classpathFiles).use { jcContainer ->
64+
val jcMethods = methods
65+
.mapNotNull { methodId ->
66+
jcContainer.cp.findMethodOrNull(methodId).also {
67+
if (it == null) {
68+
logger.error { "Method [$methodId] not found in jcClasspath [${jcContainer.cp}]" }
69+
}
70+
}
6971
}
70-
}
71-
}
7272

73-
JcMachine(
74-
cp = jcContainer.cp,
75-
options = UMachineOptions(
76-
timeout = timeoutMillis.milliseconds,
77-
pathSelectionStrategies = listOf(PathSelectionStrategy.CLOSEST_TO_UNCOVERED_RANDOM),
78-
pathSelectorFairnessStrategy = PathSelectorFairnessStrategy.COMPLETELY_FAIR,
79-
solverType = SolverType.Z3,
80-
)
81-
).use { jcMachine ->
82-
jcMachine.analyzeAsync(
83-
forceTerminationTimeout = (timeoutMillis * 1.1 + 2000).toLong(),
84-
methods = jcMethods,
85-
targets = emptyList()
86-
) { state ->
87-
val jcExecutionConstruction = constructJcExecution(jcMachine, state, jcContainer)
88-
89-
val jcExecution = jcExecutionConstruction.jcExecution
90-
val executableId = jcExecution.method.method.toExecutableId(jcContainer.cp)
91-
92-
val executionConverter = JcToUtExecutionConverter(
93-
jcExecution = jcExecution,
94-
jcClasspath = jcContainer.cp,
95-
idGenerator = ReferencePreservingIntIdGenerator(),
96-
instructionIdProvider = SimpleInstructionIdProvider(),
97-
utilMethodProvider = UtilMethodProviderPlaceholder,
73+
JcMachine(
74+
cp = jcContainer.cp,
75+
options = UMachineOptions(
76+
timeout = timeoutMillis.milliseconds,
77+
pathSelectionStrategies = listOf(PathSelectionStrategy.CLOSEST_TO_UNCOVERED_RANDOM),
78+
pathSelectorFairnessStrategy = PathSelectorFairnessStrategy.COMPLETELY_FAIR,
79+
solverType = SolverType.Z3,
9880
)
99-
100-
val utResult = if (jcExecutionConstruction.useUsvmExecutor) {
101-
executionConverter.convert()
102-
} else {
103-
val initialState = executionConverter.convertInitialStateOnly()
104-
val concreteExecutor = ConcreteExecutor(concreteExecutionContext.instrumentationFactory, classpath)
105-
.apply { this.classLoader = utContext.classLoader }
106-
107-
runStandardConcreteExecution(concreteExecutor, executableId, initialState)
108-
}
109-
110-
utResult?.let {
111-
analysisResult = AnalysisResult(executableId, it)
81+
).use { jcMachine ->
82+
jcMachine.analyzeAsync(
83+
forceTerminationTimeout = (timeoutMillis * 1.1 + 2000).toLong(),
84+
methods = jcMethods,
85+
targets = emptyList()
86+
) { state ->
87+
val jcExecution = constructJcExecution(jcMachine, state, jcContainer)
88+
89+
val executableId = jcExecution.method.method.toExecutableId(jcContainer.cp)
90+
91+
val executionConverter = JcToUtExecutionConverter(
92+
jcExecution = jcExecution,
93+
jcClasspath = jcContainer.cp,
94+
idGenerator = ReferencePreservingIntIdGenerator(),
95+
instructionIdProvider = SimpleInstructionIdProvider(),
96+
utilMethodProvider = UtilMethodProviderPlaceholder,
97+
)
98+
99+
val utResult = runCatching {
100+
executionConverter.convert()
101+
}.getOrElse { e ->
102+
logger.warn(e) { "JcToUtExecutionConverter.convert(${jcExecution.method.method}) failed" }
103+
104+
val initialState = executionConverter.convertInitialStateOnly()
105+
val concreteExecutor =
106+
ConcreteExecutor(concreteExecutionContext.instrumentationFactory, classpath)
107+
.apply { this.classLoader = utContext.classLoader }
108+
109+
runStandardConcreteExecution(concreteExecutor, executableId, initialState)
110+
}
111+
112+
utResult?.let {
113+
collectedExecutions.add(executableId to it)
114+
}
112115
}
113116
}
114117
}
115118

116-
analysisResult?.let {
117-
emit(it.executableId to it.utResult)
118-
}
119+
return collectedExecutions
119120
}
120121

121122
private fun constructJcExecution(
122123
jcMachine: JcMachine,
123124
state: JcState,
124125
jcContainer: JcContainer,
125-
): JcExecutionConstruction {
126+
): JcExecution {
126127
val executor = JcTestExecutor(jcContainer.cp, jcContainer.runner)
127128

128129
val realJcExecution = runCatching {
@@ -133,16 +134,16 @@ object UsvmSymbolicEngine {
133134
classConstants = jcMachine.classConstants,
134135
allowSymbolicResult = false
135136
)
136-
}.getOrElse { null }
137+
}.getOrElse { e ->
138+
logger.warn(e) { "executor.execute(${state.entrypoint}) failed" }
139+
null
140+
}
137141

138142
realJcExecution?.let {
139-
return JcExecutionConstruction(
140-
jcExecution = it,
141-
useUsvmExecutor = true,
142-
)
143+
return it
143144
}
144145

145-
val jcExecutionWithUTest = JcExecution(
146+
return JcExecution(
146147
method = state.entrypoint.typedMethod,
147148
uTest = executor.createUTest(
148149
method = state.entrypoint.typedMethod,
@@ -153,11 +154,6 @@ object UsvmSymbolicEngine {
153154
uTestExecutionResultWrappers = emptySequence(),
154155
coverage = JcCoverage(emptyMap()),
155156
)
156-
157-
return JcExecutionConstruction(
158-
jcExecution = jcExecutionWithUTest,
159-
useUsvmExecutor = false,
160-
)
161157
}
162158

163159
private fun runStandardConcreteExecution(
@@ -175,15 +171,17 @@ object UsvmSymbolicEngine {
175171
)
176172
}
177173

178-
UtSymbolicExecution(
179-
initialState.stateBefore,
180-
concreteExecutionResult.stateAfter,
181-
concreteExecutionResult.result,
182-
concreteExecutionResult.newInstrumentation ?: initialState.instrumentations,
183-
mutableListOf(),
184-
listOf(),
185-
concreteExecutionResult.coverage
186-
)
174+
concreteExecutionResult.processedFailure()?.let { failure ->
175+
logger.warn { "Instrumented process failed with exception ${failure.exception} " +
176+
"before concrete execution started" }
177+
null
178+
} ?: UtUsvmExecution(
179+
initialState.stateBefore,
180+
concreteExecutionResult.stateAfter,
181+
concreteExecutionResult.result,
182+
concreteExecutionResult.coverage,
183+
instrumentation = concreteExecutionResult.newInstrumentation ?: initialState.instrumentations,
184+
)
187185
} catch (e: CancellationException) {
188186
logger.debug(e) { "Cancellation happened" }
189187
null
@@ -203,17 +201,12 @@ object UsvmSymbolicEngine {
203201
classpath = classpathFiles,
204202
javaHome = JdkInfoService.provide().path.toFile(),
205203
) {
206-
installFeatures(InMemoryHierarchy, Approximations, ClassScorer(TypeScorer, ::scoreClassNode))
204+
installFeatures(
205+
InMemoryHierarchy,
206+
Approximations,
207+
// ApproximationPaths(JcJars.approximationsJar, ...)
208+
ClassScorer(TypeScorer, ::scoreClassNode)
209+
)
207210
loadByteCode(classpathFiles)
208211
}
209-
210-
data class JcExecutionConstruction(
211-
val jcExecution: JcExecution,
212-
val useUsvmExecutor: Boolean,
213-
)
214-
215-
data class AnalysisResult(
216-
val executableId: ExecutableId,
217-
val utResult: UtResult,
218-
)
219212
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -864,7 +864,7 @@ private fun UtConcreteExecutionResult.violatesUtMockAssumption(): Boolean {
864864
return result.exceptionOrNull()?.javaClass?.name == UtMockAssumptionViolatedException::class.java.name
865865
}
866866

867-
private fun UtConcreteExecutionResult.processedFailure(): UtConcreteExecutionProcessedFailure?
867+
fun UtConcreteExecutionResult.processedFailure(): UtConcreteExecutionProcessedFailure?
868868
= result as? UtConcreteExecutionProcessedFailure
869869

870870
private fun checkStaticMethodsMock(execution: UtSymbolicExecution) =

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

Lines changed: 26 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -203,29 +203,24 @@ open class TestCaseGenerator(
203203
val forceMockListener = ForceMockListener.create(this, conflictTriggers)
204204
val forceStaticMockListener = ForceStaticMockListener.create(this, conflictTriggers)
205205

206-
suspend fun consumeUtResultFlow(utResultFlow: Flow<Pair<ExecutableId, UtResult>>) =
207-
utResultFlow.catch {
208-
logger.error(it) { "Error in flow" }
209-
}
210-
.collect { (executableId, utResult) ->
211-
when (utResult) {
212-
is UtExecution -> {
213-
if (utResult is UtSymbolicExecution &&
214-
(conflictTriggers.triggered(Conflict.ForceMockHappened) ||
215-
conflictTriggers.triggered(Conflict.ForceStaticMockHappened))
216-
) {
217-
utResult.containsMocking = true
218-
}
219-
method2executions.getValue(executableId) += utResult
220-
}
221-
222-
is UtError -> {
223-
method2errors.getValue(executableId).merge(utResult.description, 1, Int::plus)
224-
logger.error(utResult.error) { "UtError occurred" }
225-
}
206+
fun consumeUtResult(executableId: ExecutableId, utResult: UtResult) =
207+
when (utResult) {
208+
is UtExecution -> {
209+
if (utResult is UtSymbolicExecution &&
210+
(conflictTriggers.triggered(Conflict.ForceMockHappened) ||
211+
conflictTriggers.triggered(Conflict.ForceStaticMockHappened))
212+
) {
213+
utResult.containsMocking = true
226214
}
215+
method2executions.getValue(executableId) += utResult
227216
}
228217

218+
is UtError -> {
219+
method2errors.getValue(executableId).merge(utResult.description, 1, Int::plus)
220+
logger.error(utResult.error) { "UtError occurred" }
221+
}
222+
}
223+
229224
runIgnoringCancellationException {
230225
runBlockingWithCancellationPredicate(isCanceled) {
231226
for ((method, controller) in method2controller) {
@@ -249,9 +244,15 @@ open class TestCaseGenerator(
249244
engineActions.map { engine.apply(it) }
250245
engineActions.clear()
251246

252-
consumeUtResultFlow(generate(engine).map { utResult -> method to utResult })
247+
generate(engine)
248+
.catch {
249+
logger.error(it) { "Error in flow" }
250+
}
251+
.collect { utResult ->
252+
consumeUtResult(method, utResult)
253+
}
253254
} catch (e: Exception) {
254-
logger.error(e) {"Error in engine"}
255+
logger.error(e) { "Error in engine" }
255256
throw e
256257
}
257258
}
@@ -291,15 +292,9 @@ open class TestCaseGenerator(
291292
logger.debug("test generator global scope lifecycle check ended")
292293
}
293294

294-
// retrieves from cache ConcreteExecutor(concreteExecutionContext.instrumentationFactory, classpathForEngine)
295-
consumeUtResultFlow(
296-
UsvmSymbolicEngine.runUsvmGeneration(
297-
methods = methods,
298-
classpath = classpathForEngine,
299-
concreteExecutionContext = concreteExecutionContext,
300-
timeoutMillis = usvmTimeoutMillis,
301-
)
302-
)
295+
UsvmSymbolicEngine
296+
.runUsvmGeneration(methods, classpathForEngine, concreteExecutionContext, usvmTimeoutMillis)
297+
.forEach { (executableId, usvmExecution) -> consumeUtResult(executableId, usvmExecution) }
303298
}
304299
}
305300

0 commit comments

Comments
 (0)