Upload files to "tests"
This commit is contained in:
337
tests/schema_migration_test.lua
Normal file
337
tests/schema_migration_test.lua
Normal file
@@ -0,0 +1,337 @@
|
||||
-- tests/schema_migration_test.lua
|
||||
-- Тестирование миграции схемы данных
|
||||
|
||||
local function setup_schema_test()
|
||||
print("=== Setup Schema Migration Test ===")
|
||||
|
||||
db.execute("CREATE DATABASE IF NOT EXISTS schema_test")
|
||||
db.execute("USE schema_test")
|
||||
|
||||
-- Создаём коллекцию со старой схемой
|
||||
db.execute([[
|
||||
CREATE COLLECTION IF NOT EXISTS products
|
||||
WITH SCHEMA {
|
||||
version = "1.0.0",
|
||||
fields = {
|
||||
_id = {type = "string", required = true},
|
||||
name = {type = "string", required = true},
|
||||
price = {type = "float"}
|
||||
}
|
||||
}
|
||||
]])
|
||||
|
||||
-- Вставляем тестовые данные
|
||||
for i = 1, 50 do
|
||||
db.execute(string.format([[
|
||||
INSERT INTO products VALUES {
|
||||
_id = "prod_%d",
|
||||
name = "Product %d",
|
||||
price = %.2f
|
||||
}
|
||||
]], i, i, math.random(100, 1000) / 100))
|
||||
end
|
||||
|
||||
print("Inserted 50 test products")
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
local function test_schema_version()
|
||||
print("\n=== Test 1: Schema Version ===")
|
||||
|
||||
local version = db.execute("SHOW SCHEMA VERSION")
|
||||
print(string.format("Current schema version: %s", version))
|
||||
|
||||
if version and version ~= "" then
|
||||
print("✅ Schema version retrieved")
|
||||
return true
|
||||
else
|
||||
print("❌ Failed to get schema version")
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
local function test_add_field_migration()
|
||||
print("\n=== Test 2: Add Field Migration ===")
|
||||
|
||||
-- Миграция: добавляем поле description
|
||||
local migration = [[
|
||||
MIGRATE SCHEMA products
|
||||
ADD FIELD description {
|
||||
type = "string",
|
||||
default = "No description",
|
||||
required = false
|
||||
}
|
||||
]]
|
||||
|
||||
local result = db.execute(migration)
|
||||
print("Migration result: " .. tostring(result))
|
||||
|
||||
-- Проверяем, что у старых документов появилось поле description
|
||||
local sample = db.execute("SELECT * FROM products LIMIT 1")
|
||||
local sample_data = db.json_decode(sample)
|
||||
|
||||
if sample_data[1].description == "No description" then
|
||||
print("✅ Field added and default value applied")
|
||||
return true
|
||||
else
|
||||
print("❌ Field migration failed")
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
local function test_change_field_type_migration()
|
||||
print("\n=== Test 3: Change Field Type Migration ===")
|
||||
|
||||
-- Миграция: меняем тип price на string с префиксом "$"
|
||||
local migration = [[
|
||||
MIGRATE SCHEMA products
|
||||
MODIFY FIELD price
|
||||
TYPE string
|
||||
TRANSFORM value -> "$" .. tostring(value)
|
||||
]]
|
||||
|
||||
local result = db.execute(migration)
|
||||
print("Migration result: " .. tostring(result))
|
||||
|
||||
-- Проверяем преобразование
|
||||
local sample = db.execute("SELECT price FROM products LIMIT 1")
|
||||
local sample_data = db.json_decode(sample)
|
||||
|
||||
if string.sub(sample_data[1].price, 1, 1) == "$" then
|
||||
print("✅ Field type conversion successful")
|
||||
return true
|
||||
else
|
||||
print("❌ Field type conversion failed")
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
local function test_rename_field_migration()
|
||||
print("\n=== Test 4: Rename Field Migration ===")
|
||||
|
||||
-- Миграция: переименовываем name в title
|
||||
local migration = [[
|
||||
MIGRATE SCHEMA products
|
||||
RENAME FIELD name TO title
|
||||
]]
|
||||
|
||||
local result = db.execute(migration)
|
||||
print("Migration result: " .. tostring(result))
|
||||
|
||||
-- Проверяем, что поле переименовано
|
||||
local sample = db.execute("SELECT title FROM products LIMIT 1")
|
||||
local sample_data = db.json_decode(sample)
|
||||
|
||||
local check_name = db.execute("SELECT name FROM products LIMIT 1")
|
||||
|
||||
if sample_data[1].title and check_name == "null" then
|
||||
print("✅ Field renamed successfully")
|
||||
return true
|
||||
else
|
||||
print("❌ Field rename failed")
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
local function test_remove_field_migration()
|
||||
print("\n=== Test 5: Remove Field Migration ===")
|
||||
|
||||
-- Миграция: удаляем поле description
|
||||
local migration = [[
|
||||
MIGRATE SCHEMA products
|
||||
REMOVE FIELD description
|
||||
]]
|
||||
|
||||
local result = db.execute(migration)
|
||||
print("Migration result: " .. tostring(result))
|
||||
|
||||
-- Проверяем, что поле удалено
|
||||
local sample = db.execute("SELECT * FROM products LIMIT 1")
|
||||
local sample_data = db.json_decode(sample)
|
||||
|
||||
if sample_data[1].description == nil then
|
||||
print("✅ Field removed successfully")
|
||||
return true
|
||||
else
|
||||
print("❌ Field removal failed")
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
local function test_add_validation_migration()
|
||||
print("\n=== Test 6: Add Validation Migration ===")
|
||||
|
||||
-- Добавляем валидацию для поля price
|
||||
local migration = [[
|
||||
MIGRATE SCHEMA products
|
||||
ADD VALIDATION price {
|
||||
min = 0,
|
||||
max = 10000,
|
||||
type = "float"
|
||||
}
|
||||
]]
|
||||
|
||||
local result = db.execute(migration)
|
||||
print("Migration result: " .. tostring(result))
|
||||
|
||||
-- Проверяем валидацию
|
||||
local success, err = pcall(function()
|
||||
return db.execute("INSERT INTO products VALUES {_id = 'invalid', title = 'Invalid', price = 20000}")
|
||||
end)
|
||||
|
||||
if not success and string.find(err or "", "validation") then
|
||||
print("✅ Validation added and working")
|
||||
return true
|
||||
else
|
||||
print("❌ Validation not working correctly")
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
local function test_rollback_migration()
|
||||
print("\n=== Test 7: Rollback Migration ===")
|
||||
|
||||
-- Сохраняем текущее состояние
|
||||
local before_state = db.execute("SHOW SCHEMA STATUS")
|
||||
|
||||
-- Откатываем последнюю миграцию
|
||||
local result = db.execute("ROLLBACK SCHEMA MIGRATION")
|
||||
print("Rollback result: " .. tostring(result))
|
||||
|
||||
-- Проверяем, что validation убрана
|
||||
local success, err = pcall(function()
|
||||
return db.execute("INSERT INTO products VALUES {_id = 'rollback_test', title = 'Rollback Test', price = 20000}")
|
||||
end)
|
||||
|
||||
if success then
|
||||
print("✅ Rollback successful - validation removed")
|
||||
return true
|
||||
else
|
||||
print("❌ Rollback failed")
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
local function test_schema_migration_history()
|
||||
print("\n=== Test 8: Schema Migration History ===")
|
||||
|
||||
local history = db.execute("SHOW SCHEMA MIGRATION HISTORY")
|
||||
local history_data = db.json_decode(history)
|
||||
|
||||
print("Migration history:")
|
||||
for i, migration in ipairs(history_data) do
|
||||
print(string.format(" %d: %s - %s (applied: %s)",
|
||||
i, migration.id, migration.description,
|
||||
os.date("%Y-%m-%d %H:%M:%S", migration.applied_at / 1000)))
|
||||
end
|
||||
|
||||
if #history_data >= 5 then
|
||||
print("✅ Migration history contains multiple entries")
|
||||
return true
|
||||
else
|
||||
print("⚠️ Migration history shorter than expected")
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
local function test_lazy_schema_migration()
|
||||
print("\n=== Test 9: Lazy Schema Migration ===")
|
||||
|
||||
-- Включаем ленивую миграцию
|
||||
db.execute("SET SCHEMA MIGRATION STRATEGY lazy")
|
||||
|
||||
-- Меняем схему
|
||||
db.execute([[
|
||||
MIGRATE SCHEMA products
|
||||
ADD FIELD tags {
|
||||
type = "array",
|
||||
default = {}
|
||||
}
|
||||
]])
|
||||
|
||||
-- Существующие документы не должны иметь tags сразу
|
||||
local sample = db.execute("SELECT tags FROM products LIMIT 1")
|
||||
local sample_data = db.json_decode(sample)
|
||||
|
||||
-- При первом чтении tags может отсутствовать
|
||||
-- При следующем чтении (после миграции) должно появиться
|
||||
|
||||
print("✅ Lazy migration configured")
|
||||
return true
|
||||
end
|
||||
|
||||
local function test_schema_migration_metrics()
|
||||
print("\n=== Test 10: Schema Migration Metrics ===")
|
||||
|
||||
local metrics = db.execute("SHOW SCHEMA MIGRATION METRICS")
|
||||
local metrics_data = db.json_decode(metrics)
|
||||
|
||||
print("Migration metrics:")
|
||||
for key, value in pairs(metrics_data) do
|
||||
print(string.format(" %s: %s", key, tostring(value)))
|
||||
end
|
||||
|
||||
local required_fields = {
|
||||
"total_migrations",
|
||||
"applied_migrations",
|
||||
"pending_migrations",
|
||||
"current_version"
|
||||
}
|
||||
|
||||
for _, field in ipairs(required_fields) do
|
||||
if metrics_data[field] == nil then
|
||||
print("❌ Missing metric: " .. field)
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
print("✅ All required metrics present")
|
||||
return true
|
||||
end
|
||||
|
||||
local function cleanup_schema()
|
||||
print("\n=== Cleanup ===")
|
||||
db.execute("DROP DATABASE IF EXISTS schema_test")
|
||||
print("Cleanup completed")
|
||||
end
|
||||
|
||||
local function run_all_schema_migration_tests()
|
||||
print("╔══════════════════════════════════════════════════════════════╗")
|
||||
print("║ SCHEMA MIGRATION TESTS SUITE ║")
|
||||
print("╚══════════════════════════════════════════════════════════════╝")
|
||||
|
||||
setup_schema_test()
|
||||
|
||||
local results = {
|
||||
test_schema_version(),
|
||||
test_add_field_migration(),
|
||||
test_change_field_type_migration(),
|
||||
test_rename_field_migration(),
|
||||
test_remove_field_migration(),
|
||||
test_add_validation_migration(),
|
||||
test_rollback_migration(),
|
||||
test_schema_migration_history(),
|
||||
test_lazy_schema_migration(),
|
||||
test_schema_migration_metrics()
|
||||
}
|
||||
|
||||
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_schema()
|
||||
|
||||
return passed == #results
|
||||
end
|
||||
|
||||
return run_all_schema_migration_tests()
|
||||
Reference in New Issue
Block a user