import py from xdist.looponfail import RemoteControl from xdist.looponfail import StatRecorder class TestStatRecorder: def test_filechange(self, tmpdir): tmp = tmpdir hello = tmp.ensure("hello.py") sd = StatRecorder([tmp]) changed = sd.check() assert not changed hello.write("world") changed = sd.check() assert changed (hello + "c").write("hello") changed = sd.check() assert not changed p = tmp.ensure("new.py") changed = sd.check() assert changed p.remove() changed = sd.check() assert changed tmp.join("a", "b", "c.py").ensure() changed = sd.check() assert changed tmp.join("a", "c.txt").ensure() changed = sd.check() assert changed changed = sd.check() assert not changed tmp.join("a").remove() changed = sd.check() assert changed def test_dirchange(self, tmpdir): tmp = tmpdir tmp.ensure("dir", "hello.py") sd = StatRecorder([tmp]) assert not sd.fil(tmp.join("dir")) def test_filechange_deletion_race(self, tmpdir, monkeypatch): tmp = tmpdir sd = StatRecorder([tmp]) changed = sd.check() assert not changed p = tmp.ensure("new.py") changed = sd.check() assert changed p.remove() # make check()'s visit() call return our just removed # path as if we were in a race condition monkeypatch.setattr(tmp, 'visit', lambda *args: [p]) changed = sd.check() assert changed def test_pycremoval(self, tmpdir): tmp = tmpdir hello = tmp.ensure("hello.py") sd = StatRecorder([tmp]) changed = sd.check() assert not changed pycfile = hello + "c" pycfile.ensure() hello.write("world") changed = sd.check() assert changed assert not pycfile.check() def test_waitonchange(self, tmpdir, monkeypatch): tmp = tmpdir sd = StatRecorder([tmp]) l = [True, False] monkeypatch.setattr(StatRecorder, 'check', lambda self: l.pop()) sd.waitonchange(checkinterval=0.2) assert not l class TestRemoteControl: def test_nofailures(self, testdir): item = testdir.getitem("def test_func(): pass\n") control = RemoteControl(item.config) control.setup() topdir, failures = control.runsession()[:2] assert not failures def test_failures_somewhere(self, testdir): item = testdir.getitem("def test_func():\n assert 0\n") control = RemoteControl(item.config) control.setup() failures = control.runsession() assert failures control.setup() item.fspath.write("def test_func():\n assert 1\n") removepyc(item.fspath) topdir, failures = control.runsession()[:2] assert not failures def test_failure_change(self, testdir): modcol = testdir.getitem(""" def test_func(): assert 0 """) control = RemoteControl(modcol.config) control.loop_once() assert control.failures modcol.fspath.write(py.code.Source(""" def test_func(): assert 1 def test_new(): assert 0 """)) removepyc(modcol.fspath) control.loop_once() assert not control.failures control.loop_once() assert control.failures assert str(control.failures).find("test_new") != -1 def test_failure_subdir_no_init(self, testdir): modcol = testdir.getitem(""" def test_func(): assert 0 """) parent = modcol.fspath.dirpath().dirpath() parent.chdir() modcol.config.args = [py.path.local(x).relto(parent) for x in modcol.config.args] control = RemoteControl(modcol.config) control.loop_once() assert control.failures control.loop_once() assert control.failures class TestLooponFailing: def test_looponfail_from_fail_to_ok(self, testdir): modcol = testdir.getmodulecol(""" def test_one(): x = 0 assert x == 1 def test_two(): assert 1 """) remotecontrol = RemoteControl(modcol.config) remotecontrol.loop_once() assert len(remotecontrol.failures) == 1 modcol.fspath.write(py.code.Source(""" def test_one(): assert 1 def test_two(): assert 1 """)) removepyc(modcol.fspath) remotecontrol.loop_once() assert not remotecontrol.failures def test_looponfail_from_one_to_two_tests(self, testdir): modcol = testdir.getmodulecol(""" def test_one(): assert 0 """) remotecontrol = RemoteControl(modcol.config) remotecontrol.loop_once() assert len(remotecontrol.failures) == 1 assert 'test_one' in remotecontrol.failures[0] modcol.fspath.write(py.code.Source(""" def test_one(): assert 1 # passes now def test_two(): assert 0 # new and fails """)) removepyc(modcol.fspath) remotecontrol.loop_once() assert len(remotecontrol.failures) == 0 remotecontrol.loop_once() assert len(remotecontrol.failures) == 1 assert 'test_one' not in remotecontrol.failures[0] assert 'test_two' in remotecontrol.failures[0] def test_looponfail_removed_test(self, testdir): modcol = testdir.getmodulecol(""" def test_one(): assert 0 def test_two(): assert 0 """) remotecontrol = RemoteControl(modcol.config) remotecontrol.loop_once() assert len(remotecontrol.failures) == 2 modcol.fspath.write(py.code.Source(""" def test_xxx(): # renamed test assert 0 def test_two(): assert 1 # pass now """)) removepyc(modcol.fspath) remotecontrol.loop_once() assert len(remotecontrol.failures) == 0 remotecontrol.loop_once() assert len(remotecontrol.failures) == 1 def test_looponfail_multiple_errors(self, testdir, monkeypatch): modcol = testdir.getmodulecol(""" def test_one(): assert 0 """) remotecontrol = RemoteControl(modcol.config) orig_runsession = remotecontrol.runsession def runsession_dups(): # twisted.trial test cases may report multiple errors. failures, reports, collection_failed = orig_runsession() print (failures) return failures * 2, reports, collection_failed monkeypatch.setattr(remotecontrol, 'runsession', runsession_dups) remotecontrol.loop_once() assert len(remotecontrol.failures) == 1 class TestFunctional: def test_fail_to_ok(self, testdir): p = testdir.makepyfile(""" def test_one(): x = 0 assert x == 1 """) #p = testdir.mkdir("sub").join(p1.basename) #p1.move(p) child = testdir.spawn_pytest("-f %s --traceconfig" % p) child.expect("def test_one") child.expect("x == 1") child.expect("1 failed") child.expect("### LOOPONFAILING ####") child.expect("waiting for changes") p.write(py.code.Source(""" def test_one(): x = 1 assert x == 1 """)) child.expect(".*1 passed.*") child.kill(15) def test_xfail_passes(self, testdir): p = testdir.makepyfile(""" import py @py.test.mark.xfail def test_one(): pass """) child = testdir.spawn_pytest("-f %s" % p) child.expect("1 xpass") child.expect("### LOOPONFAILING ####") child.expect("waiting for changes") child.kill(15) def removepyc(path): # XXX damn those pyc files pyc = path + "c" if pyc.check(): pyc.remove() c = path.dirpath("__pycache__") if c.check(): c.remove()