138 lines
6.9 KiB
Swift
138 lines
6.9 KiB
Swift
import XCTest
|
|
import GRDB
|
|
|
|
class DatabaseAfterNextTransactionCommitTests: GRDBTestCase {
|
|
|
|
func testTransactionCompletions() throws {
|
|
// implicit transaction
|
|
try assertTransaction(start: "", end: "CREATE TABLE t(a)", isNotifiedAs: .commit)
|
|
|
|
// explicit commit
|
|
try assertTransaction(start: "BEGIN DEFERRED TRANSACTION", end: "COMMIT", isNotifiedAs: .commit)
|
|
try assertTransaction(start: "BEGIN DEFERRED TRANSACTION; CREATE TABLE t(a)", end: "COMMIT", isNotifiedAs: .commit)
|
|
try assertTransaction(start: "BEGIN IMMEDIATE TRANSACTION", end: "COMMIT", isNotifiedAs: .commit)
|
|
try assertTransaction(start: "BEGIN IMMEDIATE TRANSACTION; CREATE TABLE t(a)", end: "COMMIT", isNotifiedAs: .commit)
|
|
try assertTransaction(start: "BEGIN EXCLUSIVE TRANSACTION", end: "COMMIT", isNotifiedAs: .commit)
|
|
try assertTransaction(start: "BEGIN EXCLUSIVE TRANSACTION; CREATE TABLE t(a)", end: "COMMIT", isNotifiedAs: .commit)
|
|
try assertTransaction(start: "SAVEPOINT test", end: "COMMIT", isNotifiedAs: .commit)
|
|
try assertTransaction(start: "SAVEPOINT test; CREATE TABLE t(a)", end: "COMMIT", isNotifiedAs: .commit)
|
|
try assertTransaction(start: "SAVEPOINT test; ROLLBACK TRANSACTION TO SAVEPOINT test", end: "RELEASE SAVEPOINT test", isNotifiedAs: .commit)
|
|
try assertTransaction(start: "SAVEPOINT test; CREATE TABLE t(a); ROLLBACK TRANSACTION TO SAVEPOINT test", end: "RELEASE SAVEPOINT test", isNotifiedAs: .commit)
|
|
try assertTransaction(start: "SAVEPOINT test", end: "RELEASE SAVEPOINT test", isNotifiedAs: .commit)
|
|
try assertTransaction(start: "SAVEPOINT test; CREATE TABLE t(a)", end: "RELEASE SAVEPOINT test", isNotifiedAs: .commit)
|
|
|
|
// explicit rollback
|
|
try assertTransaction(start: "BEGIN DEFERRED TRANSACTION", end: "ROLLBACK", isNotifiedAs: .rollback)
|
|
try assertTransaction(start: "BEGIN DEFERRED TRANSACTION; CREATE TABLE t(a)", end: "ROLLBACK", isNotifiedAs: .rollback)
|
|
try assertTransaction(start: "BEGIN IMMEDIATE TRANSACTION", end: "ROLLBACK", isNotifiedAs: .rollback)
|
|
try assertTransaction(start: "BEGIN IMMEDIATE TRANSACTION; CREATE TABLE t(a)", end: "ROLLBACK", isNotifiedAs: .rollback)
|
|
try assertTransaction(start: "BEGIN EXCLUSIVE TRANSACTION", end: "ROLLBACK", isNotifiedAs: .rollback)
|
|
try assertTransaction(start: "BEGIN EXCLUSIVE TRANSACTION; CREATE TABLE t(a)", end: "ROLLBACK", isNotifiedAs: .rollback)
|
|
try assertTransaction(start: "SAVEPOINT test", end: "ROLLBACK", isNotifiedAs: .rollback)
|
|
try assertTransaction(start: "SAVEPOINT test; CREATE TABLE t(a)", end: "ROLLBACK", isNotifiedAs: .rollback)
|
|
}
|
|
|
|
func assertTransaction(start startSQL: String, end endSQL: String, isNotifiedAs expectedCompletion: Database.TransactionCompletion) throws {
|
|
try assertTransaction_registerBefore(start: startSQL, end: endSQL, isNotifiedAs: expectedCompletion)
|
|
try assertTransaction_registerBetween(start: startSQL, end: endSQL, isNotifiedAs: expectedCompletion)
|
|
}
|
|
|
|
func assertTransaction_registerBefore(start startSQL: String, end endSQL: String, isNotifiedAs expectedCompletion: Database.TransactionCompletion) throws {
|
|
class Witness { }
|
|
|
|
let dbQueue = try makeDatabaseQueue()
|
|
try dbQueue.writeWithoutTransaction { db in
|
|
var commitCount = 0
|
|
weak var deallocationWitness: Witness? = nil
|
|
do {
|
|
let witness = Witness()
|
|
deallocationWitness = witness
|
|
// Usage test: single closure (the onCommit one)
|
|
db.afterNextTransaction { _ in
|
|
// use witness
|
|
withExtendedLifetime(witness, { })
|
|
commitCount += 1
|
|
}
|
|
}
|
|
|
|
XCTAssertNotNil(deallocationWitness)
|
|
XCTAssertEqual(commitCount, 0)
|
|
try db.execute(sql: startSQL)
|
|
try db.execute(sql: endSQL)
|
|
switch expectedCompletion {
|
|
case .commit:
|
|
XCTAssertEqual(commitCount, 1, "\(startSQL); \(endSQL)")
|
|
case .rollback:
|
|
XCTAssertEqual(commitCount, 0, "\(startSQL); \(endSQL)")
|
|
}
|
|
XCTAssertNil(deallocationWitness)
|
|
|
|
try db.inTransaction {
|
|
try db.execute(sql: "DROP TABLE IF EXISTS t; CREATE TABLE t(a); ")
|
|
return .commit
|
|
}
|
|
switch expectedCompletion {
|
|
case .commit:
|
|
XCTAssertEqual(commitCount, 1, "\(startSQL); \(endSQL)")
|
|
case .rollback:
|
|
XCTAssertEqual(commitCount, 0, "\(startSQL); \(endSQL)")
|
|
}
|
|
}
|
|
}
|
|
|
|
func assertTransaction_registerBetween(start startSQL: String, end endSQL: String, isNotifiedAs expectedCompletion: Database.TransactionCompletion) throws {
|
|
class Witness { }
|
|
|
|
let dbQueue = try makeDatabaseQueue()
|
|
try dbQueue.writeWithoutTransaction { db in
|
|
var commitCount = 0
|
|
var rollbackCount = 0
|
|
try db.execute(sql: startSQL)
|
|
|
|
weak var deallocationWitness: Witness? = nil
|
|
do {
|
|
let witness = Witness()
|
|
deallocationWitness = witness
|
|
// Usage test: both closure
|
|
db.afterNextTransaction(
|
|
onCommit: { _ in
|
|
// use witness
|
|
withExtendedLifetime(witness, { })
|
|
commitCount += 1
|
|
},
|
|
onRollback: { _ in
|
|
// use witness
|
|
withExtendedLifetime(witness, { })
|
|
rollbackCount += 1
|
|
})
|
|
}
|
|
|
|
XCTAssertNotNil(deallocationWitness)
|
|
XCTAssertEqual(commitCount, 0)
|
|
try db.execute(sql: endSQL)
|
|
switch expectedCompletion {
|
|
case .commit:
|
|
XCTAssertEqual(commitCount, 1, "\(startSQL); \(endSQL)")
|
|
XCTAssertEqual(rollbackCount, 0, "\(startSQL); \(endSQL)")
|
|
case .rollback:
|
|
XCTAssertEqual(commitCount, 0, "\(startSQL); \(endSQL)")
|
|
XCTAssertEqual(rollbackCount, 1, "\(startSQL); \(endSQL)")
|
|
}
|
|
XCTAssertNil(deallocationWitness)
|
|
|
|
try db.inTransaction {
|
|
try db.execute(sql: "DROP TABLE IF EXISTS t; CREATE TABLE t(a); ")
|
|
return .commit
|
|
}
|
|
switch expectedCompletion {
|
|
case .commit:
|
|
XCTAssertEqual(commitCount, 1, "\(startSQL); \(endSQL)")
|
|
XCTAssertEqual(rollbackCount, 0, "\(startSQL); \(endSQL)")
|
|
case .rollback:
|
|
XCTAssertEqual(commitCount, 0, "\(startSQL); \(endSQL)")
|
|
XCTAssertEqual(rollbackCount, 1, "\(startSQL); \(endSQL)")
|
|
}
|
|
}
|
|
}
|
|
}
|