| // 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 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; |
| } |
| } |
| } |