More IPC tests.

This commit is contained in:
Florian Bruhin 2015-09-02 20:40:41 +02:00
parent 18af0b4b35
commit a63f0d5409

View File

@ -27,9 +27,9 @@ from unittest import mock
import pytest import pytest
from PyQt5.QtNetwork import QLocalServer, QLocalSocket from PyQt5.QtNetwork import QLocalServer, QLocalSocket
from PyQt5.QtTest import QSignalSpy from PyQt5.QtTest import QSignalSpy
from PyQt5.QtCore import QIODevice
from qutebrowser.misc import ipc from qutebrowser.misc import ipc
from helpers import stubs
Args = collections.namedtuple('Args', 'basedir') Args = collections.namedtuple('Args', 'basedir')
@ -67,6 +67,68 @@ def qlocalsocket(qapp):
assert disconnected assert disconnected
class FakeSocket:
"""A stub for a QLocalSocket.
Args:
_can_read_line_val: The value returned for canReadLine().
_error_val: The value returned for error().
_state_val: The value returned for state().
deleted: Set to True if deleteLater() was called.
"""
def __init__(self, *, error=QLocalSocket.UnknownSocketError, state=None,
data=None):
self._error_val = error
self._state_val = state
self._data = data
self.readyRead = stubs.FakeSignal('readyRead')
self.disconnected = stubs.FakeSignal('disconnected')
self.error = stubs.FakeSignal('error', func=self._error)
self.deleted = False
def _error(self):
return self._error_val
def state(self):
return self._state_val
def canReadLine(self):
return bool(self._data)
def readLine(self):
firstline, mid, rest = self._data.partition(b'\n')
self._data = rest
return firstline + mid
def deleteLater(self):
self.deleted = True
def errorString(self):
return "Error string"
def abort(self):
pass
class FakeServer:
def __init__(self, socket):
self._socket = socket
def nextPendingConnection(self):
socket = self._socket
self._socket = None
return socket
def close(self):
pass
def deleteLater(self):
pass
def test_getpass_getuser(): def test_getpass_getuser():
"""Make sure getpass.getuser() returns something sensible.""" """Make sure getpass.getuser() returns something sensible."""
assert getpass.getuser() assert getpass.getuser()
@ -92,8 +154,8 @@ class TestListen:
exc = ipc.ListenError(qlocalserver) exc = ipc.ListenError(qlocalserver)
assert exc.code == 2 assert exc.code == 2
assert exc.message == "QLocalServer::listen: Name error" assert exc.message == "QLocalServer::listen: Name error"
msg = ("Error while listening to IPC server: QLocalServer::listen: Name " msg = ("Error while listening to IPC server: QLocalServer::listen: "
"error (error 2)") "Name error (error 2)")
assert str(exc) == msg assert str(exc) == msg
def test_remove_error(self, ipc_server, monkeypatch): def test_remove_error(self, ipc_server, monkeypatch):
@ -163,6 +225,42 @@ class TestHandleConnection:
record = caplog.records()[0] record = caplog.records()[0]
assert record.message == "No new connection to handle." assert record.message == "No new connection to handle."
def test_disconnected_immediately(self, ipc_server, caplog):
socket = FakeSocket(state=QLocalSocket.UnconnectedState)
ipc_server._server = FakeServer(socket)
ipc_server.handle_connection()
msg = "Socket was disconnected immediately."
all_msgs = [r.message for r in caplog.records()]
assert msg in all_msgs
def test_error_immediately(self, ipc_server, caplog):
socket = FakeSocket(error=QLocalSocket.ConnectionError)
ipc_server._server = FakeServer(socket)
with pytest.raises(ipc.Error) as excinfo:
ipc_server.handle_connection()
exc_msg = 'Error while handling IPC connection: Error string (error 7)'
assert str(excinfo.value) == exc_msg
msg = "We got an error immediately."
all_msgs = [r.message for r in caplog.records()]
assert msg in all_msgs
def test_read_line_immediately(self, qtbot, ipc_server, caplog):
socket = FakeSocket(data=b'{"args": ["foo"]}\n')
ipc_server._server = FakeServer(socket)
spy = QSignalSpy(ipc_server.got_args)
with qtbot.waitSignal(ipc_server.got_args, raising=True):
ipc_server.handle_connection()
assert len(spy) == 1
assert spy[0][0] == ['foo']
all_msgs = [r.message for r in caplog.records()]
assert "We can read a line immediately." in all_msgs
class TestRealConnections: class TestRealConnections:
@ -174,20 +272,29 @@ class TestRealConnections:
yield qlocalsocket yield qlocalsocket
qlocalsocket.disconnectFromServer() qlocalsocket.disconnectFromServer()
def test_normal(self, qtbot, tmpdir, ipc_server): @pytest.mark.parametrize('has_cwd', [True, False])
def test_normal(self, qtbot, tmpdir, ipc_server, mocker, has_cwd):
ipc_server.listen() ipc_server.listen()
spy = QSignalSpy(ipc_server.got_args) spy = QSignalSpy(ipc_server.got_args)
error_spy = QSignalSpy(ipc_server.got_invalid_data) error_spy = QSignalSpy(ipc_server.got_invalid_data)
with qtbot.waitSignal(ipc_server.got_args, raising=True): with qtbot.waitSignal(ipc_server.got_args, raising=True):
with tmpdir.as_cwd(): with tmpdir.as_cwd():
if not has_cwd:
m = mocker.patch('qutebrowser.misc.ipc.os')
m.getcwd.side_effect = OSError
sent = ipc.send_to_running_instance('qutebrowser-test', sent = ipc.send_to_running_instance('qutebrowser-test',
['foo']) ['foo'])
assert sent assert sent
assert len(spy) == 1 assert len(spy) == 1
assert not error_spy assert not error_spy
assert spy[0] == [['foo'], str(tmpdir)]
if has_cwd:
expected_cwd = str(tmpdir)
else:
expected_cwd = ''
assert spy[0] == [['foo'], expected_cwd]
def test_double_connection(self, qtbot, connected_socket, ipc_server, def test_double_connection(self, qtbot, connected_socket, ipc_server,
caplog): caplog):
@ -202,7 +309,7 @@ class TestRealConnections:
"handling another one.") "handling another one.")
assert message in [rec.message for rec in caplog.records()] assert message in [rec.message for rec in caplog.records()]
def test_disconnected_immediately(self, qtbot, connected_socket, def test_disconnected_without_data(self, qtbot, connected_socket,
ipc_server, caplog): ipc_server, caplog):
"""Disconnect without sending data. """Disconnect without sending data.
@ -219,9 +326,11 @@ class TestRealConnections:
b'{"is this invalid json?": true\n', b'{"is this invalid json?": true\n',
b'{"valid json without args": true}\n', b'{"valid json without args": true}\n',
]) ])
def test_invalid_data(self, qtbot, ipc_server, connected_socket, caplog, data): def test_invalid_data(self, qtbot, ipc_server, connected_socket, caplog,
data):
signals = [ipc_server.got_invalid_data, connected_socket.disconnected]
with caplog.atLevel(logging.ERROR): with caplog.atLevel(logging.ERROR):
with qtbot.waitSignal(ipc_server.got_invalid_data, raising=True): with qtbot.waitSignals(signals, raising=True):
connected_socket.write(data) connected_socket.write(data)
messages = [r.message for r in caplog.records()] messages = [r.message for r in caplog.records()]
assert messages[-1] == 'Ignoring invalid IPC data.' assert messages[-1] == 'Ignoring invalid IPC data.'
@ -235,6 +344,7 @@ class TestRealConnections:
connected_socket.write(b'{"args": ["one"]}\n{"args": ["two"]}\n') connected_socket.write(b'{"args": ["one"]}\n{"args": ["two"]}\n')
assert len(spy) == 2 assert len(spy) == 2
assert not error_spy
assert spy[0][0] == ['one'] assert spy[0][0] == ['one']
assert spy[1][0] == ['two'] assert spy[1][0] == ['two']