Skip to content
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

Use TestContainers to allow for local testing. #76

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 7 additions & 14 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,25 +21,17 @@ jobs:
- 8.x
arango:
- "arangodb:3.11"
# - "arangodb:3.10"
# - "arangodb/enterprise:3.9"
- "arangodb:latest"
# - "arangodb/enterprise:3.9"
topology:
- single
# - cluster

steps:
- uses: actions/checkout@v3

- name: chmod
run: find ./docker -name '*.sh' | xargs chmod +x

- name: arango
run: ./docker/start_db_${{ matrix.topology }}_retry_fail.sh ${{ matrix.arango }}
env:
ARANGO_LICENSE_KEY: ${{ secrets.ARANGO_LICENSE_KEY }}

- uses: actions/checkout@v4

- name: dotnet
uses: actions/setup-dotnet@v3
uses: actions/setup-dotnet@v4
with:
dotnet-version: ${{ matrix.dotnet }}

Expand All @@ -49,4 +41,5 @@ jobs:
- name: test
run: dotnet test --configuration Release
env:
ARANGODB_CONNECTION: "Server=http://172.28.3.1:8529;Realm=CI-{UUID};User=root;Password=test;"
ARANGODB_VERSION: ${{ matrix.arango }}
ARANGODB_TOPOLOGY: ${{ matrix.topology }}
11 changes: 6 additions & 5 deletions Core.Arango.Tests/Core.Arango.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -10,21 +10,22 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
<PackageReference Include="xunit" Version="2.7.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.11.1" />
<PackageReference Include="Testcontainers.ArangoDb" Version="3.10.0" />
<PackageReference Include="xunit" Version="2.9.2" />
<PackageReference Include="Xunit.Priority" Version="1.1.6" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.7">
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.2">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="coverlet.collector" Version="6.0.0">
<PackageReference Include="coverlet.collector" Version="6.0.2">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="8.0.1" />
</ItemGroup>

<ItemGroup>
Expand Down
157 changes: 138 additions & 19 deletions Core.Arango.Tests/Core/TestBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,29 +7,148 @@
using Newtonsoft.Json;
using Xunit;
using Xunit.Abstractions;
using Testcontainers.ArangoDb;
using System.Collections.Generic;
using System.IO;
using DotNet.Testcontainers.Builders;

namespace Core.Arango.Tests.Core
{
public abstract class TestBase : IAsyncLifetime
{
private const string ARANGO_LICENSE_KEY_ENVAR = "ARANGO_LICENSE_KEY";
private const string ARANGODB_VERSION_ENVAR = "ARANGODB_VERSION";
private const string ARANGODB_TOPOLOGY_ENVAR = "ARANGODB_TOPOLOGY";
private const string DefaultImage = "arangodb:latest";
private const string DefaultImagePassword = "password";
private const string DefaultImageUser = "root";
private const string ClusterValue = "cluster";

public IArangoContext Arango { get; protected set; }
private readonly static Lazy<Task<IEnumerable<ArangoDbContainer>>> Containers = new(async () =>
Environment.GetEnvironmentVariable(ARANGODB_TOPOLOGY_ENVAR) == ClusterValue
? await SetupClusterServer()
: await SetupSingleServer());

public virtual Task InitializeAsync()
public virtual async Task InitializeAsync()
{
return Task.CompletedTask;
foreach (var container in await Containers.Value)
{
await container.StartAsync()
.ConfigureAwait(false);
}
}

public async Task DisposeAsync()
private static (Dictionary<string, string> Environment, string Version) GetVersionAndEnvironment()
{
try
var environment = new Dictionary<string, string>();

if (string.IsNullOrWhiteSpace(Environment.GetEnvironmentVariable(ARANGO_LICENSE_KEY_ENVAR)))
{
foreach (var db in await Arango.Database.ListAsync())
await Arango.Database.DropAsync(db);
environment.Add(ARANGO_LICENSE_KEY_ENVAR, Environment.GetEnvironmentVariable(ARANGO_LICENSE_KEY_ENVAR));
}
catch

var version = string.IsNullOrWhiteSpace(Environment.GetEnvironmentVariable(ARANGODB_VERSION_ENVAR))
? DefaultImage
: Environment.GetEnvironmentVariable(ARANGODB_VERSION_ENVAR);

return (environment, version);
}

private static Task<List<ArangoDbContainer>> SetupSingleServer()
{
var (environment, version) = GetVersionAndEnvironment();
return Task.FromResult(new List<ArangoDbContainer>{new ArangoDbBuilder()
.WithImage(version)
.WithEnvironment(environment)
.WithPassword(DefaultImagePassword)
.Build() });
}

private static async Task<List<ArangoDbContainer>> SetupClusterServer()
{
var (environment, version) = GetVersionAndEnvironment();

// This is not yet tested. But is a largely compatible replication of the start_db_cluster script.
// 2024-10-29 20:11:32 Error while processing command-line options for arangod:
// 2024 - 10 - 29 20:11:32 unknown option '--cluster.start-dbserver false'
// I suspect that's because Cluster is only available for Enterprise?
Comment on lines +72 to +75
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Take note of this.
This option is indeed not available in the main image of ArangoDB for arangod.

var arangoDBNetwork = new NetworkBuilder()
.WithName($"ArangoDB-{Guid.NewGuid():D}")
.Build();

var jwt = Path.GetTempFileName();
File.Move(jwt, jwt + ".jwt");
jwt += ".jwt";
File.AppendAllText(jwt, "Averysecretword");

var leadAgent = $"leadagent-{Guid.NewGuid():N}";
var extraAgents = Enumerable.Range(0, 2);
var dbs = Enumerable.Range(0, 2);
var coordinators = Enumerable.Range(0, 2);

var containers = new List<ArangoDbContainer>();

var DefaultContainerConfiguration = new ArangoDbBuilder()
.WithImage(version)
.WithResourceMapping(jwt, "/jwtSecret")
.WithEnvironment(environment)
.WithPassword(DefaultImagePassword)
.WithNetwork(arangoDBNetwork);

containers.Add(DefaultContainerConfiguration
.WithName(leadAgent)
.WithCommand(
"--cluster.start-dbserver", "false",
"--cluster.start-coordinator", "false",
"--auth.jwt-secret", "/jwtSecret")
.Build());

foreach (var _ in extraAgents)
{
//
containers.Add(DefaultContainerConfiguration
.WithName($"{extraAgents}-{Guid.NewGuid():N}")
.WithCommand(
"--cluster.start-dbserver", "false",
"--cluster.start-coordinator", "false",
"--auth.jwt-secret", "/jwtSecret",
"--starter.join", leadAgent)
.Build());
}

foreach (var _ in dbs)
{
containers.Add(DefaultContainerConfiguration
.WithName($"{dbs}-{Guid.NewGuid():N}")
.WithCommand(
"--cluster.start-dbserver", "true",
"--cluster.start-coordinator", "false",
"--auth.jwt-secret", "/jwtSecret",
"--starter.join", leadAgent)
.Build());
}

foreach (var _ in coordinators)
{
containers.Add(DefaultContainerConfiguration
.WithName($"{coordinators}-{Guid.NewGuid():N}")
.WithCommand(
"--cluster.start-dbserver", "false",
"--cluster.start-coordinator", "true",
"--auth.jwt-secret", "/jwtSecret",
"--starter.join", leadAgent)
.Build());
}

await arangoDBNetwork.CreateAsync()
.ConfigureAwait(false);

return containers;
}

public async Task DisposeAsync()
{
await Task.CompletedTask;
}

public async Task SetupAsync(string serializer, string createDatabase = "test")
Expand All @@ -47,20 +166,20 @@ public async Task SetupAsync(string serializer, string createDatabase = "test")
});

if (!string.IsNullOrEmpty(createDatabase))
await Arango.Database.CreateAsync("test");
{
var databaseCreateSuccessful = await Arango.Database.CreateAsync("test");
if (databaseCreateSuccessful == false)
{
throw new Exception("Database creation failed");
}
}
}

protected string UniqueTestRealm()
{
var cs = Environment.GetEnvironmentVariable("ARANGODB_CONNECTION");

if (string.IsNullOrWhiteSpace(cs))
cs = "Server=http://localhost:8529;Realm=CI-{UUID};User=root;Password=;";

return cs.Replace("{UUID}", Guid.NewGuid().ToString("D"));
}
protected static string UniqueTestRealm()
// Last to get the Coordinators for clusters, or the only existing one for a single server.
=> $"Server={Containers.Value.Result.Last().GetTransportAddress()};User={DefaultImageUser};Realm=CI-{Guid.NewGuid():D};Password={DefaultImagePassword};";

protected void PrintQuery<T>(IQueryable<T> query, ITestOutputHelper output)
protected static void PrintQuery<T>(IQueryable<T> query, ITestOutputHelper output)
{
var aql = query.ToAql();
output.WriteLine("QUERY:");
Expand Down
2 changes: 1 addition & 1 deletion Core.Arango.Tests/IndexTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public async Task DropAll(string serializer)

await Arango.Index.CreateAsync("test", "test", new ArangoIndex
{
Fields = new List<string> {"test"},
Fields = ["test"],
Type = ArangoIndexType.Hash
});

Expand Down
20 changes: 15 additions & 5 deletions Core.Arango.Tests/LinqTest.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Linq;
using System.Threading.Tasks;
using Core.Arango.Protocol;
Expand All @@ -10,7 +8,6 @@
using Newtonsoft.Json;
using Xunit;
using Xunit.Abstractions;
using System.Linq.Expressions;

namespace Core.Arango.Tests
{
Expand Down Expand Up @@ -70,7 +67,7 @@ await Arango.Query<Project>("test")
}

[Fact]
public async Task MultiFilter()
public Task MultiFilter()
{
var q = Arango.Query<Project>("test")
.Where(x => x.Name == "Project A")
Expand All @@ -80,16 +77,20 @@ public async Task MultiFilter()
.Skip(0).Take(1);

Assert.Equal("FOR `x` IN `Project` FILTER ( `x`.`Name` == @P1 ) SORT `x`.`Name` ASC FILTER ( `x`.`Name` == @P2 ) SORT `x`.`Name` DESC LIMIT @P3 , @P4 RETURN `x`", q.ToAql().aql.Trim());

return Task.CompletedTask;
}


[Fact]
public async Task FilterOrder()
public Task FilterOrder()
{
var q = Arango.Query<Project>("test")
.Where(x => (x.Name == "Project A" || x.Name == "Project B") && x.Budget <= 0);

Assert.Equal("FOR `x` IN `Project` FILTER ( ( ( `x`.`Name` == @P1 ) OR ( `x`.`Name` == @P2 ) ) AND ( `x`.`Budget` <= @P3 ) ) RETURN `x`", q.ToAql().aql.Trim());

return Task.CompletedTask;
}

[Fact]
Expand Down Expand Up @@ -117,6 +118,7 @@ public async Task GroupBy()

_output.WriteLine(q.ToAql().aql);
_output.WriteLine("");
await Task.CompletedTask;
//_output.WriteLine(JsonConvert.SerializeObject(await q.ToListAsync(), Formatting.Indented));
}

Expand All @@ -132,6 +134,7 @@ public async Task MathAbs()

_output.WriteLine(q.ToAql().aql);
_output.WriteLine("");
await Task.CompletedTask;
//_output.WriteLine(JsonConvert.SerializeObject(await q.ToListAsync(), Formatting.Indented));
}

Expand All @@ -147,6 +150,7 @@ public async Task Ternary()

_output.WriteLine(q.ToAql().aql);
_output.WriteLine("");
await Task.CompletedTask;
//_output.WriteLine(JsonConvert.SerializeObject(await q.ToListAsync(), Formatting.Indented));
}

Expand Down Expand Up @@ -174,6 +178,7 @@ public async Task Remove()
.Remove().In<Project>().Select(x => x.Key);

_output.WriteLine(q.ToAql().aql);
await Task.CompletedTask;
}

[Fact]
Expand Down Expand Up @@ -217,10 +222,13 @@ public async Task QueryableContains()
.Contains("CB");

Assert.True(q);
await Task.CompletedTask;
}

public override async Task InitializeAsync()
{
await base.InitializeAsync();

Arango = new ArangoContext(UniqueTestRealm());
await Arango.Database.CreateAsync(D);
await Arango.Collection.CreateAsync(D, nameof(Client), ArangoCollectionType.Document);
Expand Down Expand Up @@ -300,6 +308,7 @@ public async Task StringContains()
var aql = q.ToAql().aql.Trim();

Assert.Equal("FOR `x` IN `Project` FILTER CONTAINS( `x`.`Name` , @P1 ) RETURN `x`", aql);
await Task.CompletedTask;
}

[Fact]
Expand All @@ -309,6 +318,7 @@ public async Task StringConcat()
var aql = q.ToAql().aql.Trim();

Assert.Equal("FOR `x` IN `Project` FILTER ( CONCAT( `x`.`Name` , @P1 ) == @P2 ) RETURN `x`", aql);
await Task.CompletedTask;
}
}
}
Loading
Loading