private Revision blockingCommit( Revision baseRevision, long commitTimeMillis, Author author, String summary, String detail, Markup markup, Iterable<Change<?>> changes, boolean allowEmptyCommit) { requireNonNull(baseRevision, "baseRevision"); final CommitResult res; rwLock.writeLock().lock(); try { if (closePending.get() != null) { throw closePending.get().get(); } final Revision normBaseRevision = normalizeNow(baseRevision); final Revision headRevision = cachedHeadRevision(); if (headRevision.major() != normBaseRevision.major()) { throw new ChangeConflictException( "invalid baseRevision: " + baseRevision + " (expected: " + headRevision + " or equivalent)"); } res = commit0(headRevision, headRevision.forward(1), commitTimeMillis, author, summary, detail, markup, changes, allowEmptyCommit); this.headRevision = res.revision; } finally { rwLock.writeLock().unlock(); } // Note that the notification is made while no lock is held to avoid the risk of a dead lock. notifyWatchers(res.revision, res.parentTreeId, res.treeId); return res.revision; }
private Revision blockingCommit( Revision baseRevision, long commitTimeMillis, Author author, String summary, String detail, Markup markup, Iterable<Change<?>> changes, boolean allowEmptyCommit) { requireNonNull(baseRevision, "baseRevision"); final CommitResult res; rwLock.writeLock().lock(); try { if (closePending.get() != null) { throw closePending.get().get(); } final Revision normBaseRevision = normalizeNow(baseRevision); final Revision headRevision = cachedHeadRevision(); if (headRevision.major() != normBaseRevision.major()) { throw new ChangeConflictException( "invalid baseRevision: " + baseRevision + " (expected: " + headRevision + " or equivalent)"); } res = commit0(headRevision, headRevision.forward(1), commitTimeMillis, author, summary, detail, markup, changes, allowEmptyCommit); this.headRevision = res.revision; } finally { rwLock.writeLock().unlock(); } // Note that the notification is made while no lock is held to avoid the risk of a dead lock. notifyWatchers(res.revision, res.parentTreeId, res.treeId); return res.revision; }
expected = Revision.INIT; } else { expected = headRevision.forward(1);
private Revision blockingCommit( Revision baseRevision, long commitTimeMillis, Author author, String summary, String detail, Markup markup, Iterable<Change<?>> changes, boolean allowEmptyCommit) { requireNonNull(baseRevision, "baseRevision"); final CommitResult res; rwLock.writeLock().lock(); try { if (closePending.get() != null) { throw closePending.get().get(); } final Revision normBaseRevision = normalizeNow(baseRevision); final Revision headRevision = cachedHeadRevision(); if (headRevision.major() != normBaseRevision.major()) { throw new ChangeConflictException( "invalid baseRevision: " + baseRevision + " (expected: " + headRevision + " or equivalent)"); } res = commit0(headRevision, headRevision.forward(1), commitTimeMillis, author, summary, detail, markup, changes, allowEmptyCommit); this.headRevision = res.revision; } finally { rwLock.writeLock().unlock(); } // Note that the notification is made while no lock is held to avoid the risk of a dead lock. notifyWatchers(res.revision, res.parentTreeId, res.treeId); return res.revision; }
expected = Revision.INIT; } else { expected = headRevision.forward(1);
expected = Revision.INIT; } else { expected = headRevision.forward(1);
@Test public void testWatchWithPathPattern() throws Exception { final Revision rev1 = repo.normalizeNow(HEAD); final Revision rev2 = rev1.forward(1); final Revision rev3 = rev2.forward(1); final CompletableFuture<Revision> f = repo.watch(rev1, jsonPaths[1]); // Should not notify when the path pattern does not match. repo.commit(rev1, 0L, Author.UNKNOWN, SUMMARY, jsonUpserts[0]).join(); assertThat(repo.normalizeNow(HEAD)).isEqualTo(rev2); assertThatThrownBy(() -> f.get(500, TimeUnit.MILLISECONDS)) .isInstanceOf(TimeoutException.class); // Should notify when the path pattern matches. repo.commit(rev2, 0L, Author.UNKNOWN, SUMMARY, jsonUpserts[1]).join(); assertThat(repo.normalizeNow(HEAD)).isEqualTo(rev3); assertThat(f.get(3, TimeUnit.SECONDS)).isEqualTo(rev3); }
@Test public void testWatch() throws Exception { final Revision rev1 = repo.normalizeNow(HEAD); final Revision rev2 = rev1.forward(1); final CompletableFuture<Revision> f = repo.watch(rev1, Repository.ALL_PATH); assertThat(f).isNotDone(); repo.commit(rev1, 0L, Author.UNKNOWN, SUMMARY, jsonUpserts[0]); assertThat(f.get(3, TimeUnit.SECONDS)).isEqualTo(rev2); assertThat(repo.normalizeNow(HEAD)).isEqualTo(rev2); }
@Test public void testHistory_parameterCheck() throws Exception { // Make sure that we added at least one non-initial commit. repo.commit(HEAD, 0L, Author.UNKNOWN, SUMMARY, jsonUpserts[0]).join(); final Revision head = repo.normalizeNow(HEAD); List<Commit> commits; // Even though the range contains 1, if the path is specified and does not contain "/**", // it should not include the initial commit. commits = repo.history(HEAD, new Revision(1), "non_existing_path").join(); assertThat(commits).hasSize(0); // Should include the initial empty commit if the range contain 1 and the path contains "/**". commits = repo.history(HEAD, HEAD, "/**").join(); assertThat(commits).hasSize(1); // Should not include the initial empty commit if the range does not contain 1. commits = repo.history(HEAD, HEAD, "non_existing_path").join(); assertThat(commits).isEmpty(); assertThatThrownBy(() -> repo.history(head.forward(1), head.forward(2), "non_existing_path").join()) .isInstanceOf(CompletionException.class) .hasCauseInstanceOf(RevisionNotFoundException.class); assertThatThrownBy(() -> repo.history(head.forward(1), head.backward(1), "non_existing_path").join()) .isInstanceOf(CompletionException.class) .hasCauseInstanceOf(RevisionNotFoundException.class); assertThatThrownBy(() -> repo.history(null, HEAD, "non_existing_path").join()) .isInstanceOf(CompletionException.class) .hasCauseInstanceOf(NullPointerException.class); assertThatThrownBy(() -> repo.history(HEAD, null, "non_existing_path").join()) .isInstanceOf(CompletionException.class) .hasCauseInstanceOf(NullPointerException.class); }
@Test public void testWatchRepository() throws Exception { final Revision rev1 = rule.client() .normalizeRevision(rule.project(), rule.repo1(), Revision.HEAD) .join(); final CompletableFuture<Revision> future = rule.client().watchRepository(rule.project(), rule.repo1(), rev1, "/**", 3000); assertThatThrownBy(() -> future.get(500, TimeUnit.MILLISECONDS)).isInstanceOf(TimeoutException.class); final Change<JsonNode> change = Change.ofJsonUpsert("/test/test3.json", "[ 3, 2, 1 ]"); final PushResult result = rule.client().push( rule.project(), rule.repo1(), rev1, "Add test3.json", change).join(); final Revision rev2 = result.revision(); assertThat(rev2).isEqualTo(rev1.forward(1)); assertThat(future.get(3, TimeUnit.SECONDS)).isEqualTo(rev2); }
@Test public void testDiff_rename() throws Exception { final CentralDogma client = rule.client(); final Revision rev1 = client.push(rule.project(), rule.repo1(), HEAD, "summary1", Change.ofTextUpsert("/bar.txt", "hello")).join().revision(); final Revision rev2 = client.push(rule.project(), rule.repo1(), HEAD, "summary2", Change.ofRename("/bar.txt", "/baz.txt")).join().revision(); assertThat(rev1.forward(1)).isEqualTo(rev2); assertThat(client.getDiff(rule.project(), rule.repo1(), rev1, rev2, Query.ofText("/bar.txt")).join()) .isEqualTo(Change.ofRemoval("/bar.txt")); } }
final String textPath = textPatches[0].path(); final Revision firstJsonCommit = repo.normalizeNow(HEAD).forward(1); Revision lastJsonCommit = null; for (Change<JsonNode> c : jsonPatches) { final Revision firstTextCommit = lastJsonCommit.forward(1); Revision lastTextCommit = null; for (Change<String> c : textPatches) {
@Test public void testWatchFileWithIdentityQuery() throws Exception { final Revision rev0 = rule.client() .normalizeRevision(rule.project(), rule.repo1(), Revision.HEAD) .join(); final CompletableFuture<Entry<JsonNode>> future = rule.client().watchFile( rule.project(), rule.repo1(), rev0, Query.ofJson("/test/test1.json"), 3000); assertThatThrownBy(() -> future.get(500, TimeUnit.MILLISECONDS)).isInstanceOf(TimeoutException.class); // An irrelevant change should not trigger a notification. final Change<JsonNode> change1 = Change.ofJsonUpsert("/test/test2.json", "[ 3, 2, 1 ]"); final PushResult res1 = rule.client().push( rule.project(), rule.repo1(), rev0, "Add test2.json", change1).join(); final Revision rev1 = res1.revision(); assertThatThrownBy(() -> future.get(500, TimeUnit.MILLISECONDS)).isInstanceOf(TimeoutException.class); // Make a relevant change now. final Change<JsonNode> change2 = Change.ofJsonUpsert("/test/test1.json", "[ -1, -2, -3 ]"); final PushResult res2 = rule.client().push( rule.project(), rule.repo1(), rev1, "Update test1.json", change2).join(); final Revision rev2 = res2.revision(); assertThat(rev2).isEqualTo(rev0.forward(2)); assertThat(future.get(3, TimeUnit.SECONDS)).isEqualTo( Entry.ofJson(rev2, "/test/test1.json", "[-1,-2,-3]")); }
@Test public void testDiff_remove() throws Exception { final CentralDogma client = rule.client(); final Revision rev1 = client.push(rule.project(), rule.repo1(), HEAD, "summary1", Change.ofTextUpsert("/foo.txt", "hello")).join().revision(); final Revision rev2 = client.push(rule.project(), rule.repo1(), HEAD, "summary2", Change.ofRemoval("/foo.txt")).join().revision(); assertThat(rev1.forward(1)).isEqualTo(rev2); assertThat(client.getDiff(rule.project(), rule.repo1(), rev1, rev1, Query.ofText("/foo.txt")).join().type()) .isEqualTo(ChangeType.APPLY_TEXT_PATCH); assertThat(client.getDiff(rule.project(), rule.repo1(), rev1, rev2, Query.ofText("/foo.txt")).join()) .isEqualTo(Change.ofRemoval("/foo.txt")); }
@Test public void testWatchFile() throws Exception { final Revision rev0 = rule.client() .normalizeRevision(rule.project(), rule.repo1(), Revision.HEAD) .join(); final CompletableFuture<Entry<JsonNode>> future = rule.client().watchFile(rule.project(), rule.repo1(), rev0, Query.ofJsonPath("/test/test1.json", "$[0]"), 3000); assertThatThrownBy(() -> future.get(500, TimeUnit.MILLISECONDS)).isInstanceOf(TimeoutException.class); // An irrelevant change should not trigger a notification. final Change<JsonNode> change1 = Change.ofJsonUpsert("/test/test2.json", "[ 3, 2, 1 ]"); final PushResult res1 = rule.client().push( rule.project(), rule.repo1(), rev0, "Add test2.json", change1).join(); final Revision rev1 = res1.revision(); assertThatThrownBy(() -> future.get(500, TimeUnit.MILLISECONDS)).isInstanceOf(TimeoutException.class); // Make a relevant change now. final Change<JsonNode> change2 = Change.ofJsonUpsert("/test/test1.json", "[ -1, -2, -3 ]"); final PushResult res2 = rule.client().push( rule.project(), rule.repo1(), rev1, "Add test1.json", change2).join(); final Revision rev2 = res2.revision(); assertThat(rev2).isEqualTo(rev0.forward(2)); assertThat(future.get(3, TimeUnit.SECONDS)).isEqualTo( Entry.ofJson(rev2, "/test/test1.json", "-1")); }