Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(24)

Unified Diff: base/test/sequenced_task_runner_test_template.cc

Issue 9663075: Implementation of SequencedTaskRunner based on SequencedWorkerPool. (Closed) Base URL: http://src.chromium.org/svn/trunk/src/
Patch Set: Created 8 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « base/test/sequenced_task_runner_test_template.h ('k') | base/test/sequenced_worker_pool_owner.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: base/test/sequenced_task_runner_test_template.cc
===================================================================
--- base/test/sequenced_task_runner_test_template.cc (revision 0)
+++ base/test/sequenced_task_runner_test_template.cc (revision 0)
@@ -0,0 +1,263 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/sequenced_task_runner_test_template.h"
+
+#include <ostream>
+
+#include "base/location.h"
+
+namespace base {
+
+namespace internal {
+
+TaskEvent::TaskEvent(int i, Type type)
+ : i(i), type(type) {
+}
+
+SequencedTaskTracker::SequencedTaskTracker() : next_post_i_(0) {
+}
+
+void SequencedTaskTracker::PostWrappedNonNestableTask(
+ const scoped_refptr<SequencedTaskRunner>& task_runner,
+ const Closure& task) {
+ AutoLock event_lock(lock_);
+ const int post_i = next_post_i_++;
+ Closure wrapped_task = Bind(&SequencedTaskTracker::RunTask, this,
+ task, post_i);
+ task_runner->PostNonNestableTask(FROM_HERE, wrapped_task);
+ TaskPosted(post_i);
+}
+
+void SequencedTaskTracker::PostWrappedNestableTask(
+ const scoped_refptr<SequencedTaskRunner>& task_runner,
+ const Closure& task) {
+ AutoLock event_lock(lock_);
+ const int post_i = next_post_i_++;
+ Closure wrapped_task = Bind(&SequencedTaskTracker::RunTask, this,
+ task, post_i);
+ task_runner->PostTask(FROM_HERE, wrapped_task);
+ TaskPosted(post_i);
+}
+
+void SequencedTaskTracker::PostWrappedDelayedNonNestableTask(
+ const scoped_refptr<SequencedTaskRunner>& task_runner,
+ const Closure& task,
+ TimeDelta delay) {
+ AutoLock event_lock(lock_);
+ const int post_i = next_post_i_++;
+ Closure wrapped_task = Bind(&SequencedTaskTracker::RunTask, this,
+ task, post_i);
+ task_runner->PostNonNestableDelayedTask(FROM_HERE, wrapped_task, delay);
+ TaskPosted(post_i);
+}
+
+void SequencedTaskTracker::PostNonNestableTasks(
+ const scoped_refptr<SequencedTaskRunner>& task_runner,
+ int task_count) {
+ for (int i = 0; i < task_count; ++i) {
+ PostWrappedNonNestableTask(task_runner, Closure());
+ }
+}
+
+void SequencedTaskTracker::RunTask(const Closure& task, int task_i) {
+ TaskStarted(task_i);
+ if (!task.is_null())
+ task.Run();
+ TaskEnded(task_i);
+}
+
+void SequencedTaskTracker::TaskPosted(int i) {
+ // Caller must own |lock_|.
+ events_.push_back(TaskEvent(i, TaskEvent::POST));
+}
+
+void SequencedTaskTracker::TaskStarted(int i) {
+ AutoLock lock(lock_);
+ events_.push_back(TaskEvent(i, TaskEvent::START));
+}
+
+void SequencedTaskTracker::TaskEnded(int i) {
+ AutoLock lock(lock_);
+ events_.push_back(TaskEvent(i, TaskEvent::END));
+}
+
+const std::vector<TaskEvent>&
+SequencedTaskTracker::GetTaskEvents() const {
+ return events_;
+}
+
+SequencedTaskTracker::~SequencedTaskTracker() {
+}
+
+void PrintTo(const TaskEvent& event, std::ostream* os) {
+ *os << "(i=" << event.i << ", type=";
+ switch (event.type) {
+ case TaskEvent::POST: *os << "POST"; break;
+ case TaskEvent::START: *os << "START"; break;
+ case TaskEvent::END: *os << "END"; break;
+ }
+ *os << ")";
+}
+
+void SleepForOneSecond() {
+ base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(1));
+}
+
+namespace {
+
+// Returns the task ordinals for the task event type |type| in the order that
+// they were recorded.
+std::vector<int> GetEventTypeOrder(const std::vector<TaskEvent>& events,
+ TaskEvent::Type type) {
+ std::vector<int> tasks;
+ std::vector<TaskEvent>::const_iterator event;
+ for (event = events.begin(); event != events.end(); ++event) {
+ if (event->type == type)
+ tasks.push_back(event->i);
+ }
+ return tasks;
+}
+
+// Returns all task events for task |task_i|.
+std::vector<TaskEvent::Type> GetEventsForTask(
+ const std::vector<TaskEvent>& events,
+ int task_i) {
+ std::vector<TaskEvent::Type> task_event_orders;
+ std::vector<TaskEvent>::const_iterator event;
+ for (event = events.begin(); event != events.end(); ++event) {
+ if (event->i == task_i)
+ task_event_orders.push_back(event->type);
+ }
+ return task_event_orders;
+}
+
+// Checks that the task events for each task in |events| occur in the order
+// {POST, START, END}, and that there is only one instance of each event type
+// per task.
+::testing::AssertionResult CheckEventOrdersForEachTask(
+ const std::vector<TaskEvent>& events,
+ int task_count) {
+ std::vector<TaskEvent::Type> expected_order;
+ expected_order.push_back(TaskEvent::POST);
+ expected_order.push_back(TaskEvent::START);
+ expected_order.push_back(TaskEvent::END);
+
+ // This is O(n^2), but it runs fast enough currently so is not worth
+ // optimizing.
+ for (int i = 0; i < task_count; ++i) {
+ const std::vector<TaskEvent::Type> task_events =
+ GetEventsForTask(events, i);
+ if (task_events != expected_order) {
+ return ::testing::AssertionFailure()
+ << "Events for task " << i << " are out of order; expected: "
+ << ::testing::PrintToString(expected_order) << "; actual: "
+ << ::testing::PrintToString(task_events);
+ }
+ }
+ return ::testing::AssertionSuccess();
+}
+
+// Checks that no two tasks were running at the same time. I.e. the only
+// events allowed between the START and END of a task are the POSTs of other
+// tasks.
+::testing::AssertionResult CheckNoTaskRunsOverlap(
+ const std::vector<TaskEvent>& events) {
+ // If > -1, we're currently inside a START, END pair.
+ int current_task_i = -1;
+
+ std::vector<TaskEvent>::const_iterator event;
+ for (event = events.begin(); event != events.end(); ++event) {
+ bool spurious_event_found = false;
+
+ if (current_task_i == -1) { // Not inside a START, END pair.
+ switch (event->type) {
+ case TaskEvent::POST:
+ break;
+ case TaskEvent::START:
+ current_task_i = event->i;
+ break;
+ case TaskEvent::END:
+ spurious_event_found = true;
+ break;
+ }
+
+ } else { // Inside a START, END pair.
+ bool interleaved_task_detected = false;
+
+ switch (event->type) {
+ case TaskEvent::POST:
+ if (event->i == current_task_i)
+ spurious_event_found = true;
+ break;
+ case TaskEvent::START:
+ interleaved_task_detected = true;
+ break;
+ case TaskEvent::END:
+ if (event->i != current_task_i)
+ interleaved_task_detected = true;
+ else
+ current_task_i = -1;
+ break;
+ }
+
+ if (interleaved_task_detected) {
+ return ::testing::AssertionFailure()
+ << "Found event " << ::testing::PrintToString(*event)
+ << " between START and END events for task " << current_task_i
+ << "; event dump: " << ::testing::PrintToString(events);
+ }
+ }
+
+ if (spurious_event_found) {
+ const int event_i = event - events.begin();
+ return ::testing::AssertionFailure()
+ << "Spurious event " << ::testing::PrintToString(*event)
+ << " at position " << event_i << "; event dump: "
+ << ::testing::PrintToString(events);
+ }
+ }
+
+ return ::testing::AssertionSuccess();
+}
+
+} // namespace
+
+::testing::AssertionResult CheckNonNestableInvariants(
+ const std::vector<TaskEvent>& events,
+ int task_count) {
+ const std::vector<int> post_order =
+ GetEventTypeOrder(events, TaskEvent::POST);
+ const std::vector<int> start_order =
+ GetEventTypeOrder(events, TaskEvent::START);
+ const std::vector<int> end_order =
+ GetEventTypeOrder(events, TaskEvent::END);
+
+ if (start_order != post_order) {
+ return ::testing::AssertionFailure()
+ << "Expected START order (which equals actual POST order): \n"
+ << ::testing::PrintToString(post_order)
+ << "\n Actual START order:\n"
+ << ::testing::PrintToString(start_order);
+ }
+
+ if (end_order != post_order) {
+ return ::testing::AssertionFailure()
+ << "Expected END order (which equals actual POST order): \n"
+ << ::testing::PrintToString(post_order)
+ << "\n Actual END order:\n"
+ << ::testing::PrintToString(end_order);
+ }
+
+ const ::testing::AssertionResult result =
+ CheckEventOrdersForEachTask(events, task_count);
+ if (!result)
+ return result;
+
+ return CheckNoTaskRunsOverlap(events);
+}
+
+} // namespace internal
+
+} // namespace base
Property changes on: base/test/sequenced_task_runner_test_template.cc
___________________________________________________________________
Added: svn:eol-style
+ LF
« no previous file with comments | « base/test/sequenced_task_runner_test_template.h ('k') | base/test/sequenced_worker_pool_owner.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698