public Map<String, Parameter> generateMergedWorkflowParams(
      WorkflowInstance instance, RunRequest request) {
    Workflow workflow = instance.getRuntimeWorkflow();
    Map<String, ParamDefinition> allParamDefs = new LinkedHashMap<>();
    Map<String, ParamDefinition> defaultWorkflowParams =
        defaultParamManager.getDefaultWorkflowParams();

    // merge workflow params for start
    if (request.isFreshRun()) {
      // merge default workflow params
      ParamsMergeHelper.mergeParams(
          allParamDefs,
          defaultWorkflowParams,
          ParamsMergeHelper.MergeContext.workflowCreate(ParamSource.SYSTEM_DEFAULT, request));

      // merge defined workflow params
      if (workflow.getParams() != null) {
        ParamsMergeHelper.mergeParams(
            allParamDefs,
            workflow.getParams(),
            ParamsMergeHelper.MergeContext.workflowCreate(ParamSource.DEFINITION, request));
      }
    }

    // merge workflow params from previous instance for restart
    if (!request.isFreshRun() && instance.getParams() != null) {
      Map<String, ParamDefinition> previousParamDefs =
          instance.getParams().entrySet().stream()
              .collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().toDefinition()));

      // remove reserved params, which should be injected again by the system.
      for (String paramName : Constants.RESERVED_PARAM_NAMES) {
        previousParamDefs.remove(paramName);
      }

      ParamsMergeHelper.mergeParams(
          allParamDefs,
          previousParamDefs,
          ParamsMergeHelper.MergeContext.workflowCreate(ParamSource.SYSTEM, false));
    }

    // merge run params
    if (request.getRunParams() != null) {
      ParamSource source = getParamSource(request.getInitiator(), request.isFreshRun());
      ParamsMergeHelper.mergeParams(
          allParamDefs,
          request.getRunParams(),
          ParamsMergeHelper.MergeContext.workflowCreate(source, request));
    }

    // merge user provided restart run params
    getUserRestartParam(request)
        .ifPresent(
            userRestartParams -> {
              ParamSource source = getParamSource(request.getInitiator(), request.isFreshRun());
              ParamsMergeHelper.mergeParams(
                  allParamDefs,
                  userRestartParams,
                  ParamsMergeHelper.MergeContext.workflowCreate(source, request));
            });

    // cleanup any placeholder params and convert to params
    return ParamsMergeHelper.convertToParameters(ParamsMergeHelper.cleanupParams(allParamDefs));
  }
@Test
  public void testWorkflowParamRunParamsUpstreamInitiator() {
    Map<String, ParamDefinition> runParams =
        singletonMap("p1", ParamDefinition.buildParamDefinition("p1", "d1"));

    ParamSource[] expectedSources =
        new ParamSource[] {ParamSource.FOREACH, ParamSource.SUBWORKFLOW, ParamSource.TEMPLATE};
    Initiator.Type[] initiators =
        new Initiator.Type[] {
          Initiator.Type.FOREACH, Initiator.Type.SUBWORKFLOW, Initiator.Type.TEMPLATE
        };
    for (int i = 0; i < initiators.length; i++) {
      RunRequest request =
          RunRequest.builder()
              .initiator(UpstreamInitiator.withType(initiators[i]))
              .currentPolicy(RunPolicy.START_FRESH_NEW_RUN)
              .runParams(runParams)
              .build();
      Map<String, Parameter> workflowParams =
          paramsManager.generateMergedWorkflowParams(workflowInstance, request);
      Assert.assertFalse(workflowParams.isEmpty());
      Assert.assertEquals("d1", workflowParams.get("p1").asStringParam().getValue());
      Assert.assertEquals(expectedSources[i], workflowParams.get("p1").getSource());
    }
  }