* [Buildroot] [PATCH v2 1/1] support/testing: transfer config in environment instead of class variables
@ 2026-03-06 21:55 Fiona Klute via buildroot
2026-05-30 14:32 ` Thomas Petazzoni via buildroot
0 siblings, 1 reply; 2+ messages in thread
From: Fiona Klute via buildroot @ 2026-03-06 21:55 UTC (permalink / raw)
To: buildroot
Cc: Ricardo Martincoski, Jimmy Durand Wesolowski, Julien Olivain,
guenther.harrasser, Fiona Klute
Passing runtime configuration to tests in BRConfigTest class variables
requires the "fork" start method for multiprocessing. With
"forkserver" (default for POSIX platforms since Python 3.14) class
variables modified in the parent process are lost, because the child
process does not inherit the full Python state. This broke the way
support/testing/run-tests sets configuration for BRConfigTest, so a
start method override was added in commit
3d2141bceefda32bef06ddda594eaf8665913276.
Instead this patch adds a settings dataclass (requires Python >= 3.7)
which is serialized into an environment variable from run-tests and
read during BRConfigTest.__init__(). Reading is skipped if the
environment variable is not set so test discovery (not execution)
works without configuration (e.g. utils/get-developers uses this).
With that, run-tests no longer relies on a specific multiprocessing
start method.
Signed-off-by: Fiona Klute <fiona.klute@gmx.de>
---
Changes v1 -> v2:
* Restructure to use dataclasses, which simplifies the code but
requires Python 3.7
support/testing/infra/basetest.py | 37 ++++++++++++++++++++++++++++++
support/testing/run-tests | 38 ++++++++++++-------------------
2 files changed, 52 insertions(+), 23 deletions(-)
diff --git a/support/testing/infra/basetest.py b/support/testing/infra/basetest.py
index 13f9b2d398..5fa902a77f 100644
--- a/support/testing/infra/basetest.py
+++ b/support/testing/infra/basetest.py
@@ -1,6 +1,9 @@
import unittest
import os
+import dataclasses
import datetime
+import json
+from typing import ClassVar
from infra.builder import Builder
from infra.emulator import Emulator
@@ -22,6 +25,33 @@ MINIMAL_CONFIG = \
"""
+@dataclasses.dataclass
+class BRTestSettings:
+ """support/testing/run-tests stores runtime settings in this
+ object, and serializes it into the environment variable named in
+ CONF_ENV. On instantiation, BRConfigTest loads this
+ configuration. That way configuration can be transferred into
+ multiprocessing worker processes without requiring the "fork"
+ start method.
+
+ """
+ CONF_ENV: ClassVar[str] = 'BR_TEST_CONFIG_JSON'
+
+ downloaddir: str
+ outputdir: str
+ logtofile: bool = True
+ keepbuilds: bool = False
+ jlevel: int = 0
+ timeout_multiplier: int = 1
+
+ def to_env(self) -> None:
+ os.environ[self.CONF_ENV] = json.dumps(dataclasses.asdict(self))
+
+ @classmethod
+ def from_env(cls) -> 'BRTestSettings':
+ return cls(**json.loads(os.environ[cls.CONF_ENV]))
+
+
class BRConfigTest(unittest.TestCase):
"""Test up to the configure stage."""
config: str
@@ -35,6 +65,8 @@ class BRConfigTest(unittest.TestCase):
def __init__(self, names):
super(BRConfigTest, self).__init__(names)
+ if BRTestSettings.CONF_ENV in os.environ:
+ self.conf_from_env()
self.testname = self.__class__.__name__
self.builddir = self.outputdir and os.path.join(self.outputdir, self.testname)
self.config += '\nBR2_DL_DIR="{}"\n'.format(self.downloaddir)
@@ -44,6 +76,11 @@ class BRConfigTest(unittest.TestCase):
print("{} {:40s} {}".format(datetime.datetime.now().strftime("%H:%M:%S"),
self.testname, msg))
+ def conf_from_env(self) -> None:
+ conf = BRTestSettings.from_env()
+ for f in dataclasses.fields(conf):
+ setattr(self, f.name, getattr(conf, f.name))
+
def setUp(self):
self.show_msg("Starting")
self.b = Builder(self.config, self.builddir, self.logtofile, self.jlevel)
diff --git a/support/testing/run-tests b/support/testing/run-tests
index 2c7ce87c96..f0c1cc782a 100755
--- a/support/testing/run-tests
+++ b/support/testing/run-tests
@@ -6,7 +6,7 @@ import sys
import nose2
-from infra.basetest import BRConfigTest
+from infra.basetest import BRTestSettings
import infra
@@ -44,9 +44,6 @@ def main():
script_path = os.path.realpath(__file__)
test_dir = os.path.dirname(script_path)
- if args.stdout:
- BRConfigTest.logtofile = False
-
if args.list:
print("List of tests")
nose2_args = [
@@ -69,7 +66,7 @@ def main():
parser.print_help()
return 1
- BRConfigTest.downloaddir = os.path.abspath(args.download)
+ args.download = os.path.abspath(args.download)
if args.prepare_only:
emulator_builtin_binaries = ["kernel-vexpress-5.10.202",
@@ -78,7 +75,7 @@ def main():
"versatile-pb-5.10.202.dtb"]
print("Downloading emulator builtin binaries")
for binary in emulator_builtin_binaries:
- infra.download(BRConfigTest.downloaddir, binary)
+ infra.download(args.download, binary)
return 0
if args.output is None:
@@ -90,15 +87,13 @@ def main():
if not os.path.exists(args.output):
os.mkdir(args.output)
- BRConfigTest.outputdir = os.path.abspath(args.output)
-
if args.all is False and not args.testname:
print("No test selected")
print("")
parser.print_help()
return 1
- BRConfigTest.keepbuilds = args.keep
+ jlevel = 0
if args.testcases != 1:
if args.testcases < 1:
@@ -109,7 +104,7 @@ def main():
# same default BR2_JLEVEL as package/Makefile.in
br2_jlevel = 1 + multiprocessing.cpu_count()
each_testcase = int((br2_jlevel + args.testcases) / args.testcases)
- BRConfigTest.jlevel = each_testcase
+ jlevel = each_testcase
if args.jlevel:
if args.jlevel < 0:
@@ -118,14 +113,22 @@ def main():
parser.print_help()
return 1
# the user can override the auto calculated value
- BRConfigTest.jlevel = args.jlevel
+ jlevel = args.jlevel
if args.timeout_multiplier < 1:
print("Invalid multiplier for timeout values")
print("")
parser.print_help()
return 1
- BRConfigTest.timeout_multiplier = args.timeout_multiplier
+
+ BRTestSettings(
+ logtofile=not args.stdout,
+ downloaddir=args.download,
+ outputdir=os.path.abspath(args.output),
+ keepbuilds=args.keep,
+ jlevel=jlevel,
+ timeout_multiplier=args.timeout_multiplier
+ ).to_env()
nose2_args = ["-v",
"-N", str(args.testcases),
@@ -142,15 +145,4 @@ def main():
if __name__ == "__main__":
- # python 3.14 changed default start method from fork to
- # fork-server, which is not compatible with the nose2 setup
- if multiprocessing.get_start_method(allow_none=True) != "fork":
- multiprocessing.set_start_method("fork", force=True)
- # set_start_method throws a RuntimeError if called more than
- # once.
- # Debian python3-nose2 0.15.1-2 includes a patch adding
- # another set_start_method() call, so monkey patch it out to
- # get rid of this
- multiprocessing.set_start_method = lambda *args: None
-
sys.exit(main())
--
2.53.0
_______________________________________________
buildroot mailing list
buildroot@buildroot.org
https://lists.buildroot.org/mailman/listinfo/buildroot
^ permalink raw reply related [flat|nested] 2+ messages in thread* Re: [Buildroot] [PATCH v2 1/1] support/testing: transfer config in environment instead of class variables
2026-03-06 21:55 [Buildroot] [PATCH v2 1/1] support/testing: transfer config in environment instead of class variables Fiona Klute via buildroot
@ 2026-05-30 14:32 ` Thomas Petazzoni via buildroot
0 siblings, 0 replies; 2+ messages in thread
From: Thomas Petazzoni via buildroot @ 2026-05-30 14:32 UTC (permalink / raw)
To: Fiona Klute
Cc: buildroot, Ricardo Martincoski, Jimmy Durand Wesolowski,
Julien Olivain, guenther.harrasser
On Fri, Mar 06, 2026 at 10:55:39PM +0100, Fiona Klute via buildroot wrote:
> Passing runtime configuration to tests in BRConfigTest class variables
> requires the "fork" start method for multiprocessing. With
> "forkserver" (default for POSIX platforms since Python 3.14) class
> variables modified in the parent process are lost, because the child
> process does not inherit the full Python state. This broke the way
> support/testing/run-tests sets configuration for BRConfigTest, so a
> start method override was added in commit
> 3d2141bceefda32bef06ddda594eaf8665913276.
>
> Instead this patch adds a settings dataclass (requires Python >= 3.7)
> which is serialized into an environment variable from run-tests and
> read during BRConfigTest.__init__(). Reading is skipped if the
> environment variable is not set so test discovery (not execution)
> works without configuration (e.g. utils/get-developers uses this).
>
> With that, run-tests no longer relies on a specific multiprocessing
> start method.
>
> Signed-off-by: Fiona Klute <fiona.klute@gmx.de>
Thanks a lot for having cleaned up my terrible code! Applied to next.
Best regards,
Thomas
--
Thomas Petazzoni, co-owner and CEO, Bootlin
Embedded Linux and Kernel engineering and training
https://bootlin.com
_______________________________________________
buildroot mailing list
buildroot@buildroot.org
https://lists.buildroot.org/mailman/listinfo/buildroot
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2026-05-30 14:32 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-03-06 21:55 [Buildroot] [PATCH v2 1/1] support/testing: transfer config in environment instead of class variables Fiona Klute via buildroot
2026-05-30 14:32 ` Thomas Petazzoni via buildroot
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox