1 // Copyright 2013 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 "components/dom_distiller/core/task_tracker.h"
7 #include "base/run_loop.h"
8 #include "components/dom_distiller/core/article_distillation_update.h"
9 #include "components/dom_distiller/core/article_entry.h"
10 #include "components/dom_distiller/core/distilled_content_store.h"
11 #include "components/dom_distiller/core/fake_distiller.h"
12 #include "testing/gtest/include/gtest/gtest.h"
14 using testing::Return
;
17 namespace dom_distiller
{
20 class FakeViewRequestDelegate
: public ViewRequestDelegate
{
22 virtual ~FakeViewRequestDelegate() {}
23 MOCK_METHOD1(OnArticleReady
,
24 void(const DistilledArticleProto
* article_proto
));
25 MOCK_METHOD1(OnArticleUpdated
,
26 void(ArticleDistillationUpdate article_update
));
29 class MockContentStore
: public DistilledContentStore
{
31 MOCK_CONST_METHOD2(LoadContent
,
32 void(const ArticleEntry
& entry
, LoadCallback callback
));
33 MOCK_METHOD3(SaveContent
,
34 void(const ArticleEntry
& entry
,
35 const DistilledArticleProto
& proto
,
36 SaveCallback callback
));
39 class TestCancelCallback
{
41 TestCancelCallback() : cancelled_(false) {}
42 TaskTracker::CancelCallback
GetCallback() {
43 return base::Bind(&TestCancelCallback::Cancel
, base::Unretained(this));
45 void Cancel(TaskTracker
*) { cancelled_
= true; }
46 bool Cancelled() { return cancelled_
; }
52 class MockSaveCallback
{
55 void(const ArticleEntry
&, const DistilledArticleProto
*, bool));
58 class DomDistillerTaskTrackerTest
: public testing::Test
{
60 virtual void SetUp() OVERRIDE
{
61 message_loop_
.reset(new base::MessageLoop());
63 page_0_url_
= GURL("http://www.example.com/1");
64 page_1_url_
= GURL("http://www.example.com/2");
67 ArticleEntry
GetDefaultEntry() {
69 entry
.set_entry_id(entry_id_
);
70 ArticleEntryPage
* page0
= entry
.add_pages();
71 ArticleEntryPage
* page1
= entry
.add_pages();
72 page0
->set_url(page_0_url_
.spec());
73 page1
->set_url(page_1_url_
.spec());
78 scoped_ptr
<base::MessageLoop
> message_loop_
;
79 std::string entry_id_
;
84 TEST_F(DomDistillerTaskTrackerTest
, TestHasEntryId
) {
85 MockDistillerFactory distiller_factory
;
86 TestCancelCallback cancel_callback
;
87 TaskTracker
task_tracker(
88 GetDefaultEntry(), cancel_callback
.GetCallback(), NULL
);
89 EXPECT_TRUE(task_tracker
.HasEntryId(entry_id_
));
90 EXPECT_FALSE(task_tracker
.HasEntryId("other_id"));
93 TEST_F(DomDistillerTaskTrackerTest
, TestHasUrl
) {
94 MockDistillerFactory distiller_factory
;
95 TestCancelCallback cancel_callback
;
96 TaskTracker
task_tracker(
97 GetDefaultEntry(), cancel_callback
.GetCallback(), NULL
);
98 EXPECT_TRUE(task_tracker
.HasUrl(page_0_url_
));
99 EXPECT_TRUE(task_tracker
.HasUrl(page_1_url_
));
100 EXPECT_FALSE(task_tracker
.HasUrl(GURL("http://other.url/")));
103 TEST_F(DomDistillerTaskTrackerTest
, TestViewerCancelled
) {
104 MockDistillerFactory distiller_factory
;
105 TestCancelCallback cancel_callback
;
106 TaskTracker
task_tracker(
107 GetDefaultEntry(), cancel_callback
.GetCallback(), NULL
);
109 FakeViewRequestDelegate viewer_delegate
;
110 FakeViewRequestDelegate viewer_delegate2
;
111 scoped_ptr
<ViewerHandle
> handle(task_tracker
.AddViewer(&viewer_delegate
));
112 scoped_ptr
<ViewerHandle
> handle2(task_tracker
.AddViewer(&viewer_delegate2
));
114 EXPECT_FALSE(cancel_callback
.Cancelled());
116 EXPECT_FALSE(cancel_callback
.Cancelled());
118 EXPECT_TRUE(cancel_callback
.Cancelled());
121 TEST_F(DomDistillerTaskTrackerTest
, TestViewerCancelledWithSaveRequest
) {
122 MockDistillerFactory distiller_factory
;
123 TestCancelCallback cancel_callback
;
124 TaskTracker
task_tracker(
125 GetDefaultEntry(), cancel_callback
.GetCallback(), NULL
);
127 FakeViewRequestDelegate viewer_delegate
;
128 scoped_ptr
<ViewerHandle
> handle(task_tracker
.AddViewer(&viewer_delegate
));
129 EXPECT_FALSE(cancel_callback
.Cancelled());
131 MockSaveCallback save_callback
;
132 task_tracker
.AddSaveCallback(
133 base::Bind(&MockSaveCallback::Save
, base::Unretained(&save_callback
)));
136 // Since there is a pending save request, the task shouldn't be cancelled.
137 EXPECT_FALSE(cancel_callback
.Cancelled());
140 TEST_F(DomDistillerTaskTrackerTest
, TestViewerNotifiedOnDistillationComplete
) {
141 MockDistillerFactory distiller_factory
;
142 FakeDistiller
* distiller
= new FakeDistiller(true);
143 EXPECT_CALL(distiller_factory
, CreateDistillerImpl())
144 .WillOnce(Return(distiller
));
145 TestCancelCallback cancel_callback
;
146 TaskTracker
task_tracker(
147 GetDefaultEntry(), cancel_callback
.GetCallback(), NULL
);
149 FakeViewRequestDelegate viewer_delegate
;
150 scoped_ptr
<ViewerHandle
> handle(task_tracker
.AddViewer(&viewer_delegate
));
151 base::RunLoop().RunUntilIdle();
153 EXPECT_CALL(viewer_delegate
, OnArticleReady(_
));
155 task_tracker
.StartDistiller(&distiller_factory
,
156 scoped_ptr
<DistillerPage
>().Pass());
157 base::RunLoop().RunUntilIdle();
159 EXPECT_FALSE(cancel_callback
.Cancelled());
162 TEST_F(DomDistillerTaskTrackerTest
,
163 TestSaveCallbackCalledOnDistillationComplete
) {
164 MockDistillerFactory distiller_factory
;
165 FakeDistiller
* distiller
= new FakeDistiller(true);
166 EXPECT_CALL(distiller_factory
, CreateDistillerImpl())
167 .WillOnce(Return(distiller
));
168 TestCancelCallback cancel_callback
;
169 TaskTracker
task_tracker(
170 GetDefaultEntry(), cancel_callback
.GetCallback(), NULL
);
172 MockSaveCallback save_callback
;
173 task_tracker
.AddSaveCallback(
174 base::Bind(&MockSaveCallback::Save
, base::Unretained(&save_callback
)));
175 base::RunLoop().RunUntilIdle();
177 EXPECT_CALL(save_callback
, Save(_
, _
, _
));
179 task_tracker
.StartDistiller(&distiller_factory
,
180 scoped_ptr
<DistillerPage
>().Pass());
181 base::RunLoop().RunUntilIdle();
183 EXPECT_TRUE(cancel_callback
.Cancelled());
186 DistilledArticleProto
CreateDistilledArticleForEntry(
187 const ArticleEntry
& entry
) {
188 DistilledArticleProto article
;
189 for (int i
= 0; i
< entry
.pages_size(); ++i
) {
190 DistilledPageProto
* page
= article
.add_pages();
191 page
->set_url(entry
.pages(i
).url());
192 page
->set_html("<div>" + entry
.pages(i
).url() + "</div>");
197 TEST_F(DomDistillerTaskTrackerTest
, TestBlobFetcher
) {
198 ArticleEntry entry_with_blob
= GetDefaultEntry();
199 DistilledArticleProto stored_distilled_article
=
200 CreateDistilledArticleForEntry(entry_with_blob
);
201 InMemoryContentStore content_store
;
202 content_store
.InjectContent(entry_with_blob
, stored_distilled_article
);
203 TestCancelCallback cancel_callback
;
205 TaskTracker
task_tracker(
206 entry_with_blob
, cancel_callback
.GetCallback(), &content_store
);
208 FakeViewRequestDelegate viewer_delegate
;
209 scoped_ptr
<ViewerHandle
> handle(task_tracker
.AddViewer(&viewer_delegate
));
210 base::RunLoop().RunUntilIdle();
212 const DistilledArticleProto
* distilled_article
;
214 EXPECT_CALL(viewer_delegate
, OnArticleReady(_
))
215 .WillOnce(testing::SaveArg
<0>(&distilled_article
));
217 task_tracker
.StartBlobFetcher();
218 base::RunLoop().RunUntilIdle();
220 EXPECT_EQ(stored_distilled_article
.SerializeAsString(),
221 distilled_article
->SerializeAsString());
223 EXPECT_FALSE(cancel_callback
.Cancelled());
226 TEST_F(DomDistillerTaskTrackerTest
, TestBlobFetcherFinishesFirst
) {
227 MockDistillerFactory distiller_factory
;
228 FakeDistiller
* distiller
= new FakeDistiller(false);
229 EXPECT_CALL(distiller_factory
, CreateDistillerImpl())
230 .WillOnce(Return(distiller
));
232 ArticleEntry entry_with_blob
= GetDefaultEntry();
233 DistilledArticleProto stored_distilled_article
=
234 CreateDistilledArticleForEntry(entry_with_blob
);
235 InMemoryContentStore content_store
;
236 content_store
.InjectContent(entry_with_blob
, stored_distilled_article
);
237 TestCancelCallback cancel_callback
;
238 TaskTracker
task_tracker(
239 entry_with_blob
, cancel_callback
.GetCallback(), &content_store
);
241 FakeViewRequestDelegate viewer_delegate
;
242 scoped_ptr
<ViewerHandle
> handle(task_tracker
.AddViewer(&viewer_delegate
));
243 base::RunLoop().RunUntilIdle();
245 DistilledArticleProto distilled_article
;
247 EXPECT_CALL(viewer_delegate
, OnArticleReady(_
))
248 .WillOnce(testing::SaveArgPointee
<0>(&distilled_article
));
249 bool distiller_destroyed
= false;
250 EXPECT_CALL(*distiller
, Die())
251 .WillOnce(testing::Assign(&distiller_destroyed
, true));
253 task_tracker
.StartDistiller(&distiller_factory
,
254 scoped_ptr
<DistillerPage
>().Pass());
255 task_tracker
.StartBlobFetcher();
256 base::RunLoop().RunUntilIdle();
258 testing::Mock::VerifyAndClearExpectations(&viewer_delegate
);
259 EXPECT_EQ(stored_distilled_article
.SerializeAsString(),
260 distilled_article
.SerializeAsString());
262 EXPECT_TRUE(distiller_destroyed
);
263 EXPECT_FALSE(cancel_callback
.Cancelled());
264 base::RunLoop().RunUntilIdle();
267 TEST_F(DomDistillerTaskTrackerTest
, TestBlobFetcherWithoutBlob
) {
268 MockDistillerFactory distiller_factory
;
269 FakeDistiller
* distiller
= new FakeDistiller(false);
270 EXPECT_CALL(distiller_factory
, CreateDistillerImpl())
271 .WillOnce(Return(distiller
));
273 ArticleEntry
entry(GetDefaultEntry());
274 InMemoryContentStore content_store
;
275 scoped_ptr
<DistilledArticleProto
> distilled_article(
276 new DistilledArticleProto(CreateDistilledArticleForEntry(entry
)));
278 TestCancelCallback cancel_callback
;
279 TaskTracker
task_tracker(
280 GetDefaultEntry(), cancel_callback
.GetCallback(), &content_store
);
282 FakeViewRequestDelegate viewer_delegate
;
283 scoped_ptr
<ViewerHandle
> handle(task_tracker
.AddViewer(&viewer_delegate
));
284 base::RunLoop().RunUntilIdle();
286 task_tracker
.StartBlobFetcher();
287 task_tracker
.StartDistiller(&distiller_factory
,
288 scoped_ptr
<DistillerPage
>().Pass());
290 // OnArticleReady shouldn't be called until distillation finishes (i.e. the
291 // blob fetcher shouldn't return distilled content).
292 EXPECT_CALL(viewer_delegate
, OnArticleReady(_
)).Times(0);
293 base::RunLoop().RunUntilIdle();
295 EXPECT_CALL(viewer_delegate
, OnArticleReady(_
));
296 distiller
->RunDistillerCallback(distilled_article
.Pass());
297 base::RunLoop().RunUntilIdle();
299 EXPECT_FALSE(cancel_callback
.Cancelled());
302 TEST_F(DomDistillerTaskTrackerTest
, TestDistillerFailsFirst
) {
303 MockDistillerFactory distiller_factory
;
304 FakeDistiller
* distiller
= new FakeDistiller(false);
305 EXPECT_CALL(distiller_factory
, CreateDistillerImpl())
306 .WillOnce(Return(distiller
));
308 ArticleEntry
entry(GetDefaultEntry());
309 MockContentStore content_store
;
311 TestCancelCallback cancel_callback
;
312 TaskTracker
task_tracker(
313 GetDefaultEntry(), cancel_callback
.GetCallback(), &content_store
);
315 FakeViewRequestDelegate viewer_delegate
;
316 scoped_ptr
<ViewerHandle
> handle(task_tracker
.AddViewer(&viewer_delegate
));
318 DistilledContentStore::LoadCallback content_store_load_callback
;
319 EXPECT_CALL(content_store
, LoadContent(_
, _
))
320 .WillOnce(testing::SaveArg
<1>(&content_store_load_callback
));
322 task_tracker
.StartDistiller(&distiller_factory
,
323 scoped_ptr
<DistillerPage
>().Pass());
324 task_tracker
.StartBlobFetcher();
326 EXPECT_CALL(viewer_delegate
, OnArticleReady(_
)).Times(0);
327 distiller
->RunDistillerCallback(
328 scoped_ptr
<DistilledArticleProto
>(new DistilledArticleProto
));
329 base::RunLoop().RunUntilIdle();
331 EXPECT_CALL(viewer_delegate
, OnArticleReady(_
));
332 content_store_load_callback
.Run(
334 scoped_ptr
<DistilledArticleProto
>(
335 new DistilledArticleProto(CreateDistilledArticleForEntry(entry
))));
336 base::RunLoop().RunUntilIdle();
338 EXPECT_FALSE(cancel_callback
.Cancelled());
341 TEST_F(DomDistillerTaskTrackerTest
, ContentIsSaved
) {
342 MockDistillerFactory distiller_factory
;
343 FakeDistiller
* distiller
= new FakeDistiller(false);
344 EXPECT_CALL(distiller_factory
, CreateDistillerImpl())
345 .WillOnce(Return(distiller
));
347 ArticleEntry
entry(GetDefaultEntry());
348 DistilledArticleProto distilled_article
=
349 CreateDistilledArticleForEntry(entry
);
351 MockContentStore content_store
;
352 TestCancelCallback cancel_callback
;
353 TaskTracker
task_tracker(
354 GetDefaultEntry(), cancel_callback
.GetCallback(), &content_store
);
356 FakeViewRequestDelegate viewer_delegate
;
357 scoped_ptr
<ViewerHandle
> handle(task_tracker
.AddViewer(&viewer_delegate
));
359 DistilledArticleProto stored_distilled_article
;
360 DistilledContentStore::LoadCallback content_store_load_callback
;
361 EXPECT_CALL(content_store
, SaveContent(_
, _
, _
))
362 .WillOnce(testing::SaveArg
<1>(&stored_distilled_article
));
364 task_tracker
.StartDistiller(&distiller_factory
,
365 scoped_ptr
<DistillerPage
>().Pass());
367 EXPECT_CALL(viewer_delegate
, OnArticleReady(_
));
368 distiller
->RunDistillerCallback(scoped_ptr
<DistilledArticleProto
>(
369 new DistilledArticleProto(distilled_article
)));
370 base::RunLoop().RunUntilIdle();
372 ASSERT_EQ(stored_distilled_article
.SerializeAsString(),
373 distilled_article
.SerializeAsString());
374 EXPECT_FALSE(cancel_callback
.Cancelled());
378 } // namespace dom_distiller