diff options
author | Leorize <leorize+oss@disroot.org> | 2019-10-03 17:36:07 +0200 |
---|---|---|
committer | narimiran <narimiran@disroot.org> | 2019-10-03 18:36:07 +0200 |
commit | acebcd7899bf497588b509bf0524368cf7323240 (patch) | |
tree | fe449a89e66ac1400ee029f2ecbf14d145133065 | |
parent | 880df4de625a7ae09da0a5b4b681ab4b49a98dbd (diff) | |
download | Nim-acebcd7899bf497588b509bf0524368cf7323240.tar.gz |
testament: add azure integration
-rw-r--r-- | testament/azure.nim | 95 | ||||
-rw-r--r-- | testament/specs.nim | 3 | ||||
-rw-r--r-- | testament/testament.nim | 33 | ||||
-rw-r--r-- | testament/testament.nim.cfg | 1 |
4 files changed, 122 insertions, 10 deletions
diff --git a/testament/azure.nim b/testament/azure.nim new file mode 100644 index 000000000..7299af480 --- /dev/null +++ b/testament/azure.nim @@ -0,0 +1,95 @@ +# +# +# The Nim Tester +# (c) Copyright 2019 Leorize +# +# Look at license.txt for more info. +# All rights reserved. + +import base64, json, httpclient, os, strutils +import specs + +const + ApiRuns = "/_apis/test/runs" + ApiVersion = "?api-version=5.0" + ApiResults = ApiRuns & "/$1/results" + +var runId* = -1 + +proc getAzureEnv(env: string): string = + # Conversion rule at: + # https://docs.microsoft.com/en-us/azure/devops/pipelines/process/variables#set-variables-in-pipeline + env.toUpperAscii().replace('.', '_').getEnv + +proc invokeRest(httpMethod: HttpMethod; api: string; body = ""): Response = + let http = newHttpClient() + defer: close http + result = http.request(getAzureEnv("System.TeamFoundationCollectionUri") & + getAzureEnv("System.TeamProjectId") & api & ApiVersion, + httpMethod, + $body, + newHttpHeaders { + "Accept": "application/json", + "Authorization": "Basic " & encode(':' & getAzureEnv("System.AccessToken")), + "Content-Type": "application/json" + }) + if not result.code.is2xx: + raise newException(HttpRequestError, "Server returned: " & result.body) + +proc finish*() {.noconv.} = + if not isAzure or runId < 0: + return + + try: + discard invokeRest(HttpPatch, + ApiRuns & "/" & $runId, + $ %* { "state": "Completed" }) + except: + stderr.writeLine "##vso[task.logissue type=warning;]Unable to finalize Azure backend" + stderr.writeLine getCurrentExceptionMsg() + + runId = -1 + +# TODO: Only obtain a run id if tests are run +# NOTE: We can't delete test runs with Azure's access token +proc start*() = + if not isAzure: + return + try: + if runId < 0: + runId = invokeRest(HttpPost, + ApiRuns, + $ %* { + "automated": true, + "build": { "id": getAzureEnv("Build.BuildId") }, + "buildPlatform": hostCPU, + "controller": "nim-testament", + "name": getAzureEnv("Agent.JobName") + }).body.parseJson["id"].getInt(-1) + except: + stderr.writeLine "##vso[task.logissue type=warning;]Unable to initialize Azure backend" + stderr.writeLine getCurrentExceptionMsg() + +proc addTestResult*(name, category: string; durationInMs: int; errorMsg: string; + outcome: TResultEnum) = + if not isAzure or runId < 0: + return + let outcome = case outcome + of reSuccess: "Passed" + of reDisabled, reJoined: "NotExecuted" + else: "Failed" + try: + discard invokeRest(HttpPost, + ApiResults % [$runId], + $ %* [{ + "automatedTestName": name, + "automatedTestStorage": category, + "durationInMs": durationInMs, + "errorMessage": errorMsg, + "outcome": outcome, + "testCaseTitle": name + }]) + except: + stderr.writeLine "##vso[task.logissue type=warning;]Unable to log test case: ", + name, ", outcome: ", outcome + stderr.writeLine getCurrentExceptionMsg() diff --git a/testament/specs.nim b/testament/specs.nim index 7943e63cc..30f2b97d1 100644 --- a/testament/specs.nim +++ b/testament/specs.nim @@ -13,6 +13,7 @@ var compilerPrefix* = findExe("nim") let isTravis* = existsEnv("TRAVIS") let isAppVeyor* = existsEnv("APPVEYOR") +let isAzure* = existsEnv("TF_BUILD") var skips*: seq[string] @@ -214,6 +215,8 @@ proc parseSpec*(filename: string): TSpec = if isTravis: result.err = reDisabled of "appveyor": if isAppVeyor: result.err = reDisabled + of "azure": + if isAzure: result.err = reDisabled of "32bit": if sizeof(int) == 4: result.err = reDisabled diff --git a/testament/testament.nim b/testament/testament.nim index da686a0c3..a52c573a7 100644 --- a/testament/testament.nim +++ b/testament/testament.nim @@ -12,7 +12,7 @@ import strutils, pegs, os, osproc, streams, json, backend, parseopt, specs, htmlgen, browsers, terminal, - algorithm, times, md5, sequtils + algorithm, times, md5, sequtils, azure include compiler/nodejs @@ -284,7 +284,7 @@ proc addResult(r: var TResults, test: TTest, target: TTarget, maybeStyledEcho styleBright, given, "\n" - if backendLogging and existsEnv("APPVEYOR"): + if backendLogging and (isAppVeyor or isAzure): let (outcome, msg) = case success of reSuccess: @@ -295,14 +295,17 @@ proc addResult(r: var TResults, test: TTest, target: TTarget, ("Failed", "Failure: " & $success & "\n" & given) else: ("Failed", "Failure: " & $success & "\nExpected:\n" & expected & "\n\n" & "Gotten:\n" & given) - var p = startProcess("appveyor", args=["AddTest", test.name.replace("\\", "/") & test.options, - "-Framework", "nim-testament", "-FileName", - test.cat.string, - "-Outcome", outcome, "-ErrorMessage", msg, - "-Duration", $(duration*1000).int], - options={poStdErrToStdOut, poUsePath, poParentStreams}) - discard waitForExit(p) - close(p) + if isAzure: + azure.addTestResult(name, test.cat.string, int(duration * 1000), msg, success) + else: + var p = startProcess("appveyor", args=["AddTest", test.name.replace("\\", "/") & test.options, + "-Framework", "nim-testament", "-FileName", + test.cat.string, + "-Outcome", outcome, "-ErrorMessage", msg, + "-Duration", $(duration*1000).int], + options={poStdErrToStdOut, poUsePath, poParentStreams}) + discard waitForExit(p) + close(p) proc cmpMsgs(r: var TResults, expected, given: TSpec, test: TTest, target: TTarget) = if strip(expected.msg) notin strip(given.msg): @@ -645,6 +648,8 @@ proc main() = quit Usage of "skipfrom": skipFrom = p.val.string + of "azurerunid": + runId = p.val.parseInt else: quit Usage p.next() @@ -657,6 +662,7 @@ proc main() = of "all": #processCategory(r, Category"megatest", p.cmdLineRest.string, testsDir, runJoinableTests = false) + azure.start() var myself = quoteShell(findExe("testament" / "testament")) if targetsStr.len > 0: myself &= " " & quoteShell("--targets:" & targetsStr) @@ -665,6 +671,8 @@ proc main() = if skipFrom.len > 0: myself &= " " & quoteShell("--skipFrom:" & skipFrom) + if isAzure: + myself &= " " & quoteShell("--azureRunId:" & $runId) var cats: seq[string] let rest = if p.cmdLineRest.string.len > 0: " " & p.cmdLineRest.string else: "" @@ -690,13 +698,16 @@ proc main() = progressStatus(i) processCategory(r, Category(cati), p.cmdLineRest.string, testsDir, runJoinableTests = false) else: + addQuitProc azure.finish quit osproc.execProcesses(cmds, {poEchoCmd, poStdErrToStdOut, poUsePath, poParentStreams}, beforeRunEvent = progressStatus) of "c", "cat", "category": + azure.start() skips = loadSkipFrom(skipFrom) var cat = Category(p.key) p.next processCategory(r, cat, p.cmdLineRest.string, testsDir, runJoinableTests = true) of "pcat": + azure.start() skips = loadSkipFrom(skipFrom) # 'pcat' is used for running a category in parallel. Currently the only # difference is that we don't want to run joinable tests here as they @@ -711,6 +722,7 @@ proc main() = p.next processPattern(r, pattern, p.cmdLineRest.string, simulate) of "r", "run": + azure.start() # at least one directory is required in the path, to use as a category name let pathParts = split(p.key.string, {DirSep, AltSep}) # "stdlib/nre/captures.nim" -> "stdlib" + "nre/captures.nim" @@ -726,6 +738,7 @@ proc main() = if action == "html": openDefaultBrowser(resultsFile) else: echo r, r.data backend.close() + if isMainProcess: azure.finish() var failed = r.total - r.passed - r.skipped if failed != 0: echo "FAILURE! total: ", r.total, " passed: ", r.passed, " skipped: ", diff --git a/testament/testament.nim.cfg b/testament/testament.nim.cfg index 27fd67075..69f044554 100644 --- a/testament/testament.nim.cfg +++ b/testament/testament.nim.cfg @@ -1 +1,2 @@ path = "$nim" # For compiler/nodejs +-d:ssl # For azure |