146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved.
246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)// found in the LICENSE file.
446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "base/bind.h"
646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "base/message_loop/message_loop.h"
746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "base/run_loop.h"
846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "components/dom_distiller/core/article_entry.h"
946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "components/dom_distiller/core/distilled_content_store.h"
1046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "components/dom_distiller/core/proto/distilled_article.pb.h"
1146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "testing/gtest/include/gtest/gtest.h"
1246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
1346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)namespace dom_distiller {
1446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
1546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)namespace {
1646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
1746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)ArticleEntry CreateEntry(std::string entry_id,
1846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                         std::string page_url1,
1946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                         std::string page_url2,
2046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                         std::string page_url3) {
2146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  ArticleEntry entry;
2246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  entry.set_entry_id(entry_id);
2346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (!page_url1.empty()) {
2446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    ArticleEntryPage* page = entry.add_pages();
2546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    page->set_url(page_url1);
2646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  }
2746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (!page_url2.empty()) {
2846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    ArticleEntryPage* page = entry.add_pages();
2946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    page->set_url(page_url2);
3046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  }
3146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (!page_url3.empty()) {
3246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    ArticleEntryPage* page = entry.add_pages();
3346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    page->set_url(page_url3);
3446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  }
3546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  return entry;
3646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)}
3746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
3846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)DistilledArticleProto CreateDistilledArticleForEntry(
3946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    const ArticleEntry& entry) {
4046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  DistilledArticleProto article;
4146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  for (int i = 0; i < entry.pages_size(); ++i) {
4246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    DistilledPageProto* page = article.add_pages();
4346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    page->set_url(entry.pages(i).url());
4446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    page->set_html("<div>" + entry.pages(i).url() + "</div>");
4546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  }
4646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  return article;
4746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)}
4846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
4946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)}  // namespace
5046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
5146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)class InMemoryContentStoreTest : public testing::Test {
5246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) public:
5346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  void OnLoadCallback(bool success, scoped_ptr<DistilledArticleProto> proto) {
5446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    load_success_ = success;
5546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    loaded_proto_ = proto.Pass();
5646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  }
5746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
5846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  void OnSaveCallback(bool success) { save_success_ = success; }
5946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
6046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) protected:
6146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  // testing::Test implementation:
6246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  virtual void SetUp() OVERRIDE {
6346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    store_.reset(new InMemoryContentStore(kDefaultMaxNumCachedEntries));
6446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    save_success_ = false;
6546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    load_success_ = false;
6646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    loaded_proto_.reset();
6746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  }
6846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
6946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  scoped_ptr<InMemoryContentStore> store_;
7046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  bool save_success_;
7146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  bool load_success_;
7246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  scoped_ptr<DistilledArticleProto> loaded_proto_;
7346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)};
7446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
7546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)// Tests whether saving and then loading a single article works as expected.
7646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)TEST_F(InMemoryContentStoreTest, SaveAndLoadSingleArticle) {
7746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  base::MessageLoop loop;
7846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  const ArticleEntry entry = CreateEntry("test-id", "url1", "url2", "url3");
7946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  const DistilledArticleProto stored_proto =
8046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      CreateDistilledArticleForEntry(entry);
8146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  store_->SaveContent(entry,
8246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                      stored_proto,
8346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                      base::Bind(&InMemoryContentStoreTest::OnSaveCallback,
8446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                                 base::Unretained(this)));
8546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  base::MessageLoop::current()->RunUntilIdle();
8646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  EXPECT_TRUE(save_success_);
8746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  save_success_ = false;
8846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
8946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  store_->LoadContent(entry,
9046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                      base::Bind(&InMemoryContentStoreTest::OnLoadCallback,
9146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                                 base::Unretained(this)));
9246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  base::MessageLoop::current()->RunUntilIdle();
9346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  EXPECT_TRUE(load_success_);
9446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  EXPECT_EQ(stored_proto.SerializeAsString(),
9546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)            loaded_proto_->SerializeAsString());
9646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)}
9746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
9846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)// Tests that loading articles which have never been stored, yields a callback
9946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)// where success is false.
10046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)TEST_F(InMemoryContentStoreTest, LoadNonExistentArticle) {
10146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  base::MessageLoop loop;
10246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  const ArticleEntry entry = CreateEntry("bogus-id", "url1", "url2", "url3");
10346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  store_->LoadContent(entry,
10446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                      base::Bind(&InMemoryContentStoreTest::OnLoadCallback,
10546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                                 base::Unretained(this)));
10646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  base::MessageLoop::current()->RunUntilIdle();
10746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  EXPECT_FALSE(load_success_);
10846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)}
10946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
11046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)// Verifies that content store can store multiple articles, and that ordering
11146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)// of save and store does not matter when the total number of articles does not
11246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)// exceed |kDefaultMaxNumCachedEntries|.
11346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)TEST_F(InMemoryContentStoreTest, SaveAndLoadMultipleArticles) {
11446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  base::MessageLoop loop;
11546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  // Store first article.
11646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  const ArticleEntry first_entry = CreateEntry("first", "url1", "url2", "url3");
11746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  const DistilledArticleProto first_stored_proto =
11846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      CreateDistilledArticleForEntry(first_entry);
11946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  store_->SaveContent(first_entry,
12046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                      first_stored_proto,
12146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                      base::Bind(&InMemoryContentStoreTest::OnSaveCallback,
12246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                                 base::Unretained(this)));
12346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  base::MessageLoop::current()->RunUntilIdle();
12446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  EXPECT_TRUE(save_success_);
12546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  save_success_ = false;
12646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
12746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  // Store second article.
12846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  const ArticleEntry second_entry =
129f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      CreateEntry("second", "url4", "url5", "url6");
13046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  const DistilledArticleProto second_stored_proto =
13146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      CreateDistilledArticleForEntry(second_entry);
13246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  store_->SaveContent(second_entry,
13346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                      second_stored_proto,
13446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                      base::Bind(&InMemoryContentStoreTest::OnSaveCallback,
13546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                                 base::Unretained(this)));
13646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  base::MessageLoop::current()->RunUntilIdle();
13746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  EXPECT_TRUE(save_success_);
13846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  save_success_ = false;
13946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
14046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  // Load second article.
14146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  store_->LoadContent(second_entry,
14246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                      base::Bind(&InMemoryContentStoreTest::OnLoadCallback,
14346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                                 base::Unretained(this)));
14446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  base::MessageLoop::current()->RunUntilIdle();
14546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  EXPECT_TRUE(load_success_);
14646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  load_success_ = false;
14746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  EXPECT_EQ(second_stored_proto.SerializeAsString(),
14846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)            loaded_proto_->SerializeAsString());
14946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  loaded_proto_.reset();
15046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
15146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  // Load first article.
15246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  store_->LoadContent(first_entry,
15346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                      base::Bind(&InMemoryContentStoreTest::OnLoadCallback,
15446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                                 base::Unretained(this)));
15546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  base::MessageLoop::current()->RunUntilIdle();
15646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  EXPECT_TRUE(load_success_);
15746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  EXPECT_EQ(first_stored_proto.SerializeAsString(),
15846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)            loaded_proto_->SerializeAsString());
15946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)}
16046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
16146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)// Verifies that the content store does not store unlimited number of articles,
16246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)// but expires the oldest ones when the limit for number of articles is reached.
16346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)TEST_F(InMemoryContentStoreTest, SaveAndLoadMoreThanMaxArticles) {
16446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  base::MessageLoop loop;
16546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
16646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  // Create a new store with only |kMaxNumArticles| articles as the limit.
16746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  const int kMaxNumArticles = 3;
16846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  store_.reset(new InMemoryContentStore(kMaxNumArticles));
16946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
17046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  // Store first article.
17146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  const ArticleEntry first_entry = CreateEntry("first", "url1", "url2", "url3");
17246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  const DistilledArticleProto first_stored_proto =
17346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      CreateDistilledArticleForEntry(first_entry);
17446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  store_->SaveContent(first_entry,
17546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                      first_stored_proto,
17646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                      base::Bind(&InMemoryContentStoreTest::OnSaveCallback,
17746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                                 base::Unretained(this)));
17846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  base::MessageLoop::current()->RunUntilIdle();
17946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  EXPECT_TRUE(save_success_);
18046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  save_success_ = false;
18146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
18246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  // Store second article.
18346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  const ArticleEntry second_entry =
184f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      CreateEntry("second", "url4", "url5", "url6");
18546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  const DistilledArticleProto second_stored_proto =
18646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      CreateDistilledArticleForEntry(second_entry);
18746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  store_->SaveContent(second_entry,
18846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                      second_stored_proto,
18946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                      base::Bind(&InMemoryContentStoreTest::OnSaveCallback,
19046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                                 base::Unretained(this)));
19146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  base::MessageLoop::current()->RunUntilIdle();
19246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  EXPECT_TRUE(save_success_);
19346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  save_success_ = false;
19446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
19546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  // Store third article.
196f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  const ArticleEntry third_entry = CreateEntry("third", "url7", "url8", "url9");
19746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  const DistilledArticleProto third_stored_proto =
19846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      CreateDistilledArticleForEntry(third_entry);
19946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  store_->SaveContent(third_entry,
20046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                      third_stored_proto,
20146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                      base::Bind(&InMemoryContentStoreTest::OnSaveCallback,
20246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                                 base::Unretained(this)));
20346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  base::MessageLoop::current()->RunUntilIdle();
20446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  EXPECT_TRUE(save_success_);
20546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  save_success_ = false;
20646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
20746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  // Load first article. This will make the first article the most recent
20846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  // accessed article.
20946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  store_->LoadContent(first_entry,
21046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                      base::Bind(&InMemoryContentStoreTest::OnLoadCallback,
21146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                                 base::Unretained(this)));
21246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  base::MessageLoop::current()->RunUntilIdle();
21346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  EXPECT_TRUE(load_success_);
21446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  load_success_ = false;
21546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  EXPECT_EQ(first_stored_proto.SerializeAsString(),
21646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)            loaded_proto_->SerializeAsString());
21746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  loaded_proto_.reset();
21846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
21946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  // Store fourth article.
22046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  const ArticleEntry fourth_entry =
221f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      CreateEntry("fourth", "url10", "url11", "url12");
22246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  const DistilledArticleProto fourth_stored_proto =
22346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      CreateDistilledArticleForEntry(fourth_entry);
22446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  store_->SaveContent(fourth_entry,
22546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                      fourth_stored_proto,
22646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                      base::Bind(&InMemoryContentStoreTest::OnSaveCallback,
22746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                                 base::Unretained(this)));
22846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  base::MessageLoop::current()->RunUntilIdle();
22946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  EXPECT_TRUE(save_success_);
23046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  save_success_ = false;
23146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
23246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  // Load second article, which by now is the oldest accessed article, since
23346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  // the first article has been loaded once.
23446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  store_->LoadContent(second_entry,
23546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                      base::Bind(&InMemoryContentStoreTest::OnLoadCallback,
23646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                                 base::Unretained(this)));
23746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  base::MessageLoop::current()->RunUntilIdle();
23846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  // Since the store can only contain |kMaxNumArticles| entries, this load
23946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  // should fail.
24046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  EXPECT_FALSE(load_success_);
24146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)}
24246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
243f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// Tests whether saving and then loading a single article works as expected.
244f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)TEST_F(InMemoryContentStoreTest, LookupArticleByURL) {
245f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  base::MessageLoop loop;
246f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  const ArticleEntry entry = CreateEntry("test-id", "url1", "url2", "url3");
247f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  const DistilledArticleProto stored_proto =
248f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      CreateDistilledArticleForEntry(entry);
249f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  store_->SaveContent(entry,
250f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                      stored_proto,
251f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                      base::Bind(&InMemoryContentStoreTest::OnSaveCallback,
252f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                 base::Unretained(this)));
253f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  base::MessageLoop::current()->RunUntilIdle();
254f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  EXPECT_TRUE(save_success_);
255f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  save_success_ = false;
256f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
257f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // Create an entry where the entry ID does not match, but the first URL does.
258f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  const ArticleEntry lookup_entry1 = CreateEntry("lookup-id", "url1", "", "");
259f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  store_->LoadContent(lookup_entry1,
260f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                      base::Bind(&InMemoryContentStoreTest::OnLoadCallback,
261f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                 base::Unretained(this)));
262f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  base::MessageLoop::current()->RunUntilIdle();
263f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  EXPECT_TRUE(load_success_);
264f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  EXPECT_EQ(stored_proto.SerializeAsString(),
265f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)            loaded_proto_->SerializeAsString());
266f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
267f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // Create an entry where the entry ID does not match, but the second URL does.
268f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  const ArticleEntry lookup_entry2 =
269f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      CreateEntry("lookup-id", "bogus", "url2", "");
270f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  store_->LoadContent(lookup_entry2,
271f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                      base::Bind(&InMemoryContentStoreTest::OnLoadCallback,
272f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                 base::Unretained(this)));
273f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  base::MessageLoop::current()->RunUntilIdle();
274f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  EXPECT_TRUE(load_success_);
275f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  EXPECT_EQ(stored_proto.SerializeAsString(),
276f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)            loaded_proto_->SerializeAsString());
277f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
278f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
279f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// Verifies that the content store does not store unlimited number of articles,
280f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// but expires the oldest ones when the limit for number of articles is reached.
281f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)TEST_F(InMemoryContentStoreTest, LoadArticleByURLAfterExpungedFromCache) {
282f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  base::MessageLoop loop;
283f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
284f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // Create a new store with only |kMaxNumArticles| articles as the limit.
285f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  const int kMaxNumArticles = 1;
286f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  store_.reset(new InMemoryContentStore(kMaxNumArticles));
287f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
288f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // Store an article.
289f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  const ArticleEntry first_entry = CreateEntry("first", "url1", "url2", "url3");
290f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  const DistilledArticleProto first_stored_proto =
291f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      CreateDistilledArticleForEntry(first_entry);
292f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  store_->SaveContent(first_entry,
293f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                      first_stored_proto,
294f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                      base::Bind(&InMemoryContentStoreTest::OnSaveCallback,
295f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                 base::Unretained(this)));
296f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  base::MessageLoop::current()->RunUntilIdle();
297f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  EXPECT_TRUE(save_success_);
298f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  save_success_ = false;
299f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
300f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // Looking up the first entry by URL should succeed when it is still in the
301f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // cache.
302f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  const ArticleEntry first_entry_lookup =
303f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      CreateEntry("lookup-id", "url1", "", "");
304f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  store_->LoadContent(first_entry_lookup,
305f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                      base::Bind(&InMemoryContentStoreTest::OnLoadCallback,
306f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                 base::Unretained(this)));
307f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  base::MessageLoop::current()->RunUntilIdle();
308f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  EXPECT_TRUE(load_success_);
309f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  EXPECT_EQ(first_stored_proto.SerializeAsString(),
310f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)            loaded_proto_->SerializeAsString());
311f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
312f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // Store second article. This will remove the first article from the cache.
313f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  const ArticleEntry second_entry =
314f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      CreateEntry("second", "url4", "url5", "url6");
315f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  const DistilledArticleProto second_stored_proto =
316f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      CreateDistilledArticleForEntry(second_entry);
317f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  store_->SaveContent(second_entry,
318f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                      second_stored_proto,
319f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                      base::Bind(&InMemoryContentStoreTest::OnSaveCallback,
320f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                 base::Unretained(this)));
321f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  base::MessageLoop::current()->RunUntilIdle();
322f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  EXPECT_TRUE(save_success_);
323f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  save_success_ = false;
324f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
325f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // Looking up the first entry by URL should fail when it is not in the cache.
326f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  store_->LoadContent(first_entry_lookup,
327f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                      base::Bind(&InMemoryContentStoreTest::OnLoadCallback,
328f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                 base::Unretained(this)));
329f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  base::MessageLoop::current()->RunUntilIdle();
330f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  EXPECT_FALSE(load_success_);
331f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
332f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
33346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)}  // namespace dom_distiller
334