blob: 5e25f1a90bf98a88afa5db4ea1fbd1a3e575d3ed [file] [log] [blame]
Jens Geyer72a714e2025-08-26 22:12:07 +02001#
2# Licensed to the Apache Software Foundation (ASF) under one
3# or more contributor license agreements. See the NOTICE file
4# distributed with this work for additional information
5# regarding copyright ownership. The ASF licenses this file
6# to you under the Apache License, Version 2.0 (the
7# "License"); you may not use this file except in compliance
8# with the License. You may obtain a copy of the License at
9#
10# http://www.apache.org/licenses/LICENSE-2.0
11#
12# Unless required by applicable law or agreed to in writing,
13# software distributed under the License is distributed on an
14# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15# KIND, either express or implied. See the License for the
16# specific language governing permissions and limitations
17# under the License.
18#
19
Neil Williams01d53f42020-07-07 07:27:29 -070020import errno
Gregg Donovan62ec9292026-01-29 16:51:37 -050021import time
Neil Williams01d53f42020-07-07 07:27:29 -070022import unittest
23
24from test_sslsocket import ServerAcceptor
25
26import _import_local_thrift # noqa
27
28from thrift.transport.TSocket import TServerSocket
29from thrift.transport.TSocket import TSocket
30from thrift.transport.TTransport import TTransportException
31
32
33class TSocketTest(unittest.TestCase):
Michael Smith87079492025-11-14 13:47:42 -080034 def test_failed_connection_raises_exception(self):
35 sock = TSocket(host="localhost", port=60606) # unused port
36 with self.assertRaises(TTransportException) as ctx:
37 sock.open()
38 exc = ctx.exception
39 self.assertEqual(exc.type, TTransportException.NOT_OPEN)
40 self.assertIn("Could not connect to any of", exc.message)
41 self.assertIsNotNone(exc.inner)
42 self.assertIn("Connection refused", str(exc.inner))
43
bwangelme0ed4a1d2024-04-15 12:17:40 +080044 def test_socket_readtimeout_exception(self):
45 acc = ServerAcceptor(TServerSocket(port=0))
46 acc.start()
47
48 sock = TSocket(host="localhost", port=acc.port)
49 sock.open()
50 sock.setTimeout(1)
51 sock.write(b"sleep")
52
53 with self.assertRaises(TTransportException) as ctx:
54 sock.read(5)
55 exc = ctx.exception
56 self.assertEqual(exc.message, "read timeout")
57
58 acc.client.close() # this also blocks until the other thread is done
59 acc.close()
60 sock.close()
61
Neil Williams01d53f42020-07-07 07:27:29 -070062 def test_isOpen_checks_for_readability(self):
63 # https://docs.python.org/3/library/socket.html#notes-on-socket-timeouts
64 # https://docs.python.org/3/library/socket.html#socket.socket.settimeout
65 timeouts = [
66 None, # blocking mode
67 0, # non-blocking mode
68 1.0, # timeout mode
69 ]
70
71 for timeout in timeouts:
72 acc = ServerAcceptor(TServerSocket(port=0))
73 acc.start()
74
75 sock = TSocket(host="localhost", port=acc.port)
Michael Smithe3eb9af2022-06-08 17:23:27 -070076 self.assertFalse(sock.isOpen())
Neil Williams01d53f42020-07-07 07:27:29 -070077 sock.open()
78 sock.setTimeout(timeout)
79
80 # the socket shows as open immediately after connecting
81 self.assertTrue(sock.isOpen())
82
83 # and remains open during usage
84 sock.write(b"hello")
85 self.assertTrue(sock.isOpen())
86 while True:
87 try:
88 sock.read(5)
89 except TTransportException as exc:
90 if exc.inner.errno == errno.EAGAIN:
91 # try again when we're in non-blocking mode
92 continue
93 raise
94 break
95 self.assertTrue(sock.isOpen())
96
97 # once the server side closes, it no longer shows open
98 acc.client.close() # this also blocks until the other thread is done
99 acc.close()
Neil Williams01d53f42020-07-07 07:27:29 -0700100
Csaba Ringhoferefe5e022024-08-23 14:08:35 +0200101 self.assertIsNotNone(sock.handle)
Gregg Donovan62ec9292026-01-29 16:51:37 -0500102 # Give the kernel a moment to propagate FIN before asserting.
103 deadline = time.monotonic() + 0.5
104 while sock.isOpen() and time.monotonic() < deadline:
105 time.sleep(0.01)
106 self.assertFalse(sock.isOpen(), "socket still open after 0.5s")
Csaba Ringhoferefe5e022024-08-23 14:08:35 +0200107 # after isOpen() returned False the socket should be closed (THRIFT-5813)
108 self.assertIsNone(sock.handle)
Neil Williams01d53f42020-07-07 07:27:29 -0700109
110
111if __name__ == "__main__":
112 unittest.main()