Adjust SR expression with IgnoreSelfApproval labels

In SubmitRequirementsAdapter we convert legacy submit records to submit
requirements. We differentiate between submit records created by the
default vs. custom submit rules. For submit records created by the
default submit rule, we create a separate submit requirement for each
label in the submit record.

In this change we adjust the submittability expression if the label is
setting the ignoreSelfApproval property. When this happens, we create
the submittability expression as:

Case MAX_WITH_BLOCK
	 label:$label_name=MAX,user=non_uploader
	-label:$label_name=MIN

Case MAX_NO_BLOCK
	label:$label_name=MAX,user=non_uploader

Case ANY_WITH_BLOCK
	-label:$label_name=MIN

i.e. we append the ",user=non_uploader" to the expression for the max
vote case. We've previously implemented a non_uploader arg to the label
predicate with change I3d0c7752.

Change-Id: I571d19a6d15cf95b92d386f8aba1468fcbe3dbde
diff --git a/java/com/google/gerrit/server/project/SubmitRequirementsAdapter.java b/java/com/google/gerrit/server/project/SubmitRequirementsAdapter.java
index 0383cdc..ca6c689 100644
--- a/java/com/google/gerrit/server/project/SubmitRequirementsAdapter.java
+++ b/java/com/google/gerrit/server/project/SubmitRequirementsAdapter.java
@@ -24,6 +24,7 @@
 import com.google.gerrit.entities.SubmitRequirementExpressionResult;
 import com.google.gerrit.entities.SubmitRequirementExpressionResult.Status;
 import com.google.gerrit.entities.SubmitRequirementResult;
+import com.google.gerrit.server.query.change.ChangeQueryBuilder;
 import java.util.List;
 import org.eclipse.jgit.lib.ObjectId;
 
@@ -123,15 +124,18 @@
   }
 
   private static ImmutableList<String> toExpressionAtomList(LabelType lt) {
+    String ignoreSelfApproval =
+        lt.isIgnoreSelfApproval() ? ",user=" + ChangeQueryBuilder.ARG_ID_NON_UPLOADER : "";
     switch (lt.getFunction()) {
       case MAX_WITH_BLOCK:
         return ImmutableList.of(
-            String.format("label:%s=MAX", lt.getName()),
+            String.format("label:%s=MAX", lt.getName()) + ignoreSelfApproval,
             String.format("-label:%s=MIN", lt.getName()));
       case ANY_WITH_BLOCK:
         return ImmutableList.of(String.format(String.format("-label:%s=MIN", lt.getName())));
       case MAX_NO_BLOCK:
-        return ImmutableList.of(String.format(String.format("label:%s=MAX", lt.getName())));
+        return ImmutableList.of(
+            String.format(String.format("label:%s=MAX", lt.getName())) + ignoreSelfApproval);
       case NO_BLOCK:
       case NO_OP:
       case PATCH_SET_LOCK:
diff --git a/javatests/com/google/gerrit/acceptance/api/change/ChangeIT.java b/javatests/com/google/gerrit/acceptance/api/change/ChangeIT.java
index 9f9adad..ac67444 100644
--- a/javatests/com/google/gerrit/acceptance/api/change/ChangeIT.java
+++ b/javatests/com/google/gerrit/acceptance/api/change/ChangeIT.java
@@ -4134,6 +4134,54 @@
   }
 
   @Test
+  public void submitRequirement_withMaxWithBlock_ignoringSelfApproval() throws Exception {
+    configLabel("my-label", LabelFunction.MAX_WITH_BLOCK);
+    projectOperations
+        .project(project)
+        .forUpdate()
+        .add(allowLabel("my-label").ref("refs/heads/master").group(REGISTERED_USERS).range(-1, 1))
+        .update();
+
+    configSubmitRequirement(
+        project,
+        SubmitRequirement.builder()
+            .setName("my-label")
+            .setSubmittabilityExpression(
+                SubmitRequirementExpression.create(
+                    "label:my-label=MAX,user=non_uploader -label:my-label=MIN"))
+            .setAllowOverrideInChildProjects(false)
+            .build());
+
+    // Create the change as admin
+    requestScopeOperations.setApiUser(admin.id());
+    PushOneCommit.Result r = createChange();
+    String changeId = r.getChangeId();
+
+    // Admin (a.k.a uploader) adds a -1 min vote. This is going to block submission.
+    voteLabel(changeId, "my-label", -1);
+    ChangeInfo change = gApi.changes().id(changeId).get();
+    assertThat(change.submitRequirements).hasSize(1);
+    assertSubmitRequirementStatus(
+        change.submitRequirements, "my-label", Status.UNSATISFIED, /* isLegacy= */ false);
+
+    // user (i.e. non_uploader) votes 1. Requirement is still blocking because of -1 of uploader.
+    requestScopeOperations.setApiUser(user.id());
+    voteLabel(changeId, "my-label", 1);
+    change = gApi.changes().id(changeId).get();
+    assertThat(change.submitRequirements).hasSize(1);
+    assertSubmitRequirementStatus(
+        change.submitRequirements, "my-label", Status.UNSATISFIED, /* isLegacy= */ false);
+
+    // Admin (a.k.a uploader) removes -1. Now requirement is fulfilled.
+    requestScopeOperations.setApiUser(admin.id());
+    voteLabel(changeId, "my-label", 0);
+    change = gApi.changes().id(changeId).get();
+    assertThat(change.submitRequirements).hasSize(1);
+    assertSubmitRequirementStatus(
+        change.submitRequirements, "my-label", Status.SATISFIED, /* isLegacy= */ false);
+  }
+
+  @Test
   public void submitRequirement_withLabelEqualsAny() throws Exception {
     configSubmitRequirement(
         project,
diff --git a/javatests/com/google/gerrit/server/project/SubmitRequirementsAdapterTest.java b/javatests/com/google/gerrit/server/project/SubmitRequirementsAdapterTest.java
index 2212fe7..f6c4d6a 100644
--- a/javatests/com/google/gerrit/server/project/SubmitRequirementsAdapterTest.java
+++ b/javatests/com/google/gerrit/server/project/SubmitRequirementsAdapterTest.java
@@ -69,7 +69,18 @@
             .setFunction(LabelFunction.ANY_WITH_BLOCK)
             .build();
 
-    labelTypes = Arrays.asList(codeReview, verified, codeStyle);
+    LabelType ignoreSelfApprovalLabel =
+        LabelType.builder(
+                "ISA-Label",
+                ImmutableList.of(
+                    LabelValue.create((short) 1, "Looks good to me"),
+                    LabelValue.create((short) 0, "No score"),
+                    LabelValue.create((short) -1, "I would prefer this is not merged as is")))
+            .setFunction(LabelFunction.MAX_WITH_BLOCK)
+            .setIgnoreSelfApproval(true)
+            .build();
+
+    labelTypes = Arrays.asList(codeReview, verified, codeStyle, ignoreSelfApprovalLabel);
   }
 
   @Test
@@ -129,6 +140,46 @@
   }
 
   @Test
+  public void defaultSubmitRule_withLabelStatusNeed_labelHasIgnoreSelfApproval() throws Exception {
+    SubmitRecord submitRecord =
+        createSubmitRecord(
+            "gerrit~DefaultSubmitRule",
+            Status.NOT_READY,
+            Arrays.asList(createLabel("ISA-Label", Label.Status.NEED)));
+
+    List<SubmitRequirementResult> requirements =
+        SubmitRequirementsAdapter.createResult(submitRecord, labelTypes, psCommitId);
+
+    assertThat(requirements).hasSize(1);
+    assertResult(
+        requirements.get(0),
+        /* reqName= */ "ISA-Label",
+        /* submitExpression= */ "label:ISA-Label=MAX,user=non_uploader -label:ISA-Label=MIN",
+        SubmitRequirementResult.Status.UNSATISFIED,
+        SubmitRequirementExpressionResult.Status.FAIL);
+  }
+
+  @Test
+  public void defaultSubmitRule_withLabelStatusOk_labelHasIgnoreSelfApproval() throws Exception {
+    SubmitRecord submitRecord =
+        createSubmitRecord(
+            "gerrit~DefaultSubmitRule",
+            Status.OK,
+            Arrays.asList(createLabel("ISA-Label", Label.Status.OK)));
+
+    List<SubmitRequirementResult> requirements =
+        SubmitRequirementsAdapter.createResult(submitRecord, labelTypes, psCommitId);
+
+    assertThat(requirements).hasSize(1);
+    assertResult(
+        requirements.get(0),
+        /* reqName= */ "ISA-Label",
+        /* submitExpression= */ "label:ISA-Label=MAX,user=non_uploader -label:ISA-Label=MIN",
+        SubmitRequirementResult.Status.SATISFIED,
+        SubmitRequirementExpressionResult.Status.PASS);
+  }
+
+  @Test
   public void customSubmitRule_noLabels_withStatusOk() {
     SubmitRecord submitRecord =
         createSubmitRecord("gerrit~IgnoreSelfApprovalRule", Status.OK, Arrays.asList());