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

Side by Side 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 unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « sql/recovery.cc ('k') | sql/sql.gyp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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
3 // found in the LICENSE file.
4
5 #include "base/file_util.h"
6 #include "base/files/scoped_temp_dir.h"
7 #include "base/logging.h"
8 #include "base/strings/stringprintf.h"
9 #include "sql/connection.h"
10 #include "sql/meta_table.h"
11 #include "sql/recovery.h"
12 #include "sql/statement.h"
13 #include "sql/test/scoped_error_ignorer.h"
14 #include "testing/gtest/include/gtest/gtest.h"
15 #include "third_party/sqlite/sqlite3.h"
16
17 namespace {
18
19 // Execute |sql|, and stringify the results with |column_sep| between
20 // columns and |row_sep| between rows.
21 // TODO(shess): Promote this to a central testing helper.
22 std::string ExecuteWithResults(sql::Connection* db,
23 const char* sql,
24 const char* column_sep,
25 const char* row_sep) {
26 sql::Statement s(db->GetUniqueStatement(sql));
27 std::string ret;
28 while (s.Step()) {
29 if (!ret.empty())
30 ret += row_sep;
31 for (int i = 0; i < s.ColumnCount(); ++i) {
32 if (i > 0)
33 ret += column_sep;
34 ret += s.ColumnString(i);
35 }
36 }
37 return ret;
38 }
39
40 // Dump consistent human-readable representation of the database
41 // schema. For tables or indices, this will contain the sql command
42 // to create the table or index. For certain automatic SQLite
43 // structures with no sql, the name is used.
44 std::string GetSchema(sql::Connection* db) {
45 const char kSql[] =
46 "SELECT COALESCE(sql, name) FROM sqlite_master ORDER BY 1";
47 return ExecuteWithResults(db, kSql, "|", "\n");
48 }
49
50 class SQLRecoveryTest : public testing::Test {
51 public:
52 SQLRecoveryTest() {}
53
54 virtual void SetUp() {
55 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
56 ASSERT_TRUE(db_.Open(db_path()));
57 }
58
59 virtual void TearDown() {
60 db_.Close();
61 }
62
63 sql::Connection& db() { return db_; }
64
65 base::FilePath db_path() {
66 return temp_dir_.path().AppendASCII("SQLRecoveryTest.db");
67 }
68
69 bool Reopen() {
70 db_.Close();
71 return db_.Open(db_path());
72 }
73
74 private:
75 base::ScopedTempDir temp_dir_;
76 sql::Connection db_;
77 };
78
79 TEST_F(SQLRecoveryTest, RecoverBasic) {
80 const char kCreateSql[] = "CREATE TABLE x (t TEXT)";
81 const char kInsertSql[] = "INSERT INTO x VALUES ('This is a test')";
82 ASSERT_TRUE(db().Execute(kCreateSql));
83 ASSERT_TRUE(db().Execute(kInsertSql));
84 ASSERT_EQ("CREATE TABLE x (t TEXT)", GetSchema(&db()));
85
86 // If the Recovery handle goes out of scope without being
87 // Recovered(), the database is razed.
88 {
89 scoped_ptr<sql::Recovery> recovery = sql::Recovery::Begin(&db(), db_path());
90 ASSERT_TRUE(recovery.get());
91 }
92 EXPECT_FALSE(db().is_open());
93 ASSERT_TRUE(Reopen());
94 EXPECT_TRUE(db().is_open());
95 ASSERT_EQ("", GetSchema(&db()));
96
97 // Recreate the database.
98 ASSERT_TRUE(db().Execute(kCreateSql));
99 ASSERT_TRUE(db().Execute(kInsertSql));
100 ASSERT_EQ("CREATE TABLE x (t TEXT)", GetSchema(&db()));
101
102 // Unrecoverable() also razes.
103 {
104 scoped_ptr<sql::Recovery> recovery = sql::Recovery::Begin(&db(), db_path());
105 ASSERT_TRUE(recovery.get());
106 sql::Recovery::Unrecoverable(recovery.Pass());
107
108 // TODO(shess): Test that calls to recover.db() start failing.
109 }
110 EXPECT_FALSE(db().is_open());
111 ASSERT_TRUE(Reopen());
112 EXPECT_TRUE(db().is_open());
113 ASSERT_EQ("", GetSchema(&db()));
114
115 // Recreate the database.
116 ASSERT_TRUE(db().Execute(kCreateSql));
117 ASSERT_TRUE(db().Execute(kInsertSql));
118 ASSERT_EQ("CREATE TABLE x (t TEXT)", GetSchema(&db()));
119
120 // Recovered() replaces the original with the "recovered" version.
121 {
122 scoped_ptr<sql::Recovery> recovery = sql::Recovery::Begin(&db(), db_path());
123 ASSERT_TRUE(recovery.get());
124
125 // Create the new version of the table.
126 ASSERT_TRUE(recovery->db()->Execute(kCreateSql));
127
128 // Insert different data to distinguish from original database.
129 const char kAltInsertSql[] = "INSERT INTO x VALUES ('That was a test')";
130 ASSERT_TRUE(recovery->db()->Execute(kAltInsertSql));
131
132 // Successfully recovered.
133 ASSERT_TRUE(sql::Recovery::Recovered(recovery.Pass()));
134 }
135 EXPECT_FALSE(db().is_open());
136 ASSERT_TRUE(Reopen());
137 EXPECT_TRUE(db().is_open());
138 ASSERT_EQ("CREATE TABLE x (t TEXT)", GetSchema(&db()));
139
140 const char* kXSql = "SELECT * FROM x ORDER BY 1";
141 ASSERT_EQ(ExecuteWithResults(&db(), kXSql, "|", "\n"),
142 "That was a test");
143 }
144
145 } // namespace
OLDNEW
« 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