Skip to content

Commit

Permalink
Merge pull request #23 from browserstack/binary_download
Browse files Browse the repository at this point in the history
Binary download
  • Loading branch information
AnkurGel authored Oct 25, 2016
2 parents 34e9528 + 70a6daa commit 026f928
Show file tree
Hide file tree
Showing 4 changed files with 181 additions and 47 deletions.
19 changes: 17 additions & 2 deletions lib/Local.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
var childProcess = require('child_process'),
fs = require('fs'),
path = require('path'),
running = require('is-running'),
LocalBinary = require('./LocalBinary'),
Expand All @@ -7,16 +8,17 @@ var childProcess = require('child_process'),

function Local(){
this.pid = undefined;
this.retriesLeft = 5;
this.key = process.env.BROWSERSTACK_ACCESS_KEY;
this.logfile = path.join(process.cwd(), 'local.log');
this.opcode = 'start';
this.exitCallback;
this.userArgs = [];

this.errorRegex = /\*\*\* Error: [^\r\n]*/i;
this.doneRegex = /Press Ctrl-C to exit/i;

this.start = function(options, callback){
this.userArgs = [];
var that = this;
this.addArgs(options);

Expand All @@ -29,7 +31,19 @@ function Local(){

that.opcode = 'start';
that.tunnel = childProcess.execFile(that.binaryPath, that.getBinaryArgs(), function(error, stdout, stderr){
if(error) callback(new LocalError(error.toString()));
if(error) {
console.error('Error while trying to execute binary', error);
if(that.retriesLeft > 0) {
console.log('Retrying Binary Download. Retries Left', that.retriesLeft);
that.retriesLeft -= 1;
fs.unlinkSync(that.binaryPath);
delete(that.binaryPath);
that.start(options, callback);
return;
} else {
callback(new LocalError(error.toString()));
}
}

var data = {};
if(stdout)
Expand Down Expand Up @@ -206,6 +220,7 @@ function Local(){
}
this.binary.binaryPath(conf, callback);
} else {
console.log('BINARY PATH IS DEFINED');
callback(this.binaryPath);
}
};
Expand Down
39 changes: 33 additions & 6 deletions lib/LocalBinary.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,29 +22,56 @@ function LocalBinary(){
this.httpPath = 'https://s3.amazonaws.com/browserStack/browserstack-local/BrowserStackLocal-linux-ia32';
}

this.download = function(conf, destParentDir, callback){
this.retryBinaryDownload = function(conf, destParentDir, callback, retries, binaryPath) {
var that = this;
if(retries > 0) {
console.log('Retrying Download. Retries left', retries);
fs.stat(binaryPath, function(err) {
if(err == null) {
fs.unlinkSync(binaryPath);
}
that.download(conf, destParentDir, callback, retries - 1);
});
} else {
console.error('Number of retries to download exceeded.');
}
};

this.download = function(conf, destParentDir, callback, retries){
var that = this;
if(!this.checkPath(destParentDir))
fs.mkdirSync(destParentDir);

var destBinaryName = (this.windows) ? 'BrowserStackLocal.exe' : 'BrowserStackLocal';
var binaryPath = path.join(destParentDir, destBinaryName);
var file = fs.createWriteStream(binaryPath);
var fileStream = fs.createWriteStream(binaryPath);

var options = url.parse(this.httpPath);
if(conf.proxyHost && conf.proxyPort){
if(conf.proxyHost && conf.proxyPort) {
options.agent = new HttpsProxyAgent({
host: conf.proxyHost,
port: conf.proxyPort
});
}

https.get(options, function (response) {
response.on('end', function () {
response.pipe(fileStream);
response.on('error', function(err) {
console.error('Got Error in binary download response', err);
that.retryBinaryDownload(conf, destParentDir, callback, retries, binaryPath);
});
fileStream.on('error', function (err) {
console.error('Got Error while downloading binary file', err);
that.retryBinaryDownload(conf, destParentDir, callback, retries, binaryPath);
});
fileStream.on('close', function () {
fs.chmod(binaryPath, '0755', function() {
callback(binaryPath);
});
});
response.pipe(file);
}).on('error', function(err) {
console.error('Got Error in binary downloading request', err);
that.retryBinaryDownload(conf, destParentDir, callback, retries, binaryPath);
});
};

Expand All @@ -55,7 +82,7 @@ function LocalBinary(){
if(this.checkPath(binaryPath, fs.X_OK)){
callback(binaryPath);
} else {
this.download(conf, destParentDir, callback);
this.download(conf, destParentDir, callback, 5);
}
};

Expand Down
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@
"license": "MIT",
"dependencies": {
"https-proxy-agent": "^1.0.0",
"is-running": "^2.0.0"
"is-running": "^2.0.0",
"sinon": "^1.17.6",
"temp-fs": "^0.9.9"
},
"devDependencies": {
"eslint": "1.10.3",
Expand Down
166 changes: 128 additions & 38 deletions test/local.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
var expect = require('expect.js'),
sinon = require('sinon'),
mocks = require('mocks'),
path = require('path'),
fs = require('fs'),
rimraf = require('rimraf'),
Proxy = require('proxy'),
tempfs = require('temp-fs'),
browserstack = require('../index'),
LocalBinary = require('../lib/LocalBinary');


const MAX_TIMEOUT = 600000;

describe('Local', function () {
var bsLocal;
beforeEach(function () {
Expand Down Expand Up @@ -157,53 +162,138 @@ describe('Local', function () {
});

describe('LocalBinary', function () {
var proxy;
var proxyPort;
var binary;
var tempDownloadPath;

before(function (done) {
// setup HTTP proxy server
proxy = new Proxy();
proxy.listen(function () {
proxyPort = proxy.address().port;
done();
describe('Retries', function() {
var unlinkTmp,
defaultBinaryPath,
validBinaryPath,
sandBox;

before(function(done) {
this.timeout(MAX_TIMEOUT);
// ensure that we have a valid binary downloaded

// removeIfInvalid();
(new LocalBinary()).binaryPath({}, function(binaryPath) {
defaultBinaryPath = binaryPath;
tempfs.mkdir({
recursive: true
}, function(err, dir) {
if(err) { throw err; }

validBinaryPath = path.join(dir.path, path.basename(binaryPath));
fs.rename(defaultBinaryPath, validBinaryPath, function(err) {
if(err) { throw err; }

unlinkTmp = dir.unlink;
done();
});
});
});
});
});

after(function (done) {
proxy.once('close', function () { done(); });
proxy.close();
});
beforeEach(function() {
sandBox = sinon.sandbox.create();
});

beforeEach(function () {
binary = new LocalBinary();
tempDownloadPath = path.join(process.cwd(), 'download');
});
it('Tries to download binary if its corrupted', function(done) {
fs.unlink(defaultBinaryPath, function() {
var localBinary = new LocalBinary();
var downloadStub = sandBox.stub(localBinary, 'download', function() {
downloadStub.callArgWith(2, [ defaultBinaryPath ]);
expect(downloadStub.args[0][3]).to.be(5);
});

afterEach(function () {
rimraf.sync(tempDownloadPath);
});
fs.writeFile(defaultBinaryPath, 'Random String', function() {
fs.chmod(defaultBinaryPath, '0755', function() {
localBinary.binaryPath({
}, function(binaryPath) {
expect(downloadStub.called).to.be.true;
done();
});
});
});
});
});

it('should download binaries without proxy', function (done) {
this.timeout(600000);
var conf = {};
binary.download(conf, tempDownloadPath, function (result) {
expect(fs.existsSync(result)).to.equal(true);
it('Tries to download binary if its not present', function(done) {
fs.unlink(defaultBinaryPath, function() {
var localBinary = new LocalBinary();
var downloadStub = sandBox.stub(localBinary, 'download', function() {
downloadStub.callArgWith(2, [ defaultBinaryPath ]);
expect(downloadStub.args[0][3]).to.be(5);
});

localBinary.binaryPath({
}, function(binaryPath) {
expect(downloadStub.called).to.be.true;
done();
});
});
});

afterEach(function(done) {
sandBox.restore();
done();
});

after(function(done) {
fs.rename(validBinaryPath, defaultBinaryPath, function(err) {
if(err) { throw err; }

unlinkTmp(done);
});
});
});

it('should download binaries with proxy', function (done) {
this.timeout(600000);
var conf = {
proxyHost: '127.0.0.1',
proxyPort: proxyPort
};
binary.download(conf, tempDownloadPath, function (result) {
// test for file existence
expect(fs.existsSync(result)).to.equal(true);
done();
describe('Download', function() {
var proxy;
var proxyPort;
var binary;
var tempDownloadPath;

before(function (done) {
// setup HTTP proxy server
proxy = new Proxy();
proxy.listen(function () {
proxyPort = proxy.address().port;
done();
});
});

after(function (done) {
proxy.once('close', function () { done(); });
proxy.close();
});

beforeEach(function () {
binary = new LocalBinary();
tempDownloadPath = path.join(process.cwd(), 'download');
});

afterEach(function () {
rimraf.sync(tempDownloadPath);
});

it('should download binaries without proxy', function (done) {
this.timeout(MAX_TIMEOUT);
var conf = {};
binary.download(conf, tempDownloadPath, function (result) {
expect(fs.existsSync(result)).to.equal(true);
done();
});
});

it('should download binaries with proxy', function (done) {
this.timeout(MAX_TIMEOUT);
var conf = {
proxyHost: '127.0.0.1',
proxyPort: proxyPort
};
binary.download(conf, tempDownloadPath, function (result) {
// test for file existence
expect(fs.existsSync(result)).to.equal(true);
done();
});
});
});
});

0 comments on commit 026f928

Please sign in to comment.