arturop-hydra 0.23.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (68) hide show
  1. data/.document +5 -0
  2. data/LICENSE +20 -0
  3. data/README.rdoc +39 -0
  4. data/Rakefile +56 -0
  5. data/TODO +18 -0
  6. data/VERSION +1 -0
  7. data/caliper.yml +6 -0
  8. data/hydra-icon-64x64.png +0 -0
  9. data/hydra.gemspec +131 -0
  10. data/hydra_gray.png +0 -0
  11. data/lib/hydra.rb +16 -0
  12. data/lib/hydra/cucumber/formatter.rb +29 -0
  13. data/lib/hydra/hash.rb +16 -0
  14. data/lib/hydra/js/lint.js +5150 -0
  15. data/lib/hydra/listener/abstract.rb +39 -0
  16. data/lib/hydra/listener/minimal_output.rb +24 -0
  17. data/lib/hydra/listener/notifier.rb +17 -0
  18. data/lib/hydra/listener/progress_bar.rb +48 -0
  19. data/lib/hydra/listener/report_generator.rb +30 -0
  20. data/lib/hydra/master.rb +247 -0
  21. data/lib/hydra/message.rb +47 -0
  22. data/lib/hydra/message/master_messages.rb +19 -0
  23. data/lib/hydra/message/runner_messages.rb +46 -0
  24. data/lib/hydra/message/worker_messages.rb +52 -0
  25. data/lib/hydra/messaging_io.rb +49 -0
  26. data/lib/hydra/pipe.rb +61 -0
  27. data/lib/hydra/runner.rb +306 -0
  28. data/lib/hydra/runner_listener/abstract.rb +23 -0
  29. data/lib/hydra/safe_fork.rb +31 -0
  30. data/lib/hydra/spec/autorun_override.rb +3 -0
  31. data/lib/hydra/spec/hydra_formatter.rb +26 -0
  32. data/lib/hydra/ssh.rb +41 -0
  33. data/lib/hydra/stdio.rb +16 -0
  34. data/lib/hydra/sync.rb +99 -0
  35. data/lib/hydra/tasks.rb +366 -0
  36. data/lib/hydra/tmpdir.rb +11 -0
  37. data/lib/hydra/trace.rb +24 -0
  38. data/lib/hydra/worker.rb +168 -0
  39. data/test/fixtures/assert_true.rb +7 -0
  40. data/test/fixtures/config.yml +4 -0
  41. data/test/fixtures/conflicting.rb +10 -0
  42. data/test/fixtures/features/step_definitions.rb +21 -0
  43. data/test/fixtures/features/write_alternate_file.feature +7 -0
  44. data/test/fixtures/features/write_file.feature +7 -0
  45. data/test/fixtures/hello_world.rb +3 -0
  46. data/test/fixtures/hydra_worker_init.rb +2 -0
  47. data/test/fixtures/js_file.js +4 -0
  48. data/test/fixtures/json_data.json +4 -0
  49. data/test/fixtures/many_outputs_to_console.rb +9 -0
  50. data/test/fixtures/master_listeners.rb +10 -0
  51. data/test/fixtures/runner_listeners.rb +23 -0
  52. data/test/fixtures/slow.rb +9 -0
  53. data/test/fixtures/sync_test.rb +8 -0
  54. data/test/fixtures/task_test_config.yml +6 -0
  55. data/test/fixtures/write_file.rb +10 -0
  56. data/test/fixtures/write_file_alternate_spec.rb +10 -0
  57. data/test/fixtures/write_file_spec.rb +9 -0
  58. data/test/fixtures/write_file_with_pending_spec.rb +11 -0
  59. data/test/master_test.rb +383 -0
  60. data/test/message_test.rb +31 -0
  61. data/test/pipe_test.rb +38 -0
  62. data/test/runner_test.rb +196 -0
  63. data/test/ssh_test.rb +25 -0
  64. data/test/sync_test.rb +113 -0
  65. data/test/task_test.rb +21 -0
  66. data/test/test_helper.rb +107 -0
  67. data/test/worker_test.rb +60 -0
  68. metadata +202 -0
@@ -0,0 +1,23 @@
1
+ module Hydra #:nodoc:
2
+ module RunnerListener #:nodoc:
3
+ # Abstract listener that implements all the events
4
+ # but does nothing.
5
+ class Abstract
6
+ # Create a new listener.
7
+ #
8
+ # Output: The IO object for outputting any information.
9
+ # Defaults to STDOUT, but you could pass a file in, or STDERR
10
+ def initialize(output = $stdout)
11
+ @output = output
12
+ end
13
+
14
+ # Fired by the runner just before requesting the first file
15
+ def runner_begin( runner )
16
+ end
17
+
18
+ # Fired by the runner just after stoping
19
+ def runner_end( runner )
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,31 @@
1
+ class SafeFork
2
+ def self.fork
3
+ begin
4
+ # remove our connection so it doesn't get cloned
5
+ connection = ActiveRecord::Base.remove_connection if defined?(ActiveRecord)
6
+ # fork a process
7
+ child = Process.fork do
8
+ begin
9
+ # create a new connection and perform the action
10
+ begin
11
+ ActiveRecord::Base.establish_connection((connection || {}).merge({:allow_concurrency => true})) if defined?(ActiveRecord)
12
+ rescue ActiveRecord::AdapterNotSpecified
13
+ # AR was defined but we didn't have a connection
14
+ end
15
+ yield
16
+ ensure
17
+ # make sure we remove the connection before we're done
18
+ ActiveRecord::Base.remove_connection if defined?(ActiveRecord)
19
+ end
20
+ end
21
+ ensure
22
+ # make sure we re-establish the connection before returning to the main instance
23
+ begin
24
+ ActiveRecord::Base.establish_connection((connection || {}).merge({:allow_concurrency => true})) if defined?(ActiveRecord)
25
+ rescue ActiveRecord::AdapterNotSpecified
26
+ # AR was defined but we didn't have a connection
27
+ end
28
+ end
29
+ return child
30
+ end
31
+ end
@@ -0,0 +1,3 @@
1
+ if defined?(RSpec)
2
+ RSpec::Core::Runner.disable_autorun!
3
+ end
@@ -0,0 +1,26 @@
1
+ require 'rspec/core/formatters/progress_formatter'
2
+ module RSpec
3
+ module Core
4
+ module Formatters
5
+ class HydraFormatter < ProgressFormatter
6
+ def example_passed(example)
7
+ end
8
+
9
+ def example_pending(example)
10
+ end
11
+
12
+ def example_failed(example)
13
+ end
14
+
15
+ # Stifle the post-test summary
16
+ def dump_summary(duration, example, failure, pending)
17
+ end
18
+
19
+ # Stifle pending specs
20
+ def dump_pending
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
26
+
data/lib/hydra/ssh.rb ADDED
@@ -0,0 +1,41 @@
1
+ require 'open3'
2
+ require 'hydra/messaging_io'
3
+ module Hydra #:nodoc:
4
+ # Read and write with an ssh connection. For example:
5
+ # @ssh = Hydra::SSH.new(
6
+ # 'localhost', # connect to this machine
7
+ # '/home/user', # move to the home directory
8
+ # "ruby hydra/test/echo_the_dolphin.rb" # run the echo script
9
+ # )
10
+ # @message = Hydra::Messages::TestMessage.new("Hey there!")
11
+ # @ssh.write @message
12
+ # puts @ssh.gets.text
13
+ # => "Hey there!"
14
+ #
15
+ # Note that what ever process you run should respond with Hydra messages.
16
+ class SSH
17
+ include Open3
18
+ include Hydra::MessagingIO
19
+
20
+ # Initialize new SSH connection.
21
+ # The first parameter is passed directly to ssh for starting a connection.
22
+ # The second parameter is the directory to CD into once connected.
23
+ # The third parameter is the command to run
24
+ # So you can do:
25
+ # Hydra::SSH.new('-p 3022 user@server.com', '/home/user/Desktop', 'ls -l')
26
+ # To connect to server.com as user on port 3022, then CD to their desktop, then
27
+ # list all the files.
28
+ def initialize(connection_options, directory, command)
29
+ @writer, @reader, @error = popen3("ssh -tt #{connection_options}")
30
+ @writer.write("mkdir -p #{directory}\n")
31
+ @writer.write("cd #{directory}\n")
32
+ @writer.write(command+"\n")
33
+ end
34
+
35
+ # Close the SSH connection
36
+ def close
37
+ @writer.write "exit\n"
38
+ super
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,16 @@
1
+ require 'hydra/messaging_io'
2
+ module Hydra #:nodoc:
3
+ # Read and write via stdout and stdin.
4
+ class Stdio
5
+ include Hydra::MessagingIO
6
+
7
+ # Initialize new Stdio
8
+ def initialize()
9
+ @reader = $stdin
10
+ @writer = $stdout
11
+ @reader.sync = true
12
+ @writer.sync = true
13
+ end
14
+ end
15
+ end
16
+
data/lib/hydra/sync.rb ADDED
@@ -0,0 +1,99 @@
1
+ require 'yaml'
2
+ module Hydra #:nodoc:
3
+ # Hydra class responsible for delegate work down to workers.
4
+ #
5
+ # The Sync is run once for each remote worker.
6
+ class Sync
7
+ traceable('SYNC')
8
+ self.class.traceable('SYNC MANY')
9
+
10
+ attr_reader :connect, :ssh_opts, :remote_dir
11
+
12
+ # Create a new Sync instance to rsync source from the local machine to a remote worker
13
+ #
14
+ # Arguments:
15
+ # * :worker_opts
16
+ # * A hash of the configuration options for a worker.
17
+ # * :sync
18
+ # * A hash of settings specifically for copying the source directory to be tested
19
+ # to the remote worked
20
+ # * :verbose
21
+ # * Set to true to see lots of Hydra output (for debugging)
22
+ def initialize(worker_opts, sync_opts, verbose = false)
23
+ worker_opts ||= {}
24
+ worker_opts.stringify_keys!
25
+ @verbose = verbose
26
+ @connect = worker_opts.fetch('connect') { raise "You must specify an SSH connection target" }
27
+ @ssh_opts = worker_opts.fetch('ssh_opts') { "" }
28
+ @remote_dir = worker_opts.fetch('directory') { raise "You must specify a remote directory" }
29
+
30
+ return unless sync_opts
31
+ sync_opts.stringify_keys!
32
+ @local_dir = sync_opts.fetch('directory') { raise "You must specify a synchronization directory" }
33
+ @exclude_paths = sync_opts.fetch('exclude') { [] }
34
+
35
+ trace "Initialized"
36
+ trace " Worker: (#{worker_opts.inspect})"
37
+ trace " Sync: (#{sync_opts.inspect})"
38
+
39
+ sync
40
+ end
41
+
42
+ def sync
43
+ #trace "Synchronizing with #{connect}\n\t#{sync_opts.inspect}"
44
+ exclude_opts = @exclude_paths.inject(''){|memo, path| memo += "--exclude=#{path} "}
45
+
46
+ rsync_command = [
47
+ 'rsync',
48
+ '-avz',
49
+ '--delete',
50
+ exclude_opts,
51
+ File.expand_path(@local_dir)+'/',
52
+ "-e \"ssh #{@ssh_opts}\"",
53
+ "#{@connect}:#{@remote_dir}"
54
+ ].join(" ")
55
+ trace rsync_command
56
+ trace `#{rsync_command}`
57
+ end
58
+
59
+ def self.sync_many opts
60
+ opts.stringify_keys!
61
+ config_file = opts.delete('config') { nil }
62
+ if config_file
63
+ opts.merge!(YAML.load_file(config_file).stringify_keys!)
64
+ end
65
+ @verbose = opts.fetch('verbose') { false }
66
+ @sync = opts.fetch('sync') { {} }
67
+
68
+ workers_opts = opts.fetch('workers') { [] }
69
+ @remote_worker_opts = []
70
+ workers_opts.each do |worker_opts|
71
+ worker_opts.stringify_keys!
72
+ if worker_opts['type'].to_s == 'ssh'
73
+ @remote_worker_opts << worker_opts
74
+ end
75
+ end
76
+
77
+ trace "Initialized"
78
+ trace " Sync: (#{@sync.inspect})"
79
+ trace " Workers: (#{@remote_worker_opts.inspect})"
80
+
81
+ Thread.abort_on_exception = true
82
+ trace "Processing workers"
83
+ @listeners = []
84
+ @remote_worker_opts.each do |worker_opts|
85
+ @listeners << Thread.new do
86
+ begin
87
+ trace "Syncing #{worker_opts.inspect}"
88
+ Sync.new worker_opts, @sync, @verbose
89
+ rescue
90
+ trace "Syncing failed [#{worker_opts.inspect}]"
91
+ end
92
+ end
93
+ end
94
+
95
+ @listeners.each{|l| l.join}
96
+ end
97
+
98
+ end
99
+ end
@@ -0,0 +1,366 @@
1
+ require 'open3'
2
+ module Hydra #:nodoc:
3
+ # Hydra Task Common attributes and methods
4
+ class Task
5
+ # Name of the task. Default 'hydra'
6
+ attr_accessor :name
7
+
8
+ # Files to test.
9
+ # You can add files manually via:
10
+ # t.files << [file1, file2, etc]
11
+ #
12
+ # Or you can use the add_files method
13
+ attr_accessor :files
14
+
15
+ # True if you want to see Hydra's message traces
16
+ attr_accessor :verbose
17
+
18
+ # Path to the hydra config file.
19
+ # If not set, it will check 'hydra.yml' and 'config/hydra.yml'
20
+ attr_accessor :config
21
+
22
+ # Automatically sort files using their historical runtimes.
23
+ # Defaults to true
24
+ # To disable:
25
+ # t.autosort = false
26
+ attr_accessor :autosort
27
+
28
+ # Event listeners. Defaults to the MinimalOutput listener.
29
+ # You can add additional listeners if you'd like. For example,
30
+ # on linux (with notify-send) you can add the notifier listener:
31
+ # t.listeners << Hydra::Listener::Notifier.new
32
+ attr_accessor :listeners
33
+
34
+ # Set to true if you want to run this task only on the local
35
+ # machine with one runner. A "Safe Mode" for some test
36
+ # files that may not play nice with others.
37
+ attr_accessor :serial
38
+
39
+ attr_accessor :environment
40
+
41
+ # Set to false if you don't want to show the total running time
42
+ attr_accessor :show_time
43
+
44
+ # Set to a valid file path if you want to save the output of the runners
45
+ # in a log file
46
+ attr_accessor :runner_log_file
47
+
48
+ #
49
+ # Search for the hydra config file
50
+ def find_config_file
51
+ @config ||= 'hydra.yml'
52
+ return @config if File.exists?(@config)
53
+ @config = File.join('config', 'hydra.yml')
54
+ return @config if File.exists?(@config)
55
+ @config = nil
56
+ end
57
+
58
+ # Add files to test by passing in a string to be run through Dir.glob.
59
+ # For example:
60
+ #
61
+ # t.add_files 'test/units/*.rb'
62
+ def add_files(pattern)
63
+ @files += Dir.glob(pattern)
64
+ end
65
+
66
+ end
67
+
68
+ # Define a test task that uses hydra to test the files.
69
+ #
70
+ # Hydra::TestTask.new('hydra') do |t|
71
+ # t.add_files 'test/unit/**/*_test.rb'
72
+ # t.add_files 'test/functional/**/*_test.rb'
73
+ # t.add_files 'test/integration/**/*_test.rb'
74
+ # t.verbose = false # optionally set to true for lots of debug messages
75
+ # t.autosort = false # disable automatic sorting based on runtime of tests
76
+ # end
77
+ class TestTask < Hydra::Task
78
+
79
+ # Create a new HydraTestTask
80
+ def initialize(name = :hydra)
81
+ @name = name
82
+ @files = []
83
+ @verbose = false
84
+ @autosort = true
85
+ @serial = false
86
+ @listeners = [Hydra::Listener::ProgressBar.new]
87
+ @show_time = true
88
+
89
+ yield self if block_given?
90
+
91
+ # Ensure we override rspec's at_exit
92
+ if defined?(RSpec)
93
+ RSpec::Core::Runner.disable_autorun!
94
+ end
95
+
96
+ unless @serial
97
+ @config = find_config_file
98
+ end
99
+
100
+ @opts = {
101
+ :verbose => @verbose,
102
+ :autosort => @autosort,
103
+ :files => @files,
104
+ :listeners => @listeners,
105
+ :environment => @environment,
106
+ :runner_log_file => @runner_log_file
107
+ }
108
+ if @config
109
+ @opts.merge!(:config => @config)
110
+ else
111
+ @opts.merge!(:workers => [{:type => :local, :runners => 1}])
112
+ end
113
+
114
+ define
115
+ end
116
+
117
+ private
118
+ # Create the rake task defined by this HydraTestTask
119
+ def define
120
+ desc "Hydra Tests" + (@name == :hydra ? "" : " for #{@name}")
121
+ task @name do
122
+ if Object.const_defined?('Rails') && Rails.env == 'development'
123
+ $stderr.puts %{WARNING: Rails Environment is "development". Make sure to set it properly (ex: "RAILS_ENV=test rake hydra")}
124
+ end
125
+
126
+ start = Time.now if @show_time
127
+
128
+ master = Hydra::Master.new(@opts)
129
+
130
+ $stdout.puts "\nFinished in #{'%.6f' % (Time.now - start)} seconds." if @show_time
131
+
132
+ unless master.failed_files.empty?
133
+ raise "Hydra: Not all tests passes"
134
+ end
135
+ end
136
+ end
137
+ end
138
+
139
+ # Define a test task that uses hydra to profile your test files
140
+ #
141
+ # Hydra::ProfileTask.new('hydra:prof') do |t|
142
+ # t.add_files 'test/unit/**/*_test.rb'
143
+ # t.add_files 'test/functional/**/*_test.rb'
144
+ # t.add_files 'test/integration/**/*_test.rb'
145
+ # t.generate_html = true # defaults to false
146
+ # t.generate_text = true # defaults to true
147
+ # end
148
+ class ProfileTask < Hydra::Task
149
+ # boolean: generate html output from ruby-prof
150
+ attr_accessor :generate_html
151
+ # boolean: generate text output from ruby-prof
152
+ attr_accessor :generate_text
153
+
154
+ # Create a new Hydra ProfileTask
155
+ def initialize(name = 'hydra:profile')
156
+ @name = name
157
+ @files = []
158
+ @verbose = false
159
+ @generate_html = false
160
+ @generate_text = true
161
+
162
+ yield self if block_given?
163
+
164
+ # Ensure we override rspec's at_exit
165
+ require 'hydra/spec/autorun_override'
166
+
167
+ @config = find_config_file
168
+
169
+ @opts = {
170
+ :verbose => @verbose,
171
+ :files => @files
172
+ }
173
+ define
174
+ end
175
+
176
+ private
177
+ # Create the rake task defined by this HydraTestTask
178
+ def define
179
+ desc "Hydra Test Profile" + (@name == :hydra ? "" : " for #{@name}")
180
+ task @name do
181
+ require 'ruby-prof'
182
+ RubyProf.start
183
+
184
+ runner = Hydra::Runner.new(:io => File.new('/dev/null', 'w'))
185
+ @files.each do |file|
186
+ $stdout.write runner.run_file(file)
187
+ $stdout.flush
188
+ end
189
+
190
+ $stdout.write "\nTests complete. Generating profiling output\n"
191
+ $stdout.flush
192
+
193
+ result = RubyProf.stop
194
+
195
+ if @generate_html
196
+ printer = RubyProf::GraphHtmlPrinter.new(result)
197
+ out = File.new("ruby-prof.html", 'w')
198
+ printer.print(out, :min_self => 0.05)
199
+ out.close
200
+ $stdout.write "Profiling data written to [ruby-prof.html]\n"
201
+ end
202
+
203
+ if @generate_text
204
+ printer = RubyProf::FlatPrinter.new(result)
205
+ out = File.new("ruby-prof.txt", 'w')
206
+ printer.print(out, :min_self => 0.05)
207
+ out.close
208
+ $stdout.write "Profiling data written to [ruby-prof.txt]\n"
209
+ end
210
+ end
211
+ end
212
+ end
213
+
214
+ # Define a sync task that uses hydra to rsync the source tree under test to remote workers.
215
+ #
216
+ # This task is very useful to run before a remote db:reset task to make sure the db/schema.rb
217
+ # file is up to date on the remote workers.
218
+ #
219
+ # Hydra::SyncTask.new('hydra:sync') do |t|
220
+ # t.verbose = false # optionally set to true for lots of debug messages
221
+ # end
222
+ class SyncTask < Hydra::Task
223
+
224
+ # Create a new SyncTestTask
225
+ def initialize(name = :sync)
226
+ @name = name
227
+ @verbose = false
228
+
229
+ yield self if block_given?
230
+
231
+ @config = find_config_file
232
+
233
+ @opts = {
234
+ :verbose => @verbose
235
+ }
236
+ @opts.merge!(:config => @config) if @config
237
+
238
+ define
239
+ end
240
+
241
+ private
242
+ # Create the rake task defined by this HydraSyncTask
243
+ def define
244
+ desc "Hydra Tests" + (@name == :hydra ? "" : " for #{@name}")
245
+ task @name do
246
+ Hydra::Sync.sync_many(@opts)
247
+ end
248
+ end
249
+ end
250
+
251
+ # Setup a task that will be run across all remote workers
252
+ # Hydra::RemoteTask.new('db:reset')
253
+ #
254
+ # Then you can run:
255
+ # rake hydra:remote:db:reset
256
+ class RemoteTask < Hydra::Task
257
+ include Open3
258
+ # Create a new hydra remote task with the given name.
259
+ # The task will be named hydra:remote:<name>
260
+ def initialize(name, command=nil)
261
+ @name = name
262
+ @command = command
263
+ yield self if block_given?
264
+ @config = find_config_file
265
+ if @config
266
+ define
267
+ else
268
+ task "hydra:remote:#{@name}" do ; end
269
+ end
270
+ end
271
+
272
+ private
273
+ def define
274
+ desc "Run #{@name} remotely on all workers"
275
+ task "hydra:remote:#{@name}" do
276
+ config = YAML.load_file(@config)
277
+ environment = config.fetch('environment') { 'test' }
278
+ workers = config.fetch('workers') { [] }
279
+ workers = workers.select{|w| w['type'] == 'ssh'}
280
+ @command = "RAILS_ENV=#{environment} rake #{@name}" unless @command
281
+
282
+ $stdout.write "==== Hydra Running #{@name} ====\n"
283
+ Thread.abort_on_exception = true
284
+ @listeners = []
285
+ @results = {}
286
+ workers.each do |worker|
287
+ @listeners << Thread.new do
288
+ begin
289
+ @results[worker] = if run_command(worker, @command)
290
+ "==== #{@name} passed on #{worker['connect']} ====\n"
291
+ else
292
+ "==== #{@name} failed on #{worker['connect']} ====\nPlease see above for more details.\n"
293
+ end
294
+ rescue
295
+ @results[worker] = "==== #{@name} failed for #{worker['connect']} ====\n#{$!.inspect}\n#{$!.backtrace.join("\n")}"
296
+ end
297
+ end
298
+ end
299
+ @listeners.each{|l| l.join}
300
+ $stdout.write "\n==== Hydra Running #{@name} COMPLETE ====\n\n"
301
+ $stdout.write @results.values.join("\n")
302
+ end
303
+ end
304
+
305
+ def run_command worker, command
306
+ $stdout.write "==== Hydra Running #{@name} on #{worker['connect']} ====\n"
307
+ ssh_opts = worker.fetch('ssh_opts') { '' }
308
+ writer, reader, error = popen3("ssh -tt #{ssh_opts} #{worker['connect']} ")
309
+ writer.write("cd #{worker['directory']}\n")
310
+ writer.write "echo BEGIN HYDRA\n"
311
+ writer.write(command + "\r")
312
+ writer.write "echo END HYDRA\n"
313
+ writer.write("exit\n")
314
+ writer.close
315
+ ignoring = true
316
+ passed = true
317
+ while line = reader.gets
318
+ line.chomp!
319
+ if line =~ /^rake aborted!$/
320
+ passed = false
321
+ end
322
+ if line =~ /echo END HYDRA$/
323
+ ignoring = true
324
+ end
325
+ $stdout.write "#{worker['connect']}: #{line}\n" unless ignoring
326
+ if line == 'BEGIN HYDRA'
327
+ ignoring = false
328
+ end
329
+ end
330
+ passed
331
+ end
332
+ end
333
+
334
+ # A Hydra global task is a task that is run both locally and remotely.
335
+ #
336
+ # For example:
337
+ #
338
+ # Hydra::GlobalTask.new('db:reset')
339
+ #
340
+ # Allows you to run:
341
+ #
342
+ # rake hydra:db:reset
343
+ #
344
+ # Then, db:reset will be run locally and on all remote workers. This
345
+ # makes it easy to setup your workers and run tasks all in a row.
346
+ #
347
+ # For example:
348
+ #
349
+ # rake hydra:db:reset hydra:factories hydra:tests
350
+ #
351
+ # Assuming you setup hydra:db:reset and hydra:db:factories as global
352
+ # tasks and hydra:tests as a Hydra::TestTask for all your tests
353
+ class GlobalTask < Hydra::Task
354
+ def initialize(name)
355
+ @name = name
356
+ define
357
+ end
358
+
359
+ private
360
+ def define
361
+ Hydra::RemoteTask.new(@name)
362
+ desc "Run #{@name.to_s} Locally and Remotely across all Workers"
363
+ task "hydra:#{@name.to_s}" => [@name.to_s, "hydra:remote:#{@name.to_s}"]
364
+ end
365
+ end
366
+ end