@Override
  public List<String> getKeys() throws IOException {
    return doOp(new ProviderCallable<List<String>>() {
      @Override
      public List<String> call(KMSClientProvider provider) throws IOException {
        return provider.getKeys();
      }
    }, nextIdx(), true);
  }
@Test
  public void testClientRetriesIdempotentOpWithSocketTimeoutExceptionSucceeds()
      throws Exception {
    Configuration conf = new Configuration();
    conf.setInt(
        CommonConfigurationKeysPublic.KMS_CLIENT_FAILOVER_MAX_RETRIES_KEY, 3);
    final List<String> keys = Arrays.asList("testKey");
    KMSClientProvider p1 = mock(KMSClientProvider.class);
    when(p1.getKeys())
        .thenThrow(new SocketTimeoutException("p1"))
        .thenReturn(keys);
    KMSClientProvider p2 = mock(KMSClientProvider.class);
    when(p2.getKeys()).thenThrow(new SocketTimeoutException("p2"));

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

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

    List<String> result = kp.getKeys();
    assertEquals(keys, result);
    verify(p1, Mockito.times(2)).getKeys();
    verify(p2, Mockito.times(1)).getKeys();
  }