-
-
Notifications
You must be signed in to change notification settings - Fork 1.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Expose low level API #301
Expose low level API #301
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -58,7 +58,7 @@ | |
@EqualsAndHashCode(callSuper = false) | ||
public class GenericContainer<SELF extends GenericContainer<SELF>> | ||
extends FailureDetectingExternalResource | ||
implements Container<SELF> { | ||
implements Container<SELF>, AutoCloseable { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. small non-related change to simplify the testing There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Interesting! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. FTR IntelliJ IDEA is barking about this, see https://imgur.com/a/sD1WNyG ;) (and I cannot use try with resources in my use case) |
||
|
||
private static final Charset UTF8 = Charset.forName("UTF-8"); | ||
|
||
|
@@ -134,6 +134,8 @@ public class GenericContainer<SELF extends GenericContainer<SELF>> | |
|
||
private List<Consumer<OutputFrame>> logConsumers = new ArrayList<>(); | ||
|
||
private final Set<Consumer<CreateContainerCmd>> createContainerCmdHooks = new HashSet<>(); | ||
|
||
private static final Set<String> AVAILABLE_IMAGE_NAME_CACHE = new HashSet<>(); | ||
private static final RateLimiter DOCKER_CLIENT_RATE_LIMITER = RateLimiterBuilder | ||
.newBuilder() | ||
|
@@ -191,6 +193,7 @@ private void tryStart(Profiler profiler) { | |
profiler.start("Create container"); | ||
CreateContainerCmd createCommand = dockerClient.createContainerCmd(dockerImageName); | ||
applyConfiguration(createCommand); | ||
createContainerCmdHooks.forEach(hook -> hook.accept(createCommand)); | ||
|
||
containerId = createCommand.exec().getId(); | ||
ResourceReaper.instance().registerContainerForCleanup(containerId, dockerImageName); | ||
|
@@ -881,6 +884,16 @@ public void withStartupAttempts(int attempts) { | |
this.startupAttempts = attempts; | ||
} | ||
|
||
@Override | ||
public void close() { | ||
stop(); | ||
} | ||
|
||
public SELF withCustomizer(Consumer<CreateContainerCmd> hook) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I need a help with the naming here. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe something more verbose like There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Funny thing - I initially named it There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Like this name too ;) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've decided to go with "post" hooks only because GenericObject does "pre" part already, and this new API just allows you to configure the final result and override some configuration. Do you have any example where "pre" hook might be helpful? Because I don't :) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No, don't think we need it. My point was only about the naming, including the word post makes the API a bit more self documenting. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I liked pre/post, but actually doesn't it make it confusing wrt. what it is before or after? This change is post- testcontainer's configuration step, but pre- creation of the container. So actually it seems to be confusing if we're not careful 😂 Some other ideas for the name: I'm not sure though 🤷♂️ There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Your post clarified the API a lot for me and now I agree, pre/post seems to introduce confusing semantics here. From a general API naming standpoint, There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
We should probably be making it clear to the developer, through naming and javadoc comments, that this does expose the underlying docker-java API so might change outside of our control. WDYT @bsideup ? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I agree! I'll add JavaDoc and rename the method now :) |
||
createContainerCmdHooks.add(hook); | ||
return self(); | ||
} | ||
|
||
/** | ||
* Convenience class with access to non-public members of GenericContainer. | ||
*/ | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -11,6 +11,7 @@ | |
import org.rnorth.ducttape.RetryCountExceededException; | ||
import org.rnorth.ducttape.unreliables.Unreliables; | ||
import org.testcontainers.containers.GenericContainer; | ||
import org.testcontainers.utility.Base58; | ||
import org.testcontainers.utility.TestEnvironment; | ||
|
||
import java.io.*; | ||
|
@@ -282,6 +283,26 @@ public void extraHostTest() throws IOException { | |
assertTrue("The hosts file of container contains extra host", matcher.find()); | ||
} | ||
|
||
@Test | ||
public void createContainerCmdHookTest() { | ||
// Use random name to avoid the conflicts between the tests | ||
String randomName = Base58.randomString(5); | ||
try( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 |
||
GenericContainer container = new GenericContainer<>("redis:3.0.2") | ||
.withCommand("redis-server", "--help") | ||
.withCustomizer(cmd -> cmd.withName("overrideMe")) | ||
// Preserves the order | ||
.withCustomizer(cmd -> cmd.withName(randomName)) | ||
// Allows to override pre-configured values by GenericContainer | ||
.withCustomizer(cmd -> cmd.withCmd("redis-server", "--port", "6379")) | ||
) { | ||
container.start(); | ||
|
||
assertEquals("Name is configured", "/" + randomName, container.getContainerInfo().getName()); | ||
assertEquals("Command is configured", "[redis-server, --port, 6379]", Arrays.toString(container.getContainerInfo().getConfig().getCmd())); | ||
} | ||
} | ||
|
||
private BufferedReader getReaderForContainerPort80(GenericContainer container) { | ||
|
||
return Unreliables.retryUntilSuccess(10, TimeUnit.SECONDS, () -> { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
decided to do the deprecations here