Files
gnome-jarvis/test/install.test.js
T
snxraven e9040d110a
Rolling release / release (push) Successful in 6m40s
Updates
2026-09-12 07:22:47 -04:00

139 lines
7.1 KiB
JavaScript

import test from 'node:test';
import assert from 'node:assert/strict';
import { spawn } from 'node:child_process';
import { chmod, cp, mkdir, mkdtemp, readFile, rm, writeFile } from 'node:fs/promises';
import { existsSync, readFileSync } from 'node:fs';
import os from 'node:os';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
const repo = path.resolve(fileURLToPath(new URL('..', import.meta.url)));
function run(command, args, env) {
return new Promise((resolve, reject) => {
const child = spawn(command, args, { env, cwd: repo });
let stdout = '';
let stderr = '';
child.stdout.on('data', (chunk) => { stdout += chunk; });
child.stderr.on('data', (chunk) => { stderr += chunk; });
child.on('error', reject);
child.on('close', (code) => {
if (code === 0) resolve({ stdout, stderr });
else reject(new Error(`install failed (${code}): ${stderr || stdout}`));
});
});
}
test('install.sh replaces leftover files from an older version and keeps config', async () => {
const work = await mkdtemp(path.join(os.tmpdir(), 'jarvis-install-'));
const home = path.join(work, 'home');
const root = path.join(work, 'src');
const bin = path.join(work, 'bin');
const log = path.join(work, 'commands.log');
const machine = (await run('uname', ['-m'], process.env)).stdout.trim();
const bareName = /aarch64|arm64/.test(machine) ? 'bare-runtime-linux-arm64' : 'bare-runtime-linux-x64';
try {
await mkdir(path.join(root, 'packaging'), { recursive: true });
await mkdir(path.join(root, 'apps/gnome-extension'), { recursive: true });
await mkdir(path.join(root, 'node_modules', bareName, 'bin'), { recursive: true });
await mkdir(bin, { recursive: true });
await cp(path.join(repo, 'packaging/install.sh'), path.join(root, 'packaging/install.sh'));
await cp(path.join(repo, 'packaging/jarvisd.service'), path.join(root, 'packaging/jarvisd.service'));
await cp(path.join(repo, 'packaging/qvac.config.template.json'), path.join(root, 'packaging/qvac.config.template.json'));
await cp(path.join(repo, 'apps/gnome-extension/[email protected]'), path.join(root, 'apps/gnome-extension/[email protected]'), { recursive: true });
await writeFile(path.join(root, 'node_modules', bareName, 'bin', 'bare'), '#!/bin/sh\nexit 0\n');
await chmod(path.join(root, 'node_modules', bareName, 'bin', 'bare'), 0o755);
await writeFile(path.join(root, 'daemon-marker'), 'new-tree\n');
const appDir = path.join(home, '.local/share/jarvis-qvac');
const extDir = path.join(home, '.local/share/gnome-shell/extensions/[email protected]');
const configDir = path.join(home, '.config/jarvis');
await mkdir(path.join(appDir, 'node_modules/old-pkg'), { recursive: true });
await mkdir(extDir, { recursive: true });
await mkdir(configDir, { recursive: true });
await mkdir(path.join(home, '.local/share/jarvis-qvac.staging.oldfail'), { recursive: true });
await writeFile(path.join(appDir, 'stale-old-version.js'), 'leftover from previous install\n');
await writeFile(path.join(extDir, 'old-extension.js'), 'leftover extension\n');
await writeFile(path.join(configDir, 'config.json'), '{"wakePhrase":"hey jarvis","ttsEnabled":true}\n');
await writeFile(path.join(home, '.local/share/jarvis-qvac.staging.oldfail/junk'), 'failed staging\n');
await writeFile(path.join(bin, 'systemctl'), `#!/bin/sh
echo "systemctl $*" >> '${log}'
if [ "$2" = is-active ]; then exit 0; fi
exit 0
`);
await writeFile(path.join(bin, 'gnome-extensions'), `#!/bin/sh
echo "gnome-extensions $*" >> '${log}'
if [ "$1" = install ]; then exit 1; fi
if [ "$1" = info ]; then printf '%s\\n' 'Enabled: Yes' 'State: ACTIVE'; exit 0; fi
exit 0
`);
await writeFile(path.join(bin, 'gsettings'), `#!/bin/sh
echo "gsettings $*" >> '${log}'
if [ "$1" = get ]; then printf "%s\\n" "['[email protected]']"; fi
exit 0
`);
await writeFile(path.join(bin, 'gdbus'), `#!/bin/sh
echo "gdbus $*" >> '${log}'
exit 0
`);
await writeFile(path.join(bin, 'logger'), `#!/bin/sh
echo "logger $*" >> '${log}'
exit 0
`);
await chmod(path.join(bin, 'systemctl'), 0o755);
await chmod(path.join(bin, 'gnome-extensions'), 0o755);
await chmod(path.join(bin, 'gsettings'), 0o755);
await chmod(path.join(bin, 'gdbus'), 0o755);
await chmod(path.join(bin, 'logger'), 0o755);
const result = await run('bash', [path.join(root, 'packaging/install.sh'), '--enable'], {
...process.env,
HOME: home,
PATH: `${bin}:${process.env.PATH}`,
XDG_DATA_HOME: path.join(home, '.local/share'),
XDG_CACHE_HOME: path.join(home, '.cache'),
XDG_STATE_HOME: path.join(home, '.local/state'),
});
assert.equal(existsSync(path.join(appDir, 'stale-old-version.js')), false);
assert.equal(existsSync(path.join(appDir, 'node_modules/old-pkg')), false);
assert.equal(existsSync(path.join(home, '.local/share/jarvis-qvac.staging.oldfail')), false);
assert.equal(existsSync(path.join(extDir, 'old-extension.js')), false);
assert.equal(existsSync(path.join(extDir, 'extension.js')), true);
assert.equal(await readFile(path.join(appDir, 'daemon-marker'), 'utf8'), 'new-tree\n');
assert.equal(await readFile(path.join(configDir, 'config.json'), 'utf8'), '{"wakePhrase":"hey jarvis","ttsEnabled":true}\n');
const unit = await readFile(path.join(home, '.config/systemd/user/jarvisd.service'), 'utf8');
assert.match(unit, /bare-runtime-linux/);
assert.doesNotMatch(unit, /\/usr\/bin\/node/);
const commands = await readFile(log, 'utf8');
assert.match(commands, /systemctl --user stop jarvisd\.service/);
assert.match(commands, /gnome-extensions enable jarvis@qvac\.local/);
assert.match(commands, /gdbus call .*ReloadExtension/);
assert.match(commands, /gdbus call .*EnableExtension/);
assert.match(commands, /systemctl --user restart jarvisd\.service/);
const installLog = await readFile(path.join(home, '.local/state/jarvis/install.log'), 'utf8');
assert.match(installLog, /stopping running jarvisd\.service/);
assert.match(installLog, /removing leftover staging directory/);
assert.match(installLog, /removing previous application tree/);
assert.match(installLog, /copied GNOME extension files/);
assert.match(installLog, /reloaded jarvis@qvac\.local in the running GNOME Shell/);
assert.match(installLog, /enabled GNOME extension jarvis@qvac\.local/);
assert.match(installLog, /kept existing .*config\.json/);
assert.match(installLog, /install complete; log file/);
assert.doesNotMatch(installLog, /will enable Jarvis after the next login/);
assert.match(result.stdout, /jarvis-install: stopping running jarvisd\.service/);
} finally {
await rm(work, { recursive: true, force: true });
}
});
test('first-run keeps TTS enabled even when the preview is skipped', () => {
const source = readFileSync(new URL('../packaging/first-run.sh', import.meta.url), 'utf8');
assert.match(source, /Play a TTS preview now\?/);
assert.match(source, /TTS_ENABLED=true/);
assert.doesNotMatch(source, /Enable TTS preview\?/);
assert.doesNotMatch(source, /TTS_ENABLED=false/);
assert.match(source, /spoken replies remain enabled/);
});