hydra 0.19.0 → 0.19.1

Sign up to get free protection for your applications and to get access to all the features.
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