jstd-runner 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +4 -0
- data/Gemfile +4 -0
- data/LICENSE +13 -0
- data/README.rdoc +25 -0
- data/Rakefile +7 -0
- data/autotest/discover.rb +1 -0
- data/bin/jstd-runner +5 -0
- data/jstd-runner.gemspec +25 -0
- data/lib/jstd-runner.rb +27 -0
- data/lib/jstd-runner/JsTestDriver-1.2.2.jar +0 -0
- data/lib/jstd-runner/browser.rb +62 -0
- data/lib/jstd-runner/cli.rb +50 -0
- data/lib/jstd-runner/monitorable.rb +15 -0
- data/lib/jstd-runner/runner.rb +167 -0
- data/lib/jstd-runner/server.rb +79 -0
- data/lib/jstd-runner/version.rb +3 -0
- data/lib/jstd-runner/vnc_control.rb +54 -0
- data/spec/jstd-runner/browser_spec.rb +57 -0
- data/spec/jstd-runner/cli_spec.rb +47 -0
- data/spec/jstd-runner/monitorable_spec.rb +56 -0
- data/spec/jstd-runner/runner_spec.rb +40 -0
- data/spec/jstd-runner/server_spec.rb +94 -0
- data/spec/jstd-runner/vnc_control_spec.rb +7 -0
- data/spec/spec_helper.rb +3 -0
- metadata +162 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
Copyright 2010 FINN.no AS
|
2
|
+
|
3
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
you may not use this file except in compliance with the License.
|
5
|
+
You may obtain a copy of the License at
|
6
|
+
|
7
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
|
9
|
+
Unless required by applicable law or agreed to in writing, software
|
10
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
See the License for the specific language governing permissions and
|
13
|
+
limitations under the License.
|
data/README.rdoc
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
= jstd-runner
|
2
|
+
|
3
|
+
A gem that provides a tool to launch a JsTestDriver server, capture browser(s) and monitor the involved processes.
|
4
|
+
|
5
|
+
= TODO
|
6
|
+
|
7
|
+
* Config file
|
8
|
+
* Support launching multiple browsers
|
9
|
+
* Support launching browser through a remote WebDriver server
|
10
|
+
* Configurable logging
|
11
|
+
* Prettier logging
|
12
|
+
|
13
|
+
== Note on Patches/Pull Requests
|
14
|
+
|
15
|
+
* Fork the project.
|
16
|
+
* Make your feature addition or bug fix.
|
17
|
+
* Add tests for it. This is important so I don't break it in a
|
18
|
+
future version unintentionally.
|
19
|
+
* Commit, do not mess with rakefile, version, or history.
|
20
|
+
(if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
|
21
|
+
* Send me a pull request. Bonus points for topic branches.
|
22
|
+
|
23
|
+
== Copyright
|
24
|
+
|
25
|
+
Copyright (c) 2010 FINN.no. See LICENSE for details.
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
Autotest.add_discovery { "rspec2" }
|
data/bin/jstd-runner
ADDED
data/jstd-runner.gemspec
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "jstd-runner/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "jstd-runner"
|
7
|
+
s.version = JstdRunner::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Jari Bakken"]
|
10
|
+
s.email = ["jari.bakken@gmail.com"]
|
11
|
+
s.homepage = "http://github.com/jarib/jstd-runner"
|
12
|
+
s.summary = %q{JsTestDriver wrapper}
|
13
|
+
s.description = %q{Runs a JsTestDriver server + browsers with some built-in monitoring}
|
14
|
+
|
15
|
+
s.files = `git ls-files`.split("\n")
|
16
|
+
s.executables = `git ls-files`.split("\n").map{|f| f =~ /^bin\/(.*)/ ? $1 : nil}.compact
|
17
|
+
s.require_path = 'lib'
|
18
|
+
|
19
|
+
s.add_dependency "selenium-webdriver", "0.1.0"
|
20
|
+
s.add_dependency "eventmachine", "0.12.10"
|
21
|
+
s.add_dependency "mail", "2.2.10"
|
22
|
+
s.add_dependency "daemons", "1.1.0"
|
23
|
+
|
24
|
+
s.add_development_dependency "rspec", ">= 2.0.0"
|
25
|
+
end
|
data/lib/jstd-runner.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
require "logger"
|
2
|
+
require "optparse"
|
3
|
+
require "etc"
|
4
|
+
|
5
|
+
module JstdRunner
|
6
|
+
Log = Logger.new(STDOUT)
|
7
|
+
|
8
|
+
class << self
|
9
|
+
attr_accessor :shutting_down
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
require "selenium-webdriver"
|
14
|
+
require "eventmachine"
|
15
|
+
require "daemons"
|
16
|
+
require "socket"
|
17
|
+
require "mail"
|
18
|
+
require "fileutils"
|
19
|
+
|
20
|
+
require "jstd-runner/cli"
|
21
|
+
require "jstd-runner/monitorable"
|
22
|
+
require "jstd-runner/browser"
|
23
|
+
require "jstd-runner/vnc_control"
|
24
|
+
require "jstd-runner/server"
|
25
|
+
require "jstd-runner/runner"
|
26
|
+
|
27
|
+
|
Binary file
|
@@ -0,0 +1,62 @@
|
|
1
|
+
module JstdRunner
|
2
|
+
class Browser
|
3
|
+
include Monitorable
|
4
|
+
|
5
|
+
def initialize(type = :firefox)
|
6
|
+
@type = type
|
7
|
+
@switched = @restarting = false
|
8
|
+
end
|
9
|
+
|
10
|
+
def start
|
11
|
+
Log.info "starting browser - #{@type}"
|
12
|
+
@browser = Selenium::WebDriver.for @type
|
13
|
+
end
|
14
|
+
|
15
|
+
def capture(host, port)
|
16
|
+
@restarting = true
|
17
|
+
@switched = false
|
18
|
+
start unless @browser
|
19
|
+
@browser.get "http://#{host}:#{port}/capture"
|
20
|
+
@restarting = false
|
21
|
+
end
|
22
|
+
|
23
|
+
def restart
|
24
|
+
@restarting = true
|
25
|
+
Log.info "restarting browser - #{@type}"
|
26
|
+
stop rescue nil
|
27
|
+
@switched = false
|
28
|
+
start
|
29
|
+
@restarting = false
|
30
|
+
end
|
31
|
+
|
32
|
+
def stop
|
33
|
+
Log.info "stopping browser - #{@type}"
|
34
|
+
@browser.quit if @browser
|
35
|
+
rescue Errno::ECONNREFUSED
|
36
|
+
# looks like we're not running
|
37
|
+
end
|
38
|
+
|
39
|
+
def running?
|
40
|
+
Log.info "browser state: #{status}"
|
41
|
+
true
|
42
|
+
rescue
|
43
|
+
false
|
44
|
+
end
|
45
|
+
|
46
|
+
def status
|
47
|
+
status_span.text
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
def status_span
|
53
|
+
unless @switched
|
54
|
+
@browser.switch_to.frame("0")
|
55
|
+
@switched = true
|
56
|
+
end
|
57
|
+
|
58
|
+
@browser.find_element(:tag_name => "span")
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module JstdRunner
|
2
|
+
class CLI
|
3
|
+
|
4
|
+
def initialize(args)
|
5
|
+
parse args
|
6
|
+
end
|
7
|
+
|
8
|
+
def run
|
9
|
+
runner.run
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def parse(args)
|
15
|
+
OptionParser.new { |op|
|
16
|
+
op.banner = "Usage: #{File.basename $PROGRAM_NAME} [options]"
|
17
|
+
op.separator ""
|
18
|
+
|
19
|
+
op.on("-p", "--port PORT", Integer) do |port|
|
20
|
+
runner.options[:port] = port
|
21
|
+
end
|
22
|
+
|
23
|
+
op.on("-x", "--vnc") do
|
24
|
+
runner.options[:vnc] = true
|
25
|
+
end
|
26
|
+
|
27
|
+
op.on("-m", "--monitor INTERVAL", Integer) do |int|
|
28
|
+
runner.options[:monitor_interval] = int
|
29
|
+
end
|
30
|
+
|
31
|
+
op.on("-b", "--browser BROWSER", String) do |browser|
|
32
|
+
runner.options[:browser] = browser.to_sym
|
33
|
+
end
|
34
|
+
|
35
|
+
op.on("-d", "--daemonize LOGFILE", String) do |log|
|
36
|
+
runner.options[:daemonize] = log
|
37
|
+
end
|
38
|
+
|
39
|
+
op.on("-n", "--notify email1,email2,email3", Array) do |emails|
|
40
|
+
runner.options[:emails] = emails
|
41
|
+
end
|
42
|
+
}.parse!(args)
|
43
|
+
end
|
44
|
+
|
45
|
+
def runner
|
46
|
+
@runner ||= Runner.new
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module JstdRunner
|
2
|
+
module Monitorable
|
3
|
+
def monitor(interval, &failure_callback)
|
4
|
+
EM.add_periodic_timer(interval) {
|
5
|
+
next if JstdRunner.shutting_down || @restarting
|
6
|
+
if running?
|
7
|
+
Log.info "ok: #{self}"
|
8
|
+
else
|
9
|
+
Log.info "dead: #{self}"
|
10
|
+
failure_callback.call
|
11
|
+
end
|
12
|
+
}
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,167 @@
|
|
1
|
+
module JstdRunner
|
2
|
+
class Runner
|
3
|
+
|
4
|
+
DEFAULT_OPTIONS = {
|
5
|
+
:port => 4224,
|
6
|
+
:vnc => false,
|
7
|
+
:monitor_interval => 10,
|
8
|
+
:browser => :firefox,
|
9
|
+
:daemonize => false
|
10
|
+
}
|
11
|
+
|
12
|
+
attr_reader :options
|
13
|
+
|
14
|
+
def initialize
|
15
|
+
@options = DEFAULT_OPTIONS.dup
|
16
|
+
@shutting_down = @clean_shutdown = false
|
17
|
+
@server_restarting = @browser_restarting = false
|
18
|
+
end
|
19
|
+
|
20
|
+
def run
|
21
|
+
EM.run {
|
22
|
+
configure_mailer
|
23
|
+
trap_signals
|
24
|
+
daemonize if options[:daemonize]
|
25
|
+
shutdown_hook
|
26
|
+
start_server
|
27
|
+
start_browser
|
28
|
+
capture_browser
|
29
|
+
}
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def trap_signals
|
35
|
+
trap_signal "INT"
|
36
|
+
trap_signal "TERM"
|
37
|
+
end
|
38
|
+
|
39
|
+
def trap_signal(sig)
|
40
|
+
trap(sig) {
|
41
|
+
trap sig, "DEFAULT"
|
42
|
+
Log.info "received #{sig}, shutting down"
|
43
|
+
stop
|
44
|
+
}
|
45
|
+
end
|
46
|
+
|
47
|
+
def shutting_down?
|
48
|
+
@shutting_down
|
49
|
+
end
|
50
|
+
|
51
|
+
def server_restarting?
|
52
|
+
@server_restarting
|
53
|
+
end
|
54
|
+
|
55
|
+
def browser_restarting?
|
56
|
+
@browser_restarting
|
57
|
+
end
|
58
|
+
|
59
|
+
def clean_shutdown?
|
60
|
+
@clean_shutdown
|
61
|
+
end
|
62
|
+
|
63
|
+
def shutdown_hook
|
64
|
+
at_exit {
|
65
|
+
unless clean_shutdown?
|
66
|
+
body = $! ? [$!.message, $!.backtrace].flatten.join("\n") : '(empty)'
|
67
|
+
notify "exiting @ #{Time.now}", body
|
68
|
+
end
|
69
|
+
}
|
70
|
+
end
|
71
|
+
|
72
|
+
def stop
|
73
|
+
JstdRunner.shutting_down = true
|
74
|
+
|
75
|
+
stop_browser
|
76
|
+
stop_server
|
77
|
+
|
78
|
+
EM.stop
|
79
|
+
|
80
|
+
@clean_shutdown = true
|
81
|
+
end
|
82
|
+
|
83
|
+
def start_server
|
84
|
+
server.start
|
85
|
+
server.monitor(options[:monitor_interval]) {
|
86
|
+
server.restart
|
87
|
+
capture_browser
|
88
|
+
}
|
89
|
+
end
|
90
|
+
|
91
|
+
def stop_server
|
92
|
+
server.stop
|
93
|
+
end
|
94
|
+
|
95
|
+
def start_browser
|
96
|
+
start_vnc if options[:vnc]
|
97
|
+
browser.start
|
98
|
+
browser.monitor(options[:monitor_interval]) {
|
99
|
+
browser.restart
|
100
|
+
capture_browser
|
101
|
+
}
|
102
|
+
end
|
103
|
+
|
104
|
+
def capture_browser
|
105
|
+
Log.info "capturing #{browser.inspect}"
|
106
|
+
browser.capture(server.host, server.port)
|
107
|
+
end
|
108
|
+
|
109
|
+
def stop_browser
|
110
|
+
stop_vnc if options[:vnc]
|
111
|
+
browser.stop
|
112
|
+
end
|
113
|
+
|
114
|
+
def start_vnc
|
115
|
+
vnc.start
|
116
|
+
ENV['DISPLAY'] = vnc.display
|
117
|
+
end
|
118
|
+
|
119
|
+
def stop_vnc
|
120
|
+
vnc.stop
|
121
|
+
end
|
122
|
+
|
123
|
+
def daemonize
|
124
|
+
log_file = options[:daemonize]
|
125
|
+
FileUtils.touch log_file
|
126
|
+
|
127
|
+
Daemonize.daemonize(log_file, "#{$PROGRAM_NAME}-daemonized")
|
128
|
+
end
|
129
|
+
|
130
|
+
def server
|
131
|
+
@server ||= Server.new(options[:port])
|
132
|
+
end
|
133
|
+
|
134
|
+
def browser
|
135
|
+
@browser ||= Browser.new(options[:browser])
|
136
|
+
end
|
137
|
+
|
138
|
+
def vnc
|
139
|
+
@vnc ||= VncControl.new
|
140
|
+
end
|
141
|
+
|
142
|
+
def configure_mailer
|
143
|
+
return unless options[:smtp]
|
144
|
+
|
145
|
+
uri = URI.parse(options[:smtp])
|
146
|
+
Mail.defaults {
|
147
|
+
delivery_method(uri.scheme.to_sym, :address => uri.host, :port => uri.port)
|
148
|
+
}
|
149
|
+
end
|
150
|
+
|
151
|
+
def notify(subject, body)
|
152
|
+
return unless recipients = options[:emails]
|
153
|
+
|
154
|
+
Mail.deliver {
|
155
|
+
from [Etc.getlogin, Socket.gethostname].join("@")
|
156
|
+
to recipients
|
157
|
+
subject "JstdRunner @ #{Socket.gethostname}: #{subject}"
|
158
|
+
body body
|
159
|
+
}
|
160
|
+
end
|
161
|
+
|
162
|
+
def monitor(&blk)
|
163
|
+
EM.add_periodic_timer(@options[:monitor_interval], &blk)
|
164
|
+
end
|
165
|
+
|
166
|
+
end # Runner
|
167
|
+
end # JstdRunner
|
@@ -0,0 +1,79 @@
|
|
1
|
+
module JstdRunner
|
2
|
+
class Server
|
3
|
+
include Monitorable
|
4
|
+
|
5
|
+
class StartupError < StandardError
|
6
|
+
end
|
7
|
+
|
8
|
+
class StopError < StandardError
|
9
|
+
end
|
10
|
+
|
11
|
+
JAR = File.expand_path("../JsTestDriver-1.2.2.jar", __FILE__)
|
12
|
+
LAUNCH_TIMEOUT = 120 # this is huge, but I've seen it happen
|
13
|
+
|
14
|
+
attr_reader :host, :port
|
15
|
+
|
16
|
+
def initialize(port)
|
17
|
+
@host = "127.0.0.1"
|
18
|
+
@port = Integer(port)
|
19
|
+
@restarting = false
|
20
|
+
end
|
21
|
+
|
22
|
+
def start
|
23
|
+
Log.info "starting JsTestDriver"
|
24
|
+
|
25
|
+
if immediate_poller.connected?
|
26
|
+
raise StartupError, "JsTestDriver already running on #{@host}:#{@port}"
|
27
|
+
end
|
28
|
+
|
29
|
+
process.start
|
30
|
+
|
31
|
+
unless long_poller.connected?
|
32
|
+
process.stop rescue nil
|
33
|
+
raise StartupError, "could not launch JsTestDriver server on #{@host}:#{@port} within #{LAUNCH_TIMEOUT} seconds"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def restart
|
38
|
+
@restarting = true
|
39
|
+
Log.info "restaring server"
|
40
|
+
stop rescue nil
|
41
|
+
@process = nil
|
42
|
+
start
|
43
|
+
@restarting = false
|
44
|
+
end
|
45
|
+
|
46
|
+
def stop
|
47
|
+
Log.info "stopping JsTestDriver"
|
48
|
+
process.stop
|
49
|
+
|
50
|
+
unless long_poller.closed?
|
51
|
+
raise StopError, "could not stop JsTestDriver server on port #{@host}:#{@port} witin #{LAUNCH_TIMEOUT} seconds"
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def running?
|
56
|
+
process.alive? && immediate_poller.connected?
|
57
|
+
end
|
58
|
+
|
59
|
+
private
|
60
|
+
|
61
|
+
def process
|
62
|
+
@process ||= (
|
63
|
+
proc = ChildProcess.new("java", "-jar", JAR, "--port", @port.to_s)
|
64
|
+
proc.io.inherit! if $DEBUG
|
65
|
+
|
66
|
+
proc
|
67
|
+
)
|
68
|
+
end
|
69
|
+
|
70
|
+
def long_poller
|
71
|
+
@long_poller ||= Selenium::WebDriver::SocketPoller.new(@host, @port, LAUNCH_TIMEOUT)
|
72
|
+
end
|
73
|
+
|
74
|
+
def immediate_poller
|
75
|
+
@immediate_poller ||= Selenium::WebDriver::SocketPoller.new(@host, @port, 5)
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module JstdRunner
|
2
|
+
class VncControl
|
3
|
+
|
4
|
+
class Error < StandardError
|
5
|
+
end
|
6
|
+
|
7
|
+
class << self
|
8
|
+
def displays
|
9
|
+
Dir[File.expand_path("~/.vnc/*.pid")].map { |e| e[/(\d+)\.pid/, 1] }.compact
|
10
|
+
end
|
11
|
+
|
12
|
+
def all
|
13
|
+
displays.map { |display| new(":#{display}") }
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
attr_reader :display
|
18
|
+
|
19
|
+
def initialize(display = nil)
|
20
|
+
@display = display
|
21
|
+
end
|
22
|
+
|
23
|
+
def start
|
24
|
+
if @display
|
25
|
+
server @display
|
26
|
+
Log.info "vnc server launched on #{@display.inspect}"
|
27
|
+
else
|
28
|
+
output = server
|
29
|
+
@display = output[/desktop is #{host}(\S+)/, 1]
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def stop
|
34
|
+
server "-kill", @display.to_s
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def server(*args)
|
40
|
+
out = `tightvncserver #{args.join ' '} 2>&1`
|
41
|
+
|
42
|
+
unless $?.success?
|
43
|
+
raise Error, "could not run tightvncserver: #{out.inspect}"
|
44
|
+
end
|
45
|
+
|
46
|
+
out
|
47
|
+
end
|
48
|
+
|
49
|
+
def host
|
50
|
+
@host ||= Socket.gethostname
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
module JstdRunner
|
4
|
+
describe Browser do
|
5
|
+
let(:browser) { Browser.new }
|
6
|
+
|
7
|
+
it "launches the the browser" do
|
8
|
+
Selenium::WebDriver.should_receive(:for).once
|
9
|
+
|
10
|
+
browser.start
|
11
|
+
end
|
12
|
+
|
13
|
+
it "captures the browser" do
|
14
|
+
mock_driver = mock(Selenium::WebDriver::Driver)
|
15
|
+
|
16
|
+
Selenium::WebDriver.should_receive(:for).and_return(mock_driver)
|
17
|
+
mock_driver.should_receive(:get).with("http://localhost:4224/capture")
|
18
|
+
|
19
|
+
browser.capture "localhost", 4224
|
20
|
+
end
|
21
|
+
|
22
|
+
it "stops the browser" do
|
23
|
+
mock_driver = mock(Selenium::WebDriver::Driver)
|
24
|
+
|
25
|
+
Selenium::WebDriver.should_receive(:for).and_return(mock_driver)
|
26
|
+
mock_driver.should_receive(:quit)
|
27
|
+
|
28
|
+
browser.start
|
29
|
+
browser.stop
|
30
|
+
end
|
31
|
+
|
32
|
+
it "restarts the browser" do
|
33
|
+
browser.should_receive(:stop).once
|
34
|
+
browser.should_receive(:start).once
|
35
|
+
|
36
|
+
browser.restart
|
37
|
+
end
|
38
|
+
|
39
|
+
it "restarts the browser if it was already stopped" do
|
40
|
+
browser.should_receive(:stop).once.and_raise("foo")
|
41
|
+
browser.should_receive(:start).once
|
42
|
+
|
43
|
+
browser.restart
|
44
|
+
end
|
45
|
+
|
46
|
+
it "knows if the browser is running" do
|
47
|
+
browser.stub!(:status_span).and_return(mock(:text => "Waiting..."))
|
48
|
+
browser.should be_running
|
49
|
+
end
|
50
|
+
|
51
|
+
it "knows if the browser is not running" do
|
52
|
+
# if we can't get the span, we assume it's dead
|
53
|
+
browser.stub!(:status_span).and_raise(Errno::ECONNREFUSED)
|
54
|
+
browser.should_not be_running
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
module JstdRunner
|
4
|
+
describe CLI do
|
5
|
+
let(:runner) { mock(Runner, :options => {}) }
|
6
|
+
before { Runner.stub!(:new).and_return(runner) }
|
7
|
+
|
8
|
+
def cli(str = '')
|
9
|
+
CLI.new(str.split(" "))
|
10
|
+
end
|
11
|
+
|
12
|
+
it "configures the port" do
|
13
|
+
cli "--port 1234"
|
14
|
+
runner.options[:port].should == 1234
|
15
|
+
end
|
16
|
+
|
17
|
+
it "configures VNC" do
|
18
|
+
cli "--vnc"
|
19
|
+
runner.options[:vnc].should be_true
|
20
|
+
end
|
21
|
+
|
22
|
+
it "configures the monitoring interval" do
|
23
|
+
cli "--monitor 10"
|
24
|
+
runner.options[:monitor_interval].should == 10
|
25
|
+
end
|
26
|
+
|
27
|
+
it "configures the browser type" do
|
28
|
+
cli "--browser chrome"
|
29
|
+
runner.options[:browser].should == :chrome
|
30
|
+
end
|
31
|
+
|
32
|
+
it "configures daemonization" do
|
33
|
+
cli "--daemonize /foo/bar"
|
34
|
+
runner.options[:daemonize].should == "/foo/bar"
|
35
|
+
end
|
36
|
+
|
37
|
+
it "configures email notifications" do
|
38
|
+
cli "--notify a@b.com,x@y.com"
|
39
|
+
runner.options[:emails].should == %w[a@b.com x@y.com]
|
40
|
+
end
|
41
|
+
|
42
|
+
it "delegates to the runner when run" do
|
43
|
+
runner.should_receive(:run)
|
44
|
+
cli.run
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module JstdRunner
|
4
|
+
describe Monitorable do
|
5
|
+
let(:object) {
|
6
|
+
obj = Object.new
|
7
|
+
|
8
|
+
class << obj
|
9
|
+
attr_accessor :restarting, :running
|
10
|
+
include Monitorable
|
11
|
+
|
12
|
+
def running?
|
13
|
+
@running
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
obj
|
18
|
+
}
|
19
|
+
|
20
|
+
before { EM.should_receive(:add_periodic_timer).and_yield }
|
21
|
+
after { JstdRunner.shutting_down = false }
|
22
|
+
|
23
|
+
it "yields if self is not running" do
|
24
|
+
did_yield = false
|
25
|
+
|
26
|
+
object.running = false
|
27
|
+
object.monitor(1) { did_yield = true }
|
28
|
+
|
29
|
+
did_yield.should be_true
|
30
|
+
end
|
31
|
+
|
32
|
+
it "does not yield when self is running" do
|
33
|
+
did_yield = false
|
34
|
+
|
35
|
+
object.running = true
|
36
|
+
object.monitor(1) { did_yield = true }
|
37
|
+
|
38
|
+
did_yield.should be_false
|
39
|
+
end
|
40
|
+
|
41
|
+
it "does not check when we're shutting down" do
|
42
|
+
JstdRunner.shutting_down = true
|
43
|
+
object.should_not_receive :running?
|
44
|
+
|
45
|
+
object.monitor(1) {}
|
46
|
+
end
|
47
|
+
|
48
|
+
it "does not check when self is restarting" do
|
49
|
+
object.restarting = true
|
50
|
+
object.should_not_receive :running?
|
51
|
+
|
52
|
+
object.monitor(1) {}
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
module JstdRunner
|
4
|
+
describe Runner do
|
5
|
+
let(:runner) { Runner.new }
|
6
|
+
|
7
|
+
before {
|
8
|
+
EM.stub!(:run).and_yield
|
9
|
+
runner.stub!(:at_exit)
|
10
|
+
runner.stub!(:trap)
|
11
|
+
}
|
12
|
+
|
13
|
+
it "runs and watches the server" do
|
14
|
+
browser = mock(Browser).as_null_object
|
15
|
+
runner.stub!(:browser).and_return(browser)
|
16
|
+
|
17
|
+
server = mock(Server, :host => "localhost", :port => 4224)
|
18
|
+
Server.should_receive(:new).with(4224).and_return(server)
|
19
|
+
server.should_receive(:start)
|
20
|
+
server.should_receive(:monitor).with(10)
|
21
|
+
|
22
|
+
runner.run
|
23
|
+
end
|
24
|
+
|
25
|
+
it "runs, captures and watches the browser" do
|
26
|
+
server = mock(Server, :host => "localhost", :port => 1234).as_null_object
|
27
|
+
runner.stub!(:server).and_return(server)
|
28
|
+
|
29
|
+
browser = mock(Browser)
|
30
|
+
Browser.should_receive(:new).with(:firefox).and_return(browser)
|
31
|
+
browser.should_receive(:start)
|
32
|
+
browser.should_receive(:capture).with("localhost", 1234)
|
33
|
+
browser.should_receive(:monitor).with(10)
|
34
|
+
|
35
|
+
runner.run
|
36
|
+
end
|
37
|
+
|
38
|
+
# TODO: more specs here
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
module JstdRunner
|
4
|
+
describe Server do
|
5
|
+
|
6
|
+
let(:server) { Server.new(4224) }
|
7
|
+
let(:mock_process) { mock(ChildProcess, :start => true) }
|
8
|
+
let(:connected_poller) { mock(:connected? => true, :closed? => false) }
|
9
|
+
let(:closed_poller) { mock(:connected? => false, :closed? => true) }
|
10
|
+
|
11
|
+
it "launches the server on the given port" do
|
12
|
+
server.stub!(:immediate_poller => closed_poller)
|
13
|
+
|
14
|
+
ChildProcess.should_receive(:new).with(
|
15
|
+
"java", "-jar", /JsTestDriver.+\.jar/, "--port", "4224"
|
16
|
+
).and_return(mock_process)
|
17
|
+
|
18
|
+
server.stub!(:long_poller).and_return(connected_poller)
|
19
|
+
|
20
|
+
server.start
|
21
|
+
end
|
22
|
+
|
23
|
+
it "raises a StartupError if the server is already running" do
|
24
|
+
server.stub!(:immediate_poller => connected_poller)
|
25
|
+
server.stub!(:process => mock_process)
|
26
|
+
|
27
|
+
lambda { server.start }.should raise_error(Server::StartupError)
|
28
|
+
end
|
29
|
+
|
30
|
+
it "raises a StartupError if the server doesn't start" do
|
31
|
+
server.stub!(:immediate_poller => closed_poller)
|
32
|
+
server.stub!(:long_poller => closed_poller)
|
33
|
+
server.stub!(:process => mock_process)
|
34
|
+
|
35
|
+
# in case it's alive but not launched properly
|
36
|
+
mock_process.should_receive(:stop)
|
37
|
+
|
38
|
+
lambda { server.start }.should raise_error(Server::StartupError)
|
39
|
+
end
|
40
|
+
|
41
|
+
it "restarts the server" do
|
42
|
+
server.should_receive(:stop).once
|
43
|
+
server.should_receive(:start).once
|
44
|
+
|
45
|
+
server.restart
|
46
|
+
end
|
47
|
+
|
48
|
+
it "restarts the server even if stop fails" do
|
49
|
+
server.should_receive(:stop).and_raise("argh")
|
50
|
+
server.should_receive(:start).once
|
51
|
+
|
52
|
+
server.restart
|
53
|
+
end
|
54
|
+
|
55
|
+
it "stops the server" do
|
56
|
+
server.stub!(:process => mock_process)
|
57
|
+
server.stub!(:long_poller => mock(:closed? => true))
|
58
|
+
|
59
|
+
mock_process.should_receive(:stop)
|
60
|
+
|
61
|
+
server.stop
|
62
|
+
end
|
63
|
+
|
64
|
+
it "raises a StopError if the server could not be stopped" do
|
65
|
+
server.stub!(:process => mock_process)
|
66
|
+
server.stub!(:long_poller => connected_poller)
|
67
|
+
|
68
|
+
mock_process.should_receive(:stop)
|
69
|
+
|
70
|
+
lambda { server.stop }.should raise_error(Server::StopError)
|
71
|
+
end
|
72
|
+
|
73
|
+
it "knows if the server is alive" do
|
74
|
+
server.stub!(:process => mock(:alive? => true))
|
75
|
+
server.stub!(:immediate_poller => connected_poller)
|
76
|
+
|
77
|
+
server.should be_running
|
78
|
+
end
|
79
|
+
|
80
|
+
it "considers the server dead if it does not respond to connections" do
|
81
|
+
server.stub!(:process => mock(:alive? => true))
|
82
|
+
server.stub!(:immediate_poller => closed_poller)
|
83
|
+
|
84
|
+
server.should_not be_running
|
85
|
+
end
|
86
|
+
|
87
|
+
it "considers the server dead if the process died" do
|
88
|
+
server.stub!(:process => mock(:alive? => false))
|
89
|
+
|
90
|
+
server.should_not be_running
|
91
|
+
end
|
92
|
+
|
93
|
+
end
|
94
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,162 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: jstd-runner
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 0
|
8
|
+
- 2
|
9
|
+
version: 0.0.2
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Jari Bakken
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2010-11-26 00:00:00 +01:00
|
18
|
+
default_executable:
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: selenium-webdriver
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
none: false
|
25
|
+
requirements:
|
26
|
+
- - "="
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
segments:
|
29
|
+
- 0
|
30
|
+
- 1
|
31
|
+
- 0
|
32
|
+
version: 0.1.0
|
33
|
+
type: :runtime
|
34
|
+
version_requirements: *id001
|
35
|
+
- !ruby/object:Gem::Dependency
|
36
|
+
name: eventmachine
|
37
|
+
prerelease: false
|
38
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - "="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
segments:
|
44
|
+
- 0
|
45
|
+
- 12
|
46
|
+
- 10
|
47
|
+
version: 0.12.10
|
48
|
+
type: :runtime
|
49
|
+
version_requirements: *id002
|
50
|
+
- !ruby/object:Gem::Dependency
|
51
|
+
name: mail
|
52
|
+
prerelease: false
|
53
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
54
|
+
none: false
|
55
|
+
requirements:
|
56
|
+
- - "="
|
57
|
+
- !ruby/object:Gem::Version
|
58
|
+
segments:
|
59
|
+
- 2
|
60
|
+
- 2
|
61
|
+
- 10
|
62
|
+
version: 2.2.10
|
63
|
+
type: :runtime
|
64
|
+
version_requirements: *id003
|
65
|
+
- !ruby/object:Gem::Dependency
|
66
|
+
name: daemons
|
67
|
+
prerelease: false
|
68
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
69
|
+
none: false
|
70
|
+
requirements:
|
71
|
+
- - "="
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
segments:
|
74
|
+
- 1
|
75
|
+
- 1
|
76
|
+
- 0
|
77
|
+
version: 1.1.0
|
78
|
+
type: :runtime
|
79
|
+
version_requirements: *id004
|
80
|
+
- !ruby/object:Gem::Dependency
|
81
|
+
name: rspec
|
82
|
+
prerelease: false
|
83
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
84
|
+
none: false
|
85
|
+
requirements:
|
86
|
+
- - ">="
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
segments:
|
89
|
+
- 2
|
90
|
+
- 0
|
91
|
+
- 0
|
92
|
+
version: 2.0.0
|
93
|
+
type: :development
|
94
|
+
version_requirements: *id005
|
95
|
+
description: Runs a JsTestDriver server + browsers with some built-in monitoring
|
96
|
+
email:
|
97
|
+
- jari.bakken@gmail.com
|
98
|
+
executables:
|
99
|
+
- jstd-runner
|
100
|
+
extensions: []
|
101
|
+
|
102
|
+
extra_rdoc_files: []
|
103
|
+
|
104
|
+
files:
|
105
|
+
- .gitignore
|
106
|
+
- Gemfile
|
107
|
+
- LICENSE
|
108
|
+
- README.rdoc
|
109
|
+
- Rakefile
|
110
|
+
- autotest/discover.rb
|
111
|
+
- bin/jstd-runner
|
112
|
+
- jstd-runner.gemspec
|
113
|
+
- lib/jstd-runner.rb
|
114
|
+
- lib/jstd-runner/JsTestDriver-1.2.2.jar
|
115
|
+
- lib/jstd-runner/browser.rb
|
116
|
+
- lib/jstd-runner/cli.rb
|
117
|
+
- lib/jstd-runner/monitorable.rb
|
118
|
+
- lib/jstd-runner/runner.rb
|
119
|
+
- lib/jstd-runner/server.rb
|
120
|
+
- lib/jstd-runner/version.rb
|
121
|
+
- lib/jstd-runner/vnc_control.rb
|
122
|
+
- spec/jstd-runner/browser_spec.rb
|
123
|
+
- spec/jstd-runner/cli_spec.rb
|
124
|
+
- spec/jstd-runner/monitorable_spec.rb
|
125
|
+
- spec/jstd-runner/runner_spec.rb
|
126
|
+
- spec/jstd-runner/server_spec.rb
|
127
|
+
- spec/jstd-runner/vnc_control_spec.rb
|
128
|
+
- spec/spec_helper.rb
|
129
|
+
has_rdoc: true
|
130
|
+
homepage: http://github.com/jarib/jstd-runner
|
131
|
+
licenses: []
|
132
|
+
|
133
|
+
post_install_message:
|
134
|
+
rdoc_options: []
|
135
|
+
|
136
|
+
require_paths:
|
137
|
+
- lib
|
138
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
139
|
+
none: false
|
140
|
+
requirements:
|
141
|
+
- - ">="
|
142
|
+
- !ruby/object:Gem::Version
|
143
|
+
segments:
|
144
|
+
- 0
|
145
|
+
version: "0"
|
146
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
147
|
+
none: false
|
148
|
+
requirements:
|
149
|
+
- - ">="
|
150
|
+
- !ruby/object:Gem::Version
|
151
|
+
segments:
|
152
|
+
- 0
|
153
|
+
version: "0"
|
154
|
+
requirements: []
|
155
|
+
|
156
|
+
rubyforge_project:
|
157
|
+
rubygems_version: 1.3.7
|
158
|
+
signing_key:
|
159
|
+
specification_version: 3
|
160
|
+
summary: JsTestDriver wrapper
|
161
|
+
test_files: []
|
162
|
+
|