| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117 |
- const assert = require("node:assert/strict");
- const { spawnSync } = require("node:child_process");
- const fs = require("node:fs");
- const os = require("node:os");
- const path = require("node:path");
- const test = require("node:test");
- const transit = require("transit-js");
- const Database = require("better-sqlite3");
- const {
- parseFramedRows,
- parseCliArgs,
- sanitizeGraphIdForFilename,
- writeSnapshotSqlite,
- } = require("./download_graph_db");
- function runCli(args, env = {}) {
- return spawnSync(process.execPath, [path.join(__dirname, "download_graph_db.js"), ...args], {
- encoding: "utf8",
- env: { ...process.env, ...env },
- });
- }
- test("parseCliArgs accepts required args and defaults output", () => {
- const parsed = parseCliArgs([
- "--graph-id",
- "graph-1",
- "--admin-token",
- "admin-token-value",
- ]);
- assert.equal(parsed.graphId, "graph-1");
- assert.equal(parsed.baseUrl, "https://api.logseq.com");
- assert.equal(parsed.adminToken, "admin-token-value");
- assert.equal(parsed.output, path.resolve("tmp", "graph-graph-1.snapshot.sqlite"));
- });
- test("sanitizeGraphIdForFilename replaces unsafe chars", () => {
- assert.equal(sanitizeGraphIdForFilename("us-east-1:abc/def"), "us-east-1_abc_def");
- });
- test("CLI --help exits successfully", () => {
- const result = runCli(["--help"]);
- assert.equal(result.status, 0);
- assert.match(result.stdout, /Download a graph snapshot and store it as a local sqlite debug DB/);
- });
- test("CLI rejects missing --graph-id", () => {
- const result = runCli(["--admin-token", "admin-token-value"]);
- assert.equal(result.status, 1);
- assert.match(result.stderr, /Missing required --graph-id\./);
- });
- test("CLI rejects missing admin-token when env is absent", () => {
- const result = runCli(["--graph-id", "graph-1"], { DB_SYNC_ADMIN_TOKEN: "" });
- assert.equal(result.status, 1);
- assert.match(result.stderr, /Missing admin token/);
- });
- test("parseFramedRows decodes framed transit batches", () => {
- const writer = transit.writer("json");
- const rowsA = [
- [1, "line-1", null],
- [2, "line-2", null],
- ];
- const rowsB = [
- [1000606, "line-1000606", "{\"1\":[2,3]}"],
- ];
- const encodeFrame = (rows) => {
- const payload = Buffer.from(writer.write(rows), "utf8");
- const frame = Buffer.allocUnsafe(4 + payload.length);
- frame.writeUInt32BE(payload.length, 0);
- payload.copy(frame, 4);
- return frame;
- };
- const framed = Buffer.concat([encodeFrame(rowsA), encodeFrame(rowsB)]);
- const parsed = parseFramedRows(framed);
- assert.deepEqual(parsed, [...rowsA, ...rowsB]);
- });
- test("writeSnapshotSqlite writes kvs-only sqlite like local dbs", () => {
- const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "db-sync-download-test-"));
- const dbPath = path.join(tmpDir, "graph-debug.sqlite");
- const rows = [
- [1, "line-1", null],
- [2, "line-2", null],
- [1000606, "line-1000606", "{\"1\":[2,3]}"],
- ];
- writeSnapshotSqlite({
- outputPath: dbPath,
- rows,
- });
- const db = new Database(dbPath, { readonly: true });
- const tableNames = db
- .prepare("select name from sqlite_master where type = 'table' order by name")
- .all()
- .map((row) => row.name);
- const rowCount = db.prepare("select count(1) as count from kvs").get().count;
- const row1000606 = db.prepare("select addr, content, addresses from kvs where addr = 1000606").get();
- assert.deepEqual(tableNames, ["kvs"]);
- assert.equal(rowCount, 3);
- assert.equal(row1000606.addr, 1000606);
- assert.equal(row1000606.content, "line-1000606");
- assert.equal(row1000606.addresses, "{\"1\":[2,3]}");
- db.close();
- });
|