diff options
author | abhishek.a21 <abhishek.a21@samsung.com> | 2015-07-22 02:11:44 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-07-22 09:12:55 +0000 |
commit | faf6421d12a9499b3a3d5266b5ceb33ea81ce1d2 (patch) | |
tree | fe0c36593acb4bd50c5372080be04bc0b5e1a83f /components | |
parent | 1067392cb46b944e198f085fad7e226d700ad070 (diff) | |
download | chromium_src-faf6421d12a9499b3a3d5266b5ceb33ea81ce1d2.zip chromium_src-faf6421d12a9499b3a3d5266b5ceb33ea81ce1d2.tar.gz chromium_src-faf6421d12a9499b3a3d5266b5ceb33ea81ce1d2.tar.bz2 |
Componentize //chrome/browser/offline_pages
Componentize offline_page_metadata_store_impl.[cc/h], unittest and offline_pages.proto file.
Updated BUILD.gn and corresponding .gypi files for the same.
BUG=507284
Review URL: https://codereview.chromium.org/1226173004
Cr-Commit-Position: refs/heads/master@{#339852}
Diffstat (limited to 'components')
-rw-r--r-- | components/components_tests.gyp | 1 | ||||
-rw-r--r-- | components/offline_pages.gypi | 17 | ||||
-rw-r--r-- | components/offline_pages/BUILD.gn | 7 | ||||
-rw-r--r-- | components/offline_pages/DEPS | 2 | ||||
-rw-r--r-- | components/offline_pages/offline_page_metadata_store_impl.cc | 211 | ||||
-rw-r--r-- | components/offline_pages/offline_page_metadata_store_impl.h | 67 | ||||
-rw-r--r-- | components/offline_pages/offline_page_metadata_store_impl_unittest.cc | 310 | ||||
-rw-r--r-- | components/offline_pages/proto/BUILD.gn | 12 | ||||
-rw-r--r-- | components/offline_pages/proto/offline_pages.proto | 36 |
9 files changed, 663 insertions, 0 deletions
diff --git a/components/components_tests.gyp b/components/components_tests.gyp index 509ef5e..36e465c 100644 --- a/components/components_tests.gyp +++ b/components/components_tests.gyp @@ -342,6 +342,7 @@ 'network_time/network_time_tracker_unittest.cc', ], 'offline_page_unittest_sources': [ + 'offline_pages/offline_page_metadata_store_impl_unittest.cc', 'offline_pages/offline_page_model_unittest.cc', ], 'omnibox_unittest_sources': [ diff --git a/components/offline_pages.gypi b/components/offline_pages.gypi index 668c806..b71297f 100644 --- a/components/offline_pages.gypi +++ b/components/offline_pages.gypi @@ -15,7 +15,10 @@ '../base/base.gyp:base', '../net/net.gyp:net', '../url/url.gyp:url_lib', + '../third_party/leveldatabase/leveldatabase.gyp:leveldatabase', + 'components.gyp:leveldb_proto', 'keyed_service_core', + 'offline_pages_proto', ], 'sources': [ 'offline_pages/offline_page_archiver.h', @@ -25,7 +28,21 @@ 'offline_pages/offline_page_model.h', 'offline_pages/offline_page_metadata_store.cc', 'offline_pages/offline_page_metadata_store.h', + 'offline_pages/offline_page_metadata_store_impl.cc', + 'offline_pages/offline_page_metadata_store_impl.h', ], }, + { + # Protobuf compiler / generator for the offline page item protocol buffer. + # GN version: //components/offline_pages/proto + 'target_name': 'offline_pages_proto', + 'type': 'static_library', + 'sources': [ 'offline_pages/proto/offline_pages.proto', ], + 'variables': { + 'proto_in_dir': 'offline_pages/proto', + 'proto_out_dir': 'components/offline_pages/proto', + }, + 'includes': [ '../build/protoc.gypi', ], + }, ], } diff --git a/components/offline_pages/BUILD.gn b/components/offline_pages/BUILD.gn index 36cee85..47f6adc 100644 --- a/components/offline_pages/BUILD.gn +++ b/components/offline_pages/BUILD.gn @@ -10,6 +10,8 @@ static_library("offline_pages") { "offline_page_item.h", "offline_page_metadata_store.cc", "offline_page_metadata_store.h", + "offline_page_metadata_store_impl.cc", + "offline_page_metadata_store_impl.h", "offline_page_model.cc", "offline_page_model.h", ] @@ -17,7 +19,10 @@ static_library("offline_pages") { deps = [ "//base", "//components/keyed_service/core", + "//components/leveldb_proto", + "//components/offline_pages/proto:offline_pages_proto", "//net", + "//third_party/leveldatabase", "//url", ] } @@ -25,11 +30,13 @@ static_library("offline_pages") { source_set("unit_tests") { testonly = true sources = [ + "offline_page_metadata_store_impl_unittest.cc", "offline_page_model_unittest.cc", ] deps = [ ":offline_pages", + "//components/offline_pages/proto:offline_pages_proto", "//testing/gtest", ] } diff --git a/components/offline_pages/DEPS b/components/offline_pages/DEPS index 2393a77..e49d933c0 100644 --- a/components/offline_pages/DEPS +++ b/components/offline_pages/DEPS @@ -1,4 +1,6 @@ include_rules = [ "+components/keyed_service", + "+components/leveldb_proto", "+net", + "+third_party/leveldatabase", ] diff --git a/components/offline_pages/offline_page_metadata_store_impl.cc b/components/offline_pages/offline_page_metadata_store_impl.cc new file mode 100644 index 0000000..e19585fa --- /dev/null +++ b/components/offline_pages/offline_page_metadata_store_impl.cc @@ -0,0 +1,211 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/offline_pages/offline_page_metadata_store_impl.h" + +#include "base/bind.h" +#include "base/files/file_path.h" +#include "base/location.h" +#include "base/message_loop/message_loop.h" +#include "base/sequenced_task_runner.h" +#include "base/strings/utf_string_conversions.h" +#include "base/thread_task_runner_handle.h" +#include "components/leveldb_proto/proto_database.h" +#include "components/offline_pages/offline_page_item.h" +#include "components/offline_pages/proto/offline_pages.pb.h" +#include "third_party/leveldatabase/env_chromium.h" +#include "third_party/leveldatabase/src/include/leveldb/db.h" +#include "url/gurl.h" + +using leveldb_proto::ProtoDatabase; + +namespace offline_pages { +namespace { + +typedef std::vector<OfflinePageEntry> OfflinePageEntryVector; + +void OfflinePageItemToEntry(const OfflinePageItem& item, + offline_pages::OfflinePageEntry* item_proto) { + DCHECK(item_proto); + item_proto->set_url(item.url.spec()); + item_proto->set_title(base::UTF16ToUTF8(item.title)); + item_proto->set_version(item.version); + std::string path_string; +#if defined(OS_POSIX) + path_string = item.file_path.value(); +#elif defined(OS_WIN) + path_string = base::WideToUTF8(item.file_path.value()); +#endif + item_proto->set_file_path(path_string); + item_proto->set_file_size(item.file_size); + item_proto->set_creation_time(item.creation_time.ToInternalValue()); + item_proto->set_last_access_time(item.last_access_time.ToInternalValue()); +} + +bool OfflinePageItemFromEntry(const offline_pages::OfflinePageEntry& item_proto, + OfflinePageItem* item) { + DCHECK(item); + if (!item_proto.has_url() || !item_proto.has_title() || + !item_proto.has_version() || !item_proto.has_file_path()) { + return false; + } + item->url = GURL(item_proto.url()); + item->title = base::UTF8ToUTF16(item_proto.title()); + item->version = item_proto.version(); +#if defined(OS_POSIX) + item->file_path = base::FilePath(item_proto.file_path()); +#elif defined(OS_WIN) + item->file_path = base::FilePath(base::UTF8ToWide(item_proto.file_path())); +#endif + if (item_proto.has_file_size()) { + item->file_size = item_proto.file_size(); + } + if (item_proto.has_creation_time()) { + item->creation_time = + base::Time::FromInternalValue(item_proto.creation_time()); + } + if (item_proto.has_last_access_time()) { + item->last_access_time = + base::Time::FromInternalValue(item_proto.last_access_time()); + } + return true; +} + +void OnLoadDone(const OfflinePageMetadataStore::LoadCallback& callback, + const base::Callback<void()>& failure_callback, + bool success, + scoped_ptr<OfflinePageEntryVector> entries) { + if (!success) { + // TODO(fgorski): Add UMA for this case. + DVLOG(1) << "Offline pages database load failed."; + failure_callback.Run(); + base::MessageLoop::current()->PostTask( + FROM_HERE, base::Bind(callback, false, std::vector<OfflinePageItem>())); + return; + } + + std::vector<OfflinePageItem> result; + for (OfflinePageEntryVector::iterator it = entries->begin(); + it != entries->end(); ++it) { + OfflinePageItem item; + if (OfflinePageItemFromEntry(*it, &item)) + result.push_back(item); + else + DVLOG(1) << "Failed to create offline page item from proto."; + } + + base::MessageLoop::current()->PostTask(FROM_HERE, + base::Bind(callback, true, result)); +} + +void OnUpdateDone(const OfflinePageMetadataStore::UpdateCallback& callback, + const base::Callback<void()>& failure_callback, + bool success) { + if (!success) { + // TODO(fgorski): Add UMA for this case. + DVLOG(1) << "Offline pages database update failed."; + failure_callback.Run(); + } + + base::MessageLoop::current()->PostTask(FROM_HERE, + base::Bind(callback, success)); +} + +} // namespace + +OfflinePageMetadataStoreImpl::OfflinePageMetadataStoreImpl( + scoped_ptr<ProtoDatabase<OfflinePageEntry>> database, + const base::FilePath& database_dir) + : database_(database.Pass()), weak_ptr_factory_(this) { + database_->Init(database_dir, + base::Bind(&OfflinePageMetadataStoreImpl::OnInitDone, + weak_ptr_factory_.GetWeakPtr())); +} + +OfflinePageMetadataStoreImpl::~OfflinePageMetadataStoreImpl() { +} + +void OfflinePageMetadataStoreImpl::OnInitDone(bool success) { + if (!success) { + // TODO(fgorski): Add UMA for this case. + DVLOG(1) << "Offline pages database init failed."; + ResetDB(); + return; + } +} + +void OfflinePageMetadataStoreImpl::Load(const LoadCallback& callback) { + if (!database_.get()) { + // Failing fast here, because DB is not initialized, and there is nothing + // that can be done about it. + // Callback is invoked through message loop to avoid improper retry and + // simplify testing. + DVLOG(1) << "Offline pages database not available in Load."; + base::MessageLoop::current()->PostTask( + FROM_HERE, base::Bind(callback, false, std::vector<OfflinePageItem>())); + return; + } + + database_->LoadEntries(base::Bind( + &OnLoadDone, callback, base::Bind(&OfflinePageMetadataStoreImpl::ResetDB, + weak_ptr_factory_.GetWeakPtr()))); +} + +void OfflinePageMetadataStoreImpl::AddOfflinePage( + const OfflinePageItem& offline_page_item, + const UpdateCallback& callback) { + scoped_ptr<ProtoDatabase<OfflinePageEntry>::KeyEntryVector> entries_to_save( + new ProtoDatabase<OfflinePageEntry>::KeyEntryVector()); + scoped_ptr<std::vector<std::string>> keys_to_remove( + new std::vector<std::string>()); + + OfflinePageEntry offline_page_proto; + OfflinePageItemToEntry(offline_page_item, &offline_page_proto); + entries_to_save->push_back( + std::make_pair(offline_page_proto.url(), offline_page_proto)); + + UpdateEntries(entries_to_save.Pass(), keys_to_remove.Pass(), callback); +} + +void OfflinePageMetadataStoreImpl::RemoveOfflinePage( + const GURL& page_url, + const UpdateCallback& callback) { + scoped_ptr<ProtoDatabase<OfflinePageEntry>::KeyEntryVector> entries_to_save( + new ProtoDatabase<OfflinePageEntry>::KeyEntryVector()); + scoped_ptr<std::vector<std::string>> keys_to_remove( + new std::vector<std::string>()); + + keys_to_remove->push_back(page_url.spec()); + + UpdateEntries(entries_to_save.Pass(), keys_to_remove.Pass(), callback); +} + +void OfflinePageMetadataStoreImpl::UpdateEntries( + scoped_ptr<ProtoDatabase<OfflinePageEntry>::KeyEntryVector> entries_to_save, + scoped_ptr<std::vector<std::string>> keys_to_remove, + const UpdateCallback& callback) { + if (!database_.get()) { + // Failing fast here, because DB is not initialized, and there is nothing + // that can be done about it. + // Callback is invoked through message loop to avoid improper retry and + // simplify testing. + DVLOG(1) << "Offline pages database not available in UpdateEntries."; + base::MessageLoop::current()->PostTask(FROM_HERE, + base::Bind(callback, false)); + return; + } + + database_->UpdateEntries( + entries_to_save.Pass(), keys_to_remove.Pass(), + base::Bind(&OnUpdateDone, callback, + base::Bind(&OfflinePageMetadataStoreImpl::ResetDB, + weak_ptr_factory_.GetWeakPtr()))); +} + +void OfflinePageMetadataStoreImpl::ResetDB() { + database_.reset(); + weak_ptr_factory_.InvalidateWeakPtrs(); +} + +} // namespace offline_pages diff --git a/components/offline_pages/offline_page_metadata_store_impl.h b/components/offline_pages/offline_page_metadata_store_impl.h new file mode 100644 index 0000000..5eb24fd --- /dev/null +++ b/components/offline_pages/offline_page_metadata_store_impl.h @@ -0,0 +1,67 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_OFFLINE_PAGES_OFFLINE_PAGE_METADATA_STORE_IMPL_H_ +#define CHROME_BROWSER_OFFLINE_PAGES_OFFLINE_PAGE_METADATA_STORE_IMPL_H_ + +#include <vector> + +#include "base/memory/ref_counted.h" +#include "base/memory/weak_ptr.h" +#include "components/leveldb_proto/proto_database.h" +#include "components/offline_pages/offline_page_metadata_store.h" + +namespace base { +class FilePath; +} + +namespace offline_pages { + +class OfflinePageEntry; + +// Implements OfflinePageMetadataStore using leveldb_proto::ProtoDatabase +// component. Stores metadata of offline pages as serialized protobufs in a +// LevelDB key/value pairs. +// Underlying implementation guarantees that all of the method calls will be +// executed sequentially, and started operations will finish even after the +// store is already destroyed (callbacks will be called). +class OfflinePageMetadataStoreImpl : public OfflinePageMetadataStore { + public: + OfflinePageMetadataStoreImpl( + scoped_ptr<leveldb_proto::ProtoDatabase<OfflinePageEntry>> database, + const base::FilePath& database_dir); + ~OfflinePageMetadataStoreImpl() override; + + // OfflinePageMetadataStore implementation: + void Load(const LoadCallback& callback) override; + void AddOfflinePage(const OfflinePageItem& offline_page_record, + const UpdateCallback& callback) override; + void RemoveOfflinePage(const GURL& page_url, + const UpdateCallback& callback) override; + + private: + // Callback for when initialization of the |database_| is done. + void OnInitDone(bool success); + + // Implements the update. + void UpdateEntries( + scoped_ptr<leveldb_proto::ProtoDatabase<OfflinePageEntry>::KeyEntryVector> + entries_to_save, + scoped_ptr<std::vector<std::string>> keys_to_remove, + const UpdateCallback& callback); + + // Resets the database. This is to be used when one of the operations fails + // with no good explanation. + void ResetDB(); + + scoped_ptr<leveldb_proto::ProtoDatabase<OfflinePageEntry>> database_; + + base::WeakPtrFactory<OfflinePageMetadataStoreImpl> weak_ptr_factory_; + + DISALLOW_COPY_AND_ASSIGN(OfflinePageMetadataStoreImpl); +}; + +} // namespace offline_pages + +#endif // CHROME_BROWSER_OFFLINE_PAGES_OFFLINE_PAGE_METADATA_STORE_IMPL_H_ diff --git a/components/offline_pages/offline_page_metadata_store_impl_unittest.cc b/components/offline_pages/offline_page_metadata_store_impl_unittest.cc new file mode 100644 index 0000000..7e7685e --- /dev/null +++ b/components/offline_pages/offline_page_metadata_store_impl_unittest.cc @@ -0,0 +1,310 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/offline_pages/offline_page_metadata_store_impl.h" + +#include "base/bind.h" +#include "base/files/file_path.h" +#include "base/files/scoped_temp_dir.h" +#include "base/memory/scoped_ptr.h" +#include "base/message_loop/message_loop.h" +#include "base/run_loop.h" +#include "base/strings/utf_string_conversions.h" +#include "components/leveldb_proto/proto_database_impl.h" +#include "components/offline_pages/offline_page_item.h" +#include "components/offline_pages/proto/offline_pages.pb.h" +#include "testing/gtest/include/gtest/gtest.h" + +using leveldb_proto::ProtoDatabaseImpl; + +namespace offline_pages { + +namespace { + +const char kTestURL[] = "https://example.com"; +const base::string16 kTestTitle = base::ASCIIToUTF16("Example site title"); +const base::FilePath::CharType kFilePath[] = + FILE_PATH_LITERAL("/offline_pages/example_com.mhtml"); +int64 kFileSize = 234567; + +class OfflinePageMetadataStoreImplTest : public testing::Test { + public: + enum CalledCallback { NONE, LOAD, ADD, REMOVE, DESTROY }; + enum Status { STATUS_NONE, STATUS_TRUE, STATUS_FALSE }; + + OfflinePageMetadataStoreImplTest(); + ~OfflinePageMetadataStoreImplTest() override; + + void TearDown() override { message_loop_.RunUntilIdle(); } + + scoped_ptr<OfflinePageMetadataStoreImpl> BuildStore(); + void PumpLoop(); + + void LoadCallback(bool success, + const std::vector<OfflinePageItem>& offline_pages); + void UpdateCallback(CalledCallback called_callback, bool success); + + void ClearResults(); + + protected: + CalledCallback last_called_callback_; + Status last_status_; + std::vector<OfflinePageItem> offline_pages_; + + base::ScopedTempDir temp_directory_; + base::MessageLoop message_loop_; + scoped_ptr<base::RunLoop> run_loop_; +}; + +OfflinePageMetadataStoreImplTest::OfflinePageMetadataStoreImplTest() + : last_called_callback_(NONE), last_status_(STATUS_NONE) { + EXPECT_TRUE(temp_directory_.CreateUniqueTempDir()); +} + +OfflinePageMetadataStoreImplTest::~OfflinePageMetadataStoreImplTest() { +} + +void OfflinePageMetadataStoreImplTest::PumpLoop() { + run_loop_.reset(new base::RunLoop()); + run_loop_->Run(); +} + +scoped_ptr<OfflinePageMetadataStoreImpl> +OfflinePageMetadataStoreImplTest::BuildStore() { + scoped_ptr<ProtoDatabaseImpl<offline_pages::OfflinePageEntry>> db( + new ProtoDatabaseImpl<offline_pages::OfflinePageEntry>( + message_loop_.task_runner())); + return scoped_ptr<OfflinePageMetadataStoreImpl>( + new OfflinePageMetadataStoreImpl(db.Pass(), temp_directory_.path())); +} + +void OfflinePageMetadataStoreImplTest::LoadCallback( + bool status, + const std::vector<OfflinePageItem>& offline_pages) { + last_called_callback_ = LOAD; + last_status_ = status ? STATUS_TRUE : STATUS_FALSE; + offline_pages_.swap(const_cast<std::vector<OfflinePageItem>&>(offline_pages)); + run_loop_->Quit(); +} + +void OfflinePageMetadataStoreImplTest::UpdateCallback( + CalledCallback called_callback, + bool status) { + last_called_callback_ = called_callback; + last_status_ = status ? STATUS_TRUE : STATUS_FALSE; + run_loop_->Quit(); +} + +void OfflinePageMetadataStoreImplTest::ClearResults() { + last_called_callback_ = NONE; + last_status_ = STATUS_NONE; + offline_pages_.clear(); +} + +// Loads empty store and makes sure that there are no offline pages stored in +// it. +TEST_F(OfflinePageMetadataStoreImplTest, LoadEmptyStore) { + scoped_ptr<OfflinePageMetadataStoreImpl> store(BuildStore()); + store->Load(base::Bind(&OfflinePageMetadataStoreImplTest::LoadCallback, + base::Unretained(this))); + PumpLoop(); + + EXPECT_EQ(LOAD, last_called_callback_); + EXPECT_EQ(STATUS_TRUE, last_status_); + EXPECT_EQ(0U, offline_pages_.size()); +} + +// Adds metadata of an offline page into a store and then loads from the +// store to make sure the metadata is preserved. +TEST_F(OfflinePageMetadataStoreImplTest, AddOfflinePageThenLoad) { + scoped_ptr<OfflinePageMetadataStoreImpl> store(BuildStore()); + + OfflinePageItem offline_page(GURL(kTestURL), kTestTitle, + base::FilePath(kFilePath), kFileSize); + store->AddOfflinePage( + offline_page, + base::Bind(&OfflinePageMetadataStoreImplTest::UpdateCallback, + base::Unretained(this), ADD)); + PumpLoop(); + EXPECT_EQ(ADD, last_called_callback_); + EXPECT_EQ(STATUS_TRUE, last_status_); + + ClearResults(); + store->Load(base::Bind(&OfflinePageMetadataStoreImplTest::LoadCallback, + base::Unretained(this))); + PumpLoop(); + + EXPECT_EQ(LOAD, last_called_callback_); + EXPECT_EQ(STATUS_TRUE, last_status_); + EXPECT_EQ(1U, offline_pages_.size()); + EXPECT_EQ(offline_page.url, offline_pages_[0].url); + EXPECT_EQ(offline_page.title, offline_pages_[0].title); + EXPECT_EQ(offline_page.version, offline_pages_[0].version); + EXPECT_EQ(offline_page.file_path, offline_pages_[0].file_path); + EXPECT_EQ(offline_page.file_size, offline_pages_[0].file_size); + EXPECT_EQ(offline_page.creation_time, offline_pages_[0].creation_time); + EXPECT_EQ(offline_page.last_access_time, offline_pages_[0].last_access_time); +} + +// Adds metadata of an offline page into a store and then opens the store +// again to make sure that stored metadata survives store restarts. +TEST_F(OfflinePageMetadataStoreImplTest, AddOfflinePageRestartLoad) { + scoped_ptr<OfflinePageMetadataStoreImpl> store(BuildStore()); + + OfflinePageItem offline_page(GURL(kTestURL), kTestTitle, + base::FilePath(kFilePath), kFileSize); + store->AddOfflinePage( + offline_page, + base::Bind(&OfflinePageMetadataStoreImplTest::UpdateCallback, + base::Unretained(this), ADD)); + PumpLoop(); + EXPECT_EQ(ADD, last_called_callback_); + EXPECT_EQ(STATUS_TRUE, last_status_); + + // Reset the store first to ensure file lock is removed. + store.reset(); + store = BuildStore().Pass(); + ClearResults(); + store->Load(base::Bind(&OfflinePageMetadataStoreImplTest::LoadCallback, + base::Unretained(this))); + PumpLoop(); + + EXPECT_EQ(LOAD, last_called_callback_); + EXPECT_EQ(STATUS_TRUE, last_status_); + EXPECT_EQ(1U, offline_pages_.size()); + EXPECT_EQ(offline_page.url, offline_pages_[0].url); + EXPECT_EQ(offline_page.title, offline_pages_[0].title); + EXPECT_EQ(offline_page.version, offline_pages_[0].version); + EXPECT_EQ(offline_page.file_path, offline_pages_[0].file_path); + EXPECT_EQ(offline_page.file_size, offline_pages_[0].file_size); + EXPECT_EQ(offline_page.creation_time, offline_pages_[0].creation_time); + EXPECT_EQ(offline_page.last_access_time, offline_pages_[0].last_access_time); +} + +// Tests removing offline page metadata from the store, for which it first adds +// metadata of an offline page. +TEST_F(OfflinePageMetadataStoreImplTest, RemoveOfflinePage) { + scoped_ptr<OfflinePageMetadataStoreImpl> store(BuildStore()); + + OfflinePageItem offline_page(GURL(kTestURL), kTestTitle, + base::FilePath(kFilePath), kFileSize); + store->AddOfflinePage( + offline_page, + base::Bind(&OfflinePageMetadataStoreImplTest::UpdateCallback, + base::Unretained(this), ADD)); + store->Load(base::Bind(&OfflinePageMetadataStoreImplTest::LoadCallback, + base::Unretained(this))); + store->RemoveOfflinePage( + offline_page.url, + base::Bind(&OfflinePageMetadataStoreImplTest::UpdateCallback, + base::Unretained(this), REMOVE)); + store->Load(base::Bind(&OfflinePageMetadataStoreImplTest::LoadCallback, + base::Unretained(this))); + store.reset(); + store = BuildStore().Pass(); + store->Load(base::Bind(&OfflinePageMetadataStoreImplTest::LoadCallback, + base::Unretained(this))); + // Add offline page is exectued: + PumpLoop(); + EXPECT_EQ(ADD, last_called_callback_); + EXPECT_EQ(STATUS_TRUE, last_status_); + + // Load is exectued: + ClearResults(); + PumpLoop(); + + EXPECT_EQ(LOAD, last_called_callback_); + EXPECT_EQ(STATUS_TRUE, last_status_); + EXPECT_EQ(1U, offline_pages_.size()); + + // Remove offline page is exectued: + ClearResults(); + PumpLoop(); + EXPECT_EQ(REMOVE, last_called_callback_); + EXPECT_EQ(STATUS_TRUE, last_status_); + + // Load is exectued: + ClearResults(); + PumpLoop(); + + EXPECT_EQ(LOAD, last_called_callback_); + EXPECT_EQ(STATUS_TRUE, last_status_); + EXPECT_EQ(0U, offline_pages_.size()); + + // Checking the value after reseting the store. + ClearResults(); + PumpLoop(); + EXPECT_EQ(LOAD, last_called_callback_); + EXPECT_EQ(STATUS_TRUE, last_status_); + EXPECT_EQ(0U, offline_pages_.size()); +} + +// Adds metadata of multiple offline pages into a store and removes some. +TEST_F(OfflinePageMetadataStoreImplTest, AddRemoveMultipleOfflinePages) { + scoped_ptr<OfflinePageMetadataStoreImpl> store(BuildStore()); + + OfflinePageItem offline_page_1(GURL(kTestURL), kTestTitle, + base::FilePath(kFilePath), kFileSize); + base::FilePath file_path_2 = + base::FilePath(FILE_PATH_LITERAL("//other.page.com.mhtml")); + OfflinePageItem offline_page_2(GURL("https://other.page.com"), + base::ASCIIToUTF16("Other page"), + file_path_2, 12345, base::Time::Now()); + store->AddOfflinePage( + offline_page_1, + base::Bind(&OfflinePageMetadataStoreImplTest::UpdateCallback, + base::Unretained(this), ADD)); + PumpLoop(); + EXPECT_EQ(ADD, last_called_callback_); + EXPECT_EQ(STATUS_TRUE, last_status_); + + ClearResults(); + store->AddOfflinePage( + offline_page_2, + base::Bind(&OfflinePageMetadataStoreImplTest::UpdateCallback, + base::Unretained(this), ADD)); + PumpLoop(); + EXPECT_EQ(ADD, last_called_callback_); + EXPECT_EQ(STATUS_TRUE, last_status_); + + ClearResults(); + store->Load(base::Bind(&OfflinePageMetadataStoreImplTest::LoadCallback, + base::Unretained(this))); + PumpLoop(); + + EXPECT_EQ(LOAD, last_called_callback_); + EXPECT_EQ(STATUS_TRUE, last_status_); + EXPECT_EQ(2U, offline_pages_.size()); + + store->RemoveOfflinePage( + offline_page_1.url, + base::Bind(&OfflinePageMetadataStoreImplTest::UpdateCallback, + base::Unretained(this), REMOVE)); + PumpLoop(); + EXPECT_EQ(REMOVE, last_called_callback_); + EXPECT_EQ(STATUS_TRUE, last_status_); + + ClearResults(); + store.reset(); + store = BuildStore().Pass(); + store->Load(base::Bind(&OfflinePageMetadataStoreImplTest::LoadCallback, + base::Unretained(this))); + PumpLoop(); + + EXPECT_EQ(LOAD, last_called_callback_); + EXPECT_EQ(STATUS_TRUE, last_status_); + EXPECT_EQ(1U, offline_pages_.size()); + EXPECT_EQ(offline_page_2.url, offline_pages_[0].url); + EXPECT_EQ(offline_page_2.title, offline_pages_[0].title); + EXPECT_EQ(offline_page_2.version, offline_pages_[0].version); + EXPECT_EQ(offline_page_2.file_path, offline_pages_[0].file_path); + EXPECT_EQ(offline_page_2.file_size, offline_pages_[0].file_size); + EXPECT_EQ(offline_page_2.creation_time, offline_pages_[0].creation_time); + EXPECT_EQ(offline_page_2.last_access_time, + offline_pages_[0].last_access_time); +} + +} // namespace + +} // namespace offline_pages diff --git a/components/offline_pages/proto/BUILD.gn b/components/offline_pages/proto/BUILD.gn new file mode 100644 index 0000000..7cfb1a6 --- /dev/null +++ b/components/offline_pages/proto/BUILD.gn @@ -0,0 +1,12 @@ +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import("//third_party/protobuf/proto_library.gni") + +# GYP version: components/offline_pages.gypi:offline_pages_proto +proto_library("offline_pages_proto") { + sources = [ + "offline_pages.proto", + ] +} diff --git a/components/offline_pages/proto/offline_pages.proto b/components/offline_pages/proto/offline_pages.proto new file mode 100644 index 0000000..16f23b1 --- /dev/null +++ b/components/offline_pages/proto/offline_pages.proto @@ -0,0 +1,36 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// Offline page item protocol for storage and exchanging of offline page +// metadata. + +syntax = "proto2"; + +option optimize_for = LITE_RUNTIME; +option retain_unknown_fields = true; + +package offline_pages; + +message OfflinePageEntry { + // URL of the offline page. + required string url = 1; + + // Title of the offline page. + required string title = 2; + + // Version of the offline page metadata. + required int32 version = 3; + + // Path to the offline archive. + required string file_path = 4; + + // Size of the offline archive. + optional int64 file_size = 5; + + // Creation time of the offline archive. + optional int64 creation_time = 6; + + // Last access time of the offline archive. + optional int64 last_access_time = 7; +} |