brynary-testjour 0.1.0 → 0.2.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/README.rdoc +2 -1
- data/lib/testjour/bonjour.rb +44 -7
- data/lib/testjour/cli.rb +23 -18
- data/lib/testjour/commands/base_command.rb +4 -0
- data/lib/testjour/commands/help.rb +0 -1
- data/lib/testjour/commands/list.rb +5 -20
- data/lib/testjour/commands/local_run.rb +19 -16
- data/lib/testjour/commands/run.rb +7 -23
- data/lib/testjour/commands/slave_run.rb +4 -73
- data/lib/testjour/commands/slave_start.rb +11 -8
- data/lib/testjour/commands/slave_stop.rb +1 -3
- data/lib/testjour/commands/slave_warm.rb +1 -4
- data/lib/testjour/commands/version.rb +0 -1
- data/lib/testjour/commands/warm.rb +4 -7
- data/lib/testjour/cucumber_extensions/queueing_executor.rb +77 -59
- data/lib/testjour/mysql.rb +12 -1
- data/lib/testjour/pid_file.rb +4 -0
- data/lib/testjour/rsync.rb +38 -14
- data/lib/testjour/run_command.rb +21 -0
- data/lib/testjour/slave_server.rb +7 -33
- data/lib/testjour.rb +1 -1
- metadata +3 -2
data/README.rdoc
CHANGED
@@ -44,4 +44,5 @@ For now, just pull down the code from the GitHub repo:
|
|
44
44
|
|
45
45
|
=== Authors
|
46
46
|
|
47
|
-
- Maintained by Bryan Helmkamp (http://brynary.com/)
|
47
|
+
- Maintained by Bryan Helmkamp (http://brynary.com/)
|
48
|
+
- Thanks to Weplay (http://weplay.com) for sponsoring development and supporting open sourcing it from the start
|
data/lib/testjour/bonjour.rb
CHANGED
@@ -6,11 +6,15 @@ Thread.abort_on_exception = true
|
|
6
6
|
module Testjour
|
7
7
|
SERVICE = "_testjour._tcp"
|
8
8
|
|
9
|
-
|
9
|
+
module Bonjour
|
10
10
|
|
11
11
|
class Server
|
12
12
|
attr_reader :name, :host, :port
|
13
13
|
|
14
|
+
def self.from_dnssd(reply, rr)
|
15
|
+
new(reply.name, rr.target, rr.port)
|
16
|
+
end
|
17
|
+
|
14
18
|
def initialize(name, host, port)
|
15
19
|
@name = name
|
16
20
|
@host = host
|
@@ -24,24 +28,57 @@ module Testjour
|
|
24
28
|
def uri
|
25
29
|
"druby://" + @host.gsub(/\.$/, "") + ":" + @port.to_s
|
26
30
|
end
|
31
|
+
|
32
|
+
def status_line
|
33
|
+
" %-12s %s %s" % [name, colored_status, "#{host}:#{port}"]
|
34
|
+
end
|
35
|
+
|
36
|
+
protected
|
37
|
+
|
38
|
+
def colored_status
|
39
|
+
formatted_status = ("%-12s" % status)
|
40
|
+
return formatted_status unless defined?(Testjour::Colorer)
|
41
|
+
|
42
|
+
case formatted_status.strip
|
43
|
+
when "available"
|
44
|
+
Testjour::Colorer.green(formatted_status)
|
45
|
+
else
|
46
|
+
Testjour::Colorer.yellow(formatted_status)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def status
|
51
|
+
drb_object.status
|
52
|
+
end
|
53
|
+
|
54
|
+
def drb_object
|
55
|
+
@drb_object ||= DRbObject.new(nil, uri)
|
56
|
+
end
|
27
57
|
end
|
28
58
|
|
29
|
-
def
|
30
|
-
|
59
|
+
def bonjour_servers
|
60
|
+
return @bonjour_servers if !@bonjour_servers.nil?
|
61
|
+
|
62
|
+
@bonjour_servers = []
|
31
63
|
|
32
64
|
service = DNSSD.browse(SERVICE) do |reply|
|
33
65
|
DNSSD.resolve(reply.name, reply.type, reply.domain) do |rr|
|
34
|
-
|
35
|
-
hosts << server unless hosts.any? { |h| h == server }
|
66
|
+
found_bonjour_server(Server.from_dnssd(reply, rr))
|
36
67
|
end
|
37
68
|
end
|
38
69
|
|
39
70
|
sleep 3
|
40
71
|
service.stop
|
41
|
-
return
|
72
|
+
return @bonjour_servers
|
73
|
+
end
|
74
|
+
|
75
|
+
def found_bonjour_server(server)
|
76
|
+
unless @bonjour_servers.any? { |h| h == server }
|
77
|
+
@bonjour_servers << server
|
78
|
+
end
|
42
79
|
end
|
43
80
|
|
44
|
-
def
|
81
|
+
def bonjour_serve(port)
|
45
82
|
name = ENV['USER']
|
46
83
|
|
47
84
|
tr = DNSSD::TextRecord.new
|
data/lib/testjour/cli.rb
CHANGED
@@ -33,19 +33,15 @@ module Testjour
|
|
33
33
|
self.commands = []
|
34
34
|
|
35
35
|
def execute
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
$stderr.puts "ERROR: #{$!.message}"
|
46
|
-
$stderr.puts usage
|
47
|
-
exit 1
|
48
|
-
end
|
36
|
+
raise NoCommandGiven if ARGV.empty?
|
37
|
+
raise UnknownCommand.new(command_name) unless command_klass
|
38
|
+
|
39
|
+
args = ARGV.dup
|
40
|
+
args.shift # Remove subcommand name
|
41
|
+
|
42
|
+
command_klass.new(self, args).run
|
43
|
+
rescue NoCommandGiven, UnknownCommand
|
44
|
+
exit_with_usage
|
49
45
|
end
|
50
46
|
|
51
47
|
def command_klass
|
@@ -58,6 +54,12 @@ module Testjour
|
|
58
54
|
ARGV.first
|
59
55
|
end
|
60
56
|
|
57
|
+
def exit_with_usage
|
58
|
+
$stderr.puts "ERROR: #{$!.message}"
|
59
|
+
$stderr.puts usage
|
60
|
+
exit 1
|
61
|
+
end
|
62
|
+
|
61
63
|
def usage
|
62
64
|
message = []
|
63
65
|
message << "usage: testjour <SUBCOMMAND> [OPTIONS] [ARGS...]"
|
@@ -65,13 +67,16 @@ module Testjour
|
|
65
67
|
message << "Type 'testjour version' to get this program's version."
|
66
68
|
message << ""
|
67
69
|
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
|
-
|
70
|
+
message += command_listing
|
73
71
|
message.map { |line| line.chomp }.join("\n")
|
74
72
|
end
|
73
|
+
|
74
|
+
def command_listing
|
75
|
+
self.class.commands.sort_by { |c| c.command }.map do |command_klass|
|
76
|
+
" " + command_klass.command
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
75
80
|
end
|
76
81
|
|
77
82
|
end
|
@@ -6,6 +6,8 @@ module Testjour
|
|
6
6
|
module CLI
|
7
7
|
|
8
8
|
class List < BaseCommand
|
9
|
+
include Bonjour
|
10
|
+
|
9
11
|
def self.command
|
10
12
|
"list"
|
11
13
|
end
|
@@ -19,17 +21,13 @@ module Testjour
|
|
19
21
|
end
|
20
22
|
|
21
23
|
def run
|
22
|
-
|
23
|
-
|
24
|
-
if available_servers.any?
|
24
|
+
if bonjour_servers.any?
|
25
25
|
puts
|
26
26
|
puts "Testjour servers:"
|
27
27
|
puts
|
28
28
|
|
29
|
-
|
30
|
-
|
31
|
-
status = colorize_status(slave_server.status)
|
32
|
-
puts " %-12s %s %s" % [server.name, status, "#{server.host}:#{server.port}"]
|
29
|
+
bonjour_servers.each do |server|
|
30
|
+
puts server.status_line
|
33
31
|
end
|
34
32
|
else
|
35
33
|
puts
|
@@ -37,21 +35,8 @@ module Testjour
|
|
37
35
|
end
|
38
36
|
end
|
39
37
|
|
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
38
|
end
|
53
39
|
|
54
|
-
Parser.register_command List
|
55
40
|
end
|
56
41
|
end
|
57
42
|
|
@@ -24,33 +24,38 @@ module Testjour
|
|
24
24
|
ARGV.clear # Don't pass along args to RSpec
|
25
25
|
Testjour.load_cucumber
|
26
26
|
|
27
|
-
ENV["RAILS_ENV"] = "test"
|
28
|
-
require File.expand_path("config/environment")
|
29
|
-
|
30
27
|
Testjour::MysqlDatabaseSetup.with_new_database do
|
31
28
|
Cucumber::CLI.executor.formatters = Testjour::DRbFormatter.new(queue_server)
|
32
29
|
require_files
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
30
|
+
work
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def work
|
35
|
+
begin
|
36
|
+
loop do
|
37
|
+
begin
|
38
|
+
run_file(queue_server.take_work)
|
39
|
+
rescue Testjour::QueueServer::NoWorkUnitsAvailableError
|
40
|
+
# If no work, ignore and keep looping
|
41
41
|
end
|
42
|
-
rescue DRb::DRbConnError
|
43
|
-
Testjour.logger.debug "DRb connection error. (This is normal.) Exiting runner."
|
44
42
|
end
|
43
|
+
rescue DRb::DRbConnError
|
44
|
+
Testjour.logger.debug "DRb connection error. (This is normal.) Exiting runner."
|
45
45
|
end
|
46
46
|
end
|
47
47
|
|
48
48
|
def require_files
|
49
49
|
cli = Cucumber::CLI.new
|
50
|
-
|
50
|
+
Testjour.logger.debug "Cucumber options: #{options_for_cucumber.inspect}"
|
51
|
+
cli.parse_options!(options_for_cucumber)
|
51
52
|
cli.send(:require_files)
|
52
53
|
end
|
53
54
|
|
55
|
+
def options_for_cucumber
|
56
|
+
@non_options
|
57
|
+
end
|
58
|
+
|
54
59
|
def run_file(file)
|
55
60
|
Testjour.logger.debug "Running feature file: #{file}"
|
56
61
|
features = feature_parser.parse_feature(File.expand_path(file))
|
@@ -77,7 +82,5 @@ module Testjour
|
|
77
82
|
end
|
78
83
|
|
79
84
|
end
|
80
|
-
|
81
|
-
Parser.register_command LocalRun
|
82
85
|
end
|
83
86
|
end
|
@@ -3,11 +3,15 @@ require "drb"
|
|
3
3
|
require "testjour/commands/base_command"
|
4
4
|
require "testjour/queue_server"
|
5
5
|
require "testjour/bonjour"
|
6
|
+
require "testjour/run_command"
|
6
7
|
|
7
8
|
module Testjour
|
8
9
|
module CLI
|
9
10
|
|
10
11
|
class Run < BaseCommand
|
12
|
+
include RunCommand
|
13
|
+
include Bonjour
|
14
|
+
|
11
15
|
def self.command
|
12
16
|
"run"
|
13
17
|
end
|
@@ -63,16 +67,11 @@ module Testjour
|
|
63
67
|
end
|
64
68
|
|
65
69
|
def slave_servers_to_use
|
66
|
-
|
67
|
-
@slave_servers_to_use ||= available_servers.select do |potential_server|
|
70
|
+
@slave_servers_to_use ||= bonjour_servers.select do |potential_server|
|
68
71
|
!servers_specified? || specified_servers_include?(potential_server)
|
69
72
|
end
|
70
73
|
end
|
71
74
|
|
72
|
-
def available_servers
|
73
|
-
@available_servers ||= Testjour::Bonjour.list
|
74
|
-
end
|
75
|
-
|
76
75
|
def request_build_from(server)
|
77
76
|
slave_server = DRbObject.new(nil, server.uri)
|
78
77
|
result = slave_server.run(testjour_uri, @non_options)
|
@@ -98,22 +97,8 @@ module Testjour
|
|
98
97
|
end
|
99
98
|
|
100
99
|
def start_local_runner
|
101
|
-
|
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
|
-
|
100
|
+
run_command(command_for_local_run)
|
113
101
|
@found_server += 1
|
114
|
-
Testjour.logger.info "Started local:run on PID #{pid}"
|
115
|
-
|
116
|
-
pid
|
117
102
|
end
|
118
103
|
|
119
104
|
def command_for_local_run
|
@@ -159,7 +144,6 @@ module Testjour
|
|
159
144
|
end
|
160
145
|
end
|
161
146
|
end
|
162
|
-
|
163
|
-
Parser.register_command Run
|
147
|
+
|
164
148
|
end
|
165
149
|
end
|
@@ -1,88 +1,19 @@
|
|
1
|
-
require "
|
2
|
-
require "uri"
|
3
|
-
|
4
|
-
require "testjour/commands/base_command"
|
1
|
+
require "testjour/commands/local_run"
|
5
2
|
require "testjour/rsync"
|
6
|
-
require "testjour/queue_server"
|
7
|
-
require "testjour/cucumber_extensions/drb_formatter"
|
8
|
-
require "testjour/mysql"
|
9
3
|
|
10
4
|
module Testjour
|
11
5
|
module CLI
|
12
6
|
|
13
|
-
class SlaveRun <
|
7
|
+
class SlaveRun < LocalRun
|
14
8
|
def self.command
|
15
9
|
"slave:run"
|
16
10
|
end
|
17
|
-
|
18
|
-
def initialize(parser, args)
|
19
|
-
Testjour.logger.debug "Runner command #{self.class}..."
|
20
|
-
super
|
21
|
-
@queue = @non_options.first
|
22
|
-
end
|
23
11
|
|
24
12
|
def run
|
25
|
-
|
26
|
-
|
27
|
-
end
|
28
|
-
|
29
|
-
ARGV.clear # Don't pass along args to RSpec
|
30
|
-
Testjour.load_cucumber
|
31
|
-
|
32
|
-
ENV["RAILS_ENV"] = "test"
|
33
|
-
require File.expand_path("config/environment")
|
34
|
-
|
35
|
-
Testjour::MysqlDatabaseSetup.with_new_database do
|
36
|
-
Cucumber::CLI.executor.formatters = Testjour::DRbFormatter.new(queue_server)
|
37
|
-
require_files
|
38
|
-
|
39
|
-
begin
|
40
|
-
loop do
|
41
|
-
begin
|
42
|
-
run_file(queue_server.take_work)
|
43
|
-
rescue Testjour::QueueServer::NoWorkUnitsAvailableError
|
44
|
-
# If no work, ignore and keep looping
|
45
|
-
end
|
46
|
-
end
|
47
|
-
rescue DRb::DRbConnError
|
48
|
-
Testjour.logger.debug "DRb connection error. (This is normal.) Exiting runner."
|
49
|
-
end
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
def require_files
|
54
|
-
cli = Cucumber::CLI.new
|
55
|
-
cli.parse_options!(@non_options)
|
56
|
-
cli.send(:require_files)
|
57
|
-
end
|
58
|
-
|
59
|
-
def run_file(file)
|
60
|
-
Testjour.logger.debug "Running feature file: #{file}"
|
61
|
-
features = feature_parser.parse_feature(File.expand_path(file))
|
62
|
-
Cucumber::CLI.executor.visit_features(features)
|
63
|
-
end
|
64
|
-
|
65
|
-
def queue_server
|
66
|
-
@queue_server ||= begin
|
67
|
-
DRb.start_service
|
68
|
-
DRbObject.new(nil, drb_uri)
|
69
|
-
end
|
70
|
-
end
|
71
|
-
|
72
|
-
def drb_uri
|
73
|
-
uri = URI.parse(@queue)
|
74
|
-
uri.scheme = "druby"
|
75
|
-
uri.path = ""
|
76
|
-
uri.user = nil
|
77
|
-
uri.to_s
|
78
|
-
end
|
79
|
-
|
80
|
-
def feature_parser
|
81
|
-
@feature_parser ||= Cucumber::TreetopParser::FeatureParser.new
|
13
|
+
Testjour::Rsync.copy_to_current_directory_from(@queue)
|
14
|
+
super
|
82
15
|
end
|
83
|
-
|
84
16
|
end
|
85
17
|
|
86
|
-
Parser.register_command SlaveRun
|
87
18
|
end
|
88
19
|
end
|
@@ -10,6 +10,8 @@ module Testjour
|
|
10
10
|
module CLI
|
11
11
|
|
12
12
|
class SlaveStart < BaseCommand
|
13
|
+
include Bonjour
|
14
|
+
|
13
15
|
class StopServer < Exception
|
14
16
|
end
|
15
17
|
|
@@ -24,7 +26,15 @@ module Testjour
|
|
24
26
|
|
25
27
|
def run
|
26
28
|
verify_not_a_git_repo
|
27
|
-
|
29
|
+
daemonize
|
30
|
+
Testjour.setup_logger
|
31
|
+
bonjour_serve(Testjour::SlaveServer.start)
|
32
|
+
DRb.thread.join
|
33
|
+
rescue StopServer
|
34
|
+
exit 0
|
35
|
+
end
|
36
|
+
|
37
|
+
def daemonize
|
28
38
|
original_working_directory = File.expand_path(".")
|
29
39
|
|
30
40
|
pid_file = PidFile.new("./testjour_slave.pid")
|
@@ -37,12 +47,6 @@ module Testjour
|
|
37
47
|
|
38
48
|
Dir.chdir(original_working_directory)
|
39
49
|
pid_file.write
|
40
|
-
|
41
|
-
Testjour.setup_logger
|
42
|
-
Testjour::Bonjour.serve(Testjour::SlaveServer.start)
|
43
|
-
DRb.thread.join
|
44
|
-
rescue StopServer
|
45
|
-
exit 0
|
46
50
|
end
|
47
51
|
|
48
52
|
def verify_not_a_git_repo
|
@@ -60,6 +64,5 @@ module Testjour
|
|
60
64
|
|
61
65
|
end
|
62
66
|
|
63
|
-
Parser.register_command SlaveStart
|
64
67
|
end
|
65
68
|
end
|
@@ -19,13 +19,10 @@ module Testjour
|
|
19
19
|
end
|
20
20
|
|
21
21
|
def run
|
22
|
-
|
23
|
-
Testjour::Rsync.copy_to_current_directory_from(@queue)
|
24
|
-
end
|
22
|
+
Testjour::Rsync.copy_to_current_directory_from(@queue)
|
25
23
|
end
|
26
24
|
|
27
25
|
end
|
28
26
|
|
29
|
-
Parser.register_command SlaveWarm
|
30
27
|
end
|
31
28
|
end
|
@@ -7,6 +7,8 @@ module Testjour
|
|
7
7
|
module CLI
|
8
8
|
|
9
9
|
class Warm < BaseCommand
|
10
|
+
include Bonjour
|
11
|
+
|
10
12
|
def self.command
|
11
13
|
"warm"
|
12
14
|
end
|
@@ -20,8 +22,8 @@ module Testjour
|
|
20
22
|
end
|
21
23
|
|
22
24
|
def run
|
23
|
-
if
|
24
|
-
|
25
|
+
if bonjour_servers.any?
|
26
|
+
bonjour_servers.each do |server|
|
25
27
|
request_warm_from(server)
|
26
28
|
end
|
27
29
|
|
@@ -32,10 +34,6 @@ module Testjour
|
|
32
34
|
end
|
33
35
|
end
|
34
36
|
|
35
|
-
def available_servers
|
36
|
-
@available_servers ||= Testjour::Bonjour.list
|
37
|
-
end
|
38
|
-
|
39
37
|
def request_warm_from(server)
|
40
38
|
slave_server = DRbObject.new(nil, server.uri)
|
41
39
|
result = slave_server.warm(testjour_uri)
|
@@ -68,6 +66,5 @@ module Testjour
|
|
68
66
|
end
|
69
67
|
end
|
70
68
|
|
71
|
-
Parser.register_command Warm
|
72
69
|
end
|
73
70
|
end
|
@@ -11,79 +11,97 @@ module Testjour
|
|
11
11
|
attr_accessor :queue
|
12
12
|
end
|
13
13
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
def wait_for_results
|
25
|
-
progress_bar = ProgressBar.new("0 slaves", step_count)
|
14
|
+
class ResultsFormatter
|
15
|
+
def initialize(step_count)
|
16
|
+
@passed = 0
|
17
|
+
@skipped = 0
|
18
|
+
@pending = 0
|
19
|
+
@result_uris = []
|
20
|
+
@errors = []
|
21
|
+
@progress_bar = ProgressBar.new("0 slaves", step_count)
|
22
|
+
end
|
26
23
|
|
27
|
-
|
28
|
-
|
24
|
+
def result(uri, dot, message, backtrace)
|
25
|
+
@result_uris << uri
|
26
|
+
@result_uris.uniq!
|
27
|
+
|
28
|
+
log_result(uri, dot, message, backtrace)
|
29
29
|
|
30
|
+
@progress_bar.colorer = colorer
|
31
|
+
@progress_bar.title = title
|
32
|
+
@progress_bar.inc
|
33
|
+
end
|
34
|
+
|
35
|
+
def log_result(uri, dot, message, backtrace)
|
36
|
+
case dot
|
37
|
+
when "."
|
38
|
+
@passed += 1
|
39
|
+
when "F"
|
40
|
+
@errors << [message, backtrace]
|
41
|
+
|
42
|
+
erase_current_line
|
43
|
+
print Testjour::Colorer.failed("#{@errors.size}) ")
|
44
|
+
puts Testjour::Colorer.failed(message)
|
45
|
+
puts backtrace
|
46
|
+
puts
|
47
|
+
when "P"
|
48
|
+
@pending += 1
|
49
|
+
when "_"
|
50
|
+
@skipped += 1
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def colorer
|
30
55
|
if failed?
|
31
|
-
|
32
|
-
progress_bar.title = "#{@result_uris.size} slaves, #{@errors.size} failures"
|
56
|
+
Testjour::Colorer.method(:failed).to_proc
|
33
57
|
else
|
34
|
-
|
35
|
-
|
58
|
+
Testjour::Colorer.method(:passed).to_proc
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def title
|
63
|
+
if failed?
|
64
|
+
"#{@result_uris.size} slaves, #{@errors.size} failures"
|
65
|
+
else
|
66
|
+
"#{@result_uris.size} slaves"
|
36
67
|
end
|
37
|
-
|
38
|
-
progress_bar.inc
|
39
68
|
end
|
40
69
|
|
41
|
-
|
70
|
+
def erase_current_line
|
71
|
+
print "\e[K"
|
72
|
+
end
|
42
73
|
|
43
|
-
print_summary
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
def log_result(uri, dot, message, backtrace)
|
53
|
-
@result_uris << uri
|
54
|
-
@result_uris.uniq!
|
74
|
+
def print_summary
|
75
|
+
puts
|
76
|
+
puts
|
77
|
+
puts Colorer.passed("#{@passed} steps passed") unless @passed.zero?
|
78
|
+
puts Colorer.failed("#{@errors.size} steps failed") unless @errors.empty?
|
79
|
+
puts Colorer.skipped("#{@skipped} steps skipped") unless @skipped.zero?
|
80
|
+
puts Colorer.pending("#{@pending} steps pending") unless @pending.zero?
|
81
|
+
puts
|
82
|
+
end
|
55
83
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
@
|
63
|
-
when "_"
|
64
|
-
@skipped += 1
|
84
|
+
def finish
|
85
|
+
@progress_bar.finish
|
86
|
+
print_summary
|
87
|
+
end
|
88
|
+
|
89
|
+
def failed?
|
90
|
+
@errors.any?
|
65
91
|
end
|
66
92
|
end
|
67
|
-
|
68
|
-
def
|
69
|
-
|
70
|
-
|
71
|
-
puts Colorer.passed("#{@passed} steps passed") unless @passed.zero?
|
72
|
-
puts Colorer.failed("#{@errors.size} steps failed") unless @errors.empty?
|
73
|
-
puts Colorer.skipped("#{@skipped} steps skipped") unless @skipped.zero?
|
74
|
-
puts Colorer.pending("#{@pending} steps pending") unless @pending.zero?
|
75
|
-
puts
|
93
|
+
|
94
|
+
def initialize(queue_server, step_mother)
|
95
|
+
@queue_server = queue_server
|
96
|
+
@step_count = 0
|
76
97
|
end
|
77
98
|
|
78
|
-
def
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
puts
|
83
|
-
puts Colorer.failed("#{i+1})")
|
84
|
-
puts Colorer.failed(message)
|
85
|
-
puts Colorer.failed(backtrace)
|
99
|
+
def wait_for_results
|
100
|
+
results_formatter = ResultsFormatter.new(@step_count)
|
101
|
+
step_count.times do
|
102
|
+
results_formatter.result(*@queue_server.take_result)
|
86
103
|
end
|
104
|
+
results_formatter.finish
|
87
105
|
end
|
88
106
|
|
89
107
|
def visit_feature(feature)
|
data/lib/testjour/mysql.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
RAILS_ROOT = File.expand_path(".") unless defined?(RAILS_ROOT)
|
2
|
+
|
1
3
|
module Testjour
|
2
4
|
|
3
5
|
# Stolen from deep-test
|
@@ -21,9 +23,18 @@ module Testjour
|
|
21
23
|
}
|
22
24
|
|
23
25
|
def self.with_new_database
|
26
|
+
ENV["RAILS_ENV"] ||= "test"
|
27
|
+
require File.expand_path("./vendor/rails/railties/lib/initializer")
|
28
|
+
Rails::Initializer.run(:set_load_path)
|
29
|
+
|
30
|
+
require "active_record"
|
31
|
+
require "active_record/connection_adapters/mysql_adapter"
|
32
|
+
|
24
33
|
mysql = self.new
|
25
34
|
mysql.create_database
|
26
35
|
|
36
|
+
ENV["TESTJOUR_DB"] = mysql.runner_database_name
|
37
|
+
|
27
38
|
at_exit do
|
28
39
|
mysql.drop_database
|
29
40
|
end
|
@@ -33,7 +44,7 @@ module Testjour
|
|
33
44
|
|
34
45
|
yield
|
35
46
|
end
|
36
|
-
|
47
|
+
|
37
48
|
def grant_privileges(connection)
|
38
49
|
sql = %{grant all on #{runner_database_name}.*
|
39
50
|
to %s@'localhost' identified by %s;} % [
|
data/lib/testjour/pid_file.rb
CHANGED
data/lib/testjour/rsync.rb
CHANGED
@@ -8,22 +8,46 @@ module Testjour
|
|
8
8
|
class Rsync
|
9
9
|
|
10
10
|
def self.copy_to_current_directory_from(source_uri)
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
Testjour.logger.debug("Rsync finished in %.2fs" %
|
23
|
-
|
24
|
-
raise RsyncFailed.new
|
11
|
+
new(source_uri).copy_with_retry
|
12
|
+
end
|
13
|
+
|
14
|
+
def initialize(source_uri)
|
15
|
+
@source_uri = source_uri
|
16
|
+
end
|
17
|
+
|
18
|
+
def copy_with_retry
|
19
|
+
retryable :tries => 2, :on => RsyncFailed do
|
20
|
+
Testjour.logger.info "Rsyncing: #{command}"
|
21
|
+
copy
|
22
|
+
Testjour.logger.debug("Rsync finished in %.2fs" % elapsed_time)
|
23
|
+
raise RsyncFailed.new unless successful?
|
25
24
|
end
|
26
25
|
end
|
27
26
|
|
27
|
+
def copy
|
28
|
+
@start_time = Time.now
|
29
|
+
@successful = system(command)
|
30
|
+
end
|
31
|
+
|
32
|
+
def elapsed_time
|
33
|
+
Time.now - @start_time
|
34
|
+
end
|
35
|
+
|
36
|
+
def successful?
|
37
|
+
@successful
|
38
|
+
end
|
39
|
+
|
40
|
+
def command
|
41
|
+
"rsync -az --delete --exclude=.git --exclude=*.log --exclude=*.pid #{uri.user}@#{uri.host}:#{uri.path}/ #{destination_dir}"
|
42
|
+
end
|
43
|
+
|
44
|
+
def destination_dir
|
45
|
+
File.expand_path(".")
|
46
|
+
end
|
47
|
+
|
48
|
+
def uri
|
49
|
+
URI.parse(@source_uri)
|
50
|
+
end
|
51
|
+
|
28
52
|
end
|
29
53
|
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require "systemu"
|
2
|
+
|
3
|
+
module Testjour
|
4
|
+
module RunCommand
|
5
|
+
|
6
|
+
def run_command(cmd)
|
7
|
+
pid_queue = Queue.new
|
8
|
+
|
9
|
+
Thread.new do
|
10
|
+
Thread.current.abort_on_exception = true
|
11
|
+
status, stdout, stderr = systemu(cmd) { |pid| pid_queue << pid }
|
12
|
+
Testjour.logger.warn stderr if stderr.strip.size > 0
|
13
|
+
end
|
14
|
+
|
15
|
+
pid = pid_queue.pop
|
16
|
+
Testjour.logger.info "Started on PID #{pid}: #{cmd}"
|
17
|
+
pid
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
@@ -2,12 +2,14 @@ require "thread"
|
|
2
2
|
require "drb"
|
3
3
|
require "uri"
|
4
4
|
require "timeout"
|
5
|
-
|
5
|
+
|
6
|
+
require "testjour/run_command"
|
6
7
|
|
7
8
|
module Testjour
|
8
9
|
|
9
10
|
class SlaveServer
|
10
|
-
|
11
|
+
include RunCommand
|
12
|
+
|
11
13
|
def self.start
|
12
14
|
server = self.new
|
13
15
|
DRb.start_service(nil, server)
|
@@ -28,22 +30,8 @@ module Testjour
|
|
28
30
|
Testjour.logger.info "Not running because pid exists: #{@pid}"
|
29
31
|
return false
|
30
32
|
end
|
31
|
-
|
32
|
-
|
33
|
-
@pid = nil
|
34
|
-
|
35
|
-
Thread.new do
|
36
|
-
Thread.current.abort_on_exception = true
|
37
|
-
cmd = command_to_warm_for(queue_server_url)
|
38
|
-
Testjour.logger.debug "Starting warm with command: #{cmd}"
|
39
|
-
status, stdout, stderr = systemu(cmd) { |pid| pid_queue << pid }
|
40
|
-
Testjour.logger.warn stderr if stderr.strip.size > 0
|
41
|
-
end
|
42
|
-
|
43
|
-
@pid = pid_queue.pop
|
44
|
-
|
45
|
-
Testjour.logger.info "Warming from server #{queue_server_url} on PID #{@pid}"
|
46
|
-
|
33
|
+
|
34
|
+
@pid = run_command(command_to_warm_for(queue_server_url))
|
47
35
|
return @pid
|
48
36
|
end
|
49
37
|
|
@@ -53,21 +41,7 @@ module Testjour
|
|
53
41
|
return false
|
54
42
|
end
|
55
43
|
|
56
|
-
|
57
|
-
@pid = nil
|
58
|
-
|
59
|
-
Thread.new do
|
60
|
-
Thread.current.abort_on_exception = true
|
61
|
-
cmd = command_to_run_for(queue_server_url, cucumber_options)
|
62
|
-
Testjour.logger.debug "Starting runner with command: #{cmd}"
|
63
|
-
status, stdout, stderr = systemu(cmd) { |pid| pid_queue << pid }
|
64
|
-
Testjour.logger.warn stderr if stderr.strip.size > 0
|
65
|
-
end
|
66
|
-
|
67
|
-
@pid = pid_queue.pop
|
68
|
-
|
69
|
-
Testjour.logger.info "Running tests from queue #{queue_server_url} on PID #{@pid}"
|
70
|
-
|
44
|
+
@pid = run_command(command_to_run_for(queue_server_url, cucumber_options))
|
71
45
|
return @pid
|
72
46
|
end
|
73
47
|
|
data/lib/testjour.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: brynary-testjour
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Bryan Helmkamp
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2008-12-
|
12
|
+
date: 2008-12-11 00:00:00 -08:00
|
13
13
|
default_executable: testjour
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -69,6 +69,7 @@ files:
|
|
69
69
|
- lib/testjour/progressbar.rb
|
70
70
|
- lib/testjour/queue_server.rb
|
71
71
|
- lib/testjour/rsync.rb
|
72
|
+
- lib/testjour/run_command.rb
|
72
73
|
- lib/testjour/slave_server.rb
|
73
74
|
- lib/testjour.rb
|
74
75
|
- vendor/authprogs
|