Revert 254567 "don't create SkDevice directly, use SkBitmap or (..."
[chromium-blink-merge.git] / components / dom_distiller / core / dom_distiller_service_unittest.cc
blob69e8e3a323846c3be3b2197b4c53aeb3498226ab
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/dom_distiller_service.h"
7 #include "base/bind.h"
8 #include "base/callback.h"
9 #include "base/containers/hash_tables.h"
10 #include "base/message_loop/message_loop.h"
11 #include "base/run_loop.h"
12 #include "base/strings/string_number_conversions.h"
13 #include "components/dom_distiller/core/article_entry.h"
14 #include "components/dom_distiller/core/dom_distiller_model.h"
15 #include "components/dom_distiller/core/dom_distiller_store.h"
16 #include "components/dom_distiller/core/dom_distiller_test_util.h"
17 #include "components/dom_distiller/core/fake_db.h"
18 #include "components/dom_distiller/core/fake_distiller.h"
19 #include "components/dom_distiller/core/task_tracker.h"
20 #include "testing/gmock/include/gmock/gmock.h"
21 #include "testing/gtest/include/gtest/gtest.h"
23 using testing::Invoke;
24 using testing::Return;
25 using testing::_;
27 namespace dom_distiller {
28 namespace test {
30 namespace {
32 class FakeViewRequestDelegate : public ViewRequestDelegate {
33 public:
34 virtual ~FakeViewRequestDelegate() {}
35 MOCK_METHOD1(OnArticleReady, void(const DistilledArticleProto* proto));
38 class MockDistillerObserver : public DomDistillerObserver {
39 public:
40 MOCK_METHOD1(ArticleEntriesUpdated, void(const std::vector<ArticleUpdate>&));
41 virtual ~MockDistillerObserver() {}
44 class MockArticleAvailableCallback {
45 public:
46 MOCK_METHOD1(DistillationCompleted, void(bool));
49 DomDistillerService::ArticleAvailableCallback ArticleCallback(
50 MockArticleAvailableCallback* callback) {
51 return base::Bind(&MockArticleAvailableCallback::DistillationCompleted,
52 base::Unretained(callback));
55 void RunDistillerCallback(FakeDistiller* distiller,
56 scoped_ptr<DistilledArticleProto> proto) {
57 distiller->RunDistillerCallback(proto.Pass());
58 base::RunLoop().RunUntilIdle();
61 scoped_ptr<DistilledArticleProto> CreateArticleWithURL(const std::string& url) {
62 scoped_ptr<DistilledArticleProto> proto(new DistilledArticleProto);
63 DistilledPageProto* page = proto->add_pages();
64 page->set_url(url);
65 return proto.Pass();
68 scoped_ptr<DistilledArticleProto> CreateDefaultArticle() {
69 return CreateArticleWithURL("http://www.example.com/default_article_page1")
70 .Pass();
73 } // namespace
75 class DomDistillerServiceTest : public testing::Test {
76 public:
77 virtual void SetUp() {
78 main_loop_.reset(new base::MessageLoop());
79 FakeDB* fake_db = new FakeDB(&db_model_);
80 FakeDB::EntryMap store_model;
81 store_ = test::util::CreateStoreWithFakeDB(fake_db, store_model);
82 distiller_factory_ = new MockDistillerFactory();
83 service_.reset(new DomDistillerService(
84 scoped_ptr<DomDistillerStoreInterface>(store_),
85 scoped_ptr<DistillerFactory>(distiller_factory_)));
86 fake_db->InitCallback(true);
87 fake_db->LoadCallback(true);
90 virtual void TearDown() {
91 base::RunLoop().RunUntilIdle();
92 store_ = NULL;
93 distiller_factory_ = NULL;
94 service_.reset();
97 protected:
98 // store is owned by service_.
99 DomDistillerStoreInterface* store_;
100 MockDistillerFactory* distiller_factory_;
101 scoped_ptr<DomDistillerService> service_;
102 scoped_ptr<base::MessageLoop> main_loop_;
103 FakeDB::EntryMap db_model_;
106 TEST_F(DomDistillerServiceTest, TestViewEntry) {
107 FakeDistiller* distiller = new FakeDistiller(false);
108 EXPECT_CALL(*distiller_factory_, CreateDistillerImpl())
109 .WillOnce(Return(distiller));
111 GURL url("http://www.example.com/p1");
112 std::string entry_id("id0");
113 ArticleEntry entry;
114 entry.set_entry_id(entry_id);
115 entry.add_pages()->set_url(url.spec());
117 store_->AddEntry(entry);
119 FakeViewRequestDelegate viewer_delegate;
120 scoped_ptr<ViewerHandle> handle =
121 service_->ViewEntry(&viewer_delegate, entry_id);
123 ASSERT_FALSE(distiller->GetCallback().is_null());
125 scoped_ptr<DistilledArticleProto> proto = CreateDefaultArticle();
126 EXPECT_CALL(viewer_delegate, OnArticleReady(proto.get()));
128 RunDistillerCallback(distiller, proto.Pass());
131 TEST_F(DomDistillerServiceTest, TestViewUrl) {
132 FakeDistiller* distiller = new FakeDistiller(false);
133 EXPECT_CALL(*distiller_factory_, CreateDistillerImpl())
134 .WillOnce(Return(distiller));
136 FakeViewRequestDelegate viewer_delegate;
137 GURL url("http://www.example.com/p1");
138 scoped_ptr<ViewerHandle> handle = service_->ViewUrl(&viewer_delegate, url);
140 ASSERT_FALSE(distiller->GetCallback().is_null());
141 EXPECT_EQ(url, distiller->GetUrl());
143 scoped_ptr<DistilledArticleProto> proto = CreateDefaultArticle();
144 EXPECT_CALL(viewer_delegate, OnArticleReady(proto.get()));
146 RunDistillerCallback(distiller, proto.Pass());
149 TEST_F(DomDistillerServiceTest, TestMultipleViewUrl) {
150 FakeDistiller* distiller = new FakeDistiller(false);
151 FakeDistiller* distiller2 = new FakeDistiller(false);
152 EXPECT_CALL(*distiller_factory_, CreateDistillerImpl())
153 .WillOnce(Return(distiller))
154 .WillOnce(Return(distiller2));
156 FakeViewRequestDelegate viewer_delegate;
157 FakeViewRequestDelegate viewer_delegate2;
159 GURL url("http://www.example.com/p1");
160 GURL url2("http://www.example.com/a/p1");
162 scoped_ptr<ViewerHandle> handle = service_->ViewUrl(&viewer_delegate, url);
163 scoped_ptr<ViewerHandle> handle2 = service_->ViewUrl(&viewer_delegate2, url2);
165 ASSERT_FALSE(distiller->GetCallback().is_null());
166 EXPECT_EQ(url, distiller->GetUrl());
168 scoped_ptr<DistilledArticleProto> proto = CreateDefaultArticle();
169 EXPECT_CALL(viewer_delegate, OnArticleReady(proto.get()));
171 RunDistillerCallback(distiller, proto.Pass());
173 ASSERT_FALSE(distiller2->GetCallback().is_null());
174 EXPECT_EQ(url2, distiller2->GetUrl());
176 scoped_ptr<DistilledArticleProto> proto2 = CreateDefaultArticle();
177 EXPECT_CALL(viewer_delegate2, OnArticleReady(proto2.get()));
179 RunDistillerCallback(distiller2, proto2.Pass());
182 TEST_F(DomDistillerServiceTest, TestViewUrlCancelled) {
183 FakeDistiller* distiller = new FakeDistiller(false);
184 EXPECT_CALL(*distiller_factory_, CreateDistillerImpl())
185 .WillOnce(Return(distiller));
187 bool distiller_destroyed = false;
188 EXPECT_CALL(*distiller, Die())
189 .WillOnce(testing::Assign(&distiller_destroyed, true));
191 FakeViewRequestDelegate viewer_delegate;
192 GURL url("http://www.example.com/p1");
193 scoped_ptr<ViewerHandle> handle = service_->ViewUrl(&viewer_delegate, url);
195 ASSERT_FALSE(distiller->GetCallback().is_null());
196 EXPECT_EQ(url, distiller->GetUrl());
198 EXPECT_CALL(viewer_delegate, OnArticleReady(_)).Times(0);
200 EXPECT_FALSE(distiller_destroyed);
202 handle.reset();
203 base::RunLoop().RunUntilIdle();
204 EXPECT_TRUE(distiller_destroyed);
207 TEST_F(DomDistillerServiceTest, TestViewUrlDoesNotAddEntry) {
208 FakeDistiller* distiller = new FakeDistiller(false);
209 EXPECT_CALL(*distiller_factory_, CreateDistillerImpl())
210 .WillOnce(Return(distiller));
212 FakeViewRequestDelegate viewer_delegate;
213 GURL url("http://www.example.com/p1");
214 scoped_ptr<ViewerHandle> handle = service_->ViewUrl(&viewer_delegate, url);
216 scoped_ptr<DistilledArticleProto> proto = CreateArticleWithURL(url.spec());
217 EXPECT_CALL(viewer_delegate, OnArticleReady(proto.get()));
219 RunDistillerCallback(distiller, proto.Pass());
220 base::RunLoop().RunUntilIdle();
221 // The entry should not be added to the store.
222 EXPECT_EQ(0u, store_->GetEntries().size());
225 TEST_F(DomDistillerServiceTest, TestAddAndRemoveEntry) {
226 FakeDistiller* distiller = new FakeDistiller(false);
227 EXPECT_CALL(*distiller_factory_, CreateDistillerImpl())
228 .WillOnce(Return(distiller));
230 GURL url("http://www.example.com/p1");
232 MockArticleAvailableCallback article_cb;
233 EXPECT_CALL(article_cb, DistillationCompleted(true));
235 std::string entry_id = service_->AddToList(url, ArticleCallback(&article_cb));
237 ASSERT_FALSE(distiller->GetCallback().is_null());
238 EXPECT_EQ(url, distiller->GetUrl());
240 scoped_ptr<DistilledArticleProto> proto = CreateArticleWithURL(url.spec());
241 RunDistillerCallback(distiller, proto.Pass());
243 ArticleEntry entry;
244 EXPECT_TRUE(store_->GetEntryByUrl(url, &entry));
245 EXPECT_EQ(entry.entry_id(), entry_id);
246 EXPECT_EQ(1u, store_->GetEntries().size());
247 service_->RemoveEntry(entry_id);
248 base::RunLoop().RunUntilIdle();
249 EXPECT_EQ(0u, store_->GetEntries().size());
252 TEST_F(DomDistillerServiceTest, TestCancellation) {
253 FakeDistiller* distiller = new FakeDistiller(false);
254 MockDistillerObserver observer;
255 service_->AddObserver(&observer);
257 EXPECT_CALL(*distiller_factory_, CreateDistillerImpl())
258 .WillOnce(Return(distiller));
260 MockArticleAvailableCallback article_cb;
261 EXPECT_CALL(article_cb, DistillationCompleted(false));
263 GURL url("http://www.example.com/p1");
264 std::string entry_id = service_->AddToList(url, ArticleCallback(&article_cb));
266 // Remove entry will cause the |article_cb| to be called with false value.
267 service_->RemoveEntry(entry_id);
268 base::RunLoop().RunUntilIdle();
271 TEST_F(DomDistillerServiceTest, TestMultipleObservers) {
272 FakeDistiller* distiller = new FakeDistiller(false);
273 EXPECT_CALL(*distiller_factory_, CreateDistillerImpl())
274 .WillOnce(Return(distiller));
276 const int kObserverCount = 5;
277 MockDistillerObserver observers[kObserverCount];
278 for (int i = 0; i < kObserverCount; ++i) {
279 service_->AddObserver(&observers[i]);
282 DomDistillerService::ArticleAvailableCallback article_cb;
283 GURL url("http://www.example.com/p1");
284 std::string entry_id = service_->AddToList(url, article_cb);
286 // Distillation should notify all observers that article is added.
287 std::vector<DomDistillerObserver::ArticleUpdate> expected_updates;
288 DomDistillerObserver::ArticleUpdate update;
289 update.entry_id = entry_id;
290 update.update_type = DomDistillerObserver::ArticleUpdate::ADD;
291 expected_updates.push_back(update);
293 for (int i = 0; i < kObserverCount; ++i) {
294 EXPECT_CALL(
295 observers[i],
296 ArticleEntriesUpdated(util::HasExpectedUpdates(expected_updates)));
299 scoped_ptr<DistilledArticleProto> proto = CreateDefaultArticle();
300 RunDistillerCallback(distiller, proto.Pass());
302 // Remove should notify all observers that article is removed.
303 update.update_type = DomDistillerObserver::ArticleUpdate::REMOVE;
304 expected_updates.clear();
305 expected_updates.push_back(update);
306 for (int i = 0; i < kObserverCount; ++i) {
307 EXPECT_CALL(
308 observers[i],
309 ArticleEntriesUpdated(util::HasExpectedUpdates(expected_updates)));
312 service_->RemoveEntry(entry_id);
313 base::RunLoop().RunUntilIdle();
316 TEST_F(DomDistillerServiceTest, TestMultipleCallbacks) {
317 FakeDistiller* distiller = new FakeDistiller(false);
318 EXPECT_CALL(*distiller_factory_, CreateDistillerImpl())
319 .WillOnce(Return(distiller));
321 const int kClientsCount = 5;
322 MockArticleAvailableCallback article_cb[kClientsCount];
323 // Adding a URL and then distilling calls all clients.
324 GURL url("http://www.example.com/p1");
325 const std::string entry_id =
326 service_->AddToList(url, ArticleCallback(&article_cb[0]));
327 EXPECT_CALL(article_cb[0], DistillationCompleted(true));
329 for (int i = 1; i < kClientsCount; ++i) {
330 EXPECT_EQ(entry_id,
331 service_->AddToList(url, ArticleCallback(&article_cb[i])));
332 EXPECT_CALL(article_cb[i], DistillationCompleted(true));
335 scoped_ptr<DistilledArticleProto> proto = CreateArticleWithURL(url.spec());
336 RunDistillerCallback(distiller, proto.Pass());
338 // Add the same url again, all callbacks should be called with true.
339 for (int i = 0; i < kClientsCount; ++i) {
340 EXPECT_CALL(article_cb[i], DistillationCompleted(true));
341 EXPECT_EQ(entry_id,
342 service_->AddToList(url, ArticleCallback(&article_cb[i])));
345 base::RunLoop().RunUntilIdle();
348 TEST_F(DomDistillerServiceTest, TestMultipleCallbacksOnRemove) {
349 FakeDistiller* distiller = new FakeDistiller(false);
350 EXPECT_CALL(*distiller_factory_, CreateDistillerImpl())
351 .WillOnce(Return(distiller));
353 const int kClientsCount = 5;
354 MockArticleAvailableCallback article_cb[kClientsCount];
355 // Adding a URL and remove the entry before distillation. Callback should be
356 // called with false.
357 GURL url("http://www.example.com/p1");
358 const std::string entry_id =
359 service_->AddToList(url, ArticleCallback(&article_cb[0]));
361 EXPECT_CALL(article_cb[0], DistillationCompleted(false));
362 for (int i = 1; i < kClientsCount; ++i) {
363 EXPECT_EQ(entry_id,
364 service_->AddToList(url, ArticleCallback(&article_cb[i])));
365 EXPECT_CALL(article_cb[i], DistillationCompleted(false));
368 service_->RemoveEntry(entry_id);
369 base::RunLoop().RunUntilIdle();
372 TEST_F(DomDistillerServiceTest, TestMultiplePageArticle) {
373 FakeDistiller* distiller = new FakeDistiller(false);
374 EXPECT_CALL(*distiller_factory_, CreateDistillerImpl())
375 .WillOnce(Return(distiller));
377 const int kPageCount = 8;
379 std::string base_url("http://www.example.com/p");
380 GURL pages_url[kPageCount];
381 for (int page_num = 0; page_num < kPageCount; ++page_num) {
382 pages_url[page_num] = GURL(base_url + base::IntToString(page_num));
385 MockArticleAvailableCallback article_cb;
386 EXPECT_CALL(article_cb, DistillationCompleted(true));
388 std::string entry_id =
389 service_->AddToList(pages_url[0], ArticleCallback(&article_cb));
391 ArticleEntry entry;
392 ASSERT_FALSE(distiller->GetCallback().is_null());
393 EXPECT_EQ(pages_url[0], distiller->GetUrl());
395 // Create the article with pages to pass to the distiller.
396 scoped_ptr<DistilledArticleProto> proto =
397 CreateArticleWithURL(pages_url[0].spec());
398 for (int page_num = 1; page_num < kPageCount; ++page_num) {
399 DistilledPageProto* distilled_page = proto->add_pages();
400 distilled_page->set_url(pages_url[page_num].spec());
403 RunDistillerCallback(distiller, proto.Pass());
404 EXPECT_TRUE(store_->GetEntryByUrl(pages_url[0], &entry));
406 EXPECT_EQ(kPageCount, entry.pages_size());
407 // An article should have just one entry.
408 EXPECT_EQ(1u, store_->GetEntries().size());
410 // All pages should have correct urls.
411 for (int page_num = 0; page_num < kPageCount; ++page_num) {
412 EXPECT_EQ(pages_url[page_num].spec(), entry.pages(page_num).url());
415 // Should be able to query article using any of the pages url.
416 for (int page_num = 0; page_num < kPageCount; ++page_num) {
417 EXPECT_TRUE(store_->GetEntryByUrl(pages_url[page_num], &entry));
420 service_->RemoveEntry(entry_id);
421 base::RunLoop().RunUntilIdle();
422 EXPECT_EQ(0u, store_->GetEntries().size());
425 } // namespace test
426 } // namespace dom_distiller