• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
SerialRunnerTest()16   SerialRunnerTest()
17       : inside_start_(false), done_called_(false), done_status_(PIPELINE_OK) {}
~SerialRunnerTest()18   virtual ~SerialRunnerTest() {}
19 
RunSerialRunner()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.
PushBoundFunction(PipelineStatus status)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 
PushBoundClosure()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 
PushClosure()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.
PushCancellation()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().
called(size_t index)61   bool called(size_t index) { return called_[index]; }
done_called()62   bool done_called() { return done_called_; }
done_status()63   PipelineStatus done_status() { return done_status_; }
64 
65  private:
RunBoundFunction(PipelineStatus status,size_t index,const PipelineStatusCB & status_cb)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 
RunBoundClosure(size_t index,const base::Closure & done_cb)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 
RunClosure(size_t index)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 
StartRunnerInternal(const SerialRunner::Queue & bound_fns)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 
DoneCallback(PipelineStatus status)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 
CancelSerialRunner(const PipelineStatusCB & status_cb)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 
ResetSerialRunner()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 
TEST_F(SerialRunnerTest,Empty)143 TEST_F(SerialRunnerTest, Empty) {
144   RunSerialRunner();
145 
146   EXPECT_TRUE(done_called());
147   EXPECT_EQ(PIPELINE_OK, done_status());
148 }
149 
TEST_F(SerialRunnerTest,Single)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 
TEST_F(SerialRunnerTest,Single_Error)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 
TEST_F(SerialRunnerTest,Single_Cancel)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 
TEST_F(SerialRunnerTest,Multiple)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 
TEST_F(SerialRunnerTest,Multiple_Error)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 
TEST_F(SerialRunnerTest,Multiple_Cancel)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 
TEST_F(SerialRunnerTest,BoundClosure)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 
TEST_F(SerialRunnerTest,Closure)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