Program: 5160
Project: 5160
Buggy source:
/** 
 * Validate that this is a valid pipeline. A valid pipeline has the following properties: All stages in the pipeline have a unique name. Source stages have at least one output and no inputs. Sink stages have at least one input and no outputs. There are no cycles in the pipeline. All inputs into a stage have the same schema. ErrorTransforms only have BatchSource, Transform, or BatchAggregator as input stages Returns the stages in the order they should be configured to ensure that all input stages are configured before their output.
 * @param config the user provided configuration
 * @return the order to configure the stages in
 * @throws IllegalArgumentException if the pipeline is invalid
 */
private List<StageConnections> validateConfig(ETLConfig config){
  config.validate();
  if (config.getStages().isEmpty()) {
    throw new IllegalArgumentException("String_Node_Str");
  }
  Set<String> actionStages=new HashSet<>();
  Map<String,String> stageTypes=new HashMap<>();
  Set<String> stageNames=new HashSet<>();
  for (  ETLStage stage : config.getStages()) {
    if (!stageNames.add(stage.getName())) {
      throw new IllegalArgumentException(String.format("String_Node_Str",stage.getName()));
    }
    if (Action.PLUGIN_TYPE.equals(stage.getPlugin().getType())) {
      actionStages.add(stage.getName());
    }
    stageTypes.put(stage.getName(),stage.getPlugin().getType());
  }
  for (  Connection connection : config.getConnections()) {
    if (!stageNames.contains(connection.getFrom())) {
      throw new IllegalArgumentException(String.format("String_Node_Str",connection,connection.getFrom()));
    }
    if (!stageNames.contains(connection.getTo())) {
      throw new IllegalArgumentException(String.format("String_Node_Str",connection,connection.getTo()));
    }
  }
  Dag dag=new Dag(config.getConnections());
  Map<String,StageConnections> stages=new HashMap<>();
  for (  ETLStage stage : config.getStages()) {
    String stageName=stage.getName();
    Set<String> stageInputs=dag.getNodeInputs(stageName);
    Set<String> stageOutputs=dag.getNodeOutputs(stageName);
    String stageType=stage.getPlugin().getType();
    if (isSource(stageType)) {
      if (!stageInputs.isEmpty() && !actionStages.containsAll(stageInputs)) {
        throw new IllegalArgumentException(String.format("String_Node_Str",stageName,Joiner.on(',').join(stageInputs)));
      }
    }
 else     if (isSink(stageType)) {
      if (!stageOutputs.isEmpty() && !actionStages.containsAll(stageOutputs)) {
        throw new IllegalArgumentException(String.format("String_Node_Str",stageName,Joiner.on(',').join(stageOutputs)));
      }
    }
 else {
      boolean isAction=Action.PLUGIN_TYPE.equals(stageType);
      if (!isAction) {
        if (stageInputs.isEmpty()) {
          throw new IllegalArgumentException(String.format("String_Node_Str",stageName));
        }
        if (stageOutputs.isEmpty()) {
          throw new IllegalArgumentException(String.format("String_Node_Str",stageName));
        }
      }
      boolean isErrorTransform=ErrorTransform.PLUGIN_TYPE.equals(stageType);
      if (isErrorTransform) {
        for (        String inputStage : stageInputs) {
          String inputType=stageTypes.get(inputStage);
          if (!VALID_ERROR_INPUTS.contains(inputType)) {
            throw new IllegalArgumentException(String.format("String_Node_Str",stageName,inputStage,inputType,Joiner.on(',').join(VALID_ERROR_INPUTS)));
          }
        }
      }
    }
    stages.put(stageName,new StageConnections(stage,stageInputs,stageOutputs));
  }
  List<StageConnections> traversalOrder=new ArrayList<>(stages.size());
  for (  String stageName : dag.getTopologicalOrder()) {
    traversalOrder.add(stages.get(stageName));
  }
  return traversalOrder;
}

Fixed version (ground truth):
/** 
 * Validate that this is a valid pipeline. A valid pipeline has the following properties: All stages in the pipeline have a unique name. Source stages have at least one output and no inputs. Sink stages have at least one input and no outputs. There are no cycles in the pipeline. All inputs into a stage have the same schema. ErrorTransforms only have BatchSource, Transform, or BatchAggregator as input stages Returns the stages in the order they should be configured to ensure that all input stages are configured before their output.
 * @param config the user provided configuration
 * @return the order to configure the stages in
 * @throws IllegalArgumentException if the pipeline is invalid
 */
private List<StageConnections> validateConfig(ETLConfig config){
  config.validate();
  if (config.getStages().isEmpty()) {
    throw new IllegalArgumentException("String_Node_Str");
  }
  Set<String> actionStages=new HashSet<>();
  Map<String,String> stageTypes=new HashMap<>();
  Set<String> stageNames=new HashSet<>();
  for (  ETLStage stage : config.getStages()) {
    if (!stageNames.add(stage.getName())) {
      throw new IllegalArgumentException(String.format("String_Node_Str",stage.getName()));
    }
    if (isAction(stage.getPlugin().getType())) {
      actionStages.add(stage.getName());
    }
    stageTypes.put(stage.getName(),stage.getPlugin().getType());
  }
  for (  Connection connection : config.getConnections()) {
    if (!stageNames.contains(connection.getFrom())) {
      throw new IllegalArgumentException(String.format("String_Node_Str",connection,connection.getFrom()));
    }
    if (!stageNames.contains(connection.getTo())) {
      throw new IllegalArgumentException(String.format("String_Node_Str",connection,connection.getTo()));
    }
  }
  List<StageConnections> traversalOrder=new ArrayList<>(stageNames.size());
  if (config.getConnections().isEmpty()) {
    if (actionStages.size() == 1 && stageNames.size() == 1) {
      traversalOrder.add(new StageConnections(config.getStages().iterator().next(),Collections.<String>emptyList(),Collections.<String>emptyList()));
      return traversalOrder;
    }
 else {
      throw new IllegalArgumentException("String_Node_Str" + "String_Node_Str");
    }
  }
  Dag dag=new Dag(config.getConnections());
  Map<String,StageConnections> stages=new HashMap<>();
  for (  ETLStage stage : config.getStages()) {
    String stageName=stage.getName();
    Set<String> stageInputs=dag.getNodeInputs(stageName);
    Set<String> stageOutputs=dag.getNodeOutputs(stageName);
    String stageType=stage.getPlugin().getType();
    if (isSource(stageType)) {
      if (!stageInputs.isEmpty() && !actionStages.containsAll(stageInputs)) {
        throw new IllegalArgumentException(String.format("String_Node_Str",stageName,Joiner.on(',').join(stageInputs)));
      }
    }
 else     if (isSink(stageType)) {
      if (!stageOutputs.isEmpty() && !actionStages.containsAll(stageOutputs)) {
        throw new IllegalArgumentException(String.format("String_Node_Str",stageName,Joiner.on(',').join(stageOutputs)));
      }
    }
 else {
      if (!isAction(stageType)) {
        if (stageInputs.isEmpty()) {
          throw new IllegalArgumentException(String.format("String_Node_Str",stageName));
        }
        if (stageOutputs.isEmpty()) {
          throw new IllegalArgumentException(String.format("String_Node_Str",stageName));
        }
      }
      boolean isErrorTransform=ErrorTransform.PLUGIN_TYPE.equals(stageType);
      if (isErrorTransform) {
        for (        String inputStage : stageInputs) {
          String inputType=stageTypes.get(inputStage);
          if (!VALID_ERROR_INPUTS.contains(inputType)) {
            throw new IllegalArgumentException(String.format("String_Node_Str",stageName,inputStage,inputType,Joiner.on(',').join(VALID_ERROR_INPUTS)));
          }
        }
      }
    }
    stages.put(stageName,new StageConnections(stage,stageInputs,stageOutputs));
  }
  for (  String stageName : dag.getTopologicalOrder()) {
    traversalOrder.add(stages.get(stageName));
  }
  return traversalOrder;
}