1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    * 
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   * 
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.io;
18  
19  import java.io.File;
20  import java.io.IOException;
21  import java.io.RandomAccessFile;
22  import java.lang.ref.ReferenceQueue;
23  
24  import junit.framework.Test;
25  import junit.framework.TestSuite;
26  import junit.textui.TestRunner;
27  
28  import org.apache.commons.io.testtools.FileBasedTestCase;
29  
30  /**
31   * This is used to test {@link FileCleaningTracker} for correctness.
32   *
33   * @author Noel Bergman
34   * @author Martin Cooper
35   *
36   * @version $Id: FileCleanerTestCase.java 482437 2006-12-05 01:13:05Z scolebourne $
37  
38   * @see FileCleaner
39   */
40  public class FileCleaningTrackerTestCase extends FileBasedTestCase {
41      protected FileCleaningTracker newInstance() {
42          return new FileCleaningTracker();
43      }
44  
45      private File testFile;
46      private FileCleaningTracker theInstance;
47  
48      public static void main(String[] args) {
49          TestRunner.run(suite());
50      }
51  
52      public static Test suite() {
53          return new TestSuite(FileCleaningTrackerTestCase.class);
54      }
55  
56      public FileCleaningTrackerTestCase(String name) throws IOException {
57          super(name);
58  
59          testFile = new File(getTestDirectory(), "file-test.txt");
60      }
61  
62      /** @see junit.framework.TestCase#setUp() */
63      protected void setUp() throws Exception {
64          theInstance = newInstance();
65          getTestDirectory().mkdirs();
66      }
67  
68      /** @see junit.framework.TestCase#tearDown() */
69      protected void tearDown() throws Exception {
70          FileUtils.deleteDirectory(getTestDirectory());
71          
72          // reset file cleaner class, so as not to break other tests
73  
74          /**
75           * The following block of code can possibly be removed when the
76           * deprecated {@link FileCleaner} is gone. The question is, whether
77           * we want to support reuse of {@link FileCleaningTracker} instances,
78           * which we should, IMO, not.
79           */
80          {
81              theInstance.q = new ReferenceQueue();
82              theInstance.trackers.clear();
83              theInstance.exitWhenFinished = false;
84              theInstance.reaper = null;
85          }
86          
87          theInstance = null;
88      }
89  
90      //-----------------------------------------------------------------------
91      public void testFileCleanerFile() throws Exception {
92          String path = testFile.getPath();
93          
94          assertEquals(false, testFile.exists());
95          RandomAccessFile r = new RandomAccessFile(testFile, "rw");
96          assertEquals(true, testFile.exists());
97          
98          assertEquals(0, theInstance.getTrackCount());
99          theInstance.track(path, r);
100         assertEquals(1, theInstance.getTrackCount());
101         
102         r.close();
103         testFile = null;
104         r = null;
105 
106         waitUntilTrackCount();
107         
108         assertEquals(0, theInstance.getTrackCount());
109         assertEquals(false, new File(path).exists());
110     }
111 
112     public void testFileCleanerDirectory() throws Exception {
113         createFile(testFile, 100);
114         assertEquals(true, testFile.exists());
115         assertEquals(true, getTestDirectory().exists());
116         
117         Object obj = new Object();
118         assertEquals(0, theInstance.getTrackCount());
119         theInstance.track(getTestDirectory(), obj);
120         assertEquals(1, theInstance.getTrackCount());
121         
122         obj = null;
123 
124         waitUntilTrackCount();
125 
126         assertEquals(0, theInstance.getTrackCount());
127         assertEquals(true, testFile.exists());  // not deleted, as dir not empty
128         assertEquals(true, testFile.getParentFile().exists());  // not deleted, as dir not empty
129     }
130 
131     public void testFileCleanerDirectory_NullStrategy() throws Exception {
132         createFile(testFile, 100);
133         assertEquals(true, testFile.exists());
134         assertEquals(true, getTestDirectory().exists());
135         
136         Object obj = new Object();
137         assertEquals(0, theInstance.getTrackCount());
138         theInstance.track(getTestDirectory(), obj, (FileDeleteStrategy) null);
139         assertEquals(1, theInstance.getTrackCount());
140         
141         obj = null;
142 
143         waitUntilTrackCount();
144         
145         assertEquals(0, theInstance.getTrackCount());
146         assertEquals(true, testFile.exists());  // not deleted, as dir not empty
147         assertEquals(true, testFile.getParentFile().exists());  // not deleted, as dir not empty
148     }
149 
150     public void testFileCleanerDirectory_ForceStrategy() throws Exception {
151         createFile(testFile, 100);
152         assertEquals(true, testFile.exists());
153         assertEquals(true, getTestDirectory().exists());
154         
155         Object obj = new Object();
156         assertEquals(0, theInstance.getTrackCount());
157         theInstance.track(getTestDirectory(), obj, FileDeleteStrategy.FORCE);
158         assertEquals(1, theInstance.getTrackCount());
159         
160         obj = null;
161 
162         waitUntilTrackCount();
163         
164         assertEquals(0, theInstance.getTrackCount());
165         assertEquals(false, testFile.exists());
166         assertEquals(false, testFile.getParentFile().exists());
167     }
168 
169     public void testFileCleanerNull() throws Exception {
170         try {
171             theInstance.track((File) null, new Object());
172             fail();
173         } catch (NullPointerException ex) {
174             // expected
175         }
176         try {
177             theInstance.track((File) null, new Object(), FileDeleteStrategy.NORMAL);
178             fail();
179         } catch (NullPointerException ex) {
180             // expected
181         }
182         try {
183             theInstance.track((String) null, new Object());
184             fail();
185         } catch (NullPointerException ex) {
186             // expected
187         }
188         try {
189             theInstance.track((String) null, new Object(), FileDeleteStrategy.NORMAL);
190             fail();
191         } catch (NullPointerException ex) {
192             // expected
193         }
194     }
195 
196     public void testFileCleanerExitWhenFinishedFirst() throws Exception {
197         assertEquals(false, theInstance.exitWhenFinished);
198         theInstance.exitWhenFinished();
199         assertEquals(true, theInstance.exitWhenFinished);
200         assertEquals(null, theInstance.reaper);
201         
202         waitUntilTrackCount();
203         
204         assertEquals(0, theInstance.getTrackCount());
205         assertEquals(true, theInstance.exitWhenFinished);
206         assertEquals(null, theInstance.reaper);
207     }
208 
209     public void testFileCleanerExitWhenFinished_NoTrackAfter() throws Exception {
210         assertEquals(false, theInstance.exitWhenFinished);
211         theInstance.exitWhenFinished();
212         assertEquals(true, theInstance.exitWhenFinished);
213         assertEquals(null, theInstance.reaper);
214         
215         String path = testFile.getPath();
216         Object marker = new Object();
217         try {
218             theInstance.track(path, marker);
219             fail();
220         } catch (IllegalStateException ex) {
221             // expected
222         }
223         assertEquals(true, theInstance.exitWhenFinished);
224         assertEquals(null, theInstance.reaper);
225     }
226 
227     public void testFileCleanerExitWhenFinished1() throws Exception {
228         String path = testFile.getPath();
229         
230         assertEquals(false, testFile.exists());
231         RandomAccessFile r = new RandomAccessFile(testFile, "rw");
232         assertEquals(true, testFile.exists());
233         
234         assertEquals(0, theInstance.getTrackCount());
235         theInstance.track(path, r);
236         assertEquals(1, theInstance.getTrackCount());
237         assertEquals(false, theInstance.exitWhenFinished);
238         assertEquals(true, theInstance.reaper.isAlive());
239         
240         assertEquals(false, theInstance.exitWhenFinished);
241         theInstance.exitWhenFinished();
242         assertEquals(true, theInstance.exitWhenFinished);
243         assertEquals(true, theInstance.reaper.isAlive());
244         
245         r.close();
246         testFile = null;
247         r = null;
248 
249         waitUntilTrackCount();
250         
251         assertEquals(0, theInstance.getTrackCount());
252         assertEquals(false, new File(path).exists());
253         assertEquals(true, theInstance.exitWhenFinished);
254         assertEquals(false, theInstance.reaper.isAlive());
255     }
256 
257     public void testFileCleanerExitWhenFinished2() throws Exception {
258         String path = testFile.getPath();
259         
260         assertEquals(false, testFile.exists());
261         RandomAccessFile r = new RandomAccessFile(testFile, "rw");
262         assertEquals(true, testFile.exists());
263         
264         assertEquals(0, theInstance.getTrackCount());
265         theInstance.track(path, r);
266         assertEquals(1, theInstance.getTrackCount());
267         assertEquals(false, theInstance.exitWhenFinished);
268         assertEquals(true, theInstance.reaper.isAlive());
269         
270         r.close();
271         testFile = null;
272         r = null;
273 
274         waitUntilTrackCount();
275         
276         assertEquals(0, theInstance.getTrackCount());
277         assertEquals(false, new File(path).exists());
278         assertEquals(false, theInstance.exitWhenFinished);
279         assertEquals(true, theInstance.reaper.isAlive());
280         
281         assertEquals(false, theInstance.exitWhenFinished);
282         theInstance.exitWhenFinished();
283         for (int i = 0; i < 20 && theInstance.reaper.isAlive(); i++) {
284             Thread.sleep(500L);  // allow reaper thread to die
285         }
286         assertEquals(true, theInstance.exitWhenFinished);
287         assertEquals(false, theInstance.reaper.isAlive());
288     }
289 
290     //-----------------------------------------------------------------------
291     private void waitUntilTrackCount() {
292         while (theInstance.getTrackCount() != 0) {
293             int total = 0;
294             while (theInstance.getTrackCount() != 0) {
295                 byte[] b = new byte[1024 * 1024];
296                 b[0] = (byte) System.currentTimeMillis();
297                 total = total + b[0];
298                 System.gc();
299             }
300         }
301     }
302 }