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,105 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'scout'
4
+
5
+ $0 = "scout #{$previous_commands.any? ? $previous_commands*" " + " " : "" }#{ File.basename(__FILE__) }" if $previous_commands
6
+
7
+ options = SOPT.setup <<EOF
8
+
9
+ Description of the tool
10
+
11
+ $ #{$0} [<options>] <filename> [<other|->]*
12
+
13
+ Install a workflow, or a coma separated list of workflows, from its source. If
14
+ repo is not specified then 'http://github.com/Rbbt-Workflows/' will be used. If
15
+ the workflow is already installed it will be updated. If 'all' is specified
16
+ instead of a particular workflow, all installed workflows will be updated.
17
+
18
+ You can set the environment variable SCOUT_WORKFLOW_AUTOINSTALL=true to make
19
+ workflows install automatically as required.
20
+
21
+ -h--help Print this help
22
+ EOF
23
+ if options[:help]
24
+ if defined? scout_usage
25
+ scout_usage
26
+ else
27
+ puts SOPT.doc
28
+ end
29
+ exit 0
30
+ end
31
+
32
+
33
+ workflow = ARGV[0]
34
+ base_repo = ARGV[1]
35
+
36
+ raise "No workflow specified" if workflow.nil?
37
+
38
+ workflow_dir = Scout.etc.workflow_dir.exists? ? Path.setup(Scout.etc.workflow_dir.read.strip) : Scout.workflows.find(:user)
39
+
40
+ FileUtils.mkdir_p workflow_dir unless File.exist? workflow_dir
41
+
42
+ all_workflows = workflow_dir.find.glob("*/.git").collect{|d| File.basename(File.dirname(d))}
43
+ workflows = workflow == 'all' ? all_workflows : workflow.split(",")
44
+
45
+ Misc.in_dir(workflow_dir) do
46
+ workflows.each do |workflow|
47
+ case
48
+ when File.exist?(Misc.snake_case(workflow))
49
+ Log.info "Updating: " + workflow
50
+ Misc.in_dir(Misc.snake_case(workflow)) do
51
+ `git pull`
52
+ `git checkout scout 2> /dev/null`
53
+ `git submodule init`
54
+ `git submodule update`
55
+ end
56
+ when File.exist?(workflow)
57
+ Misc.in_dir(workflow) do
58
+ Log.info "Updating: " + workflow
59
+ `git pull`
60
+ `git checkout scout 2> /dev/null`
61
+ `git submodule init`
62
+ `git submodule update`
63
+ end
64
+ else
65
+ Log.info "Installing: " + workflow
66
+
67
+ if base_repo.nil?
68
+ repo_base_url = Rbbt.etc.workflow_repo.exists? ? Rbbt.etc.workflow_repo.read.strip : 'https://github.com/Rbbt-Workflows/'
69
+ else
70
+ repo_base_url = base_repo
71
+ end
72
+
73
+
74
+ if repo_base_url.include?(workflow) or repo_base_url.include?(Misc.snake_case(workflow))
75
+ repo = repo_base_url
76
+ else
77
+ begin
78
+ repo = File.join(repo_base_url, workflow + '.git')
79
+ CMD.cmd("wget '#{repo}' -O /dev/null").read
80
+ rescue
81
+ Log.debug "Workflow repo does not exist, trying snake_case: #{ repo }"
82
+ begin
83
+ repo = File.join(repo_base_url, Misc.snake_case(workflow) + '.git')
84
+ CMD.cmd("wget '#{repo}' -O /dev/null").read
85
+ rescue
86
+ raise "Workflow repo does not exist: #{ repo }"
87
+ end
88
+ end
89
+ end
90
+
91
+ Log.warn "Cloning #{ repo }"
92
+ Misc.insist do
93
+ `git clone "#{repo}" #{ Misc.snake_case(workflow) }`
94
+ raise unless $?.success?
95
+ end
96
+ Log.warn "Initializing and updating submodules for #{repo}. You might be prompted for passwords."
97
+ Misc.in_dir(Misc.snake_case(workflow)) do
98
+ `git checkout scout 2> /dev/null`
99
+ `git submodule init`
100
+ `git submodule update`
101
+ end
102
+ end
103
+ end
104
+ end
105
+
@@ -5,7 +5,9 @@ require 'scout'
5
5
  $0 = "scout #{$previous_commands.any? ? $previous_commands*" " + " " : "" }#{ File.basename(__FILE__) }" if $previous_commands
6
6
 
7
7
  ENV["SCOUT_NO_STREAM"] = "true" if ARGV.include? "--nostream"
8
+ ARGV.delete '--nostream'
8
9
  ENV["SCOUT_UPDATE"] = "true" if ARGV.include? "--update"
10
+ ARGV.delete '--update'
9
11
 
10
12
  options = SOPT.setup <<EOF
11
13
 
@@ -16,12 +18,15 @@ $ #{$0} [<options>] <workflow> <task>
16
18
  -h--help Print this help
17
19
  --nostream Disable job streaming
18
20
  --update Update jobs with newer dependencies
19
- -jn--job_name* Name to use as job identifier
21
+ -jn--jobname* Name to use as job identifier
22
+ -li--load_inputs* Directory with inputs files to load
20
23
  -pf--print_filepath Print the file path
21
24
  -prov--provenance Print the step provenance
22
25
  -cl--clean Clean the last step
23
26
  -rcl--recursive_clean Clean all steps
24
27
  -ct--clean_task* Clean a particular task
28
+ -d--deploy* Deploy mode: serial, local, or SLURM (default 'serial')
29
+ -od--override_deps* Override deps using 'Workflow#task=<path>' array_separated
25
30
  EOF
26
31
 
27
32
  workflow_name, task_name = ARGV
@@ -34,8 +39,9 @@ task = workflow.tasks[task_name.to_sym] if task_name
34
39
 
35
40
  options[:help] = true if task.nil?
36
41
 
37
- help, provenance, clean, recursive_clean, clean_task, jobname, print_filepath = IndiferentHash.process_options options,
38
- :help, :provenance, :clean, :recursive_clean, :clean_task, :job_name, :print_filepath
42
+ help, provenance, clean, recursive_clean, clean_task, load_inputs, jobname, print_filepath, deploy, override_deps = IndiferentHash.process_options options,
43
+ :help, :provenance, :clean, :recursive_clean, :clean_task, :load_inputs, :jobname, :print_filepath, :deploy, :override_deps,
44
+ :deploy => 'serial'
39
45
 
40
46
  if help
41
47
  if defined? scout_usage
@@ -48,8 +54,20 @@ if help
48
54
  exit 0
49
55
  end
50
56
 
51
- job_options = task.get_SOPT(task)
52
- job = workflow.job(task_name, jobname, job_options)
57
+ if load_inputs
58
+ job_inputs = workflow.tasks[task_name].load_inputs(load_inputs)
59
+ else
60
+ job_inputs = task.get_SOPT
61
+ end
62
+
63
+ if override_deps
64
+ override_deps.split($array_separator || ",").each do |part|
65
+ t_, value = part.split("=")
66
+ job_inputs.merge!( t_ => value)
67
+ end
68
+ end
69
+
70
+ job = workflow.job(task_name, jobname, job_inputs)
53
71
 
54
72
  job.recursive_clean if recursive_clean
55
73
  job.clean if clean
@@ -69,13 +87,35 @@ if clean_task
69
87
  end
70
88
 
71
89
  job.clean if job.task_name.to_s == clean_task.to_s
90
+ job.clean unless job.updated?
72
91
  end
73
92
  end
74
93
 
75
94
  if provenance
76
95
  puts Step.prov_report(job)
77
96
  else
78
- job.run(true) unless job.done?
97
+ case deploy
98
+ when "serial"
99
+ job.run(true)
100
+ when "local"
101
+ orchestrator = Workflow::Orchestrator.new 3, "cpus" => Misc.processors
102
+ orchestrator.process({}, job)
103
+ when "slurm"
104
+ require 'rbbt-scout'
105
+ require_relative '../../modules/rbbt-util/lib/rbbt/hpc'
106
+ HPC::BATCH_MODULE = HPC.batch_system "SLURM"
107
+ HPC::BATCH_MODULE.orchestrate_job(job, {})
108
+ job.grace
109
+ else
110
+ if deploy.end_with?('-slurm')
111
+ server = deploy.sub('-slurm','')
112
+ OffsiteStep.setup(job, server: server, slurm: true)
113
+ else
114
+ OffsiteStep.setup(job, server: deploy)
115
+ end
116
+
117
+ job.run
118
+ end unless job.done?
79
119
 
80
120
  if print_filepath
81
121
  job.join
@@ -32,6 +32,7 @@ else
32
32
  local basedir="$(realpath $1)"
33
33
  local path="$(realpath "$2")"
34
34
  local pre=""
35
+ basedir=${basedir%.}
35
36
  while [[ ! $path = $basedir* ]]; do
36
37
  pre=${pre}../
37
38
  basedir=$(dirname $basedir)
@@ -44,9 +45,8 @@ function link(){
44
45
  local source="$1"
45
46
  local target="$2"
46
47
  local rel_source=$(relative_path "$(dirname $target)" "$source")
47
-
48
+
48
49
  [ -h "$target" ] && rm "$target"
49
- echo ln -s "$rel_source" "$target" 1>&2
50
50
  [ -h "$target" ] || ln -s "$rel_source" "$target"
51
51
  }
52
52
 
@@ -0,0 +1,25 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'scout'
4
+
5
+ $0 = "scout #{$previous_commands.any? ? $previous_commands*" " + " " : "" }#{ File.basename(__FILE__) }" if $previous_commands
6
+
7
+ options = SOPT.setup <<EOF
8
+
9
+ Description of the tool
10
+
11
+ $ #{$0} [<options>] <filename> [<other|->]*
12
+
13
+ -h--help Print this help
14
+ EOF
15
+ if options[:help]
16
+ if defined? scout_usage
17
+ scout_usage
18
+ else
19
+ puts SOPT.doc
20
+ end
21
+ exit 0
22
+ end
23
+
24
+
25
+
@@ -0,0 +1,14 @@
1
+ Misc.add_libdir if __FILE__ == $0
2
+
3
+ #require 'scout/sources/MODULE'
4
+
5
+ module MODULE
6
+ extend Workflow
7
+
8
+
9
+ end
10
+
11
+ #require 'MODULE/tasks/basic.rb'
12
+
13
+ #require 'scout/knowledge_base/MODULE'
14
+ #require 'scout/entity/MODULE'
@@ -0,0 +1,15 @@
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 TestSSH < Test::Unit::TestCase
5
+ def test_marshal
6
+ return unless SSHLine.reach?
7
+
8
+ assert TrueClass === SSHLine.rbbt(:default, 'true')
9
+ end
10
+
11
+ def test_localhost
12
+ assert SSHLine.scout('localhost', 'true')
13
+ end
14
+ end
15
+
@@ -0,0 +1,32 @@
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 TestOffsiteStep < Test::Unit::TestCase
5
+ def test_offsite_task
6
+ workflow_code =<<-EOF
7
+ module TestWF
8
+ extend Workflow
9
+
10
+ input :string, :string, "String", "string"
11
+ task :string => :string do |string| string end
12
+ end
13
+
14
+ TestWF.directory = Path.setup("#{tmpdir.offsite.TestWF}")
15
+ EOF
16
+
17
+ TmpFile.with_file workflow_code, :extension => 'rb' do |wffile|
18
+ wf = Workflow.require_workflow wffile
19
+
20
+ job = wf.job(:string)
21
+
22
+ off = OffsiteStep.setup job, server: 'localhost', workflow_name: wffile
23
+
24
+ refute off.done?
25
+ assert_equal 'string', off.run
26
+
27
+ assert off.done?
28
+ assert_equal 'string', off.run
29
+ end
30
+ end
31
+ end
32
+
@@ -0,0 +1,36 @@
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 TestSync < Test::Unit::TestCase
5
+ def test_sync
6
+ TmpFile.with_path do |tmpdir|
7
+ tmpdir = Scout.tmp.tmpdir_sync
8
+ tmpdir.dir1.foo.write("FOO")
9
+ tmpdir.dir1.bar.write("BAR")
10
+
11
+ TmpFile.with_path do |tmpdir2|
12
+ Misc.in_dir tmpdir2 do
13
+ SSHLine.sync([tmpdir.dir1], map: :current)
14
+
15
+ assert tmpdir2.glob("**/*").select{|f| f.include?('foo') }.any?
16
+ end
17
+ end
18
+ end
19
+ end
20
+
21
+ def test_sync_dir_map
22
+ TmpFile.with_path do |tmpdir|
23
+ tmpdir = Scout.tmp.tmpdir_sync
24
+ tmpdir.dir1.foo.write("FOO")
25
+ tmpdir.dir1.bar.write("BAR")
26
+
27
+ TmpFile.with_path do |tmpdir2|
28
+ SSHLine.sync([tmpdir.dir1], map: tmpdir2)
29
+ Misc.in_dir tmpdir2 do
30
+ assert tmpdir2.glob("**/*").select{|f| f.include?('foo') }.any?
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
36
+
File without changes
@@ -36,5 +36,11 @@ class TestResourcePath < Test::Unit::TestCase
36
36
  assert_include tmpfile.foo.bar.read, "TEST"
37
37
  end
38
38
  end
39
+
40
+ def test_identify
41
+ p = Scout.data.file.find(:lib)
42
+ assert p.located?
43
+ assert_equal "data/file", p.identify
44
+ end
39
45
  end
40
46
 
@@ -33,5 +33,11 @@ ValueB (Entity type)
33
33
  NamedArray.add_zipped a, [%w(d), %w(1)]
34
34
  assert_equal [%w(a b c d), %w(1 1 1 1)], a
35
35
  end
36
+
37
+ def test_method_missing
38
+ a = NamedArray.setup([1,2], [:a, :b])
39
+ assert_equal 1, a.a
40
+ assert_equal 2, a.b
41
+ end
36
42
  end
37
43
 
@@ -114,6 +114,7 @@ class TestPersist < Test::Unit::TestCase
114
114
  end
115
115
  end
116
116
  end
117
+
117
118
  if IO === io
118
119
  Open.consume_stream(io, false)
119
120
  else
@@ -137,8 +138,8 @@ class TestPersist < Test::Unit::TestCase
137
138
  Open.write(output2, io)
138
139
  end
139
140
  end
140
- Process.wait
141
- Process.wait
141
+ Process.waitpid pid1
142
+ Process.waitpid pid2
142
143
 
143
144
  assert File.exist?(output1) || File.exist?(output2)
144
145
  [pid1, pid2].zip([output2, output1]).each do |pid, found|
@@ -290,4 +290,21 @@ row2 b bbb bbbb bb
290
290
  tsv = TSV.str_setup("ID~ValueA,ValueB#:type=:flat", {})
291
291
  assert_equal "ID", tsv.key_field
292
292
  end
293
+
294
+ def test_cast_in_header
295
+ content =<<-EOF
296
+ #: :sep=/\\s+/#:type=:single
297
+ #Id Value
298
+ a 1
299
+ b 2
300
+ c 3
301
+ EOF
302
+
303
+ TmpFile.with_file(content) do |filename|
304
+ tsv = TSV.open(filename, :key_field => "Value", :grep => "#\\|2")
305
+ refute tsv.to_s.include?(":cast=:to_f")
306
+ tsv.cast = :to_f
307
+ assert_include tsv.to_s, ":cast=:to_f"
308
+ end
309
+ end
293
310
  end
@@ -56,7 +56,7 @@ class TestWorkQueue < Test::Unit::TestCase
56
56
  end
57
57
  end
58
58
 
59
- Process.wait pid
59
+ Process.waitpid pid
60
60
  q.close
61
61
 
62
62
  q.join
@@ -90,60 +90,82 @@ class TestWorkQueue < Test::Unit::TestCase
90
90
  end
91
91
 
92
92
  def test_queue_error
93
- num = 100
94
- reps = 10_000
95
-
96
- q = WorkQueue.new num do |obj|
97
- raise ScoutException if rand < 0.1
98
- [Process.pid.to_s, obj.to_s] * " "
99
- end
100
-
101
- res = []
102
- q.process do |out|
103
- res << out
104
- end
93
+ 5.times do |i|
94
+ num = 100
95
+ reps = 10_000
105
96
 
106
- Log.with_severity 7 do
107
- pid = Process.fork do
108
- reps.times do |i|
109
- q.write i
110
- end
97
+ q = WorkQueue.new num do |obj|
98
+ raise ScoutException if rand < 0.1
99
+ [Process.pid.to_s, obj.to_s] * " "
111
100
  end
112
101
 
113
- Process.waitpid pid
102
+ res = []
103
+ q.process do |out|
104
+ res << out
105
+ end
114
106
 
115
- assert_raise ScoutException do
116
- q.join
117
- t.join
107
+ Log.with_severity 7 do
108
+ t = Thread.new do
109
+ Thread.current["name"] = "queue writer"
110
+ Thread.current.report_on_exception = false
111
+ reps.times do |i|
112
+ q.write i
113
+ end
114
+ q.close
115
+ end
116
+ Thread.pass until t["name"]
117
+
118
+ assert_raise ScoutException do
119
+ begin
120
+ q.join(false)
121
+ rescue
122
+ t.raise($!)
123
+ raise $!
124
+ ensure
125
+ t.join
126
+ end
127
+ end
118
128
  end
119
129
  end
120
130
  end
121
131
 
122
132
  def test_queue_error_in_input
123
- num = 100
124
- reps = 10_000
133
+ 5.times do |i|
134
+ num = 100
135
+ reps = 10_000
125
136
 
126
- q = WorkQueue.new num do |obj|
127
- [Process.pid.to_s, obj.to_s] * " "
128
- end
129
-
130
- res = []
131
- q.process do |out|
132
- raise ScoutException
133
- res << out
134
- end
137
+ q = WorkQueue.new num do |obj|
138
+ [Process.pid.to_s, obj.to_s] * " "
139
+ end
135
140
 
136
- Log.with_severity 7 do
137
- pid = Process.fork do
138
- reps.times do |i|
139
- q.write i
140
- end
141
- q.close
141
+ res = []
142
+ q.process do |out|
143
+ raise ScoutException
144
+ res << out
142
145
  end
143
146
 
144
- assert_raise ScoutException do
145
- q.join
146
- t.join
147
+ Log.with_severity 7 do
148
+ t = Thread.new do
149
+ Thread.current.report_on_exception = false
150
+ Thread.current["name"] = "queue writer"
151
+ reps.times do |i|
152
+ q.write i
153
+ end
154
+ q.close
155
+ end
156
+ Thread.pass until t["name"]
157
+
158
+ assert_raise ScoutException do
159
+ begin
160
+ q.join(false)
161
+ rescue Exception
162
+ t.raise($!)
163
+ raise $!
164
+ ensure
165
+ t.join
166
+ q.clean
167
+ end
168
+ end
147
169
  end
148
170
  end
149
171
  end
@@ -3,7 +3,7 @@ require File.expand_path(__FILE__).sub(%r(.*/test/), '').sub(/test_(.*)\.rb/,'\1
3
3
 
4
4
  require 'scout/tsv'
5
5
  class TestTSVAdapter < Test::Unit::TestCase
6
- def _test_get_set
6
+ def test_get_set
7
7
  tsv = TSV.setup({}, :type => :list, :key_field => "Key", :fields => %w(one two three))
8
8
  tsv.type = :list
9
9
  tsv.extend TSVAdapter
@@ -43,6 +43,20 @@ row2 a b id3
43
43
  end
44
44
  end
45
45
 
46
+ def test_index_from_flat
47
+ content =<<-'EOF'
48
+ #: :sep=" "#:type=:flat
49
+ #Id ValueA
50
+ row1 a aa aaa
51
+ row2 b bb bbb
52
+ EOF
53
+
54
+ TmpFile.with_file(content) do |filename|
55
+ index = TSV.index(filename, :target => "Id")
56
+ assert_equal "row1", index["aa"]
57
+ end
58
+ end
59
+
46
60
  def test_from_tsv
47
61
  content =<<-'EOF'
48
62
  #: :sep=/\s+/#:type=:double#:merge=:concat
@@ -95,6 +95,27 @@ k a|A b|B
95
95
  assert_equal 'a', tsv['k'][0][0]
96
96
  end
97
97
 
98
+ def test_parse_head
99
+ content =<<-EOF
100
+ #: :sep=" "#:type=:double
101
+ #Key ValueA ValueB
102
+ k a|A b|B
103
+ k1 a|A b|B
104
+ k2 a|A b|B
105
+ k3 a|A b|B
106
+ k4 a|A b|B
107
+ EOF
108
+ content = StringIO.new content
109
+
110
+ tsv = TSV.parse(content, :head => 2)
111
+ assert_equal 2, tsv.keys.length
112
+
113
+ content.rewind
114
+ tsv = TSV.parse(content, :head => 3)
115
+ assert_equal 3, tsv.keys.length
116
+ end
117
+
118
+
98
119
  def test_parse_fields
99
120
  content =<<-EOF
100
121
  #: :sep=" "#:type=:double
@@ -119,6 +140,20 @@ k a|A b|B
119
140
  assert_equal [%w(b B), %w(k)], tsv['k']
120
141
  end
121
142
 
143
+ def test_parse_flat
144
+ content =<<-EOF
145
+ #: :sep=" "#:type=:flat
146
+ #Key ValueA
147
+ row1 a aa aaa
148
+ row2 b bb bbb
149
+ EOF
150
+
151
+ tsv = TSV.open(content)
152
+ assert_equal %w(a aa aaa), tsv["row1"]
153
+ tsv = TSV.open(content, :fields => ["ValueA"])
154
+ assert_equal %w(a aa aaa), tsv["row1"]
155
+ end
156
+
122
157
  def test_parse_key
123
158
  content =<<-EOF
124
159
  #: :sep=" "#:type=:double