Cleanup after each test.
[egit/charleso.git] / org.spearce.jgit.test / tst / org / spearce / jgit / lib / RepositoryTestCase.java
blobaaa35926b4f334ba6497e7de693683ee23ed3c6a
1 /*
2 * Copyright (C) 2008, Robin Rosenberg <robin.rosenberg@dewire.com>
3 * Copyright (C) 2007, Shawn O. Pearce <spearce@spearce.org>
5 * All rights reserved.
7 * Redistribution and use in source and binary forms, with or
8 * without modification, are permitted provided that the following
9 * conditions are met:
11 * - Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
14 * - Redistributions in binary form must reproduce the above
15 * copyright notice, this list of conditions and the following
16 * disclaimer in the documentation and/or other materials provided
17 * with the distribution.
19 * - Neither the name of the Git Development Community nor the
20 * names of its contributors may be used to endorse or promote
21 * products derived from this software without specific prior
22 * written permission.
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
25 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
26 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
27 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
29 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
31 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
32 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
33 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
34 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
36 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39 package org.spearce.jgit.lib;
41 import java.io.File;
42 import java.io.FileInputStream;
43 import java.io.FileOutputStream;
44 import java.io.IOException;
45 import java.io.InputStreamReader;
46 import java.io.OutputStreamWriter;
47 import java.io.Reader;
48 import java.util.ArrayList;
49 import java.util.List;
51 import junit.framework.TestCase;
52 import org.spearce.jgit.util.JGitTestUtil;
54 /**
55 * Base class for most JGit unit tests.
57 * Sets up a predefined test repository and has support for creating additional
58 * repositories and destroying them when the tests are finished.
60 * A system property <em>jgit.junit.usemmmap</em> defines whether memory mapping
61 * is used. Memory mapping has an effect on the file system, in that memory
62 * mapped files in java cannot be deleted as long as they mapped arrays have not
63 * been reclaimed by the garbage collector. The programmer cannot control this
64 * with precision, though hinting using <em>{@link java.lang.System#gc}</em>
65 * often helps.
67 public abstract class RepositoryTestCase extends TestCase {
69 protected final File trashParent = new File("trash");
71 protected File trash;
73 protected File trash_git;
75 protected static final PersonIdent jauthor;
77 protected static final PersonIdent jcommitter;
79 static {
80 jauthor = new PersonIdent("J. Author", "jauthor@example.com");
81 jcommitter = new PersonIdent("J. Committer", "jcommitter@example.com");
84 protected boolean packedGitMMAP;
86 /**
87 * Configure JGit before setting up test repositories.
89 protected void configure() {
90 packedGitMMAP = "true".equals(System.getProperty("jgit.junit.usemmmap"));
91 WindowCache.reconfigure(128*1024, 8192, packedGitMMAP, 8192);
94 /**
95 * Utility method to delete a directory recursively. It is
96 * also used internally.
98 * @param dir
100 protected void recursiveDelete(final File dir) {
101 recursiveDelete(dir, false, getClass().getName() + "." + getName());
104 protected static boolean recursiveDelete(final File dir, boolean silent,
105 final String name) {
106 if (!dir.exists())
107 return silent;
108 final File[] ls = dir.listFiles();
109 if (ls != null) {
110 for (int k = 0; k < ls.length; k++) {
111 final File e = ls[k];
112 if (e.isDirectory()) {
113 silent = recursiveDelete(e, silent, name);
114 } else {
115 if (!e.delete()) {
116 if (!silent) {
117 String msg = "Warning: Failed to delete " + e;
118 if (name != null)
119 msg += " in " + name;
120 System.out.println(msg);
122 silent = true;
127 if (!dir.delete()) {
128 if (!silent) {
129 String msg = "Warning: Failed to delete " + dir;
130 if (name != null)
131 msg += " in " + name;
132 System.out.println(msg);
134 silent = true;
136 return silent;
139 protected static void copyFile(final File src, final File dst)
140 throws IOException {
141 final FileInputStream fis = new FileInputStream(src);
142 final FileOutputStream fos = new FileOutputStream(dst);
143 final byte[] buf = new byte[4096];
144 int r;
145 while ((r = fis.read(buf)) > 0) {
146 fos.write(buf, 0, r);
148 fis.close();
149 fos.close();
152 protected File writeTrashFile(final String name, final String data)
153 throws IOException {
154 File tf = new File(trash, name);
155 File tfp = tf.getParentFile();
156 if (!tfp.exists() && !tf.getParentFile().mkdirs())
157 throw new Error("Could not create directory " + tf.getParentFile());
158 final OutputStreamWriter fw = new OutputStreamWriter(
159 new FileOutputStream(tf), "UTF-8");
160 fw.write(data);
161 fw.close();
162 return tf;
165 protected static void checkFile(File f, final String checkData)
166 throws IOException {
167 Reader r = new InputStreamReader(new FileInputStream(f), "ISO-8859-1");
168 char[] data = new char[(int) f.length()];
169 if (f.length() != r.read(data))
170 throw new IOException("Internal error reading file data from "+f);
171 assertEquals(checkData, new String(data));
174 protected Repository db;
175 private static Thread shutdownhook;
176 private static List<Runnable> shutDownCleanups = new ArrayList<Runnable>();
177 private static int testcount;
179 private ArrayList<Repository> repositoriesToClose = new ArrayList<Repository>();
181 public void setUp() throws Exception {
182 super.setUp();
183 configure();
184 final String name = getClass().getName() + "." + getName();
185 recursiveDelete(trashParent, true, name);
186 trash = new File(trashParent,"trash"+System.currentTimeMillis()+"."+(testcount++));
187 trash_git = new File(trash, ".git");
188 if (shutdownhook == null) {
189 shutdownhook = new Thread() {
190 @Override
191 public void run() {
192 // This may look superfluous, but is an extra attempt
193 // to clean up. First GC to release as many resources
194 // as possible and then try to clean up one test repo
195 // at a time (to record problems) and finally to drop
196 // the directory containing all test repositories.
197 System.gc();
198 for (Runnable r : shutDownCleanups)
199 r.run();
200 recursiveDelete(trashParent, false, null);
203 Runtime.getRuntime().addShutdownHook(shutdownhook);
205 db = new Repository(trash_git);
206 db.create();
208 final String[] packs = {
209 "pack-34be9032ac282b11fa9babdc2b2a93ca996c9c2f",
210 "pack-df2982f284bbabb6bdb59ee3fcc6eb0983e20371",
211 "pack-9fb5b411fe6dfa89cc2e6b89d2bd8e5de02b5745",
212 "pack-546ff360fe3488adb20860ce3436a2d6373d2796",
213 "pack-e6d07037cbcf13376308a0a995d1fa48f8f76aaa"
215 final File packDir = new File(db.getObjectsDirectory(), "pack");
216 for (int k = 0; k < packs.length; k++) {
217 copyFile(JGitTestUtil.getTestResourceFile(packs[k] + ".pack"), new File(packDir,
218 packs[k] + ".pack"));
219 copyFile(JGitTestUtil.getTestResourceFile(packs[k] + ".idx"), new File(packDir,
220 packs[k] + ".idx"));
223 copyFile(JGitTestUtil.getTestResourceFile("packed-refs"), new File(trash_git,"packed-refs"));
225 db.scanForPacks();
228 protected void tearDown() throws Exception {
229 db.close();
230 for (Repository r : repositoriesToClose)
231 r.close();
233 // Since memory mapping is controlled by the GC we need to
234 // tell it this is a good time to clean up and unlock
235 // memory mapped files.
236 if (packedGitMMAP)
237 System.gc();
239 final String name = getClass().getName() + "." + getName();
240 recursiveDelete(trash, false, name);
241 for (Repository r : repositoriesToClose)
242 recursiveDelete(r.getWorkDir(), false, name);
244 repositoriesToClose.clear();
246 super.tearDown();
250 * Helper for creating extra empty repos
252 * @return a new empty git repository for testing purposes
254 * @throws IOException
256 protected Repository createNewEmptyRepo() throws IOException {
257 final File newTestRepo = new File(trashParent, "new"
258 + System.currentTimeMillis() + "." + (testcount++) + "/.git");
259 assertFalse(newTestRepo.exists());
260 final Repository newRepo = new Repository(newTestRepo);
261 newRepo.create();
262 final String name = getClass().getName() + "." + getName();
263 shutDownCleanups.add(new Runnable() {
264 public void run() {
265 recursiveDelete(newTestRepo, false, name);
268 repositoriesToClose.add(newRepo);
269 return newRepo;