Home | History | Annotate | Download | only in test
      1 // Copyright (c) 2012 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/test/sequenced_task_runner_test_template.h"
      6 
      7 #include <ostream>
      8 
      9 #include "base/location.h"
     10 
     11 namespace base {
     12 
     13 namespace internal {
     14 
     15 TaskEvent::TaskEvent(int i, Type type)
     16   : i(i), type(type) {
     17 }
     18 
     19 SequencedTaskTracker::SequencedTaskTracker()
     20     : next_post_i_(0),
     21       task_end_count_(0),
     22       task_end_cv_(&lock_) {
     23 }
     24 
     25 void SequencedTaskTracker::PostWrappedNonNestableTask(
     26     const scoped_refptr<SequencedTaskRunner>& task_runner,
     27     const Closure& task) {
     28   AutoLock event_lock(lock_);
     29   const int post_i = next_post_i_++;
     30   Closure wrapped_task = Bind(&SequencedTaskTracker::RunTask, this,
     31                               task, post_i);
     32   task_runner->PostNonNestableTask(FROM_HERE, wrapped_task);
     33   TaskPosted(post_i);
     34 }
     35 
     36 void SequencedTaskTracker::PostWrappedNestableTask(
     37     const scoped_refptr<SequencedTaskRunner>& task_runner,
     38     const Closure& task) {
     39   AutoLock event_lock(lock_);
     40   const int post_i = next_post_i_++;
     41   Closure wrapped_task = Bind(&SequencedTaskTracker::RunTask, this,
     42                               task, post_i);
     43   task_runner->PostTask(FROM_HERE, wrapped_task);
     44   TaskPosted(post_i);
     45 }
     46 
     47 void SequencedTaskTracker::PostWrappedDelayedNonNestableTask(
     48     const scoped_refptr<SequencedTaskRunner>& task_runner,
     49     const Closure& task,
     50     TimeDelta delay) {
     51   AutoLock event_lock(lock_);
     52   const int post_i = next_post_i_++;
     53   Closure wrapped_task = Bind(&SequencedTaskTracker::RunTask, this,
     54                               task, post_i);
     55   task_runner->PostNonNestableDelayedTask(FROM_HERE, wrapped_task, delay);
     56   TaskPosted(post_i);
     57 }
     58 
     59 void SequencedTaskTracker::PostNonNestableTasks(
     60     const scoped_refptr<SequencedTaskRunner>& task_runner,
     61     int task_count) {
     62   for (int i = 0; i < task_count; ++i) {
     63     PostWrappedNonNestableTask(task_runner, Closure());
     64   }
     65 }
     66 
     67 void SequencedTaskTracker::RunTask(const Closure& task, int task_i) {
     68   TaskStarted(task_i);
     69   if (!task.is_null())
     70     task.Run();
     71   TaskEnded(task_i);
     72 }
     73 
     74 void SequencedTaskTracker::TaskPosted(int i) {
     75   // Caller must own |lock_|.
     76   events_.push_back(TaskEvent(i, TaskEvent::POST));
     77 }
     78 
     79 void SequencedTaskTracker::TaskStarted(int i) {
     80   AutoLock lock(lock_);
     81   events_.push_back(TaskEvent(i, TaskEvent::START));
     82 }
     83 
     84 void SequencedTaskTracker::TaskEnded(int i) {
     85   AutoLock lock(lock_);
     86   events_.push_back(TaskEvent(i, TaskEvent::END));
     87   ++task_end_count_;
     88   task_end_cv_.Signal();
     89 }
     90 
     91 const std::vector<TaskEvent>&
     92 SequencedTaskTracker::GetTaskEvents() const {
     93   return events_;
     94 }
     95 
     96 void SequencedTaskTracker::WaitForCompletedTasks(int count) {
     97   AutoLock lock(lock_);
     98   while (task_end_count_ < count)
     99     task_end_cv_.Wait();
    100 }
    101 
    102 SequencedTaskTracker::~SequencedTaskTracker() {
    103 }
    104 
    105 void PrintTo(const TaskEvent& event, std::ostream* os) {
    106   *os << "(i=" << event.i << ", type=";
    107   switch (event.type) {
    108     case TaskEvent::POST: *os << "POST"; break;
    109     case TaskEvent::START: *os << "START"; break;
    110     case TaskEvent::END: *os << "END"; break;
    111   }
    112   *os << ")";
    113 }
    114 
    115 namespace {
    116 
    117 // Returns the task ordinals for the task event type |type| in the order that
    118 // they were recorded.
    119 std::vector<int> GetEventTypeOrder(const std::vector<TaskEvent>& events,
    120                                    TaskEvent::Type type) {
    121   std::vector<int> tasks;
    122   std::vector<TaskEvent>::const_iterator event;
    123   for (event = events.begin(); event != events.end(); ++event) {
    124     if (event->type == type)
    125       tasks.push_back(event->i);
    126   }
    127   return tasks;
    128 }
    129 
    130 // Returns all task events for task |task_i|.
    131 std::vector<TaskEvent::Type> GetEventsForTask(
    132     const std::vector<TaskEvent>& events,
    133     int task_i) {
    134   std::vector<TaskEvent::Type> task_event_orders;
    135   std::vector<TaskEvent>::const_iterator event;
    136   for (event = events.begin(); event != events.end(); ++event) {
    137     if (event->i == task_i)
    138       task_event_orders.push_back(event->type);
    139   }
    140   return task_event_orders;
    141 }
    142 
    143 // Checks that the task events for each task in |events| occur in the order
    144 // {POST, START, END}, and that there is only one instance of each event type
    145 // per task.
    146 ::testing::AssertionResult CheckEventOrdersForEachTask(
    147     const std::vector<TaskEvent>& events,
    148     int task_count) {
    149   std::vector<TaskEvent::Type> expected_order;
    150   expected_order.push_back(TaskEvent::POST);
    151   expected_order.push_back(TaskEvent::START);
    152   expected_order.push_back(TaskEvent::END);
    153 
    154   // This is O(n^2), but it runs fast enough currently so is not worth
    155   // optimizing.
    156   for (int i = 0; i < task_count; ++i) {
    157     const std::vector<TaskEvent::Type> task_events =
    158         GetEventsForTask(events, i);
    159     if (task_events != expected_order) {
    160       return ::testing::AssertionFailure()
    161           << "Events for task " << i << " are out of order; expected: "
    162           << ::testing::PrintToString(expected_order) << "; actual: "
    163           << ::testing::PrintToString(task_events);
    164     }
    165   }
    166   return ::testing::AssertionSuccess();
    167 }
    168 
    169 // Checks that no two tasks were running at the same time. I.e. the only
    170 // events allowed between the START and END of a task are the POSTs of other
    171 // tasks.
    172 ::testing::AssertionResult CheckNoTaskRunsOverlap(
    173     const std::vector<TaskEvent>& events) {
    174   // If > -1, we're currently inside a START, END pair.
    175   int current_task_i = -1;
    176 
    177   std::vector<TaskEvent>::const_iterator event;
    178   for (event = events.begin(); event != events.end(); ++event) {
    179     bool spurious_event_found = false;
    180 
    181     if (current_task_i == -1) {  // Not inside a START, END pair.
    182       switch (event->type) {
    183         case TaskEvent::POST:
    184           break;
    185         case TaskEvent::START:
    186           current_task_i = event->i;
    187           break;
    188         case TaskEvent::END:
    189           spurious_event_found = true;
    190           break;
    191       }
    192 
    193     } else {  // Inside a START, END pair.
    194       bool interleaved_task_detected = false;
    195 
    196       switch (event->type) {
    197         case TaskEvent::POST:
    198           if (event->i == current_task_i)
    199             spurious_event_found = true;
    200           break;
    201         case TaskEvent::START:
    202           interleaved_task_detected = true;
    203           break;
    204         case TaskEvent::END:
    205           if (event->i != current_task_i)
    206             interleaved_task_detected = true;
    207           else
    208             current_task_i = -1;
    209           break;
    210       }
    211 
    212       if (interleaved_task_detected) {
    213         return ::testing::AssertionFailure()
    214             << "Found event " << ::testing::PrintToString(*event)
    215             << " between START and END events for task " << current_task_i
    216             << "; event dump: " << ::testing::PrintToString(events);
    217       }
    218     }
    219 
    220     if (spurious_event_found) {
    221       const int event_i = event - events.begin();
    222       return ::testing::AssertionFailure()
    223           << "Spurious event " << ::testing::PrintToString(*event)
    224           << " at position " << event_i << "; event dump: "
    225           << ::testing::PrintToString(events);
    226     }
    227   }
    228 
    229   return ::testing::AssertionSuccess();
    230 }
    231 
    232 }  // namespace
    233 
    234 ::testing::AssertionResult CheckNonNestableInvariants(
    235     const std::vector<TaskEvent>& events,
    236     int task_count) {
    237   const std::vector<int> post_order =
    238       GetEventTypeOrder(events, TaskEvent::POST);
    239   const std::vector<int> start_order =
    240       GetEventTypeOrder(events, TaskEvent::START);
    241   const std::vector<int> end_order =
    242       GetEventTypeOrder(events, TaskEvent::END);
    243 
    244   if (start_order != post_order) {
    245     return ::testing::AssertionFailure()
    246         << "Expected START order (which equals actual POST order): \n"
    247         << ::testing::PrintToString(post_order)
    248         << "\n Actual START order:\n"
    249         << ::testing::PrintToString(start_order);
    250   }
    251 
    252   if (end_order != post_order) {
    253     return ::testing::AssertionFailure()
    254         << "Expected END order (which equals actual POST order): \n"
    255         << ::testing::PrintToString(post_order)
    256         << "\n Actual END order:\n"
    257         << ::testing::PrintToString(end_order);
    258   }
    259 
    260   const ::testing::AssertionResult result =
    261       CheckEventOrdersForEachTask(events, task_count);
    262   if (!result)
    263     return result;
    264 
    265   return CheckNoTaskRunsOverlap(events);
    266 }
    267 
    268 }  // namespace internal
    269 
    270 }  // namespace base
    271