hydra 0.19.0 → 0.19.1
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/VERSION +1 -1
- data/hydra.gemspec +12 -12
- data/lib/hydra/listener/abstract.rb +11 -2
- data/lib/hydra/master.rb +24 -14
- data/lib/hydra/message/worker_messages.rb +6 -0
- data/lib/hydra/tasks.rb +10 -4
- data/lib/hydra/worker.rb +7 -3
- data/test/worker_test.rb +3 -1
- metadata +13 -13
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.19.
|
1
|
+
0.19.1
|
data/hydra.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{hydra}
|
8
|
-
s.version = "0.19.
|
8
|
+
s.version = "0.19.1"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Nick Gauthier"]
|
12
|
-
s.date = %q{2010-06-
|
12
|
+
s.date = %q{2010-06-18}
|
13
13
|
s.description = %q{Spread your tests over multiple machines to test your code faster.}
|
14
14
|
s.email = %q{nick@smartlogicsolutions.com}
|
15
15
|
s.extra_rdoc_files = [
|
@@ -85,21 +85,21 @@ Gem::Specification.new do |s|
|
|
85
85
|
s.summary = %q{Distributed testing toolkit}
|
86
86
|
s.test_files = [
|
87
87
|
"test/pipe_test.rb",
|
88
|
-
"test/
|
88
|
+
"test/sync_test.rb",
|
89
89
|
"test/ssh_test.rb",
|
90
|
-
"test/message_test.rb",
|
91
|
-
"test/master_test.rb",
|
92
|
-
"test/fixtures/write_file.rb",
|
93
|
-
"test/fixtures/slow.rb",
|
94
|
-
"test/fixtures/write_file_with_pending_spec.rb",
|
95
|
-
"test/fixtures/write_file_spec.rb",
|
96
|
-
"test/fixtures/features/step_definitions.rb",
|
97
|
-
"test/fixtures/hello_world.rb",
|
98
90
|
"test/fixtures/write_file_alternate_spec.rb",
|
99
91
|
"test/fixtures/sync_test.rb",
|
92
|
+
"test/fixtures/hello_world.rb",
|
93
|
+
"test/fixtures/features/step_definitions.rb",
|
100
94
|
"test/fixtures/assert_true.rb",
|
95
|
+
"test/fixtures/slow.rb",
|
96
|
+
"test/fixtures/write_file_spec.rb",
|
97
|
+
"test/fixtures/write_file_with_pending_spec.rb",
|
98
|
+
"test/fixtures/write_file.rb",
|
99
|
+
"test/message_test.rb",
|
100
|
+
"test/test_helper.rb",
|
101
|
+
"test/master_test.rb",
|
101
102
|
"test/runner_test.rb",
|
102
|
-
"test/sync_test.rb",
|
103
103
|
"test/worker_test.rb"
|
104
104
|
]
|
105
105
|
|
@@ -2,7 +2,7 @@ module Hydra #:nodoc:
|
|
2
2
|
module Listener #:nodoc:
|
3
3
|
# Abstract listener that implements all the events
|
4
4
|
# but does nothing.
|
5
|
-
class Abstract
|
5
|
+
class Abstract
|
6
6
|
# Create a new listener.
|
7
7
|
#
|
8
8
|
# Output: The IO object for outputting any information.
|
@@ -10,14 +10,23 @@ module Hydra #:nodoc:
|
|
10
10
|
def initialize(output = $stdout)
|
11
11
|
@output = output
|
12
12
|
end
|
13
|
+
|
13
14
|
# Fired when testing has started
|
14
15
|
def testing_begin(files)
|
15
16
|
end
|
16
17
|
|
17
|
-
# Fired when testing finishes
|
18
|
+
# Fired when testing finishes, after the workers shutdown
|
18
19
|
def testing_end
|
19
20
|
end
|
20
21
|
|
22
|
+
# Fired after runner processes have been started
|
23
|
+
def worker_begin(worker)
|
24
|
+
end
|
25
|
+
|
26
|
+
# Fired before shutting down the worker
|
27
|
+
def worker_end(worker)
|
28
|
+
end
|
29
|
+
|
21
30
|
# Fired when a file is started
|
22
31
|
def file_begin(file)
|
23
32
|
end
|
data/lib/hydra/master.rb
CHANGED
@@ -9,7 +9,7 @@ module Hydra #:nodoc:
|
|
9
9
|
#
|
10
10
|
# The Master is run once for any given testing session.
|
11
11
|
class YmlLoadError < StandardError; end
|
12
|
-
|
12
|
+
|
13
13
|
class Master
|
14
14
|
include Hydra::Messages::Master
|
15
15
|
include Open3
|
@@ -37,7 +37,7 @@ module Hydra #:nodoc:
|
|
37
37
|
puts "Testing halted by user. Untested files:"
|
38
38
|
puts @incomplete_files.join("\n")
|
39
39
|
exit
|
40
|
-
end
|
40
|
+
end
|
41
41
|
|
42
42
|
opts.stringify_keys!
|
43
43
|
config_file = opts.delete('config') { nil }
|
@@ -54,7 +54,7 @@ module Hydra #:nodoc:
|
|
54
54
|
rescue StandardError => e
|
55
55
|
raise(YmlLoadError,"config file was found, but could not be parsed.\n#{$!.inspect}")
|
56
56
|
end
|
57
|
-
|
57
|
+
|
58
58
|
opts.merge!(config_yml.stringify_keys!)
|
59
59
|
end
|
60
60
|
@files = Array(opts.fetch('files') { nil })
|
@@ -74,7 +74,7 @@ module Hydra #:nodoc:
|
|
74
74
|
@environment = opts.fetch('environment') { 'test' }
|
75
75
|
|
76
76
|
if @autosort
|
77
|
-
sort_files_from_report
|
77
|
+
sort_files_from_report
|
78
78
|
@event_listeners << Hydra::Listener::ReportGenerator.new(File.new(heuristic_file, 'w'))
|
79
79
|
end
|
80
80
|
|
@@ -93,8 +93,11 @@ module Hydra #:nodoc:
|
|
93
93
|
end
|
94
94
|
|
95
95
|
# Message handling
|
96
|
-
|
97
|
-
|
96
|
+
def worker_begin(worker)
|
97
|
+
@event_listeners.each {|l| l.worker_begin(worker) }
|
98
|
+
end
|
99
|
+
|
100
|
+
# Send a file down to a worker.
|
98
101
|
def send_file(worker)
|
99
102
|
f = @files.shift
|
100
103
|
if f
|
@@ -110,14 +113,20 @@ module Hydra #:nodoc:
|
|
110
113
|
def process_results(worker, message)
|
111
114
|
if message.output =~ /ActiveRecord::StatementInvalid(.*)[Dd]eadlock/ or
|
112
115
|
message.output =~ /PGError: ERROR(.*)[Dd]eadlock/ or
|
113
|
-
message.output =~ /Mysql::Error: SAVEPOINT(.*)does not exist: ROLLBACK/
|
116
|
+
message.output =~ /Mysql::Error: SAVEPOINT(.*)does not exist: ROLLBACK/ or
|
117
|
+
message.output =~ /Mysql::Error: Deadlock found/
|
114
118
|
trace "Deadlock detected running [#{message.file}]. Will retry at the end"
|
115
119
|
@files.push(message.file)
|
120
|
+
send_file(worker)
|
116
121
|
else
|
117
122
|
@incomplete_files.delete_at(@incomplete_files.index(message.file))
|
118
123
|
trace "#{@incomplete_files.size} Files Remaining"
|
119
124
|
@event_listeners.each{|l| l.file_end(message.file, message.output) }
|
120
125
|
if @incomplete_files.empty?
|
126
|
+
@workers.each do |worker|
|
127
|
+
@event_listeners.each{|l| l.worker_end(worker) }
|
128
|
+
end
|
129
|
+
|
121
130
|
shutdown_all_workers
|
122
131
|
else
|
123
132
|
send_file(worker)
|
@@ -129,7 +138,7 @@ module Hydra #:nodoc:
|
|
129
138
|
attr_reader :report_text
|
130
139
|
|
131
140
|
private
|
132
|
-
|
141
|
+
|
133
142
|
def boot_workers(workers)
|
134
143
|
trace "Booting #{workers.size} workers"
|
135
144
|
workers.each do |worker|
|
@@ -148,12 +157,13 @@ module Hydra #:nodoc:
|
|
148
157
|
|
149
158
|
def boot_local_worker(worker)
|
150
159
|
runners = worker.fetch('runners') { raise "You must specify the number of runners" }
|
151
|
-
trace "Booting local worker"
|
160
|
+
trace "Booting local worker"
|
152
161
|
pipe = Hydra::Pipe.new
|
153
162
|
child = SafeFork.fork do
|
154
163
|
pipe.identify_as_child
|
155
164
|
Hydra::Worker.new(:io => pipe, :runners => runners, :verbose => @verbose)
|
156
165
|
end
|
166
|
+
|
157
167
|
pipe.identify_as_parent
|
158
168
|
@workers << { :pid => child, :io => pipe, :idle => false, :type => :local }
|
159
169
|
end
|
@@ -162,11 +172,11 @@ module Hydra #:nodoc:
|
|
162
172
|
sync = Sync.new(worker, @sync, @verbose)
|
163
173
|
|
164
174
|
runners = worker.fetch('runners') { raise "You must specify the number of runners" }
|
165
|
-
command = worker.fetch('command') {
|
175
|
+
command = worker.fetch('command') {
|
166
176
|
"RAILS_ENV=#{@environment} ruby -e \"require 'rubygems'; require 'hydra'; Hydra::Worker.new(:io => Hydra::Stdio.new, :runners => #{runners}, :verbose => #{@verbose});\""
|
167
177
|
}
|
168
178
|
|
169
|
-
trace "Booting SSH worker"
|
179
|
+
trace "Booting SSH worker"
|
170
180
|
ssh = Hydra::SSH.new("#{sync.ssh_opts} #{sync.connect}", sync.remote_dir, command)
|
171
181
|
return { :io => ssh, :idle => false, :type => :ssh, :connect => sync.connect }
|
172
182
|
end
|
@@ -175,7 +185,7 @@ module Hydra #:nodoc:
|
|
175
185
|
trace "Shutting down all workers"
|
176
186
|
@workers.each do |worker|
|
177
187
|
worker[:io].write(Shutdown.new) if worker[:io]
|
178
|
-
worker[:io].close if worker[:io]
|
188
|
+
worker[:io].close if worker[:io]
|
179
189
|
end
|
180
190
|
@listeners.each{|t| t.exit}
|
181
191
|
end
|
@@ -199,7 +209,7 @@ module Hydra #:nodoc:
|
|
199
209
|
# if it exists and its for me.
|
200
210
|
# SSH gives us back echoes, so we need to ignore our own messages
|
201
211
|
if message and !message.class.to_s.index("Worker").nil?
|
202
|
-
message.handle(self, worker)
|
212
|
+
message.handle(self, worker)
|
203
213
|
end
|
204
214
|
rescue IOError
|
205
215
|
trace "lost Worker [#{worker.inspect}]"
|
@@ -208,7 +218,7 @@ module Hydra #:nodoc:
|
|
208
218
|
end
|
209
219
|
end
|
210
220
|
end
|
211
|
-
|
221
|
+
|
212
222
|
@listeners.each{|l| l.join}
|
213
223
|
@event_listeners.each{|l| l.testing_end}
|
214
224
|
end
|
@@ -8,6 +8,12 @@ module Hydra #:nodoc:
|
|
8
8
|
end
|
9
9
|
end
|
10
10
|
|
11
|
+
class WorkerBegin < Hydra::Message
|
12
|
+
def handle(master, worker)
|
13
|
+
master.worker_begin(worker)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
11
17
|
# Message telling the Runner to run a file
|
12
18
|
class RunFile < Hydra::Message
|
13
19
|
# The file that should be run
|
data/lib/hydra/tasks.rb
CHANGED
@@ -40,7 +40,7 @@ module Hydra #:nodoc:
|
|
40
40
|
return @config if File.exists?(@config)
|
41
41
|
@config = nil
|
42
42
|
end
|
43
|
-
|
43
|
+
|
44
44
|
# Add files to test by passing in a string to be run through Dir.glob.
|
45
45
|
# For example:
|
46
46
|
#
|
@@ -59,7 +59,7 @@ module Hydra #:nodoc:
|
|
59
59
|
# t.add_files 'test/integration/**/*_test.rb'
|
60
60
|
# t.verbose = false # optionally set to true for lots of debug messages
|
61
61
|
# t.autosort = false # disable automatic sorting based on runtime of tests
|
62
|
-
# end
|
62
|
+
# end
|
63
63
|
class TestTask < Hydra::Task
|
64
64
|
|
65
65
|
# Create a new HydraTestTask
|
@@ -72,6 +72,12 @@ module Hydra #:nodoc:
|
|
72
72
|
|
73
73
|
yield self if block_given?
|
74
74
|
|
75
|
+
if Object.const_defined?('RAILS_ENV') && RAILS_ENV == 'development'
|
76
|
+
$stderr.puts <<-MSG
|
77
|
+
WARNING: RAILS_ENV is "development". Make sure to set it properly (ex: "RAILS_ENV=test rake hydra")
|
78
|
+
MSG
|
79
|
+
end
|
80
|
+
|
75
81
|
# Ensure we override rspec's at_exit
|
76
82
|
require 'hydra/spec/autorun_override'
|
77
83
|
|
@@ -302,7 +308,7 @@ module Hydra #:nodoc:
|
|
302
308
|
# Hydra::GlobalTask.new('db:reset')
|
303
309
|
#
|
304
310
|
# Allows you to run:
|
305
|
-
#
|
311
|
+
#
|
306
312
|
# rake hydra:db:reset
|
307
313
|
#
|
308
314
|
# Then, db:reset will be run locally and on all remote workers. This
|
@@ -324,7 +330,7 @@ module Hydra #:nodoc:
|
|
324
330
|
def define
|
325
331
|
Hydra::RemoteTask.new(@name)
|
326
332
|
desc "Run #{@name.to_s} Locally and Remotely across all Workers"
|
327
|
-
task "hydra:#{@name.to_s}" => [@name.to_s, "hydra:remote:#{@name.to_s}"]
|
333
|
+
task "hydra:#{@name.to_s}" => [@name.to_s, "hydra:remote:#{@name.to_s}"]
|
328
334
|
end
|
329
335
|
end
|
330
336
|
end
|
data/lib/hydra/worker.rb
CHANGED
@@ -9,6 +9,8 @@ module Hydra #:nodoc:
|
|
9
9
|
class Worker
|
10
10
|
include Hydra::Messages::Worker
|
11
11
|
traceable('WORKER')
|
12
|
+
|
13
|
+
attr_reader :runners
|
12
14
|
# Create a new worker.
|
13
15
|
# * io: The IO object to use to communicate with the master
|
14
16
|
# * num_runners: The number of runners to launch
|
@@ -19,14 +21,16 @@ module Hydra #:nodoc:
|
|
19
21
|
@listeners = []
|
20
22
|
|
21
23
|
boot_runners(opts.fetch(:runners) { 1 })
|
24
|
+
@io.write(Hydra::Messages::Worker::WorkerBegin.new)
|
25
|
+
|
22
26
|
process_messages
|
23
|
-
|
27
|
+
|
24
28
|
@runners.each{|r| Process.wait r[:pid] }
|
25
29
|
end
|
26
30
|
|
27
31
|
|
28
32
|
# message handling methods
|
29
|
-
|
33
|
+
|
30
34
|
# When a runner wants a file, it hits this method with a message.
|
31
35
|
# Then the worker bubbles the file request up to the master.
|
32
36
|
def request_file(message, runner)
|
@@ -99,7 +103,7 @@ module Hydra #:nodoc:
|
|
99
103
|
begin
|
100
104
|
message = @io.gets
|
101
105
|
if message and !message.class.to_s.index("Master").nil?
|
102
|
-
trace "Received Message from Master"
|
106
|
+
trace "Received Message from Master"
|
103
107
|
trace "\t#{message.inspect}"
|
104
108
|
message.handle(self)
|
105
109
|
else
|
data/test/worker_test.rb
CHANGED
@@ -41,8 +41,10 @@ class WorkerTest < Test::Unit::TestCase
|
|
41
41
|
|
42
42
|
def request_a_file_and_verify_completion(pipe, num_runners)
|
43
43
|
pipe.identify_as_parent
|
44
|
+
pipe.gets # grab the WorkerBegin
|
44
45
|
num_runners.times do
|
45
|
-
|
46
|
+
response = pipe.gets # grab the RequestFile
|
47
|
+
assert response.is_a?(Hydra::Messages::Worker::RequestFile), "Expected RequestFile but got #{response.class.to_s}"
|
46
48
|
end
|
47
49
|
pipe.write(Hydra::Messages::Master::RunFile.new(:file => test_file))
|
48
50
|
|
metadata
CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
segments:
|
6
6
|
- 0
|
7
7
|
- 19
|
8
|
-
-
|
9
|
-
version: 0.19.
|
8
|
+
- 1
|
9
|
+
version: 0.19.1
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Nick Gauthier
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2010-06-
|
17
|
+
date: 2010-06-18 00:00:00 -04:00
|
18
18
|
default_executable:
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
@@ -161,19 +161,19 @@ specification_version: 3
|
|
161
161
|
summary: Distributed testing toolkit
|
162
162
|
test_files:
|
163
163
|
- test/pipe_test.rb
|
164
|
-
- test/
|
164
|
+
- test/sync_test.rb
|
165
165
|
- test/ssh_test.rb
|
166
|
-
- test/message_test.rb
|
167
|
-
- test/master_test.rb
|
168
|
-
- test/fixtures/write_file.rb
|
169
|
-
- test/fixtures/slow.rb
|
170
|
-
- test/fixtures/write_file_with_pending_spec.rb
|
171
|
-
- test/fixtures/write_file_spec.rb
|
172
|
-
- test/fixtures/features/step_definitions.rb
|
173
|
-
- test/fixtures/hello_world.rb
|
174
166
|
- test/fixtures/write_file_alternate_spec.rb
|
175
167
|
- test/fixtures/sync_test.rb
|
168
|
+
- test/fixtures/hello_world.rb
|
169
|
+
- test/fixtures/features/step_definitions.rb
|
176
170
|
- test/fixtures/assert_true.rb
|
171
|
+
- test/fixtures/slow.rb
|
172
|
+
- test/fixtures/write_file_spec.rb
|
173
|
+
- test/fixtures/write_file_with_pending_spec.rb
|
174
|
+
- test/fixtures/write_file.rb
|
175
|
+
- test/message_test.rb
|
176
|
+
- test/test_helper.rb
|
177
|
+
- test/master_test.rb
|
177
178
|
- test/runner_test.rb
|
178
|
-
- test/sync_test.rb
|
179
179
|
- test/worker_test.rb
|