headless 0.3.1 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG CHANGED
@@ -1,3 +1,8 @@
1
+ ## 1.0.0 (2013-01-28)
2
+
3
+ * bugfix release
4
+ * version number compliant to the [semantic versioning system](http://semver.org)
5
+
1
6
  ## 0.3.1 (2012-03-29)
2
7
 
3
8
  * added autopicking of display number, if the requested one is already taken
data/README.md CHANGED
@@ -10,6 +10,8 @@ Documentation is available at [rdoc.info](http://rdoc.info/projects/leonid-shevt
10
10
 
11
11
  [Changelog](https://github.com/leonid-shevtsov/headless/blob/master/CHANGELOG)
12
12
 
13
+ **Note: Headless will NOT hide most applications on OS X. [Here is a detailed explanation](https://github.com/leonid-shevtsov/headless/issues/31#issuecomment-8933108)**
14
+
13
15
  ## Installation
14
16
 
15
17
  On Debian/Ubuntu:
@@ -59,6 +61,27 @@ Running cucumber headless is now as simple as adding a before and after hook in
59
61
  headless.start
60
62
  end
61
63
 
64
+ ## Running tests in parallel
65
+
66
+ If you have multiple threads running acceptance tests in parallel, you want to spawn Headless before forking, and then reuse that instance with `destroy_at_exit: false`.
67
+ You can even spawn a Headless instance in one ruby script, and then reuse the same instance in other scripts by specifying the same display number and `reuse: true`.
68
+
69
+ # spawn_headless.rb
70
+ Headless.new(display: 100, destroy_at_exit: false).start
71
+
72
+
73
+ # test_suite_that_could_be_ran_multiple_times.rb
74
+ headless = Headless.new(display: 100, reuse: true, destroy_at_exit: false)
75
+ # Xvfb is already started by the first script
76
+
77
+ # reap_headless.rb
78
+ headless = Headless.new(display: 100, reuse: true)
79
+ headless.destroy
80
+
81
+
82
+
83
+
84
+
62
85
  ## Cucumber with wkhtmltopdf
63
86
 
64
87
  _Note: this is true for other programs which may use headless at the same time as cucumber is running_
@@ -3,7 +3,7 @@ spec = Gem::Specification.new do |s|
3
3
  s.email = 'leonid@shevtsov.me'
4
4
 
5
5
  s.name = 'headless'
6
- s.version = '0.3.1'
6
+ s.version = '1.0.0'
7
7
  s.summary = 'Ruby headless display interface'
8
8
 
9
9
  s.description = <<-EOF
@@ -14,5 +14,6 @@ spec = Gem::Specification.new do |s|
14
14
 
15
15
  s.files = `git ls-files`.split("\n")
16
16
 
17
+ s.add_development_dependency 'rake'
17
18
  s.add_development_dependency "rspec", "~> 2.6"
18
19
  end
@@ -15,11 +15,11 @@ require 'headless/video/video_recorder'
15
15
  # require 'rubygems'
16
16
  # require 'headless'
17
17
  # require 'selenium-webdriver'
18
- #
18
+ #
19
19
  # Headless.ly do
20
20
  # driver = Selenium::WebDriver.for :firefox
21
21
  # driver.navigate.to 'http://google.com'
22
- # puts driver.title
22
+ # puts driver.title
23
23
  # end
24
24
  #
25
25
  # Object mode:
@@ -33,7 +33,7 @@ require 'headless/video/video_recorder'
33
33
  #
34
34
  # driver = Selenium::WebDriver.for :firefox
35
35
  # driver.navigate.to 'http://google.com'
36
- # puts driver.title
36
+ # puts driver.title
37
37
  #
38
38
  # headless.destroy
39
39
  #--
@@ -42,6 +42,7 @@ require 'headless/video/video_recorder'
42
42
  class Headless
43
43
 
44
44
  DEFAULT_DISPLAY_NUMBER = 99
45
+ MAX_DISPLAY_NUMBER = 10_000
45
46
  DEFAULT_DISPLAY_DIMENSIONS = '1280x1024x24'
46
47
 
47
48
  class Exception < RuntimeError
@@ -102,6 +103,7 @@ class Headless
102
103
  headless = Headless.new(options)
103
104
  headless.start
104
105
  yield headless
106
+ ensure
105
107
  headless.destroy
106
108
  end
107
109
  class <<self; alias_method :ly, :run; end
@@ -119,38 +121,28 @@ class Headless
119
121
  private
120
122
 
121
123
  def attach_xvfb
122
- # TODO this loop isn't elegant enough
123
- success = false
124
- while !success && @display<10000
125
- begin
126
- if !xvfb_running?
127
- launch_xvfb
128
- success=true
129
- else
130
- success = @reuse_display
131
- end
132
- rescue Errno::EPERM
133
- # No permission to read pid file
134
- success = false
135
- end
124
+ possible_display_set = @autopick_display ? @display..MAX_DISPLAY_NUMBER : Array(@display)
125
+ pick_available_display(possible_display_set, @reuse_display)
126
+ end
136
127
 
137
- # TODO this is crufty
138
- if @autopick_display
139
- @display += 1 unless success
140
- else
141
- break
128
+ def pick_available_display(display_set, can_reuse)
129
+ display_set.each do |display_number|
130
+ @display = display_number
131
+ begin
132
+ return true if xvfb_running? && can_reuse
133
+ return true if !xvfb_running? && launch_xvfb
134
+ rescue Errno::EPERM # display not accessible
135
+ next
142
136
  end
143
137
  end
144
-
145
- unless success
146
- raise Headless::Exception.new("Display :#{display} is already taken and reuse=false")
147
- end
138
+ raise Headless::Exception.new("Could not find an available display")
148
139
  end
149
140
 
150
141
  def launch_xvfb
151
142
  #TODO error reporting
152
143
  result = system "#{CliUtil.path_to("Xvfb")} :#{display} -screen 0 #{dimensions} -ac >/dev/null 2>&1 &"
153
144
  raise Headless::Exception.new("Xvfb did not launch - something's wrong") unless result
145
+ return true
154
146
  end
155
147
 
156
148
  def xvfb_running?
@@ -164,7 +156,7 @@ private
164
156
  def read_xvfb_pid
165
157
  CliUtil.read_pid(pid_filename)
166
158
  end
167
-
159
+
168
160
  def hook_at_exit
169
161
  unless @at_exit_hook_installed
170
162
  @at_exit_hook_installed = true
@@ -3,7 +3,7 @@ class Headless
3
3
  def self.application_exists?(app)
4
4
  `which #{app}`.strip != ""
5
5
  end
6
-
6
+
7
7
  def self.ensure_application_exists!(app, error_message)
8
8
  if !self.application_exists?(app)
9
9
  raise Headless::Exception.new(error_message)
@@ -36,7 +36,6 @@ class Headless
36
36
  exec command
37
37
  exit! 127 # safeguard in case exec fails
38
38
  end
39
- Process.detach(pid)
40
39
 
41
40
  File.open pid_filename, 'w' do |f|
42
41
  f.puts pid
@@ -14,6 +14,7 @@ class Headless
14
14
  @tmp_file_path = options.fetch(:tmp_file_path, "/tmp/.headless_ffmpeg_#{@display}.mov")
15
15
  @log_file_path = options.fetch(:log_file_path, "/dev/null")
16
16
  @codec = options.fetch(:codec, "qtrle")
17
+ @frame_rate = options.fetch(:frame_rate, 30)
17
18
  end
18
19
 
19
20
  def capture_running?
@@ -21,7 +22,7 @@ class Headless
21
22
  end
22
23
 
23
24
  def start_capture
24
- CliUtil.fork_process("#{CliUtil.path_to('ffmpeg')} -y -r 30 -g 600 -s #{@dimensions} -f x11grab -i :#{@display} -vcodec #{@codec} #{@tmp_file_path}", @pid_file_path, @log_file_path)
25
+ CliUtil.fork_process("#{CliUtil.path_to('ffmpeg')} -y -r #{@frame_rate} -g 600 -s #{@dimensions} -f x11grab -i :#{@display} -vcodec #{@codec} #{@tmp_file_path}", @pid_file_path, @log_file_path)
25
26
  at_exit do
26
27
  exit_status = $!.status if $!.is_a?(SystemExit)
27
28
  stop_and_discard
@@ -44,10 +44,10 @@ describe Headless do
44
44
  Headless.new(options).display.should == 99
45
45
  end
46
46
  end
47
-
47
+
48
48
  context "and display reuse is not allowed" do
49
49
  let(:options) { {:reuse => false} }
50
-
50
+
51
51
  it "should pick the next available display number" do
52
52
  Headless.new(options).display.should == 100
53
53
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: headless
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.1
4
+ version: 1.0.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,27 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-03-29 00:00:00.000000000 Z
12
+ date: 2013-01-28 00:00:00.000000000 Z
13
13
  dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rake
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
14
30
  - !ruby/object:Gem::Dependency
15
31
  name: rspec
16
- requirement: &70170211681540 !ruby/object:Gem::Requirement
32
+ requirement: !ruby/object:Gem::Requirement
17
33
  none: false
18
34
  requirements:
19
35
  - - ~>
@@ -21,7 +37,12 @@ dependencies:
21
37
  version: '2.6'
22
38
  type: :development
23
39
  prerelease: false
24
- version_requirements: *70170211681540
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ version: '2.6'
25
46
  description: ! ' Headless is a Ruby interface for Xvfb. It allows you to create
26
47
  a headless display straight from Ruby code, hiding some low-level action.
27
48
 
@@ -56,16 +77,22 @@ required_ruby_version: !ruby/object:Gem::Requirement
56
77
  - - ! '>='
57
78
  - !ruby/object:Gem::Version
58
79
  version: '0'
80
+ segments:
81
+ - 0
82
+ hash: 2986386947499728446
59
83
  required_rubygems_version: !ruby/object:Gem::Requirement
60
84
  none: false
61
85
  requirements:
62
86
  - - ! '>='
63
87
  - !ruby/object:Gem::Version
64
88
  version: '0'
89
+ segments:
90
+ - 0
91
+ hash: 2986386947499728446
65
92
  requirements:
66
93
  - Xvfb
67
94
  rubyforge_project:
68
- rubygems_version: 1.8.17
95
+ rubygems_version: 1.8.24
69
96
  signing_key:
70
97
  specification_version: 3
71
98
  summary: Ruby headless display interface