Program: 56743
Project: 56743
Buggy source:
protected ScalingOperationReport processCloudwatchMetrics(Map<KinesisOperationType,Map<StreamMetric,Map<Datapoint,Double>>> currentUtilisationMetrics,Map<KinesisOperationType,StreamMetrics> streamMaxCapacity,int cwSampleDuration,DateTime now){
  ScalingOperationReport report=null;
  ScaleDirection finalScaleDirection=null;
  Map<KinesisOperationType,ScaleDirection> scaleVotes=new HashMap<>();
  for (  Map.Entry<KinesisOperationType,Map<StreamMetric,Map<Datapoint,Double>>> entry : currentUtilisationMetrics.entrySet()) {
    scaleVotes.put(entry.getKey(),ScaleDirection.NONE);
    Map<StreamMetric,Triplet<Integer,Integer,Double>> perMetricSamples=new HashMap<>();
    StreamMetric higherUtilisationMetric;
    Double higherUtilisationPct;
    for (    StreamMetric metric : StreamMetric.values()) {
      double currentMax=0D;
      double currentPct=0D;
      double latestPct=0d;
      double latestMax=0d;
      double latestAvg=0d;
      DateTime lastTime=null;
      int lowSamples=0;
      int highSamples=0;
      Map<Datapoint,Double> metrics=new HashMap<>();
      if (!currentUtilisationMetrics.containsKey(entry.getKey()) || !entry.getValue().containsKey(metric)) {
      }
 else {
        metrics=entry.getValue().get(metric);
      }
      if (metrics.size() == 0) {
        lowSamples=this.config.getScaleDown().getScaleAfterMins();
      }
      for (      Map.Entry<Datapoint,Double> datapointEntry : metrics.entrySet()) {
        currentMax=datapointEntry.getValue();
        currentPct=currentMax / streamMaxCapacity.get(entry.getKey()).get(metric);
        if (lastTime == null || new DateTime(datapointEntry.getKey().getTimestamp()).isAfter(lastTime)) {
          latestPct=currentPct;
          latestMax=currentMax;
          latestAvg=latestAvg == 0d ? currentPct : (latestAvg + currentPct) / 2;
        }
        lastTime=new DateTime(datapointEntry.getKey().getTimestamp());
        if (currentPct > new Double(this.config.getScaleUp().getScaleThresholdPct()) / 100) {
          LOG.debug(String.format("String_Node_Str",entry.getKey(),metric,currentMax,metric,currentPct * 100));
          highSamples++;
        }
 else         if (currentPct < new Double(this.config.getScaleDown().getScaleThresholdPct()) / 100) {
          LOG.debug(String.format("String_Node_Str",entry.getKey(),metric,currentMax,metric,currentPct * 100));
          lowSamples++;
        }
      }
      if (metrics.size() < cwSampleDuration) {
        lowSamples+=cwSampleDuration - metrics.size();
      }
      LOG.info(String.format(metric + "String_Node_Str" + metric+ "String_Node_Str",config.getStreamName(),entry.getKey(),metric,latestAvg * 100,latestMax,streamMaxCapacity.get(entry.getKey()).get(metric)));
      if (!perMetricSamples.containsKey(metric)) {
        perMetricSamples.put(metric,new Triplet<>(highSamples,lowSamples,latestAvg));
      }
 else {
        Triplet<Integer,Integer,Double> previousHighLow=perMetricSamples.get(metric);
        Triplet<Integer,Integer,Double> newHighLow=new Triplet<>(previousHighLow.getValue0() + highSamples,previousHighLow.getValue1() + lowSamples,(previousHighLow.getValue2() + latestAvg) / 2);
        perMetricSamples.put(metric,newHighLow);
      }
    }
    if (perMetricSamples.get(StreamMetric.Bytes).getValue2() >= perMetricSamples.get(StreamMetric.Records).getValue2()) {
      higherUtilisationMetric=StreamMetric.Bytes;
      higherUtilisationPct=perMetricSamples.get(StreamMetric.Bytes).getValue2();
    }
 else {
      higherUtilisationMetric=StreamMetric.Records;
      higherUtilisationPct=perMetricSamples.get(StreamMetric.Records).getValue2();
    }
    LOG.info(String.format("String_Node_Str",entry.getKey(),higherUtilisationMetric,higherUtilisationPct * 100));
    if (perMetricSamples.get(higherUtilisationMetric).getValue0() >= config.getScaleUp().getScaleAfterMins()) {
      scaleVotes.put(entry.getKey(),ScaleDirection.UP);
    }
 else     if (perMetricSamples.get(higherUtilisationMetric).getValue1() >= config.getScaleDown().getScaleAfterMins()) {
      scaleVotes.put(entry.getKey(),ScaleDirection.DOWN);
    }
  }
  ScaleDirection getVote=scaleVotes.get(KinesisOperationType.GET);
  ScaleDirection putVote=scaleVotes.get(KinesisOperationType.PUT);
  if (getVote != null && putVote != null) {
    if (getVote == ScaleDirection.UP || putVote == ScaleDirection.UP) {
      finalScaleDirection=ScaleDirection.UP;
    }
 else     if (getVote == ScaleDirection.NONE && putVote == ScaleDirection.NONE) {
      finalScaleDirection=ScaleDirection.NONE;
    }
 else {
      finalScaleDirection=ScaleDirection.DOWN;
    }
  }
 else {
    finalScaleDirection=(getVote == null ? putVote : getVote);
  }
  try {
    int currentShardCount=this.scaler.getOpenShardCount(this.config.getStreamName());
    if (finalScaleDirection.equals(ScaleDirection.UP)) {
      Integer scaleUpCount=this.config.getScaleUp().getScaleCount();
      LOG.info(String.format("String_Node_Str",this.config.getStreamName(),(scaleUpCount != null) ? scaleUpCount : this.config.getScaleUp().getScalePct() + "String_Node_Str",this.config.getScaleOnOperations().toString(),this.config.getScaleUp().getScaleThresholdPct(),this.config.getScaleUp().getScaleAfterMins()));
      if (scaleUpCount != null) {
        report=this.scaler.updateShardCount(this.config.getStreamName(),currentShardCount,currentShardCount + scaleUpCount,this.config.getMinShards(),this.config.getMaxShards());
      }
 else {
        report=this.scaler.updateShardCount(this.config.getStreamName(),currentShardCount,new Double(currentShardCount * (new Double(this.config.getScaleUp().getScalePct()) / 100)).intValue(),this.config.getMinShards(),this.config.getMaxShards());
      }
      if (report != null && this.config.getScaleUp().getNotificationARN() != null && this.snsClient != null) {
        StreamScalingUtils.sendNotification(this.snsClient,this.config.getScaleUp().getNotificationARN(),"String_Node_Str",(report == null ? "String_Node_Str" : report.asJson()));
      }
    }
 else     if (finalScaleDirection.equals(ScaleDirection.DOWN)) {
      if (lastScaleDown != null && now.minusMinutes(this.config.getScaleDown().getCoolOffMins()).isBefore(lastScaleDown)) {
        LOG.info(String.format("String_Node_Str",this.config.getStreamName(),this.config.getScaleDown().getCoolOffMins()));
      }
 else {
        Integer scaleDownCount=this.config.getScaleDown().getScaleCount();
        LOG.info(String.format("String_Node_Str",this.config.getStreamName(),(scaleDownCount != null) ? scaleDownCount : this.config.getScaleDown().getScalePct() + "String_Node_Str",config.getScaleOnOperations().toString(),this.config.getScaleDown().getScaleThresholdPct(),this.config.getScaleDown().getScaleAfterMins()));
        try {
          if (scaleDownCount != null) {
            report=this.scaler.updateShardCount(this.config.getStreamName(),currentShardCount,currentShardCount - scaleDownCount,this.config.getMinShards(),this.config.getMaxShards());
          }
 else {
            report=this.scaler.updateShardCount(this.config.getStreamName(),currentShardCount,new Double(currentShardCount - (new Double(this.config.getScaleDown().getScalePct()) / 100)).intValue(),this.config.getMinShards(),this.config.getMaxShards());
          }
          lastScaleDown=new DateTime(System.currentTimeMillis());
          if (report != null && this.config.getScaleDown().getNotificationARN() != null && this.snsClient != null) {
            StreamScalingUtils.sendNotification(this.snsClient,this.config.getScaleDown().getNotificationARN(),"String_Node_Str",(report == null ? "String_Node_Str" : report.asJson()));
          }
        }
 catch (        AlreadyOneShardException aose) {
          LOG.info(String.format("String_Node_Str",this.config.getStreamName()));
        }
      }
    }
 else {
      LOG.info("String_Node_Str");
      return this.scaler.reportFor(ScalingCompletionStatus.NoActionRequired,this.config.getStreamName(),0,finalScaleDirection);
    }
  }
 catch (  Exception e) {
    LOG.error("String_Node_Str" + this.config.getStreamName(),e);
  }
  return report;
}

Fixed version (ground truth):
protected ScalingOperationReport processCloudwatchMetrics(Map<KinesisOperationType,Map<StreamMetric,Map<Datapoint,Double>>> currentUtilisationMetrics,Map<KinesisOperationType,StreamMetrics> streamMaxCapacity,int cwSampleDuration,DateTime now){
  ScalingOperationReport report=null;
  ScaleDirection finalScaleDirection=null;
  Map<KinesisOperationType,ScaleDirection> scaleVotes=new HashMap<>();
  for (  Map.Entry<KinesisOperationType,Map<StreamMetric,Map<Datapoint,Double>>> entry : currentUtilisationMetrics.entrySet()) {
    scaleVotes.put(entry.getKey(),ScaleDirection.NONE);
    Map<StreamMetric,Triplet<Integer,Integer,Double>> perMetricSamples=new HashMap<>();
    StreamMetric higherUtilisationMetric;
    Double higherUtilisationPct;
    for (    StreamMetric metric : StreamMetric.values()) {
      double currentMax=0D;
      double currentPct=0D;
      double latestPct=0d;
      double latestMax=0d;
      double latestAvg=0d;
      DateTime lastTime=null;
      int lowSamples=0;
      int highSamples=0;
      Map<Datapoint,Double> metrics=new HashMap<>();
      if (!currentUtilisationMetrics.containsKey(entry.getKey()) || !entry.getValue().containsKey(metric)) {
      }
 else {
        metrics=entry.getValue().get(metric);
      }
      if (metrics.size() == 0) {
        lowSamples=this.config.getScaleDown().getScaleAfterMins();
      }
      for (      Map.Entry<Datapoint,Double> datapointEntry : metrics.entrySet()) {
        currentMax=datapointEntry.getValue();
        currentPct=currentMax / streamMaxCapacity.get(entry.getKey()).get(metric);
        if (lastTime == null || new DateTime(datapointEntry.getKey().getTimestamp()).isAfter(lastTime)) {
          latestPct=currentPct;
          latestMax=currentMax;
          latestAvg=latestAvg == 0d ? currentPct : (latestAvg + currentPct) / 2;
        }
        lastTime=new DateTime(datapointEntry.getKey().getTimestamp());
        if (currentPct > new Double(this.config.getScaleUp().getScaleThresholdPct()) / 100) {
          LOG.debug(String.format("String_Node_Str",entry.getKey(),metric,currentMax,metric,currentPct * 100));
          highSamples++;
        }
 else         if (currentPct < new Double(this.config.getScaleDown().getScaleThresholdPct()) / 100) {
          LOG.debug(String.format("String_Node_Str",entry.getKey(),metric,currentMax,metric,currentPct * 100));
          lowSamples++;
        }
      }
      if (metrics.size() < cwSampleDuration) {
        lowSamples+=cwSampleDuration - metrics.size();
      }
      LOG.info(String.format(metric + "String_Node_Str" + metric+ "String_Node_Str",config.getStreamName(),entry.getKey(),metric,latestAvg * 100,latestMax,streamMaxCapacity.get(entry.getKey()).get(metric)));
      if (!perMetricSamples.containsKey(metric)) {
        perMetricSamples.put(metric,new Triplet<>(highSamples,lowSamples,latestAvg));
      }
 else {
        Triplet<Integer,Integer,Double> previousHighLow=perMetricSamples.get(metric);
        Triplet<Integer,Integer,Double> newHighLow=new Triplet<>(previousHighLow.getValue0() + highSamples,previousHighLow.getValue1() + lowSamples,(previousHighLow.getValue2() + latestAvg) / 2);
        perMetricSamples.put(metric,newHighLow);
      }
    }
    if (perMetricSamples.get(StreamMetric.Bytes).getValue2() >= perMetricSamples.get(StreamMetric.Records).getValue2()) {
      higherUtilisationMetric=StreamMetric.Bytes;
      higherUtilisationPct=perMetricSamples.get(StreamMetric.Bytes).getValue2();
    }
 else {
      higherUtilisationMetric=StreamMetric.Records;
      higherUtilisationPct=perMetricSamples.get(StreamMetric.Records).getValue2();
    }
    LOG.info(String.format("String_Node_Str",entry.getKey(),higherUtilisationMetric,higherUtilisationPct * 100));
    if (perMetricSamples.get(higherUtilisationMetric).getValue0() >= config.getScaleUp().getScaleAfterMins()) {
      scaleVotes.put(entry.getKey(),ScaleDirection.UP);
    }
 else     if (perMetricSamples.get(higherUtilisationMetric).getValue1() >= config.getScaleDown().getScaleAfterMins()) {
      scaleVotes.put(entry.getKey(),ScaleDirection.DOWN);
    }
  }
  ScaleDirection getVote=scaleVotes.get(KinesisOperationType.GET);
  ScaleDirection putVote=scaleVotes.get(KinesisOperationType.PUT);
  if (getVote != null && putVote != null) {
    if (getVote == ScaleDirection.UP || putVote == ScaleDirection.UP) {
      finalScaleDirection=ScaleDirection.UP;
    }
 else     if (getVote == ScaleDirection.NONE && putVote == ScaleDirection.NONE) {
      finalScaleDirection=ScaleDirection.NONE;
    }
 else {
      finalScaleDirection=ScaleDirection.DOWN;
    }
  }
 else {
    finalScaleDirection=(getVote == null ? putVote : getVote);
  }
  try {
    int currentShardCount=this.scaler.getOpenShardCount(this.config.getStreamName());
    if (finalScaleDirection.equals(ScaleDirection.UP)) {
      Integer scaleUpCount=this.config.getScaleUp().getScaleCount();
      LOG.info(String.format("String_Node_Str",this.config.getStreamName(),(scaleUpCount != null) ? scaleUpCount : this.config.getScaleUp().getScalePct() + "String_Node_Str",this.config.getScaleOnOperations().toString(),this.config.getScaleUp().getScaleThresholdPct(),this.config.getScaleUp().getScaleAfterMins()));
      if (scaleUpCount != null) {
        report=this.scaler.updateShardCount(this.config.getStreamName(),currentShardCount,currentShardCount + scaleUpCount,this.config.getMinShards(),this.config.getMaxShards());
      }
 else {
        report=this.scaler.updateShardCount(this.config.getStreamName(),currentShardCount,new Double(currentShardCount * (new Double(this.config.getScaleUp().getScalePct()) / 100)).intValue(),this.config.getMinShards(),this.config.getMaxShards());
      }
      if (report != null && this.config.getScaleUp().getNotificationARN() != null && this.snsClient != null) {
        StreamScalingUtils.sendNotification(this.snsClient,this.config.getScaleUp().getNotificationARN(),"String_Node_Str",(report == null ? "String_Node_Str" : report.asJson()));
      }
    }
 else     if (finalScaleDirection.equals(ScaleDirection.DOWN)) {
      if (lastScaleDown != null && now.minusMinutes(this.config.getScaleDown().getCoolOffMins()).isBefore(lastScaleDown)) {
        LOG.info(String.format("String_Node_Str",this.config.getStreamName(),this.config.getScaleDown().getCoolOffMins()));
      }
 else {
        Integer scaleDownCount=this.config.getScaleDown().getScaleCount();
        LOG.info(String.format("String_Node_Str",this.config.getStreamName(),(scaleDownCount != null) ? scaleDownCount : this.config.getScaleDown().getScalePct() + "String_Node_Str",config.getScaleOnOperations().toString(),this.config.getScaleDown().getScaleThresholdPct(),this.config.getScaleDown().getScaleAfterMins()));
        try {
          if (scaleDownCount != null) {
            report=this.scaler.updateShardCount(this.config.getStreamName(),currentShardCount,currentShardCount - scaleDownCount,this.config.getMinShards(),this.config.getMaxShards());
          }
 else {
            report=this.scaler.updateShardCount(this.config.getStreamName(),currentShardCount,new Double(currentShardCount * (new Double(this.config.getScaleDown().getScalePct()) / 100)).intValue(),this.config.getMinShards(),this.config.getMaxShards());
          }
          lastScaleDown=new DateTime(System.currentTimeMillis());
          if (report != null && this.config.getScaleDown().getNotificationARN() != null && this.snsClient != null) {
            StreamScalingUtils.sendNotification(this.snsClient,this.config.getScaleDown().getNotificationARN(),"String_Node_Str",(report == null ? "String_Node_Str" : report.asJson()));
          }
        }
 catch (        AlreadyOneShardException aose) {
          LOG.info(String.format("String_Node_Str",this.config.getStreamName()));
        }
      }
    }
 else {
      LOG.info("String_Node_Str");
      return this.scaler.reportFor(ScalingCompletionStatus.NoActionRequired,this.config.getStreamName(),0,finalScaleDirection);
    }
  }
 catch (  Exception e) {
    LOG.error("String_Node_Str" + this.config.getStreamName(),e);
  }
  return report;
}