Skip to content

Commit c9c2a0b

Browse files
Try to fix memory leak in CgComponents (#1057)
* Try to fix memory leak in CgFieldStateManager * Removed unused testClassConstructors * Make CgContext much more thin * Clear content related maps before the processing of new test class
1 parent 1ab8f2c commit c9c2a0b

11 files changed

+218
-204
lines changed

utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/context/CgContext.kt

+5-2
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,10 @@ internal interface CgContextOwner {
215215

216216
var statesCache: EnvironmentFieldStateCache
217217

218-
var allExecutions: List<UtExecution>
218+
/**
219+
* Result models required to create generic execution in parametrized tests.
220+
*/
221+
var successfulExecutionsModels: List<UtModel>
219222

220223
fun block(init: () -> Unit): Block {
221224
val prevBlock = currentBlock
@@ -463,7 +466,7 @@ internal data class CgContext(
463466
) : CgContextOwner {
464467
override lateinit var statesCache: EnvironmentFieldStateCache
465468
override lateinit var actual: CgVariable
466-
override lateinit var allExecutions: List<UtExecution>
469+
override lateinit var successfulExecutionsModels: List<UtModel>
467470

468471
/**
469472
* This property cannot be accessed outside of test class file scope

utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/tree/CgCallableAccessManager.kt

+4-3
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ import org.utbot.framework.codegen.model.constructor.builtin.setAccessible
1313
import org.utbot.framework.codegen.model.constructor.context.CgContext
1414
import org.utbot.framework.codegen.model.constructor.context.CgContextOwner
1515
import org.utbot.framework.codegen.model.constructor.tree.CgCallableAccessManagerImpl.FieldAccessorSuitability.*
16-
import org.utbot.framework.codegen.model.constructor.util.CgComponents
16+
import org.utbot.framework.codegen.model.constructor.tree.CgTestClassConstructor.CgComponents.getStatementConstructorBy
17+
import org.utbot.framework.codegen.model.constructor.tree.CgTestClassConstructor.CgComponents.getVariableConstructorBy
1718
import org.utbot.framework.codegen.model.constructor.util.getAmbiguousOverloadsOf
1819
import org.utbot.framework.codegen.model.constructor.util.importIfNeeded
1920
import org.utbot.framework.codegen.model.constructor.util.isUtil
@@ -85,9 +86,9 @@ interface CgCallableAccessManager {
8586
internal class CgCallableAccessManagerImpl(val context: CgContext) : CgCallableAccessManager,
8687
CgContextOwner by context {
8788

88-
private val statementConstructor by lazy { CgComponents.getStatementConstructorBy(context) }
89+
private val statementConstructor by lazy { getStatementConstructorBy(context) }
8990

90-
private val variableConstructor by lazy { CgComponents.getVariableConstructorBy(context) }
91+
private val variableConstructor by lazy { getVariableConstructorBy(context) }
9192

9293
override operator fun CgExpression?.get(methodId: MethodId): CgIncompleteMethodCall =
9394
CgIncompleteMethodCall(methodId, this)

utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/tree/CgFieldStateManager.kt

+4-3
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ import org.utbot.framework.codegen.model.constructor.builtin.forName
44
import org.utbot.framework.codegen.model.constructor.builtin.getArrayElement
55
import org.utbot.framework.codegen.model.constructor.context.CgContext
66
import org.utbot.framework.codegen.model.constructor.context.CgContextOwner
7-
import org.utbot.framework.codegen.model.constructor.util.CgComponents
7+
import org.utbot.framework.codegen.model.constructor.tree.CgTestClassConstructor.CgComponents.getCallableAccessManagerBy
8+
import org.utbot.framework.codegen.model.constructor.tree.CgTestClassConstructor.CgComponents.getStatementConstructorBy
89
import org.utbot.framework.codegen.model.constructor.util.CgFieldState
910
import org.utbot.framework.codegen.model.constructor.util.CgStatementConstructor
1011
import org.utbot.framework.codegen.model.constructor.util.FieldStateCache
@@ -44,8 +45,8 @@ internal interface CgFieldStateManager {
4445
internal class CgFieldStateManagerImpl(val context: CgContext)
4546
: CgContextOwner by context,
4647
CgFieldStateManager,
47-
CgCallableAccessManager by CgComponents.getCallableAccessManagerBy(context),
48-
CgStatementConstructor by CgComponents.getStatementConstructorBy(context) {
48+
CgCallableAccessManager by getCallableAccessManagerBy(context),
49+
CgStatementConstructor by getStatementConstructorBy(context) {
4950

5051
override fun rememberInitialEnvironmentState(info: StateModificationInfo) {
5152
rememberThisInstanceState(info, FieldState.INITIAL)

utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/tree/CgMethodConstructor.kt

+15-17
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,12 @@ import org.utbot.framework.codegen.model.constructor.builtin.invoke
1515
import org.utbot.framework.codegen.model.constructor.builtin.newInstance
1616
import org.utbot.framework.codegen.model.constructor.context.CgContext
1717
import org.utbot.framework.codegen.model.constructor.context.CgContextOwner
18-
import org.utbot.framework.codegen.model.constructor.util.CgComponents
18+
import org.utbot.framework.codegen.model.constructor.tree.CgTestClassConstructor.CgComponents.getCallableAccessManagerBy
19+
import org.utbot.framework.codegen.model.constructor.tree.CgTestClassConstructor.CgComponents.getMockFrameworkManagerBy
20+
import org.utbot.framework.codegen.model.constructor.tree.CgTestClassConstructor.CgComponents.getNameGeneratorBy
21+
import org.utbot.framework.codegen.model.constructor.tree.CgTestClassConstructor.CgComponents.getStatementConstructorBy
22+
import org.utbot.framework.codegen.model.constructor.tree.CgTestClassConstructor.CgComponents.getTestFrameworkManagerBy
23+
import org.utbot.framework.codegen.model.constructor.tree.CgTestClassConstructor.CgComponents.getVariableConstructorBy
1924
import org.utbot.framework.codegen.model.constructor.util.CgStatementConstructor
2025
import org.utbot.framework.codegen.model.constructor.util.EnvironmentFieldStateCache
2126
import org.utbot.framework.codegen.model.constructor.util.FieldStateCache
@@ -148,15 +153,14 @@ import java.lang.reflect.ParameterizedType
148153
private const val DEEP_EQUALS_MAX_DEPTH = 5 // TODO move it to plugin settings?
149154

150155
internal class CgMethodConstructor(val context: CgContext) : CgContextOwner by context,
151-
CgFieldStateManager by CgComponents.getFieldStateManagerBy(context),
152-
CgCallableAccessManager by CgComponents.getCallableAccessManagerBy(context),
153-
CgStatementConstructor by CgComponents.getStatementConstructorBy(context) {
156+
CgCallableAccessManager by getCallableAccessManagerBy(context),
157+
CgStatementConstructor by getStatementConstructorBy(context) {
154158

155-
private val nameGenerator = CgComponents.getNameGeneratorBy(context)
156-
private val testFrameworkManager = CgComponents.getTestFrameworkManagerBy(context)
159+
private val nameGenerator = getNameGeneratorBy(context)
160+
private val testFrameworkManager = getTestFrameworkManagerBy(context)
157161

158-
private val variableConstructor = CgComponents.getVariableConstructorBy(context)
159-
private val mockFrameworkManager = CgComponents.getMockFrameworkManagerBy(context)
162+
private val variableConstructor = getVariableConstructorBy(context)
163+
private val mockFrameworkManager = getMockFrameworkManagerBy(context)
160164

161165
private val floatDelta: Float = 1e-6f
162166
private val doubleDelta = 1e-6
@@ -937,13 +941,6 @@ internal class CgMethodConstructor(val context: CgContext) : CgContextOwner by c
937941
}
938942

939943
private fun collectExecutionsResultFields() {
940-
val successfulExecutionsModels = allExecutions
941-
.filter {
942-
it.result is UtExecutionSuccess
943-
}.map {
944-
(it.result as UtExecutionSuccess).model
945-
}
946-
947944
for (model in successfulExecutionsModels) {
948945
when (model) {
949946
is UtCompositeModel -> {
@@ -1275,6 +1272,7 @@ internal class CgMethodConstructor(val context: CgContext) : CgContextOwner by c
12751272
rememberInitialStaticFields(statics)
12761273
val stateAnalyzer = ExecutionStateAnalyzer(execution)
12771274
val modificationInfo = stateAnalyzer.findModifiedFields()
1275+
val fieldStateManager = CgFieldStateManagerImpl(context)
12781276
// TODO: move such methods to another class and leave only 2 public methods: remember initial and final states
12791277
val mainBody = {
12801278
substituteStaticFields(statics)
@@ -1288,10 +1286,10 @@ internal class CgMethodConstructor(val context: CgContext) : CgContextOwner by c
12881286
val name = paramNames[executableId]?.get(index)
12891287
methodArguments += variableConstructor.getOrCreateVariable(param, name)
12901288
}
1291-
rememberInitialEnvironmentState(modificationInfo)
1289+
fieldStateManager.rememberInitialEnvironmentState(modificationInfo)
12921290
recordActualResult()
12931291
generateResultAssertions()
1294-
rememberFinalEnvironmentState(modificationInfo)
1292+
fieldStateManager.rememberFinalEnvironmentState(modificationInfo)
12951293
generateFieldStateAssertions()
12961294
}
12971295

utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/tree/CgTestClassConstructor.kt

+61-108
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,26 @@
11
package org.utbot.framework.codegen.model.constructor.tree
22

3-
import org.utbot.common.appendHtmlLine
3+
import org.utbot.framework.codegen.Junit4
4+
import org.utbot.framework.codegen.Junit5
45
import org.utbot.framework.codegen.ParametrizedTestSource
6+
import org.utbot.framework.codegen.TestNg
57
import org.utbot.framework.codegen.model.constructor.CgMethodTestSet
8+
import org.utbot.framework.codegen.model.constructor.TestClassModel
69
import org.utbot.framework.codegen.model.constructor.builtin.TestClassUtilMethodProvider
710
import org.utbot.framework.codegen.model.constructor.context.CgContext
811
import org.utbot.framework.codegen.model.constructor.context.CgContextOwner
9-
import org.utbot.framework.codegen.model.constructor.util.CgComponents
12+
import org.utbot.framework.codegen.model.constructor.name.CgNameGenerator
13+
import org.utbot.framework.codegen.model.constructor.name.CgNameGeneratorImpl
14+
import org.utbot.framework.codegen.model.constructor.tree.CgTestClassConstructor.CgComponents.clearContextRelatedStorage
15+
import org.utbot.framework.codegen.model.constructor.tree.CgTestClassConstructor.CgComponents.getMethodConstructorBy
16+
import org.utbot.framework.codegen.model.constructor.tree.CgTestClassConstructor.CgComponents.getNameGeneratorBy
17+
import org.utbot.framework.codegen.model.constructor.tree.CgTestClassConstructor.CgComponents.getStatementConstructorBy
18+
import org.utbot.framework.codegen.model.constructor.tree.CgTestClassConstructor.CgComponents.getTestFrameworkManagerBy
1019
import org.utbot.framework.codegen.model.constructor.util.CgStatementConstructor
11-
import org.utbot.framework.codegen.model.tree.CgMethod
20+
import org.utbot.framework.codegen.model.constructor.util.CgStatementConstructorImpl
21+
import org.utbot.framework.codegen.model.tree.CgAuxiliaryClass
1222
import org.utbot.framework.codegen.model.tree.CgExecutableUnderTestCluster
23+
import org.utbot.framework.codegen.model.tree.CgMethod
1324
import org.utbot.framework.codegen.model.tree.CgParameterDeclaration
1425
import org.utbot.framework.codegen.model.tree.CgRegion
1526
import org.utbot.framework.codegen.model.tree.CgSimpleRegion
@@ -18,32 +29,32 @@ import org.utbot.framework.codegen.model.tree.CgTestClass
1829
import org.utbot.framework.codegen.model.tree.CgTestClassFile
1930
import org.utbot.framework.codegen.model.tree.CgTestMethod
2031
import org.utbot.framework.codegen.model.tree.CgTestMethodCluster
21-
import org.utbot.framework.codegen.model.tree.CgTestMethodType.*
2232
import org.utbot.framework.codegen.model.tree.CgTripleSlashMultilineComment
33+
import org.utbot.framework.codegen.model.tree.CgUtilEntity
2334
import org.utbot.framework.codegen.model.tree.CgUtilMethod
2435
import org.utbot.framework.codegen.model.tree.buildTestClass
2536
import org.utbot.framework.codegen.model.tree.buildTestClassBody
2637
import org.utbot.framework.codegen.model.tree.buildTestClassFile
2738
import org.utbot.framework.codegen.model.visitor.importUtilMethodDependencies
39+
import org.utbot.framework.plugin.api.ClassId
2840
import org.utbot.framework.plugin.api.ExecutableId
2941
import org.utbot.framework.plugin.api.MethodId
42+
import org.utbot.framework.plugin.api.UtExecutionSuccess
3043
import org.utbot.framework.plugin.api.UtMethodTestSet
31-
import org.utbot.framework.codegen.model.constructor.TestClassModel
32-
import org.utbot.framework.codegen.model.tree.CgAuxiliaryClass
33-
import org.utbot.framework.codegen.model.tree.CgUtilEntity
34-
import org.utbot.framework.plugin.api.ClassId
3544
import org.utbot.framework.plugin.api.util.description
3645
import org.utbot.framework.plugin.api.util.humanReadableName
37-
import org.utbot.framework.plugin.api.util.kClass
38-
import kotlin.reflect.KClass
3946

4047
internal class CgTestClassConstructor(val context: CgContext) :
4148
CgContextOwner by context,
42-
CgStatementConstructor by CgComponents.getStatementConstructorBy(context) {
49+
CgStatementConstructor by getStatementConstructorBy(context) {
50+
51+
init {
52+
clearContextRelatedStorage()
53+
}
4354

44-
private val methodConstructor = CgComponents.getMethodConstructorBy(context)
45-
private val nameGenerator = CgComponents.getNameGeneratorBy(context)
46-
private val testFrameworkManager = CgComponents.getTestFrameworkManagerBy(context)
55+
private val methodConstructor = getMethodConstructorBy(context)
56+
private val nameGenerator = getNameGeneratorBy(context)
57+
private val testFrameworkManager = getTestFrameworkManagerBy(context)
4758

4859
private val testsGenerationReport: TestsGenerationReport = TestsGenerationReport()
4960

@@ -124,7 +135,10 @@ internal class CgTestClassConstructor(val context: CgContext) :
124135
return null
125136
}
126137

127-
allExecutions = testSet.executions
138+
successfulExecutionsModels = testSet
139+
.executions
140+
.filter { it.result is UtExecutionSuccess }
141+
.map { (it.result as UtExecutionSuccess).model }
128142

129143
val (methodUnderTest, _, _, clustersInfo) = testSet
130144
val regions = mutableListOf<CgRegion<CgMethod>>()
@@ -275,106 +289,45 @@ internal class CgTestClassConstructor(val context: CgContext) :
275289
*/
276290
private val CgMethodTestSet.allErrors: Map<String, Int>
277291
get() = errors + codeGenerationErrors.getOrDefault(this, mapOf())
278-
}
279292

280-
typealias MethodGeneratedTests = MutableMap<ExecutableId, MutableSet<CgTestMethod>>
281-
typealias ErrorsCount = Map<String, Int>
282-
283-
data class TestsGenerationReport(
284-
val executables: MutableSet<ExecutableId> = mutableSetOf(),
285-
var successfulExecutions: MethodGeneratedTests = mutableMapOf(),
286-
var timeoutExecutions: MethodGeneratedTests = mutableMapOf(),
287-
var failedExecutions: MethodGeneratedTests = mutableMapOf(),
288-
var crashExecutions: MethodGeneratedTests = mutableMapOf(),
289-
var errors: MutableMap<ExecutableId, ErrorsCount> = mutableMapOf()
290-
) {
291-
val classUnderTest: KClass<*>
292-
get() = executables.firstOrNull()?.classId?.kClass
293-
?: error("No executables found in test report")
294-
295-
val initialWarnings: MutableList<() -> String> = mutableListOf()
296-
val hasWarnings: Boolean
297-
get() = initialWarnings.isNotEmpty()
298-
299-
val detailedStatistics: String
300-
get() = buildString {
301-
appendHtmlLine("Class: ${classUnderTest.qualifiedName}")
302-
val testMethodsStatistic = executables.map { it.countTestMethods() }
303-
val errors = executables.map { it.countErrors() }
304-
val overallErrors = errors.sum()
305-
306-
appendHtmlLine("Successful test methods: ${testMethodsStatistic.sumBy { it.successful }}")
307-
appendHtmlLine(
308-
"Failing because of unexpected exception test methods: ${testMethodsStatistic.sumBy { it.failing }}"
309-
)
310-
appendHtmlLine(
311-
"Failing because of exceeding timeout test methods: ${testMethodsStatistic.sumBy { it.timeout }}"
312-
)
313-
appendHtmlLine(
314-
"Failing because of possible JVM crash test methods: ${testMethodsStatistic.sumBy { it.crashes }}"
315-
)
316-
appendHtmlLine("Not generated because of internal errors test methods: $overallErrors")
293+
internal object CgComponents {
294+
/**
295+
* Clears all stored data for current [CgContext].
296+
* As far as context is created per class under test,
297+
* no related data is required after it's processing.
298+
*/
299+
fun clearContextRelatedStorage() {
300+
nameGenerators.clear()
301+
statementConstructors.clear()
302+
callableAccessManagers.clear()
303+
testFrameworkManagers.clear()
304+
mockFrameworkManagers.clear()
305+
variableConstructors.clear()
306+
methodConstructors.clear()
317307
}
318308

319-
fun addMethodErrors(testSet: CgMethodTestSet, errors: Map<String, Int>) {
320-
this.errors[testSet.executableId] = errors
321-
}
309+
private val nameGenerators: MutableMap<CgContext, CgNameGenerator> = mutableMapOf()
310+
private val statementConstructors: MutableMap<CgContext, CgStatementConstructor> = mutableMapOf()
311+
private val callableAccessManagers: MutableMap<CgContext, CgCallableAccessManager> = mutableMapOf()
312+
private val testFrameworkManagers: MutableMap<CgContext, TestFrameworkManager> = mutableMapOf()
313+
private val mockFrameworkManagers: MutableMap<CgContext, MockFrameworkManager> = mutableMapOf()
322314

323-
fun addTestsByType(testSet: CgMethodTestSet, testMethods: List<CgTestMethod>) {
324-
with(testSet.executableId) {
325-
executables += this
326-
327-
testMethods.forEach {
328-
when (it.type) {
329-
SUCCESSFUL -> updateExecutions(it, successfulExecutions)
330-
FAILING -> updateExecutions(it, failedExecutions)
331-
TIMEOUT -> updateExecutions(it, timeoutExecutions)
332-
CRASH -> updateExecutions(it, crashExecutions)
333-
PARAMETRIZED -> {
334-
// Parametrized tests are not supported in the tests report yet
335-
// TODO JIRA:1507
336-
}
337-
}
338-
}
339-
}
340-
}
341-
342-
fun toString(isShort: Boolean): String = buildString {
343-
appendHtmlLine("Target: ${classUnderTest.qualifiedName}")
344-
if (initialWarnings.isNotEmpty()) {
345-
initialWarnings.forEach { appendHtmlLine(it()) }
346-
appendHtmlLine()
347-
}
348-
349-
val testMethodsStatistic = executables.map { it.countTestMethods() }
350-
val overallTestMethods = testMethodsStatistic.sumBy { it.count }
315+
private val variableConstructors: MutableMap<CgContext, CgVariableConstructor> = mutableMapOf()
316+
private val methodConstructors: MutableMap<CgContext, CgMethodConstructor> = mutableMapOf()
351317

352-
appendHtmlLine("Overall test methods: $overallTestMethods")
318+
fun getNameGeneratorBy(context: CgContext) = nameGenerators.getOrPut(context) { CgNameGeneratorImpl(context) }
319+
fun getCallableAccessManagerBy(context: CgContext) = callableAccessManagers.getOrPut(context) { CgCallableAccessManagerImpl(context) }
320+
fun getStatementConstructorBy(context: CgContext) = statementConstructors.getOrPut(context) { CgStatementConstructorImpl(context) }
353321

354-
if (!isShort) {
355-
appendHtmlLine(detailedStatistics)
322+
fun getTestFrameworkManagerBy(context: CgContext) = when (context.testFramework) {
323+
is Junit4 -> testFrameworkManagers.getOrPut(context) { Junit4Manager(context) }
324+
is Junit5 -> testFrameworkManagers.getOrPut(context) { Junit5Manager(context) }
325+
is TestNg -> testFrameworkManagers.getOrPut(context) { TestNgManager(context) }
356326
}
357-
}
358-
359-
override fun toString(): String = toString(false)
360-
361-
private fun ExecutableId.countTestMethods(): TestMethodStatistic = TestMethodStatistic(
362-
testMethodsNumber(successfulExecutions),
363-
testMethodsNumber(failedExecutions),
364-
testMethodsNumber(timeoutExecutions),
365-
testMethodsNumber(crashExecutions)
366-
)
367-
368-
private fun ExecutableId.countErrors(): Int = errors.getOrDefault(this, emptyMap()).values.sum()
369327

370-
private fun ExecutableId.testMethodsNumber(executables: MethodGeneratedTests): Int =
371-
executables.getOrDefault(this, emptySet()).size
372-
373-
private fun ExecutableId.updateExecutions(it: CgTestMethod, executions: MethodGeneratedTests) {
374-
executions.getOrPut(this) { mutableSetOf() } += it
375-
}
376-
377-
private data class TestMethodStatistic(val successful: Int, val failing: Int, val timeout: Int, val crashes: Int) {
378-
val count: Int = successful + failing + timeout + crashes
328+
fun getMockFrameworkManagerBy(context: CgContext) = mockFrameworkManagers.getOrPut(context) { MockFrameworkManager(context) }
329+
fun getVariableConstructorBy(context: CgContext) = variableConstructors.getOrPut(context) { CgVariableConstructor(context) }
330+
fun getMethodConstructorBy(context: CgContext) = methodConstructors.getOrPut(context) { CgMethodConstructor(context) }
379331
}
380332
}
333+

0 commit comments

Comments
 (0)