Skip to content

Commit

Permalink
Add bandit and pyright checks to test code
Browse files Browse the repository at this point in the history
Use tenacity where it is useful to fix pyright and bandit errors.

Change pylint target to lint target in top level Makefile, since the
target also includes using bandit and pyright.

Signed-off-by: mulhern <[email protected]>
  • Loading branch information
mulkieran committed Jan 7, 2025
1 parent 0706663 commit f819982
Show file tree
Hide file tree
Showing 11 changed files with 101 additions and 60 deletions.
2 changes: 1 addition & 1 deletion .githooks/pre-commit
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ make fmt-ci &&
make clippy &&
make yamllint &&
make tmtlint &&
make pylint &&
make lint &&
make check-typos || exit 1

export PYTHONPATH=$PWD/tests/client-dbus/src
Expand Down
10 changes: 8 additions & 2 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -192,11 +192,17 @@ jobs:
- name: Install dependencies
run: >
dnf install -y
bandit
make
pip
pylint
python3-dbus
- name: Run pylint
run: make -f Makefile pylint
- name: Install pyright
run: pip install --user pyright
- name: Run lint
run: >
PATH=${PATH}:/github/home/.local/bin
make -f Makefile lint
python-based-tests:
runs-on: ubuntu-22.04
Expand Down
8 changes: 7 additions & 1 deletion .github/workflows/support.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ jobs:
matrix:
include:
- dependencies: >
bandit
pylint
python3-dbus-client-gen
python3-dbus-python-client-gen
Expand All @@ -47,7 +48,9 @@ jobs:
python3-pyudev
python3-semantic_version
python3-tenacity
task: PYTHONPATH=./src make -f Makefile lint
task: >
PATH=${PATH}:/github/home/.local/bin
PYTHONPATH=./src make -f Makefile lint
working-directory: ./tests/client-dbus
- dependencies: black python3-isort
task: make -f Makefile fmt-ci
Expand All @@ -64,7 +67,10 @@ jobs:
dnf install -y
make
ncurses
pip
${{ matrix.dependencies }}
- name: Install pyright
run: pip install --user pyright
- name: Run test
run: ${{ matrix.task }}
working-directory: ${{ matrix.working-directory }}
8 changes: 7 additions & 1 deletion .github/workflows/weekly.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ jobs:
include:
# PYTHON CHECKS ON NEXT FEDORA PYTHON AND PYTHON TOOLS VERSION
- dependencies: >
bandit
pylint
python3-dbus-client-gen
python3-dbus-python-client-gen
Expand All @@ -25,7 +26,9 @@ jobs:
python3-pyudev
python3-semantic_version
python3-tenacity
task: PYTHONPATH=./src make -f Makefile lint
task: >
PATH=${PATH}:/github/home/.local/bin
PYTHONPATH=./src make -f Makefile lint
working-directory: ./tests/client-dbus
- dependencies: black python3-isort
task: make -f Makefile fmt-ci
Expand All @@ -45,10 +48,13 @@ jobs:
dnf install -y
make
ncurses
pip
python-unversioned-command
${{ matrix.dependencies }}
- name: Display Python version
run: python --version
- name: Install pyright
run: pip install --user pyright
- name: ${{ matrix.task }}
run: ${{ matrix.task }}
working-directory: ${{ matrix.working-directory }}
Expand Down
6 changes: 4 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -430,8 +430,10 @@ clippy: clippy-macros clippy-min clippy-udev-utils clippy-no-ipc clippy-utils cl
cargo clippy ${CLIPPY_OPTS}

## Lint Python parts of the source code
pylint:
lint:
pylint --disable=invalid-name ./src/bin/utils/stratis-decode-dm
bandit ./src/bin/utils/stratis-decode-dm --skip B101
pyright ./src/bin/utils/stratis-decode-dm

.PHONY:
audit
Expand Down Expand Up @@ -477,7 +479,7 @@ pylint:
install-udev-binaries
install-udev-cfg
license
pylint
lint
test
test-valgrind
test-loop
Expand Down
8 changes: 8 additions & 0 deletions tests/client-dbus/Makefile
Original file line number Diff line number Diff line change
@@ -1,9 +1,17 @@
UNITTEST_OPTS = --verbose

# Ignore bandit B404 errors. Any import of the subprocess module causes this
# error. We know what we are doing when we import that module and do not
# need to be warned.
BANDIT_SKIP = --skip B404,B603,B311

.PHONY: lint
lint:
pylint src/stratisd_client_dbus --ignore=_introspect.py
pylint tests --disable=R0801
bandit --recursive ./src ${BANDIT_SKIP}
bandit --recursive ./tests ${BANDIT_SKIP},B101
pyright

.PHONY: startup-tests
startup-tests:
Expand Down
18 changes: 11 additions & 7 deletions tests/client-dbus/src/stratisd_client_dbus/_implementation.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
"""

# isort: STDLIB
import xml.etree.ElementTree as ET
import xml.etree.ElementTree as ET # nosec B405

# isort: FIRSTPARTY
from dbus_client_gen import managed_object_class, mo_query_builder
Expand All @@ -31,9 +31,9 @@
)
from ._introspect import SPECS

_POOL_SPEC = ET.fromstring(SPECS[POOL_INTERFACE])
_FILESYSTEM_SPEC = ET.fromstring(SPECS[FILESYSTEM_INTERFACE])
_BLOCKDEV_SPEC = ET.fromstring(SPECS[BLOCKDEV_INTERFACE])
_POOL_SPEC = ET.fromstring(SPECS[POOL_INTERFACE]) # nosec B314
_FILESYSTEM_SPEC = ET.fromstring(SPECS[FILESYSTEM_INTERFACE]) # nosec B314
_BLOCKDEV_SPEC = ET.fromstring(SPECS[BLOCKDEV_INTERFACE]) # nosec B314

pools = mo_query_builder(_POOL_SPEC)
filesystems = mo_query_builder(_FILESYSTEM_SPEC)
Expand All @@ -46,11 +46,15 @@

ObjectManager = make_class(
"ObjectManager",
ET.fromstring(SPECS["org.freedesktop.DBus.ObjectManager"]),
ET.fromstring(SPECS["org.freedesktop.DBus.ObjectManager"]), # nosec B314
TIME_OUT,
)
Report = make_class("Report", ET.fromstring(SPECS[REPORT_INTERFACE]), TIME_OUT)
Manager = make_class("Manager", ET.fromstring(SPECS[MANAGER_INTERFACE]), TIME_OUT)
Report = make_class(
"Report", ET.fromstring(SPECS[REPORT_INTERFACE]), TIME_OUT # nosec B314
)
Manager = make_class(
"Manager", ET.fromstring(SPECS[MANAGER_INTERFACE]), TIME_OUT # nosec B314
)
Filesystem = make_class("Filesystem", _FILESYSTEM_SPEC, TIME_OUT)
Pool = make_class("Pool", _POOL_SPEC, TIME_OUT)
Blockdev = make_class("Blockdev", _BLOCKDEV_SPEC, TIME_OUT)
4 changes: 4 additions & 0 deletions tests/client-dbus/tests/udev/_loopback.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,8 @@ def create_devices(self, number):
:return: list of keys for the devices
:rtype: list of uuid.UUID
"""
assert self.dir is not None

tokens = []

first_creation = self.count == 0
Expand Down Expand Up @@ -220,6 +222,8 @@ def destroy_all(self):
Detach all the devices and delete the file(s) and directory!
:return: None
"""
assert self.dir is not None

self.destroy_devices()
os.rmdir(self.dir)
self.dir = None
72 changes: 37 additions & 35 deletions tests/client-dbus/tests/udev/_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,14 @@
import dbus
import psutil
import pyudev
from tenacity import Retrying, retry_if_exception_type, stop_after_delay, wait_fixed
from tenacity import (
RetryError,
Retrying,
retry_if_exception_type,
stop_after_attempt,
stop_after_delay,
wait_fixed,
)

# isort: LOCAL
from stratisd_client_dbus import (
Expand Down Expand Up @@ -235,7 +242,7 @@ def settle():
:return: None
"""
time.sleep(2)
subprocess.check_call(["udevadm", "settle"])
subprocess.check_call(["/usr/bin/udevadm", "settle"])


def wait_for_udev_count(expected_num):
Expand Down Expand Up @@ -288,25 +295,28 @@ def wait_for_udev(fs_type, expected_paths):
:raises RuntimeError: if unexpected device nodes are found
"""
expected_devnodes = frozenset((os.path.realpath(x) for x in expected_paths))
found_devnodes = None

context = pyudev.Context()
end_time = time.time() + 10.0

while time.time() < end_time and not expected_devnodes == found_devnodes:
found_devnodes = frozenset(
def find_devnodes():
return frozenset(
[
x.device_node
for x in context.list_devices(subsystem="block", ID_FS_TYPE=fs_type)
if x.device_node is not None
]
)
time.sleep(1)

if expected_devnodes != found_devnodes:
try:
for attempt in Retrying(wait=wait_fixed(1), stop=stop_after_delay(10)):
with attempt:
if expected_devnodes == find_devnodes():
break
except RetryError as err:
raise RuntimeError(
f'Found unexpected devnodes: expected devnodes: {", ".join(expected_devnodes)} '
f'!= found_devnodes: {", ".join(found_devnodes)}'
)
f'!= found_devnodes: {", ".join(find_devnodes())}'
) from err


def processes(name):
Expand Down Expand Up @@ -538,32 +548,24 @@ def wait_for_pools(self, expected_num, *, name=None):
:return: list of pool information found
:rtype: list of (str * MOPool)
"""
(count, limit, dbus_err, found_num, known_pools, start_time) = (
0,
expected_num + 1,
None,
None,
None,
time.time(),
)
while count < limit and not expected_num == found_num:
try:
known_pools = get_pools(name=name)
except dbus.exceptions.DBusException as err:
dbus_err = err

if known_pools is not None:
found_num = len(known_pools)

time.sleep(3)
count += 1

if found_num is None and dbus_err is not None:
try:
for attempt in Retrying(
retry=(retry_if_exception_type(dbus.exceptions.DBusException)),
wait=wait_fixed(3),
stop=stop_after_attempt(expected_num + 1),
reraise=True,
):
with attempt:
known_pools = get_pools(name=name)
if len(known_pools) == expected_num:
break
except dbus.exceptions.DBusException as err:
raise RuntimeError(
f"After {time.time() - start_time:.2f} seconds, the only "
"response is a D-Bus exception"
) from dbus_err
"Failed to obtain any information about pools from the D-Bus"
) from err

self.assertEqual(found_num, expected_num)
time.sleep(3) # Wait for the D-Bus to add an additional pool
known_pools = get_pools(name=name)
self.assertEqual(len(known_pools), expected_num)

return known_pools
2 changes: 1 addition & 1 deletion tests/client-dbus/tests/udev/test_predict.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ def _call_blockdev_size(dev):
:rtype: str
"""
with subprocess.Popen(
["blockdev", "--getsize64", dev],
["/usr/sbin/blockdev", "--getsize64", dev],
stdout=subprocess.PIPE,
) as command:
outs, _ = command.communicate()
Expand Down
Loading

0 comments on commit f819982

Please sign in to comment.