All tests are in the folder cylc-flow/tests
. Instructions here, unless
stated otherwise assume that you are working from your cylc-flow repo
dir.
Test Type | Command |
---|---|
Unit Tests | pytest |
Integration tests | pytest tests/integration |
Functional Tests | etc/bin/run-functional-tests |
Many tests rely on an alternative user config file called
flow-tests.rc
usually found at
~/.cylc/flow/<cylc-version>/flow-tests.rc
. flow-tests.rc
is used
instead of flow.rc
for tests.
Many tests (especially those which rely on non-local computers which
vary from developer to developer) use the skip_all
function from
test_header
and will return a message saying all tests have been
skipped if the correct remote settings have not been included in
flow-tests.rc
.
You may find the following idiom useful in a flow-test.rc
file:
#!jinja2
# You only have to change 1 line:
{% set MYTESTBRANCH = False %}
{% if MYTESTBRANCH == True %}
[settings]
[[for]]
your = test branch
{% elif %}
[settings]
[[for]]
master = branch
{% endif %}
You should first run tests in verbose mode using -vv
.
If you wish to use breakpoint()
to investigate failures then you will need
to add the following to your pytest command pytest <path> --dist=no -n0
to
turn off the test distribution mode.
Pytest’s own documetation is well worth a read: https://docs.pytest.org/en/stable/usage.html
You can run a single test using the following command:
cd ~/my/cylc/dev/copy
# run all the tests - this may take quite a long time
etc/bin/run-functional-tests.sh
# run a folder of tests
etc/bin/run-functional-tests.sh tests/functional/validate/
# run a single test
etc/bin/run-functional-tests.sh tests/functional/validate/00-multi.t
# run a single test in verbose mode
etc/bin/run-functional-tests.sh tests/functional/validate/00-multi.t -v
# maximum verbosity for supported tests
CYLC_TEST_DEBUG=true etc/bin/run-functional-tests.sh tests/validate/00-multi.t -v
note
adding
-v
to the test command is recommended if you are dealing with a failing test.
When running many tests you can record the tests that fail using
--state=save
. You can then re-run the only the failed tests using
--state=failed
.
For more details see man prove
.
If a test is failing the first step is to look at its test file. All test files (should) contain:
# Test validating simple multi-inheritance suites.
They will add the functions in the test_header file to the shell:
. "$(dirname "$0")/test_header"
.
hint
The test header file is a symlink in each test directory to
cylc.git/tests/lib/bash/test_header
. This file has a useful docstring. If you see an unfamiliar command in a test script it may well be definedtest_header
.
set_test_number 1
which allows the test
script to tell how many tests to expect.test_header
. Common examples
include run_ok
, run_fail
, cmp_ok
, grep_ok
and reftest
.Many of these functions take a TEST_NAME
argument which sets the name.
Often this is set by TEST_NAME=${TEST_NAME_BASE}-some-extra-label
where ${TEST_NAME_BASE}
is the name of the test file.
The tests use the bash shell so you can use bash commands to see what
they are doing, with the following caveat: To see the output you need to
redirect it to standard error using >&2
. If, for example, you wanted
to understand the directory structure of the temporary directory that
many tests create, you might add tree >&2
to a test before re-running
it.
Other useful commands include ls >&2
, cat ${TEST_NAME}.stdout >&2
and cat ${TEST_NAME}.stderr >&2
. These last will show you the standard
error and output of the last test, which may give you more information
about what went wrong.
In many cases you may get a test in the form
run_ok "${TEST_NAME}" cylc validate "${SUITE_NAME}"
. In these cases it
may be instructive to add a --debug
switch and examine the stderr
thus:
run_ok ${TEST_NAME} cylc validate --debug "${SUITE_NAME}"
cat ${TEST_NAME}.stderr >&2
cat ${TEST_NAME}.stdout >&2
Many tests also create and run a suite: You can find this in your
cylc-run folder under the name
cylctb-<date-time-string>
: Investigating this suite may often point you to the
cause of failure.
You can’t use a Python debugger straightforwardly inside the test framework - it will hang as it wait for interaction with the debugger that never comes. What you can do is place the following in the test before the cylc or rose command you wish to debug:
DUMPDIR=$(mktemp -d)
echo "Your test setup stuff is at ${DUMPDIR}" >&2
cp -r * ${DUMPDIR}
exit 0
This will dump all the test setup in a temporary directory for you to play with. If you want to debug a python program you can add Python debug statements to the code and run it:
These are:
# Python ≥ 3.7:
breakpoint()
# or Python < 3.7:
import pdb; pdb.set_trace()
Alternatively you may find that you can run the suite from your test.
Functional tests of form path/to/test.t
often come with a suite in the
form path/to/test/suite.rc
. You will need to remember to manually
provide any environment variables the workflow needs, and may need to
alter your flow.rc
to match flow-tests.rc
.
grep_ok
vs comp_ok
Tests that use comp_ok
generally compare ${TEST_NAME}.stdout
or
${TEST_NAME}.stderr
against either a reference or against /dev/null
.
They expect the entire output to be exactly the same as the
reference and are therefore very unforgiving.
grep_ok
is much less sensitive only requiring the reference output to
be present somewhere in the test output.
If you see code that looks like this:
cat >'hello.py' <<'__HELLO_PY__'
print("Hello World")
__HELLO_PY__
You are looking at an “heredoc” and you may wish to read about heredocs: A modern looking bloggy guide A web 1.0 manual