Skip to content

Commit 18c7ba4

Browse files
hugsyGrazfatherclark-ja
authored
Better tests (#813)
* first shot at refactoring ci testing * - Added skeleton for most missing command test modules - Fixed a logic error in `NopCommand` * [ci] added tests for `nop` * [ci] extra test for nop for memory check * added benchmarking capability, can be triggered directly from `pytest` * - fixed `pcustom` command test for 32b - fixed calculation of tcache in gef - added tests for `gef.heap` - improved tests for `heap` command - fixes #641 * [ci] cmd/heap - adjusted tcachebins indexes for 32b * damnit * - fixed linting - fixed test `highlight` for 32b - fixed test `pattern_search` for x86 * last fixes for tonight * fixed `pattern` and `heap` tests for good * - add 3rd party module check for `capstone`, `keystone`, `unicorn` and `ropper` * added `test_func_update_gef` * `make test` doesn't execute benchmark * - fixed errors in the `pie` subcommands - added tests for `pie` * `theme` added more tests * - improved tests for `pattern` and `edit-flags` * [ci] created cases for all arches for bin tests in `tests/heap.py` * fixed `heap` tests for good * - added ci test for `glibcarena` - fixed `theme` missing comma (original PR #808 by @mrshu ) - added missing values for `theme` * - added tests for deprecated API - added test for smart eval - more function tests * started `gef` test module * - added tests for `syscall-args` and `is-syscall` * - fixed `syscall-args` to also get catchpoints + tests * - test `show_last_exception` * make sure `syscall-args` test collects the ABI files from `gef-extras` * linting * only enable `syscall-args` test for x86 * `syscall-args` fixed typo in i686 test * Fix RISCV arch detection (#790) * Add RISCV alias so arch can be determined by ELF * Add ptrsize property to RISCV arch * Allow riscv tests to run * Update tests/api/gef_arch.py Co-authored-by: Grazfather <[email protected]> * fix: make shebang lines portable (#814) * fix: make shebang lines portable * fix: SC2006, SC2086, SC2016, SC2059 * make `heap` tests work universally * disabling capstone/keystone/unicorn for some arches for now * - fixed tests for ppc64 - added static `ptrsize` for ppc & ppc64 in gef * - `BIN_LS` -> `_target("default")` - removed auto demangle for now * - disable pytest `--pdb` from makefile - added doc for testing * Apply suggestions from code review Co-authored-by: Grazfather <[email protected]> * fixing ci * [tests] use camel case for format string helper test class * [tests] added docstring to `GefFuncDeprecatedApi` * [tests] `edit-flags` are only for known arches for now * PR review changes * PR review last batch Co-authored-by: Grazfather <[email protected]> Co-authored-by: theguy147 <[email protected]>
1 parent 37bb542 commit 18c7ba4

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

78 files changed

+3062
-1524
lines changed

.github/PULL_REQUEST_TEMPLATE.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,5 +27,5 @@
2727
- [] My PR was done against the `dev` branch, not `master`.
2828
- [] My code follows the code style of this project.
2929
- [] My change includes a change to the documentation, if required.
30-
- [] My change adds tests as appropriate.
30+
- [] If my change adds new code, [adequate tests](docs/testing.md) have been added.
3131
- [] I have read and agree to the **CONTRIBUTING** document.

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
*.out
22
*.pyc
33
TAGS
4-
*/__pycache__/
4+
__pycache__
55
tests/*.pyc
66
tests/pylint.html
77
tests/pylint.txt

Makefile

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,21 +11,15 @@ TARGET := $(shell lscpu | head -1 | sed -e 's/Architecture:\s*//g')
1111
COVERAGE_DIR ?= /tmp/cov
1212
GEF_PATH ?= $(shell readlink -f gef.py)
1313
TMPDIR ?= /tmp
14-
PYTEST_PARAMETERS := --verbose -n $(NB_CORES)
15-
ifdef DEBUG
16-
PYTEST_PARAMETERS += --pdb
17-
endif
14+
PYTEST_PARAMETERS := --verbose --forked --numprocesses=$(NB_CORES)
1815

1916
.PHONY: test test_% Test% testbins clean lint
2017

2118
test: $(TMPDIR) testbins
22-
TMPDIR=$(TMPDIR) python3 -m pytest $(PYTEST_PARAMETERS) tests/runtests.py
23-
24-
Test%: $(TMPDIR) testbins
25-
TMPDIR=$(TMPDIR) python3 -m pytest $(PYTEST_PARAMETERS) tests/runtests.py::$@
19+
TMPDIR=$(TMPDIR) python3 -m pytest $(PYTEST_PARAMETERS) -k "not benchmark"
2620

2721
test_%: $(TMPDIR) testbins
28-
TMPDIR=$(TMPDIR) python3 -m pytest $(PYTEST_PARAMETERS) tests/runtests.py -k $@
22+
TMPDIR=$(TMPDIR) python3 -m pytest $(PYTEST_PARAMETERS) -k $@
2923

3024
testbins: $(TMPDIR) $(wildcard tests/binaries/*.c)
3125
@TMPDIR=$(TMPDIR) $(MAKE) -j $(NB_CORES) -C tests/binaries TARGET=$(TARGET) all
@@ -36,7 +30,7 @@ clean:
3630

3731
lint:
3832
python3 -m pylint $(PYLINT_GEF_PARAMETERS) $(GEF_PATH)
39-
python3 -m pylint $(PYLINT_TEST_PARAMETERS) $(wildcard tests/*.py)
33+
python3 -m pylint $(PYLINT_TEST_PARAMETERS) $(wildcard tests/*.py tests/*/*.py)
4034

4135
coverage:
4236
@! ( [ -d $(COVERAGE_DIR) ] && echo "COVERAGE_DIR=$(COVERAGE_DIR) exists already")

docs/testing.md

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
## Testing GEF
2+
3+
This page describes how GEF testing is done. Any new command/functionality must receive adequate testing to be merged. Also PR failing CI (test + linting) won't be merged either.
4+
5+
6+
### Prerequisites
7+
8+
All the prerequisite packages are in `requirements.txt` file at the root of the project. So running
9+
10+
```bash
11+
python -m pip install -r requirements.txt --user -U
12+
```
13+
14+
is enough to get started.
15+
16+
17+
### Running tests
18+
19+
20+
#### Using `make tests`
21+
22+
For testing GEF on the architecture on the host running the tests (most cases), simply run
23+
24+
```bash
25+
cd /root/of/gef
26+
make test
27+
```
28+
29+
Otherwise, `make` can be adjusted to :
30+
- run one test/one group of tests specifically
31+
- eg. `make test_cmd_heap` will trigger all the test functions for the `heap` command
32+
- run for a different architecture
33+
- eg. on x86, you can test x86 too with `TARGET=i686 make TARGET=i686 test`
34+
35+
Unless a specific test is mentioned, the command `make test` will run all the non-benchmark related tests.
36+
At the end, a summary of explanation will be shown, clearly indicating the tests that have failed: for instance:
37+
38+
```
39+
=================================== short test summary info ==================================
40+
FAILED tests/commands/heap.py::HeapCommand::test_cmd_heap_bins_large - AssertionError: 'siz...
41+
FAILED tests/commands/heap.py::HeapCommand::test_cmd_heap_bins_small - AssertionError: 'siz...
42+
FAILED tests/commands/heap.py::HeapCommand::test_cmd_heap_bins_unsorted - AssertionError: '...
43+
======================== 3 failed, 4 passed, 113 deselected in 385.77s (0:06:25)==============
44+
```
45+
46+
You can then use `pytest` directly to help you fix each error specifically.
47+
48+
49+
#### Using `pytest`
50+
51+
GEF entirely relies on [`pytest`](https://pytest.org) for its testing. Refer to the project documentation for details.
52+
53+
Adding a new command __requires__ for extensive testing in a new dedicated test module that should be located in `/root/of/gef/tests/commands/my_new_command.py`
54+
55+
A skeleton of a test module would look something like:
56+
57+
```python
58+
"""
59+
`my-command` command test module
60+
"""
61+
62+
63+
from tests.utils import GefUnitTestGeneric, gdb_run_cmd, gdb_start_silent_cmd
64+
65+
66+
class MyCommandCommand(GefUnitTestGeneric):
67+
"""`my-command` command test module"""
68+
69+
def test_cmd_my_command(self):
70+
# `my-command` is expected to fail if the session is not active
71+
self.assertFailIfInactiveSession(gdb_run_cmd("my-command"))
72+
73+
# `my-command` should never throw an exception in GDB when running
74+
res = gdb_start_silent_cmd("my-command")
75+
self.assertNoException(res)
76+
77+
# it also must print out a "Hello World" message
78+
self.assertIn("Hello World", res)
79+
```
80+
81+
When running your test, you can summon `pytest` with the `--pdb` flag to enter the python testing environment to help you get more information about the reason of failure.
82+
83+
### Linting GEF
84+
85+
You can use the Makefile at the root of the project to get the proper linting settings. For most cases, the following command is enough:
86+
87+
```bash
88+
cd /root/of/gef
89+
make lint
90+
```
91+
92+
93+
### Benchmarking GEF
94+
95+
Benchmarking relies on `pytest-benchmark` and is experimental for now.
96+
97+
You can run all benchmark test cases as such:
98+
99+
```bash
100+
cd /root/of/gef
101+
pytest -k benchmark
102+
```
103+
104+
which will return (after some time) an execution summary
105+
106+
```
107+
tests/perf/benchmark.py .. [100%]
108+
109+
110+
---------------------------------------- benchmark: 3 tests -----------------------------------
111+
Name (time in ms) Min Max Mean StdDev Median IQR Outliers OPS Rounds Iterations
112+
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
113+
time_baseline 612.2325 (1.0) 630.3416 (1.01) 623.7984 (1.01) 7.2848 (1.64) 626.1485 (1.01) 9.9971 (1.81) 1;0 1.6031 (0.99) 5 1
114+
time_cmd_context 613.8124 (1.00) 625.8964 (1.0) 620.1908 (1.0) 4.4532 (1.0) 619.8831 (1.0) 5.5109 (1.0) 2;0 1.6124 (1.0) 5 1
115+
time_elf_parsing 616.5053 (1.01) 638.6965 (1.02) 628.1588 (1.01) 8.2465 (1.85) 629.0099 (1.01) 10.7885 (1.96) 2;0 1.5920 (0.99) 5 1
116+
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
117+
118+
Legend:
119+
Outliers: 1 Standard Deviation from Mean; 1.5 IQR (InterQuartile Range) from 1st Quartile and 3rd Quartile.
120+
OPS: Operations Per Second, computed as 1 / Mean
121+
============================================== 3 passed, 117 deselected in 14.78s =============================================
122+
```

0 commit comments

Comments
 (0)