OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 "base/bind.h" |
5 #include "base/file_util.h" | 6 #include "base/file_util.h" |
6 #include "base/files/scoped_temp_dir.h" | 7 #include "base/files/scoped_temp_dir.h" |
7 #include "base/logging.h" | 8 #include "base/logging.h" |
8 #include "sql/connection.h" | 9 #include "sql/connection.h" |
9 #include "sql/meta_table.h" | 10 #include "sql/meta_table.h" |
10 #include "sql/statement.h" | 11 #include "sql/statement.h" |
11 #include "sql/test/scoped_error_ignorer.h" | 12 #include "sql/test/scoped_error_ignorer.h" |
12 #include "testing/gtest/include/gtest/gtest.h" | 13 #include "testing/gtest/include/gtest/gtest.h" |
13 #include "third_party/sqlite/sqlite3.h" | 14 #include "third_party/sqlite/sqlite3.h" |
14 | 15 |
| 16 namespace { |
| 17 |
| 18 // Helper to return the count of items in sqlite_master. Return -1 in |
| 19 // case of error. |
| 20 int SqliteMasterCount(sql::Connection* db) { |
| 21 const char* kMasterCount = "SELECT COUNT(*) FROM sqlite_master"; |
| 22 sql::Statement s(db->GetUniqueStatement(kMasterCount)); |
| 23 return s.Step() ? s.ColumnInt(0) : -1; |
| 24 } |
| 25 |
15 class SQLConnectionTest : public testing::Test { | 26 class SQLConnectionTest : public testing::Test { |
16 public: | 27 public: |
17 SQLConnectionTest() {} | 28 SQLConnectionTest() {} |
18 | 29 |
19 virtual void SetUp() { | 30 virtual void SetUp() { |
20 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); | 31 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); |
21 ASSERT_TRUE(db_.Open(db_path())); | 32 ASSERT_TRUE(db_.Open(db_path())); |
22 } | 33 } |
23 | 34 |
24 virtual void TearDown() { | 35 virtual void TearDown() { |
25 db_.Close(); | 36 db_.Close(); |
26 } | 37 } |
27 | 38 |
28 sql::Connection& db() { return db_; } | 39 sql::Connection& db() { return db_; } |
29 | 40 |
30 base::FilePath db_path() { | 41 base::FilePath db_path() { |
31 return temp_dir_.path().AppendASCII("SQLConnectionTest.db"); | 42 return temp_dir_.path().AppendASCII("SQLConnectionTest.db"); |
32 } | 43 } |
33 | 44 |
| 45 // Handle errors by blowing away the database. |
| 46 void RazeErrorCallback(int expected_error, int error, sql::Statement* stmt) { |
| 47 EXPECT_EQ(expected_error, error); |
| 48 db_.RazeAndClose(); |
| 49 } |
| 50 |
34 private: | 51 private: |
35 base::ScopedTempDir temp_dir_; | 52 base::ScopedTempDir temp_dir_; |
36 sql::Connection db_; | 53 sql::Connection db_; |
37 }; | 54 }; |
38 | 55 |
39 TEST_F(SQLConnectionTest, Execute) { | 56 TEST_F(SQLConnectionTest, Execute) { |
40 // Valid statement should return true. | 57 // Valid statement should return true. |
41 ASSERT_TRUE(db().Execute("CREATE TABLE foo (a, b)")); | 58 ASSERT_TRUE(db().Execute("CREATE TABLE foo (a, b)")); |
42 EXPECT_EQ(SQLITE_OK, db().GetErrorCode()); | 59 EXPECT_EQ(SQLITE_OK, db().GetErrorCode()); |
43 | 60 |
(...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
186 } | 203 } |
187 | 204 |
188 ASSERT_TRUE(db().Raze()); | 205 ASSERT_TRUE(db().Raze()); |
189 | 206 |
190 { | 207 { |
191 sql::Statement s(db().GetUniqueStatement("PRAGMA page_count")); | 208 sql::Statement s(db().GetUniqueStatement("PRAGMA page_count")); |
192 ASSERT_TRUE(s.Step()); | 209 ASSERT_TRUE(s.Step()); |
193 EXPECT_EQ(1, s.ColumnInt(0)); | 210 EXPECT_EQ(1, s.ColumnInt(0)); |
194 } | 211 } |
195 | 212 |
196 { | 213 ASSERT_EQ(0, SqliteMasterCount(&db())); |
197 sql::Statement s(db().GetUniqueStatement("SELECT * FROM sqlite_master")); | |
198 ASSERT_FALSE(s.Step()); | |
199 } | |
200 | 214 |
201 { | 215 { |
202 sql::Statement s(db().GetUniqueStatement("PRAGMA auto_vacuum")); | 216 sql::Statement s(db().GetUniqueStatement("PRAGMA auto_vacuum")); |
203 ASSERT_TRUE(s.Step()); | 217 ASSERT_TRUE(s.Step()); |
204 // The new database has the same auto_vacuum as a fresh database. | 218 // The new database has the same auto_vacuum as a fresh database. |
205 EXPECT_EQ(pragma_auto_vacuum, s.ColumnInt(0)); | 219 EXPECT_EQ(pragma_auto_vacuum, s.ColumnInt(0)); |
206 } | 220 } |
207 } | 221 } |
208 | 222 |
209 // Test that Raze() maintains page_size. | 223 // Test that Raze() maintains page_size. |
(...skipping 28 matching lines...) Expand all Loading... |
238 | 252 |
239 // Test that Raze() results are seen in other connections. | 253 // Test that Raze() results are seen in other connections. |
240 TEST_F(SQLConnectionTest, RazeMultiple) { | 254 TEST_F(SQLConnectionTest, RazeMultiple) { |
241 const char* kCreateSql = "CREATE TABLE foo (id INTEGER PRIMARY KEY, value)"; | 255 const char* kCreateSql = "CREATE TABLE foo (id INTEGER PRIMARY KEY, value)"; |
242 ASSERT_TRUE(db().Execute(kCreateSql)); | 256 ASSERT_TRUE(db().Execute(kCreateSql)); |
243 | 257 |
244 sql::Connection other_db; | 258 sql::Connection other_db; |
245 ASSERT_TRUE(other_db.Open(db_path())); | 259 ASSERT_TRUE(other_db.Open(db_path())); |
246 | 260 |
247 // Check that the second connection sees the table. | 261 // Check that the second connection sees the table. |
248 const char *kTablesQuery = "SELECT COUNT(*) FROM sqlite_master"; | 262 ASSERT_EQ(1, SqliteMasterCount(&other_db)); |
249 sql::Statement s(other_db.GetUniqueStatement(kTablesQuery)); | |
250 ASSERT_TRUE(s.Step()); | |
251 ASSERT_EQ(1, s.ColumnInt(0)); | |
252 ASSERT_FALSE(s.Step()); // Releases the shared lock. | |
253 | 263 |
254 ASSERT_TRUE(db().Raze()); | 264 ASSERT_TRUE(db().Raze()); |
255 | 265 |
256 // The second connection sees the updated database. | 266 // The second connection sees the updated database. |
257 s.Reset(true); | 267 ASSERT_EQ(0, SqliteMasterCount(&other_db)); |
258 ASSERT_TRUE(s.Step()); | |
259 ASSERT_EQ(0, s.ColumnInt(0)); | |
260 } | 268 } |
261 | 269 |
262 TEST_F(SQLConnectionTest, RazeLocked) { | 270 TEST_F(SQLConnectionTest, RazeLocked) { |
263 const char* kCreateSql = "CREATE TABLE foo (id INTEGER PRIMARY KEY, value)"; | 271 const char* kCreateSql = "CREATE TABLE foo (id INTEGER PRIMARY KEY, value)"; |
264 ASSERT_TRUE(db().Execute(kCreateSql)); | 272 ASSERT_TRUE(db().Execute(kCreateSql)); |
265 | 273 |
266 // Open a transaction and write some data in a second connection. | 274 // Open a transaction and write some data in a second connection. |
267 // This will acquire a PENDING or EXCLUSIVE transaction, which will | 275 // This will acquire a PENDING or EXCLUSIVE transaction, which will |
268 // cause the raze to fail. | 276 // cause the raze to fail. |
269 sql::Connection other_db; | 277 sql::Connection other_db; |
(...skipping 17 matching lines...) Expand all Loading... |
287 const char *kQuery = "SELECT COUNT(*) FROM foo"; | 295 const char *kQuery = "SELECT COUNT(*) FROM foo"; |
288 sql::Statement s(other_db.GetUniqueStatement(kQuery)); | 296 sql::Statement s(other_db.GetUniqueStatement(kQuery)); |
289 ASSERT_TRUE(s.Step()); | 297 ASSERT_TRUE(s.Step()); |
290 ASSERT_FALSE(db().Raze()); | 298 ASSERT_FALSE(db().Raze()); |
291 | 299 |
292 // Complete the statement unlocks the database. | 300 // Complete the statement unlocks the database. |
293 ASSERT_FALSE(s.Step()); | 301 ASSERT_FALSE(s.Step()); |
294 ASSERT_TRUE(db().Raze()); | 302 ASSERT_TRUE(db().Raze()); |
295 } | 303 } |
296 | 304 |
| 305 // Verify that Raze() can handle an empty file. SQLite should treat |
| 306 // this as an empty database. |
| 307 TEST_F(SQLConnectionTest, RazeEmptyDB) { |
| 308 const char* kCreateSql = "CREATE TABLE foo (id INTEGER PRIMARY KEY, value)"; |
| 309 ASSERT_TRUE(db().Execute(kCreateSql)); |
| 310 db().Close(); |
| 311 |
| 312 { |
| 313 file_util::ScopedFILE file(file_util::OpenFile(db_path(), "r+")); |
| 314 ASSERT_TRUE(file.get() != NULL); |
| 315 ASSERT_EQ(0, fseek(file.get(), 0, SEEK_SET)); |
| 316 ASSERT_TRUE(file_util::TruncateFile(file.get())); |
| 317 } |
| 318 |
| 319 ASSERT_TRUE(db().Open(db_path())); |
| 320 ASSERT_TRUE(db().Raze()); |
| 321 EXPECT_EQ(0, SqliteMasterCount(&db())); |
| 322 } |
| 323 |
| 324 // Verify that Raze() can handle a file of junk. |
| 325 TEST_F(SQLConnectionTest, RazeNOTADB) { |
| 326 db().Close(); |
| 327 sql::Connection::Delete(db_path()); |
| 328 ASSERT_FALSE(file_util::PathExists(db_path())); |
| 329 |
| 330 { |
| 331 file_util::ScopedFILE file(file_util::OpenFile(db_path(), "w")); |
| 332 ASSERT_TRUE(file.get() != NULL); |
| 333 |
| 334 const char* kJunk = "This is the hour of our discontent."; |
| 335 fputs(kJunk, file.get()); |
| 336 } |
| 337 ASSERT_TRUE(file_util::PathExists(db_path())); |
| 338 |
| 339 // SQLite will successfully open the handle, but will fail with |
| 340 // SQLITE_IOERR_SHORT_READ on pragma statemenets which read the |
| 341 // header. |
| 342 { |
| 343 sql::ScopedErrorIgnorer ignore_errors; |
| 344 ignore_errors.IgnoreError(SQLITE_IOERR_SHORT_READ); |
| 345 EXPECT_TRUE(db().Open(db_path())); |
| 346 ASSERT_TRUE(ignore_errors.CheckIgnoredErrors()); |
| 347 } |
| 348 EXPECT_TRUE(db().Raze()); |
| 349 db().Close(); |
| 350 |
| 351 // Now empty, the open should open an empty database. |
| 352 EXPECT_TRUE(db().Open(db_path())); |
| 353 EXPECT_EQ(0, SqliteMasterCount(&db())); |
| 354 } |
| 355 |
| 356 // Verify that Raze() can handle a database overwritten with garbage. |
| 357 TEST_F(SQLConnectionTest, RazeNOTADB2) { |
| 358 const char* kCreateSql = "CREATE TABLE foo (id INTEGER PRIMARY KEY, value)"; |
| 359 ASSERT_TRUE(db().Execute(kCreateSql)); |
| 360 ASSERT_EQ(1, SqliteMasterCount(&db())); |
| 361 db().Close(); |
| 362 |
| 363 { |
| 364 file_util::ScopedFILE file(file_util::OpenFile(db_path(), "r+")); |
| 365 ASSERT_TRUE(file.get() != NULL); |
| 366 ASSERT_EQ(0, fseek(file.get(), 0, SEEK_SET)); |
| 367 |
| 368 const char* kJunk = "This is the hour of our discontent."; |
| 369 fputs(kJunk, file.get()); |
| 370 } |
| 371 |
| 372 // SQLite will successfully open the handle, but will fail with |
| 373 // SQLITE_NOTADB on pragma statemenets which attempt to read the |
| 374 // corrupted header. |
| 375 { |
| 376 sql::ScopedErrorIgnorer ignore_errors; |
| 377 ignore_errors.IgnoreError(SQLITE_NOTADB); |
| 378 EXPECT_TRUE(db().Open(db_path())); |
| 379 ASSERT_TRUE(ignore_errors.CheckIgnoredErrors()); |
| 380 } |
| 381 EXPECT_TRUE(db().Raze()); |
| 382 db().Close(); |
| 383 |
| 384 // Now empty, the open should succeed with an empty database. |
| 385 EXPECT_TRUE(db().Open(db_path())); |
| 386 EXPECT_EQ(0, SqliteMasterCount(&db())); |
| 387 } |
| 388 |
| 389 // Test that a callback from Open() can raze the database. This is |
| 390 // essential for cases where the Open() can fail entirely, so the |
| 391 // Raze() cannot happen later. |
| 392 // |
| 393 // Most corruptions seen in the wild seem to happen when two pages in |
| 394 // the database were not written transactionally (the transaction |
| 395 // changed both, but one wasn't successfully written for some reason). |
| 396 // A special case of that is when the header indicates that the |
| 397 // database contains more pages than are in the file. This breaks |
| 398 // things at a very basic level, verify that Raze() can handle it. |
| 399 TEST_F(SQLConnectionTest, RazeOpenCallback) { |
| 400 const char* kCreateSql = "CREATE TABLE foo (id INTEGER PRIMARY KEY, value)"; |
| 401 ASSERT_TRUE(db().Execute(kCreateSql)); |
| 402 ASSERT_EQ(1, SqliteMasterCount(&db())); |
| 403 db().Close(); |
| 404 |
| 405 // Trim a single page from the end of the file. |
| 406 { |
| 407 file_util::ScopedFILE file(file_util::OpenFile(db_path(), "r+")); |
| 408 ASSERT_TRUE(file.get() != NULL); |
| 409 ASSERT_EQ(0, fseek(file.get(), -1024, SEEK_END)); |
| 410 ASSERT_TRUE(file_util::TruncateFile(file.get())); |
| 411 } |
| 412 |
| 413 db().set_error_callback(base::Bind(&SQLConnectionTest::RazeErrorCallback, |
| 414 base::Unretained(this), |
| 415 SQLITE_CORRUPT)); |
| 416 |
| 417 // Open() will see SQLITE_CORRUPT due to size mismatch when |
| 418 // attempting to run a pragma, and the callback will RazeAndClose(). |
| 419 // Later statements will fail, including the final secure_delete, |
| 420 // which will fail the Open() itself. |
| 421 ASSERT_FALSE(db().Open(db_path())); |
| 422 db().Close(); |
| 423 |
| 424 // Now empty, the open should succeed with an empty database. |
| 425 EXPECT_TRUE(db().Open(db_path())); |
| 426 EXPECT_EQ(0, SqliteMasterCount(&db())); |
| 427 } |
| 428 |
297 // Basic test of RazeAndClose() operation. | 429 // Basic test of RazeAndClose() operation. |
298 TEST_F(SQLConnectionTest, RazeAndClose) { | 430 TEST_F(SQLConnectionTest, RazeAndClose) { |
299 const char* kCreateSql = "CREATE TABLE foo (id INTEGER PRIMARY KEY, value)"; | 431 const char* kCreateSql = "CREATE TABLE foo (id INTEGER PRIMARY KEY, value)"; |
300 const char* kPopulateSql = "INSERT INTO foo (value) VALUES (12)"; | 432 const char* kPopulateSql = "INSERT INTO foo (value) VALUES (12)"; |
301 | 433 |
302 // Test that RazeAndClose() closes the database, and that the | 434 // Test that RazeAndClose() closes the database, and that the |
303 // database is empty when re-opened. | 435 // database is empty when re-opened. |
304 ASSERT_TRUE(db().Execute(kCreateSql)); | 436 ASSERT_TRUE(db().Execute(kCreateSql)); |
305 ASSERT_TRUE(db().Execute(kPopulateSql)); | 437 ASSERT_TRUE(db().Execute(kPopulateSql)); |
306 ASSERT_TRUE(db().RazeAndClose()); | 438 ASSERT_TRUE(db().RazeAndClose()); |
307 ASSERT_FALSE(db().is_open()); | 439 ASSERT_FALSE(db().is_open()); |
308 db().Close(); | 440 db().Close(); |
309 ASSERT_TRUE(db().Open(db_path())); | 441 ASSERT_TRUE(db().Open(db_path())); |
310 { | 442 ASSERT_EQ(0, SqliteMasterCount(&db())); |
311 sql::Statement s(db().GetUniqueStatement("SELECT * FROM sqlite_master")); | |
312 ASSERT_FALSE(s.Step()); | |
313 } | |
314 | 443 |
315 // Test that RazeAndClose() can break transactions. | 444 // Test that RazeAndClose() can break transactions. |
316 ASSERT_TRUE(db().Execute(kCreateSql)); | 445 ASSERT_TRUE(db().Execute(kCreateSql)); |
317 ASSERT_TRUE(db().Execute(kPopulateSql)); | 446 ASSERT_TRUE(db().Execute(kPopulateSql)); |
318 ASSERT_TRUE(db().BeginTransaction()); | 447 ASSERT_TRUE(db().BeginTransaction()); |
319 ASSERT_TRUE(db().RazeAndClose()); | 448 ASSERT_TRUE(db().RazeAndClose()); |
320 ASSERT_FALSE(db().is_open()); | 449 ASSERT_FALSE(db().is_open()); |
321 ASSERT_FALSE(db().CommitTransaction()); | 450 ASSERT_FALSE(db().CommitTransaction()); |
322 db().Close(); | 451 db().Close(); |
323 ASSERT_TRUE(db().Open(db_path())); | 452 ASSERT_TRUE(db().Open(db_path())); |
324 { | 453 ASSERT_EQ(0, SqliteMasterCount(&db())); |
325 sql::Statement s(db().GetUniqueStatement("SELECT * FROM sqlite_master")); | |
326 ASSERT_FALSE(s.Step()); | |
327 } | |
328 } | 454 } |
329 | 455 |
330 // Test that various operations fail without crashing after | 456 // Test that various operations fail without crashing after |
331 // RazeAndClose(). | 457 // RazeAndClose(). |
332 TEST_F(SQLConnectionTest, RazeAndCloseDiagnostics) { | 458 TEST_F(SQLConnectionTest, RazeAndCloseDiagnostics) { |
333 const char* kCreateSql = "CREATE TABLE foo (id INTEGER PRIMARY KEY, value)"; | 459 const char* kCreateSql = "CREATE TABLE foo (id INTEGER PRIMARY KEY, value)"; |
334 const char* kPopulateSql = "INSERT INTO foo (value) VALUES (12)"; | 460 const char* kPopulateSql = "INSERT INTO foo (value) VALUES (12)"; |
335 const char* kSimpleSql = "SELECT 1"; | 461 const char* kSimpleSql = "SELECT 1"; |
336 | 462 |
337 ASSERT_TRUE(db().Execute(kCreateSql)); | 463 ASSERT_TRUE(db().Execute(kCreateSql)); |
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
419 // Should have both a main database file and a journal file because | 545 // Should have both a main database file and a journal file because |
420 // of journal_mode PERSIST. | 546 // of journal_mode PERSIST. |
421 base::FilePath journal(db_path().value() + FILE_PATH_LITERAL("-journal")); | 547 base::FilePath journal(db_path().value() + FILE_PATH_LITERAL("-journal")); |
422 ASSERT_TRUE(file_util::PathExists(db_path())); | 548 ASSERT_TRUE(file_util::PathExists(db_path())); |
423 ASSERT_TRUE(file_util::PathExists(journal)); | 549 ASSERT_TRUE(file_util::PathExists(journal)); |
424 | 550 |
425 sql::Connection::Delete(db_path()); | 551 sql::Connection::Delete(db_path()); |
426 EXPECT_FALSE(file_util::PathExists(db_path())); | 552 EXPECT_FALSE(file_util::PathExists(db_path())); |
427 EXPECT_FALSE(file_util::PathExists(journal)); | 553 EXPECT_FALSE(file_util::PathExists(journal)); |
428 } | 554 } |
| 555 |
| 556 } // namespace |
OLD | NEW |