Files

152 lines
5.6 KiB
Swift

import XCTest
@testable import GRDB
class BackupTestCase: GRDBTestCase {
// A "user" error simply for testing purposes
private struct AbandonBackupError: Error {}
private func setupBackupSource(_ writer: some DatabaseWriter) throws -> Int {
try writer.write { db in
try db.execute(sql: "CREATE TABLE items (id INTEGER PRIMARY KEY)")
try db.execute(sql: "INSERT INTO items (id) VALUES (0)")
}
let pageCount: Int = try writer.read { db in
try Int.fetchOne(db, sql: "PRAGMA page_count")!
}
// pageCount must be greater than 1 to allow for incremental backup testing
XCTAssertGreaterThan(pageCount, 1)
return pageCount
}
private func setupBackupDestination(_ writer: some DatabaseWriter) throws {
try writer.write { db in
try db.execute(sql: "CREATE TABLE items (id INTEGER PRIMARY KEY)")
try db.execute(sql: "INSERT INTO items (id) VALUES (1)")
}
}
func testDatabaseWriterBackup(from source: some DatabaseWriter, to destination: some DatabaseWriter) throws {
let sourceDbPageCount = try setupBackupSource(source)
try setupBackupDestination(destination)
XCTAssertThrowsError(
try source.backup(to: destination, pagesPerStep: 1) { progress in
XCTAssertLessThan(progress.completedPageCount, progress.totalPageCount)
XCTAssertFalse(progress.isCompleted)
throw AbandonBackupError()
}
)
try destination.read { db in
XCTAssertEqual(try Int.fetchOne(db, sql: "SELECT COUNT(*) FROM items")!, 1)
XCTAssertEqual(try Int.fetchOne(db, sql: "SELECT id FROM items")!, 1)
}
var progressCount: Int = 1
var isCompleted: Bool = false
try source.backup(to: destination, pagesPerStep: 1) { progress in
let expectedCompletedPages = progressCount
XCTAssertEqual(expectedCompletedPages, progress.completedPageCount)
if progress.completedPageCount != progress.totalPageCount {
progressCount += 1
}
if progress.isCompleted {
isCompleted = true
// Should not re-throw
throw AbandonBackupError()
}
}
XCTAssertEqual(sourceDbPageCount, progressCount)
XCTAssertTrue(isCompleted)
try destination.read { db in
XCTAssertEqual(try Int.fetchOne(db, sql: "SELECT COUNT(*) FROM items")!, 1)
XCTAssertEqual(try Int.fetchOne(db, sql: "SELECT id FROM items")!, 0)
}
try source.write { db in
try db.execute(sql: "DROP TABLE items")
}
try source.backup(to: destination)
try destination.read { db in
XCTAssertFalse(try db.tableExists("items"))
}
}
func testDatabaseBackup(from source: some DatabaseWriter, to destination: some DatabaseWriter) throws {
let sourceDbPageCount = try setupBackupSource(source)
try setupBackupDestination(destination)
try source.write { sourceDb in
try destination.barrierWriteWithoutTransaction { destDb in
XCTAssertThrowsError(
try sourceDb.backup(to: destDb, pagesPerStep: 1) { progress in
XCTAssertLessThan(progress.completedPageCount, progress.totalPageCount)
throw AbandonBackupError()
}
)
}
}
// Assert that the items table is as it was before the backup was abandoned.
// Is this a valid assertion?
try destination.read { db in
XCTAssertEqual(try Int.fetchOne(db, sql: "SELECT COUNT(*) FROM items")!, 1)
XCTAssertEqual(try Int.fetchOne(db, sql: "SELECT id FROM items")!, 1)
}
try source.write { dbSource in
try destination.barrierWriteWithoutTransaction { dbDest in
var progressCount: Int = 1
var isCompleted: Bool = false
try dbSource.backup(to: dbDest, pagesPerStep: 1) { progress in
let expectedCompletedPages = progressCount
XCTAssertEqual(expectedCompletedPages, progress.completedPageCount)
if progress.completedPageCount != progress.totalPageCount {
progressCount += 1
}
if progress.isCompleted {
isCompleted = true
// Should not re-throw
throw AbandonBackupError()
}
}
XCTAssertEqual(sourceDbPageCount, progressCount)
XCTAssertTrue(isCompleted)
}
}
try destination.read { db in
XCTAssertEqual(try Int.fetchOne(db, sql: "SELECT COUNT(*) FROM items")!, 1)
XCTAssertEqual(try Int.fetchOne(db, sql: "SELECT id FROM items")!, 0)
}
try source.write { db in
try db.execute(sql: "DROP TABLE items")
}
try source.backup(to: destination)
try destination.read { db in
XCTAssertFalse(try db.tableExists("items"))
}
}
// Test passes if it compiles.
// See <https://github.com/groue/GRDB.swift/issues/1541>
func testBackupToAnyDatabaseWriter(
_ reader: some DatabaseReader,
destination: any DatabaseWriter
) throws {
try reader.backup(to: destination)
}
}