2 * Copyright (C) 2008, Robin Rosenberg <robin.rosenberg@dewire.com>
3 * Copyright (C) 2007, Shawn O. Pearce <spearce@spearce.org>
7 * Redistribution and use in source and binary forms, with or
8 * without modification, are permitted provided that the following
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
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
;
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
;
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>
67 public abstract class RepositoryTestCase
extends TestCase
{
69 protected final File trashParent
= new File("trash");
73 protected File trash_git
;
75 protected static final PersonIdent jauthor
;
77 protected static final PersonIdent jcommitter
;
80 jauthor
= new PersonIdent("J. Author", "jauthor@example.com");
81 jcommitter
= new PersonIdent("J. Committer", "jcommitter@example.com");
84 protected boolean packedGitMMAP
;
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);
95 * Utility method to delete a directory recursively. It is
96 * also used internally.
100 protected void recursiveDelete(final File dir
) {
101 recursiveDelete(dir
, false, getClass().getName() + "." + getName());
104 protected static boolean recursiveDelete(final File dir
, boolean silent
,
108 final File
[] ls
= dir
.listFiles();
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
);
117 String msg
= "Warning: Failed to delete " + e
;
119 msg
+= " in " + name
;
120 System
.out
.println(msg
);
129 String msg
= "Warning: Failed to delete " + dir
;
131 msg
+= " in " + name
;
132 System
.out
.println(msg
);
139 protected static void copyFile(final File src
, final File dst
)
141 final FileInputStream fis
= new FileInputStream(src
);
142 final FileOutputStream fos
= new FileOutputStream(dst
);
143 final byte[] buf
= new byte[4096];
145 while ((r
= fis
.read(buf
)) > 0) {
146 fos
.write(buf
, 0, r
);
152 protected File
writeTrashFile(final String name
, final String data
)
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");
165 protected static void checkFile(File f
, final String checkData
)
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
{
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() {
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.
198 for (Runnable r
: shutDownCleanups
)
200 recursiveDelete(trashParent
, false, null);
203 Runtime
.getRuntime().addShutdownHook(shutdownhook
);
205 db
= new Repository(trash_git
);
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
,
223 copyFile(JGitTestUtil
.getTestResourceFile("packed-refs"), new File(trash_git
,"packed-refs"));
228 protected void tearDown() throws Exception
{
230 for (Repository r
: repositoriesToClose
)
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.
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();
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
);
262 final String name
= getClass().getName() + "." + getName();
263 shutDownCleanups
.add(new Runnable() {
265 recursiveDelete(newTestRepo
, false, name
);
268 repositoriesToClose
.add(newRepo
);