324 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Java
		
	
	
	
	
	
			
		
		
	
	
			324 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Java
		
	
	
	
	
	
// Copyright (C) 2015 The Android Open Source Project
 | 
						|
//
 | 
						|
// Licensed under the Apache License, Version 2.0 (the "License");
 | 
						|
// you may not use this file except in compliance with the License.
 | 
						|
// You may obtain a copy of the License at
 | 
						|
//
 | 
						|
// http://www.apache.org/licenses/LICENSE-2.0
 | 
						|
//
 | 
						|
// Unless required by applicable law or agreed to in writing, software
 | 
						|
// distributed under the License is distributed on an "AS IS" BASIS,
 | 
						|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
						|
// See the License for the specific language governing permissions and
 | 
						|
// limitations under the License.
 | 
						|
 | 
						|
package com.google.gerrit.server.git;
 | 
						|
 | 
						|
import static com.google.common.truth.Truth.assertThat;
 | 
						|
 | 
						|
import com.google.common.collect.ImmutableListMultimap;
 | 
						|
import com.google.common.collect.ImmutableSet;
 | 
						|
import com.google.common.collect.SortedSetMultimap;
 | 
						|
import com.google.gerrit.reviewdb.client.Change;
 | 
						|
import com.google.gerrit.reviewdb.client.PatchSet;
 | 
						|
import com.google.gerrit.testing.GerritBaseTests;
 | 
						|
import org.eclipse.jgit.internal.storage.dfs.DfsRepositoryDescription;
 | 
						|
import org.eclipse.jgit.internal.storage.dfs.InMemoryRepository;
 | 
						|
import org.eclipse.jgit.junit.TestRepository;
 | 
						|
import org.eclipse.jgit.lib.ObjectId;
 | 
						|
import org.eclipse.jgit.revwalk.RevCommit;
 | 
						|
import org.eclipse.jgit.revwalk.RevSort;
 | 
						|
import org.eclipse.jgit.revwalk.RevWalk;
 | 
						|
import org.junit.Before;
 | 
						|
import org.junit.Test;
 | 
						|
 | 
						|
public class GroupCollectorTest extends GerritBaseTests {
 | 
						|
  private TestRepository<?> tr;
 | 
						|
 | 
						|
  @Before
 | 
						|
  public void setUp() throws Exception {
 | 
						|
    tr = new TestRepository<>(new InMemoryRepository(new DfsRepositoryDescription("repo")));
 | 
						|
  }
 | 
						|
 | 
						|
  @Test
 | 
						|
  public void commitWhoseParentIsUninterestingGetsNewGroup() throws Exception {
 | 
						|
    RevCommit branchTip = tr.commit().create();
 | 
						|
    RevCommit a = tr.commit().parent(branchTip).create();
 | 
						|
 | 
						|
    SortedSetMultimap<ObjectId, String> groups =
 | 
						|
        collectGroups(newWalk(a, branchTip), patchSets(), groups());
 | 
						|
 | 
						|
    assertThat(groups).containsEntry(a, a.name());
 | 
						|
  }
 | 
						|
 | 
						|
  @Test
 | 
						|
  public void commitWhoseParentIsNewPatchSetGetsParentsGroup() throws Exception {
 | 
						|
    RevCommit branchTip = tr.commit().create();
 | 
						|
    RevCommit a = tr.commit().parent(branchTip).create();
 | 
						|
    RevCommit b = tr.commit().parent(a).create();
 | 
						|
 | 
						|
    SortedSetMultimap<ObjectId, String> groups =
 | 
						|
        collectGroups(newWalk(b, branchTip), patchSets(), groups());
 | 
						|
 | 
						|
    assertThat(groups).containsEntry(a, a.name());
 | 
						|
    assertThat(groups).containsEntry(b, a.name());
 | 
						|
  }
 | 
						|
 | 
						|
  @Test
 | 
						|
  public void commitWhoseParentIsExistingPatchSetGetsParentsGroup() throws Exception {
 | 
						|
    RevCommit branchTip = tr.commit().create();
 | 
						|
    RevCommit a = tr.commit().parent(branchTip).create();
 | 
						|
    RevCommit b = tr.commit().parent(a).create();
 | 
						|
 | 
						|
    String group = "deadbeefdeadbeefdeadbeefdeadbeefdeadbeef";
 | 
						|
    SortedSetMultimap<ObjectId, String> groups =
 | 
						|
        collectGroups(
 | 
						|
            newWalk(b, branchTip), patchSets().put(a, psId(1, 1)), groups().put(psId(1, 1), group));
 | 
						|
 | 
						|
    assertThat(groups).containsEntry(a, group);
 | 
						|
    assertThat(groups).containsEntry(b, group);
 | 
						|
  }
 | 
						|
 | 
						|
  @Test
 | 
						|
  public void commitWhoseParentIsExistingPatchSetWithNoGroup() throws Exception {
 | 
						|
    RevCommit branchTip = tr.commit().create();
 | 
						|
    RevCommit a = tr.commit().parent(branchTip).create();
 | 
						|
    RevCommit b = tr.commit().parent(a).create();
 | 
						|
 | 
						|
    SortedSetMultimap<ObjectId, String> groups =
 | 
						|
        collectGroups(newWalk(b, branchTip), patchSets().put(a, psId(1, 1)), groups());
 | 
						|
 | 
						|
    assertThat(groups).containsEntry(a, a.name());
 | 
						|
    assertThat(groups).containsEntry(b, a.name());
 | 
						|
  }
 | 
						|
 | 
						|
  @Test
 | 
						|
  public void mergeCommitAndNewParentsAllGetSameGroup() throws Exception {
 | 
						|
    RevCommit branchTip = tr.commit().create();
 | 
						|
    RevCommit a = tr.commit().parent(branchTip).create();
 | 
						|
    RevCommit b = tr.commit().parent(branchTip).create();
 | 
						|
    RevCommit m = tr.commit().parent(a).parent(b).create();
 | 
						|
 | 
						|
    SortedSetMultimap<ObjectId, String> groups =
 | 
						|
        collectGroups(newWalk(m, branchTip), patchSets(), groups());
 | 
						|
 | 
						|
    assertThat(groups).containsEntry(a, a.name());
 | 
						|
    assertThat(groups).containsEntry(b, a.name());
 | 
						|
    assertThat(groups).containsEntry(m, a.name());
 | 
						|
  }
 | 
						|
 | 
						|
  @Test
 | 
						|
  public void mergeCommitWhereOneParentHasExistingGroup() throws Exception {
 | 
						|
    RevCommit branchTip = tr.commit().create();
 | 
						|
    RevCommit a = tr.commit().parent(branchTip).create();
 | 
						|
    RevCommit b = tr.commit().parent(branchTip).create();
 | 
						|
    RevCommit m = tr.commit().parent(a).parent(b).create();
 | 
						|
 | 
						|
    String group = "deadbeefdeadbeefdeadbeefdeadbeefdeadbeef";
 | 
						|
    SortedSetMultimap<ObjectId, String> groups =
 | 
						|
        collectGroups(
 | 
						|
            newWalk(m, branchTip), patchSets().put(b, psId(1, 1)), groups().put(psId(1, 1), group));
 | 
						|
 | 
						|
    // Merge commit and other parent get the existing group.
 | 
						|
    assertThat(groups).containsEntry(a, group);
 | 
						|
    assertThat(groups).containsEntry(b, group);
 | 
						|
    assertThat(groups).containsEntry(m, group);
 | 
						|
  }
 | 
						|
 | 
						|
  @Test
 | 
						|
  public void mergeCommitWhereBothParentsHaveDifferentGroups() throws Exception {
 | 
						|
    RevCommit branchTip = tr.commit().create();
 | 
						|
    RevCommit a = tr.commit().parent(branchTip).create();
 | 
						|
    RevCommit b = tr.commit().parent(branchTip).create();
 | 
						|
    RevCommit m = tr.commit().parent(a).parent(b).create();
 | 
						|
 | 
						|
    String group1 = "deadbeefdeadbeefdeadbeefdeadbeefdeadbeef";
 | 
						|
    String group2 = "1234567812345678123456781234567812345678";
 | 
						|
    SortedSetMultimap<ObjectId, String> groups =
 | 
						|
        collectGroups(
 | 
						|
            newWalk(m, branchTip),
 | 
						|
            patchSets().put(a, psId(1, 1)).put(b, psId(2, 1)),
 | 
						|
            groups().put(psId(1, 1), group1).put(psId(2, 1), group2));
 | 
						|
 | 
						|
    assertThat(groups).containsEntry(a, group1);
 | 
						|
    assertThat(groups).containsEntry(b, group2);
 | 
						|
    // Merge commit gets joined group of parents.
 | 
						|
    assertThat(groups.asMap()).containsEntry(m, ImmutableSet.of(group1, group2));
 | 
						|
  }
 | 
						|
 | 
						|
  @Test
 | 
						|
  public void mergeCommitMergesGroupsFromParent() throws Exception {
 | 
						|
    RevCommit branchTip = tr.commit().create();
 | 
						|
    RevCommit a = tr.commit().parent(branchTip).create();
 | 
						|
    RevCommit b = tr.commit().parent(branchTip).create();
 | 
						|
    RevCommit m = tr.commit().parent(a).parent(b).create();
 | 
						|
 | 
						|
    String group1 = "deadbeefdeadbeefdeadbeefdeadbeefdeadbeef";
 | 
						|
    String group2a = "1234567812345678123456781234567812345678";
 | 
						|
    String group2b = "ef123456ef123456ef123456ef123456ef123456";
 | 
						|
    SortedSetMultimap<ObjectId, String> groups =
 | 
						|
        collectGroups(
 | 
						|
            newWalk(m, branchTip),
 | 
						|
            patchSets().put(a, psId(1, 1)).put(b, psId(2, 1)),
 | 
						|
            groups().put(psId(1, 1), group1).put(psId(2, 1), group2a).put(psId(2, 1), group2b));
 | 
						|
 | 
						|
    assertThat(groups).containsEntry(a, group1);
 | 
						|
    assertThat(groups.asMap()).containsEntry(b, ImmutableSet.of(group2a, group2b));
 | 
						|
    // Joined parent groups are split and resorted.
 | 
						|
    assertThat(groups.asMap()).containsEntry(m, ImmutableSet.of(group1, group2a, group2b));
 | 
						|
  }
 | 
						|
 | 
						|
  @Test
 | 
						|
  public void mergeCommitWithOneUninterestingParentAndOtherParentIsExisting() throws Exception {
 | 
						|
    RevCommit branchTip = tr.commit().create();
 | 
						|
    RevCommit a = tr.commit().parent(branchTip).create();
 | 
						|
    RevCommit m = tr.commit().parent(branchTip).parent(a).create();
 | 
						|
 | 
						|
    String group = "deadbeefdeadbeefdeadbeefdeadbeefdeadbeef";
 | 
						|
    SortedSetMultimap<ObjectId, String> groups =
 | 
						|
        collectGroups(
 | 
						|
            newWalk(m, branchTip), patchSets().put(a, psId(1, 1)), groups().put(psId(1, 1), group));
 | 
						|
 | 
						|
    assertThat(groups).containsEntry(a, group);
 | 
						|
    assertThat(groups).containsEntry(m, group);
 | 
						|
  }
 | 
						|
 | 
						|
  @Test
 | 
						|
  public void mergeCommitWithOneUninterestingParentAndOtherParentIsNew() throws Exception {
 | 
						|
    RevCommit branchTip = tr.commit().create();
 | 
						|
    RevCommit a = tr.commit().parent(branchTip).create();
 | 
						|
    RevCommit m = tr.commit().parent(branchTip).parent(a).create();
 | 
						|
 | 
						|
    SortedSetMultimap<ObjectId, String> groups =
 | 
						|
        collectGroups(newWalk(m, branchTip), patchSets(), groups());
 | 
						|
 | 
						|
    assertThat(groups).containsEntry(a, a.name());
 | 
						|
    assertThat(groups).containsEntry(m, a.name());
 | 
						|
  }
 | 
						|
 | 
						|
  @Test
 | 
						|
  public void multipleMergeCommitsInHistoryAllResolveToSameGroup() throws Exception {
 | 
						|
    RevCommit branchTip = tr.commit().create();
 | 
						|
    RevCommit a = tr.commit().parent(branchTip).create();
 | 
						|
    RevCommit b = tr.commit().parent(branchTip).create();
 | 
						|
    RevCommit c = tr.commit().parent(branchTip).create();
 | 
						|
    RevCommit m1 = tr.commit().parent(b).parent(c).create();
 | 
						|
    RevCommit m2 = tr.commit().parent(a).parent(m1).create();
 | 
						|
 | 
						|
    SortedSetMultimap<ObjectId, String> groups =
 | 
						|
        collectGroups(newWalk(m2, branchTip), patchSets(), groups());
 | 
						|
 | 
						|
    assertThat(groups).containsEntry(a, a.name());
 | 
						|
    assertThat(groups).containsEntry(b, a.name());
 | 
						|
    assertThat(groups).containsEntry(c, a.name());
 | 
						|
    assertThat(groups).containsEntry(m1, a.name());
 | 
						|
    assertThat(groups).containsEntry(m2, a.name());
 | 
						|
  }
 | 
						|
 | 
						|
  @Test
 | 
						|
  public void mergeCommitWithDuplicatedParentGetsParentsGroup() throws Exception {
 | 
						|
    RevCommit branchTip = tr.commit().create();
 | 
						|
    RevCommit a = tr.commit().parent(branchTip).create();
 | 
						|
    RevCommit m = tr.commit().parent(a).parent(a).create();
 | 
						|
    tr.getRevWalk().parseBody(m);
 | 
						|
    assertThat(m.getParentCount()).isEqualTo(2);
 | 
						|
    assertThat(m.getParent(0)).isEqualTo(m.getParent(1));
 | 
						|
 | 
						|
    SortedSetMultimap<ObjectId, String> groups =
 | 
						|
        collectGroups(newWalk(m, branchTip), patchSets(), groups());
 | 
						|
 | 
						|
    assertThat(groups).containsEntry(a, a.name());
 | 
						|
    assertThat(groups).containsEntry(m, a.name());
 | 
						|
  }
 | 
						|
 | 
						|
  @Test
 | 
						|
  public void mergeCommitWithOneNewParentAndTwoExistingPatchSets() throws Exception {
 | 
						|
    RevCommit branchTip = tr.commit().create();
 | 
						|
    RevCommit a = tr.commit().parent(branchTip).create();
 | 
						|
    RevCommit b = tr.commit().parent(branchTip).create();
 | 
						|
    RevCommit c = tr.commit().parent(b).create();
 | 
						|
    RevCommit m = tr.commit().parent(a).parent(c).create();
 | 
						|
 | 
						|
    String group1 = "deadbeefdeadbeefdeadbeefdeadbeefdeadbeef";
 | 
						|
    String group2 = "1234567812345678123456781234567812345678";
 | 
						|
    SortedSetMultimap<ObjectId, String> groups =
 | 
						|
        collectGroups(
 | 
						|
            newWalk(m, branchTip),
 | 
						|
            patchSets().put(a, psId(1, 1)).put(b, psId(2, 1)),
 | 
						|
            groups().put(psId(1, 1), group1).put(psId(2, 1), group2));
 | 
						|
 | 
						|
    assertThat(groups).containsEntry(a, group1);
 | 
						|
    assertThat(groups).containsEntry(b, group2);
 | 
						|
    assertThat(groups).containsEntry(c, group2);
 | 
						|
    assertThat(groups.asMap()).containsEntry(m, ImmutableSet.of(group1, group2));
 | 
						|
  }
 | 
						|
 | 
						|
  @Test
 | 
						|
  public void collectGroupsForMultipleTipsInParallel() throws Exception {
 | 
						|
    RevCommit branchTip = tr.commit().create();
 | 
						|
    RevCommit a = tr.commit().parent(branchTip).create();
 | 
						|
    RevCommit b = tr.commit().parent(a).create();
 | 
						|
    RevCommit c = tr.commit().parent(branchTip).create();
 | 
						|
    RevCommit d = tr.commit().parent(c).create();
 | 
						|
 | 
						|
    RevWalk rw = newWalk(b, branchTip);
 | 
						|
    rw.markStart(rw.parseCommit(d));
 | 
						|
    // Schema upgrade case: all commits are existing patch sets, but none have
 | 
						|
    // groups assigned yet.
 | 
						|
    SortedSetMultimap<ObjectId, String> groups =
 | 
						|
        collectGroups(
 | 
						|
            rw,
 | 
						|
            patchSets()
 | 
						|
                .put(branchTip, psId(1, 1))
 | 
						|
                .put(a, psId(2, 1))
 | 
						|
                .put(b, psId(3, 1))
 | 
						|
                .put(c, psId(4, 1))
 | 
						|
                .put(d, psId(5, 1)),
 | 
						|
            groups());
 | 
						|
 | 
						|
    assertThat(groups).containsEntry(a, a.name());
 | 
						|
    assertThat(groups).containsEntry(b, a.name());
 | 
						|
    assertThat(groups).containsEntry(c, c.name());
 | 
						|
    assertThat(groups).containsEntry(d, c.name());
 | 
						|
  }
 | 
						|
 | 
						|
  // TODO(dborowitz): Tests for octopus merges.
 | 
						|
 | 
						|
  private static PatchSet.Id psId(int c, int p) {
 | 
						|
    return PatchSet.id(Change.id(c), p);
 | 
						|
  }
 | 
						|
 | 
						|
  private RevWalk newWalk(ObjectId start, ObjectId branchTip) throws Exception {
 | 
						|
    // Match RevWalk conditions from ReceiveCommits.
 | 
						|
    RevWalk rw = new RevWalk(tr.getRepository());
 | 
						|
    rw.sort(RevSort.TOPO);
 | 
						|
    rw.sort(RevSort.REVERSE, true);
 | 
						|
    rw.markStart(rw.parseCommit(start));
 | 
						|
    rw.markUninteresting(rw.parseCommit(branchTip));
 | 
						|
    return rw;
 | 
						|
  }
 | 
						|
 | 
						|
  private static SortedSetMultimap<ObjectId, String> collectGroups(
 | 
						|
      RevWalk rw,
 | 
						|
      ImmutableListMultimap.Builder<ObjectId, PatchSet.Id> patchSetsBySha,
 | 
						|
      ImmutableListMultimap.Builder<PatchSet.Id, String> groupLookup)
 | 
						|
      throws Exception {
 | 
						|
    GroupCollector gc = new GroupCollector(patchSetsBySha.build(), groupLookup.build());
 | 
						|
    RevCommit c;
 | 
						|
    while ((c = rw.next()) != null) {
 | 
						|
      gc.visit(c);
 | 
						|
    }
 | 
						|
    return gc.getGroups();
 | 
						|
  }
 | 
						|
 | 
						|
  // Helper methods for constructing various map arguments, to avoid lots of
 | 
						|
  // type specifications.
 | 
						|
  private static ImmutableListMultimap.Builder<ObjectId, PatchSet.Id> patchSets() {
 | 
						|
    return ImmutableListMultimap.builder();
 | 
						|
  }
 | 
						|
 | 
						|
  private static ImmutableListMultimap.Builder<PatchSet.Id, String> groups() {
 | 
						|
    return ImmutableListMultimap.builder();
 | 
						|
  }
 | 
						|
}
 |