/**
 * 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 org.apache.pinot.core.query.aggregation.groupby;

import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.pinot.common.request.context.ExpressionContext;
import org.apache.pinot.core.operator.blocks.TransformBlock;
import org.apache.pinot.core.operator.transform.TransformOperator;
import org.apache.pinot.core.plan.DocIdSetPlanNode;
import org.apache.pinot.core.plan.TransformPlanNode;
import org.apache.pinot.core.plan.maker.InstancePlanMakerImplV2;
import org.apache.pinot.core.query.request.context.QueryContext;
import org.apache.pinot.core.query.request.context.utils.QueryContextConverterUtils;
import org.apache.pinot.segment.local.indexsegment.immutable.ImmutableSegmentLoader;
import org.apache.pinot.segment.local.segment.creator.impl.SegmentIndexCreationDriverImpl;
import org.apache.pinot.segment.local.segment.readers.GenericRowRecordReader;
import org.apache.pinot.segment.spi.IndexSegment;
import org.apache.pinot.segment.spi.creator.SegmentGeneratorConfig;
import org.apache.pinot.spi.config.table.TableConfig;
import org.apache.pinot.spi.config.table.TableType;
import org.apache.pinot.spi.data.DimensionFieldSpec;
import org.apache.pinot.spi.data.FieldSpec;
import org.apache.pinot.spi.data.Schema;
import org.apache.pinot.spi.data.readers.GenericRow;
import org.apache.pinot.spi.utils.ReadMode;
import org.apache.pinot.spi.utils.builder.TableConfigBuilder;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;

import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertFalse;
import static org.testng.Assert.assertTrue;


public class DictionaryBasedGroupKeyGeneratorTest {
  private static final String SEGMENT_NAME = "testSegment";
  private static final String INDEX_DIR_PATH = FileUtils.getTempDirectoryPath() + File.separator + SEGMENT_NAME;
  private static final int NUM_ROWS = 1000;
  private static final int UNIQUE_ROWS = 100;
  private static final int MAX_STEP_LENGTH = 1000;
  private static final int MAX_NUM_MULTI_VALUES = 10;
  private static final int NUM_GROUPS = 20;
  private static final int[] SV_GROUP_KEY_BUFFER = new int[NUM_GROUPS];
  private static final int[][] MV_GROUP_KEY_BUFFER = new int[NUM_GROUPS][];
  private static final String FILTER_COLUMN = "docId";
  private static final String[] SV_COLUMNS = {"s1", "s2", "s3", "s4", "s5", "s6", "s7", "s8", "s9", "s10"};
  private static final String[] MV_COLUMNS = {"m1", "m2"};

  private final long _randomSeed = System.currentTimeMillis();
  private final Random _random = new Random(_randomSeed);
  private final String _errorMessage = "Random seed is: " + _randomSeed;

  private TransformOperator _transformOperator;
  private TransformBlock _transformBlock;

  @BeforeClass
  private void setup()
      throws Exception {
    FileUtils.deleteQuietly(new File(INDEX_DIR_PATH));

    List<GenericRow> rows = new ArrayList<>(NUM_ROWS);
    int value = _random.nextInt(MAX_STEP_LENGTH);

    // Generate random values for the segment
    for (int i = 0; i < UNIQUE_ROWS; i++) {
      Map<String, Object> map = new HashMap<>();
      map.put(FILTER_COLUMN, i);
      for (String svColumn : SV_COLUMNS) {
        map.put(svColumn, value);
        value += 1 + _random.nextInt(MAX_STEP_LENGTH);
      }
      for (String mvColumn : MV_COLUMNS) {
        int numMultiValues = 1 + _random.nextInt(MAX_NUM_MULTI_VALUES);
        Integer[] values = new Integer[numMultiValues];
        for (int k = 0; k < numMultiValues; k++) {
          values[k] = value;
          value += 1 + _random.nextInt(MAX_STEP_LENGTH);
        }
        map.put(mvColumn, values);
      }
      GenericRow row = new GenericRow();
      row.init(map);
      rows.add(row);
    }
    for (int i = UNIQUE_ROWS; i < NUM_ROWS; i++) {
      rows.add(rows.get(i % UNIQUE_ROWS));
    }

    // Create an index segment with the random values
    Schema schema = new Schema();
    schema.addField(new DimensionFieldSpec(FILTER_COLUMN, FieldSpec.DataType.INT, true));
    for (String singleValueColumn : SV_COLUMNS) {
      schema.addField(new DimensionFieldSpec(singleValueColumn, FieldSpec.DataType.INT, true));
    }
    for (String multiValueColumn : MV_COLUMNS) {
      schema.addField(new DimensionFieldSpec(multiValueColumn, FieldSpec.DataType.INT, false));
    }

    TableConfig tableConfig = new TableConfigBuilder(TableType.OFFLINE).setTableName("test").build();

    SegmentGeneratorConfig config = new SegmentGeneratorConfig(tableConfig, schema);
    config.setOutDir(INDEX_DIR_PATH);
    config.setSegmentName(SEGMENT_NAME);

    SegmentIndexCreationDriverImpl driver = new SegmentIndexCreationDriverImpl();
    driver.init(config, new GenericRowRecordReader(rows));
    driver.build();
    IndexSegment indexSegment = ImmutableSegmentLoader.load(new File(INDEX_DIR_PATH, SEGMENT_NAME), ReadMode.heap);

    // Generate a random query to filter out 2 unique rows
    int docId1 = _random.nextInt(50);
    int docId2 = docId1 + 1 + _random.nextInt(50);
    // NOTE: put all columns into group-by so that transform operator has expressions for all columns
    String query =
        String.format("SELECT COUNT(*) FROM testTable WHERE %s IN (%d, %d) GROUP BY %s, %s", FILTER_COLUMN, docId1,
            docId2, StringUtils.join(SV_COLUMNS, ", "), StringUtils.join(MV_COLUMNS, ", "));
    QueryContext queryContext = QueryContextConverterUtils.getQueryContext(query);

    List<ExpressionContext> expressions = new ArrayList<>();
    for (String column : SV_COLUMNS) {
      expressions.add(ExpressionContext.forIdentifier(column));
    }
    for (String column : MV_COLUMNS) {
      expressions.add(ExpressionContext.forIdentifier(column));
    }
    TransformPlanNode transformPlanNode =
        new TransformPlanNode(indexSegment, queryContext, expressions, DocIdSetPlanNode.MAX_DOC_PER_CALL);
    _transformOperator = transformPlanNode.run();
    _transformBlock = _transformOperator.nextBlock();
  }

  @Test
  public void testArrayBasedSingleValue() {
    // Cardinality product (100) smaller than arrayBasedThreshold
    String[] groupByColumns = {"s1"};

    // Test initial status
    DictionaryBasedGroupKeyGenerator dictionaryBasedGroupKeyGenerator =
        new DictionaryBasedGroupKeyGenerator(_transformOperator, getExpressions(groupByColumns),
            InstancePlanMakerImplV2.DEFAULT_NUM_GROUPS_LIMIT,
            InstancePlanMakerImplV2.DEFAULT_MAX_INITIAL_RESULT_HOLDER_CAPACITY);
    assertEquals(dictionaryBasedGroupKeyGenerator.getGlobalGroupKeyUpperBound(), UNIQUE_ROWS, _errorMessage);
    assertEquals(dictionaryBasedGroupKeyGenerator.getCurrentGroupKeyUpperBound(), UNIQUE_ROWS, _errorMessage);

    // Test group key generation
    dictionaryBasedGroupKeyGenerator.generateKeysForBlock(_transformBlock, SV_GROUP_KEY_BUFFER);
    assertEquals(dictionaryBasedGroupKeyGenerator.getCurrentGroupKeyUpperBound(), UNIQUE_ROWS, _errorMessage);
    compareSingleValueBuffer();
    testGetGroupKeys(dictionaryBasedGroupKeyGenerator.getGroupKeys(), 2);
  }

  @Test
  public void testIntMapBasedSingleValue() {
    // Cardinality product (1,000,000) larger than arrayBasedThreshold but smaller than Integer.MAX_VALUE
    String[] groupByColumns = {"s1", "s2", "s3"};

    // Test initial status
    DictionaryBasedGroupKeyGenerator dictionaryBasedGroupKeyGenerator =
        new DictionaryBasedGroupKeyGenerator(_transformOperator, getExpressions(groupByColumns),
            InstancePlanMakerImplV2.DEFAULT_NUM_GROUPS_LIMIT,
            InstancePlanMakerImplV2.DEFAULT_MAX_INITIAL_RESULT_HOLDER_CAPACITY);
    assertEquals(dictionaryBasedGroupKeyGenerator.getGlobalGroupKeyUpperBound(),
        InstancePlanMakerImplV2.DEFAULT_NUM_GROUPS_LIMIT, _errorMessage);
    assertEquals(dictionaryBasedGroupKeyGenerator.getCurrentGroupKeyUpperBound(), 0, _errorMessage);

    // Test group key generation
    dictionaryBasedGroupKeyGenerator.generateKeysForBlock(_transformBlock, SV_GROUP_KEY_BUFFER);
    assertEquals(dictionaryBasedGroupKeyGenerator.getCurrentGroupKeyUpperBound(), 2, _errorMessage);
    compareSingleValueBuffer();
    testGetGroupKeys(dictionaryBasedGroupKeyGenerator.getGroupKeys(), 2);
  }

  @Test
  public void testLongMapBasedSingleValue() {
    // Cardinality product (10,000,000,000) larger than Integer.MAX_VALUE but smaller than LONG.MAX_VALUE
    String[] groupByColumns = {"s1", "s2", "s3", "s4", "s5"};

    // Test initial status
    DictionaryBasedGroupKeyGenerator dictionaryBasedGroupKeyGenerator =
        new DictionaryBasedGroupKeyGenerator(_transformOperator, getExpressions(groupByColumns),
            InstancePlanMakerImplV2.DEFAULT_NUM_GROUPS_LIMIT,
            InstancePlanMakerImplV2.DEFAULT_MAX_INITIAL_RESULT_HOLDER_CAPACITY);
    assertEquals(dictionaryBasedGroupKeyGenerator.getGlobalGroupKeyUpperBound(),
        InstancePlanMakerImplV2.DEFAULT_NUM_GROUPS_LIMIT, _errorMessage);
    assertEquals(dictionaryBasedGroupKeyGenerator.getCurrentGroupKeyUpperBound(), 0, _errorMessage);

    // Test group key generation
    dictionaryBasedGroupKeyGenerator.generateKeysForBlock(_transformBlock, SV_GROUP_KEY_BUFFER);
    assertEquals(dictionaryBasedGroupKeyGenerator.getCurrentGroupKeyUpperBound(), 2, _errorMessage);
    compareSingleValueBuffer();
    testGetGroupKeys(dictionaryBasedGroupKeyGenerator.getGroupKeys(), 2);
  }

  @Test
  public void testArrayMapBasedSingleValue() {
    // Cardinality product larger than Long.MAX_VALUE
    String[] groupByColumns = {"s1", "s2", "s3", "s4", "s5", "s6", "s7", "s8", "s9", "s10"};

    // Test initial status
    DictionaryBasedGroupKeyGenerator dictionaryBasedGroupKeyGenerator =
        new DictionaryBasedGroupKeyGenerator(_transformOperator, getExpressions(groupByColumns),
            InstancePlanMakerImplV2.DEFAULT_NUM_GROUPS_LIMIT,
            InstancePlanMakerImplV2.DEFAULT_MAX_INITIAL_RESULT_HOLDER_CAPACITY);
    assertEquals(dictionaryBasedGroupKeyGenerator.getGlobalGroupKeyUpperBound(),
        InstancePlanMakerImplV2.DEFAULT_NUM_GROUPS_LIMIT, _errorMessage);
    assertEquals(dictionaryBasedGroupKeyGenerator.getCurrentGroupKeyUpperBound(), 0, _errorMessage);

    // Test group key generation
    dictionaryBasedGroupKeyGenerator.generateKeysForBlock(_transformBlock, SV_GROUP_KEY_BUFFER);
    assertEquals(dictionaryBasedGroupKeyGenerator.getCurrentGroupKeyUpperBound(), 2, _errorMessage);
    compareSingleValueBuffer();
    testGetGroupKeys(dictionaryBasedGroupKeyGenerator.getGroupKeys(), 2);
  }

  /**
   * Helper method to compare the values inside the single value group key buffer.
   *
   * All odd number index values should be the same, all even number index values should be the same.
   * Odd number index values should be different from even number index values.
   */
  private void compareSingleValueBuffer() {
    assertTrue(SV_GROUP_KEY_BUFFER[0] != SV_GROUP_KEY_BUFFER[1], _errorMessage);
    for (int i = 2; i < NUM_GROUPS; i += 2) {
      assertEquals(SV_GROUP_KEY_BUFFER[i], SV_GROUP_KEY_BUFFER[0], _errorMessage);
      assertEquals(SV_GROUP_KEY_BUFFER[i + 1], SV_GROUP_KEY_BUFFER[1], _errorMessage);
    }
  }

  @Test
  public void testArrayBasedMultiValue() {
    // Cardinality product (100 - 1,000) smaller than arrayBasedThreshold
    String[] groupByColumns = {"m1"};

    // Test initial status
    DictionaryBasedGroupKeyGenerator dictionaryBasedGroupKeyGenerator =
        new DictionaryBasedGroupKeyGenerator(_transformOperator, getExpressions(groupByColumns),
            InstancePlanMakerImplV2.DEFAULT_NUM_GROUPS_LIMIT,
            InstancePlanMakerImplV2.DEFAULT_MAX_INITIAL_RESULT_HOLDER_CAPACITY);
    int groupKeyUpperBound = dictionaryBasedGroupKeyGenerator.getGlobalGroupKeyUpperBound();
    assertEquals(dictionaryBasedGroupKeyGenerator.getCurrentGroupKeyUpperBound(), groupKeyUpperBound, _errorMessage);

    // Test group key generation
    dictionaryBasedGroupKeyGenerator.generateKeysForBlock(_transformBlock, MV_GROUP_KEY_BUFFER);
    int numUniqueKeys = MV_GROUP_KEY_BUFFER[0].length + MV_GROUP_KEY_BUFFER[1].length;
    assertEquals(dictionaryBasedGroupKeyGenerator.getCurrentGroupKeyUpperBound(), groupKeyUpperBound, _errorMessage);
    compareMultiValueBuffer();
    testGetGroupKeys(dictionaryBasedGroupKeyGenerator.getGroupKeys(), numUniqueKeys);
  }

  @Test
  public void tesIntMapBasedMultiValue() {
    // Cardinality product (1,000,000 - 100,000,000) larger than arrayBasedThreshold but smaller than Integer.MAX_VALUE
    String[] groupByColumns = {"m1", "m2", "s1"};

    // Test initial status
    DictionaryBasedGroupKeyGenerator dictionaryBasedGroupKeyGenerator =
        new DictionaryBasedGroupKeyGenerator(_transformOperator, getExpressions(groupByColumns),
            InstancePlanMakerImplV2.DEFAULT_NUM_GROUPS_LIMIT,
            InstancePlanMakerImplV2.DEFAULT_MAX_INITIAL_RESULT_HOLDER_CAPACITY);
    assertEquals(dictionaryBasedGroupKeyGenerator.getGlobalGroupKeyUpperBound(),
        InstancePlanMakerImplV2.DEFAULT_NUM_GROUPS_LIMIT, _errorMessage);
    assertEquals(dictionaryBasedGroupKeyGenerator.getCurrentGroupKeyUpperBound(), 0, _errorMessage);

    // Test group key generation
    dictionaryBasedGroupKeyGenerator.generateKeysForBlock(_transformBlock, MV_GROUP_KEY_BUFFER);
    int numUniqueKeys = MV_GROUP_KEY_BUFFER[0].length + MV_GROUP_KEY_BUFFER[1].length;
    assertEquals(dictionaryBasedGroupKeyGenerator.getCurrentGroupKeyUpperBound(), numUniqueKeys, _errorMessage);
    compareMultiValueBuffer();
    testGetGroupKeys(dictionaryBasedGroupKeyGenerator.getGroupKeys(), numUniqueKeys);
  }

  @Test
  public void testLongMapBasedMultiValue() {
    // Cardinality product (10,000,000,000 - 1,000,000,000,000) larger than Integer.MAX_VALUE but smaller than LONG
    // .MAX_VALUE
    String[] groupByColumns = {"m1", "m2", "s1", "s2", "s3"};

    // Test initial status
    DictionaryBasedGroupKeyGenerator dictionaryBasedGroupKeyGenerator =
        new DictionaryBasedGroupKeyGenerator(_transformOperator, getExpressions(groupByColumns),
            InstancePlanMakerImplV2.DEFAULT_NUM_GROUPS_LIMIT,
            InstancePlanMakerImplV2.DEFAULT_MAX_INITIAL_RESULT_HOLDER_CAPACITY);
    assertEquals(dictionaryBasedGroupKeyGenerator.getGlobalGroupKeyUpperBound(),
        InstancePlanMakerImplV2.DEFAULT_NUM_GROUPS_LIMIT, _errorMessage);
    assertEquals(dictionaryBasedGroupKeyGenerator.getCurrentGroupKeyUpperBound(), 0, _errorMessage);

    // Test group key generation
    dictionaryBasedGroupKeyGenerator.generateKeysForBlock(_transformBlock, MV_GROUP_KEY_BUFFER);
    int numUniqueKeys = MV_GROUP_KEY_BUFFER[0].length + MV_GROUP_KEY_BUFFER[1].length;
    assertEquals(dictionaryBasedGroupKeyGenerator.getCurrentGroupKeyUpperBound(), numUniqueKeys, _errorMessage);
    compareMultiValueBuffer();
    testGetGroupKeys(dictionaryBasedGroupKeyGenerator.getGroupKeys(), numUniqueKeys);
  }

  @Test
  public void testArrayMapBasedMultiValue() {
    // Cardinality product larger than Long.MAX_VALUE
    String[] groupByColumns = {"m1", "m2", "s1", "s2", "s3", "s4", "s5", "s6", "s7", "s8", "s9", "s10"};

    // Test initial status
    DictionaryBasedGroupKeyGenerator dictionaryBasedGroupKeyGenerator =
        new DictionaryBasedGroupKeyGenerator(_transformOperator, getExpressions(groupByColumns),
            InstancePlanMakerImplV2.DEFAULT_NUM_GROUPS_LIMIT,
            InstancePlanMakerImplV2.DEFAULT_MAX_INITIAL_RESULT_HOLDER_CAPACITY);
    assertEquals(dictionaryBasedGroupKeyGenerator.getGlobalGroupKeyUpperBound(),
        InstancePlanMakerImplV2.DEFAULT_NUM_GROUPS_LIMIT, _errorMessage);
    assertEquals(dictionaryBasedGroupKeyGenerator.getCurrentGroupKeyUpperBound(), 0, _errorMessage);

    // Test group key generation
    dictionaryBasedGroupKeyGenerator.generateKeysForBlock(_transformBlock, MV_GROUP_KEY_BUFFER);
    int numUniqueKeys = MV_GROUP_KEY_BUFFER[0].length + MV_GROUP_KEY_BUFFER[1].length;
    assertEquals(dictionaryBasedGroupKeyGenerator.getCurrentGroupKeyUpperBound(), numUniqueKeys, _errorMessage);
    compareMultiValueBuffer();
    testGetGroupKeys(dictionaryBasedGroupKeyGenerator.getGroupKeys(), numUniqueKeys);
  }

  @Test
  public void testNumGroupsLimit() {
    String[] groupByColumns = {"m1", "m2"};
    int numGroupsLimit = 1;
    // NOTE: arrayBasedThreshold must be smaller or equal to numGroupsLimit
    DictionaryBasedGroupKeyGenerator dictionaryBasedGroupKeyGenerator =
        new DictionaryBasedGroupKeyGenerator(_transformOperator, getExpressions(groupByColumns), numGroupsLimit,
            numGroupsLimit);
    assertEquals(dictionaryBasedGroupKeyGenerator.getGlobalGroupKeyUpperBound(), numGroupsLimit, _errorMessage);
    assertEquals(dictionaryBasedGroupKeyGenerator.getCurrentGroupKeyUpperBound(), 0, _errorMessage);

    // Test group key generation
    dictionaryBasedGroupKeyGenerator.generateKeysForBlock(_transformBlock, MV_GROUP_KEY_BUFFER);
    assertEquals(dictionaryBasedGroupKeyGenerator.getCurrentGroupKeyUpperBound(), numGroupsLimit, _errorMessage);
    // Only the first key should be 0, all others should be GroupKeyGenerator.INVALID_ID (-1)
    boolean firstKey = true;
    for (int groupKey : MV_GROUP_KEY_BUFFER[0]) {
      if (firstKey) {
        assertEquals(groupKey, 0);
        firstKey = false;
      } else {
        assertEquals(groupKey, GroupKeyGenerator.INVALID_ID);
      }
    }
    for (int groupKey : MV_GROUP_KEY_BUFFER[1]) {
      assertEquals(groupKey, GroupKeyGenerator.INVALID_ID);
    }
    for (int i = 2; i < NUM_GROUPS; i += 2) {
      assertEquals(MV_GROUP_KEY_BUFFER[i], MV_GROUP_KEY_BUFFER[0], _errorMessage);
      assertEquals(MV_GROUP_KEY_BUFFER[i + 1], MV_GROUP_KEY_BUFFER[1], _errorMessage);
    }
    testGetGroupKeys(dictionaryBasedGroupKeyGenerator.getGroupKeys(), numGroupsLimit);
  }

  private static ExpressionContext[] getExpressions(String[] columns) {
    int numColumns = columns.length;
    ExpressionContext[] expressions = new ExpressionContext[numColumns];
    for (int i = 0; i < numColumns; i++) {
      expressions[i] = ExpressionContext.forIdentifier(columns[i]);
    }
    return expressions;
  }

  /**
   * Helper method to compare the values inside the multi value group key buffer.
   *
   * All odd number index values should be the same, all even number index values should be the same.
   * Odd number index values should be different from even number index values.
   */
  private void compareMultiValueBuffer() {
    assertFalse(Arrays.equals(MV_GROUP_KEY_BUFFER[0], MV_GROUP_KEY_BUFFER[1]), _errorMessage);
    for (int i = 2; i < NUM_GROUPS; i += 2) {
      assertEquals(MV_GROUP_KEY_BUFFER[i], MV_GROUP_KEY_BUFFER[0], _errorMessage);
      assertEquals(MV_GROUP_KEY_BUFFER[i + 1], MV_GROUP_KEY_BUFFER[1], _errorMessage);
    }
  }

  /**
   * Helper method to test the group key iterator returned by getGroupKeys().
   *
   * @param groupKeyIterator group key iterator.
   * @param numUniqueKeys number of unique keys.
   */
  private void testGetGroupKeys(Iterator<GroupKeyGenerator.GroupKey> groupKeyIterator, int numUniqueKeys) {
    int count = 0;
    Set<Integer> idSet = new HashSet<>();
    Set<List<Object>> groupKeySet = new HashSet<>();

    while (groupKeyIterator.hasNext()) {
      count++;
      GroupKeyGenerator.GroupKey groupKey = groupKeyIterator.next();
      idSet.add(groupKey._groupId);
      groupKeySet.add(Arrays.asList(groupKey._keys));
    }

    assertEquals(count, numUniqueKeys, _errorMessage);
    assertEquals(idSet.size(), numUniqueKeys, _errorMessage);
    assertEquals(groupKeySet.size(), numUniqueKeys, _errorMessage);
  }

  @Test
  public void testMapDefaultValue() {
    assertEquals(DictionaryBasedGroupKeyGenerator.THREAD_LOCAL_LONG_MAP.get().defaultReturnValue(),
        GroupKeyGenerator.INVALID_ID);
    assertEquals(DictionaryBasedGroupKeyGenerator.THREAD_LOCAL_INT_ARRAY_MAP.get().defaultReturnValue(),
        GroupKeyGenerator.INVALID_ID);
  }

  @AfterClass
  public void tearDown() {
    FileUtils.deleteQuietly(new File(INDEX_DIR_PATH));
  }
}
