mirror of
https://github.com/logos-storage/logos-storage-nim.git
synced 2026-01-12 02:13:08 +00:00
In situations like timeouts, windows will hang when attempting to close the test process streams. In this case, we have to force kill the test process externally. This is the same process as force killing hardhat nodes after they are already terminated, but windows refuses hangs when closing their process streams. This commit creates a forceKillProcess utility that allows a process to be killed by its process name and matching commandline criteria, like TestId (for test process) or --port (for hardhat)
83 lines
2.6 KiB
Nim
83 lines
2.6 KiB
Nim
import std/os
|
|
import pkg/chronos
|
|
import pkg/chronos/asyncproc
|
|
import pkg/codex/logutils
|
|
|
|
{.push raises: [].}
|
|
|
|
proc nextFreePort*(startPort: int): Future[int] {.async: (raises: [CancelledError]).} =
|
|
proc client(server: StreamServer, transp: StreamTransport) {.async: (raises: []).} =
|
|
await transp.closeWait()
|
|
|
|
var port = startPort
|
|
while true:
|
|
trace "checking if port is free", port
|
|
try:
|
|
let host = initTAddress("127.0.0.1", port)
|
|
# We use ReuseAddr here only to be able to reuse the same IP/Port when
|
|
# there's a TIME_WAIT socket. It's useful when running the test multiple
|
|
# times or if a test ran previously using the same port.
|
|
var server = createStreamServer(host, client, {ReuseAddr})
|
|
trace "port is free", port
|
|
await server.closeWait()
|
|
return port
|
|
except TransportOsError:
|
|
trace "port is not free", port
|
|
inc port
|
|
except TransportAddressError:
|
|
raiseAssert "bad address"
|
|
|
|
proc sanitize*(pathSegment: string): string =
|
|
var sanitized = pathSegment
|
|
for invalid in invalidFilenameChars.items:
|
|
sanitized = sanitized.replace(invalid, '_').replace(' ', '_')
|
|
sanitized
|
|
|
|
proc getLogFile*(
|
|
logDir, startTime, suiteName, testName, role: string, index = int.none
|
|
): string {.raises: [IOError, OSError].} =
|
|
let logsDir =
|
|
if logDir == "":
|
|
currentSourcePath.parentDir() / "logs" / sanitize(startTime & "__" & suiteName) /
|
|
sanitize(testName)
|
|
else:
|
|
logDir / sanitize(suiteName) / sanitize(testName)
|
|
|
|
createDir(logsDir)
|
|
|
|
var fn = $role
|
|
if idx =? index:
|
|
fn &= "_" & $idx
|
|
fn &= ".log"
|
|
|
|
let fileName = logsDir / fn
|
|
return fileName
|
|
|
|
proc appendFile*(filename: string, content: string) {.raises: [IOError].} =
|
|
## Opens a file named `filename` for writing. Then writes the
|
|
## `content` completely to the file and closes the file afterwards.
|
|
## Raises an IO exception in case of an error.
|
|
var f: File
|
|
try:
|
|
f = open(filename, fmAppend)
|
|
f.write(content)
|
|
except IOError as e:
|
|
raise newException(IOError, "cannot open and write " & filename & ": " & e.msg)
|
|
finally:
|
|
close(f)
|
|
|
|
when defined(windows):
|
|
proc forceKillProcess(
|
|
processName, matchingCriteria: string
|
|
): Future[CommandExResponse] {.
|
|
async: (
|
|
raises: [
|
|
AsyncProcessError, AsyncProcessTimeoutError, CancelledError, ValueError, OSError
|
|
]
|
|
)
|
|
.} =
|
|
let path = splitFile(currentSourcePath()).dir / "scripts" / "winkillprocess.sh"
|
|
let cmd = &"{absolutePath(path)} kill {processName} \"{matchingCriteria}\""
|
|
trace "Forcefully killing windows process", processName, matchingCriteria, cmd
|
|
return await execCommandEx(cmd, timeout = 5.seconds)
|