Chromium Code Reviews| Index: components/offline_pages/offline_page_metadata_store_impl_unittest.cc |
| diff --git a/components/offline_pages/offline_page_metadata_store_impl_unittest.cc b/components/offline_pages/offline_page_metadata_store_impl_unittest.cc |
| index 2ed53a23477395f3b7bbe4c459249fde93e00c2d..6cb3cb9f0a8f6526dd4a806c13173523ad1c08e3 100644 |
| --- a/components/offline_pages/offline_page_metadata_store_impl_unittest.cc |
| +++ b/components/offline_pages/offline_page_metadata_store_impl_unittest.cc |
| @@ -18,12 +18,16 @@ |
| #include "components/offline_pages/offline_page_item.h" |
| #include "components/offline_pages/offline_page_metadata_store_sql.h" |
| #include "components/offline_pages/offline_page_model.h" |
| +#include "sql/connection.h" |
| +#include "sql/statement.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| namespace offline_pages { |
| namespace { |
| +#define OFFLINE_PAGES_TABLE_V1 "offlinepages_v1" |
|
fgorski
2016/06/03 20:04:17
wow. I didn't realize we are versioning the table
jianli
2016/06/03 21:12:18
We can certainly do this, but using define in our
romax
2016/06/03 23:11:39
yes they'll be in a near future plan.
|
| + |
| const char kTestClientNamespace[] = "CLIENT_NAMESPACE"; |
| const char kTestURL[] = "https://example.com"; |
| const ClientId kTestClientId1(kTestClientNamespace, "1234"); |
| @@ -31,10 +35,67 @@ const ClientId kTestClientId2(kTestClientNamespace, "5678"); |
| const base::FilePath::CharType kFilePath[] = |
| FILE_PATH_LITERAL("/offline_pages/example_com.mhtml"); |
| int64_t kFileSize = 234567; |
| +int64_t kOfflineId = 12345; |
| + |
| +// Build a store with outdated schema to simulate the upgrading process. |
| +// TODO(romax): move it to sql_unittests. |
| +void BuildTestStoreV1(const base::FilePath& file) { |
|
jianli
2016/06/03 21:12:18
BuildTestStoreV1 => BuildTestStoreWithOutdatedSche
romax
2016/06/03 23:11:39
Done.
|
| + sql::Connection connection; |
| + ASSERT_TRUE( |
| + connection.Open(file.Append(FILE_PATH_LITERAL("OfflinePages.db")))); |
| + ASSERT_TRUE(connection.is_open()); |
| + ASSERT_TRUE(connection.BeginTransaction()); |
| + ASSERT_TRUE(connection.Execute("CREATE TABLE " OFFLINE_PAGES_TABLE_V1 |
| + "(offline_id INTEGER PRIMARY KEY NOT NULL, " |
| + "creation_time INTEGER NOT NULL, " |
| + "file_size INTEGER NOT NULL, " |
| + "version INTEGER NOT NULL, " |
| + "last_access_time INTEGER NOT NULL, " |
| + "access_count INTEGER NOT NULL, " |
| + "status INTEGER NOT NULL DEFAULT 0, " |
| + "user_initiated INTEGER, " |
| + "client_namespace VARCHAR NOT NULL, " |
| + "client_id VARCHAR NOT NULL, " |
| + "online_url VARCHAR NOT NULL, " |
| + "offline_url VARCHAR NOT NULL DEFAULT '', " |
| + "file_path VARCHAR NOT NULL " |
| + ")")); |
| + ASSERT_TRUE(connection.CommitTransaction()); |
| + sql::Statement statement(connection.GetUniqueStatement( |
| + "INSERT INTO " OFFLINE_PAGES_TABLE_V1 |
| + "(offline_id, creation_time, file_size, version, " |
| + "last_access_time, access_count, client_namespace, " |
| + "client_id, online_url, file_path) " |
| + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)")); |
| + statement.BindInt64(0, kOfflineId); |
| + statement.BindInt(1, 0); |
| + statement.BindInt64(2, kFileSize); |
| + statement.BindInt(3, 0); |
| + statement.BindInt(4, 0); |
| + statement.BindInt(5, 1); |
| + statement.BindCString(6, kTestClientNamespace); |
| + statement.BindString(7, kTestClientId1.id); |
| + statement.BindCString(8, kTestURL); |
| + base::FilePath path = base::FilePath(kFilePath); |
| +#if defined(OS_POSIX) |
| + std::string path_string = path.value(); |
| +#elif defined(OS_WIN) |
| + std::string path_string = base::WideToUTF8(path.value()); |
| +#else |
| +#error Unknown OS |
| +#endif |
| + statement.BindString(9, path_string); |
|
jianli
2016/06/03 21:12:18
Doing "statement.BindString(9, kFilePath.MaybeAsAS
romax
2016/06/03 23:11:39
Done.
|
| + ASSERT_TRUE(statement.Run()); |
| + ASSERT_TRUE(connection.DoesTableExist(OFFLINE_PAGES_TABLE_V1)); |
| + ASSERT_FALSE( |
| + connection.DoesColumnExist(OFFLINE_PAGES_TABLE_V1, "expiration_time")); |
| +} |
| class OfflinePageMetadataStoreFactory { |
| public: |
| virtual OfflinePageMetadataStore* BuildStore(const base::FilePath& file) = 0; |
| + virtual OfflinePageMetadataStore* BuildStoreV1( |
| + const base::FilePath& file) = 0; |
| }; |
| class OfflinePageMetadataStoreSQLFactory |
| @@ -45,6 +106,13 @@ class OfflinePageMetadataStoreSQLFactory |
| base::ThreadTaskRunnerHandle::Get(), file); |
| return store; |
| } |
| + |
| + OfflinePageMetadataStore* BuildStoreV1(const base::FilePath& file) override { |
| + BuildTestStoreV1(file); |
| + OfflinePageMetadataStoreSQL* store = new OfflinePageMetadataStoreSQL( |
| + base::ThreadTaskRunnerHandle::Get(), file); |
| + return store; |
| + } |
| }; |
| enum CalledCallback { NONE, LOAD, ADD, REMOVE, DESTROY }; |
| @@ -119,6 +187,7 @@ template <typename T> |
| class OfflinePageMetadataStoreTest : public OfflinePageMetadataStoreTestBase { |
| public: |
| std::unique_ptr<OfflinePageMetadataStore> BuildStore(); |
| + std::unique_ptr<OfflinePageMetadataStore> BuildStoreV1WithUpgrade(); |
|
jianli
2016/06/03 21:12:18
BuildStoreV1WithUpgrade => BuildStoreWithUpgradeFr
romax
2016/06/03 23:11:39
Done.
|
| protected: |
| T factory_; |
| @@ -135,6 +204,17 @@ OfflinePageMetadataStoreTest<T>::BuildStore() { |
| return store; |
| } |
| +template <typename T> |
| +std::unique_ptr<OfflinePageMetadataStore> |
| +OfflinePageMetadataStoreTest<T>::BuildStoreV1WithUpgrade() { |
| + std::unique_ptr<OfflinePageMetadataStore> store( |
| + factory_.BuildStoreV1(temp_directory_.path())); |
| + store->Load(base::Bind(&OfflinePageMetadataStoreTestBase::LoadCallback, |
| + base::Unretained(this))); |
| + PumpLoop(); |
| + return store; |
| +} |
| + |
| typedef testing::Types<OfflinePageMetadataStoreSQLFactory> MyTypes; |
| TYPED_TEST_CASE(OfflinePageMetadataStoreTest, MyTypes); |
| @@ -147,6 +227,37 @@ TYPED_TEST(OfflinePageMetadataStoreTest, LoadEmptyStore) { |
| EXPECT_EQ(0U, this->offline_pages_.size()); |
| } |
| +// Loads a store which has an outdated schema. |
| +// This test case would crash if it's not handling correctly when we're loading |
| +// old version stores. |
| +// TODO(romax): Move this to sql_unittest. |
| +TYPED_TEST(OfflinePageMetadataStoreTest, LoadPreviousVersionStore) { |
| + std::unique_ptr<OfflinePageMetadataStore> store( |
| + this->BuildStoreV1WithUpgrade()); |
| + EXPECT_EQ(LOAD, this->last_called_callback_); |
| + EXPECT_EQ(STATUS_TRUE, this->last_status_); |
| + EXPECT_EQ(1U, this->offline_pages_.size()); |
| + OfflinePageItem offline_page(GURL(kTestURL), 1234LL, kTestClientId1, |
| + base::FilePath(kFilePath), kFileSize); |
| + store->AddOrUpdateOfflinePage( |
|
jianli
2016/06/03 21:12:18
Please also set expiration_time before calling Add
romax
2016/06/03 23:11:39
Done.
|
| + offline_page, |
| + base::Bind(&OfflinePageMetadataStoreTestBase::UpdateCallback, |
| + base::Unretained(this), ADD)); |
| + this->PumpLoop(); |
| + EXPECT_EQ(ADD, this->last_called_callback_); |
| + EXPECT_EQ(STATUS_TRUE, this->last_status_); |
| + this->ClearResults(); |
| + |
| + // Close the store first to ensure file lock is removed. |
| + store.reset(); |
| + store = this->BuildStore(); |
| + this->PumpLoop(); |
| + |
| + EXPECT_EQ(LOAD, this->last_called_callback_); |
| + EXPECT_EQ(STATUS_TRUE, this->last_status_); |
| + EXPECT_EQ(2U, this->offline_pages_.size()); |
|
jianli
2016/06/03 21:12:18
Change to use ASSERT_EQ.
Please also add some bas
romax
2016/06/03 23:11:39
Done.
|
| +} |
| + |
| // Adds metadata of an offline page into a store and then opens the store |
| // again to make sure that stored metadata survives store restarts. |
| TYPED_TEST(OfflinePageMetadataStoreTest, AddOfflinePage) { |