File: spec-transaction-begin-commit-rollback.R

package info (click to toggle)
r-cran-dbitest 1.8.2-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 1,216 kB
  • sloc: sh: 10; makefile: 2
file content (183 lines) | stat: -rw-r--r-- 5,605 bytes parent folder | download
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
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
#' spec_transaction_begin_commit_rollback
#' @family transaction specifications
#' @usage NULL
#' @format NULL
#' @keywords NULL
spec_transaction_begin_commit_rollback <- list(
  begin_formals = function() {
    # <establish formals of described functions>
    expect_equal(names(formals(dbBegin)), c("conn", "..."))
  },
  #
  commit_formals = function() {
    # <establish formals of described functions>
    expect_equal(names(formals(dbCommit)), c("conn", "..."))
  },
  #
  rollback_formals = function() {
    # <establish formals of described functions>
    expect_equal(names(formals(dbRollback)), c("conn", "..."))
  },

  begin_commit_return_value = function(con) {
    #' @return
    #' `dbBegin()`, `dbCommit()` and `dbRollback()` return `TRUE`, invisibly.
    expect_invisible_true(dbBegin(con))
    on.exit({
      dbRollback(con)
    })
    expect_invisible_true(dbCommit(con))
    on.exit(NULL)
  },
  #
  begin_rollback_return_value = function(con) {
    expect_invisible_true(dbBegin(con))
    expect_invisible_true(dbRollback(con))
  },

  #'
  begin_commit_closed = function(ctx, closed_con) {
    #' @section Failure modes:
    #' The implementations are expected to raise an error in case of failure,
    #' but this is not tested.
    #' In any way, all generics throw an error with a closed
    expect_error(dbBegin(closed_con))
    expect_error(dbCommit(closed_con))
    expect_error(dbRollback(closed_con))
  },
  #
  begin_commit_invalid = function(ctx, invalid_con) {
    #' or invalid connection.
    expect_error(dbBegin(invalid_con))
    expect_error(dbCommit(invalid_con))
    expect_error(dbRollback(invalid_con))
  },
  #
  commit_without_begin = function(con) {
    #' In addition, a call to `dbCommit()`
    expect_error(dbCommit(con))
  },
  #
  rollback_without_begin = function(con) {
    #' or `dbRollback()`
    #' without a prior call to `dbBegin()` raises an error.
    expect_error(dbRollback(con))
  },
  #
  begin_begin = function(con) {
    #' Nested transactions are not supported by DBI,
    #' an attempt to call `dbBegin()` twice
    dbBegin(con)
    on.exit({
      dbRollback(con)
    })
    #' yields an error.
    expect_error(dbBegin(con))
    dbCommit(con)
    on.exit(NULL)
  },

  begin_commit = function(con) {
    #' @section Specification:
    #' Actual support for transactions may vary between backends.
    #' A transaction is initiated by a call to `dbBegin()`
    dbBegin(con)
    #' and committed by a call to `dbCommit()`.
    success <- FALSE
    expect_error(
      {
        dbCommit(con)
        success <- TRUE
      },
      NA
    )
    if (!success) dbRollback(con)
  },

  begin_write_commit_1 = function(con) {
    #' Data written in a transaction must persist after the transaction is committed.
    #' For example, a record that is missing when the transaction is started

    # table_name not in formals on purpose: this means that this table won't be
    # removed at the end of the test
    table_name <- "dbit00"
    dbWriteTable(con, table_name, data.frame(a = 0L), overwrite = TRUE)

    dbBegin(con)
    on.exit({
      dbRollback(con)
    })

    #' but is created during the transaction
    dbExecute(con, paste0("INSERT INTO ", table_name, " (a) VALUES (1)"))

    #' must exist
    expect_equal(check_df(dbReadTable(con, table_name)), data.frame(a = 0:1))

    #' both during
    dbCommit(con)
    on.exit(NULL)

    #' and after the transaction,
    expect_equal(check_df(dbReadTable(con, table_name)), data.frame(a = 0:1))
  },
  # second stage
  begin_write_commit_2 = function(con, table_name = "dbit00") {
    #' and also in a new connection.
    expect_true(dbExistsTable(con, table_name))
    expect_equal(check_df(dbReadTable(con, table_name)), data.frame(a = 0:1))
  },
  #
  #'
  begin_rollback = function(con) {
    #' A transaction
    dbBegin(con)
    #' can also be aborted with `dbRollback()`.
    expect_error(dbRollback(con), NA)
  },

  begin_write_rollback = function(con, table_name) {
    #' All data written in such a transaction must be removed after the
    #' transaction is rolled back.
    #' For example, a record that is missing when the transaction is started
    dbWriteTable(con, table_name, data.frame(a = 0L), overwrite = TRUE)

    dbBegin(con)

    #' but is created during the transaction
    dbWriteTable(con, table_name, data.frame(a = 1L), append = TRUE)

    #' must not exist anymore after the rollback.
    dbRollback(con)
    expect_equal(check_df(dbReadTable(con, table_name)), data.frame(a = 0L))
  },
  #
  begin_write_disconnect_1 = function(local_con) {
    # table_name not in formals on purpose: this means that this table won't be
    # removed at the end of the test
    table_name <- "dbit01"
    #'
    #' Disconnection from a connection with an open transaction
    dbWriteTable(local_con, table_name, data.frame(a = 0L), overwrite = TRUE)

    dbBegin(local_con)

    dbWriteTable(local_con, table_name, data.frame(a = 1L), append = TRUE)
  },
  #
  begin_write_disconnect_2 = function(local_con, table_name = "dbit01") {
    #' effectively rolls back the transaction.
    #' All data written in such a transaction must be removed after the
    #' transaction is rolled back.
    expect_equal(check_df(dbReadTable(local_con, table_name)), data.frame(a = 0L))
  },

  #'
  #' The behavior is not specified if other arguments are passed to these
  #' functions. In particular, \pkg{RSQLite} issues named transactions
  #' with support for nesting
  #' if the `name` argument is set.
  #'
  #' The transaction isolation level is not specified by DBI.
  NULL
)