| /* | |
| * Licensed to the Apache Software Foundation (ASF) under one | |
| * or more contributor license agreements. See the NOTICE file | |
| * distributed with this work for additional information | |
| * regarding copyright ownership. The ASF licenses this file | |
| * to you under the Apache License, Version 2.0 (the | |
| * "License"); you may not use this file except in compliance | |
| * with the License. You may obtain a copy of the License at | |
| * | |
| * http://www.apache.org/licenses/LICENSE-2.0 | |
| * | |
| * Unless required by applicable law or agreed to in writing, | |
| * software distributed under the License is distributed on an | |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | |
| * KIND, either express or implied. See the License for the | |
| * specific language governing permissions and limitations | |
| * under the License. | |
| */ | |
| import assert from 'node:assert/strict'; | |
| import childProcess from 'node:child_process'; | |
| import { EventEmitter } from 'node:events'; | |
| import { syncBuiltinESMExports } from 'node:module'; | |
| import test from 'node:test'; | |
| import { fileURLToPath } from 'node:url'; | |
| import { runCli } from './run-cli.mjs'; | |
| const launcher = fileURLToPath(new URL('./run-cli.mjs', import.meta.url)); | |
| const root = fileURLToPath(new URL('../../', import.meta.url)); | |
| test('development builds select the native capability before forwarding CLI arguments', async (t) => { | |
| let invocation; | |
| t.mock.method(childProcess, 'spawn', (command, args, options) => { | |
| invocation = { command, args, options }; | |
| const child = new EventEmitter(); | |
| queueMicrotask(() => child.emit('exit', 0, null)); | |
| return child; | |
| }); | |
| syncBuiltinESMExports(); | |
| t.after(() => { | |
| t.mock.restoreAll(); | |
| syncBuiltinESMExports(); | |
| }); | |
| const native = ['run', '--locked', '-p', 'maka-cli', '--', 'code', '--log', 'a b.sqlite']; | |
| const bridge = [ | |
| 'run', | |
| '--locked', | |
| '-p', | |
| 'maka-cli', | |
| '--no-default-features', | |
| '--', | |
| 'code', | |
| '--log', | |
| 'a b.sqlite', | |
| ]; | |
| for (const [mode, platform, osRelease, expected] of [ | |
| [undefined, 'linux', '6.8.0-generic', native], | |
| [undefined, 'linux', '6.6.87.2-microsoft-standard-WSL2', bridge], | |
| ['auto', 'linux', '4.4.0-Microsoft', bridge], | |
| ['auto', 'darwin', 'Microsoft', native], | |
| ['auto', 'win32', 'Microsoft', native], | |
| ['native', 'linux', '6.6.87.2-microsoft-standard-WSL2', native], | |
| ['bridge', 'linux', '6.8.0-generic', bridge], | |
| ]) { | |
| const env = mode === undefined ? {} : { MAKA_CUA_BUILD_MODE: mode }; | |
| assert.deepEqual( | |
| await runCli(['code', '--log', 'a b.sqlite'], { | |
| env, | |
| platform, | |
| osRelease, | |
| repositoryRoot: '/source checkout', | |
| }), | |
| { code: 0, signal: null }, | |
| ); | |
| assert.deepEqual(invocation, { | |
| command: 'cargo', | |
| args: expected, | |
| options: { | |
| cwd: '/source checkout', | |
| env, | |
| stdio: 'inherit', | |
| windowsHide: true, | |
| }, | |
| }); | |
| } | |
| }); | |
| // Run the public Node entrypoint while replacing only its external Cargo process. | |
| function invokeLauncher(event, env = {}) { | |
| const preload = ` | |
| import childProcess from 'node:child_process'; | |
| import { EventEmitter } from 'node:events'; | |
| import { syncBuiltinESMExports } from 'node:module'; | |
| childProcess.spawn = (command, args, options) => { | |
| process.stdout.write(JSON.stringify({ command, args, cwd: options.cwd }) + '\\n'); | |
| const child = new EventEmitter(); | |
| queueMicrotask(() => ${event}); | |
| return child; | |
| }; | |
| syncBuiltinESMExports(); | |
| `; | |
| return childProcess.spawnSync( | |
| process.execPath, | |
| ['--import', 'data:text/javascript,' + encodeURIComponent(preload), launcher, '--help'], | |
| { | |
| env: { ...process.env, MAKA_CUA_BUILD_MODE: 'bridge', ...env }, | |
| encoding: 'utf8', | |
| timeout: 10_000, | |
| windowsHide: true, | |
| }, | |
| ); | |
| } | |
| test('the launcher preserves Cargo failures and invokes Cargo from the repository', () => { | |
| const result = invokeLauncher("child.emit('exit', 29, null)"); | |
| assert.equal(result.status, 29); | |
| assert.equal(result.stderr, ''); | |
| assert.deepEqual(JSON.parse(result.stdout), { | |
| command: 'cargo', | |
| args: ['build', '--locked', '-p', 'maka-python-runtime', '--bin', 'maka-python-worker'], | |
| cwd: root, | |
| }); | |
| }); | |
| test('the launcher reports a Cargo spawn error', () => { | |
| const result = invokeLauncher("child.emit('error', new Error('Cargo could not start'))"); | |
| assert.equal(result.status, 1); | |
| assert.equal(result.stderr, 'Cargo could not start\n'); | |
| }); | |
| test('the launcher rejects unknown build modes before starting Cargo', () => { | |
| const result = invokeLauncher("child.emit('exit', 0, null)", { MAKA_CUA_BUILD_MODE: 'typo' }); | |
| assert.equal(result.status, 1); | |
| assert.equal(result.stdout, ''); | |
| assert.equal(result.stderr, 'MAKA_CUA_BUILD_MODE must be auto, native, or bridge\n'); | |
| }); | |
| test('the launcher preserves Cargo termination signals', { | |
| skip: process.platform === 'win32', | |
| }, () => { | |
| const result = invokeLauncher("child.emit('exit', null, 'SIGTERM')"); | |
| assert.equal(result.status, null); | |
| assert.equal(result.signal, 'SIGTERM'); | |
| }); |