private void TestRebalance(
            IShardAllocationStrategy allocationStrategy,
            IImmutableDictionary <IActorRef, IImmutableList <string> > allocations,
            ImmutableList <IImmutableDictionary <IActorRef, IImmutableList <string> > > steps,
            int maxSteps)
        {
            var round           = steps.Count;
            var rebalanceResult = allocationStrategy.Rebalance(allocations, ImmutableHashSet <string> .Empty).Result;
            var newAllocations  = LeastShardAllocationStrategySpec.AfterRebalance(allocationStrategy, allocations, rebalanceResult);

            LeastShardAllocationStrategySpec.CountShards(newAllocations).Should().Be(LeastShardAllocationStrategySpec.CountShards(allocations), $"test {allocationStrategy}[{ string.Join(", ", LeastShardAllocationStrategySpec.CountShardsPerRegion(allocations))}]: ");
            var min      = LeastShardAllocationStrategySpec.CountShardsPerRegion(newAllocations).Min();
            var max      = LeastShardAllocationStrategySpec.CountShardsPerRegion(newAllocations).Max();
            var diff     = max - min;
            var newSteps = steps.Add(newAllocations);

            if (diff <= 1)
            {
                if (round >= 3 && maxSteps <= 10)
                {
                    // Should be very rare (I have not seen it)
                    Sys.Log.Info($"rebalance solved in round {round}, [{string.Join(" => ", newSteps.Select(step => string.Join(", ", LeastShardAllocationStrategySpec.CountShardsPerRegion(step))))}]");
                }
            }
            else if (round == maxSteps)
            {
                throw new AssertionFailedException($"Couldn't solve rebalance in $round rounds, [{string.Join(" => ", newSteps.Select(step => string.Join(", ", LeastShardAllocationStrategySpec.CountShardsPerRegion(step))))}]");
            }
            else
            {
                TestRebalance(allocationStrategy, newAllocations, newSteps, maxSteps);
            }
        }
        private void TestRebalance(
            IShardAllocationStrategy allocationStrategy,
            int maxRegions,
            int maxShardsPerRegion,
            int expectedMaxSteps)
        {
            foreach (var i in Enumerable.Range(1, iterationsPerTest))
            {
                iteration += 1;
                var numberOfRegions = rnd.Next(maxRegions) + 1;

                var memberArray = Enumerable.Range(1, numberOfRegions).Select(n => LeastShardAllocationStrategySpec.NewUpMember("127.0.0.1", port: n)).ToArray();
                clusterMembers = ImmutableSortedSet.Create(memberArray);//.toIndexedSeq: _ *);
                var regions = Enumerable.Range(1, numberOfRegions).Select(n => LeastShardAllocationStrategySpec.NewFakeRegion($"{iteration}-R{n}", memberArray[n - 1]));

                //var regions = Enumerable.Range(1, numberOfRegions).Select(n => Sys.ActorOf(Props.Empty, $"{iteration}-R{n}")).ToImmutableList();
                var countPerRegion = regions.ToImmutableDictionary(region => region, region => rnd.Next(maxShardsPerRegion));
                var allocations    = CreateAllocations(countPerRegion);
                TestRebalance(allocationStrategy, allocations, ImmutableList.Create(allocations), expectedMaxSteps);
                foreach (var region in regions)
                {
                    Sys.Stop(region);
                }
            }
        }
 internal static IActorRef NewFakeRegion(string idForDebug, Member member) => LeastShardAllocationStrategySpec.NewFakeRegion(idForDebug, member);
 internal static Member NewUpMember(string host, int port = 252525, AppVersion version = null) => LeastShardAllocationStrategySpec.NewUpMember(host, port, version);