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

Side by Side Diff: chrome/browser/sync/glue/bookmark_model_worker_unittest.cc

Issue 160598: Add files to browser/sync. (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 11 years, 4 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 | Annotate | Revision Log
Property Changes:
Added: svn:eol-style
+ LF
OLDNEW
(Empty)
1 // Copyright (c) 2006-2009 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 #ifdef CHROME_PERSONALIZATION
5
6 #include "base/thread.h"
7 #include "chrome/browser/sync/engine/syncapi.h"
8 #include "chrome/browser/sync/glue/bookmark_model_worker.h"
9 #include "testing/gtest/include/gtest/gtest.h"
10
11 using browser_sync::BookmarkModelWorker;
12 using namespace sync_api;
13
14 // Various boilerplate, primarily for the StopWithPendingWork test.
15
16 class BookmarkModelWorkerVisitor : public ModelSafeWorkerInterface::Visitor {
17 public:
18 BookmarkModelWorkerVisitor(MessageLoop* faux_ui_loop,
19 base::WaitableEvent* was_run,
20 bool quit_loop)
21 : faux_ui_loop_(faux_ui_loop), quit_loop_when_run_(quit_loop),
22 was_run_(was_run) { }
23 virtual ~BookmarkModelWorkerVisitor() { }
24
25 virtual void DoWork() {
26 EXPECT_EQ(MessageLoop::current(), faux_ui_loop_);
27 was_run_->Signal();
28 if (quit_loop_when_run_)
29 MessageLoop::current()->Quit();
30 }
31
32 private:
33 MessageLoop* faux_ui_loop_;
34 bool quit_loop_when_run_;
35 base::WaitableEvent* was_run_;
36 DISALLOW_COPY_AND_ASSIGN(BookmarkModelWorkerVisitor);
37 };
38
39 // A faux-syncer that only interacts with its model safe worker.
40 class Syncer {
41 public:
42 explicit Syncer(BookmarkModelWorker* worker) : worker_(worker) {}
43 ~Syncer() {}
44
45 void SyncShare(BookmarkModelWorkerVisitor* visitor) {
46 worker_->CallDoWorkFromModelSafeThreadAndWait(visitor);
47 }
48 private:
49 BookmarkModelWorker* worker_;
50 DISALLOW_COPY_AND_ASSIGN(Syncer);
51 };
52
53 // A task run from the SyncerThread to "sync share", ie tell the Syncer to
54 // ask it's ModelSafeWorker to do something.
55 class FakeSyncShareTask : public Task {
56 public:
57 FakeSyncShareTask(Syncer* syncer, BookmarkModelWorkerVisitor* visitor)
58 : syncer_(syncer), visitor_(visitor) {
59 }
60 virtual void Run() {
61 syncer_->SyncShare(visitor_);
62 }
63 private:
64 Syncer* syncer_;
65 BookmarkModelWorkerVisitor* visitor_;
66 DISALLOW_COPY_AND_ASSIGN(FakeSyncShareTask);
67 };
68
69 // A task run from the CoreThread to simulate terminating syncapi.
70 class FakeSyncapiShutdownTask : public Task {
71 public:
72 FakeSyncapiShutdownTask(base::Thread* syncer_thread,
73 BookmarkModelWorker* worker,
74 base::WaitableEvent** jobs,
75 size_t job_count)
76 : syncer_thread_(syncer_thread), worker_(worker), jobs_(jobs),
77 job_count_(job_count), all_jobs_done_(false, false) { }
78 virtual void Run() {
79 // In real life, we would try and close a sync directory, which would
80 // result in the syncer calling it's own destructor, which results in
81 // the SyncerThread::HaltSyncer being called, which sets the
82 // syncer in RequestEarlyExit mode and waits until the Syncer finishes
83 // SyncShare to remove the syncer from it's watch. Here we just manually
84 // wait until all outstanding jobs are done to simulate what happens in
85 // SyncerThread::HaltSyncer.
86 all_jobs_done_.WaitMany(jobs_, job_count_);
87
88 // These two calls are made from SyncBackendHost::Core::DoShutdown.
89 syncer_thread_->Stop();
90 worker_->OnSyncerShutdownComplete();
91 }
92 private:
93 base::Thread* syncer_thread_;
94 BookmarkModelWorker* worker_;
95 base::WaitableEvent** jobs_;
96 size_t job_count_;
97 base::WaitableEvent all_jobs_done_;
98 DISALLOW_COPY_AND_ASSIGN(FakeSyncapiShutdownTask);
99 };
100
101 class BookmarkModelWorkerTest : public testing::Test {
102 public:
103 BookmarkModelWorkerTest() : faux_syncer_thread_("FauxSyncerThread"),
104 faux_core_thread_("FauxCoreThread") { }
105
106 virtual void SetUp() {
107 faux_syncer_thread_.Start();
108 bmw_.reset(new BookmarkModelWorker(&faux_ui_loop_));
109 syncer_.reset(new Syncer(bmw_.get()));
110 }
111
112 Syncer* syncer() { return syncer_.get(); }
113 BookmarkModelWorker* bmw() { return bmw_.get(); }
114 base::Thread* core_thread() { return &faux_core_thread_; }
115 base::Thread* syncer_thread() { return &faux_syncer_thread_; }
116 MessageLoop* ui_loop() { return &faux_ui_loop_; }
117 private:
118 MessageLoop faux_ui_loop_;
119 base::Thread faux_syncer_thread_;
120 base::Thread faux_core_thread_;
121 scoped_ptr<BookmarkModelWorker> bmw_;
122 scoped_ptr<Syncer> syncer_;
123 };
124
125 TEST_F(BookmarkModelWorkerTest, ScheduledWorkRunsOnUILoop) {
126 base::WaitableEvent v_was_run(false, false);
127 scoped_ptr<BookmarkModelWorkerVisitor> v(
128 new BookmarkModelWorkerVisitor(ui_loop(), &v_was_run, true));
129
130 syncer_thread()->message_loop()->PostTask(FROM_HERE,
131 new FakeSyncShareTask(syncer(), v.get()));
132
133 // We are on the UI thread, so run our loop to process the
134 // (hopefully) scheduled task from a SyncShare invocation.
135 MessageLoop::current()->Run();
136
137 bmw()->OnSyncerShutdownComplete();
138 bmw()->Stop();
139 syncer_thread()->Stop();
140 }
141
142 TEST_F(BookmarkModelWorkerTest, StopWithPendingWork) {
143 // What we want to set up is the following:
144 // ("ui_thread" is the thread we are currently executing on)
145 // 1 - simulate the user shutting down the browser, and the ui thread needing
146 // to terminate the core thread.
147 // 2 - the core thread is where the syncapi is accessed from, and so it needs
148 // to shut down the SyncerThread.
149 // 3 - the syncer is waiting on the BookmarkModelWorker to
150 // perform a task for it.
151 // The BookmarkModelWorker's manual shutdown pump will save the day, as the
152 // UI thread is not actually trying to join() the core thread, it is merely
153 // waiting for the SyncerThread to give it work or to finish. After that, it
154 // will join the core thread which should succeed as the SyncerThread has left
155 // the building. Unfortunately this test as written is not provably decidable,
156 // as it will always halt on success, but it may not on failure (namely if
157 // the task scheduled by the Syncer is _never_ run).
158 core_thread()->Start();
159 base::WaitableEvent v_ran(false, false);
160 scoped_ptr<BookmarkModelWorkerVisitor> v(new BookmarkModelWorkerVisitor(
161 ui_loop(), &v_ran, false));
162 base::WaitableEvent* jobs[] = { &v_ran };
163
164 // The current message loop is not running, so queue a task to cause
165 // BookmarkModelWorker::Stop() to play a crucial role. See comment below.
166 syncer_thread()->message_loop()->PostTask(FROM_HERE,
167 new FakeSyncShareTask(syncer(), v.get()));
168
169 // This is what gets the core_thread blocked on the syncer_thread.
170 core_thread()->message_loop()->PostTask(FROM_HERE,
171 new FakeSyncapiShutdownTask(syncer_thread(), bmw(), jobs, 1));
172
173 // This is what gets the UI thread blocked until NotifyExitRequested,
174 // which is called when FakeSyncapiShutdownTask runs and deletes the syncer.
175 bmw()->Stop();
176
177 EXPECT_FALSE(syncer_thread()->IsRunning());
178 core_thread()->Stop();
179 }
180
181 TEST_F(BookmarkModelWorkerTest, HypotheticalManualPumpFlooding) {
182 // This situation should not happen in real life because the Syncer should
183 // never send more than one CallDoWork notification after early_exit_requested
184 // has been set, but our BookmarkModelWorker is built to handle this case
185 // nonetheless. It may be needed in the future, and since we support it and
186 // it is not actually exercised in the wild this test is essential.
187 // It is identical to above except we schedule more than one visitor.
188 core_thread()->Start();
189
190 // Our ammunition.
191 base::WaitableEvent fox1_ran(false, false);
192 scoped_ptr<BookmarkModelWorkerVisitor> fox1(new BookmarkModelWorkerVisitor(
193 ui_loop(), &fox1_ran, false));
194 base::WaitableEvent fox2_ran(false, false);
195 scoped_ptr<BookmarkModelWorkerVisitor> fox2(new BookmarkModelWorkerVisitor(
196 ui_loop(), &fox2_ran, false));
197 base::WaitableEvent fox3_ran(false, false);
198 scoped_ptr<BookmarkModelWorkerVisitor> fox3(new BookmarkModelWorkerVisitor(
199 ui_loop(), &fox3_ran, false));
200 base::WaitableEvent* jobs[] = { &fox1_ran, &fox2_ran, &fox3_ran };
201
202 // The current message loop is not running, so queue a task to cause
203 // BookmarkModelWorker::Stop() to play a crucial role. See comment below.
204 syncer_thread()->message_loop()->PostTask(FROM_HERE,
205 new FakeSyncShareTask(syncer(), fox1.get()));
206 syncer_thread()->message_loop()->PostTask(FROM_HERE,
207 new FakeSyncShareTask(syncer(), fox2.get()));
208
209 // This is what gets the core_thread blocked on the syncer_thread.
210 core_thread()->message_loop()->PostTask(FROM_HERE,
211 new FakeSyncapiShutdownTask(syncer_thread(), bmw(), jobs, 3));
212 syncer_thread()->message_loop()->PostTask(FROM_HERE,
213 new FakeSyncShareTask(syncer(), fox3.get()));
214
215 // This is what gets the UI thread blocked until NotifyExitRequested,
216 // which is called when FakeSyncapiShutdownTask runs and deletes the syncer.
217 bmw()->Stop();
218
219 // Was the thread killed?
220 EXPECT_FALSE(syncer_thread()->IsRunning());
221 core_thread()->Stop();
222 }
223
224 #endif // CHROME_PERSONALIZATION
OLDNEW
« no previous file with comments | « chrome/browser/sync/glue/bookmark_model_worker.cc ('k') | chrome/browser/sync/glue/http_bridge.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698