public void Saving_with_concurrent_event_edits_should_be_subject_to_concurrency_checks() { // test created in response to an issue with concurrent edits happening within the window between // reading the current version number of the aggregate and the event source record being updated with // the new version number. this would leave the event stream for an event source out of sequence and // the aggregate in a state in which it could not be retrieved :o var concurrencyExceptionThrown = false; var targetStore = new MsSqlServerEventStore(connectionString); var theEventSourceId = Guid.NewGuid(); var theCommitId = Guid.NewGuid(); // make sure that the event source for the aggregate is created var creationEvent = Prepare.Events(new CustomerCreatedEvent("Foo", 35)) .ForSourceUncomitted(theEventSourceId, theCommitId); targetStore.Store(creationEvent); var tasks = new Task[130]; // now simulate concurreny updates coming in on the same aggregate for (int idx = 0; idx < tasks.Length; idx++) { tasks[idx] = Task.Factory.StartNew(() => { var changeEvent = new CustomerNameChanged(DateTime.Now.Ticks.ToString()) { CustomerId = theEventSourceId }; var eventStream = Prepare.Events(changeEvent) .ForSourceUncomitted(theEventSourceId, Guid.NewGuid(), 2); try { targetStore.Store(eventStream); } catch (ConcurrencyException) { concurrencyExceptionThrown = true; } targetStore.ReadFrom(theEventSourceId, long.MinValue, long.MaxValue); }); } Task.WaitAll(tasks); if (concurrencyExceptionThrown == false) { Assert.True(false, "We're expecting concurrency exceptions!"); } }
public void Saving_with_concurrent_event_adds_should_not_be_causing_deadlocks() { // test created in response to an issue with high frequency adds causing deadlocks on the EventSource table. // I reworked the sequencing of reads/updates to the EventSource table to reduce the amount // of time to any locks will be held. But this wasn't strictly required as the problem resided // in the fact that there was no index on the event source table result in full table scans occuring. // I therefore also changed the DDL to incude an non clustered index on EventSource.Id which resulted // in a nice performance boost during informal testing. var targetStore = new MsSqlServerEventStore(connectionString); var tasks = new Task[30]; // this number require to reproduce the issue might vary depending on hardware for (int idx = 0; idx < tasks.Length; idx++) { tasks[idx] = Task.Factory.StartNew(() => { var theEventSourceId = Guid.NewGuid(); var theCommitId = Guid.NewGuid(); var eventStream = Prepare.Events(new CustomerCreatedEvent(Task.CurrentId.ToString(), 35)) .ForSourceUncomitted(theEventSourceId, theCommitId); // should not be receiving a deadlock targetStore.Store(eventStream); }); } Task.WaitAll(tasks); }
public void Storing_event_source_should_succeed() { var targetStore = new MsSqlServerEventStore(connectionString); var theEventSourceId = Guid.NewGuid(); var theCommitId = Guid.NewGuid(); var eventStream = Prepare.Events( new CustomerCreatedEvent("Foo", 35), new CustomerNameChanged("Name" + 2), new CustomerNameChanged("Name" + 3), new CustomerNameChanged("Name" + 4)) .ForSourceUncomitted(theEventSourceId, theCommitId); targetStore.Store(eventStream); var eventsFromStore = targetStore.ReadFrom(theEventSourceId, long.MinValue, long.MaxValue); eventsFromStore.Count().Should().Be(eventStream.Count()); for (int i = 0; i < eventsFromStore.Count(); i++) { var uncommittedEvent = eventStream.ElementAt(i); var committedEvent = eventsFromStore.ElementAt(i); committedEvent.EventSourceId.Should().Be(uncommittedEvent.EventSourceId); committedEvent.EventIdentifier.Should().Be(uncommittedEvent.EventIdentifier); committedEvent.EventSequence.Should().Be(uncommittedEvent.EventSequence); committedEvent.Payload.GetType().Should().Be(uncommittedEvent.Payload.GetType()); } }
private static void GenerateEvents() { var eventStore = new MsSqlServerEventStore(ConfigurationManager.ConnectionStrings["Main"].ConnectionString); for (int i = 0; i < 1000; i++) { var uncommittedEventStream = new UncommittedEventStream(Guid.NewGuid()); uncommittedEventStream.Append(new UncommittedEvent(Guid.NewGuid(), Guid.NewGuid(), i, i, DateTime.Now, new object(), new Version(1, 0))); eventStore.Store(uncommittedEventStream); } }
public void Storing_empty_event_stream_should_not_throw() { var targetStore = new MsSqlServerEventStore(connectionString); var theEventSourceId = Guid.NewGuid(); var theCommitId = Guid.NewGuid(); var eventStream = Prepare.Events(new object[0]) .ForSourceUncomitted(theEventSourceId, theCommitId); targetStore.Store(eventStream); Assert.True(true); }
public void Storing_entity_sourced_event_should_preserve_entity_id() { var targetStore = new MsSqlServerEventStore(connectionString); var theEventSourceId = Guid.NewGuid(); var theCommitId = Guid.NewGuid(); var theEntityId = Guid.NewGuid(); var eventStream = Prepare.Events(new AccountNameChangedEvent(theEntityId, "NewName")) .ForSourceUncomitted(theEventSourceId, theCommitId); targetStore.Store(eventStream); var restoredEvent = targetStore.ReadFrom(theEventSourceId, long.MinValue, long.MaxValue).Single(); var payload = (AccountNameChangedEvent)restoredEvent.Payload; payload.EntityId.Should().Be(theEntityId); }
public void Saving_snapshot_should_not_throw_an_exception_when_snapshot_is_valid() { var targetStore = new MsSqlServerEventStore(connectionString); var anId = Guid.NewGuid(); var aCommitId = Guid.NewGuid(); var aVersion = 12; var eventStream = Prepare.Events(new object()) .ForSourceUncomitted(anId, aCommitId); var snapshot = new Snapshot(anId, aVersion, new MySnapshot()); targetStore.Store(eventStream); targetStore.SaveSnapshot(snapshot); var savedSnapshot = targetStore.GetSnapshot(anId, long.MaxValue); savedSnapshot.EventSourceId.Should().Be(anId); savedSnapshot.Version.Should().Be(aVersion); }