From 566dddfa1b7b4711f0ca25d439c5421bfc6c283f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E9=B9=8F?= Date: Thu, 18 Jun 2026 13:06:36 +0800 Subject: [PATCH] Verify run preview descendant cleanup --- .../front/RunPreviewProcessRunnerTest.java | 47 ++++++++++++++++++- 1 file changed, 45 insertions(+), 2 deletions(-) diff --git a/RuoYi-Vue/ruoyi-generator/src/test/java/com/ruoyi/generator/service/front/RunPreviewProcessRunnerTest.java b/RuoYi-Vue/ruoyi-generator/src/test/java/com/ruoyi/generator/service/front/RunPreviewProcessRunnerTest.java index 236f530..6c3a5af 100644 --- a/RuoYi-Vue/ruoyi-generator/src/test/java/com/ruoyi/generator/service/front/RunPreviewProcessRunnerTest.java +++ b/RuoYi-Vue/ruoyi-generator/src/test/java/com/ruoyi/generator/service/front/RunPreviewProcessRunnerTest.java @@ -11,6 +11,7 @@ import java.nio.file.Files; import java.util.HashMap; import java.util.Map; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; @@ -53,27 +54,38 @@ public class RunPreviewProcessRunnerTest } @Test - public void startCommandRecordsManagedWindowsProcessPid() throws Exception + public void stopManagedWindowsProcessTerminatesDescendantProcess() throws Exception { if (!isWindows()) { return; } File projectDirectory = temporaryFolder.newFolder("managed-process"); + File childPidFile = new File(projectDirectory, "child.pid"); RunPreviewProcessRunner runner = new RunPreviewProcessRunner(); Process process = runner.startCommandForTesting( - "ping 127.0.0.1 -n 3 > nul", projectDirectory, new HashMap()); + "powershell.exe -NoProfile -NonInteractive -Command " + + "\"$PID | Set-Content -NoNewline child.pid; Start-Sleep -Seconds 30\"", + projectDirectory, new HashMap()); + long childPid = -1L; try { assertTrue(process instanceof ManagedPreviewProcess); assertTrue(((ManagedPreviewProcess) process).waitForRootPid(2000L) > 0L); + assertTrue(waitForFile(childPidFile, 2000L)); + childPid = Long.parseLong(new String( + Files.readAllBytes(childPidFile.toPath()), StandardCharsets.UTF_8).trim()); + assertTrue(isWindowsProcessAlive(childPid)); } finally { new RunPreviewProcessKiller().stop(process, null); } + + assertFalse(process.isAlive()); + assertFalse(isWindowsProcessAlive(childPid)); } private File viteProject() throws IOException @@ -99,6 +111,37 @@ public class RunPreviewProcessRunnerTest return nodeHome; } + private boolean waitForFile(File file, long timeoutMillis) throws InterruptedException + { + long deadline = System.currentTimeMillis() + timeoutMillis; + while (System.currentTimeMillis() < deadline) + { + if (file.isFile() && file.length() > 0L) + { + return true; + } + Thread.sleep(25L); + } + return file.isFile() && file.length() > 0L; + } + + private boolean isWindowsProcessAlive(long pid) throws Exception + { + if (pid <= 0L) + { + return false; + } + Process check = new ProcessBuilder( + "powershell.exe", + "-NoProfile", + "-NonInteractive", + "-Command", + "if (Get-Process -Id " + pid + " -ErrorAction SilentlyContinue) { exit 0 } else { exit 1 }") + .redirectErrorStream(true) + .start(); + return check.waitFor() == 0; + } + private boolean isWindows() { String osName = System.getProperty("os.name");