public async Task Test_CanDequeue_WithTaskTypes_MultipleTypesPerDequeueCall()
        {
            DateTimeOffset refNow = mDataSource
                                    .LastPostedAt
                                    .AddMilliseconds(1);

            int expectedDequeueCount = mDataSource
                                       .NumTasksInQueue;

            string[] taskTypes = mDataSource.InQueueTaskTypes
                                 .Select(t => t.FullName)
                                 .ToArray();

            using (PostgreSqlTaskQueueConsumer taskQueue =
                       CreateTaskQueue(() => refNow))
                using (ConsumedQueuedTaskTokenChecker checker =
                           new ConsumedQueuedTaskTokenChecker(mDataSource))
                {
                    for (int i = 0; i < expectedDequeueCount; i++)
                    {
                        await Run_ConsumeTestAsync(taskQueue,
                                                   checker,
                                                   refNow,
                                                   taskTypes);
                    }
                }
        }
        public async Task Test_CanDequeue_WithTaskTypes_MultipleTypesPerDequeueCall_ParallelConsumers(int nConsumers)
        {
            int expectedDequeueCount = mDataSource
                                       .NumTasksInQueue;

            DateTimeOffset refNow = mDataSource
                                    .LastPostedAt
                                    .AddMilliseconds(1);

            string[] taskTypes = mDataSource.InQueueTaskTypes
                                 .Select(t => t.FullName)
                                 .ToArray();

            Task[] consumers = new Task[nConsumers];

            int[] loopPartitions = expectedDequeueCount
                                   .PartitionValue(nConsumers);

            Assert.AreEqual(expectedDequeueCount,
                            loopPartitions.Sum());

            for (int iConsumer = 0; iConsumer < nConsumers; iConsumer++)
            {
                int loopCount = loopPartitions[iConsumer];
                consumers[iConsumer] = Task.Run(async() =>
                {
                    using (PostgreSqlTaskQueueConsumer taskQueue =
                               CreateTaskQueue(() => refNow))
                        using (ConsumedQueuedTaskTokenChecker checker =
                                   new ConsumedQueuedTaskTokenChecker(mDataSource))
                        {
                            for (int iTest = 0; iTest < loopCount; iTest++)
                            {
                                await Run_ConsumeTestAsync(taskQueue,
                                                           checker,
                                                           refNow,
                                                           taskTypes);
                            }
                        }
                });
            }

            await Task.WhenAll(consumers);
        }
        public async Task Test_CanDequeue_WithoutTaskTypes()
        {
            DateTimeOffset refNow = mDataSource
                                    .LastPostedAt
                                    .AddMilliseconds(1);

            int expectedDequeueCount = mDataSource
                                       .NumTasksInQueue;

            using (PostgreSqlTaskQueueConsumer taskQueue =
                       CreateTaskQueue(() => refNow))
                using (ConsumedQueuedTaskTokenChecker checker =
                           new ConsumedQueuedTaskTokenChecker(mDataSource))
                {
                    for (int i = 0; i < expectedDequeueCount; i++)
                    {
                        await Run_ConsumeTestAsync(taskQueue, checker, refNow);
                    }
                }
        }
        private async Task Run_ConsumeTestAsync(PostgreSqlTaskQueueConsumer taskQueue,
                                                ConsumedQueuedTaskTokenChecker checker,
                                                DateTimeOffset refNow,
                                                params string[] payloadTypes)
        {
            IQueuedTaskToken newTaskToken;

            if (payloadTypes != null && payloadTypes.Length > 0)
            {
                newTaskToken = await taskQueue.DequeueAsync(payloadTypes);
            }
            else
            {
                newTaskToken = await taskQueue.DequeueAsync();
            }

            checker.AssertConsumedTokenValid(newTaskToken, refNow);

            await checker.AssertTaskNotInDbAnymoreAsync(newTaskToken);

            await checker.AssertTaskResultInDbAndCorrectAsync(newTaskToken);
        }
        public async Task Test_CanDequeue_WithTaskTypes_OneTypePerDequeueCall()
        {
            DateTimeOffset refNow = mDataSource
                                    .LastPostedAt
                                    .AddMilliseconds(1);

            using (PostgreSqlTaskQueueConsumer taskQueue =
                       CreateTaskQueue(() => refNow))
                using (ConsumedQueuedTaskTokenChecker checker =
                           new ConsumedQueuedTaskTokenChecker(mDataSource))
                {
                    foreach (Type taskType in mDataSource.InQueueTaskTypes)
                    {
                        int expectedDequeueCount = mDataSource.CountTasksOfTypeInQueue(taskType);
                        for (int i = 0; i < expectedDequeueCount; i++)
                        {
                            await Run_ConsumeTestAsync(taskQueue,
                                                       checker,
                                                       refNow,
                                                       taskType.FullName);
                        }
                    }
                }
        }