Skip to content

Implement properly streams closure after running cmd in JavaScript #1768

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Feb 3, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -39,22 +39,21 @@ class JsRunTestsCommand : CliktCommand(name = "run_js", help = "Runs tests for t
val outputAbsolutePath = output?.let { makeAbsolutePath(it) }
when (testFramework) {
"mocha" -> {
val (textReader, error) = JsCmdExec.runCommand(
val (inputText, errorText) = JsCmdExec.runCommand(
dir = dir,
shouldWait = true,
cmd = arrayOf("mocha", fileWithTestsAbsolutePath)
)
val errorText = error.readText()
if (errorText.isNotEmpty()) {
logger.error { "An error has occurred while running tests for $fileWithTests : $errorText" }
logger.error { "An error has occurred while running tests for $fileWithTests: $errorText" }
} else {
val text = textReader.readText()
outputAbsolutePath?.let {
val file = File(it)
file.createNewFile()
file.writeText(text)
} ?: logger.info { "\n$text" }
file.writeText(inputText)
} ?: logger.info { "Output absolute path is null with text: $inputText" }
}
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -105,11 +105,11 @@ object JsDialogProcessor {
try {
jsTestsModel?.pathToNode = NodeJsLocalInterpreterManager.getInstance()
.interpreters.first().interpreterSystemIndependentPath
val (_, error) = JsCmdExec.runCommand(
val (_, errorText) = JsCmdExec.runCommand(
shouldWait = true,
cmd = arrayOf("node", "-v")
)
if (error.readText().isNotEmpty()) throw NoSuchElementException()
if (errorText.isNotEmpty()) throw NoSuchElementException()
} catch (e: NoSuchElementException) {
Messages.showErrorDialog(
"Node.js interpreter is not found in IDEA settings.\n" +
Expand Down Expand Up @@ -266,9 +266,8 @@ fun installMissingRequirement(project: Project, pathToNPM: String, requirement:
if (result == Messages.CANCEL)
return

val (_, errorStream) = installRequirement(pathToNPM, requirement, project.basePath)
val (_, errorText) = installRequirement(pathToNPM, requirement, project.basePath)

val errorText = errorStream.readText()
if (errorText.isNotEmpty()) {
showErrorDialogLater(
project,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,35 +3,30 @@ package org.utbot.intellij.plugin.language.js
import com.intellij.openapi.ui.Messages
import utils.JsCmdExec
import utils.OsProvider
import java.io.BufferedReader

fun getFrameworkLibraryPath(npmPackageName: String, model: JsTestsModel?): String? {
val (bufferedReader, errorReader) = JsCmdExec.runCommand(
val (inputText, _) = JsCmdExec.runCommand(
dir = model?.project?.basePath!!,
shouldWait = true,
timeout = 10,
cmd = arrayOf(OsProvider.getProviderByOs().getAbstractivePathTool(), npmPackageName)
)
val input = bufferedReader.readText()
val error = errorReader.readText()

if ((error.isNotEmpty() or !input.contains(npmPackageName)) && !findFrameworkLibrary(npmPackageName, model)) {
if (!inputText.contains(npmPackageName) && !findFrameworkLibrary(npmPackageName, model)) {
installMissingRequirement(model.project, model.pathToNPM, npmPackageName)
return null
}
return input.substringBefore(npmPackageName) + npmPackageName
return inputText.substringBefore(npmPackageName) + npmPackageName
}

private fun npmListByFlag(model: JsTestsModel, flag: String): String {
val (bufferReader, _) = JsCmdExec.runCommand(
val (inputText, _) = JsCmdExec.runCommand(
dir = model.project.basePath!!,
shouldWait = true,
timeout = 10,
cmd = arrayOf(model.pathToNPM, "list", flag)
)
val packages = bufferReader.readText()
bufferReader.close()
return packages
return inputText
}

fun findFrameworkLibrary(npmPackageName: String, model: JsTestsModel): Boolean {
Expand All @@ -48,14 +43,15 @@ fun findFrameworkLibrary(npmPackageName: String, model: JsTestsModel): Boolean {
return packageText.contains(npmPackageName)
}

fun installRequirement(pathToNPM: String, requirement: String, installingDir: String?): Pair<BufferedReader, BufferedReader> {
fun installRequirement(pathToNPM: String, requirement: String, installingDir: String?): Pair<String, String> {
val installationType = if (requirement == "mocha") "-l" else "-g"

val (buf1, buf2) = JsCmdExec.runCommand(
val (inputText, errorText) = JsCmdExec.runCommand(
dir = installingDir,
shouldWait = true,
timeout = 10,
cmd = arrayOf(pathToNPM, "install", installationType) + requirement
)
return buf1 to buf2

return Pair(inputText, errorText)
}
2 changes: 1 addition & 1 deletion utbot-js/src/main/kotlin/api/JsUtModelConstructor.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@ import framework.api.js.JsUndefinedModel
import framework.api.js.util.jsErrorClassId
import framework.api.js.util.jsUndefinedClassId
import fuzzer.providers.JsObjectModelProvider
import org.utbot.framework.concrete.constructors.UtModelConstructorInterface
import org.utbot.framework.plugin.api.ClassId
import org.utbot.framework.plugin.api.UtAssembleModel
import org.utbot.framework.plugin.api.UtExecutableCallModel
import org.utbot.framework.plugin.api.UtModel
import org.utbot.instrumentation.instrumentation.execution.constructors.UtModelConstructorInterface

class JsUtModelConstructor : UtModelConstructorInterface {

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package framework.codegen.model.constructor.tree

import org.utbot.framework.plugin.api.ConcreteExecutionFailureException
import org.utbot.framework.plugin.api.ConstructorId
import org.utbot.framework.plugin.api.ExecutableId
import org.utbot.framework.plugin.api.MethodId
Expand All @@ -10,7 +9,6 @@ import org.utbot.framework.plugin.api.onFailure
import org.utbot.framework.plugin.api.onSuccess
import org.utbot.framework.plugin.api.util.voidClassId
import org.utbot.framework.util.isUnit
import java.security.AccessControlException
import org.utbot.framework.codegen.domain.context.CgContext
import org.utbot.framework.codegen.domain.models.CgTestMethod
import org.utbot.framework.codegen.domain.models.CgTestMethodType
Expand Down Expand Up @@ -110,24 +108,9 @@ class JsCgMethodConstructor(ctx: CgContext) : CgMethodConstructor(ctx) {
return
}

when (exception) {
is ConcreteExecutionFailureException -> {
methodType = CgTestMethodType.CRASH
writeWarningAboutCrash()
}

is AccessControlException -> {
methodType = CgTestMethodType.CRASH
writeWarningAboutFailureTest(exception)
return
}

else -> {
methodType = CgTestMethodType.FAILING
writeWarningAboutFailureTest(exception)
}
}
methodType = CgTestMethodType.FAILING
writeWarningAboutFailureTest(exception)

methodInvocationBlock()
}
}
}
13 changes: 6 additions & 7 deletions utbot-js/src/main/kotlin/service/BasicCoverageService.kt
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
package service

import java.io.File
import java.util.Collections
import org.apache.commons.io.FileUtils
import org.json.JSONException
import org.json.JSONObject
import org.utbot.framework.plugin.api.TimeoutException
import settings.JsTestGenerationSettings.tempFileName
import utils.JsCmdExec
import java.io.File
import java.util.Collections

// TODO: 1. Make searching for file coverage in coverage report more specific, not just by file name.
class BasicCoverageService(
Expand Down Expand Up @@ -102,7 +102,7 @@ class BasicCoverageService(
private fun generateCoverageReport(filePath: String, index: Int) {
try {
with(context) {
val (_, error) =
val (_, errorText) =
JsCmdExec.runCommand(
cmd = arrayOf(
settings.pathToNYC,
Expand All @@ -116,9 +116,8 @@ class BasicCoverageService(
dir = context.projectPath,
timeout = settings.timeout,
)
val errText = error.readText()
if (errText.isNotEmpty()) {
println(errText)
if (errorText.isNotEmpty()) {
println(errorText)
}
}
} catch (e: TimeoutException) {
Expand All @@ -142,4 +141,4 @@ class BasicCoverageService(
file.writeText(scriptText)
file.createNewFile()
}
}
}
20 changes: 11 additions & 9 deletions utbot-js/src/main/kotlin/service/FastCoverageService.kt
Original file line number Diff line number Diff line change
@@ -1,19 +1,22 @@
package service

import java.io.File
import java.util.Collections
import mu.KotlinLogging
import org.apache.commons.io.FileUtils
import org.json.JSONException
import org.json.JSONObject
import settings.JsTestGenerationSettings.tempFileName
import utils.JsCmdExec
import java.io.File
import java.util.Collections

private val logger = KotlinLogging.logger {}

class FastCoverageService(
private val context: ServiceContext,
private val scriptTexts: List<String>,
private val testCaseIndices: IntRange,
private val baseCoverageScriptText: String,
): ICoverageService {
) : ICoverageService {

private val utbotDirPath = "${context.projectPath}/${context.utbotDir}"
private val coverageList = mutableListOf<Pair<Int, JSONObject>>()
Expand Down Expand Up @@ -125,7 +128,7 @@ class FastCoverageService(
private fun generateCoverageReport() {
scriptTexts.indices.toList().parallelStream().forEach { parallelIndex ->
with(context) {
val (_, error) = JsCmdExec.runCommand(
val (_, errorText) = JsCmdExec.runCommand(
cmd = arrayOf(settings.pathToNode, "$utbotDirPath/$tempFileName$parallelIndex.js"),
dir = context.projectPath,
shouldWait = true,
Expand All @@ -137,13 +140,12 @@ class FastCoverageService(
resFile.delete()
val json = JSONObject(rawResult)
val index = json.getInt("index")
if (index != i) println("ERROR: index $index != i $i")
if (index != i) logger.error { "ERROR: index $index != i $i" }
coverageList.add(index to json.getJSONObject("s"))
_resultList.add(index to json.get("result").toString())
}
val errText = error.readText()
if (errText.isNotEmpty()) {
println(errText)
if (errorText.isNotEmpty()) {
logger.error { errorText }
}
}
}
Expand All @@ -155,4 +157,4 @@ class FastCoverageService(
file.writeText(scriptText)
file.createNewFile()
}
}
}
12 changes: 6 additions & 6 deletions utbot-js/src/main/kotlin/service/TernService.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ import com.google.javascript.rhino.Node
import framework.api.js.JsClassId
import framework.api.js.JsMultipleClassId
import framework.api.js.util.jsUndefinedClassId
import java.io.File
import java.util.Locale
import org.json.JSONException
import org.json.JSONObject
import parser.JsParserUtils
Expand All @@ -16,6 +14,8 @@ import parser.JsParserUtils.getConstructor
import utils.JsCmdExec
import utils.MethodTypes
import utils.constructClass
import java.io.File
import java.util.Locale

/*
NOTE: this approach is quite bad, but we failed to implement alternatives.
Expand Down Expand Up @@ -80,6 +80,7 @@ test("${context.filePathToInference}")
private fun installDeps(path: String) {
JsCmdExec.runCommand(
dir = path,
shouldWait = true,
cmd = arrayOf(context.settings.pathToNPM, "i", "tern", "-l")
)
}
Expand All @@ -92,15 +93,14 @@ test("${context.filePathToInference}")

private fun runTypeInferencer() {
with(context) {
val (reader, _) = JsCmdExec.runCommand(
val (inputText, _) = JsCmdExec.runCommand(
dir = "$projectPath/$utbotDir/",
shouldWait = true,
timeout = 20,
cmd = arrayOf(settings.pathToNode, "${projectPath}/$utbotDir/ternScript.js"),
)
val text = reader.readText().replaceAfterLast("}", "")
json = try {
JSONObject(text)
JSONObject(inputText.replaceAfterLast("}", ""))
} catch (_: Throwable) {
JSONObject()
}
Expand Down Expand Up @@ -205,4 +205,4 @@ test("${context.filePathToInference}")
classId
}
}
}
}
8 changes: 5 additions & 3 deletions utbot-js/src/main/kotlin/utils/JsCmdExec.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package utils

import org.utbot.framework.plugin.api.TimeoutException
import settings.JsTestGenerationSettings.defaultTimeout
import java.io.BufferedReader
import java.io.File
import java.util.concurrent.TimeUnit

Expand All @@ -13,7 +12,7 @@ object JsCmdExec {
shouldWait: Boolean = false,
timeout: Long = defaultTimeout,
vararg cmd: String,
): Pair<BufferedReader, BufferedReader> {
): Pair<String, String> {
val builder = ProcessBuilder(*OsProvider.getProviderByOs().getCmdPrefix(), *cmd)
dir?.let {
builder.directory(File(it))
Expand All @@ -28,6 +27,9 @@ object JsCmdExec {
throw TimeoutException("")
}
}
return Pair(process.inputStream.bufferedReader(), process.errorStream.bufferedReader())
return Pair(
process.inputStream.bufferedReader().use { it.readText() },
process.errorStream.bufferedReader().use { it.readText() }
)
}
}