1
1
package org.utbot.intellij.plugin.process
2
2
3
3
import com.intellij.ide.plugins.cl.PluginClassLoader
4
- import com.intellij.openapi.application.ApplicationManager
4
+ import com.intellij.openapi.project.DumbService
5
+ import com.intellij.openapi.project.Project
5
6
import com.intellij.psi.PsiMethod
6
7
import com.intellij.refactoring.util.classMembers.MemberInfo
7
8
import com.jetbrains.rd.util.lifetime.Lifetime
8
- import com.jetbrains.rd.util.lifetime.onTermination
9
9
import com.jetbrains.rd.util.lifetime.throwIfNotAlive
10
10
import kotlinx.coroutines.runBlocking
11
11
import kotlinx.coroutines.sync.Mutex
12
12
import kotlinx.coroutines.sync.withLock
13
13
import mu.KotlinLogging
14
- import org.jetbrains.kotlin.scripting.resolve.classId
15
14
import org.utbot.common.AbstractSettings
16
15
import org.utbot.common.getPid
16
+ import org.utbot.common.osSpecificJavaExecutable
17
17
import org.utbot.common.utBotTempDirectory
18
18
import org.utbot.framework.UtSettings
19
19
import org.utbot.framework.codegen.*
20
20
import org.utbot.framework.codegen.model.UtilClassKind
21
- import org.utbot.framework.codegen.model.constructor.tree.TestsGenerationReport
22
21
import org.utbot.framework.plugin.api.*
23
22
import org.utbot.framework.plugin.services.JdkInfo
24
23
import org.utbot.framework.plugin.services.JdkInfoDefaultProvider
25
24
import org.utbot.framework.plugin.services.JdkInfoService
26
25
import org.utbot.framework.plugin.services.WorkingDirService
26
+ import org.utbot.framework.process.OpenModulesContainer
27
27
import org.utbot.framework.process.generated.*
28
28
import org.utbot.framework.process.generated.Signature
29
29
import org.utbot.framework.util.Conflict
@@ -39,85 +39,77 @@ import org.utbot.rd.startUtProcessWithRdServer
39
39
import org.utbot.sarif.SourceFindingStrategy
40
40
import java.io.File
41
41
import java.nio.file.Path
42
- import java.util.*
42
+ import kotlin.io.path.deleteIfExists
43
43
import kotlin.io.path.pathString
44
44
import kotlin.random.Random
45
45
import kotlin.reflect.KProperty1
46
46
import kotlin.reflect.full.memberProperties
47
47
48
+ private val engineProcessLogConfigurations = utBotTempDirectory.toFile().resolve(" rdEngineProcessLogConfigurations" )
48
49
private val logger = KotlinLogging .logger {}
49
50
private val engineProcessLogDirectory = utBotTempDirectory.toFile().resolve(" rdEngineProcessLogs" )
50
51
51
- data class RdGTestenerationResult (val notEmptyCases : Int , val testSetsId : Long )
52
+ data class RdTestGenerationResult (val notEmptyCases : Int , val testSetsId : Long )
52
53
53
- class EngineProcess (val lifetime : Lifetime ) {
54
+ class EngineProcess (parent : Lifetime , val project : Project ) {
55
+ private val ldef = parent.createNested()
54
56
private val id = Random .nextLong()
55
57
private var count = 0
58
+ private var configPath: Path ? = null
56
59
57
- companion object {
58
- private var configPath: Path ? = null
59
- private fun getOrCreateLogConfig (): String {
60
- var realPath = configPath
61
- if (realPath == null ) {
62
- synchronized(this ) {
63
- realPath = configPath
64
- if (realPath == null ) {
65
- utBotTempDirectory.toFile().mkdirs()
66
- configPath = utBotTempDirectory.toFile().resolve(" EngineProcess_log4j2.xml" ).apply {
67
- writeText(
68
- """ <?xml version="1.0" encoding="UTF-8"?>
60
+ private fun getOrCreateLogConfig (): String {
61
+ var realPath = configPath
62
+ if (realPath == null ) {
63
+ engineProcessLogConfigurations.mkdirs()
64
+ configPath = File .createTempFile(" epl" , " .xml" , engineProcessLogConfigurations).apply {
65
+ val onMatch = if (UtSettings .logConcreteExecutionErrors) " NEUTRAL" else " DENY"
66
+ writeText(
67
+ """ <?xml version="1.0" encoding="UTF-8"?>
69
68
<Configuration>
70
69
<Appenders>
71
70
<Console name="Console" target="SYSTEM_OUT">
72
- <ThresholdFilter level="ERROR " onMatch="DENY " onMismatch="DENY"/>
71
+ <ThresholdFilter level="${ UtSettings .engineProcessLogLevel.name.uppercase()} " onMatch="$onMatch " onMismatch="DENY"/>
73
72
<PatternLayout pattern="%d{HH:mm:ss.SSS} | %-5level | %c{1} | %msg%n"/>
74
73
</Console>
75
74
</Appenders>
76
75
<Loggers>
77
- <Root level="error ">
76
+ <Root level="${ UtSettings .engineProcessLogLevel.name.lowercase()} ">
78
77
<AppenderRef ref="Console"/>
79
78
</Root>
80
79
</Loggers>
81
80
</Configuration>"""
82
- )
83
- }.toPath()
84
- realPath = configPath
85
- }
86
- }
87
- }
88
- return realPath!! .pathString
81
+ )
82
+ }.toPath()
83
+ realPath = configPath
89
84
}
85
+ return realPath!! .pathString
90
86
}
91
- // because we cannot load idea bundled lifetime or it will break everything
92
87
93
88
private fun debugArgument (): String {
94
89
return " -agentlib:jdwp=transport=dt_socket,server=y,suspend=y,quiet=y,address=5005" .takeIf { Settings .runIdeaProcessWithDebug }
95
90
? : " "
96
91
}
97
92
98
- private val kryoHelper = KryoHelper (lifetime )
93
+ private val kryoHelper = KryoHelper (ldef )
99
94
100
95
private suspend fun engineModel (): EngineProcessModel {
101
- lifetime .throwIfNotAlive()
96
+ ldef .throwIfNotAlive()
102
97
return lock.withLock {
103
98
var proc = current
104
99
105
100
if (proc == null ) {
106
- proc = startUtProcessWithRdServer(lifetime ) { port ->
101
+ proc = startUtProcessWithRdServer(ldef ) { port ->
107
102
val current = JdkInfoDefaultProvider ().info
108
103
val required = JdkInfoService .jdkInfoProvider.info
109
104
val java =
110
- JdkInfoService .jdkInfoProvider.info.path.resolve(" bin${File .separatorChar} javaw " ).toString()
105
+ JdkInfoService .jdkInfoProvider.info.path.resolve(" bin${File .separatorChar}${osSpecificJavaExecutable()} " ).toString()
111
106
val cp = (this .javaClass.classLoader as PluginClassLoader ).classPath.baseUrls.joinToString(
112
107
separator = " ;" ,
113
108
prefix = " \" " ,
114
109
postfix = " \" "
115
110
)
116
111
val classname = " org.utbot.framework.process.EngineMainKt"
117
- val javaVersionSpecificArguments =
118
- listOf (" --add-opens" , " java.base/jdk.internal.misc=ALL-UNNAMED" , " --illegal-access=warn" )
119
- .takeIf { JdkInfoService .provide().version > 8 }
120
- ? : emptyList()
112
+ val javaVersionSpecificArguments = OpenModulesContainer .javaVersionSpecificArguments
121
113
val directory = WorkingDirService .provide().toFile()
122
114
val log4j2ConfigFile = " \" -Dlog4j2.configurationFile=${getOrCreateLogConfig()} \" "
123
115
val debugArg = debugArgument()
@@ -172,7 +164,7 @@ class EngineProcess(val lifetime: Lifetime) {
172
164
private var current: ProcessWithRdServer ? = null
173
165
174
166
fun setupUtContext (classpathForUrlsClassloader : List <String >) = runBlocking {
175
- engineModel().setupUtContext.startSuspending(lifetime , SetupContextParams (classpathForUrlsClassloader))
167
+ engineModel().setupUtContext.startSuspending(ldef , SetupContextParams (classpathForUrlsClassloader))
176
168
}
177
169
178
170
// suppose that only 1 simultaneous test generator process can be executed in idea
@@ -186,7 +178,7 @@ class EngineProcess(val lifetime: Lifetime) {
186
178
) = runBlocking {
187
179
engineModel().isCancelled.set(handler = isCancelled)
188
180
engineModel().createTestGenerator.startSuspending(
189
- lifetime ,
181
+ ldef ,
190
182
TestGeneratorParams (buildDir.toTypedArray(), classPath, dependencyPaths, JdkInfo (jdkInfo.path.pathString, jdkInfo.version))
191
183
)
192
184
}
@@ -238,9 +230,9 @@ class EngineProcess(val lifetime: Lifetime) {
238
230
isFuzzingEnabled : Boolean ,
239
231
fuzzingValue : Double ,
240
232
searchDirectory : String
241
- ): RdGTestenerationResult = runBlocking {
233
+ ): RdTestGenerationResult = runBlocking {
242
234
val result = engineModel().generate.startSuspending(
243
- lifetime ,
235
+ ldef ,
244
236
GenerateParams (
245
237
mockInstalled,
246
238
staticsMockingIsConfigured,
@@ -257,7 +249,7 @@ class EngineProcess(val lifetime: Lifetime) {
257
249
)
258
250
)
259
251
260
- return @runBlocking RdGTestenerationResult (result.notEmptyCases, result.testSetsId)
252
+ return @runBlocking RdTestGenerationResult (result.notEmptyCases, result.testSetsId)
261
253
}
262
254
263
255
fun render (
@@ -278,7 +270,7 @@ class EngineProcess(val lifetime: Lifetime) {
278
270
testClassPackageName : String
279
271
): Pair <String , UtilClassKind ?> = runBlocking {
280
272
val result = engineModel().render.startSuspending(
281
- lifetime , RenderParams (
273
+ ldef , RenderParams (
282
274
testSetsId,
283
275
kryoHelper.writeObject(classUnderTest),
284
276
kryoHelper.writeObject(paramNames),
@@ -300,9 +292,9 @@ class EngineProcess(val lifetime: Lifetime) {
300
292
}
301
293
302
294
fun forceTermination () = runBlocking {
295
+ configPath?.deleteIfExists()
303
296
engineModel().stopProcess.start(Unit )
304
297
current?.terminate()
305
- engineModel().writeSarifReport
306
298
}
307
299
308
300
fun writeSarif (reportFilePath : Path ,
@@ -312,23 +304,23 @@ class EngineProcess(val lifetime: Lifetime) {
312
304
) = runBlocking {
313
305
current!! .protocol.rdSourceFindingStrategy.let {
314
306
it.getSourceFile.set { params ->
315
- ApplicationManager .getApplication().runReadAction <String ?> {
307
+ DumbService .getInstance(project).runReadActionInSmartMode <String ?> {
316
308
sourceFindingStrategy.getSourceFile(
317
309
params.classFqn,
318
310
params.extension
319
311
)?.canonicalPath
320
312
}
321
313
}
322
314
it.getSourceRelativePath.set { params ->
323
- ApplicationManager .getApplication().runReadAction <String > {
315
+ DumbService .getInstance(project).runReadActionInSmartMode <String > {
324
316
sourceFindingStrategy.getSourceRelativePath(
325
317
params.classFqn,
326
318
params.extension
327
319
)
328
320
}
329
321
}
330
322
it.testsRelativePath.set { _ ->
331
- ApplicationManager .getApplication().runReadAction <String > {
323
+ DumbService .getInstance(project).runReadActionInSmartMode <String > {
332
324
sourceFindingStrategy.testsRelativePath
333
325
}
334
326
}
@@ -374,8 +366,8 @@ class EngineProcess(val lifetime: Lifetime) {
374
366
}
375
367
376
368
init {
377
- lifetime .onTermination {
378
- current?.terminate ()
369
+ ldef .onTermination {
370
+ forceTermination ()
379
371
}
380
372
}
381
373
}
0 commit comments