leapp-repository/0014-makefile-add-dev_test_no_lint-target.patch
Petr Stodulka 75c9028095 RHEL 8.10: CTC1 candidate
- Enable new upgrade path for RHEL 8.10 -> RHEL 9.4 (including RHEL with SAP HANA)
- Introduce generic transition of systemd services states during the IPU
- Introduce possibility to upgrade with local repositories
- Improve possibilities of upgrade when a proxy is configured in DNF configutation file
- Fix handling of symlinks under /etc/pki when managing certificates
- Fix the upgrade with custom https repositories
- Default to the NO_RHSM mode when subscription-manager is not installed
- Detect customized configuration of dynamic linker
- Drop the invalid `tuv` target channel for the --channel option
- Fix the issue of going out of bounds in the isccfg parser
- Fix traceback when saving the rhsm facts results and the /etc/rhsm/facts directory doesn’t exist yet
- Load all rpm repository substitutions that dnf knows about, not just "releasever" only
- Simplify handling of upgrades on systems using RHUI, reducing the maintenance burden for cloud providers
- Detect possible unexpected RPM GPG keys has been installed during RPM transaction
- Resolves: RHEL-16729
2023-11-16 20:15:43 +01:00

173 lines
7.0 KiB
Diff

From 6ae2d5aadbf6a626cf27ca4594a3945e2c249122 Mon Sep 17 00:00:00 2001
From: mhecko <mhecko@redhat.com>
Date: Tue, 1 Aug 2023 12:44:47 +0200
Subject: [PATCH 14/38] makefile: add dev_test_no_lint target
Add a target for testing individual actors with almost-instant
execution time. Testing individual actors currently involves
a process in which every actor is instantiated in a separate
process, the created instance reports actor information such as actor's
name and then exits. As many processes are created, this process is
time consuming (cca 7s) which disrupts developer's workflow and causes
attention shift.
A newly added target `dev_test_no_lint` uses an introduced script
`find_actors`. To achieve the similar level of framework protection
as spawning actors in a separate process, the `find_actors` script
does not execute actors at all, and instead works on their ASTs.
Specifically, the script looks for all files named `actor.py`, finds
all classes that (explicitely) subclass Actor, and reads its `name`
attribute.
Usage example:
ACTOR=check_target_iso make dev_test_no_lint
---
Makefile | 15 +++++---
utils/find_actors.py | 81 ++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 91 insertions(+), 5 deletions(-)
create mode 100644 utils/find_actors.py
diff --git a/Makefile b/Makefile
index b63192e3..e3c40e01 100644
--- a/Makefile
+++ b/Makefile
@@ -16,9 +16,12 @@ REPOSITORIES ?= $(shell ls $(_SYSUPG_REPOS) | xargs echo | tr " " ",")
SYSUPG_TEST_PATHS=$(shell echo $(REPOSITORIES) | sed -r "s|(,\\|^)| $(_SYSUPG_REPOS)/|g")
TEST_PATHS:=commands repos/common $(SYSUPG_TEST_PATHS)
+# python version to run test with
+_PYTHON_VENV=$${PYTHON_VENV:-python2.7}
ifdef ACTOR
- TEST_PATHS=`python utils/actor_path.py $(ACTOR)`
+ TEST_PATHS=`$(_PYTHON_VENV) utils/actor_path.py $(ACTOR)`
+ APPROX_TEST_PATHS=$(shell $(_PYTHON_VENV) utils/find_actors.py -C repos $(ACTOR)) # Dev only
endif
ifeq ($(TEST_LIBS),y)
@@ -32,9 +35,6 @@ endif
# needed only in case the Python2 should be used
_USE_PYTHON_INTERPRETER=$${_PYTHON_INTERPRETER}
-# python version to run test with
-_PYTHON_VENV=$${PYTHON_VENV:-python2.7}
-
# by default use values you can see below, but in case the COPR_* var is defined
# use it instead of the default
_COPR_REPO=$${COPR_REPO:-leapp}
@@ -127,6 +127,7 @@ help:
@echo " - can be changed by setting TEST_CONTAINER env"
@echo " test_container_all run lint and tests in all available containers"
@echo " test_container_no_lint run tests without linting in container, see test_container"
+ @echo " dev_test_no_lint (advanced users) run only tests of a single actor specified by the ACTOR variable"
@echo " test_container_all_no_lint run tests without linting in all available containers"
@echo " clean_containers clean all testing and building container images (to force a rebuild for example)"
@echo ""
@@ -486,6 +487,10 @@ fast_lint:
echo "No files to lint."; \
fi
+dev_test_no_lint:
+ . $(VENVNAME)/bin/activate; \
+ $(_PYTHON_VENV) -m pytest $(REPORT_ARG) $(APPROX_TEST_PATHS) $(LIBRARY_PATH)
+
dashboard_data:
. $(VENVNAME)/bin/activate; \
snactor repo find --path repos/; \
@@ -494,4 +499,4 @@ dashboard_data:
popd
.PHONY: help build clean prepare source srpm copr_build _build_local build_container print_release register install-deps install-deps-fedora lint test_no_lint test dashboard_data fast_lint
-.PHONY: test_container test_container_no_lint test_container_all test_container_all_no_lint clean_containers _build_container_image _test_container_ipu
+.PHONY: test_container test_container_no_lint test_container_all test_container_all_no_lint clean_containers _build_container_image _test_container_ipu dev_test_no_lint
diff --git a/utils/find_actors.py b/utils/find_actors.py
new file mode 100644
index 00000000..25cc2217
--- /dev/null
+++ b/utils/find_actors.py
@@ -0,0 +1,81 @@
+import argparse
+import ast
+import os
+import sys
+
+
+def is_direct_actor_def(ast_node):
+ if not isinstance(ast_node, ast.ClassDef):
+ return False
+
+ direcly_named_bases = (base for base in ast_node.bases if isinstance(base, ast.Name))
+ for class_base in direcly_named_bases:
+ # We are looking for direct name 'Actor'
+ if class_base.id == 'Actor':
+ return True
+
+ return False
+
+
+def extract_actor_name_from_def(actor_class_def):
+ assignment_value_class = ast.Str if sys.version_info < (3,8) else ast.Constant
+ assignment_value_attrib = 's' if sys.version_info < (3,8) else 'value'
+
+ actor_name = None
+ class_level_assignments = (child for child in actor_class_def.body if isinstance(child, ast.Assign))
+ # Search for class-level assignment specifying actor's name: `name = 'name'`
+ for child in class_level_assignments:
+ assignment = child
+ for target in assignment.targets:
+ assignment_adds_name_attrib = isinstance(target, ast.Name) and target.id == 'name'
+ assignment_uses_a_constant_string = isinstance(assignment.value, assignment_value_class)
+ if assignment_adds_name_attrib and assignment_uses_a_constant_string:
+ rhs = assignment.value # <lhs> = <rhs>
+ actor_name = getattr(rhs, assignment_value_attrib)
+ break
+ if actor_name is not None:
+ break
+ return actor_name
+
+
+def get_actor_names(actor_path):
+ with open(actor_path) as actor_file:
+ try:
+ actor_def = ast.parse(actor_file.read())
+ except SyntaxError:
+ error = ('Failed to parse {0}. The actor might contain syntax errors, or perhaps it '
+ 'is written with Python3-specific syntax?\n')
+ sys.stderr.write(error.format(actor_path))
+ return []
+ actor_defs = [ast_node for ast_node in actor_def.body if is_direct_actor_def(ast_node)]
+ actors = [extract_actor_name_from_def(actor_def) for actor_def in actor_defs]
+ return actors
+
+
+def make_parser():
+ parser = argparse.ArgumentParser()
+ parser.add_argument('actor_names', nargs='+',
+ help='Actor names (the name attribute of the actor class) to look for.')
+ parser.add_argument('-C', '--change-dir', dest='cwd',
+ help='Path in which the actors will be looked for.', default='.')
+ return parser
+
+
+if __name__ == '__main__':
+ parser = make_parser()
+ args = parser.parse_args()
+ cwd = os.path.abspath(args.cwd)
+ actor_names_to_search_for = set(args.actor_names)
+
+ actor_paths = []
+ for directory, dummy_subdirs, dir_files in os.walk(cwd):
+ for actor_path in dir_files:
+ actor_path = os.path.join(directory, actor_path)
+ if os.path.basename(actor_path) != 'actor.py':
+ continue
+
+ defined_actor_names = set(get_actor_names(actor_path))
+ if defined_actor_names.intersection(actor_names_to_search_for):
+ actor_module_path = directory
+ actor_paths.append(actor_module_path)
+ print('\n'.join(actor_paths))
--
2.41.0