private int GetActualVersion(
            EventDescriptors eventDescriptors, 
            int expectedVersion,
            IEnumerable<Event> events,
            IConcurrencyConflictResolver conflictResolver)
        {
            var actualVersion = eventDescriptors[eventDescriptors.Count() - 1].Version;

            if (actualVersion != expectedVersion && expectedVersion != -1)
            {
                var potentialConflictingEvents =
                    eventDescriptors
                    .Where(e => e.Version > expectedVersion)
                    .Select(e => e.EventData);
                if (AnyEventsConflict(events, potentialConflictingEvents, conflictResolver))
                {
                    throw new EventStoreConcurrencyException();
                }
                else
                {
                    return actualVersion;
                }
            }

            return expectedVersion;
        }
        public void AddingEventsWithProperExpectedVersionToExistingEventDescriptorsPopulatesDatabase()
        {
            var aggregateId = Guid.NewGuid();
            var databaseMock = new DatabaseMock<EventDescriptors>();
            var existingEvents = new EventDescriptors{ Id = aggregateId };
            existingEvents.Add(new EventDescriptor(Guid.NewGuid(), new Event(), 0));
            existingEvents.Add(new EventDescriptor(Guid.NewGuid(), new Event(), 1));
            databaseMock.Put(existingEvents);
            var initialCount = existingEvents.Count();

            var expectedVersion = existingEvents.Count() - 1;
            IConcurrencyConflictResolver conflictResolver = null;
            var newEvents = new List<Event>
            {
                new Event(),
                new Event()
            };
            
            var publisherMock = new EventPublisherMock();

            var eventStore = new EventStore(publisherMock, databaseMock);

            eventStore.SaveEvents(
                aggregateId,
                newEvents,
                expectedVersion,
                conflictResolver);

            var actual = databaseMock.Get(aggregateId.ToString());

            Assert.NotNull(actual);
            Assert.Equal(newEvents.Count + initialCount, actual.Count());
            publisherMock.AssertPublishCount<Event>(newEvents.Count());
        }
        public void JsonSerializeAndDeserialize()
        {
            var id = Guid.NewGuid();
            var expected = new EventDescriptors { Id = id };
            var events = new List<Event>
            {
                new Event1(),
                new Event2<EventConstraintBase1>(),
                new Event3<EventConstraintBase1, EventConstraintBase2>()
            };

            expected.Add(new EventDescriptor { Id = Guid.NewGuid(), EventData = events[0], Version = 0 });
            expected.Add(new EventDescriptor { Id = Guid.NewGuid(), EventData = events[1], Version = -5 });
            expected.Add(new EventDescriptor { Id = Guid.NewGuid(), EventData = events[2], Version = 1 });

            var serializerSettings = new JsonSerializerSettings
            {
                MissingMemberHandling = MissingMemberHandling.Ignore,
                DefaultValueHandling = DefaultValueHandling.Ignore,
                TypeNameHandling = TypeNameHandling.All,
                ContractResolver = new PrivateMembersContractResolver(),
                DateFormatHandling = DateFormatHandling.IsoDateFormat,
                DateParseHandling = DateParseHandling.None,
                DateTimeZoneHandling = DateTimeZoneHandling.Unspecified
            };

            var intermediate = JsonConvert.SerializeObject(
                expected, 
                serializerSettings);
            var actual = (EventDescriptors)JsonConvert.DeserializeObject(
                intermediate, 
                typeof(EventDescriptors), 
                serializerSettings);

            Assert.Equal(id, actual.Id);
            Assert.Equal(expected.Count(), actual.Count());

            for (int i = 0; i < expected.Count(); i++)
            {
                Assert.Equal(expected[i].Id, actual[i].Id);
                Assert.Equal(expected[i].EventData.GetType(), actual[i].EventData.GetType());
                Assert.Equal(expected[i].Version, actual[i].Version);
            }
        }
        public void SaveEvents(
            Guid aggregateId, 
            IEnumerable<Event> events, 
            int expectedVersion,
            IConcurrencyConflictResolver conflictResolver)
        {
            lock (_saveLock)
            {
                var eventDescriptors =
                    _database.Get(aggregateId.ToString());
                var actualVersion = expectedVersion;

                if (eventDescriptors == null)
                {
                    eventDescriptors = new EventDescriptors {Id = aggregateId};
                    _database.Put(eventDescriptors);
                }
                else
                {
                    actualVersion = GetActualVersion(
                        eventDescriptors,
                        expectedVersion,
                        events,
                        conflictResolver);
                }

                var i = actualVersion;
                foreach (var @event in events)
                {
                    i++;
                    @event.Version = i;
                    @event.AggregateId = aggregateId;
                    @event.Id = Guid.NewGuid();
                    eventDescriptors.Add(
                        new EventDescriptor(aggregateId, @event, i));
                    _publisher.Publish(@event);
                }

                _database.Update(eventDescriptors);
            }
        }
        public void FetchingAggregateRootWhenExistsGetsProperListOfEvents()
        {
            var aggregateId = Guid.NewGuid();
            var databaseMock = new DatabaseMock<EventDescriptors>();
            var expected = new EventDescriptors { Id = aggregateId };
            expected.Add(new EventDescriptor(Guid.NewGuid(), new Event(), 0));
            expected.Add(new EventDescriptor(Guid.NewGuid(), new Event(), 1));
            databaseMock.Put(expected);
            var publisherMock = new EventPublisherMock();

            var eventStore = new EventStore(publisherMock, databaseMock);

            var actual = eventStore.GetEventsForAggregate(aggregateId);

            Assert.NotNull(actual);
            Assert.Equal(expected.Count(), actual.Count());
            Assert.Null(publisherMock.GetLastPublishedObject<Event>());
        }
        public async void AddingImproperlyVersionedEventsConcurrentlyWithConflictResolutionPopulatesDatabase()
        {
            var aggregateId = Guid.NewGuid();
            var databaseMock = new DatabaseMock<EventDescriptors>();
            var existingEvents = new EventDescriptors {Id = aggregateId};
            existingEvents.Add(new EventDescriptor(Guid.NewGuid(), new Event(), 0));
            existingEvents.Add(new EventDescriptor(Guid.NewGuid(), new Event(), 1));
            databaseMock.Put(existingEvents);
            var initialCount = existingEvents.Count();

            var expectedVersion = 0;
            IConcurrencyConflictResolver conflictResolver = new ConcurrencyConflictResolver();
            conflictResolver.RegisterConflictList(typeof (Event2<EventConstraint1>), new List<Type>());
            conflictResolver.RegisterConflictList(typeof (Event2<EventConstraintAnother1>), new List<Type>());
            var newEventsSource1 = new List<Event>
            {
                new Event2<EventConstraint1>()
            };
            var newEventsSource2 = new List<Event>
            {
                new Event2<EventConstraintAnother1>()
            };

            var publisherMock = new EventPublisherMock();

            var eventStore = new EventStore(publisherMock, databaseMock);

            var task1 = Task.Run(() =>
                eventStore.SaveEvents(
                    aggregateId,
                    newEventsSource1,
                    expectedVersion,
                    conflictResolver));

            var task2 = Task.Run(()=>
                    eventStore.SaveEvents(
                    aggregateId,
                    newEventsSource2,
                    expectedVersion,
                    conflictResolver));

            await Task.WhenAll(task1, task2).ConfigureAwait(false);

            var actual = databaseMock.Get(aggregateId.ToString());

            Assert.NotNull(actual);
            Assert.Equal(newEventsSource1.Count + newEventsSource2.Count + initialCount, actual.Count());
            publisherMock.AssertPublishCount<Event>(newEventsSource1.Count + newEventsSource2.Count);
        }
        public void AddingImproperlyVersionedEventsWithNoConflictResolutionExpectException()
        {
            var aggregateId = Guid.NewGuid();
            var databaseMock = new DatabaseMock<EventDescriptors>();
            var existingEvents = new EventDescriptors { Id = aggregateId };
            existingEvents.Add(new EventDescriptor(Guid.NewGuid(), new Event1(), 0));
            existingEvents.Add(new EventDescriptor(Guid.NewGuid(), new Event1(), 1));
            databaseMock.Put(existingEvents);

            var expectedVersion = existingEvents.Count() - 2;
            IConcurrencyConflictResolver conflictResolver = new ConcurrencyConflictResolver();
            conflictResolver.RegisterConflictList(typeof(Event1), new List<Type> {typeof(Event1)});
            var newEvents = new List<Event>
            {
                new Event1(),
                new Event1()
            };

            var publisherMock = new EventPublisherMock();

            var eventStore = new EventStore(publisherMock, databaseMock);

            Assert.Throws<EventStoreConcurrencyException>(() =>
                eventStore.SaveEvents(
                    aggregateId,
                    newEvents,
                    expectedVersion,
                    conflictResolver));
        }
        public void AddingEventsWithImproperExpectedVersionAndNullConflictResolverExpectException()
        {
            var aggregateId = Guid.NewGuid();
            var databaseMock = new DatabaseMock<EventDescriptors>();
            var existingEvents = new EventDescriptors { Id = aggregateId };
            existingEvents.Add(new EventDescriptor(Guid.NewGuid(), new Event(), 0));
            existingEvents.Add(new EventDescriptor(Guid.NewGuid(), new Event(), 1));
            databaseMock.Put(existingEvents);

            var expectedVersion = existingEvents.Count() - 2;
            IConcurrencyConflictResolver conflictResolver = null;
            var newEvents = new List<Event>
            {
                new Event(),
                new Event()
            };

            var publisherMock = new EventPublisherMock();

            var eventStore = new EventStore(publisherMock, databaseMock);

            Assert.Throws<EventStoreConcurrencyException>(() => 
                eventStore.SaveEvents(
                    aggregateId,
                    newEvents,
                    expectedVersion,
                    conflictResolver));
        }