/* Copyright (c) 2012-2014 Boundless and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Distribution License v1.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/org/documents/edl-v10.html
*
* Contributors:
* Gabriel Roldan (Boundless) - initial implementation
*/
package org.locationtech.geogig.test.integration;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import org.geotools.util.Range;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.locationtech.geogig.api.NodeRef;
import org.locationtech.geogig.api.ObjectId;
import org.locationtech.geogig.api.Ref;
import org.locationtech.geogig.api.RevCommit;
import org.locationtech.geogig.api.plumbing.RefParse;
import org.locationtech.geogig.api.porcelain.BranchCreateOp;
import org.locationtech.geogig.api.porcelain.CheckoutOp;
import org.locationtech.geogig.api.porcelain.CommitOp;
import org.locationtech.geogig.api.porcelain.LogOp;
import org.locationtech.geogig.api.porcelain.MergeOp;
import org.locationtech.geogig.api.porcelain.MergeOp.MergeReport;
import org.opengis.feature.Feature;
import com.google.common.base.Suppliers;
import com.google.common.collect.Iterators;
import com.google.common.collect.Lists;
public class LogOpTest extends RepositoryTestCase {
private LogOp logOp;
@Rule
public ExpectedException exception = ExpectedException.none();
@Override
protected void setUpInternal() throws Exception {
logOp = geogig.command(LogOp.class);
}
@Test
public void testEmptyRepo() throws Exception {
Iterator<RevCommit> logs = logOp.call();
assertNotNull(logs);
assertFalse(logs.hasNext());
}
@Test
public void testHeadWithSingleCommit() throws Exception {
insertAndAdd(points1);
final RevCommit firstCommit = geogig.command(CommitOp.class).call();
Iterator<RevCommit> iterator = logOp.call();
assertNotNull(iterator);
assertTrue(iterator.hasNext());
assertEquals(firstCommit, iterator.next());
assertFalse(iterator.hasNext());
}
@Test
public void testHeadWithTwoCommits() throws Exception {
insertAndAdd(points1);
final RevCommit firstCommit = geogig.command(CommitOp.class).call();
insertAndAdd(lines1);
final RevCommit secondCommit = geogig.command(CommitOp.class).call();
Iterator<RevCommit> iterator = logOp.call();
assertNotNull(iterator);
assertTrue(iterator.hasNext());
// by default returns most recent first
assertEquals(secondCommit, iterator.next());
assertTrue(iterator.hasNext());
assertEquals(firstCommit, iterator.next());
assertFalse(iterator.hasNext());
}
@Test
public void testHeadWithMultipleCommits() throws Exception {
List<Feature> features = Arrays.asList(points1, lines1, points2, lines2, points3, lines3);
LinkedList<RevCommit> expected = new LinkedList<RevCommit>();
for (Feature f : features) {
insertAndAdd(f);
final RevCommit commit = geogig.command(CommitOp.class).call();
expected.addFirst(commit);
}
Iterator<RevCommit> logs = logOp.call();
List<RevCommit> logged = new ArrayList<RevCommit>();
for (; logs.hasNext();) {
logged.add(logs.next());
}
assertEquals(expected, logged);
}
@Test
public void testPathFilterSingleFeature() throws Exception {
List<Feature> features = Arrays.asList(points1, lines1, points2, lines2, points3, lines3);
List<RevCommit> allCommits = Lists.newArrayList();
RevCommit expectedCommit = null;
for (Feature f : features) {
insertAndAdd(f);
String id = f.getIdentifier().getID();
final RevCommit commit = geogig.command(CommitOp.class).call();
if (id.equals(lines1.getIdentifier().getID())) {
expectedCommit = commit;
}
allCommits.add(commit);
}
String path = NodeRef.appendChild(linesName, lines1.getIdentifier().getID());
List<RevCommit> feature2_1Commits = toList(logOp.addPath(path).call());
assertEquals(1, feature2_1Commits.size());
assertEquals(Collections.singletonList(expectedCommit), feature2_1Commits);
}
@Test
public void testMultiplePaths() throws Exception {
List<Feature> features = Arrays.asList(points1, lines1, points2, lines2, points3, lines3);
List<RevCommit> allCommits = Lists.newArrayList();
RevCommit expectedLineCommit = null;
RevCommit expectedPointCommit = null;
for (Feature f : features) {
insertAndAdd(f);
String id = f.getIdentifier().getID();
final RevCommit commit = geogig.command(CommitOp.class).call();
if (id.equals(lines1.getIdentifier().getID())) {
expectedLineCommit = commit;
} else if (id.equals(points1.getIdentifier().getID())) {
expectedPointCommit = commit;
}
allCommits.add(commit);
}
String linesPath = NodeRef.appendChild(linesName, lines1.getIdentifier().getID());
String pointsPath = NodeRef.appendChild(pointsName, points1.getIdentifier().getID());
List<RevCommit> feature2_1Commits = toList(logOp.addPath(linesPath).call());
List<RevCommit> featureCommits = toList(logOp.addPath(pointsPath).call());
assertEquals(1, feature2_1Commits.size());
assertEquals(2, featureCommits.size());
assertEquals(Collections.singletonList(expectedLineCommit), feature2_1Commits);
assertEquals(
true,
featureCommits.contains(expectedPointCommit)
&& featureCommits.contains(expectedLineCommit));
}
@Test
public void testPathFilterByTypeName() throws Exception {
List<Feature> features = Arrays.asList(points1, lines1, points2, lines2, points3, lines3);
LinkedList<RevCommit> commits = Lists.newLinkedList();
LinkedList<RevCommit> typeName1Commits = Lists.newLinkedList();
for (Feature f : features) {
insertAndAdd(f);
final RevCommit commit = geogig.command(CommitOp.class)
.setMessage(f.getIdentifier().toString()).call();
commits.addFirst(commit);
if (pointsName.equals(f.getType().getName().getLocalPart())) {
typeName1Commits.addFirst(commit);
}
}
// path to filter commits on type1
String path = pointsName;
List<RevCommit> logCommits = toList(logOp.addPath(path).call());
assertEquals(typeName1Commits.size(), logCommits.size());
assertEquals(typeName1Commits, logCommits);
}
@Test
public void testLimit() throws Exception {
List<Feature> features = Arrays.asList(points1, lines1, points2, lines2, points3, lines3);
for (Feature f : features) {
insertAndAdd(f);
geogig.command(CommitOp.class).call();
}
assertEquals(3, Iterators.size(logOp.setLimit(3).call()));
assertEquals(1, Iterators.size(logOp.setLimit(1).call()));
assertEquals(4, Iterators.size(logOp.setLimit(4).call()));
exception.expect(IllegalArgumentException.class);
logOp.setLimit(-1).call();
}
@Test
public void testSkip() throws Exception {
List<Feature> features = Arrays.asList(points1, lines1, points2, lines2, points3, lines3);
for (Feature f : features) {
insertAndAdd(f);
geogig.command(CommitOp.class).call();
}
logOp.setSkip(2).call();
exception.expect(IllegalArgumentException.class);
logOp.setSkip(-1).call();
}
@Test
public void testTemporalConstraint() throws Exception {
List<Feature> features = Arrays.asList(points1, lines1, points2, lines2, points3, lines3);
List<Long> timestamps = Arrays.asList(Long.valueOf(1000), Long.valueOf(2000),
Long.valueOf(3000), Long.valueOf(4000), Long.valueOf(5000), Long.valueOf(6000));
LinkedList<RevCommit> allCommits = new LinkedList<RevCommit>();
for (int i = 0; i < features.size(); i++) {
Feature f = features.get(i);
Long timestamp = timestamps.get(i);
insertAndAdd(f);
final RevCommit commit = geogig.command(CommitOp.class)
.setCommitterTimestamp(timestamp).call();
allCommits.addFirst(commit);
}
// test time range exclusive
boolean minInclusive = false;
boolean maxInclusive = false;
Range<Date> commitRange = new Range<Date>(Date.class, new Date(2000), minInclusive,
new Date(5000), maxInclusive);
logOp.setTimeRange(commitRange);
List<RevCommit> logged = toList(logOp.call());
List<RevCommit> expected = allCommits.subList(2, 4);
assertEquals(expected, logged);
// test time range inclusive
minInclusive = true;
maxInclusive = true;
commitRange = new Range<Date>(Date.class, new Date(2000), minInclusive, new Date(5000),
maxInclusive);
logOp = geogig.command(LogOp.class).setTimeRange(commitRange);
logged = toList(logOp.call());
expected = allCommits.subList(1, 5);
assertEquals(expected, logged);
// test reset time range
logOp = geogig.command(LogOp.class).setTimeRange(commitRange).setTimeRange(null);
logged = toList(logOp.call());
expected = allCommits;
assertEquals(expected, logged);
}
@Test
public void testSinceUntil() throws Exception {
final ObjectId oid1_1 = insertAndAdd(points1);
final RevCommit commit1_1 = geogig.command(CommitOp.class).call();
insertAndAdd(points2);
final RevCommit commit1_2 = geogig.command(CommitOp.class).call();
insertAndAdd(lines1);
final RevCommit commit2_1 = geogig.command(CommitOp.class).call();
final ObjectId oid2_2 = insertAndAdd(lines2);
final RevCommit commit2_2 = geogig.command(CommitOp.class).call();
try {
logOp = geogig.command(LogOp.class);
logOp.setSince(oid1_1).call();
fail("Expected ISE as since is not a commit");
} catch (IllegalArgumentException e) {
assertTrue(e.getMessage().contains("since"));
}
try {
logOp = geogig.command(LogOp.class);
logOp.setSince(null).setUntil(oid2_2).call();
fail("Expected ISE as until is not a commit");
} catch (IllegalArgumentException e) {
assertTrue(e.getMessage().contains("until"));
}
List<RevCommit> logs;
List<RevCommit> expected;
logOp = geogig.command(LogOp.class);
logs = toList(logOp.setSince(commit1_2.getId()).setUntil(null).call());
expected = Arrays.asList(commit2_2, commit2_1);
assertEquals(expected, logs);
logOp = geogig.command(LogOp.class);
logs = toList(logOp.setSince(commit2_2.getId()).setUntil(null).call());
expected = Collections.emptyList();
assertEquals(expected, logs);
logOp = geogig.command(LogOp.class);
logs = toList(logOp.setSince(commit1_2.getId()).setUntil(commit2_1.getId()).call());
expected = Arrays.asList(commit2_1);
assertEquals(expected, logs);
logOp = geogig.command(LogOp.class);
logs = toList(logOp.setSince(null).setUntil(commit2_1.getId()).call());
expected = Arrays.asList(commit2_1, commit1_2, commit1_1);
assertEquals(expected, logs);
}
@Test
public void testMerged() throws Exception {
// Create the following revision graph
// o
// |
// o - Points 1 added
// |\
// | o - branch1 - Points 2 added
// |
// o - Points 3 added
// |
// o - master - HEAD - Lines 1 added
insertAndAdd(points1);
final RevCommit c1 = geogig.command(CommitOp.class).setMessage("commit for " + idP1).call();
// create branch1 and checkout
geogig.command(BranchCreateOp.class).setAutoCheckout(true).setName("branch1").call();
insertAndAdd(points2);
final RevCommit c2 = geogig.command(CommitOp.class).setMessage("commit for " + idP2).call();
// checkout master
geogig.command(CheckoutOp.class).setSource("master").call();
insertAndAdd(points3);
final RevCommit c3 = geogig.command(CommitOp.class).setMessage("commit for " + idP3).call();
insertAndAdd(lines1);
final RevCommit c4 = geogig.command(CommitOp.class).setMessage("commit for " + idL1).call();
// Merge branch1 into master to create the following revision graph
// o
// |
// o - Points 1 added
// |\
// | o - branch1 - Points 2 added
// | |
// o | - Points 3 added
// | |
// o | - Lines 1 added
// |/
// o - master - HEAD - Merge commit
Ref branch1 = geogig.command(RefParse.class).setName("branch1").call().get();
MergeReport mergeReport = geogig.command(MergeOp.class)
.addCommit(Suppliers.ofInstance(branch1.getObjectId()))
.setMessage("My merge message.").call();
RevCommit mergeCommit = mergeReport.getMergeCommit();
Iterator<RevCommit> iterator = logOp.call();
assertNotNull(iterator);
assertTrue(iterator.hasNext());
assertEquals(mergeCommit, iterator.next());
assertTrue(iterator.hasNext());
assertEquals(c4, iterator.next());
assertTrue(iterator.hasNext());
assertEquals(c3, iterator.next());
assertTrue(iterator.hasNext());
assertEquals(c2, iterator.next());
assertTrue(iterator.hasNext());
assertEquals(c1, iterator.next());
// test log using first parent only. It should not contain commit 2)
LogOp op = geogig.command(LogOp.class).setFirstParentOnly(true);
iterator = op.call();
assertNotNull(iterator);
assertTrue(iterator.hasNext());
assertEquals(mergeCommit, iterator.next());
assertTrue(iterator.hasNext());
assertEquals(c4, iterator.next());
assertTrue(iterator.hasNext());
assertEquals(c3, iterator.next());
assertTrue(iterator.hasNext());
assertEquals(c1, iterator.next());
assertFalse(iterator.hasNext());
// Test topological order
op = geogig.command(LogOp.class).setTopoOrder(true);
iterator = op.call();
assertNotNull(iterator);
assertTrue(iterator.hasNext());
assertEquals(mergeCommit, iterator.next());
assertTrue(iterator.hasNext());
assertEquals(c4, iterator.next());
assertTrue(iterator.hasNext());
assertEquals(c3, iterator.next());
assertTrue(iterator.hasNext());
assertEquals(c1, iterator.next());
assertTrue(iterator.hasNext());
assertEquals(c2, iterator.next());
assertFalse(iterator.hasNext());
}
@Test
public void testMergedWithPathFilter() throws Exception {
// Create the following revision graph
// o
// |
// o - Points 1 added
// |\
// | o - branch1 - Points 2 added
// |
// o - Points 3 added
// |
// o - master - HEAD - Lines 1 added
insertAndAdd(points1);
geogig.command(CommitOp.class).setMessage("commit for " + idP1).call();
// create branch1 and checkout
geogig.command(BranchCreateOp.class).setAutoCheckout(true).setName("branch1").call();
insertAndAdd(points2);
final RevCommit c2 = geogig.command(CommitOp.class).setMessage("commit for " + idP2).call();
// checkout master
geogig.command(CheckoutOp.class).setSource("master").call();
insertAndAdd(points3);
geogig.command(CommitOp.class).setMessage("commit for " + idP3).call();
insertAndAdd(lines1);
geogig.command(CommitOp.class).setMessage("commit for " + idL1).call();
// Merge branch1 into master to create the following revision graph
// o
// |
// o - Points 1 added
// |\
// | o - branch1 - Points 2 added
// | |
// o | - Points 3 added
// | |
// o | - Lines 1 added
// |/
// o - master - HEAD - Merge commit
Ref branch1 = geogig.command(RefParse.class).setName("branch1").call().get();
MergeReport mergeReport = geogig.command(MergeOp.class)
.addCommit(Suppliers.ofInstance(branch1.getObjectId()))
.setMessage("My merge message.").call();
RevCommit mergeCommit = mergeReport.getMergeCommit();
Iterator<RevCommit> iterator = logOp.addPath(pointsName + "/" + idP2).call();
assertNotNull(iterator);
assertTrue(iterator.hasNext());
assertEquals(mergeCommit, iterator.next());
assertTrue(iterator.hasNext());
assertEquals(c2, iterator.next());
// test log using first parent only. It should not contain commit 2)
LogOp op = geogig.command(LogOp.class).addPath(pointsName + "/" + idP2)
.setFirstParentOnly(true);
iterator = op.call();
assertNotNull(iterator);
assertTrue(iterator.hasNext());
assertEquals(mergeCommit, iterator.next());
assertFalse(iterator.hasNext());
}
@Test
public void testAll() throws Exception {
// Create the following revision graph
// o
// |
// o - Points 1 added
// |\
// | o - branch1 - Points 2 added
// |
// o - Points 3 added
// |
// o - master - HEAD - Lines 1 added
insertAndAdd(points1);
final RevCommit c1 = geogig.command(CommitOp.class).setMessage("commit for " + idP1).call();
// create branch1 and checkout
geogig.command(BranchCreateOp.class).setAutoCheckout(true).setName("branch1").call();
insertAndAdd(points2);
final RevCommit c2 = geogig.command(CommitOp.class).setMessage("commit for " + idP2).call();
// checkout master
geogig.command(CheckoutOp.class).setSource("master").call();
insertAndAdd(points3);
final RevCommit c3 = geogig.command(CommitOp.class).setMessage("commit for " + idP3).call();
insertAndAdd(lines1);
final RevCommit c4 = geogig.command(CommitOp.class).setMessage("commit for " + idL1).call();
LogOp op = geogig.command(LogOp.class);
op.addCommit(c2.getId());
op.addCommit(c4.getId());
Iterator<RevCommit> iterator = op.call();
assertNotNull(iterator);
assertTrue(iterator.hasNext());
assertEquals(c4, iterator.next());
assertTrue(iterator.hasNext());
assertEquals(c3, iterator.next());
assertTrue(iterator.hasNext());
assertEquals(c2, iterator.next());
assertTrue(iterator.hasNext());
assertEquals(c1, iterator.next());
assertFalse(iterator.hasNext());
}
@Test
public void testBranch() throws Exception {
// Create the following revision graph
// o
// |
// o - Points 1 added
// |\
// | o - branch1 - Points 2 added
// |
// o - Points 3 added
// |
// o - master - HEAD - Lines 1 added
insertAndAdd(points1);
final RevCommit c1 = geogig.command(CommitOp.class).setMessage("commit for " + idP1).call();
// create branch1 and checkout
geogig.command(BranchCreateOp.class).setAutoCheckout(true).setName("branch1").call();
insertAndAdd(points2);
final RevCommit c2 = geogig.command(CommitOp.class).setMessage("commit for " + idP2).call();
// checkout master
geogig.command(CheckoutOp.class).setSource("master").call();
insertAndAdd(points3);
geogig.command(CommitOp.class).setMessage("commit for " + idP3).call();
insertAndAdd(lines1);
geogig.command(CommitOp.class).setMessage("commit for " + idL1).call();
LogOp op = geogig.command(LogOp.class).addCommit(c2.getId());
Iterator<RevCommit> iterator = op.call();
assertNotNull(iterator);
assertTrue(iterator.hasNext());
assertEquals(c2, iterator.next());
assertTrue(iterator.hasNext());
assertEquals(c1, iterator.next());
assertFalse(iterator.hasNext());
}
@Test
public void testAuthorFilter() throws Exception {
insertAndAdd(points1);
final RevCommit firstCommit = geogig.command(CommitOp.class)
.setAuthor("firstauthor", "firstauthor@boundlessgeo.com").call();
insertAndAdd(lines1);
final RevCommit secondCommit = geogig.command(CommitOp.class)
.setAuthor("secondauthor", "secondauthor@boundlessgeo.com").call();
Iterator<RevCommit> iterator = logOp.setAuthor("firstauthor").call();
assertNotNull(iterator);
assertTrue(iterator.hasNext());
assertEquals(firstCommit, iterator.next());
assertFalse(iterator.hasNext());
iterator = logOp.setAuthor("secondauthor").call();
assertNotNull(iterator);
assertTrue(iterator.hasNext());
assertEquals(secondCommit, iterator.next());
assertFalse(iterator.hasNext());
}
@Test
public void testCommitterFilter() throws Exception {
insertAndAdd(points1);
final RevCommit firstCommit = geogig.command(CommitOp.class)
.setCommitter("firstcommitter", "firstcommitter@boundlessgeo.com").call();
insertAndAdd(lines1);
final RevCommit secondCommit = geogig.command(CommitOp.class)
.setAuthor("secondcommitter", "secondcommitter@boundlessgeo.com").call();
Iterator<RevCommit> iterator = logOp.setAuthor("firstcommitter").call();
assertNotNull(iterator);
assertTrue(iterator.hasNext());
assertEquals(firstCommit, iterator.next());
assertFalse(iterator.hasNext());
iterator = logOp.setAuthor("secondcommitter").call();
assertNotNull(iterator);
assertTrue(iterator.hasNext());
assertEquals(secondCommit, iterator.next());
assertFalse(iterator.hasNext());
}
}