private async Task <RunSummary> UnitTestPipeline(int defaultMaxConcurrency, IMessageBus messageBus,
                                                         CancellationTokenSource ctx)
        {
            //make sure all clusters go in started state (won't actually start clusters in unit test mode)
            //foreach (var g in this._grouped) g.Key?.Start();

            var testFilters = CreateTestFilters(TestFilter);
            await _grouped.SelectMany(g => g)
            .ForEachAsync(defaultMaxConcurrency,
                          async g => { await RunTestCollections(messageBus, ctx, g, testFilters).ConfigureAwait(false); })
            .ConfigureAwait(false);

            //foreach (var g in this._grouped) g.Key?.Dispose();

            return(new RunSummary
            {
                Total = Summaries.Sum(s => s.Total),
                Failed = Summaries.Sum(s => s.Failed),
                Skipped = Summaries.Sum(s => s.Skipped)
            });
        }
        private async Task <RunSummary> IntegrationPipeline(int defaultMaxConcurrency, IMessageBus messageBus,
                                                            CancellationTokenSource ctx)
        {
            var testFilters = CreateTestFilters(TestFilter);

            foreach (var group in _grouped)
            {
                ElasticXunitRunner.CurrentCluster = @group.Key;
                if (@group.Key == null)
                {
                    var testCount = @group.SelectMany(q => q.TestCases).Count();
                    Console.WriteLine($" -> Several tests skipped because they have no cluster associated");
                    Summaries.Add(new RunSummary {
                        Total = testCount, Skipped = testCount
                    });
                    continue;
                }

                var type        = @group.Key.GetType();
                var clusterName = type.Name.Replace("Cluster", string.Empty) ?? "UNKNOWN";
                if (!MatchesClusterFilter(clusterName))
                {
                    continue;
                }

                var dop = @group.Key.ClusterConfiguration?.MaxConcurrency ?? defaultMaxConcurrency;
                dop = dop <= 0 ? defaultMaxConcurrency : dop;

                var timeout = @group.Key.ClusterConfiguration?.Timeout ?? TimeSpan.FromMinutes(2);

                var skipReasons = @group.SelectMany(g => g.TestCases.Select(t => t.SkipReason)).ToList();
                var allSkipped  = skipReasons.All(r => !string.IsNullOrWhiteSpace(r));
                if (allSkipped)
                {
                    Console.WriteLine($" -> All tests from {clusterName} are skipped under the current configuration");
                    Summaries.Add(new RunSummary {
                        Total = skipReasons.Count, Skipped = skipReasons.Count
                    });
                    continue;
                }

                ClusterTotals.Add(clusterName, Stopwatch.StartNew());

                bool ValidateRunningVersion()
                {
                    try
                    {
                        var t = new ValidateRunningVersion();
                        t.Run(@group.Key);
                        return(true);
                    }
                    catch (Exception)
                    {
                        return(false);
                    }
                }

                using (@group.Key)
                {
                    if (!IntegrationTestsMayUseAlreadyRunningNode || !ValidateRunningVersion())
                    {
                        @group.Key?.Start(timeout);
                    }

                    await @group.ForEachAsync(dop,
                                              async g =>
                    {
                        await RunTestCollections(messageBus, ctx, g, testFilters).ConfigureAwait(false);
                    })
                    .ConfigureAwait(false);
                }

                ClusterTotals[clusterName].Stop();
            }

            return(new RunSummary
            {
                Total = Summaries.Sum(s => s.Total),
                Failed = Summaries.Sum(s => s.Failed),
                Skipped = Summaries.Sum(s => s.Skipped)
            });
        }