diff options
-rw-r--r-- | Makefile | 11 | ||||
-rw-r--r-- | index.mjs | 1 | ||||
-rw-r--r-- | src/accretion.mjs | 6 | ||||
-rw-r--r-- | src/api.mjs | 1 | ||||
-rwxr-xr-x | src/bin.mjs | 4 | ||||
-rw-r--r-- | src/db.mjs | 20 | ||||
-rw-r--r-- | src/hero.mjs | 23 | ||||
-rw-r--r-- | src/ircd.mjs | 1 | ||||
-rw-r--r-- | src/web.mjs | 38 | ||||
-rw-r--r-- | tests/js/accretion.mjs | 18 | ||||
-rw-r--r-- | tests/js/db.mjs | 15 | ||||
-rw-r--r-- | tests/js/escape.mjs | 9 | ||||
-rw-r--r-- | tests/js/hero.mjs | 19 | ||||
-rw-r--r-- | tests/js/ircd.mjs | 5 | ||||
-rw-r--r-- | tests/js/utils.mjs | 4 | ||||
-rw-r--r-- | tests/js/web.mjs | 5 | ||||
-rw-r--r-- | tests/runner.mjs | 2 |
17 files changed, 92 insertions, 90 deletions
@@ -55,6 +55,8 @@ derived-assets = \ $(manpages) \ side-assets = \ + tests/hero-0.sock \ + tests/hero-1.sock \ ircd.sock \ web.sock \ @@ -67,6 +69,11 @@ all: $(derived-assets) $(manpages): Makefile deps.mk +rm-sock-files: + rm -f tests/hero-0.sock tests/hero-1.sock + +tests/js/hero.mjs-check: rm-sock-files + .SUFFIXES: .mjs .mjs-check @@ -130,11 +137,11 @@ uninstall: run-ircd: all rm -f ircd.sock - ./src/papo ircd ircd.sock + ./src/bin.mjs ircd ircd.sock run-web: all rm -f web.sock - ./src/papo web web.sock + ./src/bin.mjs web web.sock ## Run the web and IRC server locally. run: all diff --git a/index.mjs b/index.mjs deleted file mode 100644 index 898ccb4..0000000 --- a/index.mjs +++ /dev/null @@ -1 +0,0 @@ -export * from "./api.mjs"; diff --git a/src/accretion.mjs b/src/accretion.mjs index 117e291..a9adb97 100644 --- a/src/accretion.mjs +++ b/src/accretion.mjs @@ -5,7 +5,7 @@ import url from "node:url"; import sqlite from "./sqlite.cjs"; -import { difference, log } from "./utils.mjs"; +import * as u from "./utils.mjs"; const DIRNAME = path.dirname(url.fileURLToPath(import.meta.url)); @@ -25,12 +25,12 @@ export const runMigrations = async db => { const done = [...(await db.all("SELECT filename FROM migrations;"))] .map(row => row.filename); const allFiles = fs.readdirSync(MIGRATIONS_DIR, "UTF-8"); - const pending = difference(new Set(allFiles), new Set(done)); + const pending = u.difference(new Set(allFiles), new Set(done)); const sortedPending = [...pending] .sort((a, b) => a.localeCompare(b, "POSIX")); for (const filename of sortedPending) { - log({ log: "exec-migration", filename }); + u.log({ log: "exec-migration", filename }); const sql = fs.readFileSync(MIGRATIONS_DIR + filename, "UTF-8"); await db.exec("BEGIN TRANSACTION;"); await db.exec(sql); diff --git a/src/api.mjs b/src/api.mjs index 27a14b1..2ec7cbf 100644 --- a/src/api.mjs +++ b/src/api.mjs @@ -1,4 +1,3 @@ -import { eq } from "./utils.mjs"; import * as ircd from "./ircd.mjs"; import * as web from "./web.mjs"; diff --git a/src/bin.mjs b/src/bin.mjs index 5dbbb25..e79904f 100755 --- a/src/bin.mjs +++ b/src/bin.mjs @@ -1,4 +1,4 @@ #!/usr/bin/env node -import { main } from "./api.mjs"; +import * as api from "./api.mjs"; -main(); +api.main(); @@ -5,15 +5,15 @@ import url from "node:url"; import sqlite from "./sqlite.cjs"; -import { promisify } from "./utils.mjs"; -import { runMigrations } from "./accretion.mjs"; +import * as u from "./utils.mjs"; +import * as accretion from "./accretion.mjs"; export const promisifyDb = dbHandle => ({ ref: dbHandle, - all: promisify((...args) => dbHandle.all(...args)), - exec: promisify((...args) => dbHandle.exec(...args)), - run: promisify((...args) => dbHandle.run(...args)), + all: u.promisify((...args) => dbHandle.all(...args)), + exec: u.promisify((...args) => dbHandle.exec(...args)), + run: u.promisify((...args) => dbHandle.run(...args)), each: (...args) => new Promise((resolve, reject) => { const cb = args[args.length - 1]; @@ -27,8 +27,8 @@ export const promisifyDb = dbHandle => ({ new Promise((resolve, reject) => { const mkStmt = stmtRef => ({ ref: stmtRef, - run: promisify((...args) => stmtRef.run(...args)), - finalize: promisify((...args) => stmtRef.finalize(...args)), + run: u.promisify((...args) => stmtRef.run(...args)), + finalize: u.promisify((...args) => stmtRef.finalize(...args)), }); const ref = dbHandle.prepare( ...args, @@ -47,9 +47,9 @@ export const open = (...args) => )); }); -export let db = null; +export let handle = null; export const init = async (dbName = process.env.PAPO_DB_PATH || ":memory:") => { - db = await open(dbName); - await runMigrations(db); + handle = await open(dbName); + await accretion.runMigrations(handle); }; diff --git a/src/hero.mjs b/src/hero.mjs index 38fdde4..aa4a5a4 100644 --- a/src/hero.mjs +++ b/src/hero.mjs @@ -2,7 +2,8 @@ import assert from "node:assert/strict"; import crypto from "node:crypto"; import http from "node:http"; -import { assocIn, getIn, first, log, promisify } from "./utils.mjs"; +import * as u from "./utils.mjs"; + export const normalizeSegments = segments => segments.length === 1 && segments[0] === "" ? @@ -45,13 +46,13 @@ export const addRoute = (table, methods, path, handlerFn) => { const segments = pathToSegments(path); const kw = hasPathParams(segments) ? "dynamic" : "static"; return methods.reduce( - (acc, el) => assocIn(acc, [kw, el].concat(segments), handlerFn), + (acc, el) => u.assocIn(acc, [kw, el].concat(segments), handlerFn), table, ); }; export const findStaticHandler = (table, method, segments) => { - const handlerFn = getIn(table, ["static", method].concat(segments)); + const handlerFn = u.getIn(table, ["static", method].concat(segments)); return !handlerFn ? null : { handlerFn, params: {} }; }; @@ -87,7 +88,7 @@ export const firstParamMatch = (tree, segments, params) => { const paramOptions = Object.keys(tree) .filter(s => s.startsWith(":")) .sort(); - return first(paramOptions, param => firstParamMatch(tree[param], nextSegments, { + return u.first(paramOptions, param => firstParamMatch(tree[param], nextSegments, { ...params, [param.slice(1)]: seg })); @@ -148,7 +149,7 @@ export const interceptorsFn = ({ logger, } = { uuidFn: crypto.randomUUID, - logger: log, + logger: u.log, }) => ({ requestId: (req, next) => next({ ...req, id: uuidFn() }), logged: async (req, next) => { @@ -204,6 +205,13 @@ export const interceptorsFn = ({ export const interceptors = interceptorsFn(); +export const defaultInterceptors = [ + interceptors.serverError, + interceptors.contentType, + interceptors.requestId, + interceptors.logged, +]; + export const chainInterceptors = arr => req => arr.length === 0 ? req : @@ -231,8 +239,9 @@ export const buildRoutes = (routes, globalInterceptors = []) => export const promisifyServer = serverHandle => ({ ref: serverHandle, - listen: promisify((...args) => serverHandle.listen(...args)), - close: promisify((...args) => serverHandle.close(...args)), + listen: u.promisify((...args) => serverHandle.listen(...args)), + close: u.promisify((...args) => serverHandle.close(...args)), + events: serverHandle, }); export const buildServer = (routes, globalInterceptors = []) => { diff --git a/src/ircd.mjs b/src/ircd.mjs index 38903f8..af4d280 100644 --- a/src/ircd.mjs +++ b/src/ircd.mjs @@ -1,5 +1,4 @@ import net from "node:net"; -import {} from "./db.mjs"; const server = net.createServer(socket => { socket.write("olar\r\n"); diff --git a/src/web.mjs b/src/web.mjs index 8eed5b4..cd875a0 100644 --- a/src/web.mjs +++ b/src/web.mjs @@ -1,30 +1,18 @@ -import http from "node:http"; +import * as u from "./utils.mjs"; +import { buildServer, defaultInterceptors } from "./hero.mjs"; -const listProducts = () => {}; -const getProduct = () => {}; -const routes = { - GET: { - "/products": listProducts, - "/products/:id": getProduct, - }, -}; +const listProducts = req => ({ status: 200 }); +const getProduct = req => ({ status: 200 }); +const getChat = req => ({ status: 200, body: "something\n" }); -const server = http.createServer((req, res) => { - const { headers ,url, method } = req; - console.log({ - headers, - url, - method, - }); - res.writeHead(200, { - "Content-Type": "text/plain", - }); - res.end("Hello, web!\n"); -}); +const server = buildServer([ + [ "GET", "/products", listProducts ], + [ "GET", "/products/:id", getProduct ], + [ "GET", "/chat", getChat ], +], defaultInterceptors); -export const app = udsPath => { - server.listen(udsPath, () => { - console.log("I'm web."); - }); +export const app = async udsPath => { + await server.listen(udsPath); + u.log({ type: "starting-server", udsPath }); }; diff --git a/tests/js/accretion.mjs b/tests/js/accretion.mjs index 3ea90c3..a0fbb66 100644 --- a/tests/js/accretion.mjs +++ b/tests/js/accretion.mjs @@ -2,27 +2,29 @@ import assert from "node:assert/strict"; import sqlite from "../../src/sqlite.cjs"; -import { runTests } from "../runner.mjs"; -import { promisifyDb, open } from "../../src/db.mjs"; -import { runMigrations } from "../../src/accretion.mjs"; +import * as runner from "../runner.mjs"; +import * as db from "../../src/db.mjs"; +import { + runMigrations, +} from "../../src/accretion.mjs"; const test_runMigrations = t => { t.start("runMigrations()"); t.test("running twice is a noop", async () => { - const db = await open(":memory:"); - const migrationsFn = () => db.all("SELECT filename FROM migrations;"); + const handle = await db.open(":memory:"); + const migrationsFn = () => handle.all("SELECT filename FROM migrations;"); assert.rejects( migrationsFn, { message: "SQLITE_ERROR: no such table: migrations" }, ); - await runMigrations(db); + await runMigrations(handle); const filled = await migrationsFn(); - await runMigrations(db); + await runMigrations(handle); const unchanged = await migrationsFn(); assert.deepEqual(filled, unchanged); @@ -30,6 +32,6 @@ const test_runMigrations = t => { }; -await runTests([ +await runner.runTests([ test_runMigrations, ]); diff --git a/tests/js/db.mjs b/tests/js/db.mjs index fcea535..c6c5c85 100644 --- a/tests/js/db.mjs +++ b/tests/js/db.mjs @@ -2,8 +2,13 @@ import assert from "node:assert/strict"; import sqlite from "../../src/sqlite.cjs"; -import { runTests } from "../runner.mjs"; -import { promisifyDb, open, db, init } from "../../src/db.mjs"; +import * as runner from "../runner.mjs"; +import { + promisifyDb, + open, + handle, + init, +} from "../../src/db.mjs"; const test_promisifyDb = t => { @@ -88,16 +93,16 @@ const test_init = t => { t.start("init()"); t.test("we only know how to deal with 1 database", async () => { await init(); - const ref1 = db; + const ref1 = handle; await init(); - const ref2 = db; + const ref2 = handle; assert.notDeepEqual(ref1, ref2); }); }; -await runTests([ +await runner.runTests([ test_promisifyDb, test_open, test_init, diff --git a/tests/js/escape.mjs b/tests/js/escape.mjs index 2cad16a..8291391 100644 --- a/tests/js/escape.mjs +++ b/tests/js/escape.mjs @@ -1,6 +1,9 @@ import assert from "node:assert/strict"; -import { runTests } from "../runner.mjs"; -import { escape } from "../../src/escape.mjs"; + +import * as runner from "../runner.mjs"; +import { + escape, +} from "../../src/escape.mjs"; const test_escape = t => { t.start("escape()"); @@ -57,6 +60,6 @@ const test_escape = t => { }; -await runTests([ +await runner.runTests([ test_escape, ]); diff --git a/tests/js/hero.mjs b/tests/js/hero.mjs index 7b8a5cc..bc9d3d2 100644 --- a/tests/js/hero.mjs +++ b/tests/js/hero.mjs @@ -1,8 +1,8 @@ import assert from "node:assert/strict"; import http from "node:http"; -import { runTests } from "../runner.mjs"; -import { assocIn } from "../../src/utils.mjs"; +import * as runner from "../runner.mjs"; +import * as u from "../../src/utils.mjs"; import { normalizeSegments, pathToSegments, @@ -17,6 +17,7 @@ import { makeRequestListener, interceptorsFn, interceptors, + defaultInterceptors, chainInterceptors, wrapHandler, buildRoutes, @@ -274,7 +275,7 @@ const test_firstParamMatch = t => { }, }; - const tree2 = assocIn(tree1, [ "path", "param1", ":deeper", "" ], fn1); + const tree2 = u.assocIn(tree1, [ "path", "param1", ":deeper", "" ], fn1); assert.deepEqual( firstParamMatch(tree1, segments, params), @@ -298,7 +299,7 @@ const test_firstParamMatch = t => { }, }; - const tree2 = assocIn(tree1, ["user", ":aaa", ""], fn1); + const tree2 = u.assocIn(tree1, ["user", ":aaa", ""], fn1); assert.deepEqual( firstParamMatch(tree1, segments, params), @@ -1163,14 +1164,8 @@ const test_buildServer = t => { t.test("integrated application server", async () => { const socketPath = "./tests/hero-1.sock"; const pathHandler = req => ({ status: 200, body: "OK" }); - const globalInterceptors = [ - interceptors.serverError, - interceptors.contentType, - interceptors.requestId, - interceptors.logged, - ]; const routes = [ [ "GET", "/path", pathHandler ] ]; - const server = buildServer(routes, globalInterceptors); + const server = buildServer(routes, defaultInterceptors); await server.listen(socketPath); const response = await socketRequest(socketPath, "/path"); @@ -1181,7 +1176,7 @@ const test_buildServer = t => { }; -await runTests([ +await runner.runTests([ test_normalizeSegments, test_pathToSegments, test_hasPathParams, diff --git a/tests/js/ircd.mjs b/tests/js/ircd.mjs index e5eda66..d385a72 100644 --- a/tests/js/ircd.mjs +++ b/tests/js/ircd.mjs @@ -1,7 +1,6 @@ -import { runTests } from "../runner.mjs"; -import { } from "../../src/ircd.mjs"; +import * as runner from "../runner.mjs"; -await runTests([ +await runner.runTests([ ]); diff --git a/tests/js/utils.mjs b/tests/js/utils.mjs index e4f21d0..e2475b0 100644 --- a/tests/js/utils.mjs +++ b/tests/js/utils.mjs @@ -1,6 +1,6 @@ import assert from "node:assert/strict"; -import { runTests } from "../runner.mjs"; +import * as runner from "../runner.mjs"; import { eq, keys, @@ -291,7 +291,7 @@ const test_promisify = t => { }; -await runTests([ +await runner.runTests([ test_eq, test_keys, test_difference, diff --git a/tests/js/web.mjs b/tests/js/web.mjs index 00cce70..d385a72 100644 --- a/tests/js/web.mjs +++ b/tests/js/web.mjs @@ -1,7 +1,6 @@ -import { runTests } from "../runner.mjs"; -import { } from "../../src/web.mjs"; +import * as runner from "../runner.mjs"; -await runTests([ +await runner.runTests([ ]); diff --git a/tests/runner.mjs b/tests/runner.mjs index 79bda8c..0adca10 100644 --- a/tests/runner.mjs +++ b/tests/runner.mjs @@ -1,5 +1,3 @@ -import { eq } from "../src/utils.mjs"; - class AssertionError extends Error {} const red = s => `\x1b[31m${s}\x1b[0m`; |