1 // Copyright (c) 2012 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 "chrome/browser/google_apis/operation_registry.h"
7 #include "base/compiler_specific.h"
8 #include "base/memory/weak_ptr.h"
9 #include "base/message_loop.h"
10 #include "chrome/browser/google_apis/operation_registry.h"
11 #include "content/public/test/test_browser_thread.h"
12 #include "testing/gmock/include/gmock/gmock.h"
13 #include "testing/gtest/include/gtest/gtest.h"
15 using testing::ElementsAre
;
17 namespace google_apis
{
21 class MockOperation
: public OperationRegistry::Operation
,
22 public base::SupportsWeakPtr
<MockOperation
> {
24 MockOperation(OperationRegistry
* registry
,
26 const base::FilePath
& path
)
27 : OperationRegistry::Operation(registry
, type
, path
) {}
29 MOCK_METHOD0(DoCancel
, void());
31 // Make them public so that they can be called from test cases.
32 using OperationRegistry::Operation::NotifyStart
;
33 using OperationRegistry::Operation::NotifyProgress
;
34 using OperationRegistry::Operation::NotifyFinish
;
35 using OperationRegistry::Operation::NotifySuspend
;
36 using OperationRegistry::Operation::NotifyResume
;
39 class MockUploadOperation
: public MockOperation
{
41 explicit MockUploadOperation(OperationRegistry
* registry
)
42 : MockOperation(registry
,
44 base::FilePath(FILE_PATH_LITERAL("/dummy/upload"))) {}
47 class MockDownloadOperation
: public MockOperation
{
49 explicit MockDownloadOperation(OperationRegistry
* registry
)
50 : MockOperation(registry
,
52 base::FilePath(FILE_PATH_LITERAL("/dummy/download"))) {}
55 class MockOtherOperation
: public MockOperation
{
57 explicit MockOtherOperation(OperationRegistry
* registry
)
58 : MockOperation(registry
,
60 base::FilePath(FILE_PATH_LITERAL("/dummy/other"))) {}
63 class TestObserver
: public OperationRegistryObserver
{
65 virtual void OnProgressUpdate(
66 const OperationProgressStatusList
& list
) OVERRIDE
{
70 const OperationProgressStatusList
& status() const {
75 OperationProgressStatusList status_
;
79 : public ::testing::MatcherInterface
<const OperationProgressStatus
&> {
81 ProgressMatcher(int64 expected_current
, int64 expected_total
)
82 : expected_current_(expected_current
),
83 expected_total_(expected_total
) {}
85 virtual bool MatchAndExplain(
86 const OperationProgressStatus
& status
,
87 testing::MatchResultListener
* /* listener */) const OVERRIDE
{
88 return status
.progress_current
== expected_current_
&&
89 status
.progress_total
== expected_total_
;
92 virtual void DescribeTo(::std::ostream
* os
) const OVERRIDE
{
93 *os
<< "current / total equals " << expected_current_
<< " / " <<
97 virtual void DescribeNegationTo(::std::ostream
* os
) const OVERRIDE
{
98 *os
<< "current / total does not equal " << expected_current_
<< " / " <<
103 const int64 expected_current_
;
104 const int64 expected_total_
;
107 testing::Matcher
<const OperationProgressStatus
&> Progress(
108 int64 current
, int64 total
) {
109 return testing::MakeMatcher(new ProgressMatcher(current
, total
));
114 // Pretty-prints OperationProgressStatus for testing purpose.
115 std::ostream
& operator<<(std::ostream
& os
,
116 const OperationProgressStatus
& status
) {
117 return os
<< status
.DebugString();
120 class OperationRegistryTest
: public testing::Test
{
122 OperationRegistryTest()
123 : ui_thread_(content::BrowserThread::UI
, &message_loop_
) {
125 MessageLoopForUI message_loop_
;
126 content::TestBrowserThread ui_thread_
;
129 TEST_F(OperationRegistryTest
, OneSuccess
) {
130 TestObserver observer
;
131 OperationRegistry registry
;
132 registry
.DisableNotificationFrequencyControlForTest();
133 registry
.AddObserver(&observer
);
135 base::WeakPtr
<MockOperation
> op1
=
136 (new MockUploadOperation(®istry
))->AsWeakPtr();
137 EXPECT_CALL(*op1
, DoCancel()).Times(0);
139 EXPECT_EQ(0U, observer
.status().size());
141 EXPECT_THAT(observer
.status(), ElementsAre(Progress(0, -1)));
142 op1
->NotifyProgress(0, 100);
143 EXPECT_THAT(observer
.status(), ElementsAre(Progress(0, 100)));
144 op1
->NotifyProgress(100, 100);
145 EXPECT_THAT(observer
.status(), ElementsAre(Progress(100, 100)));
146 op1
->NotifyFinish(OPERATION_COMPLETED
);
147 // Contains one "COMPLETED" notification.
148 EXPECT_THAT(observer
.status(), ElementsAre(Progress(100, 100)));
149 // Then it is removed.
150 EXPECT_EQ(0U, registry
.GetProgressStatusList().size());
151 EXPECT_EQ(NULL
, op1
.get()); // deleted
154 TEST_F(OperationRegistryTest
, OneCancel
) {
155 TestObserver observer
;
156 OperationRegistry registry
;
157 registry
.DisableNotificationFrequencyControlForTest();
158 registry
.AddObserver(&observer
);
160 base::WeakPtr
<MockOperation
> op1
=
161 (new MockUploadOperation(®istry
))->AsWeakPtr();
162 EXPECT_CALL(*op1
, DoCancel());
164 EXPECT_EQ(0U, observer
.status().size());
166 EXPECT_THAT(observer
.status(), ElementsAre(Progress(0, -1)));
167 op1
->NotifyProgress(0, 100);
168 EXPECT_THAT(observer
.status(), ElementsAre(Progress(0, 100)));
169 registry
.CancelAll();
170 EXPECT_THAT(observer
.status(), ElementsAre(Progress(0, 100)));
171 EXPECT_EQ(0U, registry
.GetProgressStatusList().size());
172 EXPECT_EQ(NULL
, op1
.get()); // deleted
175 TEST_F(OperationRegistryTest
, TwoSuccess
) {
176 TestObserver observer
;
177 OperationRegistry registry
;
178 registry
.DisableNotificationFrequencyControlForTest();
179 registry
.AddObserver(&observer
);
181 base::WeakPtr
<MockOperation
> op1
=
182 (new MockUploadOperation(®istry
))->AsWeakPtr();
183 base::WeakPtr
<MockOperation
> op2
=
184 (new MockDownloadOperation(®istry
))->AsWeakPtr();
185 EXPECT_CALL(*op1
, DoCancel()).Times(0);
186 EXPECT_CALL(*op2
, DoCancel()).Times(0);
188 EXPECT_EQ(0U, observer
.status().size());
190 op1
->NotifyProgress(0, 100);
191 EXPECT_THAT(observer
.status(), ElementsAre(Progress(0, 100)));
193 op2
->NotifyProgress(0, 200);
194 op1
->NotifyProgress(50, 100);
195 EXPECT_THAT(observer
.status(), ElementsAre(Progress(50, 100),
197 op1
->NotifyFinish(OPERATION_COMPLETED
);
198 EXPECT_THAT(observer
.status(), ElementsAre(Progress(50, 100),
200 EXPECT_EQ(1U, registry
.GetProgressStatusList().size());
201 op2
->NotifyFinish(OPERATION_COMPLETED
);
202 EXPECT_THAT(observer
.status(), ElementsAre(Progress(0, 200)));
203 EXPECT_EQ(0U, registry
.GetProgressStatusList().size());
204 EXPECT_EQ(NULL
, op1
.get()); // deleted
205 EXPECT_EQ(NULL
, op2
.get()); // deleted
208 TEST_F(OperationRegistryTest
, ThreeCancel
) {
209 TestObserver observer
;
210 OperationRegistry registry
;
211 registry
.DisableNotificationFrequencyControlForTest();
212 registry
.AddObserver(&observer
);
214 base::WeakPtr
<MockOperation
> op1
=
215 (new MockUploadOperation(®istry
))->AsWeakPtr();
216 base::WeakPtr
<MockOperation
> op2
=
217 (new MockDownloadOperation(®istry
))->AsWeakPtr();
218 base::WeakPtr
<MockOperation
> op3
=
219 (new MockOtherOperation(®istry
))->AsWeakPtr();
220 EXPECT_CALL(*op1
, DoCancel());
221 EXPECT_CALL(*op2
, DoCancel());
222 EXPECT_CALL(*op3
, DoCancel());
224 EXPECT_EQ(0U, observer
.status().size());
226 EXPECT_EQ(1U, observer
.status().size());
228 EXPECT_EQ(2U, observer
.status().size());
230 EXPECT_EQ(2U, observer
.status().size()); // only upload/download is reported.
231 registry
.CancelAll();
232 EXPECT_EQ(1U, observer
.status().size()); // holds the last one "COMPLETED"
233 EXPECT_EQ(0U, registry
.GetProgressStatusList().size());
234 EXPECT_EQ(NULL
, op1
.get()); // deleted
235 EXPECT_EQ(NULL
, op2
.get()); // deleted
236 EXPECT_EQ(NULL
, op3
.get()); // deleted. CancelAll cares all operations.
239 TEST_F(OperationRegistryTest
, RestartOperation
) {
240 TestObserver observer
;
241 OperationRegistry registry
;
242 registry
.DisableNotificationFrequencyControlForTest();
243 registry
.AddObserver(&observer
);
245 base::WeakPtr
<MockOperation
> op1
=
246 (new MockUploadOperation(®istry
))->AsWeakPtr();
247 EXPECT_CALL(*op1
, DoCancel()).Times(0);
250 EXPECT_EQ(1U, registry
.GetProgressStatusList().size());
251 op1
->NotifyStart(); // restart
252 EXPECT_EQ(1U, registry
.GetProgressStatusList().size());
253 op1
->NotifyProgress(0, 200);
254 op1
->NotifyFinish(OPERATION_COMPLETED
);
255 EXPECT_EQ(0U, registry
.GetProgressStatusList().size());
256 EXPECT_EQ(NULL
, op1
.get()); // deleted
260 TEST_F(OperationRegistryTest
, SuspendCancel
) {
261 TestObserver observer
;
262 OperationRegistry registry
;
263 registry
.DisableNotificationFrequencyControlForTest();
264 registry
.AddObserver(&observer
);
266 // Suspend-then-resume is a hack in OperationRegistry to tie physically
267 // split but logically single operation (= chunked uploading split into
268 // multiple HTTP requests). When the "logically-single" operation is
269 // canceled between the two physical operations,
270 // |----op1----| CANCEL! |----op2----|
271 // the cancellation is notified to the callback function associated with
272 // op2, not op1. This is because, op1's callback is already invoked at this
273 // point to notify the completion of the physical operation. Completion
274 // callback must not be called more than once.
276 base::WeakPtr
<MockOperation
> op1
=
277 (new MockUploadOperation(®istry
))->AsWeakPtr();
278 EXPECT_CALL(*op1
, DoCancel()).Times(0);
281 op1
->NotifySuspend();
282 registry
.CancelAll();
283 EXPECT_EQ(NULL
, op1
.get()); // deleted
285 base::WeakPtr
<MockOperation
> op2
=
286 (new MockUploadOperation(®istry
))->AsWeakPtr();
287 EXPECT_CALL(*op2
, DoCancel()).Times(1);
290 EXPECT_EQ(NULL
, op2
.get()); // deleted
293 } // namespace google_apis