• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "sync/api/attachments/attachment_service_proxy.h"
6 
7 #include "base/bind.h"
8 #include "base/memory/ref_counted_memory.h"
9 #include "base/memory/scoped_ptr.h"
10 #include "base/message_loop/message_loop.h"
11 #include "base/run_loop.h"
12 #include "base/synchronization/lock.h"
13 #include "base/synchronization/waitable_event.h"
14 #include "base/threading/non_thread_safe.h"
15 #include "base/threading/thread.h"
16 #include "sync/api/attachments/attachment.h"
17 #include "sync/api/attachments/attachment_service.h"
18 #include "sync/api/sync_data.h"
19 #include "sync/internal_api/public/base/model_type.h"
20 #include "sync/protocol/sync.pb.h"
21 #include "testing/gtest/include/gtest/gtest.h"
22 
23 namespace syncer {
24 
25 // A stub implementation of AttachmentService that counts the number of times
26 // its methods are invoked.
27 class StubAttachmentService : public AttachmentService,
28                               public base::NonThreadSafe {
29  public:
StubAttachmentService()30   StubAttachmentService() : call_count_(0), weak_ptr_factory_(this) {
31     // DetachFromThread because we will be constructed in one thread and
32     // used/destroyed in another.
33     DetachFromThread();
34   }
35 
~StubAttachmentService()36   virtual ~StubAttachmentService() {}
37 
GetOrDownloadAttachments(const AttachmentIdList & attachment_ids,const GetOrDownloadCallback & callback)38   virtual void GetOrDownloadAttachments(const AttachmentIdList& attachment_ids,
39                                         const GetOrDownloadCallback& callback)
40       OVERRIDE {
41     CalledOnValidThread();
42     Increment();
43     scoped_ptr<AttachmentMap> attachments(new AttachmentMap());
44     base::MessageLoop::current()->PostTask(
45         FROM_HERE,
46         base::Bind(callback,
47                    AttachmentService::GET_UNSPECIFIED_ERROR,
48                    base::Passed(&attachments)));
49   }
50 
DropAttachments(const AttachmentIdList & attachment_ids,const DropCallback & callback)51   virtual void DropAttachments(const AttachmentIdList& attachment_ids,
52                                const DropCallback& callback) OVERRIDE {
53     CalledOnValidThread();
54     Increment();
55     base::MessageLoop::current()->PostTask(
56         FROM_HERE, base::Bind(callback, AttachmentService::DROP_SUCCESS));
57   }
58 
StoreAttachments(const AttachmentList & attachments,const StoreCallback & callback)59   virtual void StoreAttachments(const AttachmentList& attachments,
60                                 const StoreCallback& callback) OVERRIDE {
61     CalledOnValidThread();
62     Increment();
63     base::MessageLoop::current()->PostTask(
64         FROM_HERE, base::Bind(callback, AttachmentService::STORE_SUCCESS));
65   }
66 
OnSyncDataDelete(const SyncData & sync_data)67   virtual void OnSyncDataDelete(const SyncData& sync_data) OVERRIDE {
68     CalledOnValidThread();
69     Increment();
70   }
71 
OnSyncDataUpdate(const AttachmentIdList & old_attachment_ids,const SyncData & updated_sync_data)72   virtual void OnSyncDataUpdate(const AttachmentIdList& old_attachment_ids,
73                                 const SyncData& updated_sync_data) OVERRIDE {
74     CalledOnValidThread();
75     Increment();
76   }
77 
AsWeakPtr()78   virtual base::WeakPtr<AttachmentService> AsWeakPtr() {
79     return weak_ptr_factory_.GetWeakPtr();
80   }
81 
82   // Return the number of method invocations.
GetCallCount() const83   int GetCallCount() const {
84     base::AutoLock lock(mutex_);
85     return call_count_;
86   }
87 
88  private:
89   // Protects call_count_.
90   mutable base::Lock mutex_;
91   int call_count_;
92 
93   // Must be last data member.
94   base::WeakPtrFactory<AttachmentService> weak_ptr_factory_;
95 
Increment()96   void Increment() {
97     base::AutoLock lock(mutex_);
98     ++call_count_;
99   }
100 };
101 
102 class AttachmentServiceProxyTest : public testing::Test,
103                                    public base::NonThreadSafe {
104  protected:
AttachmentServiceProxyTest()105   AttachmentServiceProxyTest() {}
106 
SetUp()107   virtual void SetUp() {
108     CalledOnValidThread();
109     stub_thread.reset(new base::Thread("attachment service stub thread"));
110     stub_thread->Start();
111     stub.reset(new StubAttachmentService);
112     proxy.reset(new AttachmentServiceProxy(stub_thread->message_loop_proxy(),
113                                            stub->AsWeakPtr()));
114 
115     sync_data =
116         SyncData::CreateLocalData("tag", "title", sync_pb::EntitySpecifics());
117     sync_data_delete =
118         SyncData::CreateLocalDelete("tag", syncer::PREFERENCES);
119 
120     callback_get_or_download =
121         base::Bind(&AttachmentServiceProxyTest::IncrementGetOrDownload,
122                    base::Unretained(this));
123     callback_drop = base::Bind(&AttachmentServiceProxyTest::IncrementDrop,
124                                base::Unretained(this));
125     callback_store = base::Bind(&AttachmentServiceProxyTest::IncrementStore,
126                                 base::Unretained(this));
127     count_callback_get_or_download = 0;
128     count_callback_drop = 0;
129     count_callback_store = 0;
130   }
131 
TearDown()132   virtual void TearDown()
133       OVERRIDE {
134     // We must take care to call the stub's destructor on the stub_thread
135     // because that's the thread to which its WeakPtrs are bound.
136     if (stub) {
137       stub_thread->message_loop()->DeleteSoon(FROM_HERE, stub.release());
138       WaitForStubThread();
139     }
140     stub_thread->Stop();
141   }
142 
143   // a GetOrDownloadCallback
IncrementGetOrDownload(const AttachmentService::GetOrDownloadResult &,scoped_ptr<AttachmentMap>)144   void IncrementGetOrDownload(const AttachmentService::GetOrDownloadResult&,
145                               scoped_ptr<AttachmentMap>) {
146     CalledOnValidThread();
147     ++count_callback_get_or_download;
148   }
149 
150   // a DropCallback
IncrementDrop(const AttachmentService::DropResult &)151   void IncrementDrop(const AttachmentService::DropResult&) {
152     CalledOnValidThread();
153     ++count_callback_drop;
154   }
155 
156   // a StoreCallback
IncrementStore(const AttachmentService::StoreResult &)157   void IncrementStore(const AttachmentService::StoreResult&) {
158     CalledOnValidThread();
159     ++count_callback_store;
160   }
161 
WaitForStubThread()162   void WaitForStubThread() {
163     base::WaitableEvent done(false, false);
164     stub_thread->message_loop()->PostTask(
165         FROM_HERE,
166         base::Bind(&base::WaitableEvent::Signal, base::Unretained(&done)));
167     done.Wait();
168   }
169 
170   base::MessageLoop loop;
171   scoped_ptr<base::Thread> stub_thread;
172   scoped_ptr<StubAttachmentService> stub;
173   scoped_ptr<AttachmentServiceProxy> proxy;
174 
175   SyncData sync_data;
176   SyncData sync_data_delete;
177 
178   AttachmentService::GetOrDownloadCallback callback_get_or_download;
179   AttachmentService::DropCallback callback_drop;
180   AttachmentService::StoreCallback callback_store;
181 
182   // number of times callback_get_or_download was invoked
183   int count_callback_get_or_download;
184   // number of times callback_drop was invoked
185   int count_callback_drop;
186   // number of times callback_store was invoked
187   int count_callback_store;
188 };
189 
190 // Verify that each of AttachmentServiceProxy's regular methods (those that
191 // don't take callbacks) are invoked on the stub.
TEST_F(AttachmentServiceProxyTest,MethodsAreProxied)192 TEST_F(AttachmentServiceProxyTest, MethodsAreProxied) {
193   proxy->OnSyncDataDelete(sync_data_delete);
194   proxy->OnSyncDataUpdate(AttachmentIdList(), sync_data);
195   WaitForStubThread();
196   EXPECT_EQ(2, stub->GetCallCount());
197 }
198 
199 // Verify that each of AttachmentServiceProxy's callback methods (those that
200 // take callbacks) are invoked on the stub and that the passed callbacks are
201 // invoked in this thread.
TEST_F(AttachmentServiceProxyTest,MethodsWithCallbacksAreProxied)202 TEST_F(AttachmentServiceProxyTest, MethodsWithCallbacksAreProxied) {
203   proxy->GetOrDownloadAttachments(AttachmentIdList(), callback_get_or_download);
204   proxy->DropAttachments(AttachmentIdList(), callback_drop);
205   proxy->StoreAttachments(AttachmentList(), callback_store);
206   // Wait for the posted calls to execute in the stub thread.
207   WaitForStubThread();
208   EXPECT_EQ(3, stub->GetCallCount());
209   // At this point the stub thread has finished executed the calls. However, the
210   // result callbacks it has posted may not have executed yet. Wait a second
211   // time to ensure the stub thread has executed the posted result callbacks.
212   WaitForStubThread();
213 
214   loop.RunUntilIdle();
215   EXPECT_EQ(1, count_callback_get_or_download);
216   EXPECT_EQ(1, count_callback_drop);
217   EXPECT_EQ(1, count_callback_store);
218 }
219 
220 // Verify that it's safe to use an AttachmentServiceProxy even after its wrapped
221 // AttachmentService has been destroyed.
TEST_F(AttachmentServiceProxyTest,WrappedIsDestroyed)222 TEST_F(AttachmentServiceProxyTest, WrappedIsDestroyed) {
223   proxy->GetOrDownloadAttachments(AttachmentIdList(), callback_get_or_download);
224   // Wait for the posted calls to execute in the stub thread.
225   WaitForStubThread();
226   EXPECT_EQ(1, stub->GetCallCount());
227   // Wait a second time ensure the stub thread has executed the posted result
228   // callbacks.
229   WaitForStubThread();
230 
231   loop.RunUntilIdle();
232   EXPECT_EQ(1, count_callback_get_or_download);
233 
234   // Destroy the stub and call GetOrDownloadAttachments again.
235   stub_thread->message_loop()->DeleteSoon(FROM_HERE, stub.release());
236   WaitForStubThread();
237 
238   // Now that the wrapped object has been destroyed, call again and see that we
239   // don't crash and the count remains the same.
240   proxy->GetOrDownloadAttachments(AttachmentIdList(), callback_get_or_download);
241   WaitForStubThread();
242   WaitForStubThread();
243   loop.RunUntilIdle();
244   EXPECT_EQ(1, count_callback_get_or_download);
245 }
246 
247 }  // namespace syncer
248