Skip to content

Commit 2886098

Browse files
* integration tests
* More informative error messages * If video recorder provider is libav, use avconv binary instead of ffmpeg * Rewritten Xvfb launch using Process.spawn and avoiding a shell * Do not manually remove X11 lock file when stopping Xvfb; this isn’t conventional. Should eliminate some errors with not being able to find Xvfb * Detect situation when Xvfb can’t listen to any sockets and raise corresponding error * Properly working integration tests
1 parent 28d0b73 commit 2886098

File tree

7 files changed

+243
-165
lines changed

7 files changed

+243
-165
lines changed

.travis.yml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,8 @@ language: ruby
22
rvm:
33
- 1.9.3
44
- 2.0
5-
- 2.1
5+
- 2.2
6+
before_install:
7+
- "sudo apt-get update"
8+
- "sudo apt-get install -y firefox xvfb libav-tools"
69
script: "rspec"

headless.gemspec

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,5 @@ spec = Gem::Specification.new do |s|
1616

1717
s.add_development_dependency 'rake'
1818
s.add_development_dependency "rspec", "~> 3"
19+
s.add_development_dependency "selenium-webdriver"
1920
end

lib/headless.rb

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,13 @@ def stop
103103
# Switches back from the headless server and terminates the headless session
104104
def destroy
105105
stop
106-
CliUtil.kill_process(pid_filename)
106+
CliUtil.kill_process(pid_filename, preserve_pid_file: true)
107+
end
108+
109+
# Same as destroy, but waits for Xvfb process to terminate
110+
def destroy_sync
111+
stop
112+
CliUtil.kill_process(pid_filename, preserve_pid_file: true, wait: true)
107113
end
108114

109115
# Block syntax:
@@ -159,18 +165,30 @@ def pick_available_display(display_set, can_reuse)
159165
end
160166

161167
def launch_xvfb
162-
#TODO error reporting
163-
result = system "#{CliUtil.path_to("Xvfb")} :#{display} -screen 0 #{dimensions} -ac >/dev/null 2>&1 &"
164-
raise Headless::Exception.new("Xvfb did not launch - something's wrong") unless result
165-
ensure_xvfb_is_running
168+
out_pipe, in_pipe = IO.pipe
169+
pid = Process.spawn(
170+
CliUtil.path_to("Xvfb"), ":#{display}", "-screen", "0", dimensions, "-ac",
171+
err: in_pipe)
172+
in_pipe.close
173+
raise Headless::Exception.new("Xvfb did not launch - something's wrong") unless pid
174+
ensure_xvfb_is_running(out_pipe)
166175
return true
167176
end
168177

169-
def ensure_xvfb_is_running
178+
def ensure_xvfb_is_running(out_pipe)
170179
start_time = Time.now
180+
errors = ""
171181
begin
182+
begin
183+
errors += out_pipe.read_nonblock(10000)
184+
if errors.include? "Cannot establish any listening sockets"
185+
raise Headless::Exception.new("Display socket is taken but lock file is missing - check the Headless troubleshooting guide")
186+
end
187+
rescue IO::WaitReadable
188+
# will retry next cycle
189+
end
172190
sleep 0.01 # to avoid cpu hogging
173-
raise Headless::Exception.new("Xvfb is frozen") if (Time.now-start_time)>=@xvfb_launch_timeout
191+
raise Headless::Exception.new("Xvfb launched but did not complete initialization") if (Time.now-start_time)>=@xvfb_launch_timeout
174192
end while !xvfb_running?
175193
end
176194

@@ -197,4 +215,3 @@ def hook_at_exit
197215
end
198216
end
199217
end
200-

lib/headless/cli_util.rb

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -53,11 +53,13 @@ def self.kill_process(pid_filename, options={})
5353
# Process.wait tried to wait on a dead process
5454
end
5555
end
56-
57-
begin
58-
FileUtils.rm pid_filename
59-
rescue Errno::ENOENT
60-
# pid file already removed
56+
57+
unless options[:preserve_pid_file]
58+
begin
59+
FileUtils.rm pid_filename
60+
rescue Errno::ENOENT
61+
# pid file already removed
62+
end
6163
end
6264
end
6365
end

lib/headless/video/video_recorder.rb

Lines changed: 29 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@ class VideoRecorder
55
attr_accessor :pid_file_path, :tmp_file_path, :log_file_path
66

77
def initialize(display, dimensions, options = {})
8-
CliUtil.ensure_application_exists!('ffmpeg', 'Ffmpeg not found on your system. Install it with sudo apt-get install ffmpeg')
9-
108
@display = display
119
@dimensions = dimensions[/.+(?=x)/]
1210

@@ -17,33 +15,14 @@ def initialize(display, dimensions, options = {})
1715
@frame_rate = options.fetch(:frame_rate, 30)
1816
@provider = options.fetch(:provider, :libav) # or :ffmpeg
1917
@extra = Array(options.fetch(:extra, []))
18+
19+
CliUtil.ensure_application_exists!(provider_binary, "#{provider_binary} not found on your system. Install it or change video recorder provider")
2020
end
2121

2222
def capture_running?
2323
CliUtil.read_pid @pid_file_path
2424
end
2525

26-
def command_line_for_capture
27-
if @provider == :libav
28-
group_of_pic_size_option = '-g 600'
29-
dimensions = @dimensions
30-
else
31-
group_of_pic_size_option = nil
32-
dimensions = @dimensions.match(/^(\d+x\d+)/)[0]
33-
end
34-
35-
([
36-
CliUtil.path_to('ffmpeg'),
37-
"-y",
38-
"-r #{@frame_rate}",
39-
"-s #{dimensions}",
40-
"-f x11grab",
41-
"-i :#{@display}",
42-
group_of_pic_size_option,
43-
"-vcodec #{@codec}"
44-
].compact + @extra + [@tmp_file_path]).join(' ')
45-
end
46-
4726
def start_capture
4827
CliUtil.fork_process(command_line_for_capture,
4928
@pid_file_path, @log_file_path)
@@ -73,5 +52,32 @@ def stop_and_discard
7352
# that's ok if the file doesn't exist
7453
end
7554
end
55+
56+
private
57+
58+
def provider_binary
59+
@provider==:libav ? 'avconv' : 'ffmpeg'
60+
end
61+
62+
def command_line_for_capture
63+
if @provider == :libav
64+
group_of_pic_size_option = '-g 600'
65+
dimensions = @dimensions
66+
else
67+
group_of_pic_size_option = nil
68+
dimensions = @dimensions.match(/^(\d+x\d+)/)[0]
69+
end
70+
71+
([
72+
CliUtil.path_to(provider_binary),
73+
"-y",
74+
"-r #{@frame_rate}",
75+
"-s #{dimensions}",
76+
"-f x11grab",
77+
"-i :#{@display}",
78+
group_of_pic_size_option,
79+
"-vcodec #{@codec}"
80+
].compact + @extra + [@tmp_file_path]).join(' ')
81+
end
7682
end
7783
end

0 commit comments

Comments
 (0)