1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46 package org.eclipse.jgit.junit;
47
48 import static org.junit.Assert.assertFalse;
49 import static org.junit.Assert.fail;
50
51 import java.io.File;
52 import java.io.IOException;
53 import java.util.ArrayList;
54 import java.util.Collections;
55 import java.util.HashMap;
56 import java.util.List;
57 import java.util.Map;
58 import java.util.concurrent.TimeUnit;
59
60 import org.eclipse.jgit.internal.storage.file.FileRepository;
61 import org.eclipse.jgit.lib.Constants;
62 import org.eclipse.jgit.lib.PersonIdent;
63 import org.eclipse.jgit.lib.Repository;
64 import org.eclipse.jgit.lib.RepositoryCache;
65 import org.eclipse.jgit.storage.file.FileBasedConfig;
66 import org.eclipse.jgit.storage.file.WindowCacheConfig;
67 import org.eclipse.jgit.util.FS;
68 import org.eclipse.jgit.util.FileUtils;
69 import org.eclipse.jgit.util.SystemReader;
70 import org.junit.After;
71 import org.junit.Before;
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90 public abstract class LocalDiskRepositoryTestCase {
91 private static final boolean useMMAP = "true".equals(System
92 .getProperty("jgit.junit.usemmap"));
93
94
95 protected PersonIdent author;
96
97
98 protected PersonIdent committer;
99
100 private final List<Repository> toClose = new ArrayList<Repository>();
101 private File tmp;
102
103 private MockSystemReader mockSystemReader;
104
105 @Before
106 public void setUp() throws Exception {
107 tmp = File.createTempFile("jgit_test_", "_tmp");
108 CleanupThread.deleteOnShutdown(tmp);
109 if (!tmp.delete() || !tmp.mkdir())
110 throw new IOException("Cannot create " + tmp);
111
112 mockSystemReader = new MockSystemReader();
113 mockSystemReader.userGitConfig = new FileBasedConfig(new File(tmp,
114 "usergitconfig"), FS.DETECTED);
115 ceilTestDirectories(getCeilings());
116 SystemReader.setInstance(mockSystemReader);
117
118 final long now = mockSystemReader.getCurrentTime();
119 final int tz = mockSystemReader.getTimezone(now);
120 author = new PersonIdent("J. Author", "jauthor@example.com");
121 author = new PersonIdent(author, now, tz);
122
123 committer = new PersonIdent("J. Committer", "jcommitter@example.com");
124 committer = new PersonIdent(committer, now, tz);
125
126 final WindowCacheConfig c = new WindowCacheConfig();
127 c.setPackedGitLimit(128 * WindowCacheConfig.KB);
128 c.setPackedGitWindowSize(8 * WindowCacheConfig.KB);
129 c.setPackedGitMMAP(useMMAP);
130 c.setDeltaBaseCacheLimit(8 * WindowCacheConfig.KB);
131 c.install();
132 }
133
134 protected File getTemporaryDirectory() {
135 return tmp.getAbsoluteFile();
136 }
137
138 protected List<File> getCeilings() {
139 return Collections.singletonList(getTemporaryDirectory());
140 }
141
142 private void ceilTestDirectories(List<File> ceilings) {
143 mockSystemReader.setProperty(Constants.GIT_CEILING_DIRECTORIES_KEY, makePath(ceilings));
144 }
145
146 private static String makePath(List<?> objects) {
147 final StringBuilder stringBuilder = new StringBuilder();
148 for (Object object : objects) {
149 if (stringBuilder.length() > 0)
150 stringBuilder.append(File.pathSeparatorChar);
151 stringBuilder.append(object.toString());
152 }
153 return stringBuilder.toString();
154 }
155
156 @After
157 public void tearDown() throws Exception {
158 RepositoryCache.clear();
159 for (Repository r : toClose)
160 r.close();
161 toClose.clear();
162
163
164
165
166
167 if (useMMAP)
168 System.gc();
169 if (tmp != null)
170 recursiveDelete(tmp, false, true);
171 if (tmp != null && !tmp.exists())
172 CleanupThread.removed(tmp);
173
174 SystemReader.setInstance(null);
175 }
176
177
178 protected void tick() {
179 final long delta = TimeUnit.MILLISECONDS.convert(5 * 60,
180 TimeUnit.SECONDS);
181 final long now = author.getWhen().getTime() + delta;
182 final int tz = mockSystemReader.getTimezone(now);
183
184 author = new PersonIdent(author, now, tz);
185 committer = new PersonIdent(committer, now, tz);
186 }
187
188
189
190
191
192
193
194 protected void recursiveDelete(final File dir) {
195 recursiveDelete(dir, false, true);
196 }
197
198 private static boolean recursiveDelete(final File dir,
199 boolean silent, boolean failOnError) {
200 assert !(silent && failOnError);
201 if (!dir.exists())
202 return silent;
203 final File[] ls = dir.listFiles();
204 if (ls != null)
205 for (int k = 0; k < ls.length; k++) {
206 final File e = ls[k];
207 if (e.isDirectory())
208 silent = recursiveDelete(e, silent, failOnError);
209 else if (!e.delete()) {
210 if (!silent)
211 reportDeleteFailure(failOnError, e);
212 silent = !failOnError;
213 }
214 }
215 if (!dir.delete()) {
216 if (!silent)
217 reportDeleteFailure(failOnError, dir);
218 silent = !failOnError;
219 }
220 return silent;
221 }
222
223 private static void reportDeleteFailure(boolean failOnError, File e) {
224 String severity = failOnError ? "ERROR" : "WARNING";
225 String msg = severity + ": Failed to delete " + e;
226 if (failOnError)
227 fail(msg);
228 else
229 System.err.println(msg);
230 }
231
232
233
234
235
236
237
238
239 protected FileRepository createBareRepository() throws IOException {
240 return createRepository(true );
241 }
242
243
244
245
246
247
248
249
250 protected FileRepository createWorkRepository() throws IOException {
251 return createRepository(false );
252 }
253
254
255
256
257
258
259
260
261
262
263
264 private FileRepository createRepository(boolean bare) throws IOException {
265 File gitdir = createUniqueTestGitDir(bare);
266 FileRepository db = new FileRepository(gitdir);
267 assertFalse(gitdir.exists());
268 db.create(bare);
269 toClose.add(db);
270 return db;
271 }
272
273
274
275
276
277
278
279
280 public void addRepoToClose(Repository r) {
281 toClose.add(r);
282 }
283
284
285
286
287
288
289
290
291
292 protected File createTempDirectory(String name) throws IOException {
293 File directory = new File(createTempFile(), name);
294 FileUtils.mkdirs(directory);
295 return directory.getCanonicalFile();
296 }
297
298
299
300
301
302
303
304
305
306
307 protected File createUniqueTestGitDir(boolean bare) throws IOException {
308 String gitdirName = createTempFile().getPath();
309 if (!bare)
310 gitdirName += "/";
311 return new File(gitdirName + Constants.DOT_GIT);
312 }
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327 protected File createTempFile() throws IOException {
328 File p = File.createTempFile("tmp_", "", tmp);
329 if (!p.delete()) {
330 throw new IOException("Cannot obtain unique path " + tmp);
331 }
332 return p;
333 }
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351 protected int runHook(final Repository db, final File hook,
352 final String... args) throws IOException, InterruptedException {
353 final String[] argv = new String[1 + args.length];
354 argv[0] = hook.getAbsolutePath();
355 System.arraycopy(args, 0, argv, 1, args.length);
356
357 final Map<String, String> env = cloneEnv();
358 env.put("GIT_DIR", db.getDirectory().getAbsolutePath());
359 putPersonIdent(env, "AUTHOR", author);
360 putPersonIdent(env, "COMMITTER", committer);
361
362 final File cwd = db.getWorkTree();
363 final Process p = Runtime.getRuntime().exec(argv, toEnvArray(env), cwd);
364 p.getOutputStream().close();
365 p.getErrorStream().close();
366 p.getInputStream().close();
367 return p.waitFor();
368 }
369
370 private static void putPersonIdent(final Map<String, String> env,
371 final String type, final PersonIdent who) {
372 final String ident = who.toExternalString();
373 final String date = ident.substring(ident.indexOf("> ") + 2);
374 env.put("GIT_" + type + "_NAME", who.getName());
375 env.put("GIT_" + type + "_EMAIL", who.getEmailAddress());
376 env.put("GIT_" + type + "_DATE", date);
377 }
378
379
380
381
382
383
384
385
386
387
388
389 protected File write(final String body) throws IOException {
390 final File f = File.createTempFile("temp", "txt", tmp);
391 try {
392 write(f, body);
393 return f;
394 } catch (Error e) {
395 f.delete();
396 throw e;
397 } catch (RuntimeException e) {
398 f.delete();
399 throw e;
400 } catch (IOException e) {
401 f.delete();
402 throw e;
403 }
404 }
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420 protected void write(final File f, final String body) throws IOException {
421 JGitTestUtil.write(f, body);
422 }
423
424 protected String read(final File f) throws IOException {
425 return JGitTestUtil.read(f);
426 }
427
428 private static String[] toEnvArray(final Map<String, String> env) {
429 final String[] envp = new String[env.size()];
430 int i = 0;
431 for (Map.Entry<String, String> e : env.entrySet())
432 envp[i++] = e.getKey() + "=" + e.getValue();
433 return envp;
434 }
435
436 private static HashMap<String, String> cloneEnv() {
437 return new HashMap<String, String>(System.getenv());
438 }
439
440 private static final class CleanupThread extends Thread {
441 private static final CleanupThread me;
442 static {
443 me = new CleanupThread();
444 Runtime.getRuntime().addShutdownHook(me);
445 }
446
447 static void deleteOnShutdown(File tmp) {
448 synchronized (me) {
449 me.toDelete.add(tmp);
450 }
451 }
452
453 static void removed(File tmp) {
454 synchronized (me) {
455 me.toDelete.remove(tmp);
456 }
457 }
458
459 private final List<File> toDelete = new ArrayList<File>();
460
461 @Override
462 public void run() {
463
464
465
466
467
468 System.gc();
469 synchronized (this) {
470 boolean silent = false;
471 boolean failOnError = false;
472 for (File tmp : toDelete)
473 recursiveDelete(tmp, silent, failOnError);
474 }
475 }
476 }
477 }