mirror of
https://github.com/python/cpython.git
synced 2025-07-16 15:55:18 +00:00
asyncio, Tulip issue 139: Improve error messages on "fatal errors"
Mention if the error was caused by a read or a write, and be more specific on the object (ex: "pipe transport" instead of "transport").
This commit is contained in:
parent
c098241342
commit
065ca25aae
6 changed files with 64 additions and 38 deletions
|
@ -53,10 +53,10 @@ class _ProactorBasePipeTransport(transports._FlowControlMixin,
|
||||||
if self._read_fut is not None:
|
if self._read_fut is not None:
|
||||||
self._read_fut.cancel()
|
self._read_fut.cancel()
|
||||||
|
|
||||||
def _fatal_error(self, exc):
|
def _fatal_error(self, exc, message='Fatal error on pipe transport'):
|
||||||
if not isinstance(exc, (BrokenPipeError, ConnectionResetError)):
|
if not isinstance(exc, (BrokenPipeError, ConnectionResetError)):
|
||||||
self._loop.call_exception_handler({
|
self._loop.call_exception_handler({
|
||||||
'message': 'Fatal transport error',
|
'message': message,
|
||||||
'exception': exc,
|
'exception': exc,
|
||||||
'transport': self,
|
'transport': self,
|
||||||
'protocol': self._protocol,
|
'protocol': self._protocol,
|
||||||
|
@ -151,11 +151,11 @@ class _ProactorReadPipeTransport(_ProactorBasePipeTransport,
|
||||||
self._read_fut = self._loop._proactor.recv(self._sock, 4096)
|
self._read_fut = self._loop._proactor.recv(self._sock, 4096)
|
||||||
except ConnectionAbortedError as exc:
|
except ConnectionAbortedError as exc:
|
||||||
if not self._closing:
|
if not self._closing:
|
||||||
self._fatal_error(exc)
|
self._fatal_error(exc, 'Fatal read error on pipe transport')
|
||||||
except ConnectionResetError as exc:
|
except ConnectionResetError as exc:
|
||||||
self._force_close(exc)
|
self._force_close(exc)
|
||||||
except OSError as exc:
|
except OSError as exc:
|
||||||
self._fatal_error(exc)
|
self._fatal_error(exc, 'Fatal read error on pipe transport')
|
||||||
except futures.CancelledError:
|
except futures.CancelledError:
|
||||||
if not self._closing:
|
if not self._closing:
|
||||||
raise
|
raise
|
||||||
|
@ -246,7 +246,7 @@ class _ProactorBaseWritePipeTransport(_ProactorBasePipeTransport,
|
||||||
except ConnectionResetError as exc:
|
except ConnectionResetError as exc:
|
||||||
self._force_close(exc)
|
self._force_close(exc)
|
||||||
except OSError as exc:
|
except OSError as exc:
|
||||||
self._fatal_error(exc)
|
self._fatal_error(exc, 'Fatal write error on pipe transport')
|
||||||
|
|
||||||
def can_write_eof(self):
|
def can_write_eof(self):
|
||||||
return True
|
return True
|
||||||
|
|
|
@ -377,11 +377,11 @@ class _SelectorTransport(transports._FlowControlMixin,
|
||||||
self._conn_lost += 1
|
self._conn_lost += 1
|
||||||
self._loop.call_soon(self._call_connection_lost, None)
|
self._loop.call_soon(self._call_connection_lost, None)
|
||||||
|
|
||||||
def _fatal_error(self, exc):
|
def _fatal_error(self, exc, message='Fatal error on transport'):
|
||||||
# Should be called from exception handler only.
|
# Should be called from exception handler only.
|
||||||
if not isinstance(exc, (BrokenPipeError, ConnectionResetError)):
|
if not isinstance(exc, (BrokenPipeError, ConnectionResetError)):
|
||||||
self._loop.call_exception_handler({
|
self._loop.call_exception_handler({
|
||||||
'message': 'Fatal transport error',
|
'message': message,
|
||||||
'exception': exc,
|
'exception': exc,
|
||||||
'transport': self,
|
'transport': self,
|
||||||
'protocol': self._protocol,
|
'protocol': self._protocol,
|
||||||
|
@ -452,7 +452,7 @@ class _SelectorSocketTransport(_SelectorTransport):
|
||||||
except (BlockingIOError, InterruptedError):
|
except (BlockingIOError, InterruptedError):
|
||||||
pass
|
pass
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
self._fatal_error(exc)
|
self._fatal_error(exc, 'Fatal read error on socket transport')
|
||||||
else:
|
else:
|
||||||
if data:
|
if data:
|
||||||
self._protocol.data_received(data)
|
self._protocol.data_received(data)
|
||||||
|
@ -488,7 +488,7 @@ class _SelectorSocketTransport(_SelectorTransport):
|
||||||
except (BlockingIOError, InterruptedError):
|
except (BlockingIOError, InterruptedError):
|
||||||
pass
|
pass
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
self._fatal_error(exc)
|
self._fatal_error(exc, 'Fatal write error on socket transport')
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
data = data[n:]
|
data = data[n:]
|
||||||
|
@ -511,7 +511,7 @@ class _SelectorSocketTransport(_SelectorTransport):
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
self._loop.remove_writer(self._sock_fd)
|
self._loop.remove_writer(self._sock_fd)
|
||||||
self._buffer.clear()
|
self._buffer.clear()
|
||||||
self._fatal_error(exc)
|
self._fatal_error(exc, 'Fatal write error on socket transport')
|
||||||
else:
|
else:
|
||||||
if n:
|
if n:
|
||||||
del self._buffer[:n]
|
del self._buffer[:n]
|
||||||
|
@ -678,7 +678,7 @@ class _SelectorSslTransport(_SelectorTransport):
|
||||||
self._loop.remove_reader(self._sock_fd)
|
self._loop.remove_reader(self._sock_fd)
|
||||||
self._loop.add_writer(self._sock_fd, self._write_ready)
|
self._loop.add_writer(self._sock_fd, self._write_ready)
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
self._fatal_error(exc)
|
self._fatal_error(exc, 'Fatal read error on SSL transport')
|
||||||
else:
|
else:
|
||||||
if data:
|
if data:
|
||||||
self._protocol.data_received(data)
|
self._protocol.data_received(data)
|
||||||
|
@ -712,7 +712,7 @@ class _SelectorSslTransport(_SelectorTransport):
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
self._loop.remove_writer(self._sock_fd)
|
self._loop.remove_writer(self._sock_fd)
|
||||||
self._buffer.clear()
|
self._buffer.clear()
|
||||||
self._fatal_error(exc)
|
self._fatal_error(exc, 'Fatal write error on SSL transport')
|
||||||
return
|
return
|
||||||
|
|
||||||
if n:
|
if n:
|
||||||
|
@ -770,7 +770,7 @@ class _SelectorDatagramTransport(_SelectorTransport):
|
||||||
except OSError as exc:
|
except OSError as exc:
|
||||||
self._protocol.error_received(exc)
|
self._protocol.error_received(exc)
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
self._fatal_error(exc)
|
self._fatal_error(exc, 'Fatal read error on datagram transport')
|
||||||
else:
|
else:
|
||||||
self._protocol.datagram_received(data, addr)
|
self._protocol.datagram_received(data, addr)
|
||||||
|
|
||||||
|
@ -805,7 +805,8 @@ class _SelectorDatagramTransport(_SelectorTransport):
|
||||||
self._protocol.error_received(exc)
|
self._protocol.error_received(exc)
|
||||||
return
|
return
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
self._fatal_error(exc)
|
self._fatal_error(exc,
|
||||||
|
'Fatal write error on datagram transport')
|
||||||
return
|
return
|
||||||
|
|
||||||
# Ensure that what we buffer is immutable.
|
# Ensure that what we buffer is immutable.
|
||||||
|
@ -827,7 +828,8 @@ class _SelectorDatagramTransport(_SelectorTransport):
|
||||||
self._protocol.error_received(exc)
|
self._protocol.error_received(exc)
|
||||||
return
|
return
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
self._fatal_error(exc)
|
self._fatal_error(exc,
|
||||||
|
'Fatal write error on datagram transport')
|
||||||
return
|
return
|
||||||
|
|
||||||
self._maybe_resume_protocol() # May append to buffer.
|
self._maybe_resume_protocol() # May append to buffer.
|
||||||
|
|
|
@ -271,7 +271,7 @@ class _UnixReadPipeTransport(transports.ReadTransport):
|
||||||
except (BlockingIOError, InterruptedError):
|
except (BlockingIOError, InterruptedError):
|
||||||
pass
|
pass
|
||||||
except OSError as exc:
|
except OSError as exc:
|
||||||
self._fatal_error(exc)
|
self._fatal_error(exc, 'Fatal read error on pipe transport')
|
||||||
else:
|
else:
|
||||||
if data:
|
if data:
|
||||||
self._protocol.data_received(data)
|
self._protocol.data_received(data)
|
||||||
|
@ -291,11 +291,11 @@ class _UnixReadPipeTransport(transports.ReadTransport):
|
||||||
if not self._closing:
|
if not self._closing:
|
||||||
self._close(None)
|
self._close(None)
|
||||||
|
|
||||||
def _fatal_error(self, exc):
|
def _fatal_error(self, exc, message='Fatal error on pipe transport'):
|
||||||
# should be called by exception handler only
|
# should be called by exception handler only
|
||||||
if not (isinstance(exc, OSError) and exc.errno == errno.EIO):
|
if not (isinstance(exc, OSError) and exc.errno == errno.EIO):
|
||||||
self._loop.call_exception_handler({
|
self._loop.call_exception_handler({
|
||||||
'message': 'Fatal transport error',
|
'message': message,
|
||||||
'exception': exc,
|
'exception': exc,
|
||||||
'transport': self,
|
'transport': self,
|
||||||
'protocol': self._protocol,
|
'protocol': self._protocol,
|
||||||
|
@ -381,7 +381,7 @@ class _UnixWritePipeTransport(transports._FlowControlMixin,
|
||||||
n = 0
|
n = 0
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
self._conn_lost += 1
|
self._conn_lost += 1
|
||||||
self._fatal_error(exc)
|
self._fatal_error(exc, 'Fatal write error on pipe transport')
|
||||||
return
|
return
|
||||||
if n == len(data):
|
if n == len(data):
|
||||||
return
|
return
|
||||||
|
@ -406,7 +406,7 @@ class _UnixWritePipeTransport(transports._FlowControlMixin,
|
||||||
# Remove writer here, _fatal_error() doesn't it
|
# Remove writer here, _fatal_error() doesn't it
|
||||||
# because _buffer is empty.
|
# because _buffer is empty.
|
||||||
self._loop.remove_writer(self._fileno)
|
self._loop.remove_writer(self._fileno)
|
||||||
self._fatal_error(exc)
|
self._fatal_error(exc, 'Fatal write error on pipe transport')
|
||||||
else:
|
else:
|
||||||
if n == len(data):
|
if n == len(data):
|
||||||
self._loop.remove_writer(self._fileno)
|
self._loop.remove_writer(self._fileno)
|
||||||
|
@ -443,11 +443,11 @@ class _UnixWritePipeTransport(transports._FlowControlMixin,
|
||||||
def abort(self):
|
def abort(self):
|
||||||
self._close(None)
|
self._close(None)
|
||||||
|
|
||||||
def _fatal_error(self, exc):
|
def _fatal_error(self, exc, message='Fatal error on pipe transport'):
|
||||||
# should be called by exception handler only
|
# should be called by exception handler only
|
||||||
if not isinstance(exc, (BrokenPipeError, ConnectionResetError)):
|
if not isinstance(exc, (BrokenPipeError, ConnectionResetError)):
|
||||||
self._loop.call_exception_handler({
|
self._loop.call_exception_handler({
|
||||||
'message': 'Fatal transport error',
|
'message': message,
|
||||||
'exception': exc,
|
'exception': exc,
|
||||||
'transport': self,
|
'transport': self,
|
||||||
'protocol': self._protocol,
|
'protocol': self._protocol,
|
||||||
|
|
|
@ -69,7 +69,9 @@ class ProactorSocketTransportTests(unittest.TestCase):
|
||||||
tr = _ProactorSocketTransport(self.loop, self.sock, self.protocol)
|
tr = _ProactorSocketTransport(self.loop, self.sock, self.protocol)
|
||||||
tr._fatal_error = unittest.mock.Mock()
|
tr._fatal_error = unittest.mock.Mock()
|
||||||
tr._loop_reading()
|
tr._loop_reading()
|
||||||
tr._fatal_error.assert_called_with(err)
|
tr._fatal_error.assert_called_with(
|
||||||
|
err,
|
||||||
|
'Fatal read error on pipe transport')
|
||||||
|
|
||||||
def test_loop_reading_aborted_closing(self):
|
def test_loop_reading_aborted_closing(self):
|
||||||
self.loop._proactor.recv.side_effect = ConnectionAbortedError()
|
self.loop._proactor.recv.side_effect = ConnectionAbortedError()
|
||||||
|
@ -105,7 +107,9 @@ class ProactorSocketTransportTests(unittest.TestCase):
|
||||||
tr = _ProactorSocketTransport(self.loop, self.sock, self.protocol)
|
tr = _ProactorSocketTransport(self.loop, self.sock, self.protocol)
|
||||||
tr._fatal_error = unittest.mock.Mock()
|
tr._fatal_error = unittest.mock.Mock()
|
||||||
tr._loop_reading()
|
tr._loop_reading()
|
||||||
tr._fatal_error.assert_called_with(err)
|
tr._fatal_error.assert_called_with(
|
||||||
|
err,
|
||||||
|
'Fatal read error on pipe transport')
|
||||||
|
|
||||||
def test_write(self):
|
def test_write(self):
|
||||||
tr = _ProactorSocketTransport(self.loop, self.sock, self.protocol)
|
tr = _ProactorSocketTransport(self.loop, self.sock, self.protocol)
|
||||||
|
@ -142,7 +146,9 @@ class ProactorSocketTransportTests(unittest.TestCase):
|
||||||
tr._fatal_error = unittest.mock.Mock()
|
tr._fatal_error = unittest.mock.Mock()
|
||||||
tr._buffer = [b'da', b'ta']
|
tr._buffer = [b'da', b'ta']
|
||||||
tr._loop_writing()
|
tr._loop_writing()
|
||||||
tr._fatal_error.assert_called_with(err)
|
tr._fatal_error.assert_called_with(
|
||||||
|
err,
|
||||||
|
'Fatal write error on pipe transport')
|
||||||
tr._conn_lost = 1
|
tr._conn_lost = 1
|
||||||
|
|
||||||
tr.write(b'data')
|
tr.write(b'data')
|
||||||
|
|
|
@ -655,7 +655,7 @@ class SelectorTransportTests(unittest.TestCase):
|
||||||
|
|
||||||
m_exc.assert_called_with(
|
m_exc.assert_called_with(
|
||||||
test_utils.MockPattern(
|
test_utils.MockPattern(
|
||||||
'Fatal transport error\nprotocol:.*\ntransport:.*'),
|
'Fatal error on transport\nprotocol:.*\ntransport:.*'),
|
||||||
exc_info=(OSError, MOCK_ANY, MOCK_ANY))
|
exc_info=(OSError, MOCK_ANY, MOCK_ANY))
|
||||||
|
|
||||||
tr._force_close.assert_called_with(exc)
|
tr._force_close.assert_called_with(exc)
|
||||||
|
@ -785,7 +785,9 @@ class SelectorSocketTransportTests(unittest.TestCase):
|
||||||
transport._fatal_error = unittest.mock.Mock()
|
transport._fatal_error = unittest.mock.Mock()
|
||||||
transport._read_ready()
|
transport._read_ready()
|
||||||
|
|
||||||
transport._fatal_error.assert_called_with(err)
|
transport._fatal_error.assert_called_with(
|
||||||
|
err,
|
||||||
|
'Fatal read error on socket transport')
|
||||||
|
|
||||||
def test_write(self):
|
def test_write(self):
|
||||||
data = b'data'
|
data = b'data'
|
||||||
|
@ -898,7 +900,9 @@ class SelectorSocketTransportTests(unittest.TestCase):
|
||||||
self.loop, self.sock, self.protocol)
|
self.loop, self.sock, self.protocol)
|
||||||
transport._fatal_error = unittest.mock.Mock()
|
transport._fatal_error = unittest.mock.Mock()
|
||||||
transport.write(data)
|
transport.write(data)
|
||||||
transport._fatal_error.assert_called_with(err)
|
transport._fatal_error.assert_called_with(
|
||||||
|
err,
|
||||||
|
'Fatal write error on socket transport')
|
||||||
transport._conn_lost = 1
|
transport._conn_lost = 1
|
||||||
|
|
||||||
self.sock.reset_mock()
|
self.sock.reset_mock()
|
||||||
|
@ -1001,7 +1005,9 @@ class SelectorSocketTransportTests(unittest.TestCase):
|
||||||
transport._fatal_error = unittest.mock.Mock()
|
transport._fatal_error = unittest.mock.Mock()
|
||||||
transport._buffer.extend(b'data')
|
transport._buffer.extend(b'data')
|
||||||
transport._write_ready()
|
transport._write_ready()
|
||||||
transport._fatal_error.assert_called_with(err)
|
transport._fatal_error.assert_called_with(
|
||||||
|
err,
|
||||||
|
'Fatal write error on socket transport')
|
||||||
|
|
||||||
@unittest.mock.patch('asyncio.base_events.logger')
|
@unittest.mock.patch('asyncio.base_events.logger')
|
||||||
def test_write_ready_exception_and_close(self, m_log):
|
def test_write_ready_exception_and_close(self, m_log):
|
||||||
|
@ -1237,7 +1243,9 @@ class SelectorSslTransportTests(unittest.TestCase):
|
||||||
transport = self._make_one()
|
transport = self._make_one()
|
||||||
transport._fatal_error = unittest.mock.Mock()
|
transport._fatal_error = unittest.mock.Mock()
|
||||||
transport._read_ready()
|
transport._read_ready()
|
||||||
transport._fatal_error.assert_called_with(err)
|
transport._fatal_error.assert_called_with(
|
||||||
|
err,
|
||||||
|
'Fatal read error on SSL transport')
|
||||||
|
|
||||||
def test_write_ready_send(self):
|
def test_write_ready_send(self):
|
||||||
self.sslsock.send.return_value = 4
|
self.sslsock.send.return_value = 4
|
||||||
|
@ -1319,7 +1327,9 @@ class SelectorSslTransportTests(unittest.TestCase):
|
||||||
transport._buffer = list_to_buffer([b'data'])
|
transport._buffer = list_to_buffer([b'data'])
|
||||||
transport._fatal_error = unittest.mock.Mock()
|
transport._fatal_error = unittest.mock.Mock()
|
||||||
transport._write_ready()
|
transport._write_ready()
|
||||||
transport._fatal_error.assert_called_with(err)
|
transport._fatal_error.assert_called_with(
|
||||||
|
err,
|
||||||
|
'Fatal write error on SSL transport')
|
||||||
self.assertEqual(list_to_buffer(), transport._buffer)
|
self.assertEqual(list_to_buffer(), transport._buffer)
|
||||||
|
|
||||||
def test_write_ready_read_wants_write(self):
|
def test_write_ready_read_wants_write(self):
|
||||||
|
@ -1407,7 +1417,9 @@ class SelectorDatagramTransportTests(unittest.TestCase):
|
||||||
transport._fatal_error = unittest.mock.Mock()
|
transport._fatal_error = unittest.mock.Mock()
|
||||||
transport._read_ready()
|
transport._read_ready()
|
||||||
|
|
||||||
transport._fatal_error.assert_called_with(err)
|
transport._fatal_error.assert_called_with(
|
||||||
|
err,
|
||||||
|
'Fatal read error on datagram transport')
|
||||||
|
|
||||||
def test_read_ready_oserr(self):
|
def test_read_ready_oserr(self):
|
||||||
transport = _SelectorDatagramTransport(
|
transport = _SelectorDatagramTransport(
|
||||||
|
@ -1517,7 +1529,9 @@ class SelectorDatagramTransportTests(unittest.TestCase):
|
||||||
transport.sendto(data, ())
|
transport.sendto(data, ())
|
||||||
|
|
||||||
self.assertTrue(transport._fatal_error.called)
|
self.assertTrue(transport._fatal_error.called)
|
||||||
transport._fatal_error.assert_called_with(err)
|
transport._fatal_error.assert_called_with(
|
||||||
|
err,
|
||||||
|
'Fatal write error on datagram transport')
|
||||||
transport._conn_lost = 1
|
transport._conn_lost = 1
|
||||||
|
|
||||||
transport._address = ('123',)
|
transport._address = ('123',)
|
||||||
|
@ -1633,7 +1647,9 @@ class SelectorDatagramTransportTests(unittest.TestCase):
|
||||||
transport._buffer.append((b'data', ()))
|
transport._buffer.append((b'data', ()))
|
||||||
transport._sendto_ready()
|
transport._sendto_ready()
|
||||||
|
|
||||||
transport._fatal_error.assert_called_with(err)
|
transport._fatal_error.assert_called_with(
|
||||||
|
err,
|
||||||
|
'Fatal write error on datagram transport')
|
||||||
|
|
||||||
def test_sendto_ready_error_received(self):
|
def test_sendto_ready_error_received(self):
|
||||||
self.sock.sendto.side_effect = ConnectionRefusedError
|
self.sock.sendto.side_effect = ConnectionRefusedError
|
||||||
|
@ -1667,7 +1683,7 @@ class SelectorDatagramTransportTests(unittest.TestCase):
|
||||||
self.assertFalse(self.protocol.error_received.called)
|
self.assertFalse(self.protocol.error_received.called)
|
||||||
m_exc.assert_called_with(
|
m_exc.assert_called_with(
|
||||||
test_utils.MockPattern(
|
test_utils.MockPattern(
|
||||||
'Fatal transport error\nprotocol:.*\ntransport:.*'),
|
'Fatal error on transport\nprotocol:.*\ntransport:.*'),
|
||||||
exc_info=(ConnectionRefusedError, MOCK_ANY, MOCK_ANY))
|
exc_info=(ConnectionRefusedError, MOCK_ANY, MOCK_ANY))
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -365,7 +365,7 @@ class UnixReadPipeTransportTests(unittest.TestCase):
|
||||||
tr._close.assert_called_with(err)
|
tr._close.assert_called_with(err)
|
||||||
m_logexc.assert_called_with(
|
m_logexc.assert_called_with(
|
||||||
test_utils.MockPattern(
|
test_utils.MockPattern(
|
||||||
'Fatal transport error\nprotocol:.*\ntransport:.*'),
|
'Fatal read error on pipe transport\nprotocol:.*\ntransport:.*'),
|
||||||
exc_info=(OSError, MOCK_ANY, MOCK_ANY))
|
exc_info=(OSError, MOCK_ANY, MOCK_ANY))
|
||||||
|
|
||||||
@unittest.mock.patch('os.read')
|
@unittest.mock.patch('os.read')
|
||||||
|
@ -558,7 +558,9 @@ class UnixWritePipeTransportTests(unittest.TestCase):
|
||||||
m_write.assert_called_with(5, b'data')
|
m_write.assert_called_with(5, b'data')
|
||||||
self.assertFalse(self.loop.writers)
|
self.assertFalse(self.loop.writers)
|
||||||
self.assertEqual([], tr._buffer)
|
self.assertEqual([], tr._buffer)
|
||||||
tr._fatal_error.assert_called_with(err)
|
tr._fatal_error.assert_called_with(
|
||||||
|
err,
|
||||||
|
'Fatal write error on pipe transport')
|
||||||
self.assertEqual(1, tr._conn_lost)
|
self.assertEqual(1, tr._conn_lost)
|
||||||
|
|
||||||
tr.write(b'data')
|
tr.write(b'data')
|
||||||
|
@ -660,7 +662,7 @@ class UnixWritePipeTransportTests(unittest.TestCase):
|
||||||
self.assertTrue(tr._closing)
|
self.assertTrue(tr._closing)
|
||||||
m_logexc.assert_called_with(
|
m_logexc.assert_called_with(
|
||||||
test_utils.MockPattern(
|
test_utils.MockPattern(
|
||||||
'Fatal transport error\nprotocol:.*\ntransport:.*'),
|
'Fatal write error on pipe transport\nprotocol:.*\ntransport:.*'),
|
||||||
exc_info=(OSError, MOCK_ANY, MOCK_ANY))
|
exc_info=(OSError, MOCK_ANY, MOCK_ANY))
|
||||||
self.assertEqual(1, tr._conn_lost)
|
self.assertEqual(1, tr._conn_lost)
|
||||||
test_utils.run_briefly(self.loop)
|
test_utils.run_briefly(self.loop)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue