From d12136d44d1142944f42de3b2f619bcca5a08166 Mon Sep 17 00:00:00 2001 From: Tyler Goodlet Date: Sat, 8 Sep 2018 09:44:29 -0400 Subject: [PATCH] Add some mult-program tests Run the arbiter-actor in a separate program and do some basic tests to make sure everything works - particularly, registration and cancellation. --- tests/conftest.py | 1 + tests/test_multi_program.py | 77 +++++++++++++++++++++++++++++++++++++ 2 files changed, 78 insertions(+) create mode 100644 tests/test_multi_program.py diff --git a/tests/conftest.py b/tests/conftest.py index 9822a65..5226305 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -8,6 +8,7 @@ import pytest import tractor +pytest_plugins = ['pytester'] _arb_addr = '127.0.0.1', random.randint(1000, 9999) diff --git a/tests/test_multi_program.py b/tests/test_multi_program.py new file mode 100644 index 0000000..6a3a347 --- /dev/null +++ b/tests/test_multi_program.py @@ -0,0 +1,77 @@ +""" +Multiple python programs invoking ``tractor.run()`` +""" +import sys +import time +import signal +import subprocess + +import pytest +import tractor + + +from conftest import tractor_test + + +def sig_prog(proc, sig): + "Kill the actor-process with ctr-c." + proc.send_signal(sig) + ret = proc.wait() + assert ret + + +@pytest.fixture +def daemon(loglevel, testdir, arb_addr): + cmdargs = [ + sys.executable, '-c', + "import tractor; tractor.run_daemon(arbiter_addr={}, loglevel={})" + .format( + arb_addr, + "'{}'".format(loglevel) if loglevel else None) + ] + proc = testdir.popen( + cmdargs, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + ) + assert not proc.returncode + time.sleep(0.2) + yield proc + # TODO: why sometimes does SIGINT not work on teardown? + sig_prog(proc, signal.SIGINT) + + +def test_abort_on_sigint(daemon): + assert daemon.returncode is None + time.sleep(0.1) + sig_prog(daemon, signal.SIGINT) + assert daemon.returncode == 1 + # XXX: oddly, couldn't get capfd.readouterr() to work here? + assert "KeyboardInterrupt" in str(daemon.stderr.read()) + + +@tractor_test +async def test_cancel_remote_arbiter(daemon, arb_addr): + async with tractor.get_arbiter(*arb_addr) as portal: + await portal.cancel_actor() + + time.sleep(0.1) + # the arbiter channel server is cancelled but not its main task + assert daemon.returncode is None + + # no arbiter socket should exist + with pytest.raises(OSError): + async with tractor.get_arbiter(*arb_addr) as portal: + pass + + +@tractor_test +async def test_register_duplicate_name(daemon): + async with tractor.open_nursery() as n: + p1 = await n.start_actor('doggy') + p2 = await n.start_actor('doggy') + + async with tractor.wait_for_actor('doggy') as portal: + assert portal.channel.uid in (p2.channel.uid, p1.channel.uid) + + await n.cancel()