Repository navigation
test: stop a leftover soffice from hanging the test run (#1158) - #1160
Merged
Merged
Conversation
The LibreOffice oracles read their script's output to the end before waiting with a timeout, and the scripts started soffice with that same output. A soffice.bin orphaned by a timed-out shutdown call kept the pipe open, so the read never returned and the timeout never ran. Tests now run the scripts through TestProcess, which reads on background tasks, kills the process tree at the deadline and stops waiting on a pipe a leftover process still holds. Every LibreOffice script starts and stops soffice through lo_soffice.py, with no inherited output, its own process group, and a whole-group stop.
Guard the scripts' shutdown so a failed unaccept still stops the listener, wait for the whole process group before escalating to SIGKILL, keep Python bytecode caches out of the source tree, and name the six scripts the change covers.
CI's busy test host starved the thread pool for longer than the drain grace, so a pool-task reader had read nothing when the helper gave up. Each output pump is now its own background thread.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #1158
Why
A full
dotnet testrun sat idle for 80 minutes inside the header/footer comparison smoke test. The test starts a Python script that drives LibreOffice, reads the script's output to the end, and only then waits for the script with a two-minute timeout. Reading to the end only finishes when every process holding the output pipe has closed it. The script startedsofficewith that same output, and when its shutdown call timed out it killed only thesofficeshell wrapper; thesoffice.binit had launched kept running and kept the pipe open. So the read never finished and the timeout never ran.How it works
Both halves the issue suggested are done, so either one alone would have prevented the hang.
Test side. A new helper,
Docxodus.Tests/TestProcess.cs, runs a child process the safe way: it reads stdout and stderr on two dedicated background threads (not thread-pool tasks, which a busy test host can starve), waits for the process with a deadline, kills the whole process tree when the deadline passes, and then gives the readers a short grace period (5 s). If a leftover process still holds the pipe after that, the helper returns what it has read and reports the output as incomplete instead of waiting. The three LibreOffice oracle runners (header/footer smoke, comment real-document, block-format real-document) now use it. The helper also setsPYTHONDONTWRITEBYTECODEso the scripts don't leave__pycache__in the source tree.Script side. A new module,
tools/diffharness/lo/lo_soffice.py, starts everysofficewith/dev/nullfor its standard streams and in its own process group, and stops it by signalling the whole group (SIGTERM, wait for the group to empty, then SIGKILL). The--unacceptshutdown call runs the same way and is killed as a group if it takes longer than 10 s. The six UNO oracle scripts (header/footer, comment, bookmark, footnote, compare, batch) use it; their LibreOffice logic is unchanged.Validation
TestProcessTests): a shell that exits while a backgroundsleep 60holds its stdout returns within the bound; a process past its deadline is killed with its output kept; stdout/stderr are both collected. With the helper mutated back to read-to-end-before-wait, two of them fail after hanging the full 60 s.test_lo_soffice.py): a fakesofficewhose child outlives it no longer holds the caller's pipe; stopping the listener ends what it started; a detached command is killed as a group at its timeout. Removing the/dev/nullredirection or the separate session makes them fail.soffice.binleft afterwards. All six rewired scripts were smoke-run against a fixture.tools/diffharness/lo: 17 tests pass.Adversarial review
One round of hostile review ran on the diff before opening. It confirmed against the real LibreOffice launcher (
soffice→oosplash→soffice.bin, all in one group) that the group kill reachessoffice.bin, and that a no-listener--unaccept(the orphan from the issue) is now killed after 10 s. It found four low-severity problems, all fixed in the second commit: the CHANGELOG overclaimed "every script" (lo_render.pymanages its own processes); the oracle runs left__pycache__in the tree; a failingunacceptcall could skip stopping the listener; and the SIGKILL grace waited on the wrapper rather than the whole group. The first CI run then exposed a fifth problem: the readers were thread-pool tasks, and on CI's busy test host they had not run within the one-second drain grace, so the descendant test saw empty output. The third commit moves each reader to its own thread. Two other spawn sites with lower exposure (SourceFileCopyrightTestsrunninggit, and the history-recovery probe) were left as they are.