Skip to content

Commit f4400a0

Browse files
authored
Do not resolve LazyFuture from RemoteDockerImage#toString (#2930)
1 parent 22c6403 commit f4400a0

File tree

2 files changed

+48
-12
lines changed

2 files changed

+48
-12
lines changed

core/src/main/java/org/testcontainers/utility/LazyFuture.java

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@
22

33
import lombok.AccessLevel;
44
import lombok.Getter;
5-
import lombok.experimental.Delegate;
65
import org.rnorth.ducttape.timeouts.Timeouts;
76

87
import java.util.concurrent.*;
8+
import java.util.concurrent.atomic.AtomicReference;
99

1010
/**
1111
* Future implementation with lazy result evaluation <b>in the same Thread</b> as caller.
@@ -14,31 +14,37 @@
1414
*/
1515
public abstract class LazyFuture<T> implements Future<T> {
1616

17-
@Delegate(excludes = Excludes.class)
18-
private final Future<T> delegate = CompletableFuture.completedFuture(null);
19-
2017
@Getter(value = AccessLevel.MODULE, lazy = true)
2118
private final T resolvedValue = resolve();
2219

2320
abstract protected T resolve();
2421

2522
@Override
26-
public T get() throws InterruptedException, ExecutionException {
23+
public boolean cancel(boolean mayInterruptIfRunning) {
24+
return false;
25+
}
26+
27+
@Override
28+
public boolean isCancelled() {
29+
return false;
30+
}
31+
32+
@Override
33+
public boolean isDone() {
34+
return ((AtomicReference<?>) resolvedValue).get() != null;
35+
}
36+
37+
@Override
38+
public T get() {
2739
return getResolvedValue();
2840
}
2941

3042
@Override
31-
public T get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
43+
public T get(long timeout, TimeUnit unit) throws TimeoutException {
3244
try {
3345
return Timeouts.getWithTimeout((int) timeout, unit, this::get);
3446
} catch (org.rnorth.ducttape.TimeoutException e) {
3547
throw new TimeoutException(e.getMessage());
3648
}
3749
}
38-
39-
private interface Excludes<T> {
40-
T get();
41-
42-
T get(long timeout, TimeUnit unit);
43-
}
4450
}

core/src/test/java/org/testcontainers/images/RemoteDockerImageTest.java

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,11 @@
66

77
import org.junit.Test;
88
import org.testcontainers.utility.Base58;
9+
import org.testcontainers.utility.LazyFuture;
910

1011
import java.util.concurrent.CompletableFuture;
12+
import java.util.concurrent.Future;
13+
import java.util.concurrent.atomic.AtomicBoolean;
1114

1215
public class RemoteDockerImageTest {
1316

@@ -44,4 +47,31 @@ public void toStringDoesntResolveImageNameFuture() {
4447
imageNameFuture.complete(imageName);
4548
assertThat(remoteDockerImage.toString(), containsString("imageName=" + imageName));
4649
}
50+
51+
@Test(timeout=5000L)
52+
public void toStringDoesntResolveLazyFuture() throws Exception {
53+
String imageName = Base58.randomString(8).toLowerCase();
54+
AtomicBoolean resolved = new AtomicBoolean(false);
55+
Future<String> imageNameFuture = new LazyFuture<String>() {
56+
@Override
57+
protected String resolve() {
58+
resolved.set(true);
59+
return imageName;
60+
}
61+
};
62+
63+
// verify that we've set up the test properly
64+
assertFalse(imageNameFuture.isDone());
65+
66+
RemoteDockerImage remoteDockerImage = new RemoteDockerImage(imageNameFuture);
67+
assertThat(remoteDockerImage.toString(), containsString("imageName=<resolving>"));
68+
69+
// Make sure the act of calling toString doesn't resolve the imageNameFuture
70+
assertFalse(imageNameFuture.isDone());
71+
assertFalse(resolved.get());
72+
73+
// Trigger resolve
74+
imageNameFuture.get();
75+
assertThat(remoteDockerImage.toString(), containsString("imageName=" + imageName));
76+
}
4777
}

0 commit comments

Comments
 (0)