mirror of
https://github.com/louislam/uptime-kuma.git
synced 2026-10-13 17:02:17 -05:00
141 lines
5.5 KiB
JavaScript
141 lines
5.5 KiB
JavaScript
/**
|
|
* Regenerate test/fixtures/v2-kuma.db, a pristine Uptime Kuma 2.5.3 SQLite database.
|
|
*
|
|
* The migration test (test/backend-test/test-migration-v2-to-v3.ts) upgrades this real
|
|
* 2.5.3 database to v3 to make sure the upgrade path keeps working (see #7944).
|
|
*
|
|
* It is generated by booting the official 2.5.3 slim image once with an empty data dir,
|
|
* letting it create the database, then checkpointing the WAL so the file is standalone.
|
|
*
|
|
* Usage:
|
|
* node extra/prepare-v2-test-db.mjs
|
|
*
|
|
* Requires Docker. Only run this when the v2 schema actually changed.
|
|
*/
|
|
import { execFileSync } from "node:child_process";
|
|
import fs from "node:fs";
|
|
import os from "node:os";
|
|
import path from "node:path";
|
|
import zlib from "node:zlib";
|
|
import { fileURLToPath } from "node:url";
|
|
import BetterSqlite3 from "better-sqlite3";
|
|
import bcrypt from "bcryptjs";
|
|
|
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
const repoRoot = path.join(__dirname, "..");
|
|
const fixturePath = path.join(repoRoot, "test/fixtures/v2-kuma.db.gz");
|
|
const image = "louislam/uptime-kuma:2.5.3-slim";
|
|
const containerName = "uptime-kuma-v2-fixture";
|
|
const adminPassword = "Kuma-V2-Test-Password";
|
|
|
|
/**
|
|
* Run a command and inherit stdio.
|
|
* @param {string} command Command to run
|
|
* @param {string[]} args Arguments
|
|
* @returns {void}
|
|
*/
|
|
function run(command, args) {
|
|
console.log(`$ ${command} ${args.join(" ")}`);
|
|
execFileSync(command, args, { stdio: "inherit" });
|
|
}
|
|
|
|
/**
|
|
* Copy a file if it exists.
|
|
* @param {string} from Source
|
|
* @param {string} to Destination
|
|
* @returns {void}
|
|
*/
|
|
function copyIfExists(from, to) {
|
|
if (fs.existsSync(from)) {
|
|
fs.copyFileSync(from, to);
|
|
}
|
|
}
|
|
|
|
const dataDir = fs.mkdtempSync(path.join(os.tmpdir(), "uk-v2-fixture-"));
|
|
const workDir = fs.mkdtempSync(path.join(os.tmpdir(), "uk-v2-work-"));
|
|
|
|
try {
|
|
run("docker", ["rm", "-f", containerName]);
|
|
run("docker", [
|
|
"run",
|
|
"-d",
|
|
"--name",
|
|
containerName,
|
|
"-e",
|
|
"UPTIME_KUMA_DB_TYPE=sqlite",
|
|
"-v",
|
|
`${dataDir}:/app/data`,
|
|
image,
|
|
]);
|
|
|
|
// Wait until the container created and migrated the database
|
|
const dbPath = path.join(dataDir, "kuma.db");
|
|
const deadline = Date.now() + 120_000;
|
|
while (Date.now() < deadline) {
|
|
if (fs.existsSync(dbPath) && fs.statSync(dbPath).size > 0) {
|
|
const walPath = `${dbPath}-wal`;
|
|
if (fs.existsSync(walPath) && fs.statSync(walPath).size > 0) {
|
|
break;
|
|
}
|
|
}
|
|
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
}
|
|
|
|
if (!fs.existsSync(dbPath)) {
|
|
throw new Error("Timed out waiting for the v2 database to be created");
|
|
}
|
|
|
|
run("docker", ["stop", containerName]);
|
|
|
|
// The 2.5.3 image keeps the schema in the WAL file, so copy all three files and checkpoint
|
|
copyIfExists(dbPath, path.join(workDir, "kuma.db"));
|
|
copyIfExists(`${dbPath}-wal`, path.join(workDir, "kuma.db-wal"));
|
|
copyIfExists(`${dbPath}-shm`, path.join(workDir, "kuma.db-shm"));
|
|
|
|
const db = new BetterSqlite3(path.join(workDir, "kuma.db"));
|
|
db.pragma("wal_checkpoint(TRUNCATE)");
|
|
|
|
// Seed a realistic 2.5.3 dataset (an admin with one of each owned resource), so the fixture
|
|
// can be used to boot the server directly.
|
|
const now = new Date().toISOString().slice(0, 19).replace("T", " ");
|
|
const adminPasswordHash = await bcrypt.hash(adminPassword, 10);
|
|
db.prepare("INSERT INTO user (username, password, active, timezone, twofa_status) VALUES (?, ?, 1, 'UTC', 0)").run(
|
|
"admin",
|
|
adminPasswordHash
|
|
);
|
|
db.prepare(
|
|
"INSERT INTO monitor (name, active, user_id, interval, type, url, method, maxretries, maxredirects, accepted_statuscodes_json, retry_interval, created_date) VALUES ('Migrated Monitor', 0, 1, 60, 'http', 'https://example.com', 'GET', 0, 10, '[\"200-299\"]', 60, ?)"
|
|
).run(now);
|
|
db.prepare("INSERT INTO notification (name, active, user_id, is_default, config) VALUES ('Notif 1', 1, 1, 0, '{}')").run();
|
|
db.prepare(
|
|
"INSERT INTO maintenance (title, description, user_id, active, strategy, weekdays, days_of_month) VALUES ('Maintenance 1', '', 1, 1, 'manual', '[]', '[]')"
|
|
).run();
|
|
db.prepare(
|
|
"INSERT INTO proxy (user_id, protocol, host, port, auth, active, `default`, created_date) VALUES (1, 'http', '127.0.0.1', 8080, 0, 1, 0, ?)"
|
|
).run(now);
|
|
db.prepare("INSERT INTO docker_host (user_id, docker_daemon, docker_type, name) VALUES (1, 'tcp://127.0.0.1:2375', 'socket', 'Docker 1')").run();
|
|
db.prepare("INSERT INTO remote_browser (name, url, user_id) VALUES ('Browser 1', 'http://127.0.0.1:9222', 1)").run();
|
|
db.prepare("INSERT INTO api_key (key, name, user_id, created_date, active) VALUES (?, 'API Key 1', 1, ?, 1)").run(
|
|
await bcrypt.hash("test-api-key", 10),
|
|
now
|
|
);
|
|
|
|
// Keep the fixture compact and in rollback-journal mode so simply opening it does not create
|
|
// -wal/-shm sidecar files. Set VACUUM for a compact file, then it is gzipped before being saved.
|
|
db.pragma("journal_mode = DELETE");
|
|
db.exec("VACUUM");
|
|
db.close();
|
|
|
|
fs.mkdirSync(path.dirname(fixturePath), { recursive: true });
|
|
fs.writeFileSync(fixturePath, zlib.gzipSync(fs.readFileSync(path.join(workDir, "kuma.db")), { level: 9 }));
|
|
console.log(`Wrote ${fixturePath}`);
|
|
} finally {
|
|
try {
|
|
run("docker", ["rm", "-f", containerName]);
|
|
} catch (e) {
|
|
// Ignore
|
|
}
|
|
fs.rmSync(dataDir, { recursive: true, force: true });
|
|
fs.rmSync(workDir, { recursive: true, force: true });
|
|
}
|