1
0
Fork 0
mirror of https://github.com/openstf/stf synced 2025-10-04 18:29:17 +02:00

Provider works more or less now.

This commit is contained in:
Simo Kinnunen 2014-01-07 20:09:39 +09:00
parent 789e608dab
commit 3f62a51d83
4 changed files with 132 additions and 15 deletions

8
lib/device.js Normal file
View 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')

View file

@ -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()
})

View file

@ -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

View file

@ -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')
}) })
}) })