1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.vfs.test;
18
19 import junit.extensions.TestSetup;
20 import junit.framework.Test;
21 import junit.framework.TestSuite;
22 import org.apache.commons.AbstractVfsTestCase;
23 import org.apache.commons.vfs.FileName;
24 import org.apache.commons.vfs.FileObject;
25 import org.apache.commons.vfs.impl.DefaultFileReplicator;
26 import org.apache.commons.vfs.impl.DefaultFileSystemManager;
27 import org.apache.commons.vfs.impl.PrivilegedFileReplicator;
28 import org.apache.commons.vfs.provider.local.DefaultLocalFileProvider;
29
30 import java.io.File;
31 import java.lang.reflect.Field;
32 import java.lang.reflect.Method;
33 import java.lang.reflect.Modifier;
34 import java.util.ArrayList;
35 import java.util.Enumeration;
36 import java.util.List;
37
38 /***
39 * The suite of tests for a file system.
40 *
41 * @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a>
42 * @author Gary D. Gregory
43 * @version $Id: AbstractTestSuite.java 480428 2006-11-29 06:15:24Z bayard $
44 */
45 public class AbstractTestSuite
46 extends TestSetup
47 {
48 private final ProviderTestConfig providerConfig;
49 private final String prefix;
50 private TestSuite testSuite;
51
52 private FileObject baseFolder;
53 private FileObject readFolder;
54 private FileObject writeFolder;
55 private DefaultFileSystemManager manager;
56 private File tempDir;
57
58 private Thread[] startThreadSnapshot;
59 private Thread[] endThreadSnapshot;
60
61 /***
62 * Adds the tests for a file system to this suite.
63 */
64 public AbstractTestSuite(final ProviderTestConfig providerConfig) throws Exception
65 {
66 this(providerConfig, "", false);
67 }
68
69 protected AbstractTestSuite(final ProviderTestConfig providerConfig,
70 final String prefix,
71 final boolean nested)
72 throws Exception
73 {
74 super(new TestSuite());
75 testSuite = (TestSuite) fTest;
76 this.providerConfig = providerConfig;
77 this.prefix = prefix;
78 addBaseTests();
79 if (!nested)
80 {
81
82
83
84
85 }
86 }
87
88 /***
89 * Adds base tests - excludes the nested test cases.
90 */
91 protected void addBaseTests() throws Exception
92 {
93 }
94
95 /***
96 * Adds the tests from a class to this suite. The supplied class must be
97 * a subclass of {@link AbstractProviderTestCase} and have a public a
98 * no-args constructor. This method creates an instance of the supplied
99 * class for each public 'testNnnn' method provided by the class.
100 */
101 public void addTests(final Class testClass) throws Exception
102 {
103
104 if (!AbstractProviderTestCase.class.isAssignableFrom(testClass))
105 {
106 throw new Exception("Test class " + testClass.getName() + " is not assignable to " + AbstractProviderTestCase.class.getName());
107 }
108
109
110 final Method[] methods = testClass.getMethods();
111 for (int i = 0; i < methods.length; i++)
112 {
113 final Method method = methods[i];
114 if (!method.getName().startsWith("test")
115 || Modifier.isStatic(method.getModifiers())
116 || method.getReturnType() != Void.TYPE
117 || method.getParameterTypes().length != 0)
118 {
119 continue;
120 }
121
122
123 final AbstractProviderTestCase testCase = (AbstractProviderTestCase) testClass.newInstance();
124 testCase.setMethod(method);
125 testCase.setName(prefix + method.getName());
126 testSuite.addTest(testCase);
127 }
128 }
129
130 protected void setUp() throws Exception
131 {
132 startThreadSnapshot = createThreadSnapshot();
133
134
135 tempDir = AbstractVfsTestCase.getTestDirectory("temp");
136 checkTempDir("Temp dir not empty before test");
137
138
139 manager = new DefaultFileSystemManager();
140 manager.setFilesCache(providerConfig.getFilesCache());
141
142 final DefaultFileReplicator replicator = new DefaultFileReplicator(tempDir);
143 manager.setReplicator(new PrivilegedFileReplicator(replicator));
144 manager.setTemporaryFileStore(replicator);
145
146 providerConfig.prepare(manager);
147
148 if (!manager.hasProvider("file"))
149 {
150 manager.addProvider("file", new DefaultLocalFileProvider());
151 }
152
153 manager.init();
154
155
156 baseFolder = providerConfig.getBaseTestFolder(manager);
157 readFolder = baseFolder.resolveFile("read-tests");
158 writeFolder = baseFolder.resolveFile("write-tests");
159
160
161 assertTrue("Folder does not exist: " + readFolder, readFolder.exists());
162 assertFalse(readFolder.getName().getPath().equals(FileName.ROOT_PATH));
163
164
165 final Enumeration tests = testSuite.tests();
166 while (tests.hasMoreElements())
167 {
168 final Test test = (Test) tests.nextElement();
169 if (test instanceof AbstractProviderTestCase)
170 {
171 final AbstractProviderTestCase providerTestCase = (AbstractProviderTestCase) test;
172 providerTestCase.setConfig(manager, providerConfig, baseFolder, readFolder, writeFolder);
173 }
174 }
175 }
176
177 protected void tearDown() throws Exception
178 {
179 readFolder.close();
180 writeFolder.close();
181 baseFolder.close();
182
183 readFolder = null;
184 writeFolder = null;
185 baseFolder = null;
186 testSuite = null;
187 fTest = null;
188
189
190 System.err.println(".");
191 System.gc();
192 Thread.sleep(1000);
193 System.err.println(".");
194 System.gc();
195 Thread.sleep(1000);
196 System.err.println(".");
197 System.gc();
198 Thread.sleep(1000);
199 System.err.println(".");
200 System.gc();
201 Thread.sleep(1000);
202
203 manager.freeUnusedResources();
204 endThreadSnapshot = createThreadSnapshot();
205
206 Thread[] diffThreadSnapshot = diffThreadSnapshot(startThreadSnapshot, endThreadSnapshot);
207 if (diffThreadSnapshot.length > 0)
208 {
209 String message = dumpThreadSnapshot(diffThreadSnapshot);
210
211
212
213
214
215
216
217
218
219
220
221 System.out.println(message);
222
223 }
224
225
226 manager.close();
227
228
229 checkTempDir("Temp dir not empty after test");
230 }
231
232 /***
233 * Asserts that the temp dir is empty or gone.
234 */
235 private void checkTempDir(final String assertMsg)
236 {
237 if (tempDir.exists())
238 {
239 assertTrue(assertMsg + " (" + tempDir.getAbsolutePath() + ")", tempDir.isDirectory() && tempDir.list().length == 0);
240 }
241 }
242
243 private String dumpThreadSnapshot(Thread[] threadSnapshot)
244 {
245 StringBuffer sb = new StringBuffer(256);
246 sb.append("created threads still running:\n");
247
248 Field threadTargetField = null;
249 try
250 {
251 threadTargetField = Thread.class.getDeclaredField("target");
252 threadTargetField.setAccessible(true);
253 }
254 catch (NoSuchFieldException e)
255 {
256 ;
257 }
258
259 for (int iter = 0; iter < threadSnapshot.length; iter++)
260 {
261 Thread thread = threadSnapshot[iter];
262 if (thread == null)
263 {
264 continue;
265 }
266
267 sb.append("#");
268 sb.append(iter + 1);
269 sb.append(": ");
270 sb.append(thread.getThreadGroup().getName());
271 sb.append("\t");
272 sb.append(thread.getName());
273 sb.append("\t");
274 if (thread.isDaemon())
275 {
276 sb.append("daemon");
277 }
278 else
279 {
280 sb.append("not_a_daemon");
281 }
282
283 if (threadTargetField != null)
284 {
285 sb.append("\t");
286 try
287 {
288 Object threadTarget = threadTargetField.get(thread);
289 if (threadTarget != null)
290 {
291 sb.append(threadTarget.getClass());
292 }
293 else
294 {
295 sb.append("null");
296 }
297 }
298 catch (IllegalAccessException e)
299 {
300 sb.append("unknown class");
301 }
302 }
303
304 sb.append("\n");
305 }
306
307 return sb.toString();
308 }
309
310 private Thread[] diffThreadSnapshot(Thread[] startThreadSnapshot, Thread[] endThreadSnapshot)
311 {
312 List diff = new ArrayList(10);
313
314 nextEnd: for (int iterEnd = 0; iterEnd < endThreadSnapshot.length; iterEnd++)
315 {
316 nextStart: for (int iterStart = 0; iterStart < startThreadSnapshot.length; iterStart++)
317 {
318 if (startThreadSnapshot[iterStart] == endThreadSnapshot[iterEnd])
319 {
320 continue nextEnd;
321 }
322 }
323
324 diff.add(endThreadSnapshot[iterEnd]);
325 }
326
327 Thread ret[] = new Thread[diff.size()];
328 diff.toArray(ret);
329 return ret;
330 }
331
332 private Thread[] createThreadSnapshot()
333 {
334 ThreadGroup tg = Thread.currentThread().getThreadGroup();
335 while (tg.getParent() != null)
336 {
337 tg = tg.getParent();
338 }
339
340 Thread snapshot[] = new Thread[200];
341 tg.enumerate(snapshot, true);
342
343 return snapshot;
344 }
345 }