private void RandomDemand(Dictionary <int, SubFlowState> map, RandomDemandProperties props)
        {
            while (true)
            {
                var nextIndex = ThreadLocalRandom.Current.Next(0, map.Count);
                var key       = map.Keys.ToArray()[nextIndex];
                if (!map[key].HasDemand)
                {
                    var state = map[key];
                    map[key] = new SubFlowState(state.Probe, true, state.FirstElement);

                    state.Probe.Request(1);

                    // need to verify elements that are first element in subFlow or is in nextElement buffer before
                    // pushing next element from upstream
                    if (state.FirstElement != null)
                    {
                        state.Probe.ExpectNext().ShouldBeEquivalentTo(state.FirstElement);
                        map[key] = new SubFlowState(state.Probe, false, null);
                    }
                    else if (props.BlockingNextElement != null && Math.Abs(props.BlockingNextElement[0] % 100) == key)
                    {
                        state.Probe.ExpectNext().ShouldBeEquivalentTo(props.BlockingNextElement);
                        props.BlockingNextElement = null;
                        map[key] = new SubFlowState(state.Probe, false, null);
                    }
                    else if (props.BlockingNextElement == null)
                    {
                        break;
                    }
                }
            }
        }
        public void GroupBy_must_work_with_random_demand()
        {
            this.AssertAllStagesStopped(() =>
            {
                var settings     = ActorMaterializerSettings.Create(Sys).WithInputBuffer(1, 1);
                var materializer = Sys.Materializer(settings);

                var props = new RandomDemandProperties
                {
                    Kit = this
                };
                Enumerable.Range(0, 100)
                .ToList()
                .ForEach(_ => props.Probes.Add(new TaskCompletionSource <TestSubscriber.Probe <ByteString> >()));

                var map = new Dictionary <int, SubFlowState>();

                var publisherProbe = this.CreateManualPublisherProbe <ByteString>();
                var probeShape     = new SinkShape <ByteString>(new Inlet <ByteString>("ProbeSink.in"));
                var probeSink      = new ProbeSink(probeShape, props, Attributes.None);
                Source.FromPublisher(publisherProbe)
                .GroupBy(100, element => Math.Abs(element[0] % 100))
                .To(new Sink <ByteString, TestSubscriber.Probe <ByteString> >(probeSink))
                .Run(materializer);

                var upstreamSubscription = publisherProbe.ExpectSubscription();

                for (var i = 1; i <= 400; i++)
                {
                    var byteString = RandomByteString(10);
                    var index      = Math.Abs(byteString[0] % 100);

                    upstreamSubscription.ExpectRequest();
                    upstreamSubscription.SendNext(byteString);

                    if (map.TryGetValue(index, out var state))
                    {
                        if (state.FirstElement != null) //first element in subFlow
                        {
                            if (!state.HasDemand)
                            {
                                props.BlockingNextElement = byteString;
                            }
                            RandomDemand(map, props);
                        }
                        else if (state.HasDemand)
                        {
                            if (props.BlockingNextElement == null)
                            {
                                state.Probe.ExpectNext().ShouldBeEquivalentTo(byteString);
                                map[index] = new SubFlowState(state.Probe, false, null);
                                RandomDemand(map, props);
                            }
                            else
                            {
                                true.ShouldBeFalse("INVALID CASE");
                            }
                        }
                        else
                        {
                            props.BlockingNextElement = byteString;
                            RandomDemand(map, props);
                        }
                    }
                    else
                    {
                        var probe = props.Probes[props.ProbesReaderTop].Task.AwaitResult();
                        props.ProbesReaderTop++;
                        map[index] = new SubFlowState(probe, false, byteString);
                        //stream automatically requests next element
                    }
                }
                upstreamSubscription.SendComplete();
            }, Materializer);
        }