Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(291)

Unified Diff: components/offline_pages/offline_page_metadata_store_impl_unittest.cc

Issue 2019333008: [Offline Pages] Fix crash due to table inconsistency. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: comments from jianli@ Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « components/offline_pages/BUILD.gn ('k') | components/offline_pages/offline_page_metadata_store_sql.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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..6684482ef4af960fc77f467b191cc083ab6bb823 100644
--- a/components/offline_pages/offline_page_metadata_store_impl_unittest.cc
+++ b/components/offline_pages/offline_page_metadata_store_impl_unittest.cc
@@ -18,23 +18,76 @@
#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"
+
const char kTestClientNamespace[] = "CLIENT_NAMESPACE";
const char kTestURL[] = "https://example.com";
const ClientId kTestClientId1(kTestClientNamespace, "1234");
const ClientId kTestClientId2(kTestClientNamespace, "5678");
const base::FilePath::CharType kFilePath[] =
FILE_PATH_LITERAL("/offline_pages/example_com.mhtml");
-int64_t kFileSize = 234567;
+int64_t kFileSize = 234567LL;
+int64_t kOfflineId = 12345LL;
+
+// Build a store with outdated schema to simulate the upgrading process.
+// TODO(romax): move it to sql_unittests.
+void BuildTestStoreWithOutdatedSchema(const base::FilePath& file) {
+ 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, kTestClientId2.id);
+ statement.BindCString(8, kTestURL);
+ statement.BindString(9, base::FilePath(kFilePath).MaybeAsASCII());
+ 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 +98,13 @@ class OfflinePageMetadataStoreSQLFactory
base::ThreadTaskRunnerHandle::Get(), file);
return store;
}
+
+ OfflinePageMetadataStore* BuildStoreV1(const base::FilePath& file) override {
+ BuildTestStoreWithOutdatedSchema(file);
+ OfflinePageMetadataStoreSQL* store = new OfflinePageMetadataStoreSQL(
+ base::ThreadTaskRunnerHandle::Get(), file);
+ return store;
+ }
};
enum CalledCallback { NONE, LOAD, ADD, REMOVE, DESTROY };
@@ -119,6 +179,8 @@ template <typename T>
class OfflinePageMetadataStoreTest : public OfflinePageMetadataStoreTestBase {
public:
std::unique_ptr<OfflinePageMetadataStore> BuildStore();
+ std::unique_ptr<OfflinePageMetadataStore>
+ BuildStoreWithUpgradeFromOutdatedSchema();
protected:
T factory_;
@@ -135,6 +197,17 @@ OfflinePageMetadataStoreTest<T>::BuildStore() {
return store;
}
+template <typename T>
+std::unique_ptr<OfflinePageMetadataStore>
+OfflinePageMetadataStoreTest<T>::BuildStoreWithUpgradeFromOutdatedSchema() {
+ 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 +220,53 @@ 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->BuildStoreWithUpgradeFromOutdatedSchema());
+ 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);
+ base::Time expiration_time = base::Time::Now();
+ offline_page.expiration_time = expiration_time;
+ store->AddOrUpdateOfflinePage(
+ 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_);
+ ASSERT_EQ(2U, this->offline_pages_.size());
+ if (this->offline_pages_[0].offline_id != offline_page.offline_id) {
+ std::swap(this->offline_pages_[0], this->offline_pages_[1]);
+ }
+ EXPECT_EQ(offline_page.url, this->offline_pages_[0].url);
+ EXPECT_EQ(offline_page.offline_id, this->offline_pages_[0].offline_id);
+ EXPECT_EQ(offline_page.file_path, this->offline_pages_[0].file_path);
+ EXPECT_EQ(offline_page.last_access_time,
+ this->offline_pages_[0].last_access_time);
+ EXPECT_EQ(offline_page.expiration_time,
+ this->offline_pages_[0].expiration_time);
+ EXPECT_EQ(offline_page.client_id, this->offline_pages_[0].client_id);
+ EXPECT_EQ(kOfflineId, this->offline_pages_[1].offline_id);
+ EXPECT_EQ(kFileSize, this->offline_pages_[1].file_size);
+ EXPECT_EQ(kTestClientId2, this->offline_pages_[1].client_id);
+}
+
// 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) {
@@ -170,7 +290,7 @@ TYPED_TEST(OfflinePageMetadataStoreTest, AddOfflinePage) {
EXPECT_EQ(LOAD, this->last_called_callback_);
EXPECT_EQ(STATUS_TRUE, this->last_status_);
- EXPECT_EQ(1U, this->offline_pages_.size());
+ ASSERT_EQ(1U, this->offline_pages_.size());
EXPECT_EQ(offline_page.url, this->offline_pages_[0].url);
EXPECT_EQ(offline_page.offline_id, this->offline_pages_[0].offline_id);
EXPECT_EQ(offline_page.version, this->offline_pages_[0].version);
@@ -305,7 +425,7 @@ TYPED_TEST(OfflinePageMetadataStoreTest, AddRemoveMultipleOfflinePages) {
EXPECT_EQ(LOAD, this->last_called_callback_);
EXPECT_EQ(STATUS_TRUE, this->last_status_);
- EXPECT_EQ(1U, this->offline_pages_.size());
+ ASSERT_EQ(1U, this->offline_pages_.size());
EXPECT_EQ(offline_page_2.url, this->offline_pages_[0].url);
EXPECT_EQ(offline_page_2.offline_id, this->offline_pages_[0].offline_id);
EXPECT_EQ(offline_page_2.version, this->offline_pages_[0].version);
@@ -343,7 +463,7 @@ TYPED_TEST(OfflinePageMetadataStoreTest, UpdateOfflinePage) {
EXPECT_EQ(LOAD, this->last_called_callback_);
EXPECT_EQ(STATUS_TRUE, this->last_status_);
- EXPECT_EQ(1U, this->offline_pages_.size());
+ ASSERT_EQ(1U, this->offline_pages_.size());
EXPECT_EQ(offline_page.url, this->offline_pages_[0].url);
EXPECT_EQ(offline_page.offline_id, this->offline_pages_[0].offline_id);
EXPECT_EQ(offline_page.version, this->offline_pages_[0].version);
@@ -376,7 +496,7 @@ TYPED_TEST(OfflinePageMetadataStoreTest, UpdateOfflinePage) {
EXPECT_EQ(LOAD, this->last_called_callback_);
EXPECT_EQ(STATUS_TRUE, this->last_status_);
- EXPECT_EQ(1U, this->offline_pages_.size());
+ ASSERT_EQ(1U, this->offline_pages_.size());
EXPECT_EQ(offline_page.url, this->offline_pages_[0].url);
EXPECT_EQ(offline_page.offline_id, this->offline_pages_[0].offline_id);
EXPECT_EQ(offline_page.version, this->offline_pages_[0].version);
« no previous file with comments | « components/offline_pages/BUILD.gn ('k') | components/offline_pages/offline_page_metadata_store_sql.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698