Home | History | Annotate | Download | only in base
      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