blob: 0054f2ef104848e0c5fd73078dc2c1280228e76b [file] [log] [blame]
// Copyright (C) 2022 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.plugins.codeowners.backend;
import static com.google.common.collect.ImmutableSet.toImmutableSet;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth8.assertThat;
import static com.google.gerrit.server.group.SystemGroupBackend.REGISTERED_USERS;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.gerrit.acceptance.TestAccount;
import com.google.gerrit.acceptance.config.GerritConfig;
import com.google.gerrit.acceptance.testsuite.project.ProjectOperations;
import com.google.gerrit.acceptance.testsuite.project.TestProjectUpdate;
import com.google.gerrit.acceptance.testsuite.request.RequestScopeOperations;
import com.google.gerrit.entities.Account;
import com.google.gerrit.entities.Change;
import com.google.gerrit.entities.PatchSet;
import com.google.gerrit.entities.PatchSetApproval;
import com.google.gerrit.entities.Project;
import com.google.gerrit.extensions.api.changes.ChangeApi;
import com.google.gerrit.extensions.api.changes.ReviewInput;
import com.google.gerrit.extensions.common.LabelDefinitionInput;
import com.google.gerrit.extensions.restapi.RestApiException;
import com.google.gerrit.plugins.codeowners.acceptance.AbstractCodeOwnersTest;
import com.google.gerrit.plugins.codeowners.backend.config.CodeOwnersPluginConfiguration;
import com.google.gerrit.plugins.codeowners.backend.config.CodeOwnersPluginProjectConfigSnapshot;
import com.google.gerrit.server.notedb.ChangeNotes;
import com.google.gerrit.server.query.change.ChangeData;
import com.google.inject.Inject;
import org.junit.Before;
import org.junit.Test;
/** Tests for {@link CodeOwnerApprovalCheckInput}. */
public class CodeOwnerApprovalCheckInputTest extends AbstractCodeOwnersTest {
@Inject private ChangeNotes.Factory changeNotesFactory;
@Inject private ProjectOperations projectOperations;
@Inject private RequestScopeOperations requestScopeOperations;
private CodeOwnerApprovalCheckInput.Loader.Factory inputLoaderFactory;
private CodeOwnerResolver codeOwnerResolver;
private CodeOwnersPluginProjectConfigSnapshot codeOwnersConfig;
private TestAccount user2;
private Change.Id changeId;
private Change.Key changeKey;
private Account.Id changeOwner;
@Before
public void setUpCodeOwnersPlugin() throws Exception {
inputLoaderFactory =
plugin.getSysInjector().getInstance(CodeOwnerApprovalCheckInput.Loader.Factory.class);
codeOwnerResolver = plugin.getSysInjector().getInstance(CodeOwnerResolver.class);
CodeOwnersPluginConfiguration codeOwnersPluginConfiguration =
plugin.getSysInjector().getInstance(CodeOwnersPluginConfiguration.class);
codeOwnersConfig = codeOwnersPluginConfiguration.getProjectConfig(project);
}
@Before
public void setUp() throws Exception {
user2 = accountCreator.user2();
ChangeData changeData = createChange().getChange();
changeId = changeData.getId();
changeKey = changeData.change().getKey();
changeOwner = admin.id();
}
@Test
public void noReviewers() {
assertThat(loadInput().reviewers()).isEmpty();
}
@Test
public void withReviewers() throws Exception {
changeApi().addReviewer(user.email());
changeApi().addReviewer(user2.email());
// make the change owner a reviewer:
// the change owner cannot be added as a reviewer, but the change owner becomes a reviewer when
// they vote on the change
requestScopeOperations.setApiUser(changeOwner);
recommend(changeId.toString());
assertThat(loadInput().reviewers()).containsExactly(user.id(), user2.id(), changeOwner);
}
@Test
public void withReviewers_selfApprovalsIgnored() throws Exception {
disableSelfCodeReviewApprovals();
changeApi().addReviewer(user.email());
changeApi().addReviewer(user2.email());
// make the change owner a reviewer:
// the change owner cannot be added as a reviewer, but the change owner becomes a reviewer when
// they vote on the change
requestScopeOperations.setApiUser(changeOwner);
recommend(changeId.toString());
assertThat(loadInput().reviewers()).containsExactly(user.id(), user2.id());
}
@Test
public void noApprovers() {
assertThat(loadInput().approvers()).isEmpty();
}
@Test
public void withApprovers() throws Exception {
// self approve
requestScopeOperations.setApiUser(changeOwner);
recommend(changeId.toString());
// approve as user
requestScopeOperations.setApiUser(user.id());
recommend(changeId.toString());
// approve as user2
requestScopeOperations.setApiUser(user2.id());
recommend(changeId.toString());
assertThat(loadInput().approvers()).containsExactly(changeOwner, user.id(), user2.id());
}
@Test
public void withApprovers_selfApprovalsIgnored() throws Exception {
disableSelfCodeReviewApprovals();
// self approve
requestScopeOperations.setApiUser(changeOwner);
recommend(changeId.toString());
// approve as user
requestScopeOperations.setApiUser(user.id());
recommend(changeId.toString());
// approve as user2
requestScopeOperations.setApiUser(user2.id());
recommend(changeId.toString());
assertThat(loadInput().approvers()).containsExactly(user.id(), user2.id());
}
/** Test that current approvals do not count for computing previous approvers. */
@Test
@GerritConfig(name = "plugin.code-owners.enableStickyApprovals", value = "true")
public void noPreviousApprovers() throws Exception {
// self approve current patch set
requestScopeOperations.setApiUser(changeOwner);
recommend(changeId.toString());
// approve as user current patch set
requestScopeOperations.setApiUser(user.id());
recommend(changeId.toString());
// approve as user2 current patch set
requestScopeOperations.setApiUser(user2.id());
recommend(changeId.toString());
assertThat(loadInput().approversFromPreviousPatchSets()).isEmpty();
}
/** Test that previous approvals on other labels do not count for computing previous approvers. */
@Test
@GerritConfig(name = "plugin.code-owners.enableStickyApprovals", value = "true")
public void noPreviousApproversIfApprovalIsOnUnrelatedLabel() throws Exception {
// Create Foo-Review label.
LabelDefinitionInput input = new LabelDefinitionInput();
input.values = ImmutableMap.of("+1", "Approved", " 0", "Not Approved");
gApi.projects().name(project.get()).label("Foo-Review").create(input).get();
// Allow to vote on the Foo-Review label.
projectOperations
.project(project)
.forUpdate()
.add(
TestProjectUpdate.allowLabel("Foo-Review")
.range(0, 1)
.ref("refs/heads/*")
.group(REGISTERED_USERS)
.build())
.update();
// approve on Foo-Review label
requestScopeOperations.setApiUser(user.id());
gApi.changes().id(changeId.get()).current().review(new ReviewInput().label("Foo-Review", 1));
// create a second patch set
requestScopeOperations.setApiUser(changeOwner);
amendChange(changeKey.get()).assertOkStatus();
assertThat(loadInput().approversFromPreviousPatchSets()).isEmpty();
}
/**
* Test that previous votes with insufficient values do not count for computing previous
* approvers.
*/
@Test
@GerritConfig(name = "plugin.code-owners.requiredApproval", value = "Code-Review+2")
@GerritConfig(name = "plugin.code-owners.enableStickyApprovals", value = "true")
public void noPreviousApproversIfVoteIsNotAnApproval() throws Exception {
// vote with Code-Review+1, but only Code-Review+2 counts as a code owner approval
requestScopeOperations.setApiUser(user.id());
recommend(changeId.toString());
// create a second patch set
requestScopeOperations.setApiUser(changeOwner);
amendChange(changeKey.get()).assertOkStatus();
assertThat(loadInput().approversFromPreviousPatchSets()).isEmpty();
}
/** Test that previous approvals are ignored if sticky approvals are disabled. */
@Test
@GerritConfig(name = "plugin.code-owners.enableStickyApprovals", value = "false")
public void noPreviousApproversIfEnableStickyApprovalsDisabled() throws Exception {
// self approve
requestScopeOperations.setApiUser(changeOwner);
recommend(changeId.toString());
// approve as user
requestScopeOperations.setApiUser(user.id());
recommend(changeId.toString());
// approve as user2
requestScopeOperations.setApiUser(user2.id());
recommend(changeId.toString());
// create a second patch set
requestScopeOperations.setApiUser(changeOwner);
amendChange(changeKey.get()).assertOkStatus();
assertThat(loadInput().approversFromPreviousPatchSets()).isEmpty();
}
/** Test that the approvals on the previous patch set count for computing previous approvers. */
@Test
@GerritConfig(name = "plugin.code-owners.enableStickyApprovals", value = "true")
public void withPreviousApprovers() throws Exception {
// self approve
requestScopeOperations.setApiUser(changeOwner);
recommend(changeId.toString());
// approve as user
requestScopeOperations.setApiUser(user.id());
recommend(changeId.toString());
// approve as user2
requestScopeOperations.setApiUser(user2.id());
recommend(changeId.toString());
// create a second patch set
requestScopeOperations.setApiUser(changeOwner);
amendChange(changeKey.get()).assertOkStatus();
ArrayListMultimap<PatchSet.Id, Account.Id> expectedPreviousApprovers =
ArrayListMultimap.create();
expectedPreviousApprovers.putAll(
PatchSet.id(changeId, 1), ImmutableSet.of(changeOwner, user.id(), user2.id()));
assertThat(loadInput().approversFromPreviousPatchSets())
.containsExactlyEntriesIn(expectedPreviousApprovers);
}
/**
* Test that a self-approval on the previous patch set is ignored for computing previous
* approvers.
*/
@Test
@GerritConfig(name = "plugin.code-owners.enableStickyApprovals", value = "true")
public void withPreviousApprovers_selfApprovalsIgnored() throws Exception {
disableSelfCodeReviewApprovals();
// self approve
requestScopeOperations.setApiUser(changeOwner);
recommend(changeId.toString());
// approve as user
requestScopeOperations.setApiUser(user.id());
recommend(changeId.toString());
// approve as user2
requestScopeOperations.setApiUser(user2.id());
recommend(changeId.toString());
// create a second patch set
requestScopeOperations.setApiUser(changeOwner);
amendChange(changeKey.get()).assertOkStatus();
ArrayListMultimap<PatchSet.Id, Account.Id> expectedPreviousApprovers =
ArrayListMultimap.create();
expectedPreviousApprovers.putAll(
PatchSet.id(changeId, 1), ImmutableSet.of(user.id(), user2.id()));
assertThat(loadInput().approversFromPreviousPatchSets())
.containsExactlyEntriesIn(expectedPreviousApprovers);
}
/**
* Test that the approvals on different previous patch sets count for computing previous
* approvers.
*/
@Test
@GerritConfig(name = "plugin.code-owners.enableStickyApprovals", value = "true")
public void withPreviousApproversOnDifferentPatchSets() throws Exception {
// self approve
requestScopeOperations.setApiUser(changeOwner);
recommend(changeId.toString());
// create a second patch set
requestScopeOperations.setApiUser(changeOwner);
amendChange(changeKey.get()).assertOkStatus();
// approve as user
requestScopeOperations.setApiUser(user.id());
recommend(changeId.toString());
// create a third patch set
requestScopeOperations.setApiUser(changeOwner);
amendChange(changeKey.get()).assertOkStatus();
// approve as user2
requestScopeOperations.setApiUser(user2.id());
recommend(changeId.toString());
// create a 4th patch set
requestScopeOperations.setApiUser(changeOwner);
amendChange(changeKey.get()).assertOkStatus();
ArrayListMultimap<PatchSet.Id, Account.Id> expectedPreviousApprovers =
ArrayListMultimap.create();
expectedPreviousApprovers.put(PatchSet.id(changeId, 1), changeOwner);
expectedPreviousApprovers.put(PatchSet.id(changeId, 2), user.id());
expectedPreviousApprovers.put(PatchSet.id(changeId, 3), user2.id());
assertThat(loadInput().approversFromPreviousPatchSets())
.containsExactlyEntriesIn(expectedPreviousApprovers);
}
/** Test that a self-approval on an old patch set is ignored for computing previous approvers. */
@Test
@GerritConfig(name = "plugin.code-owners.enableStickyApprovals", value = "true")
public void withPreviousApproversOnDifferentPatchSets_selfApprovalsIgnored() throws Exception {
disableSelfCodeReviewApprovals();
// self approve
requestScopeOperations.setApiUser(changeOwner);
recommend(changeId.toString());
// create a second patch set
requestScopeOperations.setApiUser(changeOwner);
amendChange(changeKey.get()).assertOkStatus();
// approve as user
requestScopeOperations.setApiUser(user.id());
recommend(changeId.toString());
// create a third patch set
requestScopeOperations.setApiUser(changeOwner);
amendChange(changeKey.get()).assertOkStatus();
// approve as user2
requestScopeOperations.setApiUser(user2.id());
recommend(changeId.toString());
// create a 4th patch set
requestScopeOperations.setApiUser(changeOwner);
amendChange(changeKey.get()).assertOkStatus();
ArrayListMultimap<PatchSet.Id, Account.Id> expectedPreviousApprovers =
ArrayListMultimap.create();
expectedPreviousApprovers.put(PatchSet.id(changeId, 2), user.id());
expectedPreviousApprovers.put(PatchSet.id(changeId, 3), user2.id());
assertThat(loadInput().approversFromPreviousPatchSets())
.containsExactlyEntriesIn(expectedPreviousApprovers);
}
/**
* Test that sticky approvals do not count for computing previous approvers (because if the
* approval is sticky it's a current approval).
*/
@Test
@GerritConfig(name = "plugin.code-owners.enableStickyApprovals", value = "true")
public void noPreviousApproversIfApprovalIsCopied() throws Exception {
// Make Code-Review approvals sticky
LabelDefinitionInput input = new LabelDefinitionInput();
input.copyCondition = "is:ANY";
gApi.projects().name(allProjects.get()).label("Code-Review").update(input);
// approve as user
requestScopeOperations.setApiUser(user.id());
recommend(changeId.toString());
// create a second patch set
requestScopeOperations.setApiUser(changeOwner);
amendChange(changeKey.get()).assertOkStatus();
assertThat(loadInput().approversFromPreviousPatchSets()).isEmpty();
}
/**
* Test that a previous approval still counts for computing previous approvers if the approver
* comments on the current patch set without applying a vote.
*/
@Test
@GerritConfig(name = "plugin.code-owners.enableStickyApprovals", value = "true")
public void previousApproversIsPreservedWhenThePreviousApproverCommentsOnTheChange()
throws Exception {
// approve as user
requestScopeOperations.setApiUser(user.id());
recommend(changeId.toString());
// create a second patch set
requestScopeOperations.setApiUser(changeOwner);
amendChange(changeKey.get()).assertOkStatus();
// check that the previous approver on patch set 1 is found
ArrayListMultimap<PatchSet.Id, Account.Id> expectedPreviousApprovers =
ArrayListMultimap.create();
expectedPreviousApprovers.put(PatchSet.id(changeId, 1), user.id());
assertThat(loadInput().approversFromPreviousPatchSets())
.containsExactlyEntriesIn(expectedPreviousApprovers);
// comment on the change
requestScopeOperations.setApiUser(user.id());
ReviewInput reviewInput = ReviewInput.noScore();
reviewInput.message = "a comment";
gApi.changes().id(changeId.get()).current().review(reviewInput);
assertThat(loadInput().approversFromPreviousPatchSets())
.containsExactlyEntriesIn(expectedPreviousApprovers);
}
/**
* Test that a previous approval doesn't count for computing previous approvers if the approver
* downgrades the vote.
*/
@Test
@GerritConfig(name = "plugin.code-owners.enableStickyApprovals", value = "true")
@GerritConfig(name = "plugin.code-owners.requiredApproval", value = "Code-Review+2")
public void noPreviousApproversIfApprovalIsDowngraded() throws Exception {
// Allow all users to vote with Code-Review+2.
projectOperations
.project(project)
.forUpdate()
.add(
TestProjectUpdate.allowLabel("Code-Review")
.range(0, 2)
.ref("refs/heads/*")
.group(REGISTERED_USERS)
.build())
.update();
// approve as user
requestScopeOperations.setApiUser(user.id());
approve(changeId.toString());
// create a second patch set
requestScopeOperations.setApiUser(changeOwner);
amendChange(changeKey.get()).assertOkStatus();
// check that the previous approver on patch set 1 is found
ArrayListMultimap<PatchSet.Id, Account.Id> expectedPreviousApprovers =
ArrayListMultimap.create();
expectedPreviousApprovers.put(PatchSet.id(changeId, 1), user.id());
assertThat(loadInput().approversFromPreviousPatchSets())
.containsExactlyEntriesIn(expectedPreviousApprovers);
// change vote from Code-Review+2 to Code-Review+1 as user
requestScopeOperations.setApiUser(user.id());
recommend(changeId.toString());
// the Code-Review+1 vote on the current patch set overrode the previous approval
assertThat(loadInput().approversFromPreviousPatchSets()).isEmpty();
// create a third patch set
requestScopeOperations.setApiUser(changeOwner);
amendChange(changeKey.get()).assertOkStatus();
// the Code-Review+1 vote on the previous patch set overrode the previous approval
assertThat(loadInput().approversFromPreviousPatchSets()).isEmpty();
}
/**
* Test that a previous approval doesn't count for computing previous approvers if the approver
* re-applies the approval (because now it's a current approval).
*/
@Test
@GerritConfig(name = "plugin.code-owners.enableStickyApprovals", value = "true")
public void noPreviousApproversIfApprovalIsReapplied() throws Exception {
// approve as user
requestScopeOperations.setApiUser(user.id());
recommend(changeId.toString());
// create a second patch set
requestScopeOperations.setApiUser(changeOwner);
amendChange(changeKey.get()).assertOkStatus();
// check that the previous approver on patch set 1 is found
ArrayListMultimap<PatchSet.Id, Account.Id> expectedPreviousApprovers =
ArrayListMultimap.create();
expectedPreviousApprovers.put(PatchSet.id(changeId, 1), user.id());
assertThat(loadInput().approversFromPreviousPatchSets())
.containsExactlyEntriesIn(expectedPreviousApprovers);
// re-apply the approval
requestScopeOperations.setApiUser(user.id());
recommend(changeId.toString());
assertThat(loadInput().approversFromPreviousPatchSets()).isEmpty();
}
/**
* Test that only the last previous approval of a user counts for computing previous approvers.
*/
@Test
@GerritConfig(name = "plugin.code-owners.enableStickyApprovals", value = "true")
public void onlyLastPreviousApprovalOfAUserIsConsideredForComputingPreviousApprovers()
throws Exception {
// approve as user
requestScopeOperations.setApiUser(user.id());
recommend(changeId.toString());
// create a second patch set
requestScopeOperations.setApiUser(changeOwner);
amendChange(changeKey.get()).assertOkStatus();
// re-approve as user
requestScopeOperations.setApiUser(user.id());
recommend(changeId.toString());
// create a third patch set
requestScopeOperations.setApiUser(changeOwner);
amendChange(changeKey.get()).assertOkStatus();
ArrayListMultimap<PatchSet.Id, Account.Id> expectedPreviousApprovers =
ArrayListMultimap.create();
expectedPreviousApprovers.put(PatchSet.id(changeId, 2), user.id());
assertThat(loadInput().approversFromPreviousPatchSets())
.containsExactlyEntriesIn(expectedPreviousApprovers);
}
@Test
@GerritConfig(name = "plugin.code-owners.enableStickyApprovals", value = "true")
public void noPreviouslyApprovedPatchSets() throws Exception {
// approve current patch set
requestScopeOperations.setApiUser(user.id());
recommend(changeId.toString());
assertThat(loadInput().previouslyApprovedPatchSetsInReverseOrder()).isEmpty();
}
@Test
@GerritConfig(name = "plugin.code-owners.enableStickyApprovals", value = "true")
public void previouslyApprovedPatchSetsAreReturnedInReverseOrder() throws Exception {
// create a second patch set
requestScopeOperations.setApiUser(changeOwner);
amendChange(changeKey.get()).assertOkStatus();
// approve as user
requestScopeOperations.setApiUser(user.id());
recommend(changeId.toString());
// create a third patch set
requestScopeOperations.setApiUser(changeOwner);
amendChange(changeKey.get()).assertOkStatus();
// approve as user2, ignored since overridden on patch set 4
requestScopeOperations.setApiUser(user2.id());
recommend(changeId.toString());
// create a 4th patch set
requestScopeOperations.setApiUser(changeOwner);
amendChange(changeKey.get()).assertOkStatus();
// re- approve as user2
requestScopeOperations.setApiUser(user2.id());
recommend(changeId.toString());
// create a 5th patch set
requestScopeOperations.setApiUser(changeOwner);
amendChange(changeKey.get()).assertOkStatus();
assertThat(loadInput().previouslyApprovedPatchSetsInReverseOrder())
.containsExactly(PatchSet.id(changeId, 4), PatchSet.id(changeId, 2));
}
@Test
public void noImplicitApprover() {
assertThat(loadInput().implicitApprover()).isEmpty();
}
@Test
@GerritConfig(name = "plugin.code-owners.enableImplicitApprovals", value = "true")
public void withImplicitApprover() {
// If implicit approvals are enabled, an implicit approval of the current uploader is assumed.
// Since the change has only 1 patch set the current uploader is the change owner.
assertThat(loadInput().implicitApprover()).hasValue(changeOwner);
}
@Test
public void noOverrides() {
assertThat(loadInput().overrides()).isEmpty();
}
@Test
@GerritConfig(name = "plugin.code-owners.overrideApproval", value = "Owners-Override+1")
public void withOverrides() throws Exception {
createOwnersOverrideLabel();
ReviewInput reviewInput = new ReviewInput().label("Owners-Override", 1);
// self override
requestScopeOperations.setApiUser(changeOwner);
gApi.changes().id(changeId.toString()).current().review(reviewInput);
// override as user
requestScopeOperations.setApiUser(user.id());
gApi.changes().id(changeId.toString()).current().review(reviewInput);
// override as user2
requestScopeOperations.setApiUser(user2.id());
gApi.changes().id(changeId.toString()).current().review(reviewInput);
assertThat(
loadInput().overrides().stream()
.map(PatchSetApproval::accountId)
.collect(toImmutableSet()))
.containsExactly(changeOwner, user.id(), user2.id());
}
@Test
@GerritConfig(name = "plugin.code-owners.overrideApproval", value = "Owners-Override+1")
public void withOverrides_selfApprovalsIgnored() throws Exception {
createOwnersOverrideLabel();
disableSelfOwnersOverrideApprovals();
ReviewInput reviewInput = new ReviewInput().label("Owners-Override", 1);
// self override
requestScopeOperations.setApiUser(changeOwner);
gApi.changes().id(changeId.toString()).current().review(reviewInput);
// override as user
requestScopeOperations.setApiUser(user.id());
gApi.changes().id(changeId.toString()).current().review(reviewInput);
// override as user2
requestScopeOperations.setApiUser(user2.id());
gApi.changes().id(changeId.toString()).current().review(reviewInput);
assertThat(
loadInput().overrides().stream()
.map(PatchSetApproval::accountId)
.collect(toImmutableSet()))
.containsExactly(user.id(), user2.id());
}
@Test
public void noGlobalCodeOwners() {
CodeOwnerResolverResult globalCodeOwners = loadInput().globalCodeOwners();
assertThat(globalCodeOwners.codeOwnersAccountIds()).isEmpty();
assertThat(globalCodeOwners.ownedByAllUsers()).isFalse();
}
@Test
@GerritConfig(
name = "plugin.code-owners.globalCodeOwner",
values = {"user1@example.com", "user2@example.com"})
public void withGlobalCodeOwners() {
CodeOwnerResolverResult globalCodeOwners = loadInput().globalCodeOwners();
assertThat(globalCodeOwners.codeOwnersAccountIds()).containsExactly(user.id(), user2.id());
assertThat(globalCodeOwners.ownedByAllUsers()).isFalse();
}
@Test
@GerritConfig(name = "plugin.code-owners.globalCodeOwner", value = "*")
public void withAllUsersAsGlobalCodeOwners() {
CodeOwnerResolverResult globalCodeOwners = loadInput().globalCodeOwners();
assertThat(globalCodeOwners.codeOwnersAccountIds()).isEmpty();
assertThat(globalCodeOwners.ownedByAllUsers()).isTrue();
}
@Test
public void withFallbackCodeOwnersNone() {
assertThat(loadInput().fallbackCodeOwners()).isEqualTo(FallbackCodeOwners.NONE);
}
@Test
@GerritConfig(name = "plugin.code-owners.fallbackCodeOwners", value = "ALL_USERS")
public void withFallbackCodeOwnersAllUsers() {
assertThat(loadInput().fallbackCodeOwners()).isEqualTo(FallbackCodeOwners.ALL_USERS);
}
@Test
public void checkAllOwnersIsFalse() {
assertThat(loadInput().checkAllOwners()).isFalse();
}
@Test
public void createInputForComputingOwnedPaths_noReviewers() throws Exception {
changeApi().addReviewer(user.email());
changeApi().addReviewer(user2.email());
// CodeOwnerApprovalCheckInput#createForComputingOwnedPaths never sets reviewers
assertThat(createInputForComputingOwnedPaths(ImmutableSet.of()).reviewers()).isEmpty();
}
@Test
public void createInputForComputingOwnedPaths_noApprovers() throws Exception {
// self approve
requestScopeOperations.setApiUser(changeOwner);
recommend(changeId.toString());
// approve as user
requestScopeOperations.setApiUser(user.id());
recommend(changeId.toString());
// approve as user2
requestScopeOperations.setApiUser(user2.id());
recommend(changeId.toString());
// CodeOwnerApprovalCheckInput#createForComputingOwnedPaths always sets approvers to the given
// accounts
assertThat(createInputForComputingOwnedPaths(ImmutableSet.of()).approvers()).isEmpty();
}
@Test
public void createInputForComputingOwnedPaths_withApprovers() {
// CodeOwnerApprovalCheckInput#createForComputingOwnedPaths always sets approvers to the given
// accounts
assertThat(
createInputForComputingOwnedPaths(ImmutableSet.of(admin.id(), user.id(), user2.id()))
.approvers())
.containsExactly(admin.id(), user.id(), user2.id());
}
@Test
@GerritConfig(name = "plugin.code-owners.enableImplicitApprovals", value = "true")
public void createInputForComputingOwnedPaths_noImplicitApprover() {
// CodeOwnerApprovalCheckInput#createForComputingOwnedPaths never sets an implicit approver
assertThat(createInputForComputingOwnedPaths(ImmutableSet.of()).implicitApprover()).isEmpty();
}
@Test
@GerritConfig(name = "plugin.code-owners.overrideApproval", value = "Owners-Override+1")
public void createInputForComputingOwnedPaths_noOverride() throws Exception {
createOwnersOverrideLabel();
ReviewInput reviewInput = new ReviewInput().label("Owners-Override", 1);
// self override
requestScopeOperations.setApiUser(changeOwner);
gApi.changes().id(changeId.toString()).current().review(reviewInput);
// override as user
requestScopeOperations.setApiUser(user.id());
gApi.changes().id(changeId.toString()).current().review(reviewInput);
// override as user2
requestScopeOperations.setApiUser(user2.id());
gApi.changes().id(changeId.toString()).current().review(reviewInput);
// CodeOwnerApprovalCheckInput#createForComputingOwnedPaths never sets overrides
assertThat(createInputForComputingOwnedPaths(ImmutableSet.of()).overrides()).isEmpty();
}
@Test
public void createInputForComputingOwnedPaths_noGlobalCodeOwners() {
CodeOwnerResolverResult globalCodeOwners =
createInputForComputingOwnedPaths(ImmutableSet.of()).globalCodeOwners();
assertThat(globalCodeOwners.codeOwnersAccountIds()).isEmpty();
assertThat(globalCodeOwners.ownedByAllUsers()).isFalse();
}
@Test
@GerritConfig(
name = "plugin.code-owners.globalCodeOwner",
values = {"user1@example.com", "user2@example.com"})
public void createInputForComputingOwnedPaths_withGlobalCodeOwners() {
CodeOwnerResolverResult globalCodeOwners =
createInputForComputingOwnedPaths(ImmutableSet.of()).globalCodeOwners();
assertThat(globalCodeOwners.codeOwnersAccountIds()).containsExactly(user.id(), user2.id());
assertThat(globalCodeOwners.ownedByAllUsers()).isFalse();
}
@Test
@GerritConfig(name = "plugin.code-owners.globalCodeOwner", value = "*")
public void createInputForComputingOwnedPaths_withAllUsersAsGlobalCodeOwners() {
CodeOwnerResolverResult globalCodeOwners =
createInputForComputingOwnedPaths(ImmutableSet.of()).globalCodeOwners();
assertThat(globalCodeOwners.codeOwnersAccountIds()).isEmpty();
assertThat(globalCodeOwners.ownedByAllUsers()).isTrue();
}
@Test
public void createInputForComputingOwnedPaths_withFallbackCodeOwnersNone() {
assertThat(createInputForComputingOwnedPaths(ImmutableSet.of()).fallbackCodeOwners())
.isEqualTo(FallbackCodeOwners.NONE);
}
@Test
@GerritConfig(name = "plugin.code-owners.fallbackCodeOwners", value = "ALL_USERS")
public void createInputForComputingOwnedPaths_withFallbackCodeOwnersAllUsers() {
assertThat(createInputForComputingOwnedPaths(ImmutableSet.of()).fallbackCodeOwners())
.isEqualTo(FallbackCodeOwners.ALL_USERS);
}
@Test
public void createInputForComputingOwnedPaths_checkAllOwnersIsTrue() {
assertThat(createInputForComputingOwnedPaths(ImmutableSet.of()).checkAllOwners()).isTrue();
}
private void disableSelfCodeReviewApprovals() throws Exception {
disableSelfApprovals(allProjects, "Code-Review");
}
private void disableSelfOwnersOverrideApprovals() throws Exception {
disableSelfApprovals(project, "Owners-Override");
}
private void disableSelfApprovals(Project.NameKey project, String labelName) throws Exception {
LabelDefinitionInput input = new LabelDefinitionInput();
input.ignoreSelfApproval = true;
gApi.projects().name(project.get()).label(labelName).update(input);
}
private ChangeApi changeApi() throws RestApiException {
return gApi.changes().id(changeId.get());
}
private CodeOwnerApprovalCheckInput loadInput() {
ChangeNotes changeNotes = changeNotesFactory.create(project, changeId);
return inputLoaderFactory.create(codeOwnersConfig, codeOwnerResolver, changeNotes).load();
}
private CodeOwnerApprovalCheckInput createInputForComputingOwnedPaths(
ImmutableSet<Account.Id> accounts) {
ChangeNotes changeNotes = changeNotesFactory.create(project, changeId);
return CodeOwnerApprovalCheckInput.createForComputingOwnedPaths(
codeOwnersConfig, codeOwnerResolver, changeNotes, accounts);
}
}