Merge "Allow reset start and finish time of checks."
diff --git a/java/com/google/gerrit/plugins/checks/CheckUpdate.java b/java/com/google/gerrit/plugins/checks/CheckUpdate.java
index 315160d..0b86796 100644
--- a/java/com/google/gerrit/plugins/checks/CheckUpdate.java
+++ b/java/com/google/gerrit/plugins/checks/CheckUpdate.java
@@ -16,6 +16,7 @@
 
 import com.google.auto.value.AutoValue;
 import com.google.gerrit.plugins.checks.api.CheckState;
+import com.google.gerrit.server.util.time.TimeUtil;
 import java.sql.Timestamp;
 import java.util.Optional;
 
@@ -49,6 +50,14 @@
 
     public abstract Builder setFinished(Timestamp finished);
 
+    public Builder unsetStarted() {
+      return setStarted(TimeUtil.never());
+    }
+
+    public Builder unsetFinished() {
+      return setFinished(TimeUtil.never());
+    }
+
     public abstract CheckUpdate build();
   }
 }
diff --git a/java/com/google/gerrit/plugins/checks/acceptance/testsuite/BUILD b/java/com/google/gerrit/plugins/checks/acceptance/testsuite/BUILD
index 62a5299..577bfd4 100644
--- a/java/com/google/gerrit/plugins/checks/acceptance/testsuite/BUILD
+++ b/java/com/google/gerrit/plugins/checks/acceptance/testsuite/BUILD
@@ -8,6 +8,7 @@
     srcs = glob(["*.java"]),
     deps = [
         "//java/com/google/gerrit/acceptance:lib",
+        "//java/com/google/gerrit/server/util/time",
         "//plugins/checks:checks__plugin",
     ],
 )
diff --git a/java/com/google/gerrit/plugins/checks/acceptance/testsuite/TestCheckUpdate.java b/java/com/google/gerrit/plugins/checks/acceptance/testsuite/TestCheckUpdate.java
index 90864a6..16b4316 100644
--- a/java/com/google/gerrit/plugins/checks/acceptance/testsuite/TestCheckUpdate.java
+++ b/java/com/google/gerrit/plugins/checks/acceptance/testsuite/TestCheckUpdate.java
@@ -18,6 +18,7 @@
 import com.google.gerrit.acceptance.testsuite.ThrowingConsumer;
 import com.google.gerrit.plugins.checks.CheckKey;
 import com.google.gerrit.plugins.checks.api.CheckState;
+import com.google.gerrit.server.util.time.TimeUtil;
 import java.sql.Timestamp;
 import java.util.Optional;
 
@@ -65,6 +66,14 @@
 
     public abstract Builder finished(Timestamp finished);
 
+    public Builder clearStarted() {
+      return started(TimeUtil.never());
+    }
+
+    public Builder clearFinished() {
+      return finished(TimeUtil.never());
+    }
+
     abstract Builder checkUpdater(ThrowingConsumer<TestCheckUpdate> checkUpdate);
 
     abstract TestCheckUpdate autoBuild();
diff --git a/java/com/google/gerrit/plugins/checks/db/NoteDbCheck.java b/java/com/google/gerrit/plugins/checks/db/NoteDbCheck.java
index cb60d2c..043028a 100644
--- a/java/com/google/gerrit/plugins/checks/db/NoteDbCheck.java
+++ b/java/com/google/gerrit/plugins/checks/db/NoteDbCheck.java
@@ -9,6 +9,7 @@
 import com.google.gerrit.plugins.checks.api.CheckState;
 import com.google.gerrit.reviewdb.client.PatchSet;
 import com.google.gerrit.reviewdb.client.Project;
+import com.google.gerrit.server.util.time.TimeUtil;
 import java.sql.Timestamp;
 
 /** Representation of {@link Check} that can be serialized with GSON. */
@@ -74,11 +75,19 @@
       modified = true;
     }
     if (update.started().isPresent() && !update.started().get().equals(started)) {
-      started = update.started().get();
+      if (update.started().get().equals(TimeUtil.never())) {
+        started = null;
+      } else {
+        started = update.started().get();
+      }
       modified = true;
     }
     if (update.finished().isPresent() && !update.finished().get().equals(finished)) {
-      finished = update.finished().get();
+      if (update.finished().get().equals(TimeUtil.never())) {
+        finished = null;
+      } else {
+        finished = update.finished().get();
+      }
       modified = true;
     }
     return modified;
diff --git a/javatests/com/google/gerrit/plugins/checks/acceptance/api/UpdateCheckIT.java b/javatests/com/google/gerrit/plugins/checks/acceptance/api/UpdateCheckIT.java
index 6d15caa..ef1cf03 100644
--- a/javatests/com/google/gerrit/plugins/checks/acceptance/api/UpdateCheckIT.java
+++ b/javatests/com/google/gerrit/plugins/checks/acceptance/api/UpdateCheckIT.java
@@ -156,6 +156,16 @@
   }
 
   @Test
+  public void unsetStarted() throws Exception {
+    checkOperations.check(checkKey).forUpdate().started(TimeUtil.nowTs()).upsert();
+
+    CheckInput input = new CheckInput();
+    input.started = TimeUtil.never();
+    CheckInfo info = checksApiFactory.revision(patchSetId).id(checkKey.checkerUuid()).update(input);
+    assertThat(info.started).isNull();
+  }
+
+  @Test
   public void updateFinished() throws Exception {
     CheckInput input = new CheckInput();
     input.finished = TimeUtil.nowTs();
@@ -165,6 +175,16 @@
   }
 
   @Test
+  public void unsetFinished() throws Exception {
+    checkOperations.check(checkKey).forUpdate().finished(TimeUtil.nowTs()).upsert();
+
+    CheckInput input = new CheckInput();
+    input.finished = TimeUtil.never();
+    CheckInfo info = checksApiFactory.revision(patchSetId).id(checkKey.checkerUuid()).update(input);
+    assertThat(info.finished).isNull();
+  }
+
+  @Test
   public void updateWithEmptyInput() throws Exception {
     assertThat(
             checksApiFactory
diff --git a/javatests/com/google/gerrit/plugins/checks/acceptance/testsuite/CheckOperationsImplTest.java b/javatests/com/google/gerrit/plugins/checks/acceptance/testsuite/CheckOperationsImplTest.java
index 4e63bde..6458099 100644
--- a/javatests/com/google/gerrit/plugins/checks/acceptance/testsuite/CheckOperationsImplTest.java
+++ b/javatests/com/google/gerrit/plugins/checks/acceptance/testsuite/CheckOperationsImplTest.java
@@ -476,6 +476,18 @@
   }
 
   @Test
+  public void startedCanBeCleared() throws Exception {
+    CheckerUuid checkerUuid = checkerOperations.newChecker().repository(project).create();
+    CheckKey checkKey = CheckKey.create(project, createChange().getPatchSetId(), checkerUuid);
+    checkOperations.newCheck(checkKey).started(TimeUtil.nowTs()).upsert();
+
+    checkOperations.check(checkKey).forUpdate().clearStarted().upsert();
+
+    Optional<Timestamp> currentStarted = checkOperations.check(checkKey).get().started();
+    assertThat(currentStarted).isEmpty();
+  }
+
+  @Test
   public void finishedCanBeUpdated() throws Exception {
     CheckerUuid checkerUuid = checkerOperations.newChecker().repository(project).create();
     CheckKey checkKey = CheckKey.create(project, createChange().getPatchSetId(), checkerUuid);
@@ -489,6 +501,18 @@
   }
 
   @Test
+  public void finishedCanBeCleared() throws Exception {
+    CheckerUuid checkerUuid = checkerOperations.newChecker().repository(project).create();
+    CheckKey checkKey = CheckKey.create(project, createChange().getPatchSetId(), checkerUuid);
+    checkOperations.newCheck(checkKey).finished(TimeUtil.nowTs()).upsert();
+
+    checkOperations.check(checkKey).forUpdate().clearFinished().upsert();
+
+    Optional<Timestamp> currentFinished = checkOperations.check(checkKey).get().finished();
+    assertThat(currentFinished).isEmpty();
+  }
+
+  @Test
   public void getNotesAsText() throws Exception {
     CheckerUuid checkerUuid = checkerOperations.newChecker().repository(project).create();
     PatchSet.Id patchSetId = createChange().getPatchSetId();