| Index: media/filters/pipeline_controller_unittest.cc
|
| diff --git a/media/filters/pipeline_controller_unittest.cc b/media/filters/pipeline_controller_unittest.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..561c7b08d6abf83f33629d7c43cca41b35e73c51
|
| --- /dev/null
|
| +++ b/media/filters/pipeline_controller_unittest.cc
|
| @@ -0,0 +1,212 @@
|
| +// Copyright 2016 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 "base/bind.h"
|
| +#include "base/bind_helpers.h"
|
| +#include "base/logging.h"
|
| +#include "base/macros.h"
|
| +#include "base/memory/ref_counted.h"
|
| +#include "base/memory/scoped_ptr.h"
|
| +#include "base/message_loop/message_loop.h"
|
| +#include "base/time/time.h"
|
| +#include "media/base/mock_filters.h"
|
| +#include "media/base/pipeline.h"
|
| +#include "media/filters/pipeline_controller.h"
|
| +#include "testing/gmock/include/gmock/gmock.h"
|
| +#include "testing/gtest/include/gtest/gtest.h"
|
| +
|
| +using ::testing::_;
|
| +using ::testing::DoAll;
|
| +using ::testing::Mock;
|
| +using ::testing::Return;
|
| +using ::testing::SaveArg;
|
| +using ::testing::StrictMock;
|
| +
|
| +namespace media {
|
| +
|
| +class PipelineControllerTest : public ::testing::Test {
|
| + public:
|
| + PipelineControllerTest()
|
| + : pipeline_controller_(&pipeline_,
|
| + base::Bind(&PipelineControllerTest::CreateRenderer,
|
| + base::Unretained(this)),
|
| + base::Bind(&PipelineControllerTest::OnSeeked,
|
| + base::Unretained(this)),
|
| + base::Bind(&PipelineControllerTest::OnSuspended,
|
| + base::Unretained(this)),
|
| + base::Bind(&PipelineControllerTest::OnResumed,
|
| + base::Unretained(this)),
|
| + base::Bind(&PipelineControllerTest::OnError,
|
| + base::Unretained(this))) {}
|
| +
|
| + ~PipelineControllerTest() override {}
|
| +
|
| + PipelineStatusCB StartPipeline() {
|
| + EXPECT_FALSE(pipeline_controller_.IsStable());
|
| + PipelineStatusCB start_cb;
|
| + EXPECT_CALL(pipeline_, Start(_, _, _, _, _, _, _, _, _, _))
|
| + .WillOnce(SaveArg<4>(&start_cb));
|
| + pipeline_controller_.Start(
|
| + nullptr, nullptr, false, base::Closure(), PipelineMetadataCB(),
|
| + BufferingStateCB(), base::Closure(), AddTextTrackCB(), base::Closure());
|
| + Mock::VerifyAndClear(&pipeline_);
|
| + EXPECT_FALSE(pipeline_controller_.IsStable());
|
| + return start_cb;
|
| + }
|
| +
|
| + PipelineStatusCB SeekPipeline(base::TimeDelta time) {
|
| + EXPECT_TRUE(pipeline_controller_.IsStable());
|
| + PipelineStatusCB seek_cb;
|
| + EXPECT_CALL(pipeline_, Seek(time, _)).WillOnce(SaveArg<1>(&seek_cb));
|
| + pipeline_controller_.Seek(time, true);
|
| + Mock::VerifyAndClear(&pipeline_);
|
| + EXPECT_FALSE(pipeline_controller_.IsStable());
|
| + return seek_cb;
|
| + }
|
| +
|
| + PipelineStatusCB SuspendPipeline() {
|
| + EXPECT_TRUE(pipeline_controller_.IsStable());
|
| + PipelineStatusCB suspend_cb;
|
| + EXPECT_CALL(pipeline_, Suspend(_)).WillOnce(SaveArg<0>(&suspend_cb));
|
| + pipeline_controller_.Suspend();
|
| + Mock::VerifyAndClear(&pipeline_);
|
| + EXPECT_FALSE(pipeline_controller_.IsStable());
|
| + EXPECT_FALSE(pipeline_controller_.IsSuspended());
|
| + return suspend_cb;
|
| + }
|
| +
|
| + PipelineStatusCB ResumePipeline() {
|
| + EXPECT_TRUE(pipeline_controller_.IsSuspended());
|
| + PipelineStatusCB resume_cb;
|
| + EXPECT_CALL(pipeline_, Resume(_, _, _))
|
| + .WillOnce(
|
| + DoAll(SaveArg<1>(&last_resume_time_), SaveArg<2>(&resume_cb)));
|
| + EXPECT_CALL(pipeline_, GetMediaTime())
|
| + .WillRepeatedly(Return(base::TimeDelta()));
|
| + pipeline_controller_.Resume();
|
| + Mock::VerifyAndClear(&pipeline_);
|
| + EXPECT_FALSE(pipeline_controller_.IsStable());
|
| + EXPECT_FALSE(pipeline_controller_.IsSuspended());
|
| + return resume_cb;
|
| + }
|
| +
|
| + void Complete(const PipelineStatusCB& cb) {
|
| + cb.Run(PIPELINE_OK);
|
| + message_loop_.RunUntilIdle();
|
| + }
|
| +
|
| + protected:
|
| + scoped_ptr<Renderer> CreateRenderer() { return scoped_ptr<Renderer>(); }
|
| +
|
| + void OnSeeked(bool time_updated) {
|
| + was_seeked_ = true;
|
| + last_seeked_time_updated_ = time_updated;
|
| + }
|
| +
|
| + void OnSuspended() { was_suspended_ = true; }
|
| +
|
| + void OnResumed() { was_resumed_ = true; }
|
| +
|
| + void OnError(PipelineStatus status) { NOTREACHED(); }
|
| +
|
| + base::MessageLoop message_loop_;
|
| +
|
| + StrictMock<MockPipeline> pipeline_;
|
| + PipelineController pipeline_controller_;
|
| +
|
| + bool was_seeked_ = false;
|
| + bool last_seeked_time_updated_ = false;
|
| + bool was_suspended_ = false;
|
| + bool was_resumed_ = false;
|
| + base::TimeDelta last_resume_time_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(PipelineControllerTest);
|
| +};
|
| +
|
| +TEST_F(PipelineControllerTest, Startup) {
|
| + PipelineStatusCB start_cb = StartPipeline();
|
| + EXPECT_FALSE(was_seeked_);
|
| +
|
| + Complete(start_cb);
|
| + EXPECT_TRUE(was_seeked_);
|
| + EXPECT_FALSE(last_seeked_time_updated_);
|
| + EXPECT_FALSE(was_suspended_);
|
| + EXPECT_FALSE(was_resumed_);
|
| + EXPECT_TRUE(pipeline_controller_.IsStable());
|
| +}
|
| +
|
| +TEST_F(PipelineControllerTest, SuspendResume) {
|
| + Complete(StartPipeline());
|
| + EXPECT_TRUE(was_seeked_);
|
| + was_seeked_ = false;
|
| +
|
| + Complete(SuspendPipeline());
|
| + EXPECT_TRUE(was_suspended_);
|
| + EXPECT_FALSE(was_resumed_);
|
| + EXPECT_FALSE(pipeline_controller_.IsStable());
|
| +
|
| + Complete(ResumePipeline());
|
| + EXPECT_TRUE(was_resumed_);
|
| + EXPECT_TRUE(pipeline_controller_.IsStable());
|
| +
|
| + // |was_seeked_| should not be affected by Suspend()/Resume() at all.
|
| + EXPECT_FALSE(was_seeked_);
|
| +}
|
| +
|
| +TEST_F(PipelineControllerTest, PendingSuspend) {
|
| + Complete(StartPipeline());
|
| +
|
| + base::TimeDelta seek_time = base::TimeDelta::FromSeconds(5);
|
| + PipelineStatusCB seek_cb = SeekPipeline(seek_time);
|
| + message_loop_.RunUntilIdle();
|
| +
|
| + // While the seek is ongoing, request a suspend.
|
| + // It will be a mock failure if pipeline_.Suspend() is called.
|
| + pipeline_controller_.Suspend();
|
| + message_loop_.RunUntilIdle();
|
| +
|
| + // Expect the suspend to trigger when the seek is completed.
|
| + EXPECT_CALL(pipeline_, Suspend(_));
|
| + Complete(seek_cb);
|
| +}
|
| +
|
| +TEST_F(PipelineControllerTest, SeekMergesWithResume) {
|
| + Complete(StartPipeline());
|
| + Complete(SuspendPipeline());
|
| +
|
| + // Request a seek while suspended.
|
| + // It will be a mock failure if pipeline_.Seek() is called.
|
| + base::TimeDelta seek_time = base::TimeDelta::FromSeconds(5);
|
| + pipeline_controller_.Seek(seek_time, true);
|
| + message_loop_.RunUntilIdle();
|
| +
|
| + // Resume and verify the resume time includes the seek.
|
| + Complete(ResumePipeline());
|
| + EXPECT_EQ(seek_time, last_resume_time_);
|
| + EXPECT_TRUE(last_seeked_time_updated_);
|
| +}
|
| +
|
| +TEST_F(PipelineControllerTest, SeekMergesWithSeek) {
|
| + Complete(StartPipeline());
|
| +
|
| + base::TimeDelta seek_time_1 = base::TimeDelta::FromSeconds(5);
|
| + PipelineStatusCB seek_cb_1 = SeekPipeline(seek_time_1);
|
| + message_loop_.RunUntilIdle();
|
| +
|
| + // Request another seek while the first is ongoing.
|
| + base::TimeDelta seek_time_2 = base::TimeDelta::FromSeconds(10);
|
| + pipeline_controller_.Seek(seek_time_2, true);
|
| + message_loop_.RunUntilIdle();
|
| +
|
| + // Request a third seek. (It should replace the second.)
|
| + base::TimeDelta seek_time_3 = base::TimeDelta::FromSeconds(15);
|
| + pipeline_controller_.Seek(seek_time_3, true);
|
| + message_loop_.RunUntilIdle();
|
| +
|
| + // Expect the third seek to trigger when the first seek completes.
|
| + EXPECT_CALL(pipeline_, Seek(seek_time_3, _));
|
| + Complete(seek_cb_1);
|
| +}
|
| +
|
| +} // namespace media
|
|
|