@Override
  public List<KeyVersion> getKeyVersions(final String name) throws IOException {
    return doOp(new ProviderCallable<List<KeyVersion>>() {
      @Override
      public List<KeyVersion> call(KMSClientProvider provider)
          throws IOException {
        return provider.getKeyVersions(name);
      }
    }, nextIdx(), true);
  }
@Test
  public void testClientRetriesIdempotentOpWithSocketTimeoutExceptionFails()
      throws Exception {
    Configuration conf = new Configuration();
    conf.setInt(
        CommonConfigurationKeysPublic.KMS_CLIENT_FAILOVER_MAX_RETRIES_KEY, 2);
    final String keyName = "test";
    final String exceptionMessage = "p1 exception message";
    KMSClientProvider p1 = mock(KMSClientProvider.class);
    Exception originalEx = new SocketTimeoutException(exceptionMessage);
    when(p1.getKeyVersions(Mockito.anyString()))
        .thenThrow(originalEx);
    KMSClientProvider p2 = mock(KMSClientProvider.class);
    when(p2.getKeyVersions(Mockito.anyString()))
        .thenThrow(new SocketTimeoutException("p2 exception message"));

    when(p1.getKMSUrl()).thenReturn("p1");
    when(p2.getKMSUrl()).thenReturn("p2");

    LoadBalancingKMSClientProvider kp = new LoadBalancingKMSClientProvider(
        new KMSClientProvider[] {p1, p2}, 0, conf);

    Exception interceptedEx = intercept(SocketTimeoutException.class,
        "SocketTimeoutException: " + exceptionMessage,
        ()-> kp.getKeyVersions(keyName));
    assertEquals(originalEx, interceptedEx);

    verify(p1, Mockito.times(2))
        .getKeyVersions(Mockito.eq(keyName));
    verify(p2, Mockito.times(1))
        .getKeyVersions(Mockito.eq(keyName));
  }