| // 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.acceptance.api.change; |
| |
| import static com.google.common.truth.Truth.assertThat; |
| import static com.google.gerrit.acceptance.testsuite.project.TestProjectUpdate.allowLabel; |
| import static com.google.gerrit.server.group.SystemGroupBackend.REGISTERED_USERS; |
| import static com.google.gerrit.server.project.testing.TestLabels.labelBuilder; |
| import static com.google.gerrit.server.project.testing.TestLabels.value; |
| import static com.google.gerrit.testing.GerritJUnit.assertThrows; |
| |
| import com.google.common.collect.ImmutableList; |
| import com.google.common.collect.ImmutableSet; |
| import com.google.common.collect.Iterables; |
| import com.google.gerrit.acceptance.AbstractDaemonTest; |
| import com.google.gerrit.acceptance.PushOneCommit; |
| import com.google.gerrit.acceptance.TestAccount; |
| import com.google.gerrit.acceptance.testsuite.project.ProjectOperations; |
| import com.google.gerrit.acceptance.testsuite.request.RequestScopeOperations; |
| import com.google.gerrit.common.Nullable; |
| import com.google.gerrit.common.RawInputUtil; |
| import com.google.gerrit.entities.AccountGroup; |
| import com.google.gerrit.entities.Change; |
| import com.google.gerrit.entities.LabelId; |
| import com.google.gerrit.entities.LabelType; |
| import com.google.gerrit.entities.LabelTypes; |
| import com.google.gerrit.entities.LabelValue; |
| import com.google.gerrit.entities.PatchSet; |
| import com.google.gerrit.entities.PatchSetApproval; |
| import com.google.gerrit.entities.RefNames; |
| import com.google.gerrit.extensions.api.changes.ReviewInput; |
| import com.google.gerrit.extensions.common.ChangeInfo; |
| import com.google.gerrit.server.approval.ApprovalCopier; |
| import com.google.gerrit.server.approval.ApprovalsUtil; |
| import com.google.gerrit.server.group.SystemGroupBackend; |
| import com.google.gerrit.server.project.testing.TestLabels; |
| import com.google.gerrit.server.util.AccountTemplateUtil; |
| import com.google.gerrit.server.util.time.TimeUtil; |
| import com.google.inject.Inject; |
| import org.junit.Test; |
| |
| /** |
| * Tests to verify that copied/outdated approvals are included into the change message that is |
| * posted on patch set creation. Includes verifying that the copied/outdated approvals in the change |
| * message are correctly formatted. |
| * |
| * <p>Some of the tests only verify the correct formatting of the copied/outdated approvals in the |
| * change message that is done by {@link |
| * ApprovalsUtil#formatApprovalCopierResult(com.google.gerrit.server.approval.ApprovalCopier.Result, |
| * LabelTypes)}. This method does the formatting based on the inputs that it gets, but it doesn't do |
| * any verification of these inputs. This means it's possible to provide inputs that are |
| * inconsistent with the approval copying logic in {@link ApprovalCopier}. E.g. it's possible to |
| * provide "is:MAX" as a passing atom for a "Code-Review-1" vote and have "is:MAX" highlighted as |
| * passing in the message although the "Code-Review-1" vote doesn't match with "is:MAX". For easier |
| * readability the formatting tests avoid using such inconsistent input data, but it's not |
| * impossible that in some cases we made a mistake and the input data is inconsistent. |
| */ |
| public class CopiedApprovalsInChangeMessageIT extends AbstractDaemonTest { |
| @Inject private ApprovalsUtil approvalsUtil; |
| @Inject private ProjectOperations projectOperations; |
| @Inject private RequestScopeOperations requestScopeOperations; |
| |
| @Test |
| public void cannotFormatWithNullApprovalCopierResult() throws Exception { |
| LabelTypes labelTypes = projectCache.get(project).get().getLabelTypes(); |
| NullPointerException exception = |
| assertThrows( |
| NullPointerException.class, |
| () -> |
| approvalsUtil.formatApprovalCopierResult( |
| /* approvalCopierResult= */ null, labelTypes)); |
| assertThat(exception).hasMessageThat().isEqualTo("approvalCopierResult"); |
| } |
| |
| @Test |
| public void cannotFormatWithNullLabelTypes() throws Exception { |
| ApprovalCopier.Result approvalCopierResult = |
| ApprovalCopier.Result.create( |
| /* copiedApprovals= */ ImmutableSet.of(), /* outdatedApprovals= */ ImmutableSet.of()); |
| NullPointerException exception = |
| assertThrows( |
| NullPointerException.class, |
| () -> |
| approvalsUtil.formatApprovalCopierResult( |
| approvalCopierResult, /* labelTypes= */ null)); |
| assertThat(exception).hasMessageThat().isEqualTo("labelTypes"); |
| } |
| |
| @Test |
| public void format_noCopiedApprovals_noOutdatedApprovals() throws Exception { |
| LabelTypes labelTypes = projectCache.get(project).get().getLabelTypes(); |
| ApprovalCopier.Result approvalCopierResult = |
| ApprovalCopier.Result.create( |
| /* copiedApprovals= */ ImmutableSet.of(), /* outdatedApprovals= */ ImmutableSet.of()); |
| assertThat(approvalsUtil.formatApprovalCopierResult(approvalCopierResult, labelTypes)) |
| .isEmpty(); |
| } |
| |
| @Test |
| public void formatCopiedApproval_missingLabelType() throws Exception { |
| LabelTypes labelTypes = new LabelTypes(ImmutableList.of()); |
| PatchSetApproval patchSetApproval = createPatchSetApproval(admin, "Code-Review", 1); |
| ApprovalCopier.Result approvalCopierResult = |
| ApprovalCopier.Result.create( |
| /* copiedApprovals= */ ImmutableSet.of( |
| ApprovalCopier.Result.PatchSetApprovalData.create( |
| patchSetApproval, |
| /* passingAtoms= */ ImmutableSet.of(), |
| /* failingAtoms= */ ImmutableSet.of())), |
| /* outdatedApprovals= */ ImmutableSet.of()); |
| assertThat(approvalsUtil.formatApprovalCopierResult(approvalCopierResult, labelTypes)) |
| .hasValue("Copied Votes:\n* Code-Review+1 (label type is missing)\n"); |
| } |
| |
| @Test |
| public void formatOutdatedApproval_missingLabelType() throws Exception { |
| LabelTypes labelTypes = new LabelTypes(ImmutableList.of()); |
| PatchSetApproval patchSetApproval = createPatchSetApproval(admin, "Code-Review", 1); |
| ApprovalCopier.Result approvalCopierResult = |
| ApprovalCopier.Result.create( |
| /* copiedApprovals= */ ImmutableSet.of(), |
| /* outdatedApprovals= */ ImmutableSet.of( |
| ApprovalCopier.Result.PatchSetApprovalData.create( |
| patchSetApproval, |
| /* passingAtoms= */ ImmutableSet.of(), |
| /* failingAtoms= */ ImmutableSet.of()))); |
| assertThat(approvalsUtil.formatApprovalCopierResult(approvalCopierResult, labelTypes)) |
| .hasValue("Outdated Votes:\n* Code-Review+1 (label type is missing)\n"); |
| } |
| |
| @Test |
| public void formatCopiedApproval_noCopyCondition() throws Exception { |
| LabelTypes labelTypes = |
| new LabelTypes( |
| ImmutableList.of( |
| createLabelType(/* labelName= */ "Code-Review", /* copyCondition= */ null))); |
| PatchSetApproval patchSetApproval = createPatchSetApproval(admin, "Code-Review", 1); |
| ApprovalCopier.Result approvalCopierResult = |
| ApprovalCopier.Result.create( |
| /* copiedApprovals= */ ImmutableSet.of( |
| ApprovalCopier.Result.PatchSetApprovalData.create( |
| patchSetApproval, |
| /* passingAtoms= */ ImmutableSet.of(), |
| /* failingAtoms= */ ImmutableSet.of())), |
| /* outdatedApprovals= */ ImmutableSet.of()); |
| assertThat(approvalsUtil.formatApprovalCopierResult(approvalCopierResult, labelTypes)) |
| .hasValue("Copied Votes:\n* Code-Review+1\n"); |
| } |
| |
| @Test |
| public void formatOutdatedApproval_noCopyCondition() throws Exception { |
| LabelTypes labelTypes = |
| new LabelTypes( |
| ImmutableList.of( |
| createLabelType(/* labelName= */ "Code-Review", /* copyCondition= */ null))); |
| PatchSetApproval patchSetApproval = createPatchSetApproval(admin, "Code-Review", 1); |
| ApprovalCopier.Result approvalCopierResult = |
| ApprovalCopier.Result.create( |
| /* copiedApprovals= */ ImmutableSet.of(), |
| /* outdatedApprovals= */ ImmutableSet.of( |
| ApprovalCopier.Result.PatchSetApprovalData.create( |
| patchSetApproval, |
| /* passingAtoms= */ ImmutableSet.of(), |
| /* failingAtoms= */ ImmutableSet.of()))); |
| assertThat(approvalsUtil.formatApprovalCopierResult(approvalCopierResult, labelTypes)) |
| .hasValue("Outdated Votes:\n* Code-Review+1\n"); |
| } |
| |
| @Test |
| public void formatCopiedApproval_withCopyCondition_noUserInPredicate() throws Exception { |
| LabelTypes labelTypes = |
| new LabelTypes( |
| ImmutableList.of( |
| createLabelType( |
| /* labelName= */ "Code-Review", /* copyCondition= */ "is:MIN OR is:MAX"))); |
| PatchSetApproval patchSetApproval = createPatchSetApproval(admin, "Code-Review", -2); |
| ApprovalCopier.Result approvalCopierResult = |
| ApprovalCopier.Result.create( |
| /* copiedApprovals= */ ImmutableSet.of( |
| ApprovalCopier.Result.PatchSetApprovalData.create( |
| patchSetApproval, |
| /* passingAtoms= */ ImmutableSet.of("is:MIN"), |
| /* failingAtoms= */ ImmutableSet.of("is:MAX"))), |
| /* outdatedApprovals= */ ImmutableSet.of()); |
| assertThat(approvalsUtil.formatApprovalCopierResult(approvalCopierResult, labelTypes)) |
| .hasValue("Copied Votes:\n* Code-Review-2 (copy condition: \"**is:MIN** OR is:MAX\")\n"); |
| } |
| |
| @Test |
| public void formatOutdatedApproval_withCopyCondition_noUserInPredicate() throws Exception { |
| LabelTypes labelTypes = |
| new LabelTypes( |
| ImmutableList.of( |
| createLabelType( |
| /* labelName= */ "Code-Review", |
| /* copyCondition= */ "changekind:TRIVIAL_REBASE is:MAX"))); |
| PatchSetApproval patchSetApproval = createPatchSetApproval(admin, "Code-Review", 2); |
| ApprovalCopier.Result approvalCopierResult = |
| ApprovalCopier.Result.create( |
| /* copiedApprovals= */ ImmutableSet.of(), |
| /* outdatedApprovals= */ ImmutableSet.of( |
| ApprovalCopier.Result.PatchSetApprovalData.create( |
| patchSetApproval, |
| /* passingAtoms= */ ImmutableSet.of("is:MAX"), |
| /* failingAtoms= */ ImmutableSet.of("changekind:TRIVIAL_REBASE")))); |
| assertThat(approvalsUtil.formatApprovalCopierResult(approvalCopierResult, labelTypes)) |
| .hasValue( |
| "Outdated Votes:\n* Code-Review+2 (copy condition:" |
| + " \"changekind:TRIVIAL_REBASE **is:MAX**\")\n"); |
| } |
| |
| @Test |
| public void formatCopiedApproval_withNonParseableCopyCondition_noUserInPredicate() |
| throws Exception { |
| LabelTypes labelTypes = |
| new LabelTypes( |
| ImmutableList.of( |
| createLabelType( |
| /* labelName= */ "Code-Review", /* copyCondition= */ "foo bar baz"))); |
| PatchSetApproval patchSetApproval = createPatchSetApproval(admin, "Code-Review", 1); |
| ApprovalCopier.Result approvalCopierResult = |
| ApprovalCopier.Result.create( |
| /* copiedApprovals= */ ImmutableSet.of( |
| ApprovalCopier.Result.PatchSetApprovalData.create( |
| patchSetApproval, |
| /* passingAtoms= */ ImmutableSet.of(), |
| /* failingAtoms= */ ImmutableSet.of())), |
| /* outdatedApprovals= */ ImmutableSet.of()); |
| assertThat(approvalsUtil.formatApprovalCopierResult(approvalCopierResult, labelTypes)) |
| .hasValue( |
| "Copied Votes:\n* Code-Review+1 (non-parseable copy condition: \"foo bar baz\")\n"); |
| } |
| |
| @Test |
| public void formatOutdatedApproval_withNonParseableCopyCondition_noUserInPredicate() |
| throws Exception { |
| LabelTypes labelTypes = |
| new LabelTypes( |
| ImmutableList.of( |
| createLabelType( |
| /* labelName= */ "Code-Review", /* copyCondition= */ "foo bar baz"))); |
| PatchSetApproval patchSetApproval = createPatchSetApproval(admin, "Code-Review", 1); |
| ApprovalCopier.Result approvalCopierResult = |
| ApprovalCopier.Result.create( |
| /* copiedApprovals= */ ImmutableSet.of(), |
| /* outdatedApprovals= */ ImmutableSet.of( |
| ApprovalCopier.Result.PatchSetApprovalData.create( |
| patchSetApproval, |
| /* passingAtoms= */ ImmutableSet.of(), |
| /* failingAtoms= */ ImmutableSet.of()))); |
| assertThat(approvalsUtil.formatApprovalCopierResult(approvalCopierResult, labelTypes)) |
| .hasValue( |
| "Outdated Votes:\n* Code-Review+1 (non-parseable copy condition: \"foo bar baz\")\n"); |
| } |
| |
| @Test |
| public void formatCopiedApproval_withCopyCondition_withUserInPredicate() throws Exception { |
| String groupUuid = |
| groupCache.get(AccountGroup.nameKey("Administrators")).get().getGroupUUID().get(); |
| LabelTypes labelTypes = |
| new LabelTypes( |
| ImmutableList.of( |
| createLabelType( |
| /* labelName= */ "Code-Review", |
| /* copyCondition= */ String.format( |
| "is:MIN OR (is:MAX approverin:%s)", groupUuid)))); |
| PatchSetApproval patchSetApproval = createPatchSetApproval(admin, "Code-Review", 2); |
| ApprovalCopier.Result approvalCopierResult = |
| ApprovalCopier.Result.create( |
| /* copiedApprovals= */ ImmutableSet.of( |
| ApprovalCopier.Result.PatchSetApprovalData.create( |
| patchSetApproval, |
| /* passingAtoms= */ ImmutableSet.of( |
| "is:MAX", String.format("approverin:%s", groupUuid)), |
| /* failingAtoms= */ ImmutableSet.of("is:MIN"))), |
| /* outdatedApprovals= */ ImmutableSet.of()); |
| assertThat(approvalsUtil.formatApprovalCopierResult(approvalCopierResult, labelTypes)) |
| .hasValue( |
| String.format( |
| "Copied Votes:\n" |
| + "* Code-Review+2 by %s" |
| + " (copy condition: \"is:MIN OR (**is:MAX** **approverin:%s**)\")\n", |
| AccountTemplateUtil.getAccountTemplate(admin.id()), groupUuid)); |
| } |
| |
| @Test |
| public void formatOutdatedpproval_withCopyCondition_withUserInPredicate() throws Exception { |
| String groupUuid = |
| groupCache.get(AccountGroup.nameKey("Administrators")).get().getGroupUUID().get(); |
| LabelTypes labelTypes = |
| new LabelTypes( |
| ImmutableList.of( |
| createLabelType( |
| /* labelName= */ "Code-Review", |
| /* copyCondition= */ String.format( |
| "is:MIN OR (is:MAX approverin:%s)", groupUuid)))); |
| PatchSetApproval patchSetApproval = createPatchSetApproval(admin, "Code-Review", 1); |
| ApprovalCopier.Result approvalCopierResult = |
| ApprovalCopier.Result.create( |
| /* copiedApprovals= */ ImmutableSet.of(), |
| /* outdatedApprovals= */ ImmutableSet.of( |
| ApprovalCopier.Result.PatchSetApprovalData.create( |
| patchSetApproval, |
| /* passingAtoms= */ ImmutableSet.of(String.format("approverin:%s", groupUuid)), |
| /* failingAtoms= */ ImmutableSet.of("is:MIN", "is:MAX")))); |
| assertThat(approvalsUtil.formatApprovalCopierResult(approvalCopierResult, labelTypes)) |
| .hasValue( |
| String.format( |
| "Outdated Votes:\n" |
| + "* Code-Review+1 by %s (copy condition: \"is:MIN" |
| + " OR (is:MAX **approverin:%s**)\")\n", |
| AccountTemplateUtil.getAccountTemplate(admin.id()), groupUuid)); |
| } |
| |
| @Test |
| public void formatCopiedApproval_withCopyCondition_withUserInPredicateThatContainNonVisibleGroup() |
| throws Exception { |
| String groupUuid = |
| groupCache.get(AccountGroup.nameKey("Administrators")).get().getGroupUUID().get(); |
| LabelTypes labelTypes = |
| new LabelTypes( |
| ImmutableList.of( |
| createLabelType( |
| /* labelName= */ "Code-Review", |
| /* copyCondition= */ String.format( |
| "is:MIN OR (is:MAX approverin:%s)", groupUuid)))); |
| PatchSetApproval patchSetApproval = createPatchSetApproval(admin, "Code-Review", 2); |
| ApprovalCopier.Result approvalCopierResult = |
| ApprovalCopier.Result.create( |
| /* copiedApprovals= */ ImmutableSet.of( |
| ApprovalCopier.Result.PatchSetApprovalData.create( |
| patchSetApproval, |
| /* passingAtoms= */ ImmutableSet.of( |
| "is:MAX", String.format("approverin:%s", groupUuid)), |
| /* failingAtoms= */ ImmutableSet.of("is:MIN"))), |
| /* outdatedApprovals= */ ImmutableSet.of()); |
| |
| // Set 'user' as the current user in the request scope. |
| // 'user' cannot see the Administrators group that is used in the copy condition. |
| // Parsing the copy condition should still succeed since ApprovalsUtil should use the internal |
| // user that can see everything when parsing the copy condition. |
| requestScopeOperations.setApiUser(user.id()); |
| |
| assertThat(approvalsUtil.formatApprovalCopierResult(approvalCopierResult, labelTypes)) |
| .hasValue( |
| String.format( |
| "Copied Votes:\n" |
| + "* Code-Review+2 by %s" |
| + " (copy condition: \"is:MIN OR (**is:MAX** **approverin:%s**)\")\n", |
| AccountTemplateUtil.getAccountTemplate(admin.id()), groupUuid)); |
| } |
| |
| @Test |
| public void |
| formatOutdatedpproval_withCopyCondition_withUserInPredicateThatContainNonVisibleGroup() |
| throws Exception { |
| String groupUuid = |
| groupCache.get(AccountGroup.nameKey("Administrators")).get().getGroupUUID().get(); |
| LabelTypes labelTypes = |
| new LabelTypes( |
| ImmutableList.of( |
| createLabelType( |
| /* labelName= */ "Code-Review", |
| /* copyCondition= */ String.format( |
| "is:MIN OR (is:MAX approverin:%s)", groupUuid)))); |
| PatchSetApproval patchSetApproval = createPatchSetApproval(admin, "Code-Review", 1); |
| ApprovalCopier.Result approvalCopierResult = |
| ApprovalCopier.Result.create( |
| /* copiedApprovals= */ ImmutableSet.of(), |
| /* outdatedApprovals= */ ImmutableSet.of( |
| ApprovalCopier.Result.PatchSetApprovalData.create( |
| patchSetApproval, |
| /* passingAtoms= */ ImmutableSet.of(String.format("approverin:%s", groupUuid)), |
| /* failingAtoms= */ ImmutableSet.of("is:MIN", "is:MAX")))); |
| |
| // Set 'user' as the current user in the request scope. |
| // 'user' cannot see the Administrators group that is used in the copy condition. |
| // Parsing the copy condition should still succeed since ApprovalsUtil should use the internal |
| // user that can see everything when parsing the copy condition. |
| requestScopeOperations.setApiUser(user.id()); |
| |
| assertThat(approvalsUtil.formatApprovalCopierResult(approvalCopierResult, labelTypes)) |
| .hasValue( |
| String.format( |
| "Outdated Votes:\n" |
| + "* Code-Review+1 by %s (copy condition: \"is:MIN" |
| + " OR (is:MAX **approverin:%s**)\")\n", |
| AccountTemplateUtil.getAccountTemplate(admin.id()), groupUuid)); |
| } |
| |
| @Test |
| public void formatCopiedApproval_withNonParseableCopyCondition_withUserInPredicate() |
| throws Exception { |
| String groupUuid = |
| groupCache.get(AccountGroup.nameKey("Administrators")).get().getGroupUUID().get(); |
| LabelTypes labelTypes = |
| new LabelTypes( |
| ImmutableList.of( |
| createLabelType( |
| /* labelName= */ "Code-Review", |
| /* copyCondition= */ String.format( |
| "is:MIN OR (is:MAX approverin:%s) OR foo bar baz", groupUuid)))); |
| PatchSetApproval patchSetApproval = createPatchSetApproval(admin, "Code-Review", 1); |
| ApprovalCopier.Result approvalCopierResult = |
| ApprovalCopier.Result.create( |
| /* copiedApprovals= */ ImmutableSet.of( |
| ApprovalCopier.Result.PatchSetApprovalData.create( |
| patchSetApproval, |
| /* passingAtoms= */ ImmutableSet.of(), |
| /* failingAtoms= */ ImmutableSet.of())), |
| /* outdatedApprovals= */ ImmutableSet.of()); |
| assertThat(approvalsUtil.formatApprovalCopierResult(approvalCopierResult, labelTypes)) |
| .hasValue( |
| String.format( |
| "Copied Votes:\n" |
| + "* Code-Review+1 (non-parseable copy condition: \"is:MIN" |
| + " OR (is:MAX approverin:%s) OR foo bar baz\")\n", |
| groupUuid)); |
| } |
| |
| @Test |
| public void formatOutdatedApproval_withNonParseableCopyCondition_withUserInPredicate() |
| throws Exception { |
| String groupUuid = |
| groupCache.get(AccountGroup.nameKey("Administrators")).get().getGroupUUID().get(); |
| LabelTypes labelTypes = |
| new LabelTypes( |
| ImmutableList.of( |
| createLabelType( |
| /* labelName= */ "Code-Review", |
| /* copyCondition= */ String.format( |
| "is:MIN OR (is:MAX approverin:%s) OR foo bar baz", groupUuid)))); |
| PatchSetApproval patchSetApproval = createPatchSetApproval(admin, "Code-Review", 1); |
| ApprovalCopier.Result approvalCopierResult = |
| ApprovalCopier.Result.create( |
| /* copiedApprovals= */ ImmutableSet.of(), |
| /* outdatedApprovals= */ ImmutableSet.of( |
| ApprovalCopier.Result.PatchSetApprovalData.create( |
| patchSetApproval, |
| /* passingAtoms= */ ImmutableSet.of(), |
| /* failingAtoms= */ ImmutableSet.of()))); |
| assertThat(approvalsUtil.formatApprovalCopierResult(approvalCopierResult, labelTypes)) |
| .hasValue( |
| String.format( |
| "Outdated Votes:\n" |
| + "* Code-Review+1 (non-parseable copy condition: \"is:MIN" |
| + " OR (is:MAX approverin:%s) OR foo bar baz\")\n", |
| groupUuid)); |
| } |
| |
| @Test |
| public void formatMultipleApprovals_sameVote_missingLabelType() throws Exception { |
| LabelTypes labelTypes = new LabelTypes(ImmutableList.of()); |
| PatchSetApproval patchSetApproval1 = createPatchSetApproval(admin, "Code-Review", 1); |
| PatchSetApproval patchSetApproval2 = createPatchSetApproval(user, "Code-Review", 1); |
| ApprovalCopier.Result approvalCopierResult = |
| ApprovalCopier.Result.create( |
| /* copiedApprovals= */ ImmutableSet.of( |
| ApprovalCopier.Result.PatchSetApprovalData.create( |
| patchSetApproval1, |
| /* passingAtoms= */ ImmutableSet.of(), |
| /* failingAtoms= */ ImmutableSet.of()), |
| ApprovalCopier.Result.PatchSetApprovalData.create( |
| patchSetApproval2, |
| /* passingAtoms= */ ImmutableSet.of(), |
| /* failingAtoms= */ ImmutableSet.of())), |
| /* outdatedApprovals= */ ImmutableSet.of()); |
| assertThat(approvalsUtil.formatApprovalCopierResult(approvalCopierResult, labelTypes)) |
| .hasValue("Copied Votes:\n* Code-Review+1 (label type is missing)\n"); |
| } |
| |
| @Test |
| public void formatMultipleApprovals_differentLabels_missingLabelType() throws Exception { |
| LabelTypes labelTypes = new LabelTypes(ImmutableList.of()); |
| PatchSetApproval patchSetApproval1 = createPatchSetApproval(admin, "Code-Review", 1); |
| PatchSetApproval patchSetApproval2 = createPatchSetApproval(user, "Verified", 1); |
| ApprovalCopier.Result approvalCopierResult = |
| ApprovalCopier.Result.create( |
| /* copiedApprovals= */ ImmutableSet.of( |
| ApprovalCopier.Result.PatchSetApprovalData.create( |
| patchSetApproval1, |
| /* passingAtoms= */ ImmutableSet.of(), |
| /* failingAtoms= */ ImmutableSet.of()), |
| ApprovalCopier.Result.PatchSetApprovalData.create( |
| patchSetApproval2, |
| /* passingAtoms= */ ImmutableSet.of(), |
| /* failingAtoms= */ ImmutableSet.of())), |
| /* outdatedApprovals= */ ImmutableSet.of()); |
| assertThat(approvalsUtil.formatApprovalCopierResult(approvalCopierResult, labelTypes)) |
| .hasValue( |
| "Copied Votes:\n" |
| + "* Code-Review+1 (label type is missing)\n" |
| + "* Verified+1 (label type is missing)\n"); |
| } |
| |
| @Test |
| public void formatMultipleApprovals_differentValues_missingLabelType() throws Exception { |
| LabelTypes labelTypes = new LabelTypes(ImmutableList.of()); |
| PatchSetApproval patchSetApproval1 = createPatchSetApproval(admin, "Code-Review", 2); |
| PatchSetApproval patchSetApproval2 = createPatchSetApproval(user, "Code-Review", 1); |
| ApprovalCopier.Result approvalCopierResult = |
| ApprovalCopier.Result.create( |
| /* copiedApprovals= */ ImmutableSet.of( |
| ApprovalCopier.Result.PatchSetApprovalData.create( |
| patchSetApproval1, |
| /* passingAtoms= */ ImmutableSet.of(), |
| /* failingAtoms= */ ImmutableSet.of()), |
| ApprovalCopier.Result.PatchSetApprovalData.create( |
| patchSetApproval2, |
| /* passingAtoms= */ ImmutableSet.of(), |
| /* failingAtoms= */ ImmutableSet.of())), |
| /* outdatedApprovals= */ ImmutableSet.of()); |
| assertThat(approvalsUtil.formatApprovalCopierResult(approvalCopierResult, labelTypes)) |
| .hasValue("Copied Votes:\n* Code-Review+1, Code-Review+2 (label type is missing)\n"); |
| } |
| |
| @Test |
| public void formatMultipleApprovals_sameVote_noCopyCondition() throws Exception { |
| LabelTypes labelTypes = |
| new LabelTypes( |
| ImmutableList.of( |
| createLabelType(/* labelName= */ "Code-Review", /* copyCondition= */ null))); |
| PatchSetApproval patchSetApproval1 = createPatchSetApproval(admin, "Code-Review", 1); |
| PatchSetApproval patchSetApproval2 = createPatchSetApproval(user, "Code-Review", 1); |
| ApprovalCopier.Result approvalCopierResult = |
| ApprovalCopier.Result.create( |
| /* copiedApprovals= */ ImmutableSet.of( |
| ApprovalCopier.Result.PatchSetApprovalData.create( |
| patchSetApproval1, |
| /* passingAtoms= */ ImmutableSet.of(), |
| /* failingAtoms= */ ImmutableSet.of()), |
| ApprovalCopier.Result.PatchSetApprovalData.create( |
| patchSetApproval2, |
| /* passingAtoms= */ ImmutableSet.of(), |
| /* failingAtoms= */ ImmutableSet.of())), |
| /* outdatedApprovals= */ ImmutableSet.of()); |
| assertThat(approvalsUtil.formatApprovalCopierResult(approvalCopierResult, labelTypes)) |
| .hasValue("Copied Votes:\n* Code-Review+1\n"); |
| } |
| |
| @Test |
| public void formatMultipleApprovals_differentLabel_noCopyCondition() throws Exception { |
| LabelTypes labelTypes = |
| new LabelTypes( |
| ImmutableList.of( |
| createLabelType(/* labelName= */ "Code-Review", /* copyCondition= */ null), |
| createLabelType(/* labelName= */ "Verified", /* copyCondition= */ null))); |
| PatchSetApproval patchSetApproval1 = createPatchSetApproval(admin, "Code-Review", 1); |
| PatchSetApproval patchSetApproval2 = createPatchSetApproval(user, "Verified", 1); |
| ApprovalCopier.Result approvalCopierResult = |
| ApprovalCopier.Result.create( |
| /* copiedApprovals= */ ImmutableSet.of( |
| ApprovalCopier.Result.PatchSetApprovalData.create( |
| patchSetApproval1, |
| /* passingAtoms= */ ImmutableSet.of(), |
| /* failingAtoms= */ ImmutableSet.of()), |
| ApprovalCopier.Result.PatchSetApprovalData.create( |
| patchSetApproval2, |
| /* passingAtoms= */ ImmutableSet.of(), |
| /* failingAtoms= */ ImmutableSet.of())), |
| /* outdatedApprovals= */ ImmutableSet.of()); |
| assertThat(approvalsUtil.formatApprovalCopierResult(approvalCopierResult, labelTypes)) |
| .hasValue("Copied Votes:\n* Code-Review+1\n* Verified+1\n"); |
| } |
| |
| @Test |
| public void formatMultipleApprovals_differentValue_noCopyCondition() throws Exception { |
| LabelTypes labelTypes = |
| new LabelTypes( |
| ImmutableList.of( |
| createLabelType(/* labelName= */ "Code-Review", /* copyCondition= */ null))); |
| PatchSetApproval patchSetApproval1 = createPatchSetApproval(admin, "Code-Review", 2); |
| PatchSetApproval patchSetApproval2 = createPatchSetApproval(user, "Code-Review", 1); |
| ApprovalCopier.Result approvalCopierResult = |
| ApprovalCopier.Result.create( |
| /* copiedApprovals= */ ImmutableSet.of( |
| ApprovalCopier.Result.PatchSetApprovalData.create( |
| patchSetApproval1, |
| /* passingAtoms= */ ImmutableSet.of(), |
| /* failingAtoms= */ ImmutableSet.of()), |
| ApprovalCopier.Result.PatchSetApprovalData.create( |
| patchSetApproval2, |
| /* passingAtoms= */ ImmutableSet.of(), |
| /* failingAtoms= */ ImmutableSet.of())), |
| /* outdatedApprovals= */ ImmutableSet.of()); |
| assertThat(approvalsUtil.formatApprovalCopierResult(approvalCopierResult, labelTypes)) |
| .hasValue("Copied Votes:\n* Code-Review+1, Code-Review+2\n"); |
| } |
| |
| @Test |
| public void formatMultipleApprovals_sameVote_withCopyCondition_noUserInPredicate() |
| throws Exception { |
| LabelTypes labelTypes = |
| new LabelTypes( |
| ImmutableList.of( |
| createLabelType( |
| /* labelName= */ "Code-Review", /* copyCondition= */ "is:MIN OR is:MAX"))); |
| PatchSetApproval patchSetApproval1 = createPatchSetApproval(admin, "Code-Review", 2); |
| PatchSetApproval patchSetApproval2 = createPatchSetApproval(user, "Code-Review", 2); |
| ApprovalCopier.Result approvalCopierResult = |
| ApprovalCopier.Result.create( |
| /* copiedApprovals= */ ImmutableSet.of( |
| ApprovalCopier.Result.PatchSetApprovalData.create( |
| patchSetApproval1, |
| /* passingAtoms= */ ImmutableSet.of("is:MAX"), |
| /* failingAtoms= */ ImmutableSet.of("is:MIN")), |
| ApprovalCopier.Result.PatchSetApprovalData.create( |
| patchSetApproval2, |
| /* passingAtoms= */ ImmutableSet.of("is:MAX"), |
| /* failingAtoms= */ ImmutableSet.of("is:MIN"))), |
| /* outdatedApprovals= */ ImmutableSet.of()); |
| assertThat(approvalsUtil.formatApprovalCopierResult(approvalCopierResult, labelTypes)) |
| .hasValue("Copied Votes:\n* Code-Review+2 (copy condition: \"is:MIN OR **is:MAX**\")\n"); |
| } |
| |
| @Test |
| public void formatMultipleApprovals_differentLabel_withCopyCondition_noUserInPredicate() |
| throws Exception { |
| LabelTypes labelTypes = |
| new LabelTypes( |
| ImmutableList.of( |
| createLabelType( |
| /* labelName= */ "Code-Review", /* copyCondition= */ "is:MIN OR is:MAX"), |
| LabelType.builder( |
| "Verified", |
| ImmutableList.of( |
| LabelValue.create((short) -1, "Fails"), |
| LabelValue.create((short) 0, "No Vote"), |
| LabelValue.create((short) 1, "Succeeds"))) |
| .setCopyCondition("is:MIN OR is:MAX") |
| .build())); |
| PatchSetApproval patchSetApproval1 = createPatchSetApproval(admin, "Code-Review", 2); |
| PatchSetApproval patchSetApproval2 = createPatchSetApproval(user, "Verified", 1); |
| ApprovalCopier.Result approvalCopierResult = |
| ApprovalCopier.Result.create( |
| /* copiedApprovals= */ ImmutableSet.of( |
| ApprovalCopier.Result.PatchSetApprovalData.create( |
| patchSetApproval1, |
| /* passingAtoms= */ ImmutableSet.of("is:MAX"), |
| /* failingAtoms= */ ImmutableSet.of("is:MIN")), |
| ApprovalCopier.Result.PatchSetApprovalData.create( |
| patchSetApproval2, |
| /* passingAtoms= */ ImmutableSet.of("is:MAX"), |
| /* failingAtoms= */ ImmutableSet.of("is:MIN"))), |
| /* outdatedApprovals= */ ImmutableSet.of()); |
| assertThat(approvalsUtil.formatApprovalCopierResult(approvalCopierResult, labelTypes)) |
| .hasValue( |
| "Copied Votes:\n" |
| + "* Code-Review+2 (copy condition: \"is:MIN OR **is:MAX**\")\n" |
| + "* Verified+1 (copy condition: \"is:MIN OR **is:MAX**\")\n"); |
| } |
| |
| @Test |
| public void |
| formatMultipleApprovals_differentValue_withCopyCondition_noUserInPredicate_samePassingAtoms() |
| throws Exception { |
| LabelTypes labelTypes = |
| new LabelTypes( |
| ImmutableList.of( |
| createLabelType( |
| /* labelName= */ "Code-Review", /* copyCondition= */ "changekind:REWORK"))); |
| PatchSetApproval patchSetApproval1 = createPatchSetApproval(admin, "Code-Review", 2); |
| PatchSetApproval patchSetApproval2 = createPatchSetApproval(user, "Code-Review", 1); |
| ApprovalCopier.Result approvalCopierResult = |
| ApprovalCopier.Result.create( |
| /* copiedApprovals= */ ImmutableSet.of( |
| ApprovalCopier.Result.PatchSetApprovalData.create( |
| patchSetApproval1, |
| /* passingAtoms= */ ImmutableSet.of("changekind:REWORK"), |
| /* failingAtoms= */ ImmutableSet.of()), |
| ApprovalCopier.Result.PatchSetApprovalData.create( |
| patchSetApproval2, |
| /* passingAtoms= */ ImmutableSet.of("changekind:REWORK"), |
| /* failingAtoms= */ ImmutableSet.of())), |
| /* outdatedApprovals= */ ImmutableSet.of()); |
| assertThat(approvalsUtil.formatApprovalCopierResult(approvalCopierResult, labelTypes)) |
| .hasValue( |
| "Copied Votes:\n" |
| + "* Code-Review+1, Code-Review+2 (copy condition: \"**changekind:REWORK**\")\n"); |
| } |
| |
| @Test |
| public void |
| formatMultipleApprovals_differentValue_withCopyCondition_noUserInPredicate_differentPassingAtoms() |
| throws Exception { |
| LabelTypes labelTypes = |
| new LabelTypes( |
| ImmutableList.of( |
| createLabelType( |
| /* labelName= */ "Code-Review", /* copyCondition= */ "is:1 OR is:2"))); |
| PatchSetApproval patchSetApproval1 = createPatchSetApproval(admin, "Code-Review", 2); |
| PatchSetApproval patchSetApproval2 = createPatchSetApproval(user, "Code-Review", 1); |
| ApprovalCopier.Result approvalCopierResult = |
| ApprovalCopier.Result.create( |
| /* copiedApprovals= */ ImmutableSet.of( |
| ApprovalCopier.Result.PatchSetApprovalData.create( |
| patchSetApproval1, |
| /* passingAtoms= */ ImmutableSet.of("is:2"), |
| /* failingAtoms= */ ImmutableSet.of("is:1")), |
| ApprovalCopier.Result.PatchSetApprovalData.create( |
| patchSetApproval2, |
| /* passingAtoms= */ ImmutableSet.of("is:1"), |
| /* failingAtoms= */ ImmutableSet.of("is:2"))), |
| /* outdatedApprovals= */ ImmutableSet.of()); |
| assertThat(approvalsUtil.formatApprovalCopierResult(approvalCopierResult, labelTypes)) |
| .hasValue( |
| "Copied Votes:\n" |
| + "* Code-Review+1 (copy condition: \"**is:1** OR is:2\")\n" |
| + "* Code-Review+2 (copy condition: \"is:1 OR **is:2**\")\n"); |
| } |
| |
| @Test |
| public void formatMultipleApprovals_sameVote_withNonParseableCopyCondition_noUserInPredicate() |
| throws Exception { |
| LabelTypes labelTypes = |
| new LabelTypes( |
| ImmutableList.of( |
| createLabelType( |
| /* labelName= */ "Code-Review", /* copyCondition= */ "foo bar baz"))); |
| PatchSetApproval patchSetApproval1 = createPatchSetApproval(admin, "Code-Review", 1); |
| PatchSetApproval patchSetApproval2 = createPatchSetApproval(user, "Code-Review", 1); |
| ApprovalCopier.Result approvalCopierResult = |
| ApprovalCopier.Result.create( |
| /* copiedApprovals= */ ImmutableSet.of( |
| ApprovalCopier.Result.PatchSetApprovalData.create( |
| patchSetApproval1, |
| /* passingAtoms= */ ImmutableSet.of(), |
| /* failingAtoms= */ ImmutableSet.of()), |
| ApprovalCopier.Result.PatchSetApprovalData.create( |
| patchSetApproval2, |
| /* passingAtoms= */ ImmutableSet.of(), |
| /* failingAtoms= */ ImmutableSet.of())), |
| /* outdatedApprovals= */ ImmutableSet.of()); |
| assertThat(approvalsUtil.formatApprovalCopierResult(approvalCopierResult, labelTypes)) |
| .hasValue( |
| "Copied Votes:\n* Code-Review+1 (non-parseable copy condition: \"foo bar baz\")\n"); |
| } |
| |
| @Test |
| public void |
| formatMultipleApprovals_differentLabel_withNonParseableCopyCondition_noUserInPredicate() |
| throws Exception { |
| LabelTypes labelTypes = |
| new LabelTypes( |
| ImmutableList.of( |
| createLabelType(/* labelName= */ "Code-Review", /* copyCondition= */ "foo bar baz"), |
| createLabelType(/* labelName= */ "Verified", /* copyCondition= */ "foo bar baz"))); |
| PatchSetApproval patchSetApproval1 = createPatchSetApproval(admin, "Code-Review", 1); |
| PatchSetApproval patchSetApproval2 = createPatchSetApproval(user, "Verified", 1); |
| ApprovalCopier.Result approvalCopierResult = |
| ApprovalCopier.Result.create( |
| /* copiedApprovals= */ ImmutableSet.of( |
| ApprovalCopier.Result.PatchSetApprovalData.create( |
| patchSetApproval1, |
| /* passingAtoms= */ ImmutableSet.of(), |
| /* failingAtoms= */ ImmutableSet.of()), |
| ApprovalCopier.Result.PatchSetApprovalData.create( |
| patchSetApproval2, |
| /* passingAtoms= */ ImmutableSet.of(), |
| /* failingAtoms= */ ImmutableSet.of())), |
| /* outdatedApprovals= */ ImmutableSet.of()); |
| assertThat(approvalsUtil.formatApprovalCopierResult(approvalCopierResult, labelTypes)) |
| .hasValue( |
| "Copied Votes:\n" |
| + "* Code-Review+1 (non-parseable copy condition: \"foo bar baz\")\n" |
| + "* Verified+1 (non-parseable copy condition: \"foo bar baz\")\n"); |
| } |
| |
| @Test |
| public void |
| formatMultipleApprovals_differentValue_withNonParseableCopyCondition_noUserInPredicate() |
| throws Exception { |
| LabelTypes labelTypes = |
| new LabelTypes( |
| ImmutableList.of( |
| createLabelType( |
| /* labelName= */ "Code-Review", /* copyCondition= */ "foo bar baz"))); |
| PatchSetApproval patchSetApproval1 = createPatchSetApproval(admin, "Code-Review", 2); |
| PatchSetApproval patchSetApproval2 = createPatchSetApproval(user, "Code-Review", 1); |
| ApprovalCopier.Result approvalCopierResult = |
| ApprovalCopier.Result.create( |
| /* copiedApprovals= */ ImmutableSet.of( |
| ApprovalCopier.Result.PatchSetApprovalData.create( |
| patchSetApproval1, |
| /* passingAtoms= */ ImmutableSet.of(), |
| /* failingAtoms= */ ImmutableSet.of()), |
| ApprovalCopier.Result.PatchSetApprovalData.create( |
| patchSetApproval2, |
| /* passingAtoms= */ ImmutableSet.of(), |
| /* failingAtoms= */ ImmutableSet.of())), |
| /* outdatedApprovals= */ ImmutableSet.of()); |
| assertThat(approvalsUtil.formatApprovalCopierResult(approvalCopierResult, labelTypes)) |
| .hasValue( |
| "Copied Votes:\n" |
| + "* Code-Review+1, Code-Review+2" |
| + " (non-parseable copy condition: \"foo bar baz\")\n"); |
| } |
| |
| @Test |
| public void |
| formatMultipleApprovals_sameVote_withCopyCondition_withUserInPredicate_samePassingAtoms() |
| throws Exception { |
| String groupUuid = |
| groupCache.get(AccountGroup.nameKey("Administrators")).get().getGroupUUID().get(); |
| LabelTypes labelTypes = |
| new LabelTypes( |
| ImmutableList.of( |
| createLabelType( |
| /* labelName= */ "Code-Review", |
| /* copyCondition= */ String.format( |
| "is:MIN OR (is:MAX approverin:%s)", groupUuid)))); |
| PatchSetApproval patchSetApproval1 = createPatchSetApproval(user, "Code-Review", 2); |
| PatchSetApproval patchSetApproval2 = createPatchSetApproval(admin, "Code-Review", 2); |
| ApprovalCopier.Result approvalCopierResult = |
| ApprovalCopier.Result.create( |
| /* copiedApprovals= */ ImmutableSet.of( |
| ApprovalCopier.Result.PatchSetApprovalData.create( |
| patchSetApproval1, |
| /* passingAtoms= */ ImmutableSet.of( |
| "is:MAX", String.format("approverin:%s", groupUuid)), |
| /* failingAtoms= */ ImmutableSet.of("is:MIN")), |
| ApprovalCopier.Result.PatchSetApprovalData.create( |
| patchSetApproval2, |
| /* passingAtoms= */ ImmutableSet.of( |
| "is:MAX", String.format("approverin:%s", groupUuid)), |
| /* failingAtoms= */ ImmutableSet.of("is:MIN"))), |
| /* outdatedApprovals= */ ImmutableSet.of()); |
| assertThat(approvalsUtil.formatApprovalCopierResult(approvalCopierResult, labelTypes)) |
| .hasValue( |
| String.format( |
| "Copied Votes:\n" |
| + "* Code-Review+2 by %s, %s" |
| + " (copy condition: \"is:MIN OR (**is:MAX** **approverin:%s**)\")\n", |
| AccountTemplateUtil.getAccountTemplate(admin.id()), |
| AccountTemplateUtil.getAccountTemplate(user.id()), |
| groupUuid)); |
| } |
| |
| @Test |
| public void |
| formatMultipleApprovals_sameVote_withCopyCondition_withUserInPredicate_differentPassingAtoms() |
| throws Exception { |
| String administratorsGroupUuid = |
| groupCache.get(AccountGroup.nameKey("Administrators")).get().getGroupUUID().get(); |
| String registeredUsersGroupUuid = SystemGroupBackend.REGISTERED_USERS.get(); |
| LabelTypes labelTypes = |
| new LabelTypes( |
| ImmutableList.of( |
| createLabelType( |
| /* labelName= */ "Code-Review", |
| /* copyCondition= */ String.format( |
| "is:MIN OR (is:MAX approverin:%s) OR (is:MAX approverin:%s)", |
| administratorsGroupUuid, registeredUsersGroupUuid)))); |
| PatchSetApproval patchSetApproval1 = createPatchSetApproval(user, "Code-Review", 2); |
| PatchSetApproval patchSetApproval2 = createPatchSetApproval(admin, "Code-Review", 2); |
| ApprovalCopier.Result approvalCopierResult = |
| ApprovalCopier.Result.create( |
| /* copiedApprovals= */ ImmutableSet.of( |
| ApprovalCopier.Result.PatchSetApprovalData.create( |
| patchSetApproval1, |
| /* passingAtoms= */ ImmutableSet.of( |
| "is:MAX", String.format("approverin:%s", registeredUsersGroupUuid)), |
| /* failingAtoms= */ ImmutableSet.of( |
| "is:MIN", String.format("approverin:%s", administratorsGroupUuid))), |
| ApprovalCopier.Result.PatchSetApprovalData.create( |
| patchSetApproval2, |
| /* passingAtoms= */ ImmutableSet.of( |
| "is:MAX", |
| String.format("approverin:%s", administratorsGroupUuid), |
| String.format("approverin:%s", registeredUsersGroupUuid)), |
| /* failingAtoms= */ ImmutableSet.of("is:MIN"))), |
| /* outdatedApprovals= */ ImmutableSet.of()); |
| assertThat(approvalsUtil.formatApprovalCopierResult(approvalCopierResult, labelTypes)) |
| .hasValue( |
| String.format( |
| "Copied Votes:\n" |
| + "* Code-Review+2 by %s" |
| + " (copy condition: \"is:MIN OR (**is:MAX** **approverin:%s**)" |
| + " OR (**is:MAX** **approverin:%s**)\")\n" |
| + "* Code-Review+2 by %s" |
| + " (copy condition: \"is:MIN OR (**is:MAX** approverin:%s)" |
| + " OR (**is:MAX** **approverin:%s**)\")\n", |
| AccountTemplateUtil.getAccountTemplate(admin.id()), |
| administratorsGroupUuid, |
| registeredUsersGroupUuid, |
| AccountTemplateUtil.getAccountTemplate(user.id()), |
| administratorsGroupUuid, |
| registeredUsersGroupUuid)); |
| } |
| |
| @Test |
| public void formatMultipleApprovals_differentLabel_withCopyCondition_withUserInPredicate() |
| throws Exception { |
| String groupUuid = |
| groupCache.get(AccountGroup.nameKey("Administrators")).get().getGroupUUID().get(); |
| LabelTypes labelTypes = |
| new LabelTypes( |
| ImmutableList.of( |
| createLabelType( |
| /* labelName= */ "Code-Review", |
| /* copyCondition= */ String.format( |
| "is:MIN OR (is:MAX approverin:%s)", groupUuid)), |
| createLabelType( |
| /* labelName= */ "Verified", |
| /* copyCondition= */ String.format( |
| "is:MIN OR (is:MAX approverin:%s)", groupUuid)))); |
| PatchSetApproval patchSetApproval1 = createPatchSetApproval(user, "Code-Review", -2); |
| PatchSetApproval patchSetApproval2 = createPatchSetApproval(admin, "Verified", 1); |
| ApprovalCopier.Result approvalCopierResult = |
| ApprovalCopier.Result.create( |
| /* copiedApprovals= */ ImmutableSet.of( |
| ApprovalCopier.Result.PatchSetApprovalData.create( |
| patchSetApproval1, |
| /* passingAtoms= */ ImmutableSet.of("is:MIN"), |
| /* failingAtoms= */ ImmutableSet.of( |
| "is:MAX", String.format("approverin:%s", groupUuid))), |
| ApprovalCopier.Result.PatchSetApprovalData.create( |
| patchSetApproval2, |
| /* passingAtoms= */ ImmutableSet.of( |
| "is:MAX", String.format("approverin:%s", groupUuid)), |
| /* failingAtoms= */ ImmutableSet.of("is:MIN"))), |
| /* outdatedApprovals= */ ImmutableSet.of()); |
| assertThat(approvalsUtil.formatApprovalCopierResult(approvalCopierResult, labelTypes)) |
| .hasValue( |
| String.format( |
| "Copied Votes:\n" |
| + "* Code-Review-2 by %s (copy condition: \"**is:MIN**" |
| + " OR (is:MAX approverin:%s)\")\n" |
| + "* Verified+1 by %s (copy condition: \"is:MIN" |
| + " OR (**is:MAX** **approverin:%s**)\")\n", |
| AccountTemplateUtil.getAccountTemplate(user.id()), |
| groupUuid, |
| AccountTemplateUtil.getAccountTemplate(admin.id()), |
| groupUuid)); |
| } |
| |
| @Test |
| public void |
| formatMultipleApprovals_differentValue_withCopyCondition_withUserInPredicate_samePassingAtoms() |
| throws Exception { |
| String groupUuid = |
| groupCache.get(AccountGroup.nameKey("Administrators")).get().getGroupUUID().get(); |
| LabelTypes labelTypes = |
| new LabelTypes( |
| ImmutableList.of( |
| createLabelType( |
| /* labelName= */ "Code-Review", |
| /* copyCondition= */ String.format( |
| "is:MIN OR (is:ANY approverin:%s)", groupUuid)))); |
| PatchSetApproval patchSetApproval1 = createPatchSetApproval(admin, "Code-Review", 2); |
| PatchSetApproval patchSetApproval2 = createPatchSetApproval(user, "Code-Review", 1); |
| ApprovalCopier.Result approvalCopierResult = |
| ApprovalCopier.Result.create( |
| /* copiedApprovals= */ ImmutableSet.of( |
| ApprovalCopier.Result.PatchSetApprovalData.create( |
| patchSetApproval1, |
| /* passingAtoms= */ ImmutableSet.of( |
| "is:ANY", String.format("approverin:%s", groupUuid)), |
| /* failingAtoms= */ ImmutableSet.of("is:MIN")), |
| ApprovalCopier.Result.PatchSetApprovalData.create( |
| patchSetApproval2, |
| /* passingAtoms= */ ImmutableSet.of( |
| "is:ANY", String.format("approverin:%s", groupUuid)), |
| /* failingAtoms= */ ImmutableSet.of("is:MIN"))), |
| /* outdatedApprovals= */ ImmutableSet.of()); |
| assertThat(approvalsUtil.formatApprovalCopierResult(approvalCopierResult, labelTypes)) |
| .hasValue( |
| String.format( |
| "Copied Votes:\n" |
| + "* Code-Review+1 by %s, Code-Review+2 by %s" |
| + " (copy condition: \"is:MIN OR (**is:ANY** **approverin:%s**)\")\n", |
| AccountTemplateUtil.getAccountTemplate(user.id()), |
| AccountTemplateUtil.getAccountTemplate(admin.id()), |
| groupUuid)); |
| } |
| |
| @Test |
| public void |
| formatMultipleApprovals_differentValue_withCopyCondition_withUserInPredicate_differentPassingAtoms() |
| throws Exception { |
| String groupUuid = |
| groupCache.get(AccountGroup.nameKey("Administrators")).get().getGroupUUID().get(); |
| LabelTypes labelTypes = |
| new LabelTypes( |
| ImmutableList.of( |
| createLabelType( |
| /* labelName= */ "Code-Review", |
| /* copyCondition= */ String.format( |
| "is:MIN OR (is:1 approverin:%s) OR (is:2 approverin:%s)", |
| groupUuid, groupUuid)))); |
| PatchSetApproval patchSetApproval1 = createPatchSetApproval(admin, "Code-Review", 2); |
| PatchSetApproval patchSetApproval2 = createPatchSetApproval(user, "Code-Review", 1); |
| ApprovalCopier.Result approvalCopierResult = |
| ApprovalCopier.Result.create( |
| /* copiedApprovals= */ ImmutableSet.of( |
| ApprovalCopier.Result.PatchSetApprovalData.create( |
| patchSetApproval1, |
| /* passingAtoms= */ ImmutableSet.of( |
| "is:2", String.format("approverin:%s", groupUuid)), |
| /* failingAtoms= */ ImmutableSet.of("is:MIN", "is:1")), |
| ApprovalCopier.Result.PatchSetApprovalData.create( |
| patchSetApproval2, |
| /* passingAtoms= */ ImmutableSet.of( |
| "is:1", String.format("approverin:%s", groupUuid)), |
| /* failingAtoms= */ ImmutableSet.of("is:MIN", "is:2"))), |
| /* outdatedApprovals= */ ImmutableSet.of()); |
| assertThat(approvalsUtil.formatApprovalCopierResult(approvalCopierResult, labelTypes)) |
| .hasValue( |
| String.format( |
| "Copied Votes:\n" |
| + "* Code-Review+1 by %s" |
| + " (copy condition: \"is:MIN OR (**is:1** **approverin:%s**)" |
| + " OR (is:2 **approverin:%s**)\")\n" |
| + "* Code-Review+2 by %s" |
| + " (copy condition: \"is:MIN OR (is:1 **approverin:%s**)" |
| + " OR (**is:2** **approverin:%s**)\")\n", |
| AccountTemplateUtil.getAccountTemplate(user.id()), |
| groupUuid, |
| groupUuid, |
| AccountTemplateUtil.getAccountTemplate(admin.id()), |
| groupUuid, |
| groupUuid)); |
| } |
| |
| @Test |
| public void formatMultipleApprovals_differentAndSameValue_withCopyCondition_withUserInPredicate() |
| throws Exception { |
| TestAccount user2 = accountCreator.user2(); |
| String groupUuid = SystemGroupBackend.REGISTERED_USERS.get(); |
| LabelTypes labelTypes = |
| new LabelTypes( |
| ImmutableList.of( |
| createLabelType( |
| /* labelName= */ "Code-Review", |
| /* copyCondition= */ String.format( |
| "is:MIN OR (is:ANY approverin:%s)", groupUuid)))); |
| PatchSetApproval patchSetApproval1 = createPatchSetApproval(admin, "Code-Review", 2); |
| PatchSetApproval patchSetApproval2 = createPatchSetApproval(user2, "Code-Review", 1); |
| PatchSetApproval patchSetApproval3 = createPatchSetApproval(user, "Code-Review", 1); |
| ApprovalCopier.Result approvalCopierResult = |
| ApprovalCopier.Result.create( |
| /* copiedApprovals= */ ImmutableSet.of( |
| ApprovalCopier.Result.PatchSetApprovalData.create( |
| patchSetApproval1, |
| /* passingAtoms= */ ImmutableSet.of( |
| "is:ANY", String.format("approverin:%s", groupUuid)), |
| /* failingAtoms= */ ImmutableSet.of("is:MIN")), |
| ApprovalCopier.Result.PatchSetApprovalData.create( |
| patchSetApproval2, |
| /* passingAtoms= */ ImmutableSet.of( |
| "is:ANY", String.format("approverin:%s", groupUuid)), |
| /* failingAtoms= */ ImmutableSet.of("is:MIN")), |
| ApprovalCopier.Result.PatchSetApprovalData.create( |
| patchSetApproval3, |
| /* passingAtoms= */ ImmutableSet.of( |
| "is:ANY", String.format("approverin:%s", groupUuid)), |
| /* failingAtoms= */ ImmutableSet.of("is:MIN"))), |
| /* outdatedApprovals= */ ImmutableSet.of()); |
| assertThat(approvalsUtil.formatApprovalCopierResult(approvalCopierResult, labelTypes)) |
| .hasValue( |
| String.format( |
| "Copied Votes:\n" |
| + "* Code-Review+1 by %s, %s, Code-Review+2 by %s" |
| + " (copy condition: \"is:MIN OR (**is:ANY** **approverin:%s**)\")\n", |
| AccountTemplateUtil.getAccountTemplate(user.id()), |
| AccountTemplateUtil.getAccountTemplate(user2.id()), |
| AccountTemplateUtil.getAccountTemplate(admin.id()), |
| groupUuid)); |
| } |
| |
| @Test |
| public void formatMultipleApprovals_sameVote_withNonParseableCopyCondition_withUserInPredicate() |
| throws Exception { |
| String groupUuid = |
| groupCache.get(AccountGroup.nameKey("Administrators")).get().getGroupUUID().get(); |
| LabelTypes labelTypes = |
| new LabelTypes( |
| ImmutableList.of( |
| createLabelType( |
| /* labelName= */ "Code-Review", |
| /* copyCondition= */ String.format( |
| "is:MIN OR (is:MAX approverin:%s) OR foo bar baz", groupUuid)))); |
| PatchSetApproval patchSetApproval1 = createPatchSetApproval(admin, "Code-Review", 1); |
| PatchSetApproval patchSetApproval2 = createPatchSetApproval(user, "Code-Review", 1); |
| ApprovalCopier.Result approvalCopierResult = |
| ApprovalCopier.Result.create( |
| /* copiedApprovals= */ ImmutableSet.of( |
| ApprovalCopier.Result.PatchSetApprovalData.create( |
| patchSetApproval1, |
| /* passingAtoms= */ ImmutableSet.of(), |
| /* failingAtoms= */ ImmutableSet.of()), |
| ApprovalCopier.Result.PatchSetApprovalData.create( |
| patchSetApproval2, |
| /* passingAtoms= */ ImmutableSet.of(), |
| /* failingAtoms= */ ImmutableSet.of())), |
| /* outdatedApprovals= */ ImmutableSet.of()); |
| assertThat(approvalsUtil.formatApprovalCopierResult(approvalCopierResult, labelTypes)) |
| .hasValue( |
| String.format( |
| "Copied Votes:\n" |
| + "* Code-Review+1 (non-parseable copy condition: \"is:MIN" |
| + " OR (is:MAX approverin:%s) OR foo bar baz\")\n", |
| groupUuid)); |
| } |
| |
| @Test |
| public void |
| formatMultipleApprovals_differentLabel_withNonParseableCopyCondition_withUserInPredicate() |
| throws Exception { |
| String groupUuid = |
| groupCache.get(AccountGroup.nameKey("Administrators")).get().getGroupUUID().get(); |
| LabelTypes labelTypes = |
| new LabelTypes( |
| ImmutableList.of( |
| createLabelType( |
| /* labelName= */ "Code-Review", |
| /* copyCondition= */ String.format( |
| "is:MIN OR (is:MAX approverin:%s) OR foo bar baz", groupUuid)), |
| createLabelType( |
| /* labelName= */ "Verified", |
| /* copyCondition= */ String.format( |
| "is:MIN OR (is:MAX approverin:%s) OR foo bar baz", groupUuid)))); |
| PatchSetApproval patchSetApproval1 = createPatchSetApproval(admin, "Code-Review", 1); |
| PatchSetApproval patchSetApproval2 = createPatchSetApproval(user, "Verified", 1); |
| ApprovalCopier.Result approvalCopierResult = |
| ApprovalCopier.Result.create( |
| /* copiedApprovals= */ ImmutableSet.of( |
| ApprovalCopier.Result.PatchSetApprovalData.create( |
| patchSetApproval1, |
| /* passingAtoms= */ ImmutableSet.of(), |
| /* failingAtoms= */ ImmutableSet.of()), |
| ApprovalCopier.Result.PatchSetApprovalData.create( |
| patchSetApproval2, |
| /* passingAtoms= */ ImmutableSet.of(), |
| /* failingAtoms= */ ImmutableSet.of())), |
| /* outdatedApprovals= */ ImmutableSet.of()); |
| assertThat(approvalsUtil.formatApprovalCopierResult(approvalCopierResult, labelTypes)) |
| .hasValue( |
| String.format( |
| "Copied Votes:\n" |
| + "* Code-Review+1 (non-parseable copy condition: \"is:MIN" |
| + " OR (is:MAX approverin:%s) OR foo bar baz\")\n" |
| + "* Verified+1 (non-parseable copy condition: \"is:MIN" |
| + " OR (is:MAX approverin:%s) OR foo bar baz\")\n", |
| groupUuid, groupUuid)); |
| } |
| |
| @Test |
| public void |
| formatMultipleApprovals_differentValue_withNonParseableCopyCondition_withUserInPredicate() |
| throws Exception { |
| String groupUuid = |
| groupCache.get(AccountGroup.nameKey("Administrators")).get().getGroupUUID().get(); |
| LabelTypes labelTypes = |
| new LabelTypes( |
| ImmutableList.of( |
| createLabelType( |
| /* labelName= */ "Code-Review", |
| /* copyCondition= */ String.format( |
| "is:MIN OR (is:MAX approverin:%s) OR foo bar baz", groupUuid)))); |
| PatchSetApproval patchSetApproval1 = createPatchSetApproval(admin, "Code-Review", 2); |
| PatchSetApproval patchSetApproval2 = createPatchSetApproval(user, "Code-Review", 1); |
| ApprovalCopier.Result approvalCopierResult = |
| ApprovalCopier.Result.create( |
| /* copiedApprovals= */ ImmutableSet.of( |
| ApprovalCopier.Result.PatchSetApprovalData.create( |
| patchSetApproval1, |
| /* passingAtoms= */ ImmutableSet.of(), |
| /* failingAtoms= */ ImmutableSet.of()), |
| ApprovalCopier.Result.PatchSetApprovalData.create( |
| patchSetApproval2, |
| /* passingAtoms= */ ImmutableSet.of(), |
| /* failingAtoms= */ ImmutableSet.of())), |
| /* outdatedApprovals= */ ImmutableSet.of()); |
| assertThat(approvalsUtil.formatApprovalCopierResult(approvalCopierResult, labelTypes)) |
| .hasValue( |
| String.format( |
| "Copied Votes:\n" |
| + "* Code-Review+1, Code-Review+2 (non-parseable copy condition: \"is:MIN" |
| + " OR (is:MAX approverin:%s) OR foo bar baz\")\n", |
| groupUuid)); |
| } |
| |
| @Test |
| public void copiedAndOutdatedApprovalsAreIncludedInChangeMessageOnPatchSetCreationByPush() |
| throws Exception { |
| // Add Verified label without copy condition. |
| try (ProjectConfigUpdate u = updateProject(project)) { |
| LabelType.Builder verified = |
| labelBuilder( |
| LabelId.VERIFIED, value(1, "Passes"), value(0, "No score"), value(-1, "Failed")); |
| u.getConfig().upsertLabelType(verified.build()); |
| u.save(); |
| } |
| projectOperations |
| .project(project) |
| .forUpdate() |
| .add( |
| allowLabel(TestLabels.verified().getName()) |
| .ref(RefNames.REFS_HEADS + "*") |
| .group(REGISTERED_USERS) |
| .range(-1, 1)) |
| .update(); |
| |
| PushOneCommit.Result r = createChange(); |
| |
| // Vote Code-Review-2 (sticky because it's a veto vote and the Code-Review label has "is:MIN" as |
| // part of its copy condition) |
| gApi.changes().id(r.getChangeId()).current().review(ReviewInput.reject()); |
| |
| // Vote Verified+1 (not sticky because the Verified label has no copy condition) |
| gApi.changes().id(r.getChangeId()).current().review(new ReviewInput().label("Verified", 1)); |
| |
| amendChange(r.getChangeId()).assertOkStatus(); |
| |
| ChangeInfo change = change(r).get(); |
| assertThat(Iterables.getLast(change.messages).message) |
| .isEqualTo( |
| "Uploaded patch set 2.\n" |
| + "\n" |
| + "Copied Votes:\n" |
| + "* Code-Review-2 (copy condition: \"changekind:NO_CHANGE" |
| + " OR changekind:TRIVIAL_REBASE OR **is:MIN**\")\n" |
| + "\n" |
| + "Outdated Votes:\n" |
| + "* Verified+1\n"); |
| } |
| |
| @Test |
| public void |
| copiedAndOutdatedApprovalsAreIncludedInChangeMessageOnPatchSetCreationByPush_withReviewMessage() |
| throws Exception { |
| // Add Verified label without copy condition. |
| try (ProjectConfigUpdate u = updateProject(project)) { |
| LabelType.Builder verified = |
| labelBuilder( |
| LabelId.VERIFIED, value(1, "Passes"), value(0, "No score"), value(-1, "Failed")); |
| u.getConfig().upsertLabelType(verified.build()); |
| u.save(); |
| } |
| projectOperations |
| .project(project) |
| .forUpdate() |
| .add( |
| allowLabel(TestLabels.verified().getName()) |
| .ref(RefNames.REFS_HEADS + "*") |
| .group(REGISTERED_USERS) |
| .range(-1, 1)) |
| .update(); |
| |
| PushOneCommit.Result r = createChange(); |
| |
| // Vote Code-Review-2 (sticky because it's a veto vote and the Code-Review label has "is:MIN" as |
| // part of its copy condition) |
| gApi.changes().id(r.getChangeId()).current().review(ReviewInput.reject()); |
| |
| // Vote Verified+1 (not sticky because the Verified label has no copy condition) |
| gApi.changes().id(r.getChangeId()).current().review(new ReviewInput().label("Verified", 1)); |
| |
| String reviewMessage = "Foo-Bar-Baz"; |
| |
| amendChange(r.getChangeId(), "refs/for/master%m=" + reviewMessage, admin, testRepo) |
| .assertOkStatus(); |
| |
| ChangeInfo change = change(r).get(); |
| assertThat(Iterables.getLast(change.messages).message) |
| .isEqualTo( |
| "Uploaded patch set 2.\n" |
| + "\n" |
| + "Foo-Bar-Baz\n" |
| + "\n" |
| + "Copied Votes:\n" |
| + "* Code-Review-2 (copy condition: \"changekind:NO_CHANGE" |
| + " OR changekind:TRIVIAL_REBASE OR **is:MIN**\")\n" |
| + "\n" |
| + "Outdated Votes:\n" |
| + "* Verified+1\n"); |
| } |
| |
| @Test |
| public void copiedAndOutdatedApprovalsAreIncludedInChangeMessageOnPatchSetCreationByApi() |
| throws Exception { |
| // Add Verified label without copy condition. |
| try (ProjectConfigUpdate u = updateProject(project)) { |
| LabelType.Builder verified = |
| labelBuilder( |
| LabelId.VERIFIED, value(1, "Passes"), value(0, "No score"), value(-1, "Failed")); |
| u.getConfig().upsertLabelType(verified.build()); |
| u.save(); |
| } |
| projectOperations |
| .project(project) |
| .forUpdate() |
| .add( |
| allowLabel(TestLabels.verified().getName()) |
| .ref(RefNames.REFS_HEADS + "*") |
| .group(REGISTERED_USERS) |
| .range(-1, 1)) |
| .update(); |
| |
| PushOneCommit.Result r = createChange(); |
| |
| // Vote Code-Review-2 (sticky because it's a veto vote and the Code-Review label has "is:MIN" as |
| // part of its copy condition) |
| gApi.changes().id(r.getChangeId()).current().review(ReviewInput.reject()); |
| |
| // Vote Verified+1 (not sticky because the Verified label has no copy condition) |
| gApi.changes().id(r.getChangeId()).current().review(new ReviewInput().label("Verified", 1)); |
| |
| gApi.changes().id(r.getChangeId()).edit().modifyFile("a.txt", RawInputUtil.create("content")); |
| gApi.changes().id(r.getChangeId()).edit().publish(); |
| |
| ChangeInfo change = change(r).get(); |
| assertThat(Iterables.getLast(change.messages).message) |
| .isEqualTo( |
| "Patch Set 2: Published edit on patch set 1.\n" |
| + "\n" |
| + "Copied Votes:\n" |
| + "* Code-Review-2 (copy condition: \"changekind:NO_CHANGE" |
| + " OR changekind:TRIVIAL_REBASE OR **is:MIN**\")\n" |
| + "\n" |
| + "Outdated Votes:\n" |
| + "* Verified+1\n"); |
| } |
| |
| private PatchSetApproval createPatchSetApproval( |
| TestAccount testAccount, String label, int value) { |
| return PatchSetApproval.builder() |
| .key( |
| PatchSetApproval.key( |
| PatchSet.id(Change.id(1), 1), testAccount.id(), LabelId.create(label))) |
| .value(value) |
| .granted(TimeUtil.now()) |
| .build(); |
| } |
| |
| private LabelType createLabelType(String labelName, @Nullable String copyCondition) { |
| LabelType.Builder labelTypeBuilder = |
| LabelType.builder( |
| labelName, |
| ImmutableList.of( |
| LabelValue.create((short) -2, "Vetoed"), |
| LabelValue.create((short) -1, "Disliked"), |
| LabelValue.create((short) 0, "No Vote"), |
| LabelValue.create((short) 1, "Liked"), |
| LabelValue.create((short) 2, "Approved"))); |
| if (copyCondition != null) { |
| labelTypeBuilder.setCopyCondition(copyCondition); |
| } |
| return labelTypeBuilder.build(); |
| } |
| } |