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 CHANGED
@@ -1 +1 @@
1
- 0.19.0
1
+ 0.19.1
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{hydra}
8
- s.version = "0.19.0"
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-07}
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/test_helper.rb",
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
@@ -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
- # Send a file down to a worker.
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
@@ -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
@@ -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
@@ -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
- assert pipe.gets.is_a?(Hydra::Messages::Worker::RequestFile)
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
- - 0
9
- version: 0.19.0
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-07 00:00:00 -04:00
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/test_helper.rb
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