blob: 3817cbc09d7b8e79ec80465867968a883eaba777 [file] [log] [blame]
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/browser/scheduler/responsiveness/metric_source.h"
#include <atomic>
#include "base/bind_helpers.h"
#include "base/test/bind_test_util.h"
#include "content/browser/scheduler/responsiveness/native_event_observer.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/test/browser_task_environment.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace content {
namespace responsiveness {
namespace {
class FakeDelegate : public MetricSource::Delegate {
public:
FakeDelegate()
: set_up_on_io_thread_(false),
tear_down_on_io_thread_(false),
will_run_task_on_io_thread_(0),
did_run_task_on_io_thread_(0) {}
~FakeDelegate() override = default;
void SetUpOnIOThread() override { set_up_on_io_thread_ = true; }
void TearDownOnUIThread() override { tear_down_on_ui_thread_ = true; }
void TearDownOnIOThread() override { tear_down_on_io_thread_ = true; }
void WillRunTaskOnUIThread(const base::PendingTask* task,
bool /* was_blocked_or_low_priority */) override {
will_run_task_on_ui_thread_++;
}
void DidRunTaskOnUIThread(const base::PendingTask* task) override {
did_run_task_on_ui_thread_++;
}
void WillRunTaskOnIOThread(const base::PendingTask* task,
bool /* was_blocked_or_low_priority */) override {
will_run_task_on_io_thread_++;
}
void DidRunTaskOnIOThread(const base::PendingTask* task) override {
did_run_task_on_io_thread_++;
}
void WillRunEventOnUIThread(const void* opaque_identifier) override {}
void DidRunEventOnUIThread(const void* opaque_identifier) override {}
bool set_up_on_io_thread() { return set_up_on_io_thread_; }
bool tear_down_on_ui_thread() { return tear_down_on_ui_thread_; }
bool tear_down_on_io_thread() { return tear_down_on_io_thread_; }
int will_run_task_on_ui_thread() { return will_run_task_on_ui_thread_; }
int did_run_task_on_ui_thread() { return did_run_task_on_ui_thread_; }
int will_run_task_on_io_thread() { return will_run_task_on_io_thread_; }
int did_run_task_on_io_thread() { return did_run_task_on_io_thread_; }
private:
std::atomic_bool set_up_on_io_thread_;
bool tear_down_on_ui_thread_ = false;
std::atomic_bool tear_down_on_io_thread_;
int will_run_task_on_ui_thread_ = 0;
int did_run_task_on_ui_thread_ = 0;
std::atomic_int will_run_task_on_io_thread_;
std::atomic_int did_run_task_on_io_thread_;
};
class TestMetricSource : public MetricSource {
public:
TestMetricSource(MetricSource::Delegate* delegate,
base::OnceClosure on_destroyed = base::DoNothing())
: MetricSource(delegate), on_destroyed_(std::move(on_destroyed)) {}
std::unique_ptr<NativeEventObserver> CreateNativeEventObserver() override {
return nullptr;
}
~TestMetricSource() override {
DCHECK(on_destroyed_);
std::move(on_destroyed_).Run();
}
private:
base::OnceClosure on_destroyed_;
};
} // namespace
class ResponsivenessMetricSourceTest : public testing::Test {
public:
ResponsivenessMetricSourceTest()
: task_environment_(base::test::TaskEnvironment::MainThreadType::UI,
content::BrowserTaskEnvironment::REAL_IO_THREAD) {}
void SetUp() override { task_environment_.RunIOThreadUntilIdle(); }
void TearDown() override {
// Destroy a task onto the IO thread, which posts back to the UI thread
// to complete destruction.
task_environment_.RunIOThreadUntilIdle();
task_environment_.RunUntilIdle();
}
protected:
// This member sets up BrowserThread::IO and BrowserThread::UI. It must be the
// first member, as other members may depend on these abstractions.
content::BrowserTaskEnvironment task_environment_;
};
TEST_F(ResponsivenessMetricSourceTest, SetUpTearDown) {
std::unique_ptr<FakeDelegate> delegate = std::make_unique<FakeDelegate>();
std::unique_ptr<TestMetricSource> metric_source =
std::make_unique<TestMetricSource>(delegate.get());
EXPECT_FALSE(delegate->set_up_on_io_thread());
EXPECT_FALSE(delegate->tear_down_on_ui_thread());
EXPECT_FALSE(delegate->tear_down_on_io_thread());
metric_source->SetUp();
// Test SetUpOnIOThread() is called after running the IO thread RunLoop.
task_environment_.RunIOThreadUntilIdle();
EXPECT_TRUE(delegate->set_up_on_io_thread());
task_environment_.RunUntilIdle();
base::ScopedClosureRunner on_finish_destroy(
base::BindLambdaForTesting([&]() { metric_source = nullptr; }));
metric_source->Destroy(std::move(on_finish_destroy));
// Run IO thread to test TearDownOnIOThread().
task_environment_.RunIOThreadUntilIdle();
EXPECT_TRUE(delegate->tear_down_on_io_thread());
EXPECT_FALSE(delegate->tear_down_on_ui_thread());
// Run the UI thread to test TearDownOnUIThread().
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(delegate->tear_down_on_ui_thread());
EXPECT_FALSE(metric_source);
}
// Test that the task callbacks are correctly called on UI and IO threads.
TEST_F(ResponsivenessMetricSourceTest, RunTasks) {
std::unique_ptr<FakeDelegate> delegate = std::make_unique<FakeDelegate>();
std::unique_ptr<TestMetricSource> metric_source =
std::make_unique<TestMetricSource>(delegate.get());
metric_source->SetUp();
task_environment_.RunIOThreadUntilIdle();
task_environment_.RunUntilIdle();
content::GetUIThreadTaskRunner({})->PostTask(FROM_HERE, base::DoNothing());
task_environment_.RunUntilIdle();
EXPECT_GT(delegate->will_run_task_on_ui_thread(), 0);
EXPECT_GT(delegate->did_run_task_on_ui_thread(), 0);
content::GetIOThreadTaskRunner({})->PostTask(FROM_HERE, base::DoNothing());
task_environment_.RunUntilIdle();
EXPECT_GT(delegate->will_run_task_on_io_thread(), 0);
EXPECT_GT(delegate->did_run_task_on_io_thread(), 0);
base::ScopedClosureRunner on_finish_destroy(
base::BindLambdaForTesting([&]() { metric_source = nullptr; }));
metric_source->Destroy(std::move(on_finish_destroy));
task_environment_.RunIOThreadUntilIdle();
task_environment_.RunUntilIdle();
EXPECT_FALSE(metric_source);
}
} // namespace responsiveness
} // namespace content