import java.util.concurrent.locks.ReentrantLock;
import java.util.function.Predicate;
+import org.eclipse.jgit.events.ListenerHandle;
+import org.eclipse.jgit.events.RefsChangedListener;
import org.eclipse.jgit.junit.LocalDiskRepositoryTestCase;
import org.eclipse.jgit.junit.StrictWorkMonitor;
import org.eclipse.jgit.junit.TestRepository;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.transport.ReceiveCommand;
+import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
private RevCommit A;
private RevCommit B;
+ /**
+ * When asserting the number of RefsChangedEvents you must account for one
+ * additional event due to the initial ref setup via a number of calls to
+ * {@link #writeLooseRef(String, AnyObjectId)} (will be fired in execute()
+ * when it is detected that the on-disk loose refs have changed), or for one
+ * additional event per {@link #writeRef(String, AnyObjectId)}.
+ */
+ private int refsChangedEvents;
+
+ private ListenerHandle handle;
+
+ private RefsChangedListener refsChangedListener = event -> {
+ refsChangedEvents++;
+ };
+
@Override
@Before
public void setUp() throws Exception {
repo = new TestRepository<>(diskRepo);
A = repo.commit().create();
B = repo.commit(repo.getRevWalk().parseCommit(A));
+ refsChangedEvents = 0;
+ handle = diskRepo.getListenerList()
+ .addRefsChangedListener(refsChangedListener);
+ }
+
+ @After
+ public void removeListener() {
+ handle.remove();
+ refsChangedEvents = 0;
}
@Test
assertRefs(
"refs/heads/master", A,
"refs/heads/masters", B);
+ assertEquals(1, refsChangedEvents);
} else {
assertResults(cmds, OK, REJECTED_NONFASTFORWARD);
assertRefs(
"refs/heads/master", B,
"refs/heads/masters", B);
+ assertEquals(2, refsChangedEvents);
}
}
assertRefs(
"refs/heads/master", B,
"refs/heads/masters", A);
+ assertEquals(atomic ? 2 : 3, refsChangedEvents);
}
@Test
assertResults(cmds, OK);
assertRefs("refs/heads/master", A);
+ assertEquals(2, refsChangedEvents);
}
@Test
assertRefs(
"refs/heads/master", A,
"refs/heads/masters", B);
+ assertEquals(1, refsChangedEvents);
} else {
// Non-atomic updates are applied in order: master succeeds, then master/x
// fails due to conflict.
assertRefs(
"refs/heads/master", B,
"refs/heads/masters", B);
+ assertEquals(2, refsChangedEvents);
}
}
assertRefs(
"refs/heads/master", B,
"refs/heads/masters/x", A);
+ if (atomic) {
+ assertEquals(2, refsChangedEvents);
+ } else {
+ // The non-atomic case actually produces 5 events, but that's an
+ // implementation detail. We expect at least 4 events, one for the
+ // initial read due to writeLooseRef(), and then one for each
+ // successful ref update.
+ assertTrue(refsChangedEvents >= 4);
+ }
}
@Test
if (atomic) {
assertResults(cmds, REJECTED_MISSING_OBJECT, TRANSACTION_ABORTED);
assertRefs("refs/heads/master", A);
+ assertEquals(1, refsChangedEvents);
} else {
assertResults(cmds, REJECTED_MISSING_OBJECT, OK);
assertRefs(
"refs/heads/master", A,
"refs/heads/foo2", B);
+ assertEquals(2, refsChangedEvents);
}
}
if (atomic) {
assertResults(cmds, TRANSACTION_ABORTED, REJECTED_MISSING_OBJECT);
assertRefs("refs/heads/master", A);
+ assertEquals(1, refsChangedEvents);
} else {
assertResults(cmds, OK, REJECTED_MISSING_OBJECT);
assertRefs("refs/heads/master", B);
+ assertEquals(2, refsChangedEvents);
}
}
if (atomic) {
assertResults(cmds, LOCK_FAILURE, TRANSACTION_ABORTED);
assertRefs();
+ assertEquals(0, refsChangedEvents);
} else {
assertResults(cmds, LOCK_FAILURE, OK);
assertRefs("refs/heads/foo2", B);
+ assertEquals(1, refsChangedEvents);
}
}
if (atomic) {
assertResults(cmds, LOCK_FAILURE, TRANSACTION_ABORTED);
assertRefs("refs/heads/master", A);
+ assertEquals(1, refsChangedEvents);
} else {
assertResults(cmds, LOCK_FAILURE, OK);
assertRefs(
"refs/heads/master", A,
"refs/heads/foo2", B);
+ assertEquals(2, refsChangedEvents);
}
}
if (atomic) {
assertResults(cmds, TRANSACTION_ABORTED, LOCK_FAILURE);
assertRefs("refs/heads/master", A);
+ assertEquals(1, refsChangedEvents);
} else {
assertResults(cmds, OK, LOCK_FAILURE);
assertRefs("refs/heads/master", B);
+ assertEquals(2, refsChangedEvents);
}
}
assertRefs(
"refs/heads/master", B,
"refs/heads/branch", B);
+ assertEquals(atomic ? 2 : 3, refsChangedEvents);
assertReflogUnchanged(oldLogs, "refs/heads/master");
assertReflogUnchanged(oldLogs, "refs/heads/branch");
}
"refs/heads/master", B,
"refs/heads/branch1", B,
"refs/heads/branch2", A);
+ assertEquals(atomic ? 3 : 4, refsChangedEvents);
assertReflogEquals(
reflog(A, B, new PersonIdent(diskRepo), "a reflog"),
getLastReflog("refs/heads/master"));
"refs/heads/master", B,
"refs/heads/branch1", A,
"refs/heads/branch2", A);
+ assertEquals(atomic ? 3 : 5, refsChangedEvents);
assertReflogEquals(
// Always forced; setAllowNonFastForwards(true) bypasses the check.
reflog(A, B, new PersonIdent(diskRepo), "forced-update"),
assertResults(cmds, OK);
assertRefs("refs/heads/master", B);
+ assertEquals(2, refsChangedEvents);
assertReflogEquals(
reflog(A, B, new PersonIdent(diskRepo), "fast-forward"),
getLastReflog("refs/heads/master"));
assertRefs(
"refs/heads/master", B,
"refs/heads/branch", A);
+ assertEquals(atomic ? 2 : 3, refsChangedEvents);
assertReflogEquals(
reflog(A, B, new PersonIdent(diskRepo), "a reflog: fast-forward"),
getLastReflog("refs/heads/master"));
.setRefLogIdent(ident));
assertResults(cmds, OK, OK);
+ assertEquals(atomic ? 2 : 3, refsChangedEvents);
assertRefs(
"refs/heads/master", B,
"refs/heads/branch", B);
assertResults(cmds, OK, OK);
assertRefs("refs/heads/branch", B);
+ assertEquals(atomic ? 3 : 4, refsChangedEvents);
assertNull(getLastReflog("refs/heads/master"));
assertReflogEquals(
reflog(A, B, new PersonIdent(diskRepo), "a reflog"),
assertResults(cmds, OK, OK);
assertRefs("refs/heads/master/x", A);
+ assertEquals(atomic ? 2 : 3, refsChangedEvents);
assertNull(getLastReflog("refs/heads/master"));
assertReflogEquals(
reflog(zeroId(), A, new PersonIdent(diskRepo), "a reflog"),
if (atomic) {
assertResults(cmds, TRANSACTION_ABORTED, LOCK_FAILURE);
+ assertEquals(1, refsChangedEvents);
assertReflogUnchanged(oldLogs, "refs/heads/master");
assertReflogUnchanged(oldLogs, "refs/heads/branch");
} else {
assertResults(cmds, OK, LOCK_FAILURE);
+ assertEquals(2, refsChangedEvents);
assertReflogEquals(
reflog(A, B, new PersonIdent(diskRepo), "a reflog"),
getLastReflog("refs/heads/master"));
.setRefLogMessage("a reflog", true));
assertResults(cmds, OK, OK);
+ assertEquals(atomic ? 2 : 3, refsChangedEvents);
assertReflogEquals(
reflog(A, B, ident, "custom log"),
getLastReflog("refs/heads/master"),
execute(newBatchUpdate(cmds).setRefLogMessage("a reflog", true));
assertResults(cmds, OK, OK);
+ assertEquals(atomic ? 2 : 3, refsChangedEvents);
assertReflogUnchanged(oldLogs, "refs/heads/master");
assertReflogEquals(
reflog(zeroId(), B, new PersonIdent(diskRepo), "a reflog: created"),
if (atomic) {
assertResults(cmds, LOCK_FAILURE, TRANSACTION_ABORTED);
assertRefs("refs/heads/master", A);
+ assertEquals(1, refsChangedEvents);
} else {
// Only operates on loose refs, doesn't care that packed-refs is locked.
assertResults(cmds, OK, OK);
assertRefs(
"refs/heads/master", B,
"refs/heads/branch", B);
+ assertEquals(3, refsChangedEvents);
}
} finally {
myLock.unlock();
if (atomic) {
assertResults(cmds, TRANSACTION_ABORTED, LOCK_FAILURE);
assertRefs("refs/heads/master", A);
+ assertEquals(1, refsChangedEvents);
} else {
assertResults(cmds, OK, LOCK_FAILURE);
assertRefs(
"refs/heads/branch", B,
"refs/heads/master", A);
+ assertEquals(2, refsChangedEvents);
}
} finally {
myLock.unlock();
assertFalse(getLockFile("refs/heads/master").exists());
assertResults(cmds, OK);
+ assertEquals(2, refsChangedEvents);
assertRefs("refs/heads/master", B);
} finally {
myLock.unlock();
}
assertResults(cmds, OK, OK);
+ assertEquals(2, refsChangedEvents);
assertRefs(
"refs/heads/master", B,
"refs/heads/branch", B);