Add config and rule to ignore self approval on labels
A frequently used Prolog rule is to ignore self approvals when evaluating labels. The simple-submit-rules plugin has created such a rule in Java instead of Prolog. All of the other label functions are handled directly in core so it seems like a good fit, to also just port this one into Gerrit core given that it is used quite often. The new rule gets added as a separate rule so that we grow the SubmitRules implementations more atomically (instead of just adding it to DefaultRule). We add tests that are mainly also just ported from simple-submit-rules. Besides BUILD file and reference changes, the code was migrated to use Flogger and we are more indicative to the user in case the uploader is the only one who approved the change by adding an additional requirement. The rule uses the uploader to make it easier to explain it to users. Basing it on the author would come with the confusion that when you cherry pick a change, you can self approve in case the author of the original patch set was someone else. Basing it on the change owner would mean you can hijack any change by uploading a patch set to submit self-reviewed code. Change-Id: I78b97f60ca1bb4aaf5386103c9228f76974feea4
This commit is contained in:
parent
460a3f3c35
commit
12c87c7b78
|
@ -374,6 +374,15 @@ Branch can be a ref pattern similar to what is documented
|
|||
link:access-control.html#reference[here], but must not contain `${username}` or
|
||||
`${shardeduserid}`.
|
||||
|
||||
[[label_ignoreSelfApproval]]
|
||||
=== `label.Label-Name.ignoreSelfApproval`
|
||||
|
||||
If true, the label may be voted on by the uploader of the latest patch set,
|
||||
but their approval does not make a change submittable. Instead, a
|
||||
non-uploader who has the right to vote has to approve the change.
|
||||
|
||||
Defaults to false.
|
||||
|
||||
[[label_example]]
|
||||
=== Example
|
||||
|
||||
|
|
|
@ -36,6 +36,7 @@ public class LabelType {
|
|||
public static final boolean DEF_COPY_ALL_SCORES_ON_MERGE_FIRST_PARENT_UPDATE = false;
|
||||
public static final boolean DEF_COPY_MAX_SCORE = false;
|
||||
public static final boolean DEF_COPY_MIN_SCORE = false;
|
||||
public static final boolean DEF_IGNORE_SELF_APPROVAL = false;
|
||||
|
||||
public static LabelType withDefaultValues(String name) {
|
||||
checkName(name);
|
||||
|
@ -103,6 +104,7 @@ public class LabelType {
|
|||
protected boolean copyAllScoresIfNoCodeChange;
|
||||
protected boolean copyAllScoresIfNoChange;
|
||||
protected boolean allowPostSubmit;
|
||||
protected boolean ignoreSelfApproval;
|
||||
protected short defaultValue;
|
||||
|
||||
protected List<LabelValue> values;
|
||||
|
@ -141,6 +143,7 @@ public class LabelType {
|
|||
setCopyMaxScore(DEF_COPY_MAX_SCORE);
|
||||
setCopyMinScore(DEF_COPY_MIN_SCORE);
|
||||
setAllowPostSubmit(DEF_ALLOW_POST_SUBMIT);
|
||||
setIgnoreSelfApproval(DEF_IGNORE_SELF_APPROVAL);
|
||||
|
||||
byValue = new HashMap<>();
|
||||
for (LabelValue v : values) {
|
||||
|
@ -188,6 +191,14 @@ public class LabelType {
|
|||
this.allowPostSubmit = allowPostSubmit;
|
||||
}
|
||||
|
||||
public boolean ignoreSelfApproval() {
|
||||
return ignoreSelfApproval;
|
||||
}
|
||||
|
||||
public void setIgnoreSelfApproval(boolean ignoreSelfApproval) {
|
||||
this.ignoreSelfApproval = ignoreSelfApproval;
|
||||
}
|
||||
|
||||
public void setRefPatterns(List<String> refPatterns) {
|
||||
if (refPatterns != null) {
|
||||
this.refPatterns =
|
||||
|
|
|
@ -75,6 +75,7 @@ import com.google.gerrit.server.query.change.ChangeData;
|
|||
import com.google.gerrit.server.query.change.ChangeQueryProcessor;
|
||||
import com.google.gerrit.server.restapi.group.GroupModule;
|
||||
import com.google.gerrit.server.rules.DefaultSubmitRule;
|
||||
import com.google.gerrit.server.rules.IgnoreSelfApprovalRule;
|
||||
import com.google.gerrit.server.rules.PrologModule;
|
||||
import com.google.gerrit.server.rules.SubmitRule;
|
||||
import com.google.gerrit.server.update.BatchUpdate;
|
||||
|
@ -188,6 +189,7 @@ public class BatchProgramModule extends FactoryModule {
|
|||
factory(SubmitRuleEvaluator.Factory.class);
|
||||
install(new PrologModule());
|
||||
install(new DefaultSubmitRule.Module());
|
||||
install(new IgnoreSelfApprovalRule.Module());
|
||||
|
||||
bind(ChangeJson.Factory.class).toProvider(Providers.<ChangeJson.Factory>of(null));
|
||||
bind(EventUtil.class).toProvider(Providers.<EventUtil>of(null));
|
||||
|
|
|
@ -170,6 +170,7 @@ import com.google.gerrit.server.query.change.ConflictsCacheImpl;
|
|||
import com.google.gerrit.server.restapi.change.SuggestReviewers;
|
||||
import com.google.gerrit.server.restapi.group.GroupModule;
|
||||
import com.google.gerrit.server.rules.DefaultSubmitRule;
|
||||
import com.google.gerrit.server.rules.IgnoreSelfApprovalRule;
|
||||
import com.google.gerrit.server.rules.PrologModule;
|
||||
import com.google.gerrit.server.rules.RulesCache;
|
||||
import com.google.gerrit.server.rules.SubmitRule;
|
||||
|
@ -244,6 +245,7 @@ public class GerritGlobalModule extends FactoryModule {
|
|||
install(new NoteDbModule(cfg));
|
||||
install(new PrologModule());
|
||||
install(new DefaultSubmitRule.Module());
|
||||
install(new IgnoreSelfApprovalRule.Module());
|
||||
install(new ReceiveCommitsModule());
|
||||
install(new SshAddressesModule());
|
||||
install(ThreadLocalRequestContext.module());
|
||||
|
|
|
@ -91,6 +91,7 @@ public class ProjectConfig extends VersionedMetaData implements ValidationError.
|
|||
public static final String KEY_DEFAULT_VALUE = "defaultValue";
|
||||
public static final String KEY_COPY_MIN_SCORE = "copyMinScore";
|
||||
public static final String KEY_ALLOW_POST_SUBMIT = "allowPostSubmit";
|
||||
public static final String KEY_IGNORE_SELF_APPROVAL = "ignoreSelfApproval";
|
||||
public static final String KEY_COPY_MAX_SCORE = "copyMaxScore";
|
||||
public static final String KEY_COPY_ALL_SCORES_ON_MERGE_FIRST_PARENT_UPDATE =
|
||||
"copyAllScoresOnMergeFirstParentUpdate";
|
||||
|
@ -882,6 +883,8 @@ public class ProjectConfig extends VersionedMetaData implements ValidationError.
|
|||
}
|
||||
label.setAllowPostSubmit(
|
||||
rc.getBoolean(LABEL, name, KEY_ALLOW_POST_SUBMIT, LabelType.DEF_ALLOW_POST_SUBMIT));
|
||||
label.setIgnoreSelfApproval(
|
||||
rc.getBoolean(LABEL, name, KEY_IGNORE_SELF_APPROVAL, LabelType.DEF_IGNORE_SELF_APPROVAL));
|
||||
label.setCopyMinScore(
|
||||
rc.getBoolean(LABEL, name, KEY_COPY_MIN_SCORE, LabelType.DEF_COPY_MIN_SCORE));
|
||||
label.setCopyMaxScore(
|
||||
|
@ -1317,6 +1320,13 @@ public class ProjectConfig extends VersionedMetaData implements ValidationError.
|
|||
KEY_ALLOW_POST_SUBMIT,
|
||||
label.allowPostSubmit(),
|
||||
LabelType.DEF_ALLOW_POST_SUBMIT);
|
||||
setBooleanConfigKey(
|
||||
rc,
|
||||
LABEL,
|
||||
name,
|
||||
KEY_IGNORE_SELF_APPROVAL,
|
||||
label.ignoreSelfApproval(),
|
||||
LabelType.DEF_IGNORE_SELF_APPROVAL);
|
||||
setBooleanConfigKey(
|
||||
rc,
|
||||
LABEL,
|
||||
|
|
|
@ -0,0 +1,171 @@
|
|||
// Copyright (C) 2018 The Android Open Source Project
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package com.google.gerrit.server.rules;
|
||||
|
||||
import static com.google.common.collect.ImmutableList.toImmutableList;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.flogger.FluentLogger;
|
||||
import com.google.gerrit.common.data.LabelFunction;
|
||||
import com.google.gerrit.common.data.LabelType;
|
||||
import com.google.gerrit.common.data.SubmitRecord;
|
||||
import com.google.gerrit.common.data.SubmitRequirement;
|
||||
import com.google.gerrit.extensions.annotations.Exports;
|
||||
import com.google.gerrit.extensions.config.FactoryModule;
|
||||
import com.google.gerrit.reviewdb.client.Account;
|
||||
import com.google.gerrit.reviewdb.client.PatchSetApproval;
|
||||
import com.google.gerrit.server.project.SubmitRuleOptions;
|
||||
import com.google.gerrit.server.query.change.ChangeData;
|
||||
import com.google.gwtorm.server.OrmException;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Singleton;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Rule to require an approval from a user that did not upload the current patch set or block
|
||||
* submission.
|
||||
*/
|
||||
@Singleton
|
||||
public class IgnoreSelfApprovalRule implements SubmitRule {
|
||||
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
|
||||
private static final String E_UNABLE_TO_FETCH_UPLOADER = "Unable to fetch uploader";
|
||||
private static final String E_UNABLE_TO_FETCH_LABELS =
|
||||
"Unable to fetch labels and approvals for the change";
|
||||
|
||||
public static class Module extends FactoryModule {
|
||||
@Override
|
||||
public void configure() {
|
||||
bind(SubmitRule.class)
|
||||
.annotatedWith(Exports.named("IgnoreSelfApprovalRule"))
|
||||
.to(IgnoreSelfApprovalRule.class);
|
||||
}
|
||||
}
|
||||
|
||||
@Inject
|
||||
IgnoreSelfApprovalRule() {}
|
||||
|
||||
@Override
|
||||
public Collection<SubmitRecord> evaluate(ChangeData cd, SubmitRuleOptions options) {
|
||||
List<LabelType> labelTypes;
|
||||
List<PatchSetApproval> approvals;
|
||||
try {
|
||||
labelTypes = cd.getLabelTypes().getLabelTypes();
|
||||
approvals = cd.currentApprovals();
|
||||
} catch (OrmException e) {
|
||||
logger.atWarning().withCause(e).log(E_UNABLE_TO_FETCH_LABELS);
|
||||
return singletonRuleError(E_UNABLE_TO_FETCH_LABELS);
|
||||
}
|
||||
|
||||
boolean shouldIgnoreSelfApproval = labelTypes.stream().anyMatch(l -> l.ignoreSelfApproval());
|
||||
if (!shouldIgnoreSelfApproval) {
|
||||
// Shortcut to avoid further processing if no label should ignore uploader approvals
|
||||
return ImmutableList.of();
|
||||
}
|
||||
|
||||
Account.Id uploader;
|
||||
try {
|
||||
uploader = cd.currentPatchSet().getUploader();
|
||||
} catch (OrmException e) {
|
||||
logger.atWarning().withCause(e).log(E_UNABLE_TO_FETCH_UPLOADER);
|
||||
return singletonRuleError(E_UNABLE_TO_FETCH_UPLOADER);
|
||||
}
|
||||
|
||||
SubmitRecord submitRecord = new SubmitRecord();
|
||||
submitRecord.status = SubmitRecord.Status.OK;
|
||||
submitRecord.labels = new ArrayList<>(labelTypes.size());
|
||||
submitRecord.requirements = new ArrayList<>();
|
||||
|
||||
for (LabelType t : labelTypes) {
|
||||
if (!t.ignoreSelfApproval()) {
|
||||
// The default rules are enough in this case.
|
||||
continue;
|
||||
}
|
||||
|
||||
LabelFunction labelFunction = t.getFunction();
|
||||
if (labelFunction == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Collection<PatchSetApproval> allApprovalsForLabel = filterApprovalsByLabel(approvals, t);
|
||||
SubmitRecord.Label allApprovalsCheckResult = labelFunction.check(t, allApprovalsForLabel);
|
||||
SubmitRecord.Label ignoreSelfApprovalCheckResult =
|
||||
labelFunction.check(t, filterOutPositiveApprovalsOfUser(allApprovalsForLabel, uploader));
|
||||
|
||||
if (labelCheckPassed(allApprovalsCheckResult)
|
||||
&& !labelCheckPassed(ignoreSelfApprovalCheckResult)) {
|
||||
// The label has a valid approval from the uploader and no other valid approval. Set the
|
||||
// label
|
||||
// to NOT_READY and indicate the need for non-uploader approval as requirement.
|
||||
submitRecord.labels.add(ignoreSelfApprovalCheckResult);
|
||||
submitRecord.status = SubmitRecord.Status.NOT_READY;
|
||||
// Add an additional requirement to be more descriptive on why the label counts as not
|
||||
// approved.
|
||||
submitRecord.requirements.add(
|
||||
SubmitRequirement.builder()
|
||||
.setFallbackText("Approval from non-uploader required")
|
||||
.setType("non_uploader_approval")
|
||||
.build());
|
||||
}
|
||||
}
|
||||
|
||||
if (submitRecord.labels.isEmpty()) {
|
||||
return ImmutableList.of();
|
||||
}
|
||||
|
||||
return ImmutableList.of(submitRecord);
|
||||
}
|
||||
|
||||
private static boolean labelCheckPassed(SubmitRecord.Label label) {
|
||||
switch (label.status) {
|
||||
case OK:
|
||||
case MAY:
|
||||
return true;
|
||||
|
||||
case NEED:
|
||||
case REJECT:
|
||||
case IMPOSSIBLE:
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static Collection<SubmitRecord> singletonRuleError(String reason) {
|
||||
SubmitRecord submitRecord = new SubmitRecord();
|
||||
submitRecord.errorMessage = reason;
|
||||
submitRecord.status = SubmitRecord.Status.RULE_ERROR;
|
||||
return ImmutableList.of(submitRecord);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
static Collection<PatchSetApproval> filterOutPositiveApprovalsOfUser(
|
||||
Collection<PatchSetApproval> approvals, Account.Id user) {
|
||||
return approvals
|
||||
.stream()
|
||||
.filter(input -> input.getValue() < 0 || !input.getAccountId().equals(user))
|
||||
.collect(toImmutableList());
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
static Collection<PatchSetApproval> filterApprovalsByLabel(
|
||||
Collection<PatchSetApproval> approvals, LabelType t) {
|
||||
return approvals
|
||||
.stream()
|
||||
.filter(input -> input.getLabelId().get().equals(t.getLabelId().get()))
|
||||
.collect(toImmutableList());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,99 @@
|
|||
// Copyright (C) 2018 The Android Open Source Project
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package com.google.gerrit.acceptance.server.rules;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import com.google.gerrit.acceptance.AbstractDaemonTest;
|
||||
import com.google.gerrit.acceptance.NoHttpd;
|
||||
import com.google.gerrit.acceptance.PushOneCommit;
|
||||
import com.google.gerrit.common.data.LabelType;
|
||||
import com.google.gerrit.common.data.SubmitRecord;
|
||||
import com.google.gerrit.common.data.SubmitRequirement;
|
||||
import com.google.gerrit.server.project.SubmitRuleOptions;
|
||||
import com.google.gerrit.server.rules.IgnoreSelfApprovalRule;
|
||||
import com.google.inject.Inject;
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import org.eclipse.jgit.internal.storage.dfs.InMemoryRepository;
|
||||
import org.eclipse.jgit.junit.TestRepository;
|
||||
import org.junit.Test;
|
||||
|
||||
@NoHttpd
|
||||
public class IgnoreSelfApprovalRuleIT extends AbstractDaemonTest {
|
||||
@Inject private IgnoreSelfApprovalRule rule;
|
||||
|
||||
@Test
|
||||
public void blocksWhenUploaderIsOnlyApprover() throws Exception {
|
||||
enableRule("Code-Review", true);
|
||||
|
||||
PushOneCommit.Result r = createChange();
|
||||
approve(r.getChangeId());
|
||||
|
||||
Collection<SubmitRecord> submitRecords =
|
||||
rule.evaluate(r.getChange(), SubmitRuleOptions.defaults());
|
||||
|
||||
assertThat(submitRecords).hasSize(1);
|
||||
SubmitRecord result = submitRecords.iterator().next();
|
||||
assertThat(result.status).isEqualTo(SubmitRecord.Status.NOT_READY);
|
||||
assertThat(result.labels).isNotEmpty();
|
||||
assertThat(result.requirements)
|
||||
.containsExactly(
|
||||
SubmitRequirement.builder()
|
||||
.setFallbackText("Approval from non-uploader required")
|
||||
.setType("non_uploader_approval")
|
||||
.build());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void allowsSubmissionWhenChangeHasNonUploaderApproval() throws Exception {
|
||||
enableRule("Code-Review", true);
|
||||
|
||||
// Create change as user
|
||||
TestRepository<InMemoryRepository> userTestRepo = cloneProject(project, user);
|
||||
PushOneCommit push = pushFactory.create(db, user.getIdent(), userTestRepo);
|
||||
PushOneCommit.Result r = push.to("refs/for/master");
|
||||
|
||||
// Approve as admin
|
||||
approve(r.getChangeId());
|
||||
|
||||
Collection<SubmitRecord> submitRecords =
|
||||
rule.evaluate(r.getChange(), SubmitRuleOptions.defaults());
|
||||
assertThat(submitRecords).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doesNothingByDefault() throws Exception {
|
||||
enableRule("Code-Review", false);
|
||||
|
||||
PushOneCommit.Result r = createChange();
|
||||
approve(r.getChangeId());
|
||||
|
||||
Collection<SubmitRecord> submitRecords =
|
||||
rule.evaluate(r.getChange(), SubmitRuleOptions.defaults());
|
||||
assertThat(submitRecords).isEmpty();
|
||||
}
|
||||
|
||||
private void enableRule(String labelName, boolean newState) throws Exception {
|
||||
try (ProjectConfigUpdate u = updateProject(project)) {
|
||||
Map<String, LabelType> localLabelSections = u.getConfig().getLabelSections();
|
||||
if (localLabelSections.isEmpty()) {
|
||||
localLabelSections.putAll(projectCache.getAllProjects().getConfig().getLabelSections());
|
||||
}
|
||||
localLabelSections.get(labelName).setIgnoreSelfApproval(newState);
|
||||
u.save();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -7,9 +7,11 @@ junit_tests(
|
|||
resources = ["//prologtests:gerrit_common_test"],
|
||||
deps = [
|
||||
"//java/com/google/gerrit/common:server",
|
||||
"//java/com/google/gerrit/reviewdb:server",
|
||||
"//java/com/google/gerrit/server",
|
||||
"//java/com/google/gerrit/server/project/testing:project-test-util",
|
||||
"//java/com/google/gerrit/testing:gerrit-test-util",
|
||||
"//lib:guava",
|
||||
"//lib/guice",
|
||||
"//lib/jgit/org.eclipse.jgit:jgit",
|
||||
"//lib/prolog:runtime",
|
||||
|
|
|
@ -0,0 +1,96 @@
|
|||
// Copyright (C) 2018 The Android Open Source Project
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package com.google.gerrit.server.rules;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.gerrit.common.data.LabelType;
|
||||
import com.google.gerrit.common.data.LabelValue;
|
||||
import com.google.gerrit.reviewdb.client.Account;
|
||||
import com.google.gerrit.reviewdb.client.Change;
|
||||
import com.google.gerrit.reviewdb.client.LabelId;
|
||||
import com.google.gerrit.reviewdb.client.PatchSet;
|
||||
import com.google.gerrit.reviewdb.client.PatchSetApproval;
|
||||
import java.time.Instant;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import org.junit.Test;
|
||||
|
||||
public class IgnoreSelfApprovalRuleTest {
|
||||
private static final Change.Id CHANGE_ID = new Change.Id(100);
|
||||
private static final PatchSet.Id PS_ID = new PatchSet.Id(CHANGE_ID, 1);
|
||||
private static final LabelType VERIFIED = makeLabel("Verified");
|
||||
private static final Account.Id USER1 = makeAccount(100001);
|
||||
|
||||
@Test
|
||||
public void filtersByLabel() {
|
||||
LabelType codeReview = makeLabel("Code-Review");
|
||||
PatchSetApproval approvalVerified = makeApproval(VERIFIED.getLabelId(), USER1, 2);
|
||||
PatchSetApproval approvalCr = makeApproval(codeReview.getLabelId(), USER1, 2);
|
||||
|
||||
Collection<PatchSetApproval> filteredApprovals =
|
||||
IgnoreSelfApprovalRule.filterApprovalsByLabel(
|
||||
ImmutableList.of(approvalVerified, approvalCr), VERIFIED);
|
||||
|
||||
assertThat(filteredApprovals).containsExactly(approvalVerified);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void filtersVotesFromUser() {
|
||||
PatchSetApproval approvalM2 = makeApproval(VERIFIED.getLabelId(), USER1, -2);
|
||||
PatchSetApproval approvalM1 = makeApproval(VERIFIED.getLabelId(), USER1, -1);
|
||||
|
||||
ImmutableList<PatchSetApproval> approvals =
|
||||
ImmutableList.of(
|
||||
approvalM2,
|
||||
approvalM1,
|
||||
makeApproval(VERIFIED.getLabelId(), USER1, 0),
|
||||
makeApproval(VERIFIED.getLabelId(), USER1, +1),
|
||||
makeApproval(VERIFIED.getLabelId(), USER1, +2));
|
||||
|
||||
Collection<PatchSetApproval> filteredApprovals =
|
||||
IgnoreSelfApprovalRule.filterOutPositiveApprovalsOfUser(approvals, USER1);
|
||||
|
||||
assertThat(filteredApprovals).containsExactly(approvalM1, approvalM2);
|
||||
}
|
||||
|
||||
private static LabelType makeLabel(String labelName) {
|
||||
List<LabelValue> values = new ArrayList<>();
|
||||
// The label text is irrelevant here, only the numerical value is used
|
||||
values.add(new LabelValue((short) -2, "-2"));
|
||||
values.add(new LabelValue((short) -1, "-1"));
|
||||
values.add(new LabelValue((short) 0, "No vote."));
|
||||
values.add(new LabelValue((short) 1, "+1"));
|
||||
values.add(new LabelValue((short) 2, "+2"));
|
||||
return new LabelType(labelName, values);
|
||||
}
|
||||
|
||||
private static PatchSetApproval makeApproval(LabelId labelId, Account.Id accountId, int value) {
|
||||
PatchSetApproval.Key key = makeKey(PS_ID, accountId, labelId);
|
||||
return new PatchSetApproval(key, (short) value, Date.from(Instant.now()));
|
||||
}
|
||||
|
||||
private static PatchSetApproval.Key makeKey(
|
||||
PatchSet.Id psId, Account.Id accountId, LabelId labelId) {
|
||||
return new PatchSetApproval.Key(psId, accountId, labelId);
|
||||
}
|
||||
|
||||
private static Account.Id makeAccount(int account) {
|
||||
return new Account.Id(account);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue