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

Side by Side 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: helpers galore 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 unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « media/base/pipeline.cc ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include <vector> 5 #include <vector>
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/message_loop.h" 8 #include "base/message_loop.h"
9 #include "base/stl_util.h" 9 #include "base/stl_util.h"
10 #include "base/threading/simple_thread.h" 10 #include "base/threading/simple_thread.h"
11 #include "media/base/clock.h" 11 #include "media/base/clock.h"
12 #include "media/base/media_log.h" 12 #include "media/base/media_log.h"
13 #include "media/base/pipeline.h" 13 #include "media/base/pipeline.h"
14 #include "media/base/mock_callback.h" 14 #include "media/base/mock_callback.h"
15 #include "media/base/mock_filters.h" 15 #include "media/base/mock_filters.h"
16 #include "testing/gtest/include/gtest/gtest.h" 16 #include "testing/gtest/include/gtest/gtest.h"
17 #include "ui/gfx/size.h" 17 #include "ui/gfx/size.h"
18 18
19 using ::testing::_; 19 using ::testing::_;
20 using ::testing::DeleteArg; 20 using ::testing::DeleteArg;
21 using ::testing::DoAll; 21 using ::testing::DoAll;
22 // TODO(scherkus): Remove InSequence after refactoring Pipeline.
22 using ::testing::InSequence; 23 using ::testing::InSequence;
23 using ::testing::Invoke; 24 using ::testing::Invoke;
24 using ::testing::InvokeWithoutArgs; 25 using ::testing::InvokeWithoutArgs;
25 using ::testing::Mock; 26 using ::testing::Mock;
26 using ::testing::NotNull; 27 using ::testing::NotNull;
27 using ::testing::Return; 28 using ::testing::Return;
28 using ::testing::ReturnRef; 29 using ::testing::ReturnRef;
29 using ::testing::SaveArg; 30 using ::testing::SaveArg;
30 using ::testing::StrictMock; 31 using ::testing::StrictMock;
31 using ::testing::WithArg; 32 using ::testing::WithArg;
32 33
33 namespace media { 34 namespace media {
34 35
35 // Demuxer properties. 36 // Demuxer properties.
36 static const int kTotalBytes = 1024; 37 static const int kTotalBytes = 1024;
37 static const int kBitrate = 1234; 38 static const int kBitrate = 1234;
38 39
39 ACTION_P(SetDemuxerProperties, duration) { 40 ACTION_P(SetDemuxerProperties, duration) {
40 arg0->SetTotalBytes(kTotalBytes); 41 arg0->SetTotalBytes(kTotalBytes);
41 arg0->SetDuration(duration); 42 arg0->SetDuration(duration);
42 } 43 }
43 44
45 ACTION_P2(Stop, pipeline, stop_cb) {
46 pipeline->Stop(stop_cb);
47 }
48
49 ACTION_P2(SetError, pipeline, status) {
50 pipeline->SetErrorForTesting(status);
51 }
52
44 ACTION(RunPipelineStatusCB1) { 53 ACTION(RunPipelineStatusCB1) {
Ami GONE FROM CHROMIUM 2012/08/08 23:43:55 s/1//
scherkus (not reviewing) 2012/08/09 01:18:19 I swore we had other versions around but I guess I
45 arg1.Run(PIPELINE_OK); 54 arg1.Run(PIPELINE_OK);
46 } 55 }
47 56
48 ACTION_P(RunPipelineStatusCB1WithStatus, status) { 57 ACTION_P(RunPipelineStatusCB1WithStatus, status) {
49 arg1.Run(status); 58 arg1.Run(status);
50 } 59 }
51 60
52 // Used for setting expectations on pipeline callbacks. Using a StrictMock 61 // Used for setting expectations on pipeline callbacks. Using a StrictMock
53 // also lets us test for missing callbacks. 62 // also lets us test for missing callbacks.
54 class CallbackHelper { 63 class CallbackHelper {
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
91 virtual ~PipelineTest() { 100 virtual ~PipelineTest() {
92 if (!pipeline_->IsRunning()) { 101 if (!pipeline_->IsRunning()) {
93 return; 102 return;
94 } 103 }
95 104
96 // Shutdown sequence. 105 // Shutdown sequence.
97 if (pipeline_->IsInitialized()) { 106 if (pipeline_->IsInitialized()) {
98 EXPECT_CALL(*mocks_->demuxer(), Stop(_)) 107 EXPECT_CALL(*mocks_->demuxer(), Stop(_))
99 .WillOnce(RunClosure()); 108 .WillOnce(RunClosure());
100 109
110 // TODO(scherkus): Don't pause+flush on shutdown,
111 // see http://crbug.com/110228
101 if (audio_stream_) { 112 if (audio_stream_) {
102 EXPECT_CALL(*mocks_->audio_renderer(), Pause(_)) 113 EXPECT_CALL(*mocks_->audio_renderer(), Pause(_))
103 .WillOnce(RunClosure()); 114 .WillOnce(RunClosure());
104 EXPECT_CALL(*mocks_->audio_renderer(), Flush(_)) 115 EXPECT_CALL(*mocks_->audio_renderer(), Flush(_))
105 .WillOnce(RunClosure()); 116 .WillOnce(RunClosure());
106 EXPECT_CALL(*mocks_->audio_renderer(), Stop(_)) 117 EXPECT_CALL(*mocks_->audio_renderer(), Stop(_))
107 .WillOnce(RunClosure()); 118 .WillOnce(RunClosure());
108 } 119 }
109 120
110 if (video_stream_) { 121 if (video_stream_) {
(...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after
276 pipeline_->Seek(seek_time, 287 pipeline_->Seek(seek_time,
277 base::Bind(&CallbackHelper::OnSeek, 288 base::Bind(&CallbackHelper::OnSeek,
278 base::Unretained(&callbacks_))); 289 base::Unretained(&callbacks_)));
279 290
280 // We expect the time to be updated only after the seek has completed. 291 // We expect the time to be updated only after the seek has completed.
281 EXPECT_NE(seek_time, pipeline_->GetMediaTime()); 292 EXPECT_NE(seek_time, pipeline_->GetMediaTime());
282 message_loop_.RunAllPending(); 293 message_loop_.RunAllPending();
283 EXPECT_EQ(seek_time, pipeline_->GetMediaTime()); 294 EXPECT_EQ(seek_time, pipeline_->GetMediaTime());
284 } 295 }
285 296
297 // Initializes a pipeline containing a single audio stream.
298 void InitializeAudioPipeline() {
299 CreateAudioStream();
300 MockDemuxerStreamVector streams;
301 streams.push_back(audio_stream());
302
303 InitializeDemuxer(&streams, base::TimeDelta::FromSeconds(3000));
304 InitializeAudioDecoder(audio_stream());
305 InitializeAudioRenderer();
306 InitializePipeline(PIPELINE_OK);
307 }
308
309 // TODO(scherkus): Why separate stop/error enums and helper functions? We do
310 // radically different things whether teardown is invoked via stop vs error.
311 // The teardown path should be the same, see http://crbug.com/110228
312
313 enum StopOnSeekState {
Ami GONE FROM CHROMIUM 2012/08/08 23:43:55 I read your TODO above, but AFAICT these are only
scherkus (not reviewing) 2012/08/09 01:18:19 Took a stab but I strongly dislike how gtest param
Ami GONE FROM CHROMIUM 2012/08/09 04:41:43 Yeah, I didn't mean TEST_P necessarily.
314 kStopOnPause,
315 kStopOnFlush,
316 kStopOnSeek,
317 };
318
319 enum ErrorOnSeekState {
Ami GONE FROM CHROMIUM 2012/08/08 23:43:55 Ditto.
320 kErrorOnPause,
321 kErrorOnFlush,
322 kErrorOnSeek,
323 };
324
325 void ExpectAudioPipelineSeekStop(StopOnSeekState action) {
326 base::Closure stop_cb = base::Bind(
327 &CallbackHelper::OnStop, base::Unretained(&callbacks_));
328
329 if (action == kStopOnPause) {
330 EXPECT_CALL(*mocks_->audio_renderer(), Pause(_))
331 .WillOnce(DoAll(Stop(pipeline_, stop_cb), RunClosure()));
332 } else {
333 EXPECT_CALL(*mocks_->audio_renderer(), Pause(_)).WillOnce(RunClosure());
334 }
335
336 if (action == kStopOnFlush) {
337 EXPECT_CALL(*mocks_->audio_renderer(), Flush(_))
338 .WillOnce(DoAll(Stop(pipeline_, stop_cb), RunClosure()));
339 } else {
340 EXPECT_CALL(*mocks_->audio_renderer(), Flush(_)).WillOnce(RunClosure());
341 }
342
343 if (action == kStopOnSeek) {
344 EXPECT_CALL(*mocks_->demuxer(), Seek(_, _))
345 .WillOnce(DoAll(Stop(pipeline_, stop_cb),
346 RunPipelineStatusCB1WithStatus(PIPELINE_OK)));
Ami GONE FROM CHROMIUM 2012/08/08 23:43:55 Isn't this just RunPipelineStatusCB1()?
scherkus (not reviewing) 2012/08/09 01:18:19 Done.
347 } else {
348 EXPECT_CALL(*mocks_->demuxer(), Seek(_, _))
349 .WillOnce(RunPipelineStatusCB1());
350 }
351
352 EXPECT_CALL(*mocks_->audio_renderer(), Preroll(_, _))
353 .WillOnce(RunPipelineStatusCB1());
354 EXPECT_CALL(*mocks_->audio_renderer(), Play(_)).WillOnce(RunClosure());
355 EXPECT_CALL(callbacks_, OnSeek(PIPELINE_OK));
356 }
357
358 void ExpectAudioPipelineSeekError(ErrorOnSeekState action) {
359 if (action == kErrorOnPause) {
360 EXPECT_CALL(*mocks_->audio_renderer(), Pause(_))
361 .WillOnce(DoAll(SetError(pipeline_, PIPELINE_ERROR_READ),
362 RunClosure()));
363 EXPECT_CALL(callbacks_, OnSeek(PIPELINE_ERROR_READ));
364 return;
365 }
366
367 EXPECT_CALL(*mocks_->audio_renderer(), Pause(_)).WillOnce(RunClosure());
368
369 if (action == kErrorOnFlush) {
370 EXPECT_CALL(*mocks_->audio_renderer(), Flush(_))
371 .WillOnce(DoAll(SetError(pipeline_, PIPELINE_ERROR_READ),
372 RunClosure()));
373 EXPECT_CALL(callbacks_, OnSeek(PIPELINE_ERROR_READ));
374 return;
375 }
376
377 EXPECT_CALL(*mocks_->audio_renderer(), Flush(_)).WillOnce(RunClosure());
378
379 if (action == kErrorOnSeek) {
380 EXPECT_CALL(*mocks_->demuxer(), Seek(_, _))
381 .WillOnce(RunPipelineStatusCB1WithStatus(PIPELINE_ERROR_READ));
382 EXPECT_CALL(callbacks_, OnSeek(PIPELINE_ERROR_READ));
383 return;
384 }
385
386 NOTREACHED();
387 }
388
389 void ExpectAudioPipelineStop() {
390 // TODO(scherkus): Don't pause+flush, see http://crbug.com/110228
391 EXPECT_CALL(*mocks_->audio_renderer(), Pause(_)).WillOnce(RunClosure());
392 EXPECT_CALL(*mocks_->audio_renderer(), Flush(_)).WillOnce(RunClosure());
393 EXPECT_CALL(*mocks_->demuxer(), Stop(_)).WillOnce(RunClosure());
394 EXPECT_CALL(*mocks_->audio_renderer(), Stop(_)).WillOnce(RunClosure());
395 EXPECT_CALL(callbacks_, OnStop());
396 }
397
398 void ExpectAudioPipelineError() {
399 EXPECT_CALL(*mocks_->demuxer(), Stop(_)).WillOnce(RunClosure());
400 EXPECT_CALL(*mocks_->audio_renderer(), Stop(_)).WillOnce(RunClosure());
401 }
402
403 void DoAudioPipelineSeek() {
404 pipeline_->Seek(base::TimeDelta::FromSeconds(10), base::Bind(
405 &CallbackHelper::OnSeek, base::Unretained(&callbacks_)));
406 message_loop_.RunAllPending();
407 }
408
409 void DoAudioPipelineStop() {
410 pipeline_->Stop(base::Bind(
411 &CallbackHelper::OnStop, base::Unretained(&callbacks_)));
412 message_loop_.RunAllPending();
413 }
414
286 // Fixture members. 415 // Fixture members.
287 StrictMock<CallbackHelper> callbacks_; 416 StrictMock<CallbackHelper> callbacks_;
288 MessageLoop message_loop_; 417 MessageLoop message_loop_;
289 scoped_refptr<Pipeline> pipeline_; 418 scoped_refptr<Pipeline> pipeline_;
290 scoped_ptr<media::MockFilterCollection> mocks_; 419 scoped_ptr<media::MockFilterCollection> mocks_;
291 scoped_refptr<StrictMock<MockDemuxerStream> > audio_stream_; 420 scoped_refptr<StrictMock<MockDemuxerStream> > audio_stream_;
292 scoped_refptr<StrictMock<MockDemuxerStream> > video_stream_; 421 scoped_refptr<StrictMock<MockDemuxerStream> > video_stream_;
293 AudioRenderer::TimeCB audio_time_cb_; 422 AudioRenderer::TimeCB audio_time_cb_;
294 423
295 private: 424 private:
(...skipping 161 matching lines...) Expand 10 before | Expand all | Expand 10 after
457 586
458 // Initialize then seek! 587 // Initialize then seek!
459 InitializePipeline(PIPELINE_OK); 588 InitializePipeline(PIPELINE_OK);
460 589
461 // Every filter should receive a call to Seek(). 590 // Every filter should receive a call to Seek().
462 base::TimeDelta expected = base::TimeDelta::FromSeconds(2000); 591 base::TimeDelta expected = base::TimeDelta::FromSeconds(2000);
463 ExpectSeek(expected); 592 ExpectSeek(expected);
464 DoSeek(expected); 593 DoSeek(expected);
465 } 594 }
466 595
596 TEST_F(PipelineTest, Stop_DuringStart) {
597 base::Closure stop_cb = base::Bind(
598 &CallbackHelper::OnStop, base::Unretained(&callbacks_));
599
600 EXPECT_CALL(*mocks_->demuxer(), Initialize(_, _))
601 .WillOnce(DoAll(Stop(pipeline_, stop_cb), RunPipelineStatusCB1()));
602
603 // Stop sequence.
604 EXPECT_CALL(*mocks_->demuxer(), Stop(_))
605 .WillOnce(RunClosure());
606 EXPECT_CALL(callbacks_, OnStop());
607
608 InitializePipeline(PIPELINE_OK);
609 }
610
611 TEST_F(PipelineTest, Stop_DuringPause) {
612 InitializeAudioPipeline();
613
614 InSequence s;
615 ExpectAudioPipelineSeekStop(kStopOnPause);
616 ExpectAudioPipelineStop();
617
618 DoAudioPipelineSeek();
619 }
620
621 TEST_F(PipelineTest, Stop_DuringFlush) {
622 InitializeAudioPipeline();
623
624 InSequence s;
625 ExpectAudioPipelineSeekStop(kStopOnFlush);
626 ExpectAudioPipelineStop();
627
628 DoAudioPipelineSeek();
629 }
630
631 TEST_F(PipelineTest, Stop_DuringSeek) {
632 InitializeAudioPipeline();
633
634 InSequence s;
635 ExpectAudioPipelineSeekStop(kStopOnSeek);
636 ExpectAudioPipelineStop();
637
638 DoAudioPipelineSeek();
639 }
640
641 TEST_F(PipelineTest, Stop_DuringPlayback) {
642 InitializeAudioPipeline();
643
644 InSequence s;
645 ExpectAudioPipelineStop();
646
647 DoAudioPipelineStop();
648 }
649
650 TEST_F(PipelineTest, Error_DuringStart) {
651 EXPECT_CALL(*mocks_->demuxer(), Initialize(_, _))
652 .WillOnce(RunPipelineStatusCB1WithStatus(PIPELINE_ERROR_READ));
653
654 // Stop sequence.
655 EXPECT_CALL(*mocks_->demuxer(), Stop(_))
656 .WillOnce(RunClosure());
657
658 // Start callback should fire with error but nothing else.
659 InitializePipeline(PIPELINE_ERROR_READ);
660 }
661
662 TEST_F(PipelineTest, Error_DuringPause) {
663 InitializeAudioPipeline();
664
665 InSequence s;
666 ExpectAudioPipelineSeekError(kErrorOnPause);
667 ExpectAudioPipelineError();
668
669 DoAudioPipelineSeek();
670 }
671
672 TEST_F(PipelineTest, Error_DuringFlush) {
673 InitializeAudioPipeline();
674
675 InSequence s;
676 ExpectAudioPipelineSeekError(kErrorOnFlush);
677 ExpectAudioPipelineError();
678
679 DoAudioPipelineSeek();
680 }
681
682 TEST_F(PipelineTest, Error_DuringSeek) {
683 InitializeAudioPipeline();
684
685 InSequence s;
686 ExpectAudioPipelineSeekError(kErrorOnSeek);
687 ExpectAudioPipelineError();
688
689 DoAudioPipelineSeek();
690 }
691
692 TEST_F(PipelineTest, Error_DuringPlayback) {
693 InitializeAudioPipeline();
694
695 InSequence s;
696
697 // Curiously enough, errors during playback invokes the pause+flush shutdown
698 // path and not the error path.
699 //
700 // TODO(scherkus): Don't pause+flush, see http://crbug.com/110228
701 EXPECT_CALL(*mocks_->audio_renderer(), Pause(_)).WillOnce(RunClosure());
702 EXPECT_CALL(*mocks_->audio_renderer(), Flush(_)).WillOnce(RunClosure());
703 EXPECT_CALL(*mocks_->demuxer(), Stop(_)).WillOnce(RunClosure());
704 EXPECT_CALL(*mocks_->audio_renderer(), Stop(_)).WillOnce(RunClosure());
705
706 EXPECT_CALL(callbacks_, OnError(PIPELINE_ERROR_READ));
707
708 pipeline_->SetErrorForTesting(PIPELINE_ERROR_READ);
709 message_loop_.RunAllPending();
710 }
711
712 TEST_F(PipelineTest, Error_DuringStop) {
713 InitializeAudioPipeline();
714
715 InSequence s;
716
717 // TODO(scherkus): Don't pause+flush on shutdown, see http://crbug.com/110228
718 EXPECT_CALL(*mocks_->audio_renderer(), Pause(_)).WillOnce(RunClosure());
719 EXPECT_CALL(*mocks_->audio_renderer(), Flush(_)).WillOnce(RunClosure());
720 EXPECT_CALL(*mocks_->demuxer(), Stop(_))
721 .WillOnce(DoAll(SetError(pipeline_, PIPELINE_ERROR_READ), RunClosure()));
722 EXPECT_CALL(*mocks_->audio_renderer(), Stop(_)).WillOnce(RunClosure());
723
724 // No error callback should fire.
725 EXPECT_CALL(callbacks_, OnStop());
726
727 DoAudioPipelineStop();
728 }
729
467 TEST_F(PipelineTest, SetVolume) { 730 TEST_F(PipelineTest, SetVolume) {
468 CreateAudioStream(); 731 CreateAudioStream();
469 MockDemuxerStreamVector streams; 732 MockDemuxerStreamVector streams;
470 streams.push_back(audio_stream()); 733 streams.push_back(audio_stream());
471 734
472 InitializeDemuxer(&streams); 735 InitializeDemuxer(&streams);
473 InitializeAudioDecoder(audio_stream()); 736 InitializeAudioDecoder(audio_stream());
474 InitializeAudioRenderer(); 737 InitializeAudioRenderer();
475 738
476 // The audio renderer should receive a call to SetVolume(). 739 // The audio renderer should receive a call to SetVolume().
(...skipping 474 matching lines...) Expand 10 before | Expand all | Expand 10 after
951 TestPipelineStatusNotification(base::TimeDelta::FromMilliseconds(0)); 1214 TestPipelineStatusNotification(base::TimeDelta::FromMilliseconds(0));
952 } 1215 }
953 1216
954 // Test that different-thread, some-delay callback (the expected common case) 1217 // Test that different-thread, some-delay callback (the expected common case)
955 // works correctly. 1218 // works correctly.
956 TEST(PipelineStatusNotificationTest, DelayedCallback) { 1219 TEST(PipelineStatusNotificationTest, DelayedCallback) {
957 TestPipelineStatusNotification(base::TimeDelta::FromMilliseconds(20)); 1220 TestPipelineStatusNotification(base::TimeDelta::FromMilliseconds(20));
958 } 1221 }
959 1222
960 } // namespace media 1223 } // namespace media
OLDNEW
« 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