Repository navigation
Conversation
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
withReuse()hashed onlycreateOpts(reuseOrStartContainer), but the container is created with{ ...createOpts, HostConfig: hostConfig }, attached tonetworkModewithnetworkAliasesafter create, andgets the copied files and content after create. Two builders that differed in tmpfs, privileged mode, extra hosts,
port bindings, bind mounts, network aliases or copied content got the same hash, so the second one was handed the
first one's container.
The hash input is now built in one place (
createContainerHash) and coverscreateOpts,hostConfig, thenetwork mode and aliases, the copy inputs and
copyToContainerOptions. It is still stored in the singleorg.testcontainers.container-hashlabel.Copied files and directories are hashed by content (target, mode, file mode and bytes; directories walked
recursively in sorted order), following testcontainers-java's
hashCopiedFilesand how it feeds into the create-command hash, which also covers the host config and network settings
(L386-L402).
Unlike Java, copy entries keep their insertion order (a later copy can overwrite an earlier one) and directory
entries include their relative path. String and Buffer content is hashed directly. A
Readablecontent stream ora tar archive can't be hashed without consuming it, so only its target (and mode) is included. The docs now say so,
and that the network is part of the configuration.
The
host.testcontainers.internalextra host thatstart()adds when host ports are exposed is left out of thehash, because the port forwarder's IP changes every session and including it would create a new reusable
container per session. This matches .NET's
JsonIgnoreRuntimeExtraHosts.Extra hosts set with
withExtraHostsare hashed. The trade-off is the same as onmainand in .NET: a reusedcontainer keeps the extra host it was created with (none, or an old forwarder IP) and is not connected to the
current port forwarder network, because
reuseContainerdoesn't reconnect networks.Settings that don't change the created container (auto-remove, wait strategy, startup timeout, pull policy, log
consumer) stay out of the hash, and the version label is untouched (#1552).
Known limitations:
createOpts. Builders that set the same env, labels ortmpfs in a different order get different hashes. That starts an extra container; it never reuses the wrong one.
start()with reuse enabled reads and hashes all copied files and walks copied directories, even when anexisting container is reused (Java does the same).
Verification
npx vitest run packages/testcontainers/src/generic-container/generic-container-reuse.test.tsnetwork aliases, copied file and copied directory all reused the first container
(
expected '<id>' not to be '<id>').reuse, and a container created before
TestContainers.exposeHostPorts()keeps its hash after it. The last onefails if the port forwarder entry is hashed.
npx vitest run packages/testcontainers/src/generic-container packages/testcontainers/src/port-forwarder packages/testcontainers/src/network packages/testcontainers/src/common:18 files, 142 tests, 1 skipped. Tests in
generic-container-dockerfile.test.ts("Failed to build image") and"should bind to specified host port with a different protocol" failed intermittently while another Docker-heavy
test run shared the daemon, and passed on rerun. They don't use reuse.
common/hash.test.tshas a new unit test forhashFile.npm run format,npm run lint,npm run knip,npm run check-compiles: clean.beforeContainerCreatedonly writesdeterministic config, so they are expected to still reuse.
Not breaking
No API changes. Existing reusable containers get a new hash once, so the first run after upgrading starts a new
container instead of reusing an old one. This already happens on every release because the hash includes the
library version label.
Identical configurations still reuse, with these behaviour changes:
Network(which gets arandom name) is no longer reused across runs, and
AzureServiceBusContainer, which creates a newNetworkonevery
start(), no longer reuses. Before, these were reused, but the reused container was never connected tothe new network. Containers started with
withNetworkModeand a fixed network name are unaffected.withCopyFilesToContainersource now fails before the container is created,instead of after create when the files are copied.
Closes #1522