Package org.locationtech.geogig.test.integration

Source Code of org.locationtech.geogig.test.integration.SparseCloneTest

/* Copyright (c) 2013-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:
* Johnathan Garrett (LMN Solutions) - initial implementation
*/
package org.locationtech.geogig.test.integration;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.spy;

import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.geotools.data.DataUtilities;
import org.geotools.feature.NameImpl;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.locationtech.geogig.api.ObjectId;
import org.locationtech.geogig.api.RevCommit;
import org.locationtech.geogig.api.RevObject;
import org.locationtech.geogig.api.plumbing.RevObjectParse;
import org.locationtech.geogig.api.plumbing.UpdateRef;
import org.locationtech.geogig.api.porcelain.BranchCreateOp;
import org.locationtech.geogig.api.porcelain.CheckoutOp;
import org.locationtech.geogig.api.porcelain.CloneOp;
import org.locationtech.geogig.api.porcelain.CommitOp;
import org.locationtech.geogig.api.porcelain.ConfigOp;
import org.locationtech.geogig.api.porcelain.ConfigOp.ConfigAction;
import org.locationtech.geogig.api.porcelain.ConfigOp.ConfigScope;
import org.locationtech.geogig.api.porcelain.LogOp;
import org.locationtech.geogig.api.porcelain.MergeOp;
import org.locationtech.geogig.api.porcelain.MergeOp.MergeReport;
import org.locationtech.geogig.api.porcelain.PullOp;
import org.locationtech.geogig.api.porcelain.PushOp;
import org.locationtech.geogig.remote.AbstractMappedRemoteRepo;
import org.locationtech.geogig.remote.LocalMappedRemoteRepo;
import org.locationtech.geogig.remote.RemoteRepositoryTestCase;
import org.opengis.feature.Feature;
import org.opengis.feature.simple.SimpleFeatureType;
import org.opengis.feature.type.Name;

import com.google.common.base.Optional;
import com.google.common.base.Suppliers;

public class SparseCloneTest extends RemoteRepositoryTestCase {

    protected static final String idR1 = "Roads.1";

    protected static final String idR2 = "Roads.2";

    protected static final String idR3 = "Roads.3";

    protected static final String idC1 = "Cities.1";

    protected static final String idC2 = "Cities.2";

    protected static final String idC3 = "Cities.3";

    protected static final String citiesNs = "http://geogig.cities";

    protected static final String citiesName = "Cities";

    protected static final String citiesTypeSpec = "name:String,population:Integer,pp:Point:srid=4326";

    protected static final Name citiesTypeName = new NameImpl("http://geogig.cities", citiesName);

    protected SimpleFeatureType citiesType;

    protected Feature city1;

    protected Feature city1_modified;

    protected Feature city2;

    protected Feature city3;

    protected static final String roadsNs = "http://geogig.roads";

    protected static final String roadsName = "Roads";

    protected static final String roadsTypeSpec = "name:String,length:Integer,pp:LineString:srid=4326";

    protected static final Name roadsTypeName = new NameImpl("http://geogig.roads", roadsName);

    protected SimpleFeatureType roadsType;

    protected Feature road1;

    protected Feature road2;

    protected Feature road3;

    @Rule
    public ExpectedException exception = ExpectedException.none();

    @Override
    protected void setUpInternal() throws Exception {
        citiesType = DataUtilities.createType(citiesNs, citiesName, citiesTypeSpec);

        city1 = feature(citiesType, idC1, "San Francisco", new Integer(200000),
                "POINT(10.5559899 -71.6524294)");
        city1_modified = feature(citiesType, idC1, "San Francisco", new Integer(200000),
                "POINT(37.76169 -122.44791)");
        city2 = feature(citiesType, idC2, "San Diego", new Integer(350000),
                "POINT(32.7443 -117.2157)");
        city3 = feature(citiesType, idC3, "Los Angeles", new Integer(1000000),
                "POINT(34.0455 -118.2380)");

        roadsType = DataUtilities.createType(roadsNs, roadsName, roadsTypeSpec);

        road1 = feature(roadsType, idR1, "Main Street", new Integer(236),
                "LINESTRING (37.76169 -122.44791, 34.0455 -118.2380)");
        road2 = feature(roadsType, idR2, "Long Road", new Integer(2845),
                "LINESTRING (37.76169 -122.44791, 32.7443 -117.2157)");
        road3 = feature(roadsType, idR3, "San Rafael Way", new Integer(528),
                "LINESTRING (34.0455 -118.2380, 37.76169 -122.44791)");
    }

    private void createFilterFile(Map<String, String> filters) {
        String filterFile = "";
        for (Entry<String, String> entry : filters.entrySet()) {
            String featurePath = entry.getKey();
            String filter = entry.getValue();
            filterFile += "[" + featurePath + "]\n";
            filterFile += "type = CQL\n";
            filterFile += "filter = " + filter + "\n";
        }
        try {
            String path = this.localGeogig.geogig.getPlatform().pwd().getAbsolutePath()
                    + "/.geogig/";
            PrintWriter out = new PrintWriter(path + "filter.ini");
            out.println(filterFile);
            out.close();
            localGeogig.geogig.command(ConfigOp.class).setAction(ConfigAction.CONFIG_SET)
                    .setName("sparse.filter").setValue("filter.ini").setScope(ConfigScope.LOCAL)
                    .call();

            LocalMappedRemoteRepo remoteRepo = spy(new LocalMappedRemoteRepo(
                    remoteGeogig.getInjector(), remoteGeogig.envHome.getCanonicalFile(),
                    localGeogig.repo));

            doNothing().when(remoteRepo).close();

            remoteRepo.setGeoGig(remoteGeogig.geogig);
            this.remoteRepo = remoteRepo;
        } catch (Exception e) {
        }
    }

    @Test
    public void testSparseClone() throws Exception {

        Map<String, String> filter = new HashMap<String, String>();
        filter.put("default", "BBOX(pp,30, -125, 40, -110,'EPSG:4326')");
        filter.put("Cities", "BBOX(pp,33, -125, 40, -110,'EPSG:4326')");
        createFilterFile(filter);
        // Commit several features to the remote
        List<Feature> features = Arrays.asList(city1, city2, city3, road1, road2, road3);
        LinkedList<RevCommit> expected = new LinkedList<RevCommit>();
        Map<Feature, ObjectId> oids = new HashMap<Feature, ObjectId>();

        for (Feature f : features) {
            ObjectId oId = insertAndAdd(remoteGeogig.geogig, f);
            oids.put(f, oId);
            final RevCommit commit = remoteGeogig.geogig.command(CommitOp.class)
                    .setMessage(f.getIdentifier().toString()).call();
            expected.addFirst(commit);
            Optional<RevObject> childObject = remoteGeogig.geogig.command(RevObjectParse.class)
                    .setObjectId(oId).call();
            assertTrue(childObject.isPresent());
        }

        // Make sure the remote has all of the commits
        Iterator<RevCommit> logs = remoteGeogig.geogig.command(LogOp.class).call();
        List<RevCommit> logged = new ArrayList<RevCommit>();
        for (; logs.hasNext();) {
            logged.add(logs.next());
        }

        assertEquals(expected, logged);

        // Make sure the local repository has no commits prior to clone
        logs = localGeogig.geogig.command(LogOp.class).call();
        assertNotNull(logs);
        assertFalse(logs.hasNext());

        // clone from the remote
        CloneOp clone = clone();
        clone.setDepth(0);
        clone.setRepositoryURL(remoteGeogig.envHome.getCanonicalPath()).setBranch("master").call();

        // The features that match the filter are "Cities.3", "Roads.1", "Roads.2", and "Roads.3",
        // the "Cities.1" commit should be present since it added the "Cities" tree, but "Cities.1"
        // should not be present in the tree.

        // Make sure the local repository got the correct commits
        logs = localGeogig.geogig.command(LogOp.class).call();
        logged = new ArrayList<RevCommit>();
        for (; logs.hasNext();) {
            logged.add(logs.next());
        }

        assertEquals(5, logged.size());
        assertEquals("Roads.3", logged.get(0).getMessage());
        assertFalse(expected.get(0).getId().equals(logged.get(0).getId()));
        assertEquals("Roads.2", logged.get(1).getMessage());
        assertFalse(expected.get(1).getId().equals(logged.get(1).getId()));
        assertEquals("Roads.1", logged.get(2).getMessage());
        assertFalse(expected.get(2).getId().equals(logged.get(2).getId()));
        assertEquals("Cities.3", logged.get(3).getMessage());
        assertFalse(expected.get(3).getId().equals(logged.get(3).getId()));
        assertEquals("Cities.1", logged.get(4).getMessage());
        assertFalse(expected.get(5).getId().equals(logged.get(4).getId()));

        assertExists(localGeogig, oids.get(city3), oids.get(road1), oids.get(road2),
                oids.get(road3));
        assertNotExists(localGeogig, oids.get(city1), oids.get(city2));
    }

    @Test
    public void testSparseCloneAllMatch() throws Exception {

        Map<String, String> filter = new HashMap<String, String>();
        filter.put("default", "BBOX(pp,0, -125, 40, -70,'EPSG:4326')");
        createFilterFile(filter);
        // Commit several features to the remote
        List<Feature> features = Arrays.asList(city1, city2, city3, road1, road2, road3);
        LinkedList<RevCommit> expected = new LinkedList<RevCommit>();
        Map<Feature, ObjectId> oids = new HashMap<Feature, ObjectId>();

        for (Feature f : features) {
            ObjectId oId = insertAndAdd(remoteGeogig.geogig, f);
            oids.put(f, oId);
            final RevCommit commit = remoteGeogig.geogig.command(CommitOp.class)
                    .setMessage(f.getIdentifier().toString()).call();
            expected.addFirst(commit);
            Optional<RevObject> childObject = remoteGeogig.geogig.command(RevObjectParse.class)
                    .setObjectId(oId).call();
            assertTrue(childObject.isPresent());
        }

        // Make sure the remote has all of the commits
        Iterator<RevCommit> logs = remoteGeogig.geogig.command(LogOp.class).call();
        List<RevCommit> logged = new ArrayList<RevCommit>();
        for (; logs.hasNext();) {
            logged.add(logs.next());
        }

        assertEquals(expected, logged);

        // Make sure the local repository has no commits prior to clone
        logs = localGeogig.geogig.command(LogOp.class).call();
        assertNotNull(logs);
        assertFalse(logs.hasNext());

        // clone from the remote
        CloneOp clone = clone();
        clone.setDepth(0);
        clone.setRepositoryURL(remoteGeogig.envHome.getCanonicalPath()).setBranch("master").call();

        // Because all features match the filter, the history should be identical

        // Make sure the local repository got the correct commits
        logs = localGeogig.geogig.command(LogOp.class).call();
        logged = new ArrayList<RevCommit>();
        for (; logs.hasNext();) {
            logged.add(logs.next());
        }

        assertEquals(expected, logged);

        assertExists(localGeogig, oids.get(city1), oids.get(city2), oids.get(city3),
                oids.get(road1), oids.get(road2), oids.get(road3));
    }

    @Test
    public void testSparseCloneOnlyFirstMatch() throws Exception {

        Map<String, String> filter = new HashMap<String, String>();
        filter.put("default", "BBOX(pp,9, -80, 15, -70,'EPSG:4326')");
        createFilterFile(filter);
        // Commit several features to the remote
        List<Feature> features = Arrays.asList(city1, city2, city3, road1, road2, road3);
        LinkedList<RevCommit> expected = new LinkedList<RevCommit>();
        Map<Feature, ObjectId> oids = new HashMap<Feature, ObjectId>();

        for (Feature f : features) {
            ObjectId oId = insertAndAdd(remoteGeogig.geogig, f);
            oids.put(f, oId);
            final RevCommit commit = remoteGeogig.geogig.command(CommitOp.class)
                    .setMessage(f.getIdentifier().toString()).call();
            expected.addFirst(commit);
            Optional<RevObject> childObject = remoteGeogig.geogig.command(RevObjectParse.class)
                    .setObjectId(oId).call();
            assertTrue(childObject.isPresent());
        }

        // Make sure the remote has all of the commits
        Iterator<RevCommit> logs = remoteGeogig.geogig.command(LogOp.class).call();
        List<RevCommit> logged = new ArrayList<RevCommit>();
        for (; logs.hasNext();) {
            logged.add(logs.next());
        }

        assertEquals(expected, logged);

        // Make sure the local repository has no commits prior to clone
        logs = localGeogig.geogig.command(LogOp.class).call();
        assertNotNull(logs);
        assertFalse(logs.hasNext());

        // clone from the remote
        CloneOp clone = clone();
        clone.setDepth(0);
        clone.setRepositoryURL(remoteGeogig.envHome.getCanonicalPath()).setBranch("master").call();

        // Because only the first feature matches (Cities.1), the first commit should be the same,
        // there will also be the commit that adds the "Roads" tree but no features, and finally an
        // "Empty Placeholder Commit".

        // Make sure the local repository got the correct commits
        logs = localGeogig.geogig.command(LogOp.class).call();
        logged = new ArrayList<RevCommit>();
        for (; logs.hasNext();) {
            logged.add(logs.next());
        }

        assertEquals(3, logged.size());
        assertEquals(AbstractMappedRemoteRepo.PLACEHOLDER_COMMIT_MESSAGE, logged.get(0)
                .getMessage());
        assertFalse(expected.get(0).getId().equals(logged.get(0).getId()));
        assertEquals("Roads.1", logged.get(1).getMessage());
        assertFalse(expected.get(2).getId().equals(logged.get(1).getId()));
        assertEquals("Cities.1", logged.get(2).getMessage());
        assertTrue(expected.get(5).getId().equals(logged.get(2).getId()));

        assertExists(localGeogig, oids.get(city1));
        assertNotExists(localGeogig, oids.get(city2), oids.get(city3), oids.get(road1),
                oids.get(road2), oids.get(road3));
    }

    @Test
    public void testFeatureMovingOutOfAOI() throws Exception {

        Map<String, String> filter = new HashMap<String, String>();
        filter.put("default", "BBOX(pp,9, -80, 15, -70,'EPSG:4326')");
        createFilterFile(filter);
        // Commit several features to the remote
        List<Feature> features = Arrays.asList(city1, city1_modified);
        LinkedList<RevCommit> expected = new LinkedList<RevCommit>();
        Map<Feature, ObjectId> oids = new HashMap<Feature, ObjectId>();

        for (Feature f : features) {
            ObjectId oId = insertAndAdd(remoteGeogig.geogig, f);
            oids.put(f, oId);
            final RevCommit commit = remoteGeogig.geogig.command(CommitOp.class)
                    .setMessage(f.getIdentifier().toString()).call();
            expected.addFirst(commit);
            Optional<RevObject> childObject = remoteGeogig.geogig.command(RevObjectParse.class)
                    .setObjectId(oId).call();
            assertTrue(childObject.isPresent());
        }

        // Make sure the remote has all of the commits
        Iterator<RevCommit> logs = remoteGeogig.geogig.command(LogOp.class).call();
        List<RevCommit> logged = new ArrayList<RevCommit>();
        for (; logs.hasNext();) {
            logged.add(logs.next());
        }

        assertEquals(expected, logged);

        // Make sure the local repository has no commits prior to clone
        logs = localGeogig.geogig.command(LogOp.class).call();
        assertNotNull(logs);
        assertFalse(logs.hasNext());

        // clone from the remote
        CloneOp clone = clone();
        clone.setDepth(0);
        clone.setRepositoryURL(remoteGeogig.envHome.getCanonicalPath()).setBranch("master").call();

        // Because Cities.1 is first in our filter, then is modified to be outside the filter, it
        // should continue to be tracked. Therefore our histories should match.

        // Make sure the local repository got the correct commits
        logs = localGeogig.geogig.command(LogOp.class).call();
        logged = new ArrayList<RevCommit>();
        for (; logs.hasNext();) {
            logged.add(logs.next());
        }

        assertEquals(expected, logged);

        assertExists(localGeogig, oids.get(city1), oids.get(city1_modified));
    }

    @Test
    public void testFeatureMovingIntoAOI() throws Exception {

        Map<String, String> filter = new HashMap<String, String>();
        filter.put("Cities", "BBOX(pp,30, -125, 40, -110,'EPSG:4326')");
        createFilterFile(filter);
        // Commit several features to the remote
        List<Feature> features = Arrays.asList(city2, city1, city3, city1_modified);
        LinkedList<RevCommit> expected = new LinkedList<RevCommit>();
        Map<Feature, ObjectId> oids = new HashMap<Feature, ObjectId>();

        for (Feature f : features) {
            ObjectId oId = insertAndAdd(remoteGeogig.geogig, f);
            oids.put(f, oId);
            final RevCommit commit = remoteGeogig.geogig.command(CommitOp.class)
                    .setMessage(f.getIdentifier().toString()).call();
            expected.addFirst(commit);
            Optional<RevObject> childObject = remoteGeogig.geogig.command(RevObjectParse.class)
                    .setObjectId(oId).call();
            assertTrue(childObject.isPresent());
        }

        // Make sure the remote has all of the commits
        Iterator<RevCommit> logs = remoteGeogig.geogig.command(LogOp.class).call();
        List<RevCommit> logged = new ArrayList<RevCommit>();
        for (; logs.hasNext();) {
            logged.add(logs.next());
        }

        assertEquals(expected, logged);

        // Make sure the local repository has no commits prior to clone
        logs = localGeogig.geogig.command(LogOp.class).call();
        assertNotNull(logs);
        assertFalse(logs.hasNext());

        // clone from the remote
        CloneOp clone = clone();
        clone.setDepth(0);
        clone.setRepositoryURL(remoteGeogig.envHome.getCanonicalPath()).setBranch("master").call();

        // Cities.1 initially lies outside the filter, so the commit that adds it will not be part
        // of the sparse clone. Later the feature is moved into the AOI so it will be added at that
        // time.

        // Make sure the local repository got the correct commits
        logs = localGeogig.geogig.command(LogOp.class).call();
        logged = new ArrayList<RevCommit>();
        for (; logs.hasNext();) {
            logged.add(logs.next());
        }

        assertEquals(3, logged.size());
        assertEquals("Cities.1", logged.get(0).getMessage());
        assertFalse(expected.get(0).getId().equals(logged.get(0).getId()));
        assertEquals("Cities.3", logged.get(1).getMessage());
        assertFalse(expected.get(1).getId().equals(logged.get(1).getId()));
        assertEquals("Cities.2", logged.get(2).getMessage());
        assertTrue(expected.get(3).getId().equals(logged.get(2).getId()));

        assertExists(localGeogig, oids.get(city2), oids.get(city3), oids.get(city1_modified));
        assertNotExists(localGeogig, oids.get(city1));
    }

    @Test
    public void testPullCommitThatPassesFilter() throws Exception {
        setupSparseClone();
        // Add a commit that passes our filter to the remote.
        ObjectId oId = insertAndAdd(remoteGeogig.geogig, city1_modified);
        final RevCommit commit = remoteGeogig.geogig.command(CommitOp.class)
                .setMessage(city1_modified.getIdentifier().toString()).call();
        Optional<RevObject> childObject = remoteGeogig.geogig.command(RevObjectParse.class)
                .setObjectId(oId).call();
        assertTrue(childObject.isPresent());
        assertEquals(commit,
                remoteGeogig.geogig.getRepository().objectDatabase().getCommit(commit.getId()));

        PullOp pull = pull();
        pull.call();

        Iterator<RevCommit> logs = localGeogig.geogig.command(LogOp.class).call();
        List<RevCommit> logged = new ArrayList<RevCommit>();
        for (; logs.hasNext();) {
            logged.add(logs.next());
        }

        assertEquals("Cities.1", logged.get(0).getMessage());
        assertFalse(commit.getId().equals(logged.get(0).getId()));

        assertExists(localGeogig, oId);
    }

    @Test
    public void testPullCommitThatDoesNotPassFilter() throws Exception {
        setupSparseClone();
        // Add a commit that passes our filter to the remote.
        ObjectId oId = insertAndAdd(remoteGeogig.geogig, city1);
        final RevCommit commit = remoteGeogig.geogig.command(CommitOp.class)
                .setMessage(city1.getIdentifier().toString()).call();
        Optional<RevObject> childObject = remoteGeogig.geogig.command(RevObjectParse.class)
                .setObjectId(oId).call();
        assertTrue(childObject.isPresent());

        PullOp pull = pull();
        pull.call();

        Iterator<RevCommit> logs = localGeogig.geogig.command(LogOp.class).call();
        List<RevCommit> logged = new ArrayList<RevCommit>();
        for (; logs.hasNext();) {
            logged.add(logs.next());
        }

        assertEquals(AbstractMappedRemoteRepo.PLACEHOLDER_COMMIT_MESSAGE, logged.get(0)
                .getMessage());
        assertFalse(commit.getId().equals(logged.get(0).getId()));

        assertNotExists(localGeogig, oId);
    }

    @Test
    public void testPushCommitsFromSparseClone() throws Exception {
        setupSparseClone();
        // Add some commits to the local (sparse) repository
        List<Feature> features = Arrays.asList(city1, city1_modified, road3);
        LinkedList<RevCommit> expected = new LinkedList<RevCommit>();
        Map<Feature, ObjectId> oids = new HashMap<Feature, ObjectId>();

        for (Feature f : features) {
            ObjectId oId = insertAndAdd(localGeogig.geogig, f);
            oids.put(f, oId);
            final RevCommit commit = localGeogig.geogig.command(CommitOp.class)
                    .setMessage(f.getIdentifier().toString()).call();
            expected.addFirst(commit);
            Optional<RevObject> childObject = localGeogig.geogig.command(RevObjectParse.class)
                    .setObjectId(oId).call();
            assertTrue(childObject.isPresent());
        }

        PushOp push = push();
        push.setAll(true).call();

        Iterator<RevCommit> logs = remoteGeogig.geogig.command(LogOp.class).call();
        List<RevCommit> logged = new ArrayList<RevCommit>();
        for (; logs.hasNext();) {
            logged.add(logs.next());
        }

        assertEquals("Roads.3", logged.get(0).getMessage());
        assertFalse(expected.get(0).getId().equals(logged.get(0).getId()));
        assertEquals("Cities.1", logged.get(1).getMessage());
        assertFalse(expected.get(1).getId().equals(logged.get(1).getId()));
        assertEquals("Cities.1", logged.get(2).getMessage());
        assertFalse(expected.get(2).getId().equals(logged.get(2).getId()));

        assertExists(remoteGeogig, oids.get(city1), oids.get(city1_modified), oids.get(road3));
    }

    @Test
    public void testPushSparseMerge() throws Exception {
        setupSparseClone();
        // create a branch off an early commit
        Iterator<RevCommit> logs = localGeogig.geogig.command(LogOp.class).call();
        RevCommit initialCommit = logs.next();
        ObjectId masterCommit = initialCommit.getId();
        while (logs.hasNext()) {
            initialCommit = logs.next();
        }
        localGeogig.geogig.command(BranchCreateOp.class).setName("Branch1").setAutoCheckout(true)
                .setSource(initialCommit.getId().toString()).call();

        // Add some commits to the local (sparse) repository
        List<Feature> features = Arrays.asList(city1, city1_modified, road3);
        LinkedList<RevCommit> expected = new LinkedList<RevCommit>();
        Map<Feature, ObjectId> oids = new HashMap<Feature, ObjectId>();

        for (Feature f : features) {
            ObjectId oId = insertAndAdd(localGeogig.geogig, f);
            oids.put(f, oId);
            final RevCommit commit = localGeogig.geogig.command(CommitOp.class)
                    .setMessage(f.getIdentifier().toString()).call();
            expected.addFirst(commit);
            Optional<RevObject> childObject = localGeogig.geogig.command(RevObjectParse.class)
                    .setObjectId(oId).call();
            assertTrue(childObject.isPresent());
        }

        // Merge master into Branch1
        MergeOp merge = localGeogig.geogig.command(MergeOp.class);
        MergeReport report = merge.addCommit(Suppliers.ofInstance(masterCommit))
                .setMessage("Merge").call();

        // Update master to the new merge commit
        localGeogig.geogig.command(UpdateRef.class).setName("refs/heads/master")
                .setNewValue(report.getMergeCommit().getId()).call();

        // Checkout master
        localGeogig.geogig.command(CheckoutOp.class).setSource("master").call();

        PushOp push = push();
        push.addRefSpec("refs/heads/master").call();

        logs = remoteGeogig.geogig.command(LogOp.class).call();
        List<RevCommit> logged = new ArrayList<RevCommit>();
        for (; logs.hasNext();) {
            logged.add(logs.next());
        }

        assertEquals("Merge", logged.get(0).getMessage());
        assertFalse(report.getMergeCommit().getId().equals(logged.get(0).getId()));

        // Although we merged "Roads.2" commit into the "Roads.3" commit, making the "Roads.2"
        // commit the second parent, they should have been swapped when pushing to the full
        // repository to prevent any sparse data from being lost.
        ObjectId parent1Id = logged.get(0).getParentIds().get(0);
        ObjectId parent2Id = logged.get(0).getParentIds().get(1);

        RevCommit parent1 = remoteGeogig.geogig.getRepository().getCommit(parent1Id);
        assertNotNull(parent1);
        assertEquals("Roads.2", parent1.getMessage());
        RevCommit parent2 = remoteGeogig.geogig.getRepository().getCommit(parent2Id);
        assertNotNull(parent2);
        assertEquals("Roads.3", parent2.getMessage());

        // Verify they weren't swapped in the original
        parent1Id = report.getMergeCommit().getParentIds().get(0);
        parent2Id = report.getMergeCommit().getParentIds().get(1);

        parent1 = localGeogig.geogig.getRepository().getCommit(parent1Id);
        assertNotNull(parent1);
        assertEquals("Roads.3", parent1.getMessage());
        parent2 = localGeogig.geogig.getRepository().getCommit(parent2Id);
        assertNotNull(parent2);
        assertEquals("Roads.2", parent2.getMessage());

        assertExists(remoteGeogig, oids.get(city1), oids.get(city1_modified), oids.get(road3));
    }

    @Test
    public void testPushSparseMergeScenario2() throws Exception {
        setupSparseClone();
        // create a branch off an early commit
        Iterator<RevCommit> logs = localGeogig.geogig.command(LogOp.class).call();
        RevCommit initialCommit = logs.next();
        while (logs.hasNext()) {
            initialCommit = logs.next();
        }
        localGeogig.geogig.command(BranchCreateOp.class).setName("Branch1").setAutoCheckout(true)
                .setSource(initialCommit.getId().toString()).call();

        // Add some commits to the local (sparse) repository
        List<Feature> features = Arrays.asList(city1, city1_modified, road3);
        LinkedList<RevCommit> expected = new LinkedList<RevCommit>();
        Map<Feature, ObjectId> oids = new HashMap<Feature, ObjectId>();

        for (Feature f : features) {
            ObjectId oId = insertAndAdd(localGeogig.geogig, f);
            oids.put(f, oId);
            final RevCommit commit = localGeogig.geogig.command(CommitOp.class)
                    .setMessage(f.getIdentifier().toString()).call();
            expected.addFirst(commit);
            Optional<RevObject> childObject = localGeogig.geogig.command(RevObjectParse.class)
                    .setObjectId(oId).call();
            assertTrue(childObject.isPresent());
        }

        // Checkout master
        localGeogig.geogig.command(CheckoutOp.class).setSource("master").call();

        // Merge Branch1 into master
        MergeOp merge = localGeogig.geogig.command(MergeOp.class);
        MergeReport report = merge.addCommit(Suppliers.ofInstance(expected.get(0).getId()))
                .setMessage("Merge").call();

        PushOp push = push();
        push.addRefSpec("refs/heads/master").call();

        logs = remoteGeogig.geogig.command(LogOp.class).call();
        List<RevCommit> logged = new ArrayList<RevCommit>();
        for (; logs.hasNext();) {
            logged.add(logs.next());
        }

        assertEquals("Merge", logged.get(0).getMessage());
        assertFalse(report.getMergeCommit().getId().equals(logged.get(0).getId()));

        // Because we merged Branch1 into the "sparse" master, we don't need to swap the parents, so
        // the history should look the same.
        ObjectId parent1Id = logged.get(0).getParentIds().get(0);
        ObjectId parent2Id = logged.get(0).getParentIds().get(1);

        RevCommit parent1 = remoteGeogig.geogig.getRepository().getCommit(parent1Id);
        assertNotNull(parent1);
        assertEquals("Roads.2", parent1.getMessage());
        RevCommit parent2 = remoteGeogig.geogig.getRepository().getCommit(parent2Id);
        assertNotNull(parent2);
        assertEquals("Roads.3", parent2.getMessage());

        // Verify they weren't swapped in the original
        parent1Id = report.getMergeCommit().getParentIds().get(0);
        parent2Id = report.getMergeCommit().getParentIds().get(1);

        parent1 = localGeogig.geogig.getRepository().getCommit(parent1Id);
        assertNotNull(parent1);
        assertEquals("Roads.2", parent1.getMessage());
        parent2 = localGeogig.geogig.getRepository().getCommit(parent2Id);
        assertNotNull(parent2);
        assertEquals("Roads.3", parent2.getMessage());

        assertExists(remoteGeogig, oids.get(city1), oids.get(city1_modified), oids.get(road3));
    }

    @Test
    public void testSparseCloneWithNoBranchSpecified() throws Exception {
        Map<String, String> filter = new HashMap<String, String>();
        filter.put("default", "BBOX(pp,9, -80, 15, -70,'EPSG:4326')");
        createFilterFile(filter);

        CloneOp clone = clone();
        exception.expect(IllegalArgumentException.class);
        clone.setRepositoryURL(remoteGeogig.envHome.getCanonicalPath()).call();
    }

    @Test
    public void testSparseShallowClone() throws Exception {
        Map<String, String> filter = new HashMap<String, String>();
        filter.put("default", "BBOX(pp,9, -80, 15, -70,'EPSG:4326')");
        createFilterFile(filter);

        CloneOp clone = clone();
        clone.setDepth(3).setBranch("master");
        exception.expect(IllegalStateException.class);
        clone.setRepositoryURL(remoteGeogig.envHome.getCanonicalPath()).call();
    }

    private void setupSparseClone() throws Exception {

        Map<String, String> filter = new HashMap<String, String>();
        filter.put("default", "BBOX(pp,30, -125, 40, -110,'EPSG:4326')");
        filter.put("Cities", "BBOX(pp,33, -125, 40, -110,'EPSG:4326')");
        createFilterFile(filter);
        // Commit several features to the remote
        List<Feature> features = Arrays.asList(city3, road1, city2, road2);
        LinkedList<RevCommit> expected = new LinkedList<RevCommit>();
        Map<Feature, ObjectId> oids = new HashMap<Feature, ObjectId>();

        for (Feature f : features) {
            ObjectId oId = insertAndAdd(remoteGeogig.geogig, f);
            oids.put(f, oId);
            final RevCommit commit = remoteGeogig.geogig.command(CommitOp.class)
                    .setMessage(f.getIdentifier().toString()).call();
            expected.addFirst(commit);
            Optional<RevObject> childObject = remoteGeogig.geogig.command(RevObjectParse.class)
                    .setObjectId(oId).call();
            assertTrue(childObject.isPresent());
        }

        // Make sure the remote has all of the commits
        Iterator<RevCommit> logs = remoteGeogig.geogig.command(LogOp.class).call();
        List<RevCommit> logged = new ArrayList<RevCommit>();
        for (; logs.hasNext();) {
            logged.add(logs.next());
        }

        assertEquals(expected, logged);

        // Make sure the local repository has no commits prior to clone
        logs = localGeogig.geogig.command(LogOp.class).call();
        assertNotNull(logs);
        assertFalse(logs.hasNext());

        // clone from the remote
        CloneOp clone = clone();
        clone.setDepth(0);
        clone.setRepositoryURL(remoteGeogig.envHome.getCanonicalPath()).setBranch("master").call();

        logs = localGeogig.geogig.command(LogOp.class).call();
        logged = new ArrayList<RevCommit>();
        for (; logs.hasNext();) {
            logged.add(logs.next());
        }

        assertEquals("Roads.2", logged.get(0).getMessage());
        assertFalse(expected.get(0).getId().equals(logged.get(0).getId()));
        assertEquals(expected.get(2).getId(), logged.get(1).getId());
        assertEquals(expected.get(3).getId(), logged.get(2).getId());

    }

    private void assertExists(GeogigContainer geogig, ObjectId... features) {
        for (ObjectId object : features) {
            assertTrue(geogig.geogig.getRepository().blobExists(object));
        }
    }

    private void assertNotExists(GeogigContainer geogig, ObjectId... features) {
        for (ObjectId object : features) {
            assertFalse(geogig.geogig.getRepository().blobExists(object));
        }
    }

}
TOP

Related Classes of org.locationtech.geogig.test.integration.SparseCloneTest

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.