@Test
  public void addAndDropSegmentTest() throws IOException, StoreException {
    // start with a segment that has a high position to allow for addition of segments
    long activeSegmentPos = 2 * LOG_CAPACITY / SEGMENT_CAPACITY;
    LogSegment loadedSegment = getLogSegment(LogSegmentName.fromPositionAndGeneration(activeSegmentPos, 0), SEGMENT_CAPACITY, true);
    List<LogSegment> segmentsToLoad = Collections.singletonList(loadedSegment);
    Log log = new Log(tempDir.getAbsolutePath(), LOG_CAPACITY, StoreTestUtils.DEFAULT_DISK_SPACE_ALLOCATOR,
        createStoreConfig(SEGMENT_CAPACITY, setFilePermissionEnabled), metrics, true, segmentsToLoad,
        Collections.EMPTY_LIST.iterator(), null);

    // add a segment
    LogSegmentName segmentName = LogSegmentName.fromPositionAndGeneration(0, 0);
    LogSegment uncountedSegment = getLogSegment(segmentName, SEGMENT_CAPACITY, true);
    log.addSegment(uncountedSegment, false);
    assertEquals("Log segment instance not as expected", uncountedSegment, log.getSegment(segmentName));

    // cannot add past the active segment
    segmentName = LogSegmentName.fromPositionAndGeneration(activeSegmentPos + 1, 0);
    LogSegment segment = getLogSegment(segmentName, SEGMENT_CAPACITY, true);
    try {
      log.addSegment(segment, false);
      fail("Should not be able to add past the active segment");
    } catch (IllegalArgumentException e) {
      // expected. Nothing to do.
    }

    // since the previous one did not ask for count of segments to be increased, we should be able to add max - 1
    // more segments. This increments used segment count to the max.
    int max = (int) (LOG_CAPACITY / SEGMENT_CAPACITY);
    for (int i = 1; i < max; i++) {
      segmentName = LogSegmentName.fromPositionAndGeneration(i, 0);
      segment = getLogSegment(segmentName, SEGMENT_CAPACITY, true);
      log.addSegment(segment, true);
    }

    // fill up the active segment
    ByteBuffer buffer =
        ByteBuffer.allocate((int) (loadedSegment.getCapacityInBytes() - loadedSegment.getStartOffset()));
    CHANNEL_APPENDER.append(log, buffer);
    // write fails because no more log segments can be allocated
    buffer = ByteBuffer.allocate(1);
    try {
      CHANNEL_APPENDER.append(log, buffer);
      fail("Write should have failed because no more log segments should be allocated");
    } catch (IllegalStateException e) {
      // expected. Nothing to do.
    }

    // drop the uncounted segment
    assertEquals("Segment not as expected", uncountedSegment, log.getSegment(uncountedSegment.getName()));
    File segmentFile = uncountedSegment.getView().getFirst();
    log.dropSegment(uncountedSegment.getName(), false);
    assertNull("Segment should not be present", log.getSegment(uncountedSegment.getName()));
    assertFalse("Segment file should not be present", segmentFile.exists());

    // cannot drop a segment that does not exist
    // cannot drop the active segment
    LogSegmentName[] segmentsToDrop = {uncountedSegment.getName(), loadedSegment.getName()};
    for (LogSegmentName segmentToDrop : segmentsToDrop) {
      try {
        log.dropSegment(segmentToDrop, false);
        fail("Should have failed to drop segment");
      } catch (IllegalArgumentException e) {
        // expected. Nothing to do.
      }
    }

    // drop a segment and decrement total segment count
    log.dropSegment(log.getFirstSegment().getName(), true);

    // should be able to write now
    buffer = ByteBuffer.allocate(1);
    CHANNEL_APPENDER.append(log, buffer);

    // verify that dropSegment method can catch IOException and correctly convert it to StoreException.
    DiskSpaceAllocator mockDiskAllocator = Mockito.mock(DiskSpaceAllocator.class);
    doThrow(new IOException(StoreException.IO_ERROR_STR)).when(mockDiskAllocator)
        .free(any(File.class), anyLong(), anyString(), anyBoolean());
    segmentsToLoad = Collections.singletonList(
        getLogSegment(LogSegmentName.fromPositionAndGeneration(activeSegmentPos, 0), SEGMENT_CAPACITY, true));
    Log mockLog = new Log(tempDir.getAbsolutePath(), LOG_CAPACITY, mockDiskAllocator,
        createStoreConfig(SEGMENT_CAPACITY, setFilePermissionEnabled), metrics, true, segmentsToLoad,
        Collections.EMPTY_LIST.iterator(), null);
    mockLog.addSegment(getLogSegment(LogSegmentName.fromPositionAndGeneration(1, 0), SEGMENT_CAPACITY, true), true);
    try {
      mockLog.dropSegment(mockLog.getFirstSegment().getName(), true);
      fail("Should have failed to drop segment");
    } catch (StoreException e) {
      assertEquals("Mismatch in error code", StoreErrorCodes.IOError, e.getErrorCode());
    }
  }
Tests all cases of {@link Log#addSegment(LogSegment, boolean)} and {@link Log#dropSegment(LogSegmentName, boolean)}.
@throws IOException
ambry-store/src/test/java/com/github/ambry/store/LogTest.java