brynary-testjour 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -6,11 +6,15 @@ Thread.abort_on_exception = true
6
6
  module Testjour
7
7
  SERVICE = "_testjour._tcp"
8
8
 
9
- class Bonjour
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 self.list
30
- hosts = []
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
- server = Server.new(reply.name, rr.target, rr.port)
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 hosts
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 self.serve(port)
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
- 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
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
@@ -10,6 +10,10 @@ module Testjour
10
10
  self.name.downcase
11
11
  end
12
12
 
13
+ def self.inherited(command_class)
14
+ Parser.register_command command_class
15
+ end
16
+
13
17
  def self.options
14
18
  {}
15
19
  end
@@ -14,7 +14,6 @@ module Testjour
14
14
  end
15
15
  end
16
16
 
17
- Parser.register_command HelpCommand
18
17
  end
19
18
  end
20
19
 
@@ -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
- available_servers = Testjour::Bonjour.list
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
- 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}"]
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
- 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
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
- cli.parse_options!(@non_options)
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
- # require "rubygems"; require "ruby-debug"; Debugger.start; debugger
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
- 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
-
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 "drb"
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 < BaseCommand
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
- retryable :tries => 2, :on => RsyncFailed do
26
- Testjour::Rsync.copy_to_current_directory_from(@queue)
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
@@ -15,11 +15,9 @@ module Testjour
15
15
  end
16
16
 
17
17
  def run
18
- pid_file = PidFile.new("./testjour_slave.pid")
19
- pid_file.send_signal("TERM")
18
+ PidFile.term("./testjour_slave.pid")
20
19
  end
21
20
  end
22
21
 
23
- Parser.register_command SlaveStop
24
22
  end
25
23
  end
@@ -19,13 +19,10 @@ module Testjour
19
19
  end
20
20
 
21
21
  def run
22
- retryable :tries => 2, :on => RsyncFailed do
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
@@ -13,6 +13,5 @@ module Testjour
13
13
  end
14
14
  end
15
15
 
16
- Parser.register_command VersionCommand
17
16
  end
18
17
  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 available_servers.any?
24
- available_servers.each do |server|
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
- def initialize(queue_server, step_mother)
15
- @queue_server = queue_server
16
- @step_count = 0
17
- @passed = 0
18
- @skipped = 0
19
- @pending = 0
20
- @result_uris = []
21
- @errors = []
22
- end
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
- step_count.times do
28
- log_result(*@queue_server.take_result)
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
- progress_bar.colorer = Testjour::Colorer.method(:failed).to_proc
32
- progress_bar.title = "#{@result_uris.size} slaves, #{@errors.size} failures"
56
+ Testjour::Colorer.method(:failed).to_proc
33
57
  else
34
- progress_bar.colorer = Testjour::Colorer.method(:passed).to_proc
35
- progress_bar.title = "#{@result_uris.size} slaves"
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
- progress_bar.finish
70
+ def erase_current_line
71
+ print "\e[K"
72
+ end
42
73
 
43
- print_summary
44
- print_errors
45
- end
46
-
47
- def failed?
48
- @errors.any?
49
- end
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
- case dot
57
- when "."
58
- @passed += 1
59
- when "F"
60
- @errors << [message, backtrace]
61
- when "P"
62
- @pending += 1
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 print_summary
69
- puts
70
- puts
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 print_errors
79
- @errors.each_with_index do |error, i|
80
- message, backtrace = error
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)
@@ -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;} % [
@@ -1,6 +1,10 @@
1
1
  module Testjour
2
2
 
3
3
  class PidFile
4
+
5
+ def self.term(path)
6
+ new(path).send_signal("TERM")
7
+ end
4
8
 
5
9
  def initialize(path)
6
10
  @path = File.expand_path(path)
@@ -8,22 +8,46 @@ module Testjour
8
8
  class Rsync
9
9
 
10
10
  def self.copy_to_current_directory_from(source_uri)
11
- destination_dir = File.expand_path(".")
12
- uri = URI.parse(source_uri)
13
-
14
- command = "rsync -az --delete --exclude=.git --exclude=*.log --exclude=*.pid #{uri.user}@#{uri.host}:#{uri.path}/ #{destination_dir}"
15
-
16
- Testjour.logger.info "Rsyncing: #{command}"
17
- start_time = Time.now
18
- successful = system command
19
-
20
- if successful
21
- time = Time.now - start_time
22
- Testjour.logger.debug("Rsync finished in %.2fs" % time)
23
- else
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
- require "systemu"
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
- pid_queue = Queue.new
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
- pid_queue = Queue.new
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
@@ -31,7 +31,7 @@ module Kernel
31
31
  end
32
32
 
33
33
  module Testjour
34
- VERSION = '0.1.0'
34
+ VERSION = '0.2.0'
35
35
 
36
36
  class << self
37
37
  attr_accessor :step_mother
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.1.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-09 00:00:00 -08:00
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