#!/usr/bin/env node /* global console process */ /** * Comprehensive test for prebuilt dependencies * Verifies pyvenv.cfg and Python symlinks are correct */ import fs from 'fs'; import path from 'path'; import { fileURLToPath } from 'url'; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); const projectRoot = path.resolve(__dirname, '..'); let testsPassed = 0; let testsFailed = 0; function pass(message) { console.log(` โœ… ${message}`); testsPassed++; } function fail(message) { console.log(` โŒ ${message}`); testsFailed++; } function warn(message) { console.log(` โš ๏ธ ${message}`); } function testPyvenvCfg(venvPath, venvName) { console.log(`\n๐Ÿ“ Testing ${venvName} pyvenv.cfg`); const pyvenvCfgPath = path.join(venvPath, 'pyvenv.cfg'); if (!fs.existsSync(pyvenvCfgPath)) { fail('pyvenv.cfg not found'); return; } const content = fs.readFileSync(pyvenvCfgPath, 'utf-8'); const homeMatch = content.match(/^home\s*=\s*(.+)$/m); if (!homeMatch) { fail('No home line found in pyvenv.cfg'); return; } const homePath = homeMatch[1].trim(); // Check if using placeholder (build-time state) if (homePath.includes('{{PREBUILT_PYTHON_DIR}}')) { pass('Using placeholder (ready for packaging)'); pass(`Home: ${homePath}`); } // Check if using absolute path (should be fixed) else if (path.isAbsolute(homePath)) { // Check if it's a valid path on this machine if (fs.existsSync(homePath)) { pass('Using absolute path (runtime-fixed or local)'); pass(`Home: ${homePath}`); } else { fail('Using absolute path that does not exist!'); fail(`Path: ${homePath}`); warn('Run: npm run fix-venv-paths'); } } // Relative path else { warn(`Using relative path: ${homePath}`); } } function testPythonSymlinks(venvPath, venvName) { console.log(`\n๐Ÿ”— Testing ${venvName} Python symlinks`); const binDir = path.join(venvPath, 'bin'); if (!fs.existsSync(binDir)) { fail('bin/ directory not found'); return; } const symlinkNames = ['python', 'python3', 'python3.10']; for (const symlinkName of symlinkNames) { const symlinkPath = path.join(binDir, symlinkName); if (!fs.existsSync(symlinkPath)) { try { // Check if it's a broken symlink fs.lstatSync(symlinkPath); fail(`${symlinkName}: broken symlink (target doesn't exist)`); const target = fs.readlinkSync(symlinkPath); fail(` Target: ${target}`); warn('Run: npm run fix-symlinks'); } catch (err) { fail(`${symlinkName}: missing - ${err.message}`); warn('Run: npm run fix-symlinks'); } continue; } try { const stats = fs.lstatSync(symlinkPath); if (stats.isSymbolicLink()) { const target = fs.readlinkSync(symlinkPath); // Check if absolute path (bad) if (path.isAbsolute(target)) { fail(`${symlinkName}: using absolute path`); fail(` Target: ${target}`); warn('Run: npm run fix-symlinks'); } // Check if relative path (good) else { const resolvedPath = path.resolve(binDir, target); if (fs.existsSync(resolvedPath)) { pass(`${symlinkName} -> ${target}`); } else { fail(`${symlinkName}: relative symlink but target doesn't exist`); fail(` Target: ${target}`); fail(` Resolved: ${resolvedPath}`); } } } else { // Not a symlink, might be a copy pass(`${symlinkName}: regular file (not symlink)`); } } catch (err) { fail(`${symlinkName}: error checking - ${err.message}`); } } } function testPythonExecutable(venvPath, venvName) { console.log(`\n๐Ÿ Testing ${venvName} Python executable`); const binDir = path.join(venvPath, 'bin'); const pythonPath = path.join(binDir, 'python'); if (!fs.existsSync(pythonPath)) { fail('Python executable not found'); return; } try { // Verify it's executable (on Unix) if (process.platform !== 'win32') { const stats = fs.statSync(pythonPath); const isExecutable = (stats.mode & fs.constants.S_IXUSR) !== 0; if (isExecutable) { pass('Python is executable'); } else { fail('Python is not executable'); } } else { pass('Python file exists (Windows)'); } } catch (err) { fail(`Error checking executable: ${err.message}`); } } function main() { console.log('๐Ÿงช Testing Prebuilt Dependencies'); console.log('='.repeat(50)); const venvs = [ { path: path.join(projectRoot, 'resources', 'prebuilt', 'venv'), name: 'Backend venv', }, { path: path.join(projectRoot, 'resources', 'prebuilt', 'terminal_venv'), name: 'Terminal venv', }, ]; for (const venv of venvs) { if (!fs.existsSync(venv.path)) { console.log(`\nโš ๏ธ ${venv.name} not found: ${venv.path}`); console.log(' This is OK for development builds'); continue; } testPyvenvCfg(venv.path, venv.name); testPythonSymlinks(venv.path, venv.name); testPythonExecutable(venv.path, venv.name); } console.log('\n' + '='.repeat(50)); console.log( `\n๐Ÿ“Š Test Results: ${testsPassed} passed, ${testsFailed} failed` ); if (testsFailed > 0) { console.log('\nโŒ Some tests failed!'); console.log('\n๐Ÿ”ง To fix:'); console.log(' npm run fix-venv-paths # Fix pyvenv.cfg'); console.log(' npm run fix-symlinks # Fix Python symlinks'); process.exit(1); } else { console.log('\nโœ… All tests passed! Prebuilt dependencies are ready.'); } } main();