public static <T> T retryUntilTimeout(Callable<T> callable, Supplier<String> description, Duration timeoutDuration, long retryBackoffMs) throws Exception {
        return retryUntilTimeout(callable, description, timeoutDuration, retryBackoffMs, Time.SYSTEM);
    }
@Test
    public void testSupplier() throws Exception {
        Mockito.when(mockCallable.call()).thenThrow(new TimeoutException("timeout exception"));

        ConnectException e = assertThrows(ConnectException.class,
                () -> RetryUtil.retryUntilTimeout(mockCallable, null, Duration.ofMillis(100), 10, mockTime));
        assertTrue(e.getMessage().startsWith("Fail to callable"));

        e = assertThrows(ConnectException.class,
                () -> RetryUtil.retryUntilTimeout(mockCallable, () -> null, Duration.ofMillis(100), 10, mockTime));
        assertTrue(e.getMessage().startsWith("Fail to callable"));

        e = assertThrows(ConnectException.class,
                () -> RetryUtil.retryUntilTimeout(mockCallable, () -> "execute lambda", Duration.ofMillis(500), 10, mockTime));
        assertTrue(e.getMessage().startsWith("Fail to execute lambda"));
        Mockito.verify(mockCallable, Mockito.atLeast(3)).call();
    }