/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.datastax.driver.core.schemabuilder;

import static com.datastax.driver.core.schemabuilder.SchemaBuilder.dateTieredStrategy;
import static com.datastax.driver.core.schemabuilder.SchemaBuilder.leveledStrategy;
import static com.datastax.driver.core.schemabuilder.SchemaBuilder.sizedTieredStategy;
import static com.datastax.driver.core.schemabuilder.SchemaBuilder.timeWindowCompactionStrategy;
import static com.datastax.driver.core.schemabuilder.TableOptions.CompactionOptions.DateTieredCompactionStrategyOptions;
import static com.datastax.driver.core.schemabuilder.TableOptions.CompactionOptions.TimeWindowCompactionStrategyOptions;
import static com.datastax.driver.core.schemabuilder.TableOptions.CompactionOptions.TimeWindowCompactionStrategyOptions.CompactionWindowUnit;
import static org.assertj.core.api.Assertions.assertThat;

import org.testng.annotations.Test;

public class CompactionOptionsTest {

  @Test(groups = "unit")
  public void should_create_sized_tiered_compaction_options() throws Exception {
    // When
    final String built =
        sizedTieredStategy()
            .bucketLow(0.5)
            .bucketHigh(1.2)
            .coldReadsRatioToOmit(0.89)
            .enabled(true)
            .minThreshold(2)
            .maxThreshold(4)
            .minSSTableSizeInBytes(5000000L)
            .tombstoneCompactionIntervalInDay(3)
            .tombstoneThreshold(0.7)
            .uncheckedTombstoneCompaction(true)
            .build();

    // Then
    assertThat(built)
        .isEqualTo(
            "{'class' : 'SizeTieredCompactionStrategy', "
                + "'enabled' : true, "
                + "'tombstone_compaction_interval' : 3, "
                + "'tombstone_threshold' : 0.7, "
                + "'unchecked_tombstone_compaction' : true, "
                + "'bucket_high' : 1.2, "
                + "'bucket_low' : 0.5, "
                + "'cold_reads_to_omit' : 0.89, "
                + "'min_threshold' : 2, "
                + "'max_threshold' : 4, "
                + "'min_sstable_size' : 5000000}");
  }

  @Test(groups = "unit")
  public void should_create_leveled_compaction_option() throws Exception {
    // When
    final String built =
        leveledStrategy()
            .enabled(true)
            .ssTableSizeInMB(160)
            .tombstoneCompactionIntervalInDay(3)
            .tombstoneThreshold(0.7)
            .uncheckedTombstoneCompaction(true)
            .build();

    // Then
    assertThat(built)
        .isEqualTo(
            "{'class' : 'LeveledCompactionStrategy', "
                + "'enabled' : true, "
                + "'tombstone_compaction_interval' : 3, "
                + "'tombstone_threshold' : 0.7, "
                + "'unchecked_tombstone_compaction' : true, "
                + "'sstable_size_in_mb' : 160}");
  }

  @Test(groups = "unit")
  public void should_create_date_tiered_compaction_option() throws Exception {
    // When
    String built =
        dateTieredStrategy()
            .baseTimeSeconds(7200)
            .enabled(true)
            .maxSSTableAgeDays(400)
            .minThreshold(2)
            .maxThreshold(4)
            .timestampResolution(
                DateTieredCompactionStrategyOptions.TimeStampResolution.MICROSECONDS)
            .tombstoneCompactionIntervalInDay(3)
            .tombstoneThreshold(0.7)
            .uncheckedTombstoneCompaction(true)
            .build();

    // Then
    assertThat(built)
        .isEqualTo(
            "{'class' : 'DateTieredCompactionStrategy', "
                + "'enabled' : true, "
                + "'tombstone_compaction_interval' : 3, "
                + "'tombstone_threshold' : 0.7, "
                + "'unchecked_tombstone_compaction' : true, "
                + "'base_time_seconds' : 7200, "
                + "'max_sstable_age_days' : 400, "
                + "'min_threshold' : 2, "
                + "'max_threshold' : 4, "
                + "'timestamp_resolution' : 'MICROSECONDS'}");
  }

  @Test(groups = "unit")
  public void should_create_time_window_compaction_option() throws Exception {
    // When
    String built =
        timeWindowCompactionStrategy()
            .bucketLow(0.5)
            .bucketHigh(1.2)
            .compactionWindowUnit(CompactionWindowUnit.HOURS)
            .compactionWindowSize(5)
            .enabled(true)
            .minThreshold(2)
            .maxThreshold(4)
            .minSSTableSizeInBytes(5000000L)
            .timestampResolution(
                TimeWindowCompactionStrategyOptions.TimeStampResolution.MICROSECONDS)
            .tombstoneCompactionIntervalInDay(3)
            .tombstoneThreshold(0.7)
            .uncheckedTombstoneCompaction(true)
            .unsafeAggressiveSSTableExpiration(true)
            .build();

    // Then
    assertThat(built)
        .isEqualTo(
            "{'class' : 'TimeWindowCompactionStrategy', "
                + "'enabled' : true, "
                + "'tombstone_compaction_interval' : 3, "
                + "'tombstone_threshold' : 0.7, "
                + "'unchecked_tombstone_compaction' : true, "
                + "'bucket_high' : 1.2, "
                + "'bucket_low' : 0.5, "
                + "'compaction_window_unit' : 'HOURS', "
                + "'compaction_window_size' : 5, "
                + "'min_threshold' : 2, "
                + "'max_threshold' : 4, "
                + "'min_sstable_size' : 5000000, "
                + "'timestamp_resolution' : 'MICROSECONDS', "
                + "'unsafe_aggressive_sstable_expiration' : 'true'}");
  }

  @Test(groups = "unit")
  public void should_handle_freeform_options() {
    // When
    String built =
        dateTieredStrategy().freeformOption("foo", "bar").freeformOption("baz", 1).build();

    // Then
    assertThat(built)
        .isEqualTo(
            "{'class' : 'DateTieredCompactionStrategy', " + "'foo' : 'bar', " + "'baz' : 1}");
  }

  @Test(groups = "unit", expectedExceptions = IllegalArgumentException.class)
  public void should_throw_exception_if_cold_read_ratio_out_of_range() throws Exception {
    sizedTieredStategy().bucketLow(0.5).bucketHigh(1.2).coldReadsRatioToOmit(1.89).build();
  }

  @Test(groups = "unit", expectedExceptions = IllegalArgumentException.class)
  public void should_throw_exception_if_cold_read_ratio_negative() throws Exception {
    sizedTieredStategy().bucketLow(0.5).bucketHigh(1.2).coldReadsRatioToOmit(-1.0).build();
  }

  @Test(groups = "unit", expectedExceptions = IllegalArgumentException.class)
  public void should_throw_exception_if_tombstone_threshold_out_of_range() throws Exception {
    sizedTieredStategy().bucketLow(0.5).bucketHigh(1.2).tombstoneThreshold(1.89).build();
  }

  @Test(groups = "unit", expectedExceptions = IllegalArgumentException.class)
  public void should_throw_exception_if_tombstone_threshold_negative() throws Exception {
    sizedTieredStategy().bucketLow(0.5).bucketHigh(1.2).coldReadsRatioToOmit(-1.0).build();
  }
}
