public async Task CanSubscribeToStream() { var streamMessageReceived = false; var subscriptionDropped = false; var streamStore = new InMemoryStreamStore(); var streamId = new StreamId("test"); streamStore.SubscribeToStream(streamId, null, StreamMessageReceived, SubscriptionDropped); var message = new NewStreamMessage(Guid.NewGuid(), "Test", @"{ 'Hello': 'World' }"); await streamStore.AppendToStream(streamId, ExpectedVersion.Any, message); Thread.Sleep(100); Assert.True(streamMessageReceived); Assert.False(subscriptionDropped); async Task StreamMessageReceived(IStreamSubscription subscription, StreamMessage streamMessage, CancellationToken cancellationToken) { streamMessageReceived = true; Assert.Equal("Test", streamMessage.Type); } void SubscriptionDropped(IStreamSubscription subscription, SubscriptionDroppedReason reason, Exception exception = null) { subscriptionDropped = true; } }
public async Task When_exception_throw_by_subscription_message_received_then_should_drop_subscription() { using (var store = new InMemoryStreamStore()) { var eventReceivedException = new TaskCompletionSource <Exception>(); StreamMessageReceived messageReceived = _ => { throw new Exception(); }; SubscriptionDropped subscriptionDropped = (reason, exception) => { eventReceivedException.SetResult(exception); }; string streamId = "stream-1"; using (await store.SubscribeToStream("stream-1", StreamVersion.Start, messageReceived, subscriptionDropped)) { await store.AppendToStream(streamId, ExpectedVersion.NoStream, new NewStreamMessage(Guid.NewGuid(), "type", "{}")); var dropException = await eventReceivedException.Task.WithTimeout(); dropException.ShouldBeOfType <Exception>(); } } }
public async Task DoesNotAppendEventWhenLastEventIsFromSameDay() { var now = new DateTime(2019, 12, 25, 12, 00, 00); var utcNow = now.ToUniversalTime(); var clockProviderStub = new ClockProviderStub(now); var inMemoryStreamStore = new InMemoryStreamStore(() => utcNow); var clockHasTicked = new ClockHasTicked(new DateTime(2019, 12, 25, 11, 00, 00)); var cancellationToken = CancellationToken.None; await inMemoryStreamStore.AppendToStream( streamId : new StreamId(ClockTickingService.ClockStreamId), expectedVersion : ExpectedVersion.Any, message : new NewStreamMessage( messageId: Guid.NewGuid(), type: _eventMapping.GetEventName(clockHasTicked.GetType()), jsonData: JsonConvert.SerializeObject(clockHasTicked)), cancellationToken : cancellationToken); var sut = new ClockTickingService(inMemoryStreamStore, clockProviderStub); await sut.StartAsync(cancellationToken); var forwards = await inMemoryStreamStore.ReadAllForwards(Position.Start, Int32.MaxValue, true, cancellationToken); forwards.Messages.Should().HaveCount(1); }
public async Task CanAppendToMultipleStreamsAndReadAllForward() { var streamStore = new InMemoryStreamStore(); var stream1 = new StreamId("test1"); var stream2 = new StreamId("test2"); var message1 = new NewStreamMessage(Guid.NewGuid(), "Test1", @"{ 'Hello': 'World1' }"); await streamStore.AppendToStream(stream1, ExpectedVersion.Any, message1); var message2 = new NewStreamMessage(Guid.NewGuid(), "Test2", @"{ 'Hello': 'World2' }"); await streamStore.AppendToStream(stream2, ExpectedVersion.Any, message2); var readStreamPage = await streamStore.ReadAllForwards(StreamVersion.Start, int.MaxValue, true); Assert.Equal(2, readStreamPage.Messages.Length); }
public void CreateDependencies() { var store = new InMemoryStreamStore(); var eventMapping = new EventMapping(new Dictionary <string, Type> { { "SomethingHappened", typeof(SomethingHappened) }, { "SomethingElseHappened", typeof(SomethingElseHappened) }, }); var eventSerializer = new EventSerializer(JsonConvert.SerializeObject); var eventDeserializer = new EventDeserializer(JsonConvert.DeserializeObject); _factRepository = new StreamStoreFactRepository(store, eventMapping, eventSerializer, eventDeserializer); _handlerFactory = (eventType, @events) => async(command) => { long position = 0; foreach (var @event in events) { position = (await store.AppendToStream( (command as DoSomething).Identifier, ExpectedVersion.Any, new NewStreamMessage(Guid.NewGuid(), eventType, eventSerializer.SerializeObject(@event)), CancellationToken.None) ).CurrentPosition; } return(position); }; _handlerResolver = new Mocking <IHandlerResolver, HandlerResolverSetup>(); //_handlerResolver.When().ResolvesHandler(_handlerFactory); }
private Func <TestMessage, Task <AppendResult> > CreateMessageStorerAndStartHandling(ConnectedProjection <TestDbContext> projection) { var eventMapping = new EventMapping(EventMapping.DiscoverEventNamesInAssembly(typeof(RunnerTests).Assembly)); var testRunner = new TestRunner( new EnvelopeFactory( eventMapping, new EventDeserializer(JsonConvert.DeserializeObject)), new Logger <TestRunner>(new LoggerFactory()), projection); var options = new DbContextOptionsBuilder <TestDbContext>() .UseInMemoryDatabase("testing") .Options; using (var testDbContext = new TestDbContext(options)) { testDbContext.Database.EnsureDeleted(); } var inMemoryStreamStore = new InMemoryStreamStore(() => DateTime.UtcNow); testRunner.Handle( inMemoryStreamStore, () => new Owned <TestDbContext>(new TestDbContext(options), this)); return(async message => await inMemoryStreamStore.AppendToStream(new StreamId("Bla"), ExpectedVersion.Any, new NewStreamMessage(Guid.NewGuid(), eventMapping.GetEventName(typeof(TestMessage)), JsonConvert.SerializeObject(message)))); }
public async Task AppendToStreamWithWrongExpectedVersionThrowsException() { var streamStore = new InMemoryStreamStore(); var stremId = new StreamId("test"); var jsonIn = @"{ 'Hello': 'World' }"; var message = new NewStreamMessage(Guid.NewGuid(), "Test", jsonIn); await streamStore.AppendToStream(stremId, ExpectedVersion.NoStream, message); jsonIn = @"{ 'Hello': 'New World' }"; message = new NewStreamMessage(Guid.NewGuid(), "Test", jsonIn); await streamStore.AppendToStream(stremId, 0, message); jsonIn = @"{ 'Hello': 'Very New World' }"; message = new NewStreamMessage(Guid.NewGuid(), "Test", jsonIn); await Assert.ThrowsAsync(typeof(WrongExpectedVersionException), async() => { await streamStore.AppendToStream(stremId, 0, message); }); }
public async Task ShowWithCatchupSubscription() { //setup a projection schema (one of many ways) var projector = new SqlProjector( Resolve.WhenEqualToHandlerMessageType(new PortfolioProjection()), new TransactionalSqlCommandExecutor( new ConnectionStringSettings( "projac", @"Data Source=(localdb)\ProjectsV12;Initial Catalog=ProjacUsage;Integrated Security=SSPI;", "System.Data.SqlClient"), IsolationLevel.ReadCommitted)); projector.Project(new object[] { new DropSchema(), new CreateSchema() }); //setup a memory eventstore var store = new InMemoryStreamStore(); //setup a sample stream (using some sample events) var portfolioId = Guid.NewGuid(); var events = new object[] { new PortfolioAdded { Id = portfolioId, Name = "My Portfolio" }, new PortfolioRenamed { Id = portfolioId, Name = "Your Portfolio" }, new PortfolioRemoved { Id = portfolioId } }; var stream = string.Format("portfolio-{0}", portfolioId.ToString("N")); await store.AppendToStream( stream, ExpectedVersion.Any, events .Select(@event => new NewStreamMessage( Guid.NewGuid(), @event.GetType().FullName, JsonConvert.SerializeObject(@event))) .ToArray()); //project the sample stream (until end of stream) var subscription = store.SubscribeToStream(stream, null, async(_, rawMessage) => { var @event = JsonConvert.DeserializeObject( await rawMessage.GetJsonData(), Type.GetType(rawMessage.Type, true)); projector.Project(@event); }); //should complete within 5 seconds. await Task.Delay(TimeSpan.FromSeconds(5)); subscription.Dispose(); }
public async Task CreatingANewStreamTest(int expectedVersion, int currentVersionForOpenedStream) { var streamId = "newStreamId1"; var streamStore = new InMemoryStreamStore(); var result = await streamStore.AppendToStream(new StreamId(streamId), expectedVersion, new NewStreamMessage[0], CancellationToken.None); Assert.AreEqual(-1, result.CurrentPosition); Assert.AreEqual(currentVersionForOpenedStream, result.CurrentVersion); }
public async Task CanSubscribeToAllStreams() { var receivedMessagesCount = 0; var subscriptionDropped = false; var streamStore = new InMemoryStreamStore(); var stream1 = new StreamId("test1"); var stream2 = new StreamId("test2"); streamStore.SubscribeToAll(null, AllStreamMessageReceived, AllSubscriptionDropped); var message1 = new NewStreamMessage(Guid.NewGuid(), "Test1", @"{ 'Hello': 'World1' }"); await streamStore.AppendToStream(stream1, ExpectedVersion.Any, message1); var message2 = new NewStreamMessage(Guid.NewGuid(), "Test2", @"{ 'Hello': 'World2' }"); await streamStore.AppendToStream(stream2, ExpectedVersion.Any, message2); Thread.Sleep(100); Assert.Equal(2, receivedMessagesCount); Assert.False(subscriptionDropped); async Task AllStreamMessageReceived(IAllStreamSubscription subscription, StreamMessage streamMessage, CancellationToken cancellationToken) { if (receivedMessagesCount == 0) { Assert.Equal("Test1", streamMessage.Type); } if (receivedMessagesCount == 1) { Assert.Equal("Test2", streamMessage.Type); } receivedMessagesCount++; } void AllSubscriptionDropped(IAllStreamSubscription subscription, SubscriptionDroppedReason reason, Exception exception = null) { subscriptionDropped = true; } }
public void CreatingANonExistingStreamWithVersionAsEmptyStreamThrowsException(int expectedVersion) { var streamId = "newStreamId1"; var streamStore = new InMemoryStreamStore(); Assert.ThrowsAsync <WrongExpectedVersionException> (async() => { var result = await streamStore.AppendToStream(new StreamId(streamId), expectedVersion, new NewStreamMessage[0], CancellationToken.None); }); }
public async Task CanGetStreamVersion() { var streamStore = new InMemoryStreamStore(); var stream1 = new StreamId("test1"); var stream2 = new StreamId("test2"); var message1 = new NewStreamMessage(Guid.NewGuid(), "Test1", @"{ 'Hello': 'World1' }"); await streamStore.AppendToStream(stream1, ExpectedVersion.Any, message1); message1 = new NewStreamMessage(Guid.NewGuid(), "Test1", @"{ 'Hello': 'World1' }"); await streamStore.AppendToStream(stream1, ExpectedVersion.Any, message1); var message2 = new NewStreamMessage(Guid.NewGuid(), "Test2", @"{ 'Hello': 'World2' }"); await streamStore.AppendToStream(stream2, ExpectedVersion.Any, message2); Thread.Sleep(100); var stream1Metadata = await streamStore.GetStreamMetadata("test1"); var stream2Metadata = await streamStore.GetStreamMetadata("test2"); Assert.Equal(1, stream1Metadata.MetadataStreamVersion); Assert.Equal(0, stream2Metadata.MetadataStreamVersion); }
public async Task CanAppendToStreamAndReadFromStreamForwardAndGetJsonBack() { var streamStore = new InMemoryStreamStore(); var stremId = new StreamId("test"); var jsonIn = @"{ 'Hello': 'World' }"; var message = new NewStreamMessage(Guid.NewGuid(), "Test", jsonIn); await streamStore.AppendToStream(stremId, ExpectedVersion.Any, message); var readStreamPage = await streamStore.ReadStreamForwards(stremId, StreamVersion.Start, int.MaxValue); var jsonOut = await readStreamPage.Messages[0].GetJsonData(); Assert.Equal(1, readStreamPage.Messages.Length); Assert.Equal(jsonIn, jsonOut); }
public static async Task Main(string[] args) { Log.Logger = new LoggerConfiguration() .MinimumLevel.Debug() .Enrich.FromLogContext() .WriteTo.Console() .CreateLogger(); using (var streamStore = new InMemoryStreamStore()) using (var host = new WebHostBuilder() .UseKestrel() .UseStartup(new Startup(streamStore, new SqlStreamStoreMiddlewareOptions { UseCanonicalUrls = false })) .UseSerilog() .UseUrls("http://localhost:5050") .Build()) { // Simulating some messages in the store here (only one stream) var random = new Random(); var id = new Guid("cbf68be34d9547eb9b4a390fd2aa417b"); var messages = new NewStreamMessage[random.Next(1000, 2000)]; for (var index = 0; index < messages.Length; index++) { messages[index] = new NewStreamMessage( Guid.NewGuid(), "ItineraryPublished", JsonConvert.SerializeObject(new { ItineraryId = id, Data = index }) ); } await streamStore.AppendToStream(id.ToString("N"), ExpectedVersion.NoStream, messages); // bootstrapping the server var source = new CancellationTokenSource(); var serverTask = host.RunAsync(source.Token); // press enter to exit Console.WriteLine("Running ..."); Console.ReadLine(); source.Cancel(); await serverTask; } }
public async Task CreatingStreamAndAddingMessage(int expectedVersion, int numberOfMessages) { var streamId = "newStreamId1"; var streamStore = new InMemoryStreamStore(); var newStreamMessages = new List <NewStreamMessage>(); for (int i = 0; i < numberOfMessages; i++) { newStreamMessages.Add(new NewStreamMessage(Guid.NewGuid(), "type1", "message1", "meta1")); } var result = await streamStore.AppendToStream(new StreamId(streamId), expectedVersion, newStreamMessages.ToArray(), CancellationToken.None); Assert.AreEqual(numberOfMessages - 1, result.CurrentPosition); Assert.AreEqual(numberOfMessages - 1, result.CurrentVersion); }
public void CreatingStreamAndAddingMessageSpecifyingWrongVersion(int expectedVersion) { var streamId = "newStreamId1"; var streamStore = new InMemoryStreamStore(); var newStreamMessages = new List <NewStreamMessage>(); for (int i = 0; i < 1; i++) { newStreamMessages.Add(new NewStreamMessage(Guid.NewGuid(), "type1", "message1", "meta1")); } Assert.ThrowsAsync <WrongExpectedVersionException>(async() => { await streamStore.AppendToStream(new StreamId(streamId), expectedVersion, newStreamMessages.ToArray(), CancellationToken.None); }); }
public async Task ShowWithStream() { //setup a projection schema (one of many ways) var projector = new AsyncSqlProjector( Resolve.WhenEqualToHandlerMessageType(new PortfolioProjection()), new TransactionalSqlCommandExecutor( new ConnectionStringSettings( "projac", @"Data Source=(localdb)\ProjectsV12;Initial Catalog=ProjacUsage;Integrated Security=SSPI;", "System.Data.SqlClient"), IsolationLevel.ReadCommitted)); await projector.ProjectAsync(new object[] { new DropSchema(), new CreateSchema() }); //setup a memory eventstore var store = new InMemoryStreamStore(); //setup a sample stream (using some sample events) var portfolioId = Guid.NewGuid(); var events = new object[] { new PortfolioAdded { Id = portfolioId, Name = "My Portfolio" }, new PortfolioRenamed { Id = portfolioId, Name = "Your Portfolio" }, new PortfolioRemoved { Id = portfolioId } }; var stream = string.Format("portfolio-{0}", portfolioId.ToString("N")); await store.AppendToStream( stream, ExpectedVersion.Any, events .Select(@event => new NewStreamMessage( Guid.NewGuid(), @event.GetType().FullName, JsonConvert.SerializeObject(@event))) .ToArray()); //project the sample stream (until end of stream) var result = await store.ReadStreamForwards(stream, StreamVersion.Start, 1, true); foreach (var rawMessage in result.Messages) { var @event = JsonConvert.DeserializeObject( await rawMessage.GetJsonData(), Type.GetType(rawMessage.Type, true)); await projector.ProjectAsync(@event); } while (!result.IsEnd) { result = await store.ReadStreamForwards(stream, result.NextStreamVersion, 1, true); foreach (var rawMessage in result.Messages) { var @event = JsonConvert.DeserializeObject( await rawMessage.GetJsonData(), Type.GetType(rawMessage.Type, true)); await projector.ProjectAsync(@event); } } }