| 1 | 'use strict'
|
|---|
| 2 |
|
|---|
| 3 | const { test } = require('tap')
|
|---|
| 4 | const fs = require('fs')
|
|---|
| 5 | const path = require('path')
|
|---|
| 6 | const util = require('util')
|
|---|
| 7 | const http = require('http')
|
|---|
| 8 | const https = require('https')
|
|---|
| 9 | const install = require('../lib/install')
|
|---|
| 10 | const semver = require('semver')
|
|---|
| 11 | const devDir = require('./common').devDir()
|
|---|
| 12 | const rimraf = require('rimraf')
|
|---|
| 13 | const gyp = require('../lib/node-gyp')
|
|---|
| 14 | const log = require('npmlog')
|
|---|
| 15 |
|
|---|
| 16 | log.level = 'warn'
|
|---|
| 17 |
|
|---|
| 18 | test('download over http', async (t) => {
|
|---|
| 19 | t.plan(2)
|
|---|
| 20 |
|
|---|
| 21 | const server = http.createServer((req, res) => {
|
|---|
| 22 | t.strictEqual(req.headers['user-agent'], `node-gyp v42 (node ${process.version})`)
|
|---|
| 23 | res.end('ok')
|
|---|
| 24 | })
|
|---|
| 25 |
|
|---|
| 26 | t.tearDown(() => new Promise((resolve) => server.close(resolve)))
|
|---|
| 27 |
|
|---|
| 28 | const host = 'localhost'
|
|---|
| 29 | await new Promise((resolve) => server.listen(0, host, resolve))
|
|---|
| 30 | const { port } = server.address()
|
|---|
| 31 | const gyp = {
|
|---|
| 32 | opts: {},
|
|---|
| 33 | version: '42'
|
|---|
| 34 | }
|
|---|
| 35 | const url = `http://${host}:${port}`
|
|---|
| 36 | const res = await install.test.download(gyp, url)
|
|---|
| 37 | t.strictEqual(await res.text(), 'ok')
|
|---|
| 38 | })
|
|---|
| 39 |
|
|---|
| 40 | test('download over https with custom ca', async (t) => {
|
|---|
| 41 | t.plan(3)
|
|---|
| 42 |
|
|---|
| 43 | const cafile = path.join(__dirname, '/fixtures/ca.crt')
|
|---|
| 44 | const [cert, key, ca] = await Promise.all([
|
|---|
| 45 | fs.promises.readFile(path.join(__dirname, 'fixtures/server.crt'), 'utf8'),
|
|---|
| 46 | fs.promises.readFile(path.join(__dirname, 'fixtures/server.key'), 'utf8'),
|
|---|
| 47 | install.test.readCAFile(cafile)
|
|---|
| 48 | ])
|
|---|
| 49 |
|
|---|
| 50 | t.strictEqual(ca.length, 1)
|
|---|
| 51 |
|
|---|
| 52 | const options = { ca: ca, cert: cert, key: key }
|
|---|
| 53 | const server = https.createServer(options, (req, res) => {
|
|---|
| 54 | t.strictEqual(req.headers['user-agent'], `node-gyp v42 (node ${process.version})`)
|
|---|
| 55 | res.end('ok')
|
|---|
| 56 | })
|
|---|
| 57 |
|
|---|
| 58 | t.tearDown(() => new Promise((resolve) => server.close(resolve)))
|
|---|
| 59 |
|
|---|
| 60 | server.on('clientError', (err) => { throw err })
|
|---|
| 61 |
|
|---|
| 62 | const host = 'localhost'
|
|---|
| 63 | await new Promise((resolve) => server.listen(0, host, resolve))
|
|---|
| 64 | const { port } = server.address()
|
|---|
| 65 | const gyp = {
|
|---|
| 66 | opts: { cafile },
|
|---|
| 67 | version: '42'
|
|---|
| 68 | }
|
|---|
| 69 | const url = `https://${host}:${port}`
|
|---|
| 70 | const res = await install.test.download(gyp, url)
|
|---|
| 71 | t.strictEqual(await res.text(), 'ok')
|
|---|
| 72 | })
|
|---|
| 73 |
|
|---|
| 74 | test('download over http with proxy', async (t) => {
|
|---|
| 75 | t.plan(2)
|
|---|
| 76 |
|
|---|
| 77 | const server = http.createServer((_, res) => {
|
|---|
| 78 | res.end('ok')
|
|---|
| 79 | })
|
|---|
| 80 |
|
|---|
| 81 | const pserver = http.createServer((req, res) => {
|
|---|
| 82 | t.strictEqual(req.headers['user-agent'], `node-gyp v42 (node ${process.version})`)
|
|---|
| 83 | res.end('proxy ok')
|
|---|
| 84 | })
|
|---|
| 85 |
|
|---|
| 86 | t.tearDown(() => Promise.all([
|
|---|
| 87 | new Promise((resolve) => server.close(resolve)),
|
|---|
| 88 | new Promise((resolve) => pserver.close(resolve))
|
|---|
| 89 | ]))
|
|---|
| 90 |
|
|---|
| 91 | const host = 'localhost'
|
|---|
| 92 | await new Promise((resolve) => server.listen(0, host, resolve))
|
|---|
| 93 | const { port } = server.address()
|
|---|
| 94 | await new Promise((resolve) => pserver.listen(port + 1, host, resolve))
|
|---|
| 95 | const gyp = {
|
|---|
| 96 | opts: {
|
|---|
| 97 | proxy: `http://${host}:${port + 1}`,
|
|---|
| 98 | noproxy: 'bad'
|
|---|
| 99 | },
|
|---|
| 100 | version: '42'
|
|---|
| 101 | }
|
|---|
| 102 | const url = `http://${host}:${port}`
|
|---|
| 103 | const res = await install.test.download(gyp, url)
|
|---|
| 104 | t.strictEqual(await res.text(), 'proxy ok')
|
|---|
| 105 | })
|
|---|
| 106 |
|
|---|
| 107 | test('download over http with noproxy', async (t) => {
|
|---|
| 108 | t.plan(2)
|
|---|
| 109 |
|
|---|
| 110 | const server = http.createServer((req, res) => {
|
|---|
| 111 | t.strictEqual(req.headers['user-agent'], `node-gyp v42 (node ${process.version})`)
|
|---|
| 112 | res.end('ok')
|
|---|
| 113 | })
|
|---|
| 114 |
|
|---|
| 115 | const pserver = http.createServer((_, res) => {
|
|---|
| 116 | res.end('proxy ok')
|
|---|
| 117 | })
|
|---|
| 118 |
|
|---|
| 119 | t.tearDown(() => Promise.all([
|
|---|
| 120 | new Promise((resolve) => server.close(resolve)),
|
|---|
| 121 | new Promise((resolve) => pserver.close(resolve))
|
|---|
| 122 | ]))
|
|---|
| 123 |
|
|---|
| 124 | const host = 'localhost'
|
|---|
| 125 | await new Promise((resolve) => server.listen(0, host, resolve))
|
|---|
| 126 | const { port } = server.address()
|
|---|
| 127 | await new Promise((resolve) => pserver.listen(port + 1, host, resolve))
|
|---|
| 128 | const gyp = {
|
|---|
| 129 | opts: {
|
|---|
| 130 | proxy: `http://${host}:${port + 1}`,
|
|---|
| 131 | noproxy: host
|
|---|
| 132 | },
|
|---|
| 133 | version: '42'
|
|---|
| 134 | }
|
|---|
| 135 | const url = `http://${host}:${port}`
|
|---|
| 136 | const res = await install.test.download(gyp, url)
|
|---|
| 137 | t.strictEqual(await res.text(), 'ok')
|
|---|
| 138 | })
|
|---|
| 139 |
|
|---|
| 140 | test('download with missing cafile', async (t) => {
|
|---|
| 141 | t.plan(1)
|
|---|
| 142 | const gyp = {
|
|---|
| 143 | opts: { cafile: 'no.such.file' }
|
|---|
| 144 | }
|
|---|
| 145 | try {
|
|---|
| 146 | await install.test.download(gyp, {}, 'http://bad/')
|
|---|
| 147 | } catch (e) {
|
|---|
| 148 | t.ok(/no.such.file/.test(e.message))
|
|---|
| 149 | }
|
|---|
| 150 | })
|
|---|
| 151 |
|
|---|
| 152 | test('check certificate splitting', async (t) => {
|
|---|
| 153 | const cas = await install.test.readCAFile(path.join(__dirname, 'fixtures/ca-bundle.crt'))
|
|---|
| 154 | t.plan(2)
|
|---|
| 155 | t.strictEqual(cas.length, 2)
|
|---|
| 156 | t.notStrictEqual(cas[0], cas[1])
|
|---|
| 157 | })
|
|---|
| 158 |
|
|---|
| 159 | // only run this test if we are running a version of Node with predictable version path behavior
|
|---|
| 160 |
|
|---|
| 161 | test('download headers (actual)', async (t) => {
|
|---|
| 162 | if (process.env.FAST_TEST ||
|
|---|
| 163 | process.release.name !== 'node' ||
|
|---|
| 164 | semver.prerelease(process.version) !== null ||
|
|---|
| 165 | semver.satisfies(process.version, '<10')) {
|
|---|
| 166 | return t.skip('Skipping actual download of headers due to test environment configuration')
|
|---|
| 167 | }
|
|---|
| 168 |
|
|---|
| 169 | t.plan(12)
|
|---|
| 170 |
|
|---|
| 171 | const expectedDir = path.join(devDir, process.version.replace(/^v/, ''))
|
|---|
| 172 | await util.promisify(rimraf)(expectedDir)
|
|---|
| 173 |
|
|---|
| 174 | const prog = gyp()
|
|---|
| 175 | prog.parseArgv([])
|
|---|
| 176 | prog.devDir = devDir
|
|---|
| 177 | log.level = 'warn'
|
|---|
| 178 | await util.promisify(install)(prog, [])
|
|---|
| 179 |
|
|---|
| 180 | const data = await fs.promises.readFile(path.join(expectedDir, 'installVersion'), 'utf8')
|
|---|
| 181 | t.strictEqual(data, '9\n', 'correct installVersion')
|
|---|
| 182 |
|
|---|
| 183 | const list = await fs.promises.readdir(path.join(expectedDir, 'include/node'))
|
|---|
| 184 | t.ok(list.includes('common.gypi'))
|
|---|
| 185 | t.ok(list.includes('config.gypi'))
|
|---|
| 186 | t.ok(list.includes('node.h'))
|
|---|
| 187 | t.ok(list.includes('node_version.h'))
|
|---|
| 188 | t.ok(list.includes('openssl'))
|
|---|
| 189 | t.ok(list.includes('uv'))
|
|---|
| 190 | t.ok(list.includes('uv.h'))
|
|---|
| 191 | t.ok(list.includes('v8-platform.h'))
|
|---|
| 192 | t.ok(list.includes('v8.h'))
|
|---|
| 193 | t.ok(list.includes('zlib.h'))
|
|---|
| 194 |
|
|---|
| 195 | const lines = (await fs.promises.readFile(path.join(expectedDir, 'include/node/node_version.h'), 'utf8')).split('\n')
|
|---|
| 196 |
|
|---|
| 197 | // extract the 3 version parts from the defines to build a valid version string and
|
|---|
| 198 | // and check them against our current env version
|
|---|
| 199 | const version = ['major', 'minor', 'patch'].reduce((version, type) => {
|
|---|
| 200 | const re = new RegExp(`^#define\\sNODE_${type.toUpperCase()}_VERSION`)
|
|---|
| 201 | const line = lines.find((l) => re.test(l))
|
|---|
| 202 | const i = line ? parseInt(line.replace(/^[^0-9]+([0-9]+).*$/, '$1'), 10) : 'ERROR'
|
|---|
| 203 | return `${version}${type !== 'major' ? '.' : 'v'}${i}`
|
|---|
| 204 | }, '')
|
|---|
| 205 |
|
|---|
| 206 | t.strictEqual(version, process.version)
|
|---|
| 207 | })
|
|---|