You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Not sure this is short-run actionable, and I don't think it's actually a pytest-flask bug. If others encounter this it may still make sense to add something like the workaround I identified as an optional run mode or automatic fallback. Opening an issue in case it helps others or attracts more information/reports. The lack of similar reports makes me suspect this might come down to the OS or specific dependency versions--but I haven't had time to fiddle with them.
We had some trouble this fall with flaky test runs using live_server and selenium for end-to-end tests. I'll describe everything I can recall in case it helps someone find the issue; scroll to the end for the workaround. :)
Initial encounter/debug
The issue initially manifested as inconsistent test/fixture failures at the first location in a test that depended on finding/interacting with anything specific loaded (because the server never started and the browser has a blank page loaded). When I first encountered this, the test exception/assertion errors were all I got.
I eventually figured out that live_server._process could silently fail to start during setup. You can detect this with something like:
While most of my test runs fail (running 2 parameterized tests 8x each), there's usually only one failure across the run. It often (but not always) fails on the same test. Any remaining tests usually run fine. Playing around for a bit (different numbers of tests, turning each test into a simple pass, renaming them to force different orders) made me think that where it breaks is somewhat correlated with how much work the tests make the server do.
Stepping through the code isolated the problem to when app.run(host=host, port=port, use_reloader=False, threaded=True) is called inside the worker/target function passed to multiprocessing.Process. At the time, I had trouble introspecting the child process (see the paragraph), but I did notice the crash produces OS crash reports. Here's an example:
Today I disabled my workaround to ensure I still see the issue and noticed that something (maybe pytest--I was using 4.x at the time and now use 5.x) in my environment has shifted and the test run now prints helpful Python segfault messages and full stack traces. Here's an example:
segfault stack trace
Fatal Python error: Segmentation fault
Current thread 0x00000001121c05c0 (most recent call first):
File "/nix/store/ajn7df20f65rb00pjkayr82dppyszsn8-python3-3.6.9/lib/python3.6/socketserver.py", line 470 in server_bind
File "/nix/store/ajn7df20f65rb00pjkayr82dppyszsn8-python3-3.6.9/lib/python3.6/http/server.py", line 136 in server_bind
File "/nix/store/ajn7df20f65rb00pjkayr82dppyszsn8-python3-3.6.9/lib/python3.6/socketserver.py", line 456 in __init__
File "/nix/store/ai2cvzkgzgjq4j38rwvgym81jj8vqs1r-python3.6-Werkzeug-0.12.2/lib/python3.6/site-packages/werkzeug/serving.py", line 504 in __init__
File "/nix/store/ai2cvzkgzgjq4j38rwvgym81jj8vqs1r-python3.6-Werkzeug-0.12.2/lib/python3.6/site-packages/werkzeug/serving.py", line 587 in make_server
File "/nix/store/ai2cvzkgzgjq4j38rwvgym81jj8vqs1r-python3.6-Werkzeug-0.12.2/lib/python3.6/site-packages/werkzeug/serving.py", line 699 in inner
File "/nix/store/ai2cvzkgzgjq4j38rwvgym81jj8vqs1r-python3.6-Werkzeug-0.12.2/lib/python3.6/site-packages/werkzeug/serving.py", line 739 in run_simple
File "/nix/store/2wsznll072jgsaqp3ypmd354s9yqw9vw-python3.6-Flask-0.12.2/lib/python3.6/site-packages/flask/app.py", line 841 in run
File "/nix/store/dsdjvybj8bp9cpqw3hzl2fjd0gns0p8d-python3.6-pytest-flask-0.14.0/lib/python3.6/site-packages/pytest_flask/fixtures.py", line 67 in worker
File "/nix/store/ajn7df20f65rb00pjkayr82dppyszsn8-python3-3.6.9/lib/python3.6/multiprocessing/process.py", line 93 in run
File "/nix/store/ajn7df20f65rb00pjkayr82dppyszsn8-python3-3.6.9/lib/python3.6/multiprocessing/process.py", line 258 in _bootstrap
File "/nix/store/ajn7df20f65rb00pjkayr82dppyszsn8-python3-3.6.9/lib/python3.6/multiprocessing/popen_fork.py", line 73 in _launch
File "/nix/store/ajn7df20f65rb00pjkayr82dppyszsn8-python3-3.6.9/lib/python3.6/multiprocessing/popen_fork.py", line 19 in __init__
File "/nix/store/ajn7df20f65rb00pjkayr82dppyszsn8-python3-3.6.9/lib/python3.6/multiprocessing/context.py", line 277 in _Popen
File "/nix/store/ajn7df20f65rb00pjkayr82dppyszsn8-python3-3.6.9/lib/python3.6/multiprocessing/context.py", line 223 in _Popen
File "/nix/store/ajn7df20f65rb00pjkayr82dppyszsn8-python3-3.6.9/lib/python3.6/multiprocessing/process.py", line 105 in start
File "/nix/store/dsdjvybj8bp9cpqw3hzl2fjd0gns0p8d-python3.6-pytest-flask-0.14.0/lib/python3.6/site-packages/pytest_flask/fixtures.py", line 72 in start
File "/Users/abathur/<intentionally snipped>/tests/conftest.py", line 963 in browser
File "/nix/store/j44z35nkdkn527j7r93iajm0sv6h0678-python3.6-pytest-5.2.1/lib/python3.6/site-packages/_pytest/fixtures.py", line 775 in call_fixture_func
File "/nix/store/j44z35nkdkn527j7r93iajm0sv6h0678-python3.6-pytest-5.2.1/lib/python3.6/site-packages/_pytest/fixtures.py", line 949 in pytest_fixture_setup
File "/nix/store/njj7nw68w2kxf8z6d2s1b5zw8l2dzw3m-python3.6-pluggy-0.13.0/lib/python3.6/site-packages/pluggy/callers.py", line 187 in _multicall
File "/nix/store/njj7nw68w2kxf8z6d2s1b5zw8l2dzw3m-python3.6-pluggy-0.13.0/lib/python3.6/site-packages/pluggy/manager.py", line 86 in <lambda>
File "/nix/store/njj7nw68w2kxf8z6d2s1b5zw8l2dzw3m-python3.6-pluggy-0.13.0/lib/python3.6/site-packages/pluggy/manager.py", line 92 in _hookexec
File "/nix/store/njj7nw68w2kxf8z6d2s1b5zw8l2dzw3m-python3.6-pluggy-0.13.0/lib/python3.6/site-packages/pluggy/hooks.py", line 286 in __call__
File "/nix/store/j44z35nkdkn527j7r93iajm0sv6h0678-python3.6-pytest-5.2.1/lib/python3.6/site-packages/_pytest/fixtures.py", line 900 in execute
File "/nix/store/j44z35nkdkn527j7r93iajm0sv6h0678-python3.6-pytest-5.2.1/lib/python3.6/site-packages/_pytest/fixtures.py", line 571 in _compute_fixture_value
File "/nix/store/j44z35nkdkn527j7r93iajm0sv6h0678-python3.6-pytest-5.2.1/lib/python3.6/site-packages/_pytest/fixtures.py", line 490 in _get_active_fixturedef
File "/nix/store/j44z35nkdkn527j7r93iajm0sv6h0678-python3.6-pytest-5.2.1/lib/python3.6/site-packages/_pytest/fixtures.py", line 880 in execute
File "/nix/store/j44z35nkdkn527j7r93iajm0sv6h0678-python3.6-pytest-5.2.1/lib/python3.6/site-packages/_pytest/fixtures.py", line 571 in _compute_fixture_value
File "/nix/store/j44z35nkdkn527j7r93iajm0sv6h0678-python3.6-pytest-5.2.1/lib/python3.6/site-packages/_pytest/fixtures.py", line 490 in _get_active_fixturedef
File "/nix/store/j44z35nkdkn527j7r93iajm0sv6h0678-python3.6-pytest-5.2.1/lib/python3.6/site-packages/_pytest/fixtures.py", line 880 in execute
File "/nix/store/j44z35nkdkn527j7r93iajm0sv6h0678-python3.6-pytest-5.2.1/lib/python3.6/site-packages/_pytest/fixtures.py", line 571 in _compute_fixture_value
File "/nix/store/j44z35nkdkn527j7r93iajm0sv6h0678-python3.6-pytest-5.2.1/lib/python3.6/site-packages/_pytest/fixtures.py", line 490 in _get_active_fixturedef
File "/nix/store/j44z35nkdkn527j7r93iajm0sv6h0678-python3.6-pytest-5.2.1/lib/python3.6/site-packages/_pytest/fixtures.py", line 474 in getfixturevalue
File "/nix/store/j44z35nkdkn527j7r93iajm0sv6h0678-python3.6-pytest-5.2.1/lib/python3.6/site-packages/_pytest/fixtures.py", line 464 in _fillfixtures
File "/nix/store/j44z35nkdkn527j7r93iajm0sv6h0678-python3.6-pytest-5.2.1/lib/python3.6/site-packages/_pytest/fixtures.py", line 291 in fillfixtures
File "/nix/store/j44z35nkdkn527j7r93iajm0sv6h0678-python3.6-pytest-5.2.1/lib/python3.6/site-packages/_pytest/python.py", line 1427 in setup
File "/nix/store/j44z35nkdkn527j7r93iajm0sv6h0678-python3.6-pytest-5.2.1/lib/python3.6/site-packages/_pytest/runner.py", line 366 in prepare
File "/nix/store/j44z35nkdkn527j7r93iajm0sv6h0678-python3.6-pytest-5.2.1/lib/python3.6/site-packages/_pytest/runner.py", line 118 in pytest_runtest_setup
File "/nix/store/njj7nw68w2kxf8z6d2s1b5zw8l2dzw3m-python3.6-pluggy-0.13.0/lib/python3.6/site-packages/pluggy/callers.py", line 187 in _multicall
File "/nix/store/njj7nw68w2kxf8z6d2s1b5zw8l2dzw3m-python3.6-pluggy-0.13.0/lib/python3.6/site-packages/pluggy/manager.py", line 86 in <lambda>
File "/nix/store/njj7nw68w2kxf8z6d2s1b5zw8l2dzw3m-python3.6-pluggy-0.13.0/lib/python3.6/site-packages/pluggy/manager.py", line 92 in _hookexec
File "/nix/store/njj7nw68w2kxf8z6d2s1b5zw8l2dzw3m-python3.6-pluggy-0.13.0/lib/python3.6/site-packages/pluggy/hooks.py", line 286 in __call__
File "/nix/store/j44z35nkdkn527j7r93iajm0sv6h0678-python3.6-pytest-5.2.1/lib/python3.6/site-packages/_pytest/runner.py", line 201 in <lambda>
File "/nix/store/j44z35nkdkn527j7r93iajm0sv6h0678-python3.6-pytest-5.2.1/lib/python3.6/site-packages/_pytest/runner.py", line 229 in from_call
File "/nix/store/j44z35nkdkn527j7r93iajm0sv6h0678-python3.6-pytest-5.2.1/lib/python3.6/site-packages/_pytest/runner.py", line 201 in call_runtest_hook
File "/nix/store/j44z35nkdkn527j7r93iajm0sv6h0678-python3.6-pytest-5.2.1/lib/python3.6/site-packages/_pytest/runner.py", line 176 in call_and_report
File "/nix/store/j44z35nkdkn527j7r93iajm0sv6h0678-python3.6-pytest-5.2.1/lib/python3.6/site-packages/_pytest/runner.py", line 89 in runtestprotocol
File "/nix/store/j44z35nkdkn527j7r93iajm0sv6h0678-python3.6-pytest-5.2.1/lib/python3.6/site-packages/_pytest/runner.py", line 80 in pytest_runtest_protocol
File "/nix/store/njj7nw68w2kxf8z6d2s1b5zw8l2dzw3m-python3.6-pluggy-0.13.0/lib/python3.6/site-packages/pluggy/callers.py", line 187 in _multicall
File "/nix/store/njj7nw68w2kxf8z6d2s1b5zw8l2dzw3m-python3.6-pluggy-0.13.0/lib/python3.6/site-packages/pluggy/manager.py", line 86 in <lambda>
File "/nix/store/njj7nw68w2kxf8z6d2s1b5zw8l2dzw3m-python3.6-pluggy-0.13.0/lib/python3.6/site-packages/pluggy/manager.py", line 92 in _hookexec
File "/nix/store/njj7nw68w2kxf8z6d2s1b5zw8l2dzw3m-python3.6-pluggy-0.13.0/lib/python3.6/site-packages/pluggy/hooks.py", line 286 in __call__
File "/nix/store/j44z35nkdkn527j7r93iajm0sv6h0678-python3.6-pytest-5.2.1/lib/python3.6/site-packages/_pytest/main.py", line 256 in pytest_runtestloop
File "/nix/store/njj7nw68w2kxf8z6d2s1b5zw8l2dzw3m-python3.6-pluggy-0.13.0/lib/python3.6/site-packages/pluggy/callers.py", line 187 in _multicall
File "/nix/store/njj7nw68w2kxf8z6d2s1b5zw8l2dzw3m-python3.6-pluggy-0.13.0/lib/python3.6/site-packages/pluggy/manager.py", line 86 in <lambda>
File "/nix/store/njj7nw68w2kxf8z6d2s1b5zw8l2dzw3m-python3.6-pluggy-0.13.0/lib/python3.6/site-packages/pluggy/manager.py", line 92 in _hookexec
File "/nix/store/njj7nw68w2kxf8z6d2s1b5zw8l2dzw3m-python3.6-pluggy-0.13.0/lib/python3.6/site-packages/pluggy/hooks.py", line 286 in __call__
File "/nix/store/j44z35nkdkn527j7r93iajm0sv6h0678-python3.6-pytest-5.2.1/lib/python3.6/site-packages/_pytest/main.py", line 235 in _main
File "/nix/store/j44z35nkdkn527j7r93iajm0sv6h0678-python3.6-pytest-5.2.1/lib/python3.6/site-packages/_pytest/main.py", line 191 in wrap_session
File "/nix/store/j44z35nkdkn527j7r93iajm0sv6h0678-python3.6-pytest-5.2.1/lib/python3.6/site-packages/_pytest/main.py", line 228 in pytest_cmdline_main
File "/nix/store/njj7nw68w2kxf8z6d2s1b5zw8l2dzw3m-python3.6-pluggy-0.13.0/lib/python3.6/site-packages/pluggy/callers.py", line 187 in _multicall
File "/nix/store/njj7nw68w2kxf8z6d2s1b5zw8l2dzw3m-python3.6-pluggy-0.13.0/lib/python3.6/site-packages/pluggy/manager.py", line 86 in <lambda>
File "/nix/store/njj7nw68w2kxf8z6d2s1b5zw8l2dzw3m-python3.6-pluggy-0.13.0/lib/python3.6/site-packages/pluggy/manager.py", line 92 in _hookexec
File "/nix/store/njj7nw68w2kxf8z6d2s1b5zw8l2dzw3m-python3.6-pluggy-0.13.0/lib/python3.6/site-packages/pluggy/hooks.py", line 286 in __call__
File "/nix/store/j44z35nkdkn527j7r93iajm0sv6h0678-python3.6-pytest-5.2.1/lib/python3.6/site-packages/_pytest/config/__init__.py", line 90 in main
File "/nix/store/j44z35nkdkn527j7r93iajm0sv6h0678-python3.6-pytest-5.2.1/bin/.pytest-wrapped", line 11 in <module>
Workaround
At least in our case, threads proved a viable workaround. I achieved this by subclassing LiveServer and overriding the live_server fixture in our conftest:
frompytest_flask.fixturesimportLiveServer, _rewrite_server_nameimportsocketfromthreadingimportThreadtry:
fromurllib2importURLError, urlopenexceptImportError:
fromurllib.errorimportURLErrorfromurllib.requestimporturlopenclassPatchedLiveServer(LiveServer):
defstart(self):
"""Start application in a separate process."""self._process=Thread(
target=self.app.run,
kwargs=dict(
host=self.host, port=self.port, use_reloader=False, threaded=False
),
daemon=True,
)
self._process.start()
# We must wait for the server to start listening with a maximum# timeout of 5 seconds.timeout=5whiletimeout>0:
time.sleep(1)
try:
urlopen(self.url())
timeout=0exceptURLError:
timeout-=1defstop(self):
# inherited stop will break (thread has no terminate, join may fail)pass@pytest.fixture(scope="function")deflive_server(request, app, monkeypatch, pytestconfig):
port=pytestconfig.getvalue("live_server_port")
ifport==0:
# Bind to an open ports=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(("", 0))
port=s.getsockname()[1]
s.close()
host=pytestconfig.getvalue("live_server_host")
# Explicitly set application ``SERVER_NAME`` for test suite# and restore original value on test teardown.server_name=app.config["SERVER_NAME"] or"localhost"monkeypatch.setitem(
app.config, "SERVER_NAME", _rewrite_server_name(server_name, str(port))
)
clean_stop=request.config.getvalue("live_server_clean_stop")
server=PatchedLiveServer(app, host, port, clean_stop)
ifrequest.config.getvalue("start_live_server"):
server.start()
request.addfinalizer(server.stop)
returnserver
The text was updated successfully, but these errors were encountered:
Not sure this is short-run actionable, and I don't think it's actually a pytest-flask bug. If others encounter this it may still make sense to add something like the workaround I identified as an optional run mode or automatic fallback. Opening an issue in case it helps others or attracts more information/reports. The lack of similar reports makes me suspect this might come down to the OS or specific dependency versions--but I haven't had time to fiddle with them.
We had some trouble this fall with flaky test runs using live_server and selenium for end-to-end tests. I'll describe everything I can recall in case it helps someone find the issue; scroll to the end for the workaround. :)
Initial encounter/debug
The issue initially manifested as inconsistent test/fixture failures at the first location in a test that depended on finding/interacting with anything specific loaded (because the server never started and the browser has a blank page loaded). When I first encountered this, the test exception/assertion errors were all I got.
I eventually figured out that
live_server._process
could silently fail to start during setup. You can detect this with something like:While most of my test runs fail (running 2 parameterized tests 8x each), there's usually only one failure across the run. It often (but not always) fails on the same test. Any remaining tests usually run fine. Playing around for a bit (different numbers of tests, turning each test into a simple pass, renaming them to force different orders) made me think that where it breaks is somewhat correlated with how much work the tests make the server do.
Stepping through the code isolated the problem to when
app.run(host=host, port=port, use_reloader=False, threaded=True)
is called inside the worker/target function passed tomultiprocessing.Process
. At the time, I had trouble introspecting the child process (see the paragraph), but I did notice the crash produces OS crash reports. Here's an example:segfault crash report
Today I disabled my workaround to ensure I still see the issue and noticed that something (maybe pytest--I was using 4.x at the time and now use 5.x) in my environment has shifted and the test run now prints helpful Python segfault messages and full stack traces. Here's an example:
segfault stack trace
Workaround
At least in our case, threads proved a viable workaround. I achieved this by subclassing LiveServer and overriding the live_server fixture in our conftest:
The text was updated successfully, but these errors were encountered: