summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFlorian Bruhin <me@the-compiler.org>2022-06-21 12:08:05 +0200
committerFlorian Bruhin <me@the-compiler.org>2022-06-21 12:26:40 +0200
commit07e7998abcfb622e233992349d2fd16820b10a7f (patch)
treeb8830cec31d391fdf67b7ae5ad13f4054925bb03
parent1d816ef5e21d07e92ff9f6feb1b1661464b770cd (diff)
downloadqutebrowser-notifcation-error-handling.tar.gz
qutebrowser-notifcation-error-handling.zip
notification: Improve error case testsnotifcation-error-handling
-rw-r--r--tests/unit/browser/test_notification.py155
1 files changed, 132 insertions, 23 deletions
diff --git a/tests/unit/browser/test_notification.py b/tests/unit/browser/test_notification.py
index 54519c248..3bd6ef963 100644
--- a/tests/unit/browser/test_notification.py
+++ b/tests/unit/browser/test_notification.py
@@ -19,13 +19,19 @@
"""Unit tests for notification support."""
-from typing import List, Dict, Any, Optional
+import logging
+import itertools
+import inspect
+from typing import List, Dict, Any, Optional, TYPE_CHECKING
import pytest
-from PyQt5.QtCore import QUrl
+from PyQt5.QtCore import pyqtSignal, QUrl, QObject
from PyQt5.QtGui import QImage
from PyQt5.QtDBus import QDBusMessage, QDBus, QDBusConnection
+if TYPE_CHECKING:
+ from PyQt5.QtWebEngineCore import QWebEngineNotification
+from qutebrowser.config import configdata
from qutebrowser.misc import objects
from qutebrowser.browser.webengine import notification
@@ -117,7 +123,9 @@ class FakeDBusInterface:
return self.notify_reply
-class FakeWebEngineNotification:
+class FakeWebEngineNotification(QObject):
+
+ closed = pyqtSignal()
def origin(self) -> QUrl:
return QUrl("https://example.org")
@@ -131,16 +139,11 @@ class FakeWebEngineNotification:
def message(self) -> str:
return "notification message"
+ def tag(self) -> None:
+ return None
-@pytest.fixture
-def dbus_adapter_patches(monkeypatch, config_stub):
- monkeypatch.setattr(objects, "debug_flags", ["test-notification-service"])
- monkeypatch.setattr(notification, "QDBusInterface", FakeDBusInterface)
-
-
-@pytest.fixture
-def dbus_adapter(dbus_adapter_patches):
- return notification.DBusNotificationAdapter()
+ def show(self) -> None:
+ pass
@pytest.fixture
@@ -148,27 +151,133 @@ def fake_notification():
return FakeWebEngineNotification()
+def _get_notification_adapters():
+ return [value for _name, value in inspect.getmembers(notification, lambda obj: (
+ inspect.isclass(obj) and
+ issubclass(obj, notification.AbstractNotificationAdapter) and
+ obj is not notification.AbstractNotificationAdapter
+ ))]
+
+
+@pytest.mark.parametrize("klass", _get_notification_adapters())
+def test_name_attribute(klass, configdata_init):
+ values = configdata.DATA["content.notifications.presenter"].typ.valid_values
+ assert klass.NAME not in {"auto", "qt"} and klass.NAME in values
+
+
+class FakeNotificationAdapter(notification.AbstractNotificationAdapter):
+
+ NAME = "fake"
+
+ def __init__(self) -> None:
+ super().__init__()
+ self.presented = []
+ self.id_gen = itertools.count(1)
+
+ def present(
+ self,
+ qt_notification: "QWebEngineNotification", *,
+ replaces_id: Optional[int],
+ ) -> int:
+ self.presented.append(qt_notification)
+ return next(self.id_gen)
+
+
@dbus_test
class TestDBus:
+ NO_REPLY_ERROR = FakeDBusMessage.create_error("org.freedesktop.DBus.Error.NoReply")
+ FATAL_ERROR = FakeDBusMessage.create_error("test")
+
+ @pytest.fixture
+ def dbus_adapter_patches(self, monkeypatch, config_stub):
+ monkeypatch.setattr(objects, "debug_flags", ["test-notification-service"])
+ monkeypatch.setattr(notification, "QDBusInterface", FakeDBusInterface)
+
+ @pytest.fixture
+ def dbus_adapter(self, dbus_adapter_patches):
+ return notification.DBusNotificationAdapter()
+
+ @pytest.fixture
+ def dbus_presenter(self, dbus_adapter_patches, monkeypatch):
+ monkeypatch.setattr(
+ notification.NotificationBridgePresenter,
+ "_get_adapter_candidates",
+ lambda _self, _setting: [
+ notification.DBusNotificationAdapter,
+ FakeNotificationAdapter,
+ ],
+ )
+ return notification.NotificationBridgePresenter()
+
def test_notify_fatal_error(self, dbus_adapter, fake_notification):
- dbus_adapter.interface.notify_reply = FakeDBusMessage.create_error("test")
+ dbus_adapter.interface.notify_reply = self.FATAL_ERROR
with pytest.raises(notification.DBusError):
dbus_adapter.present(fake_notification, replaces_id=None)
+ def test_notify_fatal_error_presenter(self, dbus_presenter, fake_notification):
+ dbus_presenter._init_adapter()
+ dbus_presenter._adapter.interface.notify_reply = self.FATAL_ERROR
+ with pytest.raises(notification.DBusError):
+ dbus_presenter.present(fake_notification)
+
def test_notify_non_fatal_error(self, qtbot, dbus_adapter, fake_notification):
- error = "org.freedesktop.DBus.Error.NoReply"
- dbus_adapter.interface.notify_reply = FakeDBusMessage.create_error(error)
+ dbus_adapter.interface.notify_reply = self.NO_REPLY_ERROR
with qtbot.wait_signal(dbus_adapter.error) as blocker:
dbus_adapter.present(fake_notification, replaces_id=None)
- assert blocker.args == [f"error: {error}"]
+ assert blocker.args == [f"error: {self.NO_REPLY_ERROR.errorName()}"]
- def test_capabilities_error(self, qtbot, dbus_adapter_patches, monkeypatch):
- error = "org.freedesktop.DBus.Error.NoReply"
- monkeypatch.setattr(
- FakeDBusInterface,
- "CAPABILITIES_REPLY",
- FakeDBusMessage.create_error(error),
+ def test_notify_non_fatal_error_presenter(
+ self,
+ dbus_presenter,
+ fake_notification,
+ caplog,
+ ):
+ dbus_presenter._init_adapter()
+ dbus_presenter._adapter.interface.notify_reply = self.NO_REPLY_ERROR
+
+ with caplog.at_level(logging.ERROR):
+ dbus_presenter.present(fake_notification)
+
+ message = (
+ 'Notification error from libnotify adapter: '
+ f'{self.NO_REPLY_ERROR.errorMessage()}'
)
- with pytest.raises(notification.DBusError):
+ assert message in caplog.messages
+ assert dbus_presenter._adapter is None # adapter dropped
+
+ @pytest.mark.parametrize("error, exctype", [
+ (NO_REPLY_ERROR, notification.DBusError),
+ (FATAL_ERROR, notification.Error),
+ ])
+ def test_capabilities_error(
+ self,
+ dbus_adapter_patches,
+ monkeypatch,
+ error,
+ exctype,
+ ):
+ monkeypatch.setattr(FakeDBusInterface, "CAPABILITIES_REPLY", error)
+ with pytest.raises(exctype):
notification.DBusNotificationAdapter()
+
+ @pytest.mark.parametrize("error", [NO_REPLY_ERROR, FATAL_ERROR],
+ ids=lambda e: e.errorName())
+ def test_capabilities_error_presenter(
+ self,
+ dbus_presenter,
+ fake_notification,
+ monkeypatch,
+ caplog,
+ error,
+ ):
+ monkeypatch.setattr(FakeDBusInterface, "CAPABILITIES_REPLY", error)
+ dbus_presenter.present(fake_notification)
+ message = (
+ 'Failed to initialize libnotify notification adapter: '
+ f'{error.errorName()}: {error.errorMessage()}'
+ )
+ assert message in caplog.messages
+
+ assert isinstance(dbus_presenter._adapter, FakeNotificationAdapter)
+ assert dbus_presenter._adapter.presented == [fake_notification]