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
)
|