scout-gear 8.0.0 → 9.0.0

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