cukeforker-webdriver 0.0.1

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/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ .bundle
2
+ .idea
3
+ spec/output
4
+ output
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source :gemcutter
2
+
3
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,66 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ cukeforker-webdriver (0.0.1)
5
+ capybara
6
+ childprocess
7
+ cucumber
8
+ gherkin
9
+ rspec
10
+ selenium-webdriver
11
+
12
+ GEM
13
+ remote: http://rubygems.org/
14
+ specs:
15
+ builder (3.0.0)
16
+ capybara (1.1.1)
17
+ mime-types (>= 1.16)
18
+ nokogiri (>= 1.3.3)
19
+ rack (>= 1.0.0)
20
+ rack-test (>= 0.5.4)
21
+ selenium-webdriver (~> 2.0)
22
+ xpath (~> 0.1.4)
23
+ childprocess (0.2.2)
24
+ ffi (~> 1.0.6)
25
+ cucumber (1.0.6)
26
+ builder (>= 2.1.2)
27
+ diff-lcs (>= 1.1.2)
28
+ gherkin (~> 2.4.18)
29
+ json (>= 1.4.6)
30
+ term-ansicolor (>= 1.0.6)
31
+ diff-lcs (1.1.3)
32
+ ffi (1.0.9)
33
+ gherkin (2.4.21)
34
+ json (>= 1.4.6)
35
+ json (1.5.4)
36
+ json_pure (1.6.1)
37
+ mime-types (1.16)
38
+ nokogiri (1.5.0)
39
+ rack (1.3.3)
40
+ rack-test (0.6.1)
41
+ rack (>= 1.0)
42
+ rake (0.9.2)
43
+ rspec (2.6.0)
44
+ rspec-core (~> 2.6.0)
45
+ rspec-expectations (~> 2.6.0)
46
+ rspec-mocks (~> 2.6.0)
47
+ rspec-core (2.6.4)
48
+ rspec-expectations (2.6.0)
49
+ diff-lcs (~> 1.1.2)
50
+ rspec-mocks (2.6.0)
51
+ rubyzip (0.9.4)
52
+ selenium-webdriver (2.6.0)
53
+ childprocess (>= 0.2.1)
54
+ ffi (>= 1.0.7)
55
+ json_pure
56
+ rubyzip
57
+ term-ansicolor (1.0.6)
58
+ xpath (0.1.4)
59
+ nokogiri (~> 1.3)
60
+
61
+ PLATFORMS
62
+ ruby
63
+
64
+ DEPENDENCIES
65
+ cukeforker-webdriver!
66
+ rake (>= 0.9.2)
data/Rakefile ADDED
@@ -0,0 +1,5 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
3
+
4
+ require "rspec/core/rake_task"
5
+ RSpec::Core::RakeTask.new
@@ -0,0 +1,36 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $LOAD_PATH.unshift File.expand_path("../lib", __FILE__)
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = 'cukeforker-webdriver'
6
+ s.version = '0.0.1'
7
+ s.authors = ["Derek Ekins"]
8
+ s.description = 'Run webdriver with ports pre allocated - thanks go to Jari Bakken for the original implementation https://gist.github.com/949241'
9
+ s.summary = "#{s.name}-#{s.version}"
10
+ s.email = 'derek@spathi.com'
11
+ s.homepage = "http://github.com/dereke/cukeforker-webdriver"
12
+
13
+ s.platform = Gem::Platform::RUBY
14
+ s.post_install_message = %{
15
+ (::) (::) (::) (::) (::) (::) (::) (::) (::) (::) (::) (::) (::) (::) (::)
16
+
17
+ Thank you for installing Cukeforker Web Driver extensions
18
+
19
+ (::) (::) (::) (::) (::) (::) (::) (::) (::) (::) (::) (::) (::) (::) (::)
20
+
21
+ }
22
+
23
+ s.add_dependency 'rspec'
24
+ s.add_dependency 'cucumber'
25
+ s.add_dependency 'gherkin'
26
+ s.add_dependency 'capybara'
27
+ s.add_dependency 'selenium-webdriver'
28
+ s.add_dependency 'childprocess'
29
+
30
+ s.add_development_dependency 'rake', '>= 0.9.2'
31
+
32
+ s.rubygems_version = ">= 1.6.1"
33
+ s.files = `git ls-files`.split("\n")
34
+ s.test_files = `git ls-files -- {spec,features}/*`.split("\n")
35
+ s.require_path = "lib"
36
+ end
@@ -0,0 +1,4 @@
1
+ require 'cukeforker-webdriver/port_pool'
2
+ require 'cukeforker-webdriver/parallel_port_manager'
3
+ require 'cukeforker-webdriver/runner'
4
+
@@ -0,0 +1,26 @@
1
+ require 'capybara'
2
+ require_relative '../no_lock_firefox_bridge'
3
+
4
+ class Capybara::Selenium::Driver
5
+ def browser
6
+ unless @browser
7
+ @port = ENV['web_driver_port']
8
+ options[:port] = @port
9
+ @browser = Selenium::WebDriver::Driver.new(CukeForker::WebDriver::NoLockFirefoxBridge.new(options.reject { |key,val| SPECIAL_OPTIONS.include?(key)}))
10
+
11
+ main = Process.pid
12
+ at_exit do
13
+ quit if Process.pid == main
14
+ end
15
+ end
16
+ @browser
17
+ end
18
+
19
+ def quit
20
+ begin
21
+ @browser.quit
22
+ rescue Errno::ECONNREFUSED
23
+ ensure
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,33 @@
1
+ module CukeForker
2
+ module WebDriver
3
+ class NoLockFirefoxBridge < Selenium::WebDriver::Firefox::Bridge
4
+ def initialize(*args)
5
+ super(*args)
6
+ end
7
+
8
+ class FakeLock
9
+ def initialize(*args)
10
+ end
11
+
12
+ def locked
13
+ yield
14
+ end
15
+ end
16
+
17
+ class NoLockLauncher < Selenium::WebDriver::Firefox::Launcher
18
+ private
19
+
20
+ def find_free_port
21
+ end
22
+
23
+ def socket_lock
24
+ @socket_lock ||= FakeLock.new
25
+ end
26
+ end
27
+
28
+ def create_launcher(port, profile)
29
+ NoLockLauncher.new(Selenium::WebDriver::Firefox::Binary.new, port, profile)
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,28 @@
1
+ require 'cukeforker/abstract_listener'
2
+
3
+ module CukeForker
4
+ module WebDriver
5
+ class ParallelPortManager < CukeForker::AbstractListener
6
+ def initialize(max)
7
+ @port_pool = CukeForker::WebDriver::PortPool.new max
8
+ @available_ports = []
9
+ until @available_ports.length == max
10
+ @available_ports << @port_pool.get
11
+ end
12
+ end
13
+
14
+ def on_worker_starting(worker)
15
+ worker.data.web_driver_port = @available_ports.shift
16
+ end
17
+
18
+ def on_worker_forked(worker)
19
+ require_relative 'capybara/driver'
20
+ ENV['web_driver_port'] = worker.data.web_driver_port.to_s
21
+ end
22
+
23
+ def on_worker_finished(worker)
24
+ @available_ports << worker.data.web_driver_port
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,150 @@
1
+ require 'socket'
2
+ require 'childprocess'
3
+
4
+ module CukeForker
5
+ module WebDriver
6
+ class PortPool
7
+
8
+ class TooManyPortsError < StandardError; end
9
+ class TimeoutError < StandardError; end
10
+ class BindError < StandardError; end
11
+
12
+ START_PORT = 1024
13
+ HOST = "127.0.0.1"
14
+ RELEASE_TIMEOUT = 20
15
+ PORT_INCREMENT = 2
16
+
17
+ def initialize(capacity)
18
+ @last_port = START_PORT - 1
19
+ @capacity = capacity
20
+ @servers = []
21
+ @running = []
22
+
23
+ bind
24
+ end
25
+
26
+ def get
27
+ if @servers.empty?
28
+ STDERR.puts "out of ports, finding next"
29
+ @servers << next_server
30
+ end
31
+
32
+ s = @servers.shift
33
+ port = s.addr.fetch(1)
34
+ s.close
35
+
36
+ wait_while_listening port
37
+ port
38
+ end
39
+
40
+ def release(port)
41
+ raise TooManyPortsError if @servers.size == @capacity
42
+ server = wait_for_server(port)
43
+ @servers << server
44
+ rescue WebDriverPortPool::TimeoutError
45
+ STDERR.puts "timed out while releasing #{port}"
46
+ end
47
+
48
+ def stop
49
+ @servers.each { |s|
50
+ begin
51
+ s.close
52
+ rescue IOError
53
+ end
54
+ }
55
+ end
56
+
57
+ def close_on_exec
58
+ STDERR.puts "#{self.class}: #{Process.pid} pool closed on exec"
59
+ @servers.each { |s| ChildProcess.close_on_exec s }
60
+ end
61
+
62
+ def size
63
+ @servers.size
64
+ end
65
+
66
+ private
67
+
68
+ def bind
69
+ @servers << next_server until size == @capacity
70
+ end
71
+
72
+ def next_server
73
+ max_ports = @capacity*100
74
+ upper_bound = START_PORT + max_ports
75
+ @last_port += PORT_INCREMENT
76
+
77
+ until server = try_bind(@last_port)
78
+ if @last_port > upper_bound
79
+ raise BindError, "unable to find free port within #{START_PORT}..#{upper_bound} tries, last port tried #{@last_port}"
80
+ end
81
+
82
+ @last_port += PORT_INCREMENT
83
+ end
84
+
85
+ server
86
+ end
87
+
88
+ def try_bind(port)
89
+ server_for port
90
+ rescue SocketError, Errno::EADDRINUSE
91
+ # ok
92
+ end
93
+
94
+ def server_for(port)
95
+ s = TCPServer.new(HOST, port)
96
+ ChildProcess.close_on_exec s # make sure browsers don't inherit the file descriptors
97
+ s
98
+ end
99
+
100
+ def wait_for_server(port)
101
+ wait_until(RELEASE_TIMEOUT) {
102
+ res = try_bind port
103
+ # p `lsof -i TCP:#{port}` unless res
104
+
105
+ res
106
+ }
107
+ end
108
+
109
+ def wait_while_listening(port)
110
+ wait_until(RELEASE_TIMEOUT) {
111
+ not listening?(port, 5)
112
+ }
113
+ end
114
+
115
+ def wait_until(timeout, &blk)
116
+ max_time = Time.now + timeout
117
+
118
+ until res = yield
119
+ if Time.now >= max_time
120
+ raise TimeoutError, "timed out"
121
+ else
122
+ sleep 0.1
123
+ end
124
+ end
125
+
126
+ res
127
+ end
128
+
129
+ def listening?(port, timeout = nil)
130
+ addr = Socket.getaddrinfo(HOST, nil)
131
+ sock = Socket.new(Socket.const_get(addr[0][0]), Socket::SOCK_STREAM, 0)
132
+
133
+ if timeout
134
+ secs = Integer(timeout)
135
+ usecs = Integer((timeout - secs) * 1_000_000)
136
+ optval = [secs, usecs].pack("l_2")
137
+ sock.setsockopt Socket::SOL_SOCKET, Socket::SO_RCVTIMEO, optval
138
+ sock.setsockopt Socket::SOL_SOCKET, Socket::SO_SNDTIMEO, optval
139
+ end
140
+ sock.connect(Socket.pack_sockaddr_in(port, addr[0][3]))
141
+ sock.close
142
+
143
+ true
144
+ rescue => e
145
+ false
146
+ end
147
+
148
+ end
149
+ end
150
+ end
@@ -0,0 +1,15 @@
1
+ module CukeForker
2
+ module WebDriver
3
+ class Runner
4
+ def self.run(features, options)
5
+ max = options.fetch(:max, 2)
6
+ options[:notify] = CukeForker::WebDriver::ParallelPortManager.new(max)
7
+
8
+ CukeForker::Runner.run(
9
+ features,
10
+ options
11
+ )
12
+ end
13
+ end
14
+ end
15
+ end
metadata ADDED
@@ -0,0 +1,183 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: cukeforker-webdriver
3
+ version: !ruby/object:Gem::Version
4
+ hash: 29
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 1
10
+ version: 0.0.1
11
+ platform: ruby
12
+ authors:
13
+ - Derek Ekins
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-09-21 00:00:00 +01:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: rspec
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ hash: 3
30
+ segments:
31
+ - 0
32
+ version: "0"
33
+ type: :runtime
34
+ version_requirements: *id001
35
+ - !ruby/object:Gem::Dependency
36
+ name: cucumber
37
+ prerelease: false
38
+ requirement: &id002 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ hash: 3
44
+ segments:
45
+ - 0
46
+ version: "0"
47
+ type: :runtime
48
+ version_requirements: *id002
49
+ - !ruby/object:Gem::Dependency
50
+ name: gherkin
51
+ prerelease: false
52
+ requirement: &id003 !ruby/object:Gem::Requirement
53
+ none: false
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ hash: 3
58
+ segments:
59
+ - 0
60
+ version: "0"
61
+ type: :runtime
62
+ version_requirements: *id003
63
+ - !ruby/object:Gem::Dependency
64
+ name: capybara
65
+ prerelease: false
66
+ requirement: &id004 !ruby/object:Gem::Requirement
67
+ none: false
68
+ requirements:
69
+ - - ">="
70
+ - !ruby/object:Gem::Version
71
+ hash: 3
72
+ segments:
73
+ - 0
74
+ version: "0"
75
+ type: :runtime
76
+ version_requirements: *id004
77
+ - !ruby/object:Gem::Dependency
78
+ name: selenium-webdriver
79
+ prerelease: false
80
+ requirement: &id005 !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ">="
84
+ - !ruby/object:Gem::Version
85
+ hash: 3
86
+ segments:
87
+ - 0
88
+ version: "0"
89
+ type: :runtime
90
+ version_requirements: *id005
91
+ - !ruby/object:Gem::Dependency
92
+ name: childprocess
93
+ prerelease: false
94
+ requirement: &id006 !ruby/object:Gem::Requirement
95
+ none: false
96
+ requirements:
97
+ - - ">="
98
+ - !ruby/object:Gem::Version
99
+ hash: 3
100
+ segments:
101
+ - 0
102
+ version: "0"
103
+ type: :runtime
104
+ version_requirements: *id006
105
+ - !ruby/object:Gem::Dependency
106
+ name: rake
107
+ prerelease: false
108
+ requirement: &id007 !ruby/object:Gem::Requirement
109
+ none: false
110
+ requirements:
111
+ - - ">="
112
+ - !ruby/object:Gem::Version
113
+ hash: 63
114
+ segments:
115
+ - 0
116
+ - 9
117
+ - 2
118
+ version: 0.9.2
119
+ type: :development
120
+ version_requirements: *id007
121
+ description: Run webdriver with ports pre allocated - thanks go to Jari Bakken for the original implementation https://gist.github.com/949241
122
+ email: derek@spathi.com
123
+ executables: []
124
+
125
+ extensions: []
126
+
127
+ extra_rdoc_files: []
128
+
129
+ files:
130
+ - .gitignore
131
+ - Gemfile
132
+ - Gemfile.lock
133
+ - Rakefile
134
+ - cukeforker-webdriver.gemspec
135
+ - lib/cukeforker-webdriver.rb
136
+ - lib/cukeforker-webdriver/capybara/driver.rb
137
+ - lib/cukeforker-webdriver/no_lock_firefox_bridge.rb
138
+ - lib/cukeforker-webdriver/parallel_port_manager.rb
139
+ - lib/cukeforker-webdriver/port_pool.rb
140
+ - lib/cukeforker-webdriver/runner.rb
141
+ has_rdoc: true
142
+ homepage: http://github.com/dereke/cukeforker-webdriver
143
+ licenses: []
144
+
145
+ post_install_message: |+
146
+
147
+ (::) (::) (::) (::) (::) (::) (::) (::) (::) (::) (::) (::) (::) (::) (::)
148
+
149
+ Thank you for installing Cukeforker Web Driver extensions
150
+
151
+ (::) (::) (::) (::) (::) (::) (::) (::) (::) (::) (::) (::) (::) (::) (::)
152
+
153
+ rdoc_options: []
154
+
155
+ require_paths:
156
+ - lib
157
+ required_ruby_version: !ruby/object:Gem::Requirement
158
+ none: false
159
+ requirements:
160
+ - - ">="
161
+ - !ruby/object:Gem::Version
162
+ hash: 3
163
+ segments:
164
+ - 0
165
+ version: "0"
166
+ required_rubygems_version: !ruby/object:Gem::Requirement
167
+ none: false
168
+ requirements:
169
+ - - ">="
170
+ - !ruby/object:Gem::Version
171
+ hash: 3
172
+ segments:
173
+ - 0
174
+ version: "0"
175
+ requirements: []
176
+
177
+ rubyforge_project:
178
+ rubygems_version: 1.6.2
179
+ signing_key:
180
+ specification_version: 3
181
+ summary: cukeforker-webdriver-0.0.1
182
+ test_files: []
183
+