Skip to content

Commit

Permalink
Merge pull request #158 from binarymash/feature/#89-add-toggle-states…
Browse files Browse the repository at this point in the history
…-projection

Feature/#89 add toggle states projection
  • Loading branch information
binarymash committed Jan 28, 2019
2 parents 7edbd5e + 224aea4 commit 6cd48f3
Show file tree
Hide file tree
Showing 10 changed files with 311 additions and 49 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ protected ProjectionBuilderHarness()
ProjectionStore.WhenForAnyArgs(ps => ps.Update(Arg.Any<string>(), Arg.Any<TProjection>()))
.Do(ci => UpdatedProjection = ci.ArgAt<TProjection>(1));

StreamPosition = DataFixture.Create<long>();
StreamPosition = long.MinValue;
}

protected Fixture DataFixture { get; }
Expand Down Expand Up @@ -67,6 +67,11 @@ protected async Task WhenTheEventIsHandled()
{
try
{
if (StreamPosition == long.MinValue)
{
StreamPosition = OriginalProjection?.Audit?.StreamPosition + 1 ?? 1;
}

TimeBeforeHandled = DateTimeOffset.UtcNow;
await HandleEventImplementation();
TimeAfterHandled = DateTimeOffset.UtcNow;
Expand All @@ -82,9 +87,11 @@ protected void ThenAnExceptionIsThrown()
ThrownException.Should().NotBeNull();
}

protected void ThenTheStoredProjectionIsUnchanged()
protected async Task ThenTheStoredProjectionIsUnchanged()
{
UpdatedProjection.Should().BeEquivalentTo(OriginalProjection);
await ProjectionStore.DidNotReceiveWithAnyArgs().Create(Arg.Any<string>(), Arg.Any<TProjection>());
await ProjectionStore.DidNotReceiveWithAnyArgs().Update(Arg.Any<string>(), Arg.Any<TProjection>());
await ProjectionStore.DidNotReceiveWithAnyArgs().Delete(Arg.Any<string>());
}

protected void ThenNoProjectionIsCreated()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
namespace Evelyn.Core.Tests.ReadModel.Projections.ToggleState.ProjectEvents
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using AutoFixture;
using Evelyn.Core.WriteModel.Project.Events;
using FluentAssertions;
using TestStack.BDDfy;
using Xunit;
using Projections = Evelyn.Core.ReadModel.Projections;

public class EnvironmentStateAddedSpecs : ProjectionBuilderHarness<EnvironmentStateAdded>
{
[Fact]
public void ProjectionDoesNotExist()
{
this.Given(_ => GivenThereAreNoProjections())
.When(_ => WhenWeHandleAnEnvironmentStateAddedEvent())
.Then(_ => ThenAProjectionIsCreatedWithTheNewEnvironmentState())
.Then(_ => ThenTheProjectionAuditIsSet())
.BDDfy();
}

[Fact]
public void Nominal()
{
this.Given(_ => GivenTheProjectionExists())
.And(_ => GivenTheProjectAlreadyHasAToggleState())
.When(_ => WhenWeHandleAnEnvironmentStateAddedEvent())
.Then(_ => ThenTheNewToggleStateIsAdded())
.And(_ => ThenTheProjectionAuditIsSet())
.BDDfy();
}

[Fact]
public void ProjectionAlreadyBuilt()
{
this.Given(_ => GivenTheProjectionExists())
.And(_ => GivenTheProjectAlreadyHasAToggleState())
.And(_ => GivenTheProjectionStreamVersionIsTheSameAsTheNextEvent())
.When(_ => WhenWeHandleAnEnvironmentStateAddedEvent())
.Then(_ => ThenTheStoredProjectionIsUnchanged())
.BDDfy();
}

protected override async Task HandleEventImplementation()
{
await ProjectionBuilder.Handle(StreamPosition, Event, StoppingToken);
}

private void GivenTheProjectAlreadyHasAToggleState()
{
OriginalProjection.ToggleState.AddEnvironmentState(
DataFixture.Create<Projections.EventAudit>(),
DataFixture.Create<string>(),
DataFixture.Create<string>());
}

private void GivenTheProjectionStreamVersionIsTheSameAsTheNextEvent()
{
StreamPosition = OriginalProjection.Audit.StreamPosition;
}

private async Task WhenWeHandleAnEnvironmentStateAddedEvent()
{
Event = new EnvironmentStateAdded(
DataFixture.Create<string>(),
ProjectId,
EnvironmentKey,
DataFixture.Create<DateTimeOffset>(),
DataFixture.CreateMany<KeyValuePair<string, string>>(1));

await WhenTheEventIsHandled();
}

private void ThenAProjectionIsCreatedWithTheNewEnvironmentState()
{
var environmentStates = UpdatedProjection.ToggleState.EnvironmentStates.ToList();
environmentStates.Count.Should().Be(1);

environmentStates.Should().Contain(ts =>
ts.Key == Event.EnvironmentKey &&
ts.Value == Event.ToggleStates.ToList()[0].Value);
}

private void ThenTheNewToggleStateIsAdded()
{
var environmentStates = UpdatedProjection.ToggleState.EnvironmentStates.ToList();
environmentStates.Count.Should().Be(OriginalProjection.ToggleState.EnvironmentStates.Count() + 1);

foreach (var environmentState in OriginalProjection.ToggleState.EnvironmentStates)
{
environmentStates.Should().Contain(ts =>
ts.Key == environmentState.Key &&
ts.Value == environmentState.Value);
}

environmentStates.Should().Contain(ts =>
ts.Key == Event.EnvironmentKey &&
ts.Value == Event.ToggleStates.ToList()[0].Value);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
namespace Evelyn.Core.Tests.ReadModel.Projections.ToggleState.ProjectEvents
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using AutoFixture;
using Evelyn.Core.ReadModel.Projections.ToggleState;
using Evelyn.Core.WriteModel.Project.Events;
using FluentAssertions;
using NSubstitute;
using TestStack.BDDfy;
using Xunit;
using Projections = Evelyn.Core.ReadModel.Projections;

public class EnvironmentStateDeletedSpecs : ProjectionBuilderHarness<EnvironmentStateDeleted>
{
[Fact]
public void ProjectionDoesNotExist()
{
this.Given(_ => GivenThereAreNoProjections())
.When(_ => WhenWeHandleAnEnvironmentStateDeletedEvent())
.Then(_ => ThenAnExceptionIsThrown())
.BDDfy();
}

[Fact]
public void MultipleToggleStatesExist()
{
this.Given(_ => GivenTheProjectionExists())
.And(_ => GivenTheProjectionHasStateForOurEnvironment())
.And(_ => GivenTheProjectionHasStateForAnotherEnvironment())
.When(_ => WhenWeHandleAnEnvironmentStateDeletedEvent())
.Then(_ => ThenTheEnvironmentStateIsRemoved())
.And(_ => ThenTheProjectionAuditIsSet())
.BDDfy();
}

[Fact]
public void LastToggleStateIsDeleted()
{
this.Given(_ => GivenTheProjectionExists())
.And(_ => GivenTheProjectionHasStateForOurEnvironment())
.When(_ => WhenWeHandleAnEnvironmentStateDeletedEvent())
.Then(_ => ThenTheProjectionIsDeleted())
.BDDfy();
}

protected override async Task HandleEventImplementation()
{
await ProjectionBuilder.Handle(StreamPosition, Event, StoppingToken);
}

private async Task WhenWeHandleAnEnvironmentStateDeletedEvent()
{
Event = new EnvironmentStateDeleted(
DataFixture.Create<string>(),
ProjectId,
EnvironmentKey,
DataFixture.Create<DateTimeOffset>(),
new List<string>() { ToggleKey });

await WhenTheEventIsHandled();
}

private void ThenTheProjectionIsDeleted()
{
ProjectionStore.Received().Delete(Projection.StoreKey(ProjectId, ToggleKey));
}

private void ThenTheEnvironmentStateIsRemoved()
{
var environmentStates = UpdatedProjection.ToggleState.EnvironmentStates.ToList();
environmentStates.Count.Should().Be(OriginalProjection.ToggleState.EnvironmentStates.Count() - 1);

foreach (var environmentState in OriginalProjection.ToggleState.EnvironmentStates)
{
if (environmentState.Key != Event.EnvironmentKey)
{
environmentStates.Should().Contain(ts =>
ts.Key == environmentState.Key &&
ts.Value == environmentState.Value);
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ public class ToggleStateAddedSpecs : ProjectionBuilderHarness<ToggleStateAdded>
[Fact]
public void ProjectionDoesNotExist()
{
this.Given(_ => GivenThereIsNoProjection())
this.Given(_ => GivenThereAreNoProjections())
.When(_ => WhenWeHandleAToggleStateAddedEvent())
.Then(_ => ThenTheProjectionIsCreatedWithTheNewToggleState())
.Then(_ => ThenTheProjectionIsCreatedWithTheNewState())
.Then(_ => ThenTheProjectionAuditIsSet())
.BDDfy();
}
Expand All @@ -25,9 +25,9 @@ public void ProjectionDoesNotExist()
public void Nominal()
{
this.Given(_ => GivenTheProjectionExists())
.And(_ => GivenTheProjectAlreadyHasAToggleState())
.And(_ => GivenTheProjectionHasStateForAnotherEnvironment())
.When(_ => WhenWeHandleAToggleStateAddedEvent())
.Then(_ => ThenTheNewToggleStateIsAdded())
.Then(_ => ThenTheNewStateIsAdded())
.And(_ => ThenTheProjectionAuditIsSet())
.BDDfy();
}
Expand All @@ -37,7 +37,7 @@ protected override async Task HandleEventImplementation()
await ProjectionBuilder.Handle(StreamPosition, Event, StoppingToken);
}

private void GivenTheProjectAlreadyHasAToggleState()
private void GivenTheProjectionHasStateForAnotherEnvironment()
{
OriginalProjection.ToggleState.AddEnvironmentState(
DataFixture.Create<Projections.EventAudit>(),
Expand All @@ -55,7 +55,7 @@ private async Task WhenWeHandleAToggleStateAddedEvent()
await WhenTheEventIsHandled();
}

private void ThenTheProjectionIsCreatedWithTheNewToggleState()
private void ThenTheProjectionIsCreatedWithTheNewState()
{
var environmentStates = UpdatedProjection.ToggleState.EnvironmentStates.ToList();
environmentStates.Count.Should().Be(1);
Expand All @@ -65,7 +65,7 @@ private void ThenTheProjectionIsCreatedWithTheNewToggleState()
ts.Value == Event.Value);
}

private void ThenTheNewToggleStateIsAdded()
private void ThenTheNewStateIsAdded()
{
var environmentStates = UpdatedProjection.ToggleState.EnvironmentStates.ToList();
environmentStates.Count.Should().Be(OriginalProjection.ToggleState.EnvironmentStates.Count() + 1);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public class ToggleStateChangedSpecs : ProjectionBuilderHarness<ToggleStateChang
[Fact]
public void ProjectionDoesNotExist()
{
this.Given(_ => GivenThereIsNoProjection())
this.Given(_ => GivenThereAreNoProjections())
.When(_ => WhenWeHandleAToggleStateChangedEvent())
.Then(_ => ThenAnExceptionIsThrown())
.BDDfy();
Expand All @@ -23,8 +23,8 @@ public void ProjectionDoesNotExist()
public void Nominal()
{
this.Given(_ => GivenTheProjectionExists())
.And(_ => GivenOurToggleStateIsOnTheProjection())
.And(_ => GivenTheProjectionHasOtherToggleStates())
.And(_ => GivenTheProjectionHasStateForOurEnvironment())
.And(_ => GivenTheProjectionHasStateForAnotherEnvironment())
.When(_ => WhenWeHandleAToggleStateChangedEvent())
.Then(_ => ThenOurToggleStateIsChanged())
.And(_ => ThenTheProjectionAuditIsSet())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public class ToggleStateDeletedSpecs : ProjectionBuilderHarness<ToggleStateDelet
[Fact]
public void ProjectionDoesNotExist()
{
this.Given(_ => GivenThereIsNoProjection())
this.Given(_ => GivenThereAreNoProjections())
.When(_ => WhenWeHandleAToggleStateDeletedEvent())
.Then(_ => ThenAnExceptionIsThrown())
.BDDfy();
Expand All @@ -25,8 +25,8 @@ public void ProjectionDoesNotExist()
public void MultipleToggleStatesExist()
{
this.Given(_ => GivenTheProjectionExists())
.And(_ => GivenOurToggleStateIsOnTheProjection())
.And(_ => GivenTheProjectionHasOtherToggleStates())
.And(_ => GivenTheProjectionHasStateForOurEnvironment())
.And(_ => GivenTheProjectionHasStateForAnotherEnvironment())
.When(_ => WhenWeHandleAToggleStateDeletedEvent())
.Then(_ => ThenOurToggleStateIsRemoved())
.And(_ => ThenTheProjectionAuditIsSet())
Expand All @@ -37,7 +37,7 @@ public void MultipleToggleStatesExist()
public void LastToggleStateIsDeleted()
{
this.Given(_ => GivenTheProjectionExists())
.And(_ => GivenOurToggleStateIsOnTheProjection())
.And(_ => GivenTheProjectionHasStateForOurEnvironment())
.When(_ => WhenWeHandleAToggleStateDeletedEvent())
.Then(_ => ThenTheProjectionIsDeleted())
.BDDfy();
Expand All @@ -51,9 +51,9 @@ protected override async Task HandleEventImplementation()
private async Task WhenWeHandleAToggleStateDeletedEvent()
{
Event = DataFixture.Build<ToggleStateDeleted>()
.With(pc => pc.Id, ProjectId)
.With(pc => pc.EnvironmentKey, EnvironmentKey)
.With(pc => pc.ToggleKey, ToggleKey)
.With(e => e.Id, ProjectId)
.With(e => e.EnvironmentKey, EnvironmentKey)
.With(e => e.ToggleKey, ToggleKey)
.Create();

await WhenTheEventIsHandled();
Expand All @@ -77,7 +77,7 @@ private void ThenOurToggleStateIsRemoved()

private void ThenTheProjectionIsDeleted()
{
ProjectionStore.Received().Delete(Projection.StoreKey(ProjectId, EnvironmentKey));
ProjectionStore.Received().Delete(Projection.StoreKey(ProjectId, ToggleKey));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public ProjectionBuilderHarness()

protected string EnvironmentKey { get; set; }

protected void GivenThereIsNoProjection()
protected void GivenThereAreNoProjections()
{
ProjectId = DataFixture.Create<Guid>();
ToggleKey = DataFixture.Create<string>();
Expand All @@ -36,15 +36,15 @@ protected void GivenTheProjectionExists()
ToggleKey = DataFixture.Create<string>();
}

protected void GivenTheProjectionHasOtherToggleStates()
protected void GivenTheProjectionHasStateForAnotherEnvironment()
{
OriginalProjection.ToggleState.AddEnvironmentState(
DataFixture.Create<Projections.EventAudit>(),
DataFixture.Create<string>(),
DataFixture.Create<string>());
}

protected void GivenOurToggleStateIsOnTheProjection()
protected void GivenTheProjectionHasStateForOurEnvironment()
{
EnvironmentKey = DataFixture.Create<string>();

Expand Down

0 comments on commit 6cd48f3

Please sign in to comment.