selenium-webdriver 0.0.28 → 0.0.29
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGES +25 -0
- data/lib/selenium/webdriver.rb +6 -29
- data/lib/selenium/webdriver/chrome.rb +4 -2
- data/lib/selenium/webdriver/chrome/extension.zip +0 -0
- data/lib/selenium/webdriver/chrome/launcher.rb +15 -16
- data/lib/selenium/webdriver/common.rb +18 -0
- data/lib/selenium/webdriver/{bridge_helper.rb → common/bridge_helper.rb} +0 -0
- data/lib/selenium/webdriver/{core_ext → common/core_ext}/dir.rb +0 -0
- data/lib/selenium/webdriver/{core_ext → common/core_ext}/string.rb +0 -0
- data/lib/selenium/webdriver/{driver.rb → common/driver.rb} +19 -7
- data/lib/selenium/webdriver/{driver_extensions → common/driver_extensions}/takes_screenshot.rb +2 -2
- data/lib/selenium/webdriver/{element.rb → common/element.rb} +30 -3
- data/lib/selenium/webdriver/{error.rb → common/error.rb} +0 -0
- data/lib/selenium/webdriver/{file_reaper.rb → common/file_reaper.rb} +0 -0
- data/lib/selenium/webdriver/{find.rb → common/find.rb} +9 -1
- data/lib/selenium/webdriver/{keys.rb → common/keys.rb} +0 -0
- data/lib/selenium/webdriver/{navigation.rb → common/navigation.rb} +3 -3
- data/lib/selenium/webdriver/{options.rb → common/options.rb} +47 -5
- data/lib/selenium/webdriver/{platform.rb → common/platform.rb} +10 -0
- data/lib/selenium/webdriver/common/socket_poller.rb +47 -0
- data/lib/selenium/webdriver/{target_locator.rb → common/target_locator.rb} +11 -8
- data/lib/selenium/webdriver/{timeouts.rb → common/timeouts.rb} +0 -0
- data/lib/selenium/webdriver/common/wait.rb +60 -0
- data/lib/selenium/webdriver/common/zipper.rb +54 -0
- data/lib/selenium/webdriver/firefox.rb +6 -3
- data/lib/selenium/webdriver/firefox/binary.rb +46 -43
- data/lib/selenium/webdriver/firefox/bridge.rb +2 -10
- data/lib/selenium/webdriver/firefox/extension.rb +51 -0
- data/lib/selenium/webdriver/firefox/extension/webdriver.xpi +0 -0
- data/lib/selenium/webdriver/firefox/launcher.rb +25 -69
- data/lib/selenium/webdriver/firefox/profile.rb +123 -89
- data/lib/selenium/webdriver/firefox/profiles_ini.rb +2 -1
- data/lib/selenium/webdriver/firefox/socket_lock.rb +77 -0
- data/lib/selenium/webdriver/ie/bridge.rb +25 -38
- data/lib/selenium/webdriver/ie/lib.rb +11 -1
- data/lib/selenium/webdriver/ie/native/win32/InternetExplorerDriver.dll +0 -0
- data/lib/selenium/webdriver/ie/native/x64/InternetExplorerDriver.dll +0 -0
- data/lib/selenium/webdriver/ie/util.rb +3 -17
- data/lib/selenium/webdriver/remote/bridge.rb +9 -1
- data/lib/selenium/webdriver/remote/capabilities.rb +53 -20
- data/lib/selenium/webdriver/remote/http/default.rb +2 -2
- metadata +52 -31
- data/lib/selenium/webdriver/child_process.rb +0 -243
- data/lib/selenium/webdriver/zip_helper.rb +0 -27
Binary file
|
@@ -1,5 +1,3 @@
|
|
1
|
-
require "fcntl"
|
2
|
-
|
3
1
|
module Selenium
|
4
2
|
module WebDriver
|
5
3
|
module Firefox
|
@@ -10,9 +8,11 @@ module Selenium
|
|
10
8
|
SOCKET_LOCK_TIMEOUT = 45
|
11
9
|
STABLE_CONNECTION_TIMEOUT = 60
|
12
10
|
|
13
|
-
def initialize(binary, port
|
11
|
+
def initialize(binary, port, profile = nil)
|
14
12
|
@binary = binary
|
15
|
-
@port = port
|
13
|
+
@port = Integer(port)
|
14
|
+
|
15
|
+
raise Error::WebDriverError, "invalid port: #{@port}" if @port < 1
|
16
16
|
|
17
17
|
if profile.kind_of? Profile
|
18
18
|
@profile = profile
|
@@ -21,12 +21,6 @@ module Selenium
|
|
21
21
|
@profile = nil
|
22
22
|
end
|
23
23
|
|
24
|
-
# need to be really specific about what host to use
|
25
|
-
#
|
26
|
-
# on os x, "localhost" will resolve to 3 different addresses (see /etc/hosts)
|
27
|
-
# Ruby will loop over these and happily bind to the same port on each one,
|
28
|
-
# making it completely unusable for our purposes.
|
29
|
-
#
|
30
24
|
@host = "127.0.0.1"
|
31
25
|
end
|
32
26
|
|
@@ -35,7 +29,7 @@ module Selenium
|
|
35
29
|
end
|
36
30
|
|
37
31
|
def launch
|
38
|
-
|
32
|
+
socket_lock.locked do
|
39
33
|
find_free_port
|
40
34
|
create_profile
|
41
35
|
start_silent_and_wait
|
@@ -46,28 +40,6 @@ module Selenium
|
|
46
40
|
self
|
47
41
|
end
|
48
42
|
|
49
|
-
def with_lock
|
50
|
-
max_time = Time.now + SOCKET_LOCK_TIMEOUT
|
51
|
-
locking_port = @port - 1
|
52
|
-
|
53
|
-
until Time.now > max_time
|
54
|
-
begin
|
55
|
-
socket_lock = TCPServer.new(@host, locking_port)
|
56
|
-
# make sure the fd is not inherited by firefox
|
57
|
-
socket_lock.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC) if defined? Fcntl::FD_CLOEXEC
|
58
|
-
|
59
|
-
yield
|
60
|
-
return
|
61
|
-
rescue SocketError, Errno::EADDRINUSE
|
62
|
-
sleep 0.1
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
raise Error::WebDriverError, "unable to bind to locking port #{locking_port} within #{SOCKET_LOCK_TIMEOUT} seconds"
|
67
|
-
ensure
|
68
|
-
socket_lock.close if socket_lock
|
69
|
-
end
|
70
|
-
|
71
43
|
def find_free_port
|
72
44
|
port = @port
|
73
45
|
|
@@ -79,47 +51,29 @@ module Selenium
|
|
79
51
|
end
|
80
52
|
|
81
53
|
def create_profile
|
82
|
-
|
83
|
-
fetch_profile
|
84
|
-
if @profile.nil?
|
85
|
-
raise Error, WebDriverError, "could not find or create profile: #{profile.inspect}"
|
86
|
-
end
|
87
|
-
end
|
54
|
+
fetch_profile if @profile.nil?
|
88
55
|
|
89
|
-
@profile.
|
56
|
+
@profile.add_webdriver_extension
|
90
57
|
@profile.port = @port
|
91
|
-
@profile.
|
92
|
-
@profile.update_user_prefs
|
58
|
+
@profile_dir = @profile.layout_on_disk
|
93
59
|
end
|
94
60
|
|
95
61
|
def start
|
96
62
|
assert_profile
|
97
|
-
@binary.start_with @profile
|
63
|
+
@binary.start_with @profile, @profile_dir
|
98
64
|
end
|
99
65
|
|
100
66
|
def start_silent_and_wait
|
101
67
|
assert_profile
|
102
|
-
@binary.start_with @profile, "--silent"
|
68
|
+
@binary.start_with @profile, @profile_dir, "--silent"
|
103
69
|
@binary.wait
|
104
70
|
end
|
105
71
|
|
106
72
|
def connect_until_stable
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
return if can_connect?
|
111
|
-
sleep 0.25
|
73
|
+
poller = SocketPoller.new(@host, @port, STABLE_CONNECTION_TIMEOUT)
|
74
|
+
unless poller.success?
|
75
|
+
raise Error::WebDriverError, "unable to obtain stable firefox connection in #{STABLE_CONNECTION_TIMEOUT} seconds"
|
112
76
|
end
|
113
|
-
|
114
|
-
raise Error::WebDriverError, "unable to obtain stable firefox connection in #{STABLE_CONNECTION_TIMEOUT} seconds"
|
115
|
-
end
|
116
|
-
|
117
|
-
def can_connect?
|
118
|
-
TCPSocket.new(@host, @port).close
|
119
|
-
true
|
120
|
-
rescue Errno::ECONNREFUSED, Errno::ENOTCONN, SocketError => e
|
121
|
-
$stderr.puts "#{e.message} for #{@host}:#{@port}" if $DEBUG
|
122
|
-
false
|
123
77
|
end
|
124
78
|
|
125
79
|
def free_port?(port)
|
@@ -131,20 +85,22 @@ module Selenium
|
|
131
85
|
end
|
132
86
|
|
133
87
|
def fetch_profile
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
88
|
+
if @profile_name
|
89
|
+
@profile = Profile.from_name @profile_name
|
90
|
+
if @profile.nil?
|
91
|
+
raise Error::WebDriverError, "unable to find profile named: #{@profile_name.inspect}"
|
92
|
+
end
|
93
|
+
else
|
94
|
+
@profile = Profile.new
|
141
95
|
end
|
142
|
-
|
143
|
-
@profile = existing
|
144
96
|
end
|
145
97
|
|
146
98
|
def assert_profile
|
147
|
-
raise Error::WebDriverError, "must create_profile first" unless @profile
|
99
|
+
raise Error::WebDriverError, "must create_profile first" unless @profile && @profile_dir
|
100
|
+
end
|
101
|
+
|
102
|
+
def socket_lock
|
103
|
+
@socket_lock ||= SocketLock.new(@port - 1, SOCKET_LOCK_TIMEOUT)
|
148
104
|
end
|
149
105
|
|
150
106
|
end # Launcher
|
@@ -5,12 +5,17 @@ module Selenium
|
|
5
5
|
|
6
6
|
ANONYMOUS_PROFILE_NAME = "WEBDRIVER_ANONYMOUS_PROFILE"
|
7
7
|
EXTENSION_NAME = "fxdriver@googlecode.com"
|
8
|
-
EM_NAMESPACE_URI = "http://www.mozilla.org/2004/em-rdf#"
|
9
8
|
WEBDRIVER_EXTENSION_PATH = File.expand_path("#{WebDriver.root}/selenium/webdriver/firefox/extension/webdriver.xpi")
|
10
|
-
|
11
|
-
|
9
|
+
WEBDRIVER_PREFS = {
|
10
|
+
:native_events => 'webdriver_enable_native_events',
|
11
|
+
:untrusted_certs => 'webdriver_accept_untrusted_certs',
|
12
|
+
:untrusted_issuer => 'webdriver_assume_untrusted_issuer',
|
13
|
+
:port => 'webdriver_firefox_port',
|
14
|
+
:log_file => 'webdriver.log.file'
|
15
|
+
}
|
16
|
+
|
17
|
+
attr_reader :name, :log_file
|
12
18
|
attr_writer :secure_ssl, :native_events, :load_no_focus_lib
|
13
|
-
attr_accessor :port
|
14
19
|
|
15
20
|
class << self
|
16
21
|
def ini
|
@@ -34,23 +39,56 @@ module Selenium
|
|
34
39
|
# driver = Selenium::WebDriver.for :firefox, :profile => profile
|
35
40
|
#
|
36
41
|
|
37
|
-
def initialize(
|
38
|
-
@
|
42
|
+
def initialize(model = nil)
|
43
|
+
@model = verify_model(model)
|
44
|
+
|
45
|
+
model_prefs = read_model_prefs
|
39
46
|
|
40
|
-
|
41
|
-
|
47
|
+
if model_prefs.empty?
|
48
|
+
@native_events = DEFAULT_ENABLE_NATIVE_EVENTS
|
49
|
+
@secure_ssl = DEFAULT_SECURE_SSL
|
50
|
+
@untrusted_issuer = DEFAULT_ASSUME_UNTRUSTED_ISSUER
|
51
|
+
@load_no_focus_lib = DEFAULT_LOAD_NO_FOCUS_LIB
|
52
|
+
else
|
53
|
+
@native_events = model_prefs[WEBDRIVER_PREFS[:native_events]] == "true"
|
54
|
+
@secure_ssl = model_prefs[WEBDRIVER_PREFS[:untrusted_certs]] != "true" # FIXME: 'untrusted_certs' vs 'secure_ssl'
|
55
|
+
@untrusted_issuer = model_prefs[WEBDRIVER_PREFS[:untrusted_issuer]] == "true"
|
56
|
+
@load_no_focus_lib = model_prefs[WEBDRIVER_PREFS[:load_no_focus_lib]] == "true" # not stored in profile atm, so will always be false.
|
42
57
|
end
|
43
58
|
|
44
|
-
|
59
|
+
@additional_prefs = {}
|
60
|
+
@extensions = {}
|
61
|
+
end
|
45
62
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
@secure_ssl = DEFAULT_SECURE_SSL
|
50
|
-
@untrusted_issuer = DEFAULT_ASSUME_UNTRUSTED_ISSUER
|
51
|
-
@load_no_focus_lib = DEFAULT_LOAD_NO_FOCUS_LIB
|
63
|
+
def layout_on_disk
|
64
|
+
profile_dir = @model ? create_tmp_copy(@model) : Dir.mktmpdir("webdriver-profile")
|
65
|
+
FileReaper << profile_dir
|
52
66
|
|
53
|
-
|
67
|
+
install_extensions(profile_dir)
|
68
|
+
delete_lock_files(profile_dir)
|
69
|
+
delete_extensions_cache(profile_dir)
|
70
|
+
update_user_prefs_in(profile_dir)
|
71
|
+
|
72
|
+
profile_dir
|
73
|
+
end
|
74
|
+
|
75
|
+
def as_json(opts = nil)
|
76
|
+
{'zip' => Zipper.zip(layout_on_disk)}
|
77
|
+
end
|
78
|
+
|
79
|
+
def to_json(*args)
|
80
|
+
as_json.to_json(*args)
|
81
|
+
end
|
82
|
+
|
83
|
+
def self.from_json(json)
|
84
|
+
zip_file = Tempfile.new("webdriver-profile-duplicate-#{json.hash}")
|
85
|
+
|
86
|
+
zip_file << JSON.parse(json)['zip'].unpack("m")[0]
|
87
|
+
zip_file.close
|
88
|
+
|
89
|
+
new(Zipper.unzip(zip_file.path))
|
90
|
+
ensure
|
91
|
+
zip_file.delete if zip_file
|
54
92
|
end
|
55
93
|
|
56
94
|
#
|
@@ -75,80 +113,27 @@ module Selenium
|
|
75
113
|
@additional_prefs[key.to_s] = value
|
76
114
|
end
|
77
115
|
|
78
|
-
def
|
79
|
-
|
80
|
-
directory.gsub("/", "\\")
|
81
|
-
else
|
82
|
-
directory
|
83
|
-
end
|
116
|
+
def port=(port)
|
117
|
+
self[WEBDRIVER_PREFS[:port]] = port
|
84
118
|
end
|
85
119
|
|
86
|
-
def
|
87
|
-
|
88
|
-
|
89
|
-
prefs.merge! OVERRIDABLE_PREFERENCES
|
90
|
-
prefs.merge! @additional_prefs
|
91
|
-
prefs.merge! DEFAULT_PREFERENCES
|
92
|
-
|
93
|
-
prefs['webdriver_firefox_port'] = @port
|
94
|
-
prefs['webdriver_accept_untrusted_certs'] = !secure_ssl?
|
95
|
-
prefs['webdriver_enable_native_events'] = native_events?
|
96
|
-
prefs['webdriver_assume_untrusted_issuer'] = assume_untrusted_certificate_issuer?
|
97
|
-
|
98
|
-
# If the user sets the home page, we should also start up there
|
99
|
-
prefs["startup.homepage_welcome_url"] = prefs["browser.startup.homepage"]
|
100
|
-
|
101
|
-
write_prefs prefs
|
120
|
+
def log_file=(file)
|
121
|
+
@log_file = file
|
122
|
+
self[WEBDRIVER_PREFS[:log_file]] = file
|
102
123
|
end
|
103
124
|
|
104
|
-
def add_webdriver_extension
|
105
|
-
|
106
|
-
|
107
|
-
if File.exists? ext_path
|
108
|
-
return unless force_creation
|
125
|
+
def add_webdriver_extension
|
126
|
+
unless @extensions.has_key?(:webdriver)
|
127
|
+
add_extension(WEBDRIVER_EXTENSION_PATH, :webdriver)
|
109
128
|
end
|
110
|
-
|
111
|
-
add_extension WEBDRIVER_EXTENSION_PATH
|
112
|
-
delete_extensions_cache
|
113
129
|
end
|
114
130
|
|
115
131
|
#
|
116
|
-
#
|
132
|
+
# Add the extension (directory, .zip or .xpi) at the given path to the profile.
|
117
133
|
#
|
118
134
|
|
119
|
-
def add_extension(path)
|
120
|
-
|
121
|
-
raise Error::WebDriverError, "could not find extension at #{path.inspect}"
|
122
|
-
end
|
123
|
-
|
124
|
-
if File.directory? path
|
125
|
-
root = path
|
126
|
-
else
|
127
|
-
unless %w[.zip .xpi].include? File.extname(path)
|
128
|
-
raise Error::WebDriverError, "expected .zip or .xpi extension, got #{path.inspect}"
|
129
|
-
end
|
130
|
-
|
131
|
-
root = ZipHelper.unzip(path)
|
132
|
-
end
|
133
|
-
|
134
|
-
ext_path = File.join extensions_dir, read_id_from_install_rdf(root)
|
135
|
-
|
136
|
-
FileUtils.rm_rf ext_path
|
137
|
-
FileUtils.mkdir_p File.dirname(ext_path), :mode => 0700
|
138
|
-
FileUtils.cp_r root, ext_path
|
139
|
-
end
|
140
|
-
|
141
|
-
def extensions_dir
|
142
|
-
@extensions_dir ||= File.join(directory, "extensions")
|
143
|
-
end
|
144
|
-
|
145
|
-
def user_prefs_path
|
146
|
-
@user_prefs_path ||= File.join(directory, "user.js")
|
147
|
-
end
|
148
|
-
|
149
|
-
def delete_extensions_cache
|
150
|
-
cache = File.join(directory, "extensions.cache")
|
151
|
-
FileUtils.rm_f cache if File.exist?(cache)
|
135
|
+
def add_extension(path, name = extension_name_for(path))
|
136
|
+
@extensions[name] = Extension.new(path)
|
152
137
|
end
|
153
138
|
|
154
139
|
def native_events?
|
@@ -173,11 +158,42 @@ module Selenium
|
|
173
158
|
|
174
159
|
private
|
175
160
|
|
176
|
-
def
|
177
|
-
|
178
|
-
doc = REXML::Document.new(File.read(rdf_path))
|
161
|
+
def install_extensions(directory)
|
162
|
+
destination = File.join(directory, "extensions")
|
179
163
|
|
180
|
-
|
164
|
+
@extensions.each do |name, extension|
|
165
|
+
p :extension => name if $DEBUG
|
166
|
+
extension.write_to(destination)
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
def verify_model(model)
|
171
|
+
return unless model
|
172
|
+
|
173
|
+
raise Errno::ENOENT, model unless File.exist?(model)
|
174
|
+
raise Errno::ENOTDIR, model unless File.directory?(model)
|
175
|
+
|
176
|
+
model
|
177
|
+
end
|
178
|
+
|
179
|
+
def read_model_prefs
|
180
|
+
return {} unless @model
|
181
|
+
|
182
|
+
read_user_prefs(File.join(@model, 'user.js'))
|
183
|
+
end
|
184
|
+
|
185
|
+
def delete_extensions_cache(directory)
|
186
|
+
FileUtils.rm_f File.join(directory, "extensions.cache")
|
187
|
+
end
|
188
|
+
|
189
|
+
def delete_lock_files(directory)
|
190
|
+
%w[.parentlock parent.lock].each do |name|
|
191
|
+
FileUtils.rm_f File.join(directory, name)
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
def extension_name_for(path)
|
196
|
+
File.basename(path, File.extname(path))
|
181
197
|
end
|
182
198
|
|
183
199
|
def create_tmp_copy(directory)
|
@@ -191,13 +207,30 @@ module Selenium
|
|
191
207
|
tmp_directory
|
192
208
|
end
|
193
209
|
|
210
|
+
def update_user_prefs_in(directory)
|
211
|
+
path = File.join(directory, 'user.js')
|
212
|
+
prefs = read_user_prefs(path)
|
213
|
+
|
214
|
+
prefs.merge! OVERRIDABLE_PREFERENCES
|
215
|
+
prefs.merge! @additional_prefs
|
216
|
+
prefs.merge! DEFAULT_PREFERENCES
|
217
|
+
|
218
|
+
prefs[WEBDRIVER_PREFS[:untrusted_certs]] = !secure_ssl?
|
219
|
+
prefs[WEBDRIVER_PREFS[:native_events]] = native_events?
|
220
|
+
prefs[WEBDRIVER_PREFS[:untrusted_issuer]] = assume_untrusted_certificate_issuer?
|
221
|
+
|
222
|
+
# If the user sets the home page, we should also start up there
|
223
|
+
prefs["startup.homepage_welcome_url"] = prefs["browser.startup.homepage"]
|
224
|
+
|
225
|
+
write_prefs prefs, path
|
226
|
+
end
|
194
227
|
|
195
|
-
def
|
196
|
-
return {} unless File.exist?(
|
228
|
+
def read_user_prefs(path)
|
229
|
+
return {} unless File.exist?(path)
|
197
230
|
|
198
231
|
prefs = {}
|
199
232
|
|
200
|
-
File.read(
|
233
|
+
File.read(path).split("\n").each do |line|
|
201
234
|
if line =~ /user_pref\("([^"]+)"\s*,\s*(.+?)\);/
|
202
235
|
prefs[$1.strip] = $2.strip
|
203
236
|
end
|
@@ -206,8 +239,8 @@ module Selenium
|
|
206
239
|
prefs
|
207
240
|
end
|
208
241
|
|
209
|
-
def write_prefs(prefs)
|
210
|
-
File.open(
|
242
|
+
def write_prefs(prefs, path)
|
243
|
+
File.open(path, "w") { |file|
|
211
244
|
prefs.each do |key, value|
|
212
245
|
p key => value if $DEBUG
|
213
246
|
file.puts %{user_pref("#{key}", #{value});}
|
@@ -238,6 +271,7 @@ module Selenium
|
|
238
271
|
"extensions.update.enabled" => 'false',
|
239
272
|
"extensions.update.notifyUser" => 'false',
|
240
273
|
"network.manage-offline-status" => 'false',
|
274
|
+
"network.http.max-connections-per-server" => '10',
|
241
275
|
"security.warn_entering_secure" => 'false',
|
242
276
|
"security.warn_submit_insecure" => 'false',
|
243
277
|
"security.warn_entering_secure.show_once" => 'false',
|
@@ -0,0 +1,77 @@
|
|
1
|
+
require "fcntl"
|
2
|
+
|
3
|
+
module Selenium
|
4
|
+
module WebDriver
|
5
|
+
module Firefox
|
6
|
+
|
7
|
+
#
|
8
|
+
# @private
|
9
|
+
#
|
10
|
+
|
11
|
+
class SocketLock
|
12
|
+
|
13
|
+
#
|
14
|
+
# Need to be really specific about what host to use
|
15
|
+
#
|
16
|
+
# On os x, "localhost" will resolve to 3 different addresses (see /etc/hosts).
|
17
|
+
# Ruby will loop over these and happily bind to the same port on each one,
|
18
|
+
# making it completely unusable for our purposes.
|
19
|
+
#
|
20
|
+
|
21
|
+
HOST = "127.0.0.1"
|
22
|
+
|
23
|
+
def initialize(port, timeout)
|
24
|
+
@port = port
|
25
|
+
@timeout = timeout
|
26
|
+
end
|
27
|
+
|
28
|
+
def locked(&blk)
|
29
|
+
lock
|
30
|
+
|
31
|
+
begin
|
32
|
+
yield
|
33
|
+
ensure
|
34
|
+
release
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def lock
|
41
|
+
max_time = Time.now + @timeout
|
42
|
+
|
43
|
+
until can_lock? || Time.now >= max_time
|
44
|
+
sleep 0.1
|
45
|
+
end
|
46
|
+
|
47
|
+
unless did_lock?
|
48
|
+
raise Error::WebDriverError, "unable to bind to locking port #{@port} within #{@timeout} seconds"
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def release
|
53
|
+
@server && @server.close
|
54
|
+
end
|
55
|
+
|
56
|
+
def can_lock?
|
57
|
+
@server = TCPServer.new(HOST, @port)
|
58
|
+
|
59
|
+
# make sure the fd is not inherited by exec()'d processes
|
60
|
+
if defined? Fcntl::FD_CLOEXEC
|
61
|
+
@server.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
|
62
|
+
end
|
63
|
+
|
64
|
+
true
|
65
|
+
rescue SocketError, Errno::EADDRINUSE => ex
|
66
|
+
$stderr.puts "#{self}: #{ex.message}" if $DEBUG
|
67
|
+
false
|
68
|
+
end
|
69
|
+
|
70
|
+
def did_lock?
|
71
|
+
!!@server
|
72
|
+
end
|
73
|
+
|
74
|
+
end # SocketLock
|
75
|
+
end # Firefox
|
76
|
+
end # WebDriver
|
77
|
+
end # Selenium
|