1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
|
// Copyright (c) 2011 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_
#pragma once
#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_
|