Skip to content

Commit

Permalink
Improve Oracle support
Browse files Browse the repository at this point in the history
Use the correct database default name depending on the Docker image version and enable setting a custom database name for Oracle 18 and onwards.

Fixes testcontainers#1233
  • Loading branch information
0xced committed Dec 20, 2024
1 parent f259fff commit 655a49b
Show file tree
Hide file tree
Showing 4 changed files with 84 additions and 17 deletions.
2 changes: 1 addition & 1 deletion Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@
<PackageVersion Include="NATS.Client" Version="1.0.8"/>
<PackageVersion Include="Neo4j.Driver" Version="5.5.0"/>
<PackageVersion Include="Npgsql" Version="6.0.11"/>
<PackageVersion Include="Oracle.ManagedDataAccess.Core" Version="3.21.160"/>
<PackageVersion Include="Oracle.ManagedDataAccess.Core" Version="23.6.1"/>
<PackageVersion Include="RabbitMQ.Client" Version="6.4.0"/>
<PackageVersion Include="RavenDB.Client" Version="5.4.100"/>
<PackageVersion Include="Selenium.WebDriver" Version="4.8.1"/>
Expand Down
59 changes: 45 additions & 14 deletions src/Testcontainers.Oracle/OracleBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ public sealed class OracleBuilder : ContainerBuilder<OracleBuilder, OracleContai

public const ushort OraclePort = 1521;

[Obsolete("Not used anymore. Only valid for Oracle images > 11 and < 23")]
public const string DefaultDatabase = "XEPDB1";

public const string DefaultUsername = "oracle";
Expand Down Expand Up @@ -59,20 +60,63 @@ public OracleBuilder WithPassword(string password)
.WithEnvironment("APP_USER_PASSWORD", password);
}

/// <summary>
/// Sets the Oracle database.
/// </summary>
/// <remarks>
/// The database can only be set for Oracle 18 and onwards.
/// </remarks>
/// <param name="database">The Oracle database.</param>
/// <returns>A configured instance of <see cref="OracleBuilder" />.</returns>
public OracleBuilder WithDatabase(string database)
{
if (DockerResourceConfiguration.Image.MatchVersion(v => v.Major < 18))
throw new NotSupportedException("Setting the database is only supported on Oracle 18 and onwards.");

return WithDatabaseUnchecked(database);
}

private OracleBuilder WithDatabaseUnchecked(string database)
{
return Merge(DockerResourceConfiguration, new OracleConfiguration(database: database));
}

/// <inheritdoc />
public override OracleContainer Build()
{
Validate();

var defaultServiceName = GetDefaultServiceName();
if (DockerResourceConfiguration.Database == null)
{
return new OracleContainer(WithDatabaseUnchecked(defaultServiceName).DockerResourceConfiguration);
}

if (DockerResourceConfiguration.Database != defaultServiceName)
{
return new OracleContainer(WithEnvironment("ORACLE_DATABASE", DockerResourceConfiguration.Database).DockerResourceConfiguration);
}

return new OracleContainer(DockerResourceConfiguration);
}

private string GetDefaultServiceName()
{
if (DockerResourceConfiguration.Image.MatchVersion(v => v.Major >= 23))
return "FREEPDB1";

if (DockerResourceConfiguration.Image.MatchVersion(v => v.Major > 11))
return "XEPDB1";

return "XE";
}

/// <inheritdoc />
protected override OracleBuilder Init()
{
return base.Init()
.WithImage(OracleImage)
.WithPortBinding(OraclePort, true)
.WithDatabase(DefaultDatabase)
.WithUsername(DefaultUsername)
.WithPassword(DefaultPassword)
.WithWaitStrategy(Wait.ForUnixContainer().UntilMessageIsLogged("DATABASE IS READY TO USE!"));
Expand Down Expand Up @@ -105,17 +149,4 @@ protected override OracleBuilder Merge(OracleConfiguration oldValue, OracleConfi
{
return new OracleBuilder(new OracleConfiguration(oldValue, newValue));
}

/// <summary>
/// Sets the Oracle database.
/// </summary>
/// <remarks>
/// The Docker image does not allow to configure the database.
/// </remarks>
/// <param name="database">The Oracle database.</param>
/// <returns>A configured instance of <see cref="OracleBuilder" />.</returns>
private OracleBuilder WithDatabase(string database)
{
return Merge(DockerResourceConfiguration, new OracleConfiguration(database: database));
}
}
39 changes: 37 additions & 2 deletions tests/Testcontainers.Oracle.Tests/OracleContainerTest.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
namespace Testcontainers.Oracle;

public class OracleContainerTest(OracleContainerTest.OracleFixture oracleFixture) : IClassFixture<OracleContainerTest.OracleFixture>
public abstract class OracleContainerTest(OracleContainerTest.OracleFixture oracleFixture)
{
[Fact]
[Trait(nameof(DockerCli.DockerPlatform), nameof(DockerCli.DockerPlatform.Linux))]
Expand Down Expand Up @@ -32,8 +32,43 @@ public async Task ExecScriptReturnsSuccessful()
Assert.Empty(execResult.Stderr);
}

public class OracleFixture(IMessageSink messageSink) : DbContainerFixture<OracleBuilder, OracleContainer>(messageSink)
public class OracleFixture(IMessageSink messageSink, string edition, int? version, string database = null) : DbContainerFixture<OracleBuilder, OracleContainer>(messageSink)
{
public override DbProviderFactory DbProviderFactory => OracleClientFactory.Instance;

protected override OracleBuilder Configure(OracleBuilder builder)
{
if (edition == default && version == default)
{
return builder;
}

var image = $"gvenzl/oracle-{edition}:{version}-slim-faststart";
return database == null ? builder.WithImage(image) : builder.WithImage(image).WithDatabase(database);
}
}

[UsedImplicitly] public sealed class OracleDefault(OracleDefaultFixture fixture) : OracleContainerTest(fixture), IClassFixture<OracleDefaultFixture>;
[UsedImplicitly] public sealed class Oracle11(Oracle11Fixture fixture) : OracleContainerTest(fixture), IClassFixture<Oracle11Fixture>;
[UsedImplicitly] public sealed class Oracle18(Oracle18Fixture fixture) : OracleContainerTest(fixture), IClassFixture<Oracle18Fixture>;
[UsedImplicitly] public sealed class Oracle21(Oracle21Fixture fixture) : OracleContainerTest(fixture), IClassFixture<Oracle21Fixture>;
[UsedImplicitly] public sealed class Oracle23(Oracle23Fixture fixture) : OracleContainerTest(fixture), IClassFixture<Oracle23Fixture>;
[UsedImplicitly] public sealed class Oracle18Default(Oracle18FixtureDefault fixture) : OracleContainerTest(fixture), IClassFixture<Oracle18FixtureDefault>;
[UsedImplicitly] public sealed class Oracle21Default(Oracle21FixtureDefault fixture) : OracleContainerTest(fixture), IClassFixture<Oracle21FixtureDefault>;
[UsedImplicitly] public sealed class Oracle23Default(Oracle23FixtureDefault fixture) : OracleContainerTest(fixture), IClassFixture<Oracle23FixtureDefault>;
[UsedImplicitly] public sealed class Oracle18Scott(Oracle18FixtureScott fixture) : OracleContainerTest(fixture), IClassFixture<Oracle18FixtureScott>;
[UsedImplicitly] public sealed class Oracle21Scott(Oracle21FixtureScott fixture) : OracleContainerTest(fixture), IClassFixture<Oracle21FixtureScott>;
[UsedImplicitly] public sealed class Oracle23Scott(Oracle23FixtureScott fixture) : OracleContainerTest(fixture), IClassFixture<Oracle23FixtureScott>;

[UsedImplicitly] public class OracleDefaultFixture(IMessageSink messageSink) : OracleFixture(messageSink, default, default);
[UsedImplicitly] public class Oracle11Fixture(IMessageSink messageSink) : OracleFixture(messageSink, "xe", 11);
[UsedImplicitly] public class Oracle18Fixture(IMessageSink messageSink) : OracleFixture(messageSink, "xe", 18);
[UsedImplicitly] public class Oracle21Fixture(IMessageSink messageSink) : OracleFixture(messageSink, "xe", 21);
[UsedImplicitly] public class Oracle23Fixture(IMessageSink messageSink) : OracleFixture(messageSink, "free", 23);
[UsedImplicitly] public class Oracle18FixtureDefault(IMessageSink messageSink) : OracleFixture(messageSink, "xe", 18, "XEPDB1");
[UsedImplicitly] public class Oracle21FixtureDefault(IMessageSink messageSink) : OracleFixture(messageSink, "xe", 21, "XEPDB1");
[UsedImplicitly] public class Oracle23FixtureDefault(IMessageSink messageSink) : OracleFixture(messageSink, "free", 23, "FREEPDB1");
[UsedImplicitly] public class Oracle18FixtureScott(IMessageSink messageSink) : OracleFixture(messageSink, "xe", 18, "SCOTT");
[UsedImplicitly] public class Oracle21FixtureScott(IMessageSink messageSink) : OracleFixture(messageSink, "xe", 21, "SCOTT");
[UsedImplicitly] public class Oracle23FixtureScott(IMessageSink messageSink) : OracleFixture(messageSink, "free", 23, "SCOTT");
}
1 change: 1 addition & 0 deletions tests/Testcontainers.Oracle.Tests/Usings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
global using System.Data.Common;
global using System.Threading.Tasks;
global using DotNet.Testcontainers.Commons;
global using JetBrains.Annotations;
global using Oracle.ManagedDataAccess.Client;
global using Testcontainers.Xunit;
global using Xunit;
Expand Down

0 comments on commit 655a49b

Please sign in to comment.