@@ -6,6 +6,7 @@
#
import os
+import sys
import unittest
from unittest import mock
@@ -53,5 +54,15 @@ class TestConcurrency(TestBase):
for other in {1, 2, 3} - {n}:
self.assertNotIn("testStreams%d" % other, output)
+ def test_concurrent_streams_restored(self):
+ # Each process' results are read in a separate thread; after running,
+ # sys.stdout and sys.stderr must be the original streams again. Any
+ # problem here is a race, so run several times.
+ stdout, stderr = sys.stdout, sys.stderr
+ for i in range(50):
+ self._run(['results'], processes=2)
+ self.assertIs(sys.stdout, stdout)
+ self.assertIs(sys.stderr, stderr)
+
if __name__ == '__main__':
unittest.main()
@@ -55,7 +55,9 @@ class BBThreadsafeForwardingResult(ThreadsafeForwardingResult):
self.threadnum = threadnum
self.totalinprocess = totalinprocess
self.totaltests = totaltests
- self.buffer = True
+ # Don't set self.buffer, the output comes through outputbuf. Buffering
+ # here would swap sys.stdout/stderr in each reader thread, unlocked,
+ # and could leave them replaced after the tests have run.
self.outputbuf = output
# The process' output accumulates in outputbuf; this is how much of
# it was given to earlier results
BBThreadsafeForwardingResult set buffer = True, so the forwarding result for each test process swapped sys.stdout and sys.stderr for buffers in its startTest() and restored them in stopTest(). These run in separate reader threads without any locking, and each result records the streams to restore when it is created, which happens after the reader threads for earlier processes have started. sys.stdout/stderr could be left pointing at a buffer after the tests ran, losing later output and making any later forked test process fail at sys.stdout.fileno(). The output of the test processes comes through the passthrough buffer and is given to the final result, which does its own buffering under the semaphore, so don't buffer in the forwarding results. Add a test which checks the streams are restored after concurrent runs. AI-Generated: Uses Claude Opus 5.5 Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org> --- meta/lib/oeqa/core/tests/test_concurrency.py | 11 +++++++++++ meta/lib/oeqa/core/utils/concurrencytest.py | 4 +++- 2 files changed, 14 insertions(+), 1 deletion(-)