From c9caf84c91737fa444135f9226f1f103a306dedf Mon Sep 17 00:00:00 2001 From: Ouarzy Date: Wed, 8 Apr 2015 17:41:27 +0200 Subject: [PATCH 01/14] [Core][Message][Test failed] When Delete By Someone Else Than Author Then Do Not Raise MessageDeleted --- Mixter.Domain.Tests/Core/Messages/MessageTest.cs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Mixter.Domain.Tests/Core/Messages/MessageTest.cs b/Mixter.Domain.Tests/Core/Messages/MessageTest.cs index dd3edb4c..5de15f16 100644 --- a/Mixter.Domain.Tests/Core/Messages/MessageTest.cs +++ b/Mixter.Domain.Tests/Core/Messages/MessageTest.cs @@ -80,5 +80,14 @@ public void WhenDeleteThenRaiseMessageDeleted() message.Delete(_eventPublisher, Author); Check.That(_eventPublisher.Events).ContainsExactly(new MessageDeleted(message.GetId())); } + + [TestMethod] + public void WhenDeleteBySomeoneElseThanAuthorThenDoNotRaiseMessageDeleted() + { + var semeoneElseThanAuthor = new UserId("someone@mixit.fr"); + var message = Message.Publish(new EventPublisher(), Author, MessageContent); + message.Delete(_eventPublisher, semeoneElseThanAuthor); + Check.That(_eventPublisher.Events).IsEmpty(); + } } } \ No newline at end of file From c92ddec7c4606ec47d27101236eb6978441b024b Mon Sep 17 00:00:00 2001 From: Ouarzy Date: Wed, 8 Apr 2015 17:58:31 +0200 Subject: [PATCH 02/14] [Core][Message][Test failed] Given Deleted Message When Delete Then Nothing --- Mixter.Domain.Tests/Core/Messages/MessageTest.cs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Mixter.Domain.Tests/Core/Messages/MessageTest.cs b/Mixter.Domain.Tests/Core/Messages/MessageTest.cs index 5de15f16..4818f755 100644 --- a/Mixter.Domain.Tests/Core/Messages/MessageTest.cs +++ b/Mixter.Domain.Tests/Core/Messages/MessageTest.cs @@ -89,5 +89,14 @@ public void WhenDeleteBySomeoneElseThanAuthorThenDoNotRaiseMessageDeleted() message.Delete(_eventPublisher, semeoneElseThanAuthor); Check.That(_eventPublisher.Events).IsEmpty(); } + + [TestMethod] + public void GivenDeletedMessageWhenDeleteThenNothing() + { + var message = Message.Publish(new EventPublisher(), Author, MessageContent); + message.Delete(new EventPublisher(), Author); + message.Delete(_eventPublisher, Author); + Check.That(_eventPublisher.Events).IsEmpty(); + } } } \ No newline at end of file From ce2a60b5201f1ebdf16e964159143c8b0aa71c5d Mon Sep 17 00:00:00 2001 From: Ouarzy Date: Wed, 8 Apr 2015 18:14:48 +0200 Subject: [PATCH 03/14] [Core][Message][Test failed] Given A Deleted Message When Reply Then Nothing --- Mixter.Domain.Tests/Core/Messages/MessageTest.cs | 10 ++++++++++ Mixter.Domain/Core/Messages/Message.cs | 9 +++------ 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/Mixter.Domain.Tests/Core/Messages/MessageTest.cs b/Mixter.Domain.Tests/Core/Messages/MessageTest.cs index 4818f755..1606001b 100644 --- a/Mixter.Domain.Tests/Core/Messages/MessageTest.cs +++ b/Mixter.Domain.Tests/Core/Messages/MessageTest.cs @@ -98,5 +98,15 @@ public void GivenDeletedMessageWhenDeleteThenNothing() message.Delete(_eventPublisher, Author); Check.That(_eventPublisher.Events).IsEmpty(); } + + [TestMethod] + public void GivenADeletedMessageWhenReplyThenNothing() + { + var message = Message.Publish(new EventPublisher(), Author, MessageContent); + message.Delete(new EventPublisher(), Author); + message.Reply(_eventPublisher, Replier, ReplyContent); + Check.That(_eventPublisher.Events).IsEmpty(); + } + } } \ No newline at end of file diff --git a/Mixter.Domain/Core/Messages/Message.cs b/Mixter.Domain/Core/Messages/Message.cs index 6a89e737..17155652 100644 --- a/Mixter.Domain/Core/Messages/Message.cs +++ b/Mixter.Domain/Core/Messages/Message.cs @@ -30,7 +30,7 @@ public static Message Publish(IEventPublisher eventPublisher, UserId author, str public void Republish(IEventPublisher eventPublisher, UserId republisher) { - if (!_projection.Publishers.Contains(republisher) && !_projection.IsDeleted) + if (!_projection.Publishers.Contains(republisher)) { var evt = new MessageRepublished(GetId(), republisher); PublishEvent(eventPublisher, evt); @@ -45,11 +45,8 @@ private void PublishEvent(IEventPublisher eventPublisher, TEvent evt) wh public void Reply(IEventPublisher eventPublisher, UserId replier, string replyContent) { - if (!_projection.IsDeleted) - { - var evt = new ReplyMessagePublished(MessageId.Generate(), replier, replyContent, _projection.Id); - eventPublisher.Publish(evt); - } + var evt = new ReplyMessagePublished(MessageId.Generate(), replier, replyContent, _projection.Id); + eventPublisher.Publish(evt); } public void Delete(IEventPublisher eventPublisher, UserId deleter) From 2920759da6e08d96890e43b27d89b7516fe3dc49 Mon Sep 17 00:00:00 2001 From: Ouarzy Date: Wed, 8 Apr 2015 18:20:37 +0200 Subject: [PATCH 04/14] [Core][Message][Test failed] Given Deleted Message When Republish Then Nothing --- Mixter.Domain.Tests/Core/Messages/MessageTest.cs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Mixter.Domain.Tests/Core/Messages/MessageTest.cs b/Mixter.Domain.Tests/Core/Messages/MessageTest.cs index 1606001b..1288eb6e 100644 --- a/Mixter.Domain.Tests/Core/Messages/MessageTest.cs +++ b/Mixter.Domain.Tests/Core/Messages/MessageTest.cs @@ -108,5 +108,13 @@ public void GivenADeletedMessageWhenReplyThenNothing() Check.That(_eventPublisher.Events).IsEmpty(); } + [TestMethod] + public void GivenDeletedMessageWhenRepublishThenNothing() + { + var message = Message.Publish(new EventPublisher(), Author, MessageContent); + message.Delete(new EventPublisher(), Author); + message.Republish(_eventPublisher, Republisher); + Check.That(_eventPublisher.Events).IsEmpty(); + } } } \ No newline at end of file From 8db7776b182ad77dbacbc186549877b0a63ca058 Mon Sep 17 00:00:00 2001 From: Ouarzy Date: Sat, 11 Apr 2015 10:34:06 +0200 Subject: [PATCH 05/14] [Core][Message][Test failed] Final version of message tests with tests refacto --- .../Core/Messages/MessageTest.cs | 171 +++++++++++++----- 1 file changed, 130 insertions(+), 41 deletions(-) diff --git a/Mixter.Domain.Tests/Core/Messages/MessageTest.cs b/Mixter.Domain.Tests/Core/Messages/MessageTest.cs index 1288eb6e..84c3f1b1 100644 --- a/Mixter.Domain.Tests/Core/Messages/MessageTest.cs +++ b/Mixter.Domain.Tests/Core/Messages/MessageTest.cs @@ -1,9 +1,10 @@ +using System; +using System.Collections.Generic; using System.Linq; using Microsoft.VisualStudio.TestTools.UnitTesting; using Mixter.Domain.Core.Messages; using Mixter.Domain.Core.Messages.Events; using Mixter.Domain.Identity; -using Mixter.Infrastructure; using Mixter.Infrastructure.Tests.Infrastructure; using NFluent; @@ -17,6 +18,7 @@ public class MessageTest private static readonly UserId Author = new UserId("pierre@mixit.fr"); private static readonly UserId Republisher = new UserId("alfred@mixit.fr"); + private static readonly MessageId MessageId = MessageId.Generate(); private static readonly UserId Replier = new UserId("jean@mixit.fr"); private EventPublisherFake _eventPublisher; @@ -39,82 +41,169 @@ public void WhenPublishMessageThenRaiseUserMessagePublished() [TestMethod] public void WhenRepublishMessageThenRaiseMessageRepublished() { - var message = Message.Publish(new EventPublisher(), Author, MessageContent); - message.Republish(_eventPublisher, Republisher); - Check.That(_eventPublisher.Events).ContainsExactly(new MessageRepublished(message.GetId(), Republisher)); + Given(new MessagePublished(MessageId, Author, MessageContent)) + .When(o => o.Republish(_eventPublisher, Republisher)) + .ThenHas(new MessageRepublished(MessageId, Republisher)); } [TestMethod] public void WhenRepublishMyOwnMessageThenDoNotRaiseMessageRepublished() { - var message = Message.Publish(new EventPublisher(), Author, MessageContent); - message.Republish(_eventPublisher, Author); - Check.That(_eventPublisher.Events).IsEmpty(); + Given(new MessagePublished(MessageId, Author, MessageContent)) + .When(o => o.Republish(_eventPublisher, Author)) + .ThenNothing(); } [TestMethod] public void WhenRepublishTwoTimesSameMessageThenDoNotRaiseMessageRepublished() { - var message = Message.Publish(new EventPublisher(), Author, MessageContent); - message.Republish(_eventPublisher, Republisher); - message.Republish(_eventPublisher, Republisher); - Check.That(_eventPublisher.Events).ContainsExactly(new MessageRepublished(message.GetId(), Republisher)); + Given(new MessagePublished(MessageId, Author, MessageContent)) + .And(new MessageRepublished(MessageId, Republisher)) + .When(o => o.Republish(_eventPublisher, Republisher)) + .ThenNothing(); } [TestMethod] public void WhenReplyThenRaiseReplyMessagePublished() { - var message = Message.Publish(_eventPublisher, Author, MessageContent); - message.Reply(_eventPublisher, Replier, ReplyContent); - var replyEvent = _eventPublisher.Events.OfType().First(); - Check.That(replyEvent.ParentId).IsEqualTo(message.GetId()); - Check.That(replyEvent.ReplyContent).IsEqualTo(ReplyContent); - Check.That(replyEvent.Replier).IsEqualTo(Replier); - Check.That(replyEvent.ReplyId).IsNotEqualTo(message.GetId()); + Given(new MessagePublished(MessageId, Author, MessageContent)) + .When(o => o.Reply(_eventPublisher, Replier, ReplyContent)) + .ThenHasEvent(evt => + { + Check.That(evt.ParentId).IsEqualTo(MessageId); + Check.That(evt.ReplyContent).IsEqualTo(ReplyContent); + Check.That(evt.Replier).IsEqualTo(Replier); + Check.That(evt.ReplyId).IsNotEqualTo(MessageId); + }); } - + [TestMethod] public void WhenDeleteThenRaiseMessageDeleted() { - var message = Message.Publish(new EventPublisher(), Author, MessageContent); - message.Delete(_eventPublisher, Author); - Check.That(_eventPublisher.Events).ContainsExactly(new MessageDeleted(message.GetId())); + Given(new MessagePublished(MessageId, Author, MessageContent)) + .When(o => o.Delete(_eventPublisher, Author)) + .ThenHasOnly(new MessageDeleted(MessageId)); } [TestMethod] public void WhenDeleteBySomeoneElseThanAuthorThenDoNotRaiseMessageDeleted() { - var semeoneElseThanAuthor = new UserId("someone@mixit.fr"); - var message = Message.Publish(new EventPublisher(), Author, MessageContent); - message.Delete(_eventPublisher, semeoneElseThanAuthor); - Check.That(_eventPublisher.Events).IsEmpty(); + Given(new MessagePublished(MessageId, Author, MessageContent)) + .When(o => o.Delete(_eventPublisher, new UserId("clement@mix-it.fr"))) + .ThenNothing(); + } + + [TestMethod] + public void GivenIsRepublishedWhenDeleteByRepublisherThenDoNotRaiseMessageDeleted() + { + Given(new MessagePublished(MessageId, Author, MessageContent)) + .And(new MessageRepublished(MessageId, Republisher)) + .When(o => o.Delete(_eventPublisher, Republisher)) + .ThenNothing(); } [TestMethod] - public void GivenDeletedMessageWhenDeleteThenNothing() + public void GiveDeletedMessageWhenDeleteThenNothing() { - var message = Message.Publish(new EventPublisher(), Author, MessageContent); - message.Delete(new EventPublisher(), Author); - message.Delete(_eventPublisher, Author); - Check.That(_eventPublisher.Events).IsEmpty(); + Given(new MessagePublished(MessageId, Author, MessageContent)) + .And(new MessageDeleted(MessageId)) + .When(o => o.Delete(_eventPublisher, Author)) + .ThenNothing(); } [TestMethod] - public void GivenADeletedMessageWhenReplyThenNothing() + public void GivenReplyMessageWhenGetIdHasReplayMessageId() { - var message = Message.Publish(new EventPublisher(), Author, MessageContent); - message.Delete(new EventPublisher(), Author); - message.Reply(_eventPublisher, Replier, ReplyContent); - Check.That(_eventPublisher.Events).IsEmpty(); + var replyMessageId = MessageId.Generate(); + var message = CreateMessage(new ReplyMessagePublished(replyMessageId, Replier, ReplyContent, MessageId)); + + Check.That(message.GetId()).IsEqualTo(replyMessageId); } [TestMethod] - public void GivenDeletedMessageWhenRepublishThenNothing() + public void GivenADeletedMessageWhenReplyThenDoNotRaiseMessageDeleted() + { + Given(new MessagePublished(MessageId, Author, MessageContent)) + .And(new MessageDeleted(MessageId)) + .When(o => o.Reply(_eventPublisher, Replier, ReplyContent)) + .ThenNothing(); + } + + [TestMethod] + public void GivenDeletedMessageWhenRepublishThenDoNotRaiseMessageRepublished() + { + Given(new MessagePublished(MessageId, Author, MessageContent)) + .And(new MessageDeleted(MessageId)) + .When(o => o.Republish(_eventPublisher, Republisher)) + .ThenNothing(); + } + + private Message CreateMessage(params IDomainEvent[] events) + { + return new Message(events); + } + + private GivenFactory Given(IDomainEvent evt) + { + return new GivenFactory(evt, _eventPublisher); + } + + private class GivenFactory { - var message = Message.Publish(new EventPublisher(), Author, MessageContent); - message.Delete(new EventPublisher(), Author); - message.Republish(_eventPublisher, Republisher); - Check.That(_eventPublisher.Events).IsEmpty(); + private readonly IList _events = new List(); + private readonly EventPublisherFake _eventPublisherFake; + + public GivenFactory(IDomainEvent evt, EventPublisherFake eventPublisherFake) + { + _events.Add(evt); + _eventPublisherFake = eventPublisherFake; + } + + public GivenFactory And(IDomainEvent evt) + { + _events.Add(evt); + + return this; + } + + public ThenFactory When(Action when) + { + var message = new Message(_events); + when(message); + + return new ThenFactory(_eventPublisherFake); + } + + public class ThenFactory + { + private readonly EventPublisherFake _eventPublisherFake; + + public ThenFactory(EventPublisherFake eventPublisherFake) + { + _eventPublisherFake = eventPublisherFake; + } + + public void ThenHas(IDomainEvent domainEvent) + { + Check.That(_eventPublisherFake.Events).Contains(domainEvent); + } + + public void ThenNothing() + { + Check.That(_eventPublisherFake.Events).IsEmpty(); + } + + public void ThenHasEvent(Action then) + { + var evt = _eventPublisherFake.Events.OfType().First(); + then(evt); + } + + public void ThenHasOnly(IDomainEvent domainEvent) + { + Check.That(_eventPublisherFake.Events).ContainsExactly(domainEvent); + } + } } } } \ No newline at end of file From 34b08ec6a07cb5a5f131accd7e900f539819844e Mon Sep 17 00:00:00 2001 From: Ouarzy Date: Sat, 11 Apr 2015 11:17:09 +0200 Subject: [PATCH 06/14] [Core][UpdateTimeline][Test failed] Update author timeline when author message published --- .../Messages/Handlers/UpdateTimelineTest.cs | 38 +++++++++++++++++++ .../Core/Messages/MessageTest.cs | 2 +- .../Core/Messages/Handlers/UpdateTimeline.cs | 22 +++++++++++ .../EventPublisherFake.cs | 2 +- .../EventPublisherTest.cs | 2 +- .../EventPublisherWithStorageTest.cs | 2 +- .../{Infrastructure => }/EventsStoreTest.cs | 2 +- .../TimelineMessagesRepository.cs | 22 +++++++++++ 8 files changed, 87 insertions(+), 5 deletions(-) create mode 100644 Mixter.Domain.Tests/Core/Messages/Handlers/UpdateTimelineTest.cs create mode 100644 Mixter.Domain/Core/Messages/Handlers/UpdateTimeline.cs rename Mixter.Infrastructure.Tests/{Infrastructure => }/EventPublisherFake.cs (88%) rename Mixter.Infrastructure.Tests/{Infrastructure => }/EventPublisherTest.cs (97%) rename Mixter.Infrastructure.Tests/{Infrastructure => }/EventPublisherWithStorageTest.cs (95%) rename Mixter.Infrastructure.Tests/{Infrastructure => }/EventsStoreTest.cs (97%) create mode 100644 Mixter.Infrastructure/TimelineMessagesRepository.cs diff --git a/Mixter.Domain.Tests/Core/Messages/Handlers/UpdateTimelineTest.cs b/Mixter.Domain.Tests/Core/Messages/Handlers/UpdateTimelineTest.cs new file mode 100644 index 00000000..4482fa97 --- /dev/null +++ b/Mixter.Domain.Tests/Core/Messages/Handlers/UpdateTimelineTest.cs @@ -0,0 +1,38 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Mixter.Domain.Core.Messages; +using Mixter.Domain.Core.Messages.Events; +using Mixter.Domain.Core.Messages.Handlers; +using Mixter.Domain.Identity; +using Mixter.Infrastructure; +using NFluent; + +namespace Mixter.Domain.Tests.Core.Messages.Handlers +{ + [TestClass] + public class UpdateTimelineTest + { + private const string Content = "Hello"; + + private static readonly UserId Author = new UserId("author@mixit.fr"); + private static readonly MessageId MessageId = MessageId.Generate(); + + private TimelineMessagesRepository _repository; + private UpdateTimeline _handler; + + [TestInitialize] + public void Initialize() + { + _repository = new TimelineMessagesRepository(); + _handler = new UpdateTimeline(_repository); + } + + [TestMethod] + public void WhenHandleMessagePublishedThenSaveTimelineMessageProjectionForAuthor() + { + _handler.Handle(new MessagePublished(MessageId, Author, Content)); + + Check.That(_repository.GetMessagesOfUser(Author)) + .ContainsExactly(new TimelineMessageProjection(Author, Author, Content, MessageId)); + } + } +} diff --git a/Mixter.Domain.Tests/Core/Messages/MessageTest.cs b/Mixter.Domain.Tests/Core/Messages/MessageTest.cs index 84c3f1b1..2c072482 100644 --- a/Mixter.Domain.Tests/Core/Messages/MessageTest.cs +++ b/Mixter.Domain.Tests/Core/Messages/MessageTest.cs @@ -5,7 +5,7 @@ using Mixter.Domain.Core.Messages; using Mixter.Domain.Core.Messages.Events; using Mixter.Domain.Identity; -using Mixter.Infrastructure.Tests.Infrastructure; +using Mixter.Infrastructure.Tests; using NFluent; namespace Mixter.Domain.Tests.Core.Messages diff --git a/Mixter.Domain/Core/Messages/Handlers/UpdateTimeline.cs b/Mixter.Domain/Core/Messages/Handlers/UpdateTimeline.cs new file mode 100644 index 00000000..6edddb40 --- /dev/null +++ b/Mixter.Domain/Core/Messages/Handlers/UpdateTimeline.cs @@ -0,0 +1,22 @@ +using Mixter.Domain.Core.Messages.Events; + +namespace Mixter.Domain.Core.Messages.Handlers +{ + public class UpdateTimeline : IEventHandler, IEventHandler + { + private readonly ITimelineMessagesRepository _timelineMessagesRepository; + + public UpdateTimeline(ITimelineMessagesRepository timelineMessagesRepository) + { + _timelineMessagesRepository = timelineMessagesRepository; + } + + public void Handle(MessagePublished evt) + { + } + + public void Handle(ReplyMessagePublished evt) + { + } + } +} diff --git a/Mixter.Infrastructure.Tests/Infrastructure/EventPublisherFake.cs b/Mixter.Infrastructure.Tests/EventPublisherFake.cs similarity index 88% rename from Mixter.Infrastructure.Tests/Infrastructure/EventPublisherFake.cs rename to Mixter.Infrastructure.Tests/EventPublisherFake.cs index 66222b76..a8ccea2c 100644 --- a/Mixter.Infrastructure.Tests/Infrastructure/EventPublisherFake.cs +++ b/Mixter.Infrastructure.Tests/EventPublisherFake.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; using Mixter.Domain; -namespace Mixter.Infrastructure.Tests.Infrastructure +namespace Mixter.Infrastructure.Tests { public class EventPublisherFake : IEventPublisher { diff --git a/Mixter.Infrastructure.Tests/Infrastructure/EventPublisherTest.cs b/Mixter.Infrastructure.Tests/EventPublisherTest.cs similarity index 97% rename from Mixter.Infrastructure.Tests/Infrastructure/EventPublisherTest.cs rename to Mixter.Infrastructure.Tests/EventPublisherTest.cs index 622f2e97..208d222f 100644 --- a/Mixter.Infrastructure.Tests/Infrastructure/EventPublisherTest.cs +++ b/Mixter.Infrastructure.Tests/EventPublisherTest.cs @@ -2,7 +2,7 @@ using Mixter.Domain; using NFluent; -namespace Mixter.Infrastructure.Tests.Infrastructure +namespace Mixter.Infrastructure.Tests { [TestClass] public class EventPublisherTest diff --git a/Mixter.Infrastructure.Tests/Infrastructure/EventPublisherWithStorageTest.cs b/Mixter.Infrastructure.Tests/EventPublisherWithStorageTest.cs similarity index 95% rename from Mixter.Infrastructure.Tests/Infrastructure/EventPublisherWithStorageTest.cs rename to Mixter.Infrastructure.Tests/EventPublisherWithStorageTest.cs index 068cfe71..29ed8280 100644 --- a/Mixter.Infrastructure.Tests/Infrastructure/EventPublisherWithStorageTest.cs +++ b/Mixter.Infrastructure.Tests/EventPublisherWithStorageTest.cs @@ -2,7 +2,7 @@ using Mixter.Domain; using NFluent; -namespace Mixter.Infrastructure.Tests.Infrastructure +namespace Mixter.Infrastructure.Tests { [TestClass] public class EventPublisherWithStorageTest diff --git a/Mixter.Infrastructure.Tests/Infrastructure/EventsStoreTest.cs b/Mixter.Infrastructure.Tests/EventsStoreTest.cs similarity index 97% rename from Mixter.Infrastructure.Tests/Infrastructure/EventsStoreTest.cs rename to Mixter.Infrastructure.Tests/EventsStoreTest.cs index 6c845ae0..ac0c9755 100644 --- a/Mixter.Infrastructure.Tests/Infrastructure/EventsStoreTest.cs +++ b/Mixter.Infrastructure.Tests/EventsStoreTest.cs @@ -3,7 +3,7 @@ using Mixter.Domain; using NFluent; -namespace Mixter.Infrastructure.Tests.Infrastructure +namespace Mixter.Infrastructure.Tests { [TestClass] public class EventsStoreTest diff --git a/Mixter.Infrastructure/TimelineMessagesRepository.cs b/Mixter.Infrastructure/TimelineMessagesRepository.cs new file mode 100644 index 00000000..e7c1a19f --- /dev/null +++ b/Mixter.Infrastructure/TimelineMessagesRepository.cs @@ -0,0 +1,22 @@ +using System.Collections.Generic; +using System.Linq; +using Mixter.Domain.Core.Messages; +using Mixter.Domain.Identity; + +namespace Mixter.Infrastructure +{ + public class TimelineMessagesRepository : ITimelineMessagesRepository + { + private readonly HashSet _messages = new HashSet(); + + public void Save(TimelineMessageProjection messageProjection) + { + _messages.Add(messageProjection); + } + + public IEnumerable GetMessagesOfUser(UserId userId) + { + return _messages.Where(o => o.OwnerId.Equals(userId)); + } + } +} From d1a21adf7acc36f6f814818ec8e48a3d66410937 Mon Sep 17 00:00:00 2001 From: Ouarzy Date: Sat, 11 Apr 2015 11:32:09 +0200 Subject: [PATCH 07/14] [Core][UpdateTimeline][Test failed] Update replier timeline when replier message reply --- .../Core/Messages/Handlers/UpdateTimelineTest.cs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/Mixter.Domain.Tests/Core/Messages/Handlers/UpdateTimelineTest.cs b/Mixter.Domain.Tests/Core/Messages/Handlers/UpdateTimelineTest.cs index 4482fa97..b57c493f 100644 --- a/Mixter.Domain.Tests/Core/Messages/Handlers/UpdateTimelineTest.cs +++ b/Mixter.Domain.Tests/Core/Messages/Handlers/UpdateTimelineTest.cs @@ -34,5 +34,16 @@ public void WhenHandleMessagePublishedThenSaveTimelineMessageProjectionForAuthor Check.That(_repository.GetMessagesOfUser(Author)) .ContainsExactly(new TimelineMessageProjection(Author, Author, Content, MessageId)); } + + [TestMethod] + public void WhenHandleMessageRepliedThenSaveTimelineMessageProjectionForReplier() + { + var parentMessageId = MessageId.Generate(); + var replier = new UserId("author@mixit.fr"); + _handler.Handle(new ReplyMessagePublished(MessageId, replier, Content, parentMessageId)); + + Check.That(_repository.GetMessagesOfUser(replier)) + .ContainsExactly(new TimelineMessageProjection(replier, replier, Content, MessageId)); + } } } From 44880393368347939413031e51b85d3c377e0699 Mon Sep 17 00:00:00 2001 From: Ouarzy Date: Sat, 11 Apr 2015 12:29:02 +0200 Subject: [PATCH 08/14] [Core][Subscription] Allow subscription to follow user --- .../Core/Subscriptions/SubscriptionTest.cs | 34 +++++++++++ .../Events/FolloweeMessagePublished.cs | 23 ++++++++ .../Core/Subscriptions/Events/UserFollowed.cs | 18 ++++++ .../Subscriptions/Events/UserUnfollowed.cs | 17 ++++++ .../Subscriptions/ISubscriptionsRepository.cs | 7 +++ .../Core/Subscriptions/Subscription.cs | 14 +++++ .../Core/Subscriptions/SubscriptionId.cs | 18 ++++++ .../TimelineMessagesRepositoryTest.cs | 57 +++++++++++++++++++ 8 files changed, 188 insertions(+) create mode 100644 Mixter.Domain.Tests/Core/Subscriptions/SubscriptionTest.cs create mode 100644 Mixter.Domain/Core/Subscriptions/Events/FolloweeMessagePublished.cs create mode 100644 Mixter.Domain/Core/Subscriptions/Events/UserFollowed.cs create mode 100644 Mixter.Domain/Core/Subscriptions/Events/UserUnfollowed.cs create mode 100644 Mixter.Domain/Core/Subscriptions/ISubscriptionsRepository.cs create mode 100644 Mixter.Domain/Core/Subscriptions/Subscription.cs create mode 100644 Mixter.Domain/Core/Subscriptions/SubscriptionId.cs create mode 100644 Mixter.Infrastructure.Tests/TimelineMessagesRepositoryTest.cs diff --git a/Mixter.Domain.Tests/Core/Subscriptions/SubscriptionTest.cs b/Mixter.Domain.Tests/Core/Subscriptions/SubscriptionTest.cs new file mode 100644 index 00000000..d8a87eb0 --- /dev/null +++ b/Mixter.Domain.Tests/Core/Subscriptions/SubscriptionTest.cs @@ -0,0 +1,34 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Mixter.Domain.Core.Messages; +using Mixter.Domain.Core.Subscriptions; +using Mixter.Domain.Core.Subscriptions.Events; +using Mixter.Domain.Identity; +using Mixter.Infrastructure.Tests; +using NFluent; + +namespace Mixter.Domain.Tests.Core.Subscriptions +{ + [TestClass] + public class SubscriptionTest + { + private static readonly UserId Follower = new UserId("emilien@mixit.fr"); + private static readonly UserId Followee = new UserId("florent@mixit.fr"); + private static readonly SubscriptionId SubscriptionId = new SubscriptionId(Follower, Followee); + + private EventPublisherFake _eventPublisher; + + [TestInitialize] + public void Initialize() + { + _eventPublisher = new EventPublisherFake(); + } + + [TestMethod] + public void WhenFollowThenUserFollowedIsRaised() + { + Subscription.FollowUser(_eventPublisher, Follower, Followee); + + Check.That(_eventPublisher.Events).Contains(new UserFollowed(SubscriptionId)); + } + } +} diff --git a/Mixter.Domain/Core/Subscriptions/Events/FolloweeMessagePublished.cs b/Mixter.Domain/Core/Subscriptions/Events/FolloweeMessagePublished.cs new file mode 100644 index 00000000..4a12ea89 --- /dev/null +++ b/Mixter.Domain/Core/Subscriptions/Events/FolloweeMessagePublished.cs @@ -0,0 +1,23 @@ +using Mixter.Domain.Core.Messages; + +namespace Mixter.Domain.Core.Subscriptions.Events +{ + public struct FolloweeMessagePublished : IDomainEvent + { + public SubscriptionId SubscriptionId { get; private set; } + + public MessageId MessageId { get; private set; } + + public FolloweeMessagePublished(SubscriptionId subscriptionId, MessageId messageId) + : this() + { + SubscriptionId = subscriptionId; + MessageId = messageId; + } + + public object GetAggregateId() + { + return SubscriptionId; + } + } +} \ No newline at end of file diff --git a/Mixter.Domain/Core/Subscriptions/Events/UserFollowed.cs b/Mixter.Domain/Core/Subscriptions/Events/UserFollowed.cs new file mode 100644 index 00000000..45d4d2f3 --- /dev/null +++ b/Mixter.Domain/Core/Subscriptions/Events/UserFollowed.cs @@ -0,0 +1,18 @@ +namespace Mixter.Domain.Core.Subscriptions.Events +{ + public struct UserFollowed : IDomainEvent + { + public SubscriptionId SubscriptionId { get; private set; } + + public UserFollowed(SubscriptionId subscriptionId) + : this() + { + SubscriptionId = subscriptionId; + } + + public object GetAggregateId() + { + return SubscriptionId; + } + } +} \ No newline at end of file diff --git a/Mixter.Domain/Core/Subscriptions/Events/UserUnfollowed.cs b/Mixter.Domain/Core/Subscriptions/Events/UserUnfollowed.cs new file mode 100644 index 00000000..bd8952aa --- /dev/null +++ b/Mixter.Domain/Core/Subscriptions/Events/UserUnfollowed.cs @@ -0,0 +1,17 @@ +namespace Mixter.Domain.Core.Subscriptions.Events +{ + public struct UserUnfollowed : IDomainEvent + { + public SubscriptionId SubscriptionId { get; private set; } + + public UserUnfollowed(SubscriptionId subscriptionId) : this() + { + SubscriptionId = subscriptionId; + } + + public object GetAggregateId() + { + return SubscriptionId; + } + } +} \ No newline at end of file diff --git a/Mixter.Domain/Core/Subscriptions/ISubscriptionsRepository.cs b/Mixter.Domain/Core/Subscriptions/ISubscriptionsRepository.cs new file mode 100644 index 00000000..50da4a5b --- /dev/null +++ b/Mixter.Domain/Core/Subscriptions/ISubscriptionsRepository.cs @@ -0,0 +1,7 @@ +namespace Mixter.Domain.Core.Subscriptions +{ + public interface ISubscriptionsRepository + { + Subscription Get(SubscriptionId subscriptionId); + } +} \ No newline at end of file diff --git a/Mixter.Domain/Core/Subscriptions/Subscription.cs b/Mixter.Domain/Core/Subscriptions/Subscription.cs new file mode 100644 index 00000000..9d254780 --- /dev/null +++ b/Mixter.Domain/Core/Subscriptions/Subscription.cs @@ -0,0 +1,14 @@ +using System.Collections.Generic; +using Mixter.Domain.Core.Messages; +using Mixter.Domain.Core.Subscriptions.Events; +using Mixter.Domain.Identity; + +namespace Mixter.Domain.Core.Subscriptions +{ + public class Subscription + { + public static void FollowUser(IEventPublisher eventPublisher, UserId follower, UserId followee) + { + } + } +} \ No newline at end of file diff --git a/Mixter.Domain/Core/Subscriptions/SubscriptionId.cs b/Mixter.Domain/Core/Subscriptions/SubscriptionId.cs new file mode 100644 index 00000000..1dd9f458 --- /dev/null +++ b/Mixter.Domain/Core/Subscriptions/SubscriptionId.cs @@ -0,0 +1,18 @@ +using Mixter.Domain.Identity; + +namespace Mixter.Domain.Core.Subscriptions +{ + public struct SubscriptionId + { + public UserId Follower { get; private set; } + + public UserId Followee { get; private set; } + + public SubscriptionId(UserId follower, UserId followee) + : this() + { + Follower = follower; + Followee = followee; + } + } +} \ No newline at end of file diff --git a/Mixter.Infrastructure.Tests/TimelineMessagesRepositoryTest.cs b/Mixter.Infrastructure.Tests/TimelineMessagesRepositoryTest.cs new file mode 100644 index 00000000..3f9b5fa1 --- /dev/null +++ b/Mixter.Infrastructure.Tests/TimelineMessagesRepositoryTest.cs @@ -0,0 +1,57 @@ +using System.Linq; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Mixter.Domain.Core.Messages; +using Mixter.Domain.Identity; +using NFluent; + +namespace Mixter.Infrastructure.Tests +{ + [TestClass] + public class TimelineMessagesRepositoryTest + { + private ITimelineMessagesRepository _repository; + private readonly UserId _ownerId = new UserId("joe@mixit.fr"); + private readonly UserId _authorId = new UserId("joe@mixit.fr"); + + [TestInitialize] + public void Initialize() + { + _repository = new TimelineMessagesRepository(); + } + + [TestMethod] + public void GivenAMessageSavedWhenGetMessagesOfUserThenMessageIsReturned() + { + _repository.Save(new TimelineMessageProjection(_ownerId, _authorId, "MessageA", MessageId.Generate())); + + Check.That(_repository.GetMessagesOfUser(_ownerId)).HasSize(1); + } + + [TestMethod] + public void WhenSaveTwoMessagesOfDifferentOwnersThenGetMessagesOfUserThisMessage() + { + const string messageA = "MessageA"; + const string messageB = "MessageB"; + + _repository.Save(new TimelineMessageProjection(_ownerId, _authorId, messageA, MessageId.Generate())); + _repository.Save(new TimelineMessageProjection(new UserId("florent@mixit.fr"), _authorId, messageB, MessageId.Generate())); + + var messagesOfUser = _repository.GetMessagesOfUser(_ownerId).ToList(); + Check.That(messagesOfUser).HasSize(1); + Check.That(messagesOfUser.First().Content).IsEqualTo(messageA); + } + + [TestMethod] + public void WhenSaveTwoSameMessagesThenOnlyOneIsSaved() + { + const string messageA = "MessageA"; + + var timelineMessage = new TimelineMessageProjection(_ownerId, _authorId, messageA, MessageId.Generate()); + _repository.Save(timelineMessage); + _repository.Save(timelineMessage); + + var messagesOfUser = _repository.GetMessagesOfUser(_ownerId).ToList(); + Check.That(messagesOfUser).HasSize(1); + } + } +} \ No newline at end of file From 6b2c1327c43fd049d1b1b3a954ebffec35fd169d Mon Sep 17 00:00:00 2001 From: havivha Date: Fri, 19 Jun 2015 14:54:18 -0400 Subject: [PATCH 09/14] Haviv&Einat fix test 1.1 --- Mixter.Domain/Core/Messages/Message.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Mixter.Domain/Core/Messages/Message.cs b/Mixter.Domain/Core/Messages/Message.cs index 6a89e737..86e39e2d 100644 --- a/Mixter.Domain/Core/Messages/Message.cs +++ b/Mixter.Domain/Core/Messages/Message.cs @@ -54,6 +54,7 @@ public void Reply(IEventPublisher eventPublisher, UserId replier, string replyCo public void Delete(IEventPublisher eventPublisher, UserId deleter) { + PublishEvent(eventPublisher, new MessageDeleted(_projection.Id)); } public MessageId GetId() From 590ec638ece11fe3637b63196ba6f6aadf60482c Mon Sep 17 00:00:00 2001 From: havivha Date: Fri, 19 Jun 2015 14:57:41 -0400 Subject: [PATCH 10/14] Haviv&Einat fix test 1.2 --- Mixter.Domain/Core/Messages/Message.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Mixter.Domain/Core/Messages/Message.cs b/Mixter.Domain/Core/Messages/Message.cs index 86e39e2d..76e93bcc 100644 --- a/Mixter.Domain/Core/Messages/Message.cs +++ b/Mixter.Domain/Core/Messages/Message.cs @@ -54,7 +54,10 @@ public void Reply(IEventPublisher eventPublisher, UserId replier, string replyCo public void Delete(IEventPublisher eventPublisher, UserId deleter) { - PublishEvent(eventPublisher, new MessageDeleted(_projection.Id)); + if(_projection.Author.Equals(deleter)) + { + PublishEvent(eventPublisher, new MessageDeleted(_projection.Id)); + } } public MessageId GetId() @@ -75,6 +78,8 @@ public IEnumerable Publishers public bool IsDeleted { get; private set; } + public UserId Author { get; private set; } + public DecisionProjection() { AddHandler(When); @@ -96,6 +101,7 @@ private void When(ReplyMessagePublished evt) private void When(MessagePublished evt) { Id = evt.Id; + Author = evt.Author; _publishers.Add(evt.Author); } From 823e5b6cd7a1501adad372ad5e319c11583405b1 Mon Sep 17 00:00:00 2001 From: havivha Date: Fri, 19 Jun 2015 14:58:43 -0400 Subject: [PATCH 11/14] Haviv&Einat fix test 1.3 --- Mixter.Domain/Core/Messages/Message.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mixter.Domain/Core/Messages/Message.cs b/Mixter.Domain/Core/Messages/Message.cs index 76e93bcc..2ecfa63c 100644 --- a/Mixter.Domain/Core/Messages/Message.cs +++ b/Mixter.Domain/Core/Messages/Message.cs @@ -54,7 +54,7 @@ public void Reply(IEventPublisher eventPublisher, UserId replier, string replyCo public void Delete(IEventPublisher eventPublisher, UserId deleter) { - if(_projection.Author.Equals(deleter)) + if (_projection.Author.Equals(deleter) && !_projection.IsDeleted) { PublishEvent(eventPublisher, new MessageDeleted(_projection.Id)); } From b8563a46bb143ffb14663c03c6ab78719c1d3d81 Mon Sep 17 00:00:00 2001 From: havivha Date: Fri, 19 Jun 2015 15:00:05 -0400 Subject: [PATCH 12/14] Haviv&Einat fix test 1.4 --- Mixter.Domain/Core/Messages/Message.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Mixter.Domain/Core/Messages/Message.cs b/Mixter.Domain/Core/Messages/Message.cs index 406886f2..de628bef 100644 --- a/Mixter.Domain/Core/Messages/Message.cs +++ b/Mixter.Domain/Core/Messages/Message.cs @@ -45,8 +45,11 @@ private void PublishEvent(IEventPublisher eventPublisher, TEvent evt) wh public void Reply(IEventPublisher eventPublisher, UserId replier, string replyContent) { - var evt = new ReplyMessagePublished(MessageId.Generate(), replier, replyContent, _projection.Id); - eventPublisher.Publish(evt); + if (!_projection.IsDeleted) + { + var evt = new ReplyMessagePublished(MessageId.Generate(), replier, replyContent, _projection.Id); + eventPublisher.Publish(evt); + } } public void Delete(IEventPublisher eventPublisher, UserId deleter) From a854c615fe77379e9a6866f5fadbfea04cfc2e1a Mon Sep 17 00:00:00 2001 From: havivha Date: Fri, 19 Jun 2015 15:00:51 -0400 Subject: [PATCH 13/14] Haviv&Einat fix test 1.5 --- Mixter.Domain/Core/Messages/Message.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mixter.Domain/Core/Messages/Message.cs b/Mixter.Domain/Core/Messages/Message.cs index de628bef..9a5885cc 100644 --- a/Mixter.Domain/Core/Messages/Message.cs +++ b/Mixter.Domain/Core/Messages/Message.cs @@ -30,7 +30,7 @@ public static Message Publish(IEventPublisher eventPublisher, UserId author, str public void Republish(IEventPublisher eventPublisher, UserId republisher) { - if (!_projection.Publishers.Contains(republisher)) + if (!_projection.Publishers.Contains(republisher) && !_projection.IsDeleted) { var evt = new MessageRepublished(GetId(), republisher); PublishEvent(eventPublisher, evt); From 3fce075646b157bf92cbf5d6c8b66fea9dfa8508 Mon Sep 17 00:00:00 2001 From: havivha Date: Fri, 19 Jun 2015 15:03:43 -0400 Subject: [PATCH 14/14] Haviv&Einat fix test 1.6 --- Mixter.Domain.Tests/Core/Messages/MessageTest.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mixter.Domain.Tests/Core/Messages/MessageTest.cs b/Mixter.Domain.Tests/Core/Messages/MessageTest.cs index 84c3f1b1..079c99a1 100644 --- a/Mixter.Domain.Tests/Core/Messages/MessageTest.cs +++ b/Mixter.Domain.Tests/Core/Messages/MessageTest.cs @@ -13,7 +13,7 @@ namespace Mixter.Domain.Tests.Core.Messages [TestClass] public class MessageTest { - private const string MessageContent = "Hello"; + private const string MessageContent = "Hello miixit"; private const string ReplyContent = "ReplyContent"; private static readonly UserId Author = new UserId("pierre@mixit.fr");