diff mbox series

[v2,2/8] tests/cooker: add a shared bitbake-subprocess test base class

Message ID 20260816221507.155861-3-adrian.freihofer@siemens.com
State New
Headers show
Series cooker/tinfoil: fix -b bbappend handling and add single-task prepared-task API | expand

Commit Message

AdrianF Aug. 16, 2026, 10:14 p.m. UTC
From: Adrian Freihofer <adrian.freihofer@siemens.com>

Tests that run bitbake or tinfoil in a subprocess against a temporary
build directory can leave behind a memory-resident bitbake server (and,
if BB_HASHSERVE=auto, a hashserv) rooted at TOPDIR. That server must
release the directory before the caller's TemporaryDirectory context
manager can safely remove it, or cleanup can race a still-running
server holding files open there.

Add _BitbakeSubprocessTestCase with _run_subprocess()/_shutdown() to
provide this consistently, so the tests added on top of it in the next
commits don't each have to hand-roll the subprocess/wait boilerplate -
and, more importantly, don't get a chance to forget the wait.

AI-Generated: Uses GitHub Copilot

Signed-off-by: Adrian Freihofer <adrian.freihofer@siemens.com>
---
 lib/bb/tests/cooker.py | 52 +++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 51 insertions(+), 1 deletion(-)
diff mbox series

Patch

diff --git a/lib/bb/tests/cooker.py b/lib/bb/tests/cooker.py
index 9e524ae34..c49375ed8 100644
--- a/lib/bb/tests/cooker.py
+++ b/lib/bb/tests/cooker.py
@@ -7,12 +7,62 @@ 
 #
 
 import unittest
+import contextlib
 import os
+import subprocess
+import sys
+import tempfile
+import time
 import bb, bb.cooker
 import re
 import logging
 
-# Cooker tests
+
+class _BitbakeSubprocessTestCase(unittest.TestCase):
+    """Common helpers for tests that run bitbake/tinfoil in a subprocess.
+
+    Shared because every such subprocess can start a memory-resident bitbake
+    server (and, if BB_HASHSERVE=auto, a hashserv) rooted at TOPDIR, and both
+    must release that directory before the caller's TemporaryDirectory can be
+    safely removed.
+    """
+
+    def _run_subprocess(self, cmd, env, cwd):
+        proc = subprocess.run(
+            cmd,
+            env=env,
+            stdout=subprocess.PIPE,
+            stderr=subprocess.STDOUT,
+            universal_newlines=True,
+            cwd=cwd,
+        )
+        if proc.returncode:
+            self.fail('%s failed: %s' % (cmd, proc.stdout))
+        return proc.stdout
+
+    def _shutdown(self, builddir):
+        """Wait for the bitbake server and hashserv to release builddir.
+
+        Must run before the caller's TemporaryDirectory is removed, so it
+        cannot be a tearDown().
+        """
+        deadline = time.monotonic() + 30
+        while time.monotonic() < deadline:
+            if not any(os.path.exists(os.path.join(builddir, p))
+                       for p in ('hashserve.sock', 'bitbake.lock')):
+                return
+            time.sleep(0.5)
+
+    @contextlib.contextmanager
+    def _build_dir(self, prefix='tinfoiltest'):
+        """TemporaryDirectory that also waits out _shutdown() before removal."""
+        with tempfile.TemporaryDirectory(prefix=prefix) as builddir:
+            try:
+                yield builddir
+            finally:
+                self._shutdown(builddir)
+
+
 class CookerTest(unittest.TestCase):
     def setUp(self):
         # At least one variable needs to be set