3
3
import json
4
4
import os
5
5
import platform
6
+ import re
6
7
import signal
7
8
import subprocess
8
9
import sys
@@ -604,6 +605,32 @@ def __call__(self, line):
604
605
command = " " .join (self .command ))
605
606
606
607
608
+ class GeckodriverOutputHandler (FirefoxOutputHandler ):
609
+ PORT_RE = re .compile (b".*Listening on [^ :]*:(\d+)" )
610
+
611
+ def __init__ (self , logger , command , symbols_path = None , stackfix_dir = None , asan = False ,
612
+ leak_report_file = None , init_deadline = None ):
613
+ super ().__init__ (logger , command , symbols_path = symbols_path , stackfix_dir = stackfix_dir , asan = asan ,
614
+ leak_report_file = leak_report_file )
615
+ self .port = None
616
+ self .init_deadline = None
617
+
618
+ def after_process_start (self , pid ):
619
+ super ().after_process_start (pid )
620
+ while self .port is None :
621
+ time .sleep (0.1 )
622
+ if self .init_deadline is not None and time .time () > self .init_deadline :
623
+ raise TimeoutError ("Failed to get geckodriver port within the timeout" )
624
+
625
+ def __call__ (self , line ):
626
+ if self .port is None :
627
+ m = self .PORT_RE .match (line )
628
+ if m is not None :
629
+ self .port = int (m .groups ()[0 ])
630
+ self .logger .debug (f"Got geckodriver port { self .port } " )
631
+ super ().__call__ (line )
632
+
633
+
607
634
class ProfileCreator :
608
635
def __init__ (self , logger , prefs_root , config , test_type , extra_prefs , e10s ,
609
636
disable_fission , debug_test , browser_channel , binary , certutil_binary ,
@@ -922,12 +949,13 @@ def get_env(self, binary, debug_info, headless, chaos_mode_flags):
922
949
return env
923
950
924
951
def create_output_handler (self , cmd ):
925
- return FirefoxOutputHandler (self .logger ,
926
- cmd ,
927
- stackfix_dir = self .stackfix_dir ,
928
- symbols_path = self .symbols_path ,
929
- asan = self .asan ,
930
- leak_report_file = self .leak_report_file )
952
+ return GeckodriverOutputHandler (self .logger ,
953
+ cmd ,
954
+ stackfix_dir = self .stackfix_dir ,
955
+ symbols_path = self .symbols_path ,
956
+ asan = self .asan ,
957
+ leak_report_file = self .leak_report_file ,
958
+ init_deadline = self .init_deadline )
931
959
932
960
def start (self , group_metadata , ** kwargs ):
933
961
self .leak_report_file = setup_leak_report (self .leak_check , self .profile , self .env )
@@ -971,7 +999,12 @@ def stop(self, force=False):
971
999
time .sleep (1 )
972
1000
else :
973
1001
self .logger .debug ("WebDriver session didn't end" )
974
- super ().stop (force = force )
1002
+ try :
1003
+ super ().stop (force = force )
1004
+ finally :
1005
+ if self ._output_handler is not None :
1006
+ self ._output_handler .port = None
1007
+ self ._port = None
975
1008
976
1009
def cleanup (self ):
977
1010
super ().cleanup ()
@@ -985,10 +1018,19 @@ def settings(self, test):
985
1018
"mozleak_allowed" : self .leak_check and test .mozleak_allowed ,
986
1019
"mozleak_thresholds" : self .leak_check and test .mozleak_threshold }
987
1020
1021
+ @property
1022
+ def port (self ):
1023
+ # We read the port from geckodriver on startup
1024
+ if self ._port is None :
1025
+ if self ._output_handler is None or self ._output_handler .port is None :
1026
+ raise ValueError ("Can't get geckodriver port before it's started" )
1027
+ self ._port = self ._output_handler .port
1028
+ return self ._port
1029
+
988
1030
def make_command (self ):
989
1031
return [self .webdriver_binary ,
990
1032
"--host" , self .host ,
991
- "--port" , str ( self . port ) ] + self .webdriver_args
1033
+ "--port" , "0" ] + self .webdriver_args
992
1034
993
1035
def executor_browser (self ):
994
1036
cls , args = super ().executor_browser ()
0 commit comments