From 4c5583d45063e5da88dbf0ac287133edc8a43a4b Mon Sep 17 00:00:00 2001 From: Sebastian Tiedtke Date: Mon, 14 Jan 2013 19:38:54 -0800 Subject: [PATCH] Added new layer for iOS abstraction. --- app/appium.js | 107 ++++++++++++---------------------------------- app/controller.js | 12 +++--- app/ios.js | 96 +++++++++++++++++++++++++++++++++++++++++ app/routing.js | 1 + server.js | 13 +++--- 5 files changed, 138 insertions(+), 91 deletions(-) create mode 100644 app/ios.js diff --git a/app/appium.js b/app/appium.js index b76a8820..baef45be 100644 --- a/app/appium.js +++ b/app/appium.js @@ -1,20 +1,15 @@ // Appium webserver controller methods // https://github.com/hugs/appium/blob/master/appium/appium.py var routing = require('./routing') - , path = require('path') - , rimraf = require('rimraf') - , instruments = require('../instruments/instruments'); + , ios = require('./ios'); -var Appium = function(app, udid, verbose, removeTraceDir) { - this.app = app; - this.udid = udid; - this.verbose = verbose; - this.instruments = null; +var Appium = function(args) { + this.args = args; this.rest = null; - this.queue = []; - this.progress = 0; + this.devices = {}; + this.active = null; + this.device = null; this.sessionId = null; - this.removeTraceDir = removeTraceDir; }; Appium.prototype.attachTo = function(rest, cb) { @@ -33,91 +28,43 @@ Appium.prototype.start = function(cb) { this.sessionId = new Date().getTime(); console.log('Creating new appium session ' + this.sessionId); - if (this.instruments === null) { - this.instruments = instruments( - this.rest - , path.resolve(__dirname, '../' + this.app) - , this.udid - , path.resolve(__dirname, 'uiauto/bootstrap.js') - , path.resolve(__dirname, 'uiauto/Automation.tracetemplate') - ); + // in future all the blackberries go here. + this.active = 'iOS'; + if (typeof this.devices[this.active] === 'undefined') { + this.devices[this.active] = ios(this.rest, this.args.app, this.args.UDID, this.args.verbose, this.args.remove); } + this.device = this.devices[this.active]; - var me = this; - me.instruments.launch(function() { - console.log('Instruments launched. Starting poll loop for new commands.'); - me.instruments.setDebug(true); - cb(null, me); - }, function(code) { - if (!code || code > 0) { - me.stop(); - } + this.device.start(function(err, device) { + cb(err, device); }); - } else { - cb('Session already in progress', null); } }; +Appium.prototype.proxy = function(cmd, cb) { + this.device.proxy(cmd, cb); +}; + Appium.prototype.stop = function(cb) { if (this.sessionId === null) { return; } + var me = this; - console.log('Shutting down appium session ' + me.sessionId); - this.instruments.shutdown(function(traceDir) { - me.queue = []; - me.progress = 0; + this.device.stop(function() { + console.log('Shutting down appium session.'); me.sessionId = null; - rimraf(traceDir, function() { - if (cb) { - cb(); - } - }); + if (cb) { + cb(me.sessionId); + } }); }; -Appium.prototype.proxy = function(command, cb) { - // was thinking we should use a queue for commands instead of writing to a file - this.push([command, cb]); - console.log('Pushed command to appium work queue: ' + command); +Appium.prototype.device = function() { + return this.devices[this.active]; }; -Appium.prototype.push = function(elem) { - this.queue.push(elem); - var me = this; - - var next = function() { - if (me.queue.length <= 0 || me.progress > 0) { - return; - } - - var target = me.queue.shift(); - me.progress++; - - me.instruments.sendCommand(target[0], function(result) { - if (typeof target[1] === 'function') { - if (result === 'undefined') { - target[1](); - } else { - try { - var jsonresult = JSON.parse(result); - target[1](jsonresult); - } catch (e) { - target[1](result); - } - } - } - - // maybe there's moar work to do - me.progress--; - next(); - }); - }; - - next(); -}; - -module.exports = function(app, udid, version) { - return new Appium(app, udid, version); +module.exports = function(args) { + return new Appium(args); }; diff --git a/app/controller.js b/app/controller.js index 066ced88..4578e9df 100644 --- a/app/controller.js +++ b/app/controller.js @@ -8,7 +8,7 @@ var findElement = function(req, res, ctx, many, cb) { var command = [ctx, ".findElement", ext, "AndSetKey", ext, "('", value, "')"].join(""); - req.appium.proxy(command, function(json) { + req.device.proxy(command, function(json) { json = many ? json : json[0]; cb({ sessionId: req.appium.sessionId @@ -33,7 +33,7 @@ exports.getStatus = function(req, res) { }; exports.createSession = function(req, res) { - // we can talk to the appium client from here + // we can talk to the device client from here req.appium.start(function(err, instance) { if (err) { // of course we need to deal with err according to the WDJP spec. @@ -83,7 +83,7 @@ exports.executeScript = function(req, res) { var iosResponse =''; var requestData = req.body; try { - iosResponse = appium.client.proxy(requestData.script, true); + iosResponse = device.client.proxy(requestData.script, true); } catch (e) { var errObj = {sessionId: sessionId, 'status': 13, 'value': JSON.stringify(e)}; @@ -112,7 +112,7 @@ exports.setValue = function(req, res) { var command = ["elements['", elementId, "'].setValue('", body, "')"].join(''); - req.appium.proxy(command, function(json) { + req.device.proxy(command, function(json) { res.send({ sessionId: req.appium.sessionId , status: status @@ -128,7 +128,7 @@ exports.doClick = function(req, res) { var command = ["elements['", elementId, "'].tap()"].join(''); - req.appium.proxy(command, function(json) { + req.device.proxy(command, function(json) { res.send({ sessionId: req.appium.sessionId , status: status @@ -144,7 +144,7 @@ exports.getText = function(req, res) { var command = ["elements['", elementId, "'].getText()"].join(''); - req.appium.proxy(command, function(json) { + req.device.proxy(command, function(json) { res.send({ sessionId: req.appium.sessionId , status: status diff --git a/app/ios.js b/app/ios.js new file mode 100644 index 00000000..97958575 --- /dev/null +++ b/app/ios.js @@ -0,0 +1,96 @@ +var path = require('path') + , rimraf = require('rimraf') + , instruments = require('../instruments/instruments'); + +var IOS = function(rest, app, udid, verbose, removeTraceDir) { + this.rest = rest; + this.app = app; + this.udid = udid; + this.verbose = verbose; + this.instruments = null; + this.queue = []; + this.progress = 0; + this.removeTraceDir = removeTraceDir; +}; + +IOS.prototype.start = function(cb) { + if (this.instruments === null) { + this.instruments = instruments( + this.rest + , path.resolve(__dirname, '../' + this.app) + , this.udid + , path.resolve(__dirname, 'uiauto/bootstrap.js') + , path.resolve(__dirname, 'uiauto/Automation.tracetemplate') + ); + } + + var me = this; + me.instruments.launch(function() { + console.log('Instruments launched. Starting poll loop for new commands.'); + me.instruments.setDebug(true); + cb(null, me); + }, function(code) { + if (!code || code > 0) { + me.stop(); + } + }); +}; + +IOS.prototype.stop = function(cb) { + var me = this; + + this.instruments.shutdown(function(traceDir) { + me.queue = []; + me.progress = 0; + rimraf(traceDir, function() { + if (cb) { + cb(); + } + }); + }); +}; + +IOS.prototype.proxy = function(command, cb) { + // was thinking we should use a queue for commands instead of writing to a file + this.push([command, cb]); + console.log('Pushed command to appium work queue: ' + command); +}; + +IOS.prototype.push = function(elem) { + this.queue.push(elem); + var me = this; + + var next = function() { + if (me.queue.length <= 0 || me.progress > 0) { + return; + } + + var target = me.queue.shift(); + me.progress++; + + me.instruments.sendCommand(target[0], function(result) { + if (typeof target[1] === 'function') { + if (result === 'undefined') { + target[1](); + } else { + try { + var jsonresult = JSON.parse(result); + target[1](jsonresult); + } catch (e) { + target[1](result); + } + } + } + + // maybe there's moar work to do + me.progress--; + next(); + }); + }; + + next(); +}; + +module.exports = function(rest, app, udid, verbose, removeTraceDir) { + return new IOS(rest, app, udid, verbose, removeTraceDir); +}; diff --git a/app/routing.js b/app/routing.js index 8e1ca12a..e3f7ae8a 100644 --- a/app/routing.js +++ b/app/routing.js @@ -4,6 +4,7 @@ module.exports = function(appium) { var rest = appium.rest , inject = function(req, res, next) { req.appium = appium; + req.device = appium.device; next(); }; diff --git a/server.js b/server.js index c1511667..63293336 100644 --- a/server.js +++ b/server.js @@ -9,10 +9,13 @@ var http = require('http') , appium = require('./app/appium') , parser = require('./app/parser'); -var main = function(app, udid, verbose, port, address, remove, doneCb) { +var main = function(args, doneCb) { if (typeof doneCb === "undefined") { doneCb = function() {}; } + // in case we'll support blackberry at some point + args.device = 'iOS'; + rest.configure(function() { var bodyParser = express.bodyParser() , parserWrap = function(req, res, next) { @@ -31,12 +34,12 @@ var main = function(app, udid, verbose, port, address, remove, doneCb) { rest.use(rest.router); }); // Instantiate the appium instance - var appiumServer = appium(app, udid, verbose, remove); + var appiumServer = appium(args); // Hook up REST http interface appiumServer.attachTo(rest); // Start the web server that receives all the commands - server.listen(port, address, function() { - var logMessage = "Appium REST http interface listener started on "+address+":"+port; + server.listen(args.port, args.address, function() { + var logMessage = "Appium REST http interface listener started on "+args.address+":"+args.port; console.log(logMessage.cyan); }); server.on('close', doneCb); @@ -45,7 +48,7 @@ var main = function(app, udid, verbose, port, address, remove, doneCb) { if (require.main === module) { // Parse the command line arguments var args = parser().parseArgs(); - main(args.app, args.UDID, args.verbose, args.port, args.address, args.remove); + main(args); } module.exports.run = main;