diff options
author | Klaus Aehlig <klaus.aehlig@huawei.com> | 2022-02-23 15:02:50 +0100 |
---|---|---|
committer | Klaus Aehlig <klaus.aehlig@huawei.com> | 2022-02-23 15:02:50 +0100 |
commit | 42f55fd30b4b1bbb375924b762655cd318ca841a (patch) | |
tree | 7aea949d15a68f32b14048e95e0c874208d57e94 | |
parent | 488b7193c2b38d2324964ec4d40cdb17983d374d (diff) | |
download | justbuild-42f55fd30b4b1bbb375924b762655cd318ca841a.tar.gz |
Add shell/test rule
... allowing to run simple tests given by a shell script.
-rw-r--r-- | etc/defaults/shell/test/TARGETS | 1 | ||||
-rw-r--r-- | rules/shell/test/EXPRESSIONS | 116 | ||||
-rw-r--r-- | rules/shell/test/RULES | 50 | ||||
-rwxr-xr-x | rules/shell/test/test_runner.sh | 44 |
4 files changed, 211 insertions, 0 deletions
diff --git a/etc/defaults/shell/test/TARGETS b/etc/defaults/shell/test/TARGETS new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/etc/defaults/shell/test/TARGETS @@ -0,0 +1 @@ +{} diff --git a/rules/shell/test/EXPRESSIONS b/rules/shell/test/EXPRESSIONS new file mode 100644 index 00000000..429cd475 --- /dev/null +++ b/rules/shell/test/EXPRESSIONS @@ -0,0 +1,116 @@ +{ "test-result": + { "vars": ["name", "test.sh"] + , "expression": + { "type": "let*" + , "bindings": + [ [ "runner" + , { "type": "map_union" + , "$1": + { "type": "foreach" + , "var": "runner" + , "range": {"type": "FIELD", "name": "runner"} + , "body": + { "type": "map_union" + , "$1": + { "type": "foreach" + , "var": "runner" + , "range": + { "type": "values" + , "$1": + { "type": "DEP_ARTIFACTS" + , "dep": {"type": "var", "name": "runner"} + } + } + , "body": + { "type": "singleton_map" + , "key": "runner" + , "value": {"type": "var", "name": "runner"} + } + } + } + } + } + ] + , [ "deps" + , { "type": "TREE" + , "$1": + { "type": "disjoint_map_union" + , "msg": "Field 'deps' has to stage in a conflict free way" + , "$1": + { "type": "++" + , "$1": + [ { "type": "foreach" + , "var": "dep" + , "range": {"type": "FIELD", "name": "deps"} + , "body": + { "type": "DEP_RUNFILES" + , "dep": {"type": "var", "name": "dep"} + } + } + , { "type": "foreach" + , "var": "dep" + , "range": {"type": "FIELD", "name": "deps"} + , "body": + { "type": "DEP_ARTIFACTS" + , "dep": {"type": "var", "name": "dep"} + } + } + ] + } + } + } + ] + , [ "test-results" + , { "type": "ACTION" + , "outs": + { "type": "++" + , "$1": + [ ["result", "stdout", "stderr", "time-start", "time-stop"] + , { "type": "foreach" + , "var": "filename" + , "range": {"type": "FIELD", "name": "keep"} + , "body": + { "type": "join" + , "$1": ["work/", {"type": "var", "name": "filename"}] + } + } + ] + } + , "inputs": + { "type": "map_union" + , "$1": + [ { "type": "singleton_map" + , "key": "work" + , "value": {"type": "var", "name": "deps"} + } + , {"type": "var", "name": "runner"} + , {"type": "var", "name": "test.sh"} + ] + } + , "cmd": + { "type": "++" + , "$1": [["./runner"], {"type": "FIELD", "name": "keep"}] + } + , "may_fail": ["test"] + , "fail_message": + { "type": "join" + , "$1": ["shell test ", {"type": "var", "name": "name"}, " failed"] + } + } + ] + , [ "runfiles" + , { "type": "singleton_map" + , "key": {"type": "var", "name": "name"} + , "value": + {"type": "TREE", "$1": {"type": "var", "name": "test-results"}} + } + ] + ] + , "body": + { "type": "RESULT" + , "artifacts": {"type": "var", "name": "test-results"} + , "runfiles": {"type": "var", "name": "runfiles"} + } + } + } +} diff --git a/rules/shell/test/RULES b/rules/shell/test/RULES new file mode 100644 index 00000000..ca5ddbcf --- /dev/null +++ b/rules/shell/test/RULES @@ -0,0 +1,50 @@ +{ "script": + { "doc": ["Shell test, given by a test script"] + , "target_fields": ["deps", "test"] + , "string_fields": ["keep", "name"] + , "field_doc": + { "test": ["The shell script for the test, launched with sh"] + , "name": + [ "A name for the test, used in reporting, as well as for staging" + , "the test result tree in the runfiles" + ] + , "keep": + [ "List of names (relativ to the test working directory) of files that" + , "the test might generate that should be kept as part of the output." + , "This might be useful for further analysis of the test" + ] + , "deps": + [ "Any targets that should be staged (with artifacts and runfiles) into" + , "the tests working directory" + ] + } + , "tainted": ["test"] + , "implicit": {"runner": ["test_runner.sh"]} + , "imports": + { "test-result": "test-result" + , "stage": ["./", "../..", "stage_singleton_field"] + } + , "expression": + { "type": "let*" + , "bindings": + [ [ "test.sh" + , { "type": "context" + , "msg": "Expecting 'test' to specify precisely one file containing a shell script" + , "$1": + { "type": "let*" + , "bindings": [["fieldname", "test"], ["location", "test.sh"]] + , "body": {"type": "CALL_EXPRESSION", "name": "stage"} + } + } + ] + , [ "name" + , { "type": "assert_non_empty" + , "msg": "Have to provide a non-empty name for the test (e.g., for result staging)" + , "$1": {"type": "join", "$1": {"type": "FIELD", "name": "name"}} + } + ] + ] + , "body": {"type": "CALL_EXPRESSION", "name": "test-result"} + } + } +} diff --git a/rules/shell/test/test_runner.sh b/rules/shell/test/test_runner.sh new file mode 100755 index 00000000..969b80ad --- /dev/null +++ b/rules/shell/test/test_runner.sh @@ -0,0 +1,44 @@ +#!/bin/sh + +# ensure all required outputs are present +touch stdout +touch stderr +RESULT=UNKNOWN +echo "${RESULT}" > result +echo UNKNOWN > time-start +echo UNKNOWN > time-stop + +mkdir scratch +export TEST_TMPDIR=$(realpath scratch) +export TMPDIR="${TEST_TMPDIR}" + +# Change to the working directory; note: while unlikely, the test +# might not have test data, so we have to ensure the presence of +# the work directory. +mkdir -p work +cd work + +date +%s > ../time-start +# TODO: +# - proper wrapping with timeout +if sh ../test.sh > ../stdout 2> ../stderr +then + RESULT=PASS +else + RESULT=FAIL +fi +date +%s > ../time-stop + +# Ensure all the promissed output files in the work directory +# are present, even if the test failed to create them. +for f in "$@" +do + touch "./${f}" +done + +echo "${RESULT}" > ../result + +if [ "${RESULT}" '!=' PASS ] +then + exit 1; +fi |