@Test
  public void testBucketedTemporalTableCompaction() throws Exception {
    long day1 = 1;
    long day2 = 2;
    long day3 = 3;
    long day4 = 4;

    List<ShardIndexInfo> inputShards =
        ImmutableList.of(
            shardWithTemporalBucket(OptionalInt.of(1), DATE, day1, day1),
            shardWithTemporalBucket(OptionalInt.of(2), DATE, day2, day2),
            shardWithTemporalBucket(OptionalInt.of(1), DATE, day1, day1),
            shardWithTemporalBucket(OptionalInt.of(2), DATE, day2, day2),
            shardWithTemporalBucket(OptionalInt.of(1), DATE, day3, day3),
            shardWithTemporalBucket(OptionalInt.of(2), DATE, day4, day4));

    long tableId = bucketedTemporalTableInfo.getTableId();
    Set<OrganizationSet> actual =
        compactionSetCreator.createCompactionSets(bucketedTemporalTableInfo, inputShards);

    assertEquals(actual.size(), 2);

    Set<OrganizationSet> expected =
        ImmutableSet.of(
            new OrganizationSet(tableId, extractIndexes(inputShards, 0, 2), OptionalInt.of(1)),
            new OrganizationSet(tableId, extractIndexes(inputShards, 1, 3), OptionalInt.of(2)));
    assertEquals(actual, expected);
  }
  @Test
  public void testTemporalCompactionDate() throws Exception {
    long day1 = Duration.ofNanos(System.nanoTime()).toDays();
    long day2 = day1 + 1;
    long day3 = day1 + 2;

    List<ShardIndexInfo> inputShards =
        ImmutableList.of(
            shardWithTemporalRange(DATE, day1, day1),
            shardWithTemporalRange(DATE, day2, day2),
            shardWithTemporalRange(DATE, day3, day3),
            shardWithTemporalRange(DATE, day1, day3),
            shardWithTemporalRange(DATE, day2, day3),
            shardWithTemporalRange(DATE, day1, day2));

    long tableId = temporalTableInfo.getTableId();
    Set<OrganizationSet> actual =
        compactionSetCreator.createCompactionSets(temporalTableInfo, inputShards);

    assertEquals(actual.size(), 2);

    Set<OrganizationSet> expected =
        ImmutableSet.of(
            new OrganizationSet(tableId, extractIndexes(inputShards, 0, 3, 5), OptionalInt.empty()),
            new OrganizationSet(tableId, extractIndexes(inputShards, 1, 4), OptionalInt.empty()));
    assertEquals(actual, expected);
  }
  @Test
  public void testTemporalCompactionSpanningDays() throws Exception {
    long day1 = Duration.ofDays(Duration.ofNanos(System.nanoTime()).toDays()).toMillis();
    long day2 = Duration.ofDays(Duration.ofMillis(day1).toDays() + 1).toMillis();
    long day3 = Duration.ofDays(Duration.ofMillis(day1).toDays() + 2).toMillis();
    long day4 = Duration.ofDays(Duration.ofMillis(day1).toDays() + 3).toMillis();

    List<ShardIndexInfo> inputShards =
        ImmutableList.of(
            shardWithTemporalRange(TIMESTAMP, day1, day3), // day2
            shardWithTemporalRange(TIMESTAMP, day2, day2), // day2
            shardWithTemporalRange(TIMESTAMP, day1, day1), // day1
            shardWithTemporalRange(TIMESTAMP, day1 + 100, day2 + 100), // day1
            shardWithTemporalRange(TIMESTAMP, day1 - 100, day2 - 100), // day1
            shardWithTemporalRange(TIMESTAMP, day2 - 100, day3 - 100), // day2
            shardWithTemporalRange(TIMESTAMP, day1, day4) // day2
            );

    long tableId = temporalTableInfo.getTableId();
    Set<OrganizationSet> compactionSets =
        compactionSetCreator.createCompactionSets(temporalTableInfo, inputShards);

    assertEquals(compactionSets.size(), 2);

    Set<OrganizationSet> expected =
        ImmutableSet.of(
            new OrganizationSet(
                tableId, extractIndexes(inputShards, 0, 1, 5, 6), OptionalInt.empty()),
            new OrganizationSet(
                tableId, extractIndexes(inputShards, 2, 3, 4), OptionalInt.empty()));
    assertEquals(compactionSets, expected);
  }
  @Test
  public void testTemporalCompactionNoCompactionAcrossDays() throws Exception {
    long day1 = Duration.ofDays(Duration.ofNanos(System.nanoTime()).toDays()).toMillis();
    long day2 = Duration.ofDays(Duration.ofMillis(day1).toDays() + 1).toMillis();
    long day3 = Duration.ofDays(Duration.ofMillis(day1).toDays() + 2).toMillis();

    List<ShardIndexInfo> inputShards =
        ImmutableList.of(
            shardWithTemporalRange(TIMESTAMP, day1, day1),
            shardWithTemporalRange(TIMESTAMP, day2, day2),
            shardWithTemporalRange(TIMESTAMP, day2, day2),
            shardWithTemporalRange(TIMESTAMP, day1, day1),
            shardWithTemporalRange(TIMESTAMP, day3, day3));

    Set<OrganizationSet> actual =
        compactionSetCreator.createCompactionSets(temporalTableInfo, inputShards);
    assertEquals(actual.size(), 2);

    Set<OrganizationSet> expected =
        ImmutableSet.of(
            new OrganizationSet(
                temporalTableInfo.getTableId(),
                extractIndexes(inputShards, 0, 3),
                OptionalInt.empty()),
            new OrganizationSet(
                temporalTableInfo.getTableId(),
                extractIndexes(inputShards, 1, 2),
                OptionalInt.empty()));
    assertEquals(actual, expected);
  }
  @Test
  public void testNonTemporalOrganizationSetSimple() throws Exception {
    List<ShardIndexInfo> inputShards =
        ImmutableList.of(shardWithSize(10, 10), shardWithSize(10, 10), shardWithSize(10, 10));

    Set<OrganizationSet> compactionSets =
        compactionSetCreator.createCompactionSets(tableInfo, inputShards);
    assertEquals(compactionSets.size(), 1);
    assertEquals(getOnlyElement(compactionSets).getShards(), extractIndexes(inputShards, 0, 1, 2));
  }
  @Test
  public void testNonTemporalSizeBasedOrganizationSet() throws Exception {
    List<ShardIndexInfo> inputShards =
        ImmutableList.of(
            shardWithSize(10, 70),
            shardWithSize(10, 20),
            shardWithSize(10, 30),
            shardWithSize(10, 120));

    Set<OrganizationSet> compactionSets =
        compactionSetCreator.createCompactionSets(tableInfo, inputShards);

    Set<UUID> actual = new HashSet<>();
    for (OrganizationSet set : compactionSets) {
      actual.addAll(set.getShards());
    }
    assertTrue(extractIndexes(inputShards, 0, 1, 2).containsAll(actual));
  }
  @Test
  public void testBucketedTableCompaction() throws Exception {
    List<ShardIndexInfo> inputShards =
        ImmutableList.of(
            shardWithBucket(1),
            shardWithBucket(2),
            shardWithBucket(2),
            shardWithBucket(1),
            shardWithBucket(2),
            shardWithBucket(1));

    long tableId = bucketedTableInfo.getTableId();
    Set<OrganizationSet> actual =
        compactionSetCreator.createCompactionSets(bucketedTableInfo, inputShards);

    assertEquals(actual.size(), 2);

    Set<OrganizationSet> expected =
        ImmutableSet.of(
            new OrganizationSet(tableId, extractIndexes(inputShards, 0, 3, 5), OptionalInt.of(1)),
            new OrganizationSet(tableId, extractIndexes(inputShards, 1, 2, 4), OptionalInt.of(2)));
    assertEquals(actual, expected);
  }