blob: 771aad44b32865b2bb4e566c325374dc6581d88e [file] [log] [blame]
// 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.
#ifndef CHROME_BROWSER_POLICY_LOGGING_WORK_SCHEDULER_H_
#define CHROME_BROWSER_POLICY_LOGGING_WORK_SCHEDULER_H_
#include <queue>
#include <vector>
#include "base/basictypes.h"
#include "base/callback.h"
#include "base/compiler_specific.h"
#include "base/memory/linked_ptr.h"
#include "base/memory/weak_ptr.h"
#include "chrome/browser/policy/delayed_work_scheduler.h"
// Utilities for testing users of DelayedWorkScheduler. There are no
// thread-safety guarantees for the classes in this file. They expect to
// only be called from the UI thread and issue callbacks on that very same
// thread.
//
// Usage examples:
//
// Making CloudPolicyController and/or DeviceTokenFetcher run without real-time
// delays in tests:
//
// DeviceTokenFetcher fetcher(..., new DummyDelayedWorkScheduler);
//
// Running CloudPolicyController and/or DeviceTokenFetcher in a simulated
// environment, in which the time of any of their actions can be recorded,
// but without having to wait for the real-time delays:
//
// EventLogger logger;
// DeviceTokenFetcher fetcher(..., new LoggingEventScheduler(&logger));
// CloudPolicyController controller(..., new LoggingEventScheduler(&logger));
//
// Start the policy subsystem, and use logger.RegisterEvent() in case of
// any interesting events. The time of all these events will be recorded
// by |logger|. After that, the results can be extracted easily:
//
// std::vector<int64> logged_events;
// logger.Swap(&logged_events);
//
// Each element of |logged_events| corresponds to a logger event, and stores
// the virtual time when it was logged. Events are in ascending order.
namespace policy {
// Helper class for LoggingWorkScheduler. It essentially emulates a real
// message loop. All the submitted tasks are run with zero delay, but the
// order in which they would run with delays is preserved.
// All the task posting requests of the schedulers will be channeled through
// a common instance of EventLogger. This makes sure, that this instance can
// keep track of time in the simulation and record logged events with correct
// timestamps.
class EventLogger {
public:
EventLogger();
~EventLogger();
// Post a task to be executed |delay| milliseconds from now. The task can be
// cancelled later by calling Reset() on the callback.
void PostDelayedWork(linked_ptr<base::Closure> callback, int64 delay);
// Register a new event that happened now according to the internal clock.
void RegisterEvent();
// Swap out the internal list of events.
void Swap(std::vector<int64>* events);
// Counts the events in a sorted integer array that are >= |start| but
// < |start| + |length|.
static int CountEvents(const std::vector<int64>& events,
int64 start, int64 length);
private:
class Task;
// Updates |current_time_| and triggers the next scheduled task. This method
// is run repeatedly on the main message loop until there are scheduled
// tasks.
void Step();
// Stores the list of scheduled tasks with their respective delays and
// schedulers.
std::priority_queue<Task> scheduled_tasks_;
// Machinery to put a call to |Step| at the end of the message loop.
bool step_pending_;
base::WeakPtrFactory<EventLogger> weak_ptr_factory_;
// Ascending list of observation-times of the logged events.
std::vector<int64> events_;
// The current time of the simulated system.
int64 current_time_;
// The total number of tasks scheduled so far.
int64 task_counter_;
DISALLOW_COPY_AND_ASSIGN(EventLogger);
};
// Issues delayed tasks with zero effective delay, but posts them through
// an EventLogger, to make it possible to log events and reconstruct their
// execution time.
class LoggingWorkScheduler : public DelayedWorkScheduler {
public:
// An EventLogger may be shared by more than one schedulers, therefore
// no ownership is taken.
explicit LoggingWorkScheduler(EventLogger* logger);
virtual ~LoggingWorkScheduler();
virtual void PostDelayedWork(const base::Closure& callback, int64 delay)
OVERRIDE;
virtual void CancelDelayedWork() OVERRIDE;
private:
EventLogger* logger_;
linked_ptr<base::Closure> callback_;
DISALLOW_COPY_AND_ASSIGN(LoggingWorkScheduler);
};
// This implementation of DelayedWorkScheduler always schedules the tasks
// with zero delay.
class DummyWorkScheduler : public DelayedWorkScheduler {
public:
DummyWorkScheduler();
virtual ~DummyWorkScheduler();
virtual void PostDelayedWork(const base::Closure& callback, int64 delay)
OVERRIDE;
private:
DISALLOW_COPY_AND_ASSIGN(DummyWorkScheduler);
};
} // namespace policy
#endif // CHROME_BROWSER_POLICY_LOGGING_WORK_SCHEDULER_H_