From 0f4ea5609abf93c9e88be38d7b56f46cdba8d4ef Mon Sep 17 00:00:00 2001 From: Jonathan Lipps Date: Thu, 21 Nov 2013 11:05:52 -0800 Subject: [PATCH] kill uiautomator before running test (fix #1517) --- lib/devices/android/adb.js | 51 ++++++++++++++++++++++++++++++ lib/devices/android/uiautomator.js | 27 +++++++++------- test/functional/apidemos/basic.js | 32 +++++++++++++++++++ 3 files changed, 98 insertions(+), 12 deletions(-) diff --git a/lib/devices/android/adb.js b/lib/devices/android/adb.js index c0e038129..6d76592e9 100644 --- a/lib/devices/android/adb.js +++ b/lib/devices/android/adb.js @@ -125,6 +125,9 @@ ADB.prototype.exec = function(cmd, cb) { }; ADB.prototype.shell = function(cmd, cb) { + if (cmd.indexOf('"') === -1) { + cmd = '"' + cmd + '"'; + } var execCmd = 'shell ' + cmd; this.exec(execCmd, cb); }; @@ -647,6 +650,54 @@ ADB.prototype.getLogcatLogs = function() { return this.logcat.getLogs(); }; +ADB.prototype.getPIDsByName = function(name, cb) { + logger.info("Getting all processes with '" + name + "'"); + this.shell("ps | grep '" + name + "'", function(err, stdout) { + if (err) return cb(err); + stdout = stdout.trim(); + if (!stdout) { + logger.info("No matching processes found"); + return cb(null, []); + } + var procs = stdout.split("\n"); + var pids = []; + _.each(procs, function(proc) { + var match = /[^\t ]+[\t ]+([0-9]+)/.exec(proc); + if (match) { + pids.push(parseInt(match[1], 10)); + } + }); + if (pids.length !== procs.length) { + var msg = "Could not extract PIDs from ps output. PIDS: " + + JSON.stringify(pids) + ", Procs: " + JSON.stringify(procs); + return cb(new Error(msg)); + } + cb(null, pids); + }); +}; + +ADB.prototype.killProcessesByName = function(name, cb) { + logger.info("Attempting to kill all '" + name + "' processes"); + this.getPIDsByName(name, function(err, pids) { + if (err) return cb(err); + var killNext = function(err) { + if (err) return cb(err); + var pid = pids.pop(); + if (typeof pid !== "undefined") { + this.killProcessByPID(pid, killNext); + } else { + cb(); + } + }.bind(this); + killNext(); + }.bind(this)); +}; + +ADB.prototype.killProcessByPID = function(pid, cb) { + logger.info("Attempting to kill process " + pid); + this.shell("kill " + pid, cb); +}; + ADB.prototype.startApp = function(pkg, activity, waitActivity, cb) { if (typeof waitActivity === "function") { cb = waitActivity; diff --git a/lib/devices/android/uiautomator.js b/lib/devices/android/uiautomator.js index 5addeea21..4a75c6687 100644 --- a/lib/devices/android/uiautomator.js +++ b/lib/devices/android/uiautomator.js @@ -24,20 +24,23 @@ var UiAutomator = function(adb, opts) { }; UiAutomator.prototype.start = function(readyCb) { - logger.info("Running bootstrap"); - var args = ["shell", "uiautomator", "runtest", "AppiumBootstrap.jar", "-c", - "io.appium.android.bootstrap.Bootstrap"]; - try { - this.proc = this.adb.spawn(args); - } catch (err) { - return readyCb(new Error("Could not start adb, is it around?")); - } + this.adb.killProcessesByName('uiautomator', function(err) { + if (err) return readyCb(err); + logger.info("Running bootstrap"); + var args = ["shell", "uiautomator", "runtest", "AppiumBootstrap.jar", "-c", + "io.appium.android.bootstrap.Bootstrap"]; + try { + this.proc = this.adb.spawn(args); + } catch (err) { + return readyCb(new Error("Could not start adb, is it around?")); + } - this.onSocketReady = readyCb; + this.onSocketReady = readyCb; - this.proc.stdout.on('data', this.outputStreamHandler.bind(this)); - this.proc.stderr.on('data', this.errorStreamHandler.bind(this)); - this.proc.on('exit', this.exitHandler.bind(this)); + this.proc.stdout.on('data', this.outputStreamHandler.bind(this)); + this.proc.stderr.on('data', this.errorStreamHandler.bind(this)); + this.proc.on('exit', this.exitHandler.bind(this)); + }.bind(this)); }; UiAutomator.prototype.setExitHandler = function(onExit) { diff --git a/test/functional/apidemos/basic.js b/test/functional/apidemos/basic.js index 74730c26d..3ddf9dfef 100644 --- a/test/functional/apidemos/basic.js +++ b/test/functional/apidemos/basic.js @@ -1,6 +1,9 @@ +/* global describe:true, before:true, after:true */ "use strict"; var path = require('path') + , ADB = require("../../../lib/devices/android/adb.js") + , spawn = require('child_process').spawn , appPath = path.resolve(__dirname, "../../../sample-code/apps/ApiDemos/bin/ApiDemos-debug.apk") , badAppPath = path.resolve(__dirname, "../../../sample-code/apps/ApiDemos/bin/ApiDemos-debugz.apk") , appPkg = "com.example.android.apis" @@ -159,3 +162,32 @@ describeNoPkg('no package sent in with caps', function(h) { done(); }); }, null, null, null, {expectConnError: true}); + +describe('pre-existing uiautomator session', function() { + before(function(done) { + var adb = new ADB(); + var binPath = path.resolve(__dirname, "..", "..", "..", "build", + "android_bootstrap", "AppiumBootstrap.jar"); + var uiArgs = ["shell", "uiautomator", "runtest", "AppiumBootstrap.jar", "-c", + "io.appium.android.bootstrap.Bootstrap"]; + adb.push(binPath, "/data/local/tmp/", function(err) { + should.not.exist(err); + spawn("adb", uiArgs); + setTimeout(function() { + adb.getPIDsByName("uiautomator", function(err, pids) { + should.not.exist(err); + pids.length.should.equal(1); + done(); + }); + }, 500); + }); + }); + describeWd('launching new session', function(h) { + it('should kill pre-existing uiautomator process', function(done) { + h.driver.getWindowSize(function(err) { + should.not.exist(err); + done(); + }); + }); + }); +});