diff --git a/README.md b/README.md index 3410edd2a..b22b4c95a 100644 --- a/README.md +++ b/README.md @@ -67,6 +67,14 @@ the [do’s and don’ts](http://docs.geteventflow.net/DosAndDonts.html) and the [complete example](#complete-example). It features entities, a read model for an entity, delete on read models, specifications and snapshots. + * **[.NET Core:](https://github.com/johnny-chan/EventFlowDemo)** + A Web API running .NET Core 2.2 using the event flow. It uses the pre-defined + command/entities/events from the [complete example](#complete-example). There are endpoints to + create a new example event, getting a data model and to replay all data models. + +* **[ElasticSearch/.NET Core:](https://github.com/DureSameen/EventFlowWithElasticSearch)** + It is configured with EventFlow, ElasticSearch, EventStore and RabbitMq. See "withRabbitMq" branch for #384. + ### Overview Here is a list of the EventFlow concepts. Use the links to navigate diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 8c9ae602c..58cfca050 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -1,16 +1,41 @@ -### New in 0.69 (not released yet) +### New in 0.70 (not released yet) + +* Breaking: Changed target framework to to .NET Framework 4.5.2 for the following NuGet packages, + as Microsoft has [discontinued](https://github.com/Microsoft/dotnet/blob/master/releases/README.md) + support for .NET Framework 4.5.1 + - `EventFlow` + - `EventFlow.TestHelpers` + - `EventFlow.Autofac` + - `EventFlow.Elasticsearch` + - `EventFlow.Examples.Shipping` + - `EventFlow.Examples.Shipping.Queries.InMemory` + - `EventFlow.Hangfire` + - `EventFlow.MongoDB` + - `EventFlow.MsSql` + - `EventFlow.Owin` + - `EventFlow.PostgreSql` + - `EventFlow.RabbitMQ` + - `EventFlow.Sql` + - `EventFlow.SQLite` +* New: Added [SourceLink](https://github.com/dotnet/sourcelink) support +* Fix: `DispatchToSagas.ProcessSagaAsync` use `EventId` instead of `SourceId` as `SourceId` + for delivery of external event to AggregateSaga +* Fix: `Identity.NewComb()` now produces string values that doesn't cause + too much index fragmentation in MSSQL string columns + +### New in 0.69.3772 (released 2019-02-12) * New: Added configuration option to set the "point of no return" when using cancellation tokens. After this point in processing, cancellation tokens are ignored: `options.Configure(c => c.CancellationBoundary = CancellationBoundary.BeforeCommittingEvents)` -* Fix: Added the schema `dbo` to the `eventdatamodel_list_type` in script - `0002 - Create eventdatamodel_list_type.sql` for `EventFlow.MsSql`. * New: Added `EventFlowOptions.RunOnStartup` extension method to register `IBootstrap` types that should run on application startup. * New: Support for async read model updates (`IAmAsyncReadModelFor`). You can mix and match asynchronous and synchronous updates, as long as you don't subscribe to the same event in both ways. +* Fix: Added the schema `dbo` to the `eventdatamodel_list_type` in script + `0002 - Create eventdatamodel_list_type.sql` for `EventFlow.MsSql`. * Fix: `LoadAllCommittedEvents` now correctly handles cases where the `GlobalSequenceNumber` column contains gaps larger than the page size. This bug lead to incomplete event application when using the `ReadModelPopulator` (see #564). diff --git a/Source/Common.props b/Source/Common.props index e6a94a075..453362dcb 100644 --- a/Source/Common.props +++ b/Source/Common.props @@ -1,6 +1,10 @@ - embedded - True + embedded + True + true + true + true + snupkg \ No newline at end of file diff --git a/Source/EventFlow.AspNetCore.Tests/EventFlow.AspNetCore.Tests.csproj b/Source/EventFlow.AspNetCore.Tests/EventFlow.AspNetCore.Tests.csproj index 7fd1cbd02..a54693a44 100644 --- a/Source/EventFlow.AspNetCore.Tests/EventFlow.AspNetCore.Tests.csproj +++ b/Source/EventFlow.AspNetCore.Tests/EventFlow.AspNetCore.Tests.csproj @@ -8,10 +8,10 @@ - - - - + + + + diff --git a/Source/EventFlow.AspNetCore.Tests/IntegrationTests/Site/SiteTests.cs b/Source/EventFlow.AspNetCore.Tests/IntegrationTests/Site/SiteTests.cs index 3ca422ef1..0dc83904c 100644 --- a/Source/EventFlow.AspNetCore.Tests/IntegrationTests/Site/SiteTests.cs +++ b/Source/EventFlow.AspNetCore.Tests/IntegrationTests/Site/SiteTests.cs @@ -82,7 +82,7 @@ public void PublishCommand_WithNull_ThrowsException() // Arrange + Act Action action = () => Task.WaitAll(PostAsync("commands/ThingyPing/1", null)); - action.ShouldThrow("because of command is null."); + action.Should().Throw("because of command is null."); } private async Task GetAsync(string url) diff --git a/Source/EventFlow.AspNetCore/EventFlow.AspNetCore.csproj b/Source/EventFlow.AspNetCore/EventFlow.AspNetCore.csproj index 751cdd446..167a69879 100644 --- a/Source/EventFlow.AspNetCore/EventFlow.AspNetCore.csproj +++ b/Source/EventFlow.AspNetCore/EventFlow.AspNetCore.csproj @@ -24,6 +24,7 @@ + diff --git a/Source/EventFlow.Autofac.Tests/EventFlow.Autofac.Tests.csproj b/Source/EventFlow.Autofac.Tests/EventFlow.Autofac.Tests.csproj index 99dedd8ad..a65c955ac 100644 --- a/Source/EventFlow.Autofac.Tests/EventFlow.Autofac.Tests.csproj +++ b/Source/EventFlow.Autofac.Tests/EventFlow.Autofac.Tests.csproj @@ -1,7 +1,7 @@  - net451 + net452 True False diff --git a/Source/EventFlow.Autofac.Tests/app.config b/Source/EventFlow.Autofac.Tests/app.config index 069e3fd6d..d05299f92 100644 --- a/Source/EventFlow.Autofac.Tests/app.config +++ b/Source/EventFlow.Autofac.Tests/app.config @@ -1,7 +1,7 @@ - + diff --git a/Source/EventFlow.Autofac/EventFlow.Autofac.csproj b/Source/EventFlow.Autofac/EventFlow.Autofac.csproj index 0599a27d9..d0cdd87a1 100644 --- a/Source/EventFlow.Autofac/EventFlow.Autofac.csproj +++ b/Source/EventFlow.Autofac/EventFlow.Autofac.csproj @@ -1,7 +1,7 @@  - + - net451;netstandard1.6;netstandard2.0 + net452;netstandard1.6;netstandard2.0 True True False @@ -20,7 +20,7 @@ en-US UPDATED BY BUILD - + @@ -29,6 +29,9 @@ + + + diff --git a/Source/EventFlow.DependencyInjection.Tests/EventFlow.DependencyInjection.Tests.csproj b/Source/EventFlow.DependencyInjection.Tests/EventFlow.DependencyInjection.Tests.csproj index b0e1f1bb9..64c21f448 100644 --- a/Source/EventFlow.DependencyInjection.Tests/EventFlow.DependencyInjection.Tests.csproj +++ b/Source/EventFlow.DependencyInjection.Tests/EventFlow.DependencyInjection.Tests.csproj @@ -7,9 +7,9 @@ - - - + + + diff --git a/Source/EventFlow.DependencyInjection/EventFlow.DependencyInjection.csproj b/Source/EventFlow.DependencyInjection/EventFlow.DependencyInjection.csproj index 4402474be..f02d9fbb0 100644 --- a/Source/EventFlow.DependencyInjection/EventFlow.DependencyInjection.csproj +++ b/Source/EventFlow.DependencyInjection/EventFlow.DependencyInjection.csproj @@ -24,6 +24,7 @@ + diff --git a/Source/EventFlow.Elasticsearch.Tests/EventFlow.Elasticsearch.Tests.csproj b/Source/EventFlow.Elasticsearch.Tests/EventFlow.Elasticsearch.Tests.csproj index dc5cad552..743244fb6 100644 --- a/Source/EventFlow.Elasticsearch.Tests/EventFlow.Elasticsearch.Tests.csproj +++ b/Source/EventFlow.Elasticsearch.Tests/EventFlow.Elasticsearch.Tests.csproj @@ -1,7 +1,7 @@  - net451 + net452 True False diff --git a/Source/EventFlow.Elasticsearch.Tests/app.config b/Source/EventFlow.Elasticsearch.Tests/app.config index 069e3fd6d..d05299f92 100644 --- a/Source/EventFlow.Elasticsearch.Tests/app.config +++ b/Source/EventFlow.Elasticsearch.Tests/app.config @@ -1,7 +1,7 @@ - + diff --git a/Source/EventFlow.Elasticsearch/EventFlow.Elasticsearch.csproj b/Source/EventFlow.Elasticsearch/EventFlow.Elasticsearch.csproj index ead84c393..2c6155a3c 100644 --- a/Source/EventFlow.Elasticsearch/EventFlow.Elasticsearch.csproj +++ b/Source/EventFlow.Elasticsearch/EventFlow.Elasticsearch.csproj @@ -1,7 +1,7 @@  - net451;netstandard1.6;netstandard2.0 + net452;netstandard1.6;netstandard2.0 True True False @@ -24,6 +24,7 @@ + diff --git a/Source/EventFlow.EntityFramework.Tests/EventFlow.EntityFramework.Tests.csproj b/Source/EventFlow.EntityFramework.Tests/EventFlow.EntityFramework.Tests.csproj index 56e4510de..220cada80 100644 --- a/Source/EventFlow.EntityFramework.Tests/EventFlow.EntityFramework.Tests.csproj +++ b/Source/EventFlow.EntityFramework.Tests/EventFlow.EntityFramework.Tests.csproj @@ -9,9 +9,9 @@ - - - + + + diff --git a/Source/EventFlow.EntityFramework/EventFlow.EntityFramework.csproj b/Source/EventFlow.EntityFramework/EventFlow.EntityFramework.csproj index 6d871c7b3..288f6e353 100644 --- a/Source/EventFlow.EntityFramework/EventFlow.EntityFramework.csproj +++ b/Source/EventFlow.EntityFramework/EventFlow.EntityFramework.csproj @@ -25,6 +25,9 @@ 2.1.0 + + + diff --git a/Source/EventFlow.EventStores.EventStore.Tests/app.config b/Source/EventFlow.EventStores.EventStore.Tests/app.config index 069e3fd6d..d05299f92 100644 --- a/Source/EventFlow.EventStores.EventStore.Tests/app.config +++ b/Source/EventFlow.EventStores.EventStore.Tests/app.config @@ -1,7 +1,7 @@ - + diff --git a/Source/EventFlow.EventStores.EventStore/EventFlow.EventStores.EventStore.csproj b/Source/EventFlow.EventStores.EventStore/EventFlow.EventStores.EventStore.csproj index b04ba887e..c8dd0aaf4 100644 --- a/Source/EventFlow.EventStores.EventStore/EventFlow.EventStores.EventStore.csproj +++ b/Source/EventFlow.EventStores.EventStore/EventFlow.EventStores.EventStore.csproj @@ -29,6 +29,9 @@ + + + diff --git a/Source/EventFlow.Examples.Shipping.Queries.InMemory/EventFlow.Examples.Shipping.Queries.InMemory.csproj b/Source/EventFlow.Examples.Shipping.Queries.InMemory/EventFlow.Examples.Shipping.Queries.InMemory.csproj index 7ba7e32f8..ac4539cc9 100644 --- a/Source/EventFlow.Examples.Shipping.Queries.InMemory/EventFlow.Examples.Shipping.Queries.InMemory.csproj +++ b/Source/EventFlow.Examples.Shipping.Queries.InMemory/EventFlow.Examples.Shipping.Queries.InMemory.csproj @@ -1,7 +1,7 @@  - net451 + net452 True False diff --git a/Source/EventFlow.Examples.Shipping.Tests/EventFlow.Examples.Shipping.Tests.csproj b/Source/EventFlow.Examples.Shipping.Tests/EventFlow.Examples.Shipping.Tests.csproj index fd96fb805..049d91e60 100644 --- a/Source/EventFlow.Examples.Shipping.Tests/EventFlow.Examples.Shipping.Tests.csproj +++ b/Source/EventFlow.Examples.Shipping.Tests/EventFlow.Examples.Shipping.Tests.csproj @@ -1,7 +1,7 @@  - net451 + net452 True False diff --git a/Source/EventFlow.Examples.Shipping.Tests/IntegrationTests/Scenarios.cs b/Source/EventFlow.Examples.Shipping.Tests/IntegrationTests/Scenarios.cs index fede29e26..a5e38b8ab 100644 --- a/Source/EventFlow.Examples.Shipping.Tests/IntegrationTests/Scenarios.cs +++ b/Source/EventFlow.Examples.Shipping.Tests/IntegrationTests/Scenarios.cs @@ -37,7 +37,7 @@ using EventFlow.Extensions; using EventFlow.Logs; using EventFlow.TestHelpers; -using FluentAssertions; +using FluentAssertions.Extensions; using NUnit.Framework; namespace EventFlow.Examples.Shipping.Tests.IntegrationTests diff --git a/Source/EventFlow.Examples.Shipping.Tests/UnitTests/Domain/Model/CargoModel/Speficications/TransportLegsAreConnectedSpecificationTests.cs b/Source/EventFlow.Examples.Shipping.Tests/UnitTests/Domain/Model/CargoModel/Speficications/TransportLegsAreConnectedSpecificationTests.cs index 40ec39273..a77c3098f 100644 --- a/Source/EventFlow.Examples.Shipping.Tests/UnitTests/Domain/Model/CargoModel/Speficications/TransportLegsAreConnectedSpecificationTests.cs +++ b/Source/EventFlow.Examples.Shipping.Tests/UnitTests/Domain/Model/CargoModel/Speficications/TransportLegsAreConnectedSpecificationTests.cs @@ -27,6 +27,7 @@ using EventFlow.Examples.Shipping.Domain.Model.VoyageModel.Entities; using EventFlow.TestHelpers; using FluentAssertions; +using FluentAssertions.Extensions; using NUnit.Framework; namespace EventFlow.Examples.Shipping.Tests.UnitTests.Domain.Model.CargoModel.Speficications diff --git a/Source/EventFlow.Examples.Shipping.Tests/UnitTests/ExternalServices/Routing/RoutingServiceTests.cs b/Source/EventFlow.Examples.Shipping.Tests/UnitTests/ExternalServices/Routing/RoutingServiceTests.cs index dbcd76087..3dd32d2df 100644 --- a/Source/EventFlow.Examples.Shipping.Tests/UnitTests/ExternalServices/Routing/RoutingServiceTests.cs +++ b/Source/EventFlow.Examples.Shipping.Tests/UnitTests/ExternalServices/Routing/RoutingServiceTests.cs @@ -26,6 +26,7 @@ using EventFlow.Examples.Shipping.ExternalServices.Routing; using EventFlow.TestHelpers; using FluentAssertions; +using FluentAssertions.Extensions; using NUnit.Framework; namespace EventFlow.Examples.Shipping.Tests.UnitTests.ExternalServices.Routing diff --git a/Source/EventFlow.Examples.Shipping.Tests/Voyages.cs b/Source/EventFlow.Examples.Shipping.Tests/Voyages.cs index 836f4458c..f63a135fb 100644 --- a/Source/EventFlow.Examples.Shipping.Tests/Voyages.cs +++ b/Source/EventFlow.Examples.Shipping.Tests/Voyages.cs @@ -24,7 +24,7 @@ using System.Collections.Generic; using EventFlow.Examples.Shipping.Domain.Model.VoyageModel; using EventFlow.Examples.Shipping.Domain.Model.VoyageModel.ValueObjects; -using FluentAssertions; +using FluentAssertions.Extensions; namespace EventFlow.Examples.Shipping.Tests { diff --git a/Source/EventFlow.Examples.Shipping.Tests/app.config b/Source/EventFlow.Examples.Shipping.Tests/app.config index 069e3fd6d..d05299f92 100644 --- a/Source/EventFlow.Examples.Shipping.Tests/app.config +++ b/Source/EventFlow.Examples.Shipping.Tests/app.config @@ -1,7 +1,7 @@ - + diff --git a/Source/EventFlow.Examples.Shipping/EventFlow.Examples.Shipping.csproj b/Source/EventFlow.Examples.Shipping/EventFlow.Examples.Shipping.csproj index 94b95c9c4..08e3c55a8 100644 --- a/Source/EventFlow.Examples.Shipping/EventFlow.Examples.Shipping.csproj +++ b/Source/EventFlow.Examples.Shipping/EventFlow.Examples.Shipping.csproj @@ -1,7 +1,7 @@  - net451 + net452 True False diff --git a/Source/EventFlow.Hangfire.Tests/EventFlow.Hangfire.Tests.csproj b/Source/EventFlow.Hangfire.Tests/EventFlow.Hangfire.Tests.csproj index 4c1ce80bd..1bbd88abf 100644 --- a/Source/EventFlow.Hangfire.Tests/EventFlow.Hangfire.Tests.csproj +++ b/Source/EventFlow.Hangfire.Tests/EventFlow.Hangfire.Tests.csproj @@ -1,7 +1,7 @@  - net451 + net452 True False diff --git a/Source/EventFlow.Hangfire.Tests/app.config b/Source/EventFlow.Hangfire.Tests/app.config index b4d0b5fb8..48b7bb111 100644 --- a/Source/EventFlow.Hangfire.Tests/app.config +++ b/Source/EventFlow.Hangfire.Tests/app.config @@ -1,7 +1,7 @@ - + diff --git a/Source/EventFlow.Hangfire/EventFlow.Hangfire.csproj b/Source/EventFlow.Hangfire/EventFlow.Hangfire.csproj index a0e60fdaa..64c83a387 100644 --- a/Source/EventFlow.Hangfire/EventFlow.Hangfire.csproj +++ b/Source/EventFlow.Hangfire/EventFlow.Hangfire.csproj @@ -1,7 +1,7 @@  - net451;netstandard1.6;netstandard2.0 + net452;netstandard1.6;netstandard2.0 True True False @@ -25,7 +25,8 @@ - + + diff --git a/Source/EventFlow.MongoDB.Tests/app.config b/Source/EventFlow.MongoDB.Tests/app.config index 069e3fd6d..d05299f92 100644 --- a/Source/EventFlow.MongoDB.Tests/app.config +++ b/Source/EventFlow.MongoDB.Tests/app.config @@ -1,7 +1,7 @@ - + diff --git a/Source/EventFlow.MongoDB/EventFlow.MongoDB.csproj b/Source/EventFlow.MongoDB/EventFlow.MongoDB.csproj index 7975335ae..7360bd74c 100644 --- a/Source/EventFlow.MongoDB/EventFlow.MongoDB.csproj +++ b/Source/EventFlow.MongoDB/EventFlow.MongoDB.csproj @@ -1,7 +1,7 @@  - net451;netstandard1.6 + net452;netstandard1.6 EventFlow.MongoDB True False @@ -24,6 +24,7 @@ + diff --git a/Source/EventFlow.MsSql.Tests/EventFlow.MsSql.Tests.csproj b/Source/EventFlow.MsSql.Tests/EventFlow.MsSql.Tests.csproj index adf9858d2..3873e3e67 100644 --- a/Source/EventFlow.MsSql.Tests/EventFlow.MsSql.Tests.csproj +++ b/Source/EventFlow.MsSql.Tests/EventFlow.MsSql.Tests.csproj @@ -1,7 +1,7 @@  - net451 + net452 True False diff --git a/Source/EventFlow.MsSql.Tests/Extensions/MsSqlDatabaseExtensions.cs b/Source/EventFlow.MsSql.Tests/Extensions/MsSqlDatabaseExtensions.cs new file mode 100644 index 000000000..24a224235 --- /dev/null +++ b/Source/EventFlow.MsSql.Tests/Extensions/MsSqlDatabaseExtensions.cs @@ -0,0 +1,20 @@ +using System.Collections.Generic; +using System.Linq; +using Dapper; +using EventFlow.TestHelpers.MsSql; + +namespace EventFlow.MsSql.Tests.Extensions +{ + public static class MsSqlDatabaseExtensions + { + public static IReadOnlyCollection Query(this IMsSqlDatabase database, string sql) + { + return database.WithConnection>(c => c.Query(sql).ToList()); + } + + public static int Execute(this IMsSqlDatabase database, string sql, object param) + { + return database.WithConnection(c => c.Execute(sql, param)); + } + } +} diff --git a/Source/EventFlow.MsSql.Tests/IntegrationTests/EventStores/MsSqlEventStoreTests.cs b/Source/EventFlow.MsSql.Tests/IntegrationTests/EventStores/MsSqlEventStoreTests.cs index 4be7bc1b7..b6a8db53e 100644 --- a/Source/EventFlow.MsSql.Tests/IntegrationTests/EventStores/MsSqlEventStoreTests.cs +++ b/Source/EventFlow.MsSql.Tests/IntegrationTests/EventStores/MsSqlEventStoreTests.cs @@ -21,7 +21,6 @@ // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -using System.Threading.Tasks; using EventFlow.Configuration; using EventFlow.Extensions; using EventFlow.MsSql.EventStores; diff --git a/Source/EventFlow.MsSql.Tests/IntegrationTests/IdentityIndexFragmentationTests.cs b/Source/EventFlow.MsSql.Tests/IntegrationTests/IdentityIndexFragmentationTests.cs new file mode 100644 index 000000000..bb44eabf7 --- /dev/null +++ b/Source/EventFlow.MsSql.Tests/IntegrationTests/IdentityIndexFragmentationTests.cs @@ -0,0 +1,211 @@ +using System; +using System.Linq; +using System.Threading; +using EventFlow.Core; +using EventFlow.Extensions; +using EventFlow.MsSql.Tests.Extensions; +using EventFlow.TestHelpers; +using EventFlow.TestHelpers.MsSql; +using FluentAssertions; +using NUnit.Framework; + +// ReSharper disable StringLiteralTypo + +namespace EventFlow.MsSql.Tests.IntegrationTests +{ + [Category(Categories.Integration)] + public class IdentityIndexFragmentationTests : Test + { + private const int ROWS = 10000; + private IMsSqlDatabase _testDatabase; + + private class MagicId : Identity + { + public MagicId(string value) : base(value) + { + } + } + + [Test] + public void VerifyIdentityHasThereLittleFragmentationUsingString() + { + // Act + InsertRows(() => MagicId.NewComb().Value, ROWS, "IndexFragmentationString"); + + // Assert + var fragmentation = GetIndexFragmentation("IndexFragmentationString"); + fragmentation.Should().BeLessThan(10); + } + + + [Test] + public void SanityIntLowFragmentationStoredInGuid() + { + // Arrange + var i = 0; + + // Act + InsertRows(() => + { + Interlocked.Increment(ref i); + return $"{i,5}"; + }, + ROWS, + "IndexFragmentationString"); + + // Assert + var fragmentation = GetIndexFragmentation("IndexFragmentationString"); + fragmentation.Should().BeLessThan(10); + } + + [Test] + public void SanityIntAsHexLowFragmentationStoredInGuid() + { + // Arrange + var i = 0; + + // Act + InsertRows(() => + { + Interlocked.Increment(ref i); + return $"{i,5:X}"; + }, + ROWS, + "IndexFragmentationString"); + + // Assert + var fragmentation = GetIndexFragmentation("IndexFragmentationString"); + fragmentation.Should().BeLessThan(10); + } + + + [Test] + public void SanityCombYieldsLowFragmentationStoredInGuid() + { + // Act + InsertRows(GuidFactories.Comb.Create, ROWS, "IndexFragmentationGuid"); + + // Assert + var fragmentation = GetIndexFragmentation("IndexFragmentationGuid"); + fragmentation.Should().BeLessThan(10); + } + + [Test] + public void SanityCombYieldsHighFragmentationStoredInString() + { + // Act + InsertRows(() => GuidFactories.Comb.Create().ToString("N"), ROWS, "IndexFragmentationString"); + + // Assert + var fragmentation = GetIndexFragmentation("IndexFragmentationString"); + fragmentation.Should().BeGreaterThan(90); + } + + [Test] + public void SanityGuidIdentityYieldsHighFragmentationStoredInString() + { + // Act + InsertRows(() => MagicId.New.Value, ROWS, "IndexFragmentationString"); + + // Assert + var fragmentation = GetIndexFragmentation("IndexFragmentationString"); + fragmentation.Should().BeGreaterThan(30); // closer to 100 in reality + } + + [Test] + public void SanityGuidIdentityYieldsHighFragmentationStoredInGuid() + { + // Act + InsertRows(() => MagicId.New.GetGuid(), ROWS, "IndexFragmentationGuid"); + + // Assert + var fragmentation = GetIndexFragmentation("IndexFragmentationGuid"); + fragmentation.Should().BeGreaterThan(30); // closer to 100 in reality + } + + public void InsertRows(Func generator, int count, string table) + { + var ids = Enumerable.Range(0, count) + .Select(_ => generator()) + .ToList(); + + foreach (var id in ids.Take(20)) + { + Console.WriteLine(id); + } + + foreach (var id in ids) + { + _testDatabase.Execute($"INSERT INTO {table} (Id) VALUES (@Id)", new { Id = id }); + } + } + + private double GetIndexFragmentation(string table) + { + const string sql = @" + SELECT dbschemas.[name] as 'schema', + dbtables.[name] as 'table', + dbindexes.[name] as 'index', + indexstats.avg_fragmentation_in_percent AS 'fragmentation', + indexstats.page_count AS 'pageCount', + index_level AS 'level' + FROM sys.dm_db_index_physical_stats (DB_ID(), NULL, NULL, NULL, 'DETAILED') AS indexstats + INNER JOIN sys.tables dbtables on dbtables.[object_id] = indexstats.[object_id] + INNER JOIN sys.schemas dbschemas on dbtables.[schema_id] = dbschemas.[schema_id] + INNER JOIN sys.indexes AS dbindexes ON dbindexes.[object_id] = indexstats.[object_id] + AND indexstats.index_id = dbindexes.index_id + WHERE indexstats.database_id = DB_ID() + ORDER BY dbschemas.[name],dbtables.[name],dbindexes.[name],index_level desc + "; + + var rows = _testDatabase.Query(sql) + .Where(r => string.Equals(table, r.Table, StringComparison.OrdinalIgnoreCase)) + .OrderBy(r => r.Level) + .ToList(); + + return rows.First().Fragmentation; + } + + [SetUp] + public void SetUp() + { + _testDatabase = MsSqlHelpz.CreateDatabase("index_fragmentation"); + _testDatabase.Execute("CREATE TABLE IndexFragmentationString (Id nvarchar(250) PRIMARY KEY)"); + _testDatabase.Execute("CREATE TABLE IndexFragmentationGuid (Id uniqueidentifier PRIMARY KEY)"); + } + + [TearDown] + public void TearDown() + { + _testDatabase.DisposeSafe("DROP test database"); + } + + private class IndexFragmentationDetails + { + public IndexFragmentationDetails( + string schema, + string table, + string index, + double fragmentation, + long pageCount, + byte level) + { + Schema = schema; + Table = table; + Index = index; + Fragmentation = fragmentation; + PageCount = pageCount; + Level = level; + } + + public string Schema { get; } + public string Table { get; } + public string Index { get; } + + public double Fragmentation { get; } + public long PageCount { get; } + + public byte Level { get; } + } + } +} diff --git a/Source/EventFlow.MsSql.Tests/app.config b/Source/EventFlow.MsSql.Tests/app.config index 069e3fd6d..d05299f92 100644 --- a/Source/EventFlow.MsSql.Tests/app.config +++ b/Source/EventFlow.MsSql.Tests/app.config @@ -1,7 +1,7 @@ - + diff --git a/Source/EventFlow.MsSql/EventFlow.MsSql.csproj b/Source/EventFlow.MsSql/EventFlow.MsSql.csproj index 00180d0d3..e1d82cbd9 100644 --- a/Source/EventFlow.MsSql/EventFlow.MsSql.csproj +++ b/Source/EventFlow.MsSql/EventFlow.MsSql.csproj @@ -1,7 +1,7 @@  - net451;netstandard1.6;netstandard2.0 + net452;netstandard1.6;netstandard2.0 True True False @@ -25,6 +25,7 @@ + diff --git a/Source/EventFlow.Owin.Tests/EventFlow.Owin.Tests.csproj b/Source/EventFlow.Owin.Tests/EventFlow.Owin.Tests.csproj index eec6eee8f..bf2e6a6fd 100644 --- a/Source/EventFlow.Owin.Tests/EventFlow.Owin.Tests.csproj +++ b/Source/EventFlow.Owin.Tests/EventFlow.Owin.Tests.csproj @@ -1,7 +1,7 @@  - net451 + net452 True False diff --git a/Source/EventFlow.Owin.Tests/IntegrationTests/Site/SiteTests.cs b/Source/EventFlow.Owin.Tests/IntegrationTests/Site/SiteTests.cs index d1d6e3a40..55b76fec2 100644 --- a/Source/EventFlow.Owin.Tests/IntegrationTests/Site/SiteTests.cs +++ b/Source/EventFlow.Owin.Tests/IntegrationTests/Site/SiteTests.cs @@ -76,7 +76,7 @@ public void PublishCommand_WithNull_ThrowsException() // Arrange + Act Action action = () => Task.WaitAll(PostAsync("commands/ThingyPing/1", null)); - action.ShouldThrow("because of command is null."); + action.Should().Throw("because of command is null."); } private Task GetAsync(string url) diff --git a/Source/EventFlow.Owin.Tests/app.config b/Source/EventFlow.Owin.Tests/app.config index bc93d152f..395954ca5 100644 --- a/Source/EventFlow.Owin.Tests/app.config +++ b/Source/EventFlow.Owin.Tests/app.config @@ -1,7 +1,7 @@ - + diff --git a/Source/EventFlow.Owin/EventFlow.Owin.csproj b/Source/EventFlow.Owin/EventFlow.Owin.csproj index 37ef9f821..e705b7458 100644 --- a/Source/EventFlow.Owin/EventFlow.Owin.csproj +++ b/Source/EventFlow.Owin/EventFlow.Owin.csproj @@ -1,7 +1,7 @@  - net451 + net452 True True False @@ -25,6 +25,7 @@ + diff --git a/Source/EventFlow.PostgreSql.Tests/EventFlow.PostgreSql.Tests.csproj b/Source/EventFlow.PostgreSql.Tests/EventFlow.PostgreSql.Tests.csproj index 44f9fdf49..13dd078ca 100644 --- a/Source/EventFlow.PostgreSql.Tests/EventFlow.PostgreSql.Tests.csproj +++ b/Source/EventFlow.PostgreSql.Tests/EventFlow.PostgreSql.Tests.csproj @@ -1,7 +1,7 @@  - net451 + net452 True False diff --git a/Source/EventFlow.PostgreSql.Tests/app.config b/Source/EventFlow.PostgreSql.Tests/app.config index a71fe2a42..b34d158b8 100644 --- a/Source/EventFlow.PostgreSql.Tests/app.config +++ b/Source/EventFlow.PostgreSql.Tests/app.config @@ -1,7 +1,7 @@ - + diff --git a/Source/EventFlow.PostgreSql/EventFlow.PostgreSql.csproj b/Source/EventFlow.PostgreSql/EventFlow.PostgreSql.csproj index 1b86a3775..aa11a40d7 100644 --- a/Source/EventFlow.PostgreSql/EventFlow.PostgreSql.csproj +++ b/Source/EventFlow.PostgreSql/EventFlow.PostgreSql.csproj @@ -1,7 +1,7 @@  - net451;netstandard2.0 + net452;netstandard2.0 True True False @@ -38,6 +38,7 @@ + diff --git a/Source/EventFlow.RabbitMQ.Tests/EventFlow.RabbitMQ.Tests.csproj b/Source/EventFlow.RabbitMQ.Tests/EventFlow.RabbitMQ.Tests.csproj index 43b7c58be..6130cac07 100644 --- a/Source/EventFlow.RabbitMQ.Tests/EventFlow.RabbitMQ.Tests.csproj +++ b/Source/EventFlow.RabbitMQ.Tests/EventFlow.RabbitMQ.Tests.csproj @@ -1,7 +1,7 @@  - net451 + net452 True False diff --git a/Source/EventFlow.RabbitMQ.Tests/UnitTests/Integrations/RabbitMqPublisherTests.cs b/Source/EventFlow.RabbitMQ.Tests/UnitTests/Integrations/RabbitMqPublisherTests.cs index bc4f387d5..ba013e384 100644 --- a/Source/EventFlow.RabbitMQ.Tests/UnitTests/Integrations/RabbitMqPublisherTests.cs +++ b/Source/EventFlow.RabbitMQ.Tests/UnitTests/Integrations/RabbitMqPublisherTests.cs @@ -29,9 +29,9 @@ using EventFlow.Logs; using EventFlow.RabbitMQ.Integrations; using EventFlow.TestHelpers; +using AutoFixture; using Moq; using NUnit.Framework; -using Ploeh.AutoFixture; using RabbitMQ.Client; namespace EventFlow.RabbitMQ.Tests.UnitTests.Integrations diff --git a/Source/EventFlow.RabbitMQ.Tests/app.config b/Source/EventFlow.RabbitMQ.Tests/app.config index 069e3fd6d..d05299f92 100644 --- a/Source/EventFlow.RabbitMQ.Tests/app.config +++ b/Source/EventFlow.RabbitMQ.Tests/app.config @@ -1,7 +1,7 @@ - + diff --git a/Source/EventFlow.RabbitMQ/EventFlow.RabbitMQ.csproj b/Source/EventFlow.RabbitMQ/EventFlow.RabbitMQ.csproj index 2be601f6f..acd41f673 100644 --- a/Source/EventFlow.RabbitMQ/EventFlow.RabbitMQ.csproj +++ b/Source/EventFlow.RabbitMQ/EventFlow.RabbitMQ.csproj @@ -1,7 +1,7 @@  - net451;netstandard1.6 + net452;netstandard1.6 True True False @@ -27,6 +27,7 @@ + \ No newline at end of file diff --git a/Source/EventFlow.SQLite.Tests/EventFlow.SQLite.Tests.csproj b/Source/EventFlow.SQLite.Tests/EventFlow.SQLite.Tests.csproj index 8a66fd26b..8971d9153 100644 --- a/Source/EventFlow.SQLite.Tests/EventFlow.SQLite.Tests.csproj +++ b/Source/EventFlow.SQLite.Tests/EventFlow.SQLite.Tests.csproj @@ -1,7 +1,7 @@  - net451 + net452 True False diff --git a/Source/EventFlow.SQLite.Tests/app.config b/Source/EventFlow.SQLite.Tests/app.config index 069e3fd6d..d05299f92 100644 --- a/Source/EventFlow.SQLite.Tests/app.config +++ b/Source/EventFlow.SQLite.Tests/app.config @@ -1,7 +1,7 @@ - + diff --git a/Source/EventFlow.SQLite/EventFlow.SQLite.csproj b/Source/EventFlow.SQLite/EventFlow.SQLite.csproj index 6ffc3ce42..7f6a24516 100644 --- a/Source/EventFlow.SQLite/EventFlow.SQLite.csproj +++ b/Source/EventFlow.SQLite/EventFlow.SQLite.csproj @@ -1,7 +1,7 @@  - net451;netstandard2.0 + net452;netstandard2.0 True True False @@ -25,6 +25,7 @@ + diff --git a/Source/EventFlow.Sql.Tests/EventFlow.Sql.Tests.csproj b/Source/EventFlow.Sql.Tests/EventFlow.Sql.Tests.csproj index 4e32fbc0e..1582e7b4a 100644 --- a/Source/EventFlow.Sql.Tests/EventFlow.Sql.Tests.csproj +++ b/Source/EventFlow.Sql.Tests/EventFlow.Sql.Tests.csproj @@ -1,7 +1,7 @@  - net451 + net452 True False diff --git a/Source/EventFlow.Sql.Tests/app.config b/Source/EventFlow.Sql.Tests/app.config index 069e3fd6d..d05299f92 100644 --- a/Source/EventFlow.Sql.Tests/app.config +++ b/Source/EventFlow.Sql.Tests/app.config @@ -1,7 +1,7 @@ - + diff --git a/Source/EventFlow.Sql/EventFlow.Sql.csproj b/Source/EventFlow.Sql/EventFlow.Sql.csproj index 8a8d17c06..a47035bb5 100644 --- a/Source/EventFlow.Sql/EventFlow.Sql.csproj +++ b/Source/EventFlow.Sql/EventFlow.Sql.csproj @@ -1,7 +1,7 @@  - net451;netstandard1.6;netstandard2.0 + net452;netstandard1.6;netstandard2.0 True True False @@ -26,6 +26,7 @@ + @@ -33,6 +34,6 @@ - + \ No newline at end of file diff --git a/Source/EventFlow.TestHelpers/EventFlow.TestHelpers.csproj b/Source/EventFlow.TestHelpers/EventFlow.TestHelpers.csproj index 2194a7443..ad3c8bf8c 100644 --- a/Source/EventFlow.TestHelpers/EventFlow.TestHelpers.csproj +++ b/Source/EventFlow.TestHelpers/EventFlow.TestHelpers.csproj @@ -1,7 +1,7 @@  - net451 + net452 True False False @@ -25,10 +25,11 @@ UPDATED BY BUILD - - + + + - + diff --git a/Source/EventFlow.TestHelpers/MsSql/MsSqlConnectionString.cs b/Source/EventFlow.TestHelpers/MsSql/MsSqlConnectionString.cs index d3c3ca628..aec961ca1 100644 --- a/Source/EventFlow.TestHelpers/MsSql/MsSqlConnectionString.cs +++ b/Source/EventFlow.TestHelpers/MsSql/MsSqlConnectionString.cs @@ -73,6 +73,7 @@ public void Execute(string sql) } }); } + public void WithConnection(Action action) { WithConnection(c => diff --git a/Source/EventFlow.TestHelpers/Suites/TestSuiteForEventStore.cs b/Source/EventFlow.TestHelpers/Suites/TestSuiteForEventStore.cs index dc85042c7..49728ffe4 100644 --- a/Source/EventFlow.TestHelpers/Suites/TestSuiteForEventStore.cs +++ b/Source/EventFlow.TestHelpers/Suites/TestSuiteForEventStore.cs @@ -293,7 +293,7 @@ public async Task AggregatesCanUpdatedAfterOptimisticConcurrency() // Assert aggregate1 = await LoadAggregateAsync(id).ConfigureAwait(false); - aggregate1.PingsReceived.ShouldAllBeEquivalentTo(new[] {pingId1, pingId2}); + aggregate1.PingsReceived.Should().BeEquivalentTo(new[] {pingId1, pingId2}); } [Test] @@ -322,7 +322,7 @@ await commandBus.PublishAsync( // Assert var aggregate = await LoadAggregateAsync(id).ConfigureAwait(false); - aggregate.PingsReceived.ShouldAllBeEquivalentTo(new []{pingId1, pingId2}); + aggregate.PingsReceived.Should().BeEquivalentTo(new []{pingId1, pingId2}); } [Test] @@ -339,7 +339,7 @@ await CommandBus.PublishAsync( // Assert PublishedDomainEvents.Count.Should().Be(10); - PublishedDomainEvents.Select(d => d.AggregateSequenceNumber).ShouldAllBeEquivalentTo(Enumerable.Range(1, 10)); + PublishedDomainEvents.Select(d => d.AggregateSequenceNumber).Should().BeEquivalentTo(Enumerable.Range(1, 10)); } [Test] @@ -360,7 +360,7 @@ await CommandBus.PublishAsync( // Assert PublishedDomainEvents.Count.Should().Be(10); - PublishedDomainEvents.Select(d => d.AggregateSequenceNumber).ShouldAllBeEquivalentTo(Enumerable.Range(11, 10)); + PublishedDomainEvents.Select(d => d.AggregateSequenceNumber).Should().BeEquivalentTo(Enumerable.Range(11, 10)); } [Test] diff --git a/Source/EventFlow.TestHelpers/Suites/TestSuiteForReadModelStore.cs b/Source/EventFlow.TestHelpers/Suites/TestSuiteForReadModelStore.cs index e14122bc2..fcb3ae16e 100644 --- a/Source/EventFlow.TestHelpers/Suites/TestSuiteForReadModelStore.cs +++ b/Source/EventFlow.TestHelpers/Suites/TestSuiteForReadModelStore.cs @@ -35,9 +35,9 @@ using EventFlow.TestHelpers.Aggregates.Queries; using EventFlow.TestHelpers.Aggregates.ValueObjects; using EventFlow.TestHelpers.Extensions; +using AutoFixture; using FluentAssertions; using NUnit.Framework; -using Ploeh.AutoFixture; namespace EventFlow.TestHelpers.Suites { @@ -113,7 +113,7 @@ public async Task CanStoreMultipleMessages() // Assert returnedThingyMessages.Should().HaveCount(thingyMessages.Count); - returnedThingyMessages.ShouldAllBeEquivalentTo(thingyMessages); + returnedThingyMessages.Should().BeEquivalentTo(thingyMessages); } [Test] @@ -135,7 +135,7 @@ await CommandBus.PublishAsync(new ThingyImportCommand( // Assert thingy.PingsReceived.Should().Be(pingIds.Count); - returnedThingyMessages.ShouldAllBeEquivalentTo(returnedThingyMessages); + returnedThingyMessages.Should().BeEquivalentTo(thingyMessages); } [Test] @@ -306,7 +306,7 @@ public async Task CanStoreMessageHistory() // Assert returnedThingyMessages.Should().HaveCount(thingyMessages.Count); - returnedThingyMessages.ShouldAllBeEquivalentTo(thingyMessages); + returnedThingyMessages.Should().BeEquivalentTo(thingyMessages); } private class WaitState diff --git a/Source/EventFlow.TestHelpers/Suites/TestSuiteForServiceRegistration.cs b/Source/EventFlow.TestHelpers/Suites/TestSuiteForServiceRegistration.cs index de26a5640..36c6a2f46 100644 --- a/Source/EventFlow.TestHelpers/Suites/TestSuiteForServiceRegistration.cs +++ b/Source/EventFlow.TestHelpers/Suites/TestSuiteForServiceRegistration.cs @@ -165,7 +165,7 @@ public void ServiceViaGenericNotFoundThrowsException() { var resolver = Sut.CreateResolver(false); Action callingResolve = () => resolver.Resolve(); - callingResolve.ShouldThrow(); + callingResolve.Should().Throw(); } [Test] @@ -173,7 +173,7 @@ public void ServiceViaTypeNotFoundThrowsException() { var resolver = Sut.CreateResolver(false); Action callingResolve = () => resolver.Resolve(typeof(IMagicInterface)); - callingResolve.ShouldThrow(); + callingResolve.Should().Throw(); } [Test] @@ -402,7 +402,7 @@ public void AbstractMetadataProviderIsNotRegistered() }); // Assert - act.ShouldNotThrow(); + act.Should().NotThrow(); } public static void Assert_Decorator(IServiceRegistration serviceRegistration) @@ -445,7 +445,7 @@ public void AbstractSubscriberIsNotRegistered() }); // Assert - act.ShouldNotThrow(); + act.Should().NotThrow(); } public abstract class AbstractTestSubscriber : @@ -476,7 +476,7 @@ public void AbstractCommandHandlerIsNotRegistered() }); // Assert - act.ShouldNotThrow(); + act.Should().NotThrow(); } public abstract class AbstractTestCommandHandler : @@ -497,7 +497,7 @@ public void AbstractEventUpgraderIsNotRegistered() }); // Assert - act.ShouldNotThrow(); + act.Should().NotThrow(); } public abstract class AbstractTestEventUpgrader : IEventUpgrader @@ -519,7 +519,7 @@ public void AbstractQueryHandlerIsNotRegistered() }); // Assert - act.ShouldNotThrow(); + act.Should().NotThrow(); } [Test] diff --git a/Source/EventFlow.TestHelpers/Suites/TestSuiteForSnapshotStore.cs b/Source/EventFlow.TestHelpers/Suites/TestSuiteForSnapshotStore.cs index 9c8290fae..18152ae4d 100644 --- a/Source/EventFlow.TestHelpers/Suites/TestSuiteForSnapshotStore.cs +++ b/Source/EventFlow.TestHelpers/Suites/TestSuiteForSnapshotStore.cs @@ -197,7 +197,7 @@ public async Task OldSnapshotsAreUpgradedToLatestVersionAndAppliedToAggregate() // Assert thingyAggregate.Version.Should().Be(expectedVersion); - thingyAggregate.PingsReceived.ShouldAllBeEquivalentTo(pingIds); + thingyAggregate.PingsReceived.Should().BeEquivalentTo(pingIds); thingyAggregate.SnapshotVersions.Should().Contain(new[] {ThingySnapshotVersion.Version1, ThingySnapshotVersion.Version2}); } diff --git a/Source/EventFlow.TestHelpers/Test.cs b/Source/EventFlow.TestHelpers/Test.cs index 2c55cd7c1..e3b809cab 100644 --- a/Source/EventFlow.TestHelpers/Test.cs +++ b/Source/EventFlow.TestHelpers/Test.cs @@ -30,10 +30,10 @@ using EventFlow.Logs; using EventFlow.TestHelpers.Aggregates; using EventFlow.TestHelpers.Aggregates.Entities; +using AutoFixture; +using AutoFixture.AutoMoq; using Moq; using NUnit.Framework; -using Ploeh.AutoFixture; -using Ploeh.AutoFixture.AutoMoq; namespace EventFlow.TestHelpers { @@ -120,6 +120,7 @@ protected IDomainEvent ToDomainEvent { Timestamp = A(), SourceId = A(), + EventId = A(), }; if (aggregateSequenceNumber == 0) diff --git a/Source/EventFlow.TestHelpers/TestsFor.cs b/Source/EventFlow.TestHelpers/TestsFor.cs index f2cf3ec56..907a14d6f 100644 --- a/Source/EventFlow.TestHelpers/TestsFor.cs +++ b/Source/EventFlow.TestHelpers/TestsFor.cs @@ -22,14 +22,14 @@ // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. using System; +using AutoFixture; using NUnit.Framework; -using Ploeh.AutoFixture; namespace EventFlow.TestHelpers { public abstract class TestsFor : Test { - private Lazy _lazySut; + private Lazy _lazySut; protected TSut Sut => _lazySut.Value; [SetUp] diff --git a/Source/EventFlow.TestHelpers/app.config b/Source/EventFlow.TestHelpers/app.config index 069e3fd6d..d05299f92 100644 --- a/Source/EventFlow.TestHelpers/app.config +++ b/Source/EventFlow.TestHelpers/app.config @@ -1,7 +1,7 @@ - + diff --git a/Source/EventFlow.Tests/EventFlow.Tests.csproj b/Source/EventFlow.Tests/EventFlow.Tests.csproj index 074d66d34..c37ac947d 100644 --- a/Source/EventFlow.Tests/EventFlow.Tests.csproj +++ b/Source/EventFlow.Tests/EventFlow.Tests.csproj @@ -1,7 +1,7 @@  - net451 + net452 True False diff --git a/Source/EventFlow.Tests/IntegrationTests/ReadStores/MultipleAggregateReadStoreManagerTests.cs b/Source/EventFlow.Tests/IntegrationTests/ReadStores/MultipleAggregateReadStoreManagerTests.cs index eecb375cd..8aa4b914f 100644 --- a/Source/EventFlow.Tests/IntegrationTests/ReadStores/MultipleAggregateReadStoreManagerTests.cs +++ b/Source/EventFlow.Tests/IntegrationTests/ReadStores/MultipleAggregateReadStoreManagerTests.cs @@ -63,7 +63,7 @@ public async Task EventOrdering() // Assert var readModelAb = await QueryProcessor.ProcessAsync(new ReadModelByIdQuery(ReadModeld), CancellationToken.None); - readModelAb.Indexes.ShouldAllBeEquivalentTo( + readModelAb.Indexes.Should().BeEquivalentTo( new []{0, 1, 2, 3}, o => o.WithStrictOrdering()); } diff --git a/Source/EventFlow.Tests/IntegrationTests/Sagas/AggregateSagaTests.cs b/Source/EventFlow.Tests/IntegrationTests/Sagas/AggregateSagaTests.cs index 289d1146d..fd50e1dc5 100644 --- a/Source/EventFlow.Tests/IntegrationTests/Sagas/AggregateSagaTests.cs +++ b/Source/EventFlow.Tests/IntegrationTests/Sagas/AggregateSagaTests.cs @@ -157,17 +157,17 @@ public async Task PublishingStartAndCompleteWithPingsResultInCorrectMessages() // Assert - saga var thingySaga = await LoadSagaAsync(thingyId).ConfigureAwait(false); thingySaga.State.Should().Be(SagaState.Completed); - thingySaga.PingIdsSinceStarted.ShouldAllBeEquivalentTo(pingsWithRunningSaga); + thingySaga.PingIdsSinceStarted.Should().BeEquivalentTo(pingsWithRunningSaga); // Assert - aggregate var thingyAggregate = await LoadAggregateAsync(thingyId).ConfigureAwait(false); - thingyAggregate.PingsReceived.ShouldAllBeEquivalentTo( + thingyAggregate.PingsReceived.Should().BeEquivalentTo( pingsWithNewSaga.Concat(pingsWithRunningSaga).Concat(pingsWithCompletedSaga)); var receivedSagaPingIds = thingyAggregate.Messages .Select(m => PingId.With(m.Message)) .ToList(); receivedSagaPingIds.Should().HaveCount(3); - receivedSagaPingIds.ShouldAllBeEquivalentTo(pingsWithRunningSaga); + receivedSagaPingIds.Should().BeEquivalentTo(pingsWithRunningSaga); } protected override IRootResolver CreateRootResolver(IEventFlowOptions eventFlowOptions) diff --git a/Source/EventFlow.Tests/IntegrationTests/Sagas/AlternativeSagaStoreTests.cs b/Source/EventFlow.Tests/IntegrationTests/Sagas/AlternativeSagaStoreTests.cs index fa6aa8395..f60d5c885 100644 --- a/Source/EventFlow.Tests/IntegrationTests/Sagas/AlternativeSagaStoreTests.cs +++ b/Source/EventFlow.Tests/IntegrationTests/Sagas/AlternativeSagaStoreTests.cs @@ -115,7 +115,7 @@ public void SagaLocatorReturningNullDoesntThrow() Action action = () => _commandBus.Publish(new AlternativeSagaStoreTestClasses.SagaTestBCommand(aggregateId), CancellationToken.None); // Assert - action.ShouldNotThrow(); + action.Should().NotThrow(); } [Test] diff --git a/Source/EventFlow.Tests/IntegrationTests/UnicodeTests.cs b/Source/EventFlow.Tests/IntegrationTests/UnicodeTests.cs index f5a8ec116..9e0baf2d1 100644 --- a/Source/EventFlow.Tests/IntegrationTests/UnicodeTests.cs +++ b/Source/EventFlow.Tests/IntegrationTests/UnicodeTests.cs @@ -46,7 +46,7 @@ public void UpperCaseIdentityThrows() Action action = () => new Identität1("Identität1-00000000-0000-0000-0000-000000000000"); // Assert - action.ShouldThrow(); + action.Should().Throw(); } [Test] @@ -79,7 +79,7 @@ public void UnicodeCommands() Action action = () => commandDefinitions.Load(typeof(Cömmand)); // Assert - action.ShouldNotThrow(); + action.Should().NotThrow(); } [Test] @@ -92,7 +92,7 @@ public void UnicodeEvents() Action action = () => eventDefinitionService.Load(typeof(Püng1Event)); // Assert - action.ShouldNotThrow(); + action.Should().NotThrow(); } [Test] diff --git a/Source/EventFlow.Tests/UnitTests/Aggregates/AggregateRootTests.cs b/Source/EventFlow.Tests/UnitTests/Aggregates/AggregateRootTests.cs index 3aca91f93..f98ee4797 100644 --- a/Source/EventFlow.Tests/UnitTests/Aggregates/AggregateRootTests.cs +++ b/Source/EventFlow.Tests/UnitTests/Aggregates/AggregateRootTests.cs @@ -150,7 +150,7 @@ public void ApplyEventWithOutOfOrderSequenceNumberShouldThrow() Action applyingEvents = () => Sut.ApplyEvents(new []{ domainEvent }); // Assert - applyingEvents.ShouldThrow(); + applyingEvents.Should().Throw(); } } } \ No newline at end of file diff --git a/Source/EventFlow.Tests/UnitTests/Aggregates/AggregateStoreTests.cs b/Source/EventFlow.Tests/UnitTests/Aggregates/AggregateStoreTests.cs index 099874122..b1978c94f 100644 --- a/Source/EventFlow.Tests/UnitTests/Aggregates/AggregateStoreTests.cs +++ b/Source/EventFlow.Tests/UnitTests/Aggregates/AggregateStoreTests.cs @@ -39,9 +39,9 @@ using EventFlow.TestHelpers.Aggregates.Events; using EventFlow.TestHelpers.Aggregates.ValueObjects; using EventFlow.TestHelpers.Extensions; +using AutoFixture; using Moq; using NUnit.Framework; -using Ploeh.AutoFixture; namespace EventFlow.Tests.UnitTests.Aggregates { diff --git a/Source/EventFlow.Tests/UnitTests/Core/VersionedTypes/VersionedTypeDefinitionServiceTestSuite.cs b/Source/EventFlow.Tests/UnitTests/Core/VersionedTypes/VersionedTypeDefinitionServiceTestSuite.cs index 1ac7374e1..bf54bf1f8 100644 --- a/Source/EventFlow.Tests/UnitTests/Core/VersionedTypes/VersionedTypeDefinitionServiceTestSuite.cs +++ b/Source/EventFlow.Tests/UnitTests/Core/VersionedTypes/VersionedTypeDefinitionServiceTestSuite.cs @@ -26,9 +26,9 @@ using System.Linq; using EventFlow.Core.VersionedTypes; using EventFlow.TestHelpers; +using AutoFixture; using FluentAssertions; using NUnit.Framework; -using Ploeh.AutoFixture; namespace EventFlow.Tests.UnitTests.Core.VersionedTypes { @@ -206,7 +206,7 @@ public void GetAllDefinitions_WhenAllLoaded_ReturnsAll() .ToList(); // Assert - result.ShouldAllBeEquivalentTo(expectedTypes); + result.Should().BeEquivalentTo(expectedTypes); } [Test] diff --git a/Source/EventFlow.Tests/UnitTests/EventStores/ConcurrentFilesEventPersistanceTests.cs b/Source/EventFlow.Tests/UnitTests/EventStores/ConcurrentFilesEventPersistanceTests.cs index f791ff018..4cefb05d0 100644 --- a/Source/EventFlow.Tests/UnitTests/EventStores/ConcurrentFilesEventPersistanceTests.cs +++ b/Source/EventFlow.Tests/UnitTests/EventStores/ConcurrentFilesEventPersistanceTests.cs @@ -97,7 +97,7 @@ public void MultipleInstancesWithSamePathFail() Action action = () => Task.WaitAll(tasks.ToArray()); // Assert - action.ShouldThrow("because of concurrent access to the same files."); + action.Should().Throw("because of concurrent access to the same files."); } [Test] @@ -114,7 +114,7 @@ public void MultipleInstancesWithDifferentPathsWork() Action action = () => Task.WaitAll(tasks.ToArray()); // Assert - action.ShouldNotThrow(); + action.Should().NotThrow(); } [Test] @@ -131,7 +131,7 @@ public void SingleInstanceWorks() Action action = () => Task.WaitAll(tasks.ToArray()); // Assert - action.ShouldNotThrow(); + action.Should().NotThrow(); } private IFilesEventStoreConfiguration ConfigurePath(string storePath) diff --git a/Source/EventFlow.Tests/UnitTests/EventStores/EventDefinitionServiceTests.cs b/Source/EventFlow.Tests/UnitTests/EventStores/EventDefinitionServiceTests.cs index b97e0be1a..f205b0b77 100644 --- a/Source/EventFlow.Tests/UnitTests/EventStores/EventDefinitionServiceTests.cs +++ b/Source/EventFlow.Tests/UnitTests/EventStores/EventDefinitionServiceTests.cs @@ -61,7 +61,7 @@ public void GetDefinitions_OnEventWithMultipleDefinitions_ReturnsThemAll() eventDefinitions.Should().HaveCount(3); eventDefinitions .Select(d => $"{d.Name}-V{d.Version}") - .ShouldAllBeEquivalentTo(new []{"multi-names-event-V1", "MultiNamesEvent-V1", "MultiNamesEvent-V2"}); + .Should().BeEquivalentTo(new []{"multi-names-event-V1", "MultiNamesEvent-V1", "MultiNamesEvent-V2"}); } [EventVersion("Fancy", 42)] diff --git a/Source/EventFlow.Tests/UnitTests/EventStores/Snapshots/SnapshotUpgradeServiceTests.cs b/Source/EventFlow.Tests/UnitTests/EventStores/Snapshots/SnapshotUpgradeServiceTests.cs index 60b1a8d13..e6717bb29 100644 --- a/Source/EventFlow.Tests/UnitTests/EventStores/Snapshots/SnapshotUpgradeServiceTests.cs +++ b/Source/EventFlow.Tests/UnitTests/EventStores/Snapshots/SnapshotUpgradeServiceTests.cs @@ -67,7 +67,7 @@ public async Task UpgradeAsync() // Assert snapshot.Should().BeOfType(); var snapshotV3 = (ThingySnapshot) snapshot; - snapshotV3.PingsReceived.ShouldAllBeEquivalentTo(pingIds); + snapshotV3.PingsReceived.Should().BeEquivalentTo(pingIds); snapshotV3.PreviousVersions.Should().Contain(ThingySnapshotVersion.Version1); snapshotV3.PreviousVersions.Should().Contain(ThingySnapshotVersion.Version2); } diff --git a/Source/EventFlow.Tests/UnitTests/ReadStores/AggregateReadStoreManagerTests.cs b/Source/EventFlow.Tests/UnitTests/ReadStores/AggregateReadStoreManagerTests.cs index 7bd3d343e..5ebbc6ce9 100644 --- a/Source/EventFlow.Tests/UnitTests/ReadStores/AggregateReadStoreManagerTests.cs +++ b/Source/EventFlow.Tests/UnitTests/ReadStores/AggregateReadStoreManagerTests.cs @@ -74,7 +74,7 @@ public async Task EventsAreApplied() // Assert AppliedDomainEvents.Should().HaveCount(emittedEvents.Length); - AppliedDomainEvents.ShouldAllBeEquivalentTo(emittedEvents); + AppliedDomainEvents.Should().BeEquivalentTo(emittedEvents); } [Test] @@ -149,7 +149,7 @@ public async Task StoredEventsAreAppliedIfThereAreMissingEvents() // Assert AppliedDomainEvents.Should().HaveCount(storedEvents.Length); - AppliedDomainEvents.ShouldAllBeEquivalentTo(storedEvents); + AppliedDomainEvents.Should().BeEquivalentTo(storedEvents); } [Test] @@ -161,7 +161,7 @@ public void ThrowsIfReadModelSubscribesNoEvents() ReadModelWithoutEvents>(null, null, null, null, null); }; - a.ShouldThrow().WithInnerMessage("*does not implement any*"); + a.Should().Throw().WithInnerException().WithMessage("*does not implement any*"); } [Test] @@ -173,7 +173,7 @@ public void ThrowsIfReadModelSubscribesSameEventTwice() ReadModelWithAmbigiousEvents>(null, null, null, null, null); }; - a.ShouldThrow().WithInnerMessage("*implements ambiguous*"); + a.Should().Throw().WithInnerException().WithMessage("*implements ambiguous*"); } private class ReadModelWithoutEvents : IReadModel diff --git a/Source/EventFlow.Tests/UnitTests/Sagas/DispatchToSagasTests.cs b/Source/EventFlow.Tests/UnitTests/Sagas/DispatchToSagasTests.cs index d7d846a07..a2000060b 100644 --- a/Source/EventFlow.Tests/UnitTests/Sagas/DispatchToSagasTests.cs +++ b/Source/EventFlow.Tests/UnitTests/Sagas/DispatchToSagasTests.cs @@ -91,6 +91,23 @@ public async Task SagaUpdaterIsInvokedCorrectly() Times.Exactly(domainEventCount)); } + [Test] + public async Task SagaStoreReceivesEventIdAsSourceId() + { + // Arrange + var sagaMock = Arrange_Woking_SagaStore(SagaState.Running); + var domainEvent = ADomainEvent(); + + // Act + await Sut.ProcessAsync(new[] { domainEvent }, CancellationToken.None).ConfigureAwait(false); + + // Assert + _sagaStoreMock.Verify(a => a.UpdateAsync(It.IsAny(), It.IsAny(), + domainEvent.Metadata.EventId, + It.IsAny>(), + It.IsAny())); + } + [Test] public async Task SagaErrorHandlerIsInvokedCorrectly() { diff --git a/Source/EventFlow.Tests/UnitTests/ValueObjects/SingleValueObjectTests.cs b/Source/EventFlow.Tests/UnitTests/ValueObjects/SingleValueObjectTests.cs index 9a6a26c6e..9ee24c562 100644 --- a/Source/EventFlow.Tests/UnitTests/ValueObjects/SingleValueObjectTests.cs +++ b/Source/EventFlow.Tests/UnitTests/ValueObjects/SingleValueObjectTests.cs @@ -64,7 +64,7 @@ public void Ordering() var orderedSingleValueObjects = singleValueObjects.OrderBy(v => v).ToList(); // Assert - orderedSingleValueObjects.Select(v => v.Value).ShouldAllBeEquivalentTo( + orderedSingleValueObjects.Select(v => v.Value).Should().BeEquivalentTo( orderedValues, o => o.WithStrictOrdering()); } @@ -82,7 +82,7 @@ public void EnumOrdering() var orderedSingleValueObjects = singleValueObjects.OrderBy(v => v).ToList(); // Assert - orderedSingleValueObjects.Select(v => v.Value).ShouldAllBeEquivalentTo( + orderedSingleValueObjects.Select(v => v.Value).Should().BeEquivalentTo( orderedValues, o => o.WithStrictOrdering()); } @@ -115,7 +115,7 @@ public void EnumOrderingManual() .ToList(); // Assert - orderedValues.ShouldAllBeEquivalentTo( + orderedValues.Should().BeEquivalentTo( new [] { MagicEnum.Zero, diff --git a/Source/EventFlow.Tests/app.config b/Source/EventFlow.Tests/app.config index 069e3fd6d..d05299f92 100644 --- a/Source/EventFlow.Tests/app.config +++ b/Source/EventFlow.Tests/app.config @@ -1,7 +1,7 @@ - + diff --git a/Source/EventFlow/Core/Caching/MemoryCache.cs b/Source/EventFlow/Core/Caching/MemoryCache.cs index 7a015954e..6fb9c1981 100644 --- a/Source/EventFlow/Core/Caching/MemoryCache.cs +++ b/Source/EventFlow/Core/Caching/MemoryCache.cs @@ -21,7 +21,7 @@ // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -#if NET451 +#if NET452 using System; using System.Runtime.Caching; diff --git a/Source/EventFlow/Core/GuidFactories.cs b/Source/EventFlow/Core/GuidFactories.cs index d90b8c83c..b5f265434 100644 --- a/Source/EventFlow/Core/GuidFactories.cs +++ b/Source/EventFlow/Core/GuidFactories.cs @@ -24,33 +24,82 @@ using System; using System.Security.Cryptography; using System.Text; +using System.Threading; namespace EventFlow.Core { public static class GuidFactories { - /// - /// Creates a sequential Guid that can be used to avoid database fragmentation - /// http://stackoverflow.com/a/2187898 - /// public static class Comb { + private static int _counter; + + private static long GetTicks() + { + var i = Interlocked.Increment(ref _counter); + return DateTime.UtcNow.Ticks + i; + } + + /// + /// Generates a GUID values that causes less index fragmentation when stored + /// in e.g. uniqueidentifier columns in MSSQL. + /// + /// + /// 2825c1d8-4587-cc55-08c1-08d6bde2765b + /// 901337ba-c64b-c6d4-08c2-08d6bde2765b + /// 45d57ba2-acc5-ce80-08c3-08d6bde2765b + /// 36528acf-352a-c28c-08c4-08d6bde2765b + /// 6fc88b5e-3782-c8fd-08c5-08d6bde2765b + /// public static Guid Create() { - var destinationArray = Guid.NewGuid().ToByteArray(); - var time = new DateTime(0x76c, 1, 1); - var now = DateTime.Now; - var span = new TimeSpan(now.Ticks - time.Ticks); - var timeOfDay = now.TimeOfDay; - var bytes = BitConverter.GetBytes(span.Days); - var array = BitConverter.GetBytes((long)(timeOfDay.TotalMilliseconds / 3.333333)); - - Array.Reverse(bytes); - Array.Reverse(array); - Array.Copy(bytes, bytes.Length - 2, destinationArray, destinationArray.Length - 6, 2); - Array.Copy(array, array.Length - 4, destinationArray, destinationArray.Length - 4, 4); - - return new Guid(destinationArray); + var uid = Guid.NewGuid().ToByteArray(); + var binDate = BitConverter.GetBytes(GetTicks()); + + return new Guid( + new[] + { + uid[0], uid[1], uid[2], uid[3], + uid[4], uid[5], + uid[6], (byte)(0xc0 | (0xf & uid[7])), + binDate[1], binDate[0], + binDate[7], binDate[6], binDate[5], binDate[4], binDate[3], binDate[2] + }); + } + + /// + /// Generates a GUID values that causes less index fragmentation when stored + /// in e.g. nvarchar(n) columns in MSSQL. + /// + /// + /// 899ee1b9-bde2-08d6-20d8-b7e20375c7c9 + /// 899f09b9-bde2-08d6-fd1c-5ec8f3349bcf + /// 899f09ba-bde2-08d6-1521-51d781607ac4 + /// 899f09bb-bde2-08d6-7e6a-fe84f5237dc4 + /// 899f09bc-bde2-08d6-c2f0-276123e06fcf + /// + public static Guid CreateForString() + { + /* + From: https://docs.microsoft.com/en-us/dotnet/api/system.guid.tobytearray + Note that the order of bytes in the returned byte array is different from the string + representation of a Guid value. The order of the beginning four-byte group and the + next two two-byte groups is reversed, whereas the order of the last two-byte group + and the closing six-byte group is the same. + */ + + var uid = Guid.NewGuid().ToByteArray(); + var binDate = BitConverter.GetBytes(GetTicks()); + + return new Guid( + new[] + { + binDate[0], binDate[1], binDate[2], binDate[3], + binDate[4], binDate[5], + binDate[6], binDate[7], + uid[0], uid[1], + uid[2], uid[3], uid[4], uid[5], uid[6], (byte)(0xc0 | (0xf & uid[7])), + }); } } diff --git a/Source/EventFlow/Core/Identity.cs b/Source/EventFlow/Core/Identity.cs index bfd2ec239..808823860 100644 --- a/Source/EventFlow/Core/Identity.cs +++ b/Source/EventFlow/Core/Identity.cs @@ -64,7 +64,7 @@ public static T NewDeterministic(Guid namespaceId, byte[] nameBytes) public static T NewComb() { - var guid = GuidFactories.Comb.Create(); + var guid = GuidFactories.Comb.CreateForString(); return With(guid); } diff --git a/Source/EventFlow/EventFlow.csproj b/Source/EventFlow/EventFlow.csproj index c4d4eef78..6d01e8b85 100644 --- a/Source/EventFlow/EventFlow.csproj +++ b/Source/EventFlow/EventFlow.csproj @@ -1,7 +1,7 @@  - net451;netstandard1.6;netstandard2.0 + net452;netstandard1.6;netstandard2.0 True True False @@ -27,12 +27,13 @@ + All - + \ No newline at end of file diff --git a/Source/EventFlow/EventFlowOptions.cs b/Source/EventFlow/EventFlowOptions.cs index 111637d44..46c4a600a 100644 --- a/Source/EventFlow/EventFlowOptions.cs +++ b/Source/EventFlow/EventFlowOptions.cs @@ -222,7 +222,7 @@ private void RegisterDefaults(IServiceRegistration serviceRegistration) serviceRegistration.Register(); serviceRegistration.Register(); serviceRegistration.Register(); -#if NET451 +#if NET452 serviceRegistration.Register(Lifetime.Singleton); #else serviceRegistration.Register(Lifetime.Singleton); diff --git a/Source/EventFlow/Sagas/DispatchToSagas.cs b/Source/EventFlow/Sagas/DispatchToSagas.cs index f6170b8db..f8928779c 100644 --- a/Source/EventFlow/Sagas/DispatchToSagas.cs +++ b/Source/EventFlow/Sagas/DispatchToSagas.cs @@ -104,7 +104,7 @@ private async Task ProcessSagaAsync( await _sagaStore.UpdateAsync( sagaId, details.SagaType, - domainEvent.Metadata.SourceId, + domainEvent.Metadata.EventId, (s, c) => UpdateSagaAsync(s, domainEvent, details, c), cancellationToken) .ConfigureAwait(false); diff --git a/appveyor.yml b/appveyor.yml index fb648f1cd..5403c6442 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,7 +1,7 @@ init: - git config --global core.autocrlf input -version: 0.69.{build} +version: 0.70.{build} skip_tags: true diff --git a/build.cake b/build.cake index 0e77ff1a2..5e8da2f34 100644 --- a/build.cake +++ b/build.cake @@ -325,7 +325,7 @@ void ExecuteTest(string files, string resultsFile) { ArgumentCustomization = aggs => aggs.Append("-returntargetcode"), OldStyle = true, - MergeOutput = true + MergeOutput = true } .WithFilter("+[EventFlow*]*") .WithFilter("-[*Tests]*") diff --git a/build.ps1 b/build.ps1 index 265bd1238..e53d2a288 100644 --- a/build.ps1 +++ b/build.ps1 @@ -85,7 +85,7 @@ function GetProxyEnabledWebClient { $wc = New-Object System.Net.WebClient $proxy = [System.Net.WebRequest]::GetSystemWebProxy() - $proxy.Credentials = [System.Net.CredentialCache]::DefaultCredentials + $proxy.Credentials = [System.Net.CredentialCache]::DefaultCredentials $wc.Proxy = $proxy return $wc } @@ -115,7 +115,7 @@ if ((Test-Path $PSScriptRoot) -and !(Test-Path $TOOLS_DIR)) { # Make sure that packages.config exist. if (!(Test-Path $PACKAGES_CONFIG)) { - Write-Verbose -Message "Downloading packages.config..." + Write-Verbose -Message "Downloading packages.config..." try { $wc = GetProxyEnabledWebClient $wc.DownloadFile("https://cakebuild.net/download/bootstrapper/packages", $PACKAGES_CONFIG) } catch {