Skip to content

Commit 7158f08

Browse files
committed
Added specs. Bundler.
1 parent 98546d0 commit 7158f08

File tree

6 files changed

+169
-20
lines changed

6 files changed

+169
-20
lines changed

Gemfile

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
source "http://rubygems.org"
2+
3+
# Specify your gem's dependencies in ci_util.gemspec
4+
gemspec

Rakefile

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
require "bundler/gem_tasks"

.gemspec headless.gemspec

+4-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ require 'rake'
33
spec = Gem::Specification.new do |s|
44
s.author = 'Leonid Shevtsov'
55
s.email = '[email protected]'
6-
6+
77
s.name = 'headless'
88
s.version = '0.1.0'
99
s.summary = 'Ruby headless display interface'
@@ -16,4 +16,7 @@ spec = Gem::Specification.new do |s|
1616

1717
s.files = FileList['lib/*.rb', '[A-Z]*'].to_a
1818
s.has_rdoc = true
19+
20+
s.add_development_dependency "rspec", "~> 2.6"
21+
s.add_development_dependency "ruby-debug"
1922
end

lib/headless.rb

+14-19
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
require 'headless/cli_util'
2+
13
# A class incapsulating the creation and usage of a headless X server
24
#
35
# == Prerequisites
@@ -54,22 +56,20 @@ class Exception < ::Exception
5456
# * +reuse+ (default true) - if given display server already exists, should we use it or fail miserably?
5557
# * +dimensions+ (default 1280x1024x24) - display dimensions and depth. Not all combinations are possible, refer to +man Xvfb+.
5658
def initialize(options = {})
57-
find_xvfb
59+
raise Exception.new("Xvfb not found on your system") unless CliUtil.application_exists?("Xvfb")
5860

5961
@display = options.fetch(:display, 99).to_i
6062
@reuse_display = options.fetch(:reuse, true)
6163
@dimensions = options.fetch(:dimensions, '1280x1024x24')
6264

6365
#TODO more logic here, autopicking the display number
6466
if @reuse_display
65-
launch_xvfb unless read_pid
66-
elsif read_pid
67+
launch_xvfb unless xvfb_running?
68+
elsif xvfb_running?
6769
raise Exception.new("Display :#{display} is already taken and reuse=false")
6870
else
6971
launch_xvfb
7072
end
71-
72-
raise Exception.new("Xvfb did not launch - something's wrong") unless read_pid
7373
end
7474

7575
# Switches to the headless server
@@ -86,7 +86,7 @@ def stop
8686
# Switches back from the headless server and terminates the headless session
8787
def destroy
8888
stop
89-
Process.kill('TERM', xvfb_pid) if read_pid
89+
Process.kill('TERM', read_xvfb_pid) if xvfb_running?
9090
end
9191

9292
# Block syntax:
@@ -101,27 +101,22 @@ def self.run(options={}, &block)
101101
yield headless
102102
headless.destroy
103103
end
104-
105104
class <<self; alias_method :ly, :run; end
106105

107106
private
108-
attr_reader :xvfb_pid
109-
110-
def find_xvfb
111-
@xvfb = `which Xvfb`.strip
112-
raise Exception.new('Xvfb not found on your system') if @xvfb == ''
113-
end
114107

115108
def launch_xvfb
116109
#TODO error reporting
117-
system "#{@xvfb} :#{display} -screen 0 #{dimensions} -ac >/dev/null 2>&1 &"
118-
sleep 1
110+
result = system "#{CliUtil.path_to("Xvfb")} :#{display} -screen 0 #{dimensions} -ac >/dev/null 2>&1 &"
111+
raise Exception.new("Xvfb did not launch - something's wrong") unless result
112+
end
113+
114+
def xvfb_running?
115+
read_xvfb_pid
119116
end
120117

121-
def read_pid
122-
@xvfb_pid=(File.read("/tmp/.X#{display}-lock") rescue "").strip.to_i
123-
@xvfb_pid=nil if @xvfb_pid==0
124-
@xvfb_pid
118+
def read_xvfb_pid
125119
#TODO maybe check that the process still exists
120+
CliUtil.read_pid("/tmp/.X#{display}-lock")
126121
end
127122
end

lib/headless/cli_util.rb

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
class CliUtil
2+
def self.application_exists?(app)
3+
`which #{app}`.strip == ""
4+
end
5+
6+
def self.path_to(app)
7+
`which #{app}`.strip
8+
end
9+
10+
def self.read_pid(file)
11+
pid = (File.read("/tmp/.X#{display}-lock") rescue "").strip.to_i
12+
pid == 0 ? nil : pid
13+
end
14+
15+
def self.fork_process(command, pid_file)
16+
pid = fork do
17+
exec command
18+
exit! 127
19+
end
20+
21+
File.open pid_file, 'w' do |f|
22+
f.puts pid
23+
end
24+
end
25+
26+
def self.kill_process(pid_file)
27+
if File.exist? pid_file
28+
pid = File.read(pid_file).strip.to_i
29+
Process.kill 'TERM', pid
30+
FileUtils.rm pid_file
31+
else
32+
puts "#{pid_file} not found"
33+
end
34+
end
35+
36+
end

spec/headless_spec.rb

+110
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
require 'lib/headless'
2+
3+
describe Headless do
4+
before do
5+
ENV['DISPLAY'] = ":31337"
6+
end
7+
8+
context "instaniation" do
9+
context "when Xvfb is not installed" do
10+
before do
11+
CliUtil.stub!(:application_exists?).and_return(false)
12+
end
13+
14+
it "raises an error" do
15+
lambda { Headless.new }.should raise_error(Headless::Exception)
16+
end
17+
end
18+
19+
context "when Xvfb not started yet" do
20+
before do
21+
stub_environment
22+
end
23+
24+
it "starts Xvfb" do
25+
Headless.any_instance.should_receive(:system).with("/usr/bin/Xvfb :99 -screen 0 1280x1024x24 -ac >/dev/null 2>&1 &").and_return(true)
26+
27+
headless = Headless.new
28+
end
29+
30+
it "allows setting screen dimensions" do
31+
Headless.any_instance.should_receive(:system).with("/usr/bin/Xvfb :99 -screen 0 1024x768x16 -ac >/dev/null 2>&1 &").and_return(true)
32+
33+
headless = Headless.new(:dimensions => "1024x768x16")
34+
end
35+
end
36+
37+
context "when Xvfb is already running" do
38+
before do
39+
stub_environment
40+
CliUtil.stub!(:read_pid).and_return(31337)
41+
end
42+
43+
it "raises an error if reuse display is not allowed" do
44+
lambda { Headless.new(:reuse => false) }.should raise_error(Headless::Exception)
45+
end
46+
47+
it "doesn't raise an error if reuse display is allowed" do
48+
lambda { Headless.new(:reuse => true) }.should_not raise_error(Headless::Exception)
49+
lambda { Headless.new }.should_not raise_error(Headless::Exception)
50+
end
51+
end
52+
end
53+
54+
describe "#start" do
55+
before do
56+
stub_environment
57+
58+
@headless = Headless.new
59+
end
60+
61+
it "switches to the headless server" do
62+
ENV['DISPLAY'].should == ":31337"
63+
@headless.start
64+
ENV['DISPLAY'].should == ":99"
65+
end
66+
end
67+
68+
describe "#stop" do
69+
before do
70+
stub_environment
71+
72+
@headless = Headless.new
73+
end
74+
75+
it "switches back from the headless server" do
76+
ENV['DISPLAY'].should == ":31337"
77+
@headless.start
78+
ENV['DISPLAY'].should == ":99"
79+
@headless.stop
80+
ENV['DISPLAY'].should == ":31337"
81+
end
82+
end
83+
84+
describe "#destroy" do
85+
before do
86+
stub_environment
87+
@headless = Headless.new
88+
89+
CliUtil.stub!(:read_pid).and_return(4444)
90+
end
91+
92+
it "switches back from the headless server and terminates the headless session" do
93+
Process.should_receive(:kill).with('TERM', 4444)
94+
95+
ENV['DISPLAY'].should == ":31337"
96+
@headless.start
97+
ENV['DISPLAY'].should == ":99"
98+
@headless.destroy
99+
ENV['DISPLAY'].should == ":31337"
100+
end
101+
end
102+
103+
private
104+
105+
def stub_environment
106+
CliUtil.stub!(:application_exists?).and_return(true)
107+
CliUtil.stub!(:read_pid).and_return(nil)
108+
CliUtil.stub!(:path_to).and_return("/usr/bin/Xvfb")
109+
end
110+
end

0 commit comments

Comments
 (0)