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 @@
// found in the LICENSE file.
#include "media/base/fake_audio_worker.h"
#include <vector>
#include "base/bind.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/test/scoped_task_environment.h"
#include "base/time/time.h"
#include "build/build_config.h"
#include "media/base/audio_parameters.h"
#include "testing/gmock/include/gmock/gmock-matchers.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace media {
......@@ -22,8 +26,7 @@ class FakeAudioWorkerTest : public testing::Test {
FakeAudioWorkerTest()
: params_(AudioParameters::AUDIO_FAKE, CHANNEL_LAYOUT_STEREO, 44100, 128),
fake_worker_(scoped_task_environment_.GetMainThreadTaskRunner(),
params_),
seen_callbacks_(0) {
params_) {
time_between_callbacks_ = base::TimeDelta::FromMicroseconds(
params_.frames_per_buffer() * base::Time::kMicrosecondsPerSecond /
static_cast<float>(params_.sample_rate()));
......@@ -32,73 +35,68 @@ class FakeAudioWorkerTest : public testing::Test {
~FakeAudioWorkerTest() override = default;
void CalledByFakeWorker(base::TimeTicks ideal_time, base::TimeTicks now) {
seen_callbacks_++;
callbacks_.push_back(base::TimeTicks::Now());
}
void RunOnAudioThread() {
ASSERT_TRUE(scoped_task_environment_.GetMainThreadTaskRunner()
->BelongsToCurrentThread());
ASSERT_TRUE(TaskRunner()->BelongsToCurrentThread());
fake_worker_.Start(base::BindRepeating(
&FakeAudioWorkerTest::CalledByFakeWorker, base::Unretained(this)));
}
void RunOnceOnAudioThread() {
ASSERT_TRUE(scoped_task_environment_.GetMainThreadTaskRunner()
->BelongsToCurrentThread());
ASSERT_TRUE(TaskRunner()->BelongsToCurrentThread());
RunOnAudioThread();
// Start() should immediately post a task to run the callback, so we
// should end up with only a single callback being run.
scoped_task_environment_.GetMainThreadTaskRunner()->PostTask(
FROM_HERE, base::BindOnce(&FakeAudioWorkerTest::EndTest,
base::Unretained(this), 1));
TaskRunner()->PostTask(FROM_HERE,
base::BindOnce(&FakeAudioWorkerTest::EndTest,
base::Unretained(this), 1));
}
void StopStartOnAudioThread() {
ASSERT_TRUE(scoped_task_environment_.GetMainThreadTaskRunner()
->BelongsToCurrentThread());
ASSERT_TRUE(TaskRunner()->BelongsToCurrentThread());
fake_worker_.Stop();
RunOnAudioThread();
}
void TimeCallbacksOnAudioThread(int callbacks) {
ASSERT_TRUE(scoped_task_environment_.GetMainThreadTaskRunner()
->BelongsToCurrentThread());
void TimeCallbacksOnAudioThread(size_t callbacks) {
ASSERT_TRUE(TaskRunner()->BelongsToCurrentThread());
if (seen_callbacks_ == 0) {
if (callbacks_.size() == 0) {
RunOnAudioThread();
start_time_ = base::TimeTicks::Now();
}
// Keep going until we've seen the requested number of callbacks.
if (seen_callbacks_ < callbacks) {
scoped_task_environment_.GetMainThreadTaskRunner()->PostDelayedTask(
if (callbacks_.size() < callbacks) {
TaskRunner()->PostDelayedTask(
FROM_HERE,
base::BindOnce(&FakeAudioWorkerTest::TimeCallbacksOnAudioThread,
base::Unretained(this), callbacks),
time_between_callbacks_ / 2);
} else {
end_time_ = base::TimeTicks::Now();
EndTest(callbacks);
}
}
void EndTest(int callbacks) {
ASSERT_TRUE(scoped_task_environment_.GetMainThreadTaskRunner()
->BelongsToCurrentThread());
void EndTest(size_t callbacks) {
ASSERT_TRUE(TaskRunner()->BelongsToCurrentThread());
fake_worker_.Stop();
EXPECT_LE(callbacks, seen_callbacks_);
run_loop_.QuitWhenIdle();
EXPECT_LE(callbacks, callbacks_.size());
}
scoped_refptr<base::SingleThreadTaskRunner> TaskRunner() {
return scoped_task_environment_.GetMainThreadTaskRunner();
}
protected:
base::test::ScopedTaskEnvironment scoped_task_environment_;
base::RunLoop run_loop_;
base::test::ScopedTaskEnvironment scoped_task_environment_{
base::test::ScopedTaskEnvironment::MainThreadType::MOCK_TIME,
base::test::ScopedTaskEnvironment::NowSource::MAIN_THREAD_MOCK_TIME};
AudioParameters params_;
FakeAudioWorker fake_worker_;
base::TimeTicks start_time_;
base::TimeTicks end_time_;
base::TimeDelta time_between_callbacks_;
int seen_callbacks_;
std::vector<base::TimeTicks> callbacks_;
private:
DISALLOW_COPY_AND_ASSIGN(FakeAudioWorkerTest);
......@@ -115,53 +113,52 @@ TEST_F(FakeAudioWorkerTest, MAYBE_FakeBasicCallback) {
scoped_task_environment_.GetMainThreadTaskRunner()->PostTask(
FROM_HERE, base::BindOnce(&FakeAudioWorkerTest::RunOnceOnAudioThread,
base::Unretained(this)));
run_loop_.Run();
scoped_task_environment_.RunUntilIdle();
}
// Ensure the time between callbacks is sane.
//
// TODO(https://crbug.com/960729): Test is flaky because its behavior depends on
// real wallclock time. Need to mock time to fix this.
TEST_F(FakeAudioWorkerTest, DISABLED_TimeBetweenCallbacks) {
scoped_task_environment_.GetMainThreadTaskRunner()->PostTask(
// Ensure the time between callbacks is correct.
TEST_F(FakeAudioWorkerTest, TimeBetweenCallbacks) {
TaskRunner()->PostTask(
FROM_HERE,
base::BindOnce(&FakeAudioWorkerTest::TimeCallbacksOnAudioThread,
base::Unretained(this), kTestCallbacks));
run_loop_.Run();
scoped_task_environment_.FastForwardUntilNoTasksRemain();
// There are only (kTestCallbacks - 1) intervals between kTestCallbacks.
base::TimeDelta actual_time_between_callbacks =
(end_time_ - start_time_) / (seen_callbacks_ - 1);
base::TimeTicks start_time = callbacks_.front();
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.
EXPECT_GE(actual_time_between_callbacks, time_between_callbacks_);
std::vector<int64_t> 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
// between callbacks. Since this test runs on the bots we can't be too strict
// with the bounds.
if (actual_time_between_callbacks > 2 * time_between_callbacks_)
LOG(ERROR) << "Time between fake audio callbacks is too large!";
EXPECT_THAT(time_between_callbacks,
testing::Each(time_between_callbacks_.InMilliseconds()));
}
// Ensure Start()/Stop() on the worker doesn't generate too many callbacks. See
// http://crbug.com/159049.
// Flaky test; see crbug.com/974078
TEST_F(FakeAudioWorkerTest, DISABLED_StartStopClearsCallbacks) {
scoped_task_environment_.GetMainThreadTaskRunner()->PostTask(
TaskRunner()->PostTask(
FROM_HERE,
base::BindOnce(&FakeAudioWorkerTest::TimeCallbacksOnAudioThread,
base::Unretained(this), kTestCallbacks));
// Issue a Stop() / Start() in between expected callbacks to maximize the
// chance of catching the worker doing the wrong thing.
scoped_task_environment_.GetMainThreadTaskRunner()->PostDelayedTask(
FROM_HERE,
base::BindOnce(&FakeAudioWorkerTest::StopStartOnAudioThread,
base::Unretained(this)),
time_between_callbacks_ / 2);
scoped_task_environment_.FastForwardBy(time_between_callbacks_ / 2);
TaskRunner()->PostTask(
FROM_HERE, base::BindOnce(&FakeAudioWorkerTest::StopStartOnAudioThread,
base::Unretained(this)));
// EndTest() will ensure the proper number of callbacks have occurred.
run_loop_.Run();
scoped_task_environment_.FastForwardUntilNoTasksRemain();
}
} // 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