|
| 1 | +import { Shell, SpawnStatus, VerbosityLevel } from 'codify-plugin-lib'; |
| 2 | +import { testSpawn } from 'codify-plugin-test'; |
1 | 3 | import { Command } from 'commander'; |
2 | | -import { glob } from 'glob'; |
3 | | -import { spawn, spawnSync } from 'node:child_process'; |
| 4 | +import { spawn } from 'node:child_process'; |
4 | 5 | import * as inspector from 'node:inspector'; |
5 | 6 | import os from 'node:os'; |
6 | | -import { OS } from 'codify-schemas'; |
| 7 | +import path from 'node:path'; |
| 8 | + |
| 9 | +import { codifySpawn } from '../src/utils/codify-spawn'; |
7 | 10 |
|
8 | 11 | const IP_REGEX = /VM was assigned with (.*) IP/; |
9 | 12 |
|
10 | 13 | const program = new Command(); |
11 | 14 |
|
12 | 15 | program |
| 16 | + .option('--launchPersistent', 'Launches a persistent VM for testing', false) |
13 | 17 | .option('--operatingSystem <operatingSystem>', 'Operating system to run tests on', os.platform()) |
| 18 | + .option('--persistent', 'Runs tests on a persistent VM (reuse) to skip the overhead of launching a new VM each time', false) |
14 | 19 | .argument('[file]', 'File to run') |
15 | 20 | .action(main) |
16 | 21 | .parse() |
17 | 22 |
|
18 | | -async function main(argument: string, args: { operatingSystem: string }): Promise<void> { |
| 23 | +async function main(argument: string, args: { operatingSystem: string; persistent: boolean; launchPersistent: boolean }): Promise<void> { |
19 | 24 | const debug = isInDebugMode(); |
20 | 25 | if (debug) { |
21 | 26 | console.log('Running in debug mode!') |
22 | 27 | } |
23 | 28 |
|
| 29 | + if (args.launchPersistent) { |
| 30 | + await launchPersistentVm(); |
| 31 | + return process.exit(0); |
| 32 | + } |
| 33 | + |
| 34 | + if (args.persistent) { |
| 35 | + if (!argument) { |
| 36 | + throw new Error('No test specified for persistent mode'); |
| 37 | + } |
| 38 | + |
| 39 | + await launchPersistentTest(argument, debug, args.operatingSystem); |
| 40 | + return process.exit(0); |
| 41 | + } |
| 42 | + |
24 | 43 | if (!argument) { |
25 | 44 | await launchTestAll(debug, args.operatingSystem) |
26 | 45 | return process.exit(0); |
@@ -49,6 +68,67 @@ async function launchSingleTest(test: string, debug: boolean, operatingSystem: s |
49 | 68 | await run(`cirrus run --lazy-pull ${image} -e FILE_NAME="${test}" -o simple`, debug) |
50 | 69 | } |
51 | 70 |
|
| 71 | +async function launchPersistentTest(test: string, debug: boolean, operatingSystem: string) { |
| 72 | + if (operatingSystem === 'darwin') { |
| 73 | + const { data: vmList } = await codifySpawn('tart list --format json'); |
| 74 | + console.log(vmList); |
| 75 | + |
| 76 | + const parsedVmList = JSON.parse(vmList); |
| 77 | + const runningVm = parsedVmList.find(vm => vm.Name.startsWith('codify-test-vm') && vm.Running === true); |
| 78 | + if (!runningVm) { |
| 79 | + throw new Error('No persistent VM found'); |
| 80 | + } |
| 81 | + |
| 82 | + const vmName = runningVm.Name; |
| 83 | + const dir = '/Users/admin/codify-homebrew-plugin'; |
| 84 | + |
| 85 | + const debugFlag = debug ? ' -e DEBUG="--inspect-brk=9229"' : '' |
| 86 | + |
| 87 | + console.log('Refreshing files on VM...'); |
| 88 | + const { data: ipAddr } = await testSpawn(`tart ip ${vmName}`); |
| 89 | + await testSpawn(`tart exec ${vmName} rm -rf ${dir}/src`); |
| 90 | + await testSpawn(`tart exec ${vmName} rm -rf ${dir}/test`); |
| 91 | + await testSpawn(`sshpass -p "admin" scp -r -o PubkeyAuthentication=no -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null ${path.join(process.cwd(), 'test')} admin@${ipAddr}:${dir}/test`); |
| 92 | + await testSpawn(`sshpass -p "admin" scp -r -o PubkeyAuthentication=no -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null ${path.join(process.cwd(), 'src')} admin@${ipAddr}:${dir}/src`); |
| 93 | + |
| 94 | + console.log('Done refreshing files on VM. Starting tests...'); |
| 95 | + VerbosityLevel.set(3); |
| 96 | + await codifySpawn(`tart exec -i ${vmName} zsh -i -c "cd ${dir} && FORCE_COLOR=true npm run test -- ${test} --disable-console-intercept ${debugFlag} --no-file-parallelism"`); |
| 97 | + } |
| 98 | +} |
| 99 | + |
| 100 | +async function launchPersistentVm() { |
| 101 | + const newVmName = `codify-test-vm-${Date.now()}`; |
| 102 | + console.log(`Cloning new VM... ${newVmName}`); |
| 103 | + |
| 104 | + await testSpawn(`tart clone codify-test-vm ${newVmName}`); |
| 105 | + testSpawn(`tart run ${newVmName}`) |
| 106 | + .then(cleanupVm) |
| 107 | + |
| 108 | + process.on('exit', cleanupVm); |
| 109 | + process.on('SIGINT', cleanupVm); |
| 110 | + process.on('SIGHUP', cleanupVm); |
| 111 | + process.on('SIGTERM', cleanupVm); |
| 112 | + |
| 113 | + await sleep(5000); |
| 114 | + await waitUntilVmIsReady(newVmName); |
| 115 | + |
| 116 | + const { data: ipAddr } = await testSpawn(`tart ip ${newVmName}`); |
| 117 | + await testSpawn(`sshpass -p "admin" rsync -avz -e 'ssh -o PubkeyAuthentication=no -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null' --exclude 'node_modules' --exclude '.git' --exclude 'dist' --exclude '.fleet' ${process.cwd()} admin@${ipAddr}:~`); |
| 118 | + await testSpawn(`tart exec ${newVmName} zsh -i -c "cd ~/codify-homebrew-plugin && npm ci"`); |
| 119 | + console.log('Finished installing dependencies. Start tests in a new terminal window.'); |
| 120 | + |
| 121 | + await sleep(1_000_000_000); |
| 122 | + // This is effective the end just without a return |
| 123 | + |
| 124 | + async function cleanupVm() { |
| 125 | + console.log('Deleting VM after...') |
| 126 | + await testSpawn(`tart delete ${newVmName}`); |
| 127 | + process.exit(0); |
| 128 | + } |
| 129 | +} |
| 130 | + |
| 131 | + |
52 | 132 | async function run(cmd: string, debug: boolean, simple = true) { |
53 | 133 | const messageBuffer: string[] = []; |
54 | 134 |
|
@@ -108,7 +188,22 @@ async function run(cmd: string, debug: boolean, simple = true) { |
108 | 188 |
|
109 | 189 | } |
110 | 190 |
|
| 191 | +function sleep(ms: number) { |
| 192 | + return new Promise(resolve => setTimeout(resolve, ms)); |
| 193 | +} |
111 | 194 |
|
112 | 195 | function isInDebugMode() { |
113 | 196 | return inspector.url() !== undefined; |
114 | 197 | } |
| 198 | + |
| 199 | + |
| 200 | +async function waitUntilVmIsReady(vmName: string): Promise<void> { |
| 201 | + while (true) { |
| 202 | + const result = await testSpawn(`tart exec ${vmName} pwd`, { interactive: true }) |
| 203 | + if (result.status === SpawnStatus.SUCCESS) { |
| 204 | + return; |
| 205 | + } |
| 206 | + |
| 207 | + await sleep(1000); |
| 208 | + } |
| 209 | +} |
0 commit comments