1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.io;
18
19 import static org.junit.jupiter.api.Assertions.assertEquals;
20 import static org.junit.jupiter.api.Assertions.assertFalse;
21 import static org.junit.jupiter.api.Assertions.assertNull;
22 import static org.junit.jupiter.api.Assertions.assertThrows;
23 import static org.junit.jupiter.api.Assertions.assertTrue;
24
25 import java.io.BufferedOutputStream;
26 import java.io.File;
27 import java.io.FileNotFoundException;
28 import java.io.IOException;
29 import java.io.RandomAccessFile;
30 import java.lang.ref.ReferenceQueue;
31 import java.nio.file.Files;
32 import java.nio.file.Path;
33 import java.nio.file.Paths;
34 import java.util.ArrayList;
35 import java.util.List;
36
37 import org.apache.commons.io.file.AbstractTempDirTest;
38 import org.apache.commons.io.test.TestUtils;
39 import org.junit.jupiter.api.AfterEach;
40 import org.junit.jupiter.api.BeforeEach;
41 import org.junit.jupiter.api.Test;
42
43
44
45
46 public class FileCleaningTrackerTest extends AbstractTempDirTest {
47
48 private File testFile;
49 private Path testPath;
50
51 private FileCleaningTracker theInstance;
52
53 RandomAccessFile createRandomAccessFile() throws FileNotFoundException {
54 return RandomAccessFileMode.READ_WRITE.create(testFile);
55 }
56
57 protected FileCleaningTracker newInstance() {
58 return new FileCleaningTracker();
59 }
60
61 private void pauseForDeleteToComplete(File file) {
62 int count = 0;
63 while (file.exists() && count++ < 40) {
64 TestUtils.sleepQuietly(500L);
65 file = new File(file.getPath());
66 }
67 }
68
69 private void pauseForDeleteToComplete(Path file) {
70 int count = 0;
71 while (Files.exists(file) && count++ < 40) {
72 TestUtils.sleepQuietly(500L);
73 file = Paths.get(file.toAbsolutePath().toString());
74 }
75 }
76
77 @BeforeEach
78 public void setUp() {
79 testFile = new File(tempDirFile, "file-test.txt");
80 testPath = testFile.toPath();
81 theInstance = newInstance();
82 }
83
84 private String showFailures() {
85 if (theInstance.deleteFailures.size() == 1) {
86 return "[Delete Failed: " + theInstance.deleteFailures.get(0) + "]";
87 }
88 return "[Delete Failures: " + theInstance.deleteFailures.size() + "]";
89 }
90
91 @AfterEach
92 public void tearDown() {
93
94
95
96
97
98
99
100
101 {
102 if (theInstance != null) {
103 theInstance.q = new ReferenceQueue<>();
104 theInstance.trackers.clear();
105 theInstance.deleteFailures.clear();
106 theInstance.exitWhenFinished = false;
107 theInstance.reaper = null;
108 }
109 }
110
111 theInstance = null;
112 }
113
114 @Test
115 public void testFileCleanerDirectory_ForceStrategy_FileSource() throws Exception {
116 if (!testFile.getParentFile().exists()) {
117 throw new IOException("Cannot create file " + testFile
118 + " as the parent directory does not exist");
119 }
120 try (BufferedOutputStream output =
121 new BufferedOutputStream(Files.newOutputStream(testFile.toPath()))) {
122 TestUtils.generateTestData(output, 100);
123 }
124 assertTrue(testFile.exists());
125 assertTrue(tempDirFile.exists());
126
127 Object obj = new Object();
128 assertEquals(0, theInstance.getTrackCount());
129 theInstance.track(tempDirFile, obj, FileDeleteStrategy.FORCE);
130 assertEquals(1, theInstance.getTrackCount());
131
132 obj = null;
133
134 waitUntilTrackCount();
135 pauseForDeleteToComplete(testFile.getParentFile());
136
137 assertEquals(0, theInstance.getTrackCount());
138 assertFalse(new File(testFile.getPath()).exists(), showFailures());
139 assertFalse(testFile.getParentFile().exists(), showFailures());
140 }
141
142 @Test
143 public void testFileCleanerDirectory_ForceStrategy_PathSource() throws Exception {
144 if (!Files.exists(testPath.getParent())) {
145 throw new IOException("Cannot create file " + testPath
146 + " as the parent directory does not exist");
147 }
148 try (BufferedOutputStream output =
149 new BufferedOutputStream(Files.newOutputStream(testPath))) {
150 TestUtils.generateTestData(output, 100);
151 }
152 assertTrue(Files.exists(testPath));
153 assertTrue(Files.exists(tempDirPath));
154
155 Object obj = new Object();
156 assertEquals(0, theInstance.getTrackCount());
157 theInstance.track(tempDirPath, obj, FileDeleteStrategy.FORCE);
158 assertEquals(1, theInstance.getTrackCount());
159
160 obj = null;
161
162 waitUntilTrackCount();
163 pauseForDeleteToComplete(testPath.getParent());
164
165 assertEquals(0, theInstance.getTrackCount());
166 assertFalse(Files.exists(testPath), showFailures());
167 assertFalse(Files.exists(testPath.getParent()), showFailures());
168 }
169
170 @Test
171 public void testFileCleanerDirectory_NullStrategy() throws Exception {
172 TestUtils.createFile(testFile, 100);
173 assertTrue(testFile.exists());
174 assertTrue(tempDirFile.exists());
175
176 Object obj = new Object();
177 assertEquals(0, theInstance.getTrackCount());
178 theInstance.track(tempDirFile, obj, null);
179 assertEquals(1, theInstance.getTrackCount());
180
181 obj = null;
182
183 waitUntilTrackCount();
184
185 assertEquals(0, theInstance.getTrackCount());
186 assertTrue(testFile.exists());
187 assertTrue(testFile.getParentFile().exists());
188 }
189
190 @Test
191 public void testFileCleanerDirectoryFileSource() throws Exception {
192 TestUtils.createFile(testFile, 100);
193 assertTrue(testFile.exists());
194 assertTrue(tempDirFile.exists());
195
196 Object obj = new Object();
197 assertEquals(0, theInstance.getTrackCount());
198 theInstance.track(tempDirFile, obj);
199 assertEquals(1, theInstance.getTrackCount());
200
201 obj = null;
202
203 waitUntilTrackCount();
204
205 assertEquals(0, theInstance.getTrackCount());
206 assertTrue(testFile.exists());
207 assertTrue(testFile.getParentFile().exists());
208 }
209
210 @Test
211 public void testFileCleanerDirectoryPathSource() throws Exception {
212 TestUtils.createFile(testPath, 100);
213 assertTrue(Files.exists(testPath));
214 assertTrue(Files.exists(tempDirPath));
215
216 Object obj = new Object();
217 assertEquals(0, theInstance.getTrackCount());
218 theInstance.track(tempDirPath, obj);
219 assertEquals(1, theInstance.getTrackCount());
220
221 obj = null;
222
223 waitUntilTrackCount();
224
225 assertEquals(0, theInstance.getTrackCount());
226 assertTrue(Files.exists(testPath));
227 assertTrue(Files.exists(testPath.getParent()));
228 }
229
230 @Test
231 public void testFileCleanerExitWhenFinished_NoTrackAfter() {
232 assertFalse(theInstance.exitWhenFinished);
233 theInstance.exitWhenFinished();
234 assertTrue(theInstance.exitWhenFinished);
235 assertNull(theInstance.reaper);
236
237 final String path = testFile.getPath();
238 final Object marker = new Object();
239
240 assertThrows(IllegalStateException.class, () -> theInstance.track(path, marker));
241 assertTrue(theInstance.exitWhenFinished);
242 assertNull(theInstance.reaper);
243 }
244
245 @Test
246 public void testFileCleanerExitWhenFinished1() throws Exception {
247 final String path = testFile.getPath();
248
249 assertFalse(testFile.exists(), "1-testFile exists: " + testFile);
250
251
252 RandomAccessFile raf = createRandomAccessFile();
253 assertTrue(testFile.exists(), "2-testFile exists");
254
255 assertEquals(0, theInstance.getTrackCount(), "3-Track Count");
256 theInstance.track(path, raf);
257 assertEquals(1, theInstance.getTrackCount(), "4-Track Count");
258 assertFalse(theInstance.exitWhenFinished, "5-exitWhenFinished");
259 assertTrue(theInstance.reaper.isAlive(), "6-reaper.isAlive");
260
261 assertFalse(theInstance.exitWhenFinished, "7-exitWhenFinished");
262 theInstance.exitWhenFinished();
263 assertTrue(theInstance.exitWhenFinished, "8-exitWhenFinished");
264 assertTrue(theInstance.reaper.isAlive(), "9-reaper.isAlive");
265
266 raf.close();
267 testFile = null;
268 raf = null;
269
270 waitUntilTrackCount();
271 pauseForDeleteToComplete(new File(path));
272
273 assertEquals(0, theInstance.getTrackCount(), "10-Track Count");
274 assertFalse(new File(path).exists(), "11-testFile exists " + showFailures());
275 assertTrue(theInstance.exitWhenFinished, "12-exitWhenFinished");
276 assertFalse(theInstance.reaper.isAlive(), "13-reaper.isAlive");
277 }
278
279 @Test
280 public void testFileCleanerExitWhenFinished2() throws Exception {
281 final String path = testFile.getPath();
282
283 assertFalse(testFile.exists());
284 RandomAccessFile r = createRandomAccessFile();
285 assertTrue(testFile.exists());
286
287 assertEquals(0, theInstance.getTrackCount());
288 theInstance.track(path, r);
289 assertEquals(1, theInstance.getTrackCount());
290 assertFalse(theInstance.exitWhenFinished);
291 assertTrue(theInstance.reaper.isAlive());
292
293 r.close();
294 testFile = null;
295 r = null;
296
297 waitUntilTrackCount();
298 pauseForDeleteToComplete(new File(path));
299
300 assertEquals(0, theInstance.getTrackCount());
301 assertFalse(new File(path).exists(), showFailures());
302 assertFalse(theInstance.exitWhenFinished);
303 assertTrue(theInstance.reaper.isAlive());
304
305 assertFalse(theInstance.exitWhenFinished);
306 theInstance.exitWhenFinished();
307 for (int i = 0; i < 20 && theInstance.reaper.isAlive(); i++) {
308 TestUtils.sleep(500L);
309 }
310 assertTrue(theInstance.exitWhenFinished);
311 assertFalse(theInstance.reaper.isAlive());
312 }
313
314 @Test
315 public void testFileCleanerExitWhenFinishedFirst() throws Exception {
316 assertFalse(theInstance.exitWhenFinished);
317 theInstance.exitWhenFinished();
318 assertTrue(theInstance.exitWhenFinished);
319 assertNull(theInstance.reaper);
320
321 waitUntilTrackCount();
322
323 assertEquals(0, theInstance.getTrackCount());
324 assertTrue(theInstance.exitWhenFinished);
325 assertNull(theInstance.reaper);
326 }
327
328 @Test
329 public void testFileCleanerFile() throws Exception {
330 final String path = testFile.getPath();
331
332 assertFalse(testFile.exists());
333 RandomAccessFile r = createRandomAccessFile();
334 assertTrue(testFile.exists());
335
336 assertEquals(0, theInstance.getTrackCount());
337 theInstance.track(path, r);
338 assertEquals(1, theInstance.getTrackCount());
339
340 r.close();
341 testFile = null;
342 r = null;
343
344 waitUntilTrackCount();
345 pauseForDeleteToComplete(new File(path));
346
347 assertEquals(0, theInstance.getTrackCount());
348 assertFalse(new File(path).exists(), showFailures());
349 }
350 @Test
351 public void testFileCleanerNull() {
352 assertThrows(NullPointerException.class, () -> theInstance.track((File) null, new Object()));
353 assertThrows(NullPointerException.class, () -> theInstance.track((File) null, new Object(), FileDeleteStrategy.NORMAL));
354 assertThrows(NullPointerException.class, () -> theInstance.track((String) null, new Object()));
355 assertThrows(NullPointerException.class, () -> theInstance.track((String) null, new Object(), FileDeleteStrategy.NORMAL));
356 }
357
358 private void waitUntilTrackCount() throws Exception {
359 System.gc();
360 TestUtils.sleep(500);
361 int count = 0;
362 while (theInstance.getTrackCount() != 0 && count++ < 5) {
363 List<String> list = new ArrayList<>();
364 try {
365 long i = 0;
366 while (theInstance.getTrackCount() != 0) {
367 list.add(
368 "A Big String A Big String A Big String A Big String A Big String A Big String A Big String A Big String A Big String A Big String "
369 + i++);
370 }
371 } catch (final Throwable ignored) {
372 }
373 list = null;
374 System.gc();
375 TestUtils.sleep(1000);
376 }
377 if (theInstance.getTrackCount() != 0) {
378 throw new IllegalStateException("Your JVM is not releasing References, try running the test with less memory (-Xmx)");
379 }
380
381 }
382 }