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

Side by Side 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: fix win build 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 unified diff | Download patch
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "components/offline_pages/offline_page_metadata_store.h" 5 #include "components/offline_pages/offline_page_metadata_store.h"
6 6
7 #include <stdint.h> 7 #include <stdint.h>
8 8
9 #include <memory> 9 #include <memory>
10 10
11 #include "base/bind.h" 11 #include "base/bind.h"
12 #include "base/files/file_path.h" 12 #include "base/files/file_path.h"
13 #include "base/files/scoped_temp_dir.h" 13 #include "base/files/scoped_temp_dir.h"
14 #include "base/strings/string_number_conversions.h" 14 #include "base/strings/string_number_conversions.h"
15 #include "base/strings/utf_string_conversions.h" 15 #include "base/strings/utf_string_conversions.h"
16 #include "base/test/test_simple_task_runner.h" 16 #include "base/test/test_simple_task_runner.h"
17 #include "base/threading/thread_task_runner_handle.h" 17 #include "base/threading/thread_task_runner_handle.h"
18 #include "components/offline_pages/offline_page_item.h" 18 #include "components/offline_pages/offline_page_item.h"
19 #include "components/offline_pages/offline_page_metadata_store_sql.h" 19 #include "components/offline_pages/offline_page_metadata_store_sql.h"
20 #include "components/offline_pages/offline_page_model.h" 20 #include "components/offline_pages/offline_page_model.h"
21 #include "sql/connection.h"
21 #include "testing/gtest/include/gtest/gtest.h" 22 #include "testing/gtest/include/gtest/gtest.h"
22 23
23 namespace offline_pages { 24 namespace offline_pages {
24 25
25 namespace { 26 namespace {
26 27
28 #define OFFLINE_PAGES_TABLE_NAME "offlinepages_v1"
29
27 const char kTestClientNamespace[] = "CLIENT_NAMESPACE"; 30 const char kTestClientNamespace[] = "CLIENT_NAMESPACE";
28 const char kTestURL[] = "https://example.com"; 31 const char kTestURL[] = "https://example.com";
29 const ClientId kTestClientId1(kTestClientNamespace, "1234"); 32 const ClientId kTestClientId1(kTestClientNamespace, "1234");
30 const ClientId kTestClientId2(kTestClientNamespace, "5678"); 33 const ClientId kTestClientId2(kTestClientNamespace, "5678");
31 const base::FilePath::CharType kFilePath[] = 34 const base::FilePath::CharType kFilePath[] =
32 FILE_PATH_LITERAL("/offline_pages/example_com.mhtml"); 35 FILE_PATH_LITERAL("/offline_pages/example_com.mhtml");
33 int64_t kFileSize = 234567; 36 int64_t kFileSize = 234567;
34 37
38 // Build a store with outdated schema to simulate the upgrading process.
39 // TODO(romax): move it to sql_unittests.
fgorski 2016/06/03 18:17:16 good point. Another test that we should include i
romax 2016/06/03 19:36:22 i've combined this case with the newly added test.
40 void BuildBadTable(const base::FilePath& file) {
fgorski 2016/06/03 18:17:16 How about BuildStoreV1 (and then look at the comme
romax 2016/06/03 19:36:22 Done.
41 sql::Connection connection;
42 ASSERT_TRUE(
43 connection.Open(file.Append(FILE_PATH_LITERAL("OfflinePages.db"))));
44 ASSERT_TRUE(connection.is_open());
45 ASSERT_TRUE(connection.BeginTransaction());
46 ASSERT_TRUE(connection.Execute("CREATE TABLE " OFFLINE_PAGES_TABLE_NAME
47 "(offline_id INTEGER PRIMARY KEY NOT NULL,"
48 " creation_time INTEGER NOT NULL,"
49 " file_size INTEGER NOT NULL,"
50 " version INTEGER NOT NULL,"
51 " last_access_time INTEGER NOT NULL,"
52 " access_count INTEGER NOT NULL,"
53 " status INTEGER NOT NULL DEFAULT 0,"
54 " user_initiated INTEGER,"
55 " client_namespace VARCHAR NOT NULL,"
56 " client_id VARCHAR NOT NULL,"
57 " online_url VARCHAR NOT NULL,"
58 " offline_url VARCHAR NOT NULL DEFAULT '',"
59 " file_path VARCHAR NOT NULL"
60 ")"));
61 ASSERT_TRUE(connection.CommitTransaction());
62 ASSERT_TRUE(connection.DoesTableExist(OFFLINE_PAGES_TABLE_NAME));
63 ASSERT_FALSE(
64 connection.DoesColumnExist(OFFLINE_PAGES_TABLE_NAME, "expiration_time"));
65 }
66
35 class OfflinePageMetadataStoreFactory { 67 class OfflinePageMetadataStoreFactory {
36 public: 68 public:
37 virtual OfflinePageMetadataStore* BuildStore(const base::FilePath& file) = 0; 69 virtual OfflinePageMetadataStore* BuildStore(const base::FilePath& file) = 0;
70 virtual OfflinePageMetadataStore* BuildBadStore(
fgorski 2016/06/03 18:17:16 Can we call it: BuildV1Store() or something indica
romax 2016/06/03 19:36:22 Done.
71 const base::FilePath& file) = 0;
38 }; 72 };
39 73
40 class OfflinePageMetadataStoreSQLFactory 74 class OfflinePageMetadataStoreSQLFactory
41 : public OfflinePageMetadataStoreFactory { 75 : public OfflinePageMetadataStoreFactory {
42 public: 76 public:
43 OfflinePageMetadataStore* BuildStore(const base::FilePath& file) override { 77 OfflinePageMetadataStore* BuildStore(const base::FilePath& file) override {
44 OfflinePageMetadataStoreSQL* store = new OfflinePageMetadataStoreSQL( 78 OfflinePageMetadataStoreSQL* store = new OfflinePageMetadataStoreSQL(
45 base::ThreadTaskRunnerHandle::Get(), file); 79 base::ThreadTaskRunnerHandle::Get(), file);
46 return store; 80 return store;
47 } 81 }
82
83 OfflinePageMetadataStore* BuildBadStore(const base::FilePath& file) override {
84 BuildBadTable(file);
85 OfflinePageMetadataStoreSQL* store = new OfflinePageMetadataStoreSQL(
86 base::ThreadTaskRunnerHandle::Get(), file);
87 return store;
88 }
48 }; 89 };
49 90
50 enum CalledCallback { NONE, LOAD, ADD, REMOVE, DESTROY }; 91 enum CalledCallback { NONE, LOAD, ADD, REMOVE, DESTROY };
51 enum Status { STATUS_NONE, STATUS_TRUE, STATUS_FALSE }; 92 enum Status { STATUS_NONE, STATUS_TRUE, STATUS_FALSE };
52 93
53 class OfflinePageMetadataStoreTestBase : public testing::Test { 94 class OfflinePageMetadataStoreTestBase : public testing::Test {
54 public: 95 public:
55 OfflinePageMetadataStoreTestBase(); 96 OfflinePageMetadataStoreTestBase();
56 ~OfflinePageMetadataStoreTestBase() override; 97 ~OfflinePageMetadataStoreTestBase() override;
57 98
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
112 void OfflinePageMetadataStoreTestBase::ClearResults() { 153 void OfflinePageMetadataStoreTestBase::ClearResults() {
113 last_called_callback_ = NONE; 154 last_called_callback_ = NONE;
114 last_status_ = STATUS_NONE; 155 last_status_ = STATUS_NONE;
115 offline_pages_.clear(); 156 offline_pages_.clear();
116 } 157 }
117 158
118 template <typename T> 159 template <typename T>
119 class OfflinePageMetadataStoreTest : public OfflinePageMetadataStoreTestBase { 160 class OfflinePageMetadataStoreTest : public OfflinePageMetadataStoreTestBase {
120 public: 161 public:
121 std::unique_ptr<OfflinePageMetadataStore> BuildStore(); 162 std::unique_ptr<OfflinePageMetadataStore> BuildStore();
163 std::unique_ptr<OfflinePageMetadataStore> BuildBadStore();
122 164
123 protected: 165 protected:
124 T factory_; 166 T factory_;
125 }; 167 };
126 168
127 template <typename T> 169 template <typename T>
128 std::unique_ptr<OfflinePageMetadataStore> 170 std::unique_ptr<OfflinePageMetadataStore>
129 OfflinePageMetadataStoreTest<T>::BuildStore() { 171 OfflinePageMetadataStoreTest<T>::BuildStore() {
130 std::unique_ptr<OfflinePageMetadataStore> store( 172 std::unique_ptr<OfflinePageMetadataStore> store(
131 factory_.BuildStore(temp_directory_.path())); 173 factory_.BuildStore(temp_directory_.path()));
132 store->Load(base::Bind(&OfflinePageMetadataStoreTestBase::LoadCallback, 174 store->Load(base::Bind(&OfflinePageMetadataStoreTestBase::LoadCallback,
133 base::Unretained(this))); 175 base::Unretained(this)));
134 PumpLoop(); 176 PumpLoop();
135 return store; 177 return store;
136 } 178 }
137 179
180 template <typename T>
181 std::unique_ptr<OfflinePageMetadataStore>
182 OfflinePageMetadataStoreTest<T>::BuildBadStore() {
183 std::unique_ptr<OfflinePageMetadataStore> store(
184 factory_.BuildBadStore(temp_directory_.path()));
185 store->Load(base::Bind(&OfflinePageMetadataStoreTestBase::LoadCallback,
186 base::Unretained(this)));
187 PumpLoop();
188 return store;
189 }
190
138 typedef testing::Types<OfflinePageMetadataStoreSQLFactory> MyTypes; 191 typedef testing::Types<OfflinePageMetadataStoreSQLFactory> MyTypes;
139 TYPED_TEST_CASE(OfflinePageMetadataStoreTest, MyTypes); 192 TYPED_TEST_CASE(OfflinePageMetadataStoreTest, MyTypes);
140 193
141 // Loads empty store and makes sure that there are no offline pages stored in 194 // Loads empty store and makes sure that there are no offline pages stored in
142 // it. 195 // it.
143 TYPED_TEST(OfflinePageMetadataStoreTest, LoadEmptyStore) { 196 TYPED_TEST(OfflinePageMetadataStoreTest, LoadEmptyStore) {
144 std::unique_ptr<OfflinePageMetadataStore> store(this->BuildStore()); 197 std::unique_ptr<OfflinePageMetadataStore> store(this->BuildStore());
145 EXPECT_EQ(LOAD, this->last_called_callback_); 198 EXPECT_EQ(LOAD, this->last_called_callback_);
146 EXPECT_EQ(STATUS_TRUE, this->last_status_); 199 EXPECT_EQ(STATUS_TRUE, this->last_status_);
147 EXPECT_EQ(0U, this->offline_pages_.size()); 200 EXPECT_EQ(0U, this->offline_pages_.size());
148 } 201 }
149 202
203 // Loads a store which has an outdated schema.
204 // This test case would crash if it's not handling correctly when we're loading
205 // old version stores.
206 // TODO(romax): Move this to sql_unittest.
207 TYPED_TEST(OfflinePageMetadataStoreTest, LoadExistingBadStore) {
208 std::unique_ptr<OfflinePageMetadataStore> store(this->BuildBadStore());
fgorski 2016/06/03 18:17:16 can you omit this->?
romax 2016/06/03 19:36:22 no, since TYPED_TEST is a derived template class s
fgorski 2016/06/03 20:04:17 Acknowledged. Thanks for checking.
209 EXPECT_EQ(LOAD, this->last_called_callback_);
210 EXPECT_EQ(STATUS_TRUE, this->last_status_);
211 EXPECT_EQ(0U, this->offline_pages_.size());
212 OfflinePageItem offline_page(GURL(kTestURL), 1234LL, kTestClientId1,
213 base::FilePath(kFilePath), kFileSize);
214 store->AddOrUpdateOfflinePage(
215 offline_page,
216 base::Bind(&OfflinePageMetadataStoreTestBase::UpdateCallback,
217 base::Unretained(this), ADD));
218 this->PumpLoop();
219 EXPECT_EQ(ADD, this->last_called_callback_);
220 EXPECT_EQ(STATUS_TRUE, this->last_status_);
221 }
222
150 // Adds metadata of an offline page into a store and then opens the store 223 // Adds metadata of an offline page into a store and then opens the store
151 // again to make sure that stored metadata survives store restarts. 224 // again to make sure that stored metadata survives store restarts.
152 TYPED_TEST(OfflinePageMetadataStoreTest, AddOfflinePage) { 225 TYPED_TEST(OfflinePageMetadataStoreTest, AddOfflinePage) {
153 std::unique_ptr<OfflinePageMetadataStore> store(this->BuildStore()); 226 std::unique_ptr<OfflinePageMetadataStore> store(this->BuildStore());
154 OfflinePageItem offline_page(GURL(kTestURL), 1234LL, kTestClientId1, 227 OfflinePageItem offline_page(GURL(kTestURL), 1234LL, kTestClientId1,
155 base::FilePath(kFilePath), kFileSize); 228 base::FilePath(kFilePath), kFileSize);
156 store->AddOrUpdateOfflinePage( 229 store->AddOrUpdateOfflinePage(
157 offline_page, 230 offline_page,
158 base::Bind(&OfflinePageMetadataStoreTestBase::UpdateCallback, 231 base::Bind(&OfflinePageMetadataStoreTestBase::UpdateCallback,
159 base::Unretained(this), ADD)); 232 base::Unretained(this), ADD));
(...skipping 226 matching lines...) Expand 10 before | Expand all | Expand 10 after
386 EXPECT_EQ(offline_page.last_access_time, 459 EXPECT_EQ(offline_page.last_access_time,
387 this->offline_pages_[0].last_access_time); 460 this->offline_pages_[0].last_access_time);
388 EXPECT_EQ(offline_page.expiration_time, 461 EXPECT_EQ(offline_page.expiration_time,
389 this->offline_pages_[0].expiration_time); 462 this->offline_pages_[0].expiration_time);
390 EXPECT_EQ(offline_page.access_count, this->offline_pages_[0].access_count); 463 EXPECT_EQ(offline_page.access_count, this->offline_pages_[0].access_count);
391 EXPECT_EQ(offline_page.client_id, this->offline_pages_[0].client_id); 464 EXPECT_EQ(offline_page.client_id, this->offline_pages_[0].client_id);
392 } 465 }
393 466
394 } // namespace 467 } // namespace
395 } // namespace offline_pages 468 } // namespace offline_pages
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698