fix a bunch of refactoring issues

This commit is contained in:
Jonathan Lipps
2013-10-21 18:38:22 -07:00
parent 9f129c2172
commit d2a362118a
6 changed files with 117 additions and 101 deletions

View File

@@ -113,6 +113,9 @@ ADB.prototype.checkAdbPresent = function(cb) {
};
ADB.prototype.exec = function(cmd, cb) {
if (!cmd) {
return cb(new Error("You need to pass in a command to exec()"));
}
cmd = this.adbCmd + ' ' + cmd;
logger.debug("executing: " + cmd);
exec(cmd, {maxBuffer: 524288}, function(err, stdout, stderr) {
@@ -432,7 +435,7 @@ ADB.prototype.getEmulatorPort = function(cb) {
cb(new Error("No devices connected"));
} else {
// pick first device
var port = this.getPortFromEmulatorString(devices[0]);
var port = this.getPortFromEmulatorString(devices[0].udid);
if (port) {
cb(null, port);
} else {
@@ -454,6 +457,14 @@ ADB.prototype.push = function(localPath, remotePath, cb) {
this.exec('push ' + localPath + ' ' + remotePath, cb);
};
ADB.prototype.pull = function(remotePath, localPath, cb) {
try {
localPath = JSON.parse(localPath);
} catch(e) { }
localPath = JSON.stringify(localPath);
this.exec('pull ' + remotePath + ' ' + localPath, cb);
};
ADB.prototype.getPortFromEmulatorString = function(emStr) {
var portPattern = /emulator-(\d+)/;
if (portPattern.test(emStr)) {
@@ -637,6 +648,11 @@ ADB.prototype.getLogcatLogs = function() {
};
ADB.prototype.startApp = function(pkg, activity, waitActivity, cb) {
if (typeof waitActivity === "function") {
cb = waitActivity;
waitActivity = false;
}
var cmd = "am start -n " + pkg + "/" + activity;
this.shell(cmd, function(err, stdout) {
if(err) return cb(err);
@@ -655,7 +671,11 @@ ADB.prototype.startApp = function(pkg, activity, waitActivity, cb) {
}
}
this.waitForActivity(pkg, waitActivity, cb);
if (waitActivity) {
this.waitForActivity(pkg, waitActivity, cb);
} else {
cb();
}
}.bind(this));
};
@@ -735,7 +755,7 @@ ADB.prototype.waitForActivity = function(pkg, act, waitMs, cb) {
this.waitForActivityOrNot(pkg, act, false, waitMs, cb);
};
ADB.prototype.waitForActivity = function(pkg, act, waitMs, cb) {
ADB.prototype.waitForNotActivity = function(pkg, act, waitMs, cb) {
this.waitForActivityOrNot(pkg, act, true, waitMs, cb);
};
@@ -798,8 +818,8 @@ ADB.prototype.instrument = function(pkg, activity, instrumentWith, cb) {
});
};
ADB.prototype.checkAndSignApk = function(apk, cb) {
this.checkApkCert(apk, function(err, appSigned) {
ADB.prototype.checkAndSignApk = function(apk, pkg, cb) {
this.checkApkCert(apk, pkg, function(err, appSigned) {
if (err) return cb(err);
if (!appSigned) {
this.sign([apk], cb);
@@ -809,14 +829,6 @@ ADB.prototype.checkAndSignApk = function(apk, cb) {
}.bind(this));
};
ADB.prototype.pushAndInstallApp = function(apk, remoteApk, cb) {
this.push(apk, remoteApk, function(err) {
if (err) return err;
this.installRemote(remoteApk, cb);
});
};
ADB.prototype.forceStop = function(pkg, cb) {
this.shell('am force-stop ' + pkg, cb);
};
@@ -842,8 +854,9 @@ ADB.prototype.isAppInstalled = function(pkg, cb) {
var apkInstalledRgx = new RegExp('^package:' +
pkg.replace(/([^a-zA-Z])/g, "\\$1") + '$', 'm');
installed = apkInstalledRgx.test(stdout);
this.debug("App is " + (!installed ? "not" : "") + " installed");
cb(null, installed);
});
}.bind(this));
};
ADB.prototype.back = function(cb) {
@@ -868,7 +881,7 @@ ADB.prototype.keyevent = function(keycode, cb) {
ADB.prototype.isScreenLocked = function(cb) {
var cmd = "dumpsys window";
this.exec(cmd, function(err, stdout) {
this.shell(cmd, function(err, stdout) {
if (err) return cb(err);
var screenLocked = /mShowingLockscreen=\w+/gi.exec(stdout);

View File

@@ -47,7 +47,7 @@ androidCommon.prepareEmulator = function(cb) {
return cb();
}
this.adb.launchAVD(this.avdName, cb);
});
}.bind(this));
} else {
cb();
}
@@ -64,12 +64,14 @@ androidCommon.prepareActiveDevice = function(cb) {
}
deviceId = this.udid;
} else {
var emPort = this.adb.getPortFromEmulatorString(devices[0].udid);
deviceId = devices[0].udid;
var emPort = this.adb.getPortFromEmulatorString(deviceId);
this.adb.setEmulatorPort(emPort);
}
this.debug("Setting device id to " + deviceId);
logger.info("Setting device id to " + deviceId);
this.adb.setDeviceId(deviceId);
});
cb();
}.bind(this));
};
androidCommon.installApp = function(cb) {
@@ -80,20 +82,27 @@ androidCommon.installApp = function(cb) {
}
this.adb.isAppInstalled(this.appPackage, function(err, installed) {
if (installed && this.fastReset) {
if (installed && this.opts.fastReset) {
this.adb.stopAndClear(this.appPackage, cb);
} else if (!installed) {
this.adb.checkAndSignApk(this.apkPath, this.appPackage, function(err) {
if (err) return cb(err);
this.adb.mkdir(this.remoteTempPath(), function(err) {
if (err) return cb(err);
this.getAppMd5(function(err, md5) {
var remoteApk = this.remoteTempPath() + md5 + '.apk';
this.getAppMd5(function(err, md5Hash) {
var remoteApk = this.remoteTempPath() + md5Hash + '.apk';
if (err) return cb(err);
this.removeTempApks([md5], function(err, appExists) {
this.removeTempApks([md5Hash], function(err, appExists) {
if (err) return cb(err);
if (appExists) return cb();
this.adb.pushAndInstallApp(this.apkPath, remoteApk, cb);
var install = function(err) {
if (err) return cb(err);
this.adb.installRemote(remoteApk, cb);
}.bind(this);
if (appExists) {
install();
} else {
this.adb.push(this.apkPath, remoteApk, install);
}
}.bind(this));
}.bind(this));
}.bind(this));
@@ -107,7 +116,9 @@ androidCommon.installApp = function(cb) {
androidCommon.getAppMd5 = function(cb) {
fs.readFile(this.apkPath, function(err, buffer) {
if (err) return cb(err);
cb(md5(buffer));
var md5Hash = md5(buffer);
logger.info("MD5 for app is " + md5Hash);
cb(null, md5Hash);
}.bind(this));
};
@@ -116,6 +127,7 @@ androidCommon.remoteTempPath = function() {
};
androidCommon.removeTempApks = function(exceptMd5s, cb) {
logger.info("Removing any old apks");
if (typeof exceptMd5s === "function") {
cb = exceptMd5s;
exceptMd5s = [];
@@ -133,31 +145,39 @@ androidCommon.removeTempApks = function(exceptMd5s, cb) {
}.bind(this);
var removeApks = function(apks, cb) {
if (apks.length < 1) {
logger.info("No apks to examine");
return cb();
}
var matchingApkFound = false;
var noMd5Matched = true;
var removes = [];
_.each(apks, function(path) {
path = path.trim();
noMd5Matched = true;
_.each(exceptMd5s, function(md5) {
if (path !== '' && path.indexOf(md5) !== -1) {
noMd5Matched = false;
if (path !== "") {
noMd5Matched = true;
_.each(exceptMd5s, function(md5Hash) {
if (path.indexOf(md5Hash) !== -1) {
noMd5Matched = false;
}
});
if (noMd5Matched) {
removes.push('rm "' + path + '"');
} else {
logger.info("Found an apk we want to keep at " + path);
matchingApkFound = true;
}
});
if (noMd5Matched) {
removes.push('rm \\"' + path + '\\"');
} else {
matchingApkFound = true;
}
});
// Invoking adb shell with an empty string will open a shell console
// so return here if there's nothing to remove.
if (removes.length < 1) {
logger.info("Couldn't find any apks to remove");
return cb(null, matchingApkFound);
}
var cmd = removes.join[" && "];
var cmd = removes.join(" && ");
this.adb.shell(cmd, function() {
cb(null, matchingApkFound);
});

View File

@@ -348,23 +348,16 @@ androidController.setOrientation = function(orientation, cb) {
};
androidController.localScreenshot = function(file, cb) {
this.adb.requireDeviceId();
async.series([
function(cb) {
this.proxy(["takeScreenshot"], cb);
}.bind(this),
function(cb) {
var cmd = this.adb.adbCmd + ' pull /data/local/tmp/screenshot.png "' + file + '"';
exec(cmd, { maxBuffer: 524288 }, function(err, stdout, stderr) {
if (err) {
logger.warn(stderr);
return cb(err);
}
cb(null);
});
this.adb.pull('/data/local/tmp/screenshot.png', file, cb);
}.bind(this),
],
function(){
function(err) {
if (err) return cb(err);
cb(null, {
status: status.codes.Success.code
});
@@ -372,57 +365,37 @@ androidController.localScreenshot = function(file, cb) {
};
androidController.getScreenshot = function(cb) {
this.adb.requireDeviceId();
var localfile = temp.path({prefix: 'appium', suffix: '.png'});
var b64data = "";
async.series([
function(cb) {
var png = "/data/local/tmp/screenshot.png";
var cmd = [this.adb.adbCmd, 'shell', '"/system/bin/rm', png + ';', '/system/bin/screencap -p', png, '"'].join(' ');
logger.debug("getScreenshot: " + cmd);
exec(cmd, { maxBuffer: 524288 }, function(err, stdout, stderr) {
if (err) {
logger.warn(stderr);
return cb(err);
}
cb(null);
});
var cmd = ['"/system/bin/rm', png + ';', '/system/bin/screencap -p',
png, '"'].join(' ');
this.adb.shell(cmd, cb);
}.bind(this),
function(cb) {
if (fs.existsSync(localfile)) fs.unlinkSync(localfile);
var cmd = this.adb.adbCmd + ' pull /data/local/tmp/screenshot.png "' + localfile + '"';
logger.debug("getScreenshot: " + cmd);
exec(cmd, { maxBuffer: 524288 }, function(err, stdout, stderr) {
if (err) {
logger.warn(stderr);
return cb(err);
}
cb(null);
});
this.adb.pull('/data/local/tmp/screenshot.png', localfile, cb);
}.bind(this),
function(cb) {
fs.readFile(localfile, function read(err, data) {
if (err) {
cb(err);
} else {
b64data = new Buffer(data).toString('base64');
cb(null);
}
fs.readFile(localfile, function(err, data) {
if (err) return cb(err);
b64data = new Buffer(data).toString('base64');
cb();
});
},
function(cb) {
fs.unlink(localfile, function(err) {
if (err) {
cb(err);
} else {
cb(null);
}
if (err) return cb(err);
cb();
});
}
],
// Top level cb
function(err, res) {
function(err) {
if (err) return cb(err);
cb(null, {
status: status.codes.Success.code
, value: b64data
@@ -639,8 +612,8 @@ androidController.getCurrentActivity = function(cb) {
androidController.fastReset = function(cb) {
async.series([
function(cb) { this.adb.stopAndClear(this.appPackage, cb); }.bind(this),
this.adb.waitForNotActivity.bind(this),
this.adb.startApp.bind(this)
this.waitForActivityToStop.bind(this),
this.startApp.bind(this)
], cb);
};

View File

@@ -34,8 +34,8 @@ Android.prototype.initialize = function(opts) {
this.udid = opts.udid;
this.appPackage = opts.appPackage;
this.appActivity = opts.appActivity;
this.appWaitActivity = opts.appWaitActivity;
this.avdName = opts.avdName;
this.appWaitActivity = opts.appWaitActivity || opts.appActivity;
this.avdName = opts.avdName || null;
this.appDeviceReadyTimeout = opts.appDeviceReadyTimeout;
this.verbose = opts.verbose;
this.queue = [];
@@ -73,6 +73,7 @@ Android.prototype.start = function(cb, onDie) {
if (typeof launchCb === "undefined" || launchCb === null) {
launchCb = cb;
}
// These messages are from adb.js. Must update when adb.js changes.
var relaunchOn = [
'Could not find a connected Android device'
, 'Device did not become ready'
@@ -86,7 +87,6 @@ Android.prototype.start = function(cb, onDie) {
};
if (err) {
// This message is from adb.js. Must update when adb.js changes.
if (err.message === null ||
typeof err.message === 'undefined' ||
checkShouldRelaunch(err.message.toString())) {
@@ -115,25 +115,27 @@ Android.prototype.start = function(cb, onDie) {
var onExit = function(code) {
if (!didLaunch) {
logger.error("ADB quit before it successfully launched");
cb("ADB quit unexpectedly before successfully launching");
var msg = "UiAutomator quit before it successfully launched";
logger.error(msg);
cb(new Error(msg));
code = code || 1;
} else if (typeof this.cbForCurrentCmd === "function") {
var error = new UnknownError("ADB died while responding to command, " +
"please check appium logs!");
var error = new UnknownError("UiAutomator died while responding to " +
"command, please check appium logs!");
this.cbForCurrentCmd(error, null);
code = code || 1;
}
if (this.adb) {
this.adb.uninstallApp(function() {
this.uninstallApp(function() {
this.adb = null;
this.uiautomator = null;
this.shuttingDown = false;
this.onStop(code);
this.onStop = null;
}.bind(this));
} else {
logger.info("We're in android's exit callback but adb is gone already");
logger.info("We're in uiautomator's exit callback but adb is gone already");
}
}.bind(this);
@@ -151,7 +153,7 @@ Android.prototype.startAppium = function(onLaunch, onExit) {
logger.info("Starting android appium");
this.uiautomator.onExit = onExit;
logger.debug("Using fast reset? " + this.fastReset);
logger.debug("Using fast reset? " + this.opts.fastReset);
async.series([
this.prepareDevice.bind(this),
@@ -211,7 +213,7 @@ Android.prototype.pushAppium = function(cb) {
cb(new Error("Could not find AppiumBootstrap.jar; please run " +
"'grunt buildAndroidBootstrap'"));
} else {
this.adb.push(binPath, this.remoteTempDir(), cb);
this.adb.push(binPath, this.remoteTempPath(), cb);
}
}.bind(this));
};
@@ -360,6 +362,10 @@ Android.prototype.wakeUp = function(cb) {
this.proxy(["wake", {}], cb);
};
Android.prototype.waitForActivityToStop = function(cb) {
this.adb.waitForNotActivity(this.appPackage, this.appWaitActivity, cb);
};
Android.prototype.waitForCondition = deviceCommon.waitForCondition;
Android.prototype.setCommandTimeout = function(secs, cb) {

View File

@@ -19,9 +19,12 @@ var ADB = require('./adb.js')
var Selendroid = function(opts) {
this.opts = opts;
this.opts.devicePort = 8080;
this.avdName = opts.avdName || null;
this.appWaitActivity = opts.appWaitActivity;
this.serverApk = null;
this.appPackage = opts.appPackage;
this.apkPath = opts.apkPath;
this.appActivity = opts.appActivity;
this.desiredCaps = opts.desiredCaps;
this.onStop = function() {};
this.selendroidSessionId = null;
@@ -66,7 +69,7 @@ Selendroid.prototype.start = function(cb) {
if (!modServerExists) {
logger.info("Rebuilt selendroid server does not exist, inserting " +
"modified manifest");
this.insertSelendroidManifest(this.selendroidServerPath, cb);
this.insertSelendroidManifest(this.apkPath, cb);
} else {
logger.info("Rebuilt selendroid server already exists, no need to " +
"rebuild it with a new manifest");
@@ -86,7 +89,7 @@ Selendroid.prototype.start = function(cb) {
}.bind(this));
}.bind(this);
async.waterfall([
async.series([
this.ensureServerExists.bind(this),
this.prepareDevice.bind(this),
checkModServerExists,
@@ -96,12 +99,14 @@ Selendroid.prototype.start = function(cb) {
conditionalInstallSelendroid,
this.installApp.bind(this),
this.forwardPort.bind(this),
this.pushUnlock(cb).bind(this),
this.unlockScreen(cb).bind(this),
this.pushSelendroid(cb).bind(this),
this.pushUnlock.bind(this),
this.unlockScreen.bind(this),
this.pushSelendroid.bind(this),
this.waitForServer.bind(this),
this.createSession.bind(this)
], cb);
], function(err) {
if (err) return cb(err);
this.createSession(cb);
});
};
Selendroid.prototype.pushSelendroid = function(cb) {
@@ -260,8 +265,8 @@ Selendroid.prototype.insertSelendroidManifest = function(serverPath, cb) {
function(cb) { this.adb.checkSdkBinaryPresent("aapt", cb); }.bind(this),
function(cb) { this.adb.compileManifest(dstManifest, newPackage,
this.appPackage, cb); }.bind(this),
function(cb) { this.insertManifest(dstManifest, serverPath, newServerPath,
cb); }.bind(this)
function(cb) { this.adb.insertManifest(dstManifest, serverPath,
newServerPath, cb); }.bind(this)
], cb);
};

View File

@@ -27,7 +27,6 @@ UiAutomator.prototype.start = function(readyCb, exitCb) {
}
logger.info("Running bootstrap");
this.requireDeviceId();
var args = ["shell", "uiautomator", "runtest", "AppiumBootstrap.jar", "-c",
"io.appium.android.bootstrap.Bootstrap"];
try {