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 13class SQLTransactionTest : public testing::Test { 14 public: 15 SQLTransactionTest() {} 16 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 25 void TearDown() { 26 db_.Close(); 27 } 28 29 sql::Connection& db() { return db_; } 30 31 // Returns the number of rows in table "foo". 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 43TEST_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 59TEST_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. 88TEST_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