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 3 // found in the LICENSE file. 4 5 #include "base/files/file_util.h" 6 #include "base/files/scoped_temp_dir.h" 7 #include "sql/connection.h" 8 #include "sql/statement.h" 9 #include "sql/transaction.h" 10 #include "testing/gtest/include/gtest/gtest.h" 11 #include "third_party/sqlite/sqlite3.h" 12 13 class SQLTransactionTest : public testing::Test { 14 public: 15 virtual void SetUp() { 16 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); 17 ASSERT_TRUE(db_.Open( 18 temp_dir_.path().AppendASCII("SQLTransactionTest.db"))); 19 20 ASSERT_TRUE(db().Execute("CREATE TABLE foo (a, b)")); 21 } 22 23 virtual void TearDown() { 24 db_.Close(); 25 } 26 27 sql::Connection& db() { return db_; } 28 29 // Returns the number of rows in table "foo". 30 int CountFoo() { 31 sql::Statement count(db().GetUniqueStatement("SELECT count(*) FROM foo")); 32 count.Step(); 33 return count.ColumnInt(0); 34 } 35 36 private: 37 base::ScopedTempDir temp_dir_; 38 sql::Connection db_; 39 }; 40 41 TEST_F(SQLTransactionTest, Commit) { 42 { 43 sql::Transaction t(&db()); 44 EXPECT_FALSE(t.is_open()); 45 EXPECT_TRUE(t.Begin()); 46 EXPECT_TRUE(t.is_open()); 47 48 EXPECT_TRUE(db().Execute("INSERT INTO foo (a, b) VALUES (1, 2)")); 49 50 t.Commit(); 51 EXPECT_FALSE(t.is_open()); 52 } 53 54 EXPECT_EQ(1, CountFoo()); 55 } 56 57 TEST_F(SQLTransactionTest, Rollback) { 58 // Test some basic initialization, and that rollback runs when you exit the 59 // scope. 60 { 61 sql::Transaction t(&db()); 62 EXPECT_FALSE(t.is_open()); 63 EXPECT_TRUE(t.Begin()); 64 EXPECT_TRUE(t.is_open()); 65 66 EXPECT_TRUE(db().Execute("INSERT INTO foo (a, b) VALUES (1, 2)")); 67 } 68 69 // Nothing should have been committed since it was implicitly rolled back. 70 EXPECT_EQ(0, CountFoo()); 71 72 // Test explicit rollback. 73 sql::Transaction t2(&db()); 74 EXPECT_FALSE(t2.is_open()); 75 EXPECT_TRUE(t2.Begin()); 76 77 EXPECT_TRUE(db().Execute("INSERT INTO foo (a, b) VALUES (1, 2)")); 78 t2.Rollback(); 79 EXPECT_FALSE(t2.is_open()); 80 81 // Nothing should have been committed since it was explicitly rolled back. 82 EXPECT_EQ(0, CountFoo()); 83 } 84 85 // Rolling back any part of a transaction should roll back all of them. 86 TEST_F(SQLTransactionTest, NestedRollback) { 87 EXPECT_EQ(0, db().transaction_nesting()); 88 89 // Outermost transaction. 90 { 91 sql::Transaction outer(&db()); 92 EXPECT_TRUE(outer.Begin()); 93 EXPECT_EQ(1, db().transaction_nesting()); 94 95 // The first inner one gets committed. 96 { 97 sql::Transaction inner1(&db()); 98 EXPECT_TRUE(inner1.Begin()); 99 EXPECT_TRUE(db().Execute("INSERT INTO foo (a, b) VALUES (1, 2)")); 100 EXPECT_EQ(2, db().transaction_nesting()); 101 102 inner1.Commit(); 103 EXPECT_EQ(1, db().transaction_nesting()); 104 } 105 106 // One row should have gotten inserted. 107 EXPECT_EQ(1, CountFoo()); 108 109 // The second inner one gets rolled back. 110 { 111 sql::Transaction inner2(&db()); 112 EXPECT_TRUE(inner2.Begin()); 113 EXPECT_TRUE(db().Execute("INSERT INTO foo (a, b) VALUES (1, 2)")); 114 EXPECT_EQ(2, db().transaction_nesting()); 115 116 inner2.Rollback(); 117 EXPECT_EQ(1, db().transaction_nesting()); 118 } 119 120 // A third inner one will fail in Begin since one has already been rolled 121 // back. 122 EXPECT_EQ(1, db().transaction_nesting()); 123 { 124 sql::Transaction inner3(&db()); 125 EXPECT_FALSE(inner3.Begin()); 126 EXPECT_EQ(1, db().transaction_nesting()); 127 } 128 } 129 EXPECT_EQ(0, db().transaction_nesting()); 130 EXPECT_EQ(0, CountFoo()); 131 } 132