package com.asolutions.scmsshd.test.integration;
import static org.spearce.jgit.lib.Constants.R_HEADS;
import static org.spearce.jgit.lib.Constants.R_REMOTES;
import static org.spearce.jgit.lib.Constants.R_TAGS;
import java.io.File;
import java.io.IOException;
import java.io.PrintStream;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.apache.commons.io.FileUtils;
import org.junit.After;
import org.junit.Before;
import org.spearce.jgit.errors.NotSupportedException;
import org.spearce.jgit.errors.TransportException;
import org.spearce.jgit.lib.Constants;
import org.spearce.jgit.lib.NullProgressMonitor;
import org.spearce.jgit.lib.ObjectId;
import org.spearce.jgit.lib.Ref;
import org.spearce.jgit.lib.RefUpdate;
import org.spearce.jgit.lib.Repository;
import org.spearce.jgit.transport.FetchResult;
import org.spearce.jgit.transport.PushResult;
import org.spearce.jgit.transport.RefSpec;
import org.spearce.jgit.transport.RemoteConfig;
import org.spearce.jgit.transport.RemoteRefUpdate;
import org.spearce.jgit.transport.SshSessionFactory;
import org.spearce.jgit.transport.TrackingRefUpdate;
import org.spearce.jgit.transport.Transport;
import org.spearce.jgit.transport.URIish;
import org.spearce.jgit.transport.RemoteRefUpdate.Status;
import com.asolutions.scmsshd.test.integration.util.TestSSHSessionFactory;
public class IntegrationTestCase {
private ArrayList<File> scratchDirs = new ArrayList<File>();
private static int port = (int) (10000 + (Math.random() * 20000));
public IntegrationTestCase() {
super();
}
@Before
public void setTestSessionFactory(){
SshSessionFactory.setInstance(new TestSSHSessionFactory());
}
@After
public void removeScratchDirs() throws IOException {
for (File dir : scratchDirs) {
FileUtils.deleteDirectory(dir);
}
}
public File makeScratchDir() {
File basedir = new File(System.getProperty("java.io.tmpdir"));
File scratchDir = new File(basedir, "scumd-test-"
+ System.currentTimeMillis());
scratchDirs.add(scratchDir);
return scratchDir;
}
protected int generatePort() {
return port++;
}
protected static char shortTypeOf(final RefUpdate.Result r) {
if (r == RefUpdate.Result.LOCK_FAILURE)
return '!';
if (r == RefUpdate.Result.IO_FAILURE)
return '!';
if (r == RefUpdate.Result.NEW)
return '*';
if (r == RefUpdate.Result.FORCED)
return '+';
if (r == RefUpdate.Result.FAST_FORWARD)
return ' ';
if (r == RefUpdate.Result.REJECTED)
return '!';
if (r == RefUpdate.Result.NO_CHANGE)
return '=';
return ' ';
}
protected void showFetchResult(final Transport tn, final FetchResult r,
PrintStream out, Repository db) {
boolean shownURI = false;
for (final TrackingRefUpdate u : r.getTrackingRefUpdates()) {
if (u.getResult() == RefUpdate.Result.NO_CHANGE) {
continue;
}
final char type = shortTypeOf(u.getResult());
final String longType = longTypeOf(u, db);
final String src = abbreviateRef(u.getRemoteName(), false);
final String dst = abbreviateRef(u.getLocalName(), true);
if (!shownURI) {
out.print("From ");
out.print(tn.getURI());
out.println();
shownURI = true;
}
out.format(" %c %-17s %-10s -> %s", type, longType, src, dst);
out.println();
}
}
protected String longTypeOf(final TrackingRefUpdate u, Repository db) {
final RefUpdate.Result r = u.getResult();
if (r == RefUpdate.Result.LOCK_FAILURE)
return "[lock fail]";
if (r == RefUpdate.Result.IO_FAILURE)
return "[i/o error]";
if (r == RefUpdate.Result.REJECTED)
return "[rejected]";
if (ObjectId.zeroId().equals(u.getNewObjectId()))
return "[deleted]";
if (r == RefUpdate.Result.NEW) {
if (u.getRemoteName().startsWith(Constants.R_HEADS))
return "[new branch]";
else if (u.getLocalName().startsWith(Constants.R_TAGS))
return "[new tag]";
return "[new]";
}
if (r == RefUpdate.Result.FORCED) {
final String aOld = u.getOldObjectId().abbreviate(db).name();
final String aNew = u.getNewObjectId().abbreviate(db).name();
return aOld + "..." + aNew;
}
if (r == RefUpdate.Result.FAST_FORWARD) {
final String aOld = u.getOldObjectId().abbreviate(db).name();
final String aNew = u.getNewObjectId().abbreviate(db).name();
return aOld + ".." + aNew;
}
if (r == RefUpdate.Result.NO_CHANGE)
return "[up to date]";
return "[" + r.name() + "]";
}
protected String abbreviateRef(String dst, boolean abbreviateRemote) {
if (dst.startsWith(R_HEADS))
dst = dst.substring(R_HEADS.length());
else if (dst.startsWith(R_TAGS))
dst = dst.substring(R_TAGS.length());
else if (abbreviateRemote && dst.startsWith(R_REMOTES))
dst = dst.substring(R_REMOTES.length());
return dst;
}
protected void addRemoteConfigForLocalGitDirectory(Repository db,
File gitDir, String remoteName) throws URISyntaxException,
IOException {
URIish remoteUri = new URIish("file://" + gitDir.getAbsolutePath());
RemoteConfig rc = new RemoteConfig(db.getConfig(), remoteName);
rc.addURI(remoteUri);
rc.addFetchRefSpec(new RefSpec().setForceUpdate(true)
.setSourceDestination(Constants.R_HEADS + "*",
Constants.R_REMOTES + remoteName + "/*"));
rc.update(db.getConfig());
db.getConfig().save();
}
protected FetchResult cloneFromRemote(Repository db, String remoteName)
throws NotSupportedException, URISyntaxException,
TransportException {
Transport tn = Transport.open(db, remoteName);
FetchResult r = tn.fetch(NullProgressMonitor.INSTANCE, null);
showFetchResult(tn, r, System.out, db);
return r;
}
protected void addRemoteConfigForRemoteGitDirectory(Repository db, String remoteName, int serverPort, String repoDirectoryName)
throws URISyntaxException, IOException {
URIish remoteUri = new URIish("ssh://user@localhost:" + serverPort
+ "/" + repoDirectoryName);
RemoteConfig rc = new RemoteConfig(db.getConfig(), remoteName);
rc.addURI(remoteUri);
rc.addFetchRefSpec(new RefSpec().setForceUpdate(true)
.setSourceDestination(Constants.R_HEADS + "*",
Constants.R_REMOTES + remoteName + "/*"));
rc.update(db.getConfig());
db.getConfig().save();
}
protected Repository createCloneToRepo() throws IOException {
Repository db = new Repository(makeScratchDir());
db.create();
db.getConfig().setBoolean("core", null, "bare", false);
db.getConfig().save();
return db;
}
protected void push(String remoteName, String refspec,
Repository fromRepository) throws NotSupportedException,
URISyntaxException, IOException, TransportException {
final List<Transport> transports = Transport.openAll(fromRepository,
remoteName);
for (final Transport transport : transports) {
transport.setPushThin(false);
transport.setDryRun(false);
ArrayList<RefSpec> refSpecs = new ArrayList<RefSpec>();
refSpecs.add(new RefSpec(refspec));
final Collection<RemoteRefUpdate> toPush = transport
.findRemoteRefUpdatesFor(refSpecs);
final URIish uri = transport.getURI();
final PushResult result;
try {
result = transport.push(NullProgressMonitor.INSTANCE, toPush);
} finally {
transport.close();
}
printPushResult(uri, result, System.out, fromRepository);
}
}
protected void createBareRepo(File scratchDir) throws IOException {
Repository repo = new Repository(scratchDir);
repo.create();
repo.getConfig().setBoolean("core", null, "bare", true);
repo.close();
}
protected void printPushResult(final URIish uri, final PushResult result,
PrintStream out, Repository db) {
boolean everythingUpToDate = true;
// at first, print up-to-date ones...
for (final RemoteRefUpdate rru : result.getRemoteUpdates()) {
if (rru.getStatus() == Status.UP_TO_DATE) {
printRefUpdateResult(uri, result, rru, out, db);
} else
everythingUpToDate = false;
}
for (final RemoteRefUpdate rru : result.getRemoteUpdates()) {
// ...then successful updates...
if (rru.getStatus() == Status.OK)
printRefUpdateResult(uri, result, rru, out, db);
}
for (final RemoteRefUpdate rru : result.getRemoteUpdates()) {
// ...finally, others (problematic)
if (rru.getStatus() != Status.OK
&& rru.getStatus() != Status.UP_TO_DATE)
printRefUpdateResult(uri, result, rru, out, db);
}
if (everythingUpToDate)
out.println("Everything up-to-date");
}
protected void printRefUpdateResult(final URIish uri,
final PushResult result, final RemoteRefUpdate rru,
PrintStream out, Repository db) {
out.format("To %s\n", uri);
final String remoteName = rru.getRemoteName();
final String srcRef = rru.isDelete() ? null : rru.getSrcRef();
switch (rru.getStatus()) {
case OK:
if (rru.isDelete())
printUpdateLine('-', "[deleted]", null, remoteName, null, out);
else {
final Ref oldRef = result.getAdvertisedRef(remoteName);
if (oldRef == null) {
final String summary;
if (remoteName.startsWith(Constants.R_TAGS))
summary = "[new tag]";
else
summary = "[new branch]";
printUpdateLine('*', summary, srcRef, remoteName, null,
out);
} else {
boolean fastForward = rru.isFastForward();
final char flag = fastForward ? ' ' : '+';
final String summary = oldRef.getObjectId().abbreviate(db)
.name()
+ (fastForward ? ".." : "...")
+ rru.getNewObjectId().abbreviate(db).name();
final String message = fastForward ? null : "forced update";
printUpdateLine(flag, summary, srcRef, remoteName, message,
out);
}
}
break;
case NON_EXISTING:
printUpdateLine('X', "[no match]", null, remoteName, null, out);
break;
case REJECTED_NODELETE:
printUpdateLine('!', "[rejected]", null, remoteName,
"remote side does not support deleting refs", out);
break;
case REJECTED_NONFASTFORWARD:
printUpdateLine('!', "[rejected]", srcRef, remoteName,
"non-fast forward", out);
break;
case REJECTED_REMOTE_CHANGED:
final String message = "remote ref object changed - is not expected one "
+ rru.getExpectedOldObjectId().abbreviate(db).name();
printUpdateLine('!', "[rejected]", srcRef, remoteName, message,
out);
break;
case REJECTED_OTHER_REASON:
printUpdateLine('!', "[remote rejected]", srcRef, remoteName, rru
.getMessage(), out);
break;
case UP_TO_DATE:
printUpdateLine('=', "[up to date]", srcRef, remoteName, null, out);
break;
case NOT_ATTEMPTED:
case AWAITING_REPORT:
printUpdateLine('?', "[unexpected push-process behavior]", srcRef,
remoteName, rru.getMessage(), out);
break;
}
}
protected void printUpdateLine(final char flag, final String summary,
final String srcRef, final String destRef, final String message,
PrintStream out) {
out.format(" %c %-17s", flag, summary);
if (srcRef != null)
out.format(" %s ->", abbreviateRef(srcRef, true));
out.format(" %s", abbreviateRef(destRef, true));
if (message != null)
out.format(" (%s)", message);
out.println();
}
}