mirror of
				https://github.com/facebook/zstd.git
				synced 2025-11-04 00:02:59 -05:00 
			
		
		
		
	`./run.py --set-exact-output` will update `stdout.expect` and `stderr.expect` to match the expected output. This doesn't apply to outputs which use `.glob` or `.ignore`.
		
			
				
	
	
		
			259 lines
		
	
	
		
			7.1 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
			
		
		
	
	
			259 lines
		
	
	
		
			7.1 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
# CLI tests
 | 
						|
 | 
						|
The CLI tests are focused on testing the zstd CLI.
 | 
						|
They are intended to be simple tests that the CLI and arguments work as advertised.
 | 
						|
They are not intended to test the library, only the code in `programs/`.
 | 
						|
The library will get incidental coverage, but if you find yourself trying to trigger a specific condition in the library, this is the wrong tool.
 | 
						|
 | 
						|
## Test runner usage
 | 
						|
 | 
						|
The test runner `run.py` will run tests against the in-tree build of `zstd` and `datagen` by default. Which means that `zstd` and `datagen` must be built.
 | 
						|
 | 
						|
The `zstd` binary used can be passed with `--zstd /path/to/zstd`.
 | 
						|
Additionally, to run `zstd` through a tool like `valgrind` or `qemu`, set the `--exec-prefix 'valgrind -q'` flag.
 | 
						|
 | 
						|
Similarly, the `--datagen`, and `--zstdgrep` flags can be set to specify
 | 
						|
the paths to their respective binaries. However, these tools do not use
 | 
						|
the `EXEC_PREFIX`.
 | 
						|
 | 
						|
Each test executes in its own scratch directory under `scratch/test/name`. E.g. `scratch/basic/help.sh/`. Normally these directories are removed after the test executes. However, the `--preserve` flag will preserve these directories after execution, and save the tests exit code, stdout, and stderr in the scratch directory to `exit`, `stderr`, and `stdout` respectively. This can be useful for debugging/editing a test and updating the expected output.
 | 
						|
 | 
						|
### Running all the tests
 | 
						|
 | 
						|
By default the test runner `run.py` will run all the tests, and report the results.
 | 
						|
 | 
						|
Examples:
 | 
						|
 | 
						|
```
 | 
						|
./run.py
 | 
						|
./run.py --preserve
 | 
						|
./run.py --zstd ../../build/programs/zstd --datagen ../../build/tests/datagen
 | 
						|
```
 | 
						|
 | 
						|
### Running specific tests
 | 
						|
 | 
						|
A set of test names can be passed to the test runner `run.py` to only execute those tests.
 | 
						|
This can be useful for writing or debugging a test, especially with `--preserve`.
 | 
						|
 | 
						|
The test name can either be the path to the test file, or the test name, which is the path relative to the test directory.
 | 
						|
 | 
						|
Examples:
 | 
						|
 | 
						|
```
 | 
						|
./run.py basic/help.sh
 | 
						|
./run.py --preserve basic/help.sh basic/version.sh
 | 
						|
./run.py --preserve --verbose basic/help.sh
 | 
						|
```
 | 
						|
 | 
						|
### Updating exact output
 | 
						|
 | 
						|
If a test is failing because a `.stderr.exact` or `.stdout.exact` no longer matches, you can re-run the tests with `--set-exact-output` and the correct output will be written.
 | 
						|
 | 
						|
Example:
 | 
						|
```
 | 
						|
./run.py --set-exact-output
 | 
						|
./run.py basic/help.sh --set-exact-output
 | 
						|
```
 | 
						|
 | 
						|
## Writing a test
 | 
						|
 | 
						|
Test cases are arbitrary executables, and can be written in any language, but are generally shell scripts.
 | 
						|
After the script executes, the exit code, stderr, and stdout are compared against the expectations.
 | 
						|
 | 
						|
Each test is run in a clean directory that the test can use for intermediate files. This directory will be cleaned up at the end of the test, unless `--preserve` is passed to the test runner. Additionally, the `setup` script can prepare the directory before the test runs.
 | 
						|
 | 
						|
### Calling zstd, utilities, and environment variables
 | 
						|
 | 
						|
The `$PATH` for tests is prepended with the `bin/` sub-directory, which contains helper scripts for ease of testing.
 | 
						|
The `zstd` binary will call the zstd binary specified by `run.py` with the correct `$EXEC_PREFIX`.
 | 
						|
Similarly, `datagen`, `unzstd`, `zstdgrep`, `zstdcat`, etc, are provided.
 | 
						|
 | 
						|
Helper utilities like `cmp_size`, `println`, and `die` are provided here too. See their scripts for details.
 | 
						|
 | 
						|
Common shell script libraries are provided under `common/`, with helper variables and functions. They can be sourced with `source "$COMMON/library.sh`.
 | 
						|
 | 
						|
Lastly, environment variables are provided for testing, which can be listed when calling `run.py` with `--verbose`.
 | 
						|
They are generally used by the helper scripts in `bin/` to coordinate everything.
 | 
						|
 | 
						|
### Basic test case
 | 
						|
 | 
						|
When executing your `$TEST` executable, by default the exit code is expected to be `0`. However, you can provide an alternate expected exit code in a `$TEST.exit` file.
 | 
						|
 | 
						|
When executing your `$TEST` executable, by default the expected stderr and stdout are empty. However, you can override the default by providing one of three files:
 | 
						|
 | 
						|
* `$TEST.{stdout,stderr}.exact`
 | 
						|
* `$TEST.{stdout,stderr}.glob`
 | 
						|
* `$TEST.{stdout,stderr}.ignore`
 | 
						|
 | 
						|
If you provide a `.exact` file, the output is expected to exactly match, byte-for-byte.
 | 
						|
 | 
						|
If you provide a `.glob` file, the output is expected to match the expected file, where each line is interpreted as a glob syntax. Additionally, a line containing only `...` matches all lines until the next expected line matches.
 | 
						|
 | 
						|
If you provide a `.ignore` file, the output is ignored.
 | 
						|
 | 
						|
#### Passing examples
 | 
						|
 | 
						|
All these examples pass.
 | 
						|
 | 
						|
Exit 1, and change the expectation to be 1.
 | 
						|
 | 
						|
```
 | 
						|
exit-1.sh
 | 
						|
---
 | 
						|
#!/bin/sh
 | 
						|
exit 1
 | 
						|
---
 | 
						|
 | 
						|
exit-1.sh.exit
 | 
						|
---
 | 
						|
1
 | 
						|
---
 | 
						|
```
 | 
						|
 | 
						|
Check the stdout output exactly matches.
 | 
						|
 | 
						|
```
 | 
						|
echo.sh
 | 
						|
---
 | 
						|
#!/bin/sh
 | 
						|
echo "hello world"
 | 
						|
---
 | 
						|
 | 
						|
echo.sh.stdout.exact
 | 
						|
---
 | 
						|
hello world
 | 
						|
---
 | 
						|
```
 | 
						|
 | 
						|
Check the stderr output using a glob.
 | 
						|
 | 
						|
```
 | 
						|
random.sh
 | 
						|
---
 | 
						|
#!/bin/sh
 | 
						|
head -c 10 < /dev/urandom | xxd >&2
 | 
						|
---
 | 
						|
 | 
						|
random.sh.stderr.glob
 | 
						|
---
 | 
						|
00000000: * * * * *                 *
 | 
						|
```
 | 
						|
 | 
						|
Multiple lines can be matched with ...
 | 
						|
 | 
						|
```
 | 
						|
random-num-lines.sh
 | 
						|
---
 | 
						|
#!/bin/sh
 | 
						|
echo hello
 | 
						|
seq 0 $RANDOM
 | 
						|
echo world
 | 
						|
---
 | 
						|
 | 
						|
random-num-lines.sh.stdout.glob
 | 
						|
---
 | 
						|
hello
 | 
						|
0
 | 
						|
...
 | 
						|
world
 | 
						|
---
 | 
						|
```
 | 
						|
 | 
						|
#### Failing examples
 | 
						|
 | 
						|
Exit code is expected to be 0, but is 1.
 | 
						|
 | 
						|
```
 | 
						|
exit-1.sh
 | 
						|
---
 | 
						|
#!/bin/sh
 | 
						|
exit 1
 | 
						|
---
 | 
						|
```
 | 
						|
 | 
						|
Stdout is expected to be empty, but isn't.
 | 
						|
 | 
						|
```
 | 
						|
echo.sh
 | 
						|
---
 | 
						|
#!/bin/sh
 | 
						|
echo hello world
 | 
						|
```
 | 
						|
 | 
						|
Stderr is expected to be hello but is world.
 | 
						|
 | 
						|
```
 | 
						|
hello.sh
 | 
						|
---
 | 
						|
#!/bin/sh
 | 
						|
echo world >&2
 | 
						|
---
 | 
						|
 | 
						|
hello.sh.stderr.exact
 | 
						|
---
 | 
						|
hello
 | 
						|
---
 | 
						|
```
 | 
						|
 | 
						|
### Setup & teardown scripts
 | 
						|
 | 
						|
Finally, test writing can be eased with setup and teardown scripts.
 | 
						|
Each directory in the test directory is a test-suite consisting of all tests within that directory (but not sub-directories).
 | 
						|
This test suite can come with 4 scripts to help test writing:
 | 
						|
 | 
						|
* `setup_once`
 | 
						|
* `teardown_once`
 | 
						|
* `setup`
 | 
						|
* `teardown`
 | 
						|
 | 
						|
The `setup_once` and `teardown_once` are run once before and after all the tests in the suite respectively.
 | 
						|
They operate in the scratch directory for the test suite, which is the parent directory of each scratch directory for each test case.
 | 
						|
They can do work that is shared between tests to improve test efficiency.
 | 
						|
For example, the `dictionaries/setup_once` script builds several dictionaries, for use in the `dictionaries` tests.
 | 
						|
 | 
						|
The `setup` and `teardown` scripts run before and after each test case respectively, in the test case's scratch directory.
 | 
						|
These scripts can do work that is shared between test cases to make tests more succinct.
 | 
						|
For example, the `dictionaries/setup` script copies the dictionaries built by the `dictionaries/setup_once` script into the test's scratch directory, to make them easier to use, and make sure they aren't accidentally modified.
 | 
						|
 | 
						|
#### Examples
 | 
						|
 | 
						|
```
 | 
						|
basic/setup
 | 
						|
---
 | 
						|
#!/bin/sh
 | 
						|
# Create some files for testing with
 | 
						|
datagen > file
 | 
						|
datagen > file0
 | 
						|
datagen > file1
 | 
						|
---
 | 
						|
 | 
						|
basic/test.sh
 | 
						|
---
 | 
						|
#!/bin/sh
 | 
						|
zstd file file0 file1
 | 
						|
---
 | 
						|
 | 
						|
dictionaries/setup_once
 | 
						|
---
 | 
						|
#!/bin/sh
 | 
						|
set -e
 | 
						|
 | 
						|
mkdir files/ dicts/
 | 
						|
for i in $(seq 10); do
 | 
						|
	datagen -g1000 > files/$i
 | 
						|
done
 | 
						|
 | 
						|
zstd --train -r files/ -o dicts/0
 | 
						|
---
 | 
						|
 | 
						|
dictionaries/setup
 | 
						|
---
 | 
						|
#!/bin/sh
 | 
						|
 | 
						|
# Runs in the test case's scratch directory.
 | 
						|
# The test suite's scratch directory that
 | 
						|
# `setup_once` operates in is the parent directory.
 | 
						|
cp -r ../files ../dicts .
 | 
						|
---
 | 
						|
```
 |