Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
namespace DotNet.Testcontainers.Configurations
{
using System.Text.Json;

internal static class DefaultJsonSerializerOptions
{
static DefaultJsonSerializerOptions()
{
Instance.Converters.Add(new JsonOrderedKeysConverter());
}

public static JsonSerializerOptions Instance { get; } = new JsonSerializerOptions();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,16 @@ namespace DotNet.Testcontainers.Configurations

internal sealed class JsonIgnoreRuntimeResourceLabels : JsonOrderedKeysConverter
{
private static readonly ISet<string> IgnoreLabels = new HashSet<string> { ResourceReaper.ResourceReaperSessionLabel, TestcontainersClient.TestcontainersVersionLabel, TestcontainersClient.TestcontainersSessionIdLabel };
private static readonly ISet<string> IgnoreLabels = new HashSet<string>
{
ResourceReaper.ResourceReaperSessionLabel,
TestcontainersClient.TestcontainersVersionLabel,
TestcontainersClient.TestcontainersSessionIdLabel,
};

public override void Write(Utf8JsonWriter writer, IReadOnlyDictionary<string, string> value, JsonSerializerOptions options)
{
var labels = value.Where(label => !IgnoreLabels.Contains(label.Key)).ToDictionary(label => label.Key, label => label.Value);

base.Write(writer, labels, options);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,6 @@ namespace DotNet.Testcontainers.Configurations
[PublicAPI]
public class ResourceConfiguration<TCreateResourceEntity> : IResourceConfiguration<TCreateResourceEntity>
{
private static readonly JsonSerializerOptions JsonSerializerOptions;

static ResourceConfiguration()
{
JsonSerializerOptions = new JsonSerializerOptions { Converters = { new JsonOrderedKeysConverter() } };
}

/// <summary>
/// Initializes a new instance of the <see cref="ResourceConfiguration{TCreateResourceEntity}" /> class.
/// </summary>
Expand Down Expand Up @@ -95,7 +88,7 @@ protected ResourceConfiguration(IResourceConfiguration<TCreateResourceEntity> ol
/// <inheritdoc />
public virtual string GetReuseHash()
{
var jsonUtf8Bytes = JsonSerializer.SerializeToUtf8Bytes(this, GetType(), JsonSerializerOptions);
var jsonUtf8Bytes = JsonSerializer.SerializeToUtf8Bytes(this, GetType(), DefaultJsonSerializerOptions.Instance);

#if NET6_0_OR_GREATER
return Convert.ToBase64String(SHA1.HashData(jsonUtf8Bytes));
Expand Down
88 changes: 63 additions & 25 deletions tests/Testcontainers.Platform.Linux.Tests/ReusableResourceTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -104,37 +104,75 @@
{
[Fact]
[Trait(nameof(DockerCli.DockerPlatform), nameof(DockerCli.DockerPlatform.Linux))]
public void ForSameConfigurationCreatedInDifferentOrder()
public void ForKnownConfiguration()
{
var env1 = new Dictionary<string, string>
{
["keyA"] = "valueA",
["keyB"] = "valueB",
};
var env2 = new Dictionary<string, string>
{
["keyB"] = "valueB",
["keyA"] = "valueA",
};
var hash1 = new ReuseHashContainerBuilder().WithEnvironment(env1).WithLabel("labelA", "A").WithLabel("labelB", "B").GetReuseHash();
var hash2 = new ReuseHashContainerBuilder().WithEnvironment(env2).WithLabel("labelB", "B").WithLabel("labelA", "A").GetReuseHash();
Assert.Equal(hash1, hash2);
// Given
var env = new Dictionary<string, string>();
env["keyA"] = "valueA";
env["keyB"] = "valueB";

// When
var hash = new ReuseHashContainerBuilder()
.WithEnvironment(env)
.WithLabel("labelA", "A")
.WithLabel("labelB", "B")
.GetReuseHash();

// Then

// `50MEP+vnxEkQFo5PrndJ7oKOfh8=` is the Base64-encoded SHA-1 hash of this JSON:
//
// {
// "Image": null,
// "Name": null,
// "Entrypoint": null,
// "Command": [],
// "Environments": {
// "keyA": "valueA",
// "keyB": "valueB"
// },
// "ExposedPorts": {},
// "PortBindings": {},
// "NetworkAliases": [],
// "ExtraHosts": [],
// "Labels": {
// "labelA": "A",
// "labelB": "B",
// "org.testcontainers": "true",
// "org.testcontainers.lang": "dotnet"
// }
// }
Assert.Equal("50MEP+vnxEkQFo5PrndJ7oKOfh8=", hash);

Check failure on line 145 in tests/Testcontainers.Platform.Linux.Tests/ReusableResourceTest.cs

View workflow job for this annotation

GitHub Actions / test-report

Testcontainers.Tests.ReusableResourceTest+ReuseHashTest+EqualTest ► ForKnownConfiguration

Failed test found in: Testcontainers.Platform.Linux/Testcontainers.Platform.Linux.Tests.trx Error: Assert.Equal() Failure: Strings differ ↓ (pos 0) Expected: "50MEP+vnxEkQFo5PrndJ7oKOfh8=" Actual: "zS1Mk5gxRr6ulIvjvC0uvjYAjlo=" ↑ (pos 0) at Testcontainers.Tests.ReusableResourceTest.ReuseHashTest.EqualTest.ForKnownConfiguration() in /home/runner/work/testcontainers-dotnet/testcontainers-dotnet/tests/Testcontainers.Platform.Linux.Tests/ReusableResourceTest.cs:line 145 at System.RuntimeMethodHandle.InvokeMethod(Object target, Void** arguments, Signature sig, Boolean isConstructor) at System.Reflection.MethodBaseInvoker.InvokeWithNoArgs(Object obj, BindingFlags invokeAttr)
Raw output
Assert.Equal() Failure: Strings differ
           ↓ (pos 0)
Expected: "50MEP+vnxEkQFo5PrndJ7oKOfh8="
Actual:   "zS1Mk5gxRr6ulIvjvC0uvjYAjlo="
           ↑ (pos 0)
   at Testcontainers.Tests.ReusableResourceTest.ReuseHashTest.EqualTest.ForKnownConfiguration() in /home/runner/work/testcontainers-dotnet/testcontainers-dotnet/tests/Testcontainers.Platform.Linux.Tests/ReusableResourceTest.cs:line 145
   at System.RuntimeMethodHandle.InvokeMethod(Object target, Void** arguments, Signature sig, Boolean isConstructor)
   at System.Reflection.MethodBaseInvoker.InvokeWithNoArgs(Object obj, BindingFlags invokeAttr)
}

[Fact]
[Trait(nameof(DockerCli.DockerPlatform), nameof(DockerCli.DockerPlatform.Linux))]
public void ForGivenConfiguration()
public void ForSameConfigurationInDifferentOrder()
{
var env = new Dictionary<string, string>
{
["keyB"] = "valueB",
["keyA"] = "valueA",
};
var hash = new ReuseHashContainerBuilder().WithEnvironment(env).WithLabel("labelB", "B").WithLabel("labelA", "A").GetReuseHash();

// 50MEP+vnxEkQFo5PrndJ7oKOfh8= is the base64 encoded SHA1 of this JSON:
// {"Image":null,"Name":null,"Entrypoint":null,"Command":[],"Environments":{"keyA":"valueA","keyB":"valueB"},"ExposedPorts":{},"PortBindings":{},"NetworkAliases":[],"ExtraHosts":[],"Labels":{"labelA":"A","labelB":"B","org.testcontainers":"true","org.testcontainers.lang":"dotnet"}}
Assert.Equal("50MEP+vnxEkQFo5PrndJ7oKOfh8=", hash);
// Given
var env1 = new Dictionary<string, string>();
env1["keyA"] = "valueA";
env1["keyB"] = "valueB";

var env2 = new Dictionary<string, string>();
env2["keyB"] = "valueB";
env2["keyA"] = "valueA";

// When
var hash1 = new ReuseHashContainerBuilder()
.WithEnvironment(env1)
.WithLabel("labelA", "A")
.WithLabel("labelB", "B")
.GetReuseHash();

var hash2 = new ReuseHashContainerBuilder()
.WithEnvironment(env2)
.WithLabel("labelB", "B")
.WithLabel("labelA", "A")
.GetReuseHash();

// Then
Assert.Equal(hash1, hash2);
}
}

Expand Down