Dissolve gerrit-server top-level directory
Change-Id: I538512dfe0f1bea774c01fdd45fa410a45634011
This commit is contained in:
		
				
					committed by
					
						
						Dave Borowitz
					
				
			
			
				
	
			
			
			
						parent
						
							472396c797
						
					
				
				
					commit
					376a7bbb64
				
			
							
								
								
									
										162
									
								
								javatests/com/google/gerrit/server/git/DestinationListTest.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										162
									
								
								javatests/com/google/gerrit/server/git/DestinationListTest.java
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,162 @@
 | 
			
		||||
// 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 static org.easymock.EasyMock.createNiceMock;
 | 
			
		||||
import static org.easymock.EasyMock.replay;
 | 
			
		||||
 | 
			
		||||
import com.google.gerrit.reviewdb.client.Branch;
 | 
			
		||||
import com.google.gerrit.reviewdb.client.Project;
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
import java.util.HashSet;
 | 
			
		||||
import java.util.Set;
 | 
			
		||||
import junit.framework.TestCase;
 | 
			
		||||
import org.junit.Test;
 | 
			
		||||
 | 
			
		||||
public class DestinationListTest extends TestCase {
 | 
			
		||||
  public static final String R_FOO = "refs/heads/foo";
 | 
			
		||||
  public static final String R_BAR = "refs/heads/bar";
 | 
			
		||||
 | 
			
		||||
  public static final String P_MY = "myproject";
 | 
			
		||||
  public static final String P_SLASH = "my/project/with/slashes";
 | 
			
		||||
  public static final String P_COMPLEX = " a/project/with spaces and \ttabs ";
 | 
			
		||||
 | 
			
		||||
  public static final String L_FOO = R_FOO + "\t" + P_MY + "\n";
 | 
			
		||||
  public static final String L_BAR = R_BAR + "\t" + P_SLASH + "\n";
 | 
			
		||||
  public static final String L_FOO_PAD_F = " " + R_FOO + "\t" + P_MY + "\n";
 | 
			
		||||
  public static final String L_FOO_PAD_E = R_FOO + " \t" + P_MY + "\n";
 | 
			
		||||
  public static final String L_COMPLEX = R_FOO + "\t" + P_COMPLEX + "\n";
 | 
			
		||||
  public static final String L_BAD = R_FOO + "\n";
 | 
			
		||||
 | 
			
		||||
  public static final String HEADER = "# Ref\tProject\n";
 | 
			
		||||
  public static final String HEADER_PROPER = "# Ref         \tProject\n";
 | 
			
		||||
  public static final String C1 = "# A Simple Comment\n";
 | 
			
		||||
  public static final String C2 = "# Comment with a tab\t and multi # # #\n";
 | 
			
		||||
 | 
			
		||||
  public static final String F_SIMPLE = L_FOO + L_BAR;
 | 
			
		||||
  public static final String F_PROPER = L_BAR + L_FOO; // alpha order
 | 
			
		||||
  public static final String F_PAD_F = L_FOO_PAD_F + L_BAR;
 | 
			
		||||
  public static final String F_PAD_E = L_FOO_PAD_E + L_BAR;
 | 
			
		||||
 | 
			
		||||
  public static final String LABEL = "label";
 | 
			
		||||
  public static final String LABEL2 = "another";
 | 
			
		||||
 | 
			
		||||
  public static final Branch.NameKey B_FOO = dest(P_MY, R_FOO);
 | 
			
		||||
  public static final Branch.NameKey B_BAR = dest(P_SLASH, R_BAR);
 | 
			
		||||
  public static final Branch.NameKey B_COMPLEX = dest(P_COMPLEX, R_FOO);
 | 
			
		||||
 | 
			
		||||
  public static final Set<Branch.NameKey> D_SIMPLE = new HashSet<>();
 | 
			
		||||
 | 
			
		||||
  static {
 | 
			
		||||
    D_SIMPLE.clear();
 | 
			
		||||
    D_SIMPLE.add(B_FOO);
 | 
			
		||||
    D_SIMPLE.add(B_BAR);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private static Branch.NameKey dest(String project, String ref) {
 | 
			
		||||
    return new Branch.NameKey(new Project.NameKey(project), ref);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test
 | 
			
		||||
  public void testParseSimple() throws Exception {
 | 
			
		||||
    DestinationList dl = new DestinationList();
 | 
			
		||||
    dl.parseLabel(LABEL, F_SIMPLE, null);
 | 
			
		||||
    Set<Branch.NameKey> branches = dl.getDestinations(LABEL);
 | 
			
		||||
    assertThat(branches).containsExactlyElementsIn(D_SIMPLE);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test
 | 
			
		||||
  public void testParseWHeader() throws Exception {
 | 
			
		||||
    DestinationList dl = new DestinationList();
 | 
			
		||||
    dl.parseLabel(LABEL, HEADER + F_SIMPLE, null);
 | 
			
		||||
    Set<Branch.NameKey> branches = dl.getDestinations(LABEL);
 | 
			
		||||
    assertThat(branches).containsExactlyElementsIn(D_SIMPLE);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test
 | 
			
		||||
  public void testParseWComments() throws Exception {
 | 
			
		||||
    DestinationList dl = new DestinationList();
 | 
			
		||||
    dl.parseLabel(LABEL, C1 + F_SIMPLE + C2, null);
 | 
			
		||||
    Set<Branch.NameKey> branches = dl.getDestinations(LABEL);
 | 
			
		||||
    assertThat(branches).containsExactlyElementsIn(D_SIMPLE);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test
 | 
			
		||||
  public void testParseFooComment() throws Exception {
 | 
			
		||||
    DestinationList dl = new DestinationList();
 | 
			
		||||
    dl.parseLabel(LABEL, "#" + L_FOO + L_BAR, null);
 | 
			
		||||
    Set<Branch.NameKey> branches = dl.getDestinations(LABEL);
 | 
			
		||||
    assertThat(branches).doesNotContain(B_FOO);
 | 
			
		||||
    assertThat(branches).contains(B_BAR);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test
 | 
			
		||||
  public void testParsePaddedFronts() throws Exception {
 | 
			
		||||
    DestinationList dl = new DestinationList();
 | 
			
		||||
    dl.parseLabel(LABEL, F_PAD_F, null);
 | 
			
		||||
    Set<Branch.NameKey> branches = dl.getDestinations(LABEL);
 | 
			
		||||
    assertThat(branches).containsExactlyElementsIn(D_SIMPLE);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test
 | 
			
		||||
  public void testParsePaddedEnds() throws Exception {
 | 
			
		||||
    DestinationList dl = new DestinationList();
 | 
			
		||||
    dl.parseLabel(LABEL, F_PAD_E, null);
 | 
			
		||||
    Set<Branch.NameKey> branches = dl.getDestinations(LABEL);
 | 
			
		||||
    assertThat(branches).containsExactlyElementsIn(D_SIMPLE);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test
 | 
			
		||||
  public void testParseComplex() throws Exception {
 | 
			
		||||
    DestinationList dl = new DestinationList();
 | 
			
		||||
    dl.parseLabel(LABEL, L_COMPLEX, null);
 | 
			
		||||
    Set<Branch.NameKey> branches = dl.getDestinations(LABEL);
 | 
			
		||||
    assertThat(branches).contains(B_COMPLEX);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test(expected = IOException.class)
 | 
			
		||||
  public void testParseBad() throws IOException {
 | 
			
		||||
    ValidationError.Sink sink = createNiceMock(ValidationError.Sink.class);
 | 
			
		||||
    replay(sink);
 | 
			
		||||
    new DestinationList().parseLabel(LABEL, L_BAD, sink);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test
 | 
			
		||||
  public void testParse2Labels() throws Exception {
 | 
			
		||||
    DestinationList dl = new DestinationList();
 | 
			
		||||
    dl.parseLabel(LABEL, F_SIMPLE, null);
 | 
			
		||||
    Set<Branch.NameKey> branches = dl.getDestinations(LABEL);
 | 
			
		||||
    assertThat(branches).containsExactlyElementsIn(D_SIMPLE);
 | 
			
		||||
 | 
			
		||||
    dl.parseLabel(LABEL2, L_COMPLEX, null);
 | 
			
		||||
    branches = dl.getDestinations(LABEL);
 | 
			
		||||
    assertThat(branches).containsExactlyElementsIn(D_SIMPLE);
 | 
			
		||||
    branches = dl.getDestinations(LABEL2);
 | 
			
		||||
    assertThat(branches).contains(B_COMPLEX);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test
 | 
			
		||||
  public void testAsText() throws Exception {
 | 
			
		||||
    String text = HEADER_PROPER + "#\n" + F_PROPER;
 | 
			
		||||
    DestinationList dl = new DestinationList();
 | 
			
		||||
    dl.parseLabel(LABEL, F_SIMPLE, null);
 | 
			
		||||
    String asText = dl.asText(LABEL);
 | 
			
		||||
    assertThat(text).isEqualTo(asText);
 | 
			
		||||
 | 
			
		||||
    dl.parseLabel(LABEL2, asText, null);
 | 
			
		||||
    assertThat(text).isEqualTo(dl.asText(LABEL2));
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										322
									
								
								javatests/com/google/gerrit/server/git/GroupCollectorTest.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										322
									
								
								javatests/com/google/gerrit/server/git/GroupCollectorTest.java
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,322 @@
 | 
			
		||||
// 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 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 {
 | 
			
		||||
  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 new PatchSet.Id(new 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();
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										120
									
								
								javatests/com/google/gerrit/server/git/GroupListTest.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										120
									
								
								javatests/com/google/gerrit/server/git/GroupListTest.java
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,120 @@
 | 
			
		||||
// Copyright (C) 2014 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 org.easymock.EasyMock.anyObject;
 | 
			
		||||
import static org.easymock.EasyMock.createMock;
 | 
			
		||||
import static org.easymock.EasyMock.createNiceMock;
 | 
			
		||||
import static org.easymock.EasyMock.expectLastCall;
 | 
			
		||||
import static org.easymock.EasyMock.replay;
 | 
			
		||||
import static org.easymock.EasyMock.verify;
 | 
			
		||||
import static org.junit.Assert.assertEquals;
 | 
			
		||||
import static org.junit.Assert.assertNotNull;
 | 
			
		||||
import static org.junit.Assert.assertNull;
 | 
			
		||||
import static org.junit.Assert.assertTrue;
 | 
			
		||||
 | 
			
		||||
import com.google.gerrit.common.data.GroupReference;
 | 
			
		||||
import com.google.gerrit.reviewdb.client.AccountGroup;
 | 
			
		||||
import com.google.gerrit.reviewdb.client.Project;
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
import java.util.Collection;
 | 
			
		||||
import java.util.Collections;
 | 
			
		||||
import java.util.Set;
 | 
			
		||||
import org.junit.Before;
 | 
			
		||||
import org.junit.Test;
 | 
			
		||||
 | 
			
		||||
public class GroupListTest {
 | 
			
		||||
  private static final Project.NameKey PROJECT = new Project.NameKey("project");
 | 
			
		||||
  private static final String TEXT =
 | 
			
		||||
      "# UUID                                  \tGroup Name\n"
 | 
			
		||||
          + "#\n"
 | 
			
		||||
          + "d96b998f8a66ff433af50befb975d0e2bb6e0999\tNon-Interactive Users\n"
 | 
			
		||||
          + "ebe31c01aec2c9ac3b3c03e87a47450829ff4310\tAdministrators\n";
 | 
			
		||||
 | 
			
		||||
  private GroupList groupList;
 | 
			
		||||
 | 
			
		||||
  @Before
 | 
			
		||||
  public void setup() throws IOException {
 | 
			
		||||
    ValidationError.Sink sink = createNiceMock(ValidationError.Sink.class);
 | 
			
		||||
    replay(sink);
 | 
			
		||||
    groupList = GroupList.parse(PROJECT, TEXT, sink);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test
 | 
			
		||||
  public void byUUID() throws Exception {
 | 
			
		||||
    AccountGroup.UUID uuid = new AccountGroup.UUID("d96b998f8a66ff433af50befb975d0e2bb6e0999");
 | 
			
		||||
 | 
			
		||||
    GroupReference groupReference = groupList.byUUID(uuid);
 | 
			
		||||
 | 
			
		||||
    assertEquals(uuid, groupReference.getUUID());
 | 
			
		||||
    assertEquals("Non-Interactive Users", groupReference.getName());
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test
 | 
			
		||||
  public void put() {
 | 
			
		||||
    AccountGroup.UUID uuid = new AccountGroup.UUID("abc");
 | 
			
		||||
    GroupReference groupReference = new GroupReference(uuid, "Hutzliputz");
 | 
			
		||||
 | 
			
		||||
    groupList.put(uuid, groupReference);
 | 
			
		||||
 | 
			
		||||
    assertEquals(3, groupList.references().size());
 | 
			
		||||
    GroupReference found = groupList.byUUID(uuid);
 | 
			
		||||
    assertEquals(groupReference, found);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test
 | 
			
		||||
  public void references() throws Exception {
 | 
			
		||||
    Collection<GroupReference> result = groupList.references();
 | 
			
		||||
 | 
			
		||||
    assertEquals(2, result.size());
 | 
			
		||||
    AccountGroup.UUID uuid = new AccountGroup.UUID("ebe31c01aec2c9ac3b3c03e87a47450829ff4310");
 | 
			
		||||
    GroupReference expected = new GroupReference(uuid, "Administrators");
 | 
			
		||||
 | 
			
		||||
    assertTrue(result.contains(expected));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test
 | 
			
		||||
  public void uUIDs() throws Exception {
 | 
			
		||||
    Set<AccountGroup.UUID> result = groupList.uuids();
 | 
			
		||||
 | 
			
		||||
    assertEquals(2, result.size());
 | 
			
		||||
    AccountGroup.UUID expected = new AccountGroup.UUID("ebe31c01aec2c9ac3b3c03e87a47450829ff4310");
 | 
			
		||||
    assertTrue(result.contains(expected));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test
 | 
			
		||||
  public void validationError() throws Exception {
 | 
			
		||||
    ValidationError.Sink sink = createMock(ValidationError.Sink.class);
 | 
			
		||||
    sink.error(anyObject(ValidationError.class));
 | 
			
		||||
    expectLastCall().times(2);
 | 
			
		||||
    replay(sink);
 | 
			
		||||
    groupList = GroupList.parse(PROJECT, TEXT.replace("\t", "    "), sink);
 | 
			
		||||
    verify(sink);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test
 | 
			
		||||
  public void retainAll() throws Exception {
 | 
			
		||||
    AccountGroup.UUID uuid = new AccountGroup.UUID("d96b998f8a66ff433af50befb975d0e2bb6e0999");
 | 
			
		||||
    groupList.retainUUIDs(Collections.singleton(uuid));
 | 
			
		||||
 | 
			
		||||
    assertNotNull(groupList.byUUID(uuid));
 | 
			
		||||
    assertNull(groupList.byUUID(new AccountGroup.UUID("ebe31c01aec2c9ac3b3c03e87a47450829ff4310")));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test
 | 
			
		||||
  public void asText() throws Exception {
 | 
			
		||||
    assertTrue(TEXT.equals(groupList.asText()));
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										227
									
								
								javatests/com/google/gerrit/server/git/LabelNormalizerTest.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										227
									
								
								javatests/com/google/gerrit/server/git/LabelNormalizerTest.java
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,227 @@
 | 
			
		||||
// Copyright (C) 2014 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.gerrit.common.data.Permission.forLabel;
 | 
			
		||||
import static com.google.gerrit.server.group.SystemGroupBackend.REGISTERED_USERS;
 | 
			
		||||
import static com.google.gerrit.server.project.testing.Util.allow;
 | 
			
		||||
import static com.google.gerrit.server.project.testing.Util.category;
 | 
			
		||||
import static com.google.gerrit.server.project.testing.Util.value;
 | 
			
		||||
import static org.junit.Assert.assertEquals;
 | 
			
		||||
 | 
			
		||||
import com.google.common.collect.ImmutableList;
 | 
			
		||||
import com.google.gerrit.common.TimeUtil;
 | 
			
		||||
import com.google.gerrit.common.data.AccessSection;
 | 
			
		||||
import com.google.gerrit.common.data.LabelType;
 | 
			
		||||
import com.google.gerrit.lifecycle.LifecycleManager;
 | 
			
		||||
import com.google.gerrit.reviewdb.client.Account;
 | 
			
		||||
import com.google.gerrit.reviewdb.client.Branch;
 | 
			
		||||
import com.google.gerrit.reviewdb.client.Change;
 | 
			
		||||
import com.google.gerrit.reviewdb.client.LabelId;
 | 
			
		||||
import com.google.gerrit.reviewdb.client.PatchSet;
 | 
			
		||||
import com.google.gerrit.reviewdb.client.PatchSetApproval;
 | 
			
		||||
import com.google.gerrit.reviewdb.client.PatchSetInfo;
 | 
			
		||||
import com.google.gerrit.reviewdb.server.ReviewDb;
 | 
			
		||||
import com.google.gerrit.server.CurrentUser;
 | 
			
		||||
import com.google.gerrit.server.IdentifiedUser;
 | 
			
		||||
import com.google.gerrit.server.account.AccountManager;
 | 
			
		||||
import com.google.gerrit.server.account.AuthRequest;
 | 
			
		||||
import com.google.gerrit.server.config.AllProjectsName;
 | 
			
		||||
import com.google.gerrit.server.git.LabelNormalizer.Result;
 | 
			
		||||
import com.google.gerrit.server.notedb.ChangeNotes;
 | 
			
		||||
import com.google.gerrit.server.project.ProjectCache;
 | 
			
		||||
import com.google.gerrit.server.schema.SchemaCreator;
 | 
			
		||||
import com.google.gerrit.server.util.RequestContext;
 | 
			
		||||
import com.google.gerrit.server.util.ThreadLocalRequestContext;
 | 
			
		||||
import com.google.gerrit.testing.InMemoryDatabase;
 | 
			
		||||
import com.google.gerrit.testing.InMemoryModule;
 | 
			
		||||
import com.google.inject.Guice;
 | 
			
		||||
import com.google.inject.Inject;
 | 
			
		||||
import com.google.inject.Injector;
 | 
			
		||||
import com.google.inject.Provider;
 | 
			
		||||
import com.google.inject.util.Providers;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import org.eclipse.jgit.lib.Repository;
 | 
			
		||||
import org.junit.After;
 | 
			
		||||
import org.junit.Before;
 | 
			
		||||
import org.junit.Test;
 | 
			
		||||
 | 
			
		||||
/** Unit tests for {@link LabelNormalizer}. */
 | 
			
		||||
public class LabelNormalizerTest {
 | 
			
		||||
  @Inject private AccountManager accountManager;
 | 
			
		||||
  @Inject private AllProjectsName allProjects;
 | 
			
		||||
  @Inject private GitRepositoryManager repoManager;
 | 
			
		||||
  @Inject private IdentifiedUser.GenericFactory userFactory;
 | 
			
		||||
  @Inject private InMemoryDatabase schemaFactory;
 | 
			
		||||
  @Inject private LabelNormalizer norm;
 | 
			
		||||
  @Inject private MetaDataUpdate.User metaDataUpdateFactory;
 | 
			
		||||
  @Inject private ProjectCache projectCache;
 | 
			
		||||
  @Inject private SchemaCreator schemaCreator;
 | 
			
		||||
  @Inject protected ThreadLocalRequestContext requestContext;
 | 
			
		||||
  @Inject private ChangeNotes.Factory changeNotesFactory;
 | 
			
		||||
 | 
			
		||||
  private LifecycleManager lifecycle;
 | 
			
		||||
  private ReviewDb db;
 | 
			
		||||
  private Account.Id userId;
 | 
			
		||||
  private IdentifiedUser user;
 | 
			
		||||
  private Change change;
 | 
			
		||||
  private ChangeNotes notes;
 | 
			
		||||
 | 
			
		||||
  @Before
 | 
			
		||||
  public void setUpInjector() throws Exception {
 | 
			
		||||
    Injector injector = Guice.createInjector(new InMemoryModule());
 | 
			
		||||
    injector.injectMembers(this);
 | 
			
		||||
    lifecycle = new LifecycleManager();
 | 
			
		||||
    lifecycle.add(injector);
 | 
			
		||||
    lifecycle.start();
 | 
			
		||||
 | 
			
		||||
    db = schemaFactory.open();
 | 
			
		||||
    schemaCreator.create(db);
 | 
			
		||||
    userId = accountManager.authenticate(AuthRequest.forUser("user")).getAccountId();
 | 
			
		||||
    user = userFactory.create(userId);
 | 
			
		||||
 | 
			
		||||
    requestContext.setContext(
 | 
			
		||||
        new RequestContext() {
 | 
			
		||||
          @Override
 | 
			
		||||
          public CurrentUser getUser() {
 | 
			
		||||
            return user;
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          @Override
 | 
			
		||||
          public Provider<ReviewDb> getReviewDbProvider() {
 | 
			
		||||
            return Providers.of(db);
 | 
			
		||||
          }
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
    configureProject();
 | 
			
		||||
    setUpChange();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private void configureProject() throws Exception {
 | 
			
		||||
    ProjectConfig pc = loadAllProjects();
 | 
			
		||||
    for (AccessSection sec : pc.getAccessSections()) {
 | 
			
		||||
      for (String label : pc.getLabelSections().keySet()) {
 | 
			
		||||
        sec.removePermission(forLabel(label));
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    LabelType lt =
 | 
			
		||||
        category("Verified", value(1, "Verified"), value(0, "No score"), value(-1, "Fails"));
 | 
			
		||||
    pc.getLabelSections().put(lt.getName(), lt);
 | 
			
		||||
    save(pc);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private void setUpChange() throws Exception {
 | 
			
		||||
    change =
 | 
			
		||||
        new Change(
 | 
			
		||||
            new Change.Key("Iabcd1234abcd1234abcd1234abcd1234abcd1234"),
 | 
			
		||||
            new Change.Id(1),
 | 
			
		||||
            userId,
 | 
			
		||||
            new Branch.NameKey(allProjects, "refs/heads/master"),
 | 
			
		||||
            TimeUtil.nowTs());
 | 
			
		||||
    PatchSetInfo ps = new PatchSetInfo(new PatchSet.Id(change.getId(), 1));
 | 
			
		||||
    ps.setSubject("Test change");
 | 
			
		||||
    change.setCurrentPatchSet(ps);
 | 
			
		||||
    db.changes().insert(ImmutableList.of(change));
 | 
			
		||||
    notes = changeNotesFactory.createChecked(db, change);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @After
 | 
			
		||||
  public void tearDown() {
 | 
			
		||||
    if (lifecycle != null) {
 | 
			
		||||
      lifecycle.stop();
 | 
			
		||||
    }
 | 
			
		||||
    requestContext.setContext(null);
 | 
			
		||||
    if (db != null) {
 | 
			
		||||
      db.close();
 | 
			
		||||
    }
 | 
			
		||||
    InMemoryDatabase.drop(schemaFactory);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test
 | 
			
		||||
  public void noNormalizeByPermission() throws Exception {
 | 
			
		||||
    ProjectConfig pc = loadAllProjects();
 | 
			
		||||
    allow(pc, forLabel("Code-Review"), -1, 1, REGISTERED_USERS, "refs/heads/*");
 | 
			
		||||
    allow(pc, forLabel("Verified"), -1, 1, REGISTERED_USERS, "refs/heads/*");
 | 
			
		||||
    save(pc);
 | 
			
		||||
 | 
			
		||||
    PatchSetApproval cr = psa(userId, "Code-Review", 2);
 | 
			
		||||
    PatchSetApproval v = psa(userId, "Verified", 1);
 | 
			
		||||
    assertEquals(Result.create(list(cr, v), list(), list()), norm.normalize(notes, list(cr, v)));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test
 | 
			
		||||
  public void normalizeByType() throws Exception {
 | 
			
		||||
    ProjectConfig pc = loadAllProjects();
 | 
			
		||||
    allow(pc, forLabel("Code-Review"), -5, 5, REGISTERED_USERS, "refs/heads/*");
 | 
			
		||||
    allow(pc, forLabel("Verified"), -5, 5, REGISTERED_USERS, "refs/heads/*");
 | 
			
		||||
    save(pc);
 | 
			
		||||
 | 
			
		||||
    PatchSetApproval cr = psa(userId, "Code-Review", 5);
 | 
			
		||||
    PatchSetApproval v = psa(userId, "Verified", 5);
 | 
			
		||||
    assertEquals(
 | 
			
		||||
        Result.create(list(), list(copy(cr, 2), copy(v, 1)), list()),
 | 
			
		||||
        norm.normalize(notes, list(cr, v)));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test
 | 
			
		||||
  public void emptyPermissionRangeKeepsResult() throws Exception {
 | 
			
		||||
    PatchSetApproval cr = psa(userId, "Code-Review", 1);
 | 
			
		||||
    PatchSetApproval v = psa(userId, "Verified", 1);
 | 
			
		||||
    assertEquals(Result.create(list(cr, v), list(), list()), norm.normalize(notes, list(cr, v)));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test
 | 
			
		||||
  public void explicitZeroVoteOnNonEmptyRangeIsPresent() throws Exception {
 | 
			
		||||
    ProjectConfig pc = loadAllProjects();
 | 
			
		||||
    allow(pc, forLabel("Code-Review"), -1, 1, REGISTERED_USERS, "refs/heads/*");
 | 
			
		||||
    save(pc);
 | 
			
		||||
 | 
			
		||||
    PatchSetApproval cr = psa(userId, "Code-Review", 0);
 | 
			
		||||
    PatchSetApproval v = psa(userId, "Verified", 0);
 | 
			
		||||
    assertEquals(Result.create(list(cr, v), list(), list()), norm.normalize(notes, list(cr, v)));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private ProjectConfig loadAllProjects() throws Exception {
 | 
			
		||||
    try (Repository repo = repoManager.openRepository(allProjects)) {
 | 
			
		||||
      ProjectConfig pc = new ProjectConfig(allProjects);
 | 
			
		||||
      pc.load(repo);
 | 
			
		||||
      return pc;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private void save(ProjectConfig pc) throws Exception {
 | 
			
		||||
    try (MetaDataUpdate md = metaDataUpdateFactory.create(pc.getProject().getNameKey(), user)) {
 | 
			
		||||
      pc.commit(md);
 | 
			
		||||
      projectCache.evict(pc.getProject().getNameKey());
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private PatchSetApproval psa(Account.Id accountId, String label, int value) {
 | 
			
		||||
    return new PatchSetApproval(
 | 
			
		||||
        new PatchSetApproval.Key(change.currentPatchSetId(), accountId, new LabelId(label)),
 | 
			
		||||
        (short) value,
 | 
			
		||||
        TimeUtil.nowTs());
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private PatchSetApproval copy(PatchSetApproval src, int newValue) {
 | 
			
		||||
    PatchSetApproval result = new PatchSetApproval(src.getKey().getParentKey(), src);
 | 
			
		||||
    result.setValue((short) newValue);
 | 
			
		||||
    return result;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private static List<PatchSetApproval> list(PatchSetApproval... psas) {
 | 
			
		||||
    return ImmutableList.<PatchSetApproval>copyOf(psas);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,251 @@
 | 
			
		||||
// 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 static com.google.common.truth.TruthJUnit.assume;
 | 
			
		||||
 | 
			
		||||
import com.google.gerrit.reviewdb.client.Project;
 | 
			
		||||
import com.google.gerrit.server.config.SitePaths;
 | 
			
		||||
import com.google.gerrit.server.util.HostPlatform;
 | 
			
		||||
import com.google.gerrit.testing.TempFileUtil;
 | 
			
		||||
import com.google.gwtorm.client.KeyUtil;
 | 
			
		||||
import com.google.gwtorm.server.StandardKeyEncoder;
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
import java.nio.file.Files;
 | 
			
		||||
import java.nio.file.Path;
 | 
			
		||||
import org.easymock.EasyMockSupport;
 | 
			
		||||
import org.eclipse.jgit.errors.RepositoryNotFoundException;
 | 
			
		||||
import org.eclipse.jgit.lib.Config;
 | 
			
		||||
import org.eclipse.jgit.lib.Constants;
 | 
			
		||||
import org.eclipse.jgit.lib.Repository;
 | 
			
		||||
import org.eclipse.jgit.lib.RepositoryCache;
 | 
			
		||||
import org.eclipse.jgit.lib.RepositoryCache.FileKey;
 | 
			
		||||
import org.eclipse.jgit.util.FS;
 | 
			
		||||
import org.junit.Before;
 | 
			
		||||
import org.junit.Test;
 | 
			
		||||
 | 
			
		||||
public class LocalDiskRepositoryManagerTest extends EasyMockSupport {
 | 
			
		||||
 | 
			
		||||
  static {
 | 
			
		||||
    KeyUtil.setEncoderImpl(new StandardKeyEncoder());
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private Config cfg;
 | 
			
		||||
  private SitePaths site;
 | 
			
		||||
  private LocalDiskRepositoryManager repoManager;
 | 
			
		||||
 | 
			
		||||
  @Before
 | 
			
		||||
  public void setUp() throws Exception {
 | 
			
		||||
    site = new SitePaths(TempFileUtil.createTempDirectory().toPath());
 | 
			
		||||
    site.resolve("git").toFile().mkdir();
 | 
			
		||||
    cfg = new Config();
 | 
			
		||||
    cfg.setString("gerrit", null, "basePath", "git");
 | 
			
		||||
    repoManager = new LocalDiskRepositoryManager(site, cfg);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test(expected = IllegalStateException.class)
 | 
			
		||||
  public void testThatNullBasePathThrowsAnException() {
 | 
			
		||||
    new LocalDiskRepositoryManager(site, new Config());
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test
 | 
			
		||||
  public void projectCreation() throws Exception {
 | 
			
		||||
    Project.NameKey projectA = new Project.NameKey("projectA");
 | 
			
		||||
    try (Repository repo = repoManager.createRepository(projectA)) {
 | 
			
		||||
      assertThat(repo).isNotNull();
 | 
			
		||||
    }
 | 
			
		||||
    try (Repository repo = repoManager.openRepository(projectA)) {
 | 
			
		||||
      assertThat(repo).isNotNull();
 | 
			
		||||
    }
 | 
			
		||||
    assertThat(repoManager.list()).containsExactly(projectA);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test(expected = RepositoryNotFoundException.class)
 | 
			
		||||
  public void testProjectCreationWithEmptyName() throws Exception {
 | 
			
		||||
    repoManager.createRepository(new Project.NameKey(""));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test(expected = RepositoryNotFoundException.class)
 | 
			
		||||
  public void testProjectCreationWithTrailingSlash() throws Exception {
 | 
			
		||||
    repoManager.createRepository(new Project.NameKey("projectA/"));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test(expected = RepositoryNotFoundException.class)
 | 
			
		||||
  public void testProjectCreationWithBackSlash() throws Exception {
 | 
			
		||||
    repoManager.createRepository(new Project.NameKey("a\\projectA"));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test(expected = RepositoryNotFoundException.class)
 | 
			
		||||
  public void testProjectCreationAbsolutePath() throws Exception {
 | 
			
		||||
    repoManager.createRepository(new Project.NameKey("/projectA"));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test(expected = RepositoryNotFoundException.class)
 | 
			
		||||
  public void testProjectCreationStartingWithDotDot() throws Exception {
 | 
			
		||||
    repoManager.createRepository(new Project.NameKey("../projectA"));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test(expected = RepositoryNotFoundException.class)
 | 
			
		||||
  public void testProjectCreationContainsDotDot() throws Exception {
 | 
			
		||||
    repoManager.createRepository(new Project.NameKey("a/../projectA"));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test(expected = RepositoryNotFoundException.class)
 | 
			
		||||
  public void testProjectCreationDotPathSegment() throws Exception {
 | 
			
		||||
    repoManager.createRepository(new Project.NameKey("a/./projectA"));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test(expected = RepositoryNotFoundException.class)
 | 
			
		||||
  public void testProjectCreationWithTwoSlashes() throws Exception {
 | 
			
		||||
    repoManager.createRepository(new Project.NameKey("a//projectA"));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test(expected = RepositoryNotFoundException.class)
 | 
			
		||||
  public void testProjectCreationWithPathSegmentEndingByDotGit() throws Exception {
 | 
			
		||||
    repoManager.createRepository(new Project.NameKey("a/b.git/projectA"));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test(expected = RepositoryNotFoundException.class)
 | 
			
		||||
  public void testProjectCreationWithQuestionMark() throws Exception {
 | 
			
		||||
    repoManager.createRepository(new Project.NameKey("project?A"));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test(expected = RepositoryNotFoundException.class)
 | 
			
		||||
  public void testProjectCreationWithPercentageSign() throws Exception {
 | 
			
		||||
    repoManager.createRepository(new Project.NameKey("project%A"));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test(expected = RepositoryNotFoundException.class)
 | 
			
		||||
  public void testProjectCreationWithWidlcard() throws Exception {
 | 
			
		||||
    repoManager.createRepository(new Project.NameKey("project*A"));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test(expected = RepositoryNotFoundException.class)
 | 
			
		||||
  public void testProjectCreationWithColon() throws Exception {
 | 
			
		||||
    repoManager.createRepository(new Project.NameKey("project:A"));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test(expected = RepositoryNotFoundException.class)
 | 
			
		||||
  public void testProjectCreationWithLessThatSign() throws Exception {
 | 
			
		||||
    repoManager.createRepository(new Project.NameKey("project<A"));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test(expected = RepositoryNotFoundException.class)
 | 
			
		||||
  public void testProjectCreationWithGreaterThatSign() throws Exception {
 | 
			
		||||
    repoManager.createRepository(new Project.NameKey("project>A"));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test(expected = RepositoryNotFoundException.class)
 | 
			
		||||
  public void testProjectCreationWithPipe() throws Exception {
 | 
			
		||||
    repoManager.createRepository(new Project.NameKey("project|A"));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test(expected = RepositoryNotFoundException.class)
 | 
			
		||||
  public void testProjectCreationWithDollarSign() throws Exception {
 | 
			
		||||
    repoManager.createRepository(new Project.NameKey("project$A"));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test(expected = RepositoryNotFoundException.class)
 | 
			
		||||
  public void testProjectCreationWithCarriageReturn() throws Exception {
 | 
			
		||||
    repoManager.createRepository(new Project.NameKey("project\\rA"));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test(expected = IllegalStateException.class)
 | 
			
		||||
  public void testProjectRecreation() throws Exception {
 | 
			
		||||
    repoManager.createRepository(new Project.NameKey("a"));
 | 
			
		||||
    repoManager.createRepository(new Project.NameKey("a"));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test(expected = IllegalStateException.class)
 | 
			
		||||
  public void testProjectRecreationAfterRestart() throws Exception {
 | 
			
		||||
    repoManager.createRepository(new Project.NameKey("a"));
 | 
			
		||||
    LocalDiskRepositoryManager newRepoManager = new LocalDiskRepositoryManager(site, cfg);
 | 
			
		||||
    newRepoManager.createRepository(new Project.NameKey("a"));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test
 | 
			
		||||
  public void openRepositoryCreatedDirectlyOnDisk() throws Exception {
 | 
			
		||||
    Project.NameKey projectA = new Project.NameKey("projectA");
 | 
			
		||||
    createRepository(repoManager.getBasePath(projectA), projectA.get());
 | 
			
		||||
    try (Repository repo = repoManager.openRepository(projectA)) {
 | 
			
		||||
      assertThat(repo).isNotNull();
 | 
			
		||||
    }
 | 
			
		||||
    assertThat(repoManager.list()).containsExactly(projectA);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test(expected = RepositoryCaseMismatchException.class)
 | 
			
		||||
  public void testNameCaseMismatch() throws Exception {
 | 
			
		||||
    assume().that(HostPlatform.isWin32() || HostPlatform.isMac()).isTrue();
 | 
			
		||||
    repoManager.createRepository(new Project.NameKey("a"));
 | 
			
		||||
    repoManager.createRepository(new Project.NameKey("A"));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test(expected = RepositoryCaseMismatchException.class)
 | 
			
		||||
  public void testNameCaseMismatchWithSymlink() throws Exception {
 | 
			
		||||
    assume().that(HostPlatform.isWin32() || HostPlatform.isMac()).isTrue();
 | 
			
		||||
    Project.NameKey name = new Project.NameKey("a");
 | 
			
		||||
    repoManager.createRepository(name);
 | 
			
		||||
    createSymLink(name, "b.git");
 | 
			
		||||
    repoManager.createRepository(new Project.NameKey("B"));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test(expected = RepositoryCaseMismatchException.class)
 | 
			
		||||
  public void testNameCaseMismatchAfterRestart() throws Exception {
 | 
			
		||||
    assume().that(HostPlatform.isWin32() || HostPlatform.isMac()).isTrue();
 | 
			
		||||
    Project.NameKey name = new Project.NameKey("a");
 | 
			
		||||
    repoManager.createRepository(name);
 | 
			
		||||
 | 
			
		||||
    LocalDiskRepositoryManager newRepoManager = new LocalDiskRepositoryManager(site, cfg);
 | 
			
		||||
    newRepoManager.createRepository(new Project.NameKey("A"));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private void createSymLink(Project.NameKey project, String link) throws IOException {
 | 
			
		||||
    Path base = repoManager.getBasePath(project);
 | 
			
		||||
    Path projectDir = base.resolve(project.get() + ".git");
 | 
			
		||||
    Path symlink = base.resolve(link);
 | 
			
		||||
    Files.createSymbolicLink(symlink, projectDir);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test(expected = RepositoryNotFoundException.class)
 | 
			
		||||
  public void testOpenRepositoryInvalidName() throws Exception {
 | 
			
		||||
    repoManager.openRepository(new Project.NameKey("project%?|<>A"));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test
 | 
			
		||||
  public void list() throws Exception {
 | 
			
		||||
    Project.NameKey projectA = new Project.NameKey("projectA");
 | 
			
		||||
    createRepository(repoManager.getBasePath(projectA), projectA.get());
 | 
			
		||||
 | 
			
		||||
    Project.NameKey projectB = new Project.NameKey("path/projectB");
 | 
			
		||||
    createRepository(repoManager.getBasePath(projectB), projectB.get());
 | 
			
		||||
 | 
			
		||||
    Project.NameKey projectC = new Project.NameKey("anotherPath/path/projectC");
 | 
			
		||||
    createRepository(repoManager.getBasePath(projectC), projectC.get());
 | 
			
		||||
    // create an invalid git repo named only .git
 | 
			
		||||
    repoManager.getBasePath(null).resolve(".git").toFile().mkdir();
 | 
			
		||||
    // create an invalid repo name
 | 
			
		||||
    createRepository(repoManager.getBasePath(null), "project?A");
 | 
			
		||||
    assertThat(repoManager.list()).containsExactly(projectA, projectB, projectC);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private void createRepository(Path directory, String projectName) throws IOException {
 | 
			
		||||
    String n = projectName + Constants.DOT_GIT_EXT;
 | 
			
		||||
    FileKey loc = FileKey.exact(directory.resolve(n).toFile(), FS.DETECTED);
 | 
			
		||||
    try (Repository db = RepositoryCache.open(loc, false)) {
 | 
			
		||||
      db.create(true /* bare */);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,164 @@
 | 
			
		||||
// 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 static org.easymock.EasyMock.createNiceMock;
 | 
			
		||||
import static org.easymock.EasyMock.expect;
 | 
			
		||||
import static org.easymock.EasyMock.replay;
 | 
			
		||||
import static org.easymock.EasyMock.reset;
 | 
			
		||||
 | 
			
		||||
import com.google.gerrit.reviewdb.client.Project;
 | 
			
		||||
import com.google.gerrit.server.config.RepositoryConfig;
 | 
			
		||||
import com.google.gerrit.server.config.SitePaths;
 | 
			
		||||
import com.google.gerrit.testing.GerritBaseTests;
 | 
			
		||||
import com.google.gerrit.testing.TempFileUtil;
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
import java.nio.file.Path;
 | 
			
		||||
import java.nio.file.Paths;
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.Arrays;
 | 
			
		||||
import java.util.SortedSet;
 | 
			
		||||
import org.eclipse.jgit.errors.RepositoryNotFoundException;
 | 
			
		||||
import org.eclipse.jgit.lib.Config;
 | 
			
		||||
import org.eclipse.jgit.lib.Constants;
 | 
			
		||||
import org.eclipse.jgit.lib.Repository;
 | 
			
		||||
import org.eclipse.jgit.lib.RepositoryCache;
 | 
			
		||||
import org.eclipse.jgit.lib.RepositoryCache.FileKey;
 | 
			
		||||
import org.eclipse.jgit.util.FS;
 | 
			
		||||
import org.junit.After;
 | 
			
		||||
import org.junit.Before;
 | 
			
		||||
import org.junit.Test;
 | 
			
		||||
 | 
			
		||||
public class MultiBaseLocalDiskRepositoryManagerTest extends GerritBaseTests {
 | 
			
		||||
  private Config cfg;
 | 
			
		||||
  private SitePaths site;
 | 
			
		||||
  private MultiBaseLocalDiskRepositoryManager repoManager;
 | 
			
		||||
  private RepositoryConfig configMock;
 | 
			
		||||
 | 
			
		||||
  @Before
 | 
			
		||||
  public void setUp() throws IOException {
 | 
			
		||||
    site = new SitePaths(TempFileUtil.createTempDirectory().toPath());
 | 
			
		||||
    site.resolve("git").toFile().mkdir();
 | 
			
		||||
    cfg = new Config();
 | 
			
		||||
    cfg.setString("gerrit", null, "basePath", "git");
 | 
			
		||||
    configMock = createNiceMock(RepositoryConfig.class);
 | 
			
		||||
    expect(configMock.getAllBasePaths()).andReturn(new ArrayList<Path>()).anyTimes();
 | 
			
		||||
    replay(configMock);
 | 
			
		||||
    repoManager = new MultiBaseLocalDiskRepositoryManager(site, cfg, configMock);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @After
 | 
			
		||||
  public void tearDown() throws IOException {
 | 
			
		||||
    TempFileUtil.cleanup();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test
 | 
			
		||||
  public void defaultRepositoryLocation()
 | 
			
		||||
      throws RepositoryCaseMismatchException, RepositoryNotFoundException, IOException {
 | 
			
		||||
    Project.NameKey someProjectKey = new Project.NameKey("someProject");
 | 
			
		||||
    Repository repo = repoManager.createRepository(someProjectKey);
 | 
			
		||||
    assertThat(repo.getDirectory()).isNotNull();
 | 
			
		||||
    assertThat(repo.getDirectory().exists()).isTrue();
 | 
			
		||||
    assertThat(repo.getDirectory().getParent())
 | 
			
		||||
        .isEqualTo(repoManager.getBasePath(someProjectKey).toAbsolutePath().toString());
 | 
			
		||||
 | 
			
		||||
    repo = repoManager.openRepository(someProjectKey);
 | 
			
		||||
    assertThat(repo.getDirectory()).isNotNull();
 | 
			
		||||
    assertThat(repo.getDirectory().exists()).isTrue();
 | 
			
		||||
    assertThat(repo.getDirectory().getParent())
 | 
			
		||||
        .isEqualTo(repoManager.getBasePath(someProjectKey).toAbsolutePath().toString());
 | 
			
		||||
 | 
			
		||||
    assertThat(repoManager.getBasePath(someProjectKey).toAbsolutePath().toString())
 | 
			
		||||
        .isEqualTo(repoManager.getBasePath(someProjectKey).toAbsolutePath().toString());
 | 
			
		||||
 | 
			
		||||
    SortedSet<Project.NameKey> repoList = repoManager.list();
 | 
			
		||||
    assertThat(repoList.size()).isEqualTo(1);
 | 
			
		||||
    assertThat(repoList.toArray(new Project.NameKey[repoList.size()]))
 | 
			
		||||
        .isEqualTo(new Project.NameKey[] {someProjectKey});
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test
 | 
			
		||||
  public void alternateRepositoryLocation() throws IOException {
 | 
			
		||||
    Path alternateBasePath = TempFileUtil.createTempDirectory().toPath();
 | 
			
		||||
    Project.NameKey someProjectKey = new Project.NameKey("someProject");
 | 
			
		||||
    reset(configMock);
 | 
			
		||||
    expect(configMock.getBasePath(someProjectKey)).andReturn(alternateBasePath).anyTimes();
 | 
			
		||||
    expect(configMock.getAllBasePaths()).andReturn(Arrays.asList(alternateBasePath)).anyTimes();
 | 
			
		||||
    replay(configMock);
 | 
			
		||||
 | 
			
		||||
    Repository repo = repoManager.createRepository(someProjectKey);
 | 
			
		||||
    assertThat(repo.getDirectory()).isNotNull();
 | 
			
		||||
    assertThat(repo.getDirectory().exists()).isTrue();
 | 
			
		||||
    assertThat(repo.getDirectory().getParent()).isEqualTo(alternateBasePath.toString());
 | 
			
		||||
 | 
			
		||||
    repo = repoManager.openRepository(someProjectKey);
 | 
			
		||||
    assertThat(repo.getDirectory()).isNotNull();
 | 
			
		||||
    assertThat(repo.getDirectory().exists()).isTrue();
 | 
			
		||||
    assertThat(repo.getDirectory().getParent()).isEqualTo(alternateBasePath.toString());
 | 
			
		||||
 | 
			
		||||
    assertThat(repoManager.getBasePath(someProjectKey).toAbsolutePath().toString())
 | 
			
		||||
        .isEqualTo(alternateBasePath.toString());
 | 
			
		||||
 | 
			
		||||
    SortedSet<Project.NameKey> repoList = repoManager.list();
 | 
			
		||||
    assertThat(repoList.size()).isEqualTo(1);
 | 
			
		||||
    assertThat(repoList.toArray(new Project.NameKey[repoList.size()]))
 | 
			
		||||
        .isEqualTo(new Project.NameKey[] {someProjectKey});
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test
 | 
			
		||||
  public void listReturnRepoFromProperLocation() throws IOException {
 | 
			
		||||
    Project.NameKey basePathProject = new Project.NameKey("basePathProject");
 | 
			
		||||
    Project.NameKey altPathProject = new Project.NameKey("altPathProject");
 | 
			
		||||
    Project.NameKey misplacedProject1 = new Project.NameKey("misplacedProject1");
 | 
			
		||||
    Project.NameKey misplacedProject2 = new Project.NameKey("misplacedProject2");
 | 
			
		||||
 | 
			
		||||
    Path alternateBasePath = TempFileUtil.createTempDirectory().toPath();
 | 
			
		||||
 | 
			
		||||
    reset(configMock);
 | 
			
		||||
    expect(configMock.getBasePath(altPathProject)).andReturn(alternateBasePath).anyTimes();
 | 
			
		||||
    expect(configMock.getBasePath(misplacedProject2)).andReturn(alternateBasePath).anyTimes();
 | 
			
		||||
    expect(configMock.getAllBasePaths()).andReturn(Arrays.asList(alternateBasePath)).anyTimes();
 | 
			
		||||
    replay(configMock);
 | 
			
		||||
 | 
			
		||||
    repoManager.createRepository(basePathProject);
 | 
			
		||||
    repoManager.createRepository(altPathProject);
 | 
			
		||||
    // create the misplaced ones without the repomanager otherwise they would
 | 
			
		||||
    // end up at the proper place.
 | 
			
		||||
    createRepository(repoManager.getBasePath(basePathProject), misplacedProject2);
 | 
			
		||||
    createRepository(alternateBasePath, misplacedProject1);
 | 
			
		||||
 | 
			
		||||
    SortedSet<Project.NameKey> repoList = repoManager.list();
 | 
			
		||||
    assertThat(repoList.size()).isEqualTo(2);
 | 
			
		||||
    assertThat(repoList.toArray(new Project.NameKey[repoList.size()]))
 | 
			
		||||
        .isEqualTo(new Project.NameKey[] {altPathProject, basePathProject});
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private void createRepository(Path directory, Project.NameKey projectName) throws IOException {
 | 
			
		||||
    String n = projectName.get() + Constants.DOT_GIT_EXT;
 | 
			
		||||
    FileKey loc = FileKey.exact(directory.resolve(n).toFile(), FS.DETECTED);
 | 
			
		||||
    try (Repository db = RepositoryCache.open(loc, false)) {
 | 
			
		||||
      db.create(true /* bare */);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test(expected = IllegalStateException.class)
 | 
			
		||||
  public void testRelativeAlternateLocation() {
 | 
			
		||||
    configMock = createNiceMock(RepositoryConfig.class);
 | 
			
		||||
    expect(configMock.getAllBasePaths()).andReturn(Arrays.asList(Paths.get("repos"))).anyTimes();
 | 
			
		||||
    replay(configMock);
 | 
			
		||||
    repoManager = new MultiBaseLocalDiskRepositoryManager(site, cfg, configMock);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										526
									
								
								javatests/com/google/gerrit/server/git/ProjectConfigTest.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										526
									
								
								javatests/com/google/gerrit/server/git/ProjectConfigTest.java
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,526 @@
 | 
			
		||||
// Copyright (C) 2011 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 static com.google.common.truth.Truth.assertWithMessage;
 | 
			
		||||
 | 
			
		||||
import com.google.common.collect.Iterables;
 | 
			
		||||
import com.google.gerrit.common.data.AccessSection;
 | 
			
		||||
import com.google.gerrit.common.data.ContributorAgreement;
 | 
			
		||||
import com.google.gerrit.common.data.GroupReference;
 | 
			
		||||
import com.google.gerrit.common.data.LabelType;
 | 
			
		||||
import com.google.gerrit.common.data.Permission;
 | 
			
		||||
import com.google.gerrit.common.data.PermissionRule;
 | 
			
		||||
import com.google.gerrit.reviewdb.client.AccountGroup;
 | 
			
		||||
import com.google.gerrit.reviewdb.client.Project;
 | 
			
		||||
import com.google.gerrit.reviewdb.client.RefNames;
 | 
			
		||||
import com.google.gerrit.server.config.PluginConfig;
 | 
			
		||||
import com.google.gerrit.server.extensions.events.GitReferenceUpdated;
 | 
			
		||||
import com.google.gwtorm.client.KeyUtil;
 | 
			
		||||
import com.google.gwtorm.server.StandardKeyEncoder;
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
import java.util.Arrays;
 | 
			
		||||
import java.util.Collections;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
import org.eclipse.jgit.errors.ConfigInvalidException;
 | 
			
		||||
import org.eclipse.jgit.errors.IncorrectObjectTypeException;
 | 
			
		||||
import org.eclipse.jgit.errors.MissingObjectException;
 | 
			
		||||
import org.eclipse.jgit.junit.LocalDiskRepositoryTestCase;
 | 
			
		||||
import org.eclipse.jgit.junit.TestRepository;
 | 
			
		||||
import org.eclipse.jgit.lib.Ref;
 | 
			
		||||
import org.eclipse.jgit.lib.RefUpdate;
 | 
			
		||||
import org.eclipse.jgit.lib.RefUpdate.Result;
 | 
			
		||||
import org.eclipse.jgit.lib.Repository;
 | 
			
		||||
import org.eclipse.jgit.revwalk.RevCommit;
 | 
			
		||||
import org.eclipse.jgit.revwalk.RevObject;
 | 
			
		||||
import org.eclipse.jgit.util.RawParseUtils;
 | 
			
		||||
import org.junit.Before;
 | 
			
		||||
import org.junit.BeforeClass;
 | 
			
		||||
import org.junit.Test;
 | 
			
		||||
 | 
			
		||||
public class ProjectConfigTest extends LocalDiskRepositoryTestCase {
 | 
			
		||||
  private static final String LABEL_SCORES_CONFIG =
 | 
			
		||||
      "  copyMinScore = "
 | 
			
		||||
          + !LabelType.DEF_COPY_MIN_SCORE
 | 
			
		||||
          + "\n" //
 | 
			
		||||
          + "  copyMaxScore = "
 | 
			
		||||
          + !LabelType.DEF_COPY_MAX_SCORE
 | 
			
		||||
          + "\n" //
 | 
			
		||||
          + "  copyAllScoresOnMergeFirstParentUpdate = "
 | 
			
		||||
          + !LabelType.DEF_COPY_ALL_SCORES_ON_MERGE_FIRST_PARENT_UPDATE
 | 
			
		||||
          + "\n" //
 | 
			
		||||
          + "  copyAllScoresOnTrivialRebase = "
 | 
			
		||||
          + !LabelType.DEF_COPY_ALL_SCORES_ON_TRIVIAL_REBASE
 | 
			
		||||
          + "\n" //
 | 
			
		||||
          + "  copyAllScoresIfNoCodeChange = "
 | 
			
		||||
          + !LabelType.DEF_COPY_ALL_SCORES_IF_NO_CODE_CHANGE
 | 
			
		||||
          + "\n" //
 | 
			
		||||
          + "  copyAllScoresIfNoChange = "
 | 
			
		||||
          + !LabelType.DEF_COPY_ALL_SCORES_IF_NO_CHANGE
 | 
			
		||||
          + "\n";
 | 
			
		||||
 | 
			
		||||
  private final GroupReference developers =
 | 
			
		||||
      new GroupReference(new AccountGroup.UUID("X"), "Developers");
 | 
			
		||||
  private final GroupReference staff = new GroupReference(new AccountGroup.UUID("Y"), "Staff");
 | 
			
		||||
 | 
			
		||||
  private Repository db;
 | 
			
		||||
  private TestRepository<Repository> util;
 | 
			
		||||
 | 
			
		||||
  @BeforeClass
 | 
			
		||||
  public static void setUpOnce() {
 | 
			
		||||
    KeyUtil.setEncoderImpl(new StandardKeyEncoder());
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Override
 | 
			
		||||
  @Before
 | 
			
		||||
  public void setUp() throws Exception {
 | 
			
		||||
    super.setUp();
 | 
			
		||||
    db = createBareRepository();
 | 
			
		||||
    util = new TestRepository<>(db);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test
 | 
			
		||||
  public void readConfig() throws Exception {
 | 
			
		||||
    RevCommit rev =
 | 
			
		||||
        util.commit(
 | 
			
		||||
            util.tree( //
 | 
			
		||||
                util.file("groups", util.blob(group(developers))), //
 | 
			
		||||
                util.file(
 | 
			
		||||
                    "project.config",
 | 
			
		||||
                    util.blob(
 | 
			
		||||
                        "" //
 | 
			
		||||
                            + "[access \"refs/heads/*\"]\n" //
 | 
			
		||||
                            + "  exclusiveGroupPermissions = read submit create\n" //
 | 
			
		||||
                            + "  submit = group Developers\n" //
 | 
			
		||||
                            + "  push = group Developers\n" //
 | 
			
		||||
                            + "  read = group Developers\n" //
 | 
			
		||||
                            + "[accounts]\n" //
 | 
			
		||||
                            + "  sameGroupVisibility = deny group Developers\n" //
 | 
			
		||||
                            + "  sameGroupVisibility = block group Staff\n" //
 | 
			
		||||
                            + "[contributor-agreement \"Individual\"]\n" //
 | 
			
		||||
                            + "  description = A simple description\n" //
 | 
			
		||||
                            + "  accepted = group Developers\n" //
 | 
			
		||||
                            + "  accepted = group Staff\n" //
 | 
			
		||||
                            + "  autoVerify = group Developers\n" //
 | 
			
		||||
                            + "  agreementUrl = http://www.example.com/agree\n")) //
 | 
			
		||||
                ));
 | 
			
		||||
 | 
			
		||||
    ProjectConfig cfg = read(rev);
 | 
			
		||||
    assertThat(cfg.getAccountsSection().getSameGroupVisibility()).hasSize(2);
 | 
			
		||||
    ContributorAgreement ca = cfg.getContributorAgreement("Individual");
 | 
			
		||||
    assertThat(ca.getName()).isEqualTo("Individual");
 | 
			
		||||
    assertThat(ca.getDescription()).isEqualTo("A simple description");
 | 
			
		||||
    assertThat(ca.getAgreementUrl()).isEqualTo("http://www.example.com/agree");
 | 
			
		||||
    assertThat(ca.getAccepted()).hasSize(2);
 | 
			
		||||
    assertThat(ca.getAccepted().get(0).getGroup()).isEqualTo(developers);
 | 
			
		||||
    assertThat(ca.getAccepted().get(1).getGroup().getName()).isEqualTo("Staff");
 | 
			
		||||
    assertThat(ca.getAutoVerify().getName()).isEqualTo("Developers");
 | 
			
		||||
 | 
			
		||||
    AccessSection section = cfg.getAccessSection("refs/heads/*");
 | 
			
		||||
    assertThat(section).isNotNull();
 | 
			
		||||
    assertThat(cfg.getAccessSection("refs/*")).isNull();
 | 
			
		||||
 | 
			
		||||
    Permission create = section.getPermission(Permission.CREATE);
 | 
			
		||||
    Permission submit = section.getPermission(Permission.SUBMIT);
 | 
			
		||||
    Permission read = section.getPermission(Permission.READ);
 | 
			
		||||
    Permission push = section.getPermission(Permission.PUSH);
 | 
			
		||||
 | 
			
		||||
    assertThat(create.getExclusiveGroup()).isTrue();
 | 
			
		||||
    assertThat(submit.getExclusiveGroup()).isTrue();
 | 
			
		||||
    assertThat(read.getExclusiveGroup()).isTrue();
 | 
			
		||||
    assertThat(push.getExclusiveGroup()).isFalse();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test
 | 
			
		||||
  public void readConfigLabelDefaultValue() throws Exception {
 | 
			
		||||
    RevCommit rev =
 | 
			
		||||
        util.commit(
 | 
			
		||||
            util.tree( //
 | 
			
		||||
                util.file("groups", util.blob(group(developers))), //
 | 
			
		||||
                util.file(
 | 
			
		||||
                    "project.config",
 | 
			
		||||
                    util.blob(
 | 
			
		||||
                        "" //
 | 
			
		||||
                            + "[label \"CustomLabel\"]\n" //
 | 
			
		||||
                            + "  value = -1 Negative\n" //
 | 
			
		||||
                            + "  value =  0 No Score\n" //
 | 
			
		||||
                            + "  value =  1 Positive\n")) //
 | 
			
		||||
                ));
 | 
			
		||||
 | 
			
		||||
    ProjectConfig cfg = read(rev);
 | 
			
		||||
    Map<String, LabelType> labels = cfg.getLabelSections();
 | 
			
		||||
    Short dv = labels.entrySet().iterator().next().getValue().getDefaultValue();
 | 
			
		||||
    assertThat((int) dv).isEqualTo(0);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test
 | 
			
		||||
  public void readConfigLabelDefaultValueInRange() throws Exception {
 | 
			
		||||
    RevCommit rev =
 | 
			
		||||
        util.commit(
 | 
			
		||||
            util.tree( //
 | 
			
		||||
                util.file("groups", util.blob(group(developers))), //
 | 
			
		||||
                util.file(
 | 
			
		||||
                    "project.config",
 | 
			
		||||
                    util.blob(
 | 
			
		||||
                        "" //
 | 
			
		||||
                            + "[label \"CustomLabel\"]\n" //
 | 
			
		||||
                            + "  value = -1 Negative\n" //
 | 
			
		||||
                            + "  value =  0 No Score\n" //
 | 
			
		||||
                            + "  value =  1 Positive\n" //
 | 
			
		||||
                            + "  defaultValue = -1\n")) //
 | 
			
		||||
                ));
 | 
			
		||||
 | 
			
		||||
    ProjectConfig cfg = read(rev);
 | 
			
		||||
    Map<String, LabelType> labels = cfg.getLabelSections();
 | 
			
		||||
    Short dv = labels.entrySet().iterator().next().getValue().getDefaultValue();
 | 
			
		||||
    assertThat((int) dv).isEqualTo(-1);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test
 | 
			
		||||
  public void readConfigLabelDefaultValueNotInRange() throws Exception {
 | 
			
		||||
    RevCommit rev =
 | 
			
		||||
        util.commit(
 | 
			
		||||
            util.tree( //
 | 
			
		||||
                util.file("groups", util.blob(group(developers))), //
 | 
			
		||||
                util.file(
 | 
			
		||||
                    "project.config",
 | 
			
		||||
                    util.blob(
 | 
			
		||||
                        "" //
 | 
			
		||||
                            + "[label \"CustomLabel\"]\n" //
 | 
			
		||||
                            + "  value = -1 Negative\n" //
 | 
			
		||||
                            + "  value =  0 No Score\n" //
 | 
			
		||||
                            + "  value =  1 Positive\n" //
 | 
			
		||||
                            + "  defaultValue = -2\n")) //
 | 
			
		||||
                ));
 | 
			
		||||
 | 
			
		||||
    ProjectConfig cfg = read(rev);
 | 
			
		||||
    assertThat(cfg.getValidationErrors()).hasSize(1);
 | 
			
		||||
    assertThat(Iterables.getOnlyElement(cfg.getValidationErrors()).getMessage())
 | 
			
		||||
        .isEqualTo("project.config: Invalid defaultValue \"-2\" for label \"CustomLabel\"");
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test
 | 
			
		||||
  public void readConfigLabelScores() throws Exception {
 | 
			
		||||
    RevCommit rev =
 | 
			
		||||
        util.commit(
 | 
			
		||||
            util.tree( //
 | 
			
		||||
                util.file("groups", util.blob(group(developers))), //
 | 
			
		||||
                util.file(
 | 
			
		||||
                    "project.config",
 | 
			
		||||
                    util.blob(
 | 
			
		||||
                        "" //
 | 
			
		||||
                            + "[label \"CustomLabel\"]\n" //
 | 
			
		||||
                            + LABEL_SCORES_CONFIG)) //
 | 
			
		||||
                ));
 | 
			
		||||
 | 
			
		||||
    ProjectConfig cfg = read(rev);
 | 
			
		||||
    Map<String, LabelType> labels = cfg.getLabelSections();
 | 
			
		||||
    LabelType type = labels.entrySet().iterator().next().getValue();
 | 
			
		||||
    assertThat(type.isCopyMinScore()).isNotEqualTo(LabelType.DEF_COPY_MIN_SCORE);
 | 
			
		||||
    assertThat(type.isCopyMaxScore()).isNotEqualTo(LabelType.DEF_COPY_MAX_SCORE);
 | 
			
		||||
    assertThat(type.isCopyAllScoresOnMergeFirstParentUpdate())
 | 
			
		||||
        .isNotEqualTo(LabelType.DEF_COPY_ALL_SCORES_ON_MERGE_FIRST_PARENT_UPDATE);
 | 
			
		||||
    assertThat(type.isCopyAllScoresOnTrivialRebase())
 | 
			
		||||
        .isNotEqualTo(LabelType.DEF_COPY_ALL_SCORES_ON_TRIVIAL_REBASE);
 | 
			
		||||
    assertThat(type.isCopyAllScoresIfNoCodeChange())
 | 
			
		||||
        .isNotEqualTo(LabelType.DEF_COPY_ALL_SCORES_IF_NO_CODE_CHANGE);
 | 
			
		||||
    assertThat(type.isCopyAllScoresIfNoChange())
 | 
			
		||||
        .isNotEqualTo(LabelType.DEF_COPY_ALL_SCORES_IF_NO_CHANGE);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test
 | 
			
		||||
  public void editConfig() throws Exception {
 | 
			
		||||
    RevCommit rev =
 | 
			
		||||
        util.commit(
 | 
			
		||||
            util.tree( //
 | 
			
		||||
                util.file("groups", util.blob(group(developers))), //
 | 
			
		||||
                util.file(
 | 
			
		||||
                    "project.config",
 | 
			
		||||
                    util.blob(
 | 
			
		||||
                        "" //
 | 
			
		||||
                            + "[access \"refs/heads/*\"]\n" //
 | 
			
		||||
                            + "  exclusiveGroupPermissions = read submit\n" //
 | 
			
		||||
                            + "  submit = group Developers\n" //
 | 
			
		||||
                            + "  upload = group Developers\n" //
 | 
			
		||||
                            + "  read = group Developers\n" //
 | 
			
		||||
                            + "[accounts]\n" //
 | 
			
		||||
                            + "  sameGroupVisibility = deny group Developers\n" //
 | 
			
		||||
                            + "  sameGroupVisibility = block group Staff\n" //
 | 
			
		||||
                            + "[contributor-agreement \"Individual\"]\n" //
 | 
			
		||||
                            + "  description = A simple description\n" //
 | 
			
		||||
                            + "  accepted = group Developers\n" //
 | 
			
		||||
                            + "  autoVerify = group Developers\n" //
 | 
			
		||||
                            + "  agreementUrl = http://www.example.com/agree\n" //
 | 
			
		||||
                            + "[label \"CustomLabel\"]\n" //
 | 
			
		||||
                            + LABEL_SCORES_CONFIG)) //
 | 
			
		||||
                ));
 | 
			
		||||
    update(rev);
 | 
			
		||||
 | 
			
		||||
    ProjectConfig cfg = read(rev);
 | 
			
		||||
    AccessSection section = cfg.getAccessSection("refs/heads/*");
 | 
			
		||||
    cfg.getAccountsSection()
 | 
			
		||||
        .setSameGroupVisibility(Collections.singletonList(new PermissionRule(cfg.resolve(staff))));
 | 
			
		||||
    Permission submit = section.getPermission(Permission.SUBMIT);
 | 
			
		||||
    submit.add(new PermissionRule(cfg.resolve(staff)));
 | 
			
		||||
    ContributorAgreement ca = cfg.getContributorAgreement("Individual");
 | 
			
		||||
    ca.setAccepted(Collections.singletonList(new PermissionRule(cfg.resolve(staff))));
 | 
			
		||||
    ca.setAutoVerify(null);
 | 
			
		||||
    ca.setDescription("A new description");
 | 
			
		||||
    rev = commit(cfg);
 | 
			
		||||
    assertThat(text(rev, "project.config"))
 | 
			
		||||
        .isEqualTo(
 | 
			
		||||
            "" //
 | 
			
		||||
                + "[access \"refs/heads/*\"]\n" //
 | 
			
		||||
                + "  exclusiveGroupPermissions = read submit\n" //
 | 
			
		||||
                + "  submit = group Developers\n" //
 | 
			
		||||
                + "\tsubmit = group Staff\n" //
 | 
			
		||||
                + "  upload = group Developers\n" //
 | 
			
		||||
                + "  read = group Developers\n" //
 | 
			
		||||
                + "[accounts]\n" //
 | 
			
		||||
                + "  sameGroupVisibility = group Staff\n" //
 | 
			
		||||
                + "[contributor-agreement \"Individual\"]\n" //
 | 
			
		||||
                + "  description = A new description\n" //
 | 
			
		||||
                + "  accepted = group Staff\n" //
 | 
			
		||||
                + "  agreementUrl = http://www.example.com/agree\n"
 | 
			
		||||
                + "[label \"CustomLabel\"]\n" //
 | 
			
		||||
                + LABEL_SCORES_CONFIG
 | 
			
		||||
                + "\tfunction = MaxWithBlock\n" // label gets this function when it is created
 | 
			
		||||
                + "\tdefaultValue = 0\n"); //  label gets this value when it is created
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test
 | 
			
		||||
  public void editConfigMissingGroupTableEntry() throws Exception {
 | 
			
		||||
    RevCommit rev =
 | 
			
		||||
        util.commit(
 | 
			
		||||
            util.tree( //
 | 
			
		||||
                util.file("groups", util.blob(group(developers))), //
 | 
			
		||||
                util.file(
 | 
			
		||||
                    "project.config",
 | 
			
		||||
                    util.blob(
 | 
			
		||||
                        "" //
 | 
			
		||||
                            + "[access \"refs/heads/*\"]\n" //
 | 
			
		||||
                            + "  exclusiveGroupPermissions = read submit\n" //
 | 
			
		||||
                            + "  submit = group People Who Can Submit\n" //
 | 
			
		||||
                            + "  upload = group Developers\n" //
 | 
			
		||||
                            + "  read = group Developers\n")) //
 | 
			
		||||
                ));
 | 
			
		||||
    update(rev);
 | 
			
		||||
 | 
			
		||||
    ProjectConfig cfg = read(rev);
 | 
			
		||||
    AccessSection section = cfg.getAccessSection("refs/heads/*");
 | 
			
		||||
    Permission submit = section.getPermission(Permission.SUBMIT);
 | 
			
		||||
    submit.add(new PermissionRule(cfg.resolve(staff)));
 | 
			
		||||
    rev = commit(cfg);
 | 
			
		||||
    assertThat(text(rev, "project.config"))
 | 
			
		||||
        .isEqualTo(
 | 
			
		||||
            "" //
 | 
			
		||||
                + "[access \"refs/heads/*\"]\n" //
 | 
			
		||||
                + "  exclusiveGroupPermissions = read submit\n" //
 | 
			
		||||
                + "  submit = group People Who Can Submit\n" //
 | 
			
		||||
                + "\tsubmit = group Staff\n" //
 | 
			
		||||
                + "  upload = group Developers\n" //
 | 
			
		||||
                + "  read = group Developers\n");
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test
 | 
			
		||||
  public void readExistingPluginConfig() throws Exception {
 | 
			
		||||
    RevCommit rev =
 | 
			
		||||
        util.commit(
 | 
			
		||||
            util.tree( //
 | 
			
		||||
                util.file(
 | 
			
		||||
                    "project.config",
 | 
			
		||||
                    util.blob(
 | 
			
		||||
                        "" //
 | 
			
		||||
                            + "[plugin \"somePlugin\"]\n" //
 | 
			
		||||
                            + "  key1 = value1\n" //
 | 
			
		||||
                            + "  key2 = value2a\n"
 | 
			
		||||
                            + "  key2 = value2b\n")) //
 | 
			
		||||
                ));
 | 
			
		||||
    update(rev);
 | 
			
		||||
 | 
			
		||||
    ProjectConfig cfg = read(rev);
 | 
			
		||||
    PluginConfig pluginCfg = cfg.getPluginConfig("somePlugin");
 | 
			
		||||
    assertThat(pluginCfg.getNames().size()).isEqualTo(2);
 | 
			
		||||
    assertThat(pluginCfg.getString("key1")).isEqualTo("value1");
 | 
			
		||||
    assertThat(pluginCfg.getStringList(("key2"))).isEqualTo(new String[] {"value2a", "value2b"});
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test
 | 
			
		||||
  public void readUnexistingPluginConfig() throws Exception {
 | 
			
		||||
    ProjectConfig cfg = new ProjectConfig(new Project.NameKey("test"));
 | 
			
		||||
    cfg.load(db);
 | 
			
		||||
    PluginConfig pluginCfg = cfg.getPluginConfig("somePlugin");
 | 
			
		||||
    assertThat(pluginCfg.getNames()).isEmpty();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test
 | 
			
		||||
  public void editPluginConfig() throws Exception {
 | 
			
		||||
    RevCommit rev =
 | 
			
		||||
        util.commit(
 | 
			
		||||
            util.tree( //
 | 
			
		||||
                util.file(
 | 
			
		||||
                    "project.config",
 | 
			
		||||
                    util.blob(
 | 
			
		||||
                        "" //
 | 
			
		||||
                            + "[plugin \"somePlugin\"]\n" //
 | 
			
		||||
                            + "  key1 = value1\n" //
 | 
			
		||||
                            + "  key2 = value2a\n" //
 | 
			
		||||
                            + "  key2 = value2b\n")) //
 | 
			
		||||
                ));
 | 
			
		||||
    update(rev);
 | 
			
		||||
 | 
			
		||||
    ProjectConfig cfg = read(rev);
 | 
			
		||||
    PluginConfig pluginCfg = cfg.getPluginConfig("somePlugin");
 | 
			
		||||
    pluginCfg.setString("key1", "updatedValue1");
 | 
			
		||||
    pluginCfg.setStringList("key2", Arrays.asList("updatedValue2a", "updatedValue2b"));
 | 
			
		||||
    rev = commit(cfg);
 | 
			
		||||
    assertThat(text(rev, "project.config"))
 | 
			
		||||
        .isEqualTo(
 | 
			
		||||
            "" //
 | 
			
		||||
                + "[plugin \"somePlugin\"]\n" //
 | 
			
		||||
                + "\tkey1 = updatedValue1\n" //
 | 
			
		||||
                + "\tkey2 = updatedValue2a\n" //
 | 
			
		||||
                + "\tkey2 = updatedValue2b\n");
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test
 | 
			
		||||
  public void readPluginConfigGroupReference() throws Exception {
 | 
			
		||||
    RevCommit rev =
 | 
			
		||||
        util.commit(
 | 
			
		||||
            util.tree( //
 | 
			
		||||
                util.file("groups", util.blob(group(developers))), //
 | 
			
		||||
                util.file(
 | 
			
		||||
                    "project.config",
 | 
			
		||||
                    util.blob(
 | 
			
		||||
                        "" //
 | 
			
		||||
                            + "[plugin \"somePlugin\"]\n" //
 | 
			
		||||
                            + "key1 = "
 | 
			
		||||
                            + developers.toConfigValue()
 | 
			
		||||
                            + "\n")) //
 | 
			
		||||
                ));
 | 
			
		||||
    update(rev);
 | 
			
		||||
 | 
			
		||||
    ProjectConfig cfg = read(rev);
 | 
			
		||||
    PluginConfig pluginCfg = cfg.getPluginConfig("somePlugin");
 | 
			
		||||
    assertThat(pluginCfg.getNames().size()).isEqualTo(1);
 | 
			
		||||
    assertThat(pluginCfg.getGroupReference("key1")).isEqualTo(developers);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test
 | 
			
		||||
  public void readPluginConfigGroupReferenceNotInGroupsFile() throws Exception {
 | 
			
		||||
    RevCommit rev =
 | 
			
		||||
        util.commit(
 | 
			
		||||
            util.tree( //
 | 
			
		||||
                util.file("groups", util.blob(group(developers))), //
 | 
			
		||||
                util.file(
 | 
			
		||||
                    "project.config",
 | 
			
		||||
                    util.blob(
 | 
			
		||||
                        "" //
 | 
			
		||||
                            + "[plugin \"somePlugin\"]\n" //
 | 
			
		||||
                            + "key1 = "
 | 
			
		||||
                            + staff.toConfigValue()
 | 
			
		||||
                            + "\n")) //
 | 
			
		||||
                ));
 | 
			
		||||
    update(rev);
 | 
			
		||||
 | 
			
		||||
    ProjectConfig cfg = read(rev);
 | 
			
		||||
    assertThat(cfg.getValidationErrors()).hasSize(1);
 | 
			
		||||
    assertThat(Iterables.getOnlyElement(cfg.getValidationErrors()).getMessage())
 | 
			
		||||
        .isEqualTo(
 | 
			
		||||
            "project.config: group \"" + staff.getName() + "\" not in " + GroupList.FILE_NAME);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test
 | 
			
		||||
  public void editPluginConfigGroupReference() throws Exception {
 | 
			
		||||
    RevCommit rev =
 | 
			
		||||
        util.commit(
 | 
			
		||||
            util.tree( //
 | 
			
		||||
                util.file("groups", util.blob(group(developers))), //
 | 
			
		||||
                util.file(
 | 
			
		||||
                    "project.config",
 | 
			
		||||
                    util.blob(
 | 
			
		||||
                        "" //
 | 
			
		||||
                            + "[plugin \"somePlugin\"]\n" //
 | 
			
		||||
                            + "key1 = "
 | 
			
		||||
                            + developers.toConfigValue()
 | 
			
		||||
                            + "\n")) //
 | 
			
		||||
                ));
 | 
			
		||||
    update(rev);
 | 
			
		||||
 | 
			
		||||
    ProjectConfig cfg = read(rev);
 | 
			
		||||
    PluginConfig pluginCfg = cfg.getPluginConfig("somePlugin");
 | 
			
		||||
    assertThat(pluginCfg.getNames().size()).isEqualTo(1);
 | 
			
		||||
    assertThat(pluginCfg.getGroupReference("key1")).isEqualTo(developers);
 | 
			
		||||
 | 
			
		||||
    pluginCfg.setGroupReference("key1", staff);
 | 
			
		||||
    rev = commit(cfg);
 | 
			
		||||
    assertThat(text(rev, "project.config"))
 | 
			
		||||
        .isEqualTo(
 | 
			
		||||
            "" //
 | 
			
		||||
                + "[plugin \"somePlugin\"]\n" //
 | 
			
		||||
                + "\tkey1 = "
 | 
			
		||||
                + staff.toConfigValue()
 | 
			
		||||
                + "\n");
 | 
			
		||||
    assertThat(text(rev, "groups"))
 | 
			
		||||
        .isEqualTo(
 | 
			
		||||
            "# UUID\tGroup Name\n" //
 | 
			
		||||
                + "#\n" //
 | 
			
		||||
                + staff.getUUID().get()
 | 
			
		||||
                + "     \t"
 | 
			
		||||
                + staff.getName()
 | 
			
		||||
                + "\n");
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private ProjectConfig read(RevCommit rev) throws IOException, ConfigInvalidException {
 | 
			
		||||
    ProjectConfig cfg = new ProjectConfig(new Project.NameKey("test"));
 | 
			
		||||
    cfg.load(db, rev);
 | 
			
		||||
    return cfg;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private RevCommit commit(ProjectConfig cfg)
 | 
			
		||||
      throws IOException, MissingObjectException, IncorrectObjectTypeException {
 | 
			
		||||
    try (MetaDataUpdate md =
 | 
			
		||||
        new MetaDataUpdate(GitReferenceUpdated.DISABLED, cfg.getProject().getNameKey(), db)) {
 | 
			
		||||
      util.tick(5);
 | 
			
		||||
      util.setAuthorAndCommitter(md.getCommitBuilder());
 | 
			
		||||
      md.setMessage("Edit\n");
 | 
			
		||||
      cfg.commit(md);
 | 
			
		||||
 | 
			
		||||
      Ref ref = db.exactRef(RefNames.REFS_CONFIG);
 | 
			
		||||
      return util.getRevWalk().parseCommit(ref.getObjectId());
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private void update(RevCommit rev) throws Exception {
 | 
			
		||||
    RefUpdate u = db.updateRef(RefNames.REFS_CONFIG);
 | 
			
		||||
    u.disableRefLog();
 | 
			
		||||
    u.setNewObjectId(rev);
 | 
			
		||||
    Result result = u.forceUpdate();
 | 
			
		||||
    assertWithMessage("Cannot update ref for test: " + result)
 | 
			
		||||
        .that(result)
 | 
			
		||||
        .isAnyOf(Result.FAST_FORWARD, Result.FORCED, Result.NEW, Result.NO_CHANGE);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private String text(RevCommit rev, String path) throws Exception {
 | 
			
		||||
    RevObject blob = util.get(rev.getTree(), path);
 | 
			
		||||
    byte[] data = db.open(blob).getCachedBytes(Integer.MAX_VALUE);
 | 
			
		||||
    return RawParseUtils.decode(data);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private static String group(GroupReference g) {
 | 
			
		||||
    return g.getUUID().get() + "\t" + g.getName() + "\n";
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										119
									
								
								javatests/com/google/gerrit/server/git/QueryListTest.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										119
									
								
								javatests/com/google/gerrit/server/git/QueryListTest.java
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,119 @@
 | 
			
		||||
// 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 static org.easymock.EasyMock.createNiceMock;
 | 
			
		||||
import static org.easymock.EasyMock.replay;
 | 
			
		||||
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
import junit.framework.TestCase;
 | 
			
		||||
import org.junit.Test;
 | 
			
		||||
 | 
			
		||||
public class QueryListTest extends TestCase {
 | 
			
		||||
  public static final String Q_P = "project:foo";
 | 
			
		||||
  public static final String Q_B = "branch:bar";
 | 
			
		||||
  public static final String Q_COMPLEX = "branch:bar AND peers:'is:open\t'";
 | 
			
		||||
 | 
			
		||||
  public static final String N_FOO = "foo";
 | 
			
		||||
  public static final String N_BAR = "bar";
 | 
			
		||||
 | 
			
		||||
  public static final String L_FOO = N_FOO + "\t" + Q_P + "\n";
 | 
			
		||||
  public static final String L_BAR = N_BAR + "\t" + Q_B + "\n";
 | 
			
		||||
  public static final String L_FOO_PROP = N_FOO + "   \t" + Q_P + "\n";
 | 
			
		||||
  public static final String L_BAR_PROP = N_BAR + "   \t" + Q_B + "\n";
 | 
			
		||||
  public static final String L_FOO_PAD_F = " " + N_FOO + "\t" + Q_P + "\n";
 | 
			
		||||
  public static final String L_FOO_PAD_E = N_FOO + " \t" + Q_P + "\n";
 | 
			
		||||
  public static final String L_BAR_PAD_F = N_BAR + "\t " + Q_B + "\n";
 | 
			
		||||
  public static final String L_BAR_PAD_E = N_BAR + "\t" + Q_B + " \n";
 | 
			
		||||
  public static final String L_COMPLEX = N_FOO + "\t" + Q_COMPLEX + "\t \n";
 | 
			
		||||
  public static final String L_BAD = N_FOO + "\n";
 | 
			
		||||
 | 
			
		||||
  public static final String HEADER = "# Name\tQuery\n";
 | 
			
		||||
  public static final String C1 = "# A Simple Comment\n";
 | 
			
		||||
  public static final String C2 = "# Comment with a tab\t and multi # # #\n";
 | 
			
		||||
 | 
			
		||||
  public static final String F_SIMPLE = L_FOO + L_BAR;
 | 
			
		||||
  public static final String F_PROPER = L_BAR_PROP + L_FOO_PROP; // alpha order
 | 
			
		||||
  public static final String F_PAD_F = L_FOO_PAD_F + L_BAR_PAD_F;
 | 
			
		||||
  public static final String F_PAD_E = L_FOO_PAD_E + L_BAR_PAD_E;
 | 
			
		||||
 | 
			
		||||
  @Test
 | 
			
		||||
  public void testParseSimple() throws Exception {
 | 
			
		||||
    QueryList ql = QueryList.parse(F_SIMPLE, null);
 | 
			
		||||
    assertThat(ql.getQuery(N_FOO)).isEqualTo(Q_P);
 | 
			
		||||
    assertThat(ql.getQuery(N_BAR)).isEqualTo(Q_B);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test
 | 
			
		||||
  public void testParseWHeader() throws Exception {
 | 
			
		||||
    QueryList ql = QueryList.parse(HEADER + F_SIMPLE, null);
 | 
			
		||||
    assertThat(ql.getQuery(N_FOO)).isEqualTo(Q_P);
 | 
			
		||||
    assertThat(ql.getQuery(N_BAR)).isEqualTo(Q_B);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test
 | 
			
		||||
  public void testParseWComments() throws Exception {
 | 
			
		||||
    QueryList ql = QueryList.parse(C1 + F_SIMPLE + C2, null);
 | 
			
		||||
    assertThat(ql.getQuery(N_FOO)).isEqualTo(Q_P);
 | 
			
		||||
    assertThat(ql.getQuery(N_BAR)).isEqualTo(Q_B);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test
 | 
			
		||||
  public void testParseFooComment() throws Exception {
 | 
			
		||||
    QueryList ql = QueryList.parse("#" + L_FOO + L_BAR, null);
 | 
			
		||||
    assertThat(ql.getQuery(N_FOO)).isNull();
 | 
			
		||||
    assertThat(ql.getQuery(N_BAR)).isEqualTo(Q_B);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test
 | 
			
		||||
  public void testParsePaddedFronts() throws Exception {
 | 
			
		||||
    QueryList ql = QueryList.parse(F_PAD_F, null);
 | 
			
		||||
    assertThat(ql.getQuery(N_FOO)).isEqualTo(Q_P);
 | 
			
		||||
    assertThat(ql.getQuery(N_BAR)).isEqualTo(Q_B);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test
 | 
			
		||||
  public void testParsePaddedEnds() throws Exception {
 | 
			
		||||
    QueryList ql = QueryList.parse(F_PAD_E, null);
 | 
			
		||||
    assertThat(ql.getQuery(N_FOO)).isEqualTo(Q_P);
 | 
			
		||||
    assertThat(ql.getQuery(N_BAR)).isEqualTo(Q_B);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test
 | 
			
		||||
  public void testParseComplex() throws Exception {
 | 
			
		||||
    QueryList ql = QueryList.parse(L_COMPLEX, null);
 | 
			
		||||
    assertThat(ql.getQuery(N_FOO)).isEqualTo(Q_COMPLEX);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test(expected = IOException.class)
 | 
			
		||||
  public void testParseBad() throws Exception {
 | 
			
		||||
    ValidationError.Sink sink = createNiceMock(ValidationError.Sink.class);
 | 
			
		||||
    replay(sink);
 | 
			
		||||
    QueryList.parse(L_BAD, sink);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test
 | 
			
		||||
  public void testAsText() throws Exception {
 | 
			
		||||
    String expectedText = HEADER + "#\n" + F_PROPER;
 | 
			
		||||
    QueryList ql = QueryList.parse(F_SIMPLE, null);
 | 
			
		||||
    String asText = ql.asText();
 | 
			
		||||
    assertThat(asText).isEqualTo(expectedText);
 | 
			
		||||
 | 
			
		||||
    ql = QueryList.parse(asText, null);
 | 
			
		||||
    asText = ql.asText();
 | 
			
		||||
    assertThat(asText).isEqualTo(expectedText);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user