summaryrefslogtreecommitdiff
path: root/share
diff options
context:
space:
mode:
Diffstat (limited to 'share')
-rw-r--r--share/common/lib/files.yaml58
-rw-r--r--share/common/lib/runcmd.yaml65
-rw-r--r--share/python/lib/daemon.yaml69
-rw-r--r--share/python/lib/runcmd.py1
-rw-r--r--share/python/template/scenarios.py10
-rw-r--r--share/rust/lib/datadir.yaml7
-rw-r--r--share/rust/template/macros.rs.tera2
-rw-r--r--share/rust/template/template.rs.tera2
-rw-r--r--share/subplot.css40
9 files changed, 247 insertions, 7 deletions
diff --git a/share/common/lib/files.yaml b/share/common/lib/files.yaml
index cb39b96..689a5f3 100644
--- a/share/common/lib/files.yaml
+++ b/share/common/lib/files.yaml
@@ -10,6 +10,9 @@
function: files_create_from_embedded
types:
embedded_file: file
+ doc: |
+ Create a file on disk from an embedded file in the subplot
+ document. The created file has the same name as the embedded file.
- given: file {filename_on_disk} from {embedded_file}
impl:
@@ -20,6 +23,9 @@
types:
filename_on_disk: path
embedded_file: file
+ doc: |
+ Create a file on disk from an embedded file in the subplot
+ document. Set the name of the created file.
- when: I write "{text}" to file {filename}
impl:
@@ -30,6 +36,8 @@
types:
filename: path
text: text
+ doc: |
+ Create a file on disk with the given content.
# Manage directories (distinct from files).
@@ -41,6 +49,8 @@
function: files_make_directory
types:
path: path
+ doc: |
+ Create a directory on disk.
- when: I create directory {path}
impl:
@@ -50,6 +60,8 @@
function: files_make_directory
types:
path: path
+ doc: |
+ Create a directory on disk.
- when: I remove directory {path}
impl:
@@ -59,6 +71,8 @@
function: files_remove_directory
types:
path: path
+ doc: |
+ Remove a directory on disk.
- then: directory {path} exists
impl:
@@ -68,6 +82,8 @@
function: files_directory_exists
types:
path: path
+ doc: |
+ Check that a directory exists.
- then: directory {path} does not exist
impl:
@@ -77,6 +93,8 @@
function: files_directory_does_not_exist
types:
path: path
+ doc: |
+ Check that a directory does not exist.
- then: directory {path} is empty
impl:
@@ -86,6 +104,8 @@
function: files_directory_is_empty
types:
path: path
+ doc: |
+ Check that a directory exists and does not contain anything.
- then: directory {path} is not empty
impl:
@@ -95,6 +115,8 @@
function: files_directory_is_not_empty
types:
path: path
+ doc: |
+ Check that a directory exists and contains something.
# File metadata management and testing.
@@ -108,6 +130,8 @@
types:
filename: path
mtime: text
+ doc: |
+ Create a file with specific modification time.
- when: I remember metadata for file {filename}
impl:
@@ -117,6 +141,8 @@
function: files_remember_metadata
types:
filename: path
+ doc: |
+ Remember the metadata of a file.
- when: I touch file {filename}
impl:
@@ -126,6 +152,8 @@
function: files_touch
types:
filename: path
+ doc: |
+ Update the modification time of a file to be current time.
- then: file {filename} has same metadata as before
impl:
@@ -135,6 +163,9 @@
function: files_has_remembered_metadata
types:
filename: path
+ doc: |
+ Check that a file has the same metadata as remembered from
+ earlier.
- then: file {filename} has different metadata from before
impl:
@@ -144,6 +175,8 @@
function: files_has_different_metadata
types:
filename: path
+ doc: |
+ Check that a file metadata has changed from earlier.
- then: file {filename} has changed from before
impl:
@@ -153,6 +186,8 @@
function: files_has_different_metadata
types:
filename: path
+ doc: |
+ Check that file metadata has changed from before.
- then: file {filename} has a very recent modification time
impl:
@@ -162,6 +197,8 @@
function: files_mtime_is_recent
types:
filename: path
+ doc: |
+ Check that file modification time is recent.
- then: file {filename} has a very old modification time
impl:
@@ -171,6 +208,8 @@
function: files_mtime_is_ancient
types:
filename: path
+ doc: |
+ Check that file modification is far in the past.
# Testing file existence.
@@ -182,6 +221,8 @@
function: files_file_exists
types:
filename: path
+ doc: |
+ Check that a file exist.
- then: file {filename} does not exist
impl:
@@ -191,6 +232,8 @@
function: files_file_does_not_exist
types:
filename: path
+ doc: |
+ Check that a file does not exist.
- then: only files (?P<filenames>.+) exist
impl:
@@ -199,6 +242,10 @@
python:
function: files_only_these_exist
regex: true
+ types:
+ filenames: text
+ doc: |
+ Check that the test directory only contains specific files.
# Tests on file content.
@@ -211,6 +258,8 @@
types:
filename: path
data: text
+ doc: |
+ Check that a file contains a string.
- then: file {filename} doesn't contain "{data}"
impl:
@@ -221,6 +270,8 @@
types:
filename: path
data: text
+ doc: |
+ Check that a file does not contain a string.
- then: file {filename} matches regex /{regex}/
impl:
@@ -231,6 +282,8 @@
types:
filename: path
regex: text
+ doc: |
+ Check that file content matches a regular expression.
- then: file {filename} matches regex "{regex}"
impl:
@@ -241,6 +294,8 @@
types:
filename: path
regex: text
+ doc: |
+ Check that file content matches a regular expression.
- then: files {filename1} and {filename2} match
impl:
@@ -251,4 +306,5 @@
types:
filename1: path
filename2: path
-
+ doc: |
+ Check that two files have the same content.
diff --git a/share/common/lib/runcmd.yaml b/share/common/lib/runcmd.yaml
index 7be2c05..b20eac8 100644
--- a/share/common/lib/runcmd.yaml
+++ b/share/common/lib/runcmd.yaml
@@ -8,6 +8,8 @@
function: subplotlib::steplibrary::runcmd::helper_script
types:
script: file
+ doc: |
+ Install a helper script from an embedded file.
- given: srcdir is in the PATH
impl:
@@ -15,6 +17,10 @@
function: runcmd_helper_srcdir_path
rust:
function: subplotlib::steplibrary::runcmd::helper_srcdir_path
+ doc: |
+ Make sure the source directory of the project being testes is on
+ the shell PATH. This makes it easy for tests to invoke programs
+ from the source tree.
- when: I run {argv0}{args:text}
impl:
@@ -22,6 +28,8 @@
function: runcmd_step
rust:
function: subplotlib::steplibrary::runcmd::run
+ doc: |
+ Run a program, and make sure it succeeds.
- when: I run, in {dirname}, {argv0}{args}
impl:
@@ -33,6 +41,9 @@
dirname: path
argv0: word
args: text
+ doc: |
+ Change to a different directory and run a program, and make sure
+ it succeeds;
- when: I try to run {argv0}{args:text}
impl:
@@ -40,6 +51,9 @@
function: runcmd_try_to_run
rust:
function: subplotlib::steplibrary::runcmd::try_to_run
+ doc: |
+ Run a program, but allow it to fail. Other steps can check if it
+ succeeded.
- when: I try to run, in {dirname}, {argv0}{args}
impl:
@@ -51,6 +65,9 @@
dirname: path
argv0: word
args: text
+ doc: |
+ Change to a different directory and run a program, but allow it to
+ fail. Other steps can check if it succeeded.
# Steps to examine exit code of latest command.
@@ -62,6 +79,9 @@
function: subplotlib::steplibrary::runcmd::exit_code_is
types:
exit: int
+ doc: |
+ Make sure the latest command run by `lib/runcmd` had a specific
+ exit code.
- then: exit code is not {exit}
impl:
@@ -71,6 +91,9 @@
function: subplotlib::steplibrary::runcmd::exit_code_is_not
types:
exit: int
+ doc: |
+ Make sure the latest command run by `lib/runcmd` did not have a
+ specific exit code.
- then: command is successful
impl:
@@ -78,6 +101,9 @@
function: runcmd_exit_code_is_zero
rust:
function: subplotlib::steplibrary::runcmd::exit_code_is_zero
+ doc: |
+ Make sure the latest command run by `lib/runcmd` indicated the
+ command succeeded.
- then: command fails
impl:
@@ -85,6 +111,9 @@
function: runcmd_exit_code_is_nonzero
rust:
function: subplotlib::steplibrary::runcmd::exit_code_is_nonzero
+ doc: |
+ Make sure the latest command run by `lib/runcmd` indicated the
+ command failed.
# Steps to examine stdout/stderr for exact content.
@@ -94,6 +123,9 @@
function: runcmd_stdout_is
rust:
function: subplotlib::steplibrary::runcmd::stdout_is
+ doc: |
+ Make sure the standard output of the latest command run by
+ `lib/runcmd` is exactly as desired.
- then: 'stdout isn''t exactly "{text:text}"'
impl:
@@ -101,6 +133,9 @@
function: runcmd_stdout_isnt
rust:
function: subplotlib::steplibrary::runcmd::stdout_isnt
+ doc: |
+ Make sure the standard output of the latest command run by
+ `lib/runcmd` is different from what is not wanted.
- then: stderr is exactly "{text:text}"
impl:
@@ -108,6 +143,9 @@
function: runcmd_stderr_is
rust:
function: subplotlib::steplibrary::runcmd::stderr_is
+ doc: |
+ Make sure the standard error output of the latest command run by
+ `lib/runcmd` is exactly as desired.
- then: 'stderr isn''t exactly "{text:text}"'
impl:
@@ -115,6 +153,9 @@
function: runcmd_stderr_isnt
rust:
function: subplotlib::steplibrary::runcmd::stderr_isnt
+ doc: |
+ Make sure the standard error output of the latest command run by
+ `lib/runcmd` is different from what is not wanted.
# Steps to examine stdout/stderr for sub-strings.
@@ -124,6 +165,9 @@
function: runcmd_stdout_contains
rust:
function: subplotlib::steplibrary::runcmd::stdout_contains
+ doc: |
+ Make sure the standard output of the latest command run by
+ `lib/runcmd` contains the desired sub-string.
- then: 'stdout doesn''t contain "{text:text}"'
impl:
@@ -131,6 +175,9 @@
function: runcmd_stdout_doesnt_contain
rust:
function: subplotlib::steplibrary::runcmd::stdout_doesnt_contain
+ doc: |
+ Make sure the standard output of the latest command run by
+ `lib/runcmd` does not contain the sub-string.
- then: stderr contains "{text:text}"
impl:
@@ -138,6 +185,9 @@
function: runcmd_stderr_contains
rust:
function: subplotlib::steplibrary::runcmd::stderr_contains
+ doc: |
+ Make sure the standard output of the latest command run by
+ `lib/runcmd` contains the desired sub-string.
- then: 'stderr doesn''t contain "{text:text}"'
impl:
@@ -145,6 +195,9 @@
function: runcmd_stderr_doesnt_contain
rust:
function: subplotlib::steplibrary::runcmd::stderr_doesnt_contain
+ doc: |
+ Make sure the standard error output of the latest command run by
+ `lib/runcmd` does not contain the sub-string.
# Steps to match stdout/stderr against regular expressions.
@@ -154,6 +207,9 @@
function: runcmd_stdout_matches_regex
rust:
function: subplotlib::steplibrary::runcmd::stdout_matches_regex
+ doc: |
+ Make sure the standard output of the latest command run by
+ `lib/runcmd` matches the desired regular expression.
- then: stdout doesn't match regex {regex:text}
impl:
@@ -161,6 +217,9 @@
function: runcmd_stdout_doesnt_match_regex
rust:
function: subplotlib::steplibrary::runcmd::stdout_doesnt_match_regex
+ doc: |
+ Make sure the standard output of the latest command run by
+ `lib/runcmd` does not match a regular expression.
- then: stderr matches regex {regex:text}
impl:
@@ -168,6 +227,9 @@
function: runcmd_stderr_matches_regex
rust:
function: subplotlib::steplibrary::runcmd::stderr_matches_regex
+ doc: |
+ Make sure the standard error output of the latest command run by
+ `lib/runcmd` matches the desired regular expression.
- then: stderr doesn't match regex {regex:text}
impl:
@@ -175,3 +237,6 @@
function: runcmd_stderr_doesnt_match_regex
rust:
function: subplotlib::steplibrary::runcmd::stderr_doesnt_match_regex
+ doc: |
+ Make sure the standard error output of the latest command run by
+ `lib/runcmd` does not match a regular expression.
diff --git a/share/python/lib/daemon.yaml b/share/python/lib/daemon.yaml
index acca151..e385880 100644
--- a/share/python/lib/daemon.yaml
+++ b/share/python/lib/daemon.yaml
@@ -2,6 +2,8 @@
impl:
python:
function: daemon_no_such_process
+ doc: |
+ Ensure a given process is not running.
- given: a daemon helper shell script {filename}
impl:
@@ -9,88 +11,155 @@
function: _daemon_shell_script
types:
filename: file
+ doc: |
+ Install a helper script from an embedded file.
- when: I start "{path}{args:text}" as a background process as {name}, on port {port}
impl:
python:
function: daemon_start_on_port
+ doc: |
+ Start a process in the background (as a daemon) and wait until it
+ listens on its assigned port.
- when: I start "(?P<path>[^ "]+)(?P<args>[^"]*)" as a background process as (?P<name>[^,]+), on port (?P<port>\d+), with environment (?P<env>.*)
regex: true
+ types:
+ args: text
+ path: path
+ name: text
+ port: uint
+ env: text
impl:
python:
function: daemon_start_on_port
+ doc: |
+ Start a process in the background (as a daemon) and wait until it
+ listens on its assigned port. Remember the process under the given
+ name.
- when: I try to start "{path}{args:text}" as {name}, on port {port}
impl:
python:
function: _daemon_start_soonish
cleanup: _daemon_stop_soonish
+ doc: |
+ Try to start a background process (as a daemon), but don't fail if
+ starting it fails.
- when: I try to start "(?P<path>[^ "]+)(?P<args>[^"]*)" as (?P<name>[^,]+), on port (?P<port>\d+), with environment (?P<env>.*)
regex: true
+ types:
+ path: path
+ args: text
+ name: text
+ port: uint
+ env: text
impl:
python:
function: _daemon_start_soonish
cleanup: _daemon_stop_soonish
+ doc: |
+ Start a process in the background (as a daemon) and wait until it
+ listens on its assigned port. Remember the process under the given
+ name. Don't fail if this fails.
- when: I start "{path}{args:text}" as a background process as {name}
impl:
python:
function: _daemon_start
+ doc: |
+ Start a process in the background (as a daemon). Remember the
+ process under the given name. Don't fail if this fails.
- when: I start "(?P<path>[^ "]+)(?P<args>[^"]*)" as a background process as (?P<name>[^,]+), with environment (?P<env>.*)
regex: true
+ types:
+ path: path
+ args: text
+ name: text
+ env: text
impl:
python:
function: _daemon_start
+ doc: |
+ Start a process in the background (as a daemon), with specific
+ environment variables set. Remember the process under the given
+ name. Don't fail if this fails.
- when: I stop background process {name}
impl:
python:
function: daemon_stop
+ doc: |
+ Stop a background process that was started earlier with the given
+ name.
- when: daemon {name} has produced output
impl:
python:
function: daemon_has_produced_output
+ doc: |
+ Wait until the named daemon has produced output to its stdout or
+ stderr.
- then: a process "{args:text}" is running
impl:
python:
function: daemon_process_exists
+ doc: |
+ Check that a given process is running.
- then: there is no "{args:text}" process
impl:
python:
function: daemon_no_such_process
+ doc: |
+ Check that a given process is not running.
- then: starting daemon fails with "{message:text}"
impl:
python:
function: daemon_start_fails_with
+ doc: |
+ Check that starting a daemon previously failed, and the error
+ message contains the given text.
- then: starting the daemon succeeds
impl:
python:
function: daemon_start_succeeds
+ doc: |
+ Check that staring a daemon previous succeeded.
- then: daemon {name} stdout is "{text:text}"
impl:
python:
function: daemon_stdout_is
+ doc: |
+ Check that the named daemon has written exactly the given text to
+ its stdout.
- then: daemon {name} stdout contains "{text:text}"
impl:
python:
function: daemon_stdout_contains
+ doc: |
+ Check that the named daemon has written the given text to its
+ stdout, possibly among other text.
- then: daemon {name} stdout doesn't contain "{text:text}"
impl:
python:
function: daemon_stdout_doesnt_contain
+ doc: |
+ Check that the named daemon has not written the given text to its
+ stdout.
- then: daemon {name} stderr is "{text:text}"
impl:
python:
function: daemon_stderr_is
+ doc: |
+ Check that the named daemon has written exactly the given text to
+ its stderr.
diff --git a/share/python/lib/runcmd.py b/share/python/lib/runcmd.py
index c4a6a12..6a4965f 100644
--- a/share/python/lib/runcmd.py
+++ b/share/python/lib/runcmd.py
@@ -70,7 +70,6 @@ def runcmd_run(ctx, argv, **kwargs):
logging.debug("runcmd_run: running command")
log_value("argv", 1, dict(enumerate(argv)))
- log_value("env", 1, env)
log_value("kwargs:", 1, kwargs)
p = subprocess.Popen(argv, env=env, **kwargs)
diff --git a/share/python/template/scenarios.py b/share/python/template/scenarios.py
index b215133..a6aa9f4 100644
--- a/share/python/template/scenarios.py
+++ b/share/python/template/scenarios.py
@@ -42,12 +42,14 @@ class Step:
self._cleanup(ctx, **self._args)
+_logged_env = False
+
+
class Scenario:
def __init__(self, ctx):
self._title = None
self._steps = []
self._ctx = ctx
- self._logged_env = False
def get_title(self):
return self._title
@@ -91,7 +93,9 @@ class Scenario:
os.environ.update(overrides)
os.environ.update(extra_env)
- if not self._logged_env:
- self._logged_env = True
+ global _logged_env
+ if not _logged_env:
+ _logged_env = True
log_value("extra_env", 0, dict(extra_env))
+ log_value("overrides", 0, dict(overrides))
log_value("os.environ", 0, dict(os.environ))
diff --git a/share/rust/lib/datadir.yaml b/share/rust/lib/datadir.yaml
index f4c313b..b77e5ef 100644
--- a/share/rust/lib/datadir.yaml
+++ b/share/rust/lib/datadir.yaml
@@ -9,9 +9,16 @@
function: subplotlib::steplibrary::datadir::datadir_has_enough_space
types:
bytes: uint
+ doc: |
+ Check the test data directory has at least the given amount of
+ free space expressed as bytes.
+
- given: datadir has at least {megabytes}M of space
impl:
rust:
function: subplotlib::steplibrary::datadir::datadir_has_enough_space_megabytes
types:
megabytes: uint
+ doc: |
+ Check the test data directory has at least the given amount of
+ free space expressed as megabytes.
diff --git a/share/rust/template/macros.rs.tera b/share/rust/template/macros.rs.tera
index 104eb23..cc1d9c4 100644
--- a/share/rust/template/macros.rs.tera
+++ b/share/rust/template/macros.rs.tera
@@ -27,5 +27,5 @@
)
{% endif -%}
{% endfor -%}
- .build(format!("{} {}", "{{step.kind | lower}}", base64_decode("{{step.text | base64}}")))
+ .build(format!("{} {}", "{{step.kind | lower}}", base64_decode("{{step.text | base64}}")), {{ step.origin | location }})
{%- endmacro builder -%}
diff --git a/share/rust/template/template.rs.tera b/share/rust/template/template.rs.tera
index 65fb755..447129c 100644
--- a/share/rust/template/template.rs.tera
+++ b/share/rust/template/template.rs.tera
@@ -30,7 +30,7 @@ lazy_static! {
#[test]
#[allow(non_snake_case)]
fn {{ scenario.title | nameslug }}() {
- let mut scenario = Scenario::new(&base64_decode("{{scenario.title | base64}}"));
+ let mut scenario = Scenario::new(&base64_decode("{{scenario.title | base64}}"), {{ scenario.origin | location }});
{% for step in scenario.steps %}
let step = {{ macros::builder(stepfn=step.function, step=step) }};
{%- if step.cleanup %}
diff --git a/share/subplot.css b/share/subplot.css
new file mode 100644
index 0000000..292a5f7
--- /dev/null
+++ b/share/subplot.css
@@ -0,0 +1,40 @@
+div.toc ol {
+ list-style-type: none;
+ padding: 0;
+ padding-inline-start: 2ch;
+}
+
+pre.file {
+ background: yellow;
+ border: 10px black;
+ padding: 1em;
+}
+
+div.scenario {
+ background: yellow;
+ padding: 1em;
+}
+
+span.capture-word {
+ font-family: monospace;
+}
+span.capture-text {
+ font-family: monospace;
+}
+span.capture-int {
+ font-weight: bold;
+}
+span.capture-uint {
+ font-weight: bold;
+}
+span.capture-number {
+ font-weight: bold;
+}
+span.capture-file {
+ font-family: monospace;
+}
+
+span.capture-path {
+ font-family: monospace;
+ font-weight: bold;
+}