Skip to content

Commit ba5ffbb

Browse files
ricksbrownpsociety
andauthored
Enable use of download mirrors (#28)
* Allow setting chromium revision from .npmrc * Allow the download host URL to be overriden * Update tests to allow multiple installs * Update readme with download host option * Address PR feedback * Refactor tests to use a helper * Document the expected download mirror structure * Allow configuration via .npmrc This builds on the work in #27, providing an alternative to env vars via the .npmrc. I have also bolstered the unit testing significantly and allowed the environment to be mocked out. * Address PR feedback 1. Move tests to test/ directory 2. Remove experimental config._setEnv mocking method and update tests 3. Refactor new config.getEnvVar method 4. Refactor confusing ALT_URL variable in utils test Also: * removed now superfluous "install from mirror" test * Updated target NodeJS versions on CI, the specified ones were ancient I have changed it to LTS and Latest which will never age. Co-authored-by: psociety <[email protected]>
1 parent 605d31b commit ba5ffbb

File tree

8 files changed

+158
-22
lines changed

8 files changed

+158
-22
lines changed

.travis.yml

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,5 @@ os:
44
- linux
55
- osx
66
node_js:
7-
- "7"
8-
- "8"
9-
- "9"
7+
- "lts/*"
108
- "node"

README.MD

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,39 @@ npm config set no-proxy localhost,127.0.0.1,example.org
4141
Additionally proxy settings found in the environment variables `HTTP_PROXY`, `HTTPS_PROXY` and `NO_PROXY` will be used if they are not defined in the `.npmrc` file.
4242

4343
### Install a concrete revision
44-
If you want to specify the revision of Chromium to be installed, just set the environment variable CHROMIUM_REVISION to the number of the revision you want to install, as in:
44+
If you want to specify the revision of Chromium to be installed, just set the environment variable `CHROMIUM_REVISION` to the number of the revision you want to install, as in:
4545
```shell script
4646
export CHROMIUM_REVISION=729994
4747
```
4848

49+
Note - may also be set in .npmrc like so:
50+
51+
```ini
52+
chromium_revision=729994
53+
```
54+
55+
### Use a Download Mirror
56+
You may download a specific revision from an alternate download host using the environment variable `CHROMIUM_DOWNLOAD_HOST`, for example:
57+
58+
```bash
59+
export CHROMIUM_REVISION=737027
60+
export CHROMIUM_DOWNLOAD_HOST=https://npm.taobao.org/mirrors/chromium-browser-snapshots/
61+
62+
# If running on Linux x64 this will download binary from:
63+
# https://npm.taobao.org/mirrors/chromium-browser-snapshots/Linux_x64/737027/chrome-linux.zip?alt=media
64+
```
65+
66+
Notes on `CHROMIUM_DOWNLOAD_HOST`:
67+
68+
* The default download host is `https://www.googleapis.com/download/storage/v1/b/chromium-browser-snapshots/o/`
69+
* Mirrors are expected to host binaries in the structure: `<CHROMIUM_DOWNLOAD_HOST>/<PLATFORM_ARCHITECTURE>/<REVISION>/<OS_CHROMIUM_FILE_NAME>.zip?alt=media` for example see the taobao mirror [chromium-browser-snapshots](https://npm.taobao.org/mirrors/chromium-browser-snapshots/).
70+
* May also be set in .npmrc like so:
71+
72+
```ini
73+
chromium_download_host=https://npm.taobao.org/mirrors/chromium-browser-snapshots/
74+
chromium_revision=737027
75+
```
76+
4977
## Selenium WebDriver Headless (without UI) tests
5078
It's extremely easy to use **node-chromium** with **selenium-webdriver** to perform e2e tests without spawning browser UI.
5179
First, install all dependencies

config.js

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,25 @@
33
const path = require('path');
44

55
module.exports = {
6-
BIN_OUT_PATH: path.join(__dirname, 'lib', 'chromium')
6+
/**
7+
* The default CDN URL, used if not overridden by user
8+
*/
9+
CDN_URL: 'https://www.googleapis.com/download/storage/v1/b/chromium-browser-snapshots/o/',
10+
/**
11+
* The default filesystem path where chromium will be installed.
12+
*/
13+
BIN_OUT_PATH: path.join(__dirname, 'lib', 'chromium'),
14+
/**
15+
* Gets a configuration parameter from the environment.
16+
* Will first check for a lowercase variant set via npm config in the format: `npm_config_${name.toLowerCase()}`.
17+
* If not set then will check the environment for the variable, as provided.
18+
* @param {string} name The name of the environment variable, case sensitive, conventionally uppercase.
19+
* @returns {string} The value of the environment variable.
20+
*/
21+
getEnvVar: name => {
22+
if (!name) {
23+
return '';
24+
}
25+
return process.env[`npm_config_${name.toLowerCase()}`] || process.env[name] || '';
26+
}
727
};

install.js

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,6 @@ const debug = require('debug')('node-chromium');
99
const config = require('./config');
1010
const utils = require('./utils');
1111

12-
const chromiumRevision = process.env.npm_config_chromium_revision || process.env.CHROMIUM_REVISION;
13-
1412
function createTempFile() {
1513
return new Promise((resolve, reject) => {
1614
tmp.file((error, path) => {
@@ -68,8 +66,9 @@ function unzipArchive(archivePath, outputFolder) {
6866
}
6967

7068
async function install() {
69+
const chromiumRevision = config.getEnvVar('CHROMIUM_REVISION');
7170
try {
72-
console.info('Step 1. Retrieving Chromium latest revision number');
71+
console.info('Step 1. Retrieving Chromium revision number');
7372
const revision = chromiumRevision || await utils.getLatestRevisionNumber();
7473

7574
console.info(`Step 2. Downloading Chromium (this might take a while). Revision number: ${revision}`);
@@ -84,4 +83,9 @@ async function install() {
8483
}
8584
}
8685

87-
module.exports = install();
86+
if (require.main === module) {
87+
// Module called directly, not via "require", so execute install...
88+
install();
89+
}
90+
91+
module.exports = install;

test/test-config.js

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
'use strict';
2+
3+
import test from 'ava';
4+
5+
const config = require('../config');
6+
7+
/* eslint camelcase: ["error", {properties: "never"}] */
8+
9+
test.serial('getEnvVar returns string always', t => {
10+
delete process.env.FOO_BAR; // Make sure this doesn't exist
11+
t.is('', config.getEnvVar('FOO_BAR'));
12+
});
13+
14+
test.serial('getEnvVar basic test', t => {
15+
const expected = Date.now().toString();
16+
try {
17+
process.env.FOO_BAR = expected;
18+
t.is(expected, config.getEnvVar('FOO_BAR'));
19+
} finally {
20+
delete process.env.FOO_BAR;
21+
}
22+
});
23+
24+
test.serial('getEnvVar looks for npm_config version', t => {
25+
const expected = Date.now().toString();
26+
try {
27+
process.env.npm_config_foo_bar = expected;
28+
t.is(expected, config.getEnvVar('FOO_BAR'));
29+
} finally {
30+
delete process.env.npm_config_foo_bar;
31+
}
32+
});
33+
34+
test.serial('getEnvVar prefers npm_config version', t => {
35+
const expected = Date.now().toString();
36+
try {
37+
process.env.FOO_BAR = 'foobar';
38+
process.env.npm_config_foo_bar = expected;
39+
t.is(expected, config.getEnvVar('FOO_BAR'), 'npm_config_ variant should trump raw env var');
40+
} finally {
41+
delete process.env.FOO_BAR;
42+
delete process.env.npm_config_foo_bar;
43+
}
44+
});

test-install.js renamed to test/test-install.js

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,9 @@ const rimraf = require('rimraf');
77
const got = require('got');
88
const debug = require('debug')('node-chromium');
99

10-
const utils = require('./utils');
11-
const config = require('./config');
12-
13-
const install = async () => {
14-
await require('./install');
15-
};
10+
const utils = require('../utils');
11+
const config = require('../config');
12+
const install = require('../install');
1613

1714
test.before(t => {
1815
// Deleting output folder
@@ -29,12 +26,12 @@ test.serial('Canary Test', t => {
2926
t.pass();
3027
});
3128

32-
test('Before Install Process', t => {
29+
test.serial('Before Install Process', t => {
3330
const binPath = utils.getOsChromiumBinPath();
3431
t.false(fs.existsSync(binPath), `Chromium binary is found in: [${binPath}]`);
3532
});
3633

37-
test('Chromium Install', async t => {
34+
test.serial('Chromium Install', async t => {
3835
await install();
3936

4037
const binPath = utils.getOsChromiumBinPath();
@@ -48,6 +45,7 @@ test.serial('Different OS support', async t => {
4845

4946
const originalPlatform = process.platform;
5047

48+
/* eslint-disable no-await-in-loop */
5149
for (const platform of supportedPlatforms) {
5250
mockPlatform(platform);
5351

@@ -56,6 +54,7 @@ test.serial('Different OS support', async t => {
5654
const url = utils.getDownloadUrl(revision);
5755
t.true(await isUrlAccessible(url));
5856
}
57+
/* eslint-enable no-await-in-loop */
5958

6059
for (const platform of notSupportedPlatforms) {
6160
mockPlatform(platform);

test/test-utils.js

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
'use strict';
2+
3+
import test from 'ava';
4+
5+
const config = require('../config');
6+
const utils = require('../utils');
7+
8+
const OVERRIDE_URL = 'http://example.com/chromium-browser-snapshots/';
9+
10+
/* eslint camelcase: ["error", {properties: "never"}] */
11+
12+
test.beforeEach(t => {
13+
process.env = {}; // Prevent the real environment from interfering with these tests
14+
t.pass();
15+
});
16+
17+
test.serial('getDownloadUrl uses default', t => {
18+
const url = utils.getDownloadUrl('737027');
19+
t.true(url.indexOf(config.CDN_URL) === 0, `By default the URL should download from ${config.CDN_URL} but got ${url}`);
20+
});
21+
22+
test.serial('getDownloadUrl contains revision', t => {
23+
const revision = '737027';
24+
const url = utils.getDownloadUrl(revision);
25+
t.true(url.indexOf(revision) > 0, `Expected revision ${revision} in ${url}`);
26+
});
27+
28+
test.serial('getDownloadUrl honors environment variable', t => {
29+
process.env.CHROMIUM_DOWNLOAD_HOST = OVERRIDE_URL;
30+
31+
const url = utils.getDownloadUrl('737027');
32+
t.true(url.indexOf(OVERRIDE_URL) === 0, `Download URL should honor environment variable ${OVERRIDE_URL} but got ${url}`);
33+
});
34+
35+
test.serial('getDownloadUrl honors npm config', t => {
36+
process.env.npm_config_chromium_download_host = OVERRIDE_URL;
37+
38+
const url = utils.getDownloadUrl('737027');
39+
t.true(url.indexOf(OVERRIDE_URL) === 0, `Download URL should honor npm config ${OVERRIDE_URL} but got ${url}`);
40+
});

utils.js

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,6 @@ const tunnel = require('tunnel');
77

88
const config = require('./config');
99

10-
const CDN_URL = 'https://www.googleapis.com/download/storage/v1/b/chromium-browser-snapshots/o/';
11-
1210
module.exports = {
1311
/**
1412
* Returns chromium output folder name for current OS
@@ -60,16 +58,21 @@ module.exports = {
6058
* @returns {string}
6159
*/
6260
getDownloadUrl(revision) {
63-
return `${this.getOsCdnUrl()}%2F${revision}%2F${this.getOsChromiumFolderName()}.zip?alt=media`;
61+
const altUrl = config.getEnvVar('CHROMIUM_DOWNLOAD_HOST');
62+
let revisionPath = `/${revision}/${this.getOsChromiumFolderName()}`;
63+
if (!altUrl) {
64+
revisionPath = encodeURIComponent(revisionPath); // Needed for googleapis.com
65+
}
66+
return `${this.getOsCdnUrl()}${revisionPath}.zip?alt=media`;
6467
},
6568

6669
/**
67-
* Returns CDN Url according to current OS
70+
* Returns download Url according to current OS
6871
*
6972
* @returns {string}
7073
*/
7174
getOsCdnUrl() {
72-
let url = CDN_URL;
75+
let url = config.getEnvVar('CHROMIUM_DOWNLOAD_HOST') || config.CDN_URL;
7376

7477
const platform = process.platform;
7578

0 commit comments

Comments
 (0)