Skip to content

Commit ae74439

Browse files
committed
Merge branch 'develop'
2 parents 0fe1a95 + e718af5 commit ae74439

8 files changed

Lines changed: 76 additions & 22 deletions

File tree

RELEASE_NOTES.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,11 @@
1-
### New in 0.58 (not released yet)
1+
### New in 0.59 (not released yet)
2+
3+
* Fix: Commands are now correctly published when no events are emitted from a saga
4+
after handling a domain event
5+
* Minor fix: Updated name of Primary Key for MSSQL Snapshot Store to be different
6+
from MSSQL Event Store, so both can be used in the same database without conflicts
7+
8+
### New in 0.58.3377 (released 2018-05-15)
29

310
* Minor fix: Corrected log in `CommandBus` regarding events emitted due to command
411

Source/EventFlow.MsSql/SnapshotStores/Scripts/0001 - Create EventFlowSnapshots.sql

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ BEGIN
77
[AggregateSequenceNumber] [int] NOT NULL,
88
[Data] [nvarchar](MAX) NOT NULL,
99
[Metadata] [nvarchar](MAX) NOT NULL,
10-
CONSTRAINT [PK_EventFlow] PRIMARY KEY CLUSTERED
10+
CONSTRAINT [PK_EventFlowSnapshots] PRIMARY KEY CLUSTERED
1111
(
1212
[Id] ASC
1313
)
@@ -19,4 +19,4 @@ BEGIN
1919
[AggregateId] ASC,
2020
[AggregateSequenceNumber] ASC
2121
)
22-
END
22+
END

Source/EventFlow.TestHelpers/Aggregates/Sagas/ThingySaga.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,4 +110,4 @@ public void Apply(ThingySagaCompletedEvent aggregateEvent)
110110
Complete();
111111
}
112112
}
113-
}
113+
}

Source/EventFlow.TestHelpers/Test.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,10 +79,10 @@ protected T Inject<T>(T instance)
7979
return instance;
8080
}
8181

82-
protected Mock<T> InjectMock<T>()
82+
protected Mock<T> InjectMock<T>(params object[] args)
8383
where T : class
8484
{
85-
var mock = new Mock<T>();
85+
var mock = new Mock<T>(args);
8686
Fixture.Inject(mock.Object);
8787
return mock;
8888
}

Source/EventFlow.Tests/UnitTests/Sagas/AggregateSagas/SagaAggregateStoreTests.cs

Lines changed: 54 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -23,14 +23,15 @@
2323

2424
using System;
2525
using System.Collections.Generic;
26+
using System.Linq;
2627
using System.Threading;
2728
using System.Threading.Tasks;
2829
using EventFlow.Aggregates;
2930
using EventFlow.Core;
3031
using EventFlow.Core.Caching;
31-
using EventFlow.Sagas;
3232
using EventFlow.Sagas.AggregateSagas;
3333
using EventFlow.TestHelpers;
34+
using EventFlow.TestHelpers.Aggregates.Events;
3435
using EventFlow.TestHelpers.Aggregates.Sagas;
3536
using Moq;
3637
using NUnit.Framework;
@@ -40,26 +41,25 @@ namespace EventFlow.Tests.UnitTests.Sagas.AggregateSagas
4041
[Category(Categories.Unit)]
4142
public class SagaAggregateStoreTests : TestsFor<SagaAggregateStore>
4243
{
44+
private ThingySagaId _thingySagaId;
45+
private Mock<ThingySaga> _thingySaga;
46+
4347
[SetUp]
4448
public void SetUp()
4549
{
50+
_thingySagaId = A<ThingySagaId>();
51+
_thingySaga = InjectMock<ThingySaga>(_thingySagaId);
52+
4653
Inject<IMemoryCache>(A<MemoryCache>());
4754
}
4855

4956
[Test]
5057
public async Task AggregateStore_UpdateAsync_IsInvoked()
5158
{
5259
// Arrange
53-
var aggregateStoreMock = InjectMock<IAggregateStore>();
5460
var thingySagaId = A<ThingySagaId>();
5561
var sourceId = A<SourceId>();
56-
aggregateStoreMock
57-
.Setup(s => s.UpdateAsync(
58-
thingySagaId,
59-
sourceId,
60-
It.IsAny<Func<ThingySaga, CancellationToken, Task>>(),
61-
It.IsAny<CancellationToken>()))
62-
.ReturnsAsync(new List<IDomainEvent>());
62+
var aggregateStoreMock = ArrangeAggregateStoreMock(thingySagaId, sourceId, A<bool>());
6363

6464
// Act
6565
await Sut.UpdateAsync(
@@ -78,5 +78,50 @@ await Sut.UpdateAsync(
7878
It.IsAny<CancellationToken>()),
7979
Times.Once);
8080
}
81+
82+
[TestCase(true)]
83+
[TestCase(false)]
84+
public async Task CommandBus_PublishAsync_IsInvoked(bool eventsAreEmitted)
85+
{
86+
// Arrange
87+
var thingySagaId = A<ThingySagaId>();
88+
var sourceId = A<SourceId>();
89+
ArrangeAggregateStoreMock(thingySagaId, sourceId, eventsAreEmitted);
90+
91+
// Act
92+
await Sut.UpdateAsync(
93+
thingySagaId,
94+
typeof(ThingySaga),
95+
sourceId,
96+
(s, c) => Task.FromResult(0),
97+
CancellationToken.None);
98+
99+
// Assert
100+
_thingySaga.Verify(
101+
s => s.PublishAsync(It.IsAny<ICommandBus>(), It.IsAny<CancellationToken>()),
102+
Times.AtLeastOnce);
103+
}
104+
105+
private Mock<IAggregateStore> ArrangeAggregateStoreMock(
106+
ThingySagaId thingySagaId,
107+
ISourceId sourceId,
108+
bool returnsDomainEvents)
109+
{
110+
var aggregateStoreMock = InjectMock<IAggregateStore>();
111+
var domainEvents = ManyDomainEvents<ThingyPingEvent>(returnsDomainEvents ? 3 : 0)
112+
.Cast<IDomainEvent>()
113+
.ToList();
114+
115+
aggregateStoreMock
116+
.Setup(s => s.UpdateAsync(
117+
thingySagaId,
118+
sourceId,
119+
It.IsAny<Func<ThingySaga, CancellationToken, Task>>(),
120+
It.IsAny<CancellationToken>()))
121+
.Callback<ThingySagaId, ISourceId, Func<ThingySaga, CancellationToken, Task>, CancellationToken>(
122+
(id, sid, f, c) => f(_thingySaga.Object, CancellationToken.None).Wait(c))
123+
.ReturnsAsync(domainEvents);
124+
return aggregateStoreMock;
125+
}
81126
}
82127
}

Source/EventFlow/Sagas/AggregateSagas/AggregateSaga.cs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -64,13 +64,15 @@ protected void Publish<TCommandAggregate, TCommandAggregateIdentity, TExecutionR
6464
? SagaState.Completed
6565
: IsNew ? SagaState.New : SagaState.Running;
6666

67-
public async Task PublishAsync(ICommandBus commandBus, CancellationToken cancellationToken)
67+
public virtual async Task PublishAsync(ICommandBus commandBus, CancellationToken cancellationToken)
6868
{
69-
foreach (var unpublishedCommand in _unpublishedCommands.ToList())
69+
var commandsToPublish = _unpublishedCommands.ToList();
70+
_unpublishedCommands.Clear();
71+
72+
foreach (var unpublishedCommand in commandsToPublish)
7073
{
7174
await unpublishedCommand(commandBus, cancellationToken).ConfigureAwait(false);
72-
_unpublishedCommands.Remove(unpublishedCommand);
7375
}
7476
}
7577
}
76-
}
78+
}

Source/EventFlow/Sagas/AggregateSagas/SagaAggregateStore.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ public override async Task<ISaga> UpdateAsync(
6565
cancellationToken)
6666
.ConfigureAwait(false);
6767

68-
var domainEvents = await storeAggregateSagaAsync(
68+
await storeAggregateSagaAsync(
6969
this,
7070
sagaId,
7171
sourceId,
@@ -77,7 +77,7 @@ public override async Task<ISaga> UpdateAsync(
7777
cancellationToken)
7878
.ConfigureAwait(false);
7979

80-
if (!domainEvents.Any())
80+
if (saga is null)
8181
{
8282
return null;
8383
}

appveyor.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
init:
22
- git config --global core.autocrlf input
33

4-
version: 0.58.{build}
4+
version: 0.59.{build}
55

66
skip_tags: true
77

0 commit comments

Comments
 (0)