package com.beijunyi.parallelgit;
import java.io.File;
import java.io.IOException;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import com.beijunyi.parallelgit.utils.*;
import org.eclipse.jgit.dircache.DirCache;
import org.eclipse.jgit.dircache.DirCacheBuilder;
import org.eclipse.jgit.dircache.DirCacheEntry;
import org.eclipse.jgit.errors.NoWorkTreeException;
import org.eclipse.jgit.internal.storage.dfs.DfsRepositoryDescription;
import org.eclipse.jgit.internal.storage.dfs.InMemoryRepository;
import org.eclipse.jgit.lib.*;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.util.FileUtils;
import org.junit.After;
import org.junit.Before;
import static com.beijunyi.parallelgit.utils.CacheUtils.*;
import static java.util.UUID.randomUUID;
import static org.eclipse.jgit.lib.Constants.*;
import static org.eclipse.jgit.lib.FileMode.REGULAR_FILE;
import static org.junit.Assert.*;
public abstract class AbstractParallelGitTest {
protected File repoDir;
protected Repository repo;
protected DirCache cache;
@Before
public void setUpCache() {
cache = DirCache.newInCore();
}
@After
public void closeRepository() throws IOException {
if(repo != null)
repo.close();
if(repoDir != null && repoDir.exists())
FileUtils.delete(repoDir, FileUtils.RECURSIVE);
}
@Nonnull
protected ObjectId writeToCache(String path, byte[] content, FileMode mode) throws IOException {
ObjectId blobId = repo != null ? BlobUtils.insertBlob(content, repo) : calculateBlobId(content);
if(findEntry(path, cache) >= 0) {
updateFile(path, content, mode);
} else {
addFile(path, mode, blobId, cache);
}
return blobId;
}
@Nonnull
protected ObjectId writeToCache(String path, byte[] content) throws IOException {
return writeToCache(path, content, REGULAR_FILE);
}
@Nonnull
protected ObjectId writeToCache(String path, String content) throws IOException {
return writeToCache(path, encode(content));
}
@Nonnull
protected ObjectId writeToCache(String path) throws IOException {
return writeToCache(path, someBytes());
}
@Nonnull
protected ObjectId writeSomethingToCache() throws IOException {
return writeToCache(randomUUID().toString() + ".txt");
}
protected void writeMultipleToCache(String... paths) throws IOException {
DirCacheBuilder builder = CacheUtils.keepEverything(cache);
for(String path : paths) {
AnyObjectId blobId = repo != null ? BlobUtils.insertBlob(someBytes(), repo) : someObjectId();
addFile(path, REGULAR_FILE, blobId, builder);
}
builder.finish();
}
@Nonnull
protected ObjectId updateFile(String path, byte[] content, FileMode mode) throws IOException {
ObjectId blobId = BlobUtils.insertBlob(content, repo);
CacheUtils.updateFileBlob(path, blobId, mode, cache);
return blobId;
}
@Nonnull
protected ObjectId updateFile(String path, byte[] content) throws IOException {
ObjectId blobId = BlobUtils.insertBlob(content, repo);
CacheUtils.updateFileBlob(path, blobId, cache);
return blobId;
}
@Nonnull
protected ObjectId updateFile(String path, String content) throws IOException {
return updateFile(path, encode(content));
}
@Nonnull
protected static String someText() {
return randomUUID().toString();
}
@Nonnull
protected static String someFilename() {
return someText() + ".txt";
}
@Nonnull
protected static byte[] someBytes() {
return encodeASCII(someText());
}
@Nonnull
protected static ObjectId someObjectId() {
return calculateBlobId(someBytes());
}
@Nonnull
protected static String someCommitMessage() {
return someText() + " commit: " + someText();
}
@Nonnull
protected static PersonIdent somePersonIdent() {
String name = someText();
return new PersonIdent(name, name + "@test.com");
}
@Nonnull
protected RevCommit commit(String message, @Nullable AnyObjectId parent) throws IOException {
return CommitUtils.createCommit(message, cache, somePersonIdent(), parent, repo);
}
@Nonnull
protected RevCommit commit(@Nullable AnyObjectId parent) throws IOException {
return commit(someCommitMessage(), parent);
}
@Nonnull
protected RevCommit commit() throws IOException {
return commit(null);
}
protected void updateBranchHead(String branch, AnyObjectId commit, boolean init) throws IOException {
if(init)
BranchUtils.initBranch(branch, commit, repo);
else
BranchUtils.newCommit(branch, commit, repo);
}
@Nonnull
protected RevCommit commitToBranch(String branch, String message, @Nullable AnyObjectId parent) throws IOException {
if(parent == null && BranchUtils.branchExists(branch, repo))
parent = BranchUtils.getHeadCommit(branch, repo);
RevCommit commitId = commit(message, parent);
updateBranchHead(branch, commitId, parent == null);
return commitId;
}
@Nonnull
protected RevCommit commitToBranch(String branch, @Nullable AnyObjectId parent) throws IOException {
return commitToBranch(branch, someCommitMessage(), parent);
}
@Nonnull
protected RevCommit commitToBranch(String branch) throws IOException {
return commitToBranch(branch, someCommitMessage(), null);
}
@Nonnull
protected RevCommit commitToMaster(String message, @Nullable AnyObjectId parent) throws IOException {
return commitToBranch(MASTER, message, parent);
}
@Nonnull
protected RevCommit commitToMaster(String message) throws IOException {
return commitToBranch(MASTER, message, null);
}
@Nonnull
protected RevCommit commitToMaster() throws IOException {
return commitToBranch(MASTER);
}
protected void clearCache() {
cache = DirCache.newInCore();
}
protected void initRepositoryDir() throws IOException {
if(repoDir == null)
repoDir = FileUtils.createTempDir(getClass().getSimpleName(), null, null);
}
@Nonnull
protected RevCommit initContent() throws IOException {
RevCommit head = commitToMaster();
clearCache();
return head;
}
@Nonnull
protected RevCommit initRepository(boolean memory, boolean bare) throws IOException {
if(!memory)
initRepositoryDir();
repo = memory ? new TestRepository(bare) : RepositoryUtils.createRepository(repoDir, bare);
return initContent();
}
@Nonnull
protected RevCommit initFileRepository(boolean bare) throws IOException {
return initRepository(false, bare);
}
@Nonnull
protected RevCommit initMemoryRepository(boolean bare) throws IOException {
return initRepository(true, bare);
}
@Nonnull
protected RevCommit initRepository() throws IOException {
return initRepository(true, true);
}
@Nonnull
public static ObjectId calculateBlobId(byte[] data) {
return new ObjectInserter.Formatter().idFor(OBJ_BLOB, data);
}
public static void assertCacheEquals(@Nullable String message, DirCache expected, DirCache actual) {
if(expected != actual) {
String header = message == null ? "" : message + ": ";
int cacheSize = assertCacheSameSize(expected, actual, header);
DirCacheEntry[] expectedEntries = expected.getEntriesWithin("");
DirCacheEntry[] actualEntries = actual.getEntriesWithin("");
for(int i = 0; i < cacheSize; ++i) {
DirCacheEntry expectedEntry = expectedEntries[i];
DirCacheEntry actualEntry = actualEntries[i];
assertCacheEntryEquals(expectedEntry, actualEntry, header, i);
}
}
}
public static void assertCacheEquals(DirCache expected, DirCache actual) {
assertCacheEquals(null, expected, actual);
}
private static int assertCacheSameSize(DirCache expected, DirCache actual, String header) {
int actualSize = actual.getEntryCount();
int expectedSize = expected.getEntryCount();
if(actualSize != expectedSize)
fail(header + "cache sizes differed, expected.size=" + expectedSize + " actual.size=" + actualSize);
return expectedSize;
}
private static void assertCacheEntryEquals(DirCacheEntry expected, DirCacheEntry actual, String header, int index) {
try {
assertEquals("fileMode", expected.getFileMode(), actual.getFileMode());
assertEquals("length", expected.getLength(), actual.getLength());
assertEquals("objectId", expected.getObjectId(), actual.getObjectId());
assertEquals("stage", expected.getStage(), actual.getStage());
assertEquals("path", expected.getPathString(), actual.getPathString());
} catch(AssertionError e) {
fail(header + "caches first differed at entry [" + index + "]; " + e.getMessage());
}
}
protected static class TestRepository extends InMemoryRepository {
private final File directory;
private final File workTree;
public TestRepository(boolean bare) {
super(new DfsRepositoryDescription());
File mockLocation = new File(System.getProperty("java.io.tmpdir"));
directory = bare ? mockLocation : new File(mockLocation, DOT_GIT);
workTree = bare ? null : mockLocation;
}
public TestRepository() {
this(true);
}
@Override
public boolean isBare() {
return workTree == null;
}
@Nonnull
@Override
public File getWorkTree() throws NoWorkTreeException {
if(workTree == null)
throw new NoWorkTreeException();
return workTree;
}
@Nonnull
@Override
public File getDirectory() {
return directory;
}
}
}