blob: 16640ee5714eb79ae71a5079347ffc69ef58e825 [file] [log] [blame]
// Copyright 2011 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 "cc/scheduler/begin_frame_source.h"
#include <stdint.h>
#include "base/test/test_simple_task_runner.h"
#include "cc/test/begin_frame_args_test.h"
#include "cc/test/begin_frame_source_test.h"
#include "cc/test/scheduler_test_common.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
using testing::Mock;
using testing::StrictMock;
namespace cc {
namespace {
// BeginFrameObserverBase testing ---------------------------------------
class MockMinimalBeginFrameObserverBase : public BeginFrameObserverBase {
public:
MOCK_METHOD1(OnBeginFrameDerivedImpl, bool(const BeginFrameArgs&));
MOCK_METHOD1(OnBeginFrameSourcePausedChanged, void(bool));
int64_t dropped_begin_frame_args() const { return dropped_begin_frame_args_; }
};
TEST(BeginFrameObserverBaseTest, OnBeginFrameImplementation) {
using ::testing::Return;
MockMinimalBeginFrameObserverBase obs;
::testing::InSequence ordered; // These calls should be ordered
// Initial conditions
EXPECT_EQ(BeginFrameArgs(), obs.LastUsedBeginFrameArgs());
EXPECT_EQ(0, obs.dropped_begin_frame_args());
#ifndef NDEBUG
EXPECT_DEATH({ obs.OnBeginFrame(BeginFrameArgs()); }, "");
#endif
BeginFrameArgs args1 =
CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 100, 200, 300);
EXPECT_CALL(obs, OnBeginFrameDerivedImpl(args1)).WillOnce(Return(true));
obs.OnBeginFrame(args1);
EXPECT_EQ(args1, obs.LastUsedBeginFrameArgs());
EXPECT_EQ(0, obs.dropped_begin_frame_args());
#ifndef NDEBUG
EXPECT_DEATH({
obs.OnBeginFrame(CreateBeginFrameArgsForTesting(
BEGINFRAME_FROM_HERE, 50, 200, 300));
},
"");
#endif
// Returning false shouldn't update the LastUsedBeginFrameArgs value.
BeginFrameArgs args2 =
CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 200, 300, 400);
EXPECT_CALL(obs, OnBeginFrameDerivedImpl(args2)).WillOnce(Return(false));
obs.OnBeginFrame(args2);
EXPECT_EQ(args1, obs.LastUsedBeginFrameArgs());
EXPECT_EQ(1, obs.dropped_begin_frame_args());
BeginFrameArgs args3 =
CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 150, 300, 400);
EXPECT_CALL(obs, OnBeginFrameDerivedImpl(args3)).WillOnce(Return(true));
obs.OnBeginFrame(args3);
EXPECT_EQ(args3, obs.LastUsedBeginFrameArgs());
EXPECT_EQ(1, obs.dropped_begin_frame_args());
}
// BeginFrameSource testing ----------------------------------------------
TEST(BeginFrameSourceBaseTest, ObserverManipulation) {
MockBeginFrameObserver obs;
MockBeginFrameObserver otherObs;
FakeBeginFrameSource source;
EXPECT_BEGIN_FRAME_SOURCE_PAUSED(obs, false);
source.AddObserver(&obs);
EXPECT_TRUE(source.has_observers());
#ifndef NDEBUG
// Adding an observer when it already exists should DCHECK fail.
EXPECT_DEATH({ source.AddObserver(&obs); }, "");
// Removing wrong observer should DCHECK fail.
EXPECT_DEATH({ source.RemoveObserver(&otherObs); }, "");
// Removing an observer when there is no observer should DCHECK fail.
EXPECT_DEATH(
{
source.RemoveObserver(&obs);
source.RemoveObserver(&obs);
},
"");
#endif
source.RemoveObserver(&obs);
EXPECT_FALSE(source.has_observers());
EXPECT_BEGIN_FRAME_SOURCE_PAUSED(otherObs, false);
source.AddObserver(&otherObs);
EXPECT_TRUE(source.has_observers());
source.RemoveObserver(&otherObs);
EXPECT_FALSE(source.has_observers());
}
TEST(BeginFrameSourceBaseTest, Observer) {
FakeBeginFrameSource source;
MockBeginFrameObserver obs;
EXPECT_BEGIN_FRAME_SOURCE_PAUSED(obs, false);
source.AddObserver(&obs);
EXPECT_BEGIN_FRAME_USED(obs, 100, 200, 300);
EXPECT_BEGIN_FRAME_DROP(obs, 400, 600, 300);
EXPECT_BEGIN_FRAME_DROP(obs, 450, 650, 300);
EXPECT_BEGIN_FRAME_USED(obs, 700, 900, 300);
SEND_BEGIN_FRAME_USED(source, 100, 200, 300);
SEND_BEGIN_FRAME_DROP(source, 400, 600, 300);
SEND_BEGIN_FRAME_DROP(source, 450, 650, 300);
SEND_BEGIN_FRAME_USED(source, 700, 900, 300);
}
TEST(BeginFrameSourceBaseTest, NoObserver) {
FakeBeginFrameSource source;
SEND_BEGIN_FRAME_DROP(source, 100, 200, 300);
}
TEST(BeginFrameSourceBaseTest, SetBeginFrameSourcePaused) {
FakeBeginFrameSource source;
MockBeginFrameObserver obs;
EXPECT_BEGIN_FRAME_SOURCE_PAUSED(obs, false);
source.AddObserver(&obs);
EXPECT_BEGIN_FRAME_SOURCE_PAUSED(obs, true);
source.SetBeginFrameSourcePaused(true);
EXPECT_BEGIN_FRAME_SOURCE_PAUSED(obs, false);
source.SetBeginFrameSourcePaused(false);
}
TEST(BeginFrameSourceBaseTest, MultipleObservers) {
FakeBeginFrameSource source;
StrictMock<MockBeginFrameObserver> obs1, obs2;
EXPECT_BEGIN_FRAME_SOURCE_PAUSED(obs1, false);
source.AddObserver(&obs1);
EXPECT_BEGIN_FRAME_USED(obs1, 100, 200, 100);
SEND_BEGIN_FRAME_USED(source, 100, 200, 100);
EXPECT_BEGIN_FRAME_SOURCE_PAUSED(obs2, false);
source.AddObserver(&obs2);
EXPECT_BEGIN_FRAME_USED(obs1, 200, 300, 100);
EXPECT_BEGIN_FRAME_USED(obs2, 200, 300, 100);
SEND_BEGIN_FRAME_USED(source, 200, 300, 100);
EXPECT_BEGIN_FRAME_SOURCE_PAUSED(obs1, true);
EXPECT_BEGIN_FRAME_SOURCE_PAUSED(obs2, true);
source.SetBeginFrameSourcePaused(true);
source.RemoveObserver(&obs1);
EXPECT_BEGIN_FRAME_SOURCE_PAUSED(obs2, false);
source.SetBeginFrameSourcePaused(false);
EXPECT_BEGIN_FRAME_USED(obs2, 300, 400, 100);
SEND_BEGIN_FRAME_USED(source, 300, 400, 100);
source.RemoveObserver(&obs2);
}
class LoopingBeginFrameObserver : public BeginFrameObserverBase {
public:
BeginFrameSource* source_;
void AsValueInto(base::trace_event::TracedValue* dict) const override {
dict->SetString("type", "LoopingBeginFrameObserver");
dict->BeginDictionary("source");
source_->AsValueInto(dict);
dict->EndDictionary();
}
protected:
// BeginFrameObserverBase
bool OnBeginFrameDerivedImpl(const BeginFrameArgs& args) override {
return true;
}
void OnBeginFrameSourcePausedChanged(bool paused) override {}
};
TEST(BeginFrameSourceBaseTest, DetectAsValueIntoLoop) {
LoopingBeginFrameObserver obs;
FakeBeginFrameSource source;
obs.source_ = &source;
source.AddObserver(&obs);
scoped_refptr<base::trace_event::TracedValue> state =
new base::trace_event::TracedValue();
source.AsValueInto(state.get());
}
// BackToBackBeginFrameSource testing -----------------------------------------
class TestBackToBackBeginFrameSource : public BackToBackBeginFrameSource {
public:
static scoped_ptr<TestBackToBackBeginFrameSource> Create(
base::SimpleTestTickClock* now_src,
base::SingleThreadTaskRunner* task_runner) {
return make_scoped_ptr(
new TestBackToBackBeginFrameSource(now_src, task_runner));
}
protected:
TestBackToBackBeginFrameSource(base::SimpleTestTickClock* now_src,
base::SingleThreadTaskRunner* task_runner)
: BackToBackBeginFrameSource(task_runner), now_src_(now_src) {}
base::TimeTicks Now() override { return now_src_->NowTicks(); }
// Not owned.
base::SimpleTestTickClock* now_src_;
};
class BackToBackBeginFrameSourceTest : public ::testing::Test {
public:
static const int64_t kDeadline;
static const int64_t kInterval;
scoped_ptr<base::SimpleTestTickClock> now_src_;
scoped_refptr<OrderedSimpleTaskRunner> task_runner_;
scoped_ptr<TestBackToBackBeginFrameSource> source_;
scoped_ptr<MockBeginFrameObserver> obs_;
void SetUp() override {
now_src_.reset(new base::SimpleTestTickClock());
now_src_->Advance(base::TimeDelta::FromMicroseconds(1000));
task_runner_ =
make_scoped_refptr(new OrderedSimpleTaskRunner(now_src_.get(), false));
source_ = TestBackToBackBeginFrameSource::Create(now_src_.get(),
task_runner_.get());
obs_ = make_scoped_ptr(new ::testing::StrictMock<MockBeginFrameObserver>());
}
void TearDown() override { obs_.reset(); }
};
const int64_t BackToBackBeginFrameSourceTest::kDeadline =
BeginFrameArgs::DefaultInterval().ToInternalValue();
const int64_t BackToBackBeginFrameSourceTest::kInterval =
BeginFrameArgs::DefaultInterval().ToInternalValue();
TEST_F(BackToBackBeginFrameSourceTest, AddObserverSendsBeginFrame) {
EXPECT_BEGIN_FRAME_SOURCE_PAUSED(*obs_, false);
source_->AddObserver(obs_.get());
EXPECT_TRUE(task_runner_->HasPendingTasks());
EXPECT_BEGIN_FRAME_USED(*obs_, 1000, 1000 + kDeadline, kInterval);
task_runner_->RunPendingTasks();
EXPECT_BEGIN_FRAME_USED(*obs_, 1100, 1100 + kDeadline, kInterval);
now_src_->Advance(base::TimeDelta::FromMicroseconds(100));
source_->DidFinishFrame(0);
task_runner_->RunPendingTasks();
}
TEST_F(BackToBackBeginFrameSourceTest,
DidFinishFrameThenRemoveObserverProducesNoFrame) {
EXPECT_BEGIN_FRAME_SOURCE_PAUSED(*obs_, false);
source_->AddObserver(obs_.get());
EXPECT_BEGIN_FRAME_USED(*obs_, 1000, 1000 + kDeadline, kInterval);
task_runner_->RunPendingTasks();
source_->RemoveObserver(obs_.get());
source_->DidFinishFrame(0);
EXPECT_FALSE(task_runner_->HasPendingTasks());
}
TEST_F(BackToBackBeginFrameSourceTest,
RemoveObserverThenDidFinishFrameProducesNoFrame) {
EXPECT_BEGIN_FRAME_SOURCE_PAUSED(*obs_, false);
source_->AddObserver(obs_.get());
EXPECT_BEGIN_FRAME_USED(*obs_, 1000, 1000 + kDeadline, kInterval);
task_runner_->RunPendingTasks();
now_src_->Advance(base::TimeDelta::FromMicroseconds(100));
source_->DidFinishFrame(0);
source_->RemoveObserver(obs_.get());
EXPECT_TRUE(task_runner_->HasPendingTasks());
task_runner_->RunPendingTasks();
}
TEST_F(BackToBackBeginFrameSourceTest,
TogglingObserverThenDidFinishFrameProducesCorrectFrame) {
EXPECT_BEGIN_FRAME_SOURCE_PAUSED(*obs_, false);
source_->AddObserver(obs_.get());
EXPECT_BEGIN_FRAME_USED(*obs_, 1000, 1000 + kDeadline, kInterval);
task_runner_->RunPendingTasks();
now_src_->Advance(base::TimeDelta::FromMicroseconds(100));
source_->RemoveObserver(obs_.get());
now_src_->Advance(base::TimeDelta::FromMicroseconds(10));
EXPECT_BEGIN_FRAME_SOURCE_PAUSED(*obs_, false);
source_->AddObserver(obs_.get());
now_src_->Advance(base::TimeDelta::FromMicroseconds(10));
source_->DidFinishFrame(0);
now_src_->Advance(base::TimeDelta::FromMicroseconds(10));
EXPECT_BEGIN_FRAME_USED(*obs_, 1130, 1130 + kDeadline, kInterval);
EXPECT_TRUE(task_runner_->HasPendingTasks());
task_runner_->RunPendingTasks();
}
TEST_F(BackToBackBeginFrameSourceTest,
DidFinishFrameThenTogglingObserverProducesCorrectFrame) {
EXPECT_BEGIN_FRAME_SOURCE_PAUSED(*obs_, false);
source_->AddObserver(obs_.get());
EXPECT_BEGIN_FRAME_USED(*obs_, 1000, 1000 + kDeadline, kInterval);
task_runner_->RunPendingTasks();
now_src_->Advance(base::TimeDelta::FromMicroseconds(100));
source_->DidFinishFrame(0);
now_src_->Advance(base::TimeDelta::FromMicroseconds(10));
source_->RemoveObserver(obs_.get());
now_src_->Advance(base::TimeDelta::FromMicroseconds(10));
EXPECT_BEGIN_FRAME_SOURCE_PAUSED(*obs_, false);
source_->AddObserver(obs_.get());
now_src_->Advance(base::TimeDelta::FromMicroseconds(10));
EXPECT_BEGIN_FRAME_USED(*obs_, 1130, 1130 + kDeadline, kInterval);
EXPECT_TRUE(task_runner_->HasPendingTasks());
task_runner_->RunPendingTasks();
}
TEST_F(BackToBackBeginFrameSourceTest, DidFinishFrameNoObserver) {
EXPECT_BEGIN_FRAME_SOURCE_PAUSED(*obs_, false);
source_->AddObserver(obs_.get());
source_->RemoveObserver(obs_.get());
source_->DidFinishFrame(0);
EXPECT_FALSE(task_runner_->RunPendingTasks());
}
TEST_F(BackToBackBeginFrameSourceTest, DidFinishFrameRemainingFrames) {
EXPECT_BEGIN_FRAME_SOURCE_PAUSED(*obs_, false);
source_->AddObserver(obs_.get());
EXPECT_BEGIN_FRAME_USED(*obs_, 1000, 1000 + kDeadline, kInterval);
task_runner_->RunPendingTasks();
now_src_->Advance(base::TimeDelta::FromMicroseconds(100));
source_->DidFinishFrame(3);
EXPECT_FALSE(task_runner_->HasPendingTasks());
source_->DidFinishFrame(2);
EXPECT_FALSE(task_runner_->HasPendingTasks());
source_->DidFinishFrame(1);
EXPECT_FALSE(task_runner_->HasPendingTasks());
EXPECT_BEGIN_FRAME_USED(*obs_, 1100, 1100 + kDeadline, kInterval);
source_->DidFinishFrame(0);
EXPECT_EQ(base::TimeDelta(), task_runner_->DelayToNextTaskTime());
task_runner_->RunPendingTasks();
}
TEST_F(BackToBackBeginFrameSourceTest, DidFinishFrameMultipleCallsIdempotent) {
EXPECT_BEGIN_FRAME_SOURCE_PAUSED(*obs_, false);
source_->AddObserver(obs_.get());
EXPECT_BEGIN_FRAME_USED(*obs_, 1000, 1000 + kDeadline, kInterval);
task_runner_->RunPendingTasks();
now_src_->Advance(base::TimeDelta::FromMicroseconds(100));
source_->DidFinishFrame(0);
source_->DidFinishFrame(0);
source_->DidFinishFrame(0);
EXPECT_BEGIN_FRAME_USED(*obs_, 1100, 1100 + kDeadline, kInterval);
task_runner_->RunPendingTasks();
now_src_->Advance(base::TimeDelta::FromMicroseconds(100));
source_->DidFinishFrame(0);
source_->DidFinishFrame(0);
source_->DidFinishFrame(0);
EXPECT_BEGIN_FRAME_USED(*obs_, 1200, 1200 + kDeadline, kInterval);
task_runner_->RunPendingTasks();
}
TEST_F(BackToBackBeginFrameSourceTest, DelayInPostedTaskProducesCorrectFrame) {
EXPECT_BEGIN_FRAME_SOURCE_PAUSED(*obs_, false);
source_->AddObserver(obs_.get());
EXPECT_BEGIN_FRAME_USED(*obs_, 1000, 1000 + kDeadline, kInterval);
task_runner_->RunPendingTasks();
now_src_->Advance(base::TimeDelta::FromMicroseconds(100));
source_->DidFinishFrame(0);
now_src_->Advance(base::TimeDelta::FromMicroseconds(50));
EXPECT_BEGIN_FRAME_USED(*obs_, 1150, 1150 + kDeadline, kInterval);
EXPECT_TRUE(task_runner_->HasPendingTasks());
task_runner_->RunPendingTasks();
}
// SyntheticBeginFrameSource testing ------------------------------------------
class SyntheticBeginFrameSourceTest : public ::testing::Test {
public:
scoped_ptr<base::SimpleTestTickClock> now_src_;
scoped_refptr<OrderedSimpleTaskRunner> task_runner_;
scoped_ptr<TestSyntheticBeginFrameSource> source_;
scoped_ptr<MockBeginFrameObserver> obs_;
void SetUp() override {
now_src_.reset(new base::SimpleTestTickClock());
now_src_->Advance(base::TimeDelta::FromMicroseconds(1000));
task_runner_ =
make_scoped_refptr(new OrderedSimpleTaskRunner(now_src_.get(), false));
source_ = TestSyntheticBeginFrameSource::Create(
now_src_.get(), task_runner_.get(),
base::TimeDelta::FromMicroseconds(10000));
obs_ = make_scoped_ptr(new MockBeginFrameObserver());
}
void TearDown() override { obs_.reset(); }
};
TEST_F(SyntheticBeginFrameSourceTest,
AddObserverCallsOnBeginFrameWithMissedTick) {
now_src_->Advance(base::TimeDelta::FromMicroseconds(9010));
EXPECT_BEGIN_FRAME_SOURCE_PAUSED(*obs_, false);
EXPECT_BEGIN_FRAME_USED_MISSED(*obs_, 10000, 20000, 10000);
source_->AddObserver(obs_.get()); // Should cause the last tick to be sent
// No tasks should need to be run for this to occur.
}
TEST_F(SyntheticBeginFrameSourceTest, AddObserverCallsCausesOnBeginFrame) {
EXPECT_BEGIN_FRAME_SOURCE_PAUSED(*obs_, false);
EXPECT_BEGIN_FRAME_USED_MISSED(*obs_, 0, 10000, 10000);
source_->AddObserver(obs_.get());
EXPECT_EQ(10000, task_runner_->NextTaskTime().ToInternalValue());
EXPECT_BEGIN_FRAME_USED(*obs_, 10000, 20000, 10000);
now_src_->Advance(base::TimeDelta::FromMicroseconds(9010));
task_runner_->RunPendingTasks();
}
TEST_F(SyntheticBeginFrameSourceTest, BasicOperation) {
task_runner_->SetAutoAdvanceNowToPendingTasks(true);
EXPECT_BEGIN_FRAME_SOURCE_PAUSED(*obs_, false);
EXPECT_BEGIN_FRAME_USED_MISSED(*obs_, 0, 10000, 10000);
source_->AddObserver(obs_.get());
EXPECT_BEGIN_FRAME_USED(*obs_, 10000, 20000, 10000);
EXPECT_BEGIN_FRAME_USED(*obs_, 20000, 30000, 10000);
EXPECT_BEGIN_FRAME_USED(*obs_, 30000, 40000, 10000);
task_runner_->RunUntilTime(base::TimeTicks::FromInternalValue(30001));
source_->RemoveObserver(obs_.get());
// No new frames....
task_runner_->RunUntilTime(base::TimeTicks::FromInternalValue(60000));
}
TEST_F(SyntheticBeginFrameSourceTest, VSyncChanges) {
task_runner_->SetAutoAdvanceNowToPendingTasks(true);
EXPECT_BEGIN_FRAME_SOURCE_PAUSED(*obs_, false);
EXPECT_BEGIN_FRAME_USED_MISSED(*obs_, 0, 10000, 10000);
source_->AddObserver(obs_.get());
EXPECT_BEGIN_FRAME_USED(*obs_, 10000, 20000, 10000);
EXPECT_BEGIN_FRAME_USED(*obs_, 20000, 30000, 10000);
EXPECT_BEGIN_FRAME_USED(*obs_, 30000, 40000, 10000);
task_runner_->RunUntilTime(base::TimeTicks::FromInternalValue(30001));
// Update the vsync information
source_->OnUpdateVSyncParameters(base::TimeTicks::FromInternalValue(27500),
base::TimeDelta::FromMicroseconds(10001));
EXPECT_BEGIN_FRAME_USED(*obs_, 40000, 47502, 10001);
EXPECT_BEGIN_FRAME_USED(*obs_, 47502, 57503, 10001);
EXPECT_BEGIN_FRAME_USED(*obs_, 57503, 67504, 10001);
task_runner_->RunUntilTime(base::TimeTicks::FromInternalValue(60000));
}
TEST_F(SyntheticBeginFrameSourceTest, MultipleObservers) {
StrictMock<MockBeginFrameObserver> obs1, obs2;
// now_src_ starts off at 1000.
task_runner_->RunForPeriod(base::TimeDelta::FromMicroseconds(9010));
EXPECT_BEGIN_FRAME_SOURCE_PAUSED(obs1, false);
EXPECT_BEGIN_FRAME_USED_MISSED(obs1, 10000, 20000, 10000);
source_->AddObserver(&obs1); // Should cause the last tick to be sent
// No tasks should need to be run for this to occur.
EXPECT_BEGIN_FRAME_USED(obs1, 20000, 30000, 10000);
task_runner_->RunForPeriod(base::TimeDelta::FromMicroseconds(10000));
EXPECT_BEGIN_FRAME_SOURCE_PAUSED(obs2, false);
EXPECT_BEGIN_FRAME_USED_MISSED(obs2, 20000, 30000, 10000);
source_->AddObserver(&obs2); // Should cause the last tick to be sent
// No tasks should need to be run for this to occur.
EXPECT_BEGIN_FRAME_USED(obs1, 30000, 40000, 10000);
EXPECT_BEGIN_FRAME_USED(obs2, 30000, 40000, 10000);
task_runner_->RunForPeriod(base::TimeDelta::FromMicroseconds(10000));
source_->RemoveObserver(&obs1);
EXPECT_BEGIN_FRAME_USED(obs2, 40000, 50000, 10000);
task_runner_->RunForPeriod(base::TimeDelta::FromMicroseconds(10000));
source_->RemoveObserver(&obs2);
task_runner_->RunUntilTime(base::TimeTicks::FromInternalValue(50000));
EXPECT_FALSE(task_runner_->HasPendingTasks());
}
TEST_F(SyntheticBeginFrameSourceTest, DoubleTick) {
StrictMock<MockBeginFrameObserver> obs;
EXPECT_BEGIN_FRAME_SOURCE_PAUSED(obs, false);
EXPECT_BEGIN_FRAME_USED_MISSED(obs, 0, 10000, 10000);
source_->AddObserver(&obs);
source_->OnUpdateVSyncParameters(base::TimeTicks::FromInternalValue(5000),
base::TimeDelta::FromInternalValue(10000));
now_src_->Advance(base::TimeDelta::FromInternalValue(4000));
// No begin frame received.
task_runner_->RunPendingTasks();
// Begin frame received.
source_->OnUpdateVSyncParameters(base::TimeTicks::FromInternalValue(10000),
base::TimeDelta::FromInternalValue(10000));
now_src_->Advance(base::TimeDelta::FromInternalValue(5000));
EXPECT_BEGIN_FRAME_USED(obs, 10000, 20000, 10000);
task_runner_->RunPendingTasks();
}
TEST_F(SyntheticBeginFrameSourceTest, DoubleTickMissedFrame) {
StrictMock<MockBeginFrameObserver> obs;
EXPECT_BEGIN_FRAME_SOURCE_PAUSED(obs, false);
EXPECT_BEGIN_FRAME_USED_MISSED(obs, 0, 10000, 10000);
source_->AddObserver(&obs);
source_->RemoveObserver(&obs);
source_->OnUpdateVSyncParameters(base::TimeTicks::FromInternalValue(5000),
base::TimeDelta::FromInternalValue(10000));
now_src_->Advance(base::TimeDelta::FromInternalValue(4000));
// No missed frame received.
EXPECT_BEGIN_FRAME_SOURCE_PAUSED(obs, false);
source_->AddObserver(&obs);
source_->RemoveObserver(&obs);
// Missed frame received.
source_->OnUpdateVSyncParameters(base::TimeTicks::FromInternalValue(10000),
base::TimeDelta::FromInternalValue(10000));
now_src_->Advance(base::TimeDelta::FromInternalValue(5000));
EXPECT_BEGIN_FRAME_SOURCE_PAUSED(obs, false);
EXPECT_BEGIN_FRAME_USED_MISSED(obs, 10000, 20000, 10000);
source_->AddObserver(&obs);
source_->RemoveObserver(&obs);
}
// BeginFrameSourceMultiplexer testing -----------------------------------
class BeginFrameSourceMultiplexerTest : public ::testing::Test {
protected:
void SetUp() override {
mux_ = BeginFrameSourceMultiplexer::Create();
source1_store_ = make_scoped_ptr(new FakeBeginFrameSource());
source2_store_ = make_scoped_ptr(new FakeBeginFrameSource());
source3_store_ = make_scoped_ptr(new FakeBeginFrameSource());
source1_ = source1_store_.get();
source2_ = source2_store_.get();
source3_ = source3_store_.get();
}
void TearDown() override {
// Make sure the mux is torn down before the sources.
mux_.reset();
}
scoped_ptr<BeginFrameSourceMultiplexer> mux_;
FakeBeginFrameSource* source1_;
FakeBeginFrameSource* source2_;
FakeBeginFrameSource* source3_;
private:
scoped_ptr<FakeBeginFrameSource> source1_store_;
scoped_ptr<FakeBeginFrameSource> source2_store_;
scoped_ptr<FakeBeginFrameSource> source3_store_;
};
TEST_F(BeginFrameSourceMultiplexerTest, SourcesManipulation) {
EXPECT_EQ(NULL, mux_->ActiveSource());
mux_->AddSource(source1_);
EXPECT_EQ(source1_, mux_->ActiveSource());
mux_->SetActiveSource(NULL);
EXPECT_EQ(NULL, mux_->ActiveSource());
mux_->SetActiveSource(source1_);
#ifndef NDEBUG
// Setting a source which isn't in the mux as active should DCHECK fail.
EXPECT_DEATH({ mux_->SetActiveSource(source2_); }, "");
// Adding a source which is already added should DCHECK fail.
EXPECT_DEATH({ mux_->AddSource(source1_); }, "");
// Removing a source which isn't in the mux should DCHECK fail.
EXPECT_DEATH({ mux_->RemoveSource(source2_); }, "");
// Removing the active source fails
EXPECT_DEATH({ mux_->RemoveSource(source1_); }, "");
#endif
// Test manipulation doesn't segfault.
mux_->AddSource(source2_);
mux_->RemoveSource(source2_);
mux_->AddSource(source2_);
mux_->SetActiveSource(source2_);
EXPECT_EQ(source2_, mux_->ActiveSource());
mux_->RemoveSource(source1_);
}
TEST_F(BeginFrameSourceMultiplexerTest, SwitchActiveSource) {
mux_->AddSource(source1_);
mux_->AddSource(source2_);
EXPECT_FALSE(source1_->has_observers());
EXPECT_FALSE(source2_->has_observers());
MockBeginFrameObserver obs;
mux_->AddObserver(&obs);
mux_->SetActiveSource(source1_);
EXPECT_TRUE(source1_->has_observers());
EXPECT_FALSE(source2_->has_observers());
mux_->SetActiveSource(source2_);
EXPECT_FALSE(source1_->has_observers());
EXPECT_TRUE(source2_->has_observers());
}
TEST_F(BeginFrameSourceMultiplexerTest, SingleObserver) {
mux_->AddSource(source1_);
mux_->AddSource(source2_);
mux_->SetActiveSource(source1_);
EXPECT_FALSE(source1_->has_observers());
EXPECT_FALSE(source2_->has_observers());
MockBeginFrameObserver obs;
EXPECT_BEGIN_FRAME_SOURCE_PAUSED(obs, false);
mux_->AddObserver(&obs);
EXPECT_TRUE(source1_->has_observers());
EXPECT_FALSE(source2_->has_observers());
EXPECT_BEGIN_FRAME_USED(obs, 100, 200, 100);
SEND_BEGIN_FRAME_USED(*source1_, 100, 200, 100);
SEND_BEGIN_FRAME_DROP(*source2_, 150, 250, 100);
mux_->RemoveObserver(&obs);
EXPECT_FALSE(source1_->has_observers());
EXPECT_FALSE(source2_->has_observers());
}
TEST_F(BeginFrameSourceMultiplexerTest, MultipleObservers) {
mux_->AddSource(source1_);
mux_->AddSource(source2_);
mux_->SetActiveSource(source1_);
EXPECT_FALSE(source1_->has_observers());
EXPECT_FALSE(source2_->has_observers());
StrictMock<MockBeginFrameObserver> obs1, obs2;
EXPECT_BEGIN_FRAME_SOURCE_PAUSED(obs1, false);
mux_->AddObserver(&obs1);
EXPECT_TRUE(source1_->has_observers());
EXPECT_FALSE(source2_->has_observers());
EXPECT_BEGIN_FRAME_USED(obs1, 100, 200, 100);
SEND_BEGIN_FRAME_USED(*source1_, 100, 200, 100);
SEND_BEGIN_FRAME_DROP(*source2_, 200, 300, 100);
EXPECT_BEGIN_FRAME_SOURCE_PAUSED(obs2, false);
mux_->AddObserver(&obs2);
EXPECT_BEGIN_FRAME_USED(obs1, 300, 400, 100);
EXPECT_BEGIN_FRAME_USED(obs2, 300, 400, 100);
SEND_BEGIN_FRAME_USED(*source1_, 300, 400, 100);
SEND_BEGIN_FRAME_DROP(*source2_, 400, 500, 100);
EXPECT_BEGIN_FRAME_SOURCE_PAUSED(obs1, true);
EXPECT_BEGIN_FRAME_SOURCE_PAUSED(obs2, true);
source1_->SetBeginFrameSourcePaused(true);
EXPECT_BEGIN_FRAME_SOURCE_PAUSED(obs1, false);
EXPECT_BEGIN_FRAME_SOURCE_PAUSED(obs2, false);
mux_->SetActiveSource(source2_);
EXPECT_FALSE(source1_->has_observers());
EXPECT_TRUE(source2_->has_observers());
EXPECT_BEGIN_FRAME_USED(obs1, 600, 700, 100);
EXPECT_BEGIN_FRAME_USED(obs2, 600, 700, 100);
SEND_BEGIN_FRAME_DROP(*source1_, 500, 600, 100);
SEND_BEGIN_FRAME_USED(*source2_, 600, 700, 100);
mux_->RemoveObserver(&obs1);
EXPECT_FALSE(source1_->has_observers());
EXPECT_TRUE(source2_->has_observers());
EXPECT_BEGIN_FRAME_USED(obs2, 800, 900, 100);
SEND_BEGIN_FRAME_DROP(*source1_, 700, 800, 100);
SEND_BEGIN_FRAME_USED(*source2_, 800, 900, 100);
mux_->RemoveObserver(&obs2);
EXPECT_FALSE(source1_->has_observers());
EXPECT_FALSE(source2_->has_observers());
}
TEST_F(BeginFrameSourceMultiplexerTest, BeginFramesSimple) {
mux_->AddSource(source1_);
mux_->AddSource(source2_);
mux_->SetActiveSource(source1_);
MockBeginFrameObserver obs;
EXPECT_BEGIN_FRAME_SOURCE_PAUSED(obs, false);
mux_->AddObserver(&obs);
EXPECT_BEGIN_FRAME_USED(obs, 100, 200, 300);
EXPECT_BEGIN_FRAME_USED(obs, 400, 600, 300);
mux_->SetActiveSource(source1_);
SEND_BEGIN_FRAME_USED(*source1_, 100, 200, 300);
SEND_BEGIN_FRAME_DROP(*source2_, 200, 500, 300);
mux_->SetActiveSource(source2_);
SEND_BEGIN_FRAME_USED(*source2_, 400, 600, 300);
SEND_BEGIN_FRAME_DROP(*source1_, 500, 700, 300);
}
TEST_F(BeginFrameSourceMultiplexerTest, BeginFramesBackwardsProtection) {
mux_->AddSource(source1_);
mux_->AddSource(source2_);
MockBeginFrameObserver obs;
EXPECT_BEGIN_FRAME_SOURCE_PAUSED(obs, false);
mux_->AddObserver(&obs);
EXPECT_BEGIN_FRAME_USED(obs, 400, 600, 300);
EXPECT_BEGIN_FRAME_USED(obs, 700, 900, 300);
EXPECT_BEGIN_FRAME_USED(obs, 1000, 1200, 300);
EXPECT_BEGIN_FRAME_USED(obs, 1001, 1201, 301);
mux_->SetActiveSource(source1_);
SEND_BEGIN_FRAME_USED(*source1_, 400, 600, 300);
SEND_BEGIN_FRAME_USED(*source1_, 700, 900, 300);
mux_->SetActiveSource(source2_);
SEND_BEGIN_FRAME_DROP(*source2_, 699, 899, 300);
SEND_BEGIN_FRAME_USED(*source2_, 1000, 1200, 300);
mux_->SetActiveSource(source1_);
SEND_BEGIN_FRAME_USED(*source1_, 1001, 1201, 301);
}
TEST_F(BeginFrameSourceMultiplexerTest, MinimumIntervalNegativeFails) {
#ifndef NDEBUG
EXPECT_DEATH(
{ mux_->SetMinimumInterval(base::TimeDelta::FromInternalValue(-100)); },
"");
#endif
}
TEST_F(BeginFrameSourceMultiplexerTest, MinimumIntervalZero) {
mux_->SetMinimumInterval(base::TimeDelta());
mux_->AddSource(source1_);
MockBeginFrameObserver obs;
EXPECT_BEGIN_FRAME_SOURCE_PAUSED(obs, false);
mux_->AddObserver(&obs);
EXPECT_BEGIN_FRAME_USED(obs, 100, 200, 300);
EXPECT_BEGIN_FRAME_USED(obs, 400, 600, 300);
EXPECT_BEGIN_FRAME_USED(obs, 700, 900, 300);
SEND_BEGIN_FRAME_USED(*source1_, 100, 200, 300);
SEND_BEGIN_FRAME_USED(*source1_, 400, 600, 300);
SEND_BEGIN_FRAME_USED(*source1_, 700, 900, 300);
}
TEST_F(BeginFrameSourceMultiplexerTest, MinimumIntervalBasic) {
mux_->SetMinimumInterval(base::TimeDelta::FromInternalValue(600));
mux_->AddSource(source1_);
MockBeginFrameObserver obs;
EXPECT_BEGIN_FRAME_SOURCE_PAUSED(obs, false);
mux_->AddObserver(&obs);
EXPECT_BEGIN_FRAME_USED(obs, 100, 200, 300);
EXPECT_BEGIN_FRAME_USED(obs, 700, 900, 300);
SEND_BEGIN_FRAME_USED(*source1_, 100, 200, 300);
SEND_BEGIN_FRAME_DROP(*source1_, 400, 600, 300);
SEND_BEGIN_FRAME_USED(*source1_, 700, 900, 300);
}
TEST_F(BeginFrameSourceMultiplexerTest, MinimumIntervalWithMultipleSources) {
mux_->SetMinimumInterval(base::TimeDelta::FromMicroseconds(150));
mux_->AddSource(source1_);
mux_->AddSource(source2_);
MockBeginFrameObserver obs;
EXPECT_BEGIN_FRAME_SOURCE_PAUSED(obs, false);
mux_->AddObserver(&obs);
EXPECT_BEGIN_FRAME_USED(obs, 400, 600, 300);
EXPECT_BEGIN_FRAME_USED(obs, 700, 900, 300);
EXPECT_BEGIN_FRAME_USED(obs, 1050, 1250, 300);
mux_->SetActiveSource(source1_);
SEND_BEGIN_FRAME_USED(*source1_, 400, 600, 300);
SEND_BEGIN_FRAME_USED(*source1_, 700, 900, 300);
mux_->SetActiveSource(source2_);
SEND_BEGIN_FRAME_DROP(*source2_, 750, 1050, 300);
SEND_BEGIN_FRAME_USED(*source2_, 1050, 1250, 300);
mux_->SetActiveSource(source1_);
SEND_BEGIN_FRAME_DROP(*source2_, 1100, 1400, 300);
}
TEST_F(BeginFrameSourceMultiplexerTest, BeginFrameSourcePaused) {
mux_->AddSource(source1_);
mux_->AddSource(source2_);
mux_->SetActiveSource(source1_);
MockBeginFrameObserver obs;
EXPECT_BEGIN_FRAME_SOURCE_PAUSED(obs, false);
mux_->AddObserver(&obs);
Mock::VerifyAndClearExpectations(&obs);
EXPECT_BEGIN_FRAME_SOURCE_PAUSED(obs, true);
source1_->SetBeginFrameSourcePaused(true);
EXPECT_BEGIN_FRAME_SOURCE_PAUSED(obs, false);
source1_->SetBeginFrameSourcePaused(false);
Mock::VerifyAndClearExpectations(&obs);
mux_->SetActiveSource(source2_);
Mock::VerifyAndClearExpectations(&obs);
EXPECT_BEGIN_FRAME_SOURCE_PAUSED(obs, true);
source2_->SetBeginFrameSourcePaused(true);
EXPECT_BEGIN_FRAME_SOURCE_PAUSED(obs, false);
source2_->SetBeginFrameSourcePaused(false);
}
TEST_F(BeginFrameSourceMultiplexerTest,
BeginFrameSourcePausedUpdateOnSourceTransition) {
mux_->AddSource(source1_);
mux_->AddSource(source2_);
source1_->SetBeginFrameSourcePaused(true);
source2_->SetBeginFrameSourcePaused(false);
mux_->SetActiveSource(source1_);
MockBeginFrameObserver obs;
EXPECT_BEGIN_FRAME_SOURCE_PAUSED(obs, true);
mux_->AddObserver(&obs);
Mock::VerifyAndClearExpectations(&obs);
// Paused to not paused.
EXPECT_BEGIN_FRAME_SOURCE_PAUSED(obs, false);
mux_->SetActiveSource(source2_);
Mock::VerifyAndClearExpectations(&obs);
// Not paused to paused.
EXPECT_BEGIN_FRAME_SOURCE_PAUSED(obs, true);
mux_->SetActiveSource(source1_);
Mock::VerifyAndClearExpectations(&obs);
EXPECT_BEGIN_FRAME_SOURCE_PAUSED(obs, false);
source1_->SetBeginFrameSourcePaused(false);
Mock::VerifyAndClearExpectations(&obs);
// Not paused to not paused.
mux_->SetActiveSource(source2_);
Mock::VerifyAndClearExpectations(&obs);
EXPECT_BEGIN_FRAME_SOURCE_PAUSED(obs, true);
source2_->SetBeginFrameSourcePaused(true);
Mock::VerifyAndClearExpectations(&obs);
source1_->SetBeginFrameSourcePaused(true);
// Paused to paused.
mux_->SetActiveSource(source1_);
Mock::VerifyAndClearExpectations(&obs);
}
} // namespace
} // namespace cc