@AdviseWith(adviceClasses = NettyUtilAdvice.class)
  @Test
  public void testGetFileChannelCancellation() {
    _channelPipeline.addFirst(
        new ChannelOutboundHandlerAdapter() {

          @Override
          public void write(
              ChannelHandlerContext channelHandlerContext,
              Object object,
              ChannelPromise channelPromise) {

            channelPromise.cancel(true);
          }
        });

    try {
      NoticeableFuture<Path> noticeableFuture =
          _nettyRepository.getFile(
              _embeddedChannel, Paths.get("remoteFile"), Paths.get("localFile"), false, false);

      Assert.assertTrue(noticeableFuture.isDone());
      Assert.assertTrue(noticeableFuture.isCancelled());
    } finally {
      _channelPipeline.removeFirst();
    }
  }
  @AdviseWith(adviceClasses = NettyUtilAdvice.class)
  @NewEnv(type = NewEnv.Type.CLASSLOADER)
  @Test
  public void testExecute() throws Exception {
    EmbeddedChannel embeddedChannel = NettyTestUtil.createEmptyEmbeddedChannel();

    ChannelPipeline channelPipeline = embeddedChannel.pipeline();

    channelPipeline.addFirst(NettyRPCChannelHandler.NAME, NettyRPCChannelHandler.INSTANCE);

    NettyChannelAttributes.putFabricWorker(
        embeddedChannel,
        0,
        new LocalFabricWorker<Serializable>(
            new EmbeddedProcessChannel<Serializable>(new DefaultNoticeableFuture<Serializable>())));

    ProcessCallableExecutor processCallableExecutor =
        new NettyFabricWorkerProcessCallableExecutor(embeddedChannel, 0, Long.MAX_VALUE);

    NoticeableFuture<Serializable> noticeableFuture =
        processCallableExecutor.execute(
            new ProcessCallable<Serializable>() {

              @Override
              public Serializable call() {
                return StringPool.BLANK;
              }
            });

    embeddedChannel.writeInbound(embeddedChannel.readOutbound());
    embeddedChannel.writeInbound(embeddedChannel.readOutbound());

    Assert.assertEquals(StringPool.BLANK, noticeableFuture.get());

    final ProcessException processException = new ProcessException("");

    noticeableFuture =
        processCallableExecutor.execute(
            new ProcessCallable<Serializable>() {

              @Override
              public Serializable call() throws ProcessException {
                throw processException;
              }
            });

    embeddedChannel.writeInbound(embeddedChannel.readOutbound());
    embeddedChannel.writeInbound(embeddedChannel.readOutbound());

    try {
      noticeableFuture.get();

      Assert.fail();
    } catch (ExecutionException ee) {
      Assert.assertSame(processException, ee.getCause());
    }
  }
  @Test
  public void testExecute() throws Exception {
    EmbeddedChannel embeddedChannel = NettyTestUtil.createEmptyEmbeddedChannel();

    ChannelPipeline channelPipeline = embeddedChannel.pipeline();

    channelPipeline.addFirst(NettyRPCChannelHandler.NAME, NettyRPCChannelHandler.INSTANCE);

    ProcessCallableExecutor processCallableExecutor =
        new NettyFabricAgentProcessCallableExecutor(embeddedChannel);

    NoticeableFuture<Serializable> noticeableFuture =
        processCallableExecutor.execute(
            new ProcessCallable<Serializable>() {

              @Override
              public Serializable call() {
                return StringPool.BLANK;
              }
            });

    embeddedChannel.writeInbound(embeddedChannel.readOutbound());
    embeddedChannel.writeInbound(embeddedChannel.readOutbound());

    Assert.assertEquals(StringPool.BLANK, noticeableFuture.get());

    final ProcessException processException = new ProcessException("");

    noticeableFuture =
        processCallableExecutor.execute(
            new ProcessCallable<Serializable>() {

              @Override
              public Serializable call() throws ProcessException {
                throw processException;
              }
            });

    embeddedChannel.writeInbound(embeddedChannel.readOutbound());
    embeddedChannel.writeInbound(embeddedChannel.readOutbound());

    try {
      noticeableFuture.get();

      Assert.fail();
    } catch (ExecutionException ee) {
      Assert.assertSame(processException, ee.getCause());
    }
  }
  @AdviseWith(adviceClasses = NettyUtilAdvice.class)
  @Test
  public void testGetFileFileNotFound() throws Exception {

    // With log

    Path remoteFilePath = Paths.get("remoteFile");

    try (CaptureHandler captureHandler =
        JDKLoggerTestUtil.configureJDKLogger(NettyRepository.class.getName(), Level.WARNING)) {

      NoticeableFuture<Path> noticeableFuture =
          _nettyRepository.getFile(
              _embeddedChannel, remoteFilePath, Paths.get("localFile"), false, false);

      _asyncBroker.takeWithResult(
          remoteFilePath, new FileResponse(remoteFilePath, FileResponse.FILE_NOT_FOUND, 0, false));

      Assert.assertNull(noticeableFuture.get());

      List<LogRecord> logRecords = captureHandler.getLogRecords();

      Assert.assertEquals(1, logRecords.size());

      LogRecord logRecord = logRecords.get(0);

      Assert.assertEquals(
          "Remote file " + remoteFilePath + " is not found", logRecord.getMessage());
    }

    // Without log

    try (CaptureHandler captureHandler =
        JDKLoggerTestUtil.configureJDKLogger(NettyRepository.class.getName(), Level.OFF)) {

      NoticeableFuture<Path> noticeableFuture =
          _nettyRepository.getFile(
              _embeddedChannel, remoteFilePath, Paths.get("localFile"), false, false);

      _asyncBroker.takeWithResult(
          remoteFilePath, new FileResponse(remoteFilePath, FileResponse.FILE_NOT_FOUND, 0, false));

      Assert.assertNull(noticeableFuture.get());

      List<LogRecord> logRecords = captureHandler.getLogRecords();

      Assert.assertTrue(logRecords.isEmpty());
    }
  }
  @AdviseWith(adviceClasses = NettyUtilAdvice.class)
  @Test
  public void testGetFileTimeoutCancellation() {
    NettyRepository nettyRepository = new NettyRepository(_repositoryPath, 0);

    _channelPipeline.addLast(
        new FileResponseChannelHandler(
            nettyRepository.getAsyncBroker(), _embeddedChannel.eventLoop()));

    NoticeableFuture<Path> noticeableFuture =
        nettyRepository.getFile(
            _embeddedChannel, Paths.get("remoteFile"), Paths.get("localFile"), false, false);

    Assert.assertTrue(noticeableFuture.isDone());
    Assert.assertTrue(noticeableFuture.isCancelled());
  }
  @AdviseWith(adviceClasses = NettyUtilAdvice.class)
  @Test
  public void testDispose() throws Exception {
    Path remoteFilePath = Paths.get("remoteFile");

    Path tempFilePath = FileServerTestUtil.createFileWithData(Paths.get("tempFile"));

    Map<Path, Path> pathMap = _nettyRepository.pathMap;

    FileServerTestUtil.createFileWithData(tempFilePath);

    try (CaptureHandler captureHandler =
        JDKLoggerTestUtil.configureJDKLogger(NettyRepository.class.getName(), Level.OFF)) {

      NoticeableFuture<Path> noticeableFuture =
          _nettyRepository.getFile(_embeddedChannel, remoteFilePath, null, false);

      FileResponse fileResponse =
          new FileResponse(remoteFilePath, System.currentTimeMillis(), 0, false);

      fileResponse.setLocalFile(tempFilePath);

      _asyncBroker.takeWithResult(remoteFilePath, fileResponse);

      Path localFilePath = noticeableFuture.get();

      Assert.assertNotNull(localFilePath);
      Assert.assertTrue(Files.notExists(tempFilePath));
      Assert.assertTrue(Files.exists(localFilePath));
      Assert.assertEquals(1, pathMap.size());
      Assert.assertSame(localFilePath, pathMap.get(remoteFilePath));

      _nettyRepository.dispose(false);

      Assert.assertTrue(Files.notExists(localFilePath));
      Assert.assertTrue(pathMap.isEmpty());
      Assert.assertTrue(Files.exists(_repositoryPath));

      _nettyRepository.dispose(true);

      Assert.assertTrue(Files.notExists(_repositoryPath));

      List<LogRecord> logRecords = captureHandler.getLogRecords();

      Assert.assertTrue(logRecords.isEmpty());
    }
  }
  @Test
  public void testFile() throws Exception {
    byte[] data = FileServerTestUtil.createRandomData(1024);

    long lastModified = FileServerTestUtil.getFileSystemTime(System.currentTimeMillis() - Time.DAY);

    FileResponse fileResponse = new FileResponse(_path, data.length, lastModified, false);

    NoticeableFuture<FileResponse> noticeableFuture = _asyncBroker.post(_path);

    _fileResponseChannelHandler.channelRead(
        _channelHandlerContext, fileResponse, FileServerTestUtil.wrapFirstHalf(data));

    ChannelHandler channelHandler = _channelPipeline.first();

    Assert.assertTrue(channelHandler instanceof FileUploadChannelHandler);

    FileUploadChannelHandler fileUploadChannelHandler = (FileUploadChannelHandler) channelHandler;

    _channelPipeline.fireChannelRead(FileServerTestUtil.wrapSecondHalf(data));

    channelHandler = _channelPipeline.first();

    Assert.assertFalse(channelHandler instanceof FileUploadChannelHandler);
    Assert.assertSame(fileResponse, fileUploadChannelHandler.fileResponse);
    Assert.assertSame(fileResponse, noticeableFuture.get());

    Path localFile = fileResponse.getLocalFile();

    Assert.assertNotNull(localFile);

    FileTime fileTime = Files.getLastModifiedTime(localFile);

    Assert.assertEquals(lastModified, fileTime.toMillis());
    Assert.assertArrayEquals(data, Files.readAllBytes(localFile));

    Files.delete(localFile);
  }
  @AdviseWith(adviceClasses = NettyUtilAdvice.class)
  @Test
  public void testGetFilesCancelled() {
    Map<Path, Path> pathMap = new HashMap<>();

    Path remoteFilePath1 = Paths.get("remoteFile1");

    pathMap.put(remoteFilePath1, Paths.get("localFile1"));
    pathMap.put(Paths.get("remoteFile2"), Paths.get("requestFile2"));

    NoticeableFuture<Map<Path, Path>> noticeableFuture =
        _nettyRepository.getFiles(_embeddedChannel, pathMap, true);

    Map<Path, NoticeableFuture<FileResponse>> openBids = _asyncBroker.getOpenBids();

    NoticeableFuture<FileResponse> fileGetNoticeableFuture = openBids.get(remoteFilePath1);

    Assert.assertNotNull(fileGetNoticeableFuture);

    fileGetNoticeableFuture.cancel(true);

    Assert.assertTrue(noticeableFuture.isCancelled());
  }
  protected void doTestGetFileChannelFailure(final boolean asyncBrokerFailure, boolean logging)
      throws InterruptedException {

    final Exception exception = new Exception();

    final Path remoteFilePath = Paths.get("remoteFile");

    _channelPipeline.addLast(
        new ChannelOutboundHandlerAdapter() {

          @Override
          public void write(
              ChannelHandlerContext channelHandlerContext,
              Object message,
              ChannelPromise channelPromise) {

            if (asyncBrokerFailure) {
              _asyncBroker.takeWithException(remoteFilePath, exception);
            }

            channelPromise.setFailure(exception);
          }
        });

    Level level = Level.OFF;

    if (logging) {
      level = Level.ALL;
    }

    try (CaptureHandler captureHandler =
        JDKLoggerTestUtil.configureJDKLogger(NettyRepository.class.getName(), level)) {

      NoticeableFuture<Path> noticeableFuture =
          _nettyRepository.getFile(
              _embeddedChannel, remoteFilePath, Paths.get("localFile"), false, false);

      try {
        noticeableFuture.get();
      } catch (ExecutionException ee) {
        Throwable throwable = ee.getCause();

        if (!asyncBrokerFailure) {
          Assert.assertEquals(
              "Unable to fetch remote file " + remoteFilePath, throwable.getMessage());

          throwable = throwable.getCause();
        }

        Assert.assertSame(exception, throwable);
      }

      if (logging) {
        List<LogRecord> logRecords = captureHandler.getLogRecords();

        LogRecord logRecord = logRecords.remove(0);

        Assert.assertEquals("Fetching remote file " + remoteFilePath, logRecord.getMessage());

        if (asyncBrokerFailure) {
          logRecord = logRecords.remove(0);

          Assert.assertEquals(
              "Unable to place exception because no future exists " + "with ID " + remoteFilePath,
              logRecord.getMessage());

          Throwable throwable = logRecord.getThrown();

          Assert.assertEquals(
              "Unable to fetch remote file " + remoteFilePath, throwable.getMessage());
          Assert.assertSame(exception, throwable.getCause());
        }

        Assert.assertTrue(logRecords.isEmpty());
      }
    }
  }
  @AdviseWith(adviceClasses = NettyUtilAdvice.class)
  @Test
  public void testGetFileFileNotModified() throws Exception {

    // With log

    Path remoteFilePath = Paths.get("remoteFile");
    Path cachedLocalFilePath = Paths.get("cacheLocalFile");

    Map<Path, Path> pathMap = _nettyRepository.pathMap;

    pathMap.put(remoteFilePath, cachedLocalFilePath);

    try (CaptureHandler captureHandler =
        JDKLoggerTestUtil.configureJDKLogger(NettyRepository.class.getName(), Level.FINEST)) {

      NoticeableFuture<Path> noticeableFuture =
          _nettyRepository.getFile(
              _embeddedChannel, remoteFilePath, Paths.get("localFile"), false, false);

      _asyncBroker.takeWithResult(
          remoteFilePath,
          new FileResponse(remoteFilePath, FileResponse.FILE_NOT_MODIFIED, 0, false));

      Assert.assertSame(cachedLocalFilePath, noticeableFuture.get());

      List<LogRecord> logRecords = captureHandler.getLogRecords();

      Assert.assertEquals(2, logRecords.size());

      LogRecord logRecord = logRecords.get(0);

      Assert.assertEquals("Fetching remote file " + remoteFilePath, logRecord.getMessage());

      logRecord = logRecords.get(1);

      Assert.assertEquals(
          "Remote file "
              + remoteFilePath
              + " is not modified, use cached local file "
              + cachedLocalFilePath,
          logRecord.getMessage());
    }

    // Without log

    try (CaptureHandler captureHandler =
        JDKLoggerTestUtil.configureJDKLogger(NettyRepository.class.getName(), Level.OFF)) {

      NoticeableFuture<Path> noticeableFuture =
          _nettyRepository.getFile(
              _embeddedChannel, remoteFilePath, Paths.get("localFile"), false, false);

      _asyncBroker.takeWithResult(
          remoteFilePath,
          new FileResponse(remoteFilePath, FileResponse.FILE_NOT_MODIFIED, 0, false));

      Assert.assertSame(cachedLocalFilePath, noticeableFuture.get());

      List<LogRecord> logRecords = captureHandler.getLogRecords();

      Assert.assertTrue(logRecords.isEmpty());
    }
  }
  @AdviseWith(adviceClasses = NettyUtilAdvice.class)
  @Test
  public void testGetFile() throws Exception {

    // With log, populate cache

    Path remoteFilePath = Paths.get("remoteFile");

    Path tempFilePath = FileServerTestUtil.createFileWithData(Paths.get("tempFile"));

    Map<Path, Path> pathMap = _nettyRepository.pathMap;

    try (CaptureHandler captureHandler =
        JDKLoggerTestUtil.configureJDKLogger(NettyRepository.class.getName(), Level.FINEST)) {

      NoticeableFuture<Path> noticeableFuture1 =
          _nettyRepository.getFile(_embeddedChannel, remoteFilePath, null, false);

      NoticeableFuture<Path> noticeableFuture2 =
          _nettyRepository.getFile(_embeddedChannel, remoteFilePath, null, false);

      Assert.assertNotSame(noticeableFuture1, noticeableFuture2);

      FileResponse fileResponse =
          new FileResponse(remoteFilePath, System.currentTimeMillis(), 0, false);

      fileResponse.setLocalFile(tempFilePath);

      _asyncBroker.takeWithResult(remoteFilePath, fileResponse);

      Path localFilePath = FileServerTestUtil.registerForCleanUp(noticeableFuture1.get());

      Assert.assertSame(localFilePath, noticeableFuture2.get());
      Assert.assertSame(localFilePath, fileResponse.getLocalFile());
      Assert.assertNotNull(localFilePath);
      Assert.assertTrue(Files.notExists(tempFilePath));
      Assert.assertTrue(Files.exists(localFilePath));
      Assert.assertEquals(1, pathMap.size());
      Assert.assertSame(localFilePath, pathMap.get(remoteFilePath));

      Files.delete(localFilePath);

      List<LogRecord> logRecords = captureHandler.getLogRecords();

      Assert.assertEquals(4, logRecords.size());

      LogRecord logRecord = logRecords.get(0);

      Assert.assertEquals("Fetching remote file " + remoteFilePath, logRecord.getMessage());

      logRecord = logRecords.get(1);

      Assert.assertEquals("Fetching remote file " + remoteFilePath, logRecord.getMessage());

      logRecord = logRecords.get(2);

      Assert.assertEquals(
          "Fetched remote file " + remoteFilePath + " to " + localFilePath, logRecord.getMessage());

      logRecord = logRecords.get(3);

      Assert.assertEquals(
          "Fetched remote file " + remoteFilePath + " to " + localFilePath, logRecord.getMessage());
    } finally {
      pathMap.clear();
    }

    // Without log, not populate cacge

    FileServerTestUtil.createFileWithData(tempFilePath);

    Path localFilePath1 =
        FileServerTestUtil.registerForCleanUp(_repositoryPath.resolve("localFile1"));
    Path localFilePath2 =
        FileServerTestUtil.registerForCleanUp(_repositoryPath.resolve("localFile2"));

    try (CaptureHandler captureHandler =
        JDKLoggerTestUtil.configureJDKLogger(NettyRepository.class.getName(), Level.OFF)) {

      NoticeableFuture<Path> noticeableFuture1 =
          _nettyRepository.getFile(_embeddedChannel, remoteFilePath, localFilePath1, false);

      NoticeableFuture<Path> noticeableFuture2 =
          _nettyRepository.getFile(_embeddedChannel, remoteFilePath, localFilePath2, false);

      Assert.assertNotSame(noticeableFuture1, noticeableFuture2);

      FileResponse fileResponse =
          new FileResponse(remoteFilePath, System.currentTimeMillis(), 0, false);

      fileResponse.setLocalFile(tempFilePath);

      _asyncBroker.takeWithResult(remoteFilePath, fileResponse);

      Assert.assertSame(localFilePath1, noticeableFuture1.get());
      Assert.assertSame(localFilePath2, noticeableFuture2.get());
      Assert.assertSame(localFilePath2, fileResponse.getLocalFile());
      Assert.assertTrue(Files.notExists(tempFilePath));
      Assert.assertTrue(Files.exists(localFilePath1));
      Assert.assertTrue(Files.exists(localFilePath2));
      Assert.assertTrue(pathMap.isEmpty());

      List<LogRecord> logRecords = captureHandler.getLogRecords();

      Assert.assertTrue(logRecords.isEmpty());
    }
  }