[svn r37909] a much much much larger refactoring than i originally

intended at this point:

* HostManager and HostRSync are now acting
  more locally, also easier to test.

* HostInfo deals with setting up gateways now

* HostManager, HostRSync and HostInfo are
  all tested now in test_hostmanage.py
  (and do not involve a full startup of RSessions)

* for rsyncing, the original directory structure
  (relative to config.topdir) is preserved on the
  other side, this makes "dist_rsync_roots" relatively
  clean now (but it doesn't pick up things on the fly,
  only initialises at the beginning)

* added lots of tests

* removed more occurences of pkgdir

* streamlined and simplified some tests

* removed lots of tests that do not appear to test
  specifically enough (and caused trouble for
  the refactoring)

* removed lots of (but not all, i guess) test-specific
  functionality in hostmanage.py and a bit in rsession.py

* removed HostOptions() in favour of rather directly
  accessing config values

--HG--
branch : trunk
This commit is contained in:
hpk 2007-02-04 15:05:01 +01:00
parent f2b38db33a
commit 4791dd6501
10 changed files with 342 additions and 433 deletions

View File

@ -2,32 +2,59 @@ import sys, os
import py
import time
import thread, threading
from py.__.test.rsession.master import \
setup_slave, MasterNode
from py.__.test.rsession.master import MasterNode
from py.__.test.rsession.slave import setup_slave
from py.__.test.rsession import report
class HostInfo(object):
""" Class trying to store all necessary attributes
for host
"""
host_ids = {}
_hostname2list = {}
localdest = None
def __init__(self, hostname, relpath=None):
self.hostid = self._getuniqueid(hostname)
self.hostname = hostname
self.relpath = relpath
def __init__(self, spec):
parts = spec.split(':', 1)
self.hostname = parts.pop(0)
if parts:
self.relpath = parts[0]
else:
self.relpath = "pytestcache-" + self.hostname
self.hostid = self._getuniqueid(self.hostname)
def _getuniqueid(cls, hostname):
if not hostname in cls.host_ids:
cls.host_ids[hostname] = 0
return hostname
retval = hostname + '_' + str(cls.host_ids[hostname])
cls.host_ids[hostname] += 1
return retval
_getuniqueid = classmethod(_getuniqueid)
def _getuniqueid(self, hostname):
l = self._hostname2list.setdefault(hostname, [])
hostid = hostname + "_" * len(l)
l.append(hostid)
return hostid
def initgateway(self, python="python"):
assert not hasattr(self, 'gw')
if self.hostname == "localhost":
gw = py.execnet.PopenGateway(python=python)
else:
gw = py.execnet.SshGateway(self.hostname,
remotepython=python)
self.gw = gw
channel = gw.remote_exec("""
import os
targetdir = %r
if not os.path.isabs(targetdir):
homedir = os.environ['HOME']
targetdir = os.path.join(homedir, targetdir)
if not os.path.exists(targetdir):
os.makedirs(targetdir)
channel.send(os.path.abspath(targetdir))
""" % self.relpath)
self.gw_remotepath = channel.receive()
#print "initialized", gw, "with remotepath", self.gw_remotepath
if self.hostname == "localhost":
self.localdest = py.path.local(self.gw_remotepath)
assert self.localdest.check(dir=1)
def __str__(self):
return "<HostInfo %s>" % (self.hostname,)
return "<HostInfo %s:%s>" % (self.hostname, self.relpath)
def __hash__(self):
return hash(self.hostid)
@ -39,138 +66,77 @@ class HostInfo(object):
return not self == other
class HostRSync(py.execnet.RSync):
""" An rsync wrapper which filters out *~, .svn/ and *.pyc
""" RSyncer that filters out common files
"""
def __init__(self, config):
py.execnet.RSync.__init__(self, delete=True)
self.config = config
def __init__(self, *args, **kwargs):
self._synced = {}
super(HostRSync, self).__init__(*args, **kwargs)
def filter(self, path):
if path.endswith('.pyc') or path.endswith('~'):
return False
dir, base = os.path.split(path)
try:
name = "dist_rsync_roots"
rsync_roots = self.config.conftest.rget_path(name, dir)
except AttributeError:
rsync_roots = None
if base == '.svn':
return False
if rsync_roots is None:
return True
return base in rsync_roots
path = py.path.local(path)
if not path.ext in ('.pyc', '.pyo'):
if not path.basename.endswith('~'):
if path.check(dotfile=0):
return True
class DummyGateway(object):
pass
class HostOptions(object):
""" Dummy container for host options, not to keep that
as different function parameters, mostly related to
tests only
"""
def __init__(self, remote_python="python",
optimise_localhost=True, do_sync=True,
create_gateways=True):
self.remote_python = remote_python
self.optimise_localhost = optimise_localhost
self.do_sync = do_sync
self.create_gateways = create_gateways
def add_target_host(self, host, destrelpath=None, finishedcallback=None):
key = host.hostname, host.relpath
if key in self._synced:
if finishedcallback:
finishedcallback()
return False
self._synced[key] = True
# the follow attributes are set from host.initgateway()
gw = host.gw
remotepath = host.gw_remotepath
if destrelpath is not None:
remotepath = os.path.join(remotepath, destrelpath)
super(HostRSync, self).add_target(gw,
remotepath,
finishedcallback)
return True # added the target
class HostManager(object):
def __init__(self, sshhosts, config, options=HostOptions()):
def __init__(self, sshhosts, config):
self.sshhosts = sshhosts
self.config = config
self.options = options
if not options.create_gateways:
self.prepare_gateways = self.prepare_dummy_gateways
#assert pkgdir.join("__init__.py").check(), (
# "%s probably wrong" %(pkgdir,))
def prepare_dummy_gateways(self):
for host in self.sshhosts:
gw = DummyGateway()
host.gw = gw
gw.host = host
return self.sshhosts
def prepare_ssh_gateway(self, host):
if self.options.remote_python is None:
gw = py.execnet.SshGateway(host.hostname)
else:
gw = py.execnet.SshGateway(host.hostname,
remotepython=self.options.remote_python)
return gw
def prepare_popen_rsync_gateway(self, host):
""" Popen gateway, but with forced rsync
"""
from py.__.execnet.register import PopenCmdGateway
gw = PopenCmdGateway("cd ~; python -u -c 'exec input()'")
if not host.relpath.startswith("/"):
host.relpath = os.environ['HOME'] + '/' + host.relpath
return gw
def prepare_popen_gateway(self, host):
if self.options.remote_python is None:
gw = py.execnet.PopenGateway()
else:
gw = py.execnet.PopenGateway(python=self.options.remote_python)
host.relpath = str(self.config.topdir)
return gw
def prepare_gateways(self):
dist_remotepython = self.config.getvalue("dist_remotepython")
for host in self.sshhosts:
if host.hostname == 'localhost':
if not self.options.optimise_localhost:
gw = self.prepare_popen_rsync_gateway(host)
else:
gw = self.prepare_popen_gateway(host)
else:
gw = self.prepare_ssh_gateway(host)
host.gw = gw
gw.host = host
return self.sshhosts
host.initgateway(python=dist_remotepython)
host.gw.host = host # XXX would like to avoid it
def need_rsync(self, rsynced, hostname, remoterootpath):
if (hostname, remoterootpath) in rsynced:
return False
if hostname == 'localhost' and self.options.optimise_localhost:
return False
return True
def init_rsync(self, reporter):
# send each rsync roots
roots = self.config.getvalue_pathlist("dist_rsync_roots")
if roots is None:
roots = [self.config.topdir]
self.prepare_gateways()
rsync = HostRSync()
for root in roots:
destrelpath = root.relto(self.config.topdir)
for host in self.sshhosts:
reporter(report.HostRSyncing(host))
def donecallback():
reporter(report.HostReady(host))
rsync.add_target_host(host, destrelpath,
finishedcallback=donecallback)
rsync.send(root)
def init_hosts(self, reporter, done_dict={}):
def init_hosts(self, reporter, done_dict=None):
if done_dict is None:
done_dict = {}
hosts = self.prepare_gateways()
# rsyncing
rsynced = {}
if self.options.do_sync:
rsync = HostRSync(self.config)
for host in hosts:
if not self.need_rsync(rsynced, host.hostname, host.relpath):
reporter(report.HostReady(host))
continue
rsynced[(host.hostname, host.relpath)] = True
def done(host=host):
reporter(report.HostReady(host))
reporter(report.HostRSyncing(host))
if self.options.do_sync:
rsync.add_target(host.gw, host.relpath, done)
if not self.options.do_sync:
return # for testing only
rsync.send(self.config.topdir)
# hosts ready
self.init_rsync(reporter)
return self.setup_nodes(reporter, done_dict)
def setup_nodes(self, reporter, done_dict):
nodes = []
for host in self.sshhosts:
ch = setup_slave(host.gw, host.relpath, self.config)
nodes.append(MasterNode(ch, reporter, done_dict))
if hasattr(host.gw, 'remote_exec'): # otherwise dummy for tests :/
ch = setup_slave(host, self.config)
nodes.append(MasterNode(ch, reporter, done_dict))
return nodes
def teardown_hosts(self, reporter, channels, nodes,

View File

@ -74,14 +74,3 @@ def dispatch_loop(masternodes, itemgenerator, shouldstop,
waiter()
return all_tests
def setup_slave(gateway, pkgpath, config):
from py.__.test.rsession import slave
import os
ch = gateway.remote_exec(str(py.code.Source(slave.setup, "setup()")))
#if hasattr(gateway, 'sshaddress'):
# assert not os.path.isabs(pkgpath)
ch.send(str(pkgpath))
ch.send(config.make_repr(defaultconftestnames))
return ch
defaultconftestnames = ['dist_nicelevel']

View File

@ -10,9 +10,8 @@ import time
from py.__.test.rsession import report
from py.__.test.rsession.master import \
setup_slave, MasterNode, dispatch_loop, itemgen, randomgen
from py.__.test.rsession.hostmanage import HostInfo, HostOptions, HostManager
MasterNode, dispatch_loop, itemgen, randomgen
from py.__.test.rsession.hostmanage import HostInfo, HostManager
from py.__.test.rsession.local import local_loop, plain_runner, apigen_runner,\
box_runner
from py.__.test.rsession.reporter import LocalReporter, RemoteReporter
@ -24,24 +23,12 @@ class AbstractSession(Session):
An abstract session executes collectors/items through a runner.
"""
def __init__(self, config, optimise_localhost=True):
super(AbstractSession, self).__init__(config=config)
self.optimise_localhost = optimise_localhost
def fixoptions(self):
option = self.config.option
if option.runbrowser and not option.startserver:
#print "--runbrowser implies --startserver"
option.startserver = True
super(AbstractSession, self).fixoptions()
def getpkgdir(path):
path = py.path.local(path)
pkgpath = path.pypkgpath()
if pkgpath is None:
pkgpath = path
return pkgpath
getpkgdir = staticmethod(getpkgdir)
def init_reporter(self, reporter, sshhosts, reporter_class, arg=""):
""" This initialises so called `reporter` class, which will
@ -115,18 +102,6 @@ class AbstractSession(Session):
self.checkfun = checkfun
return new_reporter, checkfun
def parse_directories(sshhosts):
""" Parse sshadresses of hosts to have distinct hostname/hostdir
"""
directories = {}
for host in sshhosts:
m = re.match("^(.*?):(.*)$", host.hostname)
if m:
host.hostname = m.group(1)
host.relpath = m.group(2) + "-" + host.hostname
else:
host.relpath = "pytestcache-%s" % host.hostname
class RSession(AbstractSession):
""" Remote version of session
"""
@ -151,7 +126,7 @@ class RSession(AbstractSession):
""" main loop for running tests. """
args = self.config.args
sshhosts, remotepython = self.read_distributed_config()
sshhosts = self._getconfighosts()
reporter, startserverflag = self.init_reporter(reporter,
sshhosts, RemoteReporter)
reporter, checkfun = self.wrap_reporter(reporter)
@ -159,9 +134,7 @@ class RSession(AbstractSession):
reporter(report.TestStarted(sshhosts))
done_dict = {}
hostopts = HostOptions(remote_python=remotepython,
optimise_localhost=self.optimise_localhost)
hostmanager = HostManager(sshhosts, self.config, hostopts)
hostmanager = HostManager(sshhosts, self.config)
try:
nodes = hostmanager.init_hosts(reporter, done_dict)
reporter(report.RsyncFinished())
@ -191,14 +164,9 @@ class RSession(AbstractSession):
self.kill_server(startserverflag)
raise
def read_distributed_config(self):
""" Read from conftest file the configuration of distributed testing
"""
sshhosts = [HostInfo(i) for i in
self.config.getvalue("dist_hosts")]
parse_directories(sshhosts)
remotepython = self.config.getvalue("dist_remotepython")
return sshhosts, remotepython
def _getconfighosts(self):
return [HostInfo(spec) for spec in
self.config.getvalue("dist_hosts")]
def dispatch_tests(self, nodes, reporter, checkfun, done_dict):
colitems = self.config.getcolitems()
@ -262,7 +230,7 @@ class LSession(AbstractSession):
print >>sys.stderr, 'building documentation'
capture = py.io.StdCaptureFD()
try:
pkgdir = self.getpkgdir(self.config.args[0])
pkgdir = py.path.local(self.config.args[0]).pypkgpath()
apigen.build(pkgdir,
DocStorageAccessor(self.docstorage),
capture)
@ -272,7 +240,7 @@ class LSession(AbstractSession):
def init_runner(self):
if self.config.option.apigen:
from py.__.apigen.tracer.tracer import Tracer, DocStorage
pkgdir = self.getpkgdir(self.config.args[0])
pkgdir = py.path.local(self.config.args[0]).pypkgpath()
apigen = py.path.local(self.config.option.apigen).pyimport()
if not hasattr(apigen, 'get_documentable_items'):
raise NotImplementedError("Provided script does not seem "
@ -288,4 +256,3 @@ class LSession(AbstractSession):
return box_runner
return plain_runner

View File

@ -106,6 +106,15 @@ def slave_main(receive, send, path, config, pidinfo):
while nextitem is not None:
nextitem = receive()
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
def setup():
def callback_gen(channel, queue, info):
def callback(item):
@ -116,19 +125,16 @@ def setup():
sys.exit(0)
queue.put(item)
return callback
# our current dir is the topdir
import os, sys
basedir = channel.receive() # path is ready
basedir = channel.receive()
config_repr = channel.receive()
# setup defaults...
sys.path.insert(0, basedir)
import py
config = py.test.config
if config._initialized:
config = config._reparse([basedir])
config.merge_repr(config_repr)
else:
config.initdirect(basedir, config_repr)
assert not config._initialized
config.initdirect(basedir, config_repr)
if not config.option.nomagic:
py.magic.invoke(assertion=1)
from py.__.test.rsession.slave import slave_main, PidInfo

View File

@ -0,0 +1,137 @@
""" RSync filter test
"""
import py
from py.__.test.rsession.hostmanage import HostRSync
from py.__.test.rsession.hostmanage import HostInfo, HostManager
class DirSetup:
def setup_method(self, method):
name = "%s.%s" %(self.__class__.__name__, method.func_name)
self.tmpdir = py.test.ensuretemp(name)
self.source = self.tmpdir.ensure("source", dir=1)
self.dest = self.tmpdir.join("dest")
class TestHostInfo:
def test_defaultpath(self):
x = HostInfo("localhost")
assert x.hostname == "localhost"
assert x.relpath == "pytestcache-" + x.hostname
def test_path(self):
x = HostInfo("localhost:/tmp")
assert x.relpath == "/tmp"
assert x.hostname == "localhost"
def test_hostid(self):
x = HostInfo("localhost")
y = HostInfo("localhost")
assert x.hostid != y.hostid
x = HostInfo("localhost:/tmp")
y = HostInfo("localhost")
assert x.hostid != y.hostid
def test_non_existing_hosts(self):
host = HostInfo("alskdjalsdkjasldkajlsd")
py.test.raises((py.process.cmdexec.Error, IOError, EOFError),
host.initgateway)
def test_initgateway_localhost_relpath(self):
name = "pytestcache-localhost"
x = HostInfo("localhost:%s" % name)
x.initgateway()
assert x.gw
try:
homedir = py.path.local(py.std.os.environ['HOME'])
expected = homedir.join(name)
assert x.gw_remotepath == str(expected)
assert x.localdest == expected
finally:
x.gw.exit()
def test_initgateway_ssh_and_remotepath(self):
option = py.test.config.option
if option.sshtarget is None:
py.test.skip("no known ssh target, use -S to set one")
x = HostInfo("%s" % (option.sshtarget, ))
x.initgateway()
assert x.gw
assert x.gw_remotepath.endswith(x.relpath)
channel = x.gw.remote_exec("""
import os
homedir = os.environ['HOME']
relpath = channel.receive()
path = os.path.join(homedir, relpath)
channel.send(path)
""")
channel.send(x.relpath)
res = channel.receive()
assert res == x.gw_remotepath
assert x.localdest is None
class TestSyncing(DirSetup):
def test_hrsync_filter(self):
self.source.ensure("dir", "file.txt")
self.source.ensure(".svn", "entries")
self.source.ensure(".somedotfile", "moreentries")
self.source.ensure("somedir", "editfile~")
syncer = HostRSync()
l = list(self.source.visit(rec=syncer.filter,
fil=syncer.filter))
assert len(l) == 3
basenames = [x.basename for x in l]
assert 'dir' in basenames
assert 'file.txt' in basenames
assert 'somedir' in basenames
def test_hrsync_one_host(self):
h1 = HostInfo("localhost:%s" % self.dest)
finished = []
rsync = HostRSync()
h1.initgateway()
rsync.add_target_host(h1)
self.source.join("hello.py").write("world")
rsync.send(self.source)
assert self.dest.join("hello.py").check()
def test_hrsync_same_host_twice(self):
h1 = HostInfo("localhost:%s" % self.dest)
h2 = HostInfo("localhost:%s" % self.dest)
finished = []
rsync = HostRSync()
l = []
h1.initgateway()
res1 = rsync.add_target_host(h1)
assert res1
res2 = rsync.add_target_host(h2)
assert not res2
class TestHostManager(DirSetup):
def test_hostmanager_init_rsync_topdir(self):
dir2 = self.source.ensure("dir1", "dir2", dir=1)
dir2.ensure("hello")
config = py.test.config._reparse([self.source])
hm = HostManager([HostInfo("localhost:" + str(self.dest))], config)
events = []
hm.init_rsync(reporter=events.append)
assert self.dest.join("dir1").check()
assert self.dest.join("dir1", "dir2").check()
assert self.dest.join("dir1", "dir2", 'hello').check()
def test_hostmanager_init_rsync_rsync_roots(self):
dir2 = self.source.ensure("dir1", "dir2", dir=1)
dir2.ensure("hello")
self.source.ensure("bogusdir", "file")
self.source.join("conftest.py").write(py.code.Source("""
dist_rsync_roots = ['dir1/dir2']
"""))
config = py.test.config._reparse([self.source])
hm = HostManager([HostInfo("localhost:" + str(self.dest))], config)
events = []
hm.init_rsync(reporter=events.append)
assert self.dest.join("dir1").check()
assert self.dest.join("dir1", "dir2").check()
assert self.dest.join("dir1", "dir2", 'hello').check()
assert not self.dest.join("bogus").check()

View File

@ -9,18 +9,19 @@ import py, sys
if sys.platform == 'win32':
py.test.skip("rsession is unsupported on Windows.")
from py.__.test.rsession.master import dispatch_loop, setup_slave, MasterNode, randomgen
from py.__.test.rsession.master import dispatch_loop, MasterNode, randomgen
from py.__.test.rsession.slave import setup_slave
from py.__.test.rsession.outcome import ReprOutcome, Outcome
from py.__.test.rsession.testing.test_slave import funcpass_spec, funcfail_spec, funchang_spec
from py.__.test.rsession import report
from py.__.test.rsession.hostmanage import HostInfo
def setup_module(mod):
# bind an empty config
config = py.test.config._reparse([])
mod.tmpdir = tmpdir = py.test.ensuretemp(mod.__name__)
# to avoid rsyncing
config = py.test.config._reparse([tmpdir])
config._overwrite('dist_taskspernode', 10)
mod.pkgdir = py.path.local(py.__file__).dirpath().dirpath()
mod.rootcol = py.test.collect.Directory(mod.pkgdir)
mod.rootcol = config._getcollector(tmpdir)
class DummyGateway(object):
def __init__(self):
@ -92,46 +93,69 @@ def test_dispatch_loop():
node.pending.pop()
dispatch_loop(masternodes, itemgenerator, shouldstop, waiter=waiter)
def test_slave_setup():
gw = py.execnet.PopenGateway()
config = py.test.config._reparse([])
channel = setup_slave(gw, pkgdir, config)
spec = rootcol._getitembynames(funcpass_spec)._get_collector_trail()
channel.send(spec)
output = ReprOutcome(channel.receive())
assert output.passed
channel.send(42)
channel.waitclose(10)
gw.exit()
class TestSlave:
def setup_class(cls):
cls.tmpdir = tmpdir = py.test.ensuretemp(cls.__name__)
pkgpath = tmpdir.join("pkg")
pkgpath.ensure("__init__.py")
pkgpath.join("test_something.py").write(py.code.Source("""
def funcpass():
pass
def test_slave_running():
def simple_report(event):
if not isinstance(event, report.ReceivedItemOutcome):
return
item = event.item
if item.code.name == 'funcpass':
assert event.outcome.passed
else:
assert not event.outcome.passed
def open_gw():
gw = py.execnet.PopenGateway()
gw.host = HostInfo("localhost")
gw.host.gw = gw
config = py.test.config._reparse([])
channel = setup_slave(gw, pkgdir, config)
mn = MasterNode(channel, simple_report, {})
return mn
master_nodes = [open_gw(), open_gw(), open_gw()]
funcpass_item = rootcol._getitembynames(funcpass_spec)
funcfail_item = rootcol._getitembynames(funcfail_spec)
itemgenerator = iter([funcfail_item] +
[funcpass_item] * 5 + [funcfail_item] * 5)
shouldstop = lambda : False
dispatch_loop(master_nodes, itemgenerator, shouldstop)
def funcfail():
raise AssertionError("hello world")
"""))
cls.config = py.test.config._reparse([tmpdir])
assert cls.config.topdir == tmpdir
cls.rootcol = cls.config._getcollector(tmpdir)
def _gettrail(self, *names):
item = self.rootcol._getitembynames(names)
return self.config.get_collector_trail(item)
def test_slave_setup(self):
host = HostInfo("localhost:%s" %(self.tmpdir,))
host.initgateway()
channel = setup_slave(host, self.config)
spec = self._gettrail("pkg", "test_something.py", "funcpass")
print "sending", spec
channel.send(spec)
output = ReprOutcome(channel.receive())
assert output.passed
channel.send(42)
channel.waitclose(10)
host.gw.exit()
def test_slave_running(self):
py.test.skip("XXX test broken, needs refactoring")
def simple_report(event):
if not isinstance(event, report.ReceivedItemOutcome):
return
item = event.item
if item.code.name == 'funcpass':
assert event.outcome.passed
else:
assert not event.outcome.passed
def open_gw():
gw = py.execnet.PopenGateway()
gw.host = HostInfo("localhost")
gw.host.gw = gw
config = py.test.config._reparse([tmpdir])
channel = setup_slave(gw.host, config)
mn = MasterNode(channel, simple_report, {})
return mn
master_nodes = [open_gw(), open_gw(), open_gw()]
funcpass_item = rootcol._getitembynames(funcpass_spec)
funcfail_item = rootcol._getitembynames(funcfail_spec)
itemgenerator = iter([funcfail_item] +
[funcpass_item] * 5 + [funcfail_item] * 5)
shouldstop = lambda : False
dispatch_loop(master_nodes, itemgenerator, shouldstop)
def test_slave_running_interrupted():
py.test.skip("XXX test broken, needs refactoring")
#def simple_report(event):
# if not isinstance(event, report.ReceivedItemOutcome):
# return
@ -146,7 +170,7 @@ def test_slave_running_interrupted():
gw = py.execnet.PopenGateway()
gw.host = HostInfo("localhost")
gw.host.gw = gw
config = py.test.config._reparse([])
config = py.test.config._reparse([tmpdir])
channel = setup_slave(gw, pkgdir, config)
mn = MasterNode(channel, reports.append, {})
return mn, gw, channel

View File

@ -52,7 +52,7 @@ class TestRestUnits(object):
'localhost\n\n')
def test_report_HostRSyncing(self):
event = report.HostRSyncing(HostInfo('localhost', '/foo/bar'))
event = report.HostRSyncing(HostInfo('localhost:/foo/bar'))
reporter.report(event)
assert stdout.getvalue() == ('::\n\n localhost: RSYNC ==> '
'/foo/bar\n\n')

View File

@ -4,38 +4,16 @@
import py
from py.__.test.rsession import report
from py.__.test.rsession.rsession import RSession, parse_directories,\
parse_directories
from py.__.test.rsession.hostmanage import HostOptions, HostManager,\
HostInfo
from py.__.test.rsession.rsession import RSession
from py.__.test.rsession.hostmanage import HostManager, HostInfo
from py.__.test.rsession.testing.test_slave import funcfail_spec,\
funcpass_spec, funcskip_spec, funcprint_spec, funcprintfail_spec, \
funcoptioncustom_spec
def setup_module(mod):
mod.pkgdir = py.path.local(py.__file__).dirpath()
mod.tmpdir = py.test.ensuretemp(mod.__name__)
def test_setup_non_existing_hosts():
setup_events = []
hosts = [HostInfo("alskdjalsdkjasldkajlsd")]
config = py.test.config._reparse([])
hm = HostManager(hosts, config)
cmd = "hm.init_hosts(setup_events.append)"
py.test.raises((py.process.cmdexec.Error, IOError, EOFError), cmd)
#assert setup_events
def test_getpkdir():
one = pkgdir.join("initpkg.py")
two = pkgdir.join("path", "__init__.py")
p1 = RSession.getpkgdir(one)
p2 = RSession.getpkgdir(two)
assert p1 == p2
assert p1 == pkgdir
def test_getpkdir_no_inits():
tmp = py.test.ensuretemp("getpkdir1")
fn = tmp.ensure("hello.py")
assert RSession.getpkgdir(fn) == fn
#def test_make_colitems():
# one = pkgdir.join("initpkg.py")
@ -74,10 +52,11 @@ def test_example_tryiter():
class TestRSessionRemote:
def test_example_distribution_minus_x(self):
destdir = py.test.ensuretemp("example_dist_dest_x")
tmpdir = py.test.ensuretemp("example_distribution_minus_x")
tmpdir.ensure("sub", "conftest.py").write(py.code.Source("""
dist_hosts = [%r]
""" % ('localhost',)))
dist_hosts = ['localhost:%s']
""" % destdir))
tmpdir.ensure("sub", "__init__.py")
tmpdir.ensure("sub", "test_one.py").write(py.code.Source("""
def test_1():
@ -92,8 +71,7 @@ class TestRSessionRemote:
def test_4(someargs):
pass
"""))
args = [str(tmpdir.join("sub")), "-x"]
config = py.test.config._reparse(args)
config = py.test.config._reparse([tmpdir.join("sub"), '-x'])
rsession = RSession(config)
allevents = []
rsession.main(reporter=allevents.append)
@ -102,13 +80,14 @@ class TestRSessionRemote:
assert len(testevents) == 3
assert rsession.checkfun()
def test_example_distribution(self):
def test_distribution_rsync_roots_example(self):
destdir = py.test.ensuretemp("example_dist_destdir")
subdir = "sub_example_dist"
tmpdir = py.test.ensuretemp("example_distribution")
tmpdir.ensure(subdir, "conftest.py").write(py.code.Source("""
dist_hosts = [%r]
dist_hosts = ["localhost:%s"]
dist_rsync_roots = ["%s", "../py"]
""" % ('localhost', tmpdir.join(subdir), )))
""" % (destdir, tmpdir.join(subdir), )))
tmpdir.ensure(subdir, "__init__.py")
tmpdir.ensure(subdir, "test_one.py").write(py.code.Source("""
def test_1():
@ -124,16 +103,18 @@ class TestRSessionRemote:
def test_6():
import py
assert py.__file__ != '%s'
""" % (str(tmpdir.join(subdir)), py.__file__)))
tmpdir.join("py").mksymlinkto(py.path.local(py.__file__).dirpath())
args = [str(tmpdir.join(subdir))]
config = py.test.config._reparse(args)
rsession = RSession(config, optimise_localhost=False)
""" % (tmpdir.join(subdir), py.__file__)))
destdir.join("py").mksymlinkto(py.path.local(py.__file__).dirpath())
config = py.test.config._reparse([tmpdir.join(subdir)])
assert config.topdir == tmpdir
assert not tmpdir.join("__init__.py").check()
rsession = RSession(config)
allevents = []
rsession.main(reporter=allevents.append)
testevents = [x for x in allevents
if isinstance(x, report.ReceivedItemOutcome)]
assert len(testevents)
print testevents
passevents = [i for i in testevents if i.outcome.passed]
failevents = [i for i in testevents if i.outcome.excinfo]
skippedevents = [i for i in testevents if i.outcome.skipped]
@ -156,13 +137,11 @@ class TestRSessionRemote:
def test_setup_teardown_ssh(self):
hosts = [HostInfo('localhost')]
parse_directories(hosts)
setup_events = []
teardown_events = []
config = py.test.config._reparse([])
opts = HostOptions(optimise_localhost=False)
hm = HostManager(hosts, config, opts)
config = py.test.config._reparse([tmpdir])
hm = HostManager(hosts, config)
nodes = hm.init_hosts(setup_events.append)
hm.teardown_hosts(teardown_events.append,
[node.channel for node in nodes], nodes)
@ -184,12 +163,10 @@ class TestRSessionRemote:
def test_setup_teardown_run_ssh(self):
hosts = [HostInfo('localhost')]
parse_directories(hosts)
allevents = []
config = py.test.config._reparse([])
opts = HostOptions(optimise_localhost=False)
hm = HostManager(hosts, config, opts)
hm = HostManager(hosts, config)
nodes = hm.init_hosts(allevents.append)
from py.__.test.rsession.testing.test_executor \
@ -223,47 +200,11 @@ class TestRSessionRemote:
passed_stdout = [i for i in passed if i.outcome.stdout.find('samfing') != -1]
assert len(passed_stdout) == len(nodes), passed
def test_config_pass(self):
""" Tests options object passing master -> server
"""
allevents = []
hosts = [HostInfo('localhost')]
parse_directories(hosts)
config = py.test.config._reparse([])
config._overwrite('custom', 'custom')
# we need to overwrite default list to serialize
from py.__.test.rsession.master import defaultconftestnames
defaultconftestnames.append("custom")
try:
opts = HostOptions(optimise_localhost=False)
hm = HostManager(hosts, config, opts)
nodes = hm.init_hosts(allevents.append)
rootcol = py.test.collect.Directory(pkgdir.dirpath())
itempass = rootcol._getitembynames(funcoptioncustom_spec)
for node in nodes:
node.send(itempass)
hm.teardown_hosts(allevents.append, [node.channel for node in nodes], nodes)
events = [i for i in allevents
if isinstance(i, report.ReceivedItemOutcome)]
passed = [i for i in events
if i.outcome.passed]
skipped = [i for i in events
if i.outcome.skipped]
assert len(passed) == 1 * len(nodes)
assert len(skipped) == 0
assert len(events) == len(passed)
finally:
defaultconftestnames.remove("custom")
def test_nice_level(self):
""" Tests if nice level behaviour is ok
"""
allevents = []
hosts = [HostInfo('localhost')]
parse_directories(hosts)
tmpdir = py.test.ensuretemp("nice")
tmpdir.ensure("__init__.py")
tmpdir.ensure("conftest.py").write(py.code.Source("""
@ -283,45 +224,6 @@ class TestRSessionRemote:
if isinstance(x, report.ReceivedItemOutcome)]
passevents = [x for x in testevents if x.outcome.passed]
assert len(passevents) == 1
class XxxTestDirectories(object):
# need complete rewrite, and unsure if it makes sense at all
def test_simple_parse(self):
sshhosts = [HostInfo(i) for i in ['h1', 'h2', 'h3']]
parse_directories(sshhosts)
def test_sophisticated_parse(self):
sshhosts = ['a@h1:/tmp', 'h2:tmp', 'h3']
dirs = parse_directories(sshhosts)
assert py.builtin.sorted(
dirs.values()) == ['/tmp', 'pytestcache', 'tmp']
def test_parse_multiple_hosts(self):
hosts = ['h1', 'h1', 'h1:/tmp']
dirs = parse_directories(hosts)
assert dirs == {(0, 'h1'): 'pytestcache', (1, 'h1'): 'pytestcache',
(2, 'h1'):'/tmp'}
class TestInithosts(object):
def test_inithosts(self):
testevents = []
hostnames = ['h1:/tmp', 'h1:/tmp', 'h1:/other', 'h2', 'h2:home']
hosts = [HostInfo(i) for i in hostnames]
parse_directories(hosts)
config = py.test.config._reparse([])
opts = HostOptions(do_sync=False, create_gateways=False)
hm = HostManager(hosts, config, opts)
nodes = hm.init_hosts(testevents.append)
events = [i for i in testevents if isinstance(i, report.HostRSyncing)]
assert len(events) == 4
assert events[0].host.hostname == 'h1'
assert events[0].host.relpath == '/tmp-h1'
assert events[1].host.hostname == 'h1'
assert events[1].host.relpath == '/other-h1'
assert events[2].host.hostname == 'h2'
assert events[2].host.relpath == 'pytestcache-h2'
assert events[3].host.hostname == 'h2'
assert events[3].host.relpath == 'home-h2'
def test_rsession_no_disthost():
tmpdir = py.test.ensuretemp("rsession_no_disthost")

View File

@ -1,30 +0,0 @@
""" RSync filter test
"""
import py
from py.__.test.rsession.hostmanage import HostRSync
def test_rsync():
tmpdir = py.test.ensuretemp("rsync_rsession")
tmpdir.ensure("a", dir=True)
tmpdir.ensure("b", dir=True)
tmpdir.ensure("conftest.py").write(py.code.Source("""
dist_rsyncroots = ['a']
"""))
tmpdir.join("a").ensure("x")
adir = tmpdir.join("a").ensure("xy", dir=True)
adir.ensure("conftest.py").write(py.code.Source("""
dist_rsyncroots = ['b', 'conftest.py']
"""))
adir.ensure("a", dir=True)
adir.ensure("b", dir=True)
config = py.test.config._reparse([str(tmpdir)])
h = HostRSync(config)
h.sourcedir = config.topdir
assert h.filter(str(tmpdir.join("a")))
assert not h.filter(str(tmpdir.join("b")))
assert h.filter(str(tmpdir.join("a").join("x")))
assert h.filter(str(adir.join("conftest.py")))
assert not h.filter(str(adir.join("a")))
assert h.filter(str(adir.join("b")))

View File

@ -11,6 +11,7 @@ if sys.platform == 'win32':
py.test.skip("rsession is unsupported on Windows.")
def setup_module(module):
module.tmpdir = py.test.ensuretemp(module.__name__)
module.rootdir = py.path.local(py.__file__).dirpath().dirpath()
module.rootcol = py.test.collect.Directory(rootdir)
@ -107,64 +108,11 @@ def test_slave_run_failing_wrapped():
assert not outcome.setupfailure
assert outcome.excinfo
def test_slave_main_simple():
res = []
failitem = rootcol._getitembynames(funcfail_spec)
passitem = rootcol._getitembynames(funcpass_spec)
q = [None,
passitem._get_collector_trail(),
failitem._get_collector_trail()
]
config = py.test.config._reparse([])
pidinfo = PidInfo()
slave_main(q.pop, res.append, str(rootdir), config, pidinfo)
assert len(res) == 2
res_repr = [ReprOutcome(r) for r in res]
assert not res_repr[0].passed and res_repr[1].passed
def test_slave_run_different_stuff():
node = gettestnode()
node.run(rootcol._getitembynames("py doc log.txt".split()).
_get_collector_trail())
def test_slave_setup_exit():
tmp = py.test.ensuretemp("slaveexit")
tmp.ensure("__init__.py")
q = py.std.Queue.Queue()
config = py.test.config._reparse([tmp])
class C:
res = []
def __init__(self):
self.q = [str(tmp),
config.make_repr(conftestnames=['dist_nicelevel']),
funchang_spec,
42,
funcpass_spec]
self.q.reverse()
def receive(self):
return self.q.pop()
def setcallback(self, callback):
import thread
def f():
while 1:
callback(self.q.pop())
f()
#thread.start_new_thread(f, ())
def close(self):
pass
send = res.append
try:
exec py.code.Source(setup, "setup()").compile() in {'channel':C()}
except SystemExit:
pass
else:
py.test.fail("Did not exit")
def test_pidinfo():
if not hasattr(os, 'fork') or not hasattr(os, 'waitpid'):
py.test.skip("Platform does not support fork")