Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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/file_util.h" | 5 #include "base/file_util.h" |
| 6 #include "base/scoped_temp_dir.h" | 6 #include "base/scoped_temp_dir.h" |
| 7 #include "sql/connection.h" | 7 #include "sql/connection.h" |
| 8 #include "sql/statement.h" | 8 #include "sql/statement.h" |
| 9 #include "testing/gtest/include/gtest/gtest.h" | 9 #include "testing/gtest/include/gtest/gtest.h" |
| 10 #include "third_party/sqlite/sqlite3.h" | 10 #include "third_party/sqlite/sqlite3.h" |
| 11 | 11 |
| 12 class SQLConnectionTest : public testing::Test { | 12 class SQLConnectionTest : public testing::Test { |
| 13 public: | 13 public: |
| 14 SQLConnectionTest() {} | 14 SQLConnectionTest() {} |
| 15 | 15 |
| 16 void SetUp() { | 16 void SetUp() { |
| 17 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); | 17 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); |
| 18 ASSERT_TRUE(db_.Open(temp_dir_.path().AppendASCII("SQLConnectionTest.db"))); | 18 ASSERT_TRUE(db_.Open(db_path())); |
| 19 } | 19 } |
| 20 | 20 |
| 21 void TearDown() { | 21 void TearDown() { |
| 22 db_.Close(); | 22 db_.Close(); |
| 23 } | 23 } |
| 24 | 24 |
| 25 sql::Connection& db() { return db_; } | 25 sql::Connection& db() { return db_; } |
| 26 | 26 |
| 27 FilePath db_path() { | |
| 28 return temp_dir_.path().AppendASCII("SQLConnectionTest.db"); | |
| 29 } | |
| 30 | |
| 27 private: | 31 private: |
| 28 ScopedTempDir temp_dir_; | 32 ScopedTempDir temp_dir_; |
| 29 sql::Connection db_; | 33 sql::Connection db_; |
| 30 }; | 34 }; |
| 31 | 35 |
| 32 TEST_F(SQLConnectionTest, Execute) { | 36 TEST_F(SQLConnectionTest, Execute) { |
| 33 // Valid statement should return true. | 37 // Valid statement should return true. |
| 34 ASSERT_TRUE(db().Execute("CREATE TABLE foo (a, b)")); | 38 ASSERT_TRUE(db().Execute("CREATE TABLE foo (a, b)")); |
| 35 EXPECT_EQ(SQLITE_OK, db().GetErrorCode()); | 39 EXPECT_EQ(SQLITE_OK, db().GetErrorCode()); |
| 36 | 40 |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 113 // Last insert row ID should be valid. | 117 // Last insert row ID should be valid. |
| 114 int64 row = db().GetLastInsertRowId(); | 118 int64 row = db().GetLastInsertRowId(); |
| 115 EXPECT_LT(0, row); | 119 EXPECT_LT(0, row); |
| 116 | 120 |
| 117 // It should be the primary key of the row we just inserted. | 121 // It should be the primary key of the row we just inserted. |
| 118 sql::Statement s(db().GetUniqueStatement("SELECT value FROM foo WHERE id=?")); | 122 sql::Statement s(db().GetUniqueStatement("SELECT value FROM foo WHERE id=?")); |
| 119 s.BindInt64(0, row); | 123 s.BindInt64(0, row); |
| 120 ASSERT_TRUE(s.Step()); | 124 ASSERT_TRUE(s.Step()); |
| 121 EXPECT_EQ(12, s.ColumnInt(0)); | 125 EXPECT_EQ(12, s.ColumnInt(0)); |
| 122 } | 126 } |
| 127 | |
| 128 // Test that sql::Connection::Raze() results in a database without the | |
| 129 // tables from the original database. | |
| 130 TEST_F(SQLConnectionTest, Raze) { | |
| 131 const char* kCreateSql = "CREATE TABLE foo (id INTEGER PRIMARY KEY, value)"; | |
| 132 ASSERT_TRUE(db().Execute(kCreateSql)); | |
| 133 ASSERT_TRUE(db().Execute("INSERT INTO foo (value) VALUES (12)")); | |
| 134 | |
| 135 { | |
| 136 sql::Statement s(db().GetUniqueStatement("PRAGMA page_count")); | |
| 137 ASSERT_TRUE(s.Step()); | |
| 138 EXPECT_EQ(2, s.ColumnInt(0)); | |
|
Greg Billock
2012/03/31 01:23:50
is this impl-dependent? that is, won't the page co
Scott Hess - ex-Googler
2012/04/04 01:28:25
Shouldn't ever vary. There should be the special
| |
| 139 } | |
| 140 | |
| 141 { | |
| 142 sql::Statement s(db().GetUniqueStatement("SELECT * FROM sqlite_master")); | |
| 143 ASSERT_TRUE(s.Step()); | |
| 144 EXPECT_EQ("table", s.ColumnString(0)); | |
| 145 EXPECT_EQ("foo", s.ColumnString(1)); | |
| 146 EXPECT_EQ("foo", s.ColumnString(2)); | |
| 147 EXPECT_EQ(2, s.ColumnInt(3)); | |
| 148 EXPECT_EQ(kCreateSql, s.ColumnString(4)); | |
| 149 } | |
| 150 | |
| 151 ASSERT_TRUE(db().Raze()); | |
| 152 | |
| 153 { | |
| 154 sql::Statement s(db().GetUniqueStatement("PRAGMA page_count")); | |
| 155 ASSERT_TRUE(s.Step()); | |
| 156 EXPECT_EQ(1, s.ColumnInt(0)); | |
| 157 } | |
| 158 | |
| 159 { | |
| 160 sql::Statement s(db().GetUniqueStatement("SELECT * FROM sqlite_master")); | |
| 161 ASSERT_FALSE(s.Step()); | |
| 162 } | |
| 163 } | |
| 164 | |
| 165 // Test that Raze() maintains page_size. | |
| 166 TEST_F(SQLConnectionTest, RazePageSize) { | |
| 167 const int kPageSize = 4096; | |
| 168 | |
| 169 // Make sure that the default size isn't already |kPageSize|. | |
| 170 // Scoped to release statement before Close(). | |
| 171 { | |
| 172 sql::Statement s(db().GetUniqueStatement("PRAGMA page_size")); | |
| 173 ASSERT_TRUE(s.Step()); | |
| 174 ASSERT_NE(kPageSize, s.ColumnInt(0)); | |
| 175 } | |
| 176 | |
| 177 // Re-open the database to allow setting the page size. | |
| 178 db().Close(); | |
| 179 db().set_page_size(kPageSize); | |
| 180 ASSERT_TRUE(db().Open(db_path())); | |
| 181 | |
| 182 // page_size should match the indicated value. | |
| 183 sql::Statement s(db().GetUniqueStatement("PRAGMA page_size")); | |
| 184 ASSERT_TRUE(s.Step()); | |
| 185 ASSERT_EQ(kPageSize, s.ColumnInt(0)); | |
| 186 | |
| 187 // After raze, page_size should still match the indicated value. | |
| 188 ASSERT_TRUE(db().Raze()); | |
| 189 s.Reset(); | |
| 190 ASSERT_TRUE(s.Step()); | |
| 191 ASSERT_EQ(kPageSize, s.ColumnInt(0)); | |
| 192 } | |
| 193 | |
| 194 // Test that Raze() results are seen in other connections. | |
| 195 TEST_F(SQLConnectionTest, RazeMultiple) { | |
| 196 const char* kCreateSql = "CREATE TABLE foo (id INTEGER PRIMARY KEY, value)"; | |
| 197 ASSERT_TRUE(db().Execute(kCreateSql)); | |
| 198 | |
| 199 sql::Connection other_db; | |
| 200 ASSERT_TRUE(other_db.Open(db_path())); | |
| 201 | |
| 202 // Check that the second connection sees the table. | |
| 203 const char *kTablesQuery = "SELECT COUNT(*) FROM sqlite_master"; | |
| 204 sql::Statement s(other_db.GetUniqueStatement(kTablesQuery)); | |
| 205 ASSERT_TRUE(s.Step()); | |
| 206 ASSERT_EQ(1, s.ColumnInt(0)); | |
| 207 ASSERT_FALSE(s.Step()); // Releases the shared lock. | |
| 208 | |
| 209 ASSERT_TRUE(db().Raze()); | |
| 210 | |
| 211 // The second connection sees the updated database. | |
| 212 s.Reset(); | |
| 213 ASSERT_TRUE(s.Step()); | |
| 214 ASSERT_EQ(0, s.ColumnInt(0)); | |
| 215 } | |
| 216 | |
| 217 TEST_F(SQLConnectionTest, RazeLocked) { | |
| 218 const char* kCreateSql = "CREATE TABLE foo (id INTEGER PRIMARY KEY, value)"; | |
| 219 ASSERT_TRUE(db().Execute(kCreateSql)); | |
| 220 | |
| 221 // Open a transaction and write some data in a second connection. | |
| 222 // This will acquire a PENDING or EXCLUSIVE transaction, which will | |
| 223 // cause the raze to fail. | |
| 224 sql::Connection other_db; | |
| 225 ASSERT_TRUE(other_db.Open(db_path())); | |
| 226 ASSERT_TRUE(other_db.BeginTransaction()); | |
| 227 const char* kInsertSql = "INSERT INTO foo VALUES (1, 'data')"; | |
| 228 ASSERT_TRUE(other_db.Execute(kInsertSql)); | |
| 229 | |
| 230 ASSERT_FALSE(db().Raze()); | |
| 231 | |
| 232 // Works after COMMIT. | |
| 233 ASSERT_TRUE(other_db.CommitTransaction()); | |
| 234 ASSERT_TRUE(db().Raze()); | |
| 235 | |
| 236 // Re-create the database. | |
| 237 ASSERT_TRUE(db().Execute(kCreateSql)); | |
| 238 ASSERT_TRUE(db().Execute(kInsertSql)); | |
| 239 | |
| 240 // An unfinished read transaction in the other connection also | |
| 241 // blocks raze. | |
| 242 const char *kQuery = "SELECT COUNT(*) FROM foo"; | |
| 243 sql::Statement s(other_db.GetUniqueStatement(kQuery)); | |
| 244 ASSERT_TRUE(s.Step()); | |
| 245 ASSERT_FALSE(db().Raze()); | |
| 246 | |
| 247 // Complete the statement unlocks the database. | |
| 248 ASSERT_FALSE(s.Step()); | |
| 249 ASSERT_TRUE(db().Raze()); | |
| 250 } | |
| 251 | |
| 252 // TODO(shess): Spin up a background thread to hold other_db, to more | |
| 253 // closely match real life. That would also allow testing | |
| 254 // RazeWithTimeout(). | |
| OLD | NEW |