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 void PushBoundClosure() { 39 bound_fns_.Push(base::Bind(&SerialRunnerTest::RunBoundClosure, 40 base::Unretained(this), 41 called_.size())); 42 called_.push_back(false); 43 } 44 45 void PushClosure() { 46 bound_fns_.Push(base::Bind(&SerialRunnerTest::RunClosure, 47 base::Unretained(this), 48 called_.size())); 49 called_.push_back(false); 50 } 51 52 // Push a bound function to the queue that will delete the SerialRunner, 53 // which should cancel all remaining queued work. 54 void PushCancellation() { 55 bound_fns_.Push(base::Bind(&SerialRunnerTest::CancelSerialRunner, 56 base::Unretained(this))); 57 } 58 59 // Queries final status of pushed functions and done callback. Valid only 60 // after calling RunSerialRunner(). 61 bool called(size_t index) { return called_[index]; } 62 bool done_called() { return done_called_; } 63 PipelineStatus done_status() { return done_status_; } 64 65 private: 66 void RunBoundFunction(PipelineStatus status, 67 size_t index, 68 const PipelineStatusCB& status_cb) { 69 EXPECT_EQ(index == 0u, inside_start_) 70 << "First bound function should run on same stack as " 71 << "SerialRunner::Run() while all others should not\n" 72 << base::debug::StackTrace().ToString(); 73 74 called_[index] = true; 75 status_cb.Run(status); 76 } 77 78 void RunBoundClosure(size_t index, 79 const base::Closure& done_cb) { 80 EXPECT_EQ(index == 0u, inside_start_) 81 << "First bound function should run on same stack as " 82 << "SerialRunner::Run() while all others should not\n" 83 << base::debug::StackTrace().ToString(); 84 85 called_[index] = true; 86 done_cb.Run(); 87 } 88 89 void RunClosure(size_t index) { 90 EXPECT_EQ(index == 0u, inside_start_) 91 << "First bound function should run on same stack as " 92 << "SerialRunner::Run() while all others should not\n" 93 << base::debug::StackTrace().ToString(); 94 95 called_[index] = true; 96 } 97 98 void StartRunnerInternal(const SerialRunner::Queue& bound_fns) { 99 inside_start_ = true; 100 runner_ = SerialRunner::Run(bound_fns_, base::Bind( 101 &SerialRunnerTest::DoneCallback, base::Unretained(this))); 102 inside_start_ = false; 103 } 104 105 void DoneCallback(PipelineStatus status) { 106 EXPECT_FALSE(inside_start_) 107 << "Done callback should not run on same stack as SerialRunner::Run()\n" 108 << base::debug::StackTrace().ToString(); 109 110 done_called_ = true; 111 done_status_ = status; 112 message_loop_.QuitWhenIdle(); 113 } 114 115 void CancelSerialRunner(const PipelineStatusCB& status_cb) { 116 // Tasks run by |runner_| shouldn't reset it, hence we post a task to do so. 117 message_loop_.PostTask(FROM_HERE, base::Bind( 118 &SerialRunnerTest::ResetSerialRunner, base::Unretained(this))); 119 status_cb.Run(PIPELINE_OK); 120 } 121 122 void ResetSerialRunner() { 123 runner_.reset(); 124 } 125 126 base::MessageLoop message_loop_; 127 SerialRunner::Queue bound_fns_; 128 scoped_ptr<SerialRunner> runner_; 129 130 // Used to enforce calling stack guarantees of the API. 131 bool inside_start_; 132 133 // Tracks whether the i'th bound function was called. 134 std::vector<bool> called_; 135 136 // Tracks whether the final done callback was called + resulting status. 137 bool done_called_; 138 PipelineStatus done_status_; 139 140 DISALLOW_COPY_AND_ASSIGN(SerialRunnerTest); 141 }; 142 143 TEST_F(SerialRunnerTest, Empty) { 144 RunSerialRunner(); 145 146 EXPECT_TRUE(done_called()); 147 EXPECT_EQ(PIPELINE_OK, done_status()); 148 } 149 150 TEST_F(SerialRunnerTest, Single) { 151 PushBoundFunction(PIPELINE_OK); 152 RunSerialRunner(); 153 154 EXPECT_TRUE(called(0)); 155 EXPECT_TRUE(done_called()); 156 EXPECT_EQ(PIPELINE_OK, done_status()); 157 } 158 159 TEST_F(SerialRunnerTest, Single_Error) { 160 PushBoundFunction(PIPELINE_ERROR_ABORT); 161 RunSerialRunner(); 162 163 EXPECT_TRUE(called(0)); 164 EXPECT_TRUE(done_called()); 165 EXPECT_EQ(PIPELINE_ERROR_ABORT, done_status()); 166 } 167 168 TEST_F(SerialRunnerTest, Single_Cancel) { 169 PushBoundFunction(PIPELINE_OK); 170 PushCancellation(); 171 RunSerialRunner(); 172 173 EXPECT_TRUE(called(0)); 174 EXPECT_FALSE(done_called()); 175 } 176 177 TEST_F(SerialRunnerTest, Multiple) { 178 PushBoundFunction(PIPELINE_OK); 179 PushBoundFunction(PIPELINE_OK); 180 RunSerialRunner(); 181 182 EXPECT_TRUE(called(0)); 183 EXPECT_TRUE(called(1)); 184 EXPECT_TRUE(done_called()); 185 EXPECT_EQ(PIPELINE_OK, done_status()); 186 } 187 188 TEST_F(SerialRunnerTest, Multiple_Error) { 189 PushBoundFunction(PIPELINE_ERROR_ABORT); 190 PushBoundFunction(PIPELINE_OK); 191 RunSerialRunner(); 192 193 EXPECT_TRUE(called(0)); 194 EXPECT_FALSE(called(1)); // A bad status cancels remaining work. 195 EXPECT_TRUE(done_called()); 196 EXPECT_EQ(PIPELINE_ERROR_ABORT, done_status()); 197 } 198 199 TEST_F(SerialRunnerTest, Multiple_Cancel) { 200 PushBoundFunction(PIPELINE_OK); 201 PushCancellation(); 202 PushBoundFunction(PIPELINE_OK); 203 RunSerialRunner(); 204 205 EXPECT_TRUE(called(0)); 206 EXPECT_FALSE(called(1)); 207 EXPECT_FALSE(done_called()); 208 } 209 210 TEST_F(SerialRunnerTest, BoundClosure) { 211 PushBoundClosure(); 212 RunSerialRunner(); 213 214 EXPECT_TRUE(called(0)); 215 EXPECT_TRUE(done_called()); 216 EXPECT_EQ(PIPELINE_OK, done_status()); 217 } 218 219 TEST_F(SerialRunnerTest, Closure) { 220 PushClosure(); 221 RunSerialRunner(); 222 223 EXPECT_TRUE(called(0)); 224 EXPECT_TRUE(done_called()); 225 EXPECT_EQ(PIPELINE_OK, done_status()); 226 } 227 228 } // namespace media 229