@Test
  public void readTest() throws IOException, StoreException {
    Random random = new Random();
    LogSegmentName segmentName = LogSegmentName.generateFirstSegmentName(false);
    LogSegment segment = getSegment(segmentName, STANDARD_SEGMENT_SIZE, true);
    try {
      long writeStartOffset = segment.getStartOffset();
      byte[] data = appendRandomData(segment, 2 * STANDARD_SEGMENT_SIZE / 3);
      readAndEnsureMatch(segment, writeStartOffset, data);
      readDirectlyAndEnsureMatch(segment, writeStartOffset, data);
      int readCount = 10;
      for (int i = 0; i < readCount; i++) {
        int position = random.nextInt(data.length);
        int size = random.nextInt(data.length - position);
        readAndEnsureMatch(segment, writeStartOffset + position, Arrays.copyOfRange(data, position, position + size));
        readDirectlyAndEnsureMatch(segment, writeStartOffset + position,
            Arrays.copyOfRange(data, position, position + size));
      }

      // check for position > endOffset and < data size written to the segment
      // setting end offset to 1/3 * (sizeInBytes - startOffset)
      segment.setEndOffset(segment.getStartOffset() + (segment.sizeInBytes() - segment.getStartOffset()) / 3);
      int position = (int) segment.getEndOffset() + random.nextInt(data.length - (int) segment.getEndOffset());
      int size = random.nextInt(data.length - position);
      readAndEnsureMatch(segment, writeStartOffset + position, Arrays.copyOfRange(data, position, position + size));
      readDirectlyAndEnsureMatch(segment, writeStartOffset + position,
          Arrays.copyOfRange(data, position, position + size));

      // error scenarios for general IO
      byte[] byteArray = new byte[data.length];
      ByteBuffer readBuf = ByteBuffer.wrap(byteArray);
      // data cannot be read at invalid offsets.
      long[] invalidOffsets = {writeStartOffset - 1, segment.sizeInBytes(), segment.sizeInBytes() + 1};
      ByteBuffer buffer = ByteBuffer.wrap(TestUtils.getRandomBytes(1));
      for (long invalidOffset : invalidOffsets) {
        try {
          segment.readInto(readBuf, invalidOffset);
          fail("Should have failed to read because position provided is invalid");
        } catch (IndexOutOfBoundsException e) {
          assertEquals("Position of buffer has changed", 0, buffer.position());
        }
      }
      if (Utils.isLinux()) {
        for (long invalidOffset : invalidOffsets) {
          try {
            segment.readIntoDirectly(byteArray, invalidOffset, data.length);
            fail("Should have failed to read because position provided is invalid");
          } catch (IndexOutOfBoundsException e) {
            assertEquals("Position of buffer has changed", 0, buffer.position());
          }
        }
      }

      // position + buffer.remaining > sizeInBytes
      long readOverFlowCount = metrics.overflowReadError.getCount();
      byteArray = new byte[2];
      readBuf = ByteBuffer.allocate(2);
      segment.setEndOffset(segment.getStartOffset());
      position = (int) segment.sizeInBytes() - 1;
      try {
        segment.readInto(readBuf, position);
        fail("Should have failed to read because position + buffer.remaining() > sizeInBytes");
      } catch (IndexOutOfBoundsException e) {
        assertEquals("Read overflow should have been reported", readOverFlowCount + 1,
            metrics.overflowReadError.getCount());
        assertEquals("Position of buffer has changed", 0, readBuf.position());
      }
      if (Utils.isLinux()) {
        try {
          segment.readIntoDirectly(byteArray, position, byteArray.length);
          fail("Should have failed to read because position + buffer.remaining() > sizeInBytes");
        } catch (IndexOutOfBoundsException e) {
          assertEquals("Read overflow should have been reported", readOverFlowCount + 2,
              metrics.overflowReadError.getCount());
        }
      }

      segment.close(false);
      // read after close
      buffer = ByteBuffer.allocate(1);
      try {
        segment.readInto(buffer, writeStartOffset);
        fail("Should have failed to read because segment is closed");
      } catch (ClosedChannelException e) {
        assertEquals("Position of buffer has changed", 0, buffer.position());
      }
      if (Utils.isLinux()) {
        byteArray = new byte[1];
        try {
          segment.readIntoDirectly(byteArray, writeStartOffset, byteArray.length);
          fail("Should have failed to read because segment is closed");
        } catch (ClosedChannelException e) {
        }
      }
    } finally {
      closeSegmentAndDeleteFile(segment);
    }
  }
Tests {@link LogSegment#readInto(ByteBuffer, long)} and {@link LogSegment#readIntoDirectly(byte[], long, int)}(if
current OS is Linux) for various cases.
@throws IOException
ambry-store/src/test/java/com/github/ambry/store/LogSegmentTest.java