public async Task SourceException_NotifiesSourceStoppedHandler() { var eventTracker = new TestEventTracker <SourceStoppedEvent>(); var serviceProvider = new TestServiceProvider( configureServices: services => services .AddSingleton(eventTracker), configureDaisy: daisy => daisy .AddEventHandlerSingleton <TestEventTrackerHandler <SourceStoppedEvent> >() ); var chainBuilder = new TestChain <Signal> { ConfigureSourcesAction = sources => sources .Add <ThrowingTestSource <Signal> >("test") }; var chain = await chainBuilder.BuildAsync(serviceProvider); chain.StartAllSources(); await chain.Sources.WaitForCompletionAsync(); var source = chain.Sources[0]; Assert.Single(eventTracker.TrackedEvents, e => e.ChainName == chain.Name && e.SourceIndex == source.Index && e.SourceName == source.Name && e.Result == SourceResult.Faulted && e.SourceExecutionId != default && e.Exception is TestException); }
public async Task AddEventHandler_SingleHandlerWithMultipleInterfaces_NotifiesSingleInstance() { var sourceStartedTracker = new TestEventTracker <SourceStartedEvent>(); var sourceStoppedTracker = new TestEventTracker <SourceStoppedEvent>(); var serviceProvider = new TestServiceProvider( configureServices: services => services .AddSingleton(sourceStartedTracker) .AddSingleton(sourceStoppedTracker), configureDaisy: daisy => daisy .AddEventHandlerSingleton <SourceEventHandler>() ); var chainBuilder = new TestChain <Signal> { ConfigureSourcesAction = sources => sources .Add <SignalTestSource>("test") }; var chain = await chainBuilder.BuildAsync(serviceProvider); chain.StartAllSources(); await chain.Sources.WaitForCompletionAsync(); Assert.Single(sourceStartedTracker.TrackedHandlerIds); Assert.Single(sourceStoppedTracker.TrackedHandlerIds); Assert.Equal(sourceStoppedTracker.TrackedHandlerIds, sourceStoppedTracker.TrackedHandlerIds); }
public async Task Configure_Sources_UsesSources() { string[] payloads = { "test1", "test2" }; var result = new ConcurrentBag <string>(); var chainBuilder = new TestChain <string> { ConfigureSourcesAction = sources => { sources.Add <SignalTestSource, Signal>("1", _ => payloads[0]); sources.Add <SignalTestSource, Signal>("2", _ => payloads[1]); }, ConfigureRootAction = root => { root.TestInspect(onProcess: (input, _) => result.Add(input)); } }; var chain = await chainBuilder.BuildAsync(); chain.StartAllSources(); await chain.Sources.WaitForCompletionAsync(); foreach (var payload in payloads) { Assert.Contains(payload, result); } }
public async Task PublishEvent_MultipleHandlersWithSingleInterface_NotifiesAllHandlers() { var eventTracker = new TestEventTracker <SourceStartedEvent>(); var serviceProvider = new TestServiceProvider( configureServices: services => services .AddSingleton(eventTracker), configureDaisy: daisy => daisy .AddEventHandlerSingleton <TestEventTrackerHandler <SourceStartedEvent> >() .AddEventHandlerSingleton <SourceStartedEventTrackerHandler>() ); var chainBuilder = new TestChain <Signal> { ConfigureSourcesAction = sources => sources .Add <SignalTestSource>("test") }; var chain = await chainBuilder.BuildAsync(serviceProvider); chain.StartAllSources(); await chain.Sources.WaitForCompletionAsync(); Assert.Equal(2, eventTracker.TrackedHandlerIds.Count); Assert.Equal(2, eventTracker.TrackedEvents.Count); }
public async Task SourceCanceled_SourceStoppedHandler() { var eventTracker = new TestEventTracker <SourceStoppedEvent>(); var serviceProvider = new TestServiceProvider( configureServices: services => services .AddSingleton(eventTracker), configureDaisy: daisy => daisy .AddEventHandlerSingleton <TestEventTrackerHandler <SourceStoppedEvent> >() ); var chainBuilder = new TestChain <Signal> { ConfigureSourcesAction = sources => sources .Add <InfiniteDelaySource>("test") }; var chain = await chainBuilder.BuildAsync(serviceProvider); chain.StartAllSources(); await chain.StopAllSourcesAsync(); var source = chain.Sources[0]; Assert.Single(eventTracker.TrackedEvents, e => e.ChainName == chain.Name && e.SourceIndex == source.Index && e.SourceName == source.Name && e.SourceExecutionId != default && e.Result == SourceResult.Canceled); }
public async Task SourceCompletion_DisposesSource() { var sourceName = "test"; var tracker = new TestExecutionTracker(); var serviceProvider = new TestServiceProvider( configureServices: services => { services.AddSingleton(tracker); }); var chainBuilder = new TestChain <Signal> { ConfigureSourcesAction = sources => { sources.Add <SignalTestSource>(sourceName); } }; var chain = await chainBuilder.BuildAsync(serviceProvider); // Source is disposed once in constructor of SourceConnector<> Assert.True(tracker.DisposeCountBySourceName.ContainsKey(sourceName)); Assert.Equal(1, tracker.DisposeCountBySourceName[sourceName]); chain.StartAllSources(); await chain.Sources.WaitForCompletionAsync(); Assert.Equal(2, tracker.DisposeCountBySourceName[sourceName]); }
public async Task Cancel_CancellationToken_FailsChain() { var result = new ConcurrentBag <Signal>(); var chainBuilder = new TestChain <Signal>() { ConfigureRootAction = root => { root .TestInspect(onProcess: (input, _) => result.Add(input)) .TestDelay(500) .TestInspect(onProcess: (input, _) => result.Add(input)); } }; var chain = await chainBuilder.BuildAsync(); var cancellationSource = new CancellationTokenSource(); cancellationSource.CancelAfter(250); var executionResult = await chain.ExecuteAsync(Signal.Static, cancellationSource.Token); Assert.Equal(ExecutionResultStatus.Faulted, executionResult.Status); Assert.Single(result); }
public async Task Process_CallsSubChainOnMatch() { const string payload1 = "Payload1"; const string payload2 = "Payload2"; const string payload3 = "Payload3"; var result1 = new List <string>(); var result2 = new List <string>(); var chainBuilder = new TestChain <string> { ConfigureRootAction = root => root .If(payload1.Equals, then => then .TestInspect(onProcess: (input, _) => result1.Add(input)) ) .If(payload2.Equals, then => then .TestInspect(onProcess: (input, _) => result2.Add(input)) ) }; using var chain = await chainBuilder.BuildAsync(); await chain.ExecuteAsync(payload1, CancellationToken.None); await chain.ExecuteAsync(payload2, CancellationToken.None); await chain.ExecuteAsync(payload3, CancellationToken.None); Assert.Single(result1); Assert.Single(result1, payload1); Assert.Single(result2); Assert.Single(result2, payload2); }
public async Task Stop_WhenRunning_StopsExecution() { var result = new ConcurrentBag <Signal>(); var chainBuilder = new TestChain <Signal>() { ConfigureSourcesAction = sources => { sources.Add <SignalTestSource>("signal"); }, ConfigureRootAction = root => { root .TestInspect(onProcess: (input, _) => result.Add(input)) .TestDelay(500) .TestInspect(onProcess: (input, _) => result.Add(input)); } }; var chain = await chainBuilder.BuildAsync(); chain.StartAllSources(); await Task.Delay(250); await chain.StopAllSourcesAsync(true); Assert.Single(result); }
public async Task Cancel_CancellationToken_StopsIteration() { var payload = new[] { "Test1", "Test2", "Test3" }; var result = new List <string>(); var cancellationTokenSource = new CancellationTokenSource(); const int maxIterations = 2; var chainBuilder = new TestChain <string[]> { ConfigureRootAction = root => root .Each(each => each .TestInspect(onProcess: (input, _) => { result.Add(input); if (result.Count == maxIterations) { cancellationTokenSource.Cancel(); } })) }; await chainBuilder.BuildAndExecuteAsync(payload, cancellationTokenSource.Token); Assert.True(payload.Take(maxIterations).SequenceEqual(result)); }
public async Task ExecuteAsync_WithThrowingConnector_ReturnsWrappedException() { var chainBuilder = new TestChain <Signal> { ConfigureRootAction = root => root.SubChain(subChain => subChain .Link <ThrowingLink <Signal>, Signal>() ) }; var chain = await chainBuilder.BuildAsync(); var throwingConnector = chain.Connectors[1]; var result = await chain.ExecuteAsync(Signal.Static, CancellationToken.None); Assert.True( result is { Status: ExecutionResultStatus.Faulted, Exception: ChainException { InnerException: TestException, Connector: {} connector, } } && connector.Equals(throwingConnector));
public void Cannot_add_self_to_chain() { var x = new TestChain("1"); Assert.Throws <ArgumentException>( () => x.And(x) ); }
public void Calls_self_and_next_via_element_interface() { var first = new TestChain("42"); var next = new TestChain("4242"); var chain = first.And(next); Assert.Equal(new[] { "42", "4242" }, chain.GetValues()); }
public Task AddItemToChain_Valid() { //Arrange / Act var chain = new TestChain(); //Assert Assert.Equal <int>(1, chain.ChainItemsCount); return(Task.CompletedTask); }
public void Cannot_add_existing_element_to_chain() { var one = new TestChain("1"); var two = new TestChain("2"); var zero = new TestChain("0").And(one).And(two); Assert.Throws <ArgumentException>( () => zero.And(zero.Next) ); }
public async void ExecuteAsync_Completes() { var chainBuilder = new TestChain <Signal> { ConfigureRootAction = root => root.Link <NoopLink <Signal>, Signal>() }; var chain = await chainBuilder.BuildAsync(); await chain.ExecuteAsync(Signal.Static, CancellationToken.None); }
public async Task ConfigureRoot_MultipleTimes_Throws() { var chainBuilder = new TestChain <Signal> { ConfigureRootAction = root => { root.Link <NoopLink <Signal>, Signal>(); root.Link <NoopLink <Signal>, Signal>(); } }; await Assert.ThrowsAsync <NotSupportedException>(async() => await chainBuilder.BuildAsync()); }
public void Concatenates_two_chains() { var first = new TestChain("1").And(new TestChain("2")); var second = new TestChain("3").And(new TestChain("4")); Assert.Equal(new[] { "1", "2" }, first.GetValues()); Assert.Equal(new[] { "3", "4" }, second.GetValues()); var result = first.And(second); Assert.NotSame(first, result); Assert.Equal(new[] { "1", "2", "3", "4" }, result.GetValues()); }
public async Task Get_Name_ReturnsName() { var chainBuilder = new TestChain <Signal>("TestChainName") { ConfigureRootAction = root => { root.Link <NoopLink <Signal>, Signal>(); } }; var chain = await chainBuilder.BuildAsync(); Assert.Equal(chainBuilder.Name, chain.Name); }
public async Task Execute_WithCanceledCancellationToken_Throws() { var chainBuilder = new TestChain <Signal> { ConfigureRootAction = root => root.Link <NoopLink <Signal>, Signal>() }; var chain = await chainBuilder.BuildAsync(); await Assert.ThrowsAsync <OperationCanceledException>(async() => { await chain.ExecuteAsync(Signal.Static, new CancellationToken(true)); }); }
public async Task Process_ReceivesInput() { const string payload = "Test"; var result = new List <string>(); var chainBuilder = new TestChain <string> { ConfigureRootAction = root => root.TestInspect(onProcess: (input, _) => result.Add(input)) }; await chainBuilder.BuildAndExecuteAsync(payload); Assert.Single(result, payload); }
public async Task GetConnectors_ReturnsConnectorsWithIndexes() { var chainBuilder = new TestChain <Signal> { ConfigureRootAction = root => root .Link <NoopLink <Signal>, Signal>() .Link <NoopLink <Signal>, Signal>() .Link <NoopLink <Signal>, Signal>() }; var chain = await chainBuilder.BuildAsync(); var indexes = chain.Connectors.Select(c => c.Index); Assert.Equal(new[] { 0, 1, 2 }, indexes); }
public async Task Process_StringArray_IteratesItems() { var payload = new[] { "Test1", "Test2", "Test3" }; var result = new List <string>(); var chainBuilder = new TestChain <string[]> { ConfigureRootAction = root => root .Each(each => each .TestInspect(onProcess: (input, _) => result.Add(input))) }; await chainBuilder.BuildAndExecuteAsync(payload); Assert.True(payload.SequenceEqual(result)); }
public async Task Process_ReturnsMappedValue() { const string testInput = "SomeString"; var result = 0; var chainBuilder = new TestChain <string> { ConfigureRootAction = root => root .Map(input => input.Length) .TestInspect(onProcess: (input, _) => result = input) }; await chainBuilder.BuildAndExecuteAsync(testInput); Assert.Equal(testInput.Length, result); }
public async Task ChainExecutionStart_NotifiesHandler() { var eventTracker = new TestEventTracker <ChainExecutionStartedEvent>(); var serviceProvider = new TestServiceProvider( configureServices: services => services .AddSingleton(eventTracker), configureDaisy: daisy => daisy .AddEventHandlerSingleton <TestEventTrackerHandler <ChainExecutionStartedEvent> >() ); var chainBuilder = new TestChain <Signal> { ConfigureRootAction = root => root .Link <NoopLink <Signal>, Signal>() }; await chainBuilder.BuildAndExecuteAsync(Signal.Static, default, serviceProvider);
public async Task Dispose_DisposesSubChain() { var disposed = false; var chainBuilder = new TestChain <Signal[]> { ConfigureRootAction = root => root .SubChain(subChain => subChain .TestInspect(onDispose: () => disposed = true) ) }; var chain = await chainBuilder.BuildAsync(); chain.Dispose(); Assert.True(disposed); }
public async Task Process_SetsResult() { const string reason = "TestReason"; var chainBuilder = new TestChain <Signal> { ConfigureRootAction = root => root .SubChain(subChain => subChain .Complete(reason) ) .Link <ThrowingLink <Signal>, Signal>() }; var result = await chainBuilder.BuildAndExecuteAsync(Signal.Static); Assert.Equal(ExecutionResult.Completed, result); }
public async Task GetSources_ReturnsSourceConnectorsWithIndexes() { var chainBuilder = new TestChain <Signal> { ConfigureSourcesAction = sources => { sources.Add <SignalTestSource>("1"); sources.Add <SignalTestSource>("2"); sources.Add <SignalTestSource>("3"); } }; var chain = await chainBuilder.BuildAsync(); var indexes = chain.Sources.Select(s => s.Index); Assert.Equal(new[] { 0, 1, 2 }, indexes); }
public async Task ReturnValidResult_Valid() { //Arrange var chain = new TestChain(); var param = "Hello World!"; //Act var result = await chain.ExecuteAsync(new TestParameterType() { Value = param }, Guid.NewGuid()); //Assert Assert.NotNull(result); Assert.IsType <string>(result); Assert.Equal($"{param} Test Chain Item reached", result); }
public async Task Set_LockStrategy_UsesLockStrategy() { var result = new ConcurrentBag <Signal>(); var lockStrategy = new SharedLockStrategy(1); var chainBuilder = new TestChain <Signal> { LockStrategy = lockStrategy, ConfigureRootAction = root => { root.TestInspect(onProcess: (input, _) => result.Add(input)); } }; var chain = await chainBuilder.BuildAsync(); await lockStrategy.RequestLockAsync(CancellationToken.None); const int releaseTimeout = 500; var releaseTask = Task.Run(async() => { await Task.Delay(releaseTimeout); lockStrategy.ReleaseLock(); }); var assertEmptyTask = Task.Run(async() => { await Task.Delay(releaseTimeout / 2); Assert.Empty(result); }); var assertResultTask = Task.Run(async() => { await Task.Delay(releaseTimeout * 2); Assert.Single(result); }); await Task.WhenAll( chain.ExecuteAsync(Signal.Static, CancellationToken.None), releaseTask, assertEmptyTask, assertResultTask ); }