summaryrefslogtreecommitdiffstats
path: root/sql
diff options
context:
space:
mode:
authorshess <shess@chromium.org>2016-02-04 12:56:22 -0800
committerCommit bot <commit-bot@chromium.org>2016-02-04 20:57:36 +0000
commit6ac39546b2c45d8a9b06ba08a19811f5f224934c (patch)
treeea037f086cc8c91f34247f46e478bc92a72085eb /sql
parent303520d6d745807a04f43f9704edbdcff33d1dbf (diff)
downloadchromium_src-6ac39546b2c45d8a9b06ba08a19811f5f224934c.zip
chromium_src-6ac39546b2c45d8a9b06ba08a19811f5f224934c.tar.gz
chromium_src-6ac39546b2c45d8a9b06ba08a19811f5f224934c.tar.bz2
[sql] Clean up sql::Recovery unit test.
Test baseline sql::Recovery::Rollback() operation. Change RecoveryCallback() to use AutoRecoverTable() rather than manual virtual table setup. Inject an artificial error to provoke callback in RecoverCorruptTable rather than calling manually. BUG=none Review URL: https://codereview.chromium.org/1669453003 Cr-Commit-Position: refs/heads/master@{#373613}
Diffstat (limited to 'sql')
-rw-r--r--sql/recovery_unittest.cc75
1 files changed, 48 insertions, 27 deletions
diff --git a/sql/recovery_unittest.cc b/sql/recovery_unittest.cc
index 73d146f..4990e83 100644
--- a/sql/recovery_unittest.cc
+++ b/sql/recovery_unittest.cc
@@ -67,9 +67,12 @@ std::string GetSchema(sql::Connection* db) {
using SQLRecoveryTest = sql::SQLTestBase;
+// Baseline sql::Recovery test covering the different ways to dispose of the
+// scoped pointer received from sql::Recovery::Begin().
TEST_F(SQLRecoveryTest, RecoverBasic) {
const char kCreateSql[] = "CREATE TABLE x (t TEXT)";
const char kInsertSql[] = "INSERT INTO x VALUES ('This is a test')";
+ const char kAltInsertSql[] = "INSERT INTO x VALUES ('That was a test')";
ASSERT_TRUE(db().Execute(kCreateSql));
ASSERT_TRUE(db().Execute(kInsertSql));
ASSERT_EQ("CREATE TABLE x (t TEXT)", GetSchema(&db()));
@@ -119,6 +122,10 @@ TEST_F(SQLRecoveryTest, RecoverBasic) {
ASSERT_TRUE(db().Execute(kInsertSql));
ASSERT_EQ("CREATE TABLE x (t TEXT)", GetSchema(&db()));
+ // Unrecovered table to distinguish from recovered database.
+ ASSERT_TRUE(db().Execute("CREATE TABLE y (c INTEGER)"));
+ ASSERT_NE("CREATE TABLE x (t TEXT)", GetSchema(&db()));
+
// Recovered() replaces the original with the "recovered" version.
{
scoped_ptr<sql::Recovery> recovery = sql::Recovery::Begin(&db(), db_path());
@@ -128,7 +135,6 @@ TEST_F(SQLRecoveryTest, RecoverBasic) {
ASSERT_TRUE(recovery->db()->Execute(kCreateSql));
// Insert different data to distinguish from original database.
- const char kAltInsertSql[] = "INSERT INTO x VALUES ('That was a test')";
ASSERT_TRUE(recovery->db()->Execute(kAltInsertSql));
// Successfully recovered.
@@ -142,12 +148,34 @@ TEST_F(SQLRecoveryTest, RecoverBasic) {
const char* kXSql = "SELECT * FROM x ORDER BY 1";
ASSERT_EQ("That was a test",
ExecuteWithResults(&db(), kXSql, "|", "\n"));
+
+ // Reset the database contents.
+ ASSERT_TRUE(db().Execute("DELETE FROM x"));
+ ASSERT_TRUE(db().Execute(kInsertSql));
+
+ // Rollback() discards recovery progress and leaves the database as it was.
+ {
+ scoped_ptr<sql::Recovery> recovery = sql::Recovery::Begin(&db(), db_path());
+ ASSERT_TRUE(recovery.get());
+
+ ASSERT_TRUE(recovery->db()->Execute(kCreateSql));
+ ASSERT_TRUE(recovery->db()->Execute(kAltInsertSql));
+
+ sql::Recovery::Rollback(std::move(recovery));
+ }
+ EXPECT_FALSE(db().is_open());
+ ASSERT_TRUE(Reopen());
+ EXPECT_TRUE(db().is_open());
+ ASSERT_EQ("CREATE TABLE x (t TEXT)", GetSchema(&db()));
+
+ ASSERT_EQ("This is a test",
+ ExecuteWithResults(&db(), kXSql, "|", "\n"));
}
// The recovery virtual table is only supported for Chromium's SQLite.
#if !defined(USE_SYSTEM_SQLITE)
-// Run recovery through its paces on a valid database.
+// Test operation of the virtual table used by sql::Recovery.
TEST_F(SQLRecoveryTest, VirtualTable) {
const char kCreateSql[] = "CREATE TABLE x (t TEXT)";
ASSERT_TRUE(db().Execute(kCreateSql));
@@ -189,6 +217,7 @@ TEST_F(SQLRecoveryTest, VirtualTable) {
}
void RecoveryCallback(sql::Connection* db, const base::FilePath& db_path,
+ const char* create_table, const char* create_index,
int* record_error, int error, sql::Statement* stmt) {
*record_error = error;
@@ -198,23 +227,11 @@ void RecoveryCallback(sql::Connection* db, const base::FilePath& db_path,
scoped_ptr<sql::Recovery> recovery = sql::Recovery::Begin(db, db_path);
ASSERT_TRUE(recovery.get());
- const char kRecoveryCreateSql[] =
- "CREATE VIRTUAL TABLE temp.recover_x using recover("
- " corrupt.x,"
- " id INTEGER STRICT,"
- " v INTEGER STRICT"
- ")";
- const char kCreateTable[] = "CREATE TABLE x (id INTEGER, v INTEGER)";
- const char kCreateIndex[] = "CREATE UNIQUE INDEX x_id ON x (id)";
-
- // Replicate data over.
- const char kRecoveryCopySql[] =
- "INSERT OR REPLACE INTO x SELECT id, v FROM recover_x";
+ ASSERT_TRUE(recovery->db()->Execute(create_table));
+ ASSERT_TRUE(recovery->db()->Execute(create_index));
- ASSERT_TRUE(recovery->db()->Execute(kRecoveryCreateSql));
- ASSERT_TRUE(recovery->db()->Execute(kCreateTable));
- ASSERT_TRUE(recovery->db()->Execute(kCreateIndex));
- ASSERT_TRUE(recovery->db()->Execute(kRecoveryCopySql));
+ size_t rows = 0;
+ ASSERT_TRUE(recovery->AutoRecoverTable("x", &rows));
ASSERT_TRUE(sql::Recovery::Recovered(std::move(recovery)));
}
@@ -253,8 +270,8 @@ TEST_F(SQLRecoveryTest, RecoverCorruptIndex) {
ASSERT_TRUE(Reopen());
int error = SQLITE_OK;
- db().set_error_callback(base::Bind(&RecoveryCallback,
- &db(), db_path(), &error));
+ db().set_error_callback(base::Bind(&RecoveryCallback, &db(), db_path(),
+ kCreateTable, kCreateIndex, &error));
// This works before the callback is called.
const char kTrivialSql[] = "SELECT COUNT(*) FROM sqlite_master";
@@ -309,11 +326,12 @@ TEST_F(SQLRecoveryTest, RecoverCorruptTable) {
const char kDeleteSql[] = "DELETE FROM x WHERE id = 0";
ASSERT_TRUE(sql::test::CorruptTableOrIndex(db_path(), "x", kDeleteSql));
- // TODO(shess): Figure out a query which causes SQLite to notice
- // this organically. Meanwhile, just handle it manually.
-
ASSERT_TRUE(Reopen());
+ int error = SQLITE_OK;
+ db().set_error_callback(base::Bind(&RecoveryCallback, &db(), db_path(),
+ kCreateTable, kCreateIndex, &error));
+
// Index shows one less than originally inserted.
const char kCountSql[] = "SELECT COUNT (*) FROM x";
EXPECT_EQ("9", ExecuteWithResults(&db(), kCountSql, "|", ","));
@@ -336,10 +354,13 @@ TEST_F(SQLRecoveryTest, RecoverCorruptTable) {
const char kTrivialSql[] = "SELECT COUNT(*) FROM sqlite_master";
EXPECT_TRUE(db().IsSQLValid(kTrivialSql));
- // Call the recovery callback manually.
- int error = SQLITE_OK;
- RecoveryCallback(&db(), db_path(), &error, SQLITE_CORRUPT, NULL);
- EXPECT_EQ(SQLITE_CORRUPT, error);
+ // TODO(shess): Figure out a statement which causes SQLite to notice the
+ // corruption. SELECT doesn't see errors because missing index values aren't
+ // visible. UPDATE or DELETE against v=0 don't see errors, even though the
+ // index item is missing. I suspect SQLite only deletes the key in these
+ // cases, but doesn't verify that one or more keys were deleted.
+ ASSERT_FALSE(db().Execute("INSERT INTO x (id, v) VALUES (0, 101)"));
+ EXPECT_EQ(SQLITE_CONSTRAINT_UNIQUE, error);
// Database handle has been poisoned.
EXPECT_FALSE(db().IsSQLValid(kTrivialSql));