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.
5 #include "sync/internal_api/public/attachments/attachment_service_proxy.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/internal_api/public/attachments/attachment_service.h"
18 #include "sync/internal_api/public/base/model_type.h"
19 #include "sync/protocol/sync.pb.h"
20 #include "testing/gtest/include/gtest/gtest.h"
24 // A stub implementation of AttachmentService that counts the number of times
25 // its methods are invoked.
26 class StubAttachmentService
: public AttachmentService
,
27 public base::NonThreadSafe
{
29 StubAttachmentService() : call_count_(0), weak_ptr_factory_(this) {
30 // DetachFromThread because we will be constructed in one thread and
31 // used/destroyed in another.
35 virtual ~StubAttachmentService() {}
37 virtual void GetOrDownloadAttachments(const AttachmentIdList
& attachment_ids
,
38 const GetOrDownloadCallback
& callback
)
40 CalledOnValidThread();
42 scoped_ptr
<AttachmentMap
> attachments(new AttachmentMap());
43 base::MessageLoop::current()->PostTask(
46 AttachmentService::GET_UNSPECIFIED_ERROR
,
47 base::Passed(&attachments
)));
50 virtual void DropAttachments(const AttachmentIdList
& attachment_ids
,
51 const DropCallback
& callback
) OVERRIDE
{
52 CalledOnValidThread();
54 base::MessageLoop::current()->PostTask(
55 FROM_HERE
, base::Bind(callback
, AttachmentService::DROP_SUCCESS
));
58 virtual void StoreAttachments(const AttachmentList
& attachments
,
59 const StoreCallback
& callback
) OVERRIDE
{
60 CalledOnValidThread();
62 base::MessageLoop::current()->PostTask(
63 FROM_HERE
, base::Bind(callback
, AttachmentService::STORE_SUCCESS
));
66 virtual base::WeakPtr
<AttachmentService
> AsWeakPtr() {
67 return weak_ptr_factory_
.GetWeakPtr();
70 // Return the number of method invocations.
71 int GetCallCount() const {
72 base::AutoLock
lock(mutex_
);
77 // Protects call_count_.
78 mutable base::Lock mutex_
;
81 // Must be last data member.
82 base::WeakPtrFactory
<AttachmentService
> weak_ptr_factory_
;
85 base::AutoLock
lock(mutex_
);
90 class AttachmentServiceProxyTest
: public testing::Test
,
91 public base::NonThreadSafe
{
93 AttachmentServiceProxyTest() {}
95 virtual void SetUp() {
96 CalledOnValidThread();
97 stub_thread
.reset(new base::Thread("attachment service stub thread"));
99 stub
.reset(new StubAttachmentService
);
100 proxy
.reset(new AttachmentServiceProxy(stub_thread
->message_loop_proxy(),
103 callback_get_or_download
=
104 base::Bind(&AttachmentServiceProxyTest::IncrementGetOrDownload
,
105 base::Unretained(this));
106 callback_drop
= base::Bind(&AttachmentServiceProxyTest::IncrementDrop
,
107 base::Unretained(this));
108 callback_store
= base::Bind(&AttachmentServiceProxyTest::IncrementStore
,
109 base::Unretained(this));
110 count_callback_get_or_download
= 0;
111 count_callback_drop
= 0;
112 count_callback_store
= 0;
115 virtual void TearDown()
117 // We must take care to call the stub's destructor on the stub_thread
118 // because that's the thread to which its WeakPtrs are bound.
120 stub_thread
->message_loop()->DeleteSoon(FROM_HERE
, stub
.release());
126 // a GetOrDownloadCallback
127 void IncrementGetOrDownload(const AttachmentService::GetOrDownloadResult
&,
128 scoped_ptr
<AttachmentMap
>) {
129 CalledOnValidThread();
130 ++count_callback_get_or_download
;
134 void IncrementDrop(const AttachmentService::DropResult
&) {
135 CalledOnValidThread();
136 ++count_callback_drop
;
140 void IncrementStore(const AttachmentService::StoreResult
&) {
141 CalledOnValidThread();
142 ++count_callback_store
;
145 void WaitForStubThread() {
146 base::WaitableEvent
done(false, false);
147 stub_thread
->message_loop()->PostTask(
149 base::Bind(&base::WaitableEvent::Signal
, base::Unretained(&done
)));
153 base::MessageLoop loop
;
154 scoped_ptr
<base::Thread
> stub_thread
;
155 scoped_ptr
<StubAttachmentService
> stub
;
156 scoped_ptr
<AttachmentServiceProxy
> proxy
;
158 AttachmentService::GetOrDownloadCallback callback_get_or_download
;
159 AttachmentService::DropCallback callback_drop
;
160 AttachmentService::StoreCallback callback_store
;
162 // number of times callback_get_or_download was invoked
163 int count_callback_get_or_download
;
164 // number of times callback_drop was invoked
165 int count_callback_drop
;
166 // number of times callback_store was invoked
167 int count_callback_store
;
170 // Verify that each of AttachmentServiceProxy's callback methods (those that
171 // take callbacks) are invoked on the stub and that the passed callbacks are
172 // invoked in this thread.
173 TEST_F(AttachmentServiceProxyTest
, MethodsWithCallbacksAreProxied
) {
174 proxy
->GetOrDownloadAttachments(AttachmentIdList(), callback_get_or_download
);
175 proxy
->DropAttachments(AttachmentIdList(), callback_drop
);
176 proxy
->StoreAttachments(AttachmentList(), callback_store
);
177 // Wait for the posted calls to execute in the stub thread.
179 EXPECT_EQ(3, stub
->GetCallCount());
180 // At this point the stub thread has finished executed the calls. However, the
181 // result callbacks it has posted may not have executed yet. Wait a second
182 // time to ensure the stub thread has executed the posted result callbacks.
186 EXPECT_EQ(1, count_callback_get_or_download
);
187 EXPECT_EQ(1, count_callback_drop
);
188 EXPECT_EQ(1, count_callback_store
);
191 // Verify that it's safe to use an AttachmentServiceProxy even after its wrapped
192 // AttachmentService has been destroyed.
193 TEST_F(AttachmentServiceProxyTest
, WrappedIsDestroyed
) {
194 proxy
->GetOrDownloadAttachments(AttachmentIdList(), callback_get_or_download
);
195 // Wait for the posted calls to execute in the stub thread.
197 EXPECT_EQ(1, stub
->GetCallCount());
198 // Wait a second time ensure the stub thread has executed the posted result
203 EXPECT_EQ(1, count_callback_get_or_download
);
205 // Destroy the stub and call GetOrDownloadAttachments again.
206 stub_thread
->message_loop()->DeleteSoon(FROM_HERE
, stub
.release());
209 // Now that the wrapped object has been destroyed, call again and see that we
210 // don't crash and the count remains the same.
211 proxy
->GetOrDownloadAttachments(AttachmentIdList(), callback_get_or_download
);
215 EXPECT_EQ(1, count_callback_get_or_download
);
218 } // namespace syncer