diff --git a/ls.nim b/ls.nim index aa12e35..ba2ad47 100644 --- a/ls.nim +++ b/ls.nim @@ -160,6 +160,8 @@ type nimDumpCache*: Table[string, NimbleDumpInfo] #path to NimbleDumpInfo entryPoints*: seq[string] responseMap*: TableRef[string, Future[JsonNode]] + testRunProcess*: Option[AsyncProcessRef] #There is only one test run process at a time + #id to future. Represents the pending requests as result of calling ls.call srv*: RpcSocketServer #Both modes uses it to store the routes. Only actually started in socket mode diff --git a/nimlangserver.nim b/nimlangserver.nim index 728ade1..bfff2f3 100644 --- a/nimlangserver.nim +++ b/nimlangserver.nim @@ -68,6 +68,7 @@ proc registerRoutes(srv: RpcSocketServer, ls: LanguageServer) = srv.register("extension/runTask", wrapRpc(partial(runTask, ls))) srv.register("extension/listTests", wrapRpc(partial(listTests, ls))) srv.register("extension/runTests", wrapRpc(partial(runTests, ls))) + srv.register("extension/cancelTest", wrapRpc(partial(cancelTest, ls))) #Notifications srv.register("$/cancelRequest", wrapRpc(partial(cancelRequest, ls))) srv.register("initialized", wrapRpc(partial(initialized, ls))) diff --git a/protocol/types.nim b/protocol/types.nim index 4eb98a4..29ad822 100644 --- a/protocol/types.nim +++ b/protocol/types.nim @@ -1088,3 +1088,5 @@ type suites*: seq[RunTestSuiteResult] fullOutput*: string + CancelTestResult* = object + cancelled*: bool diff --git a/routes.nim b/routes.nim index fe65428..c802c41 100644 --- a/routes.nim +++ b/routes.nim @@ -869,7 +869,18 @@ proc runTests*( error "Nim path not found when running tests" return RunTestProjectResult() let workspaceRoot = ls.initializeParams.getRootPath - await runTests(params.entryPoint, nimPath.get(), params.suiteName, params.testNames.get(@[]), workspaceRoot) + await runTests(params.entryPoint, nimPath.get(), params.suiteName, params.testNames.get(@[]), workspaceRoot, ls) + +proc cancelTest*( + ls: LanguageServer, params: JsonNode +): Future[CancelTestResult] {.async.} = + debug "Cancelling test" + if ls.testRunProcess.isSome: #No need to cancel the runTests request. The client should handle it. + await shutdownChildProcess(ls.testRunProcess.get) + ls.testRunProcess = none(AsyncProcessRef) + CancelTestResult(cancelled: true) + else: + CancelTestResult(cancelled: false) #Notifications proc initialized*(ls: LanguageServer, _: JsonNode): Future[void] {.async.} = diff --git a/testrunner.nim b/testrunner.nim index b75fd25..2d027ac 100644 --- a/testrunner.nim +++ b/testrunner.nim @@ -96,7 +96,8 @@ proc runTests*( nimPath: string, suiteName: Option[string], testNames: seq[string], - workspaceRoot: string + workspaceRoot: string, + ls: LanguageServer ): Future[RunTestProjectResult] {.async.} = var entryPoint = getFullPath(entryPoint, workspaceRoot) if not fileExists(entryPoint): @@ -117,6 +118,7 @@ proc runTests*( stderrHandle = AsyncProcess.Pipe, stdoutHandle = AsyncProcess.Pipe, ) + ls.testRunProcess = some(process) try: let res = await process.waitForExit(15.seconds) let processOutput = string.fromBytes(process.stdoutStream.read().await) @@ -138,4 +140,5 @@ proc runTests*( error "Output from process", output = processOutput finally: await shutdownChildProcess(process) - \ No newline at end of file + if ls.testRunProcess.isSome: + ls.testRunProcess = none(AsyncProcessRef) \ No newline at end of file diff --git a/tests/ttestrunner.nim b/tests/ttestrunner.nim index b5113b0..8a66528 100644 --- a/tests/ttestrunner.nim +++ b/tests/ttestrunner.nim @@ -3,6 +3,7 @@ import std/[os, osproc, strscans, tables, sequtils, enumerate, strutils, options import testhelpers import testrunner import chronos +import ls suite "Test Parser": test "should be able to list tests from an entry point": @@ -36,7 +37,8 @@ suite "Test Parser": suite "Test Runner": test "should be able to run tests and retrieve results": let entryPoint = getCurrentDir() / "tests" / "projects" / "testrunner" / "tests" / "sampletests.nim" - let testProjectResult = waitFor runTests(entryPoint, "nim", none(string), @[], "") + let ls = LanguageServer() + let testProjectResult = waitFor runTests(entryPoint, "nim", none(string), @[], "", ls) check testProjectResult.suites.len == 4 check testProjectResult.suites[0].name == "Sample Tests" check testProjectResult.suites[0].tests == 1