public static void mergeParams(
      Map<String, ParamDefinition> params,
      Map<String, ParamDefinition> paramsToMerge,
      MergeContext context) {
    if (paramsToMerge == null) {
      return;
    }
    Stream.concat(params.keySet().stream(), paramsToMerge.keySet().stream())
        .forEach(
            name -> {
              ParamDefinition paramToMerge = paramsToMerge.get(name);
              if (paramToMerge == null) {
                return;
              }

              if (paramToMerge.getType() == ParamType.MAP && paramToMerge.isLiteral()) {
                Map<String, ParamDefinition> baseMap = mapValueOrEmpty(params, name);
                Map<String, ParamDefinition> toMergeMap = mapValueOrEmpty(paramsToMerge, name);
                mergeParams(
                    baseMap,
                    toMergeMap,
                    MergeContext.copyWithParentMode(
                        context, params.getOrDefault(name, paramToMerge).getMode()));
                params.put(
                    name,
                    buildMergedParamDefinition(
                        name, paramToMerge, params.get(name), context, baseMap));
              } else if (paramToMerge.getType() == ParamType.STRING_MAP
                  && paramToMerge.isLiteral()) {
                Map<String, String> baseMap = stringMapValueOrEmpty(params, name);
                Map<String, String> toMergeMap = stringMapValueOrEmpty(paramsToMerge, name);
                baseMap.putAll(toMergeMap);
                params.put(
                    name,
                    buildMergedParamDefinition(
                        name, paramToMerge, params.get(name), context, baseMap));
              } else {
                params.put(
                    name,
                    buildMergedParamDefinition(
                        name, paramToMerge, params.get(name), context, paramToMerge.getValue()));
              }
            });
  }
@Test
  public void testMergeInternalModeToMode() throws JsonProcessingException {
    Map<String, ParamDefinition> allParams =
        parseParamDefMap("{'param1': {'type': 'LONG','value': 2, 'internal_mode': 'RESERVED'}}");
    Map<String, ParamDefinition> paramsToMerge =
        parseParamDefMap("{'param1': {'type': 'LONG', 'value': 3}}");
    ParamsMergeHelper.mergeParams(allParams, paramsToMerge, systemMergeContext);
    assertEquals(ParamMode.CONSTANT, allParams.get("param1").asLongParamDef().getMode());

    for (String mode : Arrays.asList("OPTIONAL", "PROVIDED", "REQUIRED")) {
      allParams =
          parseParamDefMap(
              String.format(
                  "{'param1': {'type': 'LONG','value': 2, 'internal_mode': '%s'}}", mode));
      paramsToMerge = parseParamDefMap("{'param1': {'type': 'LONG', 'value': 3}}");
      ParamsMergeHelper.mergeParams(allParams, paramsToMerge, systemMergeContext);
      assertEquals(ParamMode.MUTABLE, allParams.get("param1").asLongParamDef().getMode());
    }
  }