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 ~StubAttachmentService() override
{}
37 AttachmentStore
* GetStore() override
{ return NULL
; }
39 void GetOrDownloadAttachments(
40 const AttachmentIdList
& attachment_ids
,
41 const GetOrDownloadCallback
& callback
) override
{
42 CalledOnValidThread();
44 scoped_ptr
<AttachmentMap
> attachments(new AttachmentMap());
45 base::MessageLoop::current()->PostTask(
48 AttachmentService::GET_UNSPECIFIED_ERROR
,
49 base::Passed(&attachments
)));
52 void DropAttachments(const AttachmentIdList
& attachment_ids
,
53 const DropCallback
& callback
) override
{
54 CalledOnValidThread();
56 base::MessageLoop::current()->PostTask(
57 FROM_HERE
, base::Bind(callback
, AttachmentService::DROP_SUCCESS
));
60 void UploadAttachments(const AttachmentIdSet
& attachments_ids
) override
{
61 CalledOnValidThread();
65 virtual base::WeakPtr
<AttachmentService
> AsWeakPtr() {
66 return weak_ptr_factory_
.GetWeakPtr();
69 // Return the number of method invocations.
70 int GetCallCount() const {
71 base::AutoLock
lock(mutex_
);
76 // Protects call_count_.
77 mutable base::Lock mutex_
;
80 // Must be last data member.
81 base::WeakPtrFactory
<AttachmentService
> weak_ptr_factory_
;
84 base::AutoLock
lock(mutex_
);
89 class AttachmentServiceProxyTest
: public testing::Test
,
90 public base::NonThreadSafe
{
92 AttachmentServiceProxyTest() {}
94 void SetUp() override
{
95 CalledOnValidThread();
96 stub_thread
.reset(new base::Thread("attachment service stub thread"));
98 stub
.reset(new StubAttachmentService
);
99 proxy
.reset(new AttachmentServiceProxy(stub_thread
->message_loop_proxy(),
102 callback_get_or_download
=
103 base::Bind(&AttachmentServiceProxyTest::IncrementGetOrDownload
,
104 base::Unretained(this));
105 callback_drop
= base::Bind(&AttachmentServiceProxyTest::IncrementDrop
,
106 base::Unretained(this));
107 count_callback_get_or_download
= 0;
108 count_callback_drop
= 0;
111 void TearDown() override
{
112 // We must take care to call the stub's destructor on the stub_thread
113 // because that's the thread to which its WeakPtrs are bound.
115 stub_thread
->message_loop()->DeleteSoon(FROM_HERE
, stub
.release());
121 // a GetOrDownloadCallback
122 void IncrementGetOrDownload(const AttachmentService::GetOrDownloadResult
&,
123 scoped_ptr
<AttachmentMap
>) {
124 CalledOnValidThread();
125 ++count_callback_get_or_download
;
129 void IncrementDrop(const AttachmentService::DropResult
&) {
130 CalledOnValidThread();
131 ++count_callback_drop
;
134 void WaitForStubThread() {
135 base::WaitableEvent
done(false, false);
136 stub_thread
->message_loop()->PostTask(
138 base::Bind(&base::WaitableEvent::Signal
, base::Unretained(&done
)));
142 base::MessageLoop loop
;
143 scoped_ptr
<base::Thread
> stub_thread
;
144 scoped_ptr
<StubAttachmentService
> stub
;
145 scoped_ptr
<AttachmentServiceProxy
> proxy
;
147 AttachmentService::GetOrDownloadCallback callback_get_or_download
;
148 AttachmentService::DropCallback callback_drop
;
150 // number of times callback_get_or_download was invoked
151 int count_callback_get_or_download
;
152 // number of times callback_drop was invoked
153 int count_callback_drop
;
156 TEST_F(AttachmentServiceProxyTest
, GetStore
) {
157 EXPECT_EQ(NULL
, proxy
->GetStore());
160 // Verify that each of AttachmentServiceProxy's methods are invoked on the stub.
161 // Verify that the methods that take callbacks invoke passed callbacks on this
163 TEST_F(AttachmentServiceProxyTest
, MethodsAreProxied
) {
164 proxy
->GetOrDownloadAttachments(AttachmentIdList(), callback_get_or_download
);
165 proxy
->DropAttachments(AttachmentIdList(), callback_drop
);
166 proxy
->UploadAttachments(AttachmentIdSet());
167 // Wait for the posted calls to execute in the stub thread.
169 EXPECT_EQ(3, stub
->GetCallCount());
170 // At this point the stub thread has finished executed the calls. However, the
171 // result callbacks it has posted may not have executed yet. Wait a second
172 // time to ensure the stub thread has executed the posted result callbacks.
176 EXPECT_EQ(1, count_callback_get_or_download
);
177 EXPECT_EQ(1, count_callback_drop
);
180 // Verify that it's safe to use an AttachmentServiceProxy even after its wrapped
181 // AttachmentService has been destroyed.
182 TEST_F(AttachmentServiceProxyTest
, WrappedIsDestroyed
) {
183 proxy
->GetOrDownloadAttachments(AttachmentIdList(), callback_get_or_download
);
184 // Wait for the posted calls to execute in the stub thread.
186 EXPECT_EQ(1, stub
->GetCallCount());
187 // Wait a second time ensure the stub thread has executed the posted result
192 EXPECT_EQ(1, count_callback_get_or_download
);
194 // Destroy the stub and call GetOrDownloadAttachments again.
195 stub_thread
->message_loop()->DeleteSoon(FROM_HERE
, stub
.release());
198 // Now that the wrapped object has been destroyed, call again and see that we
199 // don't crash and the count remains the same.
200 proxy
->GetOrDownloadAttachments(AttachmentIdList(), callback_get_or_download
);
204 EXPECT_EQ(1, count_callback_get_or_download
);
207 } // namespace syncer