134 lines
4.5 KiB
JavaScript
134 lines
4.5 KiB
JavaScript
const { describe, test } = require("node:test");
|
|
const fs = require("fs");
|
|
const path = require("path");
|
|
const { GenericContainer, Wait } = require("testcontainers");
|
|
|
|
describe("Database Migration", () => {
|
|
test("SQLite migrations run successfully from fresh database", async () => {
|
|
const testDbPath = path.join(__dirname, "../../data/test-migration.db");
|
|
const testDbDir = path.dirname(testDbPath);
|
|
|
|
// Ensure data directory exists
|
|
if (!fs.existsSync(testDbDir)) {
|
|
fs.mkdirSync(testDbDir, { recursive: true });
|
|
}
|
|
|
|
// Clean up any existing test database
|
|
if (fs.existsSync(testDbPath)) {
|
|
fs.unlinkSync(testDbPath);
|
|
}
|
|
|
|
// Use the same SQLite driver as the project
|
|
const Dialect = require("knex/lib/dialects/sqlite3/index.js");
|
|
Dialect.prototype._driver = () => require("@louislam/sqlite3");
|
|
|
|
const knex = require("knex");
|
|
const db = knex({
|
|
client: Dialect,
|
|
connection: {
|
|
filename: testDbPath
|
|
},
|
|
useNullAsDefault: true,
|
|
});
|
|
|
|
// Setup R (redbean) with knex instance like production code does
|
|
const { R } = require("redbean-node");
|
|
R.setup(db);
|
|
|
|
try {
|
|
// Use production code to initialize SQLite tables (like first run)
|
|
const { createTables } = require("../../db/knex_init_db.js");
|
|
await createTables();
|
|
|
|
// Run all migrations like production code does
|
|
await R.knex.migrate.latest({
|
|
directory: path.join(__dirname, "../../db/knex_migrations")
|
|
});
|
|
|
|
// Test passes if migrations complete successfully without errors
|
|
|
|
} finally {
|
|
// Clean up
|
|
await R.knex.destroy();
|
|
if (fs.existsSync(testDbPath)) {
|
|
fs.unlinkSync(testDbPath);
|
|
}
|
|
}
|
|
});
|
|
|
|
test(
|
|
"MariaDB migrations run successfully from fresh database",
|
|
{
|
|
skip:
|
|
!!process.env.CI &&
|
|
(process.platform !== "linux" || process.arch !== "x64"),
|
|
},
|
|
async () => {
|
|
// Start MariaDB container (using MariaDB 12 to match current production)
|
|
const mariadbContainer = await new GenericContainer("mariadb:12")
|
|
.withEnvironment({
|
|
"MYSQL_ROOT_PASSWORD": "root",
|
|
"MYSQL_DATABASE": "kuma_test",
|
|
"MYSQL_USER": "kuma",
|
|
"MYSQL_PASSWORD": "kuma"
|
|
})
|
|
.withExposedPorts(3306)
|
|
.withWaitStrategy(Wait.forLogMessage("ready for connections", 2))
|
|
.withStartupTimeout(120000)
|
|
.start();
|
|
|
|
// Wait a bit more to ensure MariaDB is fully ready
|
|
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
|
|
const knex = require("knex");
|
|
const knexInstance = knex({
|
|
client: "mysql2",
|
|
connection: {
|
|
host: mariadbContainer.getHost(),
|
|
port: mariadbContainer.getMappedPort(3306),
|
|
user: "kuma",
|
|
password: "kuma",
|
|
database: "kuma_test",
|
|
connectTimeout: 60000,
|
|
},
|
|
pool: {
|
|
min: 0,
|
|
max: 10,
|
|
acquireTimeoutMillis: 60000,
|
|
idleTimeoutMillis: 60000,
|
|
},
|
|
});
|
|
|
|
// Setup R (redbean) with knex instance like production code does
|
|
const { R } = require("redbean-node");
|
|
R.setup(knexInstance);
|
|
|
|
try {
|
|
// Use production code to initialize MariaDB tables
|
|
const { createTables } = require("../../db/knex_init_db.js");
|
|
await createTables();
|
|
|
|
// Run all migrations like production code does
|
|
await R.knex.migrate.latest({
|
|
directory: path.join(__dirname, "../../db/knex_migrations")
|
|
});
|
|
|
|
// Test passes if migrations complete successfully without errors
|
|
|
|
} finally {
|
|
// Clean up
|
|
try {
|
|
await R.knex.destroy();
|
|
} catch (e) {
|
|
// Ignore cleanup errors
|
|
}
|
|
try {
|
|
await mariadbContainer.stop();
|
|
} catch (e) {
|
|
// Ignore cleanup errors
|
|
}
|
|
}
|
|
}
|
|
);
|
|
});
|