Skip to content

Commit

Permalink
Merge branch 'develop'
Browse files Browse the repository at this point in the history
  • Loading branch information
rasmus committed Sep 27, 2015
2 parents 16e5b42 + 7359312 commit 6fa270f
Show file tree
Hide file tree
Showing 27 changed files with 821 additions and 473 deletions.
24 changes: 23 additions & 1 deletion RELEASE_NOTES.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,26 @@
### New in 0.15 (not released yet)
### New in 0.16 (not released yet)

* Breaking: Removed `HasRegistrationFor<>` and `GetRegisteredServices()`
from `IServiceRegistration` and added them to `IResolver` instead. The
methods required that all service registrations went through EventFlow,
which in most cases they will not
* Obsolete: Marked `IServiceRegistration.RegisterIfNotRegistered(...)`, use
the `keepDefault = true` on the other `Register(...)` methods instead
* New: Major changes have been done to how EventFlow handles service
registration and bootstrapping in order for developers to skip calling
`CreateResolver()` (or `CreateContainer()` if using the `EventFlow.Autofac`
package) completely. EventFlow will register its bootstrap services in the
IoC container and configure itself whenever the container is created
* New: Introduced `IBootstrap` interface that you can register. It has a
single `BootAsync(...)` method that will be called as soon as the IoC
container is ready (similar to that of `IStartable` of Autofac)
* Fixed: Correct order of service registration decorators. They are now
applied in the same order they are applied, e.g., the _last_ registered
service decorator will be the "outer" service
* Fixed: Added missing `ICommand<,>` interface to abstract `Command<,>` class in
`EventFlow.Commands`.

### New in 0.15.1057 (released 2015-09-24)

* Fixed: Added `UseHangfireJobScheduler()` and marked `UseHandfireJobScheduler()`
obsolete, fixing method spelling mistake
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
// 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 Autofac;
using EventFlow.Aggregates;
using EventFlow.Autofac.Extensions;
using EventFlow.Configuration;
Expand All @@ -34,7 +36,7 @@ namespace EventFlow.Autofac.Tests.UnitTests.Aggregates
public class AutofacAggregateFactoryTests
{
[Test]
public async void CreatesNewAggregateWithIdParameter()
public async Task CreatesNewAggregateWithIdParameter()
{
// Arrange
using (var resolver = EventFlowOptions.New
Expand All @@ -55,7 +57,31 @@ public async void CreatesNewAggregateWithIdParameter()
}

[Test]
public async void CreatesNewAggregateWithIdAndInterfaceParameters()
public async Task ExternalContainerBuild()
{
// Arrange
var containerBuilder = new ContainerBuilder();
EventFlowOptions.New
.UseAutofacContainerBuilder(containerBuilder)
.UseAutofacAggregateRootFactory()
.AddAggregateRoots(typeof (AutofacAggregateFactoryTests).Assembly);

using (var container = containerBuilder.Build())
using (var lifetimeScope = container.BeginLifetimeScope())
{
var id = TestId.New;
var sut = lifetimeScope.Resolve<IAggregateFactory>();

// Act
var aggregateWithIdParameter = await sut.CreateNewAggregateAsync<TestAggregate, TestId>(id).ConfigureAwait(false);

// Assert
aggregateWithIdParameter.Id.Should().Be(id);
}
}

[Test]
public async Task CreatesNewAggregateWithIdAndInterfaceParameters()
{
// Arrange
using (var resolver = EventFlowOptions.New
Expand All @@ -75,7 +101,7 @@ public async void CreatesNewAggregateWithIdAndInterfaceParameters()
}

[Test]
public async void CreatesNewAggregateWithIdAndTypeParameters()
public async Task CreatesNewAggregateWithIdAndTypeParameters()
{
// Arrange
using (var resolver = EventFlowOptions.New
Expand Down
6 changes: 0 additions & 6 deletions Source/EventFlow.Autofac/EventFlow.Autofac.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,6 @@
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\EventFlow\Configuration\Registrations\AutofacDecorator.cs">
<Link>Registrations\AutofacDecorator.cs</Link>
</Compile>
<Compile Include="..\EventFlow\Configuration\Registrations\AutofacRegistration.cs">
<Link>Registrations\AutofacRegistration.cs</Link>
</Compile>
<Compile Include="..\EventFlow\Configuration\Registrations\AutofacResolver.cs">
<Link>Registrations\AutofacResolver.cs</Link>
</Compile>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

using EventFlow.Configuration;
using EventFlow.Extensions;
using EventFlow.RabbitMQ.Integrations;
using EventFlow.Subscribers;

Expand All @@ -35,10 +34,10 @@ public static IEventFlowOptions PublishToRabbitMq(
{
return eventFlowOptions.RegisterServices(sr =>
{
sr.RegisterIfNotRegistered<IRabbitMqConnectionFactory, RabbitMqConnectionFactory>(Lifetime.Singleton);
sr.RegisterIfNotRegistered<IRabbitMqMessageFactory, RabbitMqMessageFactory>(Lifetime.Singleton);
sr.RegisterIfNotRegistered<IRabbitMqPublisher, RabbitMqPublisher>(Lifetime.Singleton);
sr.RegisterIfNotRegistered<IRabbitMqRetryStrategy, RabbitMqRetryStrategy>(Lifetime.Singleton);
sr.Register<IRabbitMqConnectionFactory, RabbitMqConnectionFactory>(Lifetime.Singleton);
sr.Register<IRabbitMqMessageFactory, RabbitMqMessageFactory>(Lifetime.Singleton);
sr.Register<IRabbitMqPublisher, RabbitMqPublisher>(Lifetime.Singleton);
sr.Register<IRabbitMqRetryStrategy, RabbitMqRetryStrategy>(Lifetime.Singleton);

sr.Register(rc => configuration, Lifetime.Singleton);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,7 @@ public static IEventFlowOptions UseMssqlReadModel<TReadModel, TReadModelLocator>
return eventFlowOptions
.RegisterServices(f =>
{
if (!f.HasRegistrationFor<IReadModelSqlGenerator>())
{
f.Register<IReadModelSqlGenerator, ReadModelSqlGenerator>(Lifetime.Singleton);
}
f.Register<IReadModelSqlGenerator, ReadModelSqlGenerator>(Lifetime.Singleton, true);
f.Register<IMssqlReadModelStore<TReadModel>, MssqlReadModelStore<TReadModel>>();
f.Register<IReadModelStore<TReadModel>>(r => r.Resolver.Resolve<IMssqlReadModelStore<TReadModel>>());
})
Expand All @@ -52,10 +49,7 @@ public static IEventFlowOptions UseMssqlReadModel<TReadModel>(
return eventFlowOptions
.RegisterServices(f =>
{
if (!f.HasRegistrationFor<IReadModelSqlGenerator>())
{
f.Register<IReadModelSqlGenerator, ReadModelSqlGenerator>(Lifetime.Singleton);
}
f.Register<IReadModelSqlGenerator, ReadModelSqlGenerator>(Lifetime.Singleton, true);
f.Register<IMssqlReadModelStore<TReadModel>, MssqlReadModelStore<TReadModel>>();
f.Register<IReadModelStore<TReadModel>>(r => r.Resolver.Resolve<IMssqlReadModelStore<TReadModel>>());
})
Expand Down
1 change: 1 addition & 0 deletions Source/EventFlow.Tests/EventFlow.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@
<Compile Include="UnitTests\Commands\CommandTests.cs" />
<Compile Include="UnitTests\Commands\DistinctCommandTests.cs" />
<Compile Include="UnitTests\Commands\CommandDefinitionServiceTests.cs" />
<Compile Include="UnitTests\Configuration\Decorators\DecoratorServiceTests.cs" />
<Compile Include="UnitTests\Configuration\ModuleRegistrationTests.cs" />
<Compile Include="UnitTests\Core\CircularBufferTests.cs" />
<Compile Include="UnitTests\Core\IdentityTests.cs" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
// The MIT License (MIT)
//
// Copyright (c) 2015 Rasmus Mikkelsen
// https://github.com/rasmus/EventFlow
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// 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 EventFlow.Configuration;
using EventFlow.Configuration.Decorators;
using EventFlow.TestHelpers;
using FluentAssertions;
using Moq;
using NUnit.Framework;

namespace EventFlow.Tests.UnitTests.Configuration.Decorators
{
public class DecoratorServiceTests : TestsFor<DecoratorService>
{
// ReSharper disable ClassNeverInstantiated.Local
// ReSharper disable MemberCanBePrivate.Local
private interface IMagicInterface { }
private class MagicClass : IMagicInterface { }
private class MagicClassDecorator1 : IMagicInterface
{
public IMagicInterface Inner { get; }
public MagicClassDecorator1(IMagicInterface magicInterface) { Inner = magicInterface; }
}
private class MagicClassDecorator2 : IMagicInterface
{
public IMagicInterface Inner { get; }
public MagicClassDecorator2(IMagicInterface magicInterface) { Inner = magicInterface; }
}
// ReSharper restore MemberCanBePrivate.Local
// ReSharper enable ClassNeverInstantiated.Local

private Mock<IResolverContext> _resolverContextMock;

[SetUp]
public void SetUp()
{
_resolverContextMock = new Mock<IResolverContext>();
}

[Test]
public void NoDecoratorReturnsSame()
{
// Act
var instance = Sut.Decorate<IMagicInterface>(new MagicClass(), _resolverContextMock.Object);

// Assert
instance.Should().NotBeNull();
instance.Should().BeAssignableTo<MagicClass>();
}

[Test]
public void WithTwoDecoratorsWithGeneric()
{
// Arrange
Sut.AddDecorator<IMagicInterface>((r, s) => new MagicClassDecorator1(s));
Sut.AddDecorator<IMagicInterface>((r, s) => new MagicClassDecorator2(s));

// Act
var instance = Sut.Decorate<IMagicInterface>(new MagicClass(), _resolverContextMock.Object);

// Assert
instance.Should().BeAssignableTo<MagicClassDecorator2>();
var magicClassDecorator2 = (MagicClassDecorator2)instance;
magicClassDecorator2.Inner.Should().BeAssignableTo<MagicClassDecorator1>();
var magicClassDecorator1 = (MagicClassDecorator1)magicClassDecorator2.Inner;
magicClassDecorator1.Inner.Should().BeAssignableTo<MagicClass>();
}

[Test]
public void WithTwoDecoratorsWithTyped()
{
// Arrange
Sut.AddDecorator<IMagicInterface>((r, s) => new MagicClassDecorator1(s));
Sut.AddDecorator<IMagicInterface>((r, s) => new MagicClassDecorator2(s));

// Act
var instance = Sut.Decorate(typeof(IMagicInterface), new MagicClass(), _resolverContextMock.Object);

// Assert
instance.Should().BeAssignableTo<MagicClassDecorator2>();
var magicClassDecorator2 = (MagicClassDecorator2)instance;
magicClassDecorator2.Inner.Should().BeAssignableTo<MagicClassDecorator1>();
var magicClassDecorator1 = (MagicClassDecorator1)magicClassDecorator2.Inner;
magicClassDecorator1.Inner.Should().BeAssignableTo<MagicClass>();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,12 @@ private interface IMagicInterface { }
private class MagicClass : IMagicInterface { }
private class MagicClassDecorator1 : IMagicInterface
{
public IMagicInterface Inner { get; private set; }
public IMagicInterface Inner { get; }
public MagicClassDecorator1(IMagicInterface magicInterface) { Inner = magicInterface; }
}
private class MagicClassDecorator2 : IMagicInterface
{
public IMagicInterface Inner { get; private set; }
public IMagicInterface Inner { get; }
public MagicClassDecorator2(IMagicInterface magicInterface) { Inner = magicInterface; }
}
// ReSharper enable ClassNeverInstantiated.Local
Expand All @@ -53,10 +53,88 @@ public void SetUp()
}

[Test]
public void DecoratorWorks()
public void ServiceViaFactory()
{
// Arrange
// Act
_sut.Register<IMagicInterface>(r => new MagicClass());

// Assert
Assert_Service();
}

[Test]
public void ServiceViaGeneric()
{
// Act
_sut.Register<IMagicInterface, MagicClass>();

// Assert
Assert_Service();
}

[Test]
public void ServiceViaType()
{
// Act
_sut.Register(typeof(IMagicInterface), typeof(MagicClass));

// Assert
Assert_Service();
}

public void Assert_Service()
{
// Act
var resolver = _sut.CreateResolver(true);
var magicInterface = resolver.Resolve<IMagicInterface>();

// Assert
magicInterface.Should().NotBeNull();
magicInterface.Should().BeAssignableTo<MagicClass>();
}

[Test]
public void DecoratorViaFactory()
{
// Act
_sut.Register<IMagicInterface>(r => new MagicClass());

// Assert
Assert_Decorator();
}

[Test]
public void DecoratorViaGeneric()
{
// Act
_sut.Register<IMagicInterface, MagicClass>();

// Assert
Assert_Decorator();
}

[Test]
public void DecoratorViaType()
{
// Act
_sut.Register(typeof(IMagicInterface), typeof(MagicClass));

// Assert
Assert_Decorator();
}

public void Assert_Decorator()
{
// The order should be like this (like unwrapping a present with the order of
// wrapping paper applied)
//
// Call MagicClassDecorator2
// Call MagicClassDecorator1
// Call MagicClass
// Return to MagicClassDecorator1
// Return to MagicClassDecorator2

// Arrange
_sut.Decorate<IMagicInterface>((r, inner) => new MagicClassDecorator1(inner));
_sut.Decorate<IMagicInterface>((r, inner) => new MagicClassDecorator2(inner));

Expand All @@ -65,11 +143,11 @@ public void DecoratorWorks()
var magic = resolver.Resolve<IMagicInterface>();

// Assert
magic.Should().BeAssignableTo<MagicClassDecorator1>();
var magicClassDecorator1 = (MagicClassDecorator1) magic;
magicClassDecorator1.Inner.Should().BeAssignableTo<MagicClassDecorator2>();
var magicClassDecorator2 = (MagicClassDecorator2)magicClassDecorator1.Inner;
magicClassDecorator2.Inner.Should().BeAssignableTo<MagicClass>();
magic.Should().BeAssignableTo<MagicClassDecorator2>();
var magicClassDecorator2 = (MagicClassDecorator2) magic;
magicClassDecorator2.Inner.Should().BeAssignableTo<MagicClassDecorator1>();
var magicClassDecorator1 = (MagicClassDecorator1)magicClassDecorator2.Inner;
magicClassDecorator1.Inner.Should().BeAssignableTo<MagicClass>();
}
}
}
Loading

0 comments on commit 6fa270f

Please sign in to comment.