Skip to content

Commit 1797277

Browse files
committed
testcontainersGH-1261 [Enhancement]: Support Neo4j Enterprise
- Added small QoL method to support Neo4j enterprise - Added validation to throw when enterprise is requested without the correct license agreement environment variable - Added tests for enterprise & configuration changes - Changed existing test to use IAsyncDisposable instead of sync-over-async disposal
1 parent 1cc56ea commit 1797277

File tree

3 files changed

+102
-8
lines changed

3 files changed

+102
-8
lines changed

src/Testcontainers.Neo4j/Neo4jBuilder.cs

+35
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
using System.Linq;
2+
using DotNet.Testcontainers;
3+
14
namespace Testcontainers.Neo4j;
25

36
/// <inheritdoc cref="ContainerBuilder{TBuilderEntity, TContainerEntity, TConfigurationEntity}" />
@@ -6,10 +9,16 @@ public sealed class Neo4jBuilder : ContainerBuilder<Neo4jBuilder, Neo4jContainer
69
{
710
public const string Neo4jImage = "neo4j:5.4";
811

12+
public const string Neo4jEnterpriseImage = "neo4j:5.4-enterprise";
13+
914
public const ushort Neo4jHttpPort = 7474;
1015

1116
public const ushort Neo4jBoltPort = 7687;
1217

18+
private const string AcceptLicenseAgreementEnvVar = "NEO4J_ACCEPT_LICENSE_AGREEMENT";
19+
20+
private const string AcceptLicenseAgreementEnvVarValue = "yes";
21+
1322
/// <summary>
1423
/// Initializes a new instance of the <see cref="Neo4jBuilder" /> class.
1524
/// </summary>
@@ -39,6 +48,26 @@ public override Neo4jContainer Build()
3948
return new Neo4jContainer(DockerResourceConfiguration);
4049
}
4150

51+
/// <inheritdoc />
52+
protected override void Validate()
53+
{
54+
base.Validate();
55+
56+
if (IsEnterpriseImage())
57+
{
58+
const string message = $"The 'enterprise' image requires setting environment variable {AcceptLicenseAgreementEnvVar} to= '{AcceptLicenseAgreementEnvVarValue}'";
59+
_ = Guard.Argument(DockerResourceConfiguration, "Enterprise License agreement")
60+
.ThrowIf(
61+
argument => !argument.Value.Environments.TryGetValue(AcceptLicenseAgreementEnvVar, out var licenseAgreementValue) || licenseAgreementValue != AcceptLicenseAgreementEnvVarValue,
62+
argument => new ArgumentException(message, argument.Name));
63+
}
64+
}
65+
66+
private bool IsEnterpriseImage()
67+
{
68+
return DockerResourceConfiguration.Image.Tag?.Contains("enterprise") ?? false;
69+
}
70+
4271
/// <inheritdoc />
4372
protected override Neo4jBuilder Init()
4473
{
@@ -68,4 +97,10 @@ protected override Neo4jBuilder Merge(Neo4jConfiguration oldValue, Neo4jConfigur
6897
{
6998
return new Neo4jBuilder(new Neo4jConfiguration(oldValue, newValue));
7099
}
100+
101+
public Neo4jBuilder WithEnterpriseEdition()
102+
{
103+
return WithImage(Neo4jEnterpriseImage)
104+
.WithEnvironment(AcceptLicenseAgreementEnvVar, AcceptLicenseAgreementEnvVarValue);
105+
}
71106
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
using System;
2+
3+
namespace Testcontainers.Neo4j;
4+
5+
public sealed class Neo4jBuilderConfigurationTest
6+
{
7+
[Fact]
8+
public void CreatingEnterpriseContainerWithoutLicenseAgreementShouldThrow()
9+
{
10+
Assert.Throws<ArgumentException>(() => new Neo4jBuilder()
11+
.WithImage(Neo4jBuilder.Neo4jEnterpriseImage)
12+
.Build());
13+
}
14+
}
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,19 @@
1+
using System;
2+
using JetBrains.Annotations;
3+
14
namespace Testcontainers.Neo4j;
25

3-
public sealed class Neo4jContainerTest : IAsyncLifetime
6+
public abstract class Neo4jContainerTest : IAsyncLifetime
47
{
8+
private const string Neo4jDatabase = "neo4j";
9+
510
// # --8<-- [start:UseNeo4jContainer]
6-
private readonly Neo4jContainer _neo4jContainer = new Neo4jBuilder().Build();
11+
private readonly Neo4jContainer _neo4jContainer;
12+
13+
private Neo4jContainerTest(Neo4jContainer neo4jContainer)
14+
{
15+
_neo4jContainer = neo4jContainer;
16+
}
717

818
public Task InitializeAsync()
919
{
@@ -17,18 +27,53 @@ public Task DisposeAsync()
1727

1828
[Fact]
1929
[Trait(nameof(DockerCli.DockerPlatform), nameof(DockerCli.DockerPlatform.Linux))]
20-
public void SessionReturnsDatabase()
30+
public async Task SessionReturnsDatabase()
2131
{
2232
// Given
23-
const string database = "neo4j";
24-
25-
using var driver = GraphDatabase.Driver(_neo4jContainer.GetConnectionString());
33+
await using var driver = GraphDatabase.Driver(_neo4jContainer.GetConnectionString());
2634

2735
// When
28-
using var session = driver.AsyncSession(sessionConfigBuilder => sessionConfigBuilder.WithDatabase(database));
36+
await using var session = driver.AsyncSession(sessionConfigBuilder => sessionConfigBuilder.WithDatabase(Neo4jDatabase));
2937

3038
// Then
31-
Assert.Equal(database, session.SessionConfig.Database);
39+
Assert.Equal(Neo4jDatabase, session.SessionConfig.Database);
3240
}
3341
// # --8<-- [end:UseNeo4jContainer]
42+
43+
[UsedImplicitly]
44+
public sealed class Neo4jDefaultConfiguration : Neo4jContainerTest
45+
{
46+
public Neo4jDefaultConfiguration()
47+
: base(new Neo4jBuilder().Build())
48+
{
49+
}
50+
}
51+
52+
[UsedImplicitly]
53+
public sealed class Neo4jEnterpriseConfiguration : Neo4jContainerTest
54+
{
55+
public Neo4jEnterpriseConfiguration()
56+
: base(new Neo4jBuilder()
57+
.WithEnterpriseEdition()
58+
.Build())
59+
{
60+
}
61+
62+
[Fact]
63+
[Trait(nameof(DockerCli.DockerPlatform), nameof(DockerCli.DockerPlatform.Linux))]
64+
public async Task DatabaseShouldReturnEnterpriseEdition()
65+
{
66+
// Given
67+
await using var driver = GraphDatabase.Driver(_neo4jContainer.GetConnectionString());
68+
69+
// When
70+
await using var session = driver.AsyncSession(sessionConfigBuilder => sessionConfigBuilder.WithDatabase(Neo4jDatabase));
71+
var result = await session.RunAsync("CALL dbms.components() YIELD edition RETURN edition");
72+
var record = await result.SingleAsync();
73+
var edition = record["edition"].As<string>();
74+
75+
// Then
76+
Assert.Equal("enterprise", edition);
77+
}
78+
}
3479
}

0 commit comments

Comments
 (0)