chromium/base/test/task_environment_unittest.cc

// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/test/task_environment.h"

#include <atomic>
#include <memory>
#include <string_view>

#include "base/atomicops.h"
#include "base/cancelable_callback.h"
#include "base/check.h"
#include "base/debug/debugger.h"
#include "base/functional/bind.h"
#include "base/functional/callback_forward.h"
#include "base/functional/callback_helpers.h"
#include "base/logging.h"
#include "base/run_loop.h"
#include "base/strings/string_number_conversions.h"
#include "base/synchronization/atomic_flag.h"
#include "base/synchronization/waitable_event.h"
#include "base/task/current_thread.h"
#include "base/task/sequence_manager/time_domain.h"
#include "base/task/sequenced_task_runner.h"
#include "base/task/single_thread_task_runner.h"
#include "base/task/thread_pool.h"
#include "base/task/thread_pool/thread_pool_instance.h"
#include "base/test/bind.h"
#include "base/test/gtest_util.h"
#include "base/test/mock_callback.h"
#include "base/test/mock_log.h"
#include "base/test/scoped_run_loop_timeout.h"
#include "base/test/test_timeouts.h"
#include "base/test/test_waitable_event.h"
#include "base/threading/platform_thread.h"
#include "base/threading/sequence_bound.h"
#include "base/threading/sequence_local_storage_slot.h"
#include "base/threading/thread.h"
#include "base/time/clock.h"
#include "base/time/default_clock.h"
#include "base/time/tick_clock.h"
#include "base/time/time.h"
#include "base/win/com_init_util.h"
#include "build/build_config.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest-spi.h"
#include "testing/gtest/include/gtest/gtest.h"

#if BUILDFLAG(IS_POSIX)
#include <unistd.h>

#include "base/files/file_descriptor_watcher_posix.h"
#endif  // BUILDFLAG(IS_POSIX)

#if BUILDFLAG(IS_WIN)
#include "base/win/scoped_com_initializer.h"
#endif

namespace base {
namespace test {

namespace {

_;
HasSubstr;
IsNull;
Not;
Return;

class TaskEnvironmentTest : public testing::Test {};

void VerifyRunUntilIdleDidNotReturnAndSetFlag(
    AtomicFlag* run_until_idle_returned,
    AtomicFlag* task_ran) {}

void RunUntilIdleTest(
    TaskEnvironment::ThreadPoolExecutionMode thread_pool_execution_mode) {}

}  // namespace

TEST_F(TaskEnvironmentTest, QueuedRunUntilIdle) {}

TEST_F(TaskEnvironmentTest, AsyncRunUntilIdle) {}

// Verify that tasks posted to an ThreadPoolExecutionMode::QUEUED
// TaskEnvironment do not run outside of RunUntilIdle().
TEST_F(TaskEnvironmentTest, QueuedTasksDoNotRunOutsideOfRunUntilIdle) {}

// Verify that a task posted to an ThreadPoolExecutionMode::ASYNC
// TaskEnvironment can run without a call to RunUntilIdle().
TEST_F(TaskEnvironmentTest, AsyncTasksRunAsTheyArePosted) {}

// Verify that a task posted to an ThreadPoolExecutionMode::ASYNC
// TaskEnvironment after a call to RunUntilIdle() can run without another
// call to RunUntilIdle().
TEST_F(TaskEnvironmentTest, AsyncTasksRunAsTheyArePostedAfterRunUntilIdle) {}

void DelayedTasksTest(TaskEnvironment::TimeSource time_source) {}

TEST_F(TaskEnvironmentTest, DelayedTasksUnderSystemTime) {}

TEST_F(TaskEnvironmentTest, DelayedTasksUnderMockTime) {}

// Regression test for https://crbug.com/824770.
void SupportsSequenceLocalStorageOnMainThreadTest(
    TaskEnvironment::TimeSource time_source) {}

TEST_F(TaskEnvironmentTest, SupportsSequenceLocalStorageOnMainThread) {}

TEST_F(TaskEnvironmentTest,
       SupportsSequenceLocalStorageOnMainThreadWithMockTime) {}

// Verify that the right MessagePump is instantiated under each MainThreadType.
// This avoids having to run all other TaskEnvironmentTests in every
// MainThreadType which is redundant (message loop and message pump tests
// otherwise cover the advanced functionality provided by UI/IO pumps).
TEST_F(TaskEnvironmentTest, MainThreadType) {}

#if BUILDFLAG(IS_POSIX)
TEST_F(TaskEnvironmentTest, SupportsFileDescriptorWatcherOnIOMainThread) {}

TEST_F(TaskEnvironmentTest,
       SupportsFileDescriptorWatcherOnIOMockTimeMainThread) {}
#endif  // BUILDFLAG(IS_POSIX)

TEST_F(TaskEnvironmentTest, MockTimeStartsWithWholeMilliseconds) {}

// Verify that the TickClock returned by
// |TaskEnvironment::GetMockTickClock| gets updated when the
// FastForward(By|UntilNoTasksRemain) functions are called.
TEST_F(TaskEnvironmentTest, FastForwardAdvancesTickClock) {}

TEST_F(TaskEnvironmentTest, FastForwardAdvancesMockClock) {}

TEST_F(TaskEnvironmentTest, FastForwardAdvancesTime) {}

TEST_F(TaskEnvironmentTest, FastForwardAdvancesTimeTicks) {}

TEST_F(TaskEnvironmentTest, AdvanceClockAdvancesTickClock) {}

TEST_F(TaskEnvironmentTest, AdvanceClockAdvancesMockClock) {}

TEST_F(TaskEnvironmentTest, AdvanceClockAdvancesTime) {}

TEST_F(TaskEnvironmentTest, AdvanceClockAdvancesTimeTicks) {}

TEST_F(TaskEnvironmentTest, AdvanceClockAdvancesLiveTicks) {}

TEST_F(TaskEnvironmentTest, SuspendedAdvanceClockDoesntAdvanceLiveTicks) {}

TEST_F(TaskEnvironmentTest, AdvanceClockDoesNotRunTasks) {}

TEST_F(TaskEnvironmentTest, SuspendedAdvanceClockDoesNotRunTasks) {}

TEST_F(TaskEnvironmentTest, AdvanceClockSchedulesRipeDelayedTasks) {}

TEST_F(TaskEnvironmentTest, SuspendedAdvanceClockSchedulesRipeDelayedTasks) {}

// Verify that FastForwardBy() runs existing immediate tasks before advancing,
// then advances to the next delayed task, runs it, then advances the remainder
// of time when out of tasks.
TEST_F(TaskEnvironmentTest, FastForwardOnlyAdvancesWhenIdle) {}

// Verify that SuspendedFastForwardBy() behaves as FastForwardBy() but doesn't
// advance `LiveTicks`
TEST_F(TaskEnvironmentTest, SuspendedFastForwardOnlyAdvancesWhenIdle) {}

// FastForwardBy(0) should be equivalent of RunUntilIdle().
TEST_F(TaskEnvironmentTest, FastForwardZero) {}

TEST_F(TaskEnvironmentTest, NestedFastForwardBy) {}

TEST_F(TaskEnvironmentTest, NestedRunInFastForwardBy) {}

TEST_F(TaskEnvironmentTest,
       CrossThreadImmediateTaskPostingDoesntAffectMockTime) {}

TEST_F(TaskEnvironmentTest, MultiThreadedMockTime) {}

// This test ensures the implementation of FastForwardBy() doesn't fast-forward
// beyond the cap it reaches idle with pending delayed tasks further ahead on
// the main thread.
TEST_F(TaskEnvironmentTest, MultiThreadedFastForwardBy) {}

// Verify that ThreadPoolExecutionMode::QUEUED doesn't prevent running tasks and
// advancing time on the main thread.
TEST_F(TaskEnvironmentTest, MultiThreadedMockTimeAndThreadPoolQueuedMode) {}

#if BUILDFLAG(IS_WIN)
// Regression test to ensure that TaskEnvironment enables the MTA in the
// thread pool (so that the test environment matches that of the browser process
// and com_init_util.h's assertions are happy in unit tests).
TEST_F(TaskEnvironmentTest, ThreadPoolPoolAllowsMTA) {
  TaskEnvironment task_environment;
  ThreadPool::PostTask(FROM_HERE, BindOnce(&win::AssertComApartmentType,
                                           win::ComApartmentType::MTA));
  task_environment.RunUntilIdle();
}
#endif  // BUILDFLAG(IS_WIN)

TEST_F(TaskEnvironmentTest, SetsDefaultRunTimeout) {}

TEST_F(TaskEnvironmentTest, DescribeCurrentTasksHasPendingMainThreadTasks) {}

TEST_F(TaskEnvironmentTest, DescribeCurrentTasksHasThreadPoolTasks) {}

TEST_F(TaskEnvironmentTest, Basic) {}

TEST_F(TaskEnvironmentTest, RunLoopDriveable) {}

// Regression test for crbug.com/1263149
TEST_F(TaskEnvironmentTest, RunLoopGetsTurnAfterYieldingToPool) {}

// Regression test for crbug.com/1263149#c4
TEST_F(TaskEnvironmentTest, ThreadPoolAdvancesTimeUnderIdleMainThread) {}

// Regression test for
// https://chromium-review.googlesource.com/c/chromium/src/+/3255105/5 which
// incorrectly tried to address crbug.com/1263149 with
// ThreadPool::FlushForTesting(), stalling thread pool tasks that need main
// thread collaboration.
TEST_F(TaskEnvironmentTest, MainThreadCanContributeWhileFlushingPool) {}

TEST_F(TaskEnvironmentTest, CancelPendingTask) {}

TEST_F(TaskEnvironmentTest, CancelPendingImmediateTask) {}

TEST_F(TaskEnvironmentTest, NoFastForwardToCancelledTask) {}

TEST_F(TaskEnvironmentTest, NextTaskIsDelayed) {}

TEST_F(TaskEnvironmentTest, NextMainThreadPendingTaskDelayWithImmediateTask) {}

TEST_F(TaskEnvironmentTest, TimeSourceMockTimeAlsoMocksNow) {}

TEST_F(TaskEnvironmentTest, SingleThread) {}

// Verify that traits other than ThreadingMode can be applied to
// SingleThreadTaskEnvironment.
TEST_F(TaskEnvironmentTest, SingleThreadMockTime) {}

#if BUILDFLAG(IS_WIN)
namespace {

enum class ApartmentType {
  kSTA,
  kMTA,
};

void InitializeSTAApartment() {
  base::win::ScopedCOMInitializer initializer;
  EXPECT_TRUE(initializer.Succeeded());
}

void InitializeMTAApartment() {
  base::win::ScopedCOMInitializer initializer(
      base::win::ScopedCOMInitializer::kMTA);
  EXPECT_TRUE(initializer.Succeeded());
}

void InitializeCOMOnWorker(
    TaskEnvironment::ThreadPoolCOMEnvironment com_environment,
    ApartmentType apartment_type) {
  TaskEnvironment task_environment(com_environment);
  ThreadPool::PostTask(FROM_HERE, BindOnce(apartment_type == ApartmentType::kSTA
                                               ? &InitializeSTAApartment
                                               : &InitializeMTAApartment));
  task_environment.RunUntilIdle();
}

}  // namespace

TEST_F(TaskEnvironmentTest, DefaultCOMEnvironment) {
  // Attempt to initialize an MTA COM apartment. Expect this to succeed since
  // the thread is already in an MTA apartment.
  InitializeCOMOnWorker(TaskEnvironment::ThreadPoolCOMEnvironment::DEFAULT,
                        ApartmentType::kMTA);

  // Attempt to initialize an STA COM apartment. Expect this to fail since the
  // thread is already in an MTA apartment.
  EXPECT_DCHECK_DEATH(InitializeCOMOnWorker(
      TaskEnvironment::ThreadPoolCOMEnvironment::DEFAULT, ApartmentType::kSTA));
}

TEST_F(TaskEnvironmentTest, NoCOMEnvironment) {
  // Attempt to initialize both MTA and STA COM apartments. Both should succeed
  // when the thread is not already in an apartment.
  InitializeCOMOnWorker(TaskEnvironment::ThreadPoolCOMEnvironment::NONE,
                        ApartmentType::kMTA);
  InitializeCOMOnWorker(TaskEnvironment::ThreadPoolCOMEnvironment::NONE,
                        ApartmentType::kSTA);
}
#endif  // BUILDFLAG(IS_WIN)

// TODO(crbug.com/40835641): Re-enable this test
#if BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_LINUX)
#define MAYBE_ParallelExecutionFence
#else
#define MAYBE_ParallelExecutionFence
#endif
TEST_F(TaskEnvironmentTest, MAYBE_ParallelExecutionFence) {}

TEST_F(TaskEnvironmentTest, ParallelExecutionFenceWithoutTaskEnvironment) {}

TEST_F(TaskEnvironmentTest,
       ParallelExecutionFenceWithSingleThreadTaskEnvironment) {}

// Android doesn't support death tests, see base/test/gtest_util.h
#if !BUILDFLAG(IS_ANDROID)
TEST_F(TaskEnvironmentTest, ParallelExecutionFenceNonMainThreadDeath) {}
#endif  // !BUILDFLAG(IS_ANDROID)

namespace {
bool FailOnTaskEnvironmentLog(int severity,
                              const char* file,
                              int line,
                              size_t message_start,
                              const std::string& str) {}
}  // namespace

// Regression test for crbug.com/1293931
TEST_F(TaskEnvironmentTest, DisallowRunTasksRetriesForFullTimeout) {}

TEST_F(TaskEnvironmentTest, RunUntilQuit_RunsMainThread) {}

TEST_F(TaskEnvironmentTest, RunUntilQuit_RunsThreadPool) {}

namespace {

class TestLogger {};

}  // namespace

TEST_F(TaskEnvironmentTest, RunUntilQuit_QueuedExecution) {}

TEST_F(TaskEnvironmentTest, RunUntilQuit_ThreadPoolStaysQueued) {}

TEST_F(TaskEnvironmentTest, RunUntilQuit_QuitClosureInvalidatedByRun) {}

TEST_F(TaskEnvironmentTest, RunUntilQuit_MustCallQuitClosureFirst) {}

}  // namespace test
}  // namespace base