public void ShouldNotTransitionToRunCompletedWhenRunCompleted()
        {
            var builder =
                new ResultCursorBuilder(CreateSummaryBuilder(), CreateTaskQueue(), null, null, null);

            builder.CurrentState.Should().Be(ResultCursorBuilder.State.RunAndRecordsRequested);

            builder.RunCompleted(0, new[] { "a", "b", "c" }, null);
            builder.CurrentState.Should().Be(ResultCursorBuilder.State.RunAndRecordsRequested);
        }
        public async Task ShouldPauseAndResumeStreamingWithWatermarks()
        {
            var actions         = new Queue <Action>();
            var resourceHandler = new Mock <IResultResourceHandler>();
            var builder         =
                new ResultCursorBuilder(CreateSummaryBuilder(), CreateTaskQueue(),
                                        CreateMoreTaskQueue(actions),
                                        null,
                                        resourceHandler.Object, 2);

            var counter = 0;

            builder.RunCompleted(0, new[] { "a" }, null);
            builder.PullCompleted(true, null);
            builder.CurrentState.Should().Be(ResultCursorBuilder.State.RunCompleted);
            actions.Enqueue(() =>
            {
                builder.PushRecord(new object[] { 1 });
                counter++;
                builder.PushRecord(new object[] { 2 });
                counter++;
                builder.PullCompleted(true, null);
            });
            actions.Enqueue(() =>
            {
                builder.PushRecord(new object[] { 3 });
                counter++;
                builder.PullCompleted(false, null);
            });

            var cursor = builder.CreateCursor();

            var hasNext = await cursor.FetchAsync();

            hasNext.Should().BeTrue();
            resourceHandler.Verify(x => x.OnResultConsumedAsync(), Times.Never);
            counter.Should().Be(2);

            hasNext = await cursor.FetchAsync();

            hasNext.Should().BeTrue();
            resourceHandler.Verify(x => x.OnResultConsumedAsync(), Times.Once);
            counter.Should().Be(3);

            hasNext = await cursor.FetchAsync();

            hasNext.Should().BeTrue();
            counter.Should().Be(3);

            hasNext = await cursor.FetchAsync();

            hasNext.Should().BeFalse();
            counter.Should().Be(3);
        }
        public void ShouldTransitionToRecordsStreamingStreamingWhenRecordIsPushed()
        {
            var builder =
                new ResultCursorBuilder(CreateSummaryBuilder(), CreateTaskQueue(), null, null, null);

            builder.CurrentState.Should().Be(ResultCursorBuilder.State.RunAndRecordsRequested);

            builder.RunCompleted(0, new[] { "a", "b", "c" }, null);
            builder.CurrentState.Should().Be(ResultCursorBuilder.State.RunAndRecordsRequested);

            builder.PushRecord(new object[] { 1, 2, 3 });
            builder.CurrentState.Should().Be(ResultCursorBuilder.State.RecordsStreaming);
        }
            public async Task ShouldCallMoreOnceAndReturnRecords()
            {
                var actions = new Queue <Action>();
                var builder =
                    new ResultCursorBuilder(CreateSummaryBuilder(), CreateTaskQueue(actions),
                                            MoreFunction(), CancelFunction(), null, reactive: true);

                actions.Enqueue(() => builder.RunCompleted(0, new[] { "a" }, null));
                actions.Enqueue(() => builder.PushRecord(new object[] { 1 }));
                actions.Enqueue(() => builder.PushRecord(new object[] { 2 }));
                actions.Enqueue(() => builder.PushRecord(new object[] { 3 }));
                actions.Enqueue(() => builder.PullCompleted(false, null));

                var list = await builder.CreateCursor().ToListAsync(r => r[0].As <int>());

                list.Should().BeEquivalentTo(1, 2, 3);
                moreCallCount.Should().Be(1);
                cancelCallCount.Should().Be(0);
            }
            public async Task ShouldReturnFirstBatchOfRecordsAndCancel()
            {
                var actions = new Queue <Action>();
                var builder =
                    new ResultCursorBuilder(CreateSummaryBuilder(), CreateTaskQueue(actions),
                                            MoreFunction(), CancelFunction(), null, reactive: true);

                actions.Enqueue(() => builder.RunCompleted(0, new[] { "a" }, null));
                actions.Enqueue(() => builder.PushRecord(new object[] { 1 }));
                actions.Enqueue(() => builder.PushRecord(new object[] { 2 }));
                actions.Enqueue(() => builder.PullCompleted(true, null));
                actions.Enqueue(() => builder.PullCompleted(false, null));

                var cursor = builder.CreateCursor();

                var keys = await cursor.KeysAsync();

                keys.Should().BeEquivalentTo("a");

                var hasRecord1 = await cursor.FetchAsync();

                var record1 = cursor.Current;

                hasRecord1.Should().BeTrue();
                record1[0].Should().Be(1);

                var hasRecord2 = await cursor.FetchAsync();

                var record2 = cursor.Current;

                hasRecord2.Should().BeTrue();
                record2[0].Should().Be(2);

                cursor.Cancel();

                var list = await cursor.ToListAsync(r => r[0].As <int>());

                list.Should().BeEmpty();
                moreCallCount.Should().Be(1);
                cancelCallCount.Should().Be(1);
            }
            public async Task ShouldCallCancelAndReturnNoRecords()
            {
                var actions = new Queue <Action>();
                var builder =
                    new ResultCursorBuilder(CreateSummaryBuilder(), CreateTaskQueue(actions),
                                            MoreFunction(), CancelFunction(), null, reactive: true);

                actions.Enqueue(() => builder.RunCompleted(0, new[] { "a" }, null));
                actions.Enqueue(() => builder.PullCompleted(false, null));

                var cursor = builder.CreateCursor();

                var keys = await cursor.KeysAsync();

                keys.Should().BeEquivalentTo("a");

                cursor.Cancel();

                var list = await cursor.ToListAsync(r => r[0].As <int>());

                list.Should().BeEmpty();
                moreCallCount.Should().Be(0);
                cancelCallCount.Should().Be(1);
            }
        public async Task ShouldInvokeResourceHandlerWhenCompleted()
        {
            var actions         = new Queue <Action>();
            var resourceHandler = new Mock <IResultResourceHandler>();
            var builder         =
                new ResultCursorBuilder(CreateSummaryBuilder(), CreateTaskQueue(actions), null, null,
                                        resourceHandler.Object);

            actions.Enqueue(() => builder.RunCompleted(0, new[] { "a" }, null));
            actions.Enqueue(() => builder.PushRecord(new object[] { 1 }));
            actions.Enqueue(() => builder.PushRecord(new object[] { 2 }));
            actions.Enqueue(() => builder.PushRecord(new object[] { 3 }));
            actions.Enqueue(() => builder.PullCompleted(false, null));

            var cursor = builder.CreateCursor();

            var hasNext = await cursor.FetchAsync();

            hasNext.Should().BeTrue();
            resourceHandler.Verify(x => x.OnResultConsumedAsync(), Times.Never);

            hasNext = await cursor.FetchAsync();

            hasNext.Should().BeTrue();
            resourceHandler.Verify(x => x.OnResultConsumedAsync(), Times.Never);

            hasNext = await cursor.FetchAsync();

            hasNext.Should().BeTrue();
            resourceHandler.Verify(x => x.OnResultConsumedAsync(), Times.Never);

            hasNext = await cursor.FetchAsync();

            hasNext.Should().BeFalse();
            resourceHandler.Verify(x => x.OnResultConsumedAsync(), Times.Once);
        }