Commit 27450add authored by Evan Shrubsole's avatar Evan Shrubsole Committed by Commit Bot

Unflake FakeAudioWorkerTest::TimeBetweenCallbacks

Uses the ScopedTestEnvironment to switch to using mock time.
This makes the test deterministic

Bug: 960729
Change-Id: If5a9c55bd44127f9bada0eba324618577af3119e
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1660338
Commit-Queue: Evan Shrubsole <eshr@google.com>
Reviewed-by: default avatarMax Morin <maxmorin@chromium.org>
Cr-Commit-Position: refs/heads/master@{#669672}
parent 20cea9c8
...@@ -3,14 +3,18 @@ ...@@ -3,14 +3,18 @@
// found in the LICENSE file. // found in the LICENSE file.
#include "media/base/fake_audio_worker.h" #include "media/base/fake_audio_worker.h"
#include <vector>
#include "base/bind.h" #include "base/bind.h"
#include "base/macros.h" #include "base/macros.h"
#include "base/run_loop.h" #include "base/memory/scoped_refptr.h"
#include "base/single_thread_task_runner.h" #include "base/single_thread_task_runner.h"
#include "base/test/scoped_task_environment.h" #include "base/test/scoped_task_environment.h"
#include "base/time/time.h" #include "base/time/time.h"
#include "build/build_config.h" #include "build/build_config.h"
#include "media/base/audio_parameters.h" #include "media/base/audio_parameters.h"
#include "testing/gmock/include/gmock/gmock-matchers.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
namespace media { namespace media {
...@@ -22,8 +26,7 @@ class FakeAudioWorkerTest : public testing::Test { ...@@ -22,8 +26,7 @@ class FakeAudioWorkerTest : public testing::Test {
FakeAudioWorkerTest() FakeAudioWorkerTest()
: params_(AudioParameters::AUDIO_FAKE, CHANNEL_LAYOUT_STEREO, 44100, 128), : params_(AudioParameters::AUDIO_FAKE, CHANNEL_LAYOUT_STEREO, 44100, 128),
fake_worker_(scoped_task_environment_.GetMainThreadTaskRunner(), fake_worker_(scoped_task_environment_.GetMainThreadTaskRunner(),
params_), params_) {
seen_callbacks_(0) {
time_between_callbacks_ = base::TimeDelta::FromMicroseconds( time_between_callbacks_ = base::TimeDelta::FromMicroseconds(
params_.frames_per_buffer() * base::Time::kMicrosecondsPerSecond / params_.frames_per_buffer() * base::Time::kMicrosecondsPerSecond /
static_cast<float>(params_.sample_rate())); static_cast<float>(params_.sample_rate()));
...@@ -32,73 +35,68 @@ class FakeAudioWorkerTest : public testing::Test { ...@@ -32,73 +35,68 @@ class FakeAudioWorkerTest : public testing::Test {
~FakeAudioWorkerTest() override = default; ~FakeAudioWorkerTest() override = default;
void CalledByFakeWorker(base::TimeTicks ideal_time, base::TimeTicks now) { void CalledByFakeWorker(base::TimeTicks ideal_time, base::TimeTicks now) {
seen_callbacks_++; callbacks_.push_back(base::TimeTicks::Now());
} }
void RunOnAudioThread() { void RunOnAudioThread() {
ASSERT_TRUE(scoped_task_environment_.GetMainThreadTaskRunner() ASSERT_TRUE(TaskRunner()->BelongsToCurrentThread());
->BelongsToCurrentThread());
fake_worker_.Start(base::BindRepeating( fake_worker_.Start(base::BindRepeating(
&FakeAudioWorkerTest::CalledByFakeWorker, base::Unretained(this))); &FakeAudioWorkerTest::CalledByFakeWorker, base::Unretained(this)));
} }
void RunOnceOnAudioThread() { void RunOnceOnAudioThread() {
ASSERT_TRUE(scoped_task_environment_.GetMainThreadTaskRunner() ASSERT_TRUE(TaskRunner()->BelongsToCurrentThread());
->BelongsToCurrentThread());
RunOnAudioThread(); RunOnAudioThread();
// Start() should immediately post a task to run the callback, so we // Start() should immediately post a task to run the callback, so we
// should end up with only a single callback being run. // should end up with only a single callback being run.
scoped_task_environment_.GetMainThreadTaskRunner()->PostTask( TaskRunner()->PostTask(FROM_HERE,
FROM_HERE, base::BindOnce(&FakeAudioWorkerTest::EndTest, base::BindOnce(&FakeAudioWorkerTest::EndTest,
base::Unretained(this), 1)); base::Unretained(this), 1));
} }
void StopStartOnAudioThread() { void StopStartOnAudioThread() {
ASSERT_TRUE(scoped_task_environment_.GetMainThreadTaskRunner() ASSERT_TRUE(TaskRunner()->BelongsToCurrentThread());
->BelongsToCurrentThread());
fake_worker_.Stop(); fake_worker_.Stop();
RunOnAudioThread(); RunOnAudioThread();
} }
void TimeCallbacksOnAudioThread(int callbacks) { void TimeCallbacksOnAudioThread(size_t callbacks) {
ASSERT_TRUE(scoped_task_environment_.GetMainThreadTaskRunner() ASSERT_TRUE(TaskRunner()->BelongsToCurrentThread());
->BelongsToCurrentThread());
if (seen_callbacks_ == 0) { if (callbacks_.size() == 0) {
RunOnAudioThread(); RunOnAudioThread();
start_time_ = base::TimeTicks::Now();
} }
// Keep going until we've seen the requested number of callbacks. // Keep going until we've seen the requested number of callbacks.
if (seen_callbacks_ < callbacks) { if (callbacks_.size() < callbacks) {
scoped_task_environment_.GetMainThreadTaskRunner()->PostDelayedTask( TaskRunner()->PostDelayedTask(
FROM_HERE, FROM_HERE,
base::BindOnce(&FakeAudioWorkerTest::TimeCallbacksOnAudioThread, base::BindOnce(&FakeAudioWorkerTest::TimeCallbacksOnAudioThread,
base::Unretained(this), callbacks), base::Unretained(this), callbacks),
time_between_callbacks_ / 2); time_between_callbacks_ / 2);
} else { } else {
end_time_ = base::TimeTicks::Now();
EndTest(callbacks); EndTest(callbacks);
} }
} }
void EndTest(int callbacks) { void EndTest(size_t callbacks) {
ASSERT_TRUE(scoped_task_environment_.GetMainThreadTaskRunner() ASSERT_TRUE(TaskRunner()->BelongsToCurrentThread());
->BelongsToCurrentThread());
fake_worker_.Stop(); fake_worker_.Stop();
EXPECT_LE(callbacks, seen_callbacks_); EXPECT_LE(callbacks, callbacks_.size());
run_loop_.QuitWhenIdle(); }
scoped_refptr<base::SingleThreadTaskRunner> TaskRunner() {
return scoped_task_environment_.GetMainThreadTaskRunner();
} }
protected: protected:
base::test::ScopedTaskEnvironment scoped_task_environment_; base::test::ScopedTaskEnvironment scoped_task_environment_{
base::RunLoop run_loop_; base::test::ScopedTaskEnvironment::MainThreadType::MOCK_TIME,
base::test::ScopedTaskEnvironment::NowSource::MAIN_THREAD_MOCK_TIME};
AudioParameters params_; AudioParameters params_;
FakeAudioWorker fake_worker_; FakeAudioWorker fake_worker_;
base::TimeTicks start_time_;
base::TimeTicks end_time_;
base::TimeDelta time_between_callbacks_; base::TimeDelta time_between_callbacks_;
int seen_callbacks_; std::vector<base::TimeTicks> callbacks_;
private: private:
DISALLOW_COPY_AND_ASSIGN(FakeAudioWorkerTest); DISALLOW_COPY_AND_ASSIGN(FakeAudioWorkerTest);
...@@ -115,53 +113,52 @@ TEST_F(FakeAudioWorkerTest, MAYBE_FakeBasicCallback) { ...@@ -115,53 +113,52 @@ TEST_F(FakeAudioWorkerTest, MAYBE_FakeBasicCallback) {
scoped_task_environment_.GetMainThreadTaskRunner()->PostTask( scoped_task_environment_.GetMainThreadTaskRunner()->PostTask(
FROM_HERE, base::BindOnce(&FakeAudioWorkerTest::RunOnceOnAudioThread, FROM_HERE, base::BindOnce(&FakeAudioWorkerTest::RunOnceOnAudioThread,
base::Unretained(this))); base::Unretained(this)));
run_loop_.Run(); scoped_task_environment_.RunUntilIdle();
} }
// Ensure the time between callbacks is sane. // Ensure the time between callbacks is correct.
// TEST_F(FakeAudioWorkerTest, TimeBetweenCallbacks) {
// TODO(https://crbug.com/960729): Test is flaky because its behavior depends on TaskRunner()->PostTask(
// real wallclock time. Need to mock time to fix this.
TEST_F(FakeAudioWorkerTest, DISABLED_TimeBetweenCallbacks) {
scoped_task_environment_.GetMainThreadTaskRunner()->PostTask(
FROM_HERE, FROM_HERE,
base::BindOnce(&FakeAudioWorkerTest::TimeCallbacksOnAudioThread, base::BindOnce(&FakeAudioWorkerTest::TimeCallbacksOnAudioThread,
base::Unretained(this), kTestCallbacks)); base::Unretained(this), kTestCallbacks));
run_loop_.Run(); scoped_task_environment_.FastForwardUntilNoTasksRemain();
// There are only (kTestCallbacks - 1) intervals between kTestCallbacks. // There are only (kTestCallbacks - 1) intervals between kTestCallbacks.
base::TimeDelta actual_time_between_callbacks = base::TimeTicks start_time = callbacks_.front();
(end_time_ - start_time_) / (seen_callbacks_ - 1); std::vector<base::TimeTicks> expected_callback_times;
for (size_t i = 0; i < callbacks_.size(); i++) {
base::TimeTicks expected = start_time + time_between_callbacks_ * i;
expected_callback_times.push_back(expected);
}
// Ensure callback time is no faster than the expected time between callbacks. std::vector<int64_t> time_between_callbacks;
EXPECT_GE(actual_time_between_callbacks, time_between_callbacks_); for (size_t i = 0; i < callbacks_.size() - 1; i++) {
time_between_callbacks.push_back(
(callbacks_.at(i + 1) - callbacks_.at(i)).InMilliseconds());
}
// Softly check if the callback time is no slower than twice the expected time EXPECT_THAT(time_between_callbacks,
// between callbacks. Since this test runs on the bots we can't be too strict testing::Each(time_between_callbacks_.InMilliseconds()));
// with the bounds.
if (actual_time_between_callbacks > 2 * time_between_callbacks_)
LOG(ERROR) << "Time between fake audio callbacks is too large!";
} }
// Ensure Start()/Stop() on the worker doesn't generate too many callbacks. See // Ensure Start()/Stop() on the worker doesn't generate too many callbacks. See
// http://crbug.com/159049. // http://crbug.com/159049.
// Flaky test; see crbug.com/974078 // Flaky test; see crbug.com/974078
TEST_F(FakeAudioWorkerTest, DISABLED_StartStopClearsCallbacks) { TEST_F(FakeAudioWorkerTest, DISABLED_StartStopClearsCallbacks) {
scoped_task_environment_.GetMainThreadTaskRunner()->PostTask( TaskRunner()->PostTask(
FROM_HERE, FROM_HERE,
base::BindOnce(&FakeAudioWorkerTest::TimeCallbacksOnAudioThread, base::BindOnce(&FakeAudioWorkerTest::TimeCallbacksOnAudioThread,
base::Unretained(this), kTestCallbacks)); base::Unretained(this), kTestCallbacks));
// Issue a Stop() / Start() in between expected callbacks to maximize the // Issue a Stop() / Start() in between expected callbacks to maximize the
// chance of catching the worker doing the wrong thing. // chance of catching the worker doing the wrong thing.
scoped_task_environment_.GetMainThreadTaskRunner()->PostDelayedTask( scoped_task_environment_.FastForwardBy(time_between_callbacks_ / 2);
FROM_HERE, TaskRunner()->PostTask(
base::BindOnce(&FakeAudioWorkerTest::StopStartOnAudioThread, FROM_HERE, base::BindOnce(&FakeAudioWorkerTest::StopStartOnAudioThread,
base::Unretained(this)), base::Unretained(this)));
time_between_callbacks_ / 2);
// EndTest() will ensure the proper number of callbacks have occurred. // EndTest() will ensure the proper number of callbacks have occurred.
run_loop_.Run(); scoped_task_environment_.FastForwardUntilNoTasksRemain();
} }
} // namespace media } // namespace media
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment