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   // 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