-
-
Notifications
You must be signed in to change notification settings - Fork 342
feat: Add connection string provider #1588
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
base: develop
Are you sure you want to change the base?
Conversation
✅ Deploy Preview for testcontainers-dotnet ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
Summary by CodeRabbit
✏️ Tip: You can customize this high-level summary in your review settings. WalkthroughAdds a Connection String Provider API: new interfaces, enum, adapter, configuration property, builder fluent API, container wiring and GetConnectionString methods, docs, and tests to support retrieval and configuration of container connection strings and endpoints. Changes
Sequence Diagram(s)sequenceDiagram
participant Builder as ContainerBuilder
participant Config as ContainerConfiguration
participant Docker as DockerContainer
participant Provider as IConnectionStringProvider
Builder->>Builder: WithConnectionStringProvider(provider)
Builder->>Config: Clone/attach provider (wrapped if generic)
Builder->>Docker: Build & StartAsync()
Docker->>Config: Read ConnectionStringProvider
alt provider configured
Docker->>Provider: Configure(container, configuration)
Note over Docker,Provider: Provider stored on container for runtime
else no provider
Docker-->>Docker: Leave unconfigured
end
Docker->>Provider: GetConnectionString(mode/name)
Provider-->>Docker: Return connection string or throw if not configured
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes
Suggested labels
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
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.
Actionable comments posted: 1
🧹 Nitpick comments (6)
src/Testcontainers/Configurations/Containers/ConnectionMode.cs (1)
5-20: Enum shape and placement look good; optional doc tweakThe
ConnectionModeenum is minimal and well‑placed inDotNet.Testcontainers.Configurations, and theContainer/Hostvalues map cleanly to the intended usage inGetConnectionString(...).If you want to be extra explicit for consumers, you could slightly rephrase the summaries to make the perspective clear, e.g.:
- /// <summary> - /// The connection string for the container. - /// </summary> + /// <summary> + /// Resolve a connection string usable from within a container (e.g. using container hostname/alias). + /// </summary>and similarly for
Host.src/Testcontainers/Configurations/Containers/IContainerConfiguration.cs (1)
129-132: New property is reasonable, but clarify nullability and consider compatibility impactThe
ConnectionStringProviderhook fits well onIContainerConfigurationand matches the builder/container wiring.Two follow‑ups to consider:
Document null semantics
In many configurations a provider won’t be set. To make that clear to consumers, you could adjust the XML doc to signal thatnullis a valid value, e.g.:
- ///
- /// Gets the connection string provider.
- ///
- IConnectionStringProvider<IContainer, IContainerConfiguration> ConnectionStringProvider { get; }
- ///
- /// Gets the connection string provider, or if none is configured.
- ///
- IConnectionStringProvider<IContainer, IContainerConfiguration> ConnectionStringProvider { get; }
2. **Public interface expansion is breaking** Adding this property to `IContainerConfiguration` is a source/binary breaking change for any external implementations of this interface. Please double‑check that this is acceptable for the targeted release (e.g., next major), or that downstream implementers are expected to be updated accordingly. If not, an alternative could be a separate interface (e.g. `IConnectionStringConfig`) plus extension methods. </blockquote></details> <details> <summary>src/Testcontainers/Containers/ConnectionStringProviderNotConfiguredException.cs (1)</summary><blockquote> `6-19`: **Exception is fine; consider additional constructors for future extensibility** The dedicated `ConnectionStringProviderNotConfiguredException` with a clear default message works well for the current use case. If you expect this to be used in more complex flows later, you might optionally add the standard overloads (message, message+inner) to make wrapping easier, but it’s not required for this PR. </blockquote></details> <details> <summary>src/Testcontainers/Builders/ContainerBuilder`3.cs (1)</summary><blockquote> `399-403`: **Wiring looks correct; add a null guard to avoid confusing NREs** The new `WithConnectionStringProvider` correctly adapts the strongly‑typed provider into the non‑generic `ConnectionStringProvider` used by the configuration. One edge case: if someone accidentally calls `WithConnectionStringProvider(null)`, they’ll end up with an adapter whose inner provider is `null`, and the first call to `GetConnectionString` will likely blow up with a `NullReferenceException` instead of the explicit `ConnectionStringProviderNotConfiguredException`. Consider failing fast on misuse: ```diff public TBuilderEntity WithConnectionStringProvider(IConnectionStringProvider<TContainerEntity, TConfigurationEntity> connectionStringProvider) { + if (connectionStringProvider is null) + { + throw new ArgumentNullException(nameof(connectionStringProvider)); + } + return Clone( new ContainerConfiguration( connectionStringProvider: new ConnectionStringProvider<TContainerEntity, TConfigurationEntity>(connectionStringProvider))); }This keeps the happy path unchanged but makes errors clearer when the API is used incorrectly.
tests/Testcontainers.Platform.Linux.Tests/ConnectionStringProviderTest.cs (1)
32-38: Consider adding test coverage for error cases and ConnectionMode.Container.The current test validates the happy path well. Consider adding tests for:
GetConnectionStringwithout a provider configured (should throwConnectionStringProviderNotConfiguredException)GetConnectionString(ConnectionMode.Container)to verify the mode parameter is passed correctlysrc/Testcontainers/Configurations/Containers/IConnectionStringProvider.cs (1)
21-29: Consider documenting behavior for unknown connection string names.The
GetConnectionString(string name, ...)overload documents that it throws when the provider is not configured, but doesn't specify the behavior when an unknown name is requested. Consider adding documentation or a dedicated exception (e.g.,ConnectionStringNotFoundException) for clarity.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (17)
docs/api/connection_string_provider.md(1 hunks)mkdocs.yml(1 hunks)src/Testcontainers.Couchbase/CouchbaseBuilder.cs(1 hunks)src/Testcontainers/Builders/ContainerBuilder3.cs` (1 hunks)src/Testcontainers/Builders/IContainerBuilder2.cs` (2 hunks)src/Testcontainers/Configurations/Containers/ConnectionMode.cs(1 hunks)src/Testcontainers/Configurations/Containers/ConnectionStringProvider.cs(1 hunks)src/Testcontainers/Configurations/Containers/ContainerConfiguration.cs(4 hunks)src/Testcontainers/Configurations/Containers/IConnectionStringProvider.cs(1 hunks)src/Testcontainers/Configurations/Containers/IConnectionStringProvider2.cs` (1 hunks)src/Testcontainers/Configurations/Containers/IContainerConfiguration.cs(1 hunks)src/Testcontainers/Configurations/WaitStrategies/IWaitUntil.cs(1 hunks)src/Testcontainers/Configurations/WaitStrategies/IWaitWhile.cs(1 hunks)src/Testcontainers/Containers/ConnectionStringProviderNotConfiguredException.cs(1 hunks)src/Testcontainers/Containers/DockerContainer.cs(3 hunks)src/Testcontainers/Containers/IContainer.cs(1 hunks)tests/Testcontainers.Platform.Linux.Tests/ConnectionStringProviderTest.cs(1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-11-17T17:58:43.958Z
Learnt from: diegosasw
Repo: testcontainers/testcontainers-dotnet PR: 1583
File: src/Testcontainers.KurrentDb/Testcontainers.KurrentDb.csproj:7-7
Timestamp: 2025-11-17T17:58:43.958Z
Learning: In the testcontainers-dotnet repository, JetBrains.Annotations should use version 2023.3.0 to maintain consistency with the main Testcontainers csproj, rather than always using the latest available version.
Applied to files:
src/Testcontainers/Containers/IContainer.cs
🧬 Code graph analysis (8)
src/Testcontainers/Containers/IContainer.cs (1)
src/Testcontainers/Builders/ContainerBuilder.cs (1)
IContainer(54-58)
src/Testcontainers/Builders/ContainerBuilder`3.cs (2)
src/Testcontainers/Configurations/Containers/ContainerConfiguration.cs (4)
ContainerConfiguration(44-92)ContainerConfiguration(98-101)ContainerConfiguration(107-110)ContainerConfiguration(117-143)src/Testcontainers/Configurations/Containers/ConnectionStringProvider.cs (2)
ConnectionStringProvider(6-38)ConnectionStringProvider(16-19)
src/Testcontainers/Builders/IContainerBuilder`2.cs (1)
src/Testcontainers/Builders/ContainerBuilder`3.cs (16)
TBuilderEntity(55-59)TBuilderEntity(62-66)TBuilderEntity(69-72)TBuilderEntity(75-78)TBuilderEntity(81-84)TBuilderEntity(87-90)TBuilderEntity(93-96)TBuilderEntity(99-102)TBuilderEntity(105-108)TBuilderEntity(111-114)TBuilderEntity(117-120)TBuilderEntity(123-126)TBuilderEntity(129-132)TBuilderEntity(135-139)TBuilderEntity(142-145)TBuilderEntity(148-152)
tests/Testcontainers.Platform.Linux.Tests/ConnectionStringProviderTest.cs (1)
src/Testcontainers/Builders/ContainerBuilder.cs (1)
IContainer(54-58)
src/Testcontainers/Configurations/Containers/ConnectionStringProvider.cs (2)
src/Testcontainers/Configurations/Containers/IConnectionStringProvider`2.cs (1)
Configure(17-17)src/Testcontainers/Containers/DockerContainer.cs (2)
GetConnectionString(422-430)GetConnectionString(433-441)
src/Testcontainers/Configurations/Containers/IConnectionStringProvider`2.cs (2)
src/Testcontainers/Builders/ContainerBuilder.cs (1)
IContainer(54-58)src/Testcontainers/Configurations/Containers/ConnectionStringProvider.cs (1)
Configure(22-25)
src/Testcontainers/Configurations/Containers/IContainerConfiguration.cs (1)
src/Testcontainers/Configurations/Containers/ConnectionStringProvider.cs (2)
ConnectionStringProvider(6-38)ConnectionStringProvider(16-19)
src/Testcontainers/Configurations/Containers/IConnectionStringProvider.cs (3)
src/Testcontainers/Containers/ConnectionStringProviderNotConfiguredException.cs (1)
PublicAPI(9-19)src/Testcontainers/Containers/DockerContainer.cs (3)
PublicAPI(19-789)GetConnectionString(422-430)GetConnectionString(433-441)src/Testcontainers/Configurations/Containers/ConnectionStringProvider.cs (2)
GetConnectionString(28-31)GetConnectionString(34-37)
🪛 LanguageTool
docs/api/connection_string_provider.md
[style] ~4-~4: Using many exclamation marks might seem excessive (in this case: 3 exclamation marks for a text that’s 750 characters long)
Context: ... API base addresses) in a uniform way. !!!note Testcontainers modules do not ...
(EN_EXCESSIVE_EXCLAMATION)
🪛 markdownlint-cli2 (0.18.1)
docs/api/connection_string_provider.md
13-13: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
34-34: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
60-60: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (7)
- GitHub Check: ci (Testcontainers.Bigtable, ubuntu-24.04)
- GitHub Check: ci (Testcontainers.ActiveMq, ubuntu-24.04)
- GitHub Check: ci (Testcontainers.Cassandra, ubuntu-24.04)
- GitHub Check: ci (Testcontainers.BigQuery, ubuntu-24.04)
- GitHub Check: ci (Testcontainers.Azurite, ubuntu-24.04)
- GitHub Check: ci (Testcontainers.ArangoDb, ubuntu-24.04)
- GitHub Check: analyze (csharp)
🔇 Additional comments (18)
src/Testcontainers.Couchbase/CouchbaseBuilder.cs (1)
179-185: Doc comment clarification forcontainerparameter looks goodThe updated XML documentation explicitly stating "The Couchbase container." is clearer and aligns with how
containeris used throughoutConfigureCouchbaseAsync; no further changes needed here.mkdocs.yml (1)
43-43: Connection string provider docs entry correctly wired into navThe new
api/connection_string_provider.mdentry is placed consistently within the API section; no issues from a docs/config standpoint.src/Testcontainers/Configurations/WaitStrategies/IWaitWhile.cs (1)
16-16: Doc wording matches generic wait semanticsThe updated parameter description (“check the condition for”) better reflects
IWaitWhile’s purpose and stays consistent withIWaitUntil; no functional impact.src/Testcontainers/Configurations/WaitStrategies/IWaitUntil.cs (1)
16-16: Consistent documentation across wait strategy interfacesThe revised parameter description is clearer and aligns with
IWaitWhile; looks good.src/Testcontainers/Containers/IContainer.cs (1)
17-17: Extending IContainer with IConnectionStringProvider is a breaking API surface changeHaving
IContainerimplementIConnectionStringProvideris a nice ergonomic win (container.GetConnectionString(...)), but it also means:
- Any custom
IContainerimplementations outside this repo now have to implement the provider contract.- Existing compiled code against the old interface may break at runtime once upgraded.
Please validate that this is intended for the release train this PR targets (e.g., planned major version) and, if not, consider alternatives such as:
- A separate interface (e.g.
IConnectionStringAwareContainer) implemented byDockerContainerand module containers, plus- Extension methods on
IContainerthat safely downcast or throw a clearer error when the provider isn’t supported.src/Testcontainers/Builders/IContainerBuilder`2.cs (2)
24-25: LGTM!The added generic constraints properly enforce type safety for the container and configuration entities, which enables the strongly-typed connection string provider pattern.
505-512: LGTM!The new
WithConnectionStringProvidermethod follows the established fluent builder pattern, has proper documentation, and correctly uses the generic type parameters for type-safe provider registration.src/Testcontainers/Configurations/Containers/ContainerConfiguration.cs (3)
65-91: LGTM!The new
connectionStringProviderparameter and its assignment follow the established pattern for other configuration properties in this class.
140-140: LGTM!Using
BuildConfiguration.Combinefor the connection string provider in the copy/merge constructor is consistent with how other configuration properties are handled.
223-226: LGTM!The
[JsonIgnore]attribute is appropriate since the provider contains runtime logic and references that shouldn't be serialized. This is consistent with other similar properties likeStartupCallbackandOutputConsumer.docs/api/connection_string_provider.md (1)
1-78: LGTM!The documentation is comprehensive, with clear examples for both generic and module-specific providers. The note about modules not yet implementing the feature sets appropriate expectations for users.
src/Testcontainers/Containers/DockerContainer.cs (3)
32-32: LGTM!The new private field follows the naming convention of other private fields in this class.
421-441: LGTM!Both
GetConnectionStringoverloads correctly check for null provider and throwConnectionStringProviderNotConfiguredExceptionwith a clear message. The delegation to the underlying provider is straightforward.
587-593: LGTM!The provider wiring is correctly placed after the container has started and readiness checks have passed. This ensures that
Configurereceives a fully initialized container with valid state, allowing the provider to access container information like ports and hostname.src/Testcontainers/Configurations/Containers/ConnectionStringProvider.cs (1)
22-25: The casts rely on the framework ensuring type consistency.The casts to
TContainerEntityandTConfigurationEntitywill throwInvalidCastExceptionif the container/configuration types don't match. Since this is an internal class and the framework controls instantiation viaContainerBuilder.WithConnectionStringProvider, this is acceptable. The type constraints and builder pattern ensure correct usage.src/Testcontainers/Configurations/Containers/IConnectionStringProvider`2.cs (3)
1-4: LGTM!Namespace and using statements are appropriate.
6-10: Contravariance correctly applied.The
inmodifiers on both generic type parameters are appropriate since they're used only as input to theConfiguremethod. The generic constraints ensure type safety while the contravariance enables flexibility in the adapter pattern.
12-17: LGTM!The
Configuremethod signature is clean and enables the provider to access both container and configuration information. The design integrates well with the adapter pattern shown inConnectionStringProvider.cs.
src/Testcontainers/Configurations/Containers/ConnectionStringProvider.cs
Show resolved
Hide resolved
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.
Actionable comments posted: 1
🧹 Nitpick comments (1)
src/Testcontainers/Configurations/Containers/ConnectionStringProvider.cs (1)
16-18: Consider adding null validation for the constructor parameter.Although this is an internal class, adding a null check would improve defensive programming and make debugging easier if the class is misused.
Apply this diff to add validation:
public ConnectionStringProvider(IConnectionStringProvider<TContainerEntity, TConfigurationEntity> connectionStringProvider) { + ArgumentNullException.ThrowIfNull(connectionStringProvider); _connectionStringProvider = connectionStringProvider; }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
docs/api/connection_string_provider.md(1 hunks)src/Testcontainers/Configurations/Containers/ConnectionStringProvider.cs(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/Testcontainers/Configurations/Containers/ConnectionStringProvider.cs (1)
src/Testcontainers/Containers/DockerContainer.cs (2)
GetConnectionString(422-430)GetConnectionString(433-441)
🪛 LanguageTool
docs/api/connection_string_provider.md
[style] ~4-~4: Using many exclamation marks might seem excessive (in this case: 3 exclamation marks for a text that’s 1503 characters long)
Context: ... API base addresses) in a uniform way. !!!note Testcontainers modules do not ...
(EN_EXCESSIVE_EXCLAMATION)
🪛 markdownlint-cli2 (0.18.1)
docs/api/connection_string_provider.md
13-13: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (59)
- GitHub Check: ci (Testcontainers.Azurite, ubuntu-24.04)
- GitHub Check: ci (Testcontainers.ArangoDb, ubuntu-24.04)
- GitHub Check: ci (Testcontainers.Bigtable, ubuntu-24.04)
- GitHub Check: ci (Testcontainers.ActiveMq, ubuntu-24.04)
- GitHub Check: ci (Testcontainers.Cassandra, ubuntu-24.04)
- GitHub Check: ci (Testcontainers.BigQuery, ubuntu-24.04)
- GitHub Check: ci (Testcontainers.Azurite, ubuntu-24.04)
- GitHub Check: ci (Testcontainers.ArangoDb, ubuntu-24.04)
- GitHub Check: ci (Testcontainers.Bigtable, ubuntu-24.04)
- GitHub Check: ci (Testcontainers.ActiveMq, ubuntu-24.04)
- GitHub Check: ci (Testcontainers.Cassandra, ubuntu-24.04)
- GitHub Check: ci (Testcontainers.BigQuery, ubuntu-24.04)
- GitHub Check: ci (Testcontainers.Azurite, ubuntu-24.04)
- GitHub Check: ci (Testcontainers.ArangoDb, ubuntu-24.04)
- GitHub Check: ci (Testcontainers.Bigtable, ubuntu-24.04)
- GitHub Check: ci (Testcontainers.ActiveMq, ubuntu-24.04)
- GitHub Check: ci (Testcontainers.Cassandra, ubuntu-24.04)
- GitHub Check: ci (Testcontainers.BigQuery, ubuntu-24.04)
- GitHub Check: ci (Testcontainers.Azurite, ubuntu-24.04)
- GitHub Check: ci (Testcontainers.ArangoDb, ubuntu-24.04)
- GitHub Check: ci (Testcontainers.Bigtable, ubuntu-24.04)
- GitHub Check: ci (Testcontainers.ActiveMq, ubuntu-24.04)
- GitHub Check: ci (Testcontainers.Cassandra, ubuntu-24.04)
- GitHub Check: ci (Testcontainers.BigQuery, ubuntu-24.04)
- GitHub Check: ci (Testcontainers.Azurite, ubuntu-24.04)
- GitHub Check: ci (Testcontainers.ArangoDb, ubuntu-24.04)
- GitHub Check: ci (Testcontainers.Bigtable, ubuntu-24.04)
- GitHub Check: ci (Testcontainers.ActiveMq, ubuntu-24.04)
- GitHub Check: ci (Testcontainers.Cassandra, ubuntu-24.04)
- GitHub Check: ci (Testcontainers.BigQuery, ubuntu-24.04)
- GitHub Check: ci (Testcontainers.Azurite, ubuntu-24.04)
- GitHub Check: ci (Testcontainers.ArangoDb, ubuntu-24.04)
- GitHub Check: ci (Testcontainers.Bigtable, ubuntu-24.04)
- GitHub Check: ci (Testcontainers.ActiveMq, ubuntu-24.04)
- GitHub Check: ci (Testcontainers.Cassandra, ubuntu-24.04)
- GitHub Check: ci (Testcontainers.BigQuery, ubuntu-24.04)
- GitHub Check: ci (Testcontainers.Azurite, ubuntu-24.04)
- GitHub Check: ci (Testcontainers.ArangoDb, ubuntu-24.04)
- GitHub Check: ci (Testcontainers.Bigtable, ubuntu-24.04)
- GitHub Check: ci (Testcontainers.ActiveMq, ubuntu-24.04)
- GitHub Check: ci (Testcontainers.Cassandra, ubuntu-24.04)
- GitHub Check: ci (Testcontainers.BigQuery, ubuntu-24.04)
- GitHub Check: ci (Testcontainers.Azurite, ubuntu-24.04)
- GitHub Check: ci (Testcontainers.ArangoDb, ubuntu-24.04)
- GitHub Check: ci (Testcontainers.Bigtable, ubuntu-24.04)
- GitHub Check: ci (Testcontainers.ActiveMq, ubuntu-24.04)
- GitHub Check: ci (Testcontainers.Cassandra, ubuntu-24.04)
- GitHub Check: ci (Testcontainers.BigQuery, ubuntu-24.04)
- GitHub Check: ci (Testcontainers.Azurite, ubuntu-24.04)
- GitHub Check: ci (Testcontainers.ArangoDb, ubuntu-24.04)
- GitHub Check: ci (Testcontainers.Bigtable, ubuntu-24.04)
- GitHub Check: ci (Testcontainers.ActiveMq, ubuntu-24.04)
- GitHub Check: ci (Testcontainers.BigQuery, ubuntu-24.04)
- GitHub Check: ci (Testcontainers.ClickHouse, ubuntu-24.04)
- GitHub Check: ci (Testcontainers.Azurite, ubuntu-24.04)
- GitHub Check: ci (Testcontainers.ArangoDb, ubuntu-24.04)
- GitHub Check: ci (Testcontainers.Bigtable, ubuntu-24.04)
- GitHub Check: ci (Testcontainers.ActiveMq, ubuntu-24.04)
- GitHub Check: ci (Testcontainers.BigQuery, ubuntu-24.04)
🔇 Additional comments (7)
src/Testcontainers/Configurations/Containers/ConnectionStringProvider.cs (3)
1-9: LGTM! Clean adapter pattern setup.The class structure correctly implements the adapter pattern by wrapping a generic
IConnectionStringProvider<TContainerEntity, TConfigurationEntity>and exposing it asIConnectionStringProvider<IContainer, IContainerConfiguration>. The generic constraints are appropriate.
12-14: Past review comment has been addressed.The XML documentation now correctly references
ConnectionStringProvider{TContainerEntity, TConfigurationEntity}instead ofContainerConfiguration.
27-37: LGTM! Correct delegation pattern.Both
GetConnectionStringoverloads correctly delegate to the wrapped provider with no additional logic, which is appropriate for an adapter.docs/api/connection_string_provider.md (4)
1-8: LGTM! Clear introduction and appropriate expectations.The documentation clearly explains the purpose of the Connection String Provider API and sets proper expectations that modules will integrate this in future releases. The
!!!notesyntax is correct MkDocs admonition markup, despite the static analysis hint.
9-26: LGTM! Clear usage examples.The example effectively demonstrates the three primary ways to retrieve connection strings: implicit host mode (default), explicit host mode, and container-to-container mode. The code is easy to follow.
28-55: LGTM! Comprehensive implementation guide.The generic provider example clearly demonstrates how to implement
IConnectionStringProvider<IContainer, IContainerConfiguration>with helpful inline comments explaining the purpose of each method and whenConfigureis invoked.
57-76: LGTM! Good forward-looking example.The module-specific provider example effectively demonstrates how future module integrations will work with typed containers and configurations. While
PostgreSqlContainerandPostgreSqlConfigurationdon't exist yet, this example helps developers understand the intended pattern, and the note at the beginning of the document already explains that modules will integrate this in future releases.
| /// <inheritdoc /> | ||
| public void Configure(IContainer container, IContainerConfiguration configuration) | ||
| { | ||
| _connectionStringProvider.Configure((TContainerEntity)container, (TConfigurationEntity)configuration); | ||
| } |
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.
🧩 Analysis chain
Script executed:
#!/bin/bash
# Search for WithConnectionStringProvider to understand how it registers providers
rg -n -B 5 -A 15 'WithConnectionStringProvider' --type csRepository: testcontainers/testcontainers-dotnet
<shell_result>
Repository: testcontainers/testcontainers-dotnet
Exit code: 0
stdout:
src/Testcontainers/Builders/IContainerBuilder`2.cs-507- /// Sets the connection string provider.
src/Testcontainers/Builders/IContainerBuilder`2.cs-508- /// </summary>
src/Testcontainers/Builders/IContainerBuilder`2.cs-509- /// <param name="connectionStringProvider">The connection string provider.</param>
src/Testcontainers/Builders/IContainerBuilder`2.cs-510- /// <returns>A configured instance of <typeparamref name="TBuilderEntity" />.</returns>
src/Testcontainers/Builders/IContainerBuilder`2.cs-511- [PublicAPI]
src/Testcontainers/Builders/IContainerBuilder`2.cs:512: TBuilderEntity WithConnectionStringProvider(IConnectionStringProvider<TContainerEntity, TConfigurationEntity> connectionStringProvider);
src/Testcontainers/Builders/IContainerBuilder`2.cs-513- }
src/Testcontainers/Builders/IContainerBuilder`2.cs-514-}
--
src/Testcontainers/Builders/ContainerBuilder`3.cs-395- {
src/Testcontainers/Builders/ContainerBuilder`3.cs-396- return Clone(new ContainerConfiguration(startupCallback: (container, configuration, ct) => startupCallback((TContainerEntity)container, (TConfigurationEntity)configuration, ct)));
src/Testcontainers/Builders/ContainerBuilder`3.cs-397- }
src/Testcontainers/Builders/ContainerBuilder`3.cs-398-
src/Testcontainers/Builders/ContainerBuilder`3.cs-399- /// <inheritdoc />
src/Testcontainers/Builders/ContainerBuilder`3.cs:400: public TBuilderEntity WithConnectionStringProvider(IConnectionStringProvider<TContainerEntity, TConfigurationEntity> connectionStringProvider)
src/Testcontainers/Builders/ContainerBuilder`3.cs-401- {
src/Testcontainers/Builders/ContainerBuilder`3.cs-402- return Clone(new ContainerConfiguration(connectionStringProvider: new ConnectionStringProvider<TContainerEntity, TConfigurationEntity>(connectionStringProvider)));
src/Testcontainers/Builders/ContainerBuilder`3.cs-403- }
src/Testcontainers/Builders/ContainerBuilder`3.cs-404-
src/Testcontainers/Builders/ContainerBuilder`3.cs-405- /// <inheritdoc />
src/Testcontainers/Builders/ContainerBuilder`3.cs-406- protected override TBuilderEntity Init()
src/Testcontainers/Builders/ContainerBuilder`3.cs-407- {
src/Testcontainers/Builders/ContainerBuilder`3.cs-408- return base.Init().WithImagePullPolicy(PullPolicy.Missing).WithPortForwarding().WithOutputConsumer(Consume.DoNotConsumeStdoutAndStderr()).WithWaitStrategy(Wait.ForUnixContainer()).WithStartupCallback((_, _, _) => Task.CompletedTask);
src/Testcontainers/Builders/ContainerBuilder`3.cs-409- }
src/Testcontainers/Builders/ContainerBuilder`3.cs-410-
src/Testcontainers/Builders/ContainerBuilder`3.cs-411- /// <inheritdoc />
src/Testcontainers/Builders/ContainerBuilder`3.cs-412- protected override void Validate()
src/Testcontainers/Builders/ContainerBuilder`3.cs-413- {
src/Testcontainers/Builders/ContainerBuilder`3.cs-414- base.Validate();
src/Testcontainers/Builders/ContainerBuilder`3.cs-415-
--
tests/Testcontainers.Platform.Linux.Tests/ConnectionStringProviderTest.cs-11- public ConnectionStringProviderTests()
tests/Testcontainers.Platform.Linux.Tests/ConnectionStringProviderTest.cs-12- {
tests/Testcontainers.Platform.Linux.Tests/ConnectionStringProviderTest.cs-13- _container = new ContainerBuilder()
tests/Testcontainers.Platform.Linux.Tests/ConnectionStringProviderTest.cs-14- .WithImage(CommonImages.Alpine)
tests/Testcontainers.Platform.Linux.Tests/ConnectionStringProviderTest.cs-15- .WithCommand(CommonCommands.SleepInfinity)
tests/Testcontainers.Platform.Linux.Tests/ConnectionStringProviderTest.cs:16: .WithConnectionStringProvider(_connectionStringProvider)
tests/Testcontainers.Platform.Linux.Tests/ConnectionStringProviderTest.cs-17- .Build();
tests/Testcontainers.Platform.Linux.Tests/ConnectionStringProviderTest.cs-18- }
tests/Testcontainers.Platform.Linux.Tests/ConnectionStringProviderTest.cs-19-
tests/Testcontainers.Platform.Linux.Tests/ConnectionStringProviderTest.cs-20- public async ValueTask InitializeAsync()
tests/Testcontainers.Platform.Linux.Tests/ConnectionStringProviderTest.cs-21- {
tests/Testcontainers.Platform.Linux.Tests/ConnectionStringProviderTest.cs-22- await _container.StartAsync()
tests/Testcontainers.Platform.Linux.Tests/ConnectionStringProviderTest.cs-23- .ConfigureAwait(false);
tests/Testcontainers.Platform.Linux.Tests/ConnectionStringProviderTest.cs-24- }
tests/Testcontainers.Platform.Linux.Tests/ConnectionStringProviderTest.cs-25-
tests/Testcontainers.Platform.Linux.Tests/ConnectionStringProviderTest.cs-26- public async ValueTask DisposeAsync()
tests/Testcontainers.Platform.Linux.Tests/ConnectionStringProviderTest.cs-27- {
tests/Testcontainers.Platform.Linux.Tests/ConnectionStringProviderTest.cs-28- await _container.DisposeAsync()
tests/Testcontainers.Platform.Linux.Tests/ConnectionStringProviderTest.cs-29- .ConfigureAwait(false);
tests/Testcontainers.Platform.Linux.Tests/ConnectionStringProviderTest.cs-30- }
tests/Testcontainers.Platform.Linux.Tests/ConnectionStringProviderTest.cs-31-
</shell_result>
Script executed:
#!/bin/bash
# Search for the ConnectionStringProvider<TContainerEntity, TConfigurationEntity> class definition
rg -n -B 5 -A 20 'class ConnectionStringProvider' --type csRepository: testcontainers/testcontainers-dotnet
<shell_result>
Repository: testcontainers/testcontainers-dotnet
Exit code: 0
stdout:
tests/Testcontainers.Platform.Linux.Tests/ConnectionStringProviderTest.cs-1-namespace Testcontainers.Tests;
tests/Testcontainers.Platform.Linux.Tests/ConnectionStringProviderTest.cs-2-
tests/Testcontainers.Platform.Linux.Tests/ConnectionStringProviderTest.cs:3:public sealed class ConnectionStringProviderTests : IAsyncLifetime
tests/Testcontainers.Platform.Linux.Tests/ConnectionStringProviderTest.cs-4-{
tests/Testcontainers.Platform.Linux.Tests/ConnectionStringProviderTest.cs-5- private const string ExpectedConnectionString = "connection string";
tests/Testcontainers.Platform.Linux.Tests/ConnectionStringProviderTest.cs-6-
tests/Testcontainers.Platform.Linux.Tests/ConnectionStringProviderTest.cs-7- private readonly ConnectionStringProvider _connectionStringProvider = new ConnectionStringProvider();
tests/Testcontainers.Platform.Linux.Tests/ConnectionStringProviderTest.cs-8-
tests/Testcontainers.Platform.Linux.Tests/ConnectionStringProviderTest.cs-9- private readonly IContainer _container;
tests/Testcontainers.Platform.Linux.Tests/ConnectionStringProviderTest.cs-10-
tests/Testcontainers.Platform.Linux.Tests/ConnectionStringProviderTest.cs-11- public ConnectionStringProviderTests()
tests/Testcontainers.Platform.Linux.Tests/ConnectionStringProviderTest.cs-12- {
tests/Testcontainers.Platform.Linux.Tests/ConnectionStringProviderTest.cs-13- _container = new ContainerBuilder()
tests/Testcontainers.Platform.Linux.Tests/ConnectionStringProviderTest.cs-14- .WithImage(CommonImages.Alpine)
tests/Testcontainers.Platform.Linux.Tests/ConnectionStringProviderTest.cs-15- .WithCommand(CommonCommands.SleepInfinity)
tests/Testcontainers.Platform.Linux.Tests/ConnectionStringProviderTest.cs-16- .WithConnectionStringProvider(_connectionStringProvider)
tests/Testcontainers.Platform.Linux.Tests/ConnectionStringProviderTest.cs-17- .Build();
tests/Testcontainers.Platform.Linux.Tests/ConnectionStringProviderTest.cs-18- }
tests/Testcontainers.Platform.Linux.Tests/ConnectionStringProviderTest.cs-19-
tests/Testcontainers.Platform.Linux.Tests/ConnectionStringProviderTest.cs-20- public async ValueTask InitializeAsync()
tests/Testcontainers.Platform.Linux.Tests/ConnectionStringProviderTest.cs-21- {
tests/Testcontainers.Platform.Linux.Tests/ConnectionStringProviderTest.cs-22- await _container.StartAsync()
tests/Testcontainers.Platform.Linux.Tests/ConnectionStringProviderTest.cs-23- .ConfigureAwait(false);
--
tests/Testcontainers.Platform.Linux.Tests/ConnectionStringProviderTest.cs-35- Assert.True(_connectionStringProvider.IsConfigured, "Configure should have been called during container startup.");
tests/Testcontainers.Platform.Linux.Tests/ConnectionStringProviderTest.cs-36- Assert.Equal(ExpectedConnectionString, _container.GetConnectionString());
tests/Testcontainers.Platform.Linux.Tests/ConnectionStringProviderTest.cs-37- Assert.Equal(ExpectedConnectionString, _container.GetConnectionString("name"));
tests/Testcontainers.Platform.Linux.Tests/ConnectionStringProviderTest.cs-38- }
tests/Testcontainers.Platform.Linux.Tests/ConnectionStringProviderTest.cs-39-
tests/Testcontainers.Platform.Linux.Tests/ConnectionStringProviderTest.cs:40: private sealed class ConnectionStringProvider : IConnectionStringProvider<IContainer, IContainerConfiguration>
tests/Testcontainers.Platform.Linux.Tests/ConnectionStringProviderTest.cs-41- {
tests/Testcontainers.Platform.Linux.Tests/ConnectionStringProviderTest.cs-42- public bool IsConfigured { get; private set; }
tests/Testcontainers.Platform.Linux.Tests/ConnectionStringProviderTest.cs-43-
tests/Testcontainers.Platform.Linux.Tests/ConnectionStringProviderTest.cs-44- public void Configure(IContainer container, IContainerConfiguration configuration)
tests/Testcontainers.Platform.Linux.Tests/ConnectionStringProviderTest.cs-45- {
tests/Testcontainers.Platform.Linux.Tests/ConnectionStringProviderTest.cs-46- Assert.NotNull(container);
tests/Testcontainers.Platform.Linux.Tests/ConnectionStringProviderTest.cs-47- Assert.NotNull(configuration);
tests/Testcontainers.Platform.Linux.Tests/ConnectionStringProviderTest.cs-48- IsConfigured = true;
tests/Testcontainers.Platform.Linux.Tests/ConnectionStringProviderTest.cs-49- }
tests/Testcontainers.Platform.Linux.Tests/ConnectionStringProviderTest.cs-50-
tests/Testcontainers.Platform.Linux.Tests/ConnectionStringProviderTest.cs-51- public string GetConnectionString(ConnectionMode connectionMode = ConnectionMode.Host)
tests/Testcontainers.Platform.Linux.Tests/ConnectionStringProviderTest.cs-52- {
tests/Testcontainers.Platform.Linux.Tests/ConnectionStringProviderTest.cs-53- return ExpectedConnectionString;
tests/Testcontainers.Platform.Linux.Tests/ConnectionStringProviderTest.cs-54- }
tests/Testcontainers.Platform.Linux.Tests/ConnectionStringProviderTest.cs-55-
tests/Testcontainers.Platform.Linux.Tests/ConnectionStringProviderTest.cs-56- public string GetConnectionString(string name, ConnectionMode connectionMode = ConnectionMode.Host)
tests/Testcontainers.Platform.Linux.Tests/ConnectionStringProviderTest.cs-57- {
tests/Testcontainers.Platform.Linux.Tests/ConnectionStringProviderTest.cs-58- return ExpectedConnectionString;
tests/Testcontainers.Platform.Linux.Tests/ConnectionStringProviderTest.cs-59- }
tests/Testcontainers.Platform.Linux.Tests/ConnectionStringProviderTest.cs-60- }
--
src/Testcontainers/Containers/ConnectionStringProviderNotConfiguredException.cs-5-
src/Testcontainers/Containers/ConnectionStringProviderNotConfiguredException.cs-6- /// <summary>
src/Testcontainers/Containers/ConnectionStringProviderNotConfiguredException.cs-7- /// Represents an exception that is thrown when the connection string provider is not configured.
src/Testcontainers/Containers/ConnectionStringProviderNotConfiguredException.cs-8- /// </summary>
src/Testcontainers/Containers/ConnectionStringProviderNotConfiguredException.cs-9- [PublicAPI]
src/Testcontainers/Containers/ConnectionStringProviderNotConfiguredException.cs:10: public sealed class ConnectionStringProviderNotConfiguredException : Exception
src/Testcontainers/Containers/ConnectionStringProviderNotConfiguredException.cs-11- {
src/Testcontainers/Containers/ConnectionStringProviderNotConfiguredException.cs-12- /// <summary>
src/Testcontainers/Containers/ConnectionStringProviderNotConfiguredException.cs-13- /// Initializes a new instance of the <see cref="ConnectionStringProviderNotConfiguredException" /> class.
src/Testcontainers/Containers/ConnectionStringProviderNotConfiguredException.cs-14- /// </summary>
src/Testcontainers/Containers/ConnectionStringProviderNotConfiguredException.cs-15- public ConnectionStringProviderNotConfiguredException()
src/Testcontainers/Containers/ConnectionStringProviderNotConfiguredException.cs-16- : base("No connection string provider is configured for this container.")
src/Testcontainers/Containers/ConnectionStringProviderNotConfiguredException.cs-17- {
src/Testcontainers/Containers/ConnectionStringProviderNotConfiguredException.cs-18- }
src/Testcontainers/Containers/ConnectionStringProviderNotConfiguredException.cs-19- }
src/Testcontainers/Containers/ConnectionStringProviderNotConfiguredException.cs-20-}
--
src/Testcontainers/Configurations/Containers/ConnectionStringProvider.cs-1-namespace DotNet.Testcontainers.Configurations
src/Testcontainers/Configurations/Containers/ConnectionStringProvider.cs-2-{
src/Testcontainers/Configurations/Containers/ConnectionStringProvider.cs-3- using DotNet.Testcontainers.Containers;
src/Testcontainers/Configurations/Containers/ConnectionStringProvider.cs-4-
src/Testcontainers/Configurations/Containers/ConnectionStringProvider.cs-5- /// <inheritdoc cref="IConnectionStringProvider{TContainerEntity, TConfigurationEntity}" />
src/Testcontainers/Configurations/Containers/ConnectionStringProvider.cs:6: internal sealed class ConnectionStringProvider<TContainerEntity, TConfigurationEntity> : IConnectionStringProvider<IContainer, IContainerConfiguration>
src/Testcontainers/Configurations/Containers/ConnectionStringProvider.cs-7- where TContainerEntity : IContainer
src/Testcontainers/Configurations/Containers/ConnectionStringProvider.cs-8- where TConfigurationEntity : IContainerConfiguration
src/Testcontainers/Configurations/Containers/ConnectionStringProvider.cs-9- {
src/Testcontainers/Configurations/Containers/ConnectionStringProvider.cs-10- private readonly IConnectionStringProvider<TContainerEntity, TConfigurationEntity> _connectionStringProvider;
src/Testcontainers/Configurations/Containers/ConnectionStringProvider.cs-11-
src/Testcontainers/Configurations/Containers/ConnectionStringProvider.cs-12- /// <summary>
src/Testcontainers/Configurations/Containers/ConnectionStringProvider.cs-13- /// Initializes a new instance of the <see cref="ConnectionStringProvider{TContainerEntity, TConfigurationEntity}" /> class.
src/Testcontainers/Configurations/Containers/ConnectionStringProvider.cs-14- /// </summary>
src/Testcontainers/Configurations/Containers/ConnectionStringProvider.cs-15- /// <param name="connectionStringProvider">The connection string provider.</param>
src/Testcontainers/Configurations/Containers/ConnectionStringProvider.cs-16- public ConnectionStringProvider(IConnectionStringProvider<TContainerEntity, TConfigurationEntity> connectionStringProvider)
src/Testcontainers/Configurations/Containers/ConnectionStringProvider.cs-17- {
src/Testcontainers/Configurations/Containers/ConnectionStringProvider.cs-18- _connectionStringProvider = connectionStringProvider;
src/Testcontainers/Configurations/Containers/ConnectionStringProvider.cs-19- }
src/Testcontainers/Configurations/Containers/ConnectionStringProvider.cs-20-
src/Testcontainers/Configurations/Containers/ConnectionStringProvider.cs-21- /// <inheritdoc />
src/Testcontainers/Configurations/Containers/ConnectionStringProvider.cs-22- public void Configure(IContainer container, IContainerConfiguration configuration)
src/Testcontainers/Configurations/Containers/ConnectionStringProvider.cs-23- {
src/Testcontainers/Configurations/Containers/ConnectionStringProvider.cs-24- _connectionStringProvider.Configure((TContainerEntity)container, (TConfigurationEntity)configuration);
src/Testcontainers/Configurations/Containers/ConnectionStringProvider.cs-25- }
src/Testcontainers/Configurations/Containers/ConnectionStringProvider.cs-26-
</shell_result>
Script executed:
#!/bin/bash
# Search for where Configure is called - likely in container startup logic
rg -n 'configuration\.Configure' --type cs -B 3 -A 3Repository: testcontainers/testcontainers-dotnet
<shell_result>
Repository: testcontainers/testcontainers-dotnet
Exit code: 1
</shell_result>
Script executed:
#!/bin/bash
# Search for where IContainerConfiguration instances are used and Configure is called
rg -n '\.Configure\(' --type cs -B 2 -A 2 | head -100Repository: testcontainers/testcontainers-dotnet
<shell_result>
Repository: testcontainers/testcontainers-dotnet
Exit code: 0
stdout:
tests/Testcontainers.Db2.Tests/Db2ContainerTest.cs-50- {
tests/Testcontainers.Db2.Tests/Db2ContainerTest.cs-51- protected override Db2Builder Configure(Db2Builder builder)
tests/Testcontainers.Db2.Tests/Db2ContainerTest.cs:52: => base.Configure(builder).WithWaitStrategy(Wait.ForUnixContainer().UntilDatabaseIsAvailable(DbProviderFactory));
tests/Testcontainers.Db2.Tests/Db2ContainerTest.cs-53- }
tests/Testcontainers.Db2.Tests/Db2ContainerTest.cs-54-
--
src/Testcontainers/Configurations/Containers/ConnectionStringProvider.cs-22- public void Configure(IContainer container, IContainerConfiguration configuration)
src/Testcontainers/Configurations/Containers/ConnectionStringProvider.cs-23- {
src/Testcontainers/Configurations/Containers/ConnectionStringProvider.cs:24: _connectionStringProvider.Configure((TContainerEntity)container, (TConfigurationEntity)configuration);
src/Testcontainers/Configurations/Containers/ConnectionStringProvider.cs-25- }
src/Testcontainers/Configurations/Containers/ConnectionStringProvider.cs-26-
--
src/Testcontainers/Containers/DockerContainer.cs-589- {
src/Testcontainers/Containers/DockerContainer.cs-590- _connectionStringProvider = _configuration.ConnectionStringProvider;
src/Testcontainers/Containers/DockerContainer.cs:591: _connectionStringProvider.Configure(this, _configuration);
src/Testcontainers/Containers/DockerContainer.cs-592- }
src/Testcontainers/Containers/DockerContainer.cs-593-
</shell_result>
Script executed:
#!/bin/bash
# Get the Container class definition to understand the relationship with configurations
sed -n '140,160p' src/Testcontainers/Containers/Container.csRepository: testcontainers/testcontainers-dotnet
<shell_result>
Repository: testcontainers/testcontainers-dotnet
Exit code: 2
stderr:
sed: can't read src/Testcontainers/Containers/Container.cs: No such file or directory
</shell_result>
Script executed:
#!/bin/bash
# Check Container class and how _configurations is populated
rg -n 'class Container' --type cs -A 30Repository: testcontainers/testcontainers-dotnet
<shell_result>
Repository: testcontainers/testcontainers-dotnet
Exit code: 0
stdout:
src/Testcontainers/Clients/ContainerConfigurationConverter.cs:11: internal sealed class ContainerConfigurationConverter
src/Testcontainers/Clients/ContainerConfigurationConverter.cs-12- {
src/Testcontainers/Clients/ContainerConfigurationConverter.cs-13- private const string UdpProtocolSuffix = "/udp";
src/Testcontainers/Clients/ContainerConfigurationConverter.cs-14-
src/Testcontainers/Clients/ContainerConfigurationConverter.cs-15- private const string TcpProtocolSuffix = "/tcp";
src/Testcontainers/Clients/ContainerConfigurationConverter.cs-16-
src/Testcontainers/Clients/ContainerConfigurationConverter.cs-17- private const string SctpProtocolSuffix = "/sctp";
src/Testcontainers/Clients/ContainerConfigurationConverter.cs-18-
src/Testcontainers/Clients/ContainerConfigurationConverter.cs-19- private static readonly string[] Protocols = new[] { UdpProtocolSuffix, TcpProtocolSuffix, SctpProtocolSuffix };
src/Testcontainers/Clients/ContainerConfigurationConverter.cs-20-
src/Testcontainers/Clients/ContainerConfigurationConverter.cs-21- public ContainerConfigurationConverter(IContainerConfiguration configuration)
src/Testcontainers/Clients/ContainerConfigurationConverter.cs-22- {
src/Testcontainers/Clients/ContainerConfigurationConverter.cs-23- Entrypoint = new ToCollection().Convert(configuration.Entrypoint)?.ToList();
src/Testcontainers/Clients/ContainerConfigurationConverter.cs-24- Command = new ToCollection().Convert(configuration.Command)?.ToList();
src/Testcontainers/Clients/ContainerConfigurationConverter.cs-25- ExtraHosts = new ToCollection().Convert(configuration.ExtraHosts)?.ToList();
src/Testcontainers/Clients/ContainerConfigurationConverter.cs-26- Environments = new ToMappedList().Convert(configuration.Environments)?.ToList();
src/Testcontainers/Clients/ContainerConfigurationConverter.cs-27- Labels = new ToDictionary().Convert(configuration.Labels)?.ToDictionary(item => item.Key, item => item.Value);
src/Testcontainers/Clients/ContainerConfigurationConverter.cs-28- ExposedPorts = new ToExposedPorts().Convert(configuration.ExposedPorts)?.ToDictionary(item => item.Key, item => item.Value);
src/Testcontainers/Clients/ContainerConfigurationConverter.cs-29- PortBindings = new ToPortBindings().Convert(configuration.PortBindings)?.ToDictionary(item => item.Key, item => item.Value);
src/Testcontainers/Clients/ContainerConfigurationConverter.cs-30- Mounts = new ToMounts().Convert(configuration.Mounts)?.ToList();
src/Testcontainers/Clients/ContainerConfigurationConverter.cs-31- Networks = new ToNetworks(configuration).Convert(configuration.Networks)?.ToDictionary(item => item.Key, item => item.Value);
src/Testcontainers/Clients/ContainerConfigurationConverter.cs-32- }
src/Testcontainers/Clients/ContainerConfigurationConverter.cs-33-
src/Testcontainers/Clients/ContainerConfigurationConverter.cs-34- public IList<string> Entrypoint { get; }
src/Testcontainers/Clients/ContainerConfigurationConverter.cs-35-
src/Testcontainers/Clients/ContainerConfigurationConverter.cs-36- public IList<string> Command { get; }
src/Testcontainers/Clients/ContainerConfigurationConverter.cs-37-
src/Testcontainers/Clients/ContainerConfigurationConverter.cs-38- public IList<string> ExtraHosts { get; }
src/Testcontainers/Clients/ContainerConfigurationConverter.cs-39-
src/Testcontainers/Clients/ContainerConfigurationConverter.cs-40- public IList<string> Environments { get; }
src/Testcontainers/Clients/ContainerConfigurationConverter.cs-41-
--
src/Testcontainers/Containers/ContainerNotRunningException.cs:13: public sealed class ContainerNotRunningException : Exception
src/Testcontainers/Containers/ContainerNotRunningException.cs-14- {
src/Testcontainers/Containers/ContainerNotRunningException.cs-15- private static readonly string[] LineEndings = new[] { "\r\n", "\n" };
src/Testcontainers/Containers/ContainerNotRunningException.cs-16-
src/Testcontainers/Containers/ContainerNotRunningException.cs-17- /// <summary>
src/Testcontainers/Containers/ContainerNotRunningException.cs-18- /// Initializes a new instance of the <see cref="ContainerNotRunningException" /> class.
src/Testcontainers/Containers/ContainerNotRunningException.cs-19- /// </summary>
src/Testcontainers/Containers/ContainerNotRunningException.cs-20- /// <param name="id">The container id.</param>
src/Testcontainers/Containers/ContainerNotRunningException.cs-21- /// <param name="stdout">The stdout.</param>
src/Testcontainers/Containers/ContainerNotRunningException.cs-22- /// <param name="stderr">The stderr.</param>
src/Testcontainers/Containers/ContainerNotRunningException.cs-23- /// <param name="exitCode">The exit code.</param>
src/Testcontainers/Containers/ContainerNotRunningException.cs-24- /// <param name="exception">The inner exception.</param>
src/Testcontainers/Containers/ContainerNotRunningException.cs-25- public ContainerNotRunningException(string id, string stdout, string stderr, long exitCode, [CanBeNull] Exception exception)
src/Testcontainers/Containers/ContainerNotRunningException.cs-26- : base(CreateMessage(id, stdout, stderr, exitCode), exception)
src/Testcontainers/Containers/ContainerNotRunningException.cs-27- {
src/Testcontainers/Containers/ContainerNotRunningException.cs-28- }
src/Testcontainers/Containers/ContainerNotRunningException.cs-29-
src/Testcontainers/Containers/ContainerNotRunningException.cs-30- private static string CreateMessage(string id, string stdout, string stderr, long exitCode)
src/Testcontainers/Containers/ContainerNotRunningException.cs-31- {
src/Testcontainers/Containers/ContainerNotRunningException.cs-32- var exceptionInfo = new StringBuilder(256);
src/Testcontainers/Containers/ContainerNotRunningException.cs-33- exceptionInfo.Append($"Container {id} exited with code {exitCode}.");
src/Testcontainers/Containers/ContainerNotRunningException.cs-34-
src/Testcontainers/Containers/ContainerNotRunningException.cs-35- if (!string.IsNullOrEmpty(stdout))
src/Testcontainers/Containers/ContainerNotRunningException.cs-36- {
src/Testcontainers/Containers/ContainerNotRunningException.cs-37- var stdoutLines = stdout
src/Testcontainers/Containers/ContainerNotRunningException.cs-38- .Split(LineEndings, StringSplitOptions.RemoveEmptyEntries)
src/Testcontainers/Containers/ContainerNotRunningException.cs-39- .Select(line => " " + line);
src/Testcontainers/Containers/ContainerNotRunningException.cs-40-
src/Testcontainers/Containers/ContainerNotRunningException.cs-41- exceptionInfo.AppendLine();
src/Testcontainers/Containers/ContainerNotRunningException.cs-42- exceptionInfo.AppendLine(" Stdout: ");
src/Testcontainers/Containers/ContainerNotRunningException.cs-43- exceptionInfo.Append(string.Join(Environment.NewLine, stdoutLines));
--
src/Testcontainers/Configurations/Containers/ContainerConfiguration.cs:17: public class ContainerConfiguration : ResourceConfiguration<CreateContainerParameters>, IContainerConfiguration
src/Testcontainers/Configurations/Containers/ContainerConfiguration.cs-18- {
src/Testcontainers/Configurations/Containers/ContainerConfiguration.cs-19- /// <summary>
src/Testcontainers/Configurations/Containers/ContainerConfiguration.cs-20- /// Initializes a new instance of the <see cref="ContainerConfiguration" /> class.
src/Testcontainers/Configurations/Containers/ContainerConfiguration.cs-21- /// </summary>
src/Testcontainers/Configurations/Containers/ContainerConfiguration.cs-22- /// <param name="image">The image.</param>
src/Testcontainers/Configurations/Containers/ContainerConfiguration.cs-23- /// <param name="imagePullPolicy">The image pull policy.</param>
src/Testcontainers/Configurations/Containers/ContainerConfiguration.cs-24- /// <param name="name">The name.</param>
src/Testcontainers/Configurations/Containers/ContainerConfiguration.cs-25- /// <param name="hostname">The hostname.</param>
src/Testcontainers/Configurations/Containers/ContainerConfiguration.cs-26- /// <param name="macAddress">The MAC address.</param>
src/Testcontainers/Configurations/Containers/ContainerConfiguration.cs-27- /// <param name="workingDirectory">The working directory.</param>
src/Testcontainers/Configurations/Containers/ContainerConfiguration.cs-28- /// <param name="entrypoint">The entrypoint.</param>
src/Testcontainers/Configurations/Containers/ContainerConfiguration.cs-29- /// <param name="command">The command.</param>
src/Testcontainers/Configurations/Containers/ContainerConfiguration.cs-30- /// <param name="environments">A dictionary of environment variables.</param>
src/Testcontainers/Configurations/Containers/ContainerConfiguration.cs-31- /// <param name="exposedPorts">A dictionary of exposed ports.</param>
src/Testcontainers/Configurations/Containers/ContainerConfiguration.cs-32- /// <param name="portBindings">A dictionary of port bindings.</param>
src/Testcontainers/Configurations/Containers/ContainerConfiguration.cs-33- /// <param name="resourceMappings">A list of resource mappings.</param>
src/Testcontainers/Configurations/Containers/ContainerConfiguration.cs-34- /// <param name="containers">A list of containers.</param>
src/Testcontainers/Configurations/Containers/ContainerConfiguration.cs-35- /// <param name="mounts">A list of mounts.</param>
src/Testcontainers/Configurations/Containers/ContainerConfiguration.cs-36- /// <param name="networks">A list of networks.</param>
src/Testcontainers/Configurations/Containers/ContainerConfiguration.cs-37- /// <param name="networkAliases">A list of network-scoped aliases.</param>
src/Testcontainers/Configurations/Containers/ContainerConfiguration.cs-38- /// <param name="extraHosts">A list of extra hosts.</param>
src/Testcontainers/Configurations/Containers/ContainerConfiguration.cs-39- /// <param name="outputConsumer">The output consumer.</param>
src/Testcontainers/Configurations/Containers/ContainerConfiguration.cs-40- /// <param name="waitStrategies">The wait strategies.</param>
src/Testcontainers/Configurations/Containers/ContainerConfiguration.cs-41- /// <param name="startupCallback">The startup callback.</param>
src/Testcontainers/Configurations/Containers/ContainerConfiguration.cs-42- /// <param name="autoRemove">A value indicating whether Docker removes the container after it exits or not.</param>
src/Testcontainers/Configurations/Containers/ContainerConfiguration.cs-43- /// <param name="privileged">A value indicating whether the privileged flag is set or not.</param>
src/Testcontainers/Configurations/Containers/ContainerConfiguration.cs-44- public ContainerConfiguration(
src/Testcontainers/Configurations/Containers/ContainerConfiguration.cs-45- IImage image = null,
src/Testcontainers/Configurations/Containers/ContainerConfiguration.cs-46- Func<ImageInspectResponse, bool> imagePullPolicy = null,
src/Testcontainers/Configurations/Containers/ContainerConfiguration.cs-47- string name = null,
--
src/Testcontainers.Xunit/ContainerTest.cs:12:public abstract class ContainerTest<TBuilderEntity, TContainerEntity>(ITestOutputHelper testOutputHelper, Func<TBuilderEntity, TBuilderEntity> configure = null)
src/Testcontainers.Xunit/ContainerTest.cs-13- : ContainerLifetime<TBuilderEntity, TContainerEntity>(new TestOutputLogger(testOutputHelper))
src/Testcontainers.Xunit/ContainerTest.cs-14- where TBuilderEntity : IContainerBuilder<TBuilderEntity, TContainerEntity, IContainerConfiguration>, new()
src/Testcontainers.Xunit/ContainerTest.cs-15- where TContainerEntity : IContainer
src/Testcontainers.Xunit/ContainerTest.cs-16-{
src/Testcontainers.Xunit/ContainerTest.cs-17- protected override TBuilderEntity Configure(TBuilderEntity builder) => configure != null ? configure(builder) : builder;
src/Testcontainers.Xunit/ContainerTest.cs-18-}
--
src/Testcontainers.Xunit/ContainerFixture.cs:12:public class ContainerFixture<TBuilderEntity, TContainerEntity>(IMessageSink messageSink)
src/Testcontainers.Xunit/ContainerFixture.cs-13- : ContainerLifetime<TBuilderEntity, TContainerEntity>(new MessageSinkLogger(messageSink))
src/Testcontainers.Xunit/ContainerFixture.cs-14- where TBuilderEntity : IContainerBuilder<TBuilderEntity, TContainerEntity, IContainerConfiguration>, new()
src/Testcontainers.Xunit/ContainerFixture.cs-15- where TContainerEntity : IContainer;
--
src/Testcontainers.Xunit/ContainerLifetime.cs:8:public abstract class ContainerLifetime<TBuilderEntity, TContainerEntity> : IAsyncLifetime
src/Testcontainers.Xunit/ContainerLifetime.cs-9- where TBuilderEntity : IContainerBuilder<TBuilderEntity, TContainerEntity, IContainerConfiguration>, new()
src/Testcontainers.Xunit/ContainerLifetime.cs-10- where TContainerEntity : IContainer
src/Testcontainers.Xunit/ContainerLifetime.cs-11-{
src/Testcontainers.Xunit/ContainerLifetime.cs-12- private readonly Lazy<TContainerEntity> _container;
src/Testcontainers.Xunit/ContainerLifetime.cs-13-
src/Testcontainers.Xunit/ContainerLifetime.cs-14- [CanBeNull]
src/Testcontainers.Xunit/ContainerLifetime.cs-15- private ExceptionDispatchInfo _exception;
src/Testcontainers.Xunit/ContainerLifetime.cs-16-
src/Testcontainers.Xunit/ContainerLifetime.cs-17- protected ContainerLifetime(ILogger logger)
src/Testcontainers.Xunit/ContainerLifetime.cs-18- {
src/Testcontainers.Xunit/ContainerLifetime.cs-19- _container = new Lazy<TContainerEntity>(() => Configure(new TBuilderEntity().WithLogger(logger)).Build());
src/Testcontainers.Xunit/ContainerLifetime.cs-20- }
src/Testcontainers.Xunit/ContainerLifetime.cs-21-
src/Testcontainers.Xunit/ContainerLifetime.cs-22- /// <summary>
src/Testcontainers.Xunit/ContainerLifetime.cs-23- /// Gets the container instance.
src/Testcontainers.Xunit/ContainerLifetime.cs-24- /// </summary>
src/Testcontainers.Xunit/ContainerLifetime.cs-25- public TContainerEntity Container
src/Testcontainers.Xunit/ContainerLifetime.cs-26- {
src/Testcontainers.Xunit/ContainerLifetime.cs-27- get
src/Testcontainers.Xunit/ContainerLifetime.cs-28- {
src/Testcontainers.Xunit/ContainerLifetime.cs-29- _exception?.Throw();
src/Testcontainers.Xunit/ContainerLifetime.cs-30- return _container.Value;
src/Testcontainers.Xunit/ContainerLifetime.cs-31- }
src/Testcontainers.Xunit/ContainerLifetime.cs-32- }
src/Testcontainers.Xunit/ContainerLifetime.cs-33-
src/Testcontainers.Xunit/ContainerLifetime.cs-34- /// <inheritdoc />
src/Testcontainers.Xunit/ContainerLifetime.cs-35- LifetimeTask IAsyncLifetime.InitializeAsync() => InitializeAsync();
src/Testcontainers.Xunit/ContainerLifetime.cs-36-
src/Testcontainers.Xunit/ContainerLifetime.cs-37-#if !XUNIT_V3
src/Testcontainers.Xunit/ContainerLifetime.cs-38- /// <inheritdoc />
--
src/Testcontainers/Builders/ContainerBuilder.cs:29: public class ContainerBuilder : ContainerBuilder<ContainerBuilder, IContainer, IContainerConfiguration>
src/Testcontainers/Builders/ContainerBuilder.cs-30- {
src/Testcontainers/Builders/ContainerBuilder.cs-31- /// <summary>
src/Testcontainers/Builders/ContainerBuilder.cs-32- /// Initializes a new instance of the <see cref="ContainerBuilder" /> class.
src/Testcontainers/Builders/ContainerBuilder.cs-33- /// </summary>
src/Testcontainers/Builders/ContainerBuilder.cs-34- public ContainerBuilder()
src/Testcontainers/Builders/ContainerBuilder.cs-35- : this(new ContainerConfiguration())
src/Testcontainers/Builders/ContainerBuilder.cs-36- {
src/Testcontainers/Builders/ContainerBuilder.cs-37- DockerResourceConfiguration = Init().DockerResourceConfiguration;
src/Testcontainers/Builders/ContainerBuilder.cs-38- }
src/Testcontainers/Builders/ContainerBuilder.cs-39-
src/Testcontainers/Builders/ContainerBuilder.cs-40- /// <summary>
src/Testcontainers/Builders/ContainerBuilder.cs-41- /// Initializes a new instance of the <see cref="ContainerBuilder" /> class.
src/Testcontainers/Builders/ContainerBuilder.cs-42- /// </summary>
src/Testcontainers/Builders/ContainerBuilder.cs-43- /// <param name="dockerResourceConfiguration">The Docker resource configuration.</param>
src/Testcontainers/Builders/ContainerBuilder.cs-44- protected ContainerBuilder(IContainerConfiguration dockerResourceConfiguration)
src/Testcontainers/Builders/ContainerBuilder.cs-45- : base(dockerResourceConfiguration)
src/Testcontainers/Builders/ContainerBuilder.cs-46- {
src/Testcontainers/Builders/ContainerBuilder.cs-47- DockerResourceConfiguration = dockerResourceConfiguration;
src/Testcontainers/Builders/ContainerBuilder.cs-48- }
src/Testcontainers/Builders/ContainerBuilder.cs-49-
src/Testcontainers/Builders/ContainerBuilder.cs-50- /// <inheritdoc />
src/Testcontainers/Builders/ContainerBuilder.cs-51- protected override IContainerConfiguration DockerResourceConfiguration { get; }
src/Testcontainers/Builders/ContainerBuilder.cs-52-
src/Testcontainers/Builders/ContainerBuilder.cs-53- /// <inheritdoc />
src/Testcontainers/Builders/ContainerBuilder.cs-54- public override IContainer Build()
src/Testcontainers/Builders/ContainerBuilder.cs-55- {
src/Testcontainers/Builders/ContainerBuilder.cs-56- Validate();
src/Testcontainers/Builders/ContainerBuilder.cs-57- return new DockerContainer(DockerResourceConfiguration);
src/Testcontainers/Builders/ContainerBuilder.cs-58- }
src/Testcontainers/Builders/ContainerBuilder.cs-59-
--
src/Testcontainers/Builders/ContainerBuilder`3.cs:25: public abstract class ContainerBuilder<TBuilderEntity, TContainerEntity, TConfigurationEntity> : AbstractBuilder<TBuilderEntity, TContainerEntity, CreateContainerParameters, TConfigurationEntity>, IContainerBuilder<TBuilderEntity, TContainerEntity, TConfigurationEntity>
src/Testcontainers/Builders/ContainerBuilder`3.cs-26- where TBuilderEntity : ContainerBuilder<TBuilderEntity, TContainerEntity, TConfigurationEntity>
src/Testcontainers/Builders/ContainerBuilder`3.cs-27- where TContainerEntity : IContainer
src/Testcontainers/Builders/ContainerBuilder`3.cs-28- where TConfigurationEntity : IContainerConfiguration
src/Testcontainers/Builders/ContainerBuilder`3.cs-29- {
src/Testcontainers/Builders/ContainerBuilder`3.cs-30- /// <summary>
src/Testcontainers/Builders/ContainerBuilder`3.cs-31- /// Initializes a new instance of the <see cref="ContainerBuilder{TBuilderEntity, TContainerEntity, TConfigurationEntity}" /> class.
src/Testcontainers/Builders/ContainerBuilder`3.cs-32- /// </summary>
src/Testcontainers/Builders/ContainerBuilder`3.cs-33- /// <param name="dockerResourceConfiguration">The Docker resource configuration.</param>
src/Testcontainers/Builders/ContainerBuilder`3.cs-34- protected ContainerBuilder(TConfigurationEntity dockerResourceConfiguration)
src/Testcontainers/Builders/ContainerBuilder`3.cs-35- : base(dockerResourceConfiguration)
src/Testcontainers/Builders/ContainerBuilder`3.cs-36- {
src/Testcontainers/Builders/ContainerBuilder`3.cs-37- }
src/Testcontainers/Builders/ContainerBuilder`3.cs-38-
src/Testcontainers/Builders/ContainerBuilder`3.cs-39- /// <summary>
src/Testcontainers/Builders/ContainerBuilder`3.cs-40- /// Gets the name of the environment variable that must be set to accept the image license agreement.
src/Testcontainers/Builders/ContainerBuilder`3.cs-41- /// </summary>
src/Testcontainers/Builders/ContainerBuilder`3.cs-42- protected virtual string AcceptLicenseAgreementEnvVar { get; }
src/Testcontainers/Builders/ContainerBuilder`3.cs-43-
src/Testcontainers/Builders/ContainerBuilder`3.cs-44- /// <summary>
src/Testcontainers/Builders/ContainerBuilder`3.cs-45- /// Gets the expected value of <see cref="AcceptLicenseAgreementEnvVar" /> that indicates acceptance of the license agreement.
src/Testcontainers/Builders/ContainerBuilder`3.cs-46- /// </summary>
src/Testcontainers/Builders/ContainerBuilder`3.cs-47- protected virtual string AcceptLicenseAgreement { get; }
src/Testcontainers/Builders/ContainerBuilder`3.cs-48-
src/Testcontainers/Builders/ContainerBuilder`3.cs-49- /// <summary>
src/Testcontainers/Builders/ContainerBuilder`3.cs-50- /// Gets the expected value of <see cref="AcceptLicenseAgreementEnvVar" /> that indicates rejection of the license agreement.
src/Testcontainers/Builders/ContainerBuilder`3.cs-51- /// </summary>
src/Testcontainers/Builders/ContainerBuilder`3.cs-52- protected virtual string DeclineLicenseAgreement { get; }
src/Testcontainers/Builders/ContainerBuilder`3.cs-53-
src/Testcontainers/Builders/ContainerBuilder`3.cs-54- /// <inheritdoc />
src/Testcontainers/Builders/ContainerBuilder`3.cs-55- public virtual TBuilderEntity WithAcceptLicenseAgreement(bool acceptLicenseAgreement)
--
tests/Testcontainers.Tests/Unit/Clients/ContainerConfigurationConverterTest.cs:9: public static class ContainerConfigurationConverterTest
tests/Testcontainers.Tests/Unit/Clients/ContainerConfigurationConverterTest.cs-10- {
tests/Testcontainers.Tests/Unit/Clients/ContainerConfigurationConverterTest.cs-11- private const string Port = "2375";
tests/Testcontainers.Tests/Unit/Clients/ContainerConfigurationConverterTest.cs-12-
tests/Testcontainers.Tests/Unit/Clients/ContainerConfigurationConverterTest.cs-13- public sealed class ExposedPorts
tests/Testcontainers.Tests/Unit/Clients/ContainerConfigurationConverterTest.cs-14- {
tests/Testcontainers.Tests/Unit/Clients/ContainerConfigurationConverterTest.cs-15- [Fact]
tests/Testcontainers.Tests/Unit/Clients/ContainerConfigurationConverterTest.cs-16- public void ShouldAddTcpPortSuffix()
tests/Testcontainers.Tests/Unit/Clients/ContainerConfigurationConverterTest.cs-17- {
tests/Testcontainers.Tests/Unit/Clients/ContainerConfigurationConverterTest.cs-18- // Given
tests/Testcontainers.Tests/Unit/Clients/ContainerConfigurationConverterTest.cs-19- var containerConfiguration = new ContainerConfiguration(exposedPorts: new Dictionary<string, string> { { Port, null } });
tests/Testcontainers.Tests/Unit/Clients/ContainerConfigurationConverterTest.cs-20-
tests/Testcontainers.Tests/Unit/Clients/ContainerConfigurationConverterTest.cs-21- // When
tests/Testcontainers.Tests/Unit/Clients/ContainerConfigurationConverterTest.cs-22- var exposedPort = new ContainerConfigurationConverter(containerConfiguration).ExposedPorts.Single().Key;
tests/Testcontainers.Tests/Unit/Clients/ContainerConfigurationConverterTest.cs-23-
tests/Testcontainers.Tests/Unit/Clients/ContainerConfigurationConverterTest.cs-24- // Then
tests/Testcontainers.Tests/Unit/Clients/ContainerConfigurationConverterTest.cs-25- Assert.Equal($"{Port}/tcp", exposedPort);
tests/Testcontainers.Tests/Unit/Clients/ContainerConfigurationConverterTest.cs-26- }
tests/Testcontainers.Tests/Unit/Clients/ContainerConfigurationConverterTest.cs-27-
tests/Testcontainers.Tests/Unit/Clients/ContainerConfigurationConverterTest.cs-28- [Theory]
tests/Testcontainers.Tests/Unit/Clients/ContainerConfigurationConverterTest.cs-29- [InlineData("UDP")]
tests/Testcontainers.Tests/Unit/Clients/ContainerConfigurationConverterTest.cs-30- [InlineData("TCP")]
tests/Testcontainers.Tests/Unit/Clients/ContainerConfigurationConverterTest.cs-31- [InlineData("SCTP")]
tests/Testcontainers.Tests/Unit/Clients/ContainerConfigurationConverterTest.cs-32- public void ShouldKeepPortSuffix(string portSuffix)
tests/Testcontainers.Tests/Unit/Clients/ContainerConfigurationConverterTest.cs-33- {
tests/Testcontainers.Tests/Unit/Clients/ContainerConfigurationConverterTest.cs-34- // Given
tests/Testcontainers.Tests/Unit/Clients/ContainerConfigurationConverterTest.cs-35- var qualifiedPort = $"{Port}/{portSuffix}";
tests/Testcontainers.Tests/Unit/Clients/ContainerConfigurationConverterTest.cs-36-
tests/Testcontainers.Tests/Unit/Clients/ContainerConfigurationConverterTest.cs-37- var containerConfiguration = new ContainerConfiguration(exposedPorts: new Dictionary<string, string> { { qualifiedPort, null } });
tests/Testcontainers.Tests/Unit/Clients/ContainerConfigurationConverterTest.cs-38-
tests/Testcontainers.Tests/Unit/Clients/ContainerConfigurationConverterTest.cs-39- // When
--
tests/Testcontainers.Platform.Linux.Tests/ContainerNotRunningExceptionTest.cs:3:public sealed class ContainerNotRunningExceptionTest
tests/Testcontainers.Platform.Linux.Tests/ContainerNotRunningExceptionTest.cs-4-{
tests/Testcontainers.Platform.Linux.Tests/ContainerNotRunningExceptionTest.cs-5- public static TheoryData<ContainerInfoSerializable, string> ContainerTestData { get; }
tests/Testcontainers.Platform.Linux.Tests/ContainerNotRunningExceptionTest.cs-6- = new TheoryData<ContainerInfoSerializable, string>
tests/Testcontainers.Platform.Linux.Tests/ContainerNotRunningExceptionTest.cs-7- {
tests/Testcontainers.Platform.Linux.Tests/ContainerNotRunningExceptionTest.cs-8- {
tests/Testcontainers.Platform.Linux.Tests/ContainerNotRunningExceptionTest.cs-9- new ContainerInfoSerializable("container-id", "Stdout\nStdout", "Stderr\nStderr", 1),
tests/Testcontainers.Platform.Linux.Tests/ContainerNotRunningExceptionTest.cs-10- "Container container-id exited with code 1." + Environment.NewLine +
tests/Testcontainers.Platform.Linux.Tests/ContainerNotRunningExceptionTest.cs-11- " Stdout: " + Environment.NewLine +
tests/Testcontainers.Platform.Linux.Tests/ContainerNotRunningExceptionTest.cs-12- " Stdout" + Environment.NewLine +
tests/Testcontainers.Platform.Linux.Tests/ContainerNotRunningExceptionTest.cs-13- " Stdout" + Environment.NewLine +
tests/Testcontainers.Platform.Linux.Tests/ContainerNotRunningExceptionTest.cs-14- " Stderr: " + Environment.NewLine +
tests/Testcontainers.Platform.Linux.Tests/ContainerNotRunningExceptionTest.cs-15- " Stderr" + Environment.NewLine +
tests/Testcontainers.Platform.Linux.Tests/ContainerNotRunningExceptionTest.cs-16- " Stderr"
tests/Testcontainers.Platform.Linux.Tests/ContainerNotRunningExceptionTest.cs-17- },
tests/Testcontainers.Platform.Linux.Tests/ContainerNotRunningExceptionTest.cs-18- {
tests/Testcontainers.Platform.Linux.Tests/ContainerNotRunningExceptionTest.cs-19- new ContainerInfoSerializable("container-id", "Stdout\nStdout", string.Empty, 1),
tests/Testcontainers.Platform.Linux.Tests/ContainerNotRunningExceptionTest.cs-20- "Container container-id exited with code 1." + Environment.NewLine +
tests/Testcontainers.Platform.Linux.Tests/ContainerNotRunningExceptionTest.cs-21- " Stdout: " + Environment.NewLine +
tests/Testcontainers.Platform.Linux.Tests/ContainerNotRunningExceptionTest.cs-22- " Stdout" + Environment.NewLine +
tests/Testcontainers.Platform.Linux.Tests/ContainerNotRunningExceptionTest.cs-23- " Stdout"
tests/Testcontainers.Platform.Linux.Tests/ContainerNotRunningExceptionTest.cs-24- },
tests/Testcontainers.Platform.Linux.Tests/ContainerNotRunningExceptionTest.cs-25- {
tests/Testcontainers.Platform.Linux.Tests/ContainerNotRunningExceptionTest.cs-26- new ContainerInfoSerializable("container-id", string.Empty, "Stderr\nStderr", 1),
tests/Testcontainers.Platform.Linux.Tests/ContainerNotRunningExceptionTest.cs-27- "Container container-id exited with code 1." + Environment.NewLine +
tests/Testcontainers.Platform.Linux.Tests/ContainerNotRunningExceptionTest.cs-28- " Stderr: " + Environment.NewLine +
tests/Testcontainers.Platform.Linux.Tests/ContainerNotRunningExceptionTest.cs-29- " Stderr" + Environment.NewLine +
tests/Testcontainers.Platform.Linux.Tests/ContainerNotRunningExceptionTest.cs-30- " Stderr"
tests/Testcontainers.Platform.Linux.Tests/ContainerNotRunningExceptionTest.cs-31- },
tests/Testcontainers.Platform.Linux.Tests/ContainerNotRunningExceptionTest.cs-32- {
tests/Testcontainers.Platform.Linux.Tests/ContainerNotRunningExceptionTest.cs-33- new ContainerInfoSerializable("container-id", string.Empty, string.Empty, 1),
--
tests/Testcontainers.Platform.Linux.Tests/ContainerNotRunningExceptionTest.cs:53: public sealed class ContainerInfoSerializable : IXunitSerializable
tests/Testcontainers.Platform.Linux.Tests/ContainerNotRunningExceptionTest.cs-54- {
tests/Testcontainers.Platform.Linux.Tests/ContainerNotRunningExceptionTest.cs-55- private string _id;
tests/Testcontainers.Platform.Linux.Tests/ContainerNotRunningExceptionTest.cs-56-
tests/Testcontainers.Platform.Linux.Tests/ContainerNotRunningExceptionTest.cs-57- private string _stdout;
tests/Testcontainers.Platform.Linux.Tests/ContainerNotRunningExceptionTest.cs-58-
tests/Testcontainers.Platform.Linux.Tests/ContainerNotRunningExceptionTest.cs-59- private string _stderr;
tests/Testcontainers.Platform.Linux.Tests/ContainerNotRunningExceptionTest.cs-60-
tests/Testcontainers.Platform.Linux.Tests/ContainerNotRunningExceptionTest.cs-61- private long _exitCode;
tests/Testcontainers.Platform.Linux.Tests/ContainerNotRunningExceptionTest.cs-62-
tests/Testcontainers.Platform.Linux.Tests/ContainerNotRunningExceptionTest.cs-63- public ContainerInfoSerializable()
tests/Testcontainers.Platform.Linux.Tests/ContainerNotRunningExceptionTest.cs-64- {
tests/Testcontainers.Platform.Linux.Tests/ContainerNotRunningExceptionTest.cs-65- }
tests/Testcontainers.Platform.Linux.Tests/ContainerNotRunningExceptionTest.cs-66-
tests/Testcontainers.Platform.Linux.Tests/ContainerNotRunningExceptionTest.cs-67- public ContainerInfoSerializable(string id, string stdout, string stderr, long exitCode)
tests/Testcontainers.Platform.Linux.Tests/ContainerNotRunningExceptionTest.cs-68- {
tests/Testcontainers.Platform.Linux.Tests/ContainerNotRunningExceptionTest.cs-69- _id = id;
tests/Testcontainers.Platform.Linux.Tests/ContainerNotRunningExceptionTest.cs-70- _stdout = stdout;
tests/Testcontainers.Platform.Linux.Tests/ContainerNotRunningExceptionTest.cs-71- _stderr = stderr;
tests/Testcontainers.Platform.Linux.Tests/ContainerNotRunningExceptionTest.cs-72- _exitCode = exitCode;
tests/Testcontainers.Platform.Linux.Tests/ContainerNotRunningExceptionTest.cs-73- }
tests/Testcontainers.Platform.Linux.Tests/ContainerNotRunningExceptionTest.cs-74-
tests/Testcontainers.Platform.Linux.Tests/ContainerNotRunningExceptionTest.cs-75- public (string Id, string Stdout, string Stderr, long ExitCode) ToTuple()
tests/Testcontainers.Platform.Linux.Tests/ContainerNotRunningExceptionTest.cs-76- {
tests/Testcontainers.Platform.Linux.Tests/ContainerNotRunningExceptionTest.cs-77- return (_id, _stdout, _stderr, _exitCode);
tests/Testcontainers.Platform.Linux.Tests/ContainerNotRunningExceptionTest.cs-78- }
tests/Testcontainers.Platform.Linux.Tests/ContainerNotRunningExceptionTest.cs-79-
tests/Testcontainers.Platform.Linux.Tests/ContainerNotRunningExceptionTest.cs-80- public void Deserialize(IXunitSerializationInfo info)
tests/Testcontainers.Platform.Linux.Tests/ContainerNotRunningExceptionTest.cs-81- {
tests/Testcontainers.Platform.Linux.Tests/ContainerNotRunningExceptionTest.cs-82- _id = info.GetValue<string>(nameof(_id));
tests/Testcontainers.Platform.Linux.Tests/ContainerNotRunningExceptionTest.cs-83- _stdout = info.GetValue<string>(nameof(_stdout));
--
tests/Testcontainers.Platform.Linux.Tests/ReusableResourceTest.cs:199: public sealed class ContainerBuilderTest
tests/Testcontainers.Platform.Linux.Tests/ReusableResourceTest.cs-200- {
tests/Testcontainers.Platform.Linux.Tests/ReusableResourceTest.cs-201- [Fact]
tests/Testcontainers.Platform.Linux.Tests/ReusableResourceTest.cs-202- [Trait(nameof(DockerCli.DockerPlatform), nameof(DockerCli.DockerPlatform.Linux))]
tests/Testcontainers.Platform.Linux.Tests/ReusableResourceTest.cs-203- public void EnabledCleanUpThrowsException()
tests/Testcontainers.Platform.Linux.Tests/ReusableResourceTest.cs-204- {
tests/Testcontainers.Platform.Linux.Tests/ReusableResourceTest.cs-205- // Given
tests/Testcontainers.Platform.Linux.Tests/ReusableResourceTest.cs-206- var containerBuilder = new ContainerBuilder().WithReuse(true).WithCleanUp(true);
tests/Testcontainers.Platform.Linux.Tests/ReusableResourceTest.cs-207-
tests/Testcontainers.Platform.Linux.Tests/ReusableResourceTest.cs-208- // When
tests/Testcontainers.Platform.Linux.Tests/ReusableResourceTest.cs-209- var exception = Assert.Throws<ArgumentException>(() => containerBuilder.Build());
tests/Testcontainers.Platform.Linux.Tests/ReusableResourceTest.cs-210-
tests/Testcontainers.Platform.Linux.Tests/ReusableResourceTest.cs-211- // Then
tests/Testcontainers.Platform.Linux.Tests/ReusableResourceTest.cs-212- Assert.Equal(EnabledCleanUpExceptionMessage, exception.Message);
tests/Testcontainers.Platform.Linux.Tests/ReusableResourceTest.cs-213- }
tests/Testcontainers.Platform.Linux.Tests/ReusableResourceTest.cs-214-
tests/Testcontainers.Platform.Linux.Tests/ReusableResourceTest.cs-215- [Fact]
tests/Testcontainers.Platform.Linux.Tests/ReusableResourceTest.cs-216- [Trait(nameof(DockerCli.DockerPlatform), nameof(DockerCli.DockerPlatform.Linux))]
tests/Testcontainers.Platform.Linux.Tests/ReusableResourceTest.cs-217- public void EnabledAutoRemoveThrowsException()
tests/Testcontainers.Platform.Linux.Tests/ReusableResourceTest.cs-218- {
tests/Testcontainers.Platform.Linux.Tests/ReusableResourceTest.cs-219- // Given
tests/Testcontainers.Platform.Linux.Tests/ReusableResourceTest.cs-220- var containerBuilder = new ContainerBuilder().WithReuse(true).WithAutoRemove(true);
tests/Testcontainers.Platform.Linux.Tests/ReusableResourceTest.cs-221-
tests/Testcontainers.Platform.Linux.Tests/ReusableResourceTest.cs-222- // When
tests/Testcontainers.Platform.Linux.Tests/ReusableResourceTest.cs-223- var exception = Assert.Throws<ArgumentException>(() => containerBuilder.Build());
tests/Testcontainers.Platform.Linux.Tests/ReusableResourceTest.cs-224-
tests/Testcontainers.Platform.Linux.Tests/ReusableResourceTest.cs-225- // Then
tests/Testcontainers.Platform.Linux.Tests/ReusableResourceTest.cs-226- Assert.Equal(EnabledAutoRemoveExceptionMessage, exception.Message);
tests/Testcontainers.Platform.Linux.Tests/ReusableResourceTest.cs-227- }
tests/Testcontainers.Platform.Linux.Tests/ReusableResourceTest.cs-228- }
tests/Testcontainers.Platform.Linux.Tests/ReusableResourceTest.cs-229-
</shell_result>
Script executed:
#!/bin/bash
# Let's look at the Container.cs file structure
head -200 src/Testcontainers/Containers/Container.cs | tail -100Repository: testcontainers/testcontainers-dotnet
<shell_result>
Repository: testcontainers/testcontainers-dotnet
Exit code: 0
stderr:
head: cannot open 'src/Testcontainers/Containers/Container.cs' for reading: No such file or directory
</shell_result>
Script executed:
#!/bin/bash
# Check the Container class around line 150 where Configure is called
sed -n '1,50p' src/Testcontainers/Containers/Container.csRepository: testcontainers/testcontainers-dotnet
<shell_result>
Repository: testcontainers/testcontainers-dotnet
Exit code: 2
stderr:
sed: can't read src/Testcontainers/Containers/Container.cs: No such file or directory
</shell_result>
Script executed:
#!/bin/bash
# Look at the specific area where Configure is called
sed -n '140,160p' src/Testcontainers/Containers/Container.csRepository: testcontainers/testcontainers-dotnet
<shell_result>
Repository: testcontainers/testcontainers-dotnet
Exit code: 2
stderr:
sed: can't read src/Testcontainers/Containers/Container.cs: No such file or directory
</shell_result>
Script executed:
#!/bin/bash
# Get line count first
wc -l src/Testcontainers/Containers/Container.csRepository: testcontainers/testcontainers-dotnet
<shell_result>
Repository: testcontainers/testcontainers-dotnet
Exit code: 1
stderr:
wc: src/Testcontainers/Containers/Container.cs: No such file or directory
</shell_result>
Script executed:
#!/bin/bash
# Look at the Container class definition and _configurations field
rg -n 'class Container[^B]' -A 20 src/Testcontainers/Containers/Container.cs | head -50Repository: testcontainers/testcontainers-dotnet
<shell_result>
Repository: testcontainers/testcontainers-dotnet
Exit code: 0
stderr:
src/Testcontainers/Containers/Container.cs: No such file or directory (os error 2)
</shell_result>
Script executed:
#!/bin/bash
# Examine the ContainerBuilder where Configure is called
sed -n '95,110p' src/Testcontainers/Builders/ContainerBuilder\`3.csRepository: testcontainers/testcontainers-dotnet
<shell_result>
Repository: testcontainers/testcontainers-dotnet
Exit code: 0
stdout:
return Clone(new ContainerConfiguration(image: image.ApplyHubImageNamePrefix()));
}
/// <inheritdoc />
public TBuilderEntity WithImagePullPolicy(Func<ImageInspectResponse, bool> imagePullPolicy)
{
return Clone(new ContainerConfiguration(imagePullPolicy: imagePullPolicy));
}
/// <inheritdoc />
public TBuilderEntity WithName(string name)
{
return Clone(new ContainerConfiguration(name: name));
}
/// <inheritdoc />
</shell_result>
Script executed:
#!/bin/bash
# List the files to find the ContainerBuilder file
fd 'ContainerBuilder' --type f | grep -v testRepository: testcontainers/testcontainers-dotnet
<shell_result>
Repository: testcontainers/testcontainers-dotnet
Exit code: 0
stdout:
src/Testcontainers/Builders/ContainerBuilder.cs
src/Testcontainers/Builders/ContainerBuilder`3.cs
src/Testcontainers/Builders/IContainerBuilder`2.cs
</shell_result>
Script executed:
#!/bin/bash
# Let's search for the context around line 100-101 in the builder files
rg -n 'case IContainerConfiguration:' -A 5 --type csRepository: testcontainers/testcontainers-dotnet
<shell_result>
Repository: testcontainers/testcontainers-dotnet
Exit code: 1
</shell_result>
Script executed:
#!/bin/bash
# Find the actual file
find . -name '*ContainerBuilder*.cs' -not -path '*/test*' -not -path '*/.git/*'Repository: testcontainers/testcontainers-dotnet
<shell_result>
Repository: testcontainers/testcontainers-dotnet
Exit code: 0
stdout:
./src/Testcontainers/Builders/ContainerBuilder.cs
./src/Testcontainers/Builders/ContainerBuilder`3.cs
./src/Testcontainers/Builders/IContainerBuilder`2.cs
</shell_result>
Script executed:
#!/bin/bash
# Now get the context from ContainerBuilder.cs around where Configure is called
rg -n 'case IContainerConfiguration:' -B 5 -A 5 src/Testcontainers/Builders/ContainerBuilder.csRepository: testcontainers/testcontainers-dotnet
<shell_result>
Repository: testcontainers/testcontainers-dotnet
Exit code: 1
</shell_result>
Script executed:
#!/bin/bash
# Let's see what class hierarchy ContainerBuilder has
rg -n 'public class ContainerBuilder' -A 10 src/Testcontainers/Builders/ContainerBuilder.cs | head -30Repository: testcontainers/testcontainers-dotnet
<shell_result>
Repository: testcontainers/testcontainers-dotnet
Exit code: 0
stdout:
29: public class ContainerBuilder : ContainerBuilder<ContainerBuilder, IContainer, IContainerConfiguration>
30- {
31- /// <summary>
32- /// Initializes a new instance of the <see cref="ContainerBuilder" /> class.
33- /// </summary>
34- public ContainerBuilder()
35- : this(new ContainerConfiguration())
36- {
37- DockerResourceConfiguration = Init().DockerResourceConfiguration;
38- }
39-
</shell_result>
Script executed:
#!/bin/bash
# Look at ContainerBuilder.cs to understand its structure
head -100 src/Testcontainers/Builders/ContainerBuilder.csRepository: testcontainers/testcontainers-dotnet
<shell_result>
Repository: testcontainers/testcontainers-dotnet
Exit code: 0
stdout:
namespace DotNet.Testcontainers.Builders
{
using Docker.DotNet.Models;
using DotNet.Testcontainers.Configurations;
using DotNet.Testcontainers.Containers;
using JetBrains.Annotations;
/// <summary>
/// A fluent Docker container builder.
/// </summary>
/// <remarks>
/// The container builder configuration requires at least the <see cref="ContainerBuilder{TBuilderEntity, TContainerEntity, TConfigurationEntity}.WithImage(string)" /> configuration.
/// </remarks>
/// <example>
/// The default configuration is equivalent to:
/// <code>
/// _ = new ContainerBuilder()
/// .WithDockerEndpoint(TestcontainersSettings.OS.DockerEndpointAuthConfig)
/// .WithLabel(DefaultLabels.Instance)
/// .WithCleanUp(true)
/// .WithImagePullPolicy(PullPolicy.Missing)
/// .WithOutputConsumer(Consume.DoNotConsumeStdoutAndStderr())
/// .WithWaitStrategy(Wait.ForUnixContainer())
/// .WithStartupCallback((_, ct) => Task.CompletedTask)
/// .Build();
/// </code>
/// </example>
[PublicAPI]
public class ContainerBuilder : ContainerBuilder<ContainerBuilder, IContainer, IContainerConfiguration>
{
/// <summary>
/// Initializes a new instance of the <see cref="ContainerBuilder" /> class.
/// </summary>
public ContainerBuilder()
: this(new ContainerConfiguration())
{
DockerResourceConfiguration = Init().DockerResourceConfiguration;
}
/// <summary>
/// Initializes a new instance of the <see cref="ContainerBuilder" /> class.
/// </summary>
/// <param name="dockerResourceConfiguration">The Docker resource configuration.</param>
protected ContainerBuilder(IContainerConfiguration dockerResourceConfiguration)
: base(dockerResourceConfiguration)
{
DockerResourceConfiguration = dockerResourceConfiguration;
}
/// <inheritdoc />
protected override IContainerConfiguration DockerResourceConfiguration { get; }
/// <inheritdoc />
public override IContainer Build()
{
Validate();
return new DockerContainer(DockerResourceConfiguration);
}
/// <inheritdoc />
protected sealed override ContainerBuilder Init()
{
return base.Init();
}
/// <inheritdoc />
protected override ContainerBuilder Clone(IResourceConfiguration<CreateContainerParameters> resourceConfiguration)
{
return Merge(DockerResourceConfiguration, new ContainerConfiguration(resourceConfiguration));
}
/// <inheritdoc />
protected override ContainerBuilder Clone(IContainerConfiguration resourceConfiguration)
{
return Merge(DockerResourceConfiguration, new ContainerConfiguration(resourceConfiguration));
}
/// <inheritdoc />
protected override ContainerBuilder Merge(IContainerConfiguration oldValue, IContainerConfiguration newValue)
{
return new ContainerBuilder(new ContainerConfiguration(oldValue, newValue));
}
}
}
</shell_result>
Script executed:
#!/bin/bash
# Get lines around 100-101 from ContainerBuilder.cs
sed -n '90,115p' src/Testcontainers/Builders/ContainerBuilder.csRepository: testcontainers/testcontainers-dotnet
<shell_result>
Repository: testcontainers/testcontainers-dotnet
Exit code: 0
</shell_result>
Script executed:
#!/bin/bash
# Look at Container.cs around line 150 and understand the class
sed -n '1,30p' src/Testcontainers/Containers/Container.csRepository: testcontainers/testcontainers-dotnet
<shell_result>
Repository: testcontainers/testcontainers-dotnet
Exit code: 2
stderr:
sed: can't read src/Testcontainers/Containers/Container.cs: No such file or directory
</shell_result>
Script executed:
#!/bin/bash
# Find where in Container the Configure is called and what self type is
rg -n 'foreach.*_configurations' -A 3 src/Testcontainers/Containers/Container.csRepository: testcontainers/testcontainers-dotnet
<shell_result>
Repository: testcontainers/testcontainers-dotnet
Exit code: 2
stderr:
src/Testcontainers/Containers/Container.cs: No such file or directory (os error 2)
</shell_result>
Script executed:
#!/bin/bash
# Get the full context around the Configure call in Container.cs with line numbers
cat -n src/Testcontainers/Containers/Container.cs | sed -n '140,160p'Repository: testcontainers/testcontainers-dotnet
<shell_result>
Repository: testcontainers/testcontainers-dotnet
Exit code: 0
stderr:
cat: src/Testcontainers/Containers/Container.cs: No such file or directory
</shell_result>
Script executed:
#!/bin/bash
# Check Container class signature
rg -n 'public class Container' -A 5 src/Testcontainers/Containers/Container.cs | head -20Repository: testcontainers/testcontainers-dotnet
<shell_result>
Repository: testcontainers/testcontainers-dotnet
Exit code: 0
stderr:
src/Testcontainers/Containers/Container.cs: No such file or directory (os error 2)
</shell_result>
Script executed:
#!/bin/bash
# Check if Container implements IContainer
rg -n 'class Container' src/Testcontainers/Containers/Container.cs | head -5Repository: testcontainers/testcontainers-dotnet
<shell_result>
Repository: testcontainers/testcontainers-dotnet
Exit code: 0
stderr:
src/Testcontainers/Containers/Container.cs: No such file or directory (os error 2)
</shell_result>
Script executed:
#!/bin/bash
# Now understand the complete type flow:
# 1. Check if ContainerBuilder also implements IContainer
rg -n 'class ContainerBuilder.*implements|class ContainerBuilder.*:' src/Testcontainers/Builders/ContainerBuilder.cs | head -5Repository: testcontainers/testcontainers-dotnet
<shell_result>
Repository: testcontainers/testcontainers-dotnet
Exit code: 0
stdout:
29: public class ContainerBuilder : ContainerBuilder<ContainerBuilder, IContainer, IContainerConfiguration>
</shell_result>
Script executed:
#!/bin/bash
# Check what ContainerBuilder<TBuilderEntity, TContainerEntity, TConfigurationEntity> implements
rg -n 'where TBuilderEntity' -B 5 src/Testcontainers/Builders/ContainerBuilder.cs | head -30Repository: testcontainers/testcontainers-dotnet
<shell_result>
Repository: testcontainers/testcontainers-dotnet
Exit code: 0
</shell_result>
Script executed:
#!/bin/bash
# Get just the class declaration
sed -n '14,25p' src/Testcontainers/Builders/ContainerBuilder.csRepository: testcontainers/testcontainers-dotnet
<shell_result>
Repository: testcontainers/testcontainers-dotnet
Exit code: 0
stdout:
/// <example>
/// The default configuration is equivalent to:
/// <code>
/// _ = new ContainerBuilder()
/// .WithDockerEndpoint(TestcontainersSettings.OS.DockerEndpointAuthConfig)
/// .WithLabel(DefaultLabels.Instance)
/// .WithCleanUp(true)
/// .WithImagePullPolicy(PullPolicy.Missing)
/// .WithOutputConsumer(Consume.DoNotConsumeStdoutAndStderr())
/// .WithWaitStrategy(Wait.ForUnixContainer())
/// .WithStartupCallback((_, ct) => Task.CompletedTask)
/// .Build();
</shell_result>
Script executed:
#!/bin/bash
# Simpler approach - just get the first 50 lines
head -50 src/Testcontainers/Builders/ContainerBuilder.cs | tail -20Repository: testcontainers/testcontainers-dotnet
<shell_result>
Repository: testcontainers/testcontainers-dotnet
Exit code: 0
stdout:
/// <summary>
/// Initializes a new instance of the <see cref="ContainerBuilder" /> class.
/// </summary>
public ContainerBuilder()
: this(new ContainerConfiguration())
{
DockerResourceConfiguration = Init().DockerResourceConfiguration;
}
/// <summary>
/// Initializes a new instance of the <see cref="ContainerBuilder" /> class.
/// </summary>
/// <param name="dockerResourceConfiguration">The Docker resource configuration.</param>
protected ContainerBuilder(IContainerConfiguration dockerResourceConfiguration)
: base(dockerResourceConfiguration)
{
DockerResourceConfiguration = dockerResourceConfiguration;
}
/// <inheritdoc />
</shell_result>
Script executed:
#!/bin/bash
# Check if ConnectionStringProvider is called during Build - search for Build method
rg -n 'public.*Build(' src/Testcontainers/Builders/ContainerBuilder.cs -A 15 | head -50Repository: testcontainers/testcontainers-dotnet
<shell_result>
Repository: testcontainers/testcontainers-dotnet
Exit code: 0
stderr:
regex parse error:
public.*Build(
^
error: unclosed group
</shell_result>
Script executed:
#!/bin/bash
# Check what Build() does
rg -n 'def Build|TBuilderEntity Build' src/Testcontainers/Builders/ContainerBuilder.cs -B 2 -A 15 | head -60Repository: testcontainers/testcontainers-dotnet
<shell_result>
Repository: testcontainers/testcontainers-dotnet
Exit code: 0
</shell_result>
Script executed:
#!/bin/bash
# Search the IContainerBuilder interface for Build
rg -n 'Build()' src/Testcontainers/Builders/IContainerBuilder\`2.cs -B 3 -A 10 | head -40Repository: testcontainers/testcontainers-dotnet
<shell_result>
Repository: testcontainers/testcontainers-dotnet
Exit code: 0
stdout:
1:namespace DotNet.Testcontainers.Builders
2-{
3- using System;
4- using System.Collections.Generic;
5- using System.IO;
6- using System.Threading;
7- using System.Threading.Tasks;
8- using Docker.DotNet.Models;
9- using DotNet.Testcontainers.Configurations;
10- using DotNet.Testcontainers.Containers;
11- using DotNet.Testcontainers.Images;
--
16- /// <summary>
17- /// A fluent Docker container builder.
18- /// </summary>
19: /// <typeparam name="TBuilderEntity">The builder entity.</typeparam>
20- /// <typeparam name="TContainerEntity">The resource entity.</typeparam>
21- /// <typeparam name="TConfigurationEntity">The configuration entity.</typeparam>
22- [PublicAPI]
23: public interface IContainerBuilder<out TBuilderEntity, out TContainerEntity, out TConfigurationEntity> : IAbstractBuilder<TBuilderEntity, TContainerEntity, CreateContainerParameters>
24- where TContainerEntity : IContainer
25- where TConfigurationEntity : IContainerConfiguration
26- {
27- /// <summary>
28- /// Accepts the license agreement.
29- /// </summary>
30- /// <remarks>
31- /// Modules that require a license agreement must override and implement this
32- /// method to enforce proper license acceptance behavior.
33- /// </remarks>
34- /// <param name="acceptLicenseAgreement">A boolean value indicating whether the license agreement is accepted.</param>
35: /// <returns>A configured instance of <typeparamref name="TBuilderEntity" />.</returns>
36- /// <exception cref="InvalidOperationException">Thrown when the module does not require a license agreement.</exception>
37: TBuilderEntity WithAcceptLicenseAgreement(bool acceptLicenseAgreement);
38-
39- /// <summary>
40- /// Sets the dependent container to resolve and start before starting this container configuration.
41- /// </summary>
42- /// <param name="container">The dependent container.</param>
43: /// <returns>A configured instance of <typeparamref name="TBuilderEntity" />.</returns>
</shell_result>
Script executed:
#!/bin/bash
# Get the actual Build method implementation
rg -n 'TContainerEntity Build()' -A 25 src/Testcontainers/Builders/ContainerBuilder.csRepository: testcontainers/testcontainers-dotnet
<shell_result>
Repository: testcontainers/testcontainers-dotnet
Exit code: 1
</shell_result>
Script executed:
#!/bin/bash
# Get Build() implementation with more context
sed -n '481,515p' src/Testcontainers/Builders/ContainerBuilder.csRepository: testcontainers/testcontainers-dotnet
<shell_result>
Repository: testcontainers/testcontainers-dotnet
Exit code: 0
</shell_result>
Script executed:
#!/bin/bash
# Get Build() implementation with more context - try smaller range
sed -n '481,500p' src/Testcontainers/Builders/ContainerBuilder.csRepository: testcontainers/testcontainers-dotnet
<shell_result>
Repository: testcontainers/testcontainers-dotnet
Exit code: 0
</shell_result>
Script executed:
#!/bin/bash
# Check where the configurations are processed in Build()
sed -n '481,530p' src/Testcontainers/Builders/ContainerBuilder.cs | head -60Repository: testcontainers/testcontainers-dotnet
<shell_result>
Repository: testcontainers/testcontainers-dotnet
Exit code: 0
</shell_result>
Script executed:
#!/bin/bash
# Check for tests that use WithConnectionStringProvider
rg -n 'WithConnectionStringProvider' tests/ --type cs -B 2 -A 5Repository: testcontainers/testcontainers-dotnet
<shell_result>
Repository: testcontainers/testcontainers-dotnet
Exit code: 0
stdout:
tests/Testcontainers.Platform.Linux.Tests/ConnectionStringProviderTest.cs-14- .WithImage(CommonImages.Alpine)
tests/Testcontainers.Platform.Linux.Tests/ConnectionStringProviderTest.cs-15- .WithCommand(CommonCommands.SleepInfinity)
tests/Testcontainers.Platform.Linux.Tests/ConnectionStringProviderTest.cs:16: .WithConnectionStringProvider(_connectionStringProvider)
tests/Testcontainers.Platform.Linux.Tests/ConnectionStringProviderTest.cs-17- .Build();
tests/Testcontainers.Platform.Linux.Tests/ConnectionStringProviderTest.cs-18- }
tests/Testcontainers.Platform.Linux.Tests/ConnectionStringProviderTest.cs-19-
tests/Testcontainers.Platform.Linux.Tests/ConnectionStringProviderTest.cs-20- public async ValueTask InitializeAsync()
tests/Testcontainers.Platform.Linux.Tests/ConnectionStringProviderTest.cs-21- {
</shell_result>
Script executed:
#!/bin/bash
# Check what _connectionStringProvider is in the test
sed -n '1,30p' tests/Testcontainers.Platform.Linux.Tests/ConnectionStringProviderTest.csRepository: testcontainers/testcontainers-dotnet
<shell_result>
Repository: testcontainers/testcontainers-dotnet
Exit code: 0
stdout:
namespace Testcontainers.Tests;
public sealed class ConnectionStringProviderTests : IAsyncLifetime
{
private const string ExpectedConnectionString = "connection string";
private readonly ConnectionStringProvider _connectionStringProvider = new ConnectionStringProvider();
private readonly IContainer _container;
public ConnectionStringProviderTests()
{
_container = new ContainerBuilder()
.WithImage(CommonImages.Alpine)
.WithCommand(CommonCommands.SleepInfinity)
.WithConnectionStringProvider(_connectionStringProvider)
.Build();
}
public async ValueTask InitializeAsync()
{
await _container.StartAsync()
.ConfigureAwait(false);
}
public async ValueTask DisposeAsync()
{
await _container.DisposeAsync()
.ConfigureAwait(false);
}
</shell_result>
Script executed:
#!/bin/bash
# Get file line count and structure
head -40 tests/Testcontainers.Platform.Linux.Tests/ConnectionStringProviderTest.csRepository: testcontainers/testcontainers-dotnet
<shell_result>
Repository: testcontainers/testcontainers-dotnet
Exit code: 0
stdout:
namespace Testcontainers.Tests;
public sealed class ConnectionStringProviderTests : IAsyncLifetime
{
private const string ExpectedConnectionString = "connection string";
private readonly ConnectionStringProvider _connectionStringProvider = new ConnectionStringProvider();
private readonly IContainer _container;
public ConnectionStringProviderTests()
{
_container = new ContainerBuilder()
.WithImage(CommonImages.Alpine)
.WithCommand(CommonCommands.SleepInfinity)
.WithConnectionStringProvider(_connectionStringProvider)
.Build();
}
public async ValueTask InitializeAsync()
{
await _container.StartAsync()
.ConfigureAwait(false);
}
public async ValueTask DisposeAsync()
{
await _container.DisposeAsync()
.ConfigureAwait(false);
}
[Fact]
public void GetConnectionStringReturnsExpectedValue()
{
Assert.True(_connectionStringProvider.IsConfigured, "Configure should have been called during container startup.");
Assert.Equal(ExpectedConnectionString, _container.GetConnectionString());
Assert.Equal(ExpectedConnectionString, _container.GetConnectionString("name"));
}
private sealed class ConnectionStringProvider : IConnectionStringProvider<IContainer, IContainerConfiguration>
</shell_result>
Script executed:
#!/bin/bash
# Search for TestConnectionStringProvider definition
rg -n 'class TestConnectionStringProvider' -A 15 tests/Repository: testcontainers/testcontainers-dotnet
<shell_result>
Repository: testcontainers/testcontainers-dotnet
Exit code: 1
</shell_result>
Script executed:
#!/bin/bash
# Search in test file
rg -n 'TestConnectionStringProvider' tests/Testcontainers.Platform.Linux.Tests/ConnectionStringProviderTest.cs -A 10Repository: testcontainers/testcontainers-dotnet
<shell_result>
Repository: testcontainers/testcontainers-dotnet
Exit code: 1
</shell_result>
Script executed:
#!/bin/bash
# Get more lines from the test file
tail -50 tests/Testcontainers.Platform.Linux.Tests/ConnectionStringProviderTest.csRepository: testcontainers/testcontainers-dotnet
<shell_result>
Repository: testcontainers/testcontainers-dotnet
Exit code: 0
stdout:
{
_container = new ContainerBuilder()
.WithImage(CommonImages.Alpine)
.WithCommand(CommonCommands.SleepInfinity)
.WithConnectionStringProvider(_connectionStringProvider)
.Build();
}
public async ValueTask InitializeAsync()
{
await _container.StartAsync()
.ConfigureAwait(false);
}
public async ValueTask DisposeAsync()
{
await _container.DisposeAsync()
.ConfigureAwait(false);
}
[Fact]
public void GetConnectionStringReturnsExpectedValue()
{
Assert.True(_connectionStringProvider.IsConfigured, "Configure should have been called during container startup.");
Assert.Equal(ExpectedConnectionString, _container.GetConnectionString());
Assert.Equal(ExpectedConnectionString, _container.GetConnectionString("name"));
}
private sealed class ConnectionStringProvider : IConnectionStringProvider<IContainer, IContainerConfiguration>
{
public bool IsConfigured { get; private set; }
public void Configure(IContainer container, IContainerConfiguration configuration)
{
Assert.NotNull(container);
Assert.NotNull(configuration);
IsConfigured = true;
}
public string GetConnectionString(ConnectionMode connectionMode = ConnectionMode.Host)
{
return ExpectedConnectionString;
}
public string GetConnectionString(string name, ConnectionMode connectionMode = ConnectionMode.Host)
{
return ExpectedConnectionString;
}
}
}
</shell_result>
Script executed:
#!/bin/bash
# Get the middle part of the test file
wc -l tests/Testcontainers.Platform.Linux.Tests/ConnectionStringProviderTest.csRepository: testcontainers/testcontainers-dotnet
<shell_result>
Repository: testcontainers/testcontainers-dotnet
Exit code: 0
stdout:
60 tests/Testcontainers.Platform.Linux.Tests/ConnectionStringProviderTest.cs
</shell_result>
Script executed:
#!/bin/bash
# Get the file with line numbers
cat -n tests/Testcontainers.Platform.Linux.Tests/ConnectionStringProviderTest.csRepository: testcontainers/testcontainers-dotnet
<shell_result>
Repository: testcontainers/testcontainers-dotnet
Exit code: 0
stdout:
1 namespace Testcontainers.Tests;
2
3 public sealed class ConnectionStringProviderTests : IAsyncLifetime
4 {
5 private const string ExpectedConnectionString = "connection string";
6
7 private readonly ConnectionStringProvider _connectionStringProvider = new ConnectionStringProvider();
8
9 private readonly IContainer _container;
10
11 public ConnectionStringProviderTests()
12 {
13 _container = new ContainerBuilder()
14 .WithImage(CommonImages.Alpine)
15 .WithCommand(CommonCommands.SleepInfinity)
16 .WithConnectionStringProvider(_connectionStringProvider)
17 .Build();
18 }
19
20 public async ValueTask InitializeAsync()
21 {
22 await _container.StartAsync()
23 .ConfigureAwait(false);
24 }
25
26 public async ValueTask DisposeAsync()
27 {
28 await _container.DisposeAsync()
29 .ConfigureAwait(false);
30 }
31
32 [Fact]
33 public void GetConnectionStringReturnsExpectedValue()
34 {
35 Assert.True(_connectionStringProvider.IsConfigured, "Configure should have been called during container startup.");
36 Assert.Equal(ExpectedConnectionString, _container.GetConnectionString());
37 Assert.Equal(ExpectedConnectionString, _container.GetConnectionString("name"));
38 }
39
40 private sealed class ConnectionStringProvider : IConnectionStringProvider<IContainer, IContainerConfiguration>
41 {
42 public bool IsConfigured { get; private set; }
43
44 public void Configure(IContainer container, IContainerConfiguration configuration)
45 {
46 Assert.NotNull(container);
47 Assert.NotNull(configuration);
48 IsConfigured = true;
49 }
50
51 public string GetConnectionString(ConnectionMode connectionMode = ConnectionMode.Host)
52 {
53 return ExpectedConnectionString;
54 }
55
56 public string GetConnectionString(string name, ConnectionMode connectionMode = ConnectionMode.Host)
57 {
58 return ExpectedConnectionString;
59 }
60 }
61 }
</shell_result>
Script executed:
#!/bin/bash
# Final verification: Check if Container is the default type in ContainerBuilder
# The test uses ContainerBuilder() with no generics - it should default to Container
rg -n 'public class ContainerBuilder :' src/Testcontainers/Builders/ContainerBuilder.csRepository: testcontainers/testcontainers-dotnet
<shell_result>
Repository: testcontainers/testcontainers-dotnet
Exit code: 0
stdout:
29: public class ContainerBuilder : ContainerBuilder<ContainerBuilder, IContainer, IContainerConfiguration>
</shell_result>
Script executed:
#!/bin/bash
# Check the ContainerBuilder class hierarchy - does it inherit from or implement IContainer?
rg -n 'public class ContainerBuilder.*:' src/Testcontainers/Builders/ContainerBuilder.csRepository: testcontainers/testcontainers-dotnet
<shell_result>
Repository: testcontainers/testcontainers-dotnet
Exit code: 0
stdout:
29: public class ContainerBuilder : ContainerBuilder<ContainerBuilder, IContainer, IContainerConfiguration>
</shell_result>
Script executed:
#!/bin/bash
# Get a larger view to see the full class declaration and any interfaces
sed -n '12,23p' src/Testcontainers/Builders/ContainerBuilder.csRepository: testcontainers/testcontainers-dotnet
<shell_result>
Repository: testcontainers/testcontainers-dotnet
Exit code: 0
stdout:
/// The container builder configuration requires at least the <see cref="ContainerBuilder{TBuilderEntity, TContainerEntity, TConfigurationEntity}.WithImage(string)" /> configuration.
/// </remarks>
/// <example>
/// The default configuration is equivalent to:
/// <code>
/// _ = new ContainerBuilder()
/// .WithDockerEndpoint(TestcontainersSettings.OS.DockerEndpointAuthConfig)
/// .WithLabel(DefaultLabels.Instance)
/// .WithCleanUp(true)
/// .WithImagePullPolicy(PullPolicy.Missing)
/// .WithOutputConsumer(Consume.DoNotConsumeStdoutAndStderr())
/// .WithWaitStrategy(Wait.ForUnixContainer())
</shell_result>
Script executed:
#!/bin/bash
# Let's use Python to parse and understand the declaration
python3 << 'EOF'
with open('src/Testcontainers/Builders/ContainerBuilder.cs', 'r') as f:
lines = f.readlines()
# Find class declarations around lines 12-35
for i in range(11, min(35, len(lines))):
print(f"{i+1}: {lines[i]}", end='')
EOFRepository: testcontainers/testcontainers-dotnet
<shell_result>
Repository: testcontainers/testcontainers-dotnet
Script execution failed with error: Request timed out after 120000ms (requestId=1b8be1ce-f80f-4d9c-b1be-3db70ace5584)
</shell_result>
Script executed:
#!/bin/bash
# Get more of the Build() method to see what happens with configurations
sed -n '481,520p' src/Testcontainers/Builders/ContainerBuilder.csRepository: testcontainers/testcontainers-dotnet
<shell_result>
Repository: testcontainers/testcontainers-dotnet
Exit code: 0
</shell_result>
Script executed:
#!/bin/bash
# Use Python to read and display the Build method
python3 << 'EOF'
with open('src/Testcontainers/Builders/ContainerBuilder.cs', 'r') as f:
lines = f.readlines()
# Build method starts around line 481
for i in range(480, min(530, len(lines))):
print(f"{i+1}: {lines[i]}", end='')
if i > 481 and lines[i].strip().startswith('public ') and 'Build' not in lines[i]:
break
EOFRepository: testcontainers/testcontainers-dotnet
<shell_result>
Repository: testcontainers/testcontainers-dotnet
Script execution failed with error: Request timed out after 120000ms (requestId=6a7b8f66-383d-4f50-b0e2-bae49dd1eec4)
</shell_result>
Script executed:
#!/bin/bash
# Count total lines first
total=$(wc -l < src/Testcontainers/Builders/ContainerBuilder.cs)
echo "Total lines: $total"
# Show Build method - should end when we see the next method (starting with public)
awk '/public virtual TContainerEntity Build\(\)/{p=1} p{print NR": "$0} /^ \}$/{if(p && prev ~ /^ [a-z]/) {p=0}} {prev=$0}' src/Testcontainers/Builders/ContainerBuilder.cs | head -80Repository: testcontainers/testcontainers-dotnet
<shell_result>
Repository: testcontainers/testcontainers-dotnet
Exit code: 0
stdout:
Total lines: 84
</shell_result>
Script executed:
#!/bin/bash
# Let me directly use sed to extract the full Build method
sed -n '481,540p' src/Testcontainers/Builders/ContainerBuilder.cs | cat -nRepository: testcontainers/testcontainers-dotnet
<shell_result>
Repository: testcontainers/testcontainers-dotnet
Exit code: 0
</shell_result>
Script executed:
#!/bin/bash
# Check all interfaces that ContainerBuilder implements
grep -n 'public class ContainerBuilder' src/Testcontainers/Builders/ContainerBuilder.cs -A 30 | grep -E '(class|:)' | head -5Repository: testcontainers/testcontainers-dotnet
<shell_result>
Repository: testcontainers/testcontainers-dotnet
Exit code: 0
stdout:
29: public class ContainerBuilder : ContainerBuilder<ContainerBuilder, IContainer, IContainerConfiguration>
32- /// Initializes a new instance of the <see cref="ContainerBuilder" /> class.
35- : this(new ContainerConfiguration())
41- /// Initializes a new instance of the <see cref="ContainerBuilder" /> class.
45- : base(dockerResourceConfiguration)
</shell_result>
Script executed:
#!/bin/bash
# Full class declaration check - using simpler approach
python3 << 'EOF'
import re
with open('src/Testcontainers/Builders/ContainerBuilder.cs') as f:
content = f.read()
# Find the generic ContainerBuilder class definition
match = re.search(
r'public class ContainerBuilder<TBuilderEntity, TContainerEntity, TConfigurationEntity>\s*:\s*([^\n{]+)',
content
)
if match:
print("ContainerBuilder<...> implements:", match.group(1).strip())
# Check if ContainerBuilder (non-generic) implements IContainer
match2 = re.search(
r'public class ContainerBuilder\s*:\s*([^\n{]+)',
content
)
if match2:
print("ContainerBuilder (non-generic) inherits from:", match2.group(1).strip())
EOFRepository: testcontainers/testcontainers-dotnet
<shell_result>
Repository: testcontainers/testcontainers-dotnet
Script execution failed with error: Request timed out after 120000ms (requestId=208d258e-259c-4f2e-87ce-68a58f70f8ce)
</shell_result>
Script executed:
#!/bin/bash
# Check if there's a skip or xfail on the test
rg -B 5 'ConnectionStringProviderTests' tests/Testcontainers.Platform.Linux.Tests/ConnectionStringProviderTest.cs | grep -E '(Skip|Fact|Theory|xfail)'Repository: testcontainers/testcontainers-dotnet
<shell_result>
Repository: testcontainers/testcontainers-dotnet
Exit code: 1
</shell_result>
Script executed:
#!/bin/bash
# Check all test methods in the file
rg -n '\[Fact\]|\[Theory\]|\[Skip' tests/Testcontainers.Platform.Linux.Tests/ConnectionStringProviderTest.cs -A 1Repository: testcontainers/testcontainers-dotnet
<shell_result>
Repository: testcontainers/testcontainers-dotnet
Exit code: 0
stdout:
32: [Fact]
33- public void GetConnectionStringReturnsExpectedValue()
</shell_result>
Script executed:
#!/bin/bash
# Look at WithConnectionStringProvider implementation again to see what it adds to _itemConfigurations
sed -n '400,403p' src/Testcontainers/Builders/ContainerBuilder.csRepository: testcontainers/testcontainers-dotnet
<shell_result>
Repository: testcontainers/testcontainers-dotnet
Exit code: 0
</shell_result>
Script executed:
#!/bin/bash
# Find WithConnectionStringProvider in ContainerBuilder.cs
rg -n 'WithConnectionStringProvider' src/Testcontainers/Builders/ContainerBuilder.cs -A 3Repository: testcontainers/testcontainers-dotnet
<shell_result>
Repository: testcontainers/testcontainers-dotnet
Exit code: 1
</shell_result>
Script executed:
#!/bin/bash
# Understand what Clone() does with a ContainerConfiguration
rg -n 'private.*Clone' src/Testcontainers/Builders/ContainerBuilder.cs -A 10 | head -20Repository: testcontainers/testcontainers-dotnet
<shell_result>
Repository: testcontainers/testcontainers-dotnet
Exit code: 0
</shell_result>
Script executed:
#!/bin/bash
# Check what Clone(IContainerConfiguration) does
rg -n '.*Clone.*IContainerConfiguration' src/Testcontainers/Builders/ -B 3 -A 5Repository: testcontainers/testcontainers-dotnet
<shell_result>
Repository: testcontainers/testcontainers-dotnet
Exit code: 0
stdout:
src/Testcontainers/Builders/ContainerBuilder.cs-70- }
src/Testcontainers/Builders/ContainerBuilder.cs-71-
src/Testcontainers/Builders/ContainerBuilder.cs-72- /// <inheritdoc />
src/Testcontainers/Builders/ContainerBuilder.cs:73: protected override ContainerBuilder Clone(IContainerConfiguration resourceConfiguration)
src/Testcontainers/Builders/ContainerBuilder.cs-74- {
src/Testcontainers/Builders/ContainerBuilder.cs-75- return Merge(DockerResourceConfiguration, new ContainerConfiguration(resourceConfiguration));
src/Testcontainers/Builders/ContainerBuilder.cs-76- }
src/Testcontainers/Builders/ContainerBuilder.cs-77-
src/Testcontainers/Builders/ContainerBuilder.cs-78- /// <inheritdoc />
--
src/Testcontainers/Builders/ContainerBuilder`3.cs-441- /// </summary>
src/Testcontainers/Builders/ContainerBuilder`3.cs-442- /// <param name="resourceConfiguration">The Docker resource configuration.</param>
src/Testcontainers/Builders/ContainerBuilder`3.cs-443- /// <returns>A configured instance of <typeparamref name="TBuilderEntity" />.</returns>
src/Testcontainers/Builders/ContainerBuilder`3.cs:444: protected abstract TBuilderEntity Clone(IContainerConfiguration resourceConfiguration);
src/Testcontainers/Builders/ContainerBuilder`3.cs-445-
src/Testcontainers/Builders/ContainerBuilder`3.cs-446- private TBuilderEntity WithPortForwarding()
src/Testcontainers/Builders/ContainerBuilder`3.cs-447- {
src/Testcontainers/Builders/ContainerBuilder`3.cs-448- const string hostname = "host.testcontainers.internal";
src/Testcontainers/Builders/ContainerBuilder`3.cs-449- return PortForwardingContainer.Instance != null && TestcontainersStates.Running.Equals(PortForwardingContainer.Instance.State) ? WithExtraHost(hostname, PortForwardingContainer.Instance.IpAddress) : Clone(new ContainerConfiguration());
</shell_result>
Script executed:
#!/bin/bash
# Search for Clone method
rg -n 'Clone' src/Testcontainers/Builders/ContainerBuilder.cs | head -10Repository: testcontainers/testcontainers-dotnet
<shell_result>
Repository: testcontainers/testcontainers-dotnet
Exit code: 0
stdout:
67: protected override ContainerBuilder Clone(IResourceConfiguration<CreateContainerParameters> resourceConfiguration)
73: protected override ContainerBuilder Clone(IContainerConfiguration resourceConfiguration)
</shell_result>
Script executed:
#!/bin/bash
# Get the Clone method
sed -n '29,45p' src/Testcontainers/Builders/ContainerBuilder.csRepository: testcontainers/testcontainers-dotnet
<shell_result>
Repository: testcontainers/testcontainers-dotnet
Exit code: 0
stdout:
public class ContainerBuilder : ContainerBuilder<ContainerBuilder, IContainer, IContainerConfiguration>
{
/// <summary>
/// Initializes a new instance of the <see cref="ContainerBuilder" /> class.
/// </summary>
public ContainerBuilder()
: this(new ContainerConfiguration())
{
DockerResourceConfiguration = Init().DockerResourceConfiguration;
}
/// <summary>
/// Initializes a new instance of the <see cref="ContainerBuilder" /> class.
/// </summary>
/// <param name="dockerResourceConfiguration">The Docker resource configuration.</param>
protected ContainerBuilder(IContainerConfiguration dockerResourceConfiguration)
: base(dockerResourceConfiguration)
</shell_result>
Script executed:
#!/bin/bash
# Get the Clone method with more context
sed -n '25,50p' src/Testcontainers/Builders/ContainerBuilder.cs | cat -nRepository: testcontainers/testcontainers-dotnet
<shell_result>
Repository: testcontainers/testcontainers-dotnet
Exit code: 0
stdout:
1 /// .Build();
2 /// </code>
3 /// </example>
4 [PublicAPI]
5 public class ContainerBuilder : ContainerBuilder<ContainerBuilder, IContainer, IContainerConfiguration>
6 {
7 /// <summary>
8 /// Initializes a new instance of the <see cref="ContainerBuilder" /> class.
9 /// </summary>
10 public ContainerBuilder()
11 : this(new ContainerConfiguration())
12 {
13 DockerResourceConfiguration = Init().DockerResourceConfiguration;
14 }
15
16 /// <summary>
17 /// Initializes a new instance of the <see cref="ContainerBuilder" /> class.
18 /// </summary>
19 /// <param name="dockerResourceConfiguration">The Docker resource configuration.</param>
20 protected ContainerBuilder(IContainerConfiguration dockerResourceConfiguration)
21 : base(dockerResourceConfiguration)
22 {
23 DockerResourceConfiguration = dockerResourceConfiguration;
24 }
25
26 /// <inheritdoc />
</shell_result>
Script executed:
#!/bin/bash
# Final check - is Container a base class or ancestor of ContainerBuilder?
python3 << 'EOF'
import os
import re
# Read Container class
with open('src/Testcontainers/Containers/Container.cs') as f:
container_content = f.read()
# Find what Container inherits from
match = re.search(r'public class Container\s*:\s*([^\n{]+)', container_content)
if match:
print("Container inherits from:", match.group(1).strip())
# Read ContainerBuilder
with open('src/Testcontainers/Builders/ContainerBuilder.cs') as f:
builder_content = f.read()
# Find what ContainerBuilder inherits
match2 = re.search(r'public class ContainerBuilder\s*:\s*([^\n{]+)', builder_content)
if match2:
print("ContainerBuilder inherits from:", match2.group(1).strip())
# Check if Container appears in builder file
if 'Container' in builder_content and 'Container :' in builder_content:
print("\nContainerBuilder definition mentions Container in inheritance")
# The key: does ContainerBuilder inherit from Container? (unlikely for a builder pattern)
EOFRepository: testcontainers/testcontainers-dotnet
<shell_result>
Repository: testcontainers/testcontainers-dotnet
Script execution failed with error: Request timed out after 120000ms (requestId=e0ef7ddd-9823-4c5d-9df3-4e1b9748e9f0)
</shell_result>
Based on my comprehensive verification, I need to provide the corrected review comment:
Replace unsafe casts with safe casting pattern or add runtime validation.
The Configure method performs unchecked C-style casts to the generic type parameters. While the test confirms that Configure is invoked during container startup (line 35 of the test: "Configure should have been called during container startup") rather than during the build phase, the casts still lack explicit validation. Consider using as or is patterns with explicit error handling to:
- Provide clearer error messages if type mismatches occur
- Make the type safety assumptions explicit in the code
- Improve maintainability for developers extending this adapter pattern
Example: Replace (TContainerEntity)container with container as TContainerEntity ?? throw new InvalidCastException(...).
🤖 Prompt for AI Agents
In src/Testcontainers/Configurations/Containers/ConnectionStringProvider.cs
around lines 21 to 25, the Configure method uses unchecked casts
((TContainerEntity)container and (TConfigurationEntity)configuration) which can
throw unclear InvalidCastExceptions at runtime; replace these with safe casting
and explicit validation (for example use the safe-cast pattern and throw a
descriptive exception) so that type mismatches produce clear error messages and
make the adapter's type assumptions explicit and maintainable.
What does this PR do?
This PR adds a connection string provider, which provides a standardized way to access and manage connection information for Testcontainers. Configuring connection strings for modules can sometimes be tricky or tedious, and this API aims to simplify that process.
This PR does not implement the connection string provider in modules yet. That will be done in the future. Modules would offer a default implementation that users can override or replace with their own. For now, I want to test whether the proposed solution effectively addresses the issue.
Usage
I'd appreciate feedback from the community.
Why is it important?
The connection string provider API lets developers configure a provider that resolves connection strings based on the container and its configuration.
Related issues
IConnectionStringProviderfor modules / container builder API #1074