blob: c04c474cd39daaeb56be2109c9f163b413db9e5a [file] [log] [blame]
// Copyright (C) 2010 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.project;
import static com.google.common.truth.Truth.assertThat;
import static com.google.gerrit.common.data.Permission.EDIT_TOPIC_NAME;
import static com.google.gerrit.common.data.Permission.LABEL;
import static com.google.gerrit.common.data.Permission.OWNER;
import static com.google.gerrit.common.data.Permission.PUSH;
import static com.google.gerrit.common.data.Permission.READ;
import static com.google.gerrit.common.data.Permission.SUBMIT;
import static com.google.gerrit.server.group.SystemGroupBackend.ANONYMOUS_USERS;
import static com.google.gerrit.server.group.SystemGroupBackend.CHANGE_OWNER;
import static com.google.gerrit.server.group.SystemGroupBackend.REGISTERED_USERS;
import static com.google.gerrit.server.project.Util.ADMIN;
import static com.google.gerrit.server.project.Util.DEVS;
import static com.google.gerrit.server.project.Util.allow;
import static com.google.gerrit.server.project.Util.block;
import static com.google.gerrit.server.project.Util.deny;
import static com.google.gerrit.server.project.Util.doNotInherit;
import static com.google.gerrit.testutil.InMemoryRepositoryManager.newRepository;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.collect.Lists;
import com.google.gerrit.common.data.Capable;
import com.google.gerrit.common.data.LabelType;
import com.google.gerrit.common.data.PermissionRange;
import com.google.gerrit.common.data.PermissionRule;
import com.google.gerrit.common.errors.InvalidNameException;
import com.google.gerrit.extensions.api.projects.CommentLinkInfo;
import com.google.gerrit.reviewdb.client.AccountGroup;
import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.rules.PrologEnvironment;
import com.google.gerrit.rules.RulesCache;
import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.account.CapabilityCollection;
import com.google.gerrit.server.account.CapabilityControl;
import com.google.gerrit.server.account.GroupMembership;
import com.google.gerrit.server.account.ListGroupMembership;
import com.google.gerrit.server.config.AllProjectsName;
import com.google.gerrit.server.config.AllProjectsNameProvider;
import com.google.gerrit.server.config.AllUsersName;
import com.google.gerrit.server.config.AllUsersNameProvider;
import com.google.gerrit.server.config.SitePaths;
import com.google.gerrit.server.git.ProjectConfig;
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.testutil.InMemoryDatabase;
import com.google.gerrit.testutil.InMemoryModule;
import com.google.gerrit.testutil.InMemoryRepositoryManager;
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 org.eclipse.jgit.errors.ConfigInvalidException;
import org.eclipse.jgit.internal.storage.dfs.InMemoryRepository;
import org.eclipse.jgit.lib.Repository;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class RefControlTest {
private void assertAdminsAreOwnersAndDevsAreNot() {
ProjectControl uBlah = user(local, DEVS);
ProjectControl uAdmin = user(local, DEVS, ADMIN);
assertThat(uBlah.isOwner()).named("not owner").isFalse();
assertThat(uAdmin.isOwner()).named("is owner").isTrue();
}
private void assertOwner(String ref, ProjectControl u) {
assertThat(u.controlForRef(ref).isOwner())
.named("OWN " + ref)
.isTrue();
}
private void assertNotOwner(ProjectControl u) {
assertThat(u.isOwner()).named("not owner").isFalse();
}
private void assertOwnerAnyRef(ProjectControl u) {
assertThat(u.isOwnerAnyRef()).named("owns ref").isTrue();
}
private void assertNotOwner(String ref, ProjectControl u) {
assertThat(u.controlForRef(ref).isOwner())
.named("NOT OWN " + ref)
.isFalse();
}
private void assertCanRead(ProjectControl u) {
assertThat(u.isVisible())
.named("can read")
.isTrue();
}
private void assertCannotRead(ProjectControl u) {
assertThat(u.isVisible())
.named("cannot read")
.isFalse();
}
private void assertCanRead(String ref, ProjectControl u) {
assertThat(u.controlForRef(ref).isVisible())
.named("can read " + ref)
.isTrue();
}
private void assertCannotRead(String ref, ProjectControl u) {
assertThat(u.controlForRef(ref).isVisible())
.named("cannot read " + ref)
.isFalse();
}
private void assertCanSubmit(String ref, ProjectControl u) {
assertThat(u.controlForRef(ref).canSubmit())
.named("can submit " + ref)
.isTrue();
}
private void assertCannotSubmit(String ref, ProjectControl u) {
assertThat(u.controlForRef(ref).canSubmit())
.named("can submit " + ref)
.isFalse();
}
private void assertCanUpload(ProjectControl u) {
assertThat(u.canPushToAtLeastOneRef())
.named("can upload")
.isEqualTo(Capable.OK);
}
private void assertCanUpload(String ref, ProjectControl u) {
assertThat(u.controlForRef(ref).canUpload())
.named("can upload " + ref)
.isTrue();
}
private void assertCannotUpload(ProjectControl u) {
assertThat(u.canPushToAtLeastOneRef())
.named("cannot upload")
.isNotEqualTo(Capable.OK);
}
private void assertCannotUpload(String ref, ProjectControl u) {
assertThat(u.controlForRef(ref).canUpload())
.named("cannot upload " + ref)
.isFalse();
}
private void assertBlocked(String p, String ref, ProjectControl u) {
assertThat(u.controlForRef(ref).isBlocked(p))
.named(p + " is blocked for " + ref)
.isTrue();
}
private void assertNotBlocked(String p, String ref, ProjectControl u) {
assertThat(u.controlForRef(ref).isBlocked(p))
.named(p + " is blocked for " + ref)
.isFalse();
}
private void assertCanUpdate(String ref, ProjectControl u) {
assertThat(u.controlForRef(ref).canUpdate())
.named("can update " + ref)
.isTrue();
}
private void assertCannotUpdate(String ref, ProjectControl u) {
assertThat(u.controlForRef(ref).canUpdate())
.named("cannot update " + ref)
.isFalse();
}
private void assertCanForceUpdate(String ref, ProjectControl u) {
assertThat(u.controlForRef(ref).canForceUpdate())
.named("can force push " + ref)
.isTrue();
}
private void assertCannotForceUpdate(String ref, ProjectControl u) {
assertThat(u.controlForRef(ref).canForceUpdate())
.named("cannot force push " + ref)
.isFalse();
}
private void assertCanVote(int score, PermissionRange range) {
assertThat(range.contains(score))
.named("can vote " + score)
.isTrue();
}
private void assertCannotVote(int score, PermissionRange range) {
assertThat(range.contains(score))
.named("cannot vote " + score)
.isFalse();
}
private final AllProjectsName allProjectsName =
new AllProjectsName(AllProjectsNameProvider.DEFAULT);
private final AllUsersName allUsersName =
new AllUsersName(AllUsersNameProvider.DEFAULT);
private final AccountGroup.UUID fixers = new AccountGroup.UUID("test.fixers");
private final Map<Project.NameKey, ProjectState> all = new HashMap<>();
private Project.NameKey localKey = new Project.NameKey("local");
private ProjectConfig local;
private Project.NameKey parentKey = new Project.NameKey("parent");
private ProjectConfig parent;
private InMemoryRepositoryManager repoManager;
private ProjectCache projectCache;
private PermissionCollection.Factory sectionSorter;
private ChangeControl.Factory changeControlFactory;
private ReviewDb db;
@Inject private CapabilityCollection.Factory capabilityCollectionFactory;
@Inject private CapabilityControl.Factory capabilityControlFactory;
@Inject private SchemaCreator schemaCreator;
@Inject private InMemoryDatabase schemaFactory;
@Inject private ThreadLocalRequestContext requestContext;
@Before
public void setUp() throws Exception {
repoManager = new InMemoryRepositoryManager();
projectCache = new ProjectCache() {
@Override
public ProjectState getAllProjects() {
return get(allProjectsName);
}
@Override
public ProjectState getAllUsers() {
return null;
}
@Override
public ProjectState get(Project.NameKey projectName) {
return all.get(projectName);
}
@Override
public void evict(Project p) {
}
@Override
public void remove(Project p) {
}
@Override
public void remove(Project.NameKey name) {}
@Override
public Iterable<Project.NameKey> all() {
return Collections.emptySet();
}
@Override
public Iterable<Project.NameKey> byName(String prefix) {
return Collections.emptySet();
}
@Override
public void onCreateProject(Project.NameKey newProjectName) {
}
@Override
public Set<AccountGroup.UUID> guessRelevantGroupUUIDs() {
return Collections.emptySet();
}
@Override
public ProjectState checkedGet(Project.NameKey projectName)
throws IOException {
return all.get(projectName);
}
@Override
public void evict(Project.NameKey p) {
}
};
Injector injector = Guice.createInjector(new InMemoryModule());
injector.injectMembers(this);
try {
Repository repo = repoManager.createRepository(allProjectsName);
ProjectConfig allProjects =
new ProjectConfig(new Project.NameKey(allProjectsName.get()));
allProjects.load(repo);
LabelType cr = Util.codeReview();
allProjects.getLabelSections().put(cr.getName(), cr);
add(allProjects);
} catch (IOException | ConfigInvalidException e) {
throw new RuntimeException(e);
}
db = schemaFactory.open();
schemaCreator.create(db);
Cache<SectionSortCache.EntryKey, SectionSortCache.EntryVal> c =
CacheBuilder.newBuilder().build();
sectionSorter = new PermissionCollection.Factory(new SectionSortCache(c));
parent = new ProjectConfig(parentKey);
parent.load(newRepository(parentKey));
add(parent);
local = new ProjectConfig(localKey);
local.load(newRepository(localKey));
add(local);
local.getProject().setParentName(parentKey);
requestContext.setContext(new RequestContext() {
@Override
public CurrentUser getUser() {
return null;
}
@Override
public Provider<ReviewDb> getReviewDbProvider() {
return Providers.of(db);
}
});
changeControlFactory = injector.getInstance(ChangeControl.Factory.class);
}
@After
public void tearDown() {
requestContext.setContext(null);
if (db != null) {
db.close();
}
InMemoryDatabase.drop(schemaFactory);
}
@Test
public void testOwnerProject() {
allow(local, OWNER, ADMIN, "refs/*");
assertAdminsAreOwnersAndDevsAreNot();
}
@Test
public void testDenyOwnerProject() {
allow(local, OWNER, ADMIN, "refs/*");
deny(local, OWNER, DEVS, "refs/*");
assertAdminsAreOwnersAndDevsAreNot();
}
@Test
public void testBlockOwnerProject() {
allow(local, OWNER, ADMIN, "refs/*");
block(local, OWNER, DEVS, "refs/*");
assertAdminsAreOwnersAndDevsAreNot();
}
@Test
public void testBranchDelegation1() {
allow(local, OWNER, ADMIN, "refs/*");
allow(local, OWNER, DEVS, "refs/heads/x/*");
ProjectControl uDev = user(local, DEVS);
assertNotOwner(uDev);
assertOwnerAnyRef(uDev);
assertOwner("refs/heads/x/*", uDev);
assertOwner("refs/heads/x/y", uDev);
assertOwner("refs/heads/x/y/*", uDev);
assertNotOwner("refs/*", uDev);
assertNotOwner("refs/heads/master", uDev);
}
@Test
public void testBranchDelegation2() {
allow(local, OWNER, ADMIN, "refs/*");
allow(local, OWNER, DEVS, "refs/heads/x/*");
allow(local, OWNER, fixers, "refs/heads/x/y/*");
doNotInherit(local, OWNER, "refs/heads/x/y/*");
ProjectControl uDev = user(local, DEVS);
assertNotOwner(uDev);
assertOwnerAnyRef(uDev);
assertOwner("refs/heads/x/*", uDev);
assertOwner("refs/heads/x/y", uDev);
assertOwner("refs/heads/x/y/*", uDev);
assertNotOwner("refs/*", uDev);
assertNotOwner("refs/heads/master", uDev);
ProjectControl uFix = user(local, fixers);
assertNotOwner(uFix);
assertOwnerAnyRef(uFix);
assertOwner("refs/heads/x/y/*", uFix);
assertOwner("refs/heads/x/y/bar", uFix);
assertNotOwner("refs/heads/x/*", uFix);
assertNotOwner("refs/heads/x/y", uFix);
assertNotOwner("refs/*", uFix);
assertNotOwner("refs/heads/master", uFix);
}
@Test
public void testInheritRead_SingleBranchDeniesUpload() {
allow(parent, READ, REGISTERED_USERS, "refs/*");
allow(parent, PUSH, REGISTERED_USERS, "refs/for/refs/*");
allow(local, READ, REGISTERED_USERS, "refs/heads/foobar");
doNotInherit(local, READ, "refs/heads/foobar");
doNotInherit(local, PUSH, "refs/for/refs/heads/foobar");
ProjectControl u = user(local);
assertCanUpload(u);
assertCanUpload("refs/heads/master", u);
assertCannotUpload("refs/heads/foobar", u);
}
@Test
public void testBlockPushDrafts() {
allow(parent, PUSH, REGISTERED_USERS, "refs/for/refs/*");
block(parent, PUSH, ANONYMOUS_USERS, "refs/drafts/*");
ProjectControl u = user(local);
assertCanUpload("refs/heads/master", u);
assertBlocked(PUSH, "refs/drafts/refs/heads/master", u);
}
@Test
public void testBlockPushDraftsUnblockAdmin() {
block(parent, PUSH, ANONYMOUS_USERS, "refs/drafts/*");
allow(parent, PUSH, ADMIN, "refs/drafts/*");
ProjectControl u = user(local);
ProjectControl a = user(local, "a", ADMIN);
assertBlocked(PUSH, "refs/drafts/refs/heads/master", u);
assertNotBlocked(PUSH, "refs/drafts/refs/heads/master", a);
}
@Test
public void testInheritRead_SingleBranchDoesNotOverrideInherited() {
allow(parent, READ, REGISTERED_USERS, "refs/*");
allow(parent, PUSH, REGISTERED_USERS, "refs/for/refs/*");
allow(local, READ, REGISTERED_USERS, "refs/heads/foobar");
ProjectControl u = user(local);
assertCanUpload(u);
assertCanUpload("refs/heads/master", u);
assertCanUpload("refs/heads/foobar", u);
}
@Test
public void testInheritDuplicateSections() throws Exception {
allow(parent, READ, ADMIN, "refs/*");
allow(local, READ, DEVS, "refs/heads/*");
assertCanRead(user(local, "a", ADMIN));
local = new ProjectConfig(localKey);
local.load(newRepository(localKey));
local.getProject().setParentName(parentKey);
allow(local, READ, DEVS, "refs/*");
assertCanRead(user(local, "d", DEVS));
}
@Test
public void testInheritRead_OverrideWithDeny() {
allow(parent, READ, REGISTERED_USERS, "refs/*");
deny(local, READ, REGISTERED_USERS, "refs/*");
assertCannotRead(user(local));
}
@Test
public void testInheritRead_AppendWithDenyOfRef() {
allow(parent, READ, REGISTERED_USERS, "refs/*");
deny(local, READ, REGISTERED_USERS, "refs/heads/*");
ProjectControl u = user(local);
assertCanRead(u);
assertCanRead("refs/master", u);
assertCanRead("refs/tags/foobar", u);
assertCanRead("refs/heads/master", u);
}
@Test
public void testInheritRead_OverridesAndDeniesOfRef() {
allow(parent, READ, REGISTERED_USERS, "refs/*");
deny(local, READ, REGISTERED_USERS, "refs/*");
allow(local, READ, REGISTERED_USERS, "refs/heads/*");
ProjectControl u = user(local);
assertCanRead(u);
assertCannotRead("refs/foobar", u);
assertCannotRead("refs/tags/foobar", u);
assertCanRead("refs/heads/foobar", u);
}
@Test
public void testInheritSubmit_OverridesAndDeniesOfRef() {
allow(parent, SUBMIT, REGISTERED_USERS, "refs/*");
deny(local, SUBMIT, REGISTERED_USERS, "refs/*");
allow(local, SUBMIT, REGISTERED_USERS, "refs/heads/*");
ProjectControl u = user(local);
assertCannotSubmit("refs/foobar", u);
assertCannotSubmit("refs/tags/foobar", u);
assertCanSubmit("refs/heads/foobar", u);
}
@Test
public void testCannotUploadToAnyRef() {
allow(parent, READ, REGISTERED_USERS, "refs/*");
allow(local, READ, DEVS, "refs/heads/*");
allow(local, PUSH, DEVS, "refs/for/refs/heads/*");
ProjectControl u = user(local);
assertCannotUpload(u);
assertCannotUpload("refs/heads/master", u);
}
@Test
public void testUsernamePatternCanUploadToAnyRef() {
allow(local, PUSH, REGISTERED_USERS, "refs/heads/users/${username}/*");
ProjectControl u = user(local, "a-registered-user");
assertCanUpload(u);
}
@Test
public void testUsernamePatternNonRegex() {
allow(local, READ, DEVS, "refs/sb/${username}/heads/*");
ProjectControl u = user(local, "u", DEVS);
ProjectControl d = user(local, "d", DEVS);
assertCannotRead("refs/sb/d/heads/foobar", u);
assertCanRead("refs/sb/d/heads/foobar", d);
}
@Test
public void testUsernamePatternWithRegex() {
allow(local, READ, DEVS, "^refs/sb/${username}/heads/.*");
ProjectControl u = user(local, "d.v", DEVS);
ProjectControl d = user(local, "dev", DEVS);
assertCannotRead("refs/sb/dev/heads/foobar", u);
assertCanRead("refs/sb/dev/heads/foobar", d);
}
@Test
public void testUsernameEmailPatternWithRegex() {
allow(local, READ, DEVS, "^refs/sb/${username}/heads/.*");
ProjectControl u = user(local, "d.v@ger-rit.org", DEVS);
ProjectControl d = user(local, "dev@ger-rit.org", DEVS);
assertCannotRead("refs/sb/dev@ger-rit.org/heads/foobar", u);
assertCanRead("refs/sb/dev@ger-rit.org/heads/foobar", d);
}
@Test
public void testSortWithRegex() {
allow(local, READ, DEVS, "^refs/heads/.*");
allow(parent, READ, ANONYMOUS_USERS, "^refs/heads/.*-QA-.*");
ProjectControl u = user(local, DEVS);
ProjectControl d = user(local, DEVS);
assertCanRead("refs/heads/foo-QA-bar", u);
assertCanRead("refs/heads/foo-QA-bar", d);
}
@Test
public void testBlockRule_ParentBlocksChild() {
allow(local, PUSH, DEVS, "refs/tags/*");
block(parent, PUSH, ANONYMOUS_USERS, "refs/tags/*");
ProjectControl u = user(local, DEVS);
assertCannotUpdate("refs/tags/V10", u);
}
@Test
public void testBlockRule_ParentBlocksChildEvenIfAlreadyBlockedInChild() {
allow(local, PUSH, DEVS, "refs/tags/*");
block(local, PUSH, ANONYMOUS_USERS, "refs/tags/*");
block(parent, PUSH, ANONYMOUS_USERS, "refs/tags/*");
ProjectControl u = user(local, DEVS);
assertCannotUpdate("refs/tags/V10", u);
}
@Test
public void testBlockLabelRange_ParentBlocksChild() {
allow(local, LABEL + "Code-Review", -2, +2, DEVS, "refs/heads/*");
block(parent, LABEL + "Code-Review", -2, +2, DEVS, "refs/heads/*");
ProjectControl u = user(local, DEVS);
PermissionRange range = u.controlForRef("refs/heads/master").getRange(LABEL + "Code-Review");
assertCanVote(-1, range);
assertCanVote(1, range);
assertCannotVote(-2, range);
assertCannotVote(2, range);
}
@Test
public void testBlockLabelRange_ParentBlocksChildEvenIfAlreadyBlockedInChild() {
allow(local, LABEL + "Code-Review", -2, +2, DEVS, "refs/heads/*");
block(local, LABEL + "Code-Review", -2, +2, DEVS, "refs/heads/*");
block(parent, LABEL + "Code-Review", -2, +2, DEVS,
"refs/heads/*");
ProjectControl u = user(local, DEVS);
PermissionRange range =
u.controlForRef("refs/heads/master").getRange(LABEL + "Code-Review");
assertCanVote(-1, range);
assertCanVote(1, range);
assertCannotVote(-2, range);
assertCannotVote(2, range);
}
@Test
public void testInheritSubmit_AllowInChildDoesntAffectUnblockInParent() {
block(parent, SUBMIT, ANONYMOUS_USERS, "refs/heads/*");
allow(parent, SUBMIT, REGISTERED_USERS, "refs/heads/*");
allow(local, SUBMIT, REGISTERED_USERS, "refs/heads/*");
ProjectControl u = user(local);
assertNotBlocked(SUBMIT, "refs/heads/master", u);
}
@Test
public void testUnblockNoForce() {
block(local, PUSH, ANONYMOUS_USERS, "refs/heads/*");
allow(local, PUSH, DEVS, "refs/heads/*");
ProjectControl u = user(local, DEVS);
assertCanUpdate("refs/heads/master", u);
}
@Test
public void testUnblockForce() {
PermissionRule r = block(local, PUSH, ANONYMOUS_USERS, "refs/heads/*");
r.setForce(true);
allow(local, PUSH, DEVS, "refs/heads/*").setForce(true);
ProjectControl u = user(local, DEVS);
assertCanForceUpdate("refs/heads/master", u);
}
@Test
public void testUnblockForceWithAllowNoForce_NotPossible() {
PermissionRule r = block(local, PUSH, ANONYMOUS_USERS, "refs/heads/*");
r.setForce(true);
allow(local, PUSH, DEVS, "refs/heads/*");
ProjectControl u = user(local, DEVS);
assertCannotForceUpdate("refs/heads/master", u);
}
@Test
public void testUnblockMoreSpecificRef_Fails() {
block(local, PUSH, ANONYMOUS_USERS, "refs/heads/*");
allow(local, PUSH, DEVS, "refs/heads/master");
ProjectControl u = user(local, DEVS);
assertCannotUpdate("refs/heads/master", u);
}
@Test
public void testUnblockLargerScope_Fails() {
block(local, PUSH, ANONYMOUS_USERS, "refs/heads/master");
allow(local, PUSH, DEVS, "refs/heads/*");
ProjectControl u = user(local, DEVS);
assertCannotUpdate("refs/heads/master", u);
}
@Test
public void testUnblockInLocal_Fails() {
block(parent, PUSH, ANONYMOUS_USERS, "refs/heads/*");
allow(local, PUSH, fixers, "refs/heads/*");
ProjectControl f = user(local, fixers);
assertCannotUpdate("refs/heads/master", f);
}
@Test
public void testUnblockInParentBlockInLocal() {
block(parent, PUSH, ANONYMOUS_USERS, "refs/heads/*");
allow(parent, PUSH, DEVS, "refs/heads/*");
block(local, PUSH, DEVS, "refs/heads/*");
ProjectControl d = user(local, DEVS);
assertCannotUpdate("refs/heads/master", d);
}
@Test
public void testUnblockVisibilityByRegisteredUsers() {
block(local, READ, ANONYMOUS_USERS, "refs/heads/*");
allow(local, READ, REGISTERED_USERS, "refs/heads/*");
ProjectControl u = user(local, REGISTERED_USERS);
assertThat(u.controlForRef("refs/heads/master").isVisibleByRegisteredUsers())
.named("u can read")
.isTrue();
}
@Test
public void testUnblockInLocalVisibilityByRegisteredUsers_Fails() {
block(parent, READ, ANONYMOUS_USERS, "refs/heads/*");
allow(local, READ, REGISTERED_USERS, "refs/heads/*");
ProjectControl u = user(local, REGISTERED_USERS);
assertThat(u.controlForRef("refs/heads/master").isVisibleByRegisteredUsers())
.named("u can't read")
.isFalse();
}
@Test
public void testUnblockForceEditTopicName() {
block(local, EDIT_TOPIC_NAME, ANONYMOUS_USERS, "refs/heads/*");
allow(local, EDIT_TOPIC_NAME, DEVS, "refs/heads/*").setForce(true);
ProjectControl u = user(local, DEVS);
assertThat(u.controlForRef("refs/heads/master").canForceEditTopicName())
.named("u can edit topic name")
.isTrue();
}
@Test
public void testUnblockInLocalForceEditTopicName_Fails() {
block(parent, EDIT_TOPIC_NAME, ANONYMOUS_USERS, "refs/heads/*");
allow(local, EDIT_TOPIC_NAME, DEVS, "refs/heads/*").setForce(true);
ProjectControl u = user(local, REGISTERED_USERS);
assertThat(u.controlForRef("refs/heads/master").canForceEditTopicName())
.named("u can't edit topic name")
.isFalse();
}
@Test
public void testUnblockRange() {
block(local, LABEL + "Code-Review", -1, +1, ANONYMOUS_USERS, "refs/heads/*");
allow(local, LABEL + "Code-Review", -2, +2, DEVS, "refs/heads/*");
ProjectControl u = user(local, DEVS);
PermissionRange range = u.controlForRef("refs/heads/master").getRange(LABEL + "Code-Review");
assertCanVote(-2, range);
assertCanVote(2, range);
}
@Test
public void testUnblockRangeOnMoreSpecificRef_Fails() {
block(local, LABEL + "Code-Review", -1, +1, ANONYMOUS_USERS, "refs/heads/*");
allow(local, LABEL + "Code-Review", -2, +2, DEVS, "refs/heads/master");
ProjectControl u = user(local, DEVS);
PermissionRange range = u.controlForRef("refs/heads/master").getRange(LABEL + "Code-Review");
assertCannotVote(-2, range);
assertCannotVote(2, range);
}
@Test
public void testUnblockRangeOnLargerScope_Fails() {
block(local, LABEL + "Code-Review", -1, +1, ANONYMOUS_USERS, "refs/heads/master");
allow(local, LABEL + "Code-Review", -2, +2, DEVS, "refs/heads/*");
ProjectControl u = user(local, DEVS);
PermissionRange range = u.controlForRef("refs/heads/master").getRange(LABEL + "Code-Review");
assertCannotVote(-2, range);
assertCannotVote(2, range);
}
@Test
public void testUnblockInLocalRange_Fails() {
block(parent, LABEL + "Code-Review", -1, 1, ANONYMOUS_USERS,
"refs/heads/*");
allow(local, LABEL + "Code-Review", -2, +2, DEVS, "refs/heads/*");
ProjectControl u = user(local, DEVS);
PermissionRange range =
u.controlForRef("refs/heads/master").getRange(LABEL + "Code-Review");
assertCannotVote(-2, range);
assertCannotVote(2, range);
}
@Test
public void testUnblockRangeForChangeOwner() {
allow(local, LABEL + "Code-Review", -2, +2, CHANGE_OWNER, "refs/heads/*");
ProjectControl u = user(local, DEVS);
PermissionRange range = u.controlForRef("refs/heads/master")
.getRange(LABEL + "Code-Review", true);
assertCanVote(-2, range);
assertCanVote(2, range);
}
@Test
public void testUnblockRangeForNotChangeOwner() {
allow(local, LABEL + "Code-Review", -2, +2, CHANGE_OWNER, "refs/heads/*");
ProjectControl u = user(local, DEVS);
PermissionRange range = u.controlForRef("refs/heads/master")
.getRange(LABEL + "Code-Review");
assertCannotVote(-2, range);
assertCannotVote(2, range);
}
@Test
public void testValidateRefPatternsOK() throws Exception {
RefPattern.validate("refs/*");
RefPattern.validate("^refs/heads/*");
RefPattern.validate("^refs/tags/[0-9a-zA-Z-_.]+");
RefPattern.validate("refs/heads/review/${username}/*");
}
@Test(expected = InvalidNameException.class)
public void testValidateBadRefPatternDoubleCaret() throws Exception {
RefPattern.validate("^^refs/*");
}
@Test(expected = InvalidNameException.class)
public void testValidateBadRefPatternDanglingCharacter() throws Exception {
RefPattern
.validate("^refs/heads/tmp/sdk/[0-9]{3,3}_R[1-9][A-Z][0-9]{3,3}*");
}
@Test
public void testValidateRefPatternNoDanglingCharacter() throws Exception {
RefPattern.validate("^refs/heads/tmp/sdk/[0-9]{3,3}_R[1-9][A-Z][0-9]{3,3}");
}
private InMemoryRepository add(ProjectConfig pc) {
PrologEnvironment.Factory envFactory = null;
ProjectControl.AssistedFactory projectControlFactory = null;
RulesCache rulesCache = null;
SitePaths sitePaths = null;
List<CommentLinkInfo> commentLinks = null;
InMemoryRepository repo;
try {
repo = repoManager.createRepository(pc.getName());
if (pc.getProject() == null) {
pc.load(repo);
}
} catch (IOException | ConfigInvalidException e) {
throw new RuntimeException(e);
}
all.put(pc.getName(),
new ProjectState(sitePaths, projectCache, allProjectsName, allUsersName,
projectControlFactory, envFactory, repoManager, rulesCache,
commentLinks, capabilityCollectionFactory, pc));
return repo;
}
private ProjectControl user(ProjectConfig local,
AccountGroup.UUID... memberOf) {
return user(local, null, memberOf);
}
private ProjectControl user(ProjectConfig local, String name,
AccountGroup.UUID... memberOf) {
String canonicalWebUrl = "http://localhost";
return new ProjectControl(Collections.<AccountGroup.UUID> emptySet(),
Collections.<AccountGroup.UUID> emptySet(), projectCache,
sectionSorter, null, changeControlFactory, null, null,
canonicalWebUrl, new MockUser(name, memberOf), newProjectState(local));
}
private ProjectState newProjectState(ProjectConfig local) {
add(local);
return all.get(local.getProject().getNameKey());
}
private class MockUser extends CurrentUser {
private final String username;
private final GroupMembership groups;
MockUser(String name, AccountGroup.UUID[] groupId) {
super(capabilityControlFactory);
username = name;
ArrayList<AccountGroup.UUID> groupIds = Lists.newArrayList(groupId);
groupIds.add(REGISTERED_USERS);
groupIds.add(ANONYMOUS_USERS);
groups = new ListGroupMembership(groupIds);
}
@Override
public GroupMembership getEffectiveGroups() {
return groups;
}
@Override
public String getUserName() {
return username;
}
}
}