diff --git a/lib/tasks/litestream_tasks.rake b/lib/tasks/litestream_tasks.rake index 8b2316d..edeffe1 100644 --- a/lib/tasks/litestream_tasks.rake +++ b/lib/tasks/litestream_tasks.rake @@ -93,23 +93,53 @@ namespace :litestream do options.symbolize_keys! result = Litestream::Commands.verify(database, async: true, **options) - - puts <<~TXT if result - - tables - original #{result["original"]["tables"]} - restored #{result["restored"]["tables"]} - delta #{result["original"]["tables"] - result["restored"]["tables"]} - - indexes - original #{result["original"]["indexes"]} - restored #{result["restored"]["indexes"]} - delta #{result["original"]["indexes"] - result["restored"]["indexes"]} - - rows - original #{result["original"]["rows"]} - restored #{result["restored"]["rows"]} - delta #{result["original"]["rows"] - result["restored"]["rows"]} - TXT + original_tables = result["original"]["tables"] + restored_tables = result["restored"]["tables"] + original_indexes = result["original"]["indexes"] + restored_indexes = result["restored"]["indexes"] + original_rows = result["original"]["rows"] + restored_rows = result["restored"]["rows"] + + same_number_of_tables = original_tables == restored_tables + same_number_of_indexes = original_indexes == restored_indexes + same_number_of_rows = original_rows == restored_rows + + if same_number_of_tables && same_number_of_indexes && same_number_of_rows + puts "Backup for `#{database}` verified as consistent!\n" + [ + " tables #{original_tables}", + " indexes #{original_indexes}", + " rows #{original_rows}" + ].compact.join("\n") + else + abort "Verification failed for #{database}:\n" + [ + (unless same_number_of_tables + if original_tables > restored_tables + diff = original_tables - restored_tables + " Backup is missing #{diff} table#{"s" if diff > 1}" + else + diff = restored_tables - original_tables + " Backup has extra #{diff} table#{"s" if diff > 1}" + end + end), + (unless same_number_of_indexes + if original_indexes > restored_indexes + diff = original_indexes - restored_indexes + " Backup is missing #{diff} index#{"es" if diff > 1}" + else + diff = restored_indexes - original_indexes + " Backup has extra #{diff} index#{"es" if diff > 1}" + end + end), + (unless same_number_of_rows + if original_rows > restored_rows + diff = original_rows - restored_rows + " Backup is missing #{diff} row#{"s" if diff > 1}" + else + diff = restored_rows - original_rows + " Backup has extra #{diff} row#{"s" if diff > 1}" + end + end) + ].compact.join("\n") + end end end diff --git a/test/tasks/test_litestream_tasks.rb b/test/tasks/test_litestream_tasks.rb index a21832f..02af4ee 100644 --- a/test/tasks/test_litestream_tasks.rb +++ b/test/tasks/test_litestream_tasks.rb @@ -219,74 +219,67 @@ def test_snapshots_task_with_arguments_without_separator end class TestVerifyTask < TestLitestreamTasks - def test_verify_task_with_only_database_using_single_dash + def test_verify_task_with_only_database_using_single_dash_failing ARGV.replace ["--", "-database=db/test.sqlite3"] fake = Minitest::Mock.new - out = nil - fake.expect :call, {"original" => {"tables" => 2, "indexes" => 2, "rows" => 2}, "restored" => {"tables" => 1, "indexes" => 1, "rows" => 1}}, ["db/test.sqlite3"], async: true + fake.expect :call, + {"original" => {"tables" => 2, "indexes" => 4, "rows" => 6}, "restored" => {"tables" => 1, "indexes" => 2, "rows" => 3}}, + ["db/test.sqlite3"], + async: true Litestream::Commands.stub :verify, fake do - out, _err = capture_io do - Rake.application.invoke_task "litestream:verify" + error = assert_raises SystemExit do + capture_io { Rake.application.invoke_task "litestream:verify" } end + assert_match("Verification failed for db/test.sqlite3", error.message) + assert_match("Backup is missing 1 table", error.message) + assert_match("Backup is missing 2 indexes", error.message) + assert_match("Backup is missing 3 rows", error.message) end fake.verify - assert_match(/tables\s+original\s+2\s+restored\s+1/, out) - assert_match(/indexes\s+original\s+2\s+restored\s+1/, out) - assert_match(/rows\s+original\s+2\s+restored\s+1/, out) end - def test_verify_task_with_only_database_using_double_dash + def test_verify_task_with_only_database_using_double_dash_failing ARGV.replace ["--", "--database=db/test.sqlite3"] fake = Minitest::Mock.new - out = nil - fake.expect :call, {"original" => {"tables" => 2, "indexes" => 2, "rows" => 2}, "restored" => {"tables" => 1, "indexes" => 1, "rows" => 1}}, ["db/test.sqlite3"], async: true + fake.expect :call, + {"original" => {"tables" => 1, "indexes" => 2, "rows" => 3}, "restored" => {"tables" => 2, "indexes" => 4, "rows" => 6}}, + ["db/test.sqlite3"], + async: true Litestream::Commands.stub :verify, fake do - out, _err = capture_io do - Rake.application.invoke_task "litestream:verify" + error = assert_raises SystemExit do + capture_io { Rake.application.invoke_task "litestream:verify" } end + assert_match("Verification failed for db/test.sqlite3", error.message) + assert_match("Backup has extra 1 table", error.message) + assert_match("Backup has extra 2 indexes", error.message) + assert_match("Backup has extra 3 rows", error.message) end fake.verify - assert_match(/tables\s+original\s+2\s+restored\s+1/, out) - assert_match(/indexes\s+original\s+2\s+restored\s+1/, out) - assert_match(/rows\s+original\s+2\s+restored\s+1/, out) end - def test_verify_task_with_arguments + def test_verify_task_with_arguments_succeeding ARGV.replace ["--", "-database=db/test.sqlite3", "--if-db-not-exists"] fake = Minitest::Mock.new out = nil - fake.expect :call, {"original" => {"tables" => 2, "indexes" => 2, "rows" => 2}, "restored" => {"tables" => 1, "indexes" => 1, "rows" => 1}}, ["db/test.sqlite3"], async: true, "--if-db-not-exists": nil - - Litestream::Commands.stub :verify, fake do - out, _err = capture_io do - Rake.application.invoke_task "litestream:verify" - end - end - - fake.verify - assert_match(/tables\s+original\s+2\s+restored\s+1/, out) - assert_match(/indexes\s+original\s+2\s+restored\s+1/, out) - assert_match(/rows\s+original\s+2\s+restored\s+1/, out) - end - - def test_verify_task_with_arguments_without_separator - ARGV.replace ["-database=db/test.sqlite3"] - fake = Minitest::Mock.new - out = nil - fake.expect :call, nil, [nil], async: true + fake.expect :call, + {"original" => {"tables" => 2, "indexes" => 2, "rows" => 2}, "restored" => {"tables" => 2, "indexes" => 2, "rows" => 2}}, + ["db/test.sqlite3"], + async: true, + "--if-db-not-exists": nil Litestream::Commands.stub :verify, fake do - out, _err = capture_io do - Rake.application.invoke_task "litestream:verify" - end + out, _err = capture_io { Rake.application.invoke_task "litestream:verify" } + assert_match("Backup for `db/test.sqlite3` verified as consistent!", out) + assert_match("tables 2", out) + assert_match("indexes 2", out) + assert_match("rows 2", out) end fake.verify - assert_equal "", out end end end