blob: 7543ba808ac79794ba704af68c8f785779bf2711 [file] [log] [blame]
// Copyright (C) 2018 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.acceptance.testsuite.project;
import static com.google.common.truth.Truth.assertThat;
import static com.google.gerrit.acceptance.testsuite.project.TestProjectUpdate.allow;
import static com.google.gerrit.acceptance.testsuite.project.TestProjectUpdate.allowCapability;
import static com.google.gerrit.acceptance.testsuite.project.TestProjectUpdate.allowLabel;
import static com.google.gerrit.acceptance.testsuite.project.TestProjectUpdate.block;
import static com.google.gerrit.acceptance.testsuite.project.TestProjectUpdate.blockLabel;
import static com.google.gerrit.acceptance.testsuite.project.TestProjectUpdate.capabilityKey;
import static com.google.gerrit.acceptance.testsuite.project.TestProjectUpdate.deny;
import static com.google.gerrit.acceptance.testsuite.project.TestProjectUpdate.labelPermissionKey;
import static com.google.gerrit.acceptance.testsuite.project.TestProjectUpdate.permissionKey;
import static com.google.gerrit.common.data.GlobalCapability.ADMINISTRATE_SERVER;
import static com.google.gerrit.common.data.GlobalCapability.DEFAULT_MAX_QUERY_LIMIT;
import static com.google.gerrit.common.data.GlobalCapability.QUERY_LIMIT;
import static com.google.gerrit.entities.RefNames.REFS_CONFIG;
import static com.google.gerrit.server.group.SystemGroupBackend.PROJECT_OWNERS;
import static com.google.gerrit.server.group.SystemGroupBackend.REGISTERED_USERS;
import static com.google.gerrit.testing.GerritJUnit.assertThrows;
import static com.google.gerrit.truth.ConfigSubject.assertThat;
import static java.util.stream.Collectors.toList;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableListMultimap;
import com.google.common.truth.Correspondence;
import com.google.gerrit.acceptance.AbstractDaemonTest;
import com.google.gerrit.acceptance.testsuite.group.GroupOperations;
import com.google.gerrit.acceptance.testsuite.project.TestProjectUpdate.TestPermission;
import com.google.gerrit.entities.AccountGroup;
import com.google.gerrit.entities.Permission;
import com.google.gerrit.entities.Project;
import com.google.gerrit.entities.RefNames;
import com.google.gerrit.extensions.api.projects.BranchInfo;
import com.google.gerrit.extensions.api.projects.ConfigInput;
import com.google.gerrit.server.project.ProjectConfig;
import com.google.gerrit.truth.NullAwareCorrespondence;
import com.google.inject.Inject;
import java.util.List;
import org.eclipse.jgit.junit.TestRepository;
import org.eclipse.jgit.lib.Config;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.lib.StoredConfig;
import org.junit.Test;
public class ProjectOperationsImplTest extends AbstractDaemonTest {
@Inject private ProjectOperations projectOperations;
@Inject private GroupOperations groupsOperations;
@Test
public void defaultName() throws Exception {
Project.NameKey name = projectOperations.newProject().create();
// check that the project was created (throws exception if not found.)
gApi.projects().name(name.get());
Project.NameKey name2 = projectOperations.newProject().create();
assertThat(name2).isNotEqualTo(name);
}
@Test
public void specifiedName() throws Exception {
String name = "somename";
Project.NameKey key = projectOperations.newProject().name(name).create();
assertThat(key.get()).isEqualTo(name);
}
@Test
public void emptyCommit() throws Exception {
Project.NameKey key = projectOperations.newProject().create();
List<BranchInfo> branches = gApi.projects().name(key.get()).branches().get();
assertThat(branches).isNotEmpty();
assertThat(branches.stream().map(x -> x.ref).collect(toList()))
.isEqualTo(ImmutableList.of("HEAD", "refs/meta/config", "refs/heads/master"));
}
@Test
public void specifiedBranchesAreCreatedInNewProject() throws Exception {
Project.NameKey project =
projectOperations
.newProject()
.branches("test-branch", "refs/heads/another-test-branch")
.create();
List<BranchInfo> branches = gApi.projects().name(project.get()).branches().get();
assertThat(branches)
.comparingElementsUsing(hasBranchName())
.containsAtLeast("refs/heads/test-branch", "refs/heads/another-test-branch");
}
@Test
public void specifiedBranchesAreNotCreatedInNewProjectIfNoEmptyCommitRequested()
throws Exception {
Project.NameKey project =
projectOperations
.newProject()
.branches("test-branch", "refs/heads/another-test-branch")
.noEmptyCommit()
.create();
List<BranchInfo> branches = gApi.projects().name(project.get()).branches().get();
assertThat(branches)
.comparingElementsUsing(hasBranchName())
.containsNoneOf("refs/heads/test-branch", "refs/heads/another-test-branch");
}
@Test
public void permissionOnly() throws Exception {
Project.NameKey key = projectOperations.newProject().permissionOnly(true).create();
String head = gApi.projects().name(key.get()).head();
assertThat(head).isEqualTo(RefNames.REFS_CONFIG);
}
@Test
public void createWithOwners() throws Exception {
AccountGroup.UUID uuid = groupsOperations.newGroup().create();
Project.NameKey key = projectOperations.newProject().addOwner(uuid).create();
assertPermissions(key, groupRef(uuid), "refs/*", false, Permission.OWNER);
}
@Test
public void getProjectConfig() throws Exception {
Project.NameKey key = projectOperations.newProject().create();
assertThat(projectOperations.project(key).getProjectConfig().getProject().getDescription())
.isEmpty();
ConfigInput input = new ConfigInput();
input.description = "my fancy project";
gApi.projects().name(key.get()).config(input);
assertThat(projectOperations.project(key).getProjectConfig().getProject().getDescription())
.isEqualTo("my fancy project");
}
@Test
public void getProjectConfigNoRefsMetaConfig() throws Exception {
Project.NameKey key = projectOperations.newProject().create();
deleteRefsMetaConfig(key);
ProjectConfig projectConfig = projectOperations.project(key).getProjectConfig();
assertThat(projectConfig.getName()).isEqualTo(key);
assertThat(projectConfig.getRevision()).isNull();
}
@Test
public void getConfig() throws Exception {
Project.NameKey key = projectOperations.newProject().create();
Config config = projectOperations.project(key).getConfig();
assertThat(config).isNotInstanceOf(StoredConfig.class);
assertThat(config).text().isEmpty();
ConfigInput input = new ConfigInput();
input.description = "my fancy project";
gApi.projects().name(key.get()).config(input);
config = projectOperations.project(key).getConfig();
assertThat(config).isNotInstanceOf(StoredConfig.class);
assertThat(config).sections().containsExactly("project");
assertThat(config).subsections("project").isEmpty();
assertThat(config).sectionValues("project").containsExactly("description", "my fancy project");
}
@Test
public void getConfigNoRefsMetaConfig() throws Exception {
Project.NameKey key = projectOperations.newProject().create();
deleteRefsMetaConfig(key);
Config config = projectOperations.project(key).getConfig();
assertThat(config).isNotInstanceOf(StoredConfig.class);
assertThat(config).isEmpty();
}
@Test
public void addAllowPermission() throws Exception {
Project.NameKey key = projectOperations.newProject().create();
projectOperations
.project(key)
.forUpdate()
.add(allow(Permission.ABANDON).ref("refs/foo").group(REGISTERED_USERS))
.update();
Config config = projectOperations.project(key).getConfig();
assertThat(config).sections().containsExactly("access");
assertThat(config).subsections("access").containsExactly("refs/foo");
assertThat(config)
.subsectionValues("access", "refs/foo")
.containsExactly("abandon", "group global:Registered-Users");
}
@Test
public void addDenyPermission() throws Exception {
Project.NameKey key = projectOperations.newProject().create();
projectOperations
.project(key)
.forUpdate()
.add(deny(Permission.ABANDON).ref("refs/foo").group(REGISTERED_USERS))
.update();
Config config = projectOperations.project(key).getConfig();
assertThat(config).sections().containsExactly("access");
assertThat(config).subsections("access").containsExactly("refs/foo");
assertThat(config)
.subsectionValues("access", "refs/foo")
.containsExactly("abandon", "deny group global:Registered-Users");
}
@Test
public void addBlockPermission() throws Exception {
Project.NameKey key = projectOperations.newProject().create();
projectOperations
.project(key)
.forUpdate()
.add(block(Permission.ABANDON).ref("refs/foo").group(REGISTERED_USERS))
.update();
Config config = projectOperations.project(key).getConfig();
assertThat(config).sections().containsExactly("access");
assertThat(config).subsections("access").containsExactly("refs/foo");
assertThat(config)
.subsectionValues("access", "refs/foo")
.containsExactly("abandon", "block group global:Registered-Users");
}
@Test
public void addAllowForcePermission() throws Exception {
Project.NameKey key = projectOperations.newProject().create();
projectOperations
.project(key)
.forUpdate()
.add(allow(Permission.ABANDON).ref("refs/foo").group(REGISTERED_USERS).force(true))
.update();
Config config = projectOperations.project(key).getConfig();
assertThat(config).sections().containsExactly("access");
assertThat(config).subsections("access").containsExactly("refs/foo");
assertThat(config)
.subsectionValues("access", "refs/foo")
.containsExactly("abandon", "+force group global:Registered-Users");
}
@Test
public void updateExclusivePermission() throws Exception {
Project.NameKey key = projectOperations.newProject().create();
projectOperations
.project(key)
.forUpdate()
.add(allow(Permission.ABANDON).ref("refs/foo").group(REGISTERED_USERS))
.setExclusiveGroup(permissionKey(Permission.ABANDON).ref("refs/foo"), true)
.update();
Config config = projectOperations.project(key).getConfig();
assertThat(config).sections().containsExactly("access");
assertThat(config).subsections("access").containsExactly("refs/foo");
assertThat(config)
.subsectionValues("access", "refs/foo")
.containsExactly(
"abandon", "group global:Registered-Users",
"exclusiveGroupPermissions", "abandon");
projectOperations
.project(key)
.forUpdate()
.setExclusiveGroup(permissionKey(Permission.ABANDON).ref("refs/foo"), false)
.update();
config = projectOperations.project(key).getConfig();
assertThat(config).sections().containsExactly("access");
assertThat(config).subsections("access").containsExactly("refs/foo");
assertThat(config)
.subsectionValues("access", "refs/foo")
.containsExactly("abandon", "group global:Registered-Users");
}
@Test
public void addMultipleExclusivePermission() throws Exception {
Project.NameKey key = projectOperations.newProject().create();
projectOperations
.project(key)
.forUpdate()
.setExclusiveGroup(permissionKey(Permission.ABANDON).ref("refs/foo"), true)
.setExclusiveGroup(permissionKey(Permission.CREATE).ref("refs/foo"), true)
.update();
assertThat(projectOperations.project(key).getConfig())
.subsectionValues("access", "refs/foo")
.containsEntry("exclusiveGroupPermissions", "abandon create");
projectOperations
.project(key)
.forUpdate()
.setExclusiveGroup(permissionKey(Permission.ABANDON).ref("refs/foo"), false)
.update();
assertThat(projectOperations.project(key).getConfig())
.subsectionValues("access", "refs/foo")
.containsEntry("exclusiveGroupPermissions", "create");
}
@Test
public void addMultiplePermissions() throws Exception {
Project.NameKey key = projectOperations.newProject().create();
projectOperations
.project(key)
.forUpdate()
.add(allow(Permission.ABANDON).ref("refs/foo").group(PROJECT_OWNERS))
.add(allow(Permission.CREATE).ref("refs/foo").group(REGISTERED_USERS))
.update();
Config config = projectOperations.project(key).getConfig();
assertThat(config).sections().containsExactly("access");
assertThat(config).subsections("access").containsExactly("refs/foo");
assertThat(config)
.subsectionValues("access", "refs/foo")
.containsExactly(
"abandon", "group global:Project-Owners",
"create", "group global:Registered-Users");
}
@Test
public void addDuplicatePermissions() throws Exception {
TestPermission permission =
TestProjectUpdate.allow(Permission.ABANDON).ref("refs/foo").group(REGISTERED_USERS).build();
Project.NameKey key = projectOperations.newProject().create();
projectOperations.project(key).forUpdate().add(permission).add(permission).update();
Config config = projectOperations.project(key).getConfig();
assertThat(config).sections().containsExactly("access");
assertThat(config).subsections("access").containsExactly("refs/foo");
assertThat(config)
.subsectionValues("access", "refs/foo")
.containsExactly(
"abandon", "group global:Registered-Users",
"abandon", "group global:Registered-Users");
projectOperations.project(key).forUpdate().add(permission).update();
config = projectOperations.project(key).getConfig();
assertThat(config).sections().containsExactly("access");
assertThat(config).subsections("access").containsExactly("refs/foo");
assertThat(config)
.subsectionValues("access", "refs/foo")
.containsExactly(
"abandon", "group global:Registered-Users",
"abandon", "group global:Registered-Users",
"abandon", "group global:Registered-Users");
}
@Test
public void addAllowLabelPermission() throws Exception {
Project.NameKey key = projectOperations.newProject().create();
projectOperations
.project(key)
.forUpdate()
.add(allowLabel("Code-Review").ref("refs/foo").group(REGISTERED_USERS).range(-1, 2))
.update();
Config config = projectOperations.project(key).getConfig();
assertThat(config).sections().containsExactly("access");
assertThat(config).subsections("access").containsExactly("refs/foo");
assertThat(config)
.subsectionValues("access", "refs/foo")
.containsExactly("label-Code-Review", "-1..+2 group global:Registered-Users");
}
@Test
public void addBlockLabelPermission() throws Exception {
Project.NameKey key = projectOperations.newProject().create();
projectOperations
.project(key)
.forUpdate()
.add(blockLabel("Code-Review").ref("refs/foo").group(REGISTERED_USERS).range(-1, 2))
.update();
Config config = projectOperations.project(key).getConfig();
assertThat(config).sections().containsExactly("access");
assertThat(config).subsections("access").containsExactly("refs/foo");
assertThat(config)
.subsectionValues("access", "refs/foo")
.containsExactly("label-Code-Review", "block -1..+2 group global:Registered-Users");
}
@Test
public void addAllowExclusiveLabelPermission() throws Exception {
Project.NameKey key = projectOperations.newProject().create();
projectOperations
.project(key)
.forUpdate()
.add(allowLabel("Code-Review").ref("refs/foo").group(REGISTERED_USERS).range(-1, 2))
.setExclusiveGroup(labelPermissionKey("Code-Review").ref("refs/foo"), true)
.update();
Config config = projectOperations.project(key).getConfig();
assertThat(config).sections().containsExactly("access");
assertThat(config).subsections("access").containsExactly("refs/foo");
assertThat(config)
.subsectionValues("access", "refs/foo")
.containsExactly(
"label-Code-Review", "-1..+2 group global:Registered-Users",
"exclusiveGroupPermissions", "label-Code-Review");
projectOperations
.project(key)
.forUpdate()
.setExclusiveGroup(labelPermissionKey("Code-Review").ref("refs/foo"), false)
.update();
config = projectOperations.project(key).getConfig();
assertThat(config).sections().containsExactly("access");
assertThat(config).subsections("access").containsExactly("refs/foo");
assertThat(config)
.subsectionValues("access", "refs/foo")
.containsExactly("label-Code-Review", "-1..+2 group global:Registered-Users");
}
@Test
public void addAllowLabelAsPermission() throws Exception {
Project.NameKey key = projectOperations.newProject().create();
projectOperations
.project(key)
.forUpdate()
.add(
allowLabel("Code-Review")
.ref("refs/foo")
.group(REGISTERED_USERS)
.range(-1, 2)
.impersonation(true))
.update();
Config config = projectOperations.project(key).getConfig();
assertThat(config).sections().containsExactly("access");
assertThat(config).subsections("access").containsExactly("refs/foo");
assertThat(config)
.subsectionValues("access", "refs/foo")
.containsExactly("labelAs-Code-Review", "-1..+2 group global:Registered-Users");
}
@Test
public void addAllowCapability() throws Exception {
Config config = projectOperations.project(allProjects).getConfig();
assertThat(config)
.sectionValues("capability")
.doesNotContainEntry("administrateServer", "group Registered Users");
projectOperations
.allProjectsForUpdate()
.add(allowCapability(ADMINISTRATE_SERVER).group(REGISTERED_USERS))
.update();
assertThat(projectOperations.project(allProjects).getConfig())
.sectionValues("capability")
.containsEntry("administrateServer", "group Registered Users");
}
@Test
public void addAllowCapabilityWithRange() throws Exception {
Config config = projectOperations.project(allProjects).getConfig();
assertThat(config).sectionValues("capability").doesNotContainKey("queryLimit");
projectOperations
.allProjectsForUpdate()
.add(allowCapability(QUERY_LIMIT).group(REGISTERED_USERS).range(0, 5000))
.update();
assertThat(projectOperations.project(allProjects).getConfig())
.sectionValues("capability")
.containsEntry("queryLimit", "+0..+5000 group Registered Users");
}
@Test
public void addAllowCapabilityWithDefaultRange() throws Exception {
Config config = projectOperations.project(allProjects).getConfig();
assertThat(config).sectionValues("capability").doesNotContainKey("queryLimit");
projectOperations
.allProjectsForUpdate()
.add(allowCapability(QUERY_LIMIT).group(REGISTERED_USERS))
.update();
assertThat(projectOperations.project(allProjects).getConfig())
.sectionValues("capability")
.containsEntry("queryLimit", "+0..+" + DEFAULT_MAX_QUERY_LIMIT + " group Registered Users");
}
@Test
public void removePermission() throws Exception {
Project.NameKey key = projectOperations.newProject().create();
projectOperations
.project(key)
.forUpdate()
.add(allow(Permission.ABANDON).ref("refs/foo").group(REGISTERED_USERS))
.add(allow(Permission.ABANDON).ref("refs/foo").group(PROJECT_OWNERS))
.update();
assertThat(projectOperations.project(key).getConfig())
.subsectionValues("access", "refs/foo")
.containsExactly(
"abandon", "group global:Registered-Users",
"abandon", "group global:Project-Owners");
projectOperations
.project(key)
.forUpdate()
.remove(permissionKey(Permission.ABANDON).ref("refs/foo").group(REGISTERED_USERS))
.update();
assertThat(projectOperations.project(key).getConfig())
.subsectionValues("access", "refs/foo")
.containsExactly("abandon", "group global:Project-Owners");
}
@Test
public void removeLabelPermission() throws Exception {
Project.NameKey key = projectOperations.newProject().create();
projectOperations
.project(key)
.forUpdate()
.add(allowLabel("Code-Review").ref("refs/foo").group(REGISTERED_USERS).range(-1, 2))
.add(allowLabel("Code-Review").ref("refs/foo").group(PROJECT_OWNERS).range(-2, 1))
.update();
assertThat(projectOperations.project(key).getConfig())
.subsectionValues("access", "refs/foo")
.containsExactly(
"label-Code-Review", "-1..+2 group global:Registered-Users",
"label-Code-Review", "-2..+1 group global:Project-Owners");
projectOperations
.project(key)
.forUpdate()
.remove(labelPermissionKey("Code-Review").ref("refs/foo").group(REGISTERED_USERS))
.update();
assertThat(projectOperations.project(key).getConfig())
.subsectionValues("access", "refs/foo")
.containsExactly("label-Code-Review", "-2..+1 group global:Project-Owners");
}
@Test
public void removeCapability() throws Exception {
projectOperations
.allProjectsForUpdate()
.add(allowCapability(ADMINISTRATE_SERVER).group(REGISTERED_USERS))
.add(allowCapability(ADMINISTRATE_SERVER).group(PROJECT_OWNERS))
.update();
assertThat(projectOperations.project(allProjects).getConfig())
.sectionValues("capability")
.containsAtLeastEntriesIn(
ImmutableListMultimap.of(
"administrateServer", "group Registered Users",
"administrateServer", "group Project Owners"));
projectOperations
.allProjectsForUpdate()
.remove(capabilityKey(ADMINISTRATE_SERVER).group(REGISTERED_USERS))
.update();
assertThat(projectOperations.project(allProjects).getConfig())
.sectionValues("capability")
.doesNotContainEntry("administrateServer", "group Registered Users");
}
@Test
public void removeOnePermissionForAllGroupsFromOneAccessSection() throws Exception {
Project.NameKey key = projectOperations.newProject().create();
projectOperations
.project(key)
.forUpdate()
.add(allow(Permission.ABANDON).ref("refs/foo").group(PROJECT_OWNERS))
.add(allow(Permission.ABANDON).ref("refs/foo").group(REGISTERED_USERS))
.add(allow(Permission.CREATE).ref("refs/foo").group(REGISTERED_USERS))
.update();
assertThat(projectOperations.project(key).getConfig())
.subsectionValues("access", "refs/foo")
.containsAtLeastEntriesIn(
ImmutableListMultimap.of(
"abandon", "group global:Project-Owners",
"abandon", "group global:Registered-Users",
"create", "group global:Registered-Users"));
projectOperations
.project(key)
.forUpdate()
.remove(permissionKey(Permission.ABANDON).ref("refs/foo"))
.update();
Config config = projectOperations.project(key).getConfig();
assertThat(config).subsectionValues("access", "refs/foo").doesNotContainKey("abandon");
assertThat(config)
.subsectionValues("access", "refs/foo")
.containsEntry("create", "group global:Registered-Users");
}
@Test
public void removeAllAccessSections() {
projectOperations.allProjectsForUpdate().removeAllAccessSections().update();
assertThat(projectOperations.project(allProjects).getConfig())
.sectionValues("access")
.isEmpty();
}
@Test
public void updatingCapabilitiesNotAllowedForNonAllProjects() throws Exception {
Project.NameKey key = projectOperations.newProject().create();
assertThrows(
RuntimeException.class,
() ->
projectOperations
.project(key)
.forUpdate()
.add(allowCapability(ADMINISTRATE_SERVER).group(REGISTERED_USERS))
.update());
assertThrows(
RuntimeException.class,
() ->
projectOperations
.project(key)
.forUpdate()
.remove(capabilityKey(ADMINISTRATE_SERVER))
.update());
}
private void deleteRefsMetaConfig(Project.NameKey key) throws Exception {
try (Repository repo = repoManager.openRepository(key);
TestRepository<Repository> tr = new TestRepository<>(repo)) {
tr.delete(REFS_CONFIG);
}
}
private static Correspondence<BranchInfo, String> hasBranchName() {
return NullAwareCorrespondence.transforming(branch -> branch.ref, "hasName");
}
}