@Test
  public void testRetrySuccess() throws DbxException, IOException {
    HttpRequestor mockRequestor = mock(HttpRequestor.class);
    DbxRequestConfig config =
        createRequestConfig().withAutoRetryEnabled(3).withHttpRequestor(mockRequestor).build();

    DbxClientV2 client = new DbxClientV2(config, "fakeAccessToken");
    FileMetadata expected =
        new FileMetadata(
            "bar.txt",
            "id:1HkLjqifwMAAAAAAAAAAAQ",
            new Date(1456169040985L),
            new Date(1456169040985L),
            "2e0c38735597",
            2091603);

    // 503 twice, then return result
    HttpRequestor.Uploader mockUploader = mockUploader();
    when(mockUploader.finish())
        .thenReturn(createEmptyResponse(503))
        .thenReturn(createEmptyResponse(503))
        .thenReturn(createSuccessResponse(serialize(expected)));

    when(mockRequestor.startPost(anyString(), anyHeaders())).thenReturn(mockUploader);

    Metadata actual = client.files().getMetadata(expected.getId());

    // should have only been called 3 times: initial call + 2 retries
    verify(mockRequestor, times(3)).startPost(anyString(), anyHeaders());

    assertEquals(actual.getName(), expected.getName());
    assertTrue(actual instanceof FileMetadata, actual.getClass().toString());
    assertEquals(((FileMetadata) actual).getId(), expected.getId());
  }
  @Test(expectedExceptions = RetryException.class)
  public void testRetryRetriesExceeded() throws DbxException, IOException {
    HttpRequestor mockRequestor = mock(HttpRequestor.class);
    DbxRequestConfig config =
        createRequestConfig().withAutoRetryEnabled(3).withHttpRequestor(mockRequestor).build();

    DbxClientV2 client = new DbxClientV2(config, "fakeAccessToken");

    // 503 always and forever
    HttpRequestor.Uploader mockUploader = mockUploader();
    when(mockUploader.finish()).thenReturn(createEmptyResponse(503));
    when(mockRequestor.startPost(anyString(), anyHeaders())).thenReturn(mockUploader);

    try {
      client.users().getCurrentAccount();
    } finally {
      // should only have been called 4 times: initial call plus our maximum retry limit
      verify(mockRequestor, times(1 + 3)).startPost(anyString(), anyHeaders());
    }
  }
  @Test(expectedExceptions = RetryException.class)
  public void testRetryDisabled() throws DbxException, IOException {
    HttpRequestor mockRequestor = mock(HttpRequestor.class);
    DbxRequestConfig config =
        createRequestConfig().withAutoRetryDisabled().withHttpRequestor(mockRequestor).build();

    DbxClientV2 client = new DbxClientV2(config, "fakeAccessToken");

    // 503 every time
    HttpRequestor.Uploader mockUploader = mockUploader();
    when(mockUploader.finish()).thenReturn(createEmptyResponse(503));
    when(mockRequestor.startPost(anyString(), anyHeaders())).thenReturn(mockUploader);

    try {
      client.users().getCurrentAccount();
    } finally {
      // should only have been called once since we disabled retry
      verify(mockRequestor, times(1)).startPost(anyString(), anyHeaders());
    }
  }
  @Test
  public void testRetrySuccessWithBackoff() throws DbxException, IOException {
    HttpRequestor mockRequestor = mock(HttpRequestor.class);
    DbxRequestConfig config =
        createRequestConfig().withAutoRetryEnabled(3).withHttpRequestor(mockRequestor).build();

    DbxClientV2 client = new DbxClientV2(config, "fakeAccessToken");
    FileMetadata expected =
        new FileMetadata(
            "banana.png",
            "id:eRsVsAya9YAAAAAAAAAAAQ",
            new Date(1456173312172L),
            new Date(1456173312172L),
            "89df885732c38",
            12345L);

    // 503 twice, then return result
    HttpRequestor.Uploader mockUploader = mockUploader();
    when(mockUploader.finish())
        .thenReturn(createEmptyResponse(503)) // no backoff
        .thenReturn(createRateLimitResponse(1)) // backoff 1 sec
        .thenReturn(createRateLimitResponse(2)) // backoff 2 sec
        .thenReturn(createSuccessResponse(serialize(expected)));

    when(mockRequestor.startPost(anyString(), anyHeaders())).thenReturn(mockUploader);

    long start = System.currentTimeMillis();
    Metadata actual = client.files().getMetadata(expected.getId());
    long end = System.currentTimeMillis();

    // no way easy way to properly test this, but request should
    // have taken AT LEAST 3 seconds due to backoff.
    assertTrue((end - start) >= 3000L, "duration: " + (end - start) + " millis");

    // should have been called 4 times: initial call + 3 retries
    verify(mockRequestor, times(4)).startPost(anyString(), anyHeaders());

    assertEquals(actual.getName(), expected.getName());
    assertTrue(actual instanceof FileMetadata, actual.getClass().toString());
  }
  @Test
  public void testRetryDownload() throws DbxException, IOException {
    HttpRequestor mockRequestor = mock(HttpRequestor.class);
    DbxRequestConfig config =
        createRequestConfig().withAutoRetryEnabled(3).withHttpRequestor(mockRequestor).build();

    DbxClientV2 client = new DbxClientV2(config, "fakeAccessToken");

    FileMetadata expectedMetadata =
        new FileMetadata(
            "download_me.txt",
            "id:KLavC4viCDAAAAAAAAAAAQ",
            new Date(1456169692501L),
            new Date(1456169692501L),
            "341438735597",
            2626);
    byte[] expectedBytes = new byte[] {1, 2, 3, 4};

    // 503 once, then return 200
    HttpRequestor.Uploader mockUploader = mockUploader();
    when(mockUploader.finish())
        .thenReturn(createEmptyResponse(503))
        .thenReturn(createDownloaderResponse(expectedBytes, serialize(expectedMetadata)));
    when(mockRequestor.startPost(anyString(), anyHeaders())).thenReturn(mockUploader);

    DbxDownloader<FileMetadata> downloader = client.files().download(expectedMetadata.getId());

    // should have been attempted twice
    verify(mockRequestor, times(2)).startPost(anyString(), anyHeaders());

    ByteArrayOutputStream bout = new ByteArrayOutputStream();
    FileMetadata actualMetadata = downloader.download(bout);
    byte[] actualBytes = bout.toByteArray();

    assertEquals(actualBytes, expectedBytes);
    assertEquals(actualMetadata, expectedMetadata);
  }