nulogy-hydra 0.23.2.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/.document +5 -0
- data/LICENSE +20 -0
- data/README.rdoc +39 -0
- data/Rakefile +56 -0
- data/TODO +18 -0
- data/VERSION +1 -0
- data/caliper.yml +6 -0
- data/hydra-icon-64x64.png +0 -0
- data/hydra.gemspec +131 -0
- data/hydra_gray.png +0 -0
- data/lib/hydra/cucumber/formatter.rb +29 -0
- data/lib/hydra/hash.rb +16 -0
- data/lib/hydra/js/lint.js +5150 -0
- data/lib/hydra/listener/abstract.rb +39 -0
- data/lib/hydra/listener/minimal_output.rb +24 -0
- data/lib/hydra/listener/notifier.rb +17 -0
- data/lib/hydra/listener/progress_bar.rb +48 -0
- data/lib/hydra/listener/report_generator.rb +31 -0
- data/lib/hydra/master.rb +252 -0
- data/lib/hydra/message/master_messages.rb +19 -0
- data/lib/hydra/message/runner_messages.rb +46 -0
- data/lib/hydra/message/worker_messages.rb +52 -0
- data/lib/hydra/message.rb +47 -0
- data/lib/hydra/messaging_io.rb +49 -0
- data/lib/hydra/pipe.rb +61 -0
- data/lib/hydra/proxy_config.rb +27 -0
- data/lib/hydra/runner.rb +306 -0
- data/lib/hydra/runner_listener/abstract.rb +23 -0
- data/lib/hydra/safe_fork.rb +31 -0
- data/lib/hydra/spec/autorun_override.rb +3 -0
- data/lib/hydra/spec/hydra_formatter.rb +26 -0
- data/lib/hydra/ssh.rb +41 -0
- data/lib/hydra/stdio.rb +16 -0
- data/lib/hydra/sync.rb +99 -0
- data/lib/hydra/tasks.rb +366 -0
- data/lib/hydra/threadsafe_io.rb +18 -0
- data/lib/hydra/tmpdir.rb +11 -0
- data/lib/hydra/trace.rb +29 -0
- data/lib/hydra/worker.rb +168 -0
- data/lib/hydra.rb +16 -0
- data/nulogy-hydra.gemspec +122 -0
- data/test/fixtures/assert_true.rb +7 -0
- data/test/fixtures/bad_proxy_config.yml +4 -0
- data/test/fixtures/config.yml +4 -0
- data/test/fixtures/conflicting.rb +10 -0
- data/test/fixtures/features/step_definitions.rb +21 -0
- data/test/fixtures/features/write_alternate_file.feature +7 -0
- data/test/fixtures/features/write_file.feature +7 -0
- data/test/fixtures/hello_world.rb +3 -0
- data/test/fixtures/hydra_worker_init.rb +2 -0
- data/test/fixtures/js_file.js +4 -0
- data/test/fixtures/json_data.json +4 -0
- data/test/fixtures/many_outputs_to_console.rb +9 -0
- data/test/fixtures/master_listeners.rb +10 -0
- data/test/fixtures/proxy_config.yml +4 -0
- data/test/fixtures/proxy_config_http.yml +4 -0
- data/test/fixtures/runner_listeners.rb +23 -0
- data/test/fixtures/slow.rb +9 -0
- data/test/fixtures/sync_test.rb +8 -0
- data/test/fixtures/task_test_config.yml +6 -0
- data/test/fixtures/write_file.rb +10 -0
- data/test/fixtures/write_file_alternate_spec.rb +10 -0
- data/test/fixtures/write_file_spec.rb +9 -0
- data/test/fixtures/write_file_with_pending_spec.rb +11 -0
- data/test/master_test.rb +383 -0
- data/test/message_test.rb +31 -0
- data/test/pipe_test.rb +38 -0
- data/test/proxy_config_test.rb +31 -0
- data/test/runner_test.rb +196 -0
- data/test/ssh_test.rb +25 -0
- data/test/sync_test.rb +113 -0
- data/test/task_test.rb +21 -0
- data/test/test_helper.rb +107 -0
- data/test/worker_test.rb +60 -0
- metadata +208 -0
data/test/master_test.rb
ADDED
@@ -0,0 +1,383 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'test_helper')
|
2
|
+
require File.join(File.dirname(__FILE__), 'fixtures', 'runner_listeners')
|
3
|
+
require File.join(File.dirname(__FILE__), 'fixtures', 'master_listeners')
|
4
|
+
|
5
|
+
class MasterTest < Test::Unit::TestCase
|
6
|
+
context "with a file to test and a destination to verify" do
|
7
|
+
setup do
|
8
|
+
# avoid having other tests interfering with us
|
9
|
+
sleep(0.2)
|
10
|
+
FileUtils.rm_f(target_file)
|
11
|
+
end
|
12
|
+
|
13
|
+
teardown do
|
14
|
+
FileUtils.rm_f(target_file)
|
15
|
+
end
|
16
|
+
|
17
|
+
should "run a test" do
|
18
|
+
Hydra::Master.new(
|
19
|
+
:files => [test_file]
|
20
|
+
)
|
21
|
+
assert File.exists?(target_file)
|
22
|
+
assert_equal "HYDRA", File.read(target_file)
|
23
|
+
end
|
24
|
+
|
25
|
+
# this test simulates what happens when we have 2 tests with the same
|
26
|
+
# class name but with different parent classes. This can happen when
|
27
|
+
# we have a functional and an integration test class with the same name.
|
28
|
+
should "run even with a test that will not require" do
|
29
|
+
class FileOutputListener < Hydra::Listener::Abstract
|
30
|
+
attr_accessor :output
|
31
|
+
def initialize(&block)
|
32
|
+
self.output = {}
|
33
|
+
end
|
34
|
+
|
35
|
+
def file_end(file, output)
|
36
|
+
self.output[file] = output
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
listener = FileOutputListener.new
|
41
|
+
sync_test = File.join(File.dirname(__FILE__), 'fixtures', 'sync_test.rb')
|
42
|
+
Hydra::Master.new(
|
43
|
+
# we want the actual test to run last to make sure the runner can still run tests
|
44
|
+
:files => [sync_test, conflicting_test_file, test_file],
|
45
|
+
:autosort => false,
|
46
|
+
:listeners => [listener]
|
47
|
+
)
|
48
|
+
assert_match /superclass mismatch for class SyncTest/, listener.output[conflicting_test_file]
|
49
|
+
assert_match conflicting_test_file, listener.output[conflicting_test_file]
|
50
|
+
assert File.exists?(target_file)
|
51
|
+
assert_equal "HYDRA", File.read(target_file)
|
52
|
+
end
|
53
|
+
|
54
|
+
should "run a spec with pending examples" do
|
55
|
+
progress_bar = Hydra::Listener::ProgressBar.new(StringIO.new)
|
56
|
+
Hydra::Master.new(
|
57
|
+
:files => [rspec_file_with_pending],
|
58
|
+
:listeners => [progress_bar]
|
59
|
+
)
|
60
|
+
assert File.exists?(target_file)
|
61
|
+
assert_equal "HYDRA", File.read(target_file)
|
62
|
+
assert_equal false, progress_bar.instance_variable_get('@errors')
|
63
|
+
end
|
64
|
+
|
65
|
+
should "generate a report" do
|
66
|
+
Hydra::Master.new(:files => [test_file])
|
67
|
+
assert File.exists?(target_file)
|
68
|
+
assert_equal "HYDRA", File.read(target_file)
|
69
|
+
report_file = File.join(Dir.consistent_tmpdir, 'hydra_heuristics.yml')
|
70
|
+
assert File.exists?(report_file)
|
71
|
+
assert report = YAML.load_file(report_file)
|
72
|
+
assert_not_nil report[test_file]
|
73
|
+
end
|
74
|
+
|
75
|
+
should "run a test 6 times on 1 worker with 2 runners" do
|
76
|
+
Hydra::Master.new(
|
77
|
+
:files => [test_file]*6,
|
78
|
+
:workers => [ { :type => :local, :runners => 2 } ]
|
79
|
+
)
|
80
|
+
assert File.exists?(target_file)
|
81
|
+
assert_equal "HYDRA"*6, File.read(target_file)
|
82
|
+
end
|
83
|
+
|
84
|
+
# The test being run sleeps for 5 seconds. So, if this was run in
|
85
|
+
# series, it would take at least 50 seconds. This test ensures that
|
86
|
+
# in runs in less than that amount of time. Since there are 10
|
87
|
+
# runners to run the file 10 times, it should only take 5-10 seconds
|
88
|
+
# based on overhead.
|
89
|
+
should "run a slow test 10 times on 1 worker with 10 runners quickly" do
|
90
|
+
start = Time.now
|
91
|
+
Hydra::Master.new(
|
92
|
+
:files => [File.join(File.dirname(__FILE__), 'fixtures', 'slow.rb')]*10,
|
93
|
+
:workers => [
|
94
|
+
{ :type => :local, :runners => 10 }
|
95
|
+
]
|
96
|
+
)
|
97
|
+
finish = Time.now
|
98
|
+
assert (finish-start) < 30, "took #{finish-start} seconds"
|
99
|
+
end
|
100
|
+
|
101
|
+
should "run a slow test 10 times on 2 workers with 5 runners each quickly" do
|
102
|
+
start = Time.now
|
103
|
+
Hydra::Master.new(
|
104
|
+
:files => [File.join(File.dirname(__FILE__), 'fixtures', 'slow.rb')]*10,
|
105
|
+
:workers => [
|
106
|
+
{ :type => :local, :runners => 5 },
|
107
|
+
{ :type => :local, :runners => 5 }
|
108
|
+
]
|
109
|
+
)
|
110
|
+
finish = Time.now
|
111
|
+
assert (finish-start) < 15, "took #{finish-start} seconds"
|
112
|
+
end
|
113
|
+
|
114
|
+
should "run a test via ssh" do
|
115
|
+
Hydra::Master.new(
|
116
|
+
:files => [test_file],
|
117
|
+
:workers => [{
|
118
|
+
:type => :ssh,
|
119
|
+
:connect => 'localhost',
|
120
|
+
:directory => remote_dir_path,
|
121
|
+
:runners => 1
|
122
|
+
}]
|
123
|
+
)
|
124
|
+
assert File.exists?(target_file)
|
125
|
+
assert_equal "HYDRA", File.read(target_file)
|
126
|
+
end
|
127
|
+
|
128
|
+
should "run a test with config from a yaml file" do
|
129
|
+
Hydra::Master.new(
|
130
|
+
:files => [test_file],
|
131
|
+
:config => File.join(File.dirname(__FILE__), 'fixtures', 'config.yml')
|
132
|
+
)
|
133
|
+
assert File.exists?(target_file)
|
134
|
+
assert_equal "HYDRA", File.read(target_file)
|
135
|
+
end
|
136
|
+
|
137
|
+
should "synchronize a test file over ssh with rsync" do
|
138
|
+
local = File.join(Dir.consistent_tmpdir, 'hydra', 'local')
|
139
|
+
remote = File.join(Dir.consistent_tmpdir, 'hydra', 'remote')
|
140
|
+
sync_test = File.join(File.dirname(__FILE__), 'fixtures', 'sync_test.rb')
|
141
|
+
[local, remote].each{|f| FileUtils.rm_rf f; FileUtils.mkdir_p f}
|
142
|
+
|
143
|
+
# setup the folders:
|
144
|
+
# local:
|
145
|
+
# - test_a
|
146
|
+
# - test_c
|
147
|
+
# remote:
|
148
|
+
# - test_b
|
149
|
+
#
|
150
|
+
# add test_c to exludes
|
151
|
+
FileUtils.cp(sync_test, File.join(local, 'test_a.rb'))
|
152
|
+
FileUtils.cp(sync_test, File.join(local, 'test_c.rb'))
|
153
|
+
FileUtils.cp(sync_test, File.join(remote, 'test_b.rb'))
|
154
|
+
|
155
|
+
# ensure a is not on remote
|
156
|
+
assert !File.exists?(File.join(remote, 'test_a.rb')), "A should not be on remote"
|
157
|
+
# ensure c is not on remote
|
158
|
+
assert !File.exists?(File.join(remote, 'test_c.rb')), "C should not be on remote"
|
159
|
+
# ensure b is on remote
|
160
|
+
assert File.exists?(File.join(remote, 'test_b.rb')), "B should be on remote"
|
161
|
+
|
162
|
+
Hydra::Master.new(
|
163
|
+
:files => ['test_a.rb'],
|
164
|
+
:workers => [{
|
165
|
+
:type => :ssh,
|
166
|
+
:connect => 'localhost',
|
167
|
+
:directory => remote,
|
168
|
+
:runners => 1
|
169
|
+
}],
|
170
|
+
:sync => {
|
171
|
+
:directory => local,
|
172
|
+
:exclude => ['test_c.rb']
|
173
|
+
}
|
174
|
+
)
|
175
|
+
# ensure a is copied
|
176
|
+
assert File.exists?(File.join(remote, 'test_a.rb')), "A was not copied"
|
177
|
+
# ensure c is not copied
|
178
|
+
assert !File.exists?(File.join(remote, 'test_c.rb')), "C was copied, should be excluded"
|
179
|
+
# ensure b is deleted
|
180
|
+
assert !File.exists?(File.join(remote, 'test_b.rb')), "B was not deleted"
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
context "with a runner_end event" do
|
185
|
+
setup do
|
186
|
+
# avoid having other tests interfering with us
|
187
|
+
sleep(0.2)
|
188
|
+
FileUtils.rm_f(target_file)
|
189
|
+
FileUtils.rm_f(alternate_target_file)
|
190
|
+
|
191
|
+
@runner_began_flag = File.expand_path(File.join(Dir.consistent_tmpdir, 'runner_began_flag')) #used to know when the worker is ready
|
192
|
+
FileUtils.rm_f(@runner_began_flag)
|
193
|
+
|
194
|
+
@runner_listener = 'HydraExtension::RunnerListener::RunnerEndTest.new' # runner_end method that creates alternate_target_file
|
195
|
+
@master_listener = HydraExtension::Listener::WorkerBeganFlag.new #used to know when the runner is up
|
196
|
+
end
|
197
|
+
|
198
|
+
teardown do
|
199
|
+
FileUtils.rm_f(target_file)
|
200
|
+
FileUtils.rm_f(alternate_target_file)
|
201
|
+
end
|
202
|
+
|
203
|
+
context "running a local worker" do
|
204
|
+
should "run runner_end on successful termination" do
|
205
|
+
@pid = Process.fork do
|
206
|
+
Hydra::Master.new(
|
207
|
+
:files => [test_file] * 6,
|
208
|
+
:autosort => false,
|
209
|
+
:listeners => [@master_listener],
|
210
|
+
:runner_listeners => [@runner_listener],
|
211
|
+
:verbose => false
|
212
|
+
)
|
213
|
+
end
|
214
|
+
Process.waitpid @pid
|
215
|
+
|
216
|
+
assert_file_exists alternate_target_file
|
217
|
+
end
|
218
|
+
|
219
|
+
should "run runner_end after interruption signal" do
|
220
|
+
add_infinite_worker_begin_to @master_listener
|
221
|
+
|
222
|
+
capture_stderr do # redirect stderr
|
223
|
+
@pid = Process.fork do
|
224
|
+
Hydra::Master.new(
|
225
|
+
:files => [test_file],
|
226
|
+
:autosort => false,
|
227
|
+
:listeners => [@master_listener],
|
228
|
+
:runner_listeners => [@runner_listener],
|
229
|
+
:verbose => false
|
230
|
+
)
|
231
|
+
end
|
232
|
+
end
|
233
|
+
wait_for_runner_to_begin
|
234
|
+
|
235
|
+
Process.kill 'SIGINT', @pid
|
236
|
+
Process.waitpid @pid
|
237
|
+
|
238
|
+
assert_file_exists alternate_target_file
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
242
|
+
context "running a remote worker" do
|
243
|
+
setup do
|
244
|
+
copy_worker_init_file # this method has a protection to avoid erasing an existing worker_init_file
|
245
|
+
end
|
246
|
+
|
247
|
+
teardown do
|
248
|
+
FileUtils.rm_f(@remote_init_file) unless @protect_init_file
|
249
|
+
end
|
250
|
+
|
251
|
+
should "run runner_end on successful termination" do
|
252
|
+
capture_stderr do # redirect stderr
|
253
|
+
@pid = Process.fork do
|
254
|
+
Hydra::Master.new(
|
255
|
+
:files => [test_file],
|
256
|
+
:autosort => false,
|
257
|
+
:listeners => [@master_listener],
|
258
|
+
:runner_listeners => [@runner_listener],
|
259
|
+
:workers => [{
|
260
|
+
:type => :ssh,
|
261
|
+
:connect => 'localhost',
|
262
|
+
:directory => remote_dir_path,
|
263
|
+
:runners => 1
|
264
|
+
}],
|
265
|
+
:verbose => false
|
266
|
+
)
|
267
|
+
end
|
268
|
+
end
|
269
|
+
Process.waitpid @pid
|
270
|
+
|
271
|
+
assert_file_exists alternate_target_file
|
272
|
+
end
|
273
|
+
end
|
274
|
+
end
|
275
|
+
|
276
|
+
context "redirecting runner's output and errors" do
|
277
|
+
setup do
|
278
|
+
# avoid having other tests interfering with us
|
279
|
+
sleep(0.2)
|
280
|
+
FileUtils.rm_f(target_file)
|
281
|
+
FileUtils.rm_f(runner_log_file)
|
282
|
+
FileUtils.rm_f("#{remote_dir_path}/#{runner_log_file}")
|
283
|
+
end
|
284
|
+
|
285
|
+
teardown do
|
286
|
+
FileUtils.rm_f(target_file)
|
287
|
+
FileUtils.rm_f(runner_log_file)
|
288
|
+
FileUtils.rm_f("#{remote_dir_path}/#{runner_log_file}")
|
289
|
+
end
|
290
|
+
|
291
|
+
should "create a runner log file when usign local worker and passing a log file name" do
|
292
|
+
@pid = Process.fork do
|
293
|
+
Hydra::Master.new(
|
294
|
+
:files => [test_file],
|
295
|
+
:runner_log_file => runner_log_file,
|
296
|
+
:verbose => false
|
297
|
+
)
|
298
|
+
end
|
299
|
+
Process.waitpid @pid
|
300
|
+
|
301
|
+
assert_file_exists target_file # ensure the test was successfully ran
|
302
|
+
assert_file_exists runner_log_file
|
303
|
+
end
|
304
|
+
|
305
|
+
should "create a runner log file when usign remote worker and passing a log file name" do
|
306
|
+
@pid = Process.fork do
|
307
|
+
Hydra::Master.new(
|
308
|
+
:files => [test_file],
|
309
|
+
:workers => [{
|
310
|
+
:type => :ssh,
|
311
|
+
:connect => 'localhost',
|
312
|
+
:directory => remote_dir_path,
|
313
|
+
:runners => 1
|
314
|
+
}],
|
315
|
+
:verbose => false,
|
316
|
+
:runner_log_file => runner_log_file
|
317
|
+
)
|
318
|
+
end
|
319
|
+
Process.waitpid @pid
|
320
|
+
|
321
|
+
assert_file_exists target_file # ensure the test was successfully ran
|
322
|
+
assert_file_exists "#{remote_dir_path}/#{runner_log_file}"
|
323
|
+
end
|
324
|
+
|
325
|
+
should "create the default runner log file when passing an incorrect log file path" do
|
326
|
+
default_log_file = "#{remote_dir_path}/#{Hydra::Runner::DEFAULT_LOG_FILE}" # hydra-runner.log"
|
327
|
+
FileUtils.rm_f(default_log_file)
|
328
|
+
|
329
|
+
@pid = Process.fork do
|
330
|
+
Hydra::Master.new(
|
331
|
+
:files => [test_file],
|
332
|
+
:workers => [{
|
333
|
+
:type => :ssh,
|
334
|
+
:connect => 'localhost',
|
335
|
+
:directory => remote_dir_path,
|
336
|
+
:runners => 1
|
337
|
+
}],
|
338
|
+
:verbose => false,
|
339
|
+
:runner_log_file => 'invalid-dir/#{runner_log_file}'
|
340
|
+
)
|
341
|
+
end
|
342
|
+
Process.waitpid @pid
|
343
|
+
|
344
|
+
assert_file_exists target_file # ensure the test was successfully ran
|
345
|
+
assert_file_exists default_log_file #default log file
|
346
|
+
assert !File.exists?( "#{remote_dir_path}/#{runner_log_file}" )
|
347
|
+
|
348
|
+
FileUtils.rm_f(default_log_file)
|
349
|
+
end
|
350
|
+
end
|
351
|
+
|
352
|
+
private
|
353
|
+
|
354
|
+
def runner_log_file
|
355
|
+
"my-hydra-runner.log"
|
356
|
+
end
|
357
|
+
|
358
|
+
def add_infinite_worker_begin_to master_listener
|
359
|
+
class << master_listener
|
360
|
+
def worker_begin( worker )
|
361
|
+
super
|
362
|
+
sleep 1 while true #ensure the process doesn't finish before killing it
|
363
|
+
end
|
364
|
+
end
|
365
|
+
end
|
366
|
+
|
367
|
+
# this requires that a worker_begin listener creates a file named worker_began_flag in tmp directory
|
368
|
+
def wait_for_runner_to_begin
|
369
|
+
assert_file_exists @runner_began_flag
|
370
|
+
end
|
371
|
+
|
372
|
+
# with a protection to avoid erasing something important in lib
|
373
|
+
def copy_worker_init_file
|
374
|
+
@remote_init_file = "#{remote_dir_path}/#{File.basename( hydra_worker_init_file )}"
|
375
|
+
if File.exists?( @remote_init_file )
|
376
|
+
$stderr.puts "\nWARNING!!!: #{@remote_init_file} exits and this test needs to create a new file here. Make sure there is nothing inportant in that file and remove it before running this test\n\n"
|
377
|
+
@protect_init_file = true
|
378
|
+
exit
|
379
|
+
end
|
380
|
+
# copy the hydra_worker_init to the correct location
|
381
|
+
FileUtils.cp(hydra_worker_init_file, remote_dir_path)
|
382
|
+
end
|
383
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'test_helper')
|
2
|
+
|
3
|
+
class MessageTest < Test::Unit::TestCase
|
4
|
+
class MyMessage < Hydra::Message
|
5
|
+
attr_accessor :my_var
|
6
|
+
def serialize
|
7
|
+
super(:my_var => @my_var)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
context "with a message" do
|
12
|
+
setup do
|
13
|
+
@m = MyMessage.new(:my_var => 'my value')
|
14
|
+
end
|
15
|
+
should "set values" do
|
16
|
+
assert_equal 'my value', @m.my_var
|
17
|
+
end
|
18
|
+
should "serialize" do
|
19
|
+
assert_equal(
|
20
|
+
{:class=>MyMessage, :my_var=>"my value"},
|
21
|
+
eval(@m.serialize)
|
22
|
+
)
|
23
|
+
end
|
24
|
+
should "build from serialization" do
|
25
|
+
assert_equal(
|
26
|
+
@m.my_var,
|
27
|
+
Hydra::Message.build(eval(@m.serialize)).my_var
|
28
|
+
)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
data/test/pipe_test.rb
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'test_helper')
|
2
|
+
|
3
|
+
class PipeTest < Test::Unit::TestCase
|
4
|
+
context "a pipe" do
|
5
|
+
setup do
|
6
|
+
@pipe = Hydra::Pipe.new
|
7
|
+
end
|
8
|
+
teardown do
|
9
|
+
@pipe.close
|
10
|
+
end
|
11
|
+
should "be able to write messages" do
|
12
|
+
child = Process.fork do
|
13
|
+
@pipe.identify_as_child
|
14
|
+
assert_equal "Test Message", @pipe.gets.text
|
15
|
+
@pipe.write Hydra::Messages::TestMessage.new(:text => "Message Received")
|
16
|
+
@pipe.write Hydra::Messages::TestMessage.new(:text => "Second Message")
|
17
|
+
end
|
18
|
+
@pipe.identify_as_parent
|
19
|
+
@pipe.write Hydra::Messages::TestMessage.new(:text => "Test Message")
|
20
|
+
assert_equal "Message Received", @pipe.gets.text
|
21
|
+
assert_equal "Second Message", @pipe.gets.text
|
22
|
+
Process.wait(child) #ensure it quits, so there is nothing to write to
|
23
|
+
assert_raise IOError do
|
24
|
+
@pipe.write Hydra::Messages::TestMessage.new(:text => "anyone there?")
|
25
|
+
end
|
26
|
+
end
|
27
|
+
should "not allow writing if unidentified" do
|
28
|
+
assert_raise IOError do
|
29
|
+
@pipe.write Hydra::Messages::TestMessage.new(:text => "Test Message")
|
30
|
+
end
|
31
|
+
end
|
32
|
+
should "not allow reading if unidentified" do
|
33
|
+
assert_raise IOError do
|
34
|
+
@pipe.gets
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'test_helper')
|
2
|
+
require 'yaml'
|
3
|
+
require 'hydra/proxy_config'
|
4
|
+
|
5
|
+
class ProxyConfigTest < Test::Unit::TestCase
|
6
|
+
|
7
|
+
context "proxy config" do
|
8
|
+
should "fetch and parse yml from a file source" do
|
9
|
+
assert_equal YAML::load_file("test/fixtures/config.yml"), Hydra::ProxyConfig.load(File.read("test/fixtures/proxy_config.yml"))
|
10
|
+
end
|
11
|
+
should "fetch and parse yml from a http source" do
|
12
|
+
class Net::HTTP
|
13
|
+
def self.get(path)
|
14
|
+
return File.new("test/fixtures/config.yml", "r").read
|
15
|
+
end
|
16
|
+
end
|
17
|
+
assert_equal YAML::load_file("test/fixtures/config.yml"), Hydra::ProxyConfig.load(File.read("test/fixtures/proxy_config_http.yml"))
|
18
|
+
end
|
19
|
+
should "raise exception when type is unknown" do
|
20
|
+
assert_raise Hydra::UnknownProxyType do
|
21
|
+
Hydra::ProxyConfig.load(File.read("test/fixtures/bad_proxy_config.yml"))
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
context "normal hydra config" do
|
27
|
+
should "return unserialized configuration" do
|
28
|
+
assert_equal YAML::load_file("test/fixtures/config.yml"), Hydra::ProxyConfig.load(File.read("test/fixtures/config.yml"))
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
data/test/runner_test.rb
ADDED
@@ -0,0 +1,196 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'test_helper')
|
2
|
+
require File.join(File.dirname(__FILE__), 'fixtures', 'runner_listeners')
|
3
|
+
|
4
|
+
class RunnerTest < Test::Unit::TestCase
|
5
|
+
context "with a file to test and a destination to verify" do
|
6
|
+
setup do
|
7
|
+
sleep(0.2)
|
8
|
+
FileUtils.rm_f(target_file)
|
9
|
+
FileUtils.rm_f(alternate_target_file)
|
10
|
+
end
|
11
|
+
|
12
|
+
teardown do
|
13
|
+
FileUtils.rm_f(target_file)
|
14
|
+
FileUtils.rm_f(alternate_target_file)
|
15
|
+
end
|
16
|
+
|
17
|
+
|
18
|
+
should "run a test in the foreground" do
|
19
|
+
# flip it around to the parent is in the fork, this gives
|
20
|
+
# us more direct control over the runner and proper test
|
21
|
+
# coverage output
|
22
|
+
pipe = Hydra::Pipe.new
|
23
|
+
parent = Process.fork do
|
24
|
+
request_a_file_and_verify_completion(pipe, test_file)
|
25
|
+
end
|
26
|
+
run_the_runner(pipe)
|
27
|
+
Process.wait(parent)
|
28
|
+
end
|
29
|
+
|
30
|
+
# this flips the above test, so that the main process runs a bit of the parent
|
31
|
+
# code, but only with minimal assertion
|
32
|
+
should "run a test in the background" do
|
33
|
+
pipe = Hydra::Pipe.new
|
34
|
+
child = Process.fork do
|
35
|
+
run_the_runner(pipe)
|
36
|
+
end
|
37
|
+
request_a_file_and_verify_completion(pipe, test_file)
|
38
|
+
Process.wait(child)
|
39
|
+
end
|
40
|
+
|
41
|
+
should "run a js lint file and find errors" do
|
42
|
+
runner = Hydra::Runner.new(:io => File.new('/dev/null', 'w'))
|
43
|
+
results = runner.run_file(javascript_file)
|
44
|
+
assert results =~ /Missing semicolon/, results
|
45
|
+
end
|
46
|
+
|
47
|
+
should "run a json data file and find errors" do
|
48
|
+
runner = Hydra::Runner.new(:io => File.new('/dev/null', 'w'))
|
49
|
+
results = runner.run_file(json_file)
|
50
|
+
assert results =~ /trailing comma/, results
|
51
|
+
end
|
52
|
+
|
53
|
+
should "run two rspec tests" do
|
54
|
+
runner = Hydra::Runner.new(:io => File.new('/dev/null', 'w'))
|
55
|
+
runner.run_file(rspec_file)
|
56
|
+
assert File.exists?(target_file)
|
57
|
+
assert_equal "HYDRA", File.read(target_file)
|
58
|
+
|
59
|
+
FileUtils.rm_f(target_file)
|
60
|
+
|
61
|
+
runner.run_file(alternate_rspec_file)
|
62
|
+
assert File.exists?(alternate_target_file)
|
63
|
+
assert_equal "HYDRA", File.read(alternate_target_file)
|
64
|
+
assert !File.exists?(target_file), "Tests are double running!"
|
65
|
+
end
|
66
|
+
|
67
|
+
should "run rspec tests with pending examples" do
|
68
|
+
runner = Hydra::Runner.new(:io => File.new('/dev/null', 'w'))
|
69
|
+
assert File.exists?(rspec_file_with_pending)
|
70
|
+
|
71
|
+
runner.run_file(rspec_file_with_pending)
|
72
|
+
|
73
|
+
assert File.exists?(target_file)
|
74
|
+
assert_equal "HYDRA", File.read(target_file)
|
75
|
+
|
76
|
+
FileUtils.rm_f(target_file)
|
77
|
+
end
|
78
|
+
|
79
|
+
should "run two cucumber tests" do
|
80
|
+
# because of all the crap cucumber pulls in
|
81
|
+
# we run this in a fork to not contaminate
|
82
|
+
# the main test environment
|
83
|
+
capture_stderr do # redirect stderr
|
84
|
+
pid = Process.fork do
|
85
|
+
runner = Hydra::Runner.new(:io => File.new('/dev/null', 'w'))
|
86
|
+
runner.run_file(cucumber_feature_file)
|
87
|
+
assert File.exists?(target_file)
|
88
|
+
assert_equal "HYDRA", File.read(target_file)
|
89
|
+
|
90
|
+
FileUtils.rm_f(target_file)
|
91
|
+
|
92
|
+
runner.run_file(alternate_cucumber_feature_file)
|
93
|
+
assert File.exists?(alternate_target_file)
|
94
|
+
assert_equal "HYDRA", File.read(alternate_target_file)
|
95
|
+
assert !File.exists?(target_file)
|
96
|
+
end
|
97
|
+
Process.wait pid
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
should "be able to run a runner over ssh" do
|
102
|
+
ssh = Hydra::SSH.new(
|
103
|
+
'localhost',
|
104
|
+
File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib')),
|
105
|
+
"ruby -e \"require 'rubygems'; require 'hydra'; Hydra::Runner.new(:io => Hydra::Stdio.new, :verbose => true);\""
|
106
|
+
)
|
107
|
+
assert ssh.gets.is_a?(Hydra::Messages::Runner::RequestFile)
|
108
|
+
ssh.write(Hydra::Messages::Worker::RunFile.new(:file => test_file))
|
109
|
+
|
110
|
+
# grab its response. This makes us wait for it to finish
|
111
|
+
echo = ssh.gets # get the ssh echo
|
112
|
+
response = ssh.gets
|
113
|
+
|
114
|
+
assert_equal Hydra::Messages::Runner::Results, response.class
|
115
|
+
|
116
|
+
# tell it to shut down
|
117
|
+
ssh.write(Hydra::Messages::Worker::Shutdown.new)
|
118
|
+
|
119
|
+
ssh.close
|
120
|
+
|
121
|
+
# ensure it ran
|
122
|
+
assert File.exists?(target_file)
|
123
|
+
assert_equal "HYDRA", File.read(target_file)
|
124
|
+
end
|
125
|
+
|
126
|
+
context "using runner events" do
|
127
|
+
context "on successful termination" do
|
128
|
+
setup do
|
129
|
+
@pipe = Hydra::Pipe.new
|
130
|
+
@parent = Process.fork do
|
131
|
+
request_a_file_and_verify_completion(@pipe, test_file)
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
should "fire runner_begin event" do
|
136
|
+
run_the_runner(@pipe, [HydraExtension::RunnerListener::RunnerBeginTest.new] )
|
137
|
+
Process.wait(@parent)
|
138
|
+
|
139
|
+
# ensure runner_begin was fired
|
140
|
+
assert_file_exists alternate_target_file
|
141
|
+
end
|
142
|
+
|
143
|
+
should "fire runner_end event" do
|
144
|
+
run_the_runner(@pipe, [HydraExtension::RunnerListener::RunnerEndTest.new] )
|
145
|
+
Process.wait(@parent)
|
146
|
+
|
147
|
+
assert_file_exists alternate_target_file
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
should "fire runner_end event after losing communication with worker" do
|
152
|
+
pipe = Hydra::Pipe.new
|
153
|
+
parent = Process.fork do
|
154
|
+
pipe.identify_as_parent
|
155
|
+
|
156
|
+
# grab its response.
|
157
|
+
response = pipe.gets
|
158
|
+
pipe.close #this will be detected by the runner and it should call runner_end
|
159
|
+
end
|
160
|
+
|
161
|
+
run_the_runner(pipe, [HydraExtension::RunnerListener::RunnerEndTest.new] )
|
162
|
+
Process.wait(parent)
|
163
|
+
|
164
|
+
# ensure runner_end was fired
|
165
|
+
assert File.exists?( alternate_target_file )
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
module RunnerTestHelper
|
171
|
+
def request_a_file_and_verify_completion(pipe, file)
|
172
|
+
pipe.identify_as_parent
|
173
|
+
|
174
|
+
# make sure it asks for a file, then give it one
|
175
|
+
assert pipe.gets.is_a?(Hydra::Messages::Runner::RequestFile)
|
176
|
+
pipe.write(Hydra::Messages::Worker::RunFile.new(:file => file))
|
177
|
+
|
178
|
+
# grab its response. This makes us wait for it to finish
|
179
|
+
response = pipe.gets
|
180
|
+
|
181
|
+
# tell it to shut down
|
182
|
+
pipe.write(Hydra::Messages::Worker::Shutdown.new)
|
183
|
+
|
184
|
+
# ensure it ran
|
185
|
+
assert File.exists?(target_file)
|
186
|
+
assert_equal "HYDRA", File.read(target_file)
|
187
|
+
end
|
188
|
+
|
189
|
+
def run_the_runner(pipe, listeners = [])
|
190
|
+
pipe.identify_as_child
|
191
|
+
Hydra::Runner.new( :io => pipe, :runner_listeners => listeners )
|
192
|
+
end
|
193
|
+
end
|
194
|
+
include RunnerTestHelper
|
195
|
+
end
|
196
|
+
|