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

Side by Side Diff: tests/lib/async/zone_timer_task_test.dart

Issue 1848933002: Add tasks to zones. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Address comments and copy types from other docs CL. Created 4 years, 5 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 unified diff | Download patch
« no previous file with comments | « tests/lib/async/zone_task_test.dart ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file.
4
5 // Tests timer tasks.
6
7 import 'package:expect/expect.dart';
8 import 'package:async_helper/async_helper.dart';
9 import 'dart:async';
10 import 'dart:collection';
11
12 class MyTimerSpecification implements SingleShotTimerTaskSpecification {
13 final Function callback;
14 final Duration duration;
15
16 MyTimerSpecification(this.callback, this.duration);
17
18 bool get isOneShot => true;
19 String get name => "test.timer-override";
20 }
21
22 class MyPeriodicTimerSpecification implements PeriodicTimerTaskSpecification {
23 final Function callback;
24 final Duration duration;
25
26 MyPeriodicTimerSpecification(this.callback, this.duration);
27
28 bool get isOneShot => true;
29 String get name => "test.periodic-timer-override";
30 }
31
32 /// Makes sure things are working in a simple setting.
33 /// No interceptions, changes, ...
34 Future testTimerTask() {
35 List log = [];
36
37 var testCompleter = new Completer();
38 asyncStart();
39
40 int taskIdCounter = 0;
41
42 Object createTaskHandler(Zone self, ZoneDelegate parent, Zone zone,
43 TaskCreate create, TaskSpecification specification) {
44 var taskMap = self['taskMap'];
45 var taskIdMap = self['taskIdMap'];
46 if (specification is SingleShotTimerTaskSpecification) {
47 log.add("create enter "
48 "zone: ${self['name']} "
49 "spec-duration: ${specification.duration} "
50 "spec-oneshot?: ${specification.isOneShot}");
51 var result = parent.createTask(zone, create, specification);
52 taskMap[result] = specification;
53 taskIdMap[specification] = taskIdCounter++;
54 log.add("create leave");
55 return result;
56 } else if (specification is PeriodicTimerTaskSpecification) {
57 log.add("create enter "
58 "zone: ${self['name']} "
59 "spec-duration: ${specification.duration} "
60 "spec-oneshot?: ${specification.isOneShot}");
61 var result = parent.createTask(zone, create, specification);
62 taskMap[result] = specification;
63 taskIdMap[specification] = taskIdCounter++;
64 log.add("create leave");
65 return result;
66 }
67 return parent.createTask(zone, create, specification);
68 }
69
70 void runTaskHandler(Zone self, ZoneDelegate parent, Zone zone, TaskRun run,
71 Object task, Object arg) {
72 var taskMap = self['taskMap'];
73 var taskIdMap = self['taskIdMap'];
74 if (taskMap.containsKey(task)) {
75 var spec = taskMap[task];
76 log.add("run enter "
77 "zone: ${self['name']} "
78 "task-id: ${taskIdMap[spec]} "
79 "arg: $arg");
80 parent.runTask(zone, run, task, arg);
81 log.add("run leave");
82 return;
83 }
84 parent.runTask(zone, run, task, arg);
85 }
86
87 runZoned(() async {
88 var completer0 = new Completer();
89 Timer.run(() {
90 completer0.complete("done");
91 });
92 await completer0.future;
93
94 Expect.listEquals([
95 'create enter zone: custom zone spec-duration: 0:00:00.000000 '
96 'spec-oneshot?: true',
97 'create leave',
98 'run enter zone: custom zone task-id: 0 arg: null',
99 'run leave'
100 ], log);
101 log.clear();
102
103 var completer1 = new Completer();
104 var counter1 = 0;
105 new Timer.periodic(const Duration(milliseconds: 5), (Timer timer) {
106 if (counter1++ > 1) {
107 timer.cancel();
108 completer1.complete("done");
109 }
110 });
111 await completer1.future;
112
113 Expect.listEquals([
114 'create enter zone: custom zone spec-duration: 0:00:00.005000 '
115 'spec-oneshot?: false',
116 'create leave',
117 'run enter zone: custom zone task-id: 1 arg: null',
118 'run leave',
119 'run enter zone: custom zone task-id: 1 arg: null',
120 'run leave',
121 'run enter zone: custom zone task-id: 1 arg: null',
122 'run leave'
123 ], log);
124 log.clear();
125
126 testCompleter.complete("done");
127 asyncEnd();
128 },
129 zoneValues: {'name': 'custom zone', 'taskMap': {}, 'taskIdMap': {}},
130 zoneSpecification: new ZoneSpecification(
131 createTask: createTaskHandler,
132 runTask: runTaskHandler));
133
134 return testCompleter.future;
135 }
136
137 /// More complicated zone, that intercepts...
138 Future testTimerTask2() {
139 List log = [];
140
141 var testCompleter = new Completer();
142 asyncStart();
143
144 int taskIdCounter = 0;
145
146 Object createTaskHandler(Zone self, ZoneDelegate parent, Zone zone,
147 TaskCreate create, TaskSpecification specification) {
148 var taskMap = self['taskMap'];
149 var taskIdMap = self['taskIdMap'];
150 if (specification is SingleShotTimerTaskSpecification) {
151 log.add("create enter "
152 "zone: ${self['name']} "
153 "spec-duration: ${specification.duration} "
154 "spec-oneshot?: ${specification.isOneShot}");
155 var mySpec = new MyTimerSpecification(specification.callback,
156 specification.duration + const Duration(milliseconds: 2));
157 var result = parent.createTask(zone, create, mySpec);
158 taskMap[result] = specification;
159 taskIdMap[specification] = taskIdCounter++;
160 log.add("create leave");
161 return result;
162 } else if (specification is PeriodicTimerTaskSpecification) {
163 log.add("create enter "
164 "zone: ${self['name']} "
165 "spec-duration: ${specification.duration} "
166 "spec-oneshot?: ${specification.isOneShot}");
167 var mySpec = new MyPeriodicTimerSpecification(specification.callback,
168 specification.duration + const Duration(milliseconds: 2));
169 var result = parent.createTask(zone, create, specification);
170 taskMap[result] = specification;
171 taskIdMap[specification] = taskIdCounter++;
172 log.add("create leave");
173 return result;
174 }
175 return parent.createTask(zone, create, specification);
176 }
177
178 void runTaskHandler(Zone self, ZoneDelegate parent, Zone zone, TaskRun run,
179 Object task, Object arg) {
180 var taskMap = self['taskMap'];
181 var taskIdMap = self['taskIdMap'];
182 if (taskMap.containsKey(task)) {
183 var spec = taskMap[task];
184 log.add("run enter "
185 "zone: ${self['name']} "
186 "task-id: ${taskIdMap[spec]} "
187 "arg: $arg");
188 parent.runTask(zone, run, task, arg);
189 log.add("run leave");
190 return;
191 }
192 parent.runTask(zone, run, task, arg);
193 }
194
195 runZoned(() async {
196 var completer0 = new Completer();
197 Timer.run(() {
198 completer0.complete("done");
199 });
200 await completer0.future;
201
202 // No visible change (except for the zone name) in the log, compared to the
203 // simple invocations.
204 Expect.listEquals([
205 'create enter zone: outer-zone spec-duration: 0:00:00.000000 '
206 'spec-oneshot?: true',
207 'create leave',
208 'run enter zone: outer-zone task-id: 0 arg: null',
209 'run leave'
210 ], log);
211 log.clear();
212
213 var completer1 = new Completer();
214 var counter1 = 0;
215 new Timer.periodic(const Duration(milliseconds: 5), (Timer timer) {
216 if (counter1++ > 1) {
217 timer.cancel();
218 completer1.complete("done");
219 }
220 });
221 await completer1.future;
222
223 // No visible change (except for the zone nome) in the log, compared to the
224 // simple invocations.
225 Expect.listEquals([
226 'create enter zone: outer-zone spec-duration: 0:00:00.005000 '
227 'spec-oneshot?: false',
228 'create leave',
229 'run enter zone: outer-zone task-id: 1 arg: null',
230 'run leave',
231 'run enter zone: outer-zone task-id: 1 arg: null',
232 'run leave',
233 'run enter zone: outer-zone task-id: 1 arg: null',
234 'run leave'
235 ], log);
236 log.clear();
237
238 var nestedCompleter = new Completer();
239
240 runZoned(() async {
241 var completer0 = new Completer();
242 Timer.run(() {
243 completer0.complete("done");
244 });
245 await completer0.future;
246
247 // The outer zone sees the duration change of the inner zone.
248 Expect.listEquals([
249 'create enter zone: inner-zone spec-duration: 0:00:00.000000 '
250 'spec-oneshot?: true',
251 'create enter zone: outer-zone spec-duration: 0:00:00.002000 '
252 'spec-oneshot?: true',
253 'create leave',
254 'create leave',
255 'run enter zone: inner-zone task-id: 3 arg: null',
256 'run enter zone: outer-zone task-id: 2 arg: null',
257 'run leave',
258 'run leave'
259 ], log);
260 log.clear();
261
262 var completer1 = new Completer();
263 var counter1 = 0;
264 new Timer.periodic(const Duration(milliseconds: 5), (Timer timer) {
265 if (counter1++ > 1) {
266 timer.cancel();
267 completer1.complete("done");
268 }
269 });
270 await completer1.future;
271
272 // The outer zone sees the duration change of the inner zone.
273 Expect.listEquals([
274 'create enter zone: inner-zone spec-duration: 0:00:00.005000 '
275 'spec-oneshot?: false',
276 'create enter zone: outer-zone spec-duration: 0:00:00.005000 '
277 'spec-oneshot?: false',
278 'create leave',
279 'create leave',
280 'run enter zone: inner-zone task-id: 5 arg: null',
281 'run enter zone: outer-zone task-id: 4 arg: null',
282 'run leave',
283 'run leave',
284 'run enter zone: inner-zone task-id: 5 arg: null',
285 'run enter zone: outer-zone task-id: 4 arg: null',
286 'run leave',
287 'run leave',
288 'run enter zone: inner-zone task-id: 5 arg: null',
289 'run enter zone: outer-zone task-id: 4 arg: null',
290 'run leave',
291 'run leave'
292 ], log);
293 log.clear();
294
295 nestedCompleter.complete("done");
296 },
297 zoneValues: {'name': 'inner-zone', 'taskMap': {}, 'taskIdMap': {}},
298 zoneSpecification: new ZoneSpecification(
299 createTask: createTaskHandler,
300 runTask: runTaskHandler));
301
302 await nestedCompleter.future;
303 testCompleter.complete("done");
304 asyncEnd();
305 },
306 zoneValues: {'name': 'outer-zone', 'taskMap': {}, 'taskIdMap': {}},
307 zoneSpecification: new ZoneSpecification(
308 createTask: createTaskHandler,
309 runTask: runTaskHandler));
310
311 return testCompleter.future;
312 }
313
314 class TimerEntry {
315 final int time;
316 final SimulatedTimer timer;
317
318 TimerEntry(this.time, this.timer);
319 }
320
321 class SimulatedTimer implements Timer {
322 static int _idCounter = 0;
323
324 Zone _zone;
325 final int _id = _idCounter++;
326 final Duration _duration;
327 final Function _callback;
328 final bool _isPeriodic;
329 bool _isActive = true;
330
331 SimulatedTimer(this._zone, this._duration, this._callback, this._isPeriodic);
332
333 bool get isActive => _isActive;
334
335 void cancel() {
336 _isActive = false;
337 }
338
339 void _run() {
340 if (!isActive) return;
341 _zone.runTask(_runTimer, this, null);
342 }
343
344 static void _runTimer(SimulatedTimer timer, _) {
345 if (timer._isPeriodic) {
346 timer._callback(timer);
347 } else {
348 timer._callback();
349 }
350 }
351 }
352
353 testSimulatedTimer() {
354 List log = [];
355
356 var currentTime = 0;
357 // Using a simple list as queue. Not very efficient, but the test has only
358 // very few timers running at the same time.
359 var queue = new DoubleLinkedQueue<TimerEntry>();
360
361 // Schedules the given callback at now + duration.
362 void schedule(int scheduledTime, SimulatedTimer timer) {
363 log.add("scheduling timer ${timer._id} for $scheduledTime");
364 if (queue.isEmpty) {
365 queue.add(new TimerEntry(scheduledTime, timer));
366 } else {
367 DoubleLinkedQueueEntry current = queue.firstEntry();
368 while (current != null) {
369 if (current.element.time <= scheduledTime) {
370 current = current.nextEntry();
371 } else {
372 current.prepend(new TimerEntry(scheduledTime, timer));
373 break;
374 }
375 }
376 if (current == null) {
377 queue.add(new TimerEntry(scheduledTime, timer));
378 }
379 }
380 }
381
382 void runQueue() {
383 while (queue.isNotEmpty) {
384 var item = queue.removeFirst();
385 // If multiple callbacks were scheduled at the same time, increment the
386 // current time instead of staying at the same time.
387 currentTime = item.time > currentTime ? item.time : currentTime + 1;
388 SimulatedTimer timer = item.timer;
389 log.add("running timer ${timer._id} at $currentTime "
390 "(active?: ${timer.isActive})");
391 if (!timer.isActive) continue;
392 if (timer._isPeriodic) {
393 schedule(currentTime + timer._duration.inMilliseconds, timer);
394 }
395 item.timer._run();
396 }
397 }
398
399 SimulatedTimer createSimulatedOneShotTimer(
400 SingleShotTimerTaskSpecification spec, Zone zone) {
401 var timer = new SimulatedTimer(zone, spec.duration, spec.callback, false);
402 schedule(currentTime + spec.duration.inMilliseconds, timer);
403 return timer;
404 }
405
406 SimulatedTimer createSimulatedPeriodicTimer(
407 PeriodicTimerTaskSpecification spec, Zone zone) {
408 var timer = new SimulatedTimer(zone, spec.duration, spec.callback, true);
409 schedule(currentTime + spec.duration.inMilliseconds, timer);
410 return timer;
411 }
412
413 Object createSimulatedTaskHandler(Zone self, ZoneDelegate parent, Zone zone,
414 TaskCreate create, TaskSpecification specification) {
415 var taskMap = self['taskMap'];
416 var taskIdMap = self['taskIdMap'];
417 if (specification is SingleShotTimerTaskSpecification) {
418 log.add("create enter "
419 "zone: ${self['name']} "
420 "spec-duration: ${specification.duration} "
421 "spec-oneshot?: ${specification.isOneShot}");
422 var result =
423 parent.createTask(zone, createSimulatedOneShotTimer, specification);
424 log.add("create leave");
425 return result;
426 }
427 if (specification is PeriodicTimerTaskSpecification) {
428 log.add("create enter "
429 "zone: ${self['name']} "
430 "spec-duration: ${specification.duration} "
431 "spec-oneshot?: ${specification.isOneShot}");
432 var result =
433 parent.createTask(zone, createSimulatedPeriodicTimer, specification);
434 log.add("create leave");
435 return result;
436 }
437 return parent.createTask(zone, create, specification);
438 }
439
440 runZoned(() {
441 Timer.run(() {
442 log.add("running Timer.run");
443 });
444
445 var timer0;
446
447 new Timer(const Duration(milliseconds: 10), () {
448 log.add("running Timer(10)");
449 timer0.cancel();
450 log.add("canceled timer0");
451 });
452
453 timer0 = new Timer(const Duration(milliseconds: 15), () {
454 log.add("running Timer(15)");
455 });
456
457 var counter1 = 0;
458 new Timer.periodic(const Duration(milliseconds: 5), (Timer timer) {
459 log.add("running periodic timer $counter1");
460 if (counter1++ > 1) {
461 timer.cancel();
462 }
463 });
464 },
465 zoneSpecification:
466 new ZoneSpecification(createTask: createSimulatedTaskHandler));
467
468 runQueue();
469
470 Expect.listEquals([
471 'create enter zone: null spec-duration: 0:00:00.000000 spec-oneshot?: true',
472 'scheduling timer 0 for 0',
473 'create leave',
474 'create enter zone: null spec-duration: 0:00:00.010000 spec-oneshot?: true',
475 'scheduling timer 1 for 10',
476 'create leave',
477 'create enter zone: null spec-duration: 0:00:00.015000 spec-oneshot?: true',
478 'scheduling timer 2 for 15',
479 'create leave',
480 'create enter zone: null spec-duration: 0:00:00.005000 '
481 'spec-oneshot?: false',
482 'scheduling timer 3 for 5',
483 'create leave',
484 'running timer 0 at 1 (active?: true)',
485 'running Timer.run',
486 'running timer 3 at 5 (active?: true)',
487 'scheduling timer 3 for 10',
488 'running periodic timer 0',
489 'running timer 1 at 10 (active?: true)',
490 'running Timer(10)',
491 'canceled timer0',
492 'running timer 3 at 11 (active?: true)',
493 'scheduling timer 3 for 16',
494 'running periodic timer 1',
495 'running timer 2 at 15 (active?: false)',
496 'running timer 3 at 16 (active?: true)',
497 'scheduling timer 3 for 21',
498 'running periodic timer 2',
499 'running timer 3 at 21 (active?: false)'
500 ], log);
501 log.clear();
502 }
503
504 runTests() async {
505 await testTimerTask();
506 await testTimerTask2();
507 testSimulatedTimer();
508 }
509
510 main() {
511 asyncStart();
512 runTests().then((_) {
513 asyncEnd();
514 });
515 }
OLDNEW
« no previous file with comments | « tests/lib/async/zone_task_test.dart ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698