brynary-testjour 0.1.0
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/History.txt +6 -0
- data/MIT-LICENSE.txt +19 -0
- data/README.rdoc +47 -0
- data/Rakefile +39 -0
- data/bin/testjour +8 -0
- data/lib/testjour/bonjour.rb +56 -0
- data/lib/testjour/cli.rb +78 -0
- data/lib/testjour/colorer.rb +8 -0
- data/lib/testjour/commands/base_command.rb +53 -0
- data/lib/testjour/commands/help.rb +20 -0
- data/lib/testjour/commands/list.rb +57 -0
- data/lib/testjour/commands/local_run.rb +83 -0
- data/lib/testjour/commands/run.rb +165 -0
- data/lib/testjour/commands/slave_run.rb +88 -0
- data/lib/testjour/commands/slave_start.rb +65 -0
- data/lib/testjour/commands/slave_stop.rb +25 -0
- data/lib/testjour/commands/slave_warm.rb +31 -0
- data/lib/testjour/commands/version.rb +18 -0
- data/lib/testjour/commands/warm.rb +73 -0
- data/lib/testjour/commands.rb +10 -0
- data/lib/testjour/cucumber_extensions/drb_formatter.rb +30 -0
- data/lib/testjour/cucumber_extensions/queueing_executor.rb +120 -0
- data/lib/testjour/mysql.rb +82 -0
- data/lib/testjour/pid_file.rb +43 -0
- data/lib/testjour/progressbar.rb +124 -0
- data/lib/testjour/queue_server.rb +66 -0
- data/lib/testjour/rsync.rb +29 -0
- data/lib/testjour/slave_server.rb +98 -0
- data/lib/testjour.rb +68 -0
- data/vendor/authprogs +231 -0
- metadata +102 -0
data/History.txt
ADDED
data/MIT-LICENSE.txt
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
Copyright (c) 2008 Bryan Helmkamp
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
of this software and associated documentation files (the "Software"), to deal
|
5
|
+
in the Software without restriction, including without limitation the rights
|
6
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
+
copies of the Software, and to permit persons to whom the Software is
|
8
|
+
furnished to do so, subject to the following conditions:
|
9
|
+
|
10
|
+
The above copyright notice and this permission notice shall be included in
|
11
|
+
all copies or substantial portions of the Software.
|
12
|
+
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
|
+
THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
=== Testjour
|
2
|
+
|
3
|
+
* http://github.com/brynary/testjour
|
4
|
+
|
5
|
+
=== Description
|
6
|
+
|
7
|
+
Distributed test running with autodiscovery via Bonjour (for Cucumber first)
|
8
|
+
|
9
|
+
=== Synopsis
|
10
|
+
|
11
|
+
On machines to be used as Testjour slaves:
|
12
|
+
|
13
|
+
$ mkdir testjour-working-dir
|
14
|
+
$ testjour slave:start
|
15
|
+
|
16
|
+
|
17
|
+
On your development machine, verify it can see the testjour slave:
|
18
|
+
|
19
|
+
$ testjour list
|
20
|
+
|
21
|
+
Testjour servers:
|
22
|
+
|
23
|
+
bhelmkamp available bryans-computer.local.:62434
|
24
|
+
|
25
|
+
Now run your tests:
|
26
|
+
|
27
|
+
$ testjour run features
|
28
|
+
|
29
|
+
Note: This only really makes sense if you use more than one slave. Otherwise
|
30
|
+
it's slower than just running them locally.
|
31
|
+
|
32
|
+
=== Install
|
33
|
+
|
34
|
+
To install the latest release (once there is a release):
|
35
|
+
|
36
|
+
$ sudo gem install testjour
|
37
|
+
|
38
|
+
For now, just pull down the code from the GitHub repo:
|
39
|
+
|
40
|
+
$ git clone git://github.com/brynary/testjour.git
|
41
|
+
$ cd testjour
|
42
|
+
$ rake gem
|
43
|
+
$ rake install_gem
|
44
|
+
|
45
|
+
=== Authors
|
46
|
+
|
47
|
+
- Maintained by Bryan Helmkamp (http://brynary.com/)
|
data/Rakefile
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require "rake/gempackagetask"
|
3
|
+
require "rake/clean"
|
4
|
+
require './lib/testjour.rb'
|
5
|
+
|
6
|
+
spec = Gem::Specification.new do |s|
|
7
|
+
s.name = "testjour"
|
8
|
+
s.version = Testjour::VERSION
|
9
|
+
s.author = "Bryan Helmkamp"
|
10
|
+
s.email = "bryan" + "@" + "brynary.com"
|
11
|
+
s.homepage = "http://github.com/brynary/testjour"
|
12
|
+
s.summary = "Distributed test running with autodiscovery via Bonjour (for Cucumber first)"
|
13
|
+
s.description = s.summary
|
14
|
+
s.executables = "testjour"
|
15
|
+
s.files = %w[History.txt MIT-LICENSE.txt README.rdoc Rakefile] + Dir["bin/*"] + Dir["lib/**/*"] + Dir["vendor/**/*"]
|
16
|
+
|
17
|
+
s.add_dependency "systemu", ">=1.2.0"
|
18
|
+
s.add_dependency "dnssd", ">=0.6.0"
|
19
|
+
end
|
20
|
+
|
21
|
+
Rake::GemPackageTask.new(spec) do |package|
|
22
|
+
package.gem_spec = spec
|
23
|
+
end
|
24
|
+
|
25
|
+
desc 'Show information about the gem.'
|
26
|
+
task :write_gemspec do
|
27
|
+
File.open("testjour.gemspec", 'w') do |f|
|
28
|
+
f.write spec.to_ruby
|
29
|
+
end
|
30
|
+
puts "Generated: testjour.gemspec"
|
31
|
+
end
|
32
|
+
|
33
|
+
CLEAN.include ["pkg", "*.gem", "doc", "ri", "coverage"]
|
34
|
+
|
35
|
+
desc 'Install the package as a gem.'
|
36
|
+
task :install_gem => [:clean, :package] do
|
37
|
+
gem = Dir['pkg/*.gem'].first
|
38
|
+
sh "sudo gem install --local #{gem}"
|
39
|
+
end
|
data/bin/testjour
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
require "dnssd"
|
2
|
+
require "set"
|
3
|
+
|
4
|
+
Thread.abort_on_exception = true
|
5
|
+
|
6
|
+
module Testjour
|
7
|
+
SERVICE = "_testjour._tcp"
|
8
|
+
|
9
|
+
class Bonjour
|
10
|
+
|
11
|
+
class Server
|
12
|
+
attr_reader :name, :host, :port
|
13
|
+
|
14
|
+
def initialize(name, host, port)
|
15
|
+
@name = name
|
16
|
+
@host = host
|
17
|
+
@port = port
|
18
|
+
end
|
19
|
+
|
20
|
+
def ==(other)
|
21
|
+
other.class == self.class && other.uri == self.uri
|
22
|
+
end
|
23
|
+
|
24
|
+
def uri
|
25
|
+
"druby://" + @host.gsub(/\.$/, "") + ":" + @port.to_s
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.list
|
30
|
+
hosts = []
|
31
|
+
|
32
|
+
service = DNSSD.browse(SERVICE) do |reply|
|
33
|
+
DNSSD.resolve(reply.name, reply.type, reply.domain) do |rr|
|
34
|
+
server = Server.new(reply.name, rr.target, rr.port)
|
35
|
+
hosts << server unless hosts.any? { |h| h == server }
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
sleep 3
|
40
|
+
service.stop
|
41
|
+
return hosts
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.serve(port)
|
45
|
+
name = ENV['USER']
|
46
|
+
|
47
|
+
tr = DNSSD::TextRecord.new
|
48
|
+
tr['description'] = "#{name}'s testjour server"
|
49
|
+
|
50
|
+
DNSSD.register(name, SERVICE, "local", port, tr.encode) do |reply|
|
51
|
+
Testjour.logger.info "Broadcasting: Ready to run tests under name '#{name}' on port #{port}..."
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
data/lib/testjour/cli.rb
ADDED
@@ -0,0 +1,78 @@
|
|
1
|
+
module Testjour
|
2
|
+
module CLI
|
3
|
+
|
4
|
+
class NoCommandGiven < StandardError
|
5
|
+
def message
|
6
|
+
"No command given"
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
class UnknownCommand < StandardError
|
11
|
+
def initialize(command_name)
|
12
|
+
@command_name = command_name
|
13
|
+
end
|
14
|
+
|
15
|
+
def message
|
16
|
+
"Unknown command: #{@command_name.inspect}"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.execute
|
21
|
+
Parser.new.execute
|
22
|
+
end
|
23
|
+
|
24
|
+
class Parser
|
25
|
+
class << self
|
26
|
+
attr_accessor :commands
|
27
|
+
|
28
|
+
def register_command(klass)
|
29
|
+
@commands << klass
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
self.commands = []
|
34
|
+
|
35
|
+
def execute
|
36
|
+
begin
|
37
|
+
raise NoCommandGiven if ARGV.empty?
|
38
|
+
raise UnknownCommand.new(command_name) unless command_klass
|
39
|
+
|
40
|
+
args = ARGV.dup
|
41
|
+
args.shift # Remove subcommand name
|
42
|
+
|
43
|
+
command_klass.new(self, args).run
|
44
|
+
rescue NoCommandGiven, UnknownCommand
|
45
|
+
$stderr.puts "ERROR: #{$!.message}"
|
46
|
+
$stderr.puts usage
|
47
|
+
exit 1
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def command_klass
|
52
|
+
self.class.commands.detect do |command_klass|
|
53
|
+
command_klass.command == command_name
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def command_name
|
58
|
+
ARGV.first
|
59
|
+
end
|
60
|
+
|
61
|
+
def usage
|
62
|
+
message = []
|
63
|
+
message << "usage: testjour <SUBCOMMAND> [OPTIONS] [ARGS...]"
|
64
|
+
message << "Type 'testjour help <SUBCOMMAND>' for help on a specific subcommand."
|
65
|
+
message << "Type 'testjour version' to get this program's version."
|
66
|
+
message << ""
|
67
|
+
message << "Available subcommands are:"
|
68
|
+
|
69
|
+
self.class.commands.sort_by { |c| c.command }.each do |command_klass|
|
70
|
+
message << " " + command_klass.command
|
71
|
+
end
|
72
|
+
|
73
|
+
message.map { |line| line.chomp }.join("\n")
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require "optparse"
|
2
|
+
|
3
|
+
module Testjour
|
4
|
+
module CLI
|
5
|
+
|
6
|
+
class BaseCommand
|
7
|
+
attr_reader :non_options, :options
|
8
|
+
|
9
|
+
def self.command
|
10
|
+
self.name.downcase
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.options
|
14
|
+
{}
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.help
|
18
|
+
nil
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.detailed_help
|
22
|
+
nil
|
23
|
+
end
|
24
|
+
|
25
|
+
# def self.usage
|
26
|
+
# message = []
|
27
|
+
#
|
28
|
+
# if help.nil?
|
29
|
+
# message << command
|
30
|
+
# else
|
31
|
+
# message << "#{command}: #{help}"
|
32
|
+
# end
|
33
|
+
# message << detailed_help unless detailed_help.nil?
|
34
|
+
# message << ""
|
35
|
+
# message << "Valid options:"
|
36
|
+
# message
|
37
|
+
# @option_parser.summarize(message)
|
38
|
+
# end
|
39
|
+
|
40
|
+
def initialize(parser, args)
|
41
|
+
@parser = parser
|
42
|
+
@options = {}
|
43
|
+
@non_options = option_parser.parse(args)
|
44
|
+
end
|
45
|
+
|
46
|
+
def option_parser
|
47
|
+
OptionParser.new
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require "testjour/commands/base_command"
|
2
|
+
|
3
|
+
module Testjour
|
4
|
+
module CLI
|
5
|
+
|
6
|
+
class HelpCommand < BaseCommand
|
7
|
+
def self.command
|
8
|
+
"help"
|
9
|
+
end
|
10
|
+
|
11
|
+
def run
|
12
|
+
puts @parser.usage
|
13
|
+
exit 1
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
Parser.register_command HelpCommand
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require "drb"
|
2
|
+
require "testjour/commands/base_command"
|
3
|
+
require "testjour/bonjour"
|
4
|
+
|
5
|
+
module Testjour
|
6
|
+
module CLI
|
7
|
+
|
8
|
+
class List < BaseCommand
|
9
|
+
def self.command
|
10
|
+
"list"
|
11
|
+
end
|
12
|
+
|
13
|
+
def initialize(*args)
|
14
|
+
super
|
15
|
+
Testjour.load_cucumber
|
16
|
+
require "testjour/colorer"
|
17
|
+
rescue LoadError
|
18
|
+
# No cucumber, we can't use color :(
|
19
|
+
end
|
20
|
+
|
21
|
+
def run
|
22
|
+
available_servers = Testjour::Bonjour.list
|
23
|
+
|
24
|
+
if available_servers.any?
|
25
|
+
puts
|
26
|
+
puts "Testjour servers:"
|
27
|
+
puts
|
28
|
+
|
29
|
+
available_servers.each do |server|
|
30
|
+
slave_server = DRbObject.new(nil, server.uri)
|
31
|
+
status = colorize_status(slave_server.status)
|
32
|
+
puts " %-12s %s %s" % [server.name, status, "#{server.host}:#{server.port}"]
|
33
|
+
end
|
34
|
+
else
|
35
|
+
puts
|
36
|
+
puts "No testjour servers found."
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def colorize_status(status)
|
41
|
+
formatted_status = ("%-12s" % status)
|
42
|
+
return formatted_status unless defined?(Testjour::Colorer)
|
43
|
+
|
44
|
+
case formatted_status.strip
|
45
|
+
when "available"
|
46
|
+
Testjour::Colorer.green(formatted_status)
|
47
|
+
else
|
48
|
+
Testjour::Colorer.yellow(formatted_status)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
|
54
|
+
Parser.register_command List
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
@@ -0,0 +1,83 @@
|
|
1
|
+
require "drb"
|
2
|
+
require "uri"
|
3
|
+
|
4
|
+
require "testjour/commands/base_command"
|
5
|
+
require "testjour/queue_server"
|
6
|
+
require "testjour/cucumber_extensions/drb_formatter"
|
7
|
+
require "testjour/mysql"
|
8
|
+
|
9
|
+
module Testjour
|
10
|
+
module CLI
|
11
|
+
|
12
|
+
class LocalRun < BaseCommand
|
13
|
+
def self.command
|
14
|
+
"local:run"
|
15
|
+
end
|
16
|
+
|
17
|
+
def initialize(parser, args)
|
18
|
+
Testjour.logger.debug "Runner command #{self.class}..."
|
19
|
+
super
|
20
|
+
@queue = @non_options.shift
|
21
|
+
end
|
22
|
+
|
23
|
+
def run
|
24
|
+
ARGV.clear # Don't pass along args to RSpec
|
25
|
+
Testjour.load_cucumber
|
26
|
+
|
27
|
+
ENV["RAILS_ENV"] = "test"
|
28
|
+
require File.expand_path("config/environment")
|
29
|
+
|
30
|
+
Testjour::MysqlDatabaseSetup.with_new_database do
|
31
|
+
Cucumber::CLI.executor.formatters = Testjour::DRbFormatter.new(queue_server)
|
32
|
+
require_files
|
33
|
+
|
34
|
+
begin
|
35
|
+
loop do
|
36
|
+
begin
|
37
|
+
run_file(queue_server.take_work)
|
38
|
+
rescue Testjour::QueueServer::NoWorkUnitsAvailableError
|
39
|
+
# If no work, ignore and keep looping
|
40
|
+
end
|
41
|
+
end
|
42
|
+
rescue DRb::DRbConnError
|
43
|
+
Testjour.logger.debug "DRb connection error. (This is normal.) Exiting runner."
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def require_files
|
49
|
+
cli = Cucumber::CLI.new
|
50
|
+
cli.parse_options!(@non_options)
|
51
|
+
cli.send(:require_files)
|
52
|
+
end
|
53
|
+
|
54
|
+
def run_file(file)
|
55
|
+
Testjour.logger.debug "Running feature file: #{file}"
|
56
|
+
features = feature_parser.parse_feature(File.expand_path(file))
|
57
|
+
Cucumber::CLI.executor.visit_features(features)
|
58
|
+
end
|
59
|
+
|
60
|
+
def queue_server
|
61
|
+
@queue_server ||= begin
|
62
|
+
DRb.start_service
|
63
|
+
DRbObject.new(nil, drb_uri)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def drb_uri
|
68
|
+
uri = URI.parse(@queue)
|
69
|
+
uri.scheme = "druby"
|
70
|
+
uri.path = ""
|
71
|
+
uri.user = nil
|
72
|
+
uri.to_s
|
73
|
+
end
|
74
|
+
|
75
|
+
def feature_parser
|
76
|
+
@feature_parser ||= Cucumber::TreetopParser::FeatureParser.new
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
80
|
+
|
81
|
+
Parser.register_command LocalRun
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,165 @@
|
|
1
|
+
require "drb"
|
2
|
+
|
3
|
+
require "testjour/commands/base_command"
|
4
|
+
require "testjour/queue_server"
|
5
|
+
require "testjour/bonjour"
|
6
|
+
|
7
|
+
module Testjour
|
8
|
+
module CLI
|
9
|
+
|
10
|
+
class Run < BaseCommand
|
11
|
+
def self.command
|
12
|
+
"run"
|
13
|
+
end
|
14
|
+
|
15
|
+
def initialize(*args)
|
16
|
+
Testjour.logger.debug "Runner command #{self.class}..."
|
17
|
+
Testjour.load_cucumber
|
18
|
+
|
19
|
+
super
|
20
|
+
@found_server = 0
|
21
|
+
require "testjour/cucumber_extensions/queueing_executor"
|
22
|
+
require "testjour/colorer"
|
23
|
+
end
|
24
|
+
|
25
|
+
def run
|
26
|
+
Testjour::QueueServer.with_server do |queue|
|
27
|
+
start_local_runners unless servers_specified?
|
28
|
+
start_slave_runners unless no_remote?
|
29
|
+
|
30
|
+
if @found_server.zero?
|
31
|
+
puts "No processes to build on. Aborting."
|
32
|
+
exit
|
33
|
+
end
|
34
|
+
|
35
|
+
queue_features(queue)
|
36
|
+
print_results
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def disable_cucumber_require
|
41
|
+
Cucumber::CLI.class_eval do
|
42
|
+
def require_files
|
43
|
+
ARGV.clear # Shut up RSpec
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def queue_features(queue)
|
49
|
+
Testjour.logger.debug "Queueing features..."
|
50
|
+
disable_cucumber_require
|
51
|
+
ARGV.replace(@non_options.clone)
|
52
|
+
Cucumber::CLI.executor = Testjour::QueueingExecutor.new(queue, Cucumber::CLI.step_mother)
|
53
|
+
Cucumber::CLI.execute
|
54
|
+
end
|
55
|
+
|
56
|
+
def print_results
|
57
|
+
puts
|
58
|
+
puts "Requesting build from #{@found_server} processes..."
|
59
|
+
puts
|
60
|
+
|
61
|
+
Cucumber::CLI.executor.wait_for_results
|
62
|
+
Testjour.logger.debug "DONE"
|
63
|
+
end
|
64
|
+
|
65
|
+
def slave_servers_to_use
|
66
|
+
# require "rubygems"; require "ruby-debug"; Debugger.start; debugger
|
67
|
+
@slave_servers_to_use ||= available_servers.select do |potential_server|
|
68
|
+
!servers_specified? || specified_servers_include?(potential_server)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def available_servers
|
73
|
+
@available_servers ||= Testjour::Bonjour.list
|
74
|
+
end
|
75
|
+
|
76
|
+
def request_build_from(server)
|
77
|
+
slave_server = DRbObject.new(nil, server.uri)
|
78
|
+
result = slave_server.run(testjour_uri, @non_options)
|
79
|
+
|
80
|
+
if result
|
81
|
+
Testjour.logger.info "Requesting buld from available server: #{server.uri}. Accepted."
|
82
|
+
@found_server += 1
|
83
|
+
else
|
84
|
+
Testjour.logger.info "Requesting buld from available server: #{server.uri}. Rejected."
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def start_local_runners
|
89
|
+
2.times do
|
90
|
+
start_local_runner
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def start_slave_runners
|
95
|
+
slave_servers_to_use.each do |server|
|
96
|
+
request_build_from(server)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def start_local_runner
|
101
|
+
pid_queue = Queue.new
|
102
|
+
|
103
|
+
Thread.new do
|
104
|
+
Thread.current.abort_on_exception = true
|
105
|
+
cmd = command_for_local_run
|
106
|
+
Testjour.logger.debug "Starting local:run with command: #{cmd}"
|
107
|
+
status, stdout, stderr = systemu(cmd) { |pid| pid_queue << pid }
|
108
|
+
Testjour.logger.warn stderr if stderr.strip.size > 0
|
109
|
+
end
|
110
|
+
|
111
|
+
pid = pid_queue.pop
|
112
|
+
|
113
|
+
@found_server += 1
|
114
|
+
Testjour.logger.info "Started local:run on PID #{pid}"
|
115
|
+
|
116
|
+
pid
|
117
|
+
end
|
118
|
+
|
119
|
+
def command_for_local_run
|
120
|
+
"#{testjour_bin_path} local:run #{testjour_uri} -- #{@non_options.join(' ')}".strip
|
121
|
+
end
|
122
|
+
|
123
|
+
def testjour_bin_path
|
124
|
+
File.expand_path(File.dirname(__FILE__) + "/../../../bin/testjour")
|
125
|
+
end
|
126
|
+
|
127
|
+
def testjour_uri
|
128
|
+
uri = URI.parse(DRb.uri)
|
129
|
+
uri.path = File.expand_path(".")
|
130
|
+
uri.scheme = "testjour"
|
131
|
+
uri.user = `whoami`.strip
|
132
|
+
uri.to_s
|
133
|
+
end
|
134
|
+
|
135
|
+
def specified_servers_include?(potential_server)
|
136
|
+
@options[:server].any? do |specified_server|
|
137
|
+
potential_server.host.include?(specified_server)
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
def no_remote?
|
142
|
+
@options[:no_remote]
|
143
|
+
end
|
144
|
+
|
145
|
+
def servers_specified?
|
146
|
+
@options[:server] && @options[:server].any?
|
147
|
+
end
|
148
|
+
|
149
|
+
def option_parser
|
150
|
+
OptionParser.new do |opts|
|
151
|
+
opts.on("--on SERVER", "Specify a pattern to exclude servers to. Disabled local runners") do |server|
|
152
|
+
@options[:server] ||= []
|
153
|
+
@options[:server] << server
|
154
|
+
end
|
155
|
+
|
156
|
+
opts.on("--no-remote", "Only use local runners") do |server|
|
157
|
+
@options[:no_remote] = true
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
Parser.register_command Run
|
164
|
+
end
|
165
|
+
end
|