test migration script
This commit is contained in:
@@ -21,7 +21,7 @@
|
||||
"db:migrate:undo:all": "sequelize-cli db:migrate:undo:all",
|
||||
"db:migrate:status": "sequelize-cli db:migrate:status",
|
||||
"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:list": "NODE_ENV=dev node scripts/manageAlphaInvitations.js list",
|
||||
"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