Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: do not terminate random sessions #139

Merged
merged 1 commit into from
Jun 11, 2019
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
133 changes: 90 additions & 43 deletions src/lib/saucelabs-manager.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
var request = require('request'),
log = require('./log');
log = require('./log'),
_ = require('underscore');

/**
* SessionManager Constructor
Expand All @@ -21,6 +22,8 @@ function SauceLabsSessionManager(options) {
this.retryDelay = 3000;
this.retry = 0;

this.build = null;

log.debug('[chimp][saucelabs-session-manager] created a new SessionManager', options);

}
Expand All @@ -39,17 +42,25 @@ SauceLabsSessionManager.prototype.remote = function (webdriverOptions, callback)
log.debug('[chimp][saucelabs-session-manager] creating webdriver remote ');
var browser = this.webdriver.remote(webdriverOptions);

this.build = webdriverOptions.desiredCapabilities.build;
log.debug('[chimp][saucelabs-session-manager] build: ' + this.build);

callback(null, browser);
return;
};

var DEFAULT_LIMIT = 100;

/**
* Gets a list of sessions from the SauceLabs API based on Build ID
*
* @api private
*/
SauceLabsSessionManager.prototype._getJobs = function (callback) {
var hub = this.options.sauceLabsUrl + '/jobs?full=:get_full_info&limit=10'; //default is 100 which seems like too much
SauceLabsSessionManager.prototype._getJobs = function (callback, limit, skip) {
var hub = this.options.sauceLabsUrl + '/jobs?full=true&limit=' + limit;
if (skip > 0) {
hub += '&skip=' + skip;
}

log.debug('[chimp][saucelabs-session-manager]', 'requesting sessions from', hub);

Expand All @@ -65,53 +76,89 @@ SauceLabsSessionManager.prototype._getJobs = function (callback) {
};

/**
* Kills the 1st session found running on SauceLabs
*
* @api public
*/
SauceLabsSessionManager.prototype.killCurrentSession = function (callback) {

this._getJobs(function (err, jobs) {
if (jobs && jobs.length) {
var job = jobs[0];

// This will stop the session, causing a 'User terminated' error.
// If we don't manually stop the session, we get a timed-out error.
var options = {
url: this.options.sauceLabsUrl + '/jobs/' + job.id + '/stop',
method: 'PUT'
};

request(options, function (error, response) {
if (!error && response.statusCode === 200) {
log.debug('[chimp][saucelabs-session-manager]', 'stopped session');
callback();
} else {
log.error('[chimp][saucelabs-session-manager]', 'received error', error);
callback(error);
var self = this;
var killSession = function (job) {
// This will stop the session, causing a 'User terminated' error.
// If we don't manually stop the session, we get a timed-out error.
var options = {
url: this.options.sauceLabsUrl + '/jobs/' + job.id + '/stop',
method: 'PUT'
};

request(options, function (error, response) {
if (!error && response.statusCode === 200) {
log.debug('[chimp][saucelabs-session-manager]', 'stopped session');
callback();
} else {
log.error('[chimp][saucelabs-session-manager]', 'received error', error);
callback(error);
}
});

// This will set the session to passing or else it will show as Errored out
// even though we stop it.
options = {
url: this.options.sauceLabsUrl + '/jobs/' + job.id,
method: 'PUT',
json: true,
body: { passed: true }
};

request(options, function (error, response) {
if (!error && response.statusCode === 200) {
log.debug('[chimp][saucelabs-session-manager]', 'updated session to passing state');
callback();
} else {
log.error('[chimp][saucelabs-session-manager]', 'received error', error);
callback(error);
}
});
}.bind(this)

var getJobForBuild = function(cb, skip) {
if (!self.build) {
// get one and kill it, this is the (flawed) default of chimp which will just randomly
// terminate sessions and you get an odd `Error: The test with session id XXX has already finished, and can't receive further commands.` error
console.warn('You should really consider setting a build, otherwise random sessions will be terminated!');
this._getJobs(function(err, jobs) {
if (jobs.length) {
killSession(jobs[0]);
}
}, 1);
return;
}
this._getJobs(function(err, jobs) {
// the original code never uses this error,
// probably because if we don't find anything we just leave the session alone
// we might want to revisit this behavior
// if (err) {
// cb(err);
// }
if (!jobs.length) {
// no more jobs found, let's exit
console.warn(`Couldn't find a job to terminate for build ${self.build}`);
callback();
return;
}
var currentJob = _.find(jobs, function (b) {
return b.build === self.build;
});
if (!currentJob) {
// maybe it's in the next batch?
getJobForBuild(cb, skip + DEFAULT_LIMIT)
} else {
killSession(currentJob);
}
}, DEFAULT_LIMIT, skip);
}.bind(this)

// This will set the session to passing or else it will show as Errored out
// even though we stop it.
options = {
url: this.options.sauceLabsUrl + '/jobs/' + job.id,
method: 'PUT',
json: true,
body: { passed: true }
};

request(options, function (error, response) {
if (!error && response.statusCode === 200) {
log.debug('[chimp][saucelabs-session-manager]', 'updated session to passing state');
callback();
} else {
log.error('[chimp][saucelabs-session-manager]', 'received error', error);
callback(error);
}
});
}
}.bind(this));


getJobForBuild(killSession, 0);
};

module.exports = SauceLabsSessionManager;