38
38
from lib .server import DEFAULT_SNAPSHOT_NAME
39
39
from lib .test import Test
40
40
from lib .utils import bytes_to_str
41
- from lib .utils import find_port
42
41
from lib .utils import extract_schema_from_snapshot
43
42
from lib .utils import format_process
44
43
from lib .utils import safe_makedirs
@@ -598,7 +597,7 @@ def _admin(self, port):
598
597
del self .admin
599
598
if not hasattr (self , 'tests_type' ):
600
599
self .tests_type = 'lua'
601
- self .admin = CON_SWITCH [self .tests_type ](' localhost' , port )
600
+ self .admin = CON_SWITCH [self .tests_type ](self . localhost , port )
602
601
603
602
@property
604
603
def _iproto (self ):
@@ -610,7 +609,7 @@ def _iproto(self):
610
609
def _iproto (self , port ):
611
610
if hasattr (self , 'iproto' ):
612
611
del self .iproto
613
- self .iproto = BoxConnection (' localhost' , port )
612
+ self .iproto = BoxConnection (self . localhost , port )
614
613
615
614
@property
616
615
def log_des (self ):
@@ -672,9 +671,8 @@ def __init__(self, _ini=None, test_suite=None):
672
671
self .name = "default"
673
672
self .conf = {}
674
673
self .status = None
675
- # -----InitBasicVars-----#
676
674
self .core = ini ['core' ]
677
-
675
+ self . localhost = '127.0.0.1'
678
676
self .gdb = ini ['gdb' ]
679
677
self .lldb = ini ['lldb' ]
680
678
self .script = ini ['script' ]
@@ -686,10 +684,8 @@ def __init__(self, _ini=None, test_suite=None):
686
684
self .crash_detector = None
687
685
# use this option with inspector to enable crashes in test
688
686
self .crash_enabled = False
689
-
690
687
# set in from a test let test-run ignore server's crashes
691
688
self .crash_expected = False
692
-
693
689
# filled in {Test,FuncTest,LuaTest,PythonTest}.execute()
694
690
# or passed through execfile() for PythonTest
695
691
self .current_test = None
@@ -772,9 +768,10 @@ def install(self, silent=True):
772
768
if self .use_unix_sockets_iproto :
773
769
path = os .path .join (self .vardir , self .name + ".i" )
774
770
warn_unix_socket (path )
771
+ self .listen_uri = path
775
772
self ._iproto = path
776
773
else :
777
- self ._iproto = find_port ()
774
+ self .listen_uri = self . localhost + ':0'
778
775
779
776
# these sockets will be created by tarantool itself
780
777
path = os .path .join (self .vardir , self .name + '.control' )
@@ -872,7 +869,7 @@ def start(self, silent=True, wait=True, wait_load=True, rais=True, args=[],
872
869
color_log (prefix_each_line (' | ' , self .version ()) + '\n ' ,
873
870
schema = 'version' )
874
871
875
- os .putenv ("LISTEN" , self .iproto . uri )
872
+ os .putenv ("LISTEN" , self .listen_uri )
876
873
os .putenv ("ADMIN" , self .admin .uri )
877
874
if self .rpl_master :
878
875
os .putenv ("MASTER" , self .rpl_master .iproto .uri )
@@ -933,7 +930,12 @@ def start(self, silent=True, wait=True, wait_load=True, rais=True, args=[],
933
930
934
931
port = self .admin .port
935
932
self .admin .disconnect ()
936
- self .admin = CON_SWITCH [self .tests_type ]('localhost' , port )
933
+ self .admin = CON_SWITCH [self .tests_type ](self .localhost , port )
934
+
935
+ if not self .use_unix_sockets_iproto :
936
+ if wait and wait_load and not self .crash_expected :
937
+ self ._iproto = self .get_iproto_port ()
938
+
937
939
self .status = 'started'
938
940
939
941
# Verify that the schema actually was not upgraded.
@@ -1144,7 +1146,7 @@ def wait_until_started(self, wait_load=True, deadline=None):
1144
1146
self .wait_load (deadline )
1145
1147
while not deadline or time .time () < deadline :
1146
1148
try :
1147
- temp = AdminConnection (' localhost' , self .admin .port )
1149
+ temp = AdminConnection (self . localhost , self .admin .port )
1148
1150
if not wait_load :
1149
1151
ans = yaml .safe_load (temp .execute ("2 + 2" ))
1150
1152
color_log (" | Successful connection check; don't wait for "
@@ -1270,3 +1272,60 @@ def wait_lsn(self, node_id, lsn):
1270
1272
1271
1273
def get_log (self ):
1272
1274
return TarantoolLog (self .logfile ).positioning ()
1275
+
1276
+ def get_iproto_port (self ):
1277
+ # Check the `box.cfg.listen` option, if it wasn't defined, just return.
1278
+ res = yaml .safe_load (self .admin ('box.cfg.listen' , silent = True ))[0 ]
1279
+ if res is None :
1280
+ return
1281
+
1282
+ # If `box.info.listen` (available for tarantool version >= 2.4.1) gives
1283
+ # `nil`, use a simple script intended for tarantool version < 2.4.1 to
1284
+ # get the listening socket of the instance. First, the script catches
1285
+ # both server (listening) and client (sending) sockets (they usually
1286
+ # occur when starting an instance as a replica). Then it finds the
1287
+ # listening socket among caught sockets.
1288
+ script = """
1289
+ local ffi = require('ffi')
1290
+ local socket = require('socket')
1291
+ local uri = require('uri')
1292
+ local res = box.info.listen
1293
+ if res then
1294
+ local listen_uri = uri.parse(res)
1295
+ return {{host = listen_uri.host, port = listen_uri.service}}
1296
+ else
1297
+ res = {{}}
1298
+ local val = ffi.new('int[1]')
1299
+ local len = ffi.new('size_t[1]', ffi.sizeof('int'))
1300
+ for fd = 0, 65535 do
1301
+ local addrinfo = socket.internal.name(fd)
1302
+ local is_matched = addrinfo ~= nil and
1303
+ addrinfo.host == '{localhost}' and
1304
+ addrinfo.family == 'AF_INET' and
1305
+ addrinfo.type == 'SOCK_STREAM' and
1306
+ addrinfo.protocol == 'tcp' and
1307
+ type(addrinfo.port) == 'number'
1308
+ if is_matched then
1309
+ local lvl = socket.internal.SOL_SOCKET
1310
+ ffi.C.getsockopt(fd, lvl,
1311
+ socket.internal.SO_OPT[lvl].SO_REUSEADDR.iname,
1312
+ val, len)
1313
+ if val[0] > 0 then
1314
+ table.insert(res, addrinfo)
1315
+ end
1316
+ end
1317
+ end
1318
+ if #res ~= 1 then
1319
+ error(("Zero or more than one listening TCP sockets: %s")
1320
+ :format(#res))
1321
+ end
1322
+ return {{host = res[1].host, port = res[1].port}}
1323
+ end
1324
+ """ .format (localhost = self .localhost )
1325
+ res = yaml .safe_load (self .admin (script , silent = True ))[0 ]
1326
+ if res .get ('error' ):
1327
+ color_stdout ("Failed to get iproto port: {}\n " .format (res ['error' ]),
1328
+ schema = 'error' )
1329
+ raise TarantoolStartError (self .name )
1330
+
1331
+ return int (res ['port' ])
0 commit comments