@Test
  public void indexPersistorTest() throws IOException, StoreException {
    // make sure persistor is persisting all segments
    int numIndexSegments = state.index.getIndexSegments().size();
    state.index.persistIndex();
    List<File> indexFiles = Arrays.asList(tempDir.listFiles(PersistentIndex.INDEX_SEGMENT_FILE_FILTER));
    indexFiles.sort(PersistentIndex.INDEX_SEGMENT_FILE_COMPARATOR);
    assertEquals("Not as many files written as there were index segments", numIndexSegments, indexFiles.size());
    long prevFilePersistTimeMs = Long.MIN_VALUE;
    for (File indexFile : indexFiles) {
      long thisFilePersistTimeMs = indexFile.lastModified();
      assertTrue("A later index segment was persisted earlier", prevFilePersistTimeMs <= thisFilePersistTimeMs);
      prevFilePersistTimeMs = thisFilePersistTimeMs;
    }

    // add new entries which may not be persisted
    // call persist and reload the index (index.close() is never called)
    Offset indexEndOffset = state.index.getCurrentEndOffset();
    state.addPutEntries(1, CuratedLogIndexState.PUT_RECORD_SIZE, Utils.Infinite_Time);
    MockId id = state.logOrder.lastEntry().getValue().getFirst();
    state.index.persistIndex();
    state.reloadIndex(false, false);
    assertEquals("Index End offset mismatch ",
        new Offset(indexEndOffset.getName(), indexEndOffset.getOffset() + CuratedLogIndexState.PUT_RECORD_SIZE),
        state.index.getCurrentEndOffset());
    verifyValue(id, state.index.findKey(id));

    // add entries to index alone.
    // index.persist() should throw an exception since log end offset is < index end offset
    FileSpan fileSpan = new FileSpan(state.index.getCurrentEndOffset(),
        new Offset(state.index.getCurrentEndOffset().getName(),
            state.index.getCurrentEndOffset().getOffset() + CuratedLogIndexState.PUT_RECORD_SIZE));
    IndexValue value =
        new IndexValue(CuratedLogIndexState.PUT_RECORD_SIZE, fileSpan.getStartOffset(), Utils.Infinite_Time,
            state.time.milliseconds(), Utils.getRandomShort(TestUtils.RANDOM), Utils.getRandomShort(TestUtils.RANDOM));
    state.index.addToIndex(new IndexEntry(state.getUniqueId(), value), fileSpan);
    try {
      state.index.persistIndex();
      fail("Should have thrown exception since index has entries which log does not have");
    } catch (StoreException e) {
      assertEquals("StoreException error code mismatch ", StoreErrorCodes.IllegalIndexState, e.getErrorCode());
    }
    // append to log so that log and index are in sync with each other
    state.appendToLog(CuratedLogIndexState.PUT_RECORD_SIZE);
    // test persistor.write() failure due to I/O error
    Log mockLog = Mockito.spy(state.log);
    state.log = mockLog;
    state.reloadIndex(true, false);
    try {
      doThrow(new IOException(StoreException.IO_ERROR_STR)).when(mockLog).flush();
      state.index.close(false);
      fail("Should have thrown exception due to I/O error");
    } catch (StoreException e) {
      assertEquals("StoreException error code mismatch ", StoreErrorCodes.IOError, e.getErrorCode());
    }
    // test that when IOException's error message is null, the error code should be Unknown_Error
    try {
      doThrow(new IOException()).when(mockLog).flush();
      state.index.close(false);
      fail("Should have thrown exception due to I/O error");
    } catch (StoreException e) {
      assertEquals("StoreException error code mismatch ", StoreErrorCodes.UnknownError, e.getErrorCode());
    }
    Mockito.reset(mockLog);
  }
Tests the Index persistor for all cases
@throws IOException
@throws StoreException
ambry-store/src/test/java/com/github/ambry/store/IndexTest.java