Index: media/base/pipeline_unittest.cc |
diff --git a/media/base/pipeline_unittest.cc b/media/base/pipeline_unittest.cc |
index bd00361c47959848dbf2c66e8ff21d59480b0ed5..a9011097ed56cd21916faa7e02b7b222a2d2bb1b 100644 |
--- a/media/base/pipeline_unittest.cc |
+++ b/media/base/pipeline_unittest.cc |
@@ -19,6 +19,7 @@ |
using ::testing::_; |
using ::testing::DeleteArg; |
using ::testing::DoAll; |
+// TODO(scherkus): Remove InSequence after refactoring Pipeline. |
using ::testing::InSequence; |
using ::testing::Invoke; |
using ::testing::InvokeWithoutArgs; |
@@ -41,11 +42,19 @@ ACTION_P(SetDemuxerProperties, duration) { |
arg0->SetDuration(duration); |
} |
-ACTION(RunPipelineStatusCB1) { |
+ACTION_P2(Stop, pipeline, stop_cb) { |
+ pipeline->Stop(stop_cb); |
+} |
+ |
+ACTION_P2(SetError, pipeline, status) { |
+ pipeline->SetErrorForTesting(status); |
+} |
+ |
+ACTION(RunPipelineStatusCB) { |
arg1.Run(PIPELINE_OK); |
} |
-ACTION_P(RunPipelineStatusCB1WithStatus, status) { |
+ACTION_P(RunPipelineStatusCBWithStatus, status) { |
arg1.Run(status); |
} |
@@ -98,6 +107,8 @@ class PipelineTest : public ::testing::Test { |
EXPECT_CALL(*mocks_->demuxer(), Stop(_)) |
.WillOnce(RunClosure()); |
+ // TODO(scherkus): Don't pause+flush on shutdown, |
+ // see http://crbug.com/110228 |
if (audio_stream_) { |
EXPECT_CALL(*mocks_->audio_renderer(), Pause(_)) |
.WillOnce(RunClosure()); |
@@ -134,7 +145,7 @@ class PipelineTest : public ::testing::Test { |
const base::TimeDelta& duration) { |
EXPECT_CALL(*mocks_->demuxer(), Initialize(_, _)) |
.WillOnce(DoAll(SetDemuxerProperties(duration), |
- RunPipelineStatusCB1())); |
+ RunPipelineStatusCB())); |
EXPECT_CALL(*mocks_->demuxer(), SetPlaybackRate(0.0f)); |
// Configure the demuxer to return the streams. |
@@ -162,13 +173,13 @@ class PipelineTest : public ::testing::Test { |
void InitializeVideoDecoder(const scoped_refptr<DemuxerStream>& stream) { |
EXPECT_CALL(*mocks_->video_decoder(), |
Initialize(stream, _, _)) |
- .WillOnce(RunPipelineStatusCB1()); |
+ .WillOnce(RunPipelineStatusCB()); |
} |
// Sets up expectations to allow the audio decoder to initialize. |
void InitializeAudioDecoder(const scoped_refptr<DemuxerStream>& stream) { |
EXPECT_CALL(*mocks_->audio_decoder(), Initialize(stream, _, _)) |
- .WillOnce(RunPipelineStatusCB1()); |
+ .WillOnce(RunPipelineStatusCB()); |
} |
// Sets up expectations to allow the video renderer to initialize. |
@@ -176,13 +187,13 @@ class PipelineTest : public ::testing::Test { |
EXPECT_CALL(*mocks_->video_renderer(), Initialize( |
scoped_refptr<VideoDecoder>(mocks_->video_decoder()), |
_, _, _, _, _, _, _, _)) |
- .WillOnce(RunPipelineStatusCB1()); |
+ .WillOnce(RunPipelineStatusCB()); |
EXPECT_CALL(*mocks_->video_renderer(), SetPlaybackRate(0.0f)); |
// Startup sequence. |
EXPECT_CALL(*mocks_->video_renderer(), |
Preroll(mocks_->demuxer()->GetStartTime(), _)) |
- .WillOnce(RunPipelineStatusCB1()); |
+ .WillOnce(RunPipelineStatusCB()); |
EXPECT_CALL(*mocks_->video_renderer(), Play(_)) |
.WillOnce(RunClosure()); |
} |
@@ -193,21 +204,21 @@ class PipelineTest : public ::testing::Test { |
EXPECT_CALL(*mocks_->audio_renderer(), Initialize( |
scoped_refptr<AudioDecoder>(mocks_->audio_decoder()), |
_, _, _, _, _, _)) |
- .WillOnce(DoAll(RunPipelineStatusCB1(), |
+ .WillOnce(DoAll(RunPipelineStatusCB(), |
WithArg<5>(RunClosure()))); // |disabled_cb|. |
} else { |
EXPECT_CALL(*mocks_->audio_renderer(), Initialize( |
scoped_refptr<AudioDecoder>(mocks_->audio_decoder()), |
_, _, _, _, _, _)) |
.WillOnce(DoAll(SaveArg<3>(&audio_time_cb_), |
- RunPipelineStatusCB1())); |
+ RunPipelineStatusCB())); |
} |
EXPECT_CALL(*mocks_->audio_renderer(), SetPlaybackRate(0.0f)); |
EXPECT_CALL(*mocks_->audio_renderer(), SetVolume(1.0f)); |
// Startup sequence. |
EXPECT_CALL(*mocks_->audio_renderer(), Preroll(base::TimeDelta(), _)) |
- .WillOnce(RunPipelineStatusCB1()); |
+ .WillOnce(RunPipelineStatusCB()); |
EXPECT_CALL(*mocks_->audio_renderer(), Play(_)) |
.WillOnce(RunClosure()); |
} |
@@ -244,7 +255,7 @@ class PipelineTest : public ::testing::Test { |
void ExpectSeek(const base::TimeDelta& seek_time) { |
// Every filter should receive a call to Seek(). |
EXPECT_CALL(*mocks_->demuxer(), Seek(seek_time, _)) |
- .WillOnce(RunPipelineStatusCB1()); |
+ .WillOnce(RunPipelineStatusCB()); |
if (audio_stream_) { |
EXPECT_CALL(*mocks_->audio_renderer(), Pause(_)) |
@@ -252,7 +263,7 @@ class PipelineTest : public ::testing::Test { |
EXPECT_CALL(*mocks_->audio_renderer(), Flush(_)) |
.WillOnce(RunClosure()); |
EXPECT_CALL(*mocks_->audio_renderer(), Preroll(seek_time, _)) |
- .WillOnce(RunPipelineStatusCB1()); |
+ .WillOnce(RunPipelineStatusCB()); |
EXPECT_CALL(*mocks_->audio_renderer(), Play(_)) |
.WillOnce(RunClosure()); |
} |
@@ -263,7 +274,7 @@ class PipelineTest : public ::testing::Test { |
EXPECT_CALL(*mocks_->video_renderer(), Flush(_)) |
.WillOnce(RunClosure()); |
EXPECT_CALL(*mocks_->video_renderer(), Preroll(seek_time, _)) |
- .WillOnce(RunPipelineStatusCB1()); |
+ .WillOnce(RunPipelineStatusCB()); |
EXPECT_CALL(*mocks_->video_renderer(), Play(_)) |
.WillOnce(RunClosure()); |
} |
@@ -375,7 +386,7 @@ TEST_F(PipelineTest, RequiredFilterMissing) { |
TEST_F(PipelineTest, URLNotFound) { |
EXPECT_CALL(*mocks_->demuxer(), Initialize(_, _)) |
- .WillOnce(RunPipelineStatusCB1WithStatus(PIPELINE_ERROR_URL_NOT_FOUND)); |
+ .WillOnce(RunPipelineStatusCBWithStatus(PIPELINE_ERROR_URL_NOT_FOUND)); |
EXPECT_CALL(*mocks_->demuxer(), Stop(_)) |
.WillOnce(RunClosure()); |
@@ -385,7 +396,7 @@ TEST_F(PipelineTest, URLNotFound) { |
TEST_F(PipelineTest, NoStreams) { |
EXPECT_CALL(*mocks_->demuxer(), Initialize(_, _)) |
- .WillOnce(RunPipelineStatusCB1()); |
+ .WillOnce(RunPipelineStatusCB()); |
EXPECT_CALL(*mocks_->demuxer(), Stop(_)) |
.WillOnce(RunClosure()); |
@@ -737,7 +748,7 @@ TEST_F(PipelineTest, ErrorDuringSeek) { |
.WillOnce(RunClosure()); |
EXPECT_CALL(*mocks_->demuxer(), Seek(seek_time, _)) |
- .WillOnce(RunPipelineStatusCB1WithStatus(PIPELINE_ERROR_READ)); |
+ .WillOnce(RunPipelineStatusCBWithStatus(PIPELINE_ERROR_READ)); |
EXPECT_CALL(*mocks_->demuxer(), Stop(_)) |
.WillOnce(RunClosure()); |
@@ -793,7 +804,7 @@ TEST_F(PipelineTest, NoMessageDuringTearDownFromError) { |
.WillOnce(RunClosure()); |
EXPECT_CALL(*mocks_->demuxer(), Seek(seek_time, _)) |
- .WillOnce(RunPipelineStatusCB1WithStatus(PIPELINE_ERROR_READ)); |
+ .WillOnce(RunPipelineStatusCBWithStatus(PIPELINE_ERROR_READ)); |
EXPECT_CALL(*mocks_->demuxer(), Stop(_)) |
.WillOnce(RunClosure()); |
@@ -880,14 +891,14 @@ TEST_F(PipelineTest, AudioTimeUpdateDuringSeek) { |
base::Closure closure = base::Bind(&RunTimeCB, audio_time_cb_, 300, 700); |
EXPECT_CALL(*mocks_->demuxer(), Seek(seek_time, _)) |
.WillOnce(DoAll(InvokeWithoutArgs(&closure, &base::Closure::Run), |
- RunPipelineStatusCB1())); |
+ RunPipelineStatusCB())); |
EXPECT_CALL(*mocks_->audio_renderer(), Pause(_)) |
.WillOnce(RunClosure()); |
EXPECT_CALL(*mocks_->audio_renderer(), Flush(_)) |
.WillOnce(RunClosure()); |
EXPECT_CALL(*mocks_->audio_renderer(), Preroll(seek_time, _)) |
- .WillOnce(RunPipelineStatusCB1()); |
+ .WillOnce(RunPipelineStatusCB()); |
EXPECT_CALL(*mocks_->audio_renderer(), Play(_)) |
.WillOnce(RunClosure()); |
@@ -957,4 +968,223 @@ TEST(PipelineStatusNotificationTest, DelayedCallback) { |
TestPipelineStatusNotification(base::TimeDelta::FromMilliseconds(20)); |
} |
+class PipelineTeardownTest : public PipelineTest { |
+ public: |
+ enum TeardownState { |
+ kPausing, |
+ kFlushing, |
+ kSeeking, |
+ kPrerolling, |
+ kStarting, |
+ kPlaying, |
+ }; |
+ |
+ enum StopOrError { |
+ kStop, |
+ kError, |
+ }; |
+ |
+ PipelineTeardownTest() { |
+ CreateAudioStream(); |
+ MockDemuxerStreamVector streams; |
+ streams.push_back(audio_stream()); |
+ |
+ InitializeDemuxer(&streams, base::TimeDelta::FromSeconds(3000)); |
+ InitializeAudioDecoder(audio_stream()); |
+ InitializeAudioRenderer(); |
+ InitializePipeline(PIPELINE_OK); |
+ } |
+ |
+ void RunTest(TeardownState state, StopOrError stop_or_error) { |
+ InSequence s; |
+ switch (state) { |
+ case kPausing: |
+ case kFlushing: |
+ case kSeeking: |
+ case kPrerolling: |
+ case kStarting: |
+ if (stop_or_error == kStop) { |
+ ExpectSeekStop(state); |
+ } else { |
+ ExpectSeekError(state); |
+ } |
+ DoSeek(); |
+ break; |
+ |
+ case kPlaying: |
+ if (stop_or_error == kStop) { |
+ ExpectStop(); |
+ DoStop(); |
+ } else { |
+ ExpectPlaybackError(); |
+ DoPlaybackError(); |
+ } |
+ break; |
+ } |
+ } |
+ |
+ private: |
+ // TODO(scherkus): Why separate stop/error enums and helper functions? We do |
Ami GONE FROM CHROMIUM
2012/08/09 04:41:43
rewrite comment.
scherkus (not reviewing)
2012/08/09 16:52:39
Done.
|
+ // radically different things whether teardown is invoked via stop vs error. |
+ // The teardown path should be the same, see http://crbug.com/110228 |
+ void ExpectSeekStop(TeardownState state) { |
+ base::Closure stop_cb = base::Bind( |
+ &CallbackHelper::OnStop, base::Unretained(&callbacks_)); |
+ |
+ if (state == kPausing) { |
+ EXPECT_CALL(*mocks_->audio_renderer(), Pause(_)) |
+ .WillOnce(DoAll(Stop(pipeline_, stop_cb), RunClosure())); |
+ } else { |
+ EXPECT_CALL(*mocks_->audio_renderer(), Pause(_)).WillOnce(RunClosure()); |
+ } |
+ |
+ if (state == kFlushing) { |
+ EXPECT_CALL(*mocks_->audio_renderer(), Flush(_)) |
+ .WillOnce(DoAll(Stop(pipeline_, stop_cb), RunClosure())); |
+ } else { |
+ EXPECT_CALL(*mocks_->audio_renderer(), Flush(_)).WillOnce(RunClosure()); |
+ } |
+ |
+ if (state == kSeeking) { |
+ EXPECT_CALL(*mocks_->demuxer(), Seek(_, _)) |
+ .WillOnce(DoAll(Stop(pipeline_, stop_cb), RunPipelineStatusCB())); |
+ } else { |
+ EXPECT_CALL(*mocks_->demuxer(), Seek(_, _)) |
+ .WillOnce(RunPipelineStatusCB()); |
+ } |
+ |
+ if (state == kPrerolling) { |
+ EXPECT_CALL(*mocks_->audio_renderer(), Preroll(_, _)) |
+ .WillOnce(DoAll(Stop(pipeline_, stop_cb), RunPipelineStatusCB())); |
+ } else { |
+ EXPECT_CALL(*mocks_->audio_renderer(), Preroll(_, _)) |
+ .WillOnce(RunPipelineStatusCB()); |
+ } |
+ |
+ if (state == kStarting) { |
+ EXPECT_CALL(*mocks_->audio_renderer(), Play(_)) |
+ .WillOnce(DoAll(Stop(pipeline_, stop_cb), RunClosure())); |
+ } else { |
+ EXPECT_CALL(*mocks_->audio_renderer(), Play(_)).WillOnce(RunClosure()); |
+ } |
+ |
+ EXPECT_CALL(callbacks_, OnSeek(PIPELINE_OK)); |
+ ExpectStop(); |
+ } |
+ |
+ void ExpectSeekError(TeardownState state) { |
+ SetSeekErrorExpectations(state); |
+ |
+ // Executed after the error is raised. |
+ EXPECT_CALL(callbacks_, OnSeek(PIPELINE_ERROR_READ)); |
+ EXPECT_CALL(*mocks_->demuxer(), Stop(_)).WillOnce(RunClosure()); |
+ EXPECT_CALL(*mocks_->audio_renderer(), Stop(_)).WillOnce(RunClosure()); |
+ } |
+ |
+ void SetSeekErrorExpectations(TeardownState state) { |
+ if (state == kPausing) { |
+ EXPECT_CALL(*mocks_->audio_renderer(), Pause(_)) |
+ .WillOnce(DoAll(SetError(pipeline_, PIPELINE_ERROR_READ), |
+ RunClosure())); |
+ return; |
+ } |
+ |
+ EXPECT_CALL(*mocks_->audio_renderer(), Pause(_)).WillOnce(RunClosure()); |
+ |
+ if (state == kFlushing) { |
+ EXPECT_CALL(*mocks_->audio_renderer(), Flush(_)) |
+ .WillOnce(DoAll(SetError(pipeline_, PIPELINE_ERROR_READ), |
+ RunClosure())); |
+ return; |
+ } |
+ |
+ EXPECT_CALL(*mocks_->audio_renderer(), Flush(_)).WillOnce(RunClosure()); |
+ |
+ if (state == kSeeking) { |
+ EXPECT_CALL(*mocks_->demuxer(), Seek(_, _)) |
+ .WillOnce(RunPipelineStatusCBWithStatus(PIPELINE_ERROR_READ)); |
+ return; |
+ } |
+ |
+ EXPECT_CALL(*mocks_->demuxer(), Seek(_, _)) |
+ .WillOnce(RunPipelineStatusCB()); |
+ |
+ if (state == kPrerolling) { |
+ EXPECT_CALL(*mocks_->audio_renderer(), Preroll(_, _)) |
+ .WillOnce(RunPipelineStatusCBWithStatus(PIPELINE_ERROR_READ)); |
+ return; |
+ } |
+ |
+ EXPECT_CALL(*mocks_->audio_renderer(), Preroll(_, _)) |
+ .WillOnce(RunPipelineStatusCB()); |
+ |
+ if (state == kStarting) { |
+ EXPECT_CALL(*mocks_->audio_renderer(), Play(_)) |
+ .WillOnce(DoAll(SetError(pipeline_, PIPELINE_ERROR_READ), |
+ RunClosure())); |
+ return; |
+ } |
+ |
+ NOTREACHED() << "Unexpected TeardownState: " << state; |
+ } |
+ |
+ void ExpectStop() { |
+ // TODO(scherkus): Don't pause+flush, see http://crbug.com/110228 |
+ EXPECT_CALL(*mocks_->audio_renderer(), Pause(_)).WillOnce(RunClosure()); |
+ EXPECT_CALL(*mocks_->audio_renderer(), Flush(_)).WillOnce(RunClosure()); |
+ EXPECT_CALL(*mocks_->demuxer(), Stop(_)).WillOnce(RunClosure()); |
+ EXPECT_CALL(*mocks_->audio_renderer(), Stop(_)).WillOnce(RunClosure()); |
+ |
+ EXPECT_CALL(callbacks_, OnStop()); |
+ } |
+ |
+ void ExpectPlaybackError() { |
+ // TODO(scherkus): Don't pause+flush, see http://crbug.com/110228 |
+ EXPECT_CALL(*mocks_->audio_renderer(), Pause(_)).WillOnce(RunClosure()); |
+ EXPECT_CALL(*mocks_->audio_renderer(), Flush(_)).WillOnce(RunClosure()); |
+ EXPECT_CALL(*mocks_->demuxer(), Stop(_)).WillOnce(RunClosure()); |
+ EXPECT_CALL(*mocks_->audio_renderer(), Stop(_)).WillOnce(RunClosure()); |
+ |
+ EXPECT_CALL(callbacks_, OnError(PIPELINE_ERROR_READ)); |
+ } |
+ |
+ void DoSeek() { |
+ pipeline_->Seek(base::TimeDelta::FromSeconds(10), base::Bind( |
+ &CallbackHelper::OnSeek, base::Unretained(&callbacks_))); |
+ message_loop_.RunAllPending(); |
+ } |
+ |
+ void DoStop() { |
+ pipeline_->Stop(base::Bind( |
+ &CallbackHelper::OnStop, base::Unretained(&callbacks_))); |
+ message_loop_.RunAllPending(); |
+ } |
+ |
+ void DoPlaybackError() { |
+ pipeline_->SetErrorForTesting(PIPELINE_ERROR_READ); |
+ message_loop_.RunAllPending(); |
+ } |
+ |
+ DISALLOW_COPY_AND_ASSIGN(PipelineTeardownTest); |
+}; |
+ |
+#define INSTANTIATE_TEARDOWN_TEST(stop_or_error, state) \ |
+ TEST_F(PipelineTeardownTest, stop_or_error##_##state) { \ |
+ RunTest(k##state, k##stop_or_error); \ |
+ } |
+ |
+INSTANTIATE_TEARDOWN_TEST(Stop, Pausing); |
+INSTANTIATE_TEARDOWN_TEST(Stop, Flushing); |
+INSTANTIATE_TEARDOWN_TEST(Stop, Seeking); |
+INSTANTIATE_TEARDOWN_TEST(Stop, Prerolling); |
+INSTANTIATE_TEARDOWN_TEST(Stop, Starting); |
+INSTANTIATE_TEARDOWN_TEST(Stop, Playing); |
+ |
+INSTANTIATE_TEARDOWN_TEST(Error, Pausing); |
+INSTANTIATE_TEARDOWN_TEST(Error, Flushing); |
+INSTANTIATE_TEARDOWN_TEST(Error, Seeking); |
+INSTANTIATE_TEARDOWN_TEST(Error, Prerolling); |
+INSTANTIATE_TEARDOWN_TEST(Error, Starting); |
+INSTANTIATE_TEARDOWN_TEST(Error, Playing); |
+ |
} // namespace media |