public ProvisionResponse aggregate(ProvisionResponse other) {
    if (_status == ProvisionStatus.UNDER_PROVISIONED) {
      if (other.status() == ProvisionStatus.UNDER_PROVISIONED) {
        aggregateRecommendations(other);
      }
    } else {
      switch (other.status()) {
        case UNDER_PROVISIONED:
          _status = ProvisionStatus.UNDER_PROVISIONED;
          clearRecommendation();
          aggregateRecommendations(other);
          break;
        case RIGHT_SIZED:
          _status = ProvisionStatus.RIGHT_SIZED;
          clearRecommendation();
          break;
        case OVER_PROVISIONED:
          if (_status == ProvisionStatus.OVER_PROVISIONED || _status == ProvisionStatus.UNDECIDED) {
            _status = ProvisionStatus.OVER_PROVISIONED;
            aggregateRecommendations(other);
            break;
          }
          // Keep the status as right-sized if it was right-sized before.
          break;
        case UNDECIDED:
          // Nothing to do.
          break;
        default:
          throw new IllegalArgumentException("Unsupported provision status " + other + " is provided.");
      }
    }
    return this;
  }
@Test
  public void testAggregate() {
    // Verify validity of input while creating a ProvisionResponse using an invalid recommender and recommendation.
    assertThrows(IllegalArgumentException.class, () -> new ProvisionResponse(ProvisionStatus.RIGHT_SIZED, OVER_PROV_REC, RECOMMENDER_UP));
    assertThrows(IllegalArgumentException.class, () -> new ProvisionResponse(ProvisionStatus.UNDECIDED, OVER_PROV_REC, RECOMMENDER_UP));

    // Verify validity of input while creating a ProvisionResponse using a valid recommendation, but an invalid (i.e. null) recommender.
    assertThrows(IllegalArgumentException.class, () -> new ProvisionResponse(ProvisionStatus.OVER_PROVISIONED, OVER_PROV_REC, null));
    assertThrows(IllegalArgumentException.class, () -> new ProvisionResponse(ProvisionStatus.UNDER_PROVISIONED, UNDER_PROV_REC, null));

    // Verify validity of aggregation (1) state, (2) recommendation, and (3) provision recommendations.
    // Case-1: Aggregating any provision status with {@link ProvisionStatus#UNDER_PROVISIONED} is {@link ProvisionStatus#UNDER_PROVISIONED}.
    String recommender = "Case1";
    for (ProvisionStatus status : ProvisionStatus.cachedValues()) {
      ProvisionResponse underProvisioned = new ProvisionResponse(ProvisionStatus.UNDER_PROVISIONED, UNDER_PROV_REC, recommender);
      underProvisioned.aggregate(generateProvisionResponse(status));
      assertEquals(ProvisionStatus.UNDER_PROVISIONED, underProvisioned.status());
      assertEquals(status == ProvisionStatus.UNDER_PROVISIONED
                   ? String.format("[%s] %s [%s] %s", recommender, UNDER_PROV_REC_STR, RECOMMENDER_UP, UNDER_PROV_REC_STR)
                   : String.format("[%s] %s", recommender, UNDER_PROV_REC_STR), underProvisioned.recommendation());
      assertEquals(status == ProvisionStatus.UNDER_PROVISIONED ? 2 : 1, underProvisioned.recommendationByRecommender().size());
      assertEquals(NUM_BROKERS_UP, underProvisioned.recommendationByRecommender().get(recommender).numBrokers());
      assertEquals(TYPICAL_BROKER_ID_UP, underProvisioned.recommendationByRecommender().get(recommender).typicalBrokerId());
      assertEquals(TYPICAL_BROKER_CAPACITY_UP, underProvisioned.recommendationByRecommender().get(recommender).typicalBrokerCapacity(), DELTA);
      if (status == ProvisionStatus.UNDER_PROVISIONED) {
        assertEquals(NUM_BROKERS_UP, underProvisioned.recommendationByRecommender().get(RECOMMENDER_UP).numBrokers());
        assertEquals(TYPICAL_BROKER_ID_UP, underProvisioned.recommendationByRecommender().get(RECOMMENDER_UP).typicalBrokerId());
        assertEquals(TYPICAL_BROKER_CAPACITY_UP, underProvisioned.recommendationByRecommender().get(RECOMMENDER_UP).typicalBrokerCapacity(), DELTA);
      }
    }

    // Case-2: Aggregating a provision status {@code P} with {@link ProvisionStatus#UNDECIDED} is {@code P}
    for (ProvisionStatus status : ProvisionStatus.cachedValues()) {
      ProvisionResponse undecided = new ProvisionResponse(ProvisionStatus.UNDECIDED);
      ProvisionResponse other = generateProvisionResponse(status);
      String recommendationBefore = other.recommendation();
      Map<String, ProvisionRecommendation> recommendationByRecommenderBefore = other.recommendationByRecommender();
      undecided.aggregate(other);
      assertEquals(status, undecided.status());
      assertEquals(recommendationBefore, undecided.recommendation());
      assertEquals(recommendationByRecommenderBefore, undecided.recommendationByRecommender());
    }

    // Case-3.1: Aggregating {@link ProvisionStatus#RIGHT_SIZED} with {@link ProvisionStatus#RIGHT_SIZED} or
    // {@link ProvisionStatus#OVER_PROVISIONED} is {@link ProvisionStatus#RIGHT_SIZED}
    ProvisionResponse rightSized = new ProvisionResponse(ProvisionStatus.RIGHT_SIZED);
    rightSized.aggregate(generateProvisionResponse(ProvisionStatus.RIGHT_SIZED));
    assertEquals(ProvisionStatus.RIGHT_SIZED, rightSized.status());
    assertTrue(rightSized.recommendationByRecommender().isEmpty());
    rightSized.aggregate(generateProvisionResponse(ProvisionStatus.OVER_PROVISIONED));
    assertEquals(ProvisionStatus.RIGHT_SIZED, rightSized.status());
    assertTrue(rightSized.recommendation().isEmpty());
    assertTrue(rightSized.recommendationByRecommender().isEmpty());

    // Case-3.2: Aggregating {@link ProvisionStatus#OVER_PROVISIONED} with {@link ProvisionStatus#RIGHT_SIZED} clears the recommendation
    recommender = "Case3.2";
    ProvisionResponse overProvisioned = new ProvisionResponse(ProvisionStatus.OVER_PROVISIONED, OVER_PROV_REC, recommender);
    assertFalse(overProvisioned.recommendation().isEmpty());
    assertFalse(overProvisioned.recommendationByRecommender().isEmpty());
    overProvisioned.aggregate(generateProvisionResponse(ProvisionStatus.RIGHT_SIZED));
    assertTrue(overProvisioned.recommendation().isEmpty());
    assertTrue(overProvisioned.recommendationByRecommender().isEmpty());

    // Case-4: Aggregating {@link ProvisionStatus#OVER_PROVISIONED} with {@link ProvisionStatus#OVER_PROVISIONED} yields itself
    recommender = "Case4";
    overProvisioned = new ProvisionResponse(ProvisionStatus.OVER_PROVISIONED, OVER_PROV_REC, recommender);
    assertEquals(String.format("[%s] %s", recommender, OVER_PROV_REC_STR), overProvisioned.recommendation());
    assertEquals(1, overProvisioned.recommendationByRecommender().size());
    assertEquals(NUM_BROKERS_OP, overProvisioned.recommendationByRecommender().get(recommender).numBrokers());
    assertEquals(TYPICAL_BROKER_ID_OP, overProvisioned.recommendationByRecommender().get(recommender).typicalBrokerId());
    assertEquals(TYPICAL_BROKER_CAPACITY_OP, overProvisioned.recommendationByRecommender().get(recommender).typicalBrokerCapacity(), DELTA);

    overProvisioned.aggregate(generateProvisionResponse(ProvisionStatus.OVER_PROVISIONED));
    assertEquals(ProvisionStatus.OVER_PROVISIONED, overProvisioned.status());
    assertEquals(String.format("[%s] %s [%s] %s", recommender, OVER_PROV_REC_STR, RECOMMENDER_OP, OVER_PROV_REC_STR),
                 overProvisioned.recommendation());
    assertEquals(2, overProvisioned.recommendationByRecommender().size());
    assertEquals(NUM_BROKERS_OP, overProvisioned.recommendationByRecommender().get(RECOMMENDER_OP).numBrokers());
    assertEquals(TYPICAL_BROKER_ID_OP, overProvisioned.recommendationByRecommender().get(RECOMMENDER_OP).typicalBrokerId());
    assertEquals(TYPICAL_BROKER_CAPACITY_OP, overProvisioned.recommendationByRecommender().get(RECOMMENDER_OP).typicalBrokerCapacity(), DELTA);
  }