private static IOrleansQueryable <TIGrain, TProperties> QueryActiveTestIndexGrains <TIGrain, TProperties>(IndexingTestRunnerBase runner)
     where TIGrain : ITestIndexGrain, IIndexableGrain where TProperties : ITestIndexProperties
 => runner.IndexFactory.GetActiveGrains <TIGrain, TProperties>();
        public static async Task <int> CountItemsStreamingIn <TIGrain, TIProperties, TQueryProp>(this IndexingTestRunnerBase runner,
                                                                                                 Func <IndexingTestRunnerBase, TQueryProp, Tuple <IOrleansQueryable <TIGrain, TIProperties>, Func <TIGrain, Task <TQueryProp> > > > queryTupleFunc,
                                                                                                 string propertyName, TQueryProp queryValue, int delayInMilliseconds = 0)
            where TIGrain : IIndexableGrain
        {
            if (delayInMilliseconds > 0)
            {
                await Task.Delay(delayInMilliseconds);
            }
            var taskCompletionSource = new TaskCompletionSource <int>();

            var queryTuple     = queryTupleFunc(runner, queryValue);
            var queryItems     = queryTuple.Item1;
            var queryPropAsync = queryTuple.Item2;

            int counter = 0;
            var _       = queryItems.ObserveResults(new QueryResultStreamObserver <TIGrain>(async entry =>
            {
                counter++;
                runner.Output.WriteLine($"grain id = {entry}, {propertyName} = {await queryPropAsync(entry)}, primary key = {entry.GetPrimaryKeyLong()}");
            }, () =>
            {
                taskCompletionSource.SetResult(counter);
                return(Task.CompletedTask);
            }));

            int observedCount = await taskCompletionSource.Task;

            Assert.Equal(observedCount, (await queryItems.GetResults()).Count());
            return(observedCount);
        }
 internal static Tuple <IOrleansQueryable <TIGrain, TProperties>, Func <TIGrain, Task <string> > > QueryByLocation <TIGrain, TProperties>(this IndexingTestRunnerBase runner, string queryValue)
     where TIGrain : IPlayerGrain, IIndexableGrain where TProperties : IPlayerProperties
 => Tuple.Create <IOrleansQueryable <TIGrain, TProperties>, Func <TIGrain, Task <string> > >(
     from item in QueryActivePlayerGrains <TIGrain, TProperties>(runner) where item.Location == queryValue select item,
     entry => entry.GetLocation());
 internal static Task <int> GetLocationCount <TIGrain, TProperties>(this IndexingTestRunnerBase runner, string location, int delayInMilliseconds = 0)
     where TIGrain : IPlayerGrain, IIndexableGrain where TProperties : IPlayerProperties
 => runner.CountItemsStreamingIn((r, v) => r.QueryByLocation <TIGrain, TProperties>(v), nameof(IPlayerProperties.Location), location, delayInMilliseconds);
 internal static Task <int> GetEmployeeIdCount <TIGrain, TProperties>(this IndexingTestRunnerBase runner, int id, int delayInMilliseconds = 0)
     where TIGrain : IEmployeeGrain, IIndexableGrain where TProperties : IEmployeeProperties
 => runner.CountItemsStreamingIn((r, v) => r.QueryByEmployeeId <TIGrain, TProperties>(v), nameof(IEmployeeProperties.EmployeeId), id, delayInMilliseconds);
 internal static Tuple <IOrleansQueryable <TIGrain, TProperties>, Func <TIGrain, Task <int> > > QueryByPlayerScoreTxn <TIGrain, TProperties>(
     this IndexingTestRunnerBase runner, int queryValue)
     where TIGrain : IPlayerGrainTransactional, IIndexableGrain where TProperties : IPlayerProperties
 => Tuple.Create <IOrleansQueryable <TIGrain, TProperties>, Func <TIGrain, Task <int> > >(
     from item in QueryActiveGrains <TIGrain, TProperties>(runner) where item.Score == queryValue select item,
     entry => entry.GetScore());
 internal static Task <int> GetPersonAgeCount <TIGrain, TProperties>(this IndexingTestRunnerBase runner, int age, int delayInMilliseconds = 0)
     where TIGrain : IPersonGrain, IIndexableGrain where TProperties : IPersonProperties
 => runner.CountItemsStreamingIn((r, v) => r.QueryByPersonAge <TIGrain, TProperties>(v), nameof(IPersonProperties.Age), age, delayInMilliseconds);
        public static async Task <int> CountItemsStreamingIn <TIGrain, TProperties, TQueryProp>(this IndexingTestRunnerBase runner,
                                                                                                Func <IndexingTestRunnerBase, TQueryProp, Tuple <IOrleansQueryable <TIGrain, TProperties>, Func <TIGrain, Task <TQueryProp> > > > queryTupleFunc,
                                                                                                string propertyName, TQueryProp queryValue, int delayInMilliseconds = 0)
            where TIGrain : IIndexableGrain
        {
            if (delayInMilliseconds > 0)
            {
                await Task.Delay(delayInMilliseconds);
            }
            var taskCompletionSource = new TaskCompletionSource <int>();

            var queryTuple     = queryTupleFunc(runner, queryValue);
            var queryItems     = queryTuple.Item1;
            var queryPropAsync = queryTuple.Item2;

            int counter = 0;
            await queryItems.ObserveResults(new QueryResultStreamObserver <TIGrain>(/*async*/ entry =>
            {
                counter++;

                // For Total indexes, the grain may not be active; querying the property will activate it. If we have a mix of Active and Total
                // indexes on a grain, this will cause the Active counts to be incorrect during testing. TODO: specify per-test whether to retrieve this
                var isActiveIndex = runner.IndexFactory.GetIndex(typeof(TIGrain), IndexUtils.PropertyNameToIndexName(propertyName)).IsActiveIndex();
                var propertyValue = /* isActiveIndex ? (await queryPropAsync(entry)).ToString() : */ "[not retrieved]";
                runner.Output.WriteLine($"grain id = {entry}, {propertyName} = {propertyValue}, primary key = {entry.GetPrimaryKeyLong()}");
                return(Task.CompletedTask);
            }, () =>
            {
                taskCompletionSource.SetResult(counter);
                return(Task.CompletedTask);
            }));

            int observedCount = await taskCompletionSource.Task;

            Assert.Equal(observedCount, (await queryItems.GetResults()).Count());
            return(observedCount);
        }
 internal static Tuple <IOrleansQueryable <TIGrain, TProperties>, Func <TIGrain, Task <string> > > QueryByJobDepartment <TIGrain, TProperties>(
     this IndexingTestRunnerBase runner, string queryValue)
     where TIGrain : IJobGrain, IIndexableGrain where TProperties : IJobProperties
 => Tuple.Create <IOrleansQueryable <TIGrain, TProperties>, Func <TIGrain, Task <string> > >(
     from item in QueryActiveGrains <TIGrain, TProperties>(runner) where queryValue == item.Department select item,
     entry => entry.GetDepartment());
 internal static Tuple <IOrleansQueryable <TIGrain, TProperties>, Func <TIGrain, Task <int> > > QueryByEmployeeId <TIGrain, TProperties>(
     this IndexingTestRunnerBase runner, int queryValue)
     where TIGrain : IEmployeeGrain, IIndexableGrain where TProperties : IEmployeeProperties
 => Tuple.Create <IOrleansQueryable <TIGrain, TProperties>, Func <TIGrain, Task <int> > >(
     from item in QueryActiveGrains <TIGrain, TProperties>(runner) where item.EmployeeId == queryValue select item,
     entry => entry.GetEmployeeId());
 internal static Tuple <IOrleansQueryable <TIGrain, TProperties>, Func <TIGrain, Task <string> > > QueryByPersonName <TIGrain, TProperties>(
     this IndexingTestRunnerBase runner, string queryValue)
     where TIGrain : IPersonGrain, IIndexableGrain where TProperties : IPersonProperties
 => Tuple.Create <IOrleansQueryable <TIGrain, TProperties>, Func <TIGrain, Task <string> > >(
     from item in QueryActiveGrains <TIGrain, TProperties>(runner) where item.Name == queryValue select item,
     entry => entry.GetName());
 internal static Task <int> GetNonUniqueStringCountTxn <TIGrain, TProperties>(this IndexingTestRunnerBase runner, string nonUniqueValue, int delayInMilliseconds = 0)
     where TIGrain : ITestMultiIndexGrainTransactional, IIndexableGrain where TProperties : ITestMultiIndexProperties
 => runner.CountItemsStreamingIn((r, v) => r.QueryByNonUniqueStringTxn <TIGrain, TProperties>(v), nameof(ITestMultiIndexProperties.NonUniqueString), nonUniqueValue, delayInMilliseconds);
 internal static Tuple <IOrleansQueryable <TIGrain, TProperties>, Func <TIGrain, Task <int> > > QueryByNonUniqueIntTxn <TIGrain, TProperties>(this IndexingTestRunnerBase runner, int queryValue)
     where TIGrain : ITestMultiIndexGrainTransactional, IIndexableGrain where TProperties : ITestMultiIndexProperties
 => Tuple.Create <IOrleansQueryable <TIGrain, TProperties>, Func <TIGrain, Task <int> > >(
     from item in QueryActiveGrains <TIGrain, TProperties>(runner) where queryValue == item.NonUniqueInt select item,
     entry => entry.GetNonUniqueInt());
 internal static Tuple <IOrleansQueryable <TIGrain, TProperties>, Func <TIGrain, Task <string> > > QueryByNonUniqueString <TIGrain, TProperties>(this IndexingTestRunnerBase runner, string queryValue)
     where TIGrain : ITestIndexGrain, IIndexableGrain where TProperties : ITestIndexProperties
 => Tuple.Create <IOrleansQueryable <TIGrain, TProperties>, Func <TIGrain, Task <string> > >(
     from item in QueryActiveTestIndexGrains <TIGrain, TProperties>(runner) where item.NonUniqueString == queryValue select item,
     entry => entry.GetNonUniqueString());
 internal static Task <int> GetJobDepartmentCount <TIGrain, TProperties>(this IndexingTestRunnerBase runner, string department, int delayInMilliseconds = 0)
     where TIGrain : IJobGrain, IIndexableGrain where TProperties : IJobProperties
 => runner.CountItemsStreamingIn((r, v) => r.QueryByJobDepartment <TIGrain, TProperties>(v), nameof(IJobProperties.Department), department, delayInMilliseconds);
 internal static Task <int> GetUniqueIntCount <TIGrain, TProperties>(this IndexingTestRunnerBase runner, int uniqueValue, int delayInMilliseconds = 0)
     where TIGrain : ITestIndexGrain, IIndexableGrain where TProperties : ITestIndexProperties
 => runner.CountItemsStreamingIn((r, v) => r.QueryByUniqueInt <TIGrain, TProperties>(v), nameof(ITestIndexProperties.UniqueInt), uniqueValue, delayInMilliseconds);
 internal static Task <int> GetPlayerScoreCountTxn <TIGrain, TProperties>(this IndexingTestRunnerBase runner, int score, int delayInMilliseconds = 0)
     where TIGrain : IPlayerGrainTransactional, IIndexableGrain where TProperties : IPlayerProperties
 => runner.CountItemsStreamingIn((r, v) => r.QueryByPlayerScoreTxn <TIGrain, TProperties>(v), nameof(IPlayerProperties.Score), score, delayInMilliseconds);