Return submit requirements for legacy submit records for closed changes

This is gated with the "enable_legacy_submit_requirements" experiment
feature that is already used with active changes. For closed changes,
when this experiment feature is enabled, we will present submit
requirement results to users from two different sources:
1) The stored submit requirement results from NoteDb.
2) converting submit records that are stored in NoteDb to submit
requirements.

We are doing this to ensure that, once the experiment is enabled, we
still serve submit requirements for closed (merged) changes as otherwise
submit requirement results will be empty.

Bug: Google b/202719014
Change-Id: I06f395b5fdcca7416ef11a2bae7540489228c925
diff --git a/java/com/google/gerrit/server/query/change/ChangeData.java b/java/com/google/gerrit/server/query/change/ChangeData.java
index 4086877..6e14a13 100644
--- a/java/com/google/gerrit/server/query/change/ChangeData.java
+++ b/java/com/google/gerrit/server/query/change/ChangeData.java
@@ -75,6 +75,8 @@
 import com.google.gerrit.server.change.PureRevert;
 import com.google.gerrit.server.config.AllUsersName;
 import com.google.gerrit.server.config.TrackingFooters;
+import com.google.gerrit.server.experiments.ExperimentFeatures;
+import com.google.gerrit.server.experiments.ExperimentFeaturesConstants;
 import com.google.gerrit.server.git.GitRepositoryManager;
 import com.google.gerrit.server.git.MergeUtil;
 import com.google.gerrit.server.notedb.ChangeNotes;
@@ -87,6 +89,7 @@
 import com.google.gerrit.server.project.NoSuchChangeException;
 import com.google.gerrit.server.project.ProjectCache;
 import com.google.gerrit.server.project.ProjectState;
+import com.google.gerrit.server.project.SubmitRequirementsAdapter;
 import com.google.gerrit.server.project.SubmitRequirementsEvaluator;
 import com.google.gerrit.server.project.SubmitRuleEvaluator;
 import com.google.gerrit.server.project.SubmitRuleOptions;
@@ -268,7 +271,7 @@
     ChangeData cd =
         new ChangeData(
             null, null, null, null, null, null, null, null, null, null, null, null, null, null,
-            null, null, project, id, null, null);
+            null, null, null, project, id, null, null);
     cd.currentPatchSet =
         PatchSet.builder()
             .id(PatchSet.id(id, currentPatchSetId))
@@ -286,6 +289,7 @@
   private final ChangeMessagesUtil cmUtil;
   private final ChangeNotes.Factory notesFactory;
   private final CommentsUtil commentsUtil;
+  private final ExperimentFeatures experimentFeatures;
   private final GitRepositoryManager repoManager;
   private final MergeUtil.Factory mergeUtilFactory;
   private final MergeabilityCache mergeabilityCache;
@@ -367,6 +371,7 @@
       ChangeMessagesUtil cmUtil,
       ChangeNotes.Factory notesFactory,
       CommentsUtil commentsUtil,
+      ExperimentFeatures experimentFeatures,
       GitRepositoryManager repoManager,
       MergeUtil.Factory mergeUtilFactory,
       MergeabilityCache mergeabilityCache,
@@ -386,6 +391,7 @@
     this.cmUtil = cmUtil;
     this.notesFactory = notesFactory;
     this.commentsUtil = commentsUtil;
+    this.experimentFeatures = experimentFeatures;
     this.repoManager = repoManager;
     this.mergeUtilFactory = mergeUtilFactory;
     this.mergeabilityCache = mergeabilityCache;
@@ -946,14 +952,33 @@
         return Collections.emptyMap();
       }
       Change c = change();
-      if (c != null && c.isClosed()) {
-        submitRequirements =
-            notes().getSubmitRequirementsResult().stream()
-                .collect(Collectors.toMap(r -> r.submitRequirement(), Function.identity()));
-      } else {
+      if (c == null || !c.isClosed()) {
+        // Open changes: Evaluate submit requirements online.
         submitRequirements =
             submitRequirementsEvaluator.evaluateAllRequirements(this, /* includeLegacy= */ true);
+        return submitRequirements;
       }
+      // Closed changes: Load submit requirement results from NoteDb.
+      Map<SubmitRequirement, SubmitRequirementResult> projectConfigRequirements =
+          notes().getSubmitRequirementsResult().stream()
+              .filter(r -> !r.legacy())
+              .collect(Collectors.toMap(r -> r.submitRequirement(), Function.identity()));
+      if (!experimentFeatures.isFeatureEnabled(
+          ExperimentFeaturesConstants
+              .GERRIT_BACKEND_REQUEST_FEATURE_ENABLE_LEGACY_SUBMIT_REQUIREMENTS)) {
+        submitRequirements = projectConfigRequirements;
+        return submitRequirements;
+      }
+      // Get legacy submit requirements, i.e. those created from submit records.
+      Map<SubmitRequirement, SubmitRequirementResult> legacyRequirements =
+          SubmitRequirementsAdapter.getLegacyRequirements(submitRuleEvaluatorFactory, this);
+      // Combine projectConfigRequirements with legacyRequirements
+      submitRequirements =
+          Stream.of(projectConfigRequirements, legacyRequirements)
+              .flatMap(map -> map.entrySet().stream())
+              .collect(
+                  ImmutableMap.toImmutableMap(
+                      Map.Entry::getKey, Map.Entry::getValue, (value1, value2) -> value1));
     }
     return submitRequirements;
   }
diff --git a/javatests/com/google/gerrit/acceptance/api/change/ChangeIT.java b/javatests/com/google/gerrit/acceptance/api/change/ChangeIT.java
index 6a0408a..ed9f2f3 100644
--- a/javatests/com/google/gerrit/acceptance/api/change/ChangeIT.java
+++ b/javatests/com/google/gerrit/acceptance/api/change/ChangeIT.java
@@ -4582,8 +4582,12 @@
     // 4. Merge the change. Submit requirements status is presented from NoteDb.
     gApi.changes().id(changeId).current().submit();
     change = gApi.changes().id(changeId).get();
-    // Legacy submit records are not stored as submit requirements in NoteDb.
-    assertThat(change.submitRequirements).isEmpty();
+    // Legacy submit records are returned as submit requirements.
+    assertThat(change.submitRequirements).hasSize(2);
+    assertSubmitRequirementStatus(
+        change.submitRequirements, "Code-Review", Status.SATISFIED, /* isLegacy= */ true);
+    assertSubmitRequirementStatus(
+        change.submitRequirements, "build-cop-override", Status.SATISFIED, /* isLegacy= */ true);
   }
 
   @Test