Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrate tests to RPyC #1040

Merged
merged 37 commits into from
Jan 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
6622be9
minor pylint fixes in gef
hugsy Jan 6, 2024
68787c3
adding new debug script for rpyc
hugsy Jan 6, 2024
df101d0
added new test base class `RemoteGefUnitTestGeneric`
hugsy Jan 6, 2024
7276e7a
first batch of scripts transfert
hugsy Jan 6, 2024
0a23968
added coverage conditions
hugsy Jan 6, 2024
be5ae3c
removed `update_gef` and added a new setting to allow progation of ex…
hugsy Jan 6, 2024
6892f4f
finished porting tests/api
hugsy Jan 6, 2024
678c505
typo
hugsy Jan 6, 2024
46f0e85
increased spawn time for rpyc
hugsy Jan 6, 2024
fecf5ff
docs + `tests.utils.RemoteGefUnitTestGeneric` -> `tests.base.RemoteGe…
hugsy Jan 6, 2024
38f258c
updated tests/config
hugsy Jan 6, 2024
d1893a9
added commands/aliases
hugsy Jan 6, 2024
6b50944
added commands/alsr
hugsy Jan 6, 2024
145cd89
added tests/functions
hugsy Jan 7, 2024
7203730
ported tests/commands (failing)
hugsy Jan 7, 2024
70af9ca
test fixes 1/N
hugsy Jan 7, 2024
f49cf52
test fixes 2/N
hugsy Jan 7, 2024
4afa908
test fixes 3/N
hugsy Jan 7, 2024
ea7693c
test fixes 4/N
hugsy Jan 7, 2024
9b929bb
test fixes 5/N
hugsy Jan 7, 2024
c9d7a92
test fixes 6/N
hugsy Jan 8, 2024
86b6c92
test fixes 7/N
hugsy Jan 8, 2024
d8e7e3d
test fixes 8/8 - all passes
hugsy Jan 8, 2024
563b2ad
added tests/regressions
hugsy Jan 8, 2024
1d6b31d
added some docs
hugsy Jan 8, 2024
3c124dc
fixed coverage
hugsy Jan 8, 2024
21326f7
fixed ordering
hugsy Jan 8, 2024
38c1c6d
coverage ignore failure
hugsy Jan 8, 2024
cf824ac
minor fix + added deprecation checks
hugsy Jan 8, 2024
550309d
Apply suggestions from code review
hugsy Jan 8, 2024
c3bc2bc
moved ksymaddr test to extras + removed unused code
hugsy Jan 8, 2024
8eda99b
Merge branch 'migrate_tests_to_rpyc' of github.com:hugsy/gef into mig…
hugsy Jan 8, 2024
22ed93b
simplify gef_extra plugins loading function
hugsy Jan 8, 2024
96f3cd2
added retry in case of port collision
hugsy Jan 9, 2024
7aa266d
Apply suggestions from code review
hugsy Jan 9, 2024
e54b9eb
forgot benchmark 🤦
hugsy Jan 9, 2024
09a99c4
Merge branch 'migrate_tests_to_rpyc' of github.com:hugsy/gef into mig…
hugsy Jan 9, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 3 additions & 5 deletions .github/workflows/coverage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -80,10 +80,10 @@ jobs:
* ${(forbidden_words.length === 0 || forbidden_words[0] === '') ? "**does not** include forbidden words" : "includes the forbidden words:" + forbidden_words.join(", ")}
`;

const { owner, repo, number } = context.issue;
await github.rest.issues.createComment({ owner, repo, issue_number: number, body: comment });

try {
const { owner, repo, number } = context.issue;
await github.rest.issues.createComment({ owner, repo, issue_number: number, body: comment });

if(docs_changes > 0) {
await github.rest.issues.addLabels({
owner: owner,
Expand All @@ -92,9 +92,7 @@ jobs:
labels: ['documentation']
});
}
} catch (err) { console.log(err); }

try {
if(tests_changes > 0) {
await github.rest.issues.addLabels({
owner: owner,
Expand Down
20 changes: 19 additions & 1 deletion .pylintrc
Original file line number Diff line number Diff line change
Expand Up @@ -409,7 +409,25 @@ confidence=
; anomalous-backslash-in-string,
; bad-open-mode

enable = F,E,unreachable,duplicate-key,unnecessary-semicolon,unused-variable,binary-op-exception,bad-format-string,anomalous-backslash-in-string,bad-open-mode,dangerous-default-value,trailing-whitespace,unneeded-not,singleton-comparison,unused-import,line-too-long,multiple-statements,consider-using-f-string,global-variable-not-assigned
enable =
F,
E,
anomalous-backslash-in-string,
bad-format-string,
bad-open-mode,
consider-using-f-string,
dangerous-default-value,
duplicate-key,
global-variable-not-assigned
line-too-long,
singleton-comparison,
trailing-whitespace,
unnecessary-semicolon,
unneeded-not,
unreachable,
unused-import,
unused-variable,
binary-op-exception
disable = all

[REPORTS]
Expand Down
69 changes: 58 additions & 11 deletions docs/testing.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,11 @@ You can then use `pytest` directly to help you fix each error specifically.
GEF entirely relies on [`pytest`](https://pytest.org) for its testing. Refer to the project
documentation for details.

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`
Adding new code __requires__ extensive testing. Tests can be added in their own module in the
`tests/` folder. For example, if adding a new command to `gef`, a new test module should be created
and located in `/root/of/gef/tests/commands/my_new_command.py`. The test class __must__ inherit
`tests.base.RemoteGefUnitTestGeneric`. This class allows one to manipulate gdb and gef through rpyc
under their respective `self._gdb` and `self._gef` attributes.

A skeleton of a test module would look something like:

Expand All @@ -60,30 +63,74 @@ A skeleton of a test module would look something like:
"""


from tests.utils import GefUnitTestGeneric, gdb_run_cmd, gdb_start_silent_cmd
from tests.utils import RemoteGefUnitTestGeneric


class MyCommandCommand(GefUnitTestGeneric):
class MyCommandCommand(RemoteGefUnitTestGeneric):
"""`my-command` command test module"""

def setUp(self) -> None:
# By default, tests will be executed against the default.out binary
# You can change this behavior in the `setUp` function
self._target = debug_target("my-custom-binary-for-tests")
return super().setUp()

def test_cmd_my_command(self):
# `my-command` is expected to fail if the session is not active
self.assertFailIfInactiveSession(gdb_run_cmd("my-command"))
# some convenience variables
root, gdb, gef = self._conn.root, self._gdb, self._gef

# You can then interact with any command from gdb or any class/function/variable from gef
# For instance:

# `my-command` should never throw an exception in GDB when running
res = gdb_start_silent_cmd("my-command")
self.assertNoException(res)
# * tests that `my-command` is expected to fail if the session is not active
output = gdb.execute("my-command", to_string=True)
assert output == ERROR_INACTIVE_SESSION_MESSAGE

# it also must print out a "Hello World" message
self.assertIn("Hello World", res)
# * `my-command` must print "Hello World" message when executed in running context
gdb.execute("start")
output = gdb.execute("my-command", to_string=True)
assert "Hello World" == output
```

You might want to refer to the following documentations:

* [`pytest`](https://docs.pytest.org/en/)
* [`gdb Python API`](https://sourceware.org/gdb/current/onlinedocs/gdb.html/Python-API.html)
* (maybe) [`rpyc`](https://rpyc.readthedocs.io/en/latest/)

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.

One of the most convenient ways to test `gef` properly is using the `pytest` integration of modern
editors such as VisualStudio Code or PyCharm. Without proper tests, new code will not be integrated.

Also note that GEF can be remotely controlled using the script `scripts/remote_debug.py` as such:

```text
$ gdb -q -nx
(gdb) source /path/to/gef/gef.py
[...]
gef➤ source /path/to/gef/scripts/remote_debug.py
gef➤ pi start_rpyc_service(4444)
```

Here RPyC will be started on the local host, and bound to the TCP port 4444. We can now connect
using a regular Python REPL:

```text
>>> import rpyc
>>> c = rpyc.connect("localhost", 4444)
>>> gdb = c.root._gdb
>>> gef = c.root._gef
# We can now fully control the remote GDB
>>> gdb.execute("file /bin/ls")
>>> gdb.execute("start")
>>> print(hex(gef.arch.pc))
0x55555555aab0
>>> print(hex(gef.arch.sp))
0x7fffffffdcf0
```

### Linting GEF

You can use the Makefile at the root of the project to get the proper linting settings. For most
Expand Down
Loading
Loading