pytest: Tests run when called by name but seg fault when part of a collection

Hi,

I’m running the python3-pytest package of Ubuntu 18.04, v3.3.2-2, with cov-2.5.1 from a package and faulthandler-1.5.0 from pip. (I’m not using a virtual environment.) The application I am testing makes extensive use of gevent. This has worked well until now but today, when refactoring my tests to move the startup/teardown code to a module, I’m getting seg faults.

I’ve tried to isolate the issue, and it seems to be something around pytest teardown after the last test in a collection, ie

  • running one test by name works
  • running all the tests in a file seg faults (after successful completion of all tests)
  • running one test by mark also seg faults (after successful completion of that test).

ie

$ pytest-3 test_app_cancel_upload.py -m crash_when_marked -v
===================================================================== test session starts ======================================================================
platform linux -- Python 3.6.5, pytest-3.3.2, py-1.5.2, pluggy-0.6.0 -- /usr/bin/python3
cachedir: ../../.cache
rootdir: /home/mark/dbl-uploader-clients/dbl_dot_local, inifile: pytest.ini
plugins: faulthandler-1.5.0, cov-2.5.1
collected 5 items                                                                                                                                              

test_app_cancel_upload.py::test_cancel_upload_jobs PASSED                                                                                                [100%]

====================================================================== 4 tests deselected ======================================================================
=========================================================== 1 passed, 4 deselected in 10.47 seconds ============================================================
Fatal Python error: Segmentation fault

Current thread 0x00007fe73c7eb740 (most recent call first):
Erreur de segmentation (core dumped)
$ pytest-3 test_app_cancel_upload.py::test_cancel_upload_jobs -v
===================================================================== test session starts ======================================================================
platform linux -- Python 3.6.5, pytest-3.3.2, py-1.5.2, pluggy-0.6.0 -- /usr/bin/python3
cachedir: ../../.cache
rootdir: /home/mark/dbl-uploader-clients/dbl_dot_local, inifile: pytest.ini
plugins: faulthandler-1.5.0, cov-2.5.1
collected 1 item                                                                                                                                               

test_app_cancel_upload.py::test_cancel_upload_jobs PASSED                                                                                                [100%]

=================================================================== 1 passed in 8.83 seconds ===================================================================
$ 

The test above looks like this:

@pytest.mark.crash_when_marked
@pytest.mark.cancelUploadJobs
def test_cancel_upload_jobs(temp_config_path):
    """
    Test cancelUploadJobs for host bundle
    """
    config_ob = Config(prepend_real(temp_config_path))
    du_app = DownUpApp(config_ob, verbose=True)
    # Find an entry to download
    entry_id, entry_revision = first_text_entry_ids(du_app.dbl_endpoints)
    # task to download entry
    tasks_xml = """<tasks>
    <downloadMetadata>
        <entry>{0}</entry>
        <revision>{1}</revision>
        <label>downloadedBundle</label>
        <tasks>
            <createUploadJob/>
        </tasks>
    </downloadMetadata>
</tasks>""".format(entry_id, entry_revision)
    tasks_dom = etree.fromstring(tasks_xml)
    first_bundle_id = du_app.storer.new_bundle("text", tasks_dom)
    du_app.tick_while_active(60)
    jobs = du_app.dbl_endpoints.entry_upload_jobs(entry_id)[3]
    assert len(jobs) > 0
    second_bundle_id = du_app.storer.label(first_bundle_id, "downloadedBundle")
    tasks_xml = """<tasks>
    <cancelUploadJobs/>
</tasks>"""
    du_app.storer.add_tasks_xml(second_bundle_id, etree.fromstring(tasks_xml))
    du_app.tick_while_active(60)
    assert not du_app.is_active()
    jobs = du_app.dbl_endpoints.entry_upload_jobs(entry_id)[3]
    assert len(jobs) == 0

and two of the fixtures look like this:

@pytest.fixture()
def temp_bundle_dir():
    """
    Set up a temporary bundle dir with matching settings file, delete it after use.
    """
    temp_dir = tempfile.mkdtemp()
    if platform.system() == "Windows":
        temp_dir = re.sub(
                "\\\\",
                "/",
                temp_dir
            )
    with open(prepend_test_data_dir("valid_settings.xml.template"), "r") as t_in:
        template = t_in.read()
    template = re.sub("%%TMP_DIR%%", temp_dir, template)
    temp_bundle_dir_path = os.path.join(temp_dir, "bundles")
    os.mkdir(temp_bundle_dir_path)
    temp_session_bundle_dir_path = os.path.join(temp_dir, "sessions")
    os.mkdir(temp_session_bundle_dir_path)
    print('built {0}'.format(temp_dir))
    yield temp_dir
    print('cleanup {0}'.format(temp_dir))
    shutil.rmtree(temp_dir)

@pytest.fixture
def temp_config_path(temp_bundle_dir):
    temp_dir = temp_bundle_dir
    with open(prepend_test_data_dir("valid_settings.xml.template"), "r") as t_in:
        template = t_in.read()
    template = re.sub("%%TMP_DIR%%", temp_dir, template)
    temp_config_path = os.path.join(temp_dir, "valid_settings.xml")
    with open(temp_config_path, "w") as t_out:
        t_out.write(template)
    print('config path: {0}'.format(temp_config_path))
    return temp_config_path

This looks to me like a bug in pytest, since the test behaviour varies according to how it is invoked. But I’m quite willing to believe that there’s also something evil in my code - I just have no clue how to find it.

All suggestions welcome.

About this issue

  • Original URL
  • State: closed
  • Created 6 years ago
  • Comments: 22 (9 by maintainers)

Most upvoted comments

Same here. Python version has no influence though. Running individual files is OK. Running them together segfaults.

Thanks. I have removed all my dependencies one by one, and ion my case, seems like the culprit is https://github.com/syrusakbary/snapshottest , not 100% how and why, but dropping this dependency fixed the issue for me.

I guess for future readers, while pytest might indeed be the issue, it’s better to start off with a clean venv, and see if there is any specific dependency that is the issue.

Closing this for now as it seems this is not related to pytest per-se. Will be happy to reopen if more information comes to light. 👍