Files
appium/app/selendroid.js
T

152 lines
4.6 KiB
JavaScript

"use strict";
var errors = require('./errors')
, adb = require('../android/adb')
, _ = require('underscore')
, deviceCommon = require('./device')
, request = deviceCommon.request
, proxyTo = deviceCommon.proxyTo
, getLog = deviceCommon.getLog
, getLogTypes = deviceCommon.getLogTypes
, logger = require('../logger').get('appium')
, status = require("./uiauto/lib/status")
, fs = require('fs')
, async = require('async')
, path = require('path')
, UnknownError = errors.UnknownError;
var Selendroid = function(opts) {
this.opts = opts;
this.appWaitActivity = opts.appWaitActivity;
this.serverApk = null;
this.appPackage = opts.appPackage;
this.desiredCaps = opts.desiredCaps;
this.onStop = function() {};
this.selendroidSessionId = null;
this.adb = null;
this.isProxy = true;
this.proxyHost = 'localhost';
this.proxyPort = opts.systemPort;
this.avoidProxy = [
['GET', new RegExp('^/wd/hub/session/[^/]+/log/types$')]
, ['POST', new RegExp('^/wd/hub/session/[^/]+/log')]
];
};
Selendroid.prototype.start = function(cb) {
logger.info("Starting selendroid server");
var opts = _.clone(this.opts);
opts.devicePort = 8080; // selendroid listens on 8080 on the device
this.adb = new adb(opts);
async.waterfall([
function(cb) { this.ensureServerExists(cb); }.bind(this),
function(cb) { this.adb.startSelendroid(this.serverApk, cb); }.bind(this),
function(res, cb) { this.waitForServer(cb); }.bind(this),
function(cb) { this.createSession(cb); }.bind(this),
], cb);
};
Selendroid.prototype.stop = function(cb) {
logger.info("Stopping selendroid server");
this.deleteSession(function(err) {
cb(err ? 1 : 0);
});
};
Selendroid.prototype.keyevent = function(body, cb) {
var keycode = body.keycode;
this.adb.keyevent(keycode, function() {
cb(null, {
status: status.codes.Success.code
, value: null
});
});
};
Selendroid.prototype.ensureServerExists = function(cb) {
logger.info("Checking whether selendroid is built yet");
var selBin = path.resolve(__dirname, "..", "build", "selendroid",
"selendroid.apk");
fs.stat(selBin, function(err) {
if (err) {
logger.info("Selendroid needs to be built; please run ./reset.sh " +
"--selendroid");
return cb(err);
}
logger.info("Selendroid server exists!");
this.serverApk = selBin;
cb(null);
}.bind(this));
};
Selendroid.prototype.waitForServer = function(cb) {
var waitMs = 20000
, intMs = 800
, start = Date.now();
var pingServer = function() {
this.proxyTo('/wd/hub/status', 'GET', null, function(err, res, body) {
if (body === null || typeof body === "undefined" || !body.trim()) {
if (Date.now() - start < waitMs) {
setTimeout(pingServer, intMs);
} else {
cb(new Error("Waited " + (waitMs / 1000) + " secs for " +
"selendroid server and it never showed up"));
}
} else {
logger.info("Selendroid server is alive!");
cb(null);
}
});
}.bind(this);
pingServer();
};
Selendroid.prototype.createSession = function(cb) {
logger.info("Creating Selendroid session");
var data = {desiredCapabilities: this.desiredCaps};
this.proxyTo('/wd/hub/session', 'POST', data, function(err, res, body) {
if (err) return cb(err);
if (res.statusCode === 301 && body.sessionId) {
logger.info("Successfully started selendroid session");
this.selendroidSessionId = body.sessionId;
this.adb.waitForActivity(function(err) {
if (err) {
logger.info("Selendroid hasn't started app yet, let's do it " +
"manually with adb.startApp");
return this.adb.startApp(function(err) {
if (err) return cb(err);
return cb(null, body.sessionId);
}.bind(this));
}
return cb(null, body.sessionId);
}.bind(this), 1800);
} else {
logger.error("Selendroid create session did not work. Status was " +
res.statusCode + " and body was " + body);
cb(new Error("Did not get session redirect from selendroid"));
}
}.bind(this));
};
Selendroid.prototype.deleteSession = function(cb) {
var url = '/wd/hub/session/' + this.selendroidSessionId;
this.proxyTo(url, 'DELETE', null, function(err, res) {
if (err) return cb(err);
if (res.statusCode !== 200) return cb(new Error("Status was not 200"));
this.adb.stopApp(cb);
}.bind(this));
};
Selendroid.prototype.proxyTo = proxyTo;
Selendroid.prototype.getLog = getLog;
Selendroid.prototype.getLogTypes = getLogTypes;
module.exports = function(opts) {
return new Selendroid(opts);
};