@Test
  public void testBufferCallbackUniqueBuffers() throws Exception {
    controller = new AsynchronousFileImpl(executor, pollerExecutor);
    final int NUMBER_LINES = 1000;
    final int SIZE = 512;

    controller.open(fileName, 1000);

    controller.fill(0, 1, NUMBER_LINES * SIZE, (byte) 'j');

    final ArrayList<ByteBuffer> buffers = new ArrayList<ByteBuffer>();

    BufferCallback bufferCallback =
        new BufferCallback() {
          public void bufferDone(final ByteBuffer buffer) {
            buffers.add(buffer);
          }
        };

    controller.setBufferCallback(bufferCallback);

    CountDownLatch latch = new CountDownLatch(NUMBER_LINES);
    ArrayList<Integer> result = new ArrayList<Integer>();
    for (int i = 0; i < NUMBER_LINES; i++) {
      ByteBuffer buffer1 = AsynchronousFileImpl.newBuffer(SIZE);
      buffer1.rewind();
      for (int j = 0; j < SIZE; j++) {
        buffer1.put((byte) (j % Byte.MAX_VALUE));
      }
      CountDownCallback aio = new CountDownCallback(latch, null, result, i);
      controller.write(i * SIZE, SIZE, buffer1, aio);
    }

    // The buffer callback is only called after the complete callback was
    // called.
    // Because of that a race could happen on the assertions to
    // buffers.size what would invalidate the test
    // We close the file and that would guarantee the buffer callback was
    // called for all the elements
    controller.close();

    CountDownCallback.checkResults(NUMBER_LINES, result);

    // Make sure all the buffers are unique
    ByteBuffer lineOne = null;
    for (ByteBuffer bufferTmp : buffers) {
      if (lineOne == null) {
        lineOne = bufferTmp;
      } else {
        Assert.assertTrue(lineOne != bufferTmp);
      }
    }

    for (ByteBuffer bufferTmp : buffers) {
      destroy(bufferTmp);
    }

    buffers.clear();
  }
  /**
   * This test will call file.close() when there are still callbacks being processed. This could
   * cause a crash or callbacks missing and this test is validating both situations. The file is
   * also read after being written to validate its correctness
   */
  @Test
  public void testConcurrentClose() throws Exception {
    controller = new AsynchronousFileImpl(executor, pollerExecutor);
    final int NUMBER_LINES = 1000;
    CountDownLatch readLatch = new CountDownLatch(NUMBER_LINES);
    final int SIZE = 1024;

    controller.open(fileName, 10000);

    controller.fill(0, 1, NUMBER_LINES * SIZE, (byte) 'j');

    controller.setBufferCallback(bufferCallbackDestroy);

    for (int i = 0; i < NUMBER_LINES; i++) {
      ByteBuffer buffer = AsynchronousFileImpl.newBuffer(SIZE);

      buffer.clear();
      addString("Str value " + i + "\n", buffer);
      for (int j = buffer.position(); j < buffer.capacity() - 1; j++) {
        buffer.put((byte) ' ');
      }
      buffer.put((byte) '\n');

      CountDownCallback aio = new CountDownCallback(readLatch, null, null, 0);
      controller.write(i * SIZE, SIZE, buffer, aio);
    }

    // If you call close you're supposed to wait events to finish before
    // closing it
    controller.close();

    controller.setBufferCallback(null);

    Assert.assertEquals(0, readLatch.getCount());
    waitForLatch(readLatch);
    controller.open(fileName, 10);

    ByteBuffer newBuffer = AsynchronousFileImpl.newBuffer(SIZE);

    ByteBuffer buffer = AsynchronousFileImpl.newBuffer(SIZE);

    for (int i = 0; i < NUMBER_LINES; i++) {
      newBuffer.clear();
      addString("Str value " + i + "\n", newBuffer);
      for (int j = newBuffer.position(); j < newBuffer.capacity() - 1; j++) {
        newBuffer.put((byte) ' ');
      }
      newBuffer.put((byte) '\n');

      CountDownLatch latch = new CountDownLatch(1);
      CountDownCallback aio = new CountDownCallback(latch, null, null, 0);
      controller.read(i * SIZE, SIZE, buffer, aio);
      waitForLatch(latch);
      Assert.assertEquals(0, aio.errorCalled);
      Assert.assertTrue(aio.doneCalled);

      byte bytesRead[] = new byte[SIZE];
      byte bytesCompare[] = new byte[SIZE];

      newBuffer.rewind();
      newBuffer.get(bytesCompare);
      buffer.rewind();
      buffer.get(bytesRead);

      for (int count = 0; count < SIZE; count++) {
        Assert.assertEquals(
            "byte position " + count + " differs on line " + i,
            bytesCompare[count],
            bytesRead[count]);
      }

      Assert.assertTrue(buffer.equals(newBuffer));
    }

    destroy(newBuffer);
  }
  @Test
  public void testRead() throws Exception {
    controller = new AsynchronousFileImpl(executor, pollerExecutor);
    controller.setBufferCallback(bufferCallbackDestroy);

    final int NUMBER_LINES = 1000;
    final int SIZE = 1024;

    controller.open(fileName, 1000);

    controller.fill(0, 1, NUMBER_LINES * SIZE, (byte) 'j');

    {
      CountDownLatch latch = new CountDownLatch(NUMBER_LINES);
      ArrayList<Integer> result = new ArrayList<Integer>();

      AtomicInteger errors = new AtomicInteger(0);

      for (int i = 0; i < NUMBER_LINES; i++) {
        if (i % 100 == 0) {
          System.out.println("Wrote " + i + " lines");
        }
        final ByteBuffer buffer0 = AsynchronousFileImpl.newBuffer(SIZE);
        for (int j = 0; j < SIZE; j++) {
          buffer0.put(UnitTestCase.getSamplebyte(j));
        }

        CountDownCallback aio = new CountDownCallback(latch, errors, result, i);
        controller.write(i * SIZE, SIZE, buffer0, aio);
      }

      waitForLatch(latch);

      Assert.assertEquals(0, errors.get());

      CountDownCallback.checkResults(NUMBER_LINES, result);
    }

    // If you call close you're supposed to wait events to finish before
    // closing it
    controller.close();
    controller.setBufferCallback(null);

    controller.open(fileName, 10);

    buffer = AsynchronousFileImpl.newBuffer(SIZE);

    for (int i = 0; i < NUMBER_LINES; i++) {
      if (i % 100 == 0) {
        System.out.println("Read " + i + " lines");
      }
      AsynchronousFileImpl.clearBuffer(buffer);

      CountDownLatch latch = new CountDownLatch(1);
      AtomicInteger errors = new AtomicInteger(0);
      CountDownCallback aio = new CountDownCallback(latch, errors, null, 0);

      controller.read(i * SIZE, SIZE, buffer, aio);

      waitForLatch(latch);
      Assert.assertEquals(0, errors.get());
      Assert.assertTrue(aio.doneCalled);

      byte bytesRead[] = new byte[SIZE];
      buffer.get(bytesRead);

      for (int count = 0; count < SIZE; count++) {
        Assert.assertEquals(
            "byte position " + count + " differs on line " + i + " position = " + count,
            UnitTestCase.getSamplebyte(count),
            bytesRead[count]);
      }
    }
  }