Tests are run with: `make check [flags]` where the pertinent flags are:
```shell
DEVELOPER=[0|1] - developer mode increases test coverage
VALGRIND=[0|1] - detects memory leaks during test execution but adds a significant delay
PYTEST_PAR=n - runs pytests in parallel
```
A modern desktop can build and run through all the tests in a couple of minutes with:
```shell Shell
make -j12 full-check PYTEST_PAR=24 DEVELOPER=1 VALGRIND=0
```
Adjust `-j` and `PYTEST_PAR` accordingly for your hardware.
There are four kinds of tests:
- **source tests** - run by `make check-source`, looks for whitespace, header order, and checks formatted quotes from BOLTs if BOLTDIR exists.
- **unit tests** - standalone programs that can be run individually. You can also run all of the unit tests with `make check-units`. They are `run-*.c` files in test/ subdirectories used to test routines inside C source files.
You should insert the lines when implementing a unit test:
`/* AUTOGENERATED MOCKS START */`
`/* AUTOGENERATED MOCKS END */`
and `make update-mocks` will automatically generate stub functions which will allow you to link (and conveniently crash if they're called).
- **blackbox tests** - These tests setup a mini-regtest environment and test lightningd as a whole. They can be run individually:
You can also append `-k TESTNAME` to run a single test. Environment variables `DEBUG_SUBD=<subdaemon>` and `TIMEOUT=<seconds>` can be useful for debugging subdaemons on individual tests.
- **pylightning tests** - will check contrib pylightning for codestyle and run the tests in `contrib/pylightning/tests` afterwards:
`make check-python`
Our Github Actions instance (see `.github/workflows/*.yml`) runs all these for each pull request.
#### Additional Environment Variables
```text
TEST_CHECK_DBSTMTS=[0|1] - When running blackbox tests, this will
load a plugin that logs all compiled
and expanded database statements.
Note: Only SQLite3.
TEST_DB_PROVIDER=[sqlite3|postgres] - Selects the database to use when running
##### Valgrind complains about code we don't control
Sometimes `valgrind` will complain about code we do not control ourselves, either because it's in a library we use or it's a false positive. There are generally three ways to address these issues (in descending order of preference):
1. Add a suppression for the one specific call that is causing the issue. Upon finding an issue `valgrind` is instructed in the testing framework to print filters that'd match the issue. These can be added to the suppressions file under `tests/valgrind-suppressions.txt` in order to explicitly skip reporting these in future. This is preferred over the other solutions since it only disables reporting selectively for things that were manually checked. See the [valgrind docs](https://valgrind.org/docs/manual/manual-core.html#manual-core.suppress) for details.
2. Add the process that `valgrind` is complaining about to the `--trace-children-skip` argument in `pyln-testing`. This is used in cases of full binaries not being under our control, such as the `python3` interpreter used in tests that run plugins. Do not use this for binaries that are compiled from our code, as it tends to mask real issues.
3. Mark the test as skipped if running under `valgrind`. It's mostly used to skip tests that otherwise would take considerably too long to test on CI. We discourage this for suppressions, since it is a very blunt tool.
Core Lightning currently supports coverage-guided fuzz testing using [LLVM's libfuzzer](https://www.llvm.org/docs/LibFuzzer.html) when built with `clang`.
The goal of fuzzing is to generate mutated -and often unexpected- inputs (`seed`s) to pass to (parts of) a program (`target`) in order to make sure the codepaths used:
For more info about fuzzing see [here](https://github.com/google/fuzzing/tree/master/docs), and for more about `libfuzzer` in particular see [here](https://www.llvm.org/docs/LibFuzzer.html).
In order to build the Core Lightning binaries with code coverage you will need a recent [clang](http://clang.llvm.org/). The more recent the compiler version the better.
Then you'll need to enable support at configuration time. You likely want to enable a few sanitizers for bug detections as well as experimental features for an extended coverage (not required though).
If you find coverage increasing inputs while fuzzing, please create a pull request to add them into `tests/fuzz/corpora`. Be sure to minimize any additions to the corpora first.
### Example
Here's an example workflow to contribute new inputs for the `fuzz-addr` target.
Create a directory for newly found corpus inputs and begin fuzzing:
After some time, libFuzzer may find some potential coverage increasing inputs and save them in `local_corpora/fuzz-addr`. We can then merge them into the seed corpora in `tests/fuzz/corpora`:
This will copy over any inputs that improve the coverage of the existing corpus. If any new inputs were added, create a pull request to improve the upstream seed corpus:
```shell
git add tests/fuzz/corpora/fuzz-addr/*
git commit
...
```
## Write new fuzzing targets
In order to write a new target:
- include the `libfuzz.h` header
- fill two functions: `init()` for static stuff and `run()` which will be called repeatedly with mutated data.
- read about [what makes a good fuzz target](https://github.com/google/fuzzing/blob/master/docs/good-fuzz-target.md).
A simple example is [`fuzz-addr`](https://github.com/ElementsProject/lightning/blob/master/tests/fuzz/fuzz-addr.c). It setups the chainparams and context (wally, tmpctx, ..) in `init()` then bruteforces the bech32 encoder in `run()`.