Test conflicting ListEventsAsync in the critical section
MODIFY
WalletWasabi.Tests/UnitTests/EventSourcing/InMemoryEventRepositoryTests.cs
WalletWasabi.Tests/UnitTests/EventSourcing/InMemoryEventRepositoryTests.cs
@@ -376,5 +376,58 @@ namespace WalletWasabi.Tests.UnitTests.EventSourcing
Assert.True((await EventRepository.ListAggregateIdsAsync(nameof(TestRoundAggregate)))
.SequenceEqual(new[] { "1" }));
}
+
+ [Theory]
+ [InlineData(nameof(TestInMemoryEventRepository.ValidatedCallback))]
+ [InlineData(nameof(TestInMemoryEventRepository.LockedCallback))]
+ [InlineData(nameof(TestInMemoryEventRepository.AppendedCallback))]
+ [InlineData(nameof(TestInMemoryEventRepository.UnlockedCallback))]
+ public async Task ListEventsAsync_ConflictWithAppending_Async(string listOnCallback)
+ {
+ // Arrange
+ var events_1 = new[] { new TestWrappedEvent(1, "a"), new TestWrappedEvent(2, "a") };
+ var events_2 = new[] { new TestWrappedEvent(3, "b"), new TestWrappedEvent(4, "b") };
+ await EventRepository.AppendEventsAsync(nameof(TestRoundAggregate), "1", events_1);
+
+ // Act
+ IReadOnlyList<WrappedEvent> result = Array.Empty<WrappedEvent>().ToList().AsReadOnly();
+ void ListCallback()
+ {
+ result = EventRepository.ListEventsAsync(nameof(TestRoundAggregate), "1").Result;
+ }
+ switch (listOnCallback)
+ {
+ case nameof(TestInMemoryEventRepository.ValidatedCallback):
+ TestEventRepository.ValidatedCallback = ListCallback;
+ break;
+
+ case nameof(TestInMemoryEventRepository.LockedCallback):
+ TestEventRepository.LockedCallback = ListCallback;
+ break;
+
+ case nameof(TestInMemoryEventRepository.AppendedCallback):
+ TestEventRepository.AppendedCallback = ListCallback;
+ break;
+
+ case nameof(TestInMemoryEventRepository.UnlockedCallback):
+ TestEventRepository.UnlockedCallback = ListCallback;
+ break;
+
+ default:
+ throw new ApplicationException($"unexpected value listOnCallback: '{listOnCallback}'");
+ }
+ await EventRepository.AppendEventsAsync(nameof(TestRoundAggregate), "1", events_2);
+
+ // Assert
+ var expected = events_1.AsEnumerable();
+ switch (listOnCallback)
+ {
+ case nameof(TestInMemoryEventRepository.AppendedCallback):
+ case nameof(TestInMemoryEventRepository.UnlockedCallback):
+ expected = expected.Concat(events_2);
+ break;
+ }
+ Assert.True(result.SequenceEqual(expected));
+ }
}
}

MODIFY
WalletWasabi/EventSourcing/InMemoryEventRepository.cs
WalletWasabi/EventSourcing/InMemoryEventRepository.cs
@@ -127,13 +127,13 @@ namespace WalletWasabi.EventSourcing
}
public Task<IReadOnlyList<WrappedEvent>> ListEventsAsync(string aggregateType,
- string aggregateId, long afterSequenceId = -1, int? limit = null)
+ string aggregateId, long afterSequenceId = 0, int? limit = null)
{
if (_aggregatesEventsBatches.TryGetValue(aggregateType, out var aggregateEventsBatches) &&
aggregateEventsBatches.TryGetValue(aggregateId, out var value))
{
var result = value.EventsBatches.SelectMany(a => a);
- if (-1 < afterSequenceId)
+ if (0 < afterSequenceId)
{
result = result.Where(a => afterSequenceId < a.SequenceId);
}

Test conflicting ListEventsAsync in the critical section