@Override
  public int read() throws IOException {
    Preconditions.checkState(!closed, "Cannot read: already closed");
    singleByteBuffer.position(0);

    pos += 1;
    channel.read(singleByteBuffer);
    readBytes.increment();
    readOperations.increment();

    return singleByteBuffer.array()[0] & 0xFF;
  }
@Test
  public void testRead() throws Exception {
    BlobId uri = BlobId.fromGsUtilUri("gs://bucket/path/to/read.dat");
    int dataSize = 1024 * 1024 * 10;
    byte[] data = randomData(dataSize);

    writeGCSData(uri, data);

    try (SeekableInputStream in =
        new GCSInputStream(storage, uri, null, gcpProperties, MetricsContext.nullMetrics())) {
      int readSize = 1024;
      byte[] actual = new byte[readSize];

      readAndCheck(in, in.getPos(), readSize, data, false);
      readAndCheck(in, in.getPos(), readSize, data, true);

      // Seek forward in current stream
      int seekSize = 1024;
      readAndCheck(in, in.getPos() + seekSize, readSize, data, false);
      readAndCheck(in, in.getPos() + seekSize, readSize, data, true);

      // Buffered read
      readAndCheck(in, in.getPos(), readSize, data, true);
      readAndCheck(in, in.getPos(), readSize, data, false);

      // Seek with new stream
      long seekNewStreamPosition = 2 * 1024 * 1024;
      readAndCheck(in, in.getPos() + seekNewStreamPosition, readSize, data, true);
      readAndCheck(in, in.getPos() + seekNewStreamPosition, readSize, data, false);

      // Backseek and read
      readAndCheck(in, 0, readSize, data, true);
      readAndCheck(in, 0, readSize, data, false);
    }
  }