mesh/merge-gate head 454c5662ddcb merged into trunk 671ab9a3ba7b — pass: builds mailu, sent nowhere; no bus step; 1 wait(s) for a person; every machine com…
mesh/repo-check head 454c5662ddcb merged into trunk 671ab9a3ba7b — pass: its merge-check.sh passed, each part in its toolchain: merge-check.sh (go), merge-…
mesh/delivery delivering: 0 machine step(s) passed
82 lines
4.3 KiB
TypeScript
82 lines
4.3 KiB
TypeScript
// What automx_rows reads (novox/hq issue 1630): the rows of automx2's database as stored, through a read-only
|
|
// sqlite3 inside its container. The database here is a real SQLite file made by the test with the tables
|
|
// automx/files/setup-db creates and the rows add-domains writes — with the IMAP server's name empty, the case
|
|
// the live instance is in. The fake container runs each command's statement against that database and prints
|
|
// it the way `sqlite3 -json` does (one JSON array, nothing for no rows). Run against the compiled module.
|
|
|
|
import { test } from "node:test";
|
|
import assert from "node:assert/strict";
|
|
import { DatabaseSync } from "node:sqlite";
|
|
|
|
import { readAutomx, readCommand, AUTOMX_DATABASE } from "../dist/automx.js";
|
|
|
|
function database(imapName: string): DatabaseSync {
|
|
const db = new DatabaseSync(":memory:");
|
|
db.exec(`
|
|
CREATE TABLE provider(id INT PRIMARY KEY NOT NULL, name TEXT NOT NULL, short_name TEXT NOT NULL);
|
|
CREATE TABLE server(id INT PRIMARY KEY NOT NULL, prio INT NOT NULL DEFAULT 10, name TEXT NOT NULL, port INT NOT NULL,
|
|
type TEXT NOT NULL, socket_type TEXT NOT NULL, user_name TEXT NOT NULL, authentication TEXT NOT NULL);
|
|
CREATE TABLE domain(id INT PRIMARY KEY NOT NULL, name TEXT NOT NULL, provider_id INT NOT NULL, ldapserver_id INT NULL);
|
|
CREATE TABLE server_domain(server_id INT NOT NULL, domain_id INT NOT NULL);
|
|
INSERT INTO provider VALUES (1, 'example.org', 'example.org');
|
|
INSERT INTO server(id, port, type, name, socket_type, user_name, authentication)
|
|
VALUES (2, 143, 'imap', '${imapName}', 'STARTTLS', '%EMAILADDRESS%', 'password-cleartext');
|
|
INSERT INTO server(id, port, type, name, socket_type, user_name, authentication)
|
|
VALUES (3, 587, 'smtp', 'mail.example.org', 'STARTTLS', '%EMAILADDRESS%', 'password-cleartext');
|
|
INSERT INTO domain VALUES (5, 'example.org', 1, NULL);
|
|
INSERT INTO server_domain VALUES (2, 5), (3, 5);
|
|
`);
|
|
return db;
|
|
}
|
|
|
|
function container(db: DatabaseSync, asked: string[][] = []) {
|
|
return async (_name: string, command: string[]) => {
|
|
asked.push(command);
|
|
const rows = db.prepare(command[command.length - 1]).all();
|
|
return rows.length === 0 ? "" : JSON.stringify(rows) + "\n";
|
|
};
|
|
}
|
|
|
|
test("the rows come back as stored, and an empty server name is said", async () => {
|
|
const answer = await readAutomx(container(database("")), "mailu-automx");
|
|
assert.equal(answer.database, AUTOMX_DATABASE);
|
|
assert.deepEqual(answer.unreadable, {});
|
|
assert.deepEqual(answer.tables.provider, [{ id: 1, name: "example.org", short_name: "example.org" }]);
|
|
assert.deepEqual(answer.tables.domain, [{ id: 5, name: "example.org", provider_id: 1, ldapserver_id: null }]);
|
|
assert.deepEqual(answer.tables.server_domain, [{ server_id: 2, domain_id: 5 }, { server_id: 3, domain_id: 5 }]);
|
|
assert.deepEqual(
|
|
answer.tables.server.map((s) => [s.id, s.type, s.name, s.port]),
|
|
[[2, "imap", "", 143], [3, "smtp", "mail.example.org", 587]],
|
|
);
|
|
assert.deepEqual(answer.empty_names, [{ id: 2, type: "imap" }]);
|
|
});
|
|
|
|
test("a named IMAP server is not reported empty", async () => {
|
|
const answer = await readAutomx(container(database("mail.example.org")), "mailu-automx");
|
|
assert.deepEqual(answer.empty_names, []);
|
|
});
|
|
|
|
test("every command opens the file read-only and runs one fixed SELECT", async () => {
|
|
const asked: string[][] = [];
|
|
await readAutomx(container(database("x"), asked), "mailu-automx");
|
|
assert.equal(asked.length, 4);
|
|
for (const c of asked) {
|
|
assert.deepEqual(c.slice(0, 4), ["sqlite3", "-readonly", "-json", AUTOMX_DATABASE]);
|
|
assert.match(c[4], /^SELECT /);
|
|
assert.equal(c.length, 5);
|
|
}
|
|
assert.deepEqual(readCommand("SELECT 1").length, 5);
|
|
});
|
|
|
|
test("a table that cannot be read is said and does not hide the others", async () => {
|
|
const db = database("x");
|
|
const exec = async (name: string, command: string[]) => {
|
|
if (command[4].includes("FROM domain ")) throw Object.assign(new Error("Command failed: docker exec"), { stderr: "Error: unable to open database file\nmore" });
|
|
return container(db)(name, command);
|
|
};
|
|
const answer = await readAutomx(exec, "mailu-automx");
|
|
assert.deepEqual(answer.unreadable, { domain: "Error: unable to open database file" });
|
|
assert.equal(answer.tables.provider.length, 1);
|
|
assert.equal(answer.tables.domain, undefined);
|
|
});
|