summaryrefslogtreecommitdiffstats
path: root/sql/transaction_unittest.cc
blob: fe5eee232d6c97a10640b84fd76d431f8cedc676 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "sql/connection.h"
#include "sql/statement.h"
#include "sql/transaction.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/sqlite/sqlite3.h"

class SQLTransactionTest : public testing::Test {
 public:
  virtual void SetUp() {
    ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
    ASSERT_TRUE(db_.Open(
        temp_dir_.path().AppendASCII("SQLTransactionTest.db")));

    ASSERT_TRUE(db().Execute("CREATE TABLE foo (a, b)"));
  }

  virtual void TearDown() {
    db_.Close();
  }

  sql::Connection& db() { return db_; }

  // Returns the number of rows in table "foo".
  int CountFoo() {
    sql::Statement count(db().GetUniqueStatement("SELECT count(*) FROM foo"));
    count.Step();
    return count.ColumnInt(0);
  }

 private:
  base::ScopedTempDir temp_dir_;
  sql::Connection db_;
};

TEST_F(SQLTransactionTest, Commit) {
  {
    sql::Transaction t(&db());
    EXPECT_FALSE(t.is_open());
    EXPECT_TRUE(t.Begin());
    EXPECT_TRUE(t.is_open());

    EXPECT_TRUE(db().Execute("INSERT INTO foo (a, b) VALUES (1, 2)"));

    t.Commit();
    EXPECT_FALSE(t.is_open());
  }

  EXPECT_EQ(1, CountFoo());
}

TEST_F(SQLTransactionTest, Rollback) {
  // Test some basic initialization, and that rollback runs when you exit the
  // scope.
  {
    sql::Transaction t(&db());
    EXPECT_FALSE(t.is_open());
    EXPECT_TRUE(t.Begin());
    EXPECT_TRUE(t.is_open());

    EXPECT_TRUE(db().Execute("INSERT INTO foo (a, b) VALUES (1, 2)"));
  }

  // Nothing should have been committed since it was implicitly rolled back.
  EXPECT_EQ(0, CountFoo());

  // Test explicit rollback.
  sql::Transaction t2(&db());
  EXPECT_FALSE(t2.is_open());
  EXPECT_TRUE(t2.Begin());

  EXPECT_TRUE(db().Execute("INSERT INTO foo (a, b) VALUES (1, 2)"));
  t2.Rollback();
  EXPECT_FALSE(t2.is_open());

  // Nothing should have been committed since it was explicitly rolled back.
  EXPECT_EQ(0, CountFoo());
}

// Rolling back any part of a transaction should roll back all of them.
TEST_F(SQLTransactionTest, NestedRollback) {
  EXPECT_EQ(0, db().transaction_nesting());

  // Outermost transaction.
  {
    sql::Transaction outer(&db());
    EXPECT_TRUE(outer.Begin());
    EXPECT_EQ(1, db().transaction_nesting());

    // The first inner one gets committed.
    {
      sql::Transaction inner1(&db());
      EXPECT_TRUE(inner1.Begin());
      EXPECT_TRUE(db().Execute("INSERT INTO foo (a, b) VALUES (1, 2)"));
      EXPECT_EQ(2, db().transaction_nesting());

      inner1.Commit();
      EXPECT_EQ(1, db().transaction_nesting());
    }

    // One row should have gotten inserted.
    EXPECT_EQ(1, CountFoo());

    // The second inner one gets rolled back.
    {
      sql::Transaction inner2(&db());
      EXPECT_TRUE(inner2.Begin());
      EXPECT_TRUE(db().Execute("INSERT INTO foo (a, b) VALUES (1, 2)"));
      EXPECT_EQ(2, db().transaction_nesting());

      inner2.Rollback();
      EXPECT_EQ(1, db().transaction_nesting());
    }

    // A third inner one will fail in Begin since one has already been rolled
    // back.
    EXPECT_EQ(1, db().transaction_nesting());
    {
      sql::Transaction inner3(&db());
      EXPECT_FALSE(inner3.Begin());
      EXPECT_EQ(1, db().transaction_nesting());
    }
  }
  EXPECT_EQ(0, db().transaction_nesting());
  EXPECT_EQ(0, CountFoo());
}