test migration script
This commit is contained in:
@@ -21,7 +21,7 @@
|
|||||||
"db:migrate:undo:all": "sequelize-cli db:migrate:undo:all",
|
"db:migrate:undo:all": "sequelize-cli db:migrate:undo:all",
|
||||||
"db:migrate:status": "sequelize-cli db:migrate:status",
|
"db:migrate:status": "sequelize-cli db:migrate:status",
|
||||||
"db:create": "sequelize-cli db:create",
|
"db:create": "sequelize-cli db:create",
|
||||||
"test:migrations": "node scripts/test-migrations.js",
|
"test:migrations": "NODE_ENV=test node scripts/test-migrations.js",
|
||||||
"alpha:add": "NODE_ENV=dev node scripts/manageAlphaInvitations.js add",
|
"alpha:add": "NODE_ENV=dev node scripts/manageAlphaInvitations.js add",
|
||||||
"alpha:list": "NODE_ENV=dev node scripts/manageAlphaInvitations.js list",
|
"alpha:list": "NODE_ENV=dev node scripts/manageAlphaInvitations.js list",
|
||||||
"alpha:revoke": "NODE_ENV=dev node scripts/manageAlphaInvitations.js revoke",
|
"alpha:revoke": "NODE_ENV=dev node scripts/manageAlphaInvitations.js revoke",
|
||||||
|
|||||||
225
backend/scripts/test-migrations.js
Normal file
225
backend/scripts/test-migrations.js
Normal file
@@ -0,0 +1,225 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Migration Test Script
|
||||||
|
*
|
||||||
|
* Tests that all migrations can run successfully up and down.
|
||||||
|
* This script:
|
||||||
|
* 1. Connects to a test database
|
||||||
|
* 2. Runs all migrations down (clean slate)
|
||||||
|
* 3. Runs all migrations up
|
||||||
|
* 4. Verifies tables were created
|
||||||
|
* 5. Runs all migrations down (test rollback)
|
||||||
|
* 6. Runs all migrations up again (test idempotency)
|
||||||
|
* 7. Reports results
|
||||||
|
*
|
||||||
|
* Usage:
|
||||||
|
* NODE_ENV=test npm run test:migrations
|
||||||
|
*
|
||||||
|
* Requires:
|
||||||
|
* - Test database to exist (create with: npm run db:create)
|
||||||
|
* - Environment variables set for test database connection
|
||||||
|
*/
|
||||||
|
|
||||||
|
const { execSync } = require("child_process");
|
||||||
|
const path = require("path");
|
||||||
|
|
||||||
|
// Colors for console output
|
||||||
|
const colors = {
|
||||||
|
reset: "\x1b[0m",
|
||||||
|
green: "\x1b[32m",
|
||||||
|
red: "\x1b[31m",
|
||||||
|
yellow: "\x1b[33m",
|
||||||
|
blue: "\x1b[34m",
|
||||||
|
};
|
||||||
|
|
||||||
|
function log(message, color = colors.reset) {
|
||||||
|
console.log(`${color}${message}${colors.reset}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
function logStep(step, message) {
|
||||||
|
log(`\n[${step}] ${message}`, colors.blue);
|
||||||
|
}
|
||||||
|
|
||||||
|
function logSuccess(message) {
|
||||||
|
log(` ✓ ${message}`, colors.green);
|
||||||
|
}
|
||||||
|
|
||||||
|
function logError(message) {
|
||||||
|
log(` ✗ ${message}`, colors.red);
|
||||||
|
}
|
||||||
|
|
||||||
|
function logWarning(message) {
|
||||||
|
log(` ⚠ ${message}`, colors.yellow);
|
||||||
|
}
|
||||||
|
|
||||||
|
function runCommand(command, description) {
|
||||||
|
try {
|
||||||
|
log(` Running: ${command}`, colors.yellow);
|
||||||
|
const output = execSync(command, {
|
||||||
|
cwd: path.resolve(__dirname, ".."),
|
||||||
|
encoding: "utf-8",
|
||||||
|
stdio: ["pipe", "pipe", "pipe"],
|
||||||
|
env: { ...process.env, NODE_ENV: process.env.NODE_ENV || "test" },
|
||||||
|
});
|
||||||
|
if (output.trim()) {
|
||||||
|
console.log(output);
|
||||||
|
}
|
||||||
|
logSuccess(description);
|
||||||
|
return { success: true, output };
|
||||||
|
} catch (error) {
|
||||||
|
logError(`${description} failed`);
|
||||||
|
console.error(error.stderr || error.message);
|
||||||
|
return { success: false, error };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
log("\n========================================", colors.blue);
|
||||||
|
log(" Migration Test Suite", colors.blue);
|
||||||
|
log("========================================\n", colors.blue);
|
||||||
|
|
||||||
|
const env = process.env.NODE_ENV;
|
||||||
|
|
||||||
|
// Safety checks - only allow running against test database
|
||||||
|
if (!env) {
|
||||||
|
logError("NODE_ENV is not set!");
|
||||||
|
logError("This script will DELETE ALL DATA in the target database.");
|
||||||
|
logError("You must explicitly set NODE_ENV=test to run this script.");
|
||||||
|
log("\nUsage: NODE_ENV=test npm run test:migrations\n");
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (env.toLowerCase() !== "test") {
|
||||||
|
logWarning(`Unrecognized NODE_ENV: ${env}`);
|
||||||
|
logWarning("This script will DELETE ALL DATA in the target database.");
|
||||||
|
logWarning("Recommended: NODE_ENV=test npm run test:migrations");
|
||||||
|
log("");
|
||||||
|
}
|
||||||
|
|
||||||
|
log(`Environment: ${env}`);
|
||||||
|
|
||||||
|
const results = {
|
||||||
|
steps: [],
|
||||||
|
passed: 0,
|
||||||
|
failed: 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
function recordResult(step, success) {
|
||||||
|
results.steps.push({ step, success });
|
||||||
|
if (success) {
|
||||||
|
results.passed++;
|
||||||
|
} else {
|
||||||
|
results.failed++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 1: Check migration status
|
||||||
|
logStep(1, "Checking current migration status");
|
||||||
|
const statusResult = runCommand(
|
||||||
|
"npx sequelize-cli db:migrate:status",
|
||||||
|
"Migration status check"
|
||||||
|
);
|
||||||
|
recordResult("Status check", statusResult.success);
|
||||||
|
|
||||||
|
// Step 2: Undo all migrations (clean slate)
|
||||||
|
logStep(2, "Undoing all migrations (clean slate)");
|
||||||
|
const undoAllResult = runCommand(
|
||||||
|
"npx sequelize-cli db:migrate:undo:all",
|
||||||
|
"Undo all migrations"
|
||||||
|
);
|
||||||
|
recordResult("Undo all migrations", undoAllResult.success);
|
||||||
|
|
||||||
|
if (!undoAllResult.success) {
|
||||||
|
logWarning("Undo failed - database may already be empty, continuing...");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 3: Run all migrations up
|
||||||
|
logStep(3, "Running all migrations up");
|
||||||
|
const migrateUpResult = runCommand(
|
||||||
|
"npx sequelize-cli db:migrate",
|
||||||
|
"Run all migrations"
|
||||||
|
);
|
||||||
|
recordResult("Migrate up", migrateUpResult.success);
|
||||||
|
|
||||||
|
if (!migrateUpResult.success) {
|
||||||
|
logError("Migration up failed - cannot continue");
|
||||||
|
printSummary(results);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 4: Verify migration status shows all executed
|
||||||
|
logStep(4, "Verifying all migrations executed");
|
||||||
|
const verifyResult = runCommand(
|
||||||
|
"npx sequelize-cli db:migrate:status",
|
||||||
|
"Verify migration status"
|
||||||
|
);
|
||||||
|
recordResult("Verify status", verifyResult.success);
|
||||||
|
|
||||||
|
// Step 5: Test rollback - undo all migrations
|
||||||
|
logStep(5, "Testing rollback - undoing all migrations");
|
||||||
|
const rollbackResult = runCommand(
|
||||||
|
"npx sequelize-cli db:migrate:undo:all",
|
||||||
|
"Rollback all migrations"
|
||||||
|
);
|
||||||
|
recordResult("Rollback", rollbackResult.success);
|
||||||
|
|
||||||
|
if (!rollbackResult.success) {
|
||||||
|
logError("Rollback failed - down migrations have issues");
|
||||||
|
printSummary(results);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 6: Test idempotency - run migrations up again
|
||||||
|
logStep(6, "Testing idempotency - running migrations up again");
|
||||||
|
const idempotencyResult = runCommand(
|
||||||
|
"npx sequelize-cli db:migrate",
|
||||||
|
"Re-run all migrations"
|
||||||
|
);
|
||||||
|
recordResult("Idempotency test", idempotencyResult.success);
|
||||||
|
|
||||||
|
if (!idempotencyResult.success) {
|
||||||
|
logError("Idempotency test failed - migrations may not be repeatable");
|
||||||
|
printSummary(results);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 7: Final status check
|
||||||
|
logStep(7, "Final migration status");
|
||||||
|
const finalStatusResult = runCommand(
|
||||||
|
"npx sequelize-cli db:migrate:status",
|
||||||
|
"Final status check"
|
||||||
|
);
|
||||||
|
recordResult("Final status", finalStatusResult.success);
|
||||||
|
|
||||||
|
printSummary(results);
|
||||||
|
|
||||||
|
if (results.failed > 0) {
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
log("\nMigration tests completed successfully!", colors.green);
|
||||||
|
process.exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
function printSummary(results) {
|
||||||
|
log("\n========================================", colors.blue);
|
||||||
|
log(" Test Summary", colors.blue);
|
||||||
|
log("========================================\n", colors.blue);
|
||||||
|
|
||||||
|
results.steps.forEach(({ step, success }) => {
|
||||||
|
if (success) {
|
||||||
|
logSuccess(step);
|
||||||
|
} else {
|
||||||
|
logError(step);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
log(`\nTotal: ${results.passed} passed, ${results.failed} failed`);
|
||||||
|
}
|
||||||
|
|
||||||
|
main().catch((error) => {
|
||||||
|
logError("Unexpected error:");
|
||||||
|
console.error(error);
|
||||||
|
process.exit(1);
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user