aio-libs / aiosmtpd

A reimplementation of the Python stdlib smtpd.py based on asyncio.
https://aiosmtpd.aio-libs.org
Apache License 2.0
319 stars 96 forks source link

assert_smtp_socket fails with Python 3.13.0a3 #403

Open hroncok opened 7 months ago

hroncok commented 7 months ago

Hello. In Fedora, we are trying to test our packages early with pre-releases of Python 3.13 to be prepared to upgrade to it in the development version of Fedora Linux 41. aiosmtpd fails a test.

To reproduce, I did this:

diff --git a/pytest.ini b/pytest.ini
index f2b9850..a681fff 100644
--- a/pytest.ini
+++ b/pytest.ini
@@ -8,9 +8,6 @@ addopts =
     -ra
     # show values of the local vars in errors:
     --showlocals
-    # coverage reports
-    --cov=aiosmtpd/ --cov-report term
-asyncio_mode = auto
 filterwarnings =
     error
     # TODO: Replace pkg_resources
diff --git a/tox.ini b/tox.ini
index 8282343..5e81227 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,6 +1,6 @@
 [tox]
 minversion = 3.9.0
-envlist = qa, static, docs, py{38,39,310,311,312,py3}-{nocov,cov,diffcov}
+envlist = qa, static, docs, py{38,39,310,311,312,313,py3}-{nocov,cov,diffcov}
 skip_missing_interpreters = True

 [testenv]
@@ -25,9 +25,9 @@ deps =
     pytest >= 6.0  # Require >= 6.0 for pyproject.toml support (PEP 517)
     pytest-mock
     pytest-print
-    pytest-profiling
     pytest-sugar
     py # needed for pytest-sugar as it doesn't declare dependency on it.
+    setuptools
     !nocov: coverage>=7.0.1
     !nocov: coverage[toml]
     !nocov: coverage-conditional-plugin

The changes were necessary to even run the tests with Python 3.13. pytest-profiling is not ready for 3.13 and conftest imports pkg_resources.

Then I run:

$ tox -e py313-nocov

Or directly:

$ tox -e py313-nocov -- -k test_unixsocket

I got:

...
py313-nocov: commands[2]> pytest --verbose -p no:cov --tb=short -k test_unixsocket
============================= test session starts ==============================
platform linux -- Python 3.13.0a3, pytest-8.0.0, pluggy-1.4.0 -- .../aiosmtpd/.tox/py313-nocov/bin/python
cachedir: .tox/py313-nocov/.pytest_cache
rootdir: .../aiosmtpd
configfile: pytest.ini
testpaths: aiosmtpd/tests/, aiosmtpd/qa/
plugins: sugar-1.0.0, print-1.0.0, mock-3.12.0
collecting ... collected 565 items / 564 deselected / 1 selected

aiosmtpd/tests/test_server.py::TestUnthreaded::test_unixsocket FAILED    [100%]

=================================== FAILURES ===================================
________________________ TestUnthreaded.test_unixsocket ________________________
aiosmtpd/tests/test_server.py:454: in test_unixsocket
    assert_smtp_socket(cont)
        autostop_loop = <_UnixSelectorEventLoop running=False closed=False debug=True>
        cont       = <aiosmtpd.controller.UnixSocketUnthreadedController object at 0x7f91d041d220>
        runner     = <function TestUnthreaded.runner.<locals>.starter at 0x7f91d0602f20>
        safe_socket_dir = PosixPath('/tmp/tmpdoje2ko7')
        self       = <aiosmtpd.tests.test_server.TestUnthreaded object at 0x7f91d06500b0>
        sockfile   = PosixPath('/tmp/tmpdoje2ko7/smtp')
aiosmtpd/tests/test_server.py:104: in assert_smtp_socket
    assert Path(controller.unix_socket).exists()
E   AssertionError: assert False
E    +  where False = <bound method PathBase.exists of PosixPath('/tmp/tmpdoje2ko7/smtp')>()
E    +    where <bound method PathBase.exists of PosixPath('/tmp/tmpdoje2ko7/smtp')> = PosixPath('/tmp/tmpdoje2ko7/smtp').exists
E    +      where PosixPath('/tmp/tmpdoje2ko7/smtp') = Path('/tmp/tmpdoje2ko7/smtp')
E    +        where '/tmp/tmpdoje2ko7/smtp' = <aiosmtpd.controller.UnixSocketUnthreadedController object at 0x7f91d041d220>.unix_socket
        controller = <aiosmtpd.controller.UnixSocketUnthreadedController object at 0x7f91d041d220>
------------------------------ Captured log call -------------------------------
INFO     mail.log:smtp.py:408 Available AUTH mechanisms: LOGIN(builtin) PLAIN(builtin)
INFO     mail.log:smtp.py:521 Peer: ''
INFO     mail.log:smtp.py:613 '' handling connection
DEBUG    mail.log:smtp.py:597 '' << b'220 carbon Python SMTP 1.4.4.post2'
DEBUG    mail.log:smtp.py:287 _handle_client readline: b'EHLO socket.test\r\n'
INFO     mail.log:smtp.py:287 '' >> b'EHLO socket.test'
DEBUG    mail.log:smtp.py:597 '' << b'250-carbon'
DEBUG    mail.log:smtp.py:597 '' << b'250-SIZE 33554432'
DEBUG    mail.log:smtp.py:597 '' << b'250-8BITMIME'
DEBUG    mail.log:smtp.py:597 '' << b'250-SMTPUTF8'
DEBUG    mail.log:smtp.py:597 '' << b'250 HELP'
DEBUG    mail.log:smtp.py:287 _handle_client readline: b'QUIT\r\n'
INFO     mail.log:smtp.py:287 '' >> b'QUIT'
DEBUG    mail.log:smtp.py:597 '' << b'221 Bye'
INFO     mail.log:smtp.py:528 '' connection lost
INFO     mail.log:smtp.py:759 '' Connection lost during _handle_client()
============================= slowest 10 durations =============================
3.31s call     aiosmtpd/tests/test_server.py::TestUnthreaded::test_unixsocket
0.00s setup    aiosmtpd/tests/test_server.py::TestUnthreaded::test_unixsocket
0.00s teardown aiosmtpd/tests/test_server.py::TestUnthreaded::test_unixsocket
=========================== short test summary info ============================
FAILED aiosmtpd/tests/test_server.py::TestUnthreaded::test_unixsocket - Asser...
====================== 1 failed, 564 deselected in 3.45s =======================
py313-nocov: exit 1 (3.70 seconds) .../aiosmtpd> pytest --verbose -p no:cov --tb=short -k test_unixsocket pid=856635
.pkg-cpython313: _exit> python /usr/lib/python3.12/site-packages/pyproject_api/_backend.py True setuptools.build_meta
  py313-nocov: FAIL code 1 (5.21=setup[0.60]+cmd[0.04,0.88,3.70] seconds)
  evaluation failed :( (5.39 seconds)

This is with:

$ python3.13 --version
Python 3.13.0a3

$ .tox/py313-nocov/bin/pip list
Package        Version
-------------- -----------
aiosmtpd       1.4.4.post2
atpublic       4.0
attrs          23.2.0
bandit         1.7.7
colorama       0.4.6
iniconfig      2.0.0
markdown-it-py 3.0.0
mdurl          0.1.2
packaging      23.2
pbr            6.0.0
pip            23.2.1
pluggy         1.4.0
py             1.11.0
Pygments       2.17.2
pytest         8.0.0
pytest-mock    3.12.0
pytest-print   1.0.0
pytest-sugar   1.0.0
PyYAML         6.0.1
rich           13.7.0
setuptools     69.0.3
stevedore      5.1.0
termcolor      2.4.0
manisandro commented 3 months ago

Consequence of

asyncio.loop.create_unix_server() will now automatically remove the Unix socket when the server is closed. (Contributed by Pierre Ossman in https://github.com/python/cpython/issues/111246.)

?

cont.end() will close the server which will now remove the socket. Perhaps the last part of the test should just be dropped?

diff -rupN aiosmtpd-1.4.4.post2/aiosmtpd/tests/test_server.py aiosmtpd-1.4.4.post2-new/aiosmtpd/tests/test_server.py
--- aiosmtpd-1.4.4.post2/aiosmtpd/tests/test_server.py  2023-01-19 10:37:59.000000000 +0100
+++ aiosmtpd-1.4.4.post2-new/aiosmtpd/tests/test_server.py  2024-06-12 14:00:02.133043947 +0200
@@ -446,10 +446,6 @@ class TestUnthreaded:
         # Stop the task
         cont.end()
         catchup_delay()
-        # Now the listener has gone away
-        # noinspection PyTypeChecker
-        with pytest.raises((socket.timeout, ConnectionError)):
-            assert_smtp_socket(cont)

     @pytest.mark.filterwarnings(
         "ignore::pytest.PytestUnraisableExceptionWarning"