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

Unified Diff: sql/recovery_unittest.cc

Issue 19281002: [sql] Scoped recovery framework. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Rebase to match Open() retry logic. Created 7 years, 5 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 | « sql/recovery.cc ('k') | sql/sql.gyp » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: sql/recovery_unittest.cc
diff --git a/sql/recovery_unittest.cc b/sql/recovery_unittest.cc
new file mode 100644
index 0000000000000000000000000000000000000000..8f24ff751e0b3091543711c903ed6f91f1c1d0d0
--- /dev/null
+++ b/sql/recovery_unittest.cc
@@ -0,0 +1,145 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/file_util.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/logging.h"
+#include "base/strings/stringprintf.h"
+#include "sql/connection.h"
+#include "sql/meta_table.h"
+#include "sql/recovery.h"
+#include "sql/statement.h"
+#include "sql/test/scoped_error_ignorer.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/sqlite/sqlite3.h"
+
+namespace {
+
+// Execute |sql|, and stringify the results with |column_sep| between
+// columns and |row_sep| between rows.
+// TODO(shess): Promote this to a central testing helper.
+std::string ExecuteWithResults(sql::Connection* db,
+ const char* sql,
+ const char* column_sep,
+ const char* row_sep) {
+ sql::Statement s(db->GetUniqueStatement(sql));
+ std::string ret;
+ while (s.Step()) {
+ if (!ret.empty())
+ ret += row_sep;
+ for (int i = 0; i < s.ColumnCount(); ++i) {
+ if (i > 0)
+ ret += column_sep;
+ ret += s.ColumnString(i);
+ }
+ }
+ return ret;
+}
+
+// Dump consistent human-readable representation of the database
+// schema. For tables or indices, this will contain the sql command
+// to create the table or index. For certain automatic SQLite
+// structures with no sql, the name is used.
+std::string GetSchema(sql::Connection* db) {
+ const char kSql[] =
+ "SELECT COALESCE(sql, name) FROM sqlite_master ORDER BY 1";
+ return ExecuteWithResults(db, kSql, "|", "\n");
+}
+
+class SQLRecoveryTest : public testing::Test {
+ public:
+ SQLRecoveryTest() {}
+
+ virtual void SetUp() {
+ ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+ ASSERT_TRUE(db_.Open(db_path()));
+ }
+
+ virtual void TearDown() {
+ db_.Close();
+ }
+
+ sql::Connection& db() { return db_; }
+
+ base::FilePath db_path() {
+ return temp_dir_.path().AppendASCII("SQLRecoveryTest.db");
+ }
+
+ bool Reopen() {
+ db_.Close();
+ return db_.Open(db_path());
+ }
+
+ private:
+ base::ScopedTempDir temp_dir_;
+ sql::Connection db_;
+};
+
+TEST_F(SQLRecoveryTest, RecoverBasic) {
+ const char kCreateSql[] = "CREATE TABLE x (t TEXT)";
+ const char kInsertSql[] = "INSERT INTO x VALUES ('This is a test')";
+ ASSERT_TRUE(db().Execute(kCreateSql));
+ ASSERT_TRUE(db().Execute(kInsertSql));
+ ASSERT_EQ("CREATE TABLE x (t TEXT)", GetSchema(&db()));
+
+ // If the Recovery handle goes out of scope without being
+ // Recovered(), the database is razed.
+ {
+ scoped_ptr<sql::Recovery> recovery = sql::Recovery::Begin(&db(), db_path());
+ ASSERT_TRUE(recovery.get());
+ }
+ EXPECT_FALSE(db().is_open());
+ ASSERT_TRUE(Reopen());
+ EXPECT_TRUE(db().is_open());
+ ASSERT_EQ("", GetSchema(&db()));
+
+ // Recreate the database.
+ ASSERT_TRUE(db().Execute(kCreateSql));
+ ASSERT_TRUE(db().Execute(kInsertSql));
+ ASSERT_EQ("CREATE TABLE x (t TEXT)", GetSchema(&db()));
+
+ // Unrecoverable() also razes.
+ {
+ scoped_ptr<sql::Recovery> recovery = sql::Recovery::Begin(&db(), db_path());
+ ASSERT_TRUE(recovery.get());
+ sql::Recovery::Unrecoverable(recovery.Pass());
+
+ // TODO(shess): Test that calls to recover.db() start failing.
+ }
+ EXPECT_FALSE(db().is_open());
+ ASSERT_TRUE(Reopen());
+ EXPECT_TRUE(db().is_open());
+ ASSERT_EQ("", GetSchema(&db()));
+
+ // Recreate the database.
+ ASSERT_TRUE(db().Execute(kCreateSql));
+ ASSERT_TRUE(db().Execute(kInsertSql));
+ ASSERT_EQ("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());
+ ASSERT_TRUE(recovery.get());
+
+ // Create the new version of the table.
+ 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.
+ ASSERT_TRUE(sql::Recovery::Recovered(recovery.Pass()));
+ }
+ EXPECT_FALSE(db().is_open());
+ ASSERT_TRUE(Reopen());
+ EXPECT_TRUE(db().is_open());
+ ASSERT_EQ("CREATE TABLE x (t TEXT)", GetSchema(&db()));
+
+ const char* kXSql = "SELECT * FROM x ORDER BY 1";
+ ASSERT_EQ(ExecuteWithResults(&db(), kXSql, "|", "\n"),
+ "That was a test");
+}
+
+} // namespace
« no previous file with comments | « sql/recovery.cc ('k') | sql/sql.gyp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698