jstd-runner 0.0.2
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.
- 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
|
+
|