-- 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()