예제 #1
0
        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);
        }
예제 #2
0
        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);
        }
예제 #3
0
        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);
            }
        }
예제 #4
0
        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);
        }
예제 #5
0
        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);
        }
예제 #6
0
        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]);
        }
예제 #7
0
        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);
        }
예제 #9
0
        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);
        }
예제 #10
0
        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));
        }
예제 #11
0
        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));
예제 #12
0
        public void Cannot_add_self_to_chain()
        {
            var x = new TestChain("1");

            Assert.Throws <ArgumentException>(
                () => x.And(x)
                );
        }
예제 #13
0
        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());
        }
예제 #14
0
        public Task AddItemToChain_Valid()
        {
            //Arrange / Act
            var chain = new TestChain();

            //Assert
            Assert.Equal <int>(1, chain.ChainItemsCount);

            return(Task.CompletedTask);
        }
예제 #15
0
        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)
                );
        }
예제 #16
0
        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);
        }
예제 #17
0
        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());
        }
예제 #18
0
        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());
        }
예제 #19
0
        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);
        }
예제 #20
0
        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));
            });
        }
예제 #21
0
        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);
        }
예제 #22
0
        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);
        }
예제 #23
0
        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));
        }
예제 #24
0
        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);
        }
예제 #25
0
        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);
예제 #26
0
        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);
        }
예제 #27
0
        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);
        }
예제 #28
0
        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);
        }
예제 #29
0
        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);
        }
예제 #30
0
        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
                );
        }