1 // Copyright 2013 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "base/bind.h" 6 #include "base/debug/stack_trace.h" 7 #include "base/message_loop/message_loop.h" 8 #include "media/base/pipeline_status.h" 9 #include "media/base/serial_runner.h" 10 #include "testing/gtest/include/gtest/gtest.h" 11 12 namespace media { 13 14 class SerialRunnerTest : public ::testing::Test { 15 public: 16 SerialRunnerTest() 17 : inside_start_(false), done_called_(false), done_status_(PIPELINE_OK) {} 18 virtual ~SerialRunnerTest() {} 19 20 void RunSerialRunner() { 21 message_loop_.PostTask(FROM_HERE, base::Bind( 22 &SerialRunnerTest::StartRunnerInternal, base::Unretained(this), 23 bound_fns_)); 24 message_loop_.RunUntilIdle(); 25 } 26 27 // Pushes a bound function to the queue that will run its callback with 28 // |status|. called(i) returns whether the i'th bound function pushed to the 29 // queue was called while running the SerialRunner. 30 void PushBoundFunction(PipelineStatus status) { 31 bound_fns_.Push(base::Bind(&SerialRunnerTest::RunBoundFunction, 32 base::Unretained(this), 33 status, 34 called_.size())); 35 called_.push_back(false); 36 } 37 38 // Push a bound function to the queue that will delete the SerialRunner, 39 // which should cancel all remaining queued work. 40 void PushCancellation() { 41 bound_fns_.Push(base::Bind(&SerialRunnerTest::CancelSerialRunner, 42 base::Unretained(this))); 43 } 44 45 // Queries final status of pushed functions and done callback. Valid only 46 // after calling RunSerialRunner(). 47 bool called(size_t index) { return called_[index]; } 48 bool done_called() { return done_called_; } 49 PipelineStatus done_status() { return done_status_; } 50 51 private: 52 void RunBoundFunction(PipelineStatus status, 53 size_t index, 54 const PipelineStatusCB& status_cb) { 55 EXPECT_EQ(index == 0u, inside_start_) 56 << "First bound function should run on same stack as " 57 << "SerialRunner::Run() while all others should not\n" 58 << base::debug::StackTrace().ToString(); 59 60 called_[index] = true; 61 status_cb.Run(status); 62 } 63 64 void StartRunnerInternal(const SerialRunner::Queue& bound_fns) { 65 inside_start_ = true; 66 runner_ = SerialRunner::Run(bound_fns_, base::Bind( 67 &SerialRunnerTest::DoneCallback, base::Unretained(this))); 68 inside_start_ = false; 69 } 70 71 void DoneCallback(PipelineStatus status) { 72 EXPECT_FALSE(inside_start_) 73 << "Done callback should not run on same stack as SerialRunner::Run()\n" 74 << base::debug::StackTrace().ToString(); 75 76 done_called_ = true; 77 done_status_ = status; 78 message_loop_.QuitWhenIdle(); 79 } 80 81 void CancelSerialRunner(const PipelineStatusCB& status_cb) { 82 // Tasks run by |runner_| shouldn't reset it, hence we post a task to do so. 83 message_loop_.PostTask(FROM_HERE, base::Bind( 84 &SerialRunnerTest::ResetSerialRunner, base::Unretained(this))); 85 status_cb.Run(PIPELINE_OK); 86 } 87 88 void ResetSerialRunner() { 89 runner_.reset(); 90 } 91 92 base::MessageLoop message_loop_; 93 SerialRunner::Queue bound_fns_; 94 scoped_ptr<SerialRunner> runner_; 95 96 // Used to enforce calling stack guarantees of the API. 97 bool inside_start_; 98 99 // Tracks whether the i'th bound function was called. 100 std::vector<bool> called_; 101 102 // Tracks whether the final done callback was called + resulting status. 103 bool done_called_; 104 PipelineStatus done_status_; 105 106 DISALLOW_COPY_AND_ASSIGN(SerialRunnerTest); 107 }; 108 109 TEST_F(SerialRunnerTest, Empty) { 110 RunSerialRunner(); 111 112 EXPECT_TRUE(done_called()); 113 EXPECT_EQ(PIPELINE_OK, done_status()); 114 } 115 116 TEST_F(SerialRunnerTest, Single) { 117 PushBoundFunction(PIPELINE_OK); 118 RunSerialRunner(); 119 120 EXPECT_TRUE(called(0)); 121 EXPECT_TRUE(done_called()); 122 EXPECT_EQ(PIPELINE_OK, done_status()); 123 } 124 125 TEST_F(SerialRunnerTest, Single_Error) { 126 PushBoundFunction(PIPELINE_ERROR_ABORT); 127 RunSerialRunner(); 128 129 EXPECT_TRUE(called(0)); 130 EXPECT_TRUE(done_called()); 131 EXPECT_EQ(PIPELINE_ERROR_ABORT, done_status()); 132 } 133 134 TEST_F(SerialRunnerTest, Single_Cancel) { 135 PushBoundFunction(PIPELINE_OK); 136 PushCancellation(); 137 RunSerialRunner(); 138 139 EXPECT_TRUE(called(0)); 140 EXPECT_FALSE(done_called()); 141 } 142 143 TEST_F(SerialRunnerTest, Multiple) { 144 PushBoundFunction(PIPELINE_OK); 145 PushBoundFunction(PIPELINE_OK); 146 RunSerialRunner(); 147 148 EXPECT_TRUE(called(0)); 149 EXPECT_TRUE(called(1)); 150 EXPECT_TRUE(done_called()); 151 EXPECT_EQ(PIPELINE_OK, done_status()); 152 } 153 154 TEST_F(SerialRunnerTest, Multiple_Error) { 155 PushBoundFunction(PIPELINE_ERROR_ABORT); 156 PushBoundFunction(PIPELINE_OK); 157 RunSerialRunner(); 158 159 EXPECT_TRUE(called(0)); 160 EXPECT_FALSE(called(1)); // A bad status cancels remaining work. 161 EXPECT_TRUE(done_called()); 162 EXPECT_EQ(PIPELINE_ERROR_ABORT, done_status()); 163 } 164 165 TEST_F(SerialRunnerTest, Multiple_Cancel) { 166 PushBoundFunction(PIPELINE_OK); 167 PushCancellation(); 168 PushBoundFunction(PIPELINE_OK); 169 RunSerialRunner(); 170 171 EXPECT_TRUE(called(0)); 172 EXPECT_FALSE(called(1)); 173 EXPECT_FALSE(done_called()); 174 } 175 176 } // namespace media 177