1 // Copyright 2014 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 "components/sync_driver/shared_change_processor.h"
6
7 #include <cstddef>
8
9 #include "base/bind.h"
10 #include "base/bind_helpers.h"
11 #include "base/compiler_specific.h"
12 #include "base/message_loop/message_loop.h"
13 #include "base/threading/thread.h"
14 #include "components/sync_driver/data_type_error_handler_mock.h"
15 #include "components/sync_driver/generic_change_processor.h"
16 #include "components/sync_driver/generic_change_processor_factory.h"
17 #include "components/sync_driver/sync_api_component_factory.h"
18 #include "sync/api/attachments/attachment_service_impl.h"
19 #include "sync/api/fake_syncable_service.h"
20 #include "testing/gmock/include/gmock/gmock.h"
21 #include "testing/gtest/include/gtest/gtest.h"
22
23 namespace browser_sync {
24
25 namespace {
26
27 using ::testing::NiceMock;
28 using ::testing::StrictMock;
29
30 class SyncSharedChangeProcessorTest :
31 public testing::Test,
32 public browser_sync::SyncApiComponentFactory {
33 public:
SyncSharedChangeProcessorTest()34 SyncSharedChangeProcessorTest() : backend_thread_("dbthread"),
35 did_connect_(false) {}
36
~SyncSharedChangeProcessorTest()37 virtual ~SyncSharedChangeProcessorTest() {
38 EXPECT_FALSE(db_syncable_service_.get());
39 }
40
GetSyncableServiceForType(syncer::ModelType type)41 virtual base::WeakPtr<syncer::SyncableService> GetSyncableServiceForType(
42 syncer::ModelType type) OVERRIDE {
43 return db_syncable_service_->AsWeakPtr();
44 }
45
CreateAttachmentService(syncer::AttachmentService::Delegate * delegate)46 virtual scoped_ptr<syncer::AttachmentService> CreateAttachmentService(
47 syncer::AttachmentService::Delegate* delegate) OVERRIDE {
48 return syncer::AttachmentServiceImpl::CreateForTest();
49 }
50
51 protected:
SetUp()52 virtual void SetUp() OVERRIDE {
53 shared_change_processor_ = new SharedChangeProcessor();
54 ASSERT_TRUE(backend_thread_.Start());
55 ASSERT_TRUE(backend_thread_.message_loop_proxy()->PostTask(
56 FROM_HERE,
57 base::Bind(&SyncSharedChangeProcessorTest::SetUpDBSyncableService,
58 base::Unretained(this))));
59 }
60
TearDown()61 virtual void TearDown() OVERRIDE {
62 EXPECT_TRUE(backend_thread_.message_loop_proxy()->PostTask(
63 FROM_HERE,
64 base::Bind(&SyncSharedChangeProcessorTest::TearDownDBSyncableService,
65 base::Unretained(this))));
66 // This must happen before the DB thread is stopped since
67 // |shared_change_processor_| may post tasks to delete its members
68 // on the correct thread.
69 //
70 // TODO(akalin): Write deterministic tests for the destruction of
71 // |shared_change_processor_| on the UI and DB threads.
72 shared_change_processor_ = NULL;
73 backend_thread_.Stop();
74
75 // Note: Stop() joins the threads, and that barrier prevents this read
76 // from being moved (e.g by compiler optimization) in such a way that it
77 // would race with the write in ConnectOnDBThread (because by this time,
78 // everything that could have run on |backend_thread_| has done so).
79 ASSERT_TRUE(did_connect_);
80 }
81
82 // Connect |shared_change_processor_| on the DB thread.
Connect()83 void Connect() {
84 EXPECT_TRUE(backend_thread_.message_loop_proxy()->PostTask(
85 FROM_HERE,
86 base::Bind(&SyncSharedChangeProcessorTest::ConnectOnDBThread,
87 base::Unretained(this),
88 shared_change_processor_)));
89 }
90
91 private:
92 // Used by SetUp().
SetUpDBSyncableService()93 void SetUpDBSyncableService() {
94 DCHECK(backend_thread_.message_loop_proxy()->BelongsToCurrentThread());
95 DCHECK(!db_syncable_service_.get());
96 db_syncable_service_.reset(new syncer::FakeSyncableService());
97 }
98
99 // Used by TearDown().
TearDownDBSyncableService()100 void TearDownDBSyncableService() {
101 DCHECK(backend_thread_.message_loop_proxy()->BelongsToCurrentThread());
102 DCHECK(db_syncable_service_.get());
103 db_syncable_service_.reset();
104 }
105
106 // Used by Connect(). The SharedChangeProcessor is passed in
107 // because we modify |shared_change_processor_| on the main thread
108 // (in TearDown()).
ConnectOnDBThread(const scoped_refptr<SharedChangeProcessor> & shared_change_processor)109 void ConnectOnDBThread(
110 const scoped_refptr<SharedChangeProcessor>& shared_change_processor) {
111 DCHECK(backend_thread_.message_loop_proxy()->BelongsToCurrentThread());
112 syncer::UserShare share;
113 EXPECT_TRUE(shared_change_processor->Connect(
114 this,
115 &processor_factory_,
116 &share,
117 &error_handler_,
118 syncer::AUTOFILL,
119 base::WeakPtr<syncer::SyncMergeResult>()));
120 did_connect_ = true;
121 }
122
123 base::MessageLoop frontend_loop_;
124 base::Thread backend_thread_;
125
126 scoped_refptr<SharedChangeProcessor> shared_change_processor_;
127 StrictMock<DataTypeErrorHandlerMock> error_handler_;
128
129 GenericChangeProcessorFactory processor_factory_;
130 bool did_connect_;
131
132 // Used only on DB thread.
133 scoped_ptr<syncer::FakeSyncableService> db_syncable_service_;
134 };
135
136 // Simply connect the shared change processor. It should succeed, and
137 // nothing further should happen.
TEST_F(SyncSharedChangeProcessorTest,Basic)138 TEST_F(SyncSharedChangeProcessorTest, Basic) {
139 Connect();
140 }
141
142 } // namespace
143
144 } // namespace browser_sync
145