Bubble errors from hardhat start

- bubble errors from hardhatprocess.start (instead of just logging)
- push raises: [] in all nodeprocess procs/methods to avoid leaking `Exception` exception types in method overrides
This commit is contained in:
Eric 2025-01-29 18:50:17 +11:00
parent 76a70021a9
commit 2d749035d2
No known key found for this signature in database
4 changed files with 68 additions and 30 deletions

View File

@ -15,12 +15,28 @@ export codexclient
export chronicles
export nodeprocess
{.push raises: [].}
logScope:
topics = "integration testing codex process"
type CodexProcess* = ref object of NodeProcess
type
CodexProcess* = ref object of NodeProcess
client: ?CodexClient
CodexProcessError* = object of NodeProcessError
proc raiseCodexProcessError(
msg: string, parent: ref CatchableError
) {.raises: [CodexProcessError].} =
raise newException(CodexProcessError, msg & ": " & parent.msg, parent)
template convertError(msg, body: typed) =
try:
body
except CatchableError as parent:
raiseCodexProcessError(msg, parent)
method workingDir(node: CodexProcess): string =
return currentSourcePath() / ".." / ".." / ".."
@ -33,27 +49,36 @@ method startedOutput(node: CodexProcess): string =
method processOptions(node: CodexProcess): set[AsyncProcessOption] =
return {AsyncProcessOption.StdErrToStdOut}
method outputLineEndings(node: CodexProcess): string {.raises: [].} =
method outputLineEndings(node: CodexProcess): string =
return "\n"
method onOutputLineCaptured(node: CodexProcess, line: string) {.raises: [].} =
method onOutputLineCaptured(node: CodexProcess, line: string) =
discard
proc dataDir(node: CodexProcess): string =
let config = CodexConf.load(cmdLine = node.arguments, quitOnFailure = false)
return config.dataDir.string
proc config(node: CodexProcess): CodexConf {.raises: [CodexProcessError].} =
# cannot use convertError here as it uses typed parameters which forces type
# resolution, while confutils.load uses untyped parameters and expects type
# resolution not to happen yet. In other words, it won't compile.
try:
return CodexConf.load(
cmdLine = node.arguments, quitOnFailure = false, secondarySources = nil
)
except ConfigurationError as parent:
raiseCodexProcessError "Failed to load node arguments into CodexConf", parent
proc ethAccount*(node: CodexProcess): Address =
let config = CodexConf.load(cmdLine = node.arguments, quitOnFailure = false)
without ethAccount =? config.ethAccount:
proc dataDir(node: CodexProcess): string {.raises: [CodexProcessError].} =
return node.config.dataDir.string
proc ethAccount*(node: CodexProcess): Address {.raises: [CodexProcessError].} =
without ethAccount =? node.config.ethAccount:
raiseAssert "eth account not set"
return Address(ethAccount)
proc apiUrl*(node: CodexProcess): string =
let config = CodexConf.load(cmdLine = node.arguments, quitOnFailure = false)
proc apiUrl*(node: CodexProcess): string {.raises: [CodexProcessError].} =
let config = node.config
return "http://" & config.apiBindAddress & ":" & $config.apiPort & "/api/codex/v1"
proc client*(node: CodexProcess): CodexClient =
proc client*(node: CodexProcess): CodexClient {.raises: [CodexProcessError].} =
if client =? node.client:
return client
let client = CodexClient.new(node.apiUrl)
@ -71,5 +96,6 @@ method stop*(node: CodexProcess) {.async.} =
client.close()
node.client = none CodexClient
method removeDataDir*(node: CodexProcess) =
method removeDataDir*(node: CodexProcess) {.raises: [CodexProcessError].} =
convertError("failed to remove codex node data directory"):
removeDir(node.dataDir)

View File

@ -19,6 +19,8 @@ export codexclient
export chronicles
export nodeprocess
{.push raises: [].}
logScope:
topics = "integration testing hardhat process"
@ -28,6 +30,8 @@ type
logFile: ?IoHandle
onOutputLine: OnOutputLineCaptured
HardhatProcessError* = object of NodeProcessError
method workingDir(node: HardhatProcess): string =
return currentSourcePath() / ".." / ".." / ".." / "vendor" / "codex-contracts-eth"
@ -40,7 +44,7 @@ method startedOutput(node: HardhatProcess): string =
method processOptions(node: HardhatProcess): set[AsyncProcessOption] =
return {}
method outputLineEndings(node: HardhatProcess): string {.raises: [].} =
method outputLineEndings(node: HardhatProcess): string =
return "\n"
proc openLogFile(node: HardhatProcess, logFilePath: string): IoHandle =
@ -55,14 +59,19 @@ proc openLogFile(node: HardhatProcess, logFilePath: string): IoHandle =
return fileHandle
method start*(node: HardhatProcess) {.async.} =
method start*(
node: HardhatProcess
) {.async: (raises: [CancelledError, NodeProcessError]).} =
logScope:
nodeName = node.name
try:
let binary = absolutePath(node.workingDir / node.executable)
if not fileExists(binary):
raiseAssert "cannot start hardhat, binary doesn't exist (looking for " &
&"{binary}). Try running `npm install` in {node.workingDir}."
except CatchableError as parent:
raiseAssert "failed build path to hardhat executable: " & parent.msg
let poptions = node.processOptions + {AsyncProcessOption.StdErrToStdOut}
trace "starting node",
@ -81,8 +90,10 @@ method start*(node: HardhatProcess) {.async.} =
)
except CancelledError as error:
raise error
except CatchableError as e:
error "failed to start hardhat process", error = e.msg
except CatchableError as parent:
raise newException(
HardhatProcessError, "failed to start hardhat process: " & parent.msg, parent
)
proc startNode*(
_: type HardhatProcess,

View File

@ -123,14 +123,13 @@ template multinodesuite*(name: string, body: untyped) =
args.add("--port")
args.add($port)
let node = await HardhatProcess.startNode(args, config.debugEnabled, "hardhat")
try:
let node = await HardhatProcess.startNode(args, config.debugEnabled, "hardhat")
await node.waitUntilStarted()
except NodeProcessError as e:
raiseMultiNodeSuiteError "hardhat node not started: " & e.msg
trace "hardhat node started"
return node
except NodeProcessError as e:
raiseMultiNodeSuiteError "hardhat node not started: " & e.msg
proc newCodexProcess(
roleIdx: int, conf: CodexConfig, role: Role

View File

@ -14,6 +14,8 @@ import ./codexclient
export codexclient
export chronicles
{.push raises:[].}
logScope:
topics = "integration testing node process"
@ -39,12 +41,12 @@ method startedOutput(node: NodeProcess): string {.base, gcsafe.} =
method processOptions(node: NodeProcess): set[AsyncProcessOption] {.base, gcsafe.} =
raiseAssert "not implemented"
method outputLineEndings(node: NodeProcess): string {.base, gcsafe, raises: [].} =
method outputLineEndings(node: NodeProcess): string {.base, gcsafe.} =
raiseAssert "not implemented"
method onOutputLineCaptured(
node: NodeProcess, line: string
) {.base, gcsafe, raises: [].} =
) {.base, gcsafe.} =
raiseAssert "not implemented"
method start*(node: NodeProcess) {.base, async.} =
@ -180,5 +182,5 @@ proc restart*(node: NodeProcess) {.async.} =
await node.start()
await node.waitUntilStarted()
method removeDataDir*(node: NodeProcess) {.base.} =
method removeDataDir*(node: NodeProcess) {.base, raises: [NodeProcessError].} =
raiseAssert "[removeDataDir] not implemented"