1// Copyright (c) 2012 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 "base/bind.h"
6#include "base/bind_helpers.h"
7#include "base/callback.h"
8#include "base/memory/ref_counted.h"
9#include "base/memory/scoped_ptr.h"
10#include "base/message_loop/message_loop.h"
11#include "base/synchronization/waitable_event.h"
12#include "base/threading/thread.h"
13#include "chrome/browser/sync/glue/ui_model_worker.h"
14#include "content/public/test/test_browser_thread.h"
15#include "testing/gtest/include/gtest/gtest.h"
16
17using browser_sync::UIModelWorker;
18using syncer::SyncerError;
19using content::BrowserThread;
20
21class UIModelWorkerVisitor {
22 public:
23  UIModelWorkerVisitor(base::WaitableEvent* was_run,
24                       bool quit_loop)
25     : quit_loop_when_run_(quit_loop),
26       was_run_(was_run) { }
27  virtual ~UIModelWorkerVisitor() { }
28
29  virtual syncer::SyncerError DoWork() {
30    EXPECT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::UI));
31    was_run_->Signal();
32    if (quit_loop_when_run_)
33      base::MessageLoop::current()->Quit();
34    return syncer::SYNCER_OK;
35  }
36
37 private:
38  bool quit_loop_when_run_;
39  base::WaitableEvent* was_run_;
40  DISALLOW_COPY_AND_ASSIGN(UIModelWorkerVisitor);
41};
42
43// A faux-syncer that only interacts with its model safe worker.
44class Syncer {
45 public:
46  explicit Syncer(UIModelWorker* worker) : worker_(worker) {}
47  ~Syncer() {}
48
49  void SyncShare(UIModelWorkerVisitor* visitor) {
50    // We wait until the callback is executed. So it is safe to use Unretained.
51    syncer::WorkCallback c = base::Bind(&UIModelWorkerVisitor::DoWork,
52                                       base::Unretained(visitor));
53    worker_->DoWorkAndWaitUntilDone(c);
54  }
55 private:
56  scoped_refptr<UIModelWorker> worker_;
57  DISALLOW_COPY_AND_ASSIGN(Syncer);
58};
59
60class SyncUIModelWorkerTest : public testing::Test {
61 public:
62  SyncUIModelWorkerTest() : faux_syncer_thread_("FauxSyncerThread"),
63                            faux_core_thread_("FauxCoreThread") { }
64
65  virtual void SetUp() {
66    faux_syncer_thread_.Start();
67    ui_thread_.reset(new content::TestBrowserThread(BrowserThread::UI,
68                                                    &faux_ui_loop_));
69    bmw_ = new UIModelWorker(NULL);
70    syncer_.reset(new Syncer(bmw_.get()));
71  }
72
73  Syncer* syncer() { return syncer_.get(); }
74  UIModelWorker* bmw() { return bmw_.get(); }
75  base::Thread* core_thread() { return &faux_core_thread_; }
76  base::Thread* syncer_thread() { return &faux_syncer_thread_; }
77 private:
78  base::MessageLoop faux_ui_loop_;
79  scoped_ptr<content::TestBrowserThread> ui_thread_;
80  base::Thread faux_syncer_thread_;
81  base::Thread faux_core_thread_;
82  scoped_refptr<UIModelWorker> bmw_;
83  scoped_ptr<Syncer> syncer_;
84};
85
86TEST_F(SyncUIModelWorkerTest, ScheduledWorkRunsOnUILoop) {
87  base::WaitableEvent v_was_run(false, false);
88  scoped_ptr<UIModelWorkerVisitor> v(
89      new UIModelWorkerVisitor(&v_was_run, true));
90
91  syncer_thread()->message_loop()->PostTask(FROM_HERE,
92      base::Bind(&Syncer::SyncShare, base::Unretained(syncer()), v.get()));
93
94  // We are on the UI thread, so run our loop to process the
95  // (hopefully) scheduled task from a SyncShare invocation.
96  base::MessageLoop::current()->Run();
97  syncer_thread()->Stop();
98}
99