public void updateWorkflowInstance(WorkflowInstance instance, RunRequest runRequest) {
    if (!runRequest.isFreshRun() && instance.getRuntimeDag() != null) {
      // For restart, set the baseline aggregatedInfo using the previous run aggregated info.
      instance.setAggregatedInfo(AggregatedViewHelper.computeAggregatedView(instance, true));
    }
    // set run id to the latest but unknown, which will be set later
    instance.setWorkflowRunId(Constants.LATEST_ONE);
    instance.setWorkflowUuid(IdHelper.getOrCreateUuid(runRequest.getRequestId()));
    instance.setExecutionId(null); // clear execution id if set
    instance.setRunConfig(runRequest.toRunConfig());
    instance.setRunParams(runRequest.getRunParams());
    instance.setStepRunParams(runRequest.getStepRunParams());
    instance.setInitiator(runRequest.getInitiator());
    instance.setStatus(WorkflowInstance.Status.CREATED);
    instance.setRequestTime(runRequest.getRequestTime());
    // create time will be set within transaction to ensure the same order as instance id.
    // not set startTime and endTime, modified time will be set by DB automatically
    instance.setRuntimeOverview(null); // always null before running
    instance.setArtifacts(runRequest.getArtifacts());
    // set runtime dag
    instance.setRuntimeDag(dagTranslator.translate(instance));
    // validate run params
    if (runRequest.getStepRunParams() != null) {
      Checks.checkTrue(
          runRequest.getStepRunParams().keySet().stream()
              .allMatch(instance.getRuntimeDag()::containsKey),
          "non-existing step id detected in step param overrides: inputs %s vs dag %s",
          runRequest.getStepRunParams().keySet(),
          instance.getRuntimeDag().keySet());
    }
    // set initial timeline
    instance.setTimeline(
        new Timeline(Collections.singletonList(runRequest.getInitiator().getTimelineEvent())));

    try {
      initiateWorkflowParamsAndProperties(instance, runRequest);
    } catch (RuntimeException e) {
      if (runRequest.isPersistFailedRun()) {
        instance.setStatus(WorkflowInstance.Status.FAILED);
        instance
            .getTimeline()
            .add(
                TimelineDetailsEvent.from(
                    Details.create(e, false, "Failed to initiate workflow params and properties")));
      } else {
        throw e;
      }
    }
  }
@Test
  public void testUpdateWorkflowInstance() {
    Map<String, ParamDefinition> runParams =
        Collections.singletonMap("p1", ParamDefinition.buildParamDefinition("p1", "d1"));
    RunRequest request =
        RunRequest.builder()
            .initiator(new ManualInitiator())
            .currentPolicy(RunPolicy.START_FRESH_NEW_RUN)
            .runParams(runParams)
            .build();
    Workflow workflow = definition.getWorkflow();
    WorkflowInstance instance =
        workflowHelper.createWorkflowInstance(workflow, 12345L, 1, new RunProperties(), request);
    assertEquals(workflow.getId(), instance.getWorkflowId());
    assertEquals(WorkflowInstance.Status.CREATED, instance.getStatus());
    assertEquals(12345L, instance.getInternalId().longValue());
    assertNotNull(instance.getParams());
    assertNotNull(instance.getWorkflowUuid());
    // For manual initiator, verify if params are generated.
    Mockito.verify(paramsManager, Mockito.times(1)).generateMergedWorkflowParams(instance, request);
    request =
        RunRequest.builder()
            .initiator(new TimeInitiator())
            .currentPolicy(RunPolicy.START_FRESH_NEW_RUN)
            .runParams(runParams)
            .build();
    WorkflowInstance createdInstance =
        workflowHelper.createWorkflowInstance(workflow, 123L, 1, new RunProperties(), request);
    // For trigger based, verify if null has been passed.
    Mockito.verify(paramsManager, Mockito.times(1))
        .generateMergedWorkflowParams(createdInstance, request);
  }