Merge "Fix temporary file creation and cleanup during testing"

This commit is contained in:
Dave Borowitz 2013-05-09 13:40:07 +00:00 committed by Gerrit Code Review
commit 5c830a9293
7 changed files with 101 additions and 68 deletions

View File

@ -126,6 +126,9 @@ limitations under the License.
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId> <artifactId>maven-failsafe-plugin</artifactId>
<version>2.5</version> <version>2.5</version>
<configuration>
<argLine>-Djava.io.tmpdir=${project.build.directory}</argLine>
</configuration>
<executions> <executions>
<execution> <execution>
<id>integration-test</id> <id>integration-test</id>

View File

@ -14,17 +14,6 @@
package com.google.gerrit.acceptance; package com.google.gerrit.acceptance;
import java.lang.reflect.Field;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.Callable;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import com.google.gerrit.lifecycle.LifecycleManager; import com.google.gerrit.lifecycle.LifecycleManager;
import com.google.gerrit.pgm.Daemon; import com.google.gerrit.pgm.Daemon;
import com.google.gerrit.pgm.Init; import com.google.gerrit.pgm.Init;
@ -32,15 +21,21 @@ import com.google.gerrit.server.config.FactoryModule;
import com.google.inject.Injector; import com.google.inject.Injector;
import com.google.inject.Module; import com.google.inject.Module;
import java.io.File;
import java.lang.reflect.Field;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.Callable;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
class GerritServer { class GerritServer {
/** Returns fully started Gerrit server */ /** Returns fully started Gerrit server */
static GerritServer start() throws Exception { static GerritServer start() throws Exception {
final File site = initSite();
final String sitePath = initSite();
final CyclicBarrier serverStarted = new CyclicBarrier(2); final CyclicBarrier serverStarted = new CyclicBarrier(2);
final Daemon daemon = new Daemon(new Runnable() { final Daemon daemon = new Daemon(new Runnable() {
public void run() { public void run() {
try { try {
@ -56,10 +51,10 @@ class GerritServer {
ExecutorService daemonService = Executors.newSingleThreadExecutor(); ExecutorService daemonService = Executors.newSingleThreadExecutor();
daemonService.submit(new Callable<Void>() { daemonService.submit(new Callable<Void>() {
public Void call() throws Exception { public Void call() throws Exception {
int rc = daemon.main(new String[] {"-d", sitePath, "--headless" }); int rc = daemon.main(new String[] {"-d", site.getPath(), "--headless" });
if (rc != 0) { if (rc != 0) {
System.out.println("Failed to start Gerrit daemon. Check " System.out.println("Failed to start Gerrit daemon. Check "
+ sitePath + "/logs/error_log"); + site.getPath() + "/logs/error_log");
serverStarted.reset(); serverStarted.reset();
} }
return null; return null;
@ -70,18 +65,18 @@ class GerritServer {
System.out.println("Gerrit Server Started"); System.out.println("Gerrit Server Started");
Injector i = createTestInjector(daemon); Injector i = createTestInjector(daemon);
return new GerritServer(i, daemon, daemonService); return new GerritServer(site, i, daemon, daemonService);
} }
private static String initSite() throws Exception { private static File initSite() throws Exception {
DateFormat df = new SimpleDateFormat("yyyyMMddHHmmss"); File tmp = TempFileUtil.createTempDirectory();
String path = "target/test_site_" + df.format(new Date());
Init init = new Init(); Init init = new Init();
int rc = init.main(new String[] {"-d", path, "--batch", "--no-auto-start"}); int rc = init.main(new String[] {
"-d", tmp.getPath(), "--batch", "--no-auto-start"});
if (rc != 0) { if (rc != 0) {
throw new RuntimeException("Couldn't initialize site"); throw new RuntimeException("Couldn't initialize site");
} }
return path; return tmp;
} }
private static Injector createTestInjector(Daemon daemon) throws Exception { private static Injector createTestInjector(Daemon daemon) throws Exception {
@ -103,12 +98,14 @@ class GerritServer {
return (T) f.get(obj); return (T) f.get(obj);
} }
private File sitePath;
private Daemon daemon; private Daemon daemon;
private ExecutorService daemonService; private ExecutorService daemonService;
private Injector testInjector; private Injector testInjector;
private GerritServer(Injector testInjector, private GerritServer(File sitePath, Injector testInjector,
Daemon daemon, ExecutorService daemonService) { Daemon daemon, ExecutorService daemonService) {
this.sitePath = sitePath;
this.testInjector = testInjector; this.testInjector = testInjector;
this.daemon = daemon; this.daemon = daemon;
this.daemonService = daemonService; this.daemonService = daemonService;
@ -124,5 +121,6 @@ class GerritServer {
manager.stop(); manager.stop();
daemonService.shutdownNow(); daemonService.shutdownNow();
daemonService.awaitTermination(Long.MAX_VALUE, TimeUnit.SECONDS); daemonService.awaitTermination(Long.MAX_VALUE, TimeUnit.SECONDS);
TempFileUtil.recursivelyDelete(sitePath);
} }
} }

View File

@ -15,27 +15,41 @@
package com.google.gerrit.acceptance; package com.google.gerrit.acceptance;
import java.io.File; import java.io.File;
import java.text.DateFormat; import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class TempFileUtil { public class TempFileUtil {
public static File createTempDirectory() throws IOException {
private static int testCount; File tmp = File.createTempFile("gerrit_test_", "");
private static DateFormat df = new SimpleDateFormat("yyyyMMddHHmmss"); if (!tmp.delete() || !tmp.mkdir()) {
private static final File temp = new File(new File("target"), "temp"); throw new IOException("Cannot create " + tmp.getPath());
}
private static String createUniqueTestFolderName() { return tmp;
return "test_" + (df.format(new Date()) + "_" + (testCount++));
} }
public static File createTempDirectory() { public static void recursivelyDelete(File dir) throws IOException {
final String name = createUniqueTestFolderName(); if (!dir.getPath().equals(dir.getCanonicalPath())) {
final File directory = new File(temp, name); // Directory symlink reaching outside of temporary space.
if (!directory.mkdirs()) { throw new IOException("Refusing to clear symlink " + dir.getPath());
throw new RuntimeException("failed to create folder '"
+ directory.getAbsolutePath() + "'");
} }
return directory; File[] contents = dir.listFiles();
if (contents != null) {
for (File d : contents) {
if (d.isDirectory()) {
recursivelyDelete(d);
} else {
deleteNowOrOnExit(d);
}
}
}
deleteNowOrOnExit(dir);
}
private static void deleteNowOrOnExit(File dir) {
if (!dir.delete()) {
dir.deleteOnExit();
}
}
private TempFileUtil() {
} }
} }

View File

@ -77,7 +77,7 @@ public class GitUtil {
s.exec("gerrit create-project --empty-commit --name \"" + name + "\""); s.exec("gerrit create-project --empty-commit --name \"" + name + "\"");
} }
public static Git cloneProject(String url) throws GitAPIException { public static Git cloneProject(String url) throws GitAPIException, IOException {
final File gitDir = TempFileUtil.createTempDirectory(); final File gitDir = TempFileUtil.createTempDirectory();
final CloneCommand cloneCmd = Git.cloneRepository(); final CloneCommand cloneCmd = Git.cloneRepository();
cloneCmd.setURI(url); cloneCmd.setURI(url);

View File

@ -232,6 +232,14 @@ limitations under the License.
</executions> </executions>
</plugin> </plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<argLine>-Djava.io.tmpdir=${project.build.directory}</argLine>
</configuration>
</plugin>
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId> <artifactId>maven-source-plugin</artifactId>

View File

@ -21,10 +21,9 @@ import junit.framework.TestCase;
import java.io.File; import java.io.File;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.IOException; import java.io.IOException;
import java.util.UUID;
public class SitePathsTest extends TestCase { public class SitePathsTest extends TestCase {
public void testCreate_NotExisting() throws FileNotFoundException { public void testCreate_NotExisting() throws IOException {
final File root = random(); final File root = random();
final SitePaths site = new SitePaths(root); final SitePaths site = new SitePaths(root);
assertTrue(site.isNew); assertTrue(site.isNew);
@ -32,7 +31,7 @@ public class SitePathsTest extends TestCase {
assertEquals(new File(root, "etc"), site.etc_dir); assertEquals(new File(root, "etc"), site.etc_dir);
} }
public void testCreate_Empty() throws FileNotFoundException { public void testCreate_Empty() throws IOException {
final File root = random(); final File root = random();
try { try {
assertTrue(root.mkdir()); assertTrue(root.mkdir());
@ -91,8 +90,11 @@ public class SitePathsTest extends TestCase {
assertEquals(new File(pfx + "a").getCanonicalFile(), site.resolve(pfx + "a")); assertEquals(new File(pfx + "a").getCanonicalFile(), site.resolve(pfx + "a"));
} }
private File random() { private static File random() throws IOException {
final File t = new File("target"); File tmp = File.createTempFile("gerrit_test_", "_site");
return new File(t, "random-name-" + UUID.randomUUID().toString()); if (!tmp.delete()) {
throw new IOException("Cannot create " + tmp.getPath());
}
return tmp;
} }
} }

View File

@ -52,6 +52,8 @@ package com.google.gerrit.server.tools.hooks;
import static org.junit.Assert.fail; import static org.junit.Assert.fail;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.io.ByteStreams; import com.google.common.io.ByteStreams;
import org.eclipse.jgit.junit.LocalDiskRepositoryTestCase; import org.eclipse.jgit.junit.LocalDiskRepositoryTestCase;
@ -64,10 +66,13 @@ import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.net.URL; import java.net.URL;
import java.util.List;
import java.util.Map;
public abstract class HookTestCase extends LocalDiskRepositoryTestCase { public abstract class HookTestCase extends LocalDiskRepositoryTestCase {
protected Repository repository; protected Repository repository;
private File hooksh; private final Map<String, File> hooks = Maps.newTreeMap();
private final List<File> cleanup = Lists.newArrayList();
@Override @Override
@Before @Before
@ -79,15 +84,21 @@ public abstract class HookTestCase extends LocalDiskRepositoryTestCase {
@Override @Override
@After @After
public void tearDown() throws Exception { public void tearDown() throws Exception {
if (hooksh != null) { super.tearDown();
if (!hooksh.delete()) { for (File p : cleanup) {
hooksh.deleteOnExit(); if (!p.delete()) {
p.deleteOnExit();
} }
hooksh = null;
} }
cleanup.clear();
} }
protected File getHook(final String name) throws IOException { protected File getHook(final String name) throws IOException {
File hook = hooks.get(name);
if (hook != null) {
return hook;
}
final String scproot = "com/google/gerrit/server/tools/root"; final String scproot = "com/google/gerrit/server/tools/root";
final String path = scproot + "/hooks/" + name; final String path = scproot + "/hooks/" + name;
URL url = cl().getResource(path); URL url = cl().getResource(path);
@ -95,17 +106,22 @@ public abstract class HookTestCase extends LocalDiskRepositoryTestCase {
fail("Cannot locate " + path + " in CLASSPATH"); fail("Cannot locate " + path + " in CLASSPATH");
} }
File hook;
if ("file".equals(url.getProtocol())) { if ("file".equals(url.getProtocol())) {
hook = new File(url.getPath()); hook = new File(url.getPath());
if (!hook.isFile()) { if (!hook.isFile()) {
fail("Cannot locate " + path + " in CLASSPATH"); fail("Cannot locate " + path + " in CLASSPATH");
} }
long time = hook.lastModified();
hook.setExecutable(true);
hook.setLastModified(time);
hooks.put(name, hook);
return hook;
} else if ("jar".equals(url.getProtocol())) { } else if ("jar".equals(url.getProtocol())) {
hooksh = File.createTempFile("hook_", ".sh");
InputStream in = url.openStream(); InputStream in = url.openStream();
try { try {
FileOutputStream out = new FileOutputStream(hooksh); hook = File.createTempFile("hook_", ".sh");
cleanup.add(hook);
FileOutputStream out = new FileOutputStream(hook);
try { try {
ByteStreams.copy(in, out); ByteStreams.copy(in, out);
} finally { } finally {
@ -114,21 +130,13 @@ public abstract class HookTestCase extends LocalDiskRepositoryTestCase {
} finally { } finally {
in.close(); in.close();
} }
hook = hooksh; hook.setExecutable(true);
hooks.put(name, hook);
return hook;
} else { } else {
fail("Cannot invoke " + url); fail("Cannot invoke " + url);
hook = null; return null;
} }
// The hook was copied out of our source control system into the
// target area by Java tools. Its not executable in the source
// are, nor did the copying Java program make it executable in the
// destination area. So we must force it to be executable.
//
final long time = hook.lastModified();
hook.setExecutable(true);
hook.setLastModified(time);
return hook;
} }
private ClassLoader cl() { private ClassLoader cl() {