From 4264e570f2d28e472e16b883353d918a94e3b7cd Mon Sep 17 00:00:00 2001 From: Gary Gregory Date: Sun, 26 Jul 2026 12:23:18 -0400 Subject: [PATCH] Add org.apache.commons.io.FileCleaningTracker.exitWhenFinishedTest() Used in tests, for example, Commons FileUpload. --- .../commons/io/FileCleaningTracker.java | 11 ++++++ .../commons/io/FileCleaningTrackerTest.java | 36 +++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/src/main/java/org/apache/commons/io/FileCleaningTracker.java b/src/main/java/org/apache/commons/io/FileCleaningTracker.java index 376f5d636cb..5b647ff53e3 100644 --- a/src/main/java/org/apache/commons/io/FileCleaningTracker.java +++ b/src/main/java/org/apache/commons/io/FileCleaningTracker.java @@ -220,6 +220,17 @@ public synchronized void exitWhenFinished() { } } + /** + * Tests whether {@link #exitWhenFinished()} has been called, and therefore whether the file cleaner thread will terminate when there are no more objects + * being tracked for deletion. + * + * @return {@code true} if {@link #exitWhenFinished()} has been called, {@code false} otherwise. + * @since 2.23.0 + */ + public synchronized boolean exitWhenFinishedTest() { + return exitWhenFinished; + } + /** * Gets a copy of the file paths that failed to delete. * diff --git a/src/test/java/org/apache/commons/io/FileCleaningTrackerTest.java b/src/test/java/org/apache/commons/io/FileCleaningTrackerTest.java index 85bfea1aa00..bca09be09c5 100644 --- a/src/test/java/org/apache/commons/io/FileCleaningTrackerTest.java +++ b/src/test/java/org/apache/commons/io/FileCleaningTrackerTest.java @@ -115,6 +115,42 @@ public void tearDown() { fileCleaningTracker = null; } + @Test + void testExitWhenFinishedTestMatchesField() { + // Before calling exitWhenFinished() + assertEquals(fileCleaningTracker.exitWhenFinished, fileCleaningTracker.exitWhenFinishedTest(), + "exitWhenFinishedTest() must reflect the exitWhenFinished field (before)"); + fileCleaningTracker.exitWhenFinished(); + // After calling exitWhenFinished() + assertEquals(fileCleaningTracker.exitWhenFinished, fileCleaningTracker.exitWhenFinishedTest(), + "exitWhenFinishedTest() must reflect the exitWhenFinished field (after)"); + } + + @Test + void testExitWhenFinishedTestReturnsFalseInitially() { + assertFalse(fileCleaningTracker.exitWhenFinishedTest(), "exitWhenFinishedTest() should return false before exitWhenFinished() is called"); + } + + @Test + void testExitWhenFinishedTestReturnsTrueAfterExitWhenFinished() { + fileCleaningTracker.exitWhenFinished(); + assertTrue(fileCleaningTracker.exitWhenFinishedTest(), "exitWhenFinishedTest() should return true after exitWhenFinished() is called"); + } + + @Test + void testExitWhenFinishedTestWithActiveReaper() throws Exception { + final String path = testFile.getPath(); + // Start the reaper by tracking a file + final RandomAccessFile raf = createRandomAccessFile(); + fileCleaningTracker.track(path, raf); + assertFalse(fileCleaningTracker.exitWhenFinishedTest(), "exitWhenFinishedTest() should return false while reaper is still active"); + assertTrue(fileCleaningTracker.reaper.isAlive(), "Reaper should be alive"); + fileCleaningTracker.exitWhenFinished(); + assertTrue(fileCleaningTracker.exitWhenFinishedTest(), + "exitWhenFinishedTest() should return true after exitWhenFinished() is called with active reaper"); + raf.close(); + } + @Test void testFileCleanerDirectory_ForceStrategy_FileSource() throws Exception { if (!testFile.getParentFile().exists()) {