mirror of
https://github.com/openstf/stf
synced 2025-10-04 10:19:30 +02:00
Provider works more or less now.
This commit is contained in:
parent
789e608dab
commit
3f62a51d83
4 changed files with 132 additions and 15 deletions
8
lib/device.js
Normal file
8
lib/device.js
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
var assert = require('assert')
|
||||||
|
|
||||||
|
assert.ok(process.env.ANDROID_SERIAL,
|
||||||
|
'Missing environment variable ANDROID_SERIAL')
|
||||||
|
|
||||||
|
var log = require('./util/logger')
|
||||||
|
.setGlobalIdentifier(process.env.ANDROID_SERIAL)
|
||||||
|
.createLogger('device')
|
108
lib/provider.js
108
lib/provider.js
|
@ -1,8 +1,12 @@
|
||||||
|
var path = require('path')
|
||||||
|
var fork = require('child_process').fork
|
||||||
|
|
||||||
var adb = require('adbkit')
|
var adb = require('adbkit')
|
||||||
var async = require('async')
|
var async = require('async')
|
||||||
|
|
||||||
var log = require('./util/logger').createLogger('provider')
|
var log = require('./util/logger').createLogger('provider')
|
||||||
var client = adb.createClient()
|
var client = adb.createClient()
|
||||||
|
var workers = {}
|
||||||
|
|
||||||
client.trackDevices(function(err, tracker) {
|
client.trackDevices(function(err, tracker) {
|
||||||
if (err) {
|
if (err) {
|
||||||
|
@ -14,13 +18,117 @@ client.trackDevices(function(err, tracker) {
|
||||||
|
|
||||||
tracker.on('add', function(device) {
|
tracker.on('add', function(device) {
|
||||||
log.info('Found device "%s" (%s)', device.id, device.type)
|
log.info('Found device "%s" (%s)', device.id, device.type)
|
||||||
|
maybeConnect(device)
|
||||||
})
|
})
|
||||||
|
|
||||||
tracker.on('change', function(device) {
|
tracker.on('change', function(device) {
|
||||||
log.info('Device "%s" is now "%s"', device.id, device.type)
|
log.info('Device "%s" is now "%s"', device.id, device.type)
|
||||||
|
maybeConnect(device) || maybeDisconnect(device)
|
||||||
})
|
})
|
||||||
|
|
||||||
tracker.on('remove', function(device) {
|
tracker.on('remove', function(device) {
|
||||||
log.info('Lost device "%s" (%s)', device.id, device.type)
|
log.info('Lost device "%s" (%s)', device.id, device.type)
|
||||||
|
maybeDisconnect(device)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
function isConnectable(device) {
|
||||||
|
switch (device.type) {
|
||||||
|
case 'device':
|
||||||
|
case 'emulator':
|
||||||
|
return true
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function isConnected(device) {
|
||||||
|
return workers[device.id] && workers[device.id].proc
|
||||||
|
}
|
||||||
|
|
||||||
|
function maybeConnect(device) {
|
||||||
|
if (isConnectable(device) && !isConnected(device)) {
|
||||||
|
log.debug('Spawning worker for device "%s"', device.id)
|
||||||
|
var proc = fork(path.join(__dirname, 'device'), {
|
||||||
|
env: {
|
||||||
|
ANDROID_SERIAL: device.id
|
||||||
|
}
|
||||||
|
})
|
||||||
|
proc.on('error', function(err) {
|
||||||
|
log.error('Worker of device "%s" had an error: %s',
|
||||||
|
device.id, err.message)
|
||||||
|
})
|
||||||
|
proc.on('exit', function(code, signal) {
|
||||||
|
var data = workers[device.id]
|
||||||
|
delete workers[device.id]
|
||||||
|
if (code === 0) {
|
||||||
|
log.info('Worker of device "%s" stopped cleanly', device.id)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
log.error('Worker of device "%s" had a dirty exit', device.id)
|
||||||
|
if (Date.now() - data.started < 10000) {
|
||||||
|
log.error('Worker of device "%s" failed in less than 10 seconds,' +
|
||||||
|
' will not attempt to restart', device.id)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
log.info('Restarting worker of "%s"', device.id)
|
||||||
|
maybeConnect(device)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
workers[device.id] = {
|
||||||
|
device: device
|
||||||
|
, proc: proc
|
||||||
|
, started: Date.now()
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
function maybeDisconnect(device) {
|
||||||
|
if (isConnected(device)) {
|
||||||
|
log.info('Releasing worker of %s', device.id)
|
||||||
|
gracefullyKillWorker(device.id, function() { /* noop */ })
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
function gracefullyKillWorker(id, done) {
|
||||||
|
var proc = workers[id]
|
||||||
|
, timer
|
||||||
|
|
||||||
|
timer = setTimeout(function() {
|
||||||
|
log.error('Worker of "%s" did not stop in time', id)
|
||||||
|
proc.removeListener('exit', onExit)
|
||||||
|
proc.kill('SIGKILL')
|
||||||
|
done()
|
||||||
|
}, 10000)
|
||||||
|
|
||||||
|
function onExit() {
|
||||||
|
clearTimeout(timer)
|
||||||
|
done()
|
||||||
|
}
|
||||||
|
|
||||||
|
proc.once('exit', onExit)
|
||||||
|
proc.kill('SIGTERM')
|
||||||
|
}
|
||||||
|
|
||||||
|
function gracefullyExit() {
|
||||||
|
log.info('Stopping all workers')
|
||||||
|
async.each(Object.keys(workers), gracefullyKillWorker, function(err) {
|
||||||
|
log.info('All cleaned up')
|
||||||
|
process.exit(0)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
process.on('SIGINT', function(e) {
|
||||||
|
log.debug('Received SIGINT')
|
||||||
|
gracefullyExit()
|
||||||
|
})
|
||||||
|
|
||||||
|
process.on('SIGTERM', function(e) {
|
||||||
|
log.debug('Received SIGTERM')
|
||||||
|
gracefullyExit()
|
||||||
|
})
|
||||||
|
|
|
@ -1,15 +1,15 @@
|
||||||
var util = require('util')
|
var util = require('util')
|
||||||
|
var colors = require('colors')
|
||||||
|
|
||||||
function Log(tag, stream) {
|
function Log(tag, stream) {
|
||||||
this.tag = tag
|
this.tag = tag
|
||||||
this.stream = stream || process.stderr
|
|
||||||
this.levels = {
|
this.levels = {
|
||||||
DEBUG: 'DBG'
|
DEBUG: 'DBG'.grey
|
||||||
, VERBOSE: 'VRB'
|
, VERBOSE: 'VRB'.cyan
|
||||||
, INFO: 'INF'
|
, INFO: 'INF'.green
|
||||||
, WARNING: 'WRN'
|
, WARNING: 'WRN'.yellow
|
||||||
, ERROR: 'ERR'
|
, ERROR: 'ERR'.red
|
||||||
, FATAL: 'FTL'
|
, FATAL: 'FTL'.red
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,23 +38,24 @@ Log.prototype.fatal = function() {
|
||||||
}
|
}
|
||||||
|
|
||||||
Log.prototype._format = function(priority, args) {
|
Log.prototype._format = function(priority, args) {
|
||||||
return util.format('%s %s/%s %d %s\n',
|
return util.format('%s/%s %d [%s] %s',
|
||||||
Log.globalPrefix, priority, this.tag, process.pid,
|
priority, this.tag, process.pid, Log.globalIdentifier,
|
||||||
util.format.apply(util, args))
|
util.format.apply(util, args))
|
||||||
}
|
}
|
||||||
|
|
||||||
Log.prototype._write = function(out) {
|
Log.prototype._write = function(out) {
|
||||||
this.stream.write(out)
|
console.error(out)
|
||||||
}
|
}
|
||||||
|
|
||||||
Log.globalPrefix = '*'
|
Log.globalIdentifier = '*'
|
||||||
|
|
||||||
Log.createLogger = function(tag) {
|
Log.createLogger = function(tag) {
|
||||||
return new Log(tag)
|
return new Log(tag)
|
||||||
}
|
}
|
||||||
|
|
||||||
Log.setGlobalPrefix = function(prefix) {
|
Log.setGlobalIdentifier = function(identifier) {
|
||||||
Log.globalPrefix = prefix
|
Log.globalIdentifier = identifier
|
||||||
|
return Log
|
||||||
}
|
}
|
||||||
|
|
||||||
exports = module.exports = Log
|
exports = module.exports = Log
|
||||||
|
|
|
@ -9,8 +9,8 @@ describe('Logger', function() {
|
||||||
expect(logger).itself.to.respondTo('createLogger')
|
expect(logger).itself.to.respondTo('createLogger')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should have a setGlobalPrefix method', function() {
|
it('should have a setGlobalIdentifier method', function() {
|
||||||
expect(logger).itself.to.respondTo('setGlobalPrefix')
|
expect(logger).itself.to.respondTo('setGlobalIdentifier')
|
||||||
})
|
})
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue