Skip to content

Cleanup code not executing in fixture #3409

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
zmitchell opened this issue Apr 19, 2018 · 7 comments
Closed

Cleanup code not executing in fixture #3409

zmitchell opened this issue Apr 19, 2018 · 7 comments
Labels
type: question general question, might be closed after 2 weeks of inactivity

Comments

@zmitchell
Copy link

I'm having a problem with things executing out of order in a fixture. I'm using socat to create a pair of virtual serial ports so that I can test some code that interacts with serial devices. socat needs to be running the whole time the test is run, so I use a fixture to start it in a separate process. The issue is that if I don't wait at the beginning of the test the ports aren't open by the time the test runs. If I wait first, the test passes. In either case the socat process isn't terminated, even though I'm calling terminate on the process. Here is the code:

@pytest.fixture
def socat():
    proc = Process(target=socat_command)
    proc.start()
    yield None
    proc.terminate()
    proc.join()

def socat_command():
    os.system("socat pty,rawer,echo=0,link=/tmp/port1 pty,rawer,echo=0,link=/tmp/port2")

def test_can_connect_to_port(socat):
    # time.sleep(0.5)
    settings = {"port": "/tmp/port1", "baudrate": "115200"}
    lia = LockInAmplifier(port_settings=settings)
    trio.run(lia.connect)
    assert lia._ser is not None

Why isn't the process terminated at the end? Is there a better way to do this? I want a fresh set of ports for each test so that the input/output buffers are always clean. I feel like this is just something I'm doing wrong or misunderstanding, so hopefully you can point me in the right direction.

These are the versions pinned in my Pipfile.lock:

pytest==3.5.0
pydoc-markdown==2.0.2
pre-commit==1.8.2
hypothesis==3.55.6
flake8==3.5.0
black==18.4a2
attrs==17.4.0
trio==0.4.0
pyserial==3.4
logzero==1.5.0

I'm on macOS 10.13.3.

@pytestbot
Copy link
Contributor

GitMate.io thinks possibly related issues are #517 (setup_* executed before all fixtures), #832 (some codes are not executed.), #3032 (Teardown for parametrized module scope fixtures is not executed in the teardown phase), #1907 (Cleanup MANIFEST.in), and #1895 (Incorrect finalize/cleanup order of fixtures when using request.getfixturevalue()).

@RonnyPfannschmidt
Copy link
Member

i guess that you use a multiprocessing process

then what you do is completely broken and cant possibly work, as you terminate he python process,
your parent "pytest" process will take ownership of the socat process

if all you need is to run socat and terminate it, just use a subprocess.Popen object directly,
if you need more, you will need a more detailed setup

@RonnyPfannschmidt RonnyPfannschmidt added the type: question general question, might be closed after 2 weeks of inactivity label Apr 19, 2018
@zmitchell
Copy link
Author

Yes, I'm using multiprocessing.Process to run socat in the background. If I understand you correctly, my problem is that I kill the Python process, not the socat process, so nothing is actually terminating the socat process.

Using Popen cleans up afterwards, which is an improvement, but I still have to add a time.sleep(...) at the beginning of the test to make it work properly. I'm guessing that's because socat takes some time to set itself up after it starts, but all Python knows is that socat has started.

@RonnyPfannschmidt
Copy link
Member

i strongly suggest to do a socket connection based wait in the fixture after the popen call

@zmitchell
Copy link
Author

Maybe there’s a misunderstanding, but I’m not using socat for sockets, I’m using it for serial ports.

@RonnyPfannschmidt
Copy link
Member

thanks for pointing that out, i indeed missed the finer details of the cli args

@Zac-HD
Copy link
Member

Zac-HD commented Oct 19, 2018

A try...finally clause might also help:

@pytest.fixture
def socat():
    proc = Process(target=socat_command)
    proc.start()
    try:
        yield None
    finally:
        proc.terminate()
        proc.join()

@Zac-HD Zac-HD closed this as completed Oct 19, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: question general question, might be closed after 2 weeks of inactivity
Projects
None yet
Development

No branches or pull requests

4 participants