@Test
  public void testRetryUntilSuccess() throws Exception {
    storageSystem.succeedOnAttempt(3);
    File pendingFile = new File(tempStageDir, "pending.json.snappy");
    Files.copy(new File(Resources.getResource("pending.json.snappy").toURI()), pendingFile);

    String retryDir = tempStageDir.getPath() + "/retry";

    assertEquals(storageSystem.getAttempts(pendingFile), 0);
    // attempt 1 to upload from staging directory fails and file is moved to retry directory
    assertTrue(pendingFile.exists());
    uploader =
        new S3Uploader(
            storageSystem,
            serverConfig,
            new EventPartitioner(),
            executor,
            executor,
            s3UploaderStats);
    uploader.start();
    assertFalse(pendingFile.exists());
    assertTrue(new File(retryDir, pendingFile.getName()).exists());
    assertFalse(storageSystem.hasReceivedFile(pendingFile));
    assertEquals(storageSystem.getAttempts(pendingFile), 1);

    // attempt 2: file is moved to staging from retry directory, and fails and hence gets back to
    // retry directory
    executor.elapseTime(1, TimeUnit.MINUTES);
    assertFalse(pendingFile.exists());
    assertTrue(new File(retryDir, pendingFile.getName()).exists());
    assertFalse(storageSystem.hasReceivedFile(pendingFile));
    assertEquals(storageSystem.getAttempts(pendingFile), 2);

    // retryExecutor hasn't run again
    executor.elapseTime(1, TimeUnit.MINUTES);
    assertFalse(pendingFile.exists());
    assertTrue(new File(retryDir, pendingFile.getName()).exists());
    assertFalse(storageSystem.hasReceivedFile(pendingFile));
    assertEquals(storageSystem.getAttempts(pendingFile), 2);

    // attempt 3: file is moved to staging from retry directory, succeeds and hence is deleted from
    // local directories
    executor.elapseTime(2, TimeUnit.MINUTES);
    assertFalse(pendingFile.exists());
    assertFalse(new File(retryDir, pendingFile.getName()).exists());
    assertTrue(storageSystem.hasReceivedFile(pendingFile));
    assertEquals(storageSystem.getAttempts(pendingFile), 3);
  }
  @Test
  public void testPulseMetricsForUploadAttempts() throws Exception {
    storageSystem.succeedOnAttempt(2);
    File pendingFile = new File(tempStageDir, "pending.json.snappy");
    Files.copy(new File(Resources.getResource("pending.json.snappy").toURI()), pendingFile);

    // attempt 1 to upload from staging directory fails and file is moved to retry directory
    uploader =
        new S3Uploader(
            storageSystem,
            serverConfig,
            new EventPartitioner(),
            executor,
            executor,
            s3UploaderStats);
    uploader.start();

    S3UploaderStats s3UploaderStatsArgumentVerifier =
        testingReportCollectionFactory.getArgumentVerifier(S3UploaderStats.class);
    verify(s3UploaderStatsArgumentVerifier).uploadAttempts(ARBITRARY_EVENT_TYPE, FAILURE);
    verify(s3UploaderStatsArgumentVerifier).processedTime(ARBITRARY_EVENT_TYPE);
    verifyNoMoreInteractions(s3UploaderStatsArgumentVerifier);

    S3UploaderStats s3UploaderStatsReportCollection =
        testingReportCollectionFactory.getReportCollection(S3UploaderStats.class);
    CounterStat uploadAttemptsCounterStat =
        s3UploaderStatsReportCollection.uploadAttempts(ARBITRARY_EVENT_TYPE, FAILURE);
    TimeStat processedTimeTimerStat =
        s3UploaderStatsReportCollection.processedTime(ARBITRARY_EVENT_TYPE);
    verify(uploadAttemptsCounterStat).add(1);
    verify(processedTimeTimerStat).time();
    verifyNoMoreInteractions(uploadAttemptsCounterStat);
    verifyNoMoreInteractions(processedTimeTimerStat);
  }
  @Test
  public void testFailsOnVerifyFile() throws Exception {
    File invalidJsonFile = new File(tempStageDir, "invalidjson2.snappy");
    Files.copy(new File(Resources.getResource("invalidjson2.snappy").toURI()), invalidJsonFile);

    assertTrue(invalidJsonFile.exists());
    uploader =
        new S3Uploader(
            storageSystem,
            serverConfig,
            new EventPartitioner(),
            executor,
            executor,
            s3UploaderStats);
    uploader.start();
    assertFalse(invalidJsonFile.exists());
    assertTrue(new File(tempStageDir.getPath() + "/failed", invalidJsonFile.getName()).exists());
    assertFalse(storageSystem.hasReceivedFile(invalidJsonFile));

    S3UploaderStats s3UploaderStatsArgumentVerifier =
        testingReportCollectionFactory.getArgumentVerifier(S3UploaderStats.class);
    verify(s3UploaderStatsArgumentVerifier).processedFiles(UNKNOWN_EVENT_TYPE, CORRUPT);
    verifyNoMoreInteractions(s3UploaderStatsArgumentVerifier);

    CounterStat processedFilesCounterStat =
        testingReportCollectionFactory
            .getReportCollection(S3UploaderStats.class)
            .processedFiles(UNKNOWN_EVENT_TYPE, CORRUPT);
    verify(processedFilesCounterStat).add(1);
    verifyNoMoreInteractions(processedFilesCounterStat);
  }
  @Test
  public void testUploadPendingFiles() throws Exception {
    File pendingFile = new File(tempStageDir, "pending.json.snappy");
    Files.copy(new File(Resources.getResource("pending.json.snappy").toURI()), pendingFile);

    assertTrue(pendingFile.exists());
    uploader =
        new S3Uploader(
            storageSystem,
            serverConfig,
            new EventPartitioner(),
            executor,
            executor,
            s3UploaderStats);
    uploader.start();
    assertFalse(pendingFile.exists());
    assertTrue(storageSystem.hasReceivedFile(pendingFile));

    S3UploaderStats s3UploaderStatsArgumentVerifier =
        testingReportCollectionFactory.getArgumentVerifier(S3UploaderStats.class);
    verify(s3UploaderStatsArgumentVerifier).processedFiles(ARBITRARY_EVENT_TYPE, UPLOADED);
    verify(s3UploaderStatsArgumentVerifier).uploadAttempts(ARBITRARY_EVENT_TYPE, SUCCESS);
    verify(s3UploaderStatsArgumentVerifier).processedTime(ARBITRARY_EVENT_TYPE);
    verifyNoMoreInteractions(s3UploaderStatsArgumentVerifier);

    S3UploaderStats s3UploaderStatsReportCollection =
        testingReportCollectionFactory.getReportCollection(S3UploaderStats.class);
    CounterStat processedFilesCounterStat =
        s3UploaderStatsReportCollection.processedFiles(ARBITRARY_EVENT_TYPE, UPLOADED);
    CounterStat uploadAttemptsCounterStat =
        s3UploaderStatsReportCollection.uploadAttempts(ARBITRARY_EVENT_TYPE, SUCCESS);
    TimeStat processedTimeTimerStat =
        s3UploaderStatsReportCollection.processedTime(ARBITRARY_EVENT_TYPE);
    verify(processedFilesCounterStat).add(1);
    verify(uploadAttemptsCounterStat).add(1);
    verify(processedTimeTimerStat).time();
    verifyNoMoreInteractions(processedFilesCounterStat);
    verifyNoMoreInteractions(uploadAttemptsCounterStat);
    verifyNoMoreInteractions(processedTimeTimerStat);
  }