Skip to content

Commit 1003814

Browse files
authored
Improves test runner process handling (#334)
1 parent 38adf69 commit 1003814

File tree

2 files changed

+72
-35
lines changed

2 files changed

+72
-35
lines changed

testrunner.nim

Lines changed: 43 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -36,32 +36,6 @@ proc getFullPath*(entryPoint: string, workspaceRoot: string): string =
3636
return absolutePath
3737
return entryPoint
3838

39-
proc listTests*(
40-
entryPoint: string,
41-
nimPath: string,
42-
workspaceRoot: string
43-
): Future[TestProjectInfo] {.async.} =
44-
var entryPoint = getFullPath(entryPoint, workspaceRoot)
45-
let process = await startProcess(
46-
nimPath,
47-
arguments = @["c", "-d:unittest2ListTests", "-r", "--listFullPaths", entryPoint],
48-
options = {UsePath},
49-
stderrHandle = AsyncProcess.Pipe,
50-
stdoutHandle = AsyncProcess.Pipe,
51-
)
52-
try:
53-
let res = await process.waitForExit(15.seconds)
54-
if res != 0:
55-
error "Failed to list tests", nimPath = nimPath, entryPoint = entryPoint, res = res
56-
let error = string.fromBytes(process.stderrStream.read().await)
57-
error "An error occurred while listing tests", error = error
58-
result = TestProjectInfo(error: some error)
59-
else:
60-
let rawOutput = string.fromBytes(process.stdoutStream.read().await)
61-
result = extractTestInfo(rawOutput)
62-
finally:
63-
await shutdownChildProcess(process)
64-
6539
proc parseObject(obj: var object, node: XmlNode) =
6640
for field, value in obj.fieldPairs:
6741
when value is string:
@@ -91,6 +65,37 @@ proc parseTestResults*(xmlContent: string): RunTestProjectResult =
9165
if suite.testResults.len > 0:
9266
result.suites.add(suite)
9367

68+
proc listTests*(
69+
entryPoint: string,
70+
nimPath: string,
71+
workspaceRoot: string
72+
): Future[TestProjectInfo] {.async.} =
73+
var entryPoint = getFullPath(entryPoint, workspaceRoot)
74+
debug "Listing tests", entryPoint = entryPoint, exists = fileExists(entryPoint)
75+
let args = @["c", "-d:unittest2ListTests", "-r", entryPoint]
76+
let process = await startProcess(
77+
nimPath,
78+
arguments = args,
79+
options = {UsePath},
80+
stderrHandle = AsyncProcess.Pipe,
81+
stdoutHandle = AsyncProcess.Pipe,
82+
)
83+
try:
84+
let (error, res) = await readErrorOutputUntilExit(process, 15.seconds)
85+
if res != 0:
86+
error "Failed to list tests", nimPath = nimPath, entryPoint = entryPoint, res = res
87+
error "An error occurred while listing tests"
88+
for line in error.splitLines:
89+
error "Error line: ", line = line
90+
error "Command args: ", args = args
91+
result = TestProjectInfo(error: some error)
92+
else:
93+
let rawOutput = await readAllOutput(process.stdoutStream)
94+
debug "list test raw output", rawOutput = rawOutput
95+
result = extractTestInfo(rawOutput)
96+
finally:
97+
await shutdownChildProcess(process)
98+
9499
proc runTests*(
95100
entryPoint: string,
96101
nimPath: string,
@@ -120,19 +125,23 @@ proc runTests*(
120125
)
121126
ls.testRunProcess = some(process)
122127
try:
123-
let res = await process.waitForExit(15.seconds)
124-
let processOutput = string.fromBytes(process.stdoutStream.read().await)
128+
removeFile(resultFile)
129+
let (error, res) = await readErrorOutputUntilExit(process, 15.seconds)
130+
if res != 0: #When a test fails, the process will exit with a non-zero code
131+
if fileExists(resultFile):
132+
result = parseTestResults(readFile(resultFile))
133+
result.fullOutput = error
134+
return result
125135

126-
if not fileExists(resultFile):
127-
let processError = string.fromBytes(process.stderrStream.read().await)
128-
error "Result file does not exist meaning tests were not run"
129-
error "Output from process", output = processOutput
130-
error "Error from process", error = processError
136+
error "Failed to run tests", nimPath = nimPath, entryPoint = entryPoint, res = res
137+
error "An error occurred while running tests"
138+
error "Error from process", error = error
139+
result = RunTestProjectResult(fullOutput: error)
131140
else:
132141
let xmlContent = readFile(resultFile)
133142
# echo "XML CONTENT: ", xmlContent
134143
result = parseTestResults(xmlContent)
135-
result.fullOutput = processOutput
144+
result.fullOutput = error
136145
removeFile(resultFile)
137146
except Exception as e:
138147
let processOutput = string.fromBytes(process.stdoutStream.read().await)

utils.nim

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import chronos, chronicles, chronos/asyncproc
33
import "$nim/compiler/pathutils"
44
import json_rpc/private/jrpc_sys
55
import macros
6+
import stew/byteutils
67

78
type
89
FingerTable = seq[tuple[u16pos, offset: int]]
@@ -357,4 +358,31 @@ proc shutdownChildProcess*(p: AsyncProcessRef): Future[void] {.async.} =
357358
writeStackTrace()
358359

359360
macro getField*(obj: object, fld: string): untyped =
360-
result = newDotExpr(obj, newIdentNode(fld.strVal))
361+
result = newDotExpr(obj, newIdentNode(fld.strVal))
362+
363+
364+
proc readAllOutput*(stream: AsyncStreamReader): Future[string] {.async.} =
365+
result = ""
366+
while not stream.atEof:
367+
let data = await stream.read()
368+
result.add(string.fromBytes(data))
369+
370+
proc readErrorOutputUntilExit*(process: AsyncProcessRef, duration: Duration): Future[tuple[output: string, code: int]] {.async.} =
371+
var output = ""
372+
var res = 0
373+
while true:
374+
if not process.stderrStream.atEof:
375+
let data = await process.stderrStream.read()
376+
output.add(string.fromBytes(data))
377+
378+
let hasExited = try:
379+
res = await process.waitForExit(duration)
380+
true
381+
except AsyncTimeoutError:
382+
false
383+
384+
if hasExited:
385+
while not process.stderrStream.atEof:
386+
let data = await process.stderrStream.read()
387+
output.add(string.fromBytes(data))
388+
return (output, res)

0 commit comments

Comments
 (0)