private void findDeletedEntriesSinceToIndexBasedTest() throws StoreException {
    // ------------------
    // 1. Index -> Index
    Offset secondIndexSegmentStartOffset = state.referenceIndex.higherKey(state.referenceIndex.firstKey());
    Map.Entry<MockId, TreeSet<IndexValue>> firstSegmentEntry =
        state.referenceIndex.get(secondIndexSegmentStartOffset).firstEntry();
    // Most elements from the second to be returned (because of size restrictions)
    Set<MockId> expectedKeys = new HashSet<>();
    long maxTotalSizeOfEntries = 0;
    MockId lastKey = null;
    for (Map.Entry<MockId, TreeSet<IndexValue>> segmentEntry : state.referenceIndex.get(secondIndexSegmentStartOffset)
        .entrySet()) {
      if (!segmentEntry.equals(firstSegmentEntry)) {
        if (segmentEntry.getValue().last().isDelete()
            && state.getExpectedValue(segmentEntry.getKey(), EnumSet.of(PersistentIndex.IndexEntryType.UNDELETE), null)
            == null) {
          expectedKeys.add(segmentEntry.getKey());
        }
        maxTotalSizeOfEntries += getSizeOfAllValues(segmentEntry.getValue());
      }
      lastKey = segmentEntry.getKey();
    }
    StoreFindToken startToken =
        new StoreFindToken(firstSegmentEntry.getKey(), secondIndexSegmentStartOffset, state.sessionId,
            state.incarnationId, null, null, UNINITIALIZED_RESET_KEY_VERSION);
    IndexSegment segmentOfToken = state.index.getIndexSegments().floorEntry(secondIndexSegmentStartOffset).getValue();
    StoreFindToken expectedEndToken =
        new StoreFindToken(lastKey, secondIndexSegmentStartOffset, state.sessionId, state.incarnationId,
            segmentOfToken.getResetKey(), segmentOfToken.getResetKeyType(), segmentOfToken.getResetKeyLifeVersion());
    doFindDeletedEntriesSinceTest(startToken, maxTotalSizeOfEntries, expectedKeys, expectedEndToken);

    // ------------------
    // 2. Uninitialized -> Index
    // add size of values and any keys that are supposed to be returned from the first index segment
    for (Map.Entry<MockId, TreeSet<IndexValue>> segmentEntry : state.referenceIndex.firstEntry()
        .getValue()
        .entrySet()) {
      if (segmentEntry.getValue().last().isDelete()
          && state.getExpectedValue(segmentEntry.getKey(), EnumSet.of(PersistentIndex.IndexEntryType.UNDELETE), null)
          == null) {
        expectedKeys.add(segmentEntry.getKey());
      }
      maxTotalSizeOfEntries += getSizeOfAllValues(segmentEntry.getValue());
    }
    // add size of value of firstIdInSegment
    maxTotalSizeOfEntries += getSizeOfAllValues(firstSegmentEntry.getValue());
    if (firstSegmentEntry.getValue().last().isDelete()
        && state.getExpectedValue(firstSegmentEntry.getKey(), EnumSet.of(PersistentIndex.IndexEntryType.UNDELETE), null)
        == null) {
      expectedKeys.add(firstSegmentEntry.getKey());
    }
    doFindDeletedEntriesSinceTest(new StoreFindToken(), maxTotalSizeOfEntries, expectedKeys, expectedEndToken);

    // ------------------
    // 3. Journal -> Index
    // create a journal based token for an offset that isn't in the journal
    startToken = new StoreFindToken(state.logOrder.firstKey(), state.sessionId, state.incarnationId, false, null, null,
        UNINITIALIZED_RESET_KEY_VERSION);
    doFindDeletedEntriesSinceTest(startToken, maxTotalSizeOfEntries, expectedKeys, expectedEndToken);
  }
Tests all cases of {@link PersistentIndex#findDeletedEntriesSince(FindToken, long, long)} that result in an index
based {@link StoreFindToken} being returned.
1. Uninitialized -> Index
2. Index -> Index
3. Journal -> Index
@throws StoreException
ambry-store/src/test/java/com/github/ambry/store/IndexTest.java