jupyter/terminado

0.17.1: pytest is failing in `terminado/tests/basic_test.py::UniqueTermTests::test_max_terminals` unit

kloczek opened this issue · 7 comments

I'm packaging your module as an rpm package so I'm using the typical PEP517 based build, install and test cycle used on building packages from non-root account.

  • python3 -sBm build -w --no-isolation
  • because I'm calling build with --no-isolation I'm using during all processes only locally installed modules
  • install .whl file in </install/prefix>
  • run pytest with PYTHONPATH pointing to sitearch and sitelib inside </install/prefix>

Here is pytest output:

+ PYTHONPATH=/home/tkloczko/rpmbuild/BUILDROOT/python-terminado-0.17.1-2.fc35.x86_64/usr/lib64/python3.8/site-packages:/home/tkloczko/rpmbuild/BUILDROOT/python-terminado-0.17.1-2.fc35.x86_64/usr/lib/python3.8/site-packages
+ /usr/bin/pytest -ra
=========================================================================== test session starts ============================================================================
platform linux -- Python 3.8.15, pytest-7.2.0, pluggy-1.0.0
rootdir: /home/tkloczko/rpmbuild/BUILD/terminado-0.17.1, configfile: pyproject.toml, testpaths: terminado/tests/
collected 9 items

terminado/tests/basic_test.py .......F.                                                                                                                              [100%]

================================================================================= FAILURES =================================================================================
____________________________________________________________________ UniqueTermTests.test_max_terminals ____________________________________________________________________

self = <terminado.tests.basic_test.UniqueTermTests testMethod=test_max_terminals>

    @tornado.testing.gen_test
    @pytest.mark.skipif("linux" not in platform, reason="It only works on Linux")
    async def test_max_terminals(self):
        tms = await self.get_term_clients(["/unique"] * MAX_TERMS)
        pids = await self.get_pids(tms)
        self.assertEqual(len(set(pids)), MAX_TERMS)  # All PIDs unique

        # MAX_TERMS+1 should fail
        tm = await self.get_term_client("/unique")
        msg = await tm.read_msg()
        self.assertEqual(msg, None)  # Connection closed

        # Close one
        tms[0].close()
        msg = await tms[0].read_msg()  # Closed
        self.assertEqual(msg, None)

        # Should be able to open back up to MAX_TERMS
        tm = await self.get_term_client("/unique")
        msg = await tm.read_msg()
>       self.assertEqual(msg[0], "setup")
E       TypeError: 'NoneType' object is not subscriptable

terminado/tests/basic_test.py:307: TypeError
---------------------------------------------------------------------------- Captured log call -----------------------------------------------------------------------------
WARNING  tornado.general:autoreload.py:128 tornado.autoreload started more than once in the same process
ERROR    tornado.application:web.py:1798 Uncaught exception GET /unique (127.0.0.1)
HTTPServerRequest(protocol='http', host='127.0.0.1:43321', method='GET', uri='/unique', version='HTTP/1.1', remote_ip='127.0.0.1')
Traceback (most recent call last):
  File "/usr/lib64/python3.8/site-packages/tornado/websocket.py", line 942, in _accept_connection
    open_result = handler.open(*handler.open_args, **handler.open_kwargs)
  File "/home/tkloczko/rpmbuild/BUILD/terminado-0.17.1/terminado/websocket.py", line 56, in open
    self.terminal = self.term_manager.get_terminal(url_component)
  File "/home/tkloczko/rpmbuild/BUILD/terminado-0.17.1/terminado/management.py", line 323, in get_terminal
    raise MaxTerminalsReached(self.max_terminals)
terminado.management.MaxTerminalsReached: Cannot create more than 3 terminals
ERROR    tornado.application:web.py:1798 Uncaught exception GET /unique (127.0.0.1)
HTTPServerRequest(protocol='http', host='127.0.0.1:43321', method='GET', uri='/unique', version='HTTP/1.1', remote_ip='127.0.0.1')
Traceback (most recent call last):
  File "/usr/lib64/python3.8/site-packages/tornado/websocket.py", line 942, in _accept_connection
    open_result = handler.open(*handler.open_args, **handler.open_kwargs)
  File "/home/tkloczko/rpmbuild/BUILD/terminado-0.17.1/terminado/websocket.py", line 56, in open
    self.terminal = self.term_manager.get_terminal(url_component)
  File "/home/tkloczko/rpmbuild/BUILD/terminado-0.17.1/terminado/management.py", line 323, in get_terminal
    raise MaxTerminalsReached(self.max_terminals)
terminado.management.MaxTerminalsReached: Cannot create more than 3 terminals
============================================================================= warnings summary =============================================================================
../../../../../usr/lib/python3.8/site-packages/_pytest/config/__init__.py:1294
  /usr/lib/python3.8/site-packages/_pytest/config/__init__.py:1294: PytestConfigWarning: Unknown config option: timeout

    self._warn_or_fail_if_strict(f"Unknown config option: {key}\n")

terminado/tests/basic_test.py:310
  /home/tkloczko/rpmbuild/BUILD/terminado-0.17.1/terminado/tests/basic_test.py:310: PytestUnknownMarkWarning: Unknown pytest.mark.timeout - is this a typo?  You can register custom marks to avoid this warning - for details, see https://docs.pytest.org/en/stable/how-to/mark.html
    @pytest.mark.timeout(timeout=ASYNC_TEST_TIMEOUT, method="thread")

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================================================================== slowest 10 durations ===========================================================================
8.42s call     terminado/tests/basic_test.py::NamedTermTests::test_namespace
6.90s call     terminado/tests/basic_test.py::CommonTests::test_basic_command
6.54s call     terminado/tests/basic_test.py::NamedTermTests::test_max_terminals
6.54s call     terminado/tests/basic_test.py::UniqueTermTests::test_max_terminals
4.39s call     terminado/tests/basic_test.py::UniqueTermTests::test_unique_processes
4.30s call     terminado/tests/basic_test.py::SingleTermTests::test_single_process
2.59s call     terminado/tests/basic_test.py::UniqueTermTests::test_large_io_doesnt_hang
0.80s call     terminado/tests/basic_test.py::CommonTests::test_basic
0.13s call     terminado/tests/basic_test.py::NamedTermTests::test_new

(1 durations < 0.005s hidden.  Use -vv to show these durations.)
========================================================================= short test summary info ==========================================================================
FAILED terminado/tests/basic_test.py::UniqueTermTests::test_max_terminals - TypeError: 'NoneType' object is not subscriptable
================================================================= 1 failed, 8 passed, 2 warnings in 40.89s =================================================================

Here is list of installed modules in build env

Package                       Version
----------------------------- -----------------
alabaster                     0.7.12
appdirs                       1.4.4
attrs                         22.1.0
Babel                         2.11.0
Brlapi                        0.8.3
build                         0.9.0
charset-normalizer            3.0.1
cssselect                     1.1.0
distro                        1.8.0
dnspython                     2.2.1
docutils                      0.19
editables                     0.3
exceptiongroup                1.0.0
extras                        1.0.0
fixtures                      4.0.0
gpg                           1.17.1-unknown
hatchling                     1.11.1
idna                          3.4
imagesize                     1.4.1
importlib-metadata            5.1.0
iniconfig                     1.1.1
Jinja2                        3.1.2
libcomps                      0.1.19
louis                         3.24.0
lxml                          4.9.1
markdown-it-py                2.1.0
MarkupSafe                    2.1.1
mdit-py-plugins               0.3.3
mdurl                         0.1.2
myst-parser                   0.18.1
numpy                         1.23.1
packaging                     21.3
pathspec                      0.10.2
pbr                           5.9.0
pep517                        0.13.0
pip                           22.3.1
pluggy                        1.0.0
ptyprocess                    0.7.0
Pygments                      2.13.0
PyGObject                     3.42.2
pyparsing                     3.0.9
pytest                        7.2.0
python-dateutil               2.8.2
pytz                          2022.4
PyYAML                        6.0
requests                      2.28.1
rpm                           4.17.0
scour                         0.38.2
six                           1.16.0
snowballstemmer               2.2.0
Sphinx                        5.3.0
sphinxcontrib-applehelp       1.0.2.dev20221204
sphinxcontrib-devhelp         1.0.2.dev20221204
sphinxcontrib-htmlhelp        2.0.0
sphinxcontrib-jsmath          1.0.1.dev20221204
sphinxcontrib-qthelp          1.0.3.dev20221204
sphinxcontrib-serializinghtml 1.1.5
testtools                     2.5.0
tomli                         2.0.1
tornado                       6.2
typing_extensions             4.4.0
urllib3                       1.26.12
wheel                         0.38.4
zipp                          3.11.0

Updated output after install missing pytest-timeout

+ PYTHONPATH=/home/tkloczko/rpmbuild/BUILDROOT/python-terminado-0.17.1-2.fc35.x86_64/usr/lib64/python3.8/site-packages:/home/tkloczko/rpmbuild/BUILDROOT/python-terminado-0.17.1-2.fc35.x86_64/usr/lib/python3.8/site-packages
+ /usr/bin/pytest -ra
=========================================================================== test session starts ============================================================================
platform linux -- Python 3.8.15, pytest-7.2.0, pluggy-1.0.0
rootdir: /home/tkloczko/rpmbuild/BUILD/terminado-0.17.1, configfile: pyproject.toml, testpaths: terminado/tests/
plugins: timeout-2.1.0
timeout: 300.0s
timeout method: signal
timeout func_only: False
collected 9 items

terminado/tests/basic_test.py .......F.                                                                                                                              [100%]

================================================================================= FAILURES =================================================================================
____________________________________________________________________ UniqueTermTests.test_max_terminals ____________________________________________________________________

self = <terminado.tests.basic_test.UniqueTermTests testMethod=test_max_terminals>

    @tornado.testing.gen_test
    @pytest.mark.skipif("linux" not in platform, reason="It only works on Linux")
    async def test_max_terminals(self):
        tms = await self.get_term_clients(["/unique"] * MAX_TERMS)
        pids = await self.get_pids(tms)
        self.assertEqual(len(set(pids)), MAX_TERMS)  # All PIDs unique

        # MAX_TERMS+1 should fail
        tm = await self.get_term_client("/unique")
        msg = await tm.read_msg()
        self.assertEqual(msg, None)  # Connection closed

        # Close one
        tms[0].close()
        msg = await tms[0].read_msg()  # Closed
        self.assertEqual(msg, None)

        # Should be able to open back up to MAX_TERMS
        tm = await self.get_term_client("/unique")
        msg = await tm.read_msg()
>       self.assertEqual(msg[0], "setup")
E       TypeError: 'NoneType' object is not subscriptable

terminado/tests/basic_test.py:307: TypeError
---------------------------------------------------------------------------- Captured log call -----------------------------------------------------------------------------
WARNING  tornado.general:autoreload.py:128 tornado.autoreload started more than once in the same process
ERROR    tornado.application:web.py:1798 Uncaught exception GET /unique (127.0.0.1)
HTTPServerRequest(protocol='http', host='127.0.0.1:36907', method='GET', uri='/unique', version='HTTP/1.1', remote_ip='127.0.0.1')
Traceback (most recent call last):
  File "/usr/lib64/python3.8/site-packages/tornado/websocket.py", line 942, in _accept_connection
    open_result = handler.open(*handler.open_args, **handler.open_kwargs)
  File "/home/tkloczko/rpmbuild/BUILD/terminado-0.17.1/terminado/websocket.py", line 56, in open
    self.terminal = self.term_manager.get_terminal(url_component)
  File "/home/tkloczko/rpmbuild/BUILD/terminado-0.17.1/terminado/management.py", line 323, in get_terminal
    raise MaxTerminalsReached(self.max_terminals)
terminado.management.MaxTerminalsReached: Cannot create more than 3 terminals
ERROR    tornado.application:web.py:1798 Uncaught exception GET /unique (127.0.0.1)
HTTPServerRequest(protocol='http', host='127.0.0.1:36907', method='GET', uri='/unique', version='HTTP/1.1', remote_ip='127.0.0.1')
Traceback (most recent call last):
  File "/usr/lib64/python3.8/site-packages/tornado/websocket.py", line 942, in _accept_connection
    open_result = handler.open(*handler.open_args, **handler.open_kwargs)
  File "/home/tkloczko/rpmbuild/BUILD/terminado-0.17.1/terminado/websocket.py", line 56, in open
    self.terminal = self.term_manager.get_terminal(url_component)
  File "/home/tkloczko/rpmbuild/BUILD/terminado-0.17.1/terminado/management.py", line 323, in get_terminal
    raise MaxTerminalsReached(self.max_terminals)
terminado.management.MaxTerminalsReached: Cannot create more than 3 terminals
=========================================================================== slowest 10 durations ===========================================================================
8.42s call     terminado/tests/basic_test.py::NamedTermTests::test_namespace
6.85s call     terminado/tests/basic_test.py::CommonTests::test_basic_command
6.61s call     terminado/tests/basic_test.py::NamedTermTests::test_max_terminals
6.60s call     terminado/tests/basic_test.py::UniqueTermTests::test_max_terminals
4.44s call     terminado/tests/basic_test.py::UniqueTermTests::test_unique_processes
4.30s call     terminado/tests/basic_test.py::SingleTermTests::test_single_process
2.53s call     terminado/tests/basic_test.py::UniqueTermTests::test_large_io_doesnt_hang
0.80s call     terminado/tests/basic_test.py::CommonTests::test_basic
0.13s call     terminado/tests/basic_test.py::NamedTermTests::test_new

(1 durations < 0.005s hidden.  Use -vv to show these durations.)
========================================================================= short test summary info ==========================================================================
FAILED terminado/tests/basic_test.py::UniqueTermTests::test_max_terminals - TypeError: 'NoneType' object is not subscriptable
======================================================================= 1 failed, 8 passed in 40.95s =======================================================================

I found yet another small issue.
Looks like terminado/tests is installed.
It would be good to move that directory to tests/.

We're starting to see this in Fedora rawhide: https://koschei.fedoraproject.org/package/python-terminado?collection=f38

There are quite a few dep changes, so hard to say what exactly has triggered it.

Seems like it may be intermittent as well.