headless 2.1.0 → 2.2.0
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.
- checksums.yaml +4 -4
- data/CHANGELOG +6 -0
- data/README.md +6 -1
- data/headless.gemspec +1 -1
- data/lib/headless.rb +26 -12
- data/lib/headless/cli_util.rb +15 -14
- data/spec/headless_spec.rb +34 -4
- metadata +2 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d30b463017cd61d3b19e47c94a04e9aa4061acc7
|
4
|
+
data.tar.gz: d8b07cc50c12a80ad547a8214a530cffa55db8f0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fadb8ac4e38bb5ce3dc9f2f8245d3a13055e5d384d8aafb6ef87aecfaed732505d0017054a0d7d84c58c9854456aa01015bd83e3fdfb0e047a0ef40217a13dab
|
7
|
+
data.tar.gz: 5574ded55ca457df6835da69994911da9be288fb1ab1f943e0ff3215d52d1618596876f042325b08c9e1ecc7d299de0f4542a001f654f1b81a1180cc86bfe098
|
data/CHANGELOG
CHANGED
@@ -1,3 +1,9 @@
|
|
1
|
+
## 2.2.0 (2015-07-05)
|
2
|
+
|
3
|
+
* Allow reuse of displays started by other user (from @marxarelli)
|
4
|
+
* Add support for graphicsmagick instead of ImageMagick (from @BlakeMesdag)
|
5
|
+
* Wait for Xvfb to finish when destroying it, to avoid creating zombie processes (from @samnissen)
|
6
|
+
|
1
7
|
## 2.1.0 (2015-05-10)
|
2
8
|
|
3
9
|
* Allow path to video recorder binary to be customized (from @briandamaged)
|
data/README.md
CHANGED
@@ -83,8 +83,13 @@ Headless.new(display: 100, reuse: true, destroy_at_exit: false).start
|
|
83
83
|
# reap_headless.rb
|
84
84
|
headless = Headless.new(display: 100, reuse: true)
|
85
85
|
headless.destroy
|
86
|
+
|
87
|
+
# kill_headless_without_waiting.rb
|
88
|
+
headless = Headless.new
|
89
|
+
headless.destroy_without_sync
|
86
90
|
```
|
87
|
-
|
91
|
+
|
92
|
+
There's also a different approach that creates a new virtual display for every parallel test process - see [this implementation](https://gist.github.com/rosskevin/5937888) by @rosskevin.
|
88
93
|
|
89
94
|
## Cucumber with wkhtmltopdf
|
90
95
|
|
data/headless.gemspec
CHANGED
data/lib/headless.rb
CHANGED
@@ -101,15 +101,24 @@ class Headless
|
|
101
101
|
end
|
102
102
|
|
103
103
|
# Switches back from the headless server and terminates the headless session
|
104
|
+
# while waiting for Xvfb process to terminate.
|
104
105
|
def destroy
|
105
106
|
stop
|
106
|
-
CliUtil.kill_process(pid_filename, preserve_pid_file: true)
|
107
|
+
CliUtil.kill_process(pid_filename, preserve_pid_file: true, wait: true)
|
107
108
|
end
|
108
109
|
|
109
|
-
#
|
110
|
+
# Deprecated.
|
111
|
+
# Same as destroy.
|
112
|
+
# Kept for backward compatibility in June 2015.
|
110
113
|
def destroy_sync
|
114
|
+
destroy
|
115
|
+
end
|
116
|
+
|
117
|
+
# Same as the old destroy function -- doesn't wait for Xvfb to die.
|
118
|
+
# Can cause zombies: http://stackoverflow.com/a/31003621/1651458
|
119
|
+
def destroy_without_sync
|
111
120
|
stop
|
112
|
-
CliUtil.kill_process(pid_filename, preserve_pid_file: true
|
121
|
+
CliUtil.kill_process(pid_filename, preserve_pid_file: true)
|
113
122
|
end
|
114
123
|
|
115
124
|
# Block syntax:
|
@@ -133,12 +142,16 @@ class Headless
|
|
133
142
|
|
134
143
|
def take_screenshot(file_path, options={})
|
135
144
|
using = options.fetch(:using, :imagemagick)
|
136
|
-
|
145
|
+
case using
|
146
|
+
when :imagemagick
|
137
147
|
CliUtil.ensure_application_exists!('import', "imagemagick is not found on your system. Please install it using sudo apt-get install imagemagick")
|
138
148
|
system "#{CliUtil.path_to('import')} -display localhost:#{display} -window root #{file_path}"
|
139
|
-
|
149
|
+
when :xwd
|
140
150
|
CliUtil.ensure_application_exists!('xwd', "xwd is not found on your system. Please install it using sudo apt-get install X11-apps")
|
141
151
|
system "#{CliUtil.path_to('xwd')} -display localhost:#{display} -silent -root -out #{file_path}"
|
152
|
+
when :graphicsmagick, :gm
|
153
|
+
CliUtil.ensure_application_exists!('gm', "graphicsmagick is not found on your system. Please install it.")
|
154
|
+
system "#{CliUtil.path_to('gm')} import -display localhost:#{display} -window root #{file_path}"
|
142
155
|
else
|
143
156
|
raise Headless::Exception.new('Unknown :using option value')
|
144
157
|
end
|
@@ -154,12 +167,9 @@ private
|
|
154
167
|
def pick_available_display(display_set, can_reuse)
|
155
168
|
display_set.each do |display_number|
|
156
169
|
@display = display_number
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
rescue Errno::EPERM # display not accessible
|
161
|
-
next
|
162
|
-
end
|
170
|
+
|
171
|
+
return true if xvfb_running? && can_reuse && (xvfb_mine? || !@autopick_display)
|
172
|
+
return true if !xvfb_running? && launch_xvfb
|
163
173
|
end
|
164
174
|
raise Headless::Exception.new("Could not find an available display")
|
165
175
|
end
|
@@ -192,8 +202,12 @@ private
|
|
192
202
|
end while !xvfb_running?
|
193
203
|
end
|
194
204
|
|
205
|
+
def xvfb_mine?
|
206
|
+
CliUtil.process_mine?(read_xvfb_pid)
|
207
|
+
end
|
208
|
+
|
195
209
|
def xvfb_running?
|
196
|
-
|
210
|
+
(pid = read_xvfb_pid) && CliUtil.process_running?(pid)
|
197
211
|
end
|
198
212
|
|
199
213
|
def pid_filename
|
data/lib/headless/cli_util.rb
CHANGED
@@ -14,20 +14,21 @@ class Headless
|
|
14
14
|
`which #{app}`.strip
|
15
15
|
end
|
16
16
|
|
17
|
-
def self.
|
18
|
-
|
19
|
-
|
17
|
+
def self.process_mine?(pid)
|
18
|
+
Process.kill(0, pid) && true
|
19
|
+
rescue Errno::EPERM, Errno::ESRCH
|
20
|
+
false
|
21
|
+
end
|
20
22
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
end
|
23
|
+
def self.process_running?(pid)
|
24
|
+
Process.getpgid(pid) && true
|
25
|
+
rescue Errno::ESRCH
|
26
|
+
false
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.read_pid(pid_filename)
|
30
|
+
pid = (File.read(pid_filename) rescue "").strip
|
31
|
+
pid.empty? ? nil : pid.to_i
|
31
32
|
end
|
32
33
|
|
33
34
|
def self.fork_process(command, pid_filename, log_filename='/dev/null')
|
@@ -43,7 +44,7 @@ class Headless
|
|
43
44
|
end
|
44
45
|
|
45
46
|
def self.kill_process(pid_filename, options={})
|
46
|
-
if pid =
|
47
|
+
if pid = read_pid(pid_filename)
|
47
48
|
begin
|
48
49
|
Process.kill 'TERM', pid
|
49
50
|
Process.wait pid if options[:wait]
|
data/spec/headless_spec.rb
CHANGED
@@ -38,9 +38,12 @@ describe Headless do
|
|
38
38
|
end
|
39
39
|
end
|
40
40
|
|
41
|
-
context "when Xvfb is already running" do
|
41
|
+
context "when Xvfb is already running and was started by this user" do
|
42
42
|
before do
|
43
43
|
allow(Headless::CliUtil).to receive(:read_pid).with('/tmp/.X99-lock').and_return(31337)
|
44
|
+
allow(Headless::CliUtil).to receive(:process_running?).with(31337).and_return(true)
|
45
|
+
allow(Headless::CliUtil).to receive(:process_mine?).with(31337).and_return(true)
|
46
|
+
|
44
47
|
allow(Headless::CliUtil).to receive(:read_pid).with('/tmp/.X100-lock').and_return(nil)
|
45
48
|
end
|
46
49
|
|
@@ -79,15 +82,18 @@ describe Headless do
|
|
79
82
|
|
80
83
|
context 'when Xvfb is started, but by another user' do
|
81
84
|
before do
|
82
|
-
allow(Headless::CliUtil).to receive(:read_pid).with('/tmp/.X99-lock')
|
85
|
+
allow(Headless::CliUtil).to receive(:read_pid).with('/tmp/.X99-lock').and_return(31337)
|
86
|
+
allow(Headless::CliUtil).to receive(:process_running?).with(31337).and_return(true)
|
87
|
+
allow(Headless::CliUtil).to receive(:process_mine?).with(31337).and_return(false)
|
88
|
+
|
83
89
|
allow(Headless::CliUtil).to receive(:read_pid).with('/tmp/.X100-lock').and_return(nil)
|
84
90
|
end
|
85
91
|
|
86
92
|
context "and display autopicking is not allowed" do
|
87
93
|
let(:options) { {:autopick => false} }
|
88
94
|
|
89
|
-
it "should
|
90
|
-
expect
|
95
|
+
it "should reuse the display" do
|
96
|
+
expect(Headless.new(options).display).to eq 99
|
91
97
|
end
|
92
98
|
end
|
93
99
|
|
@@ -176,6 +182,18 @@ describe Headless do
|
|
176
182
|
expect { headless.take_screenshot('a.png', :using => :xwd) }.to raise_error(Headless::Exception)
|
177
183
|
end
|
178
184
|
|
185
|
+
it "raises an error if gm is not installed with using: :graphicsmagick" do
|
186
|
+
allow(Headless::CliUtil).to receive(:application_exists?).with('gm').and_return(false)
|
187
|
+
|
188
|
+
expect { headless.take_screenshot('a.png', :using => :graphicsmagick) }.to raise_error(Headless::Exception)
|
189
|
+
end
|
190
|
+
|
191
|
+
it "raises an error if gm is not installed with using: :gm" do
|
192
|
+
allow(Headless::CliUtil).to receive(:application_exists?).with('gm').and_return(false)
|
193
|
+
|
194
|
+
expect { headless.take_screenshot('a.png', :using => :gm) }.to raise_error(Headless::Exception)
|
195
|
+
end
|
196
|
+
|
179
197
|
it "issues command to take screenshot, with default options" do
|
180
198
|
allow(Headless::CliUtil).to receive(:path_to).with('import').and_return('path/import')
|
181
199
|
expect(headless).to receive(:system).with("path/import -display localhost:99 -window root /tmp/image.png")
|
@@ -193,6 +211,18 @@ describe Headless do
|
|
193
211
|
expect(headless).to receive(:system).with("path/xwd -display localhost:99 -silent -root -out /tmp/image.png")
|
194
212
|
headless.take_screenshot("/tmp/image.png", :using => :xwd)
|
195
213
|
end
|
214
|
+
|
215
|
+
it "issues command to take screenshot, with using: :graphicsmagick" do
|
216
|
+
allow(Headless::CliUtil).to receive(:path_to).with('gm').and_return('path/gm')
|
217
|
+
expect(headless).to receive(:system).with("path/gm import -display localhost:99 -window root /tmp/image.png")
|
218
|
+
headless.take_screenshot("/tmp/image.png", :using => :graphicsmagick)
|
219
|
+
end
|
220
|
+
|
221
|
+
it "issues command to take screenshot, with using: :gm" do
|
222
|
+
allow(Headless::CliUtil).to receive(:path_to).with('gm').and_return('path/gm')
|
223
|
+
expect(headless).to receive(:system).with("path/gm import -display localhost:99 -window root /tmp/image.png")
|
224
|
+
headless.take_screenshot("/tmp/image.png", :using => :gm)
|
225
|
+
end
|
196
226
|
end
|
197
227
|
end
|
198
228
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: headless
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Leonid Shevtsov
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-05
|
11
|
+
date: 2015-08-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
@@ -98,4 +98,3 @@ signing_key:
|
|
98
98
|
specification_version: 4
|
99
99
|
summary: Ruby headless display interface
|
100
100
|
test_files: []
|
101
|
-
has_rdoc:
|