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