Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1723)

Unified Diff: media/base/pipeline_unittest.cc

Issue 10832197: Add a lot of Pipeline tests to cover stopping/error handling while in a variety of states. (Closed) Base URL: svn://chrome-svn/chrome/trunk/src
Patch Set: todo Created 8 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « media/base/pipeline.cc ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: media/base/pipeline_unittest.cc
diff --git a/media/base/pipeline_unittest.cc b/media/base/pipeline_unittest.cc
index c949ef1b82faa71bea59f4acfa26a17de9600609..36b42578d877bcceb3f2be7f11a92331cf5ec5f1 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()));
// Configure the demuxer to return the streams.
for (size_t i = 0; i < streams->size(); ++i) {
@@ -161,13 +172,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.
@@ -175,13 +186,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());
}
@@ -192,14 +203,14 @@ 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()));
}
}
@@ -217,7 +228,7 @@ class PipelineTest : public ::testing::Test {
// Startup sequence.
EXPECT_CALL(*mocks_->audio_renderer(), Preroll(base::TimeDelta(), _))
- .WillOnce(RunPipelineStatusCB1());
+ .WillOnce(RunPipelineStatusCB());
EXPECT_CALL(*mocks_->audio_renderer(), Play(_))
.WillOnce(RunClosure());
}
@@ -250,7 +261,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(_))
@@ -258,7 +269,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());
}
@@ -269,7 +280,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());
}
@@ -381,7 +392,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());
@@ -391,7 +402,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());
@@ -720,7 +731,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());
@@ -776,7 +787,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());
@@ -863,14 +874,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());
@@ -890,7 +901,7 @@ TEST_F(PipelineTest, AudioTimeUpdateDuringSeek) {
TEST_F(PipelineTest, InitFailure_Demuxer) {
PipelineStatus expected_status = DEMUXER_ERROR_COULD_NOT_OPEN;
EXPECT_CALL(*mocks_->demuxer(), Initialize(_, _))
- .WillOnce(RunPipelineStatusCB1WithStatus(expected_status));
+ .WillOnce(RunPipelineStatusCBWithStatus(expected_status));
EXPECT_CALL(*mocks_->demuxer(), Stop(_))
.WillOnce(RunClosure());
InitializePipeline(expected_status);
@@ -907,7 +918,7 @@ TEST_F(PipelineTest, InitFailure_AudioDecoder) {
PipelineStatus expected_status = PIPELINE_ERROR_DECODE;
scoped_refptr<DemuxerStream> stream = streams[0];
EXPECT_CALL(*mocks_->audio_decoder(), Initialize(stream, _, _))
- .WillOnce(RunPipelineStatusCB1WithStatus(expected_status));
+ .WillOnce(RunPipelineStatusCBWithStatus(expected_status));
EXPECT_CALL(*mocks_->demuxer(), Stop(_))
.WillOnce(RunClosure());
@@ -929,7 +940,7 @@ TEST_F(PipelineTest, InitFailure_AudioRenderer) {
EXPECT_CALL(*mocks_->audio_renderer(), Initialize(
scoped_refptr<AudioDecoder>(mocks_->audio_decoder()),
_, _, _, _, _, _))
- .WillOnce(RunPipelineStatusCB1WithStatus(expected_status));
+ .WillOnce(RunPipelineStatusCBWithStatus(expected_status));
EXPECT_CALL(*mocks_->demuxer(), Stop(_))
.WillOnce(RunClosure());
@@ -956,7 +967,7 @@ TEST_F(PipelineTest, InitFailure_VideoDecoder) {
scoped_refptr<DemuxerStream> stream = streams[1];
EXPECT_CALL(*mocks_->video_decoder(),
Initialize(stream, _, _))
- .WillOnce(RunPipelineStatusCB1WithStatus(expected_status));
+ .WillOnce(RunPipelineStatusCBWithStatus(expected_status));
EXPECT_CALL(*mocks_->demuxer(), Stop(_))
.WillOnce(RunClosure());
@@ -985,7 +996,7 @@ TEST_F(PipelineTest, InitFailure_VideoRenderer) {
EXPECT_CALL(*mocks_->video_renderer(), Initialize(
scoped_refptr<VideoDecoder>(mocks_->video_decoder()),
_, _, _, _, _, _, _, _))
- .WillOnce(RunPipelineStatusCB1WithStatus(expected_status));
+ .WillOnce(RunPipelineStatusCBWithStatus(expected_status));
EXPECT_CALL(*mocks_->demuxer(), Stop(_))
.WillOnce(RunClosure());
@@ -1053,4 +1064,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): We do 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
« no previous file with comments | « media/base/pipeline.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698