@Test
  public void markAsUndeletedBadInputTest() throws StoreException {
    assumeTrue(isLogSegmented && addUndeletes);
    // FileSpan end offset < currentIndexEndOffset
    FileSpan fileSpan = state.log.getFileSpanForMessage(state.index.getStartOffset(), 1);
    try {
      state.index.markAsUndeleted(state.deletedKeys.iterator().next(), fileSpan, state.time.milliseconds());
      fail("Should have failed because filespan provided < currentIndexEndOffset");
    } catch (IllegalArgumentException e) {
      // expected. Nothing to do.
    }

    // FileSpan spans across segments
    Offset startOffset = state.index.getCurrentEndOffset();
    LogSegmentName nextLogSegmentName = startOffset.getName().getNextPositionName();
    Offset endOffset = new Offset(nextLogSegmentName, 0);
    fileSpan = new FileSpan(startOffset, endOffset);
    try {
      state.index.markAsUndeleted(state.deletedKeys.iterator().next(), fileSpan, state.time.milliseconds());
      fail("Should have failed because fileSpan provided spanned across segments");
    } catch (IllegalArgumentException e) {
      // expected. Nothing to do.
    }

    state.appendToLog(5);
    fileSpan = state.log.getFileSpanForMessage(state.index.getCurrentEndOffset(), 5);
    // ID does not exist
    try {
      state.index.markAsUndeleted(state.getUniqueId(), fileSpan, state.time.milliseconds());
      fail("Should have failed because ID provided for undelete does not exist");
    } catch (StoreException e) {
      assertEquals("Unexpected StoreErrorCode", StoreErrorCodes.IDNotFound, e.getErrorCode());
    }

    try {
      // live keys might contain undelete keys, filter them out
      MockId id = null;
      Iterator<MockId> iter = state.liveKeys.iterator();
      while (iter.hasNext()) {
        id = iter.next();
        IndexValue value = state.getExpectedValue(id, false);
        if (value != null && !value.isUndelete()) {
          break;
        }
      }
      assertNotNull(id);
      state.index.markAsUndeleted(id, fileSpan, state.time.milliseconds());
      fail("Should have failed because ID provided for undelete hasn't be deleted yet");
    } catch (StoreException e) {
      assertEquals("Unexpected StoreErrorCode", StoreErrorCodes.IDNotDeleted, e.getErrorCode());
    }

    try {
      state.index.markAsUndeleted(state.undeletedKeys.iterator().next(), fileSpan, state.time.milliseconds());
      fail("Should have failed because ID provided for udneleted is already undeleted.");
    } catch (StoreException e) {
      assertEquals("Unexpected StoreErrorCode", StoreErrorCodes.IDUndeleted, e.getErrorCode());
    }
  }
Tests error cases for {@link PersistentIndex#markAsUndeleted(StoreKey, FileSpan, long)}.
Cases
1. FileSpan end offset < currentIndexEndOffset
2. FileSpan is across segments
3. ID does not exist
4. Live id
5. Undeleted id
6. Permanently deleted id
@throws StoreException
ambry-store/src/test/java/com/github/ambry/store/IndexTest.java