hydra 0.18.0 → 0.19.0

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/.gitignore CHANGED
@@ -17,5 +17,6 @@ tmtags
17
17
  coverage
18
18
  rdoc
19
19
  pkg
20
+ tags
20
21
 
21
22
  ## PROJECT::SPECIFIC
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.18.0
1
+ 0.19.0
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{hydra}
8
- s.version = "0.18.0"
8
+ s.version = "0.19.0"
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-05-28}
12
+ s.date = %q{2010-06-07}
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 = [
@@ -51,6 +51,7 @@ Gem::Specification.new do |s|
51
51
  "lib/hydra/spec/hydra_formatter.rb",
52
52
  "lib/hydra/ssh.rb",
53
53
  "lib/hydra/stdio.rb",
54
+ "lib/hydra/sync.rb",
54
55
  "lib/hydra/tasks.rb",
55
56
  "lib/hydra/trace.rb",
56
57
  "lib/hydra/worker.rb",
@@ -73,6 +74,7 @@ Gem::Specification.new do |s|
73
74
  "test/pipe_test.rb",
74
75
  "test/runner_test.rb",
75
76
  "test/ssh_test.rb",
77
+ "test/sync_test.rb",
76
78
  "test/test_helper.rb",
77
79
  "test/worker_test.rb"
78
80
  ]
@@ -83,20 +85,21 @@ Gem::Specification.new do |s|
83
85
  s.summary = %q{Distributed testing toolkit}
84
86
  s.test_files = [
85
87
  "test/pipe_test.rb",
88
+ "test/test_helper.rb",
86
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",
87
98
  "test/fixtures/write_file_alternate_spec.rb",
88
99
  "test/fixtures/sync_test.rb",
89
- "test/fixtures/hello_world.rb",
90
- "test/fixtures/features/step_definitions.rb",
91
100
  "test/fixtures/assert_true.rb",
92
- "test/fixtures/slow.rb",
93
- "test/fixtures/write_file_spec.rb",
94
- "test/fixtures/write_file_with_pending_spec.rb",
95
- "test/fixtures/write_file.rb",
96
- "test/message_test.rb",
97
- "test/test_helper.rb",
98
- "test/master_test.rb",
99
101
  "test/runner_test.rb",
102
+ "test/sync_test.rb",
100
103
  "test/worker_test.rb"
101
104
  ]
102
105
 
@@ -7,6 +7,7 @@ require 'hydra/safe_fork'
7
7
  require 'hydra/runner'
8
8
  require 'hydra/worker'
9
9
  require 'hydra/master'
10
+ require 'hydra/sync'
10
11
  require 'hydra/listener/abstract'
11
12
  require 'hydra/listener/minimal_output'
12
13
  require 'hydra/listener/report_generator'
@@ -1,15 +1,20 @@
1
1
  require 'hydra/hash'
2
2
  require 'open3'
3
3
  require 'tmpdir'
4
+ require 'erb'
4
5
  require 'yaml'
6
+
5
7
  module Hydra #:nodoc:
6
8
  # Hydra class responsible for delegate work down to workers.
7
9
  #
8
10
  # The Master is run once for any given testing session.
11
+ class YmlLoadError < StandardError; end
12
+
9
13
  class Master
10
14
  include Hydra::Messages::Master
11
15
  include Open3
12
16
  traceable('MASTER')
17
+
13
18
  # Create a new Master
14
19
  #
15
20
  # Options:
@@ -28,10 +33,29 @@ module Hydra #:nodoc:
28
33
  # * :autosort
29
34
  # * Set to false to disable automatic sorting by historical run-time per file
30
35
  def initialize(opts = { })
36
+ trap("SIGINT") do
37
+ puts "Testing halted by user. Untested files:"
38
+ puts @incomplete_files.join("\n")
39
+ exit
40
+ end
41
+
31
42
  opts.stringify_keys!
32
43
  config_file = opts.delete('config') { nil }
33
44
  if config_file
34
- opts.merge!(YAML.load_file(config_file).stringify_keys!)
45
+
46
+ begin
47
+ config_erb = ERB.new(IO.read(config_file)).result(binding)
48
+ rescue Exception => e
49
+ raise(YmlLoadError,"config file was found, but could not be parsed with ERB.\n#{$!.inspect}")
50
+ end
51
+
52
+ begin
53
+ config_yml = YAML::load(config_erb)
54
+ rescue StandardError => e
55
+ raise(YmlLoadError,"config file was found, but could not be parsed.\n#{$!.inspect}")
56
+ end
57
+
58
+ opts.merge!(config_yml.stringify_keys!)
35
59
  end
36
60
  @files = Array(opts.fetch('files') { nil })
37
61
  raise "No files, nothing to do" if @files.empty?
@@ -47,6 +71,7 @@ module Hydra #:nodoc:
47
71
  @verbose = opts.fetch('verbose') { false }
48
72
  @autosort = opts.fetch('autosort') { true }
49
73
  @sync = opts.fetch('sync') { nil }
74
+ @environment = opts.fetch('environment') { 'test' }
50
75
 
51
76
  if @autosort
52
77
  sort_files_from_report
@@ -134,39 +159,16 @@ module Hydra #:nodoc:
134
159
  end
135
160
 
136
161
  def boot_ssh_worker(worker)
162
+ sync = Sync.new(worker, @sync, @verbose)
163
+
137
164
  runners = worker.fetch('runners') { raise "You must specify the number of runners" }
138
- connect = worker.fetch('connect') { raise "You must specify an SSH connection target" }
139
- ssh_opts = worker.fetch('ssh_opts') { "" }
140
- directory = worker.fetch('directory') { raise "You must specify a remote directory" }
141
165
  command = worker.fetch('command') {
142
- "ruby -e \"require 'rubygems'; require 'hydra'; Hydra::Worker.new(:io => Hydra::Stdio.new, :runners => #{runners}, :verbose => #{@verbose});\""
166
+ "RAILS_ENV=#{@environment} ruby -e \"require 'rubygems'; require 'hydra'; Hydra::Worker.new(:io => Hydra::Stdio.new, :runners => #{runners}, :verbose => #{@verbose});\""
143
167
  }
144
168
 
145
- if @sync
146
- @sync.stringify_keys!
147
- trace "Synchronizing with #{connect}\n\t#{@sync.inspect}"
148
- local_dir = @sync.fetch('directory') {
149
- raise "You must specify a synchronization directory"
150
- }
151
- exclude_paths = @sync.fetch('exclude') { [] }
152
- exclude_opts = exclude_paths.inject(''){|memo, path| memo += "--exclude=#{path} "}
153
-
154
- rsync_command = [
155
- 'rsync',
156
- '-avz',
157
- '--delete',
158
- exclude_opts,
159
- File.expand_path(local_dir)+'/',
160
- "-e \"ssh #{ssh_opts}\"",
161
- "#{connect}:#{directory}"
162
- ].join(" ")
163
- trace rsync_command
164
- trace `#{rsync_command}`
165
- end
166
-
167
169
  trace "Booting SSH worker"
168
- ssh = Hydra::SSH.new("#{ssh_opts} #{connect}", directory, command)
169
- return { :io => ssh, :idle => false, :type => :ssh }
170
+ ssh = Hydra::SSH.new("#{sync.ssh_opts} #{sync.connect}", sync.remote_dir, command)
171
+ return { :io => ssh, :idle => false, :type => :ssh, :connect => sync.connect }
170
172
  end
171
173
 
172
174
  def shutdown_all_workers
@@ -180,7 +180,7 @@ module Hydra #:nodoc:
180
180
  def run_javascript_file(file)
181
181
  errors = []
182
182
  require 'v8'
183
- V8::Context.open do |context|
183
+ V8::Context.new do |context|
184
184
  context.load(File.expand_path(File.join(File.dirname(__FILE__), 'js', 'lint.js')))
185
185
  context['input'] = lambda{
186
186
  File.read(file)
@@ -27,6 +27,7 @@ module Hydra #:nodoc:
27
27
  # list all the files.
28
28
  def initialize(connection_options, directory, command)
29
29
  @writer, @reader, @error = popen3("ssh -tt #{connection_options}")
30
+ @writer.write("mkdir -p #{directory}\n")
30
31
  @writer.write("cd #{directory}\n")
31
32
  @writer.write(command+"\n")
32
33
  end
@@ -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
@@ -177,6 +177,43 @@ module Hydra #:nodoc:
177
177
  end
178
178
  end
179
179
 
180
+ # Define a sync task that uses hydra to rsync the source tree under test to remote workers.
181
+ #
182
+ # This task is very useful to run before a remote db:reset task to make sure the db/schema.rb
183
+ # file is up to date on the remote workers.
184
+ #
185
+ # Hydra::SyncTask.new('hydra:sync') do |t|
186
+ # t.verbose = false # optionally set to true for lots of debug messages
187
+ # end
188
+ class SyncTask < Hydra::Task
189
+
190
+ # Create a new SyncTestTask
191
+ def initialize(name = :sync)
192
+ @name = name
193
+ @verbose = false
194
+
195
+ yield self if block_given?
196
+
197
+ @config = find_config_file
198
+
199
+ @opts = {
200
+ :verbose => @verbose
201
+ }
202
+ @opts.merge!(:config => @config) if @config
203
+
204
+ define
205
+ end
206
+
207
+ private
208
+ # Create the rake task defined by this HydraSyncTask
209
+ def define
210
+ desc "Hydra Tests" + (@name == :hydra ? "" : " for #{@name}")
211
+ task @name do
212
+ Hydra::Sync.sync_many(@opts)
213
+ end
214
+ end
215
+ end
216
+
180
217
  # Setup a task that will be run across all remote workers
181
218
  # Hydra::RemoteTask.new('db:reset')
182
219
  #
@@ -202,32 +239,59 @@ module Hydra #:nodoc:
202
239
  desc "Run #{@name} remotely on all workers"
203
240
  task "hydra:remote:#{@name}" do
204
241
  config = YAML.load_file(@config)
242
+ environment = config.fetch('environment') { 'test' }
205
243
  workers = config.fetch('workers') { [] }
206
244
  workers = workers.select{|w| w['type'] == 'ssh'}
245
+
246
+ $stdout.write "==== Hydra Running #{@name} ====\n"
247
+ Thread.abort_on_exception = true
248
+ @listeners = []
249
+ @results = {}
207
250
  workers.each do |worker|
208
- $stdout.write "==== Hydra Running #{@name} on #{worker['connect']} ====\n"
209
- ssh_opts = worker.fetch('ssh_opts') { '' }
210
- writer, reader, error = popen3("ssh -tt #{ssh_opts} #{worker['connect']} ")
211
- writer.write("cd #{worker['directory']}\n")
212
- writer.write "echo BEGIN HYDRA\n"
213
- writer.write("RAILS_ENV=test rake #{@name}\n")
214
- writer.write "echo END HYDRA\n"
215
- writer.write("exit\n")
216
- writer.close
217
- ignoring = true
218
- while line = reader.gets
219
- line.chomp!
220
- if line =~ /echo END HYDRA$/
221
- ignoring = true
222
- end
223
- $stdout.write "#{line}\n" unless ignoring
224
- if line == 'BEGIN HYDRA'
225
- ignoring = false
251
+ @listeners << Thread.new do
252
+ begin
253
+ @results[worker] = if run_task(worker, environment)
254
+ "==== #{@name} passed on #{worker['connect']} ====\n"
255
+ else
256
+ "==== #{@name} failed on #{worker['connect']} ====\nPlease see above for more details.\n"
257
+ end
258
+ rescue
259
+ @results[worker] = "==== #{@name} failed for #{worker['connect']} ====\n#{$!.inspect}\n#{$!.backtrace.join("\n")}"
226
260
  end
227
261
  end
228
- $stdout.write "\n==== Hydra Running #{@name} COMPLETE ====\n\n"
262
+ end
263
+ @listeners.each{|l| l.join}
264
+ $stdout.write "\n==== Hydra Running #{@name} COMPLETE ====\n\n"
265
+ $stdout.write @results.values.join("\n")
266
+ end
267
+ end
268
+
269
+ def run_task worker, environment
270
+ $stdout.write "==== Hydra Running #{@name} on #{worker['connect']} ====\n"
271
+ ssh_opts = worker.fetch('ssh_opts') { '' }
272
+ writer, reader, error = popen3("ssh -tt #{ssh_opts} #{worker['connect']} ")
273
+ writer.write("cd #{worker['directory']}\n")
274
+ writer.write "echo BEGIN HYDRA\n"
275
+ writer.write("RAILS_ENV=#{environment} rake #{@name}\n")
276
+ writer.write "echo END HYDRA\n"
277
+ writer.write("exit\n")
278
+ writer.close
279
+ ignoring = true
280
+ passed = true
281
+ while line = reader.gets
282
+ line.chomp!
283
+ if line =~ /^rake aborted!$/
284
+ passed = false
285
+ end
286
+ if line =~ /echo END HYDRA$/
287
+ ignoring = true
288
+ end
289
+ $stdout.write "#{worker['connect']}: #{line}\n" unless ignoring
290
+ if line == 'BEGIN HYDRA'
291
+ ignoring = false
229
292
  end
230
293
  end
294
+ passed
231
295
  end
232
296
  end
233
297
 
@@ -0,0 +1,113 @@
1
+ require File.join(File.dirname(__FILE__), 'test_helper')
2
+
3
+ class SyncTest < Test::Unit::TestCase
4
+ context "with a file to test and a destination to verify" do
5
+ setup do
6
+ # avoid having other tests interfering with us
7
+ sleep(0.2)
8
+ #FileUtils.rm_f(target_file)
9
+ end
10
+
11
+ teardown do
12
+ #FileUtils.rm_f(target_file)
13
+ end
14
+
15
+ should "synchronize a test file over ssh with rsync" do
16
+ local = File.join(Dir.tmpdir, 'hydra', 'local')
17
+ remote = File.join(Dir.tmpdir, 'hydra', 'remote')
18
+ sync_test = File.join(File.dirname(__FILE__), 'fixtures', 'sync_test.rb')
19
+ [local, remote].each{|f| FileUtils.rm_rf f; FileUtils.mkdir_p f}
20
+
21
+ # setup the folders:
22
+ # local:
23
+ # - test_a
24
+ # - test_c
25
+ # remote:
26
+ # - test_b
27
+ #
28
+ # add test_c to exludes
29
+ FileUtils.cp(sync_test, File.join(local, 'test_a.rb'))
30
+ FileUtils.cp(sync_test, File.join(local, 'test_c.rb'))
31
+ FileUtils.cp(sync_test, File.join(remote, 'test_b.rb'))
32
+
33
+ # ensure a is not on remote
34
+ assert !File.exists?(File.join(remote, 'test_a.rb')), "A should not be on remote"
35
+ # ensure c is not on remote
36
+ assert !File.exists?(File.join(remote, 'test_c.rb')), "C should not be on remote"
37
+ # ensure b is on remote
38
+ assert File.exists?(File.join(remote, 'test_b.rb')), "B should be on remote"
39
+
40
+ Hydra::Sync.new(
41
+ {
42
+ :type => :ssh,
43
+ :connect => 'localhost',
44
+ :directory => remote,
45
+ :runners => 1
46
+ },
47
+ {
48
+ :directory => local,
49
+ :exclude => ['test_c.rb']
50
+ }
51
+ )
52
+ # ensure a is copied
53
+ assert File.exists?(File.join(remote, 'test_a.rb')), "A was not copied"
54
+ # ensure c is not copied
55
+ assert !File.exists?(File.join(remote, 'test_c.rb')), "C was copied, should be excluded"
56
+ # ensure b is deleted
57
+ assert !File.exists?(File.join(remote, 'test_b.rb')), "B was not deleted"
58
+ end
59
+
60
+ should "synchronize a test file over ssh with rsync to multiple workers" do
61
+ local = File.join(Dir.tmpdir, 'hydra', 'local')
62
+ remote_a = File.join(Dir.tmpdir, 'hydra', 'remote_a')
63
+ remote_b = File.join(Dir.tmpdir, 'hydra', 'remote_b')
64
+ sync_test = File.join(File.dirname(__FILE__), 'fixtures', 'sync_test.rb')
65
+ [local, remote_a, remote_b].each{|f| FileUtils.rm_rf f; FileUtils.mkdir_p f}
66
+
67
+ # setup the folders:
68
+ # local:
69
+ # - test_a
70
+ # remote_a:
71
+ # - test_b
72
+ # remote_b:
73
+ # - test_c
74
+ #
75
+ # add test_c to exludes
76
+ FileUtils.cp(sync_test, File.join(local, 'test_a.rb'))
77
+ FileUtils.cp(sync_test, File.join(remote_a, 'test_b.rb'))
78
+ FileUtils.cp(sync_test, File.join(remote_b, 'test_c.rb'))
79
+
80
+ # ensure a is not on remotes
81
+ assert !File.exists?(File.join(remote_a, 'test_a.rb')), "A should not be on remote_a"
82
+ assert !File.exists?(File.join(remote_b, 'test_a.rb')), "A should not be on remote_b"
83
+ # ensure b is on remote_a
84
+ assert File.exists?(File.join(remote_a, 'test_b.rb')), "B should be on remote_a"
85
+ # ensure c is on remote_b
86
+ assert File.exists?(File.join(remote_b, 'test_c.rb')), "C should be on remote_b"
87
+
88
+ Hydra::Sync.sync_many(
89
+ :workers => [{
90
+ :type => :ssh,
91
+ :connect => 'localhost',
92
+ :directory => remote_a,
93
+ :runners => 1
94
+ },
95
+ {
96
+ :type => :ssh,
97
+ :connect => 'localhost',
98
+ :directory => remote_b,
99
+ :runners => 1
100
+ }],
101
+ :sync => {
102
+ :directory => local
103
+ }
104
+ )
105
+ # ensure a is copied to both remotes
106
+ assert File.exists?(File.join(remote_a, 'test_a.rb')), "A was not copied to remote_a"
107
+ assert File.exists?(File.join(remote_b, 'test_a.rb')), "A was not copied to remote_b"
108
+ # ensure b and c are deleted from remotes
109
+ assert !File.exists?(File.join(remote_a, 'test_b.rb')), "B was not deleted from remote_a"
110
+ assert !File.exists?(File.join(remote_b, 'test_c.rb')), "C was not deleted from remote_b"
111
+ end
112
+ end
113
+ end
metadata CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
4
4
  prerelease: false
5
5
  segments:
6
6
  - 0
7
- - 18
7
+ - 19
8
8
  - 0
9
- version: 0.18.0
9
+ version: 0.19.0
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-05-28 00:00:00 -04:00
17
+ date: 2010-06-07 00:00:00 -04:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
@@ -103,6 +103,7 @@ files:
103
103
  - lib/hydra/spec/hydra_formatter.rb
104
104
  - lib/hydra/ssh.rb
105
105
  - lib/hydra/stdio.rb
106
+ - lib/hydra/sync.rb
106
107
  - lib/hydra/tasks.rb
107
108
  - lib/hydra/trace.rb
108
109
  - lib/hydra/worker.rb
@@ -125,6 +126,7 @@ files:
125
126
  - test/pipe_test.rb
126
127
  - test/runner_test.rb
127
128
  - test/ssh_test.rb
129
+ - test/sync_test.rb
128
130
  - test/test_helper.rb
129
131
  - test/worker_test.rb
130
132
  has_rdoc: true
@@ -159,18 +161,19 @@ specification_version: 3
159
161
  summary: Distributed testing toolkit
160
162
  test_files:
161
163
  - test/pipe_test.rb
164
+ - test/test_helper.rb
162
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
163
174
  - test/fixtures/write_file_alternate_spec.rb
164
175
  - test/fixtures/sync_test.rb
165
- - test/fixtures/hello_world.rb
166
- - test/fixtures/features/step_definitions.rb
167
176
  - test/fixtures/assert_true.rb
168
- - test/fixtures/slow.rb
169
- - test/fixtures/write_file_spec.rb
170
- - test/fixtures/write_file_with_pending_spec.rb
171
- - test/fixtures/write_file.rb
172
- - test/message_test.rb
173
- - test/test_helper.rb
174
- - test/master_test.rb
175
177
  - test/runner_test.rb
178
+ - test/sync_test.rb
176
179
  - test/worker_test.rb