mirror of
https://github.com/electron/node-gyp.git
synced 2025-08-15 12:58:19 +02:00
chore: misc testing fixes (#2930)
* chore: misc test fixes * Sort test runs by os first * Use cross-env for test env var * Try sorting matrix params * Make FAST_TEST the default and rename to FULL_TEST * Separate helper functions to not need to export test obj in files
This commit is contained in:
parent
d52997e975
commit
4e493d4fb2
18 changed files with 239 additions and 329 deletions
2
.github/PULL_REQUEST_TEMPLATE.md
vendored
2
.github/PULL_REQUEST_TEMPLATE.md
vendored
|
@ -7,7 +7,7 @@ Contributor guide: https://github.com/nodejs/node/blob/main/CONTRIBUTING.md
|
|||
##### Checklist
|
||||
<!-- Remove items that do not apply. For completed items, change [ ] to [x]. -->
|
||||
|
||||
- [ ] `npm install && npm test` passes
|
||||
- [ ] `npm install && npm run lint && npm test` passes
|
||||
- [ ] tests are included <!-- Bug fixes and new features should include tests -->
|
||||
- [ ] documentation is changed or added
|
||||
- [ ] commit message follows [commit guidelines](https://github.com/googleapis/release-please#how-should-i-write-my-commits)
|
||||
|
|
28
.github/workflows/tests.yml
vendored
28
.github/workflows/tests.yml
vendored
|
@ -18,11 +18,24 @@ jobs:
|
|||
- uses: actions/checkout@v4
|
||||
- run: pip install --user ruff
|
||||
- run: ruff --output-format=github --select="E,F,PLC,PLE,UP,W,YTT" --ignore="E721,PLC1901,S101,UP031" --target-version=py38 .
|
||||
Lint_JS:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout Repository
|
||||
uses: actions/checkout@v4
|
||||
- name: Use Node.js 20.x
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 20.x
|
||||
- name: Install Dependencies
|
||||
run: npm install --no-progress
|
||||
- name: Lint
|
||||
run: npm run lint
|
||||
Engines:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout Repository
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
- name: Use Node.js 20.x
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
|
@ -41,10 +54,11 @@ jobs:
|
|||
fail-fast: false
|
||||
max-parallel: 15
|
||||
matrix:
|
||||
node: [16.x, 18.x, 20.x]
|
||||
os: [macos, ubuntu, windows]
|
||||
python: ["3.8", "3.10", "3.12"]
|
||||
os: [macos-latest, ubuntu-latest, windows-latest]
|
||||
runs-on: ${{ matrix.os }}
|
||||
node: [16.x, 18.x, 20.x]
|
||||
name: ${{ matrix.os }} - ${{ matrix.python }} - ${{ matrix.node }}
|
||||
runs-on: ${{ matrix.os }}-latest
|
||||
steps:
|
||||
- name: Checkout Repository
|
||||
uses: actions/checkout@v4
|
||||
|
@ -63,7 +77,7 @@ jobs:
|
|||
npm install --no-progress
|
||||
pip install pytest
|
||||
- name: Set Windows environment
|
||||
if: startsWith(matrix.os, 'windows')
|
||||
if: matrix.os == 'windows'
|
||||
run: |
|
||||
echo 'GYP_MSVS_VERSION=2015' >> $Env:GITHUB_ENV
|
||||
echo 'GYP_MSVS_OVERRIDE_PATH=C:\\Dummy' >> $Env:GITHUB_ENV
|
||||
|
@ -77,7 +91,11 @@ jobs:
|
|||
if: runner.os != 'Windows'
|
||||
shell: bash
|
||||
run: npm test --python="${pythonLocation}/python"
|
||||
env:
|
||||
FULL_TEST: ${{ (matrix.node == '20.x' && matrix.python == '3.12') && '1' || '0' }}
|
||||
- name: Run tests (Windows)
|
||||
if: runner.os == 'Windows'
|
||||
shell: pwsh
|
||||
run: npm run test --python="${env:pythonLocation}\\python.exe"
|
||||
env:
|
||||
FULL_TEST: ${{ (matrix.node == '20.x' && matrix.python == '3.12') && '1' || '0' }}
|
||||
|
|
|
@ -32,9 +32,9 @@ if (prog.devDir) {
|
|||
|
||||
if (prog.todo.length === 0) {
|
||||
if (~process.argv.indexOf('-v') || ~process.argv.indexOf('--version')) {
|
||||
console.log('v%s', prog.version)
|
||||
log.stdout('v%s', prog.version)
|
||||
} else {
|
||||
console.log('%s', prog.usage())
|
||||
log.stdout('%s', prog.usage())
|
||||
}
|
||||
process.exit(0)
|
||||
}
|
||||
|
@ -82,12 +82,12 @@ async function run () {
|
|||
|
||||
if (command.name === 'list') {
|
||||
if (args.length) {
|
||||
args.forEach((version) => console.log(version))
|
||||
args.forEach((version) => log.stdout(version))
|
||||
} else {
|
||||
console.log('No node development files installed. Use `node-gyp install` to install a version.')
|
||||
log.stdout('No node development files installed. Use `node-gyp install` to install a version.')
|
||||
}
|
||||
} else if (args.length >= 1) {
|
||||
console.log(...args.slice(1))
|
||||
log.stdout(...args.slice(1))
|
||||
}
|
||||
|
||||
// now run the next command in the queue
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
'use strict'
|
||||
|
||||
const { openSync, closeSync, promises: fs } = require('graceful-fs')
|
||||
const { promises: fs } = require('graceful-fs')
|
||||
const path = require('path')
|
||||
const log = require('./log')
|
||||
const os = require('os')
|
||||
const processRelease = require('./process-release')
|
||||
const win = process.platform === 'win32'
|
||||
const findNodeDirectory = require('./find-node-directory')
|
||||
const createConfigGypi = require('./create-config-gypi')
|
||||
const { format: msgFormat } = require('util')
|
||||
const { createConfigGypi } = require('./create-config-gypi')
|
||||
const { format: msgFormat, findAccessibleSync } = require('util')
|
||||
const { findPython } = require('./find-python')
|
||||
const { findVisualStudio } = win ? require('./find-visualstudio') : {}
|
||||
|
||||
|
@ -277,32 +277,5 @@ async function configure (gyp, argv) {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the first file or directory from an array of candidates that is
|
||||
* readable by the current user, or undefined if none of the candidates are
|
||||
* readable.
|
||||
*/
|
||||
function findAccessibleSync (logprefix, dir, candidates) {
|
||||
for (let next = 0; next < candidates.length; next++) {
|
||||
const candidate = path.resolve(dir, candidates[next])
|
||||
let fd
|
||||
try {
|
||||
fd = openSync(candidate, 'r')
|
||||
} catch (e) {
|
||||
// this candidate was not found or not readable, do nothing
|
||||
log.silly(logprefix, 'Could not open %s: %s', candidate, e.message)
|
||||
continue
|
||||
}
|
||||
closeSync(fd)
|
||||
log.silly(logprefix, 'Found readable %s', candidate)
|
||||
return candidate
|
||||
}
|
||||
|
||||
return undefined
|
||||
}
|
||||
|
||||
module.exports = configure
|
||||
module.exports.test = {
|
||||
findAccessibleSync
|
||||
}
|
||||
module.exports.usage = 'Generates ' + (win ? 'MSVC project files' : 'a Makefile') + ' for the current module'
|
||||
|
|
|
@ -143,8 +143,8 @@ async function createConfigGypi ({ gyp, buildDir, nodeDir, vsInfo, python }) {
|
|||
return configPath
|
||||
}
|
||||
|
||||
module.exports = createConfigGypi
|
||||
module.exports.test = {
|
||||
module.exports = {
|
||||
createConfigGypi,
|
||||
parseConfigGypi,
|
||||
getCurrentConfigGypi
|
||||
}
|
||||
|
|
39
lib/download.js
Normal file
39
lib/download.js
Normal file
|
@ -0,0 +1,39 @@
|
|||
const fetch = require('make-fetch-happen')
|
||||
const { promises: fs } = require('graceful-fs')
|
||||
const log = require('./log')
|
||||
|
||||
async function download (gyp, url) {
|
||||
log.http('GET', url)
|
||||
|
||||
const requestOpts = {
|
||||
headers: {
|
||||
'User-Agent': `node-gyp v${gyp.version} (node ${process.version})`,
|
||||
Connection: 'keep-alive'
|
||||
},
|
||||
proxy: gyp.opts.proxy,
|
||||
noProxy: gyp.opts.noproxy
|
||||
}
|
||||
|
||||
const cafile = gyp.opts.cafile
|
||||
if (cafile) {
|
||||
requestOpts.ca = await readCAFile(cafile)
|
||||
}
|
||||
|
||||
const res = await fetch(url, requestOpts)
|
||||
log.http(res.status, res.url)
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
async function readCAFile (filename) {
|
||||
// The CA file can contain multiple certificates so split on certificate
|
||||
// boundaries. [\S\s]*? is used to match everything including newlines.
|
||||
const ca = await fs.readFile(filename, 'utf8')
|
||||
const re = /(-----BEGIN CERTIFICATE-----[\S\s]*?-----END CERTIFICATE-----)/g
|
||||
return ca.match(re)
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
download,
|
||||
readCAFile
|
||||
}
|
|
@ -9,12 +9,13 @@ const { Transform, promises: { pipeline } } = require('stream')
|
|||
const crypto = require('crypto')
|
||||
const log = require('./log')
|
||||
const semver = require('semver')
|
||||
const fetch = require('make-fetch-happen')
|
||||
const { download } = require('./download')
|
||||
const processRelease = require('./process-release')
|
||||
|
||||
const win = process.platform === 'win32'
|
||||
|
||||
async function install (gyp, argv) {
|
||||
console.log()
|
||||
log.stdout()
|
||||
const release = processRelease(argv, gyp, process.version, process.release)
|
||||
// Detecting target_arch based on logic from create-cnfig-gyp.js. Used on Windows only.
|
||||
const arch = win ? (gyp.opts.target_arch || gyp.opts.arch || process.arch || 'ia32') : ''
|
||||
|
@ -410,41 +411,5 @@ class ShaSum extends Transform {
|
|||
}
|
||||
}
|
||||
|
||||
async function download (gyp, url) {
|
||||
log.http('GET', url)
|
||||
|
||||
const requestOpts = {
|
||||
headers: {
|
||||
'User-Agent': `node-gyp v${gyp.version} (node ${process.version})`,
|
||||
Connection: 'keep-alive'
|
||||
},
|
||||
proxy: gyp.opts.proxy,
|
||||
noProxy: gyp.opts.noproxy
|
||||
}
|
||||
|
||||
const cafile = gyp.opts.cafile
|
||||
if (cafile) {
|
||||
requestOpts.ca = await readCAFile(cafile)
|
||||
}
|
||||
|
||||
const res = await fetch(url, requestOpts)
|
||||
log.http(res.status, res.url)
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
async function readCAFile (filename) {
|
||||
// The CA file can contain multiple certificates so split on certificate
|
||||
// boundaries. [\S\s]*? is used to match everything including newlines.
|
||||
const ca = await fs.readFile(filename, 'utf8')
|
||||
const re = /(-----BEGIN CERTIFICATE-----[\S\s]*?-----END CERTIFICATE-----)/g
|
||||
return ca.match(re)
|
||||
}
|
||||
|
||||
module.exports = install
|
||||
module.exports.test = {
|
||||
download,
|
||||
install,
|
||||
readCAFile
|
||||
}
|
||||
module.exports.usage = 'Install node development files for the specified node version.'
|
||||
|
|
10
lib/log.js
10
lib/log.js
|
@ -73,11 +73,11 @@ class Logger {
|
|||
style: { fg: 'red', bg: 'black' }
|
||||
}]
|
||||
|
||||
constructor () {
|
||||
constructor (stream) {
|
||||
process.on('log', (...args) => this.#onLog(...args))
|
||||
this.#levels = new Map(this.#levels.map((level, index) => [level.id, { ...level, index }]))
|
||||
this.level = 'info'
|
||||
this.stream = process.stderr
|
||||
this.stream = stream
|
||||
procLog.pause()
|
||||
}
|
||||
|
||||
|
@ -158,8 +158,12 @@ class Logger {
|
|||
}
|
||||
}
|
||||
|
||||
// used to suppress logs in tests
|
||||
const NULL_LOGGER = !!process.env.NODE_GYP_NULL_LOGGER
|
||||
|
||||
module.exports = {
|
||||
logger: new Logger(),
|
||||
logger: new Logger(NULL_LOGGER ? null : process.stderr),
|
||||
stdout: NULL_LOGGER ? () => {} : (...args) => console.log(...args),
|
||||
withPrefix,
|
||||
...procLog
|
||||
}
|
||||
|
|
30
lib/util.js
30
lib/util.js
|
@ -1,8 +1,9 @@
|
|||
'use strict'
|
||||
|
||||
const log = require('./log')
|
||||
const cp = require('child_process')
|
||||
const path = require('path')
|
||||
const { openSync, closeSync } = require('graceful-fs')
|
||||
const log = require('./log')
|
||||
|
||||
const execFile = async (...args) => new Promise((resolve) => {
|
||||
const child = cp.execFile(...args, (...a) => resolve(a))
|
||||
|
@ -48,8 +49,33 @@ async function regSearchKeys (keys, value, addOpts) {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the first file or directory from an array of candidates that is
|
||||
* readable by the current user, or undefined if none of the candidates are
|
||||
* readable.
|
||||
*/
|
||||
function findAccessibleSync (logprefix, dir, candidates) {
|
||||
for (let next = 0; next < candidates.length; next++) {
|
||||
const candidate = path.resolve(dir, candidates[next])
|
||||
let fd
|
||||
try {
|
||||
fd = openSync(candidate, 'r')
|
||||
} catch (e) {
|
||||
// this candidate was not found or not readable, do nothing
|
||||
log.silly(logprefix, 'Could not open %s: %s', candidate, e.message)
|
||||
continue
|
||||
}
|
||||
closeSync(fd)
|
||||
log.silly(logprefix, 'Found readable %s', candidate)
|
||||
return candidate
|
||||
}
|
||||
|
||||
return undefined
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
execFile,
|
||||
regGetValue,
|
||||
regSearchKeys
|
||||
regSearchKeys,
|
||||
findAccessibleSync
|
||||
}
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
},
|
||||
"devDependencies": {
|
||||
"bindings": "^1.5.0",
|
||||
"cross-env": "^7.0.3",
|
||||
"mocha": "^10.2.0",
|
||||
"nan": "^2.14.2",
|
||||
"require-inject": "^1.4.4",
|
||||
|
@ -45,6 +46,6 @@
|
|||
},
|
||||
"scripts": {
|
||||
"lint": "standard \"*/*.js\" \"test/**/*.js\" \".github/**/*.js\"",
|
||||
"test": "npm run lint && mocha --timeout 15000 --reporter=test/reporter.js test/test-download.js test/test-*"
|
||||
"test": "cross-env NODE_GYP_NULL_LOGGER=true mocha --timeout 15000 test/test-download.js test/test-*"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
const envPaths = require('env-paths')
|
||||
const semver = require('semver')
|
||||
|
||||
module.exports.devDir = () => envPaths('node-gyp', { suffix: '' }).cache
|
||||
module.exports.devDir = envPaths('node-gyp', { suffix: '' }).cache
|
||||
|
||||
module.exports.poison = (object, property) => {
|
||||
function fail () {
|
||||
|
@ -15,3 +16,9 @@ module.exports.poison = (object, property) => {
|
|||
}
|
||||
Object.defineProperty(object, property, descriptor)
|
||||
}
|
||||
|
||||
// Only run full test suite when instructed and on a non-prerelease version of node
|
||||
module.exports.FULL_TEST =
|
||||
process.env.FULL_TEST === '1' &&
|
||||
process.release.name === 'node' &&
|
||||
semver.prerelease(process.version) === null
|
||||
|
|
|
@ -1,75 +0,0 @@
|
|||
const Mocha = require('mocha')
|
||||
|
||||
class Reporter {
|
||||
constructor (runner) {
|
||||
this.failedTests = []
|
||||
|
||||
runner.on(Mocha.Runner.constants.EVENT_RUN_BEGIN, () => {
|
||||
console.log('Starting tests')
|
||||
})
|
||||
|
||||
runner.on(Mocha.Runner.constants.EVENT_RUN_END, () => {
|
||||
console.log('Tests finished')
|
||||
console.log()
|
||||
console.log('****************')
|
||||
console.log('* TESTS REPORT *')
|
||||
console.log('****************')
|
||||
console.log()
|
||||
console.log(`Executed ${runner.stats.suites} suites with ${runner.stats.tests} tests in ${runner.stats.duration} ms`)
|
||||
console.log(` Passed: ${runner.stats.passes}`)
|
||||
console.log(` Skipped: ${runner.stats.pending}`)
|
||||
console.log(` Failed: ${runner.stats.failures}`)
|
||||
if (this.failedTests.length > 0) {
|
||||
console.log()
|
||||
console.log(' Failed test details')
|
||||
this.failedTests.forEach((failedTest, index) => {
|
||||
console.log()
|
||||
console.log(` ${index + 1}.'${failedTest.test.fullTitle()}'`)
|
||||
console.log(` Name: ${failedTest.error.name}`)
|
||||
console.log(` Message: ${failedTest.error.message}`)
|
||||
console.log(` Code: ${failedTest.error.code}`)
|
||||
console.log(` Stack: ${failedTest.error.stack}`)
|
||||
})
|
||||
}
|
||||
console.log()
|
||||
})
|
||||
|
||||
runner.on(Mocha.Runner.constants.EVENT_SUITE_BEGIN, (suite) => {
|
||||
if (suite.root) {
|
||||
return
|
||||
}
|
||||
console.log(`Starting suite '${suite.title}'`)
|
||||
})
|
||||
|
||||
runner.on(Mocha.Runner.constants.EVENT_SUITE_END, (suite) => {
|
||||
if (suite.root) {
|
||||
return
|
||||
}
|
||||
console.log(`Suite '${suite.title}' finished`)
|
||||
console.log()
|
||||
})
|
||||
|
||||
runner.on(Mocha.Runner.constants.EVENT_TEST_BEGIN, (test) => {
|
||||
console.log(`Starting test '${test.title}'`)
|
||||
})
|
||||
|
||||
runner.on(Mocha.Runner.constants.EVENT_TEST_PASS, (test) => {
|
||||
console.log(`Test '${test.title}' passed in ${test.duration} ms`)
|
||||
})
|
||||
|
||||
runner.on(Mocha.Runner.constants.EVENT_TEST_PENDING, (test) => {
|
||||
console.log(`Test '${test.title}' skipped in ${test.duration} ms`)
|
||||
})
|
||||
|
||||
runner.on(Mocha.Runner.constants.EVENT_TEST_FAIL, (test, error) => {
|
||||
this.failedTests.push({ test, error })
|
||||
console.log(`Test '${test.title}' failed in ${test.duration} ms with ${error}`)
|
||||
})
|
||||
|
||||
runner.on(Mocha.Runner.constants.EVENT_TEST_END, (test) => {
|
||||
console.log()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Reporter
|
|
@ -4,66 +4,66 @@ const { describe, it } = require('mocha')
|
|||
const assert = require('assert')
|
||||
const path = require('path')
|
||||
const fs = require('graceful-fs')
|
||||
const { execFileSync, execFile } = require('child_process')
|
||||
const os = require('os')
|
||||
const cp = require('child_process')
|
||||
const util = require('../lib/util')
|
||||
|
||||
const addonPath = path.resolve(__dirname, 'node_modules', 'hello_world')
|
||||
const nodeGyp = path.resolve(__dirname, '..', 'bin', 'node-gyp.js')
|
||||
|
||||
function runHello (hostProcess) {
|
||||
if (!hostProcess) {
|
||||
hostProcess = process.execPath
|
||||
}
|
||||
const execFileSync = (...args) => cp.execFileSync(...args).toString().trim()
|
||||
|
||||
const execFile = async (cmd) => {
|
||||
const [err,, stderr] = await util.execFile(process.execPath, cmd, {
|
||||
env: { ...process.env, NODE_GYP_NULL_LOGGER: undefined },
|
||||
encoding: 'utf-8'
|
||||
})
|
||||
return [err, stderr.toString().trim().split(/\r?\n/)]
|
||||
}
|
||||
|
||||
function runHello (hostProcess = process.execPath) {
|
||||
const testCode = "console.log(require('hello_world').hello())"
|
||||
return execFileSync(hostProcess, ['-e', testCode], { cwd: __dirname }).toString()
|
||||
return execFileSync(hostProcess, ['-e', testCode], { cwd: __dirname })
|
||||
}
|
||||
|
||||
function getEncoding () {
|
||||
const code = 'import locale;print(locale.getdefaultlocale()[1])'
|
||||
return execFileSync('python', ['-c', code]).toString().trim()
|
||||
return execFileSync('python', ['-c', code])
|
||||
}
|
||||
|
||||
function checkCharmapValid () {
|
||||
let data
|
||||
try {
|
||||
data = execFileSync('python', ['fixtures/test-charmap.py'],
|
||||
{ cwd: __dirname })
|
||||
} catch (err) {
|
||||
const data = execFileSync('python', ['fixtures/test-charmap.py'], { cwd: __dirname })
|
||||
return data.split('\n').pop() === 'True'
|
||||
} catch {
|
||||
return false
|
||||
}
|
||||
const lines = data.toString().trim().split('\n')
|
||||
return lines.pop() === 'True'
|
||||
}
|
||||
|
||||
describe('addon', function () {
|
||||
this.timeout(300000)
|
||||
|
||||
it('build simple addon', function (done) {
|
||||
it('build simple addon', async function () {
|
||||
// Set the loglevel otherwise the output disappears when run via 'npm test'
|
||||
const cmd = [nodeGyp, 'rebuild', '-C', addonPath, '--loglevel=verbose']
|
||||
const proc = execFile(process.execPath, cmd, function (err, stdout, stderr) {
|
||||
const logLines = stderr.toString().trim().split(/\r?\n/)
|
||||
const [err, logLines] = await execFile(cmd)
|
||||
const lastLine = logLines[logLines.length - 1]
|
||||
assert.strictEqual(err, null)
|
||||
assert.strictEqual(lastLine, 'gyp info ok', 'should end in ok')
|
||||
assert.strictEqual(runHello().trim(), 'world')
|
||||
done()
|
||||
})
|
||||
proc.stdout.setEncoding('utf-8')
|
||||
proc.stderr.setEncoding('utf-8')
|
||||
assert.strictEqual(runHello(), 'world')
|
||||
})
|
||||
|
||||
it('build simple addon in path with non-ascii characters', function (done) {
|
||||
it('build simple addon in path with non-ascii characters', async function () {
|
||||
if (!checkCharmapValid()) {
|
||||
return this.skip('python console app can\'t encode non-ascii character.')
|
||||
}
|
||||
|
||||
const testDirNames = {
|
||||
// Select non-ascii characters by current encoding
|
||||
const testDirName = {
|
||||
cp936: '文件夹',
|
||||
cp1252: 'Latīna',
|
||||
cp932: 'フォルダ'
|
||||
}
|
||||
// Select non-ascii characters by current encoding
|
||||
const testDirName = testDirNames[getEncoding()]
|
||||
}[getEncoding()]
|
||||
// If encoding is UTF-8 or other then no need to test
|
||||
if (!testDirName) {
|
||||
return this.skip('no need to test')
|
||||
|
@ -105,46 +105,30 @@ describe('addon', function () {
|
|||
'--loglevel=verbose',
|
||||
'-nodedir=' + testNodeDir
|
||||
]
|
||||
const proc = execFile(process.execPath, cmd, function (err, stdout, stderr) {
|
||||
const [err, logLines] = await execFile(cmd)
|
||||
try {
|
||||
fs.unlink(testNodeDir)
|
||||
} catch (err) {
|
||||
assert.fail(err)
|
||||
}
|
||||
|
||||
const logLines = stderr.toString().trim().split(/\r?\n/)
|
||||
const lastLine = logLines[logLines.length - 1]
|
||||
assert.strictEqual(err, null)
|
||||
assert.strictEqual(lastLine, 'gyp info ok', 'should end in ok')
|
||||
assert.strictEqual(runHello().trim(), 'world')
|
||||
done()
|
||||
})
|
||||
proc.stdout.setEncoding('utf-8')
|
||||
proc.stderr.setEncoding('utf-8')
|
||||
assert.strictEqual(runHello(), 'world')
|
||||
})
|
||||
|
||||
it('addon works with renamed host executable', function (done) {
|
||||
// No `fs.copyFileSync` before node8.
|
||||
if (process.version.substr(1).split('.')[0] < 8) {
|
||||
return this.skip('skipping test for old node version')
|
||||
}
|
||||
|
||||
it('addon works with renamed host executable', async function () {
|
||||
this.timeout(300000)
|
||||
|
||||
const notNodePath = path.join(os.tmpdir(), 'notnode' + path.extname(process.execPath))
|
||||
fs.copyFileSync(process.execPath, notNodePath)
|
||||
|
||||
const cmd = [nodeGyp, 'rebuild', '-C', addonPath, '--loglevel=verbose']
|
||||
const proc = execFile(process.execPath, cmd, function (err, stdout, stderr) {
|
||||
const logLines = stderr.toString().trim().split(/\r?\n/)
|
||||
const [err, logLines] = await execFile(cmd)
|
||||
const lastLine = logLines[logLines.length - 1]
|
||||
assert.strictEqual(err, null)
|
||||
assert.strictEqual(lastLine, 'gyp info ok', 'should end in ok')
|
||||
assert.strictEqual(runHello(notNodePath).trim(), 'world')
|
||||
assert.strictEqual(runHello(notNodePath), 'world')
|
||||
fs.unlinkSync(notNodePath)
|
||||
done()
|
||||
})
|
||||
proc.stdout.setEncoding('utf-8')
|
||||
proc.stderr.setEncoding('utf-8')
|
||||
})
|
||||
})
|
||||
|
|
|
@ -3,10 +3,10 @@
|
|||
const { describe, it } = require('mocha')
|
||||
const assert = require('assert')
|
||||
const path = require('path')
|
||||
const devDir = require('./common').devDir()
|
||||
const { devDir } = require('./common')
|
||||
const gyp = require('../lib/node-gyp')
|
||||
const log = require('../lib/log')
|
||||
const requireInject = require('require-inject')
|
||||
|
||||
const configure = requireInject('../lib/configure', {
|
||||
'graceful-fs': {
|
||||
openSync: () => 0,
|
||||
|
@ -19,8 +19,6 @@ const configure = requireInject('../lib/configure', {
|
|||
}
|
||||
})
|
||||
|
||||
log.logger.stream = null
|
||||
|
||||
const EXPECTED_PYPATH = path.join(__dirname, '..', 'gyp', 'pylib')
|
||||
const SEPARATOR = process.platform === 'win32' ? ';' : ':'
|
||||
const SPAWN_RESULT = cb => ({ on: function () { cb() } })
|
||||
|
|
|
@ -4,8 +4,7 @@ const path = require('path')
|
|||
const { describe, it } = require('mocha')
|
||||
const assert = require('assert')
|
||||
const gyp = require('../lib/node-gyp')
|
||||
const createConfigGypi = require('../lib/create-config-gypi')
|
||||
const { parseConfigGypi, getCurrentConfigGypi } = createConfigGypi.test
|
||||
const { parseConfigGypi, getCurrentConfigGypi } = require('../lib/create-config-gypi')
|
||||
|
||||
describe('create-config-gypi', function () {
|
||||
it('config.gypi with no options', async function () {
|
||||
|
|
|
@ -7,14 +7,11 @@ const path = require('path')
|
|||
const http = require('http')
|
||||
const https = require('https')
|
||||
const install = require('../lib/install')
|
||||
const semver = require('semver')
|
||||
const devDir = require('./common').devDir()
|
||||
const { download, readCAFile } = require('../lib/download')
|
||||
const { FULL_TEST, devDir } = require('./common')
|
||||
const gyp = require('../lib/node-gyp')
|
||||
const log = require('../lib/log')
|
||||
const certs = require('./fixtures/certs')
|
||||
|
||||
log.logger.stream = null
|
||||
|
||||
describe('download', function () {
|
||||
it('download over http', async function () {
|
||||
const server = http.createServer((req, res) => {
|
||||
|
@ -32,7 +29,7 @@ describe('download', function () {
|
|||
version: '42'
|
||||
}
|
||||
const url = `http://${host}:${port}`
|
||||
const res = await install.test.download(gyp, url)
|
||||
const res = await download(gyp, url)
|
||||
assert.strictEqual(await res.text(), 'ok')
|
||||
})
|
||||
|
||||
|
@ -42,7 +39,7 @@ describe('download', function () {
|
|||
const cert = certs['server.crt']
|
||||
const key = certs['server.key']
|
||||
await fs.writeFile(cafile, cacontents, 'utf8')
|
||||
const ca = await install.test.readCAFile(cafile)
|
||||
const ca = await readCAFile(cafile)
|
||||
|
||||
assert.strictEqual(ca.length, 1)
|
||||
|
||||
|
@ -67,7 +64,7 @@ describe('download', function () {
|
|||
version: '42'
|
||||
}
|
||||
const url = `https://${host}:${port}`
|
||||
const res = await install.test.download(gyp, url)
|
||||
const res = await download(gyp, url)
|
||||
assert.strictEqual(await res.text(), 'ok')
|
||||
})
|
||||
|
||||
|
@ -98,7 +95,7 @@ describe('download', function () {
|
|||
version: '42'
|
||||
}
|
||||
const url = `http://${host}:${port}`
|
||||
const res = await install.test.download(gyp, url)
|
||||
const res = await download(gyp, url)
|
||||
assert.strictEqual(await res.text(), 'proxy ok')
|
||||
})
|
||||
|
||||
|
@ -129,7 +126,7 @@ describe('download', function () {
|
|||
version: '42'
|
||||
}
|
||||
const url = `http://${host}:${port}`
|
||||
const res = await install.test.download(gyp, url)
|
||||
const res = await download(gyp, url)
|
||||
assert.strictEqual(await res.text(), 'ok')
|
||||
})
|
||||
|
||||
|
@ -138,7 +135,7 @@ describe('download', function () {
|
|||
opts: { cafile: 'no.such.file' }
|
||||
}
|
||||
try {
|
||||
await install.test.download(gyp, {}, 'http://bad/')
|
||||
await download(gyp, {}, 'http://bad/')
|
||||
} catch (e) {
|
||||
assert.ok(/no.such.file/.test(e.message))
|
||||
}
|
||||
|
@ -151,7 +148,7 @@ describe('download', function () {
|
|||
after(async () => {
|
||||
await fs.unlink(cafile)
|
||||
})
|
||||
const cas = await install.test.readCAFile(path.join(__dirname, 'fixtures/ca-bundle.crt'))
|
||||
const cas = await readCAFile(path.join(__dirname, 'fixtures/ca-bundle.crt'))
|
||||
assert.strictEqual(cas.length, 2)
|
||||
assert.notStrictEqual(cas[0], cas[1])
|
||||
})
|
||||
|
@ -159,10 +156,7 @@ describe('download', function () {
|
|||
// only run this test if we are running a version of Node with predictable version path behavior
|
||||
|
||||
it('download headers (actual)', async function () {
|
||||
if (process.env.FAST_TEST ||
|
||||
process.release.name !== 'node' ||
|
||||
semver.prerelease(process.version) !== null ||
|
||||
semver.satisfies(process.version, '<10')) {
|
||||
if (!FULL_TEST) {
|
||||
return this.skip('Skipping actual download of headers due to test environment configuration')
|
||||
}
|
||||
|
||||
|
@ -174,7 +168,6 @@ describe('download', function () {
|
|||
const prog = gyp()
|
||||
prog.parseArgv([])
|
||||
prog.devDir = devDir
|
||||
log.level = 'warn'
|
||||
await install(prog, [])
|
||||
|
||||
const data = await fs.readFile(path.join(expectedDir, 'installVersion'), 'utf8')
|
||||
|
|
|
@ -4,7 +4,7 @@ const { describe, it } = require('mocha')
|
|||
const assert = require('assert')
|
||||
const path = require('path')
|
||||
const requireInject = require('require-inject')
|
||||
const configure = requireInject('../lib/configure', {
|
||||
const { findAccessibleSync } = requireInject('../lib/util', {
|
||||
'graceful-fs': {
|
||||
closeSync: function () { return undefined },
|
||||
openSync: function (path) {
|
||||
|
@ -31,43 +31,43 @@ const readableFiles = [
|
|||
describe('find-accessible-sync', function () {
|
||||
it('find accessible - empty array', function () {
|
||||
const candidates = []
|
||||
const found = configure.test.findAccessibleSync('test', dir, candidates)
|
||||
const found = findAccessibleSync('test', dir, candidates)
|
||||
assert.strictEqual(found, undefined)
|
||||
})
|
||||
|
||||
it('find accessible - single item array, readable', function () {
|
||||
const candidates = [readableFile]
|
||||
const found = configure.test.findAccessibleSync('test', dir, candidates)
|
||||
const found = findAccessibleSync('test', dir, candidates)
|
||||
assert.strictEqual(found, path.resolve(dir, readableFile))
|
||||
})
|
||||
|
||||
it('find accessible - single item array, readable in subdir', function () {
|
||||
const candidates = [readableFileInDir]
|
||||
const found = configure.test.findAccessibleSync('test', dir, candidates)
|
||||
const found = findAccessibleSync('test', dir, candidates)
|
||||
assert.strictEqual(found, path.resolve(dir, readableFileInDir))
|
||||
})
|
||||
|
||||
it('find accessible - single item array, unreadable', function () {
|
||||
const candidates = ['unreadable_file']
|
||||
const found = configure.test.findAccessibleSync('test', dir, candidates)
|
||||
const found = findAccessibleSync('test', dir, candidates)
|
||||
assert.strictEqual(found, undefined)
|
||||
})
|
||||
|
||||
it('find accessible - multi item array, no matches', function () {
|
||||
const candidates = ['non_existent_file', 'unreadable_file']
|
||||
const found = configure.test.findAccessibleSync('test', dir, candidates)
|
||||
const found = findAccessibleSync('test', dir, candidates)
|
||||
assert.strictEqual(found, undefined)
|
||||
})
|
||||
|
||||
it('find accessible - multi item array, single match', function () {
|
||||
const candidates = ['non_existent_file', readableFile]
|
||||
const found = configure.test.findAccessibleSync('test', dir, candidates)
|
||||
const found = findAccessibleSync('test', dir, candidates)
|
||||
assert.strictEqual(found, path.resolve(dir, readableFile))
|
||||
})
|
||||
|
||||
it('find accessible - multi item array, return first match', function () {
|
||||
const candidates = ['non_existent_file', anotherReadableFile, readableFile]
|
||||
const found = configure.test.findAccessibleSync('test', dir, candidates)
|
||||
const found = findAccessibleSync('test', dir, candidates)
|
||||
assert.strictEqual(found, path.resolve(dir, anotherReadableFile))
|
||||
})
|
||||
})
|
||||
|
|
|
@ -1,23 +1,22 @@
|
|||
'use strict'
|
||||
|
||||
const { describe, it, after } = require('mocha')
|
||||
const { describe, it, afterEach, beforeEach } = require('mocha')
|
||||
const { rm, mkdtemp } = require('fs/promises')
|
||||
const { createWriteStream } = require('fs')
|
||||
const assert = require('assert')
|
||||
const path = require('path')
|
||||
const os = require('os')
|
||||
const semver = require('semver')
|
||||
const { pipeline: streamPipeline } = require('stream/promises')
|
||||
const requireInject = require('require-inject')
|
||||
const { FULL_TEST } = require('./common')
|
||||
const gyp = require('../lib/node-gyp')
|
||||
|
||||
const createInstall = (mocks = {}) => requireInject('../lib/install', mocks).test
|
||||
const { download, install } = createInstall()
|
||||
const install = require('../lib/install')
|
||||
const { download } = require('../lib/download')
|
||||
|
||||
describe('install', function () {
|
||||
it('EACCES retry once', async () => {
|
||||
let statCalled = 0
|
||||
const mockInstall = createInstall({
|
||||
const mockInstall = requireInject('../lib/install', {
|
||||
'graceful-fs': {
|
||||
promises: {
|
||||
stat (_) {
|
||||
|
@ -35,7 +34,7 @@ describe('install', function () {
|
|||
ensure: true
|
||||
},
|
||||
commands: {
|
||||
install: (...args) => mockInstall.install(Gyp, ...args),
|
||||
install: (...args) => mockInstall(Gyp, ...args),
|
||||
remove: async () => {}
|
||||
}
|
||||
}
|
||||
|
@ -54,24 +53,31 @@ describe('install', function () {
|
|||
}
|
||||
})
|
||||
|
||||
// only run these tests if we are running a version of Node with predictable version path behavior
|
||||
const skipParallelInstallTests = process.env.FAST_TEST ||
|
||||
process.release.name !== 'node' ||
|
||||
semver.prerelease(process.version) !== null ||
|
||||
semver.satisfies(process.version, '<10')
|
||||
describe('parallel', function () {
|
||||
let prog
|
||||
|
||||
async function parallelInstallsTest (test, devDir, prog) {
|
||||
if (skipParallelInstallTests) {
|
||||
return test.skip('Skipping parallel installs test due to test environment configuration')
|
||||
}
|
||||
|
||||
after(async () => {
|
||||
await rm(devDir, { recursive: true, force: true })
|
||||
beforeEach(async () => {
|
||||
prog = gyp()
|
||||
prog.parseArgv([])
|
||||
prog.devDir = await mkdtemp(path.join(os.tmpdir(), 'node-gyp-test-'))
|
||||
})
|
||||
|
||||
const expectedDir = path.join(devDir, process.version.replace(/^v/, ''))
|
||||
await rm(expectedDir, { recursive: true, force: true })
|
||||
afterEach(async () => {
|
||||
await rm(prog.devDir, { recursive: true, force: true })
|
||||
prog = null
|
||||
})
|
||||
|
||||
const runIt = (name, fn) => {
|
||||
// only run these tests if we are running a version of Node with predictable version path behavior
|
||||
if (!FULL_TEST) {
|
||||
return it.skip('Skipping parallel installs test due to test environment configuration')
|
||||
}
|
||||
|
||||
return it(name, async function () {
|
||||
this.timeout(600000)
|
||||
await fn.call(this)
|
||||
const expectedDir = path.join(prog.devDir, process.version.replace(/^v/, ''))
|
||||
await rm(expectedDir, { recursive: true, force: true })
|
||||
await Promise.all([
|
||||
install(prog, []),
|
||||
install(prog, []),
|
||||
|
@ -84,49 +90,21 @@ describe('install', function () {
|
|||
install(prog, []),
|
||||
install(prog, [])
|
||||
])
|
||||
})
|
||||
}
|
||||
|
||||
it('parallel installs (ensure=true)', async function () {
|
||||
this.timeout(600000)
|
||||
|
||||
const devDir = await mkdtemp(path.join(os.tmpdir(), 'node-gyp-test-'))
|
||||
|
||||
const prog = gyp()
|
||||
prog.parseArgv([])
|
||||
prog.devDir = devDir
|
||||
runIt('ensure=true', async function () {
|
||||
prog.opts.ensure = true
|
||||
|
||||
await parallelInstallsTest(this, devDir, prog)
|
||||
})
|
||||
|
||||
it('parallel installs (ensure=false)', async function () {
|
||||
this.timeout(600000)
|
||||
|
||||
const devDir = await mkdtemp(path.join(os.tmpdir(), 'node-gyp-test-'))
|
||||
|
||||
const prog = gyp()
|
||||
prog.parseArgv([])
|
||||
prog.devDir = devDir
|
||||
runIt('ensure=false', async function () {
|
||||
prog.opts.ensure = false
|
||||
|
||||
await parallelInstallsTest(this, devDir, prog)
|
||||
})
|
||||
|
||||
it('parallel installs (tarball)', async function () {
|
||||
this.timeout(600000)
|
||||
|
||||
const devDir = await mkdtemp(path.join(os.tmpdir(), 'node-gyp-test-'))
|
||||
|
||||
const prog = gyp()
|
||||
prog.parseArgv([])
|
||||
prog.devDir = devDir
|
||||
prog.opts.tarball = path.join(devDir, 'node-headers.tar.gz')
|
||||
|
||||
await streamPipeline(
|
||||
(await download(prog, `https://nodejs.org/dist/${process.version}/node-${process.version}.tar.gz`)).body,
|
||||
createWriteStream(prog.opts.tarball)
|
||||
)
|
||||
|
||||
await parallelInstallsTest(this, devDir, prog)
|
||||
runIt('tarball', async function () {
|
||||
prog.opts.tarball = path.join(prog.devDir, 'node-headers.tar.gz')
|
||||
const dl = await download(prog, `https://nodejs.org/dist/${process.version}/node-${process.version}.tar.gz`)
|
||||
await streamPipeline(dl.body, createWriteStream(prog.opts.tarball))
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue