1// Copyright (c) 2011 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 "chrome/browser/sync/glue/data_type_manager_impl.h"
6
7#include <set>
8
9#include "base/memory/scoped_ptr.h"
10#include "base/message_loop.h"
11#include "base/stl_util-inl.h"
12#include "base/task.h"
13#include "chrome/browser/sync/glue/data_type_controller.h"
14#include "chrome/browser/sync/glue/data_type_controller_mock.h"
15#include "chrome/browser/sync/glue/sync_backend_host_mock.h"
16#include "chrome/browser/sync/profile_sync_test_util.h"
17#include "chrome/browser/sync/syncable/model_type.h"
18#include "content/browser/browser_thread.h"
19#include "content/common/notification_details.h"
20#include "content/common/notification_observer_mock.h"
21#include "content/common/notification_registrar.h"
22#include "content/common/notification_service.h"
23#include "content/common/notification_type.h"
24#include "testing/gmock/include/gmock/gmock.h"
25#include "testing/gtest/include/gtest/gtest.h"
26
27using browser_sync::DataTypeManager;
28using browser_sync::DataTypeManagerImpl;
29using browser_sync::DataTypeController;
30using browser_sync::DataTypeControllerMock;
31using browser_sync::SyncBackendHostMock;
32using testing::_;
33using testing::AtLeast;
34using testing::DoAll;
35using testing::DoDefault;
36using testing::InSequence;
37using testing::Invoke;
38using testing::InvokeWithoutArgs;
39using testing::InvokeWithoutArgs;
40using testing::Mock;
41using testing::Property;
42using testing::Pointee;
43using testing::Return;
44using testing::SaveArg;
45
46ACTION_P(InvokeCallback, callback_result) {
47  arg0->Run(callback_result, FROM_HERE);
48  delete arg0;
49}
50
51ACTION_P2(InvokeCallbackPointer, callback, argument) {
52  callback->Run(argument, FROM_HERE);
53  delete callback;
54}
55
56DataTypeManager::ConfigureResult GetResult(
57    const NotificationDetails& details) {
58  DataTypeManager::ConfigureResultWithErrorLocation* result_with_location =
59      Details<DataTypeManager::ConfigureResultWithErrorLocation>(
60      details).ptr();
61  return result_with_location->result;
62}
63
64class DataTypeManagerImpl2Test : public testing::Test {
65 public:
66  DataTypeManagerImpl2Test()
67      : ui_thread_(BrowserThread::UI, &message_loop_) {}
68
69  virtual ~DataTypeManagerImpl2Test() {
70  }
71
72 protected:
73  virtual void SetUp() {
74    registrar_.Add(&observer_,
75                   NotificationType::SYNC_CONFIGURE_START,
76                   NotificationService::AllSources());
77    registrar_.Add(&observer_,
78                   NotificationType::SYNC_CONFIGURE_DONE,
79                   NotificationService::AllSources());
80  }
81
82  DataTypeControllerMock* MakeBookmarkDTC() {
83    DataTypeControllerMock* dtc = new DataTypeControllerMock();
84    EXPECT_CALL(*dtc, enabled()).WillRepeatedly(Return(true));
85    EXPECT_CALL(*dtc, type()).WillRepeatedly(Return(syncable::BOOKMARKS));
86    EXPECT_CALL(*dtc, name()).WillRepeatedly(Return("bookmark"));
87    return dtc;
88  }
89
90  DataTypeControllerMock* MakePreferenceDTC() {
91    DataTypeControllerMock* dtc = new DataTypeControllerMock();
92    EXPECT_CALL(*dtc, enabled()).WillRepeatedly(Return(true));
93    EXPECT_CALL(*dtc, type()).WillRepeatedly(Return(syncable::PREFERENCES));
94    EXPECT_CALL(*dtc, name()).WillRepeatedly(Return("preference"));
95    return dtc;
96  }
97
98  DataTypeControllerMock* MakePasswordDTC() {
99    DataTypeControllerMock* dtc = new DataTypeControllerMock();
100    SetPasswordDTCExpectations(dtc);
101    return dtc;
102  }
103
104  void SetPasswordDTCExpectations(DataTypeControllerMock* dtc) {
105    EXPECT_CALL(*dtc, enabled()).WillRepeatedly(Return(true));
106    EXPECT_CALL(*dtc, type()).WillRepeatedly(Return(syncable::PASSWORDS));
107    EXPECT_CALL(*dtc, name()).WillRepeatedly(Return("passwords"));
108  }
109
110  void SetStartStopExpectations(DataTypeControllerMock* mock_dtc) {
111    InSequence seq;
112    EXPECT_CALL(*mock_dtc, state()).
113        WillRepeatedly(Return(DataTypeController::NOT_RUNNING));
114    EXPECT_CALL(*mock_dtc, Start(_)).
115        WillOnce(InvokeCallback((DataTypeController::OK)));
116    EXPECT_CALL(*mock_dtc, state()).
117        WillRepeatedly(Return(DataTypeController::RUNNING));
118    EXPECT_CALL(*mock_dtc, Stop()).Times(1);
119    EXPECT_CALL(*mock_dtc, state()).
120        WillRepeatedly(Return(DataTypeController::NOT_RUNNING));
121  }
122
123  void SetBusyStartStopExpectations(DataTypeControllerMock* mock_dtc,
124                                    DataTypeController::State busy_state) {
125    InSequence seq;
126    EXPECT_CALL(*mock_dtc, state()).
127        WillRepeatedly(Return(DataTypeController::NOT_RUNNING));
128    EXPECT_CALL(*mock_dtc, Start(_)).
129        WillOnce(InvokeCallback((DataTypeController::OK)));
130    EXPECT_CALL(*mock_dtc, state()).
131        WillRepeatedly(Return(busy_state));
132    EXPECT_CALL(*mock_dtc, Stop()).Times(1);
133    EXPECT_CALL(*mock_dtc, state()).
134        WillRepeatedly(Return(DataTypeController::NOT_RUNNING));
135  }
136
137  void SetNotUsedExpectations(DataTypeControllerMock* mock_dtc) {
138    EXPECT_CALL(*mock_dtc, Start(_)).Times(0);
139    EXPECT_CALL(*mock_dtc, Stop()).Times(0);
140    EXPECT_CALL(*mock_dtc, state()).
141        WillRepeatedly(Return(DataTypeController::NOT_RUNNING));
142  }
143
144  void SetConfigureStartExpectation() {
145    EXPECT_CALL(
146        observer_,
147        Observe(NotificationType(NotificationType::SYNC_CONFIGURE_START),
148                _, _));
149  }
150
151
152  void SetConfigureDoneExpectation(DataTypeManager::ConfigureResult result) {
153    EXPECT_CALL(
154        observer_,
155        Observe(NotificationType(NotificationType::SYNC_CONFIGURE_DONE), _,
156        ::testing::ResultOf(&GetResult, result)));
157  }
158
159  MessageLoopForUI message_loop_;
160  BrowserThread ui_thread_;
161  DataTypeController::TypeMap controllers_;
162  SyncBackendHostMock backend_;
163  NotificationObserverMock observer_;
164  NotificationRegistrar registrar_;
165  std::set<syncable::ModelType> types_;
166};
167
168TEST_F(DataTypeManagerImpl2Test, NoControllers) {
169  DataTypeManagerImpl dtm(&backend_, controllers_);
170  SetConfigureStartExpectation();
171  SetConfigureDoneExpectation(DataTypeManager::OK);
172  dtm.Configure(types_);
173  EXPECT_EQ(DataTypeManager::CONFIGURED, dtm.state());
174  dtm.Stop();
175  EXPECT_EQ(DataTypeManager::STOPPED, dtm.state());
176}
177
178TEST_F(DataTypeManagerImpl2Test, ConfigureOne) {
179  DataTypeControllerMock* bookmark_dtc = MakeBookmarkDTC();
180  SetStartStopExpectations(bookmark_dtc);
181  controllers_[syncable::BOOKMARKS] = bookmark_dtc;
182  EXPECT_CALL(backend_, ConfigureDataTypes(_, _, _)).Times(1);
183  DataTypeManagerImpl dtm(&backend_, controllers_);
184  types_.insert(syncable::BOOKMARKS);
185  SetConfigureStartExpectation();
186  SetConfigureDoneExpectation(DataTypeManager::OK);
187  dtm.Configure(types_);
188  EXPECT_EQ(DataTypeManager::CONFIGURED, dtm.state());
189  dtm.Stop();
190  EXPECT_EQ(DataTypeManager::STOPPED, dtm.state());
191}
192
193TEST_F(DataTypeManagerImpl2Test, ConfigureOneStopWhileStarting) {
194  DataTypeControllerMock* bookmark_dtc = MakeBookmarkDTC();
195  SetBusyStartStopExpectations(bookmark_dtc,
196                               DataTypeController::MODEL_STARTING);
197  controllers_[syncable::BOOKMARKS] = bookmark_dtc;
198  EXPECT_CALL(backend_, ConfigureDataTypes(_, _, _)).Times(1);
199  DataTypeManagerImpl dtm(&backend_, controllers_);
200  types_.insert(syncable::BOOKMARKS);
201  SetConfigureStartExpectation();
202  SetConfigureDoneExpectation(DataTypeManager::OK);
203  dtm.Configure(types_);
204  EXPECT_EQ(DataTypeManager::CONFIGURED, dtm.state());
205  dtm.Stop();
206  EXPECT_EQ(DataTypeManager::STOPPED, dtm.state());
207}
208
209TEST_F(DataTypeManagerImpl2Test, ConfigureOneStopWhileAssociating) {
210  DataTypeControllerMock* bookmark_dtc = MakeBookmarkDTC();
211  SetBusyStartStopExpectations(bookmark_dtc, DataTypeController::ASSOCIATING);
212  controllers_[syncable::BOOKMARKS] = bookmark_dtc;
213  EXPECT_CALL(backend_, ConfigureDataTypes(_, _, _)).Times(1);
214  DataTypeManagerImpl dtm(&backend_, controllers_);
215  types_.insert(syncable::BOOKMARKS);
216  SetConfigureStartExpectation();
217  SetConfigureDoneExpectation(DataTypeManager::OK);
218  dtm.Configure(types_);
219  EXPECT_EQ(DataTypeManager::CONFIGURED, dtm.state());
220  dtm.Stop();
221  EXPECT_EQ(DataTypeManager::STOPPED, dtm.state());
222}
223
224TEST_F(DataTypeManagerImpl2Test, OneWaitingForCrypto) {
225  DataTypeControllerMock* password_dtc = MakePasswordDTC();
226  EXPECT_CALL(*password_dtc, state()).Times(AtLeast(2)).
227      WillRepeatedly(Return(DataTypeController::NOT_RUNNING));
228  EXPECT_CALL(*password_dtc, Start(_)).
229      WillOnce(InvokeCallback((DataTypeController::NEEDS_CRYPTO)));
230
231  controllers_[syncable::PASSWORDS] = password_dtc;
232  EXPECT_CALL(backend_, ConfigureDataTypes(_, _, _)).Times(1);
233
234  DataTypeManagerImpl dtm(&backend_, controllers_);
235  types_.insert(syncable::PASSWORDS);
236  SetConfigureStartExpectation();
237
238  dtm.Configure(types_);
239  EXPECT_EQ(DataTypeManager::BLOCKED, dtm.state());
240
241  Mock::VerifyAndClearExpectations(&backend_);
242  Mock::VerifyAndClearExpectations(&observer_);
243  Mock::VerifyAndClearExpectations(password_dtc);
244
245  SetConfigureDoneExpectation(DataTypeManager::OK);
246  SetPasswordDTCExpectations(password_dtc);
247  EXPECT_CALL(*password_dtc, state()).
248      WillOnce(Return(DataTypeController::NOT_RUNNING)).
249      WillRepeatedly(Return(DataTypeController::RUNNING));
250  EXPECT_CALL(*password_dtc, Start(_)).
251      WillOnce(InvokeCallback((DataTypeController::OK)));
252  EXPECT_CALL(backend_, ConfigureDataTypes(_, _, _)).Times(1);
253  dtm.Configure(types_);
254
255  EXPECT_EQ(DataTypeManager::CONFIGURED, dtm.state());
256  EXPECT_CALL(*password_dtc, Stop()).Times(1);
257  dtm.Stop();
258  EXPECT_EQ(DataTypeManager::STOPPED, dtm.state());
259}
260
261TEST_F(DataTypeManagerImpl2Test, ConfigureOneThenAnother) {
262  DataTypeControllerMock* bookmark_dtc = MakeBookmarkDTC();
263  SetStartStopExpectations(bookmark_dtc);
264  controllers_[syncable::BOOKMARKS] = bookmark_dtc;
265  DataTypeControllerMock* preference_dtc = MakePreferenceDTC();
266  SetStartStopExpectations(preference_dtc);
267  controllers_[syncable::PREFERENCES] = preference_dtc;
268
269  EXPECT_CALL(backend_, ConfigureDataTypes(_, _, _)).Times(2);
270  DataTypeManagerImpl dtm(&backend_, controllers_);
271  types_.insert(syncable::BOOKMARKS);
272
273  SetConfigureStartExpectation();
274  SetConfigureDoneExpectation(DataTypeManager::OK);
275  dtm.Configure(types_);
276  EXPECT_EQ(DataTypeManager::CONFIGURED, dtm.state());
277
278  types_.insert(syncable::PREFERENCES);
279  SetConfigureStartExpectation();
280  SetConfigureDoneExpectation(DataTypeManager::OK);
281  dtm.Configure(types_);
282  EXPECT_EQ(DataTypeManager::CONFIGURED, dtm.state());
283
284  dtm.Stop();
285  EXPECT_EQ(DataTypeManager::STOPPED, dtm.state());
286}
287
288TEST_F(DataTypeManagerImpl2Test, ConfigureOneThenSwitch) {
289  DataTypeControllerMock* bookmark_dtc = MakeBookmarkDTC();
290  SetStartStopExpectations(bookmark_dtc);
291  controllers_[syncable::BOOKMARKS] = bookmark_dtc;
292  DataTypeControllerMock* preference_dtc = MakePreferenceDTC();
293  SetStartStopExpectations(preference_dtc);
294  controllers_[syncable::PREFERENCES] = preference_dtc;
295
296  EXPECT_CALL(backend_, ConfigureDataTypes(_, _, _)).Times(2);
297  DataTypeManagerImpl dtm(&backend_, controllers_);
298  types_.insert(syncable::BOOKMARKS);
299
300  SetConfigureStartExpectation();
301  SetConfigureDoneExpectation(DataTypeManager::OK);
302  dtm.Configure(types_);
303  EXPECT_EQ(DataTypeManager::CONFIGURED, dtm.state());
304
305  types_.clear();
306  types_.insert(syncable::PREFERENCES);
307  SetConfigureStartExpectation();
308  SetConfigureDoneExpectation(DataTypeManager::OK);
309  dtm.Configure(types_);
310  EXPECT_EQ(DataTypeManager::CONFIGURED, dtm.state());
311
312  dtm.Stop();
313  EXPECT_EQ(DataTypeManager::STOPPED, dtm.state());
314}
315
316void DoConfigureDataTypes(
317    const DataTypeController::TypeMap& data_type_controllers,
318    const syncable::ModelTypeSet& types,
319    CancelableTask* ready_task) {
320  ready_task->Run();
321  delete ready_task;
322}
323
324void QuitMessageLoop() {
325  MessageLoop::current()->Quit();
326}
327
328TEST_F(DataTypeManagerImpl2Test, ConfigureWhileOneInFlight) {
329  DataTypeControllerMock* bookmark_dtc = MakeBookmarkDTC();
330  // Save the callback here so we can interrupt startup.
331  DataTypeController::StartCallback* callback;
332  {
333    InSequence seq;
334    EXPECT_CALL(*bookmark_dtc, state()).
335        WillRepeatedly(Return(DataTypeController::NOT_RUNNING));
336    EXPECT_CALL(*bookmark_dtc, Start(_)).
337        WillOnce(SaveArg<0>(&callback));
338    EXPECT_CALL(*bookmark_dtc, state()).
339        WillRepeatedly(Return(DataTypeController::RUNNING));
340    EXPECT_CALL(*bookmark_dtc, Stop()).Times(1);
341    EXPECT_CALL(*bookmark_dtc, state()).
342        WillRepeatedly(Return(DataTypeController::NOT_RUNNING));
343  }
344  controllers_[syncable::BOOKMARKS] = bookmark_dtc;
345
346  DataTypeControllerMock* preference_dtc = MakePreferenceDTC();
347  SetStartStopExpectations(preference_dtc);
348  controllers_[syncable::PREFERENCES] = preference_dtc;
349
350  DataTypeManagerImpl dtm(&backend_, controllers_);
351  EXPECT_CALL(backend_, ConfigureDataTypes(_, _, _))
352    .WillOnce(Invoke(DoConfigureDataTypes))
353    .WillOnce(DoAll(Invoke(DoConfigureDataTypes),
354     InvokeWithoutArgs(QuitMessageLoop)));
355
356  types_.insert(syncable::BOOKMARKS);
357
358  SetConfigureStartExpectation();
359  SetConfigureDoneExpectation(DataTypeManager::OK);
360  dtm.Configure(types_);
361
362  // At this point, the bookmarks dtc should be in flight.  Add
363  // preferences and continue starting bookmarks.
364  types_.insert(syncable::PREFERENCES);
365  dtm.Configure(types_);
366  callback->Run(DataTypeController::OK, FROM_HERE);
367  delete callback;
368
369  MessageLoop::current()->Run();
370
371  EXPECT_EQ(DataTypeManager::CONFIGURED, dtm.state());
372
373  dtm.Stop();
374  EXPECT_EQ(DataTypeManager::STOPPED, dtm.state());
375}
376
377TEST_F(DataTypeManagerImpl2Test, OneFailingController) {
378  DataTypeControllerMock* bookmark_dtc = MakeBookmarkDTC();
379  EXPECT_CALL(*bookmark_dtc, Start(_)).
380      WillOnce(InvokeCallback((DataTypeController::ASSOCIATION_FAILED)));
381  EXPECT_CALL(*bookmark_dtc, Stop()).Times(0);
382  EXPECT_CALL(*bookmark_dtc, state()).
383      WillRepeatedly(Return(DataTypeController::NOT_RUNNING));
384  controllers_[syncable::BOOKMARKS] = bookmark_dtc;
385
386  DataTypeManagerImpl dtm(&backend_, controllers_);
387  SetConfigureStartExpectation();
388  SetConfigureDoneExpectation(DataTypeManager::ASSOCIATION_FAILED);
389  EXPECT_CALL(backend_, ConfigureDataTypes(_, _, _)).Times(1);
390
391  types_.insert(syncable::BOOKMARKS);
392  dtm.Configure(types_);
393  EXPECT_EQ(DataTypeManager::STOPPED, dtm.state());
394}
395
396TEST_F(DataTypeManagerImpl2Test, StopWhileInFlight) {
397  DataTypeControllerMock* bookmark_dtc = MakeBookmarkDTC();
398  SetStartStopExpectations(bookmark_dtc);
399  controllers_[syncable::BOOKMARKS] = bookmark_dtc;
400
401  DataTypeControllerMock* preference_dtc = MakePreferenceDTC();
402  // Save the callback here so we can interrupt startup.
403  DataTypeController::StartCallback* callback;
404  EXPECT_CALL(*preference_dtc, Start(_)).
405      WillOnce(SaveArg<0>(&callback));
406  EXPECT_CALL(*preference_dtc, state()).
407      WillRepeatedly(Return(DataTypeController::NOT_RUNNING));
408  controllers_[syncable::PREFERENCES] = preference_dtc;
409
410  DataTypeManagerImpl dtm(&backend_, controllers_);
411  SetConfigureStartExpectation();
412  SetConfigureDoneExpectation(DataTypeManager::ABORTED);
413  EXPECT_CALL(backend_, ConfigureDataTypes(_, _, _)).Times(1);
414
415  types_.insert(syncable::BOOKMARKS);
416  types_.insert(syncable::PREFERENCES);
417  dtm.Configure(types_);
418  // Configure should stop in the CONFIGURING state because we are
419  // waiting for the preferences callback to be invoked.
420  EXPECT_EQ(DataTypeManager::CONFIGURING, dtm.state());
421
422  // Call stop before the preference callback is invoked.
423  EXPECT_CALL(*preference_dtc, Stop()).
424      WillOnce(InvokeCallbackPointer(callback, DataTypeController::ABORTED));
425  dtm.Stop();
426  EXPECT_EQ(DataTypeManager::STOPPED, dtm.state());
427}
428
429TEST_F(DataTypeManagerImpl2Test, SecondControllerFails) {
430  DataTypeControllerMock* bookmark_dtc = MakeBookmarkDTC();
431  SetStartStopExpectations(bookmark_dtc);
432  controllers_[syncable::BOOKMARKS] = bookmark_dtc;
433
434  DataTypeControllerMock* preference_dtc = MakePreferenceDTC();
435  EXPECT_CALL(*preference_dtc, Start(_)).
436      WillOnce(InvokeCallback((DataTypeController::ASSOCIATION_FAILED)));
437  EXPECT_CALL(*preference_dtc, Stop()).Times(0);
438  EXPECT_CALL(*preference_dtc, state()).
439      WillRepeatedly(Return(DataTypeController::NOT_RUNNING));
440  controllers_[syncable::PREFERENCES] = preference_dtc;
441
442  DataTypeManagerImpl dtm(&backend_, controllers_);
443  SetConfigureStartExpectation();
444  SetConfigureDoneExpectation(DataTypeManager::ASSOCIATION_FAILED);
445  EXPECT_CALL(backend_, ConfigureDataTypes(_, _, _)).Times(1);
446
447  types_.insert(syncable::BOOKMARKS);
448  types_.insert(syncable::PREFERENCES);
449  dtm.Configure(types_);
450  EXPECT_EQ(DataTypeManager::STOPPED, dtm.state());
451}
452
453TEST_F(DataTypeManagerImpl2Test, ConfigureWhileDownloadPending) {
454  DataTypeControllerMock* bookmark_dtc = MakeBookmarkDTC();
455  SetStartStopExpectations(bookmark_dtc);
456  controllers_[syncable::BOOKMARKS] = bookmark_dtc;
457
458  DataTypeControllerMock* preference_dtc = MakePreferenceDTC();
459  SetStartStopExpectations(preference_dtc);
460  controllers_[syncable::PREFERENCES] = preference_dtc;
461
462  DataTypeManagerImpl dtm(&backend_, controllers_);
463  SetConfigureStartExpectation();
464  SetConfigureDoneExpectation(DataTypeManager::OK);
465  CancelableTask* task;
466  // Grab the task the first time this is called so we can configure
467  // before it is finished.
468  EXPECT_CALL(backend_, ConfigureDataTypes(_, _, _)).
469      WillOnce(SaveArg<2>(&task)).
470      WillOnce(DoDefault());
471
472  types_.insert(syncable::BOOKMARKS);
473  dtm.Configure(types_);
474  // Configure should stop in the DOWNLOAD_PENDING state because we
475  // are waiting for the download ready task to be run.
476  EXPECT_EQ(DataTypeManager::DOWNLOAD_PENDING, dtm.state());
477
478  types_.insert(syncable::PREFERENCES);
479  dtm.Configure(types_);
480
481  // Running the task will queue a restart task to the message loop, and
482  // eventually get us configured.
483  task->Run();
484  delete task;
485  MessageLoop::current()->RunAllPending();
486  EXPECT_EQ(DataTypeManager::CONFIGURED, dtm.state());
487
488  dtm.Stop();
489  EXPECT_EQ(DataTypeManager::STOPPED, dtm.state());
490}
491
492TEST_F(DataTypeManagerImpl2Test, StopWhileDownloadPending) {
493  DataTypeControllerMock* bookmark_dtc = MakeBookmarkDTC();
494  SetNotUsedExpectations(bookmark_dtc);
495  controllers_[syncable::BOOKMARKS] = bookmark_dtc;
496
497  DataTypeManagerImpl dtm(&backend_, controllers_);
498  SetConfigureStartExpectation();
499  SetConfigureDoneExpectation(DataTypeManager::ABORTED);
500  CancelableTask* task;
501  // Grab the task the first time this is called so we can stop
502  // before it is finished.
503  EXPECT_CALL(backend_, ConfigureDataTypes(_, _, _)).
504      WillOnce(SaveArg<2>(&task));
505
506  types_.insert(syncable::BOOKMARKS);
507  dtm.Configure(types_);
508  // Configure should stop in the DOWNLOAD_PENDING state because we
509  // are waiting for the download ready task to be run.
510  EXPECT_EQ(DataTypeManager::DOWNLOAD_PENDING, dtm.state());
511
512  dtm.Stop();
513  EXPECT_EQ(DataTypeManager::STOPPED, dtm.state());
514
515  // It should be perfectly safe to run this task even though the DTM
516  // has been stopped.
517  task->Run();
518  delete task;
519}
520