@@ -109,6 +109,54 @@ def test_connection_lost(self):
109
109
test_utils .run_briefly (self .loop )
110
110
self .assertIsInstance (waiter .exception (), ConnectionAbortedError )
111
111
112
+ def test_connection_lost_when_busy (self ):
113
+ # gh-118950: SSLProtocol.connection_lost not being called when OSError
114
+ # is thrown on asyncio.write.
115
+ sock = mock .Mock ()
116
+ sock .fileno = mock .Mock (return_value = 12345 )
117
+ sock .send = mock .Mock (side_effect = BrokenPipeError )
118
+
119
+ # construct StreamWriter chain that contains loop dependant logic this emulates
120
+ # what _make_ssl_transport() does in BaseSelectorEventLoop
121
+ reader = asyncio .StreamReader (limit = 2 ** 16 , loop = self .loop )
122
+ protocol = asyncio .StreamReaderProtocol (reader , loop = self .loop )
123
+ ssl_proto = self .ssl_protocol (proto = protocol )
124
+
125
+ # emulate reading decompressed data
126
+ sslobj = mock .Mock ()
127
+ sslobj .read .side_effect = ssl .SSLWantReadError
128
+ sslobj .write .side_effect = ssl .SSLWantReadError
129
+ ssl_proto ._sslobj = sslobj
130
+
131
+ # emulate outgoing data
132
+ data = b'An interesting message'
133
+
134
+ outgoing = mock .Mock ()
135
+ outgoing .read = mock .Mock (return_value = data )
136
+ outgoing .pending = len (data )
137
+ ssl_proto ._outgoing = outgoing
138
+
139
+ # use correct socket transport to initialize the SSLProtocol
140
+ self .loop ._make_socket_transport (sock , ssl_proto )
141
+
142
+ transport = ssl_proto ._app_transport
143
+ writer = asyncio .StreamWriter (transport , protocol , reader , self .loop )
144
+
145
+ async def main ():
146
+ # writes data to transport
147
+ async def write ():
148
+ writer .write (data )
149
+ await writer .drain ()
150
+
151
+ # try to write for the first time
152
+ await write ()
153
+ # try to write for the second time, this raises as the connection_lost
154
+ # callback should be done with error
155
+ with self .assertRaises (ConnectionResetError ):
156
+ await write ()
157
+
158
+ self .loop .run_until_complete (main ())
159
+
112
160
def test_close_during_handshake (self ):
113
161
# bpo-29743 Closing transport during handshake process leaks socket
114
162
waiter = self .loop .create_future ()
0 commit comments