Support 'is:inprogress' operator in pending checks query

'is:inprogress' matches checks with non-final states (NOT_STARTED,
SCHEDULED and RUNNING).

Signed-off-by: Edwin Kempin <ekempin@google.com>
Change-Id: Icfa73afe439f27e651a32803c225631017f31ced
diff --git a/java/com/google/gerrit/plugins/checks/index/CheckQueryBuilder.java b/java/com/google/gerrit/plugins/checks/index/CheckQueryBuilder.java
index 9cd98dd..e8fe87e 100644
--- a/java/com/google/gerrit/plugins/checks/index/CheckQueryBuilder.java
+++ b/java/com/google/gerrit/plugins/checks/index/CheckQueryBuilder.java
@@ -14,11 +14,15 @@
 
 package com.google.gerrit.plugins.checks.index;
 
+import static java.util.stream.Collectors.toList;
+
 import com.google.gerrit.index.query.Predicate;
 import com.google.gerrit.index.query.QueryBuilder;
 import com.google.gerrit.index.query.QueryParseException;
 import com.google.gerrit.plugins.checks.Check;
+import com.google.gerrit.plugins.checks.api.CheckState;
 import com.google.inject.Inject;
+import java.util.Arrays;
 
 public class CheckQueryBuilder extends QueryBuilder<Check> {
   public static final String FIELD_CHECKER = "checker";
@@ -39,6 +43,14 @@
 
   @Operator
   public Predicate<Check> is(String value) throws QueryParseException {
+    if ("inprogress".equalsIgnoreCase(value)) {
+      return Predicate.or(
+          Arrays.stream(CheckState.values())
+              .filter(CheckState::isInProgress)
+              .map(CheckStatePredicate::new)
+              .collect(toList()));
+    }
+
     return CheckStatePredicate.tryParse(value)
         .orElseThrow(
             () -> new QueryParseException(String.format("unsupported operator: is:%s", value)));
diff --git a/javatests/com/google/gerrit/plugins/checks/acceptance/api/QueryPendingChecksIT.java b/javatests/com/google/gerrit/plugins/checks/acceptance/api/QueryPendingChecksIT.java
index 2af316c..c15b5d1 100644
--- a/javatests/com/google/gerrit/plugins/checks/acceptance/api/QueryPendingChecksIT.java
+++ b/javatests/com/google/gerrit/plugins/checks/acceptance/api/QueryPendingChecksIT.java
@@ -263,6 +263,35 @@
   }
 
   @Test
+  public void queryPendingChecksByIsInprogressOperator() throws Exception {
+    CheckerUuid checkerUuid = checkerOperations.newChecker().repository(project).create();
+
+    // Create the check once so that in the for-loop we can always update an existing check, rather
+    // than needing to check if the check already exists and then depending on this either create or
+    // update it.
+    checkOperations
+        .newCheck(CheckKey.create(project, patchSetId, checkerUuid))
+        .setState(CheckState.NOT_STARTED)
+        .upsert();
+
+    for (CheckState checkState : CheckState.values()) {
+      checkOperations
+          .check(CheckKey.create(project, patchSetId, checkerUuid))
+          .forUpdate()
+          .setState(checkState)
+          .upsert();
+
+      List<PendingChecksInfo> pendingChecks =
+          queryPendingChecks(String.format("checker:\"%s\" is:inprogress", checkerUuid));
+      if (checkState.isInProgress()) {
+        assertThat(pendingChecks).hasSize(1);
+      } else {
+        assertThat(pendingChecks).isEmpty();
+      }
+    }
+  }
+
+  @Test
   public void invalidStateInIsOperatorIsRejected() throws Exception {
     CheckerUuid checkerUuid = checkerOperations.newChecker().repository(project).create();
     assertInvalidQuery(
diff --git a/src/main/resources/Documentation/rest-api-pending-checks.md b/src/main/resources/Documentation/rest-api-pending-checks.md
index e18e44c..8924c95 100644
--- a/src/main/resources/Documentation/rest-api-pending-checks.md
+++ b/src/main/resources/Documentation/rest-api-pending-checks.md
@@ -122,5 +122,8 @@
   Matches checks of the checker with the UUID 'CHECKER_UUID'.
 * <a id="is-operator"></a> `is:'STATE'`:
   Matches checks with the state 'STATE'.
+* <a id="is-inprogress-operator"></a> `is:inprogress`:
+  Matches checks with non-final states (`NOT_STARTED`, `SCHEDULED` and
+  `RUNNING`).
 * <a id="state-operator"></a> `state:'STATE'`:
   Matches checks with the state 'STATE'.