2007-01-24 22:24:01 +08:00
|
|
|
"""
|
|
|
|
Node code for slaves.
|
|
|
|
"""
|
|
|
|
|
|
|
|
import py
|
|
|
|
from py.__.test.rsession.executor import RunExecutor, BoxExecutor, AsyncExecutor
|
|
|
|
from py.__.test.rsession.outcome import Outcome
|
2007-02-04 04:15:55 +08:00
|
|
|
from py.__.test.outcome import Skipped
|
2007-01-25 00:46:46 +08:00
|
|
|
import thread
|
|
|
|
import os
|
2007-01-24 22:24:01 +08:00
|
|
|
|
2007-01-25 00:46:46 +08:00
|
|
|
class PidInfo(object):
|
|
|
|
""" Pure container class to store information of actually running
|
|
|
|
pid
|
|
|
|
"""
|
|
|
|
def __init__(self):
|
|
|
|
self.pid = 0
|
|
|
|
self.lock = thread.allocate_lock()
|
|
|
|
|
|
|
|
def set_pid(self, pid):
|
|
|
|
self.lock.acquire()
|
|
|
|
try:
|
|
|
|
self.pid = pid
|
|
|
|
finally:
|
|
|
|
self.lock.release()
|
|
|
|
|
|
|
|
def kill(self):
|
|
|
|
self.lock.acquire()
|
|
|
|
try:
|
|
|
|
if self.pid:
|
|
|
|
os.kill(self.pid, 15)
|
|
|
|
self.pid = 0
|
|
|
|
finally:
|
|
|
|
self.lock.release()
|
|
|
|
|
|
|
|
def waitandclear(self, pid, num):
|
|
|
|
""" This is an obscure hack to keep locking properly, adhere to posix semantics
|
|
|
|
and try to clean it as much as possible, not clean at all
|
|
|
|
"""
|
|
|
|
self.lock.acquire()
|
|
|
|
try:
|
|
|
|
retval = os.waitpid(self.pid, 0)
|
|
|
|
self.pid = 0
|
|
|
|
return retval
|
|
|
|
finally:
|
|
|
|
self.lock.release()
|
2007-01-24 22:24:01 +08:00
|
|
|
|
|
|
|
class SlaveNode(object):
|
2007-01-26 19:49:59 +08:00
|
|
|
def __init__(self, config, pidinfo, executor=AsyncExecutor):
|
|
|
|
#self.rootcollector = rootcollector
|
2007-01-25 00:46:46 +08:00
|
|
|
self.config = config
|
2007-01-24 22:24:01 +08:00
|
|
|
self.executor = executor
|
2007-01-25 00:46:46 +08:00
|
|
|
self.pidinfo = pidinfo
|
2007-01-24 22:24:01 +08:00
|
|
|
|
|
|
|
def execute(self, itemspec):
|
2007-01-26 19:49:59 +08:00
|
|
|
item = self.config._getcollector(itemspec)
|
2007-01-25 00:46:46 +08:00
|
|
|
ex = self.executor(item, config=self.config)
|
2007-01-24 22:24:01 +08:00
|
|
|
if self.executor is AsyncExecutor:
|
|
|
|
cont, pid = ex.execute()
|
2007-01-25 00:46:46 +08:00
|
|
|
self.pidinfo.set_pid(pid)
|
2007-01-24 22:24:01 +08:00
|
|
|
else:
|
|
|
|
# for tests only
|
|
|
|
return ex.execute()
|
2007-01-25 00:46:46 +08:00
|
|
|
return cont(self.pidinfo.waitandclear)
|
2007-01-24 22:24:01 +08:00
|
|
|
|
|
|
|
def run(self, itemspec):
|
|
|
|
#outcome = self.execute(itemspec)
|
|
|
|
#return outcome.make_repr()
|
|
|
|
outcome = self.execute(itemspec)
|
|
|
|
if self.executor.wraps:
|
|
|
|
return outcome
|
|
|
|
else:
|
2007-01-25 00:46:46 +08:00
|
|
|
return outcome.make_repr(self.config.option.tbstyle)
|
2007-01-24 22:24:01 +08:00
|
|
|
|
2007-01-25 00:46:46 +08:00
|
|
|
def slave_main(receive, send, path, config, pidinfo):
|
2007-01-24 22:24:01 +08:00
|
|
|
import os
|
|
|
|
assert os.path.exists(path)
|
|
|
|
path = os.path.abspath(path)
|
|
|
|
nodes = {}
|
|
|
|
def getnode(item):
|
|
|
|
node = nodes.get(item[0], None)
|
|
|
|
if node is not None:
|
|
|
|
return node
|
|
|
|
col = py.test.collect.Directory(str(py.path.local(path).join(item[0])))
|
2007-01-26 19:49:59 +08:00
|
|
|
node = nodes[item[0]] = SlaveNode(config, pidinfo)
|
2007-01-24 22:24:01 +08:00
|
|
|
return node
|
|
|
|
while 1:
|
|
|
|
nextitem = receive()
|
|
|
|
if nextitem is None:
|
|
|
|
break
|
|
|
|
try:
|
|
|
|
node = getnode(nextitem)
|
2007-01-26 19:49:59 +08:00
|
|
|
res = node.run(nextitem)
|
2007-02-04 04:15:55 +08:00
|
|
|
except Skipped, s:
|
2007-01-24 22:24:01 +08:00
|
|
|
send(Outcome(skipped=str(s)).make_repr())
|
|
|
|
except:
|
|
|
|
excinfo = py.code.ExceptionInfo()
|
|
|
|
send(Outcome(excinfo=excinfo, is_critical=True).make_repr())
|
|
|
|
else:
|
2007-01-25 00:46:46 +08:00
|
|
|
if not res[0] and not res[3] and config.option.exitfirst:
|
2007-01-24 22:24:01 +08:00
|
|
|
# we're finished, but need to eat what we can
|
|
|
|
send(res)
|
|
|
|
break
|
|
|
|
send(res)
|
|
|
|
|
|
|
|
while nextitem is not None:
|
|
|
|
nextitem = receive()
|
2007-01-25 00:46:46 +08:00
|
|
|
|
2007-02-04 22:05:01 +08:00
|
|
|
defaultconftestnames = ['dist_nicelevel']
|
|
|
|
def setup_slave(host, config):
|
|
|
|
channel = host.gw.remote_exec(str(py.code.Source(setup, "setup()")))
|
|
|
|
configrepr = config.make_repr(defaultconftestnames)
|
|
|
|
#print "sending configrepr", configrepr
|
|
|
|
channel.send(host.gw_remotepath)
|
|
|
|
channel.send(configrepr)
|
|
|
|
return channel
|
|
|
|
|
2007-01-24 22:24:01 +08:00
|
|
|
def setup():
|
2007-01-25 00:46:46 +08:00
|
|
|
def callback_gen(channel, queue, info):
|
2007-01-24 22:24:01 +08:00
|
|
|
def callback(item):
|
|
|
|
if item == 42: # magic call-cleanup
|
|
|
|
# XXX should kill a pid here
|
2007-01-25 00:46:46 +08:00
|
|
|
info.kill()
|
|
|
|
channel.close()
|
2007-01-24 22:24:01 +08:00
|
|
|
sys.exit(0)
|
|
|
|
queue.put(item)
|
|
|
|
return callback
|
2007-02-04 22:05:01 +08:00
|
|
|
# our current dir is the topdir
|
2007-01-24 22:24:01 +08:00
|
|
|
import os, sys
|
2007-02-04 22:05:01 +08:00
|
|
|
basedir = channel.receive()
|
2007-01-26 19:49:59 +08:00
|
|
|
config_repr = channel.receive()
|
2007-01-24 22:24:01 +08:00
|
|
|
# setup defaults...
|
|
|
|
sys.path.insert(0, basedir)
|
|
|
|
import py
|
2007-01-25 00:46:46 +08:00
|
|
|
config = py.test.config
|
2007-02-04 22:05:01 +08:00
|
|
|
assert not config._initialized
|
|
|
|
config.initdirect(basedir, config_repr)
|
2007-01-25 00:46:46 +08:00
|
|
|
if not config.option.nomagic:
|
2007-01-24 22:24:01 +08:00
|
|
|
py.magic.invoke(assertion=1)
|
2007-01-25 00:46:46 +08:00
|
|
|
from py.__.test.rsession.slave import slave_main, PidInfo
|
|
|
|
queue = py.std.Queue.Queue()
|
|
|
|
pidinfo = PidInfo()
|
|
|
|
channel.setcallback(callback_gen(channel, queue, pidinfo))
|
|
|
|
slave_main(queue.get, channel.send, basedir, config, pidinfo)
|
|
|
|
if not config.option.nomagic:
|
2007-01-24 22:24:01 +08:00
|
|
|
py.magic.revoke(assertion=1)
|
2007-01-25 00:46:46 +08:00
|
|
|
channel.close()
|