diff --git a/py/test/config.py b/py/test/config.py index 5f0f4cd6c..019101178 100644 --- a/py/test/config.py +++ b/py/test/config.py @@ -26,6 +26,7 @@ class Config(object): """ central bus for dealing with configuration/initialization data. """ Option = py.compat.optparse.Option # deprecated _initialized = False + _sessionclass = None def __init__(self, pytestplugins=None): self.option = CmdOptions() @@ -79,7 +80,6 @@ class Config(object): self.topdir = py.path.local(topdir) self._mergerepr(self._repr) del self._repr - self.pytestplugins.configure(config=self) def _makerepr(self): l = [] @@ -155,40 +155,19 @@ class Config(object): except AttributeError: return self._conftest.rget(name, path) + def setsessionclass(self, cls): + if self._sessionclass is not None: + raise ValueError("sessionclass already set to: %r" %( + self._sessionclass)) + self._sessionclass = cls + def initsession(self): """ return an initialized session object. """ - cls = self._getsessionclass() - session = cls(self) - session.fixoptions() - return session - - def _getsessionclass(self): - """ return Session class determined from cmdline options - and looked up in initial config modules. - """ - if self.option.session is not None: - return self._conftest.rget(self.option.session) - else: - name = self._getsessionname() - try: - return self._conftest.rget(name) - except KeyError: - pass - importpath = globals()[name] - mod = __import__(importpath, None, None, '__doc__') - return getattr(mod, name) - - def _getsessionname(self): - """ return default session name as determined from options. """ - if self.option.collectonly: - name = 'Session' - elif self.option.looponfailing: - name = 'LooponfailingSession' - elif self.option.numprocesses or self.option.dist or self.option.executable: - name = 'DSession' - else: - name = 'Session' - return name + cls = self._sessionclass + if cls is None: + from py.__.test.session import Session + cls = Session + return cls(self) def _reparse(self, args): """ this is used from tests that want to re-invoke parse(). """ @@ -222,12 +201,6 @@ config_per_process = Config( pytestplugins=py.test._PytestPlugins(py._com.pyplugins) ) -# default import paths for sessions - -Session = 'py.__.test.session' -LooponfailingSession = 'py.__.test.looponfail.remote' -DSession = 'py.__.test.dsession.dsession' - # # helpers # diff --git a/py/test/dsession/dsession.py b/py/test/dsession/dsession.py index 95bf27979..b25f9a31f 100644 --- a/py/test/dsession/dsession.py +++ b/py/test/dsession/dsession.py @@ -41,6 +41,9 @@ class DSession(Session): self.host2pending = {} self.item2host = {} self._testsfailed = False + if self.config.getvalue("executable") and \ + not self.config.getvalue("numprocesses"): + self.config.option.numprocesses = 1 def fixoptions(self): """ check, fix and determine conflicting options. """ diff --git a/py/test/dsession/masterslave.py b/py/test/dsession/masterslave.py index ee4e8e8d9..382b780c3 100644 --- a/py/test/dsession/masterslave.py +++ b/py/test/dsession/masterslave.py @@ -113,6 +113,7 @@ class SlaveNode(object): self.channel.send((eventname, args, kwargs)) def run(self): + self.config.pytestplugins.configure(self.config) from py.__.test.dsession.hostmanage import makehostup channel = self.channel self.host = host = channel.receive() diff --git a/py/test/dsession/testing/test_dsession.py b/py/test/dsession/testing/test_dsession.py index edf8df677..73900b1a9 100644 --- a/py/test/dsession/testing/test_dsession.py +++ b/py/test/dsession/testing/test_dsession.py @@ -26,6 +26,7 @@ def dumpqueue(queue): class TestDSession: def test_fixoptions(self, testdir): config = testdir.parseconfig("--exec=xxx") + config.pytestplugins.configure(config) config.initsession().fixoptions() assert config.option.numprocesses == 1 config = testdir.parseconfig("--exec=xxx", '-n3') diff --git a/py/test/dsession/testing/test_functional_dsession.py b/py/test/dsession/testing/test_functional_dsession.py index 8bdc00902..05bb90680 100644 --- a/py/test/dsession/testing/test_functional_dsession.py +++ b/py/test/dsession/testing/test_functional_dsession.py @@ -11,10 +11,6 @@ import os class TestAsyncFunctional: - def test_dist_no_disthost(self, testdir): - config = testdir.parseconfig(testdir.tmpdir, '-d') - py.test.raises(SystemExit, "config.initsession()") - def test_conftest_options(self, testdir): testdir.makepyfile(conftest=""" print "importing conftest" diff --git a/py/test/looponfail/remote.py b/py/test/looponfail/remote.py index 39172b3e9..19c0cb150 100644 --- a/py/test/looponfail/remote.py +++ b/py/test/looponfail/remote.py @@ -129,7 +129,7 @@ def slave_runsession(channel, config, fullwidth, hasmarkup): config.option.usepdb = False config.option.executable = None trails = channel.receive() - + config.pytestplugins.configure(config) DEBUG("SLAVE: initsession()") session = config.initsession() # XXX configure the reporter object's terminal writer more directly diff --git a/py/test/plugin/pytest_default.py b/py/test/plugin/pytest_default.py index 25d6fec5c..714f99a26 100644 --- a/py/test/plugin/pytest_default.py +++ b/py/test/plugin/pytest_default.py @@ -1,3 +1,5 @@ +import py + class DefaultPlugin: """ Plugin implementing defaults and general options. """ @@ -72,12 +74,40 @@ class DefaultPlugin: action="store_true", dest="runbrowser", default=False, help="run browser (implies --startserver)." ), - group._addoption('', '--boxed', + group._addoption('--boxed', action="store_true", dest="boxed", default=False, help="box each test run in a separate process"), - group._addoption('', '--rest', + group._addoption('--rest', action='store_true', dest="restreport", default=False, help="restructured text output reporting."), - group._addoption('', '--session', - action="store", dest="session", default=None, - help="lookup given sessioname in conftest.py files and use it."), + + def pytest_configure(self, config): + self.setsession(config) + + def setsession(self, config): + val = config.getvalue + if val("collectonly"): + from py.__.test.session import Session + config.setsessionclass(Session) + elif val("looponfailing"): + from py.__.test.looponfail.remote import LooponfailingSession + config.setsessionclass(LooponfailingSession) + elif val("numprocesses") or val("dist") or val("executable"): + from py.__.test.dsession.dsession import DSession + config.setsessionclass(DSession) + +def test_implied_different_sessions(tmpdir): + def x(*args): + config = py.test.config._reparse([tmpdir] + list(args)) + try: + config.pytestplugins.configure(config) + except ValueError: + return Exception + return getattr(config._sessionclass, '__name__', None) + assert x() == None + assert x('--dist') == 'DSession' + assert x('-n3') == 'DSession' + assert x('-f') == 'LooponfailingSession' + assert x('--exec=x') == 'DSession' + assert x('-f', '--exec=x') == 'LooponfailingSession' + assert x('--dist', '--exec=x', '--collectonly') == 'Session' diff --git a/py/test/testing/test_config.py b/py/test/testing/test_config.py index d6088c465..21dbd4936 100644 --- a/py/test/testing/test_config.py +++ b/py/test/testing/test_config.py @@ -1,20 +1,6 @@ import py -pytest_plugins = 'pytest_iocapture' - class TestConfigCmdlineParsing: - @py.test.mark(xfail="commit parser") - def test_config_addoption(self, stdcapture): - from py.__.test.config import Config - config = Config() - config.addoption("cat1", "--option1", action="store_true") - config.addoption("cat1", "--option2", action="store_true") - config.parse(["-h"]) - out, err = stdcapture.reset() - assert out.count("cat1") == 1 - assert out.find("option1") != -1 - assert out.find("option2") != -1 - def test_config_cmdline_options(self, testdir): testdir.makepyfile(conftest=""" import py @@ -71,9 +57,8 @@ class TestConfigCmdlineParsing: opts = spec.split() yield check_conflict_option, opts - class TestConfigAPI: - @py.test.mark(issue="ensuretemp should call config.maketemp(basename)") + @py.test.mark.issue("ensuretemp should call config.maketemp(basename)") def test_tmpdir(self): d1 = py.test.ensuretemp('hello') d2 = py.test.ensuretemp('hello') @@ -120,6 +105,20 @@ class TestConfigAPI: pl = config.getvalue_pathlist('mypathlist') assert pl == [py.path.local()] + def test_setsessionclass_and_initsession(self, testdir): + from py.__.test.config import Config + config = Config() + class Session1: + def __init__(self, config): + self.config = config + config.setsessionclass(Session1) + session = config.initsession() + assert isinstance(session, Session1) + assert session.config is config + py.test.raises(ValueError, "config.setsessionclass(Session1)") + + + class TestConfigApi_getcolitems: def test_getcolitems_onedir(self, tmpdir): config = py.test.config._reparse([tmpdir]) @@ -395,63 +394,21 @@ class TestConfigPickling: assert newcol2.fspath.basename == dir1.basename assert newcol2.fspath.relto(topdir) -class TestSessionAndOptions: - def test_implied_dsession(self, testdir): - for x in 'startserver runbrowser rest'.split(): - config = testdir.parseconfig(testdir.tmpdir, '--dist', '--%s' % x) - assert config._getsessionname() == 'DSession' +def test_options_on_small_file_do_not_blow_up(testdir): + def runfiletest(opts): + sorter = testdir.inline_run(*opts) + passed, skipped, failed = sorter.countoutcomes() + assert failed == 2 + assert skipped == passed == 0 + path = testdir.makepyfile(""" + def test_f1(): assert 0 + def test_f2(): assert 0 + """) - def test_implied_different_sessions(self, tmpdir): - config = py.test.config._reparse([tmpdir]) - assert config._getsessionname() == 'Session' - config = py.test.config._reparse([tmpdir, '--dist']) - assert config._getsessionname() == 'DSession' - config = py.test.config._reparse([tmpdir, '-n3']) - assert config._getsessionname() == 'DSession' - config = py.test.config._reparse([tmpdir, '--looponfailing']) - assert config._getsessionname() == 'LooponfailingSession' - config = py.test.config._reparse([tmpdir, '--exec=x']) - assert config._getsessionname() == 'DSession' - config = py.test.config._reparse([tmpdir, '--dist', '--exec=x']) - assert config._getsessionname() == 'DSession' - config = py.test.config._reparse([tmpdir, '-f', - '--dist', '--exec=x']) - assert config._getsessionname() == 'LooponfailingSession' - config = py.test.config._reparse([tmpdir, '-f', '-n3', - '--dist', '--exec=x', - '--collectonly']) - assert config._getsessionname() == 'Session' - - def test_sessionname_lookup_custom(self, testdir): - testdir.makepyfile(conftest=""" - from py.__.test.session import Session - class MySession(Session): - pass - """) - config = testdir.parseconfig("--session=MySession", testdir.tmpdir) - session = config.initsession() - assert session.__class__.__name__ == 'MySession' - - def test_initsession(self, tmpdir): - config = py.test.config._reparse([tmpdir]) - session = config.initsession() - assert session.config is config - - def test_default_session_options(self, testdir): - def runfiletest(opts): - sorter = testdir.inline_run(*opts) - passed, skipped, failed = sorter.countoutcomes() - assert failed == 2 - assert skipped == passed == 0 - path = testdir.makepyfile(""" - def test_f1(): assert 0 - def test_f2(): assert 0 - """) - - for opts in ([], ['-l'], ['-s'], ['--tb=no'], ['--tb=short'], - ['--tb=long'], ['--fulltrace'], ['--nomagic'], - ['--traceconfig'], ['-v'], ['-v', '-v']): - runfiletest(opts + [path]) + for opts in ([], ['-l'], ['-s'], ['--tb=no'], ['--tb=short'], + ['--tb=long'], ['--fulltrace'], ['--nomagic'], + ['--traceconfig'], ['-v'], ['-v', '-v']): + runfiletest(opts + [path]) def test_default_bus(): assert py.test.config.bus is py._com.pyplugins diff --git a/py/test/testing/test_session.py b/py/test/testing/test_session.py index 939a3fef2..0a5c4de2d 100644 --- a/py/test/testing/test_session.py +++ b/py/test/testing/test_session.py @@ -1,6 +1,11 @@ import py class SessionTests: + def test_initsession(self, tmpdir): + config = py.test.config._reparse([tmpdir]) + session = config.initsession() + assert session.config is config + def test_basic_testitem_events(self, testdir): tfile = testdir.makepyfile(""" def test_one():