serial_runner_unittest.cc revision 3551c9c881056c480085172ff9840cab31610854
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
12namespace media {
13
14class 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_FALSE(inside_start_)
56        << "Bound functions should not run on same stack as "
57        << "SerialRunner::Run()\n" << base::debug::StackTrace().ToString();
58
59    called_[index] = true;
60    status_cb.Run(status);
61  }
62
63  void StartRunnerInternal(const SerialRunner::Queue& bound_fns) {
64    inside_start_ = true;
65    runner_ = SerialRunner::Run(bound_fns_, base::Bind(
66        &SerialRunnerTest::DoneCallback, base::Unretained(this)));
67    inside_start_ = false;
68  }
69
70  void DoneCallback(PipelineStatus status) {
71    EXPECT_FALSE(inside_start_)
72        << "Done callback should not run on same stack as SerialRunner::Run()\n"
73        << base::debug::StackTrace().ToString();
74
75    done_called_ = true;
76    done_status_ = status;
77    message_loop_.QuitWhenIdle();
78  }
79
80  void CancelSerialRunner(const PipelineStatusCB& status_cb) {
81    // Tasks run by |runner_| shouldn't reset it, hence we post a task to do so.
82    message_loop_.PostTask(FROM_HERE, base::Bind(
83        &SerialRunnerTest::ResetSerialRunner, base::Unretained(this)));
84    status_cb.Run(PIPELINE_OK);
85  }
86
87  void ResetSerialRunner() {
88    runner_.reset();
89  }
90
91  base::MessageLoop message_loop_;
92  SerialRunner::Queue bound_fns_;
93  scoped_ptr<SerialRunner> runner_;
94
95  // Used to enforce calling stack guarantees of the API.
96  bool inside_start_;
97
98  // Tracks whether the i'th bound function was called.
99  std::vector<bool> called_;
100
101  // Tracks whether the final done callback was called + resulting status.
102  bool done_called_;
103  PipelineStatus done_status_;
104
105  DISALLOW_COPY_AND_ASSIGN(SerialRunnerTest);
106};
107
108TEST_F(SerialRunnerTest, Empty) {
109  RunSerialRunner();
110
111  EXPECT_TRUE(done_called());
112  EXPECT_EQ(PIPELINE_OK, done_status());
113}
114
115TEST_F(SerialRunnerTest, Single) {
116  PushBoundFunction(PIPELINE_OK);
117  RunSerialRunner();
118
119  EXPECT_TRUE(called(0));
120  EXPECT_TRUE(done_called());
121  EXPECT_EQ(PIPELINE_OK, done_status());
122}
123
124TEST_F(SerialRunnerTest, Single_Error) {
125  PushBoundFunction(PIPELINE_ERROR_ABORT);
126  RunSerialRunner();
127
128  EXPECT_TRUE(called(0));
129  EXPECT_TRUE(done_called());
130  EXPECT_EQ(PIPELINE_ERROR_ABORT, done_status());
131}
132
133TEST_F(SerialRunnerTest, Single_Cancel) {
134  PushBoundFunction(PIPELINE_OK);
135  PushCancellation();
136  RunSerialRunner();
137
138  EXPECT_TRUE(called(0));
139  EXPECT_FALSE(done_called());
140}
141
142TEST_F(SerialRunnerTest, Multiple) {
143  PushBoundFunction(PIPELINE_OK);
144  PushBoundFunction(PIPELINE_OK);
145  RunSerialRunner();
146
147  EXPECT_TRUE(called(0));
148  EXPECT_TRUE(called(1));
149  EXPECT_TRUE(done_called());
150  EXPECT_EQ(PIPELINE_OK, done_status());
151}
152
153TEST_F(SerialRunnerTest, Multiple_Error) {
154  PushBoundFunction(PIPELINE_ERROR_ABORT);
155  PushBoundFunction(PIPELINE_OK);
156  RunSerialRunner();
157
158  EXPECT_TRUE(called(0));
159  EXPECT_FALSE(called(1));  // A bad status cancels remaining work.
160  EXPECT_TRUE(done_called());
161  EXPECT_EQ(PIPELINE_ERROR_ABORT, done_status());
162}
163
164TEST_F(SerialRunnerTest, Multiple_Cancel) {
165  PushBoundFunction(PIPELINE_OK);
166  PushCancellation();
167  PushBoundFunction(PIPELINE_OK);
168  RunSerialRunner();
169
170  EXPECT_TRUE(called(0));
171  EXPECT_FALSE(called(1));
172  EXPECT_FALSE(done_called());
173}
174
175}  // namespace media
176