mirror of
https://github.com/samsonjs/vibetunnel.git
synced 2026-03-25 09:25:50 +00:00
230 lines
No EOL
7 KiB
JavaScript
Executable file
230 lines
No EOL
7 KiB
JavaScript
Executable file
#!/usr/bin/env node
|
|
|
|
// Test server runner that builds and runs the JavaScript version to avoid tsx/node-pty issues
|
|
const { spawn, execSync } = require('child_process');
|
|
const path = require('path');
|
|
const fs = require('fs');
|
|
|
|
const projectRoot = path.join(__dirname, '..');
|
|
|
|
// Check if we're in VIBETUNNEL_SEA mode and have the native executable
|
|
const nativeExecutable = path.join(projectRoot, 'native/vibetunnel');
|
|
const distCliPath = path.join(projectRoot, 'dist/cli.js');
|
|
let cliPath;
|
|
let useNode = true;
|
|
|
|
if (process.env.VIBETUNNEL_SEA === 'true' && fs.existsSync(nativeExecutable)) {
|
|
console.log('Using native executable for tests (VIBETUNNEL_SEA mode)');
|
|
cliPath = nativeExecutable;
|
|
useNode = false;
|
|
} else if (fs.existsSync(distCliPath)) {
|
|
console.log('Using TypeScript compiled version for tests');
|
|
cliPath = distCliPath;
|
|
} else {
|
|
// Fallback: build TypeScript files if needed
|
|
console.log('Building server TypeScript files for tests...');
|
|
try {
|
|
execSync('pnpm exec tsc -p tsconfig.server.json', {
|
|
stdio: 'inherit',
|
|
cwd: projectRoot
|
|
});
|
|
console.log('TypeScript build completed successfully');
|
|
cliPath = distCliPath;
|
|
} catch (error) {
|
|
console.error('Failed to build server TypeScript files:', error);
|
|
console.error('Build command exit code:', error.status);
|
|
console.error('Build command signal:', error.signal);
|
|
process.exit(1);
|
|
}
|
|
}
|
|
|
|
// Ensure native modules are available
|
|
execSync('node scripts/ensure-native-modules.js', {
|
|
stdio: 'inherit',
|
|
cwd: projectRoot
|
|
});
|
|
|
|
// Check if the CLI file exists
|
|
if (!fs.existsSync(cliPath)) {
|
|
console.error(`CLI not found at ${cliPath}`);
|
|
console.error('Available files:');
|
|
|
|
// Check native directory
|
|
const nativePath = path.join(projectRoot, 'native');
|
|
if (fs.existsSync(nativePath)) {
|
|
console.error('Native directory contents:');
|
|
const files = fs.readdirSync(nativePath);
|
|
files.forEach(file => console.error(` - ${file}`));
|
|
}
|
|
|
|
// Check dist directory
|
|
const distPath = path.join(projectRoot, 'dist');
|
|
if (fs.existsSync(distPath)) {
|
|
console.error('Dist directory contents:');
|
|
const files = fs.readdirSync(distPath);
|
|
files.forEach(file => console.error(` - ${file}`));
|
|
}
|
|
|
|
process.exit(1);
|
|
}
|
|
|
|
// Verify executable permissions for native executable
|
|
if (!useNode) {
|
|
try {
|
|
fs.accessSync(cliPath, fs.constants.X_OK);
|
|
console.log('Native executable has execute permissions');
|
|
} catch (error) {
|
|
console.error('Native executable is not executable! Attempting to fix...');
|
|
try {
|
|
fs.chmodSync(cliPath, 0o755);
|
|
console.log('Fixed executable permissions');
|
|
} catch (chmodError) {
|
|
console.error('Failed to fix permissions:', chmodError.message);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Prepare arguments based on whether we're using node or native executable
|
|
const args = useNode ? [cliPath, ...process.argv.slice(2)] : process.argv.slice(2);
|
|
const command = useNode ? 'node' : cliPath;
|
|
|
|
// Extract port from arguments
|
|
let port = 4022; // default test port
|
|
const portArgIndex = process.argv.indexOf('--port');
|
|
if (portArgIndex !== -1 && process.argv[portArgIndex + 1]) {
|
|
port = process.argv[portArgIndex + 1];
|
|
}
|
|
|
|
// Spawn the server
|
|
console.log(`Starting test server: ${command} ${args.join(' ')}`);
|
|
console.log(`Working directory: ${projectRoot}`);
|
|
console.log(`Port: ${port}`);
|
|
|
|
// Capture output for debugging in CI
|
|
const stdio = process.env.CI ? ['inherit', 'pipe', 'pipe'] : 'inherit';
|
|
|
|
const child = spawn(command, args, {
|
|
stdio: stdio,
|
|
cwd: projectRoot,
|
|
env: {
|
|
...process.env,
|
|
// Ensure we're not in SEA mode for tests (unless we're already using the native executable)
|
|
VIBETUNNEL_SEA: useNode ? '' : 'true',
|
|
PORT: port.toString()
|
|
}
|
|
});
|
|
|
|
// Capture output in CI for debugging
|
|
let stdout = '';
|
|
let stderr = '';
|
|
let hasExited = false;
|
|
|
|
if (process.env.CI) {
|
|
child.stdout.on('data', (data) => {
|
|
const str = data.toString();
|
|
stdout += str;
|
|
process.stdout.write(str);
|
|
});
|
|
|
|
child.stderr.on('data', (data) => {
|
|
const str = data.toString();
|
|
stderr += str;
|
|
process.stderr.write(str);
|
|
});
|
|
}
|
|
|
|
// Add error handling
|
|
child.on('error', (error) => {
|
|
console.error('Failed to start server process:', error);
|
|
if (error.code === 'ENOENT') {
|
|
console.error('The executable was not found. Path:', command);
|
|
} else if (error.code === 'EACCES') {
|
|
console.error('The executable does not have execute permissions');
|
|
}
|
|
process.exit(1);
|
|
});
|
|
|
|
// Log when process starts
|
|
child.on('spawn', () => {
|
|
console.log('Server process spawned successfully');
|
|
console.log(`Server PID: ${child.pid}`);
|
|
});
|
|
|
|
// Handle early exit
|
|
child.on('exit', (code, signal) => {
|
|
hasExited = true;
|
|
if (code !== 0 || signal) {
|
|
console.error(`\nServer process exited unexpectedly with code ${code}, signal ${signal}`);
|
|
if (stderr) {
|
|
console.error('Last stderr output:', stderr.slice(-1000));
|
|
}
|
|
if (stdout) {
|
|
console.error('Last stdout output:', stdout.slice(-1000));
|
|
}
|
|
|
|
// If using native executable, try to diagnose the issue
|
|
if (!useNode && process.env.CI) {
|
|
console.error('\nAttempting to diagnose native executable issue...');
|
|
try {
|
|
// Try running with --version to see if it works at all
|
|
const versionResult = require('child_process').spawnSync(cliPath, ['--version'], {
|
|
encoding: 'utf8',
|
|
env: { ...process.env, NODE_ENV: 'test' }
|
|
});
|
|
console.error('Version test result:', versionResult);
|
|
} catch (e) {
|
|
console.error('Failed to run version test:', e.message);
|
|
}
|
|
}
|
|
}
|
|
process.exit(code || 0);
|
|
});
|
|
|
|
// Wait for server to be ready before allowing parent process to continue
|
|
if (process.env.CI || process.env.WAIT_FOR_SERVER) {
|
|
// Give server a moment to start
|
|
setTimeout(() => {
|
|
if (hasExited) {
|
|
console.error('Server exited before we could check if it was ready');
|
|
return;
|
|
}
|
|
|
|
const waitChild = spawn('node', [path.join(projectRoot, 'scripts/wait-for-server.js')], {
|
|
stdio: 'inherit',
|
|
cwd: projectRoot,
|
|
env: {
|
|
...process.env,
|
|
PORT: port.toString()
|
|
}
|
|
});
|
|
|
|
waitChild.on('exit', (code) => {
|
|
if (code !== 0) {
|
|
console.error('Server failed to become ready');
|
|
child.kill();
|
|
process.exit(1);
|
|
} else {
|
|
console.log('Server is ready, tests can proceed');
|
|
|
|
// In CI, add periodic health checks
|
|
if (process.env.CI) {
|
|
const healthCheckInterval = setInterval(() => {
|
|
if (hasExited) {
|
|
clearInterval(healthCheckInterval);
|
|
return;
|
|
}
|
|
|
|
const http = require('http');
|
|
http.get(`http://localhost:${port}/api/health`, (res) => {
|
|
if (res.statusCode !== 200) {
|
|
console.error(`Health check failed with status ${res.statusCode}`);
|
|
}
|
|
}).on('error', (err) => {
|
|
console.error(`Health check error: ${err.message}`);
|
|
});
|
|
}, 10000); // Check every 10 seconds
|
|
}
|
|
}
|
|
});
|
|
}, 3000); // Wait 3 seconds before checking
|
|
} |