From e00cf5f1249b522e58fb0651ae8b00e7b74c6ab2 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 8 Mar 2022 17:51:44 -0800 Subject: [PATCH] test: use smtplib.SMTP[_SSL] timeout = notifications.smtp-timeout A new option has been added for configuration of SMTP timeout: - notifications.smtp-timeout During tests, we can change this timeout to be small, so we aren't depending on hardware-based RNG to pass the timeout. Without a timeout, users can run into a long-running test for no particular reason. Signed-off-by: Kevin Morris --- aurweb/scripts/notify.py | 5 +++- aurweb/testing/smtp.py | 3 +++ conf/config.defaults | 1 + test/test_notify.py | 49 ++++++++++++++++++++++++---------------- 4 files changed, 37 insertions(+), 21 deletions(-) diff --git a/aurweb/scripts/notify.py b/aurweb/scripts/notify.py index dbef3aa5..6afa65ae 100755 --- a/aurweb/scripts/notify.py +++ b/aurweb/scripts/notify.py @@ -104,7 +104,10 @@ class Notification: False: smtplib.SMTP, True: smtplib.SMTP_SSL, } - server = classes[use_ssl](server_addr, server_port) + smtp_timeout = aurweb.config.getint("notifications", + "smtp-timeout") + server = classes[use_ssl](server_addr, server_port, + timeout=smtp_timeout) if use_starttls: server.ehlo() diff --git a/aurweb/testing/smtp.py b/aurweb/testing/smtp.py index da64c93f..e5d67991 100644 --- a/aurweb/testing/smtp.py +++ b/aurweb/testing/smtp.py @@ -36,6 +36,9 @@ class FakeSMTP: def quit(self) -> None: self.quit_count += 1 + def __call__(self, *args, **kwargs) -> "FakeSMTP": + return self + class FakeSMTP_SSL(FakeSMTP): """ A fake version of smtplib.SMTP_SSL used for testing. """ diff --git a/conf/config.defaults b/conf/config.defaults index 371c99b2..722802cc 100644 --- a/conf/config.defaults +++ b/conf/config.defaults @@ -65,6 +65,7 @@ smtp-use-ssl = 0 smtp-use-starttls = 0 smtp-user = smtp-password = +smtp-timeout = 60 sender = notify@aur.archlinux.org reply-to = noreply@aur.archlinux.org diff --git a/test/test_notify.py b/test/test_notify.py index 2009e3a8..fdec5ed7 100644 --- a/test/test_notify.py +++ b/test/test_notify.py @@ -547,18 +547,18 @@ def test_smtp(user: User): with db.begin(): user.ResetKey = "12345678901234567890123456789012" - SMTP = FakeSMTP() + smtp = FakeSMTP() get = "aurweb.config.get" getboolean = "aurweb.config.getboolean" with mock.patch(get, side_effect=mock_smtp_config(str)): with mock.patch(getboolean, side_effect=mock_smtp_config(bool)): - with mock.patch("smtplib.SMTP", side_effect=lambda a, b: SMTP): + with mock.patch("smtplib.SMTP", side_effect=smtp): config.rehash() notif = notify.WelcomeNotification(user.ID) notif.send() config.rehash() - assert len(SMTP.emails) == 1 + assert len(smtp.emails) == 1 def mock_smtp_starttls_config(cls): @@ -586,25 +586,25 @@ def test_smtp_starttls(user: User): user.ResetKey = "12345678901234567890123456789012" user.BackupEmail = "backup@example.org" - SMTP = FakeSMTP() + smtp = FakeSMTP() get = "aurweb.config.get" getboolean = "aurweb.config.getboolean" with mock.patch(get, side_effect=mock_smtp_starttls_config(str)): with mock.patch( getboolean, side_effect=mock_smtp_starttls_config(bool)): - with mock.patch("smtplib.SMTP", side_effect=lambda a, b: SMTP): + with mock.patch("smtplib.SMTP", side_effect=smtp): notif = notify.WelcomeNotification(user.ID) notif.send() - assert SMTP.starttls_enabled - assert SMTP.user - assert SMTP.passwd + assert smtp.starttls_enabled + assert smtp.user + assert smtp.passwd - assert len(SMTP.emails) == 2 - to = SMTP.emails[0][1] + assert len(smtp.emails) == 2 + to = smtp.emails[0][1] assert to == [user.Email] - to = SMTP.emails[1][1] + to = smtp.emails[1][1] assert to == [user.BackupEmail] @@ -629,19 +629,19 @@ def test_smtp_ssl(user: User): with db.begin(): user.ResetKey = "12345678901234567890123456789012" - SMTP = FakeSMTP_SSL() + smtp = FakeSMTP_SSL() get = "aurweb.config.get" getboolean = "aurweb.config.getboolean" with mock.patch(get, side_effect=mock_smtp_ssl_config(str)): with mock.patch(getboolean, side_effect=mock_smtp_ssl_config(bool)): - with mock.patch("smtplib.SMTP_SSL", side_effect=lambda a, b: SMTP): + with mock.patch("smtplib.SMTP_SSL", side_effect=smtp): notif = notify.WelcomeNotification(user.ID) notif.send() - assert len(SMTP.emails) == 1 - assert SMTP.use_ssl - assert SMTP.user - assert SMTP.passwd + assert len(smtp.emails) == 1 + assert smtp.use_ssl + assert smtp.user + assert smtp.passwd def test_notification_defaults(): @@ -655,6 +655,7 @@ def test_notification_oserror(user: User, caplog: pytest.LogCaptureFixture): """ Try sending a notification with a bad SMTP configuration. """ caplog.set_level(ERROR) config_get = config.get + config_getint = config.getint mocked_options = { "sendmail": str(), @@ -662,8 +663,9 @@ def test_notification_oserror(user: User, caplog: pytest.LogCaptureFixture): "smtp-port": "587", "smtp-user": "notify@server.xyz", "smtp-password": "notify_server_xyz", + "smtp-timeout": 1, "sender": "notify@server.xyz", - "reply-to": "no-reply@server.xyz" + "reply-to": "no-reply@server.xyz", } def mock_config_get(section: str, key: str) -> str: @@ -672,9 +674,16 @@ def test_notification_oserror(user: User, caplog: pytest.LogCaptureFixture): return mocked_options.get(key) return config_get(section, key) + def mock_config_getint(section: str, key: str) -> str: + if section == "notifications": + if key in mocked_options: + return mocked_options.get(key) + return config_getint(section, key) + notif = notify.WelcomeNotification(user.ID) - with mock.patch("aurweb.config.get", side_effect=mock_config_get): - notif.send() + with mock.patch("aurweb.config.getint", side_effect=mock_config_getint): + with mock.patch("aurweb.config.get", side_effect=mock_config_get): + notif.send() expected = "Unable to emit notification due to an OSError" assert expected in caplog.text