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