diff --git a/core/src/main/java/org/testcontainers/utility/LazyFuture.java b/core/src/main/java/org/testcontainers/utility/LazyFuture.java index b0aa4346cbb..758082f5185 100644 --- a/core/src/main/java/org/testcontainers/utility/LazyFuture.java +++ b/core/src/main/java/org/testcontainers/utility/LazyFuture.java @@ -2,10 +2,10 @@ import lombok.AccessLevel; import lombok.Getter; -import lombok.experimental.Delegate; import org.rnorth.ducttape.timeouts.Timeouts; import java.util.concurrent.*; +import java.util.concurrent.atomic.AtomicReference; /** * Future implementation with lazy result evaluation in the same Thread as caller. @@ -14,31 +14,37 @@ */ public abstract class LazyFuture implements Future { - @Delegate(excludes = Excludes.class) - private final Future delegate = CompletableFuture.completedFuture(null); - @Getter(value = AccessLevel.MODULE, lazy = true) private final T resolvedValue = resolve(); abstract protected T resolve(); @Override - public T get() throws InterruptedException, ExecutionException { + public boolean cancel(boolean mayInterruptIfRunning) { + return false; + } + + @Override + public boolean isCancelled() { + return false; + } + + @Override + public boolean isDone() { + return ((AtomicReference) resolvedValue).get() != null; + } + + @Override + public T get() { return getResolvedValue(); } @Override - public T get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { + public T get(long timeout, TimeUnit unit) throws TimeoutException { try { return Timeouts.getWithTimeout((int) timeout, unit, this::get); } catch (org.rnorth.ducttape.TimeoutException e) { throw new TimeoutException(e.getMessage()); } } - - private interface Excludes { - T get(); - - T get(long timeout, TimeUnit unit); - } } diff --git a/core/src/test/java/org/testcontainers/images/RemoteDockerImageTest.java b/core/src/test/java/org/testcontainers/images/RemoteDockerImageTest.java index c62f15653b3..6b6a82559bf 100644 --- a/core/src/test/java/org/testcontainers/images/RemoteDockerImageTest.java +++ b/core/src/test/java/org/testcontainers/images/RemoteDockerImageTest.java @@ -6,8 +6,11 @@ import org.junit.Test; import org.testcontainers.utility.Base58; +import org.testcontainers.utility.LazyFuture; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Future; +import java.util.concurrent.atomic.AtomicBoolean; public class RemoteDockerImageTest { @@ -44,4 +47,31 @@ public void toStringDoesntResolveImageNameFuture() { imageNameFuture.complete(imageName); assertThat(remoteDockerImage.toString(), containsString("imageName=" + imageName)); } + + @Test(timeout=5000L) + public void toStringDoesntResolveLazyFuture() throws Exception { + String imageName = Base58.randomString(8).toLowerCase(); + AtomicBoolean resolved = new AtomicBoolean(false); + Future imageNameFuture = new LazyFuture() { + @Override + protected String resolve() { + resolved.set(true); + return imageName; + } + }; + + // verify that we've set up the test properly + assertFalse(imageNameFuture.isDone()); + + RemoteDockerImage remoteDockerImage = new RemoteDockerImage(imageNameFuture); + assertThat(remoteDockerImage.toString(), containsString("imageName=")); + + // Make sure the act of calling toString doesn't resolve the imageNameFuture + assertFalse(imageNameFuture.isDone()); + assertFalse(resolved.get()); + + // Trigger resolve + imageNameFuture.get(); + assertThat(remoteDockerImage.toString(), containsString("imageName=" + imageName)); + } }