From 99dd90d51aeac92a1274772589f70317a9f5a366 Mon Sep 17 00:00:00 2001 From: siiky Date: Mon, 17 Mar 2025 23:33:38 +0000 Subject: [PATCH] feat: insert stress testing machines into DB --- tests/stress/db.js | 8 +++--- tests/stress/env.js | 18 ++++++------ tests/stress/index.js | 21 +++++++++----- tests/stress/machines.js | 60 ++++++++++++++++++++++++++++------------ tests/stress/server.js | 8 +++--- 5 files changed, 74 insertions(+), 41 deletions(-) diff --git a/tests/stress/db.js b/tests/stress/db.js index 77aaff0b..34f5a79a 100644 --- a/tests/stress/db.js +++ b/tests/stress/db.js @@ -1,5 +1,5 @@ -const cp = require('node:child_process') -const path = require('node:path') +const { spawnSync } = require('node:child_process') +const { join } = require('node:path') require('../../lib/environment-helper') const db = require('../../lib/db') @@ -23,8 +23,8 @@ const help = (exit_code) => { } const migrate = async () => { - const lamassu_migrate_path = path.join(__dirname, "../../bin/lamassu-migrate") - const { stdout, stderr, status, signal, error } = cp.spawnSync(lamassu_migrate_path, [], { + const lamassu_migrate_path = join(__dirname, "../../bin/lamassu-migrate") + const { stdout, stderr, status, signal, error } = spawnSync(lamassu_migrate_path, [], { cwd: process.cwd(), encoding: 'utf8', }) diff --git a/tests/stress/env.js b/tests/stress/env.js index 0d06ba3c..597a8dee 100644 --- a/tests/stress/env.js +++ b/tests/stress/env.js @@ -1,6 +1,6 @@ -const fs = require('node:fs') -const os = require('node:os') -const path = require('node:path') +const { readFileSync, writeFileSync } = require('node:fs') +const { EOL } = require('node:os') +const { resolve } = require('node:path') const dotenv = require('dotenv') @@ -30,10 +30,10 @@ const help = (exit_code) => { } const env_read = (path) => { - const envstr = fs.readFileSync(path, { encoding: 'utf8' }) + const envstr = readFileSync(path, { encoding: 'utf8' }) return dotenv.parse(envstr) //const entries = envstr - // .split(os.EOL) + // .split(EOL) // .flatMap((line) => { // line = line.trimStart() // const i = line.indexOf('=') @@ -51,8 +51,8 @@ const env_read = (path) => { const env_write = (envvars, path) => { const envcontent = Object.entries(envvars) .map(([varname, value]) => [varname, value].join('=')) - .join(os.EOL) + os.EOL - fs.writeFileSync(path, envcontent) + .join(EOL) + EOL + writeFileSync(path, envcontent) } const run = async (args) => { @@ -70,10 +70,10 @@ const run = async (args) => { return help(EXIT.BADARGS) } - const inenvpath = path.resolve(process.cwd(), options.inenv ?? ".env") + const inenvpath = resolve(process.cwd(), options.inenv ?? ".env") const inenvvars = env_read(inenvpath) - const outenvpath = path.resolve(process.cwd(), options.outenv ?? ".stress.env") + const outenvpath = resolve(process.cwd(), options.outenv ?? ".stress.env") const outenvvars = { ...inenvvars, POSTGRES_USER: options.dbuser ?? "postgres", diff --git a/tests/stress/index.js b/tests/stress/index.js index 2d6acefc..df8c6f83 100644 --- a/tests/stress/index.js +++ b/tests/stress/index.js @@ -17,14 +17,14 @@ on each subcommand. First of all, you need to create a suitable .env file. With the following commands, .env.bak will be used as a starting point, and the result will be -saved in .env. This is to avoid losing the real configurations. +saved in .env. This helps to avoid losing the real configurations. $ cp .env .env.bak $ lamassu-server-stress-testing env --inenv .env.bak --outenv .env -The database chosen in the command above (by default lamassu_stress) -must be initialized, and must have a bare-bones configuration. The following -command does that: +The database chosen in the command above (by default 'lamassu_stress') must be +initialized, and must have a bare-bones configuration. The following command +takes care of it: $ lamassu-server-stress-testing db @@ -34,15 +34,22 @@ following command creates 10 fake machines, and saves their data in path/to/stress/data/. path/to/real/machine/code/ is the path to the root of the machine's code. -$ lamassu-server-stress-testing machines -n 10 --fake_data_dir path/to/stress/data/ --machine path/to/real/machine/code/ +$ lamassu-server-stress-testing machines -n 10 --fake_data_dir path/to/stress/data/ --machine path/to/real/machine/code/ --replace_existing + +Finally, use the following to start the lamassu-server in stress-testing mode: + +$ lamassu-server-stress-testing server `; +const rightpad = (s, w, c) => s + c.repeat(Math.max(w-s.length, 0)) + const help = (exit_code) => { - console.log("Usage: lamassu-server-stress-testing SUBCMD ARGS...",) + console.log("Usage: lamassu-server-stress-testing SUBCMD ARGS...") console.log("Where SUBCMD is one of the following:") + const max_subcmd_length = Math.max(...Object.keys(SUBCMDS).map(subcmd => subcmd.length)) Object.entries(SUBCMDS).forEach( ([subcmd, { help_message }]) => { - console.log(`\t${subcmd}\t${help_message ?? ''}`) + console.log(`\t${rightpad(subcmd, max_subcmd_length, ' ')}\t${help_message ?? ''}`) } ) diff --git a/tests/stress/machines.js b/tests/stress/machines.js index 11d5e334..f116c50a 100644 --- a/tests/stress/machines.js +++ b/tests/stress/machines.js @@ -1,11 +1,16 @@ -const cp = require('node:child_process') -const fs = require('node:fs') -const path = require('node:path') +const { fork } = require('node:child_process') +const { createHash } = require('node:crypto') +const { mkdirSync, rmSync } = require('node:fs') +const { readFile } = require('node:fs/promises') +const { join } = require('node:path') + +require('../../lib/environment-helper') +const db = require('../../lib/db') const { EXIT } = require('./consts') const CLI = require('./cli') -const help_message = "Setup fake machines to be used as stress test clients." +const help_message = "Create and insert fake machines into the DB." const cli = CLI({ grammar: [ @@ -13,6 +18,7 @@ const cli = CLI({ [["--machine", "PATH"], "Path to the machine's source code root"], [["--fake_data_dir", "PATH"], "Where to save the fake machines' data"], [["-n", "NUMBER"], "Number of fake machines to create"], + [["--replace_existing"], "Remove machines of previous runs"], ], }) @@ -23,13 +29,19 @@ const help = (exit_code) => { return exit_code } -const create_fake_machine = async (gencerts_path, fake_data_dir, i) => +const compute_machine_id = pem_path => ( + readFile(pem_path, { encoding: 'utf8' }) + .then(cert => cert.split('\r\n')) + .then(cert => Buffer.from(cert.slice(1, cert.length-2).join(''), 'base64')) + .then(raw => createHash('sha256').update(raw).digest('hex')) +) + +const create_fake_machine = async (gencerts_path, machine_data_dir, i) => ( new Promise((resolve, reject) => { - const machine_data_dir = path.join(fake_data_dir, i.toString()) - fs.mkdirSync(machine_data_dir, { recursive: true, mode: 0o750 }) + mkdirSync(machine_data_dir, { recursive: true, mode: 0o750 }) console.log("Creating fake machine number", i) - const gc = cp.fork(gencerts_path, [machine_data_dir], { + const gc = fork(gencerts_path, [machine_data_dir], { cwd: process.cwd(), encoding: 'utf8', }) @@ -45,26 +57,40 @@ const create_fake_machine = async (gencerts_path, fake_data_dir, i) => resolve(typeof(code) === 'number' ? code : EXIT.EXCEPTION) }) }) +) -const create_fake_machines = async ({ machine, fake_data_dir, n }) => { +const create_fake_machines = async ({ machine, fake_data_dir, n, replace_existing }) => { n = parseInt(n) if (Number.isNaN(n) || n <= 0) { console.error("Expected n to be a positive number, got", n) return help(EXIT.BADARGS) } - /* TODO: Remove all data of previous machines? */ - //fs.rmSync(fake_data_dir, { recursive: true, force: true }) + if (replace_existing) { + rmSync(fake_data_dir, { recursive: true, force: true }) + await db.none("DELETE FROM devices") + } /* Create the root data directory */ - fs.mkdirSync(fake_data_dir, { recursive: true, mode: 0o750 }) + mkdirSync(fake_data_dir, { recursive: true, mode: 0o750 }) - const gencerts_path = path.join(machine, "tools", "generate-certificates") - let exit_code = EXIT.OK - for (let i = 0; i < n && exit_code === EXIT.OK; i++) - exit_code = await create_fake_machine(gencerts_path, fake_data_dir, i) + const gencerts_path = join(machine, "tools", "generate-certificates") + for (let i = 0; i < n; i++) { + const machine_data_dir = join(fake_data_dir, i.toString()) + const exit_code = await create_fake_machine(gencerts_path, machine_data_dir, i) + if (exit_code !== EXIT.OK) + return exit_code - return exit_code + const device_id = await compute_machine_id(join(machine_data_dir, "client.pem")) + + await db.none( + `INSERT INTO devices (device_id, cassette1, cassette2, paired, display, created, name, last_online, location) + VALUES ($1, 0, 0, 't', 't', now(), $2, now(), '{}'::json)`, + [device_id, `machine_${i}`] + ) + } + + return EXIT.OK } const run = async (args) => { diff --git a/tests/stress/server.js b/tests/stress/server.js index ae066a6a..7374195c 100644 --- a/tests/stress/server.js +++ b/tests/stress/server.js @@ -1,5 +1,5 @@ -const cp = require('node:child_process') -const path = require('node:path') +const { fork } = require('node:child_process') +const { join } = require('node:path') const { EXIT } = require('./consts') const CLI = require('./cli') @@ -21,8 +21,8 @@ const help = (exit_code) => { const start_server = (args) => new Promise((resolve, reject) => { - const lamassu_server = path.join(__dirname, "../../bin/lamassu-server") - const ls = cp.fork(lamassu_server, args, { + const lamassu_server = join(__dirname, "../../bin/lamassu-server") + const ls = fork(lamassu_server, args, { cwd: process.cwd(), encoding: 'utf8', env: { LAMASSU_STRESS_TESTING: "YES" },