Skip to content

Commit 46a52cb

Browse files
committed
Merge branch 'develop'
2 parents 8e9a4e2 + 117e274 commit 46a52cb

23 files changed

+3036
-57
lines changed

RELEASE_NOTES.md

+9-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,12 @@
1-
### New in 0.53 (not released yet)
1+
### New in 0.54 (not released yet)
2+
3+
- **Critical fix:** `SagaAggregateStore` was incorrectly putting a object reference
4+
into its memory cache causing an object already disposed exception when working with
5+
sagas
6+
- New: Added [LibLog](https://github.com/damianh/LibLog), enable by
7+
calling the `IEventFlowOptions.UseLibLog(...)` extension
8+
9+
### New in 0.53.3204 (released 2018-01-25)
210

311
* New: Allow events to have multiple `EventVersion` attributes
412
* Fixed: `ReflectionHelper.CompileMethodInvocation` now recognises
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
// The MIT License (MIT)
2+
//
3+
// Copyright (c) 2015-2018 Rasmus Mikkelsen
4+
// Copyright (c) 2015-2018 eBay Software Foundation
5+
// https://github.com/eventflow/EventFlow
6+
//
7+
// Permission is hereby granted, free of charge, to any person obtaining a copy of
8+
// this software and associated documentation files (the "Software"), to deal in
9+
// the Software without restriction, including without limitation the rights to
10+
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
11+
// the Software, and to permit persons to whom the Software is furnished to do so,
12+
// subject to the following conditions:
13+
//
14+
// The above copyright notice and this permission notice shall be included in all
15+
// copies or substantial portions of the Software.
16+
//
17+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
19+
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
20+
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
21+
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22+
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23+
24+
using EventFlow.Autofac.Extensions;
25+
using EventFlow.Configuration;
26+
using EventFlow.TestHelpers;
27+
using EventFlow.TestHelpers.Suites;
28+
using NUnit.Framework;
29+
30+
namespace EventFlow.Autofac.Tests.IntegrationTests
31+
{
32+
[Category(Categories.Integration)]
33+
public class AutofacServiceRegistrationIntegrationTests : IntegrationTestSuiteForServiceRegistration
34+
{
35+
protected override IEventFlowOptions Options(IEventFlowOptions eventFlowOptions)
36+
{
37+
return base.Options(eventFlowOptions
38+
.UseAutofacContainerBuilder());
39+
}
40+
41+
protected override IRootResolver CreateRootResolver(IEventFlowOptions eventFlowOptions)
42+
{
43+
return eventFlowOptions
44+
.CreateResolver();
45+
}
46+
}
47+
}

Source/EventFlow.TestHelpers/IntegrationTest.cs

+13-2
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
using EventFlow.Snapshots.Stores;
3838
using EventFlow.TestHelpers.Aggregates;
3939
using EventFlow.TestHelpers.Aggregates.Commands;
40+
using EventFlow.TestHelpers.Aggregates.Sagas;
4041
using EventFlow.TestHelpers.Aggregates.ValueObjects;
4142
using EventFlow.TestHelpers.Extensions;
4243
using NUnit.Framework;
@@ -60,10 +61,10 @@ public abstract class IntegrationTest: Test
6061
[SetUp]
6162
public void SetUpIntegrationTest()
6263
{
63-
var eventFlowOptions = EventFlowOptions.New
64+
var eventFlowOptions = Options(EventFlowOptions.New)
6465
.AddDefaults(EventFlowTestHelpers.Assembly);
6566

66-
Resolver = CreateRootResolver(Options(eventFlowOptions));
67+
Resolver = CreateRootResolver(eventFlowOptions);
6768

6869
AggregateStore = Resolver.Resolve<IAggregateStore>();
6970
EventStore = Resolver.Resolve<IEventStore>();
@@ -101,6 +102,16 @@ protected async Task<PingId> PublishPingCommandAsync(ThingyId thingyId)
101102
return pingIds.Single();
102103
}
103104

105+
protected Task<ThingySaga> LoadSagaAsync(ThingyId thingyId)
106+
{
107+
// This is specified in the ThingySagaLocator
108+
var expectedThingySagaId = new ThingySagaId($"saga-{thingyId.Value}");
109+
110+
return AggregateStore.LoadAsync<ThingySaga, ThingySagaId>(
111+
expectedThingySagaId,
112+
CancellationToken.None);
113+
}
114+
104115
protected async Task<IReadOnlyCollection<PingId>> PublishPingCommandsAsync(ThingyId thingyId, int count)
105116
{
106117
if (count <= 0) throw new ArgumentOutOfRangeException(nameof(count));
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
// The MIT License (MIT)
2+
//
3+
// Copyright (c) 2015-2016 Rasmus Mikkelsen
4+
// Copyright (c) 2015-2016 eBay Software Foundation
5+
// https://github.com/rasmus/EventFlow
6+
//
7+
// Permission is hereby granted, free of charge, to any person obtaining a copy of
8+
// this software and associated documentation files (the "Software"), to deal in
9+
// the Software without restriction, including without limitation the rights to
10+
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
11+
// the Software, and to permit persons to whom the Software is furnished to do so,
12+
// subject to the following conditions:
13+
//
14+
// The above copyright notice and this permission notice shall be included in all
15+
// copies or substantial portions of the Software.
16+
//
17+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
19+
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
20+
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
21+
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22+
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23+
24+
using System.Threading;
25+
using System.Threading.Tasks;
26+
using EventFlow.Sagas;
27+
using EventFlow.TestHelpers.Aggregates;
28+
using EventFlow.TestHelpers.Aggregates.Commands;
29+
using FluentAssertions;
30+
using NUnit.Framework;
31+
32+
namespace EventFlow.TestHelpers.Suites
33+
{
34+
public abstract class IntegrationTestSuiteForServiceRegistration : IntegrationTest
35+
{
36+
[Test]
37+
public async Task PublishingStartAndCompleteTiggerEventsCompletesSaga()
38+
{
39+
// Arrange
40+
var thingyId = A<ThingyId>();
41+
42+
// Act
43+
using (var scope = Resolver.BeginScope())
44+
{
45+
var commandBus = scope.Resolve<ICommandBus>();
46+
await commandBus.PublishAsync(new ThingyRequestSagaStartCommand(thingyId), CancellationToken.None).ConfigureAwait(false);
47+
}
48+
using (var scope = Resolver.BeginScope())
49+
{
50+
var commandBus = scope.Resolve<ICommandBus>();
51+
await commandBus.PublishAsync(new ThingyRequestSagaCompleteCommand(thingyId), CancellationToken.None).ConfigureAwait(false);
52+
}
53+
54+
// Assert
55+
var thingySaga = await LoadSagaAsync(thingyId).ConfigureAwait(false);
56+
thingySaga.State.Should().Be(SagaState.Completed);
57+
}
58+
}
59+
}

Source/EventFlow.Tests/EventFlow.Tests.csproj

+1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
<ProjectReference Include="..\EventFlow.TestHelpers\EventFlow.TestHelpers.csproj" />
1010
</ItemGroup>
1111
<ItemGroup>
12+
<PackageReference Include="Serilog" Version="2.6.0" />
1213
<PackageReference Include="WindowsBase" Version="4.6.1055" />
1314
</ItemGroup>
1415
</Project>

Source/EventFlow.Tests/IntegrationTests/CommandResultTests.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ public TestExecutionResult(
5353

5454
public class TestSuccessResultCommand : Command<ThingyAggregate, ThingyId, TestExecutionResult>
5555
{
56-
public TestSuccessResultCommand(ThingyId aggregateId) : base(aggregateId, Core.SourceId.New)
56+
public TestSuccessResultCommand(ThingyId aggregateId) : base(aggregateId, EventFlow.Core.SourceId.New)
5757
{
5858
}
5959
}
@@ -72,7 +72,7 @@ public override Task<TestExecutionResult> ExecuteCommandAsync(
7272

7373
public class TestFailedResultCommand : Command<ThingyAggregate, ThingyId, IExecutionResult>
7474
{
75-
public TestFailedResultCommand(ThingyId aggregateId) : base(aggregateId, Core.SourceId.New)
75+
public TestFailedResultCommand(ThingyId aggregateId) : base(aggregateId, EventFlow.Core.SourceId.New)
7676
{
7777
}
7878
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// The MIT License (MIT)
2+
//
3+
// Copyright (c) 2015-2018 Rasmus Mikkelsen
4+
// Copyright (c) 2015-2018 eBay Software Foundation
5+
// https://github.com/eventflow/EventFlow
6+
//
7+
// Permission is hereby granted, free of charge, to any person obtaining a copy of
8+
// this software and associated documentation files (the "Software"), to deal in
9+
// the Software without restriction, including without limitation the rights to
10+
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
11+
// the Software, and to permit persons to whom the Software is furnished to do so,
12+
// subject to the following conditions:
13+
//
14+
// The above copyright notice and this permission notice shall be included in all
15+
// copies or substantial portions of the Software.
16+
//
17+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
19+
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
20+
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
21+
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22+
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23+
24+
using EventFlow.Configuration;
25+
using EventFlow.TestHelpers;
26+
using EventFlow.TestHelpers.Suites;
27+
using NUnit.Framework;
28+
29+
namespace EventFlow.Tests.IntegrationTests.Core.IoC
30+
{
31+
[Category(Categories.Integration)]
32+
public class EventFlowServiceRegistrationIntegrationTests : IntegrationTestSuiteForServiceRegistration
33+
{
34+
protected override IRootResolver CreateRootResolver(IEventFlowOptions eventFlowOptions)
35+
{
36+
return eventFlowOptions
37+
.CreateResolver();
38+
}
39+
}
40+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
// The MIT License (MIT)
2+
//
3+
// Copyright (c) 2015-2018 Rasmus Mikkelsen
4+
// Copyright (c) 2015-2018 eBay Software Foundation
5+
// https://github.com/eventflow/EventFlow
6+
//
7+
// Permission is hereby granted, free of charge, to any person obtaining a copy of
8+
// this software and associated documentation files (the "Software"), to deal in
9+
// the Software without restriction, including without limitation the rights to
10+
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
11+
// the Software, and to permit persons to whom the Software is furnished to do so,
12+
// subject to the following conditions:
13+
//
14+
// The above copyright notice and this permission notice shall be included in all
15+
// copies or substantial portions of the Software.
16+
//
17+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
19+
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
20+
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
21+
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22+
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23+
24+
using System;
25+
using System.Collections.Generic;
26+
using System.Linq;
27+
using EventFlow.Extensions;
28+
using EventFlow.TestHelpers;
29+
using FluentAssertions;
30+
using NUnit.Framework;
31+
using Serilog;
32+
using Serilog.Core;
33+
using Serilog.Events;
34+
using ILog = EventFlow.Logs.ILog;
35+
using LogLevel = EventFlow.Logs.LogLevel;
36+
37+
namespace EventFlow.Tests.IntegrationTests.Logs
38+
{
39+
public class LibLogTests : Test
40+
{
41+
[Test]
42+
public void SerilogTest()
43+
{
44+
var messages = new Dictionary<LogEventLevel, List<string>>
45+
{
46+
{LogEventLevel.Verbose, new List<string>()},
47+
{LogEventLevel.Debug, new List<string>()},
48+
{LogEventLevel.Information, new List<string>()},
49+
{LogEventLevel.Warning, new List<string>()},
50+
{LogEventLevel.Error, new List<string>()},
51+
{LogEventLevel.Fatal, new List<string>()}
52+
};
53+
54+
Serilog.Log.Logger = new LoggerConfiguration()
55+
.MinimumLevel.Verbose()
56+
.WriteTo.Sink(new DummySink(messages))
57+
.CreateLogger();
58+
59+
using (var resolver = EventFlowOptions.New
60+
.UseLibLog(LibLogProviders.Serilog)
61+
.CreateResolver())
62+
{
63+
var log = resolver.Resolve<ILog>();
64+
void TestLog(LogLevel logLevel, LogEventLevel logEventLevel)
65+
{
66+
var message = Guid.NewGuid().ToString("N");
67+
log.Write(logLevel, message);
68+
messages[logEventLevel].FirstOrDefault(m => m == message).Should().NotBeNullOrEmpty();
69+
}
70+
71+
TestLog(LogLevel.Verbose, LogEventLevel.Verbose);
72+
TestLog(LogLevel.Debug, LogEventLevel.Debug);
73+
TestLog(LogLevel.Information, LogEventLevel.Information);
74+
TestLog(LogLevel.Warning, LogEventLevel.Warning);
75+
TestLog(LogLevel.Error, LogEventLevel.Error);
76+
TestLog(LogLevel.Fatal, LogEventLevel.Fatal);
77+
}
78+
}
79+
80+
private class DummySink : ILogEventSink
81+
{
82+
private readonly Dictionary<LogEventLevel, List<string>> _messages;
83+
84+
public DummySink(Dictionary<LogEventLevel, List<string>> messages)
85+
{
86+
_messages = messages;
87+
}
88+
89+
public void Emit(LogEvent logEvent)
90+
{
91+
_messages[logEvent.Level].Add(logEvent.RenderMessage());
92+
}
93+
}
94+
}
95+
}

Source/EventFlow.Tests/IntegrationTests/Sagas/AggregateSagaTests.cs

-10
Original file line numberDiff line numberDiff line change
@@ -170,16 +170,6 @@ public async Task PublishingStartAndCompleteWithPingsResultInCorrectMessages()
170170
receivedSagaPingIds.ShouldAllBeEquivalentTo(pingsWithRunningSaga);
171171
}
172172

173-
private Task<ThingySaga> LoadSagaAsync(ThingyId thingyId)
174-
{
175-
// This is specified in the ThingySagaLocator
176-
var expectedThingySagaId = new ThingySagaId($"saga-{thingyId.Value}");
177-
178-
return AggregateStore.LoadAsync<ThingySaga, ThingySagaId>(
179-
expectedThingySagaId,
180-
CancellationToken.None);
181-
}
182-
183173
protected override IRootResolver CreateRootResolver(IEventFlowOptions eventFlowOptions)
184174
{
185175
_thingySagaStartedSubscriber = new Mock<ISubscribeSynchronousTo<ThingySaga, ThingySagaId, ThingySagaStartedEvent>>();

Source/EventFlow/Core/Caching/DictionaryMemoryCache.cs

+3-2
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,9 @@ protected override Task<T> GetAsync<T>(
6969
CacheKey cacheKey,
7070
CancellationToken cancellationToken)
7171
{
72-
var value = _cache[cacheKey.Value] as T;
73-
return Task.FromResult(value);
72+
return Task.FromResult(_cache.TryGetValue(cacheKey.Value, out var value)
73+
? value as T
74+
: default(T));
7475
}
7576
}
7677
}

Source/EventFlow/Core/Caching/MemoryCache.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ public class MemoryCache : Cache, IMemoryCache, IDisposable
3737

3838
private static string GenerateKey()
3939
{
40-
return $"eventflow-{DateTimeOffset.Now.ToString("yyyyMMdd-HHmm")}-{Guid.NewGuid().ToString("N")}";
40+
return $"eventflow-{DateTimeOffset.Now:yyyyMMdd-HHmm}-{Guid.NewGuid():N}";
4141
}
4242

4343
public MemoryCache(ILog log)

0 commit comments

Comments
 (0)