scout-gear 8.0.0 → 8.1.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.
Files changed (98) hide show
  1. checksums.yaml +4 -4
  2. data/.vimproject +26 -9
  3. data/Rakefile +6 -1
  4. data/VERSION +1 -1
  5. data/bin/scout +15 -4
  6. data/doc/lib/scout/path.md +35 -0
  7. data/doc/lib/scout/workflow/task.md +13 -0
  8. data/lib/scout/cmd.rb +23 -24
  9. data/lib/scout/concurrent_stream.rb +36 -19
  10. data/lib/scout/exceptions.rb +10 -0
  11. data/lib/scout/log/color.rb +11 -11
  12. data/lib/scout/log/progress/report.rb +7 -5
  13. data/lib/scout/log/progress/util.rb +3 -0
  14. data/lib/scout/log/trap.rb +3 -3
  15. data/lib/scout/log.rb +64 -36
  16. data/lib/scout/meta_extension.rb +34 -0
  17. data/lib/scout/misc/digest.rb +11 -2
  18. data/lib/scout/misc/format.rb +12 -7
  19. data/lib/scout/misc/monitor.rb +11 -0
  20. data/lib/scout/misc/system.rb +48 -0
  21. data/lib/scout/named_array.rb +8 -0
  22. data/lib/scout/offsite/ssh.rb +171 -0
  23. data/lib/scout/offsite/step.rb +83 -0
  24. data/lib/scout/offsite/sync.rb +55 -0
  25. data/lib/scout/offsite.rb +3 -0
  26. data/lib/scout/open/lock.rb +5 -24
  27. data/lib/scout/open/remote.rb +12 -1
  28. data/lib/scout/open/stream.rb +110 -122
  29. data/lib/scout/open/util.rb +9 -0
  30. data/lib/scout/open.rb +5 -4
  31. data/lib/scout/path/find.rb +15 -10
  32. data/lib/scout/path/util.rb +5 -0
  33. data/lib/scout/persist/serialize.rb +3 -3
  34. data/lib/scout/persist.rb +1 -1
  35. data/lib/scout/resource/path.rb +4 -0
  36. data/lib/scout/resource/util.rb +10 -4
  37. data/lib/scout/tsv/dumper.rb +2 -0
  38. data/lib/scout/tsv/index.rb +28 -86
  39. data/lib/scout/tsv/open.rb +35 -14
  40. data/lib/scout/tsv/parser.rb +9 -2
  41. data/lib/scout/tsv/persist/tokyocabinet.rb +2 -0
  42. data/lib/scout/tsv/stream.rb +204 -0
  43. data/lib/scout/tsv/transformer.rb +11 -0
  44. data/lib/scout/tsv.rb +9 -2
  45. data/lib/scout/work_queue/worker.rb +2 -2
  46. data/lib/scout/work_queue.rb +36 -12
  47. data/lib/scout/workflow/definition.rb +2 -1
  48. data/lib/scout/workflow/deployment/orchestrator.rb +245 -0
  49. data/lib/scout/workflow/deployment.rb +1 -0
  50. data/lib/scout/workflow/step/dependencies.rb +37 -11
  51. data/lib/scout/workflow/step/file.rb +5 -0
  52. data/lib/scout/workflow/step/info.rb +5 -3
  53. data/lib/scout/workflow/step/load.rb +1 -1
  54. data/lib/scout/workflow/step/provenance.rb +1 -0
  55. data/lib/scout/workflow/step/status.rb +6 -8
  56. data/lib/scout/workflow/step.rb +75 -30
  57. data/lib/scout/workflow/task/dependencies.rb +114 -0
  58. data/lib/scout/workflow/task/inputs.rb +27 -13
  59. data/lib/scout/workflow/task.rb +9 -108
  60. data/lib/scout/workflow/usage.rb +40 -12
  61. data/lib/scout/workflow.rb +4 -2
  62. data/lib/scout-gear.rb +2 -0
  63. data/lib/scout.rb +6 -0
  64. data/scout-gear.gemspec +32 -7
  65. data/scout_commands/doc +37 -0
  66. data/scout_commands/find +1 -0
  67. data/scout_commands/offsite +30 -0
  68. data/scout_commands/update +29 -0
  69. data/scout_commands/workflow/info +15 -3
  70. data/scout_commands/workflow/install +102 -0
  71. data/scout_commands/workflow/task +26 -5
  72. data/test/scout/offsite/test_ssh.rb +15 -0
  73. data/test/scout/offsite/test_step.rb +33 -0
  74. data/test/scout/offsite/test_sync.rb +36 -0
  75. data/test/scout/offsite/test_task.rb +0 -0
  76. data/test/scout/resource/test_path.rb +6 -0
  77. data/test/scout/test_named_array.rb +6 -0
  78. data/test/scout/test_persist.rb +3 -2
  79. data/test/scout/test_tsv.rb +17 -0
  80. data/test/scout/test_work_queue.rb +63 -41
  81. data/test/scout/tsv/persist/test_adapter.rb +1 -1
  82. data/test/scout/tsv/test_index.rb +14 -0
  83. data/test/scout/tsv/test_parser.rb +14 -0
  84. data/test/scout/tsv/test_stream.rb +200 -0
  85. data/test/scout/tsv/test_transformer.rb +12 -0
  86. data/test/scout/workflow/deployment/test_orchestrator.rb +272 -0
  87. data/test/scout/workflow/step/test_dependencies.rb +68 -0
  88. data/test/scout/workflow/step/test_info.rb +18 -0
  89. data/test/scout/workflow/step/test_status.rb +0 -1
  90. data/test/scout/workflow/task/test_dependencies.rb +355 -0
  91. data/test/scout/workflow/task/test_inputs.rb +53 -0
  92. data/test/scout/workflow/test_definition.rb +18 -0
  93. data/test/scout/workflow/test_documentation.rb +24 -0
  94. data/test/scout/workflow/test_step.rb +109 -0
  95. data/test/scout/workflow/test_task.rb +0 -287
  96. data/test/test_scout.rb +9 -0
  97. metadata +83 -5
  98. data/scout_commands/workflow/task_old +0 -706
@@ -21,5 +21,73 @@ class TestStepDependencies < Test::Unit::TestCase
21
21
  assert_equal 2, step2.inputs[:input2]
22
22
  assert_equal "12", step2.recursive_inputs[:input1]
23
23
  end
24
+
25
+ def test_can_fail
26
+ tmpfile = tmpdir.test_step
27
+ step1 = Step.new tmpfile.step1, NamedArray.setup(["12"], %w(input1)) do |s|
28
+ raise ScoutException
29
+ end
30
+
31
+ step2 = Step.new tmpfile.step2, NamedArray.setup([2], %w(input2)) do |times|
32
+ step1 = dependencies.first
33
+ if step1.error?
34
+ (step1.inputs.first + " has unknown characters") * times
35
+ else
36
+ (step1.inputs.first + " has " + step1.load.to_s + " characters") * times
37
+ end
38
+ end
39
+
40
+ step2.dependencies = [step1]
41
+ step2.compute = {step1.path => [:canfail] }
42
+
43
+ assert_include step2.run, "unknown"
44
+ end
45
+
46
+ def test_can_stream
47
+ tmpfile = tmpdir.test_step
48
+
49
+ Misc.with_env "SCOUT_EXPLICIT_STREAMING", "true" do
50
+ times = 10_000
51
+ sleep = 1 / times
52
+
53
+ step1 = Step.new tmpfile.step1, [times, sleep] do |times,sleep|
54
+ Open.open_pipe do |sin|
55
+ times.times do |i|
56
+ sin.puts "line-#{i}"
57
+ sleep sleep
58
+ end
59
+ end
60
+ end
61
+ step1.type = :array
62
+
63
+ step2 = Step.new tmpfile.step2 do
64
+ step1 = dependencies.first
65
+ raise ScoutException unless step1.streaming?
66
+ stream = step1.stream
67
+
68
+ Open.open_pipe do |sin|
69
+ while line = stream.gets
70
+ num = line.split("-").last
71
+ next if num.to_i % 2 == 1
72
+ sin.puts line
73
+ end
74
+ end
75
+ end
76
+ step2.type = :array
77
+ step2.dependencies = [step1]
78
+
79
+ assert_raise ScoutException do
80
+ step2.run
81
+ end
82
+
83
+ step2.recursive_clean
84
+
85
+ step2.compute = {step1.path => [:stream]}
86
+
87
+ assert_nothing_raised do
88
+ step2.run
89
+ end
90
+ end
91
+ end
24
92
  end
25
93
 
@@ -25,4 +25,22 @@ class TestStepInfo < Test::Unit::TestCase
25
25
  assert_equal "12 has 2 characters", step2.run
26
26
  end
27
27
  end
28
+
29
+ def test_inputs_marshal
30
+ TmpFile.with_file do |tmpdir|
31
+ Path.setup(tmpdir)
32
+ tmpfile = tmpdir.test_step
33
+
34
+ path = tmpfile.foo
35
+ step1 = Step.new tmpfile.step1, [path] do |s|
36
+ s.length
37
+ end
38
+
39
+ step1.run
40
+
41
+ refute Path === step1.info[:inputs][0]
42
+
43
+ end
44
+
45
+ end
28
46
  end
@@ -15,7 +15,6 @@ class TestStepStatus < Test::Unit::TestCase
15
15
 
16
16
  step2.dependencies = [step1]
17
17
 
18
- sss 0
19
18
  Misc.with_env "SCOUT_UPDATE", "true" do
20
19
  step2.run
21
20
  assert step2.updated?
@@ -0,0 +1,355 @@
1
+ require File.expand_path(__FILE__).sub(%r(/test/.*), '/test/test_helper.rb')
2
+ require File.expand_path(__FILE__).sub(%r(.*/test/), '').sub(/test_(.*)\.rb/,'\1')
3
+
4
+ require 'scout/workflow'
5
+ class TestTaskDependencies < Test::Unit::TestCase
6
+ def test_task_override_dep_exec
7
+ wf = Workflow.annonymous_workflow "TaskInputs" do
8
+ input :input1, :integer
9
+ task :step1 => :integer do |i| i end
10
+
11
+ dep :step1
12
+ input :input2, :integer, "Integer", 3
13
+ task :step2 => :integer do |i| i * step(:step1).load end
14
+ end
15
+
16
+ assert_equal 6, wf.job(:step2, :input1 => 2, :input2 => 3).exec
17
+
18
+ step1_job = wf.job(:step1, :input1 => 6)
19
+ assert_equal 18, wf.job(:step2, :input1 => 2, "TaskInputs#step1" => step1_job).exec
20
+
21
+ assert_equal 18, wf.job(:step2, :input1 => 2, "TaskInputs#step1" => step1_job).exec
22
+
23
+ assert_equal 18, wf.job(:step2, "TaskInputs#step1" => step1_job).exec
24
+ end
25
+
26
+ def test_task_override_dep
27
+ wf = Workflow.annonymous_workflow "TaskInputs" do
28
+ input :input1, :integer
29
+ task :step1 => :integer do |i| i end
30
+
31
+ dep :step1
32
+ input :input2, :integer, "Integer", 3
33
+ task :step2 => :integer do |i| i * step(:step1).load end
34
+ end
35
+
36
+ assert_equal 6, wf.job(:step2, :input1 => 2, :input2 => 3).run
37
+
38
+ step1_job = wf.job(:step1, :input1 => 6)
39
+ assert_equal 18, wf.job(:step2, :input1 => 2, "TaskInputs#step1" => step1_job).run
40
+
41
+ assert_equal 18, wf.job(:step2, :input1 => 2, "TaskInputs#step1" => step1_job).run
42
+
43
+ assert_equal 18, wf.job(:step2, "TaskInputs#step1" => step1_job).run
44
+ end
45
+
46
+ def test_input_dep
47
+ wf = Workflow.annonymous_workflow "TaskInputs" do
48
+ input :v1, :integer
49
+ input :v2, :integer
50
+ task :sum => :integer do |v1,v2|
51
+ v1 + v2
52
+ end
53
+
54
+ input :input1, :integer
55
+ task :step1 => :integer do |i| i end
56
+
57
+ input :input2, :integer
58
+ task :step2 => :integer do |i| i end
59
+
60
+ dep :step1, :input1 => 2
61
+ dep :step2, :input2 => 3
62
+ dep :sum, :v1 => :step1, :v2 => :step2
63
+ task :my_sum => :integer do
64
+ dependencies.last.load
65
+ end
66
+
67
+ dep :my_sum
68
+ task :double => :integer do
69
+ step(:my_sum).load * 2
70
+ end
71
+ end
72
+
73
+ job = wf.job(:my_sum)
74
+ assert_equal 5, job.run
75
+ assert_equal Task::DEFAULT_NAME, job.name
76
+
77
+ job = wf.job(:double)
78
+ assert_equal Task::DEFAULT_NAME, job.name
79
+
80
+ step1 = wf.job(:step1, :input1 => 3)
81
+ assert_equal 3, step1.run
82
+ job = wf.job(:double, "TaskInputs#step1" => step1)
83
+ assert_equal 12, job.run
84
+ assert_not_equal Task::DEFAULT_NAME, job.name
85
+
86
+ step1 = wf.job(:step1, :input1 => 4)
87
+ assert_equal 4, step1.run
88
+ job = wf.job(:double, "TaskInputs#step1" => step1)
89
+ assert_equal 14, job.run
90
+ assert_not_equal Task::DEFAULT_NAME, job.name
91
+ end
92
+
93
+ def test_input_dep_override
94
+ wf = Workflow.annonymous_workflow "TaskInputs" do
95
+ input :v1, :integer
96
+ input :v2, :integer
97
+ task :sum => :integer do |v1,v2|
98
+ v1 + v2
99
+ end
100
+
101
+ input :input1, :integer
102
+ task :step1 => :integer do |i| i end
103
+
104
+ input :input2, :integer
105
+ task :step2 => :integer do |i| i end
106
+
107
+ dep :step1
108
+ dep :step2
109
+ task :my_sum => :integer do
110
+ dependencies.inject(0){|acc,d| acc += d.load }
111
+ end
112
+ end
113
+
114
+ step2 = wf.job(:step2, :input2 => 4)
115
+ job = wf.job(:my_sum, :input1 => 2, :input2 => 3, "TaskInputs#step2"=> step2)
116
+ assert_equal 6, job.exec
117
+
118
+ job = wf.job(:my_sum, :input1 => 2, :input2 => 3)
119
+ assert_equal 5, job.run
120
+
121
+ TmpFile.with_file(4) do |file|
122
+ job = wf.job(:my_sum, :input1 => 2, :input2 => 3, "TaskInputs#step2"=> file)
123
+ assert_equal 6, job.run
124
+ assert_not_equal Task::DEFAULT_NAME, job.name
125
+ end
126
+ end
127
+
128
+ def test_input_rename
129
+ wf = Workflow.annonymous_workflow "TaskInputs" do
130
+ input :v1, :integer
131
+ input :v2, :integer
132
+ task :sum => :integer do |v1,v2|
133
+ v1 + v2
134
+ end
135
+
136
+ input :vv1, :integer
137
+ input :vv2, :integer
138
+ dep :sum, :v1 => :vv1, :v2 => :vv2
139
+ task :my_sum => :integer do
140
+ dependencies.last.load
141
+ end
142
+ end
143
+
144
+ job = wf.job(:my_sum, :vv1 => 2, :vv2 => 3)
145
+ assert_equal 5, job.run
146
+ end
147
+
148
+ def test_defaults_in_dep_block
149
+ wf = Workflow.annonymous_workflow "TaskInputs" do
150
+ input :v1, :integer
151
+ input :v2, :integer
152
+ task :sum => :integer do |v1,v2|
153
+ v1 + v2
154
+ end
155
+
156
+ input :vv1, :integer
157
+ input :vv2, :integer, nil, 3
158
+ dep :sum, :v1 => :placeholder, :v2 => :placeholder do |jobname,options,dependencies|
159
+ raise "Non-numeric value where integer expected" unless Numeric === options[:vv1]
160
+ {inputs: {v1: options[:vv1], v2: options[:vv2]} }
161
+ end
162
+ task :my_sum => :integer do
163
+ dependencies.last.load
164
+ end
165
+ end
166
+
167
+ job = wf.job(:my_sum, :vv1 => "2")
168
+ assert_equal 5, job.run
169
+ end
170
+
171
+ def test_dependency_jobname
172
+ wf = Workflow.annonymous_workflow "TaskInputs" do
173
+ input :v1, :integer
174
+ input :v2, :integer
175
+ task :sum => :integer do |v1,v2|
176
+ v1 + v2
177
+ end
178
+
179
+ input :vv1, :integer
180
+ input :vv2, :integer
181
+ dep :sum, :v1 => :vv1, :v2 => :vv2, :jobname => "OTHER_NAME"
182
+ task :my_sum => :integer do
183
+ dependencies.last.load
184
+ end
185
+ end
186
+
187
+ job = wf.job(:my_sum, "TEST_NAME", :vv1 => 2, :vv2 => 3)
188
+ assert_equal 5, job.run
189
+ assert_equal "TEST_NAME", job.clean_name
190
+ assert_equal "OTHER_NAME", job.step(:sum).clean_name
191
+ end
192
+
193
+ def test_no_param_last_job
194
+ wf = Workflow.annonymous_workflow "TaskInputs" do
195
+ input :v1, :integer
196
+ input :v2, :integer
197
+ task :sum => :integer do |v1,v2|
198
+ v1 + v2
199
+ end
200
+
201
+ dep :sum
202
+ task :my_sum => :integer do
203
+ dependencies.last.load
204
+ end
205
+ end
206
+
207
+ job = wf.job(:my_sum, :v1 => 2, :v2 => "3")
208
+ assert_equal 5, job.run
209
+ refute_equal Task::DEFAULT_NAME, job.name
210
+ end
211
+
212
+ def test_no_param_last_job_block
213
+ wf = Workflow.annonymous_workflow "TaskInputs" do
214
+ input :v1, :integer
215
+ input :v2, :integer
216
+ task :sum => :integer do |v1,v2|
217
+ v1 + v2
218
+ end
219
+
220
+ dep :sum do |jobname,options|
221
+ {inputs: options}
222
+ end
223
+ task :my_sum => :integer do
224
+ dependencies.last.load
225
+ end
226
+ end
227
+
228
+ job = wf.job(:my_sum, :v1 => 2, :v2 => "3")
229
+ assert_equal 5, job.run
230
+ refute_equal Task::DEFAULT_NAME, job.name
231
+ end
232
+
233
+
234
+ def test_override_inputs_block
235
+ wf = Workflow.annonymous_workflow "TaskInputs" do
236
+ input :input1, :string
237
+ task :step1 => :string do |i| i end
238
+
239
+ dep :step1, :input1 => 1 do |id,options|
240
+ {:inputs => options}
241
+ end
242
+ task :step2 => :string do |i| step(:step1).load end
243
+ end
244
+
245
+ job = wf.job(:step2, :input1 => 2)
246
+ assert_equal 1, job.run
247
+ assert_equal Task::DEFAULT_NAME, job.name
248
+ assert_not_equal Task::DEFAULT_NAME, job.step(:step1).name
249
+ end
250
+
251
+ def test_default_inputs_in_block
252
+ wf = Workflow.annonymous_workflow "TaskInputs" do
253
+ input :input1, :string
254
+ task :step1 => :string do |i| i end
255
+
256
+ dep :step1 do |id,options|
257
+ {}
258
+ end
259
+ task :step2 => :string do |i| step(:step1).load end
260
+ end
261
+
262
+ job = wf.job(:step2, "SOME_NAME", :input1 => 2)
263
+ assert_equal "SOME_NAME", job.step(:step1).clean_name
264
+ assert_equal 2, job.run
265
+ end
266
+
267
+ def test_override_inputs_block_array
268
+ wf = Workflow.annonymous_workflow "TaskInputs" do
269
+ input :input1, :string
270
+ task :step1 => :string do |i| i end
271
+
272
+ dep :step1, :input1 => 1 do |id,options|
273
+ [{:inputs => options}]
274
+ end
275
+ input :input2, :string
276
+ task :step2 => :string do |i| step(:step1).load end
277
+ end
278
+
279
+ job = wf.job(:step2, :input1 => 2)
280
+ assert_equal 1, job.run
281
+ assert_equal Task::DEFAULT_NAME, job.name
282
+ assert_not_equal Task::DEFAULT_NAME, job.step(:step1).name
283
+ end
284
+
285
+ def test_override_inputs
286
+ wf = Workflow.annonymous_workflow "TaskInputs" do
287
+ input :input1, :string
288
+ task :step1 => :string do |i| i end
289
+
290
+ dep :step1, :input1 => 1
291
+ input :input2, :string
292
+ task :step2 => :string do |i| step(:step1).load end
293
+ end
294
+
295
+ job = wf.job(:step2, :input1 => 2)
296
+ assert_equal 1, job.run
297
+ assert_equal Task::DEFAULT_NAME, job.name
298
+ assert_not_equal Task::DEFAULT_NAME, job.step(:step1).name
299
+ end
300
+
301
+ def test_non_default_inputs
302
+ wf = Workflow.annonymous_workflow "TaskInputs" do
303
+ input :input1, :integer, "", 1
304
+ input :input2, :integer, "", 0
305
+ task :step1 => :string do |i1,i2| i1 + i2 end
306
+
307
+ dep :step1, :input2 => 1
308
+ task :step2 => :string do |i| step(:step1).load end
309
+
310
+ dep :step2
311
+ task :step3 => :string do |i| step(:step1).load end
312
+ end
313
+
314
+ job = wf.job(:step3, :input1 => 1)
315
+ assert_equal Task::DEFAULT_NAME, job.name
316
+ assert_not_equal Task::DEFAULT_NAME, job.step(:step1).name
317
+ assert_equal 2, job.run
318
+
319
+ job = wf.job(:step3, :input1 => 2)
320
+ assert_equal 3, job.run
321
+
322
+
323
+ job = wf.job(:step3)
324
+ assert_equal Task::DEFAULT_NAME, job.name
325
+ assert_not_equal Task::DEFAULT_NAME, job.step(:step1).name
326
+ end
327
+
328
+ def test_can_fail
329
+ wf = Workflow.annonymous_workflow "TaskInputs" do
330
+ input :input1, :integer, "", 1
331
+ task :step1 => :string do |i1|
332
+ if i1 < 0
333
+ raise ScoutException
334
+ else
335
+ i1
336
+ end
337
+ end
338
+
339
+ dep :step1, :canfail => true
340
+ task :step2 => :string do |i|
341
+ if step(:step1).error?
342
+ 0
343
+ else
344
+ step(:step1).load
345
+ end
346
+ end
347
+ end
348
+
349
+ assert_equal 1, wf.job(:step2, :input1 => 1).run
350
+ assert_equal 2, wf.job(:step2, :input1 => 2).run
351
+ assert_equal 0, wf.job(:step2, :input1 => -2).run
352
+ end
353
+
354
+ end
355
+
@@ -21,6 +21,11 @@ class TestTaskInput < Test::Unit::TestCase
21
21
  task :task => :array do
22
22
  inputs
23
23
  end
24
+
25
+ dep :task
26
+ task :task2 => :array do
27
+ inputs
28
+ end
24
29
  end
25
30
  end
26
31
 
@@ -106,6 +111,7 @@ class TestTaskInput < Test::Unit::TestCase
106
111
  def test_save_and_load
107
112
  task = self.example_task
108
113
 
114
+ sss 0
109
115
  TmpFile.with_file("2\n3") do |integer_array_file|
110
116
  inputs = {:string => "String", :integer => 2, :integer_array => integer_array_file, :float_array => %w(1.1 2.2)}
111
117
  original_digest = task.process_inputs(inputs).last
@@ -179,4 +185,51 @@ class TestTaskInput < Test::Unit::TestCase
179
185
  end
180
186
  end
181
187
  end
188
+
189
+ def test_save_and_load_file_array_task2
190
+ task = self.example_workflow.tasks[:task2]
191
+
192
+ TmpFile.with_file do |dir|
193
+ file1 = File.join(dir, 'subdir1/file')
194
+ file2 = File.join(dir, 'subdir2/file')
195
+
196
+ Open.write(file1, "TEST1")
197
+ Open.write(file2, "TEST2")
198
+ inputs = {:string => "String", :integer => 2, :file_array => [file1, file2], :float_array => %w(1.1 2.2)}
199
+ original_digest = task.process_inputs(inputs).last
200
+
201
+ TmpFile.with_file do |save_directory|
202
+ task.save_inputs(save_directory, inputs)
203
+ Open.rm(file1)
204
+ Open.rm(file2)
205
+ new_inputs = task.load_inputs(save_directory)
206
+ new_digest = task.process_inputs(new_inputs).last
207
+ assert_equal original_digest, new_digest
208
+ end
209
+ end
210
+ end
211
+
212
+ def test_save_and_load_array_from_file
213
+ task = self.example_workflow.tasks[:task]
214
+
215
+ TmpFile.with_file do |dir|
216
+ array = %w(1 2 3 4 5)
217
+ file1 = File.join(dir, 'subdir1/file')
218
+ Open.write(file1, array * "\n")
219
+ inputs = {:array => file1 }
220
+ original_digest = task.process_inputs(inputs).last
221
+
222
+ TmpFile.with_file do |save_directory|
223
+ iii inputs
224
+ task.save_inputs(save_directory, inputs)
225
+ Open.rm(file1)
226
+ new_inputs = task.load_inputs(save_directory)
227
+ iii new_inputs
228
+ new_digest = task.process_inputs(new_inputs).last
229
+ iii new_digest
230
+ iii original_digest
231
+ assert_equal original_digest, new_digest
232
+ end
233
+ end
234
+ end
182
235
  end
@@ -0,0 +1,18 @@
1
+ require File.expand_path(__FILE__).sub(%r(/test/.*), '/test/test_helper.rb')
2
+ require File.expand_path(__FILE__).sub(%r(.*/test/), '').sub(/test_(.*)\.rb/,'\1')
3
+
4
+ class TestClass < Test::Unit::TestCase
5
+ def test_function_task
6
+ wf = Workflow.annonymous_workflow do
7
+ self.name = "StringLength"
8
+ def self.str_length(s)
9
+ s.length
10
+ end
11
+
12
+ input :string, :string
13
+ task :str_length => :integer
14
+ end
15
+ assert_equal 5, wf.job(:str_length, :string => "12345").run
16
+ end
17
+ end
18
+
@@ -26,5 +26,29 @@ class TestWorkflowDocumentation < Test::Unit::TestCase
26
26
  assert_match 'test', UsageWorkflow.documentation[:title]
27
27
  assert_match 'presented', UsageWorkflow.documentation[:description]
28
28
  end
29
+
30
+ def test_documentation_markdown
31
+ doc =<<-EOF
32
+ summary
33
+
34
+ description
35
+
36
+ # Tasks
37
+
38
+ ## task1
39
+
40
+ task 1 summary
41
+
42
+ task 1 description
43
+
44
+ ## task2
45
+ task 2 summary
46
+
47
+ task 2 description
48
+ EOF
49
+
50
+ assert_includes Workflow.parse_workflow_doc(doc)[:tasks], 'task1'
51
+ assert_includes Workflow.parse_workflow_doc(doc)[:tasks]['task2'], 'task 2 description'
52
+ end
29
53
  end
30
54
 
@@ -47,6 +47,17 @@ class TestWorkflowStep < Test::Unit::TestCase
47
47
  end
48
48
  step1.type = :array
49
49
 
50
+ step1.clean
51
+ res = step1.run(false)
52
+ refute IO === res
53
+ step1.join
54
+
55
+ step1.clean
56
+ res = step1.run(true)
57
+ assert IO === res
58
+ step1.join
59
+ step1.clean
60
+
50
61
  step2 = Step.new tmpfile.step2 do
51
62
  step1 = dependencies.first
52
63
  stream = step1.stream
@@ -229,4 +240,102 @@ class TestWorkflowStep < Test::Unit::TestCase
229
240
 
230
241
  assert_equal times, lines.length
231
242
  end
243
+
244
+ def test_fork_stream_fork
245
+ tmpfile = tmpdir.test_step
246
+
247
+ times = 10_000
248
+ sleep = 0.1 / times
249
+
250
+ step1 = Step.new tmpfile.step1, [times, sleep] do |times,sleep|
251
+ sleep 1
252
+ Open.open_pipe do |sin|
253
+ times.times do |i|
254
+ sin.puts "line-#{i}"
255
+ sleep sleep
256
+ end
257
+ end
258
+ end
259
+ step1.type = :array
260
+
261
+
262
+ step2 = Step.new tmpfile.step2 do
263
+ step1 = dependencies.first
264
+ stream = step1.stream
265
+
266
+ Open.open_pipe do |sin|
267
+ while line = stream.gets
268
+ num = line.split("-").last
269
+ next if num.to_i % 2 == 1
270
+ sin.puts "S2: " + line
271
+ end
272
+ end
273
+ end
274
+ step2.type = :array
275
+ step2.dependencies = [step1]
276
+
277
+ step3 = Step.new tmpfile.step3 do
278
+ step1 = dependencies.first
279
+ stream = step1.stream
280
+
281
+ Open.open_pipe do |sin|
282
+ while line = stream.gets
283
+ num = line.split("-").last
284
+ next if num.to_i % 2 == 0
285
+ sin.puts "S3: " + line
286
+ end
287
+ end
288
+ end
289
+ step3.type = :array
290
+ step3.dependencies = [step1]
291
+
292
+
293
+ step4 = Step.new tmpfile.step4 do
294
+ step2, step3 = dependencies
295
+
296
+ mutex = Mutex.new
297
+ Open.open_pipe do |sin|
298
+ t2 = Thread.new do
299
+ stream2 = step2.stream
300
+ while line = stream2.gets
301
+ sin.puts line
302
+ end
303
+ end
304
+
305
+ t3 = Thread.new do
306
+ stream3 = step3.stream
307
+ while line = stream3.gets
308
+ sin.puts line
309
+ end
310
+ end
311
+ t2.join
312
+ t3.join
313
+ end
314
+ end
315
+ step4.type = :array
316
+ step4.dependencies = [step2, step3]
317
+
318
+ step4.recursive_clean
319
+ step4.fork
320
+ assert Array === step4.load
321
+ assert_equal times, step4.load.size
322
+ end
323
+
324
+ def test_dependency_canfail
325
+ tmpfile = tmpdir.test_step
326
+ step1 = Step.new tmpfile.step1, ["12"] do |s|
327
+ s.length
328
+ end
329
+
330
+ step2 = Step.new tmpfile.step2 do
331
+ step1 = dependencies.first
332
+ step1.inputs.first + " has " + step1.load.to_s + " characters"
333
+ end
334
+
335
+ step2.dependencies = [step1]
336
+
337
+ assert_equal "12 has 2 characters", step2.run
338
+ assert_equal "12 has 2 characters", step2.run
339
+ end
340
+
232
341
  end