Skip to content

Commit

Permalink
Merge pull request #607 from Particular/empty-lists-1.0
Browse files Browse the repository at this point in the history
Add support for empty collections in saga data (release-1.0)
  • Loading branch information
DavidBoike authored May 3, 2024
2 parents 16ef1b5 + a0f290c commit 6258af5
Show file tree
Hide file tree
Showing 16 changed files with 805 additions and 31 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

<ItemGroup>
<PackageReference Include="GitHubActionsTestLogger" Version="2.3.3" />
<PackageReference Include="AWSSDK.DynamoDBv2" Version="3.7.103" />
<PackageReference Include="AWSSDK.DynamoDBv2" Version="3.7.302.25" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
<PackageReference Include="NServiceBus.Testing" Version="8.0.1" />
<PackageReference Include="NUnit3TestAdapter" Version="4.5.0" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,6 @@ dotnet_diagnostic.PS0013.severity = suggestion

# Persistence library doesn't need saga analyzers
dotnet_diagnostic.NSB0004.severity = none

# IDE0028: Simplify collection initialization
dotnet_diagnostic.IDE0028.severity = suggestion
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@
<TargetFrameworks>net481;net8.0</TargetFrameworks>
<SignAssembly>true</SignAssembly>
<AssemblyOriginatorKeyFile>..\NServiceBusTests.snk</AssemblyOriginatorKeyFile>
<LangVersion>10.0</LangVersion>
<LangVersion>12.0</LangVersion>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="GitHubActionsTestLogger" Version="2.3.3" />
<PackageReference Include="AWSSDK.DynamoDBv2" Version="3.7.103" />
<PackageReference Include="AWSSDK.DynamoDBv2" Version="3.7.302.25" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
<PackageReference Include="NServiceBus" Version="8.0.3" />
<PackageReference Include="NServiceBus.Testing" Version="8.0.1" />
Expand All @@ -21,7 +21,7 @@
<ItemGroup>
<ProjectReference Include="..\NServiceBus.Persistence.DynamoDB\NServiceBus.Persistence.DynamoDB.csproj" />
</ItemGroup>

<ItemGroup>
<Compile Include="..\NServiceBus.Persistence.DynamoDB.Tests\ClientFactory.cs" />
</ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
namespace NServiceBus.PersistenceTesting;

using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using NUnit.Framework;
using Sagas;

public class When_saving_saga_with_empty_list : SagaPersisterTests
{
[Test]
public async Task ShouldSave()
{
var sagaData = new EmptyCollectionsSagaData { SomeId = Guid.NewGuid().ToString() };
await SaveSaga(sagaData);

var read = await GetById<EmptyCollectionsSagaData>(sagaData.Id);
Assert.That(read, Is.Not.Null);
Assert.That(read.SomeId, Is.EqualTo(sagaData.SomeId));

AssertEverythingEmpty(read);
}

[Test]
public async Task ShouldUpdate()
{
var memStreams = Enumerable.Range(0, 5)
.Select(i => new MemoryStream(Encoding.UTF8.GetBytes($"Hello world {i}")))
.ToArray();

var sagaData = new EmptyCollectionsSagaData
{
SomeId = Guid.NewGuid().ToString(),
StringList = ["a", "b"],
StringArray = ["c", "d"],
RecordList = [new("e", 1.2), new("f", 3.4)],
RecordArray = [new("g", 5.6), new("h", 7.8)],
SimpleDict = new Dictionary<string, int>
{
["i"] = 9,
["j"] = 10,
},
Ints = [11, 12],
Doubles = [13.4, 15.6],
Floats = new HashSet<float>([1.234f, 5.678f]).ToImmutableHashSet(),
Bytes = new SortedSet<byte>([0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64]).ToImmutableSortedSet(),
Shorts = [1, 2, 3, 4],
UShorts = [1, 2, 3, 4],
Longs = new HashSet<long>([3147483647, 4147483647, 5147483647]).ToImmutableHashSet(),
ULongs = new HashSet<ulong>([3147483647, 4147483647, 5147483647, 18446744073709551615]).ToImmutableSortedSet(),
UInts = [2147483647, 4294967295],
SBytes = [0x0F, 0x10],
Decimals = new HashSet<decimal>([1.234m, 5.678m]).ToImmutableHashSet(),
HashSetOfMemoryStreams = new HashSet<MemoryStream>(memStreams),
ImmutableHashSetOfStreams = new HashSet<MemoryStream>(memStreams).ToImmutableHashSet(),
HashSetOfString = ["a", "b", "c", "d"],
SortedSetOfString = ["a", "b", "c", "d"],
ImmutableHashSetOfString = new HashSet<string>(["a", "b", "c", "d"]).ToImmutableHashSet(),
ImmutableSortedSetOfString = new SortedSet<string>(["a", "b", "c", "d"]).ToImmutableSortedSet(),

};
await SaveSaga(sagaData);

var context = configuration.GetContextBagForSagaStorage();
using (var session = configuration.CreateStorageSession())
{
await session.Open(context);
var read = await configuration.SagaStorage.Get<EmptyCollectionsSagaData>("SomeId", sagaData.SomeId, session, context);

Assert.That(read, Is.Not.Null);
Assert.That(read.SomeId, Is.EqualTo(sagaData.SomeId));

read.StringList = [];
read.StringArray = [];
read.RecordList = [];
read.RecordArray = [];
read.SimpleDict = [];
read.Ints = [];
read.Doubles = [];
read.Floats = ImmutableHashSet<float>.Empty;
read.Bytes = ImmutableSortedSet<byte>.Empty;
read.Shorts = [];
read.UShorts = [];
read.Longs = ImmutableHashSet<long>.Empty;
read.ULongs = ImmutableSortedSet<ulong>.Empty;
read.UInts = [];
read.SBytes = [];
read.Decimals = ImmutableHashSet<decimal>.Empty;
read.HashSetOfMemoryStreams = [];
read.ImmutableHashSetOfStreams = ImmutableHashSet<MemoryStream>.Empty;
read.HashSetOfString = [];
read.SortedSetOfString = [];
read.ImmutableHashSetOfString = ImmutableHashSet<string>.Empty;
read.ImmutableSortedSetOfString = ImmutableSortedSet<string>.Empty;

await configuration.SagaStorage.Update(read, session, context);
await session.CompleteAsync();
}

var read2 = await GetById<EmptyCollectionsSagaData>(sagaData.Id);
Assert.That(read2, Is.Not.Null);
Assert.That(read2.SomeId, Is.EqualTo(sagaData.SomeId));

AssertEverythingEmpty(read2);
}

void AssertEverythingEmpty(EmptyCollectionsSagaData data) => Assert.Multiple(() =>
{
Assert.That(data.StringList, Is.Empty);
Assert.That(data.StringArray, Is.Empty);
Assert.That(data.RecordList, Is.Empty);
Assert.That(data.RecordArray, Is.Empty);
Assert.That(data.SimpleDict, Is.Empty);
Assert.That(data.Ints, Is.Empty);
Assert.That(data.Doubles, Is.Empty);
Assert.That(data.Floats, Is.Empty);
Assert.That(data.Bytes, Is.Empty);
Assert.That(data.Shorts, Is.Empty);
Assert.That(data.UShorts, Is.Empty);
Assert.That(data.Longs, Is.Empty);
Assert.That(data.ULongs, Is.Empty);
Assert.That(data.UInts, Is.Empty);
Assert.That(data.SBytes, Is.Empty);
Assert.That(data.Decimals, Is.Empty);
Assert.That(data.HashSetOfMemoryStreams, Is.Empty);
Assert.That(data.ImmutableHashSetOfStreams, Is.Empty);
Assert.That(data.HashSetOfString, Is.Empty);
Assert.That(data.SortedSetOfString, Is.Empty);
Assert.That(data.ImmutableHashSetOfString, Is.Empty);
Assert.That(data.ImmutableSortedSetOfString, Is.Empty);
});

// Even though not used, need this class so saga data will get picked up by mapper
public class EmptyCollectionsSaga : Saga<EmptyCollectionsSagaData>,
IAmStartedByMessages<TestMessage>
{
public Task Handle(TestMessage message, IMessageHandlerContext context) => throw new NotImplementedException();

protected override void ConfigureHowToFindSaga(SagaPropertyMapper<EmptyCollectionsSagaData> mapper)
{
mapper.MapSaga(s => s.SomeId)
.ToMessage<TestMessage>(m => m.SomeId);
}
}

public class EmptyCollectionsSagaData : ContainSagaData
{
public string SomeId { get; set; } = "Test";

public List<string> StringList { get; set; } = [];
public string[] StringArray { get; set; } = [];
public List<SimpleType> RecordList { get; set; } = [];
public SimpleType[] RecordArray { get; set; } = [];
public Dictionary<string, int> SimpleDict { get; set; } = [];
public HashSet<int> Ints { get; set; } = [];
public SortedSet<double> Doubles { get; set; } = [];
public ImmutableHashSet<float> Floats { get; set; } = ImmutableHashSet<float>.Empty;
public ImmutableSortedSet<byte> Bytes { get; set; } = ImmutableSortedSet<byte>.Empty;
public HashSet<short> Shorts { get; set; } = [];
public SortedSet<ushort> UShorts { get; set; } = [];
public ImmutableHashSet<long> Longs { get; set; } = ImmutableHashSet<long>.Empty;
public ImmutableSortedSet<ulong> ULongs { get; set; } = ImmutableSortedSet<ulong>.Empty;
public HashSet<uint> UInts { get; set; } = [];
public SortedSet<sbyte> SBytes { get; set; } = [];
public ImmutableHashSet<decimal> Decimals { get; set; } = ImmutableHashSet<decimal>.Empty;
#pragma warning disable PS0025 // It is a test
public HashSet<MemoryStream> HashSetOfMemoryStreams { get; set; } = [];
public ImmutableHashSet<MemoryStream> ImmutableHashSetOfStreams { get; set; } = ImmutableHashSet<MemoryStream>.Empty;
#pragma warning restore PS0025
public HashSet<string> HashSetOfString { get; set; } = [];
public SortedSet<string> SortedSetOfString { get; set; } = [];
public ImmutableHashSet<string> ImmutableHashSetOfString { get; set; } = ImmutableHashSet<string>.Empty;
public ImmutableSortedSet<string> ImmutableSortedSetOfString { get; set; } = ImmutableSortedSet<string>.Empty;
}

public record SimpleType(string Id, double Value);

public class TestMessage : ICommand
{
public string SomeId { get; set; }
}

public When_saving_saga_with_empty_list(TestVariant param) : base(param)
{
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

<ItemGroup>
<PackageReference Include="GitHubActionsTestLogger" Version="2.3.3" />
<PackageReference Include="AWSSDK.DynamoDBv2" Version="3.7.103" />
<PackageReference Include="AWSSDK.DynamoDBv2" Version="3.7.302.25" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
<PackageReference Include="NServiceBus.Testing" Version="8.0.1" />
<PackageReference Include="NUnit3TestAdapter" Version="4.5.0" />
Expand Down
3 changes: 3 additions & 0 deletions src/NServiceBus.Persistence.DynamoDB.Tests/.editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,6 @@ dotnet_diagnostic.CA2007.severity = none

# Justification: Tests don't support cancellation and don't need to forward IMessageHandlerContext.CancellationToken
dotnet_diagnostic.NSB0002.severity = suggestion

# IDE0028: Simplify collection initialization
dotnet_diagnostic.IDE0028.severity = suggestion
Original file line number Diff line number Diff line change
Expand Up @@ -14,105 +14,126 @@
"BOOL": false,
"IsBOOLSet": false,
"BS": [],
"IsBSSet": false,
"L": [],
"IsLSet": false,
"M": {},
"IsMSet": false,
"N": null,
"NS": [],
"IsNSSet": false,
"NULL": false,
"S": "OUTBOX#SchemaVersionTest#FFC8A2FD-0335-47C8-A29D-9EEA6C8445D8",
"SS": []
"SS": [],
"IsSSSet": false
},
"SK": {
"B": null,
"BOOL": false,
"IsBOOLSet": false,
"BS": [],
"IsBSSet": false,
"L": [],
"IsLSet": false,
"M": {},
"IsMSet": false,
"N": null,
"NS": [],
"IsNSSet": false,
"NULL": false,
"S": "OUTBOX#METADATA#FFC8A2FD-0335-47C8-A29D-9EEA6C8445D8",
"SS": []
"SS": [],
"IsSSSet": false
},
"OperationsCount": {
"B": null,
"BOOL": false,
"IsBOOLSet": false,
"BS": [],
"IsBSSet": false,
"L": [],
"IsLSet": false,
"M": {},
"IsMSet": false,
"N": "0",
"NS": [],
"IsNSSet": false,
"NULL": false,
"S": null,
"SS": []
"SS": [],
"IsSSSet": false
},
"Dispatched": {
"B": null,
"BOOL": false,
"IsBOOLSet": true,
"BS": [],
"IsBSSet": false,
"L": [],
"IsLSet": false,
"M": {},
"IsMSet": false,
"N": null,
"NS": [],
"IsNSSet": false,
"NULL": false,
"S": null,
"SS": []
"SS": [],
"IsSSSet": false
},
"DispatchedAt": {
"B": null,
"BOOL": false,
"IsBOOLSet": false,
"BS": [],
"IsBSSet": false,
"L": [],
"IsLSet": false,
"M": {},
"IsMSet": false,
"N": null,
"NS": [],
"IsNSSet": false,
"NULL": true,
"S": null,
"SS": []
"SS": [],
"IsSSSet": false
},
"SchemaVersion": {
"B": null,
"BOOL": false,
"IsBOOLSet": false,
"BS": [],
"IsBSSet": false,
"L": [],
"IsLSet": false,
"M": {},
"IsMSet": false,
"N": null,
"NS": [],
"IsNSSet": false,
"NULL": false,
"S": "1.0",
"SS": []
"SS": [],
"IsSSSet": false
},
"ExpiresAt": {
"B": null,
"BOOL": false,
"IsBOOLSet": false,
"BS": [],
"IsBSSet": false,
"L": [],
"IsLSet": false,
"M": {},
"IsMSet": false,
"N": null,
"NS": [],
"IsNSSet": false,
"NULL": true,
"S": null,
"SS": []
"SS": [],
"IsSSSet": false
}
},
"ReturnValuesOnConditionCheckFailure": null,
Expand Down
Loading

0 comments on commit 6258af5

Please sign in to comment.