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

AdrianF <[email protected]>
Newsgroups org.openembedded.lists.bitbake-devel
Message-ID <[email protected]>
From: Adrian Freihofer <[email protected]>

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 <[email protected]>
---
 lib/bb/tests/cooker.py | 52 +++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 51 insertions(+), 1 deletion(-)

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
-- 
2.55.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.