Skip to content

Commit 4205353

Browse files
committed
Readme and follow logfile and binaryPath
1 parent cfb2d97 commit 4205353

File tree

7 files changed

+183
-75
lines changed

7 files changed

+183
-75
lines changed

README.md

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
# browserstack-local-nodejs
2+
3+
## Setup
4+
5+
```
6+
npm install browserstack
7+
```
8+
9+
## API
10+
11+
### Constructor
12+
13+
* `new BrowserStack::Local`: creates an instance of Local
14+
15+
### Methods
16+
17+
* `start(options, callback)`: starts Local instance with options. The options available are detailed below.
18+
* `stop(callback)`: stops the Local instance
19+
* `isRunning()`: checks if Local instance is running and returns a corresponding boolean value
20+
21+
The first and only argument to any callback function will be an error object.
22+
23+
### Options
24+
25+
* `key`: BrowserStack Access Key
26+
* `v`: Provides verbose logging
27+
* `f`: If you want to test local folder rather internal server, provide path to folder as value of this option
28+
* `force`: Kill other running Browserstack Local
29+
* `only`: Restricts Local Testing access to specified local servers and/or folders
30+
* `forcelocal`: Route all traffic via local machine
31+
* `onlyAutomate`: Disable Live Testing and Screenshots, just test Automate
32+
* `proxyHost`: Hostname/IP of proxy, remaining proxy options are ignored if this option is absent
33+
* `proxyPort`: Port for the proxy, defaults to 3128 when -proxyHost is used
34+
* `proxyUser`: Username for connecting to proxy (Basic Auth Only)
35+
* `proxyPass`: Password for USERNAME, will be ignored if USERNAME is empty or not specified
36+
* `localIdentifier`: If doing simultaneous multiple local testing connections, set this uniquely for different processes
37+
* `hosts`: List of hosts and ports where Local must be enabled for eg. localhost,3000,1,localhost,3001,0
38+
* `logfile`: Path to file where Local logs be saved to
39+
* `binaryPath`: Optional path to Local binary
40+
41+
42+
## Tests
43+
44+
To run the test suite run - `npm test`.
45+
46+
## Example
47+
48+
To run the example run - `node node-example.js`.

lib/ZipBinary.js

Lines changed: 34 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
var https = require('https'),
22
unzip = require('unzip'),
3-
fs = require('fs');
3+
fs = require('fs'),
4+
path = require('path');
45

56
function ZipBinary(helper) {
67
var log = helper.log;
@@ -13,34 +14,44 @@ function ZipBinary(helper) {
1314
platform = 'win32';
1415
arch = null;
1516
}
17+
const binaryName = 'BrowserStackLocal' + (platform === 'win32' ? '.exe' : '');
1618

1719
this.args = [];
1820

19-
var ensurePath = function () {
21+
var ensurePath = function (shouldFail) {
22+
var checkPath = '';
2023
try {
21-
fs.accessSync(helper.getBasePath(), fs.R_OK | fs.W_OK);
24+
checkPath = path.join(helper.getBinaryPath(), '..');
25+
fs.accessSync(checkPath, fs.R_OK | fs.W_OK);
2226
} catch(error) {
23-
log.warn('Cannot read/write to ' + helper.getBasePath());
27+
log.warn('Cannot read/write to ' + checkPath);
2428
helper.fallbackBase();
2529
return ensurePath();
2630
}
2731

2832
try {
29-
fs.accessSync(helper.getBinaryPath(), fs.F_OK);
33+
checkPath = helper.getBinaryPath();
34+
fs.accessSync(checkPath, fs.F_OK);
3035
} catch(error) {
31-
log.warn('Binary file is not present at ' + helper.getBinaryPath());
32-
return true;
36+
if (shouldFail) {
37+
log.warn('Download failed to ' + checkPath);
38+
helper.fallbackBase();
39+
return ensurePath();
40+
} else {
41+
log.warn('Binary file is not present at ' + checkPath);
42+
return true;
43+
}
3344
}
3445

3546
try {
36-
fs.accessSync(helper.getBinaryPath(), fs.R_OK | fs.W_OK | fs.X_OK);
47+
fs.accessSync(checkPath, fs.R_OK | fs.W_OK | fs.X_OK);
3748
} catch(error) {
3849
try {
39-
log.warn('Adding execute permissions to ' + helper.getBinaryPath());
40-
fs.chmodSync(helper.getBinaryPath(), '0755');
41-
fs.accessSync(helper.getBinaryPath(), fs.X_OK);
50+
log.warn('Adding execute permissions to ' + checkPath);
51+
fs.chmodSync(checkPath, '0755');
52+
fs.accessSync(checkPath, fs.X_OK);
4253
} catch(error) {
43-
log.warn('Cannot add execute permissions to ' + helper.getBasePath());
54+
log.warn('Cannot add execute permissions to ' + checkPath);
4455
helper.fallbackBase();
4556
return ensurePath();
4657
}
@@ -49,16 +60,23 @@ function ZipBinary(helper) {
4960
return false;
5061
};
5162

52-
this.update = function (callback) {
53-
if(ensurePath()) {
63+
this.update = function (callback, shouldFail) {
64+
var self = this;
65+
var binaryPath = helper.getBinaryPath();
66+
var binaryDir = path.join(binaryPath, '..');
67+
if(ensurePath(shouldFail)) {
5468
var extractStream = unzip.Extract({
55-
path: helper.getBasePath()
69+
path: binaryDir
5670
});
5771
https.get('https://www.browserstack.com/browserstack-local/BrowserStackLocal-' + platform + (arch ? '-' + arch : '') + '.zip', function (response) {
5872
log.info('Downloading binary for ' + platform + (arch ? '-' + arch : '') + ' ...');
5973
extractStream.on('close', function () {
6074
log.info('Download complete');
61-
fs.chmod(helper.getBinaryPath(), '0755', callback);
75+
fs.rename(path.join(binaryDir, binaryName), binaryPath, function() {
76+
fs.chmod(binaryPath, '0755', function() {
77+
self.update.apply(self, [ callback, true ]);
78+
});
79+
});
6280
});
6381
response.pipe(extractStream);
6482
});

lib/browserStackTunnel.js

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
var childProcess = require('child_process'),
2+
fs = require('fs'),
23
ZipBinary = require('./ZipBinary'),
34
Helper = require('./helper'),
45
Tail = require('tail').Tail;
@@ -7,8 +8,11 @@ function BrowserStackTunnel(options) {
78
var helper = new Helper.helper();
89
var log = helper.log;
910

10-
if (options.path) {
11-
helper.setBasePath(options.path);
11+
if (options.binaryPath) {
12+
helper.setBinaryPath(options.binaryPath);
13+
}
14+
if (options.logfile) {
15+
helper.setLogFilePath(options.logfile);
1216
}
1317

1418
var params = [],
@@ -47,6 +51,10 @@ function BrowserStackTunnel(options) {
4751
params.push('-vvv');
4852
}
4953

54+
if (options.f) {
55+
options.folder = options.f;
56+
}
57+
5058
if (options.force) {
5159
params.push('-force');
5260
}
@@ -55,6 +63,10 @@ function BrowserStackTunnel(options) {
5563
params.push('-forcelocal');
5664
}
5765

66+
if (options.only) {
67+
params.push('-only');
68+
}
69+
5870
if (options.onlyAutomate) {
5971
params.push('-onlyAutomate');
6072
}
@@ -155,14 +167,29 @@ function BrowserStackTunnel(options) {
155167
var logFilePath = helper.getLogFilePath();
156168
params.push('-logFile', logFilePath);
157169

170+
// Ensure log file is present
171+
fs.open(logFilePath, 'wx', function() {});
172+
158173
log.info('Local Binary is located at ' + binaryPath);
159-
log.info('Local started with args: ' + JSON.stringify(params));
174+
log.info('Log file is located at ' + logFilePath);
160175

161-
this.tail = new Tail(logFilePath);
176+
try {
177+
this.tail = new Tail(logFilePath);
178+
} catch(e) {
179+
throw new Error('Cannot access log file path - ' + logFilePath);
180+
}
162181
this.tail.on('line', this.updateState.bind(this));
163182
this.tail.on('error', this.updateState.bind(this));
164183

165-
this.tunnel = childProcess.spawn(binaryPath, binary.args.concat([options.key]).concat(params));
184+
var binaryArguments = '';
185+
if (options.folder) {
186+
binaryArguments = binary.args.concat(['-f', options.key, options.folder]).concat(params);
187+
} else {
188+
binaryArguments = binary.args.concat([options.key]).concat(params);
189+
}
190+
log.info('Local started with args: ' + JSON.stringify(binaryArguments).replace(options.key, '<access_key>'));
191+
this.tunnel = childProcess.spawn(binaryPath, binaryArguments);
192+
this.tunnel.stdout.on('data', this.updateState.bind(this));
166193
this.tunnel.stderr.on('data', this.updateState.bind(this));
167194
this.tunnel.on('error', this.killTunnel.bind(this));
168195
this.tunnel.on('exit', this.exit.bind(this));
@@ -176,6 +203,9 @@ function BrowserStackTunnel(options) {
176203
try {
177204
self._startTunnel();
178205
} catch(e) {
206+
if (e.message.toLowerCase().match(/cannot access log file path/)) {
207+
throw new Error('Cannot Access log file path. Please check write permissions.');
208+
}
179209
log.warn('The downloaded binary might be corrupt. Retrying download');
180210
binary.update(function () {
181211
self._startTunnel();

lib/helper.js

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -25,17 +25,32 @@ function helper() {
2525
const localBinaryName = 'BrowserStackLocal' + ( this.getPlatform() === 'win32' ? '.exe' : '' );
2626
const logFileName = 'local.log';
2727

28+
if(process.env.NODE_ENV === 'testing') {
29+
log.level = 'silent';
30+
}
31+
this.log = log;
32+
33+
var logFilePath = null;
34+
var binaryPath = null;
35+
2836
this.getBinaryPath = function() {
37+
if (binaryPath) {
38+
return binaryPath;
39+
}
2940
return path.resolve(path.join(basePath, localBinaryName));
3041
};
31-
this.setBasePath = function(path) {
42+
this.setBinaryPath = function(path) {
3243
currentBaseIndex = -1;
33-
basePath = path;
44+
binaryPath = path;
45+
};
46+
this.setLogFilePath = function(path) {
47+
logFilePath = path;
3448
};
3549
this.getBasePath = function() {
3650
return basePath;
3751
};
3852
this.fallbackBase = function() {
53+
binaryPath = null;
3954
currentBaseIndex += 1;
4055
if (basePaths.length <= currentBaseIndex) {
4156
var pathString = (this.getPlatform() === 'win32') ? 'C:\\Users\\Admin\\Desktop' : '/Users/user/home/';
@@ -44,14 +59,11 @@ function helper() {
4459
basePath = basePaths[currentBaseIndex];
4560
log.warn('Falling Back to ' + basePath);
4661
};
47-
48-
if(process.env.NODE_ENV === 'testing') {
49-
log.level = 'silent';
50-
}
51-
this.log = log;
52-
5362
this.getLogFilePath = function() {
54-
return path.resolve(path.join(basePath, logFileName));
63+
if (logFilePath) {
64+
return logFilePath;
65+
}
66+
return path.resolve(path.join(basePaths[1], logFileName));
5567
};
5668
}
5769

node-example.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@ var options = {
1919
// port: 8080,
2020
// sslFlag: 0
2121
//}],
22-
path: 'var',
22+
//f: __dirname,
23+
binaryPath: '/var/BrowserStackLocal',
24+
logfile: '/var/log/local.log',
2325
localIdentifier: identifier,
2426
verbose: true,
2527
//proxyUser: '',

0 commit comments

Comments
 (0)