arturop-hydra 0.23.4

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.
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