344 lines
7.4 KiB
JavaScript
344 lines
7.4 KiB
JavaScript
var crypto = require('crypto');
|
|
var https = require('https');
|
|
var querystring = require('querystring');
|
|
var utils = require('./utils');
|
|
var HttpsProxyAgent = require('https-proxy-agent');
|
|
var url = require('url');
|
|
|
|
|
|
|
|
var extend = utils.extend;
|
|
var replace = utils.replace;
|
|
|
|
var DEFAULTS = {
|
|
username: null,
|
|
password: null,
|
|
proxy: null,
|
|
hostname: 'saucelabs.com',
|
|
base: '/rest/v1/',
|
|
port: '443'
|
|
};
|
|
|
|
function SauceLabs(options) {
|
|
this.options = extend({}, DEFAULTS, options);
|
|
this.options.auth = this.options.username + ':' + this.options.password;
|
|
}
|
|
|
|
module.exports = SauceLabs;
|
|
|
|
// API
|
|
|
|
SauceLabs.prototype.getAccountDetails = function (callback) {
|
|
this.send({
|
|
method: 'GET',
|
|
path: 'users/:username'
|
|
}, callback);
|
|
};
|
|
|
|
SauceLabs.prototype.getAccountLimits = function (callback) {
|
|
this.send({
|
|
method: 'GET',
|
|
path: ':username/limits'
|
|
}, callback);
|
|
};
|
|
|
|
SauceLabs.prototype.getUserActivity = function (start, end, callback) {
|
|
if (typeof start === 'function') {
|
|
callback = start;
|
|
start = null;
|
|
end = null;
|
|
} else if (typeof end === 'function') {
|
|
callback = end;
|
|
end = null;
|
|
}
|
|
|
|
var dates = (start != null || end != null) ? {} : null;
|
|
if (start != null) {
|
|
dates.start = formatDate(start);
|
|
}
|
|
if (end != null) {
|
|
dates.end = formatDate(end);
|
|
}
|
|
|
|
this.send({
|
|
method: 'GET',
|
|
path: ':username/activity',
|
|
query: dates
|
|
}, callback);
|
|
};
|
|
|
|
SauceLabs.prototype.getUserConcurrency = function (callback) {
|
|
this.send({
|
|
method: 'GET',
|
|
path: 'users/:username/concurrency'
|
|
}, callback);
|
|
};
|
|
|
|
SauceLabs.prototype.getAccountUsage = function (callback) {
|
|
this.send({
|
|
method: 'GET',
|
|
path: 'users/:username/usage'
|
|
}, callback);
|
|
};
|
|
|
|
SauceLabs.prototype.getJobs = function (callback) {
|
|
this.send({
|
|
method: 'GET',
|
|
path: ':username/jobs',
|
|
query: { full: true }
|
|
}, callback);
|
|
};
|
|
|
|
SauceLabs.prototype.showJob = function (id, callback) {
|
|
this.send({
|
|
method: 'GET',
|
|
path: ':username/jobs/:id',
|
|
args: { id: id }
|
|
}, callback);
|
|
};
|
|
|
|
SauceLabs.prototype.showJobAssets = function (id, callback) {
|
|
this.send({
|
|
method: 'GET',
|
|
path: ':username/jobs/:id/assets',
|
|
args: { id: id }
|
|
}, callback);
|
|
};
|
|
|
|
SauceLabs.prototype.updateJob = function (id, data, callback) {
|
|
this.send({
|
|
method: 'PUT',
|
|
path: ':username/jobs/:id',
|
|
args: { id: id },
|
|
data: data
|
|
}, callback);
|
|
};
|
|
|
|
SauceLabs.prototype.stopJob = function (id, data, callback) {
|
|
this.send({
|
|
method: 'PUT',
|
|
path: ':username/jobs/:id/stop',
|
|
args: { id: id },
|
|
data: data
|
|
}, callback);
|
|
};
|
|
|
|
SauceLabs.prototype.deleteJob = function (id, callback) {
|
|
this.send({
|
|
method: 'DELETE',
|
|
path: ':username/jobs/:id',
|
|
args: { id: id }
|
|
}, callback);
|
|
};
|
|
|
|
SauceLabs.prototype.getActiveTunnels = function (callback) {
|
|
this.send({
|
|
method: 'GET',
|
|
path: ':username/tunnels'
|
|
}, callback);
|
|
};
|
|
|
|
SauceLabs.prototype.getTunnel = function (id, callback){
|
|
this.send({
|
|
method: 'GET',
|
|
path: ':username/tunnels/:id',
|
|
args: { id: id }
|
|
}, callback);
|
|
};
|
|
|
|
SauceLabs.prototype.deleteTunnel = function (id, callback){
|
|
this.send({
|
|
method: 'DELETE',
|
|
path: ':username/tunnels/:id',
|
|
args: { id: id }
|
|
}, callback);
|
|
};
|
|
|
|
SauceLabs.prototype.getServiceStatus = function (callback) {
|
|
this.send({
|
|
method: 'GET',
|
|
path: 'info/status'
|
|
}, callback);
|
|
};
|
|
|
|
SauceLabs.prototype.getBrowsers = function (callback) {
|
|
this.send({
|
|
method: 'GET',
|
|
path: 'info/browsers'
|
|
}, callback);
|
|
};
|
|
|
|
SauceLabs.prototype.getAllBrowsers = function (callback) {
|
|
this.send({
|
|
method: 'GET',
|
|
path: 'info/browsers/all'
|
|
}, callback);
|
|
};
|
|
|
|
SauceLabs.prototype.getSeleniumBrowsers = function (callback) {
|
|
this.send({
|
|
method: 'GET',
|
|
path: 'info/browsers/selenium-rc'
|
|
}, callback);
|
|
};
|
|
|
|
SauceLabs.prototype.getWebDriverBrowsers = function (callback) {
|
|
this.send({
|
|
method: 'GET',
|
|
path: 'info/browsers/webdriver'
|
|
}, callback);
|
|
};
|
|
|
|
SauceLabs.prototype.getTestCounter = function (callback) {
|
|
this.send({
|
|
method: 'GET',
|
|
path: 'info/counter'
|
|
}, callback);
|
|
};
|
|
|
|
SauceLabs.prototype.updateSubAccount = function (data, callback) {
|
|
this.send({
|
|
method: 'POST',
|
|
path: 'users/:username/subscription',
|
|
data: data
|
|
}, callback);
|
|
};
|
|
|
|
SauceLabs.prototype.deleteSubAccount = function (callback) {
|
|
this.send({
|
|
method: 'DELETE',
|
|
path: 'users/:username/subscription'
|
|
}, callback);
|
|
};
|
|
|
|
SauceLabs.prototype.createSubAccount = function (data, callback) {
|
|
this.send({
|
|
method: 'POST',
|
|
path: 'users/:username',
|
|
data: data
|
|
}, callback);
|
|
};
|
|
|
|
SauceLabs.prototype.createPublicLink = function (id, date, useHour, callback) {
|
|
if (typeof date === 'function') {
|
|
callback = date;
|
|
date = null;
|
|
useHour = false;
|
|
} else if (typeof useHour === 'function') {
|
|
callback = useHour;
|
|
useHour = false;
|
|
}
|
|
|
|
if (date != null) {
|
|
date = formatDate(date, useHour);
|
|
}
|
|
|
|
var link = generateLink(this.options.hostname, this.options.auth, date, id);
|
|
callback(null, link);
|
|
};
|
|
|
|
SauceLabs.prototype.send = function (message, callback) {
|
|
var method = message.method,
|
|
path = message.path,
|
|
args = message.args,
|
|
query = message.query,
|
|
data = message.data,
|
|
body = JSON.stringify(data);
|
|
|
|
// Build path with base, placeholders, and query.
|
|
path = this.options.base + replace(path, extend({}, this.options, args));
|
|
if (query != null) {
|
|
path += '?' + querystring.stringify(query);
|
|
}
|
|
|
|
// Make the request.
|
|
var options = extend({}, this.options, {
|
|
method: method,
|
|
path: path,
|
|
|
|
headers: {
|
|
'Accept': 'application/json',
|
|
'Content-Type': 'application/json',
|
|
'Content-Length': body != null ? Buffer.byteLength(body) : 0
|
|
}
|
|
});
|
|
makeRequest(options, body, callback);
|
|
};
|
|
|
|
SauceLabs.prototype.getSubAccountList = function (callback) {
|
|
this.send({
|
|
method: 'GET',
|
|
path: 'users/:username/list-subaccounts'
|
|
}, callback);
|
|
};
|
|
|
|
SauceLabs.prototype.getSubAccounts = function (callback) {
|
|
this.send({
|
|
method: 'GET',
|
|
path: 'users/:username/subaccounts'
|
|
}, callback);
|
|
};
|
|
|
|
// Helpers
|
|
|
|
function formatDate(date, useHour) {
|
|
return date.toISOString().replace(/T(\d+).*/, (useHour ? '-$1' : ''));
|
|
}
|
|
|
|
function generateToken(auth, date, job) {
|
|
var key = auth + (date ? ':' + date : '');
|
|
return crypto
|
|
.createHmac('md5', key)
|
|
.update(job)
|
|
.digest('hex');
|
|
}
|
|
|
|
function generateLink(hostname, auth, date, job) {
|
|
return replace('https://:hostname/jobs/:id?auth=:token', {
|
|
hostname: hostname,
|
|
id: job,
|
|
token: generateToken(auth, date, job)
|
|
});
|
|
}
|
|
|
|
function makeRequest(options, body, callback) {
|
|
if(options.proxy){
|
|
options.agent = new HttpsProxyAgent(url.parse(options.proxy));
|
|
}
|
|
var request = https.request(options, function (response) {
|
|
var result = '';
|
|
if (callback) {
|
|
response
|
|
.on('data', function (chunk) {
|
|
result += chunk;
|
|
})
|
|
.on('end', function () {
|
|
var res;
|
|
|
|
try {
|
|
res = JSON.parse(result);
|
|
} catch (e) {
|
|
callback('Could not parse response: ' + result);
|
|
return;
|
|
}
|
|
|
|
if (response.statusCode === 200) {
|
|
callback(null, res);
|
|
} else {
|
|
callback(res);
|
|
}
|
|
});
|
|
}
|
|
});
|
|
|
|
request
|
|
.on('error', function (err) {
|
|
callback('Could not send request: ' + err.message);
|
|
});
|
|
|
|
if (body != null) {
|
|
request.write(body);
|
|
}
|
|
|
|
request.end();
|
|
}
|