Files
futriix/tests/backup_test.lua

350 lines
12 KiB
Lua
Raw Permalink Normal View History

2026-06-12 18:07:05 +00:00
-- tests/backup_test.lua
-- Тестирование бэкапов и восстановления
local function setup_backup_test()
print("=== Setup Backup Test ===")
db.execute("CREATE DATABASE IF NOT EXISTS backup_test")
db.execute("USE backup_test")
db.execute([[
CREATE COLLECTION IF NOT EXISTS users
]])
-- Вставляем тестовые данные
for i = 1, 100 do
db.execute(string.format([[
INSERT INTO users VALUES {
_id = "user_%d",
name = "User %d",
email = "user%d@test.com",
score = %d,
created_at = %d
}
]], i, i, i, math.random(1, 1000), os.time() * 1000))
end
print("Inserted 100 test documents")
-- Включаем планировщик бэкапов
db.execute([[
SET BACKUP SCHEDULE daily_backup
WITH CRON "0 0 * * *"
TYPE full
RETENTION 7
]])
return true
end
local function test_full_backup()
print("\n=== Test 1: Full Backup ===")
-- Запускаем полный бэкап
local result = db.execute("BACKUP DATABASE backup_test TO full_backup.msgpack")
print("Backup result: " .. tostring(result))
-- Проверяем, что файл бэкапа создан
local backup_info = db.execute("SHOW BACKUP INFO")
local info = db.json_decode(backup_info)
print(string.format("Backup ID: %s", info.id or "unknown"))
print(string.format("Backup size: %d bytes", info.size_bytes or 0))
print(string.format("Backup time: %s", info.end_time or "unknown"))
if info.id and info.size_bytes > 0 then
print("✅ Full backup completed successfully")
return info.id
else
print("❌ Full backup failed")
return nil
end
end
local function test_incremental_backup()
print("\n=== Test 2: Incremental Backup ===")
-- Добавляем новые документы после полного бэкапа
for i = 101, 150 do
db.execute(string.format([[
INSERT INTO users VALUES {
_id = "user_%d",
name = "New User %d",
email = "newuser%d@test.com",
score = %d,
created_at = %d
}
]], i, i, i, math.random(1, 1000), os.time() * 1000))
end
print("Added 50 new documents")
-- Запускаем инкрементальный бэкап
local result = db.execute("BACKUP DATABASE backup_test INCREMENTAL TO inc_backup.msgpack")
print("Incremental backup result: " .. tostring(result))
local backup_info = db.execute("SHOW BACKUP INFO inc_backup")
local info = db.json_decode(backup_info)
if info and info.type == "incremental" then
print(string.format("Incremental backup: %d entries", info.entries_count or 0))
print("✅ Incremental backup completed successfully")
return true
else
print("❌ Incremental backup failed")
return false
end
end
local function test_backup_restore()
print("\n=== Test 3: Backup Restore ===")
-- Создаём новую БД для восстановления
db.execute("CREATE DATABASE IF NOT EXISTS restore_test")
-- Восстанавливаем из полного бэкапа
local result = db.execute("RESTORE DATABASE restore_test FROM full_backup.msgpack")
print("Restore result: " .. tostring(result))
-- Проверяем количество документов
db.execute("USE restore_test")
local count = db.execute("SELECT COUNT(*) FROM users")
local count_data = db.json_decode(count)
print(string.format("Restored documents: %d", count_data[1].count or 0))
if count_data[1].count == 100 then
print("✅ Full restore successful")
return true
else
print("❌ Restore failed: expected 100 documents")
return false
end
end
local function test_incremental_restore()
print("\n=== Test 4: Incremental Restore ===")
-- Создаём другую БД для теста инкрементального восстановления
db.execute("CREATE DATABASE IF NOT EXISTS inc_restore_test")
-- Восстанавливаем сначала полный бэкап
db.execute("USE inc_restore_test")
db.execute("RESTORE DATABASE inc_restore_test FROM full_backup.msgpack")
local before_count = db.execute("SELECT COUNT(*) FROM users")
local before_data = db.json_decode(before_count)
print(string.format("After full restore: %d documents", before_data[1].count or 0))
-- Затем применяем инкрементальный
db.execute("RESTORE DATABASE inc_restore_test INCREMENTAL FROM inc_backup.msgpack")
local after_count = db.execute("SELECT COUNT(*) FROM users")
local after_data = db.json_decode(after_count)
print(string.format("After incremental restore: %d documents", after_data[1].count or 0))
if after_data[1].count == 150 then
print("✅ Incremental restore successful")
return true
else
print(string.format("❌ Expected 150 documents, got %d", after_data[1].count or 0))
return false
end
end
local function test_backup_schedule()
print("\n=== Test 5: Backup Schedule ===")
local schedules = db.execute("SHOW BACKUP SCHEDULES")
local schedules_data = db.json_decode(schedules)
print("Current backup schedules:")
for _, schedule in ipairs(schedules_data) do
print(string.format(" %s: cron='%s', type='%s', enabled=%s",
schedule.name, schedule.cron_expr, schedule.type, tostring(schedule.enabled)))
end
if #schedules_data > 0 then
print("✅ Backup schedules configured correctly")
return true
else
print("⚠️ No backup schedules found")
return false
end
end
local function test_backup_compression()
print("\n=== Test 6: Backup Compression ===")
-- Включаем сжатие
db.execute("SET BACKUP COMPRESSION true")
-- Создаём много данных для бэкапа
for i = 1, 1000 do
db.execute(string.format([[
INSERT INTO users VALUES {
_id = "compress_%d",
data = "%s"
}
]], i, string.rep("x", 1000)))
end
local start_time = os.clock()
db.execute("BACKUP DATABASE backup_test TO compressed_backup.msgpack WITH COMPRESSION")
local duration = os.clock() - start_time
local backup_info = db.execute("SHOW BACKUP INFO compressed_backup")
local info = db.json_decode(backup_info)
print(string.format("Compressed backup size: %d bytes", info.size_bytes or 0))
print(string.format("Compression time: %.2fs", duration))
if info.size_bytes and info.size_bytes > 0 then
print("✅ Backup compression working")
return true
else
print("❌ Backup compression failed")
return false
end
end
local function test_backup_retention()
print("\n=== Test 7: Backup Retention ===")
-- Создаём несколько старых бэкапов (симуляция)
for i = 1, 10 do
db.execute(string.format("BACKUP DATABASE backup_test TO old_backup_%d.msgpack", i))
end
-- Устанавливаем retention на 5 дней
db.execute("SET BACKUP RETENTION 5")
-- Запускаем очистку
db.execute("CLEANUP BACKUPS")
local backups = db.execute("SHOW BACKUPS")
local backups_data = db.json_decode(backups)
print(string.format("Remaining backups after cleanup: %d", #backups_data))
-- Проверяем, что не все бэкапы удалены
if #backups_data > 0 then
print("✅ Backup retention working")
return true
else
print("⚠️ All backups cleaned up, retention may be too aggressive")
return false
end
end
local function test_backup_verify()
print("\n=== Test 8: Backup Verification ===")
-- Проверяем целостность бэкапа
local result = db.execute("VERIFY BACKUP full_backup.msgpack")
local verify_result = db.json_decode(result)
print(string.format("Verification result: %s", verify_result.valid and "VALID" or "INVALID"))
print(string.format("Checksum match: %s", tostring(verify_result.checksum_match)))
print(string.format("Corruption detected: %s", tostring(verify_result.corrupted)))
if verify_result.valid then
print("✅ Backup verification passed")
return true
else
print("❌ Backup verification failed")
return false
end
end
local function test_backup_parallel()
print("\n=== Test 9: Parallel Backups ===")
-- Проверяем, что параллельные бэкапы блокируются
local results = {}
local function run_backup(name)
local success, err = pcall(function()
return db.execute(string.format("BACKUP DATABASE backup_test TO parallel_%s.msgpack", name))
end)
return success
end
-- Запускаем 3 параллельных бэкапа
local threads = {}
for i = 1, 3 do
table.insert(threads, coroutine.create(function()
local result = run_backup(tostring(i))
coroutine.yield(result)
end))
end
for _, thread in ipairs(threads) do
coroutine.resume(thread)
end
local success_count = 0
for _, thread in ipairs(threads) do
local success = coroutine.resume(thread)
if success then success_count = success_count + 1 end
end
print(string.format("Parallel backups completed: %d/3 succeeded", success_count))
if success_count == 1 then
print("✅ Parallel backups correctly limited to 1")
return true
else
print("⚠️ Parallel backup behavior may need tuning")
return false
end
end
local function cleanup_backup()
print("\n=== Cleanup ===")
db.execute("DROP DATABASE IF EXISTS backup_test")
db.execute("DROP DATABASE IF EXISTS restore_test")
db.execute("DROP DATABASE IF EXISTS inc_restore_test")
print("Cleanup completed")
end
local function run_all_backup_tests()
print("╔══════════════════════════════════════════════════════════════╗")
print("║ BACKUP TESTS SUITE ║")
print("╚══════════════════════════════════════════════════════════════╝")
setup_backup_test()
local full_backup_id = test_full_backup()
local results = {
full_backup_id ~= nil,
test_incremental_backup(),
test_backup_restore(),
test_incremental_restore(),
test_backup_schedule(),
test_backup_compression(),
test_backup_retention(),
test_backup_verify(),
test_backup_parallel()
}
print("\n╔══════════════════════════════════════════════════════════════╗")
print("║ TEST RESULTS ║")
print("╚══════════════════════════════════════════════════════════════╝")
local passed = 0
for i, result in ipairs(results) do
local status = result and "✅ PASSED" or "⚠️ SKIPPED/FAILED"
print(string.format("Test %d: %s", i, status))
if result then passed = passed + 1 end
end
print(string.format("\nTotal: %d/%d tests passed", passed, #results))
cleanup_backup()
return passed == #results
end
return run_all_backup_tests()