scout-gear 10.8.4 → 10.10.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.
Files changed (89) hide show
  1. checksums.yaml +4 -4
  2. data/.vimproject +38 -0
  3. data/README.md +352 -0
  4. data/VERSION +1 -1
  5. data/bin/scout +4 -1
  6. data/doc/Association.md +288 -0
  7. data/doc/Entity.md +296 -0
  8. data/doc/KnowledgeBase.md +433 -0
  9. data/doc/Persist.md +356 -0
  10. data/doc/Semaphore.md +171 -0
  11. data/doc/TSV.md +449 -0
  12. data/doc/WorkQueue.md +359 -0
  13. data/doc/Workflow.md +586 -0
  14. data/lib/scout/association.rb +4 -2
  15. data/lib/scout/entity/identifiers.rb +1 -1
  16. data/lib/scout/entity/object.rb +1 -1
  17. data/lib/scout/entity/property.rb +5 -5
  18. data/lib/scout/entity.rb +1 -1
  19. data/lib/scout/knowledge_base/description.rb +1 -1
  20. data/lib/scout/knowledge_base/list.rb +7 -2
  21. data/lib/scout/knowledge_base/registry.rb +4 -5
  22. data/lib/scout/knowledge_base.rb +20 -2
  23. data/lib/scout/monitor.rb +10 -6
  24. data/lib/scout/persist/engine/packed_index.rb +2 -2
  25. data/lib/scout/persist/engine/sharder.rb +1 -1
  26. data/lib/scout/persist/tsv.rb +1 -0
  27. data/lib/scout/semaphore.rb +1 -1
  28. data/lib/scout/tsv/dumper.rb +3 -3
  29. data/lib/scout/tsv/open.rb +1 -0
  30. data/lib/scout/tsv/parser.rb +1 -1
  31. data/lib/scout/tsv/transformer.rb +1 -0
  32. data/lib/scout/tsv/util.rb +2 -2
  33. data/lib/scout/work_queue/socket.rb +1 -1
  34. data/lib/scout/work_queue/worker.rb +7 -5
  35. data/lib/scout/workflow/definition.rb +11 -0
  36. data/lib/scout/workflow/deployment/local.rb +288 -0
  37. data/lib/scout/workflow/deployment/orchestrator/batches.rb +130 -0
  38. data/lib/scout/workflow/deployment/orchestrator/chains.rb +104 -0
  39. data/lib/scout/workflow/deployment/orchestrator/rules.rb +256 -0
  40. data/lib/scout/workflow/deployment/orchestrator/workload.rb +67 -0
  41. data/lib/scout/workflow/deployment/scheduler/job.rb +740 -0
  42. data/lib/scout/workflow/deployment/scheduler/lfs.rb +125 -0
  43. data/lib/scout/workflow/deployment/scheduler/pbs.rb +176 -0
  44. data/lib/scout/workflow/deployment/scheduler/slurm.rb +158 -0
  45. data/lib/scout/workflow/deployment/scheduler.rb +73 -0
  46. data/lib/scout/workflow/deployment.rb +10 -1
  47. data/lib/scout/workflow/entity.rb +22 -1
  48. data/lib/scout/workflow/exceptions.rb +2 -0
  49. data/lib/scout/workflow/step/config.rb +6 -3
  50. data/lib/scout/workflow/step/file.rb +4 -0
  51. data/lib/scout/workflow/step/info.rb +10 -4
  52. data/lib/scout/workflow/step/progress.rb +52 -0
  53. data/lib/scout/workflow/step.rb +39 -5
  54. data/lib/scout/workflow/task/inputs.rb +1 -1
  55. data/lib/scout/workflow/task.rb +2 -0
  56. data/lib/scout/workflow/usage.rb +3 -2
  57. data/lib/scout/workflow/util.rb +22 -0
  58. data/scout-gear.gemspec +37 -7
  59. data/scout_commands/batch/list +1 -1
  60. data/scout_commands/cat +86 -0
  61. data/scout_commands/doc +3 -1
  62. data/scout_commands/entity +151 -0
  63. data/scout_commands/system/status +238 -0
  64. data/scout_commands/workflow/cmd +5 -13
  65. data/scout_commands/workflow/info +23 -10
  66. data/scout_commands/workflow/install +1 -1
  67. data/scout_commands/workflow/task +61 -25
  68. data/test/scout/entity/test_property.rb +1 -1
  69. data/test/scout/knowledge_base/test_registry.rb +19 -0
  70. data/test/scout/test_work_queue.rb +1 -1
  71. data/test/scout/work_queue/test_worker.rb +12 -10
  72. data/test/scout/workflow/deployment/orchestrator/test_batches.rb +138 -0
  73. data/test/scout/workflow/deployment/orchestrator/test_chains.rb +171 -0
  74. data/test/scout/workflow/deployment/orchestrator/test_rules.rb +219 -0
  75. data/test/scout/workflow/deployment/orchestrator/test_workload.rb +117 -0
  76. data/test/scout/workflow/deployment/scheduler/test_job.rb +31 -0
  77. data/test/scout/workflow/deployment/scheduler/test_lfs.rb +32 -0
  78. data/test/scout/workflow/deployment/scheduler/test_pbs.rb +32 -0
  79. data/test/scout/workflow/deployment/scheduler/test_slurm.rb +32 -0
  80. data/test/scout/workflow/deployment/{test_orchestrator.rb → test_local.rb} +161 -33
  81. data/test/scout/workflow/deployment/test_scheduler.rb +75 -0
  82. data/test/scout/workflow/deployment/test_trace.rb +1 -1
  83. data/test/scout/workflow/step/test_progress.rb +27 -0
  84. data/test/scout/workflow/task/test_inputs.rb +17 -0
  85. data/test/test_helper.rb +2 -1
  86. metadata +36 -6
  87. data/doc/lib/scout/path.md +0 -35
  88. data/doc/lib/scout/workflow/task.md +0 -13
  89. data/lib/scout/workflow/deployment/orchestrator.rb +0 -292
@@ -0,0 +1,238 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'scout'
4
+ require 'scout/monitor'
5
+
6
+ $0 = "rbbt #{$previous_commands*""} #{ File.basename(__FILE__) }" if $previous_commands
7
+
8
+ options = SOPT.setup <<EOF
9
+
10
+ Report the status of the system
11
+
12
+ $ rbbt system status <workflow> <task>
13
+
14
+ Specify workflow '.' and no task to examine the jobs of the current directory (usefull for web-server cache).
15
+
16
+ -h--help Print this help
17
+ -q--quick Quick check
18
+ -a--all Print all jobs, not only uncompleted
19
+ -i--inputs* List of inputs to print
20
+ -if--info_fields* List of info fields to print
21
+ EOF
22
+ scout_usage and exit 0 if options[:help]
23
+
24
+ workflow, task = ARGV
25
+
26
+
27
+ workflow = workflow.split "," if workflow
28
+ task = task.split "," if task
29
+
30
+ all = options.delete :all
31
+
32
+ inputs = (options[:inputs] || "").split(",")
33
+ info_fields = (options[:info_fields] || "").split(",")
34
+
35
+ def pid_msg(pid)
36
+ color = if pid and Misc.pid_alive? pid
37
+ :green
38
+ else
39
+ :red
40
+ end
41
+ if pid.nil?
42
+ ""
43
+ else
44
+ Log.color(color, pid)
45
+ end
46
+ end
47
+
48
+
49
+ #def status_msg(status)
50
+ # color = case status.to_sym
51
+ # when :error, :aborted, :missing, :dead, :broken
52
+ # :red
53
+ # when :streaming, :started
54
+ # :cyan
55
+ # when :done
56
+ # :green
57
+ # when :noinfo, :notfound
58
+ # :blue
59
+ # when :dependencies, :waiting, :setup
60
+ # :yellow
61
+ # else
62
+ # if status.to_s.index ">"
63
+ # :cyan
64
+ # else
65
+ # :cyan
66
+ # end
67
+ # end
68
+ # Log.color(color, status.to_s)
69
+ #end
70
+
71
+ def input_msg(file, inputs)
72
+
73
+ str = ""
74
+ job_inputs = Step.new(file).recursive_inputs.to_hash
75
+ IndiferentHash.setup(job_inputs)
76
+
77
+ inputs.each do |input|
78
+ value = job_inputs[input]
79
+ next if value.nil?
80
+ value_str = Misc.fingerprint(value)
81
+ str << "\t#{Log.color :magenta, input}=#{value_str}"
82
+ end
83
+ str
84
+ end
85
+
86
+ def info_msg(info, info_fields)
87
+
88
+ str = ""
89
+ info_fields.each do |field|
90
+ value = info[field]
91
+ next if value.nil?
92
+ value_str = Misc.fingerprint(value)
93
+ str << "\t#{Log.color :magenta, field}=#{value_str}"
94
+ end
95
+ str
96
+ end
97
+
98
+
99
+ puts Log.color(:magenta, "# System report")
100
+ puts
101
+ sort_files = Proc.new do |a,b|
102
+ fa,ia = a
103
+ fb,ib = b
104
+
105
+ dira = fa.split(/[:_][^\/>]*$/).first
106
+ dirb = fb.split(/[:_][^\/>]*$/).first
107
+
108
+ case dira <=> dirb
109
+ when -1
110
+ -1
111
+ when 1
112
+ 1
113
+ else
114
+ ia[:ctime] <=> ib[:ctime]
115
+ end
116
+ end
117
+
118
+
119
+ persists = Scout.persist_info
120
+ if persists.any?
121
+ puts Log.color(:magenta, "Persist:")
122
+ persists.sort_by{|f,i| i[:ctime] }.each do |file,info|
123
+ elapsed = info[:elapsed]
124
+ puts " " << file + Log.color(:blue, " -- time: #{Misc.format_seconds elapsed}")
125
+ end
126
+ puts
127
+ end
128
+
129
+ sensiblewrites = Scout.sensiblewrite_info
130
+ if sensiblewrites.any?
131
+ puts Log.color(:magenta, "Writing:")
132
+ sensiblewrites.sort_by{|f,i| i[:ctime] }.each do |file,info|
133
+ elapsed = info[:elapsed]
134
+ puts " " << file + Log.color(:blue, " -- time: #{Misc.format_seconds elapsed}")
135
+ end
136
+ puts
137
+ end
138
+
139
+ locks = Scout.lock_info
140
+ if locks.any?
141
+ puts Log.color(:magenta, "Locks:")
142
+ locks.sort(&sort_files).each do |file,info|
143
+ elapsed, pid, ppid = info.values_at :elapsed, :pid, :ppid
144
+ puts " " << file + Log.color(:blue, " -- time: #{Misc.format_seconds elapsed}; ppid: #{ppid}; pid: #{pid_msg pid}")
145
+ end
146
+ puts
147
+ end
148
+
149
+ exit 0 if workflow.nil?
150
+ workflow = nil if workflow == ["all"]
151
+
152
+ puts Log.color(:magenta, "# Workflows")
153
+
154
+ if workflow === ['.']
155
+ jobs = Scout.job_info ["all"], task, ['.']
156
+ else
157
+ jobs = Scout.job_info workflow, task
158
+ end
159
+
160
+ workflows = {}
161
+
162
+ TSV.traverse jobs, :_bar => "Checking job status" do |file,info|
163
+ next unless all || ! info[:done] || ! File.exist?(file)
164
+ workflow = info[:workflow]
165
+ task = info[:task]
166
+ workflows[workflow] ||= {}
167
+ workflows[workflow][task] ||= {}
168
+ workflows[workflow][task][file] ||= info
169
+ end
170
+
171
+ workflows.sort.each do |workflow,tasks|
172
+ tasks.sort.each do |task,jobs|
173
+ puts "* " << Log.color(:magenta, workflow) << "#" << Log.color(:yellow, task) << ": " << Log.color(:blue, jobs.length.to_s)
174
+
175
+ files_txt = jobs.collect do |file, i|
176
+ str = file.dup
177
+ if options[:quick] and i[:done]
178
+ status = 'done'
179
+ str << " #{ Step.prov_status_msg status }"
180
+ if inputs and inputs.any?
181
+ str << input_msg(file, inputs)
182
+ end
183
+
184
+ if info_fields and info_fields.any?
185
+ info = begin
186
+ Open.open(i[:info_file]) do |f|
187
+ Step.load_info(f)
188
+ end
189
+ rescue
190
+ Log.exception $!
191
+ {:status => :noinfo}
192
+ end
193
+ IndiferentHash.setup(info)
194
+ str << info_msg(info, info_fields)
195
+ end
196
+ else
197
+ info = begin
198
+ Open.open(i[:info_file]) do |f|
199
+ Step.load_info(f)
200
+ end
201
+ rescue
202
+ {:status => :noinfo}
203
+ end
204
+ IndiferentHash.setup(info)
205
+
206
+ pid = info[:pid]
207
+ status = info[:status]
208
+ status = :missing if status == :done and not (Open.exist?(file) && ! Open.broken_link?(file))
209
+ status = :broken if Open.broken_link?(file)
210
+ status = status.to_s
211
+ if status != "done" and pid and not Misc.pid_alive?(pid)
212
+ if File.exist? file
213
+ status << Log.color(:red, " (out of sync)")
214
+ else
215
+ status << Log.color(:red, " (dead)")
216
+ end
217
+ end
218
+ str << " #{ Step.prov_status_msg status }"
219
+ str << " (dirty)" if status == 'done' && Step.new(file).dirty?
220
+
221
+ if inputs and inputs.any?
222
+ str << input_msg(file, inputs)
223
+ end
224
+
225
+ if info_fields and info_fields.any?
226
+ str << info_msg(info, info_fields)
227
+ end
228
+ end
229
+ str << "; #{pid_msg pid}" unless status == "done"
230
+ str
231
+ end
232
+
233
+ files_txt.each do |f|
234
+ next if f.nil?
235
+ puts " " << f
236
+ end
237
+ end
238
+ end
@@ -12,20 +12,12 @@ $ #{$0} <workflow> <command> [<subcommands>] [<options>] [<arg> ...]
12
12
 
13
13
  -h--help Print this help
14
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
15
 
24
16
  workflow = ARGV.shift
25
17
 
26
18
  if workflow == '-h'
27
19
  if defined? scout_usage
28
- scout_usage
20
+ scout_usage
29
21
  else
30
22
  puts SOPT.doc
31
23
  end
@@ -99,11 +91,11 @@ puts
99
91
  puts Log.color :magenta, "## COMMANDS"
100
92
  puts
101
93
  puts Log.color :magenta, "Command:"
102
- puts
94
+ puts
103
95
  puts " scout #{$previous_commands * " "} "
104
- puts
96
+ puts
105
97
  puts Log.color :magenta, "Subcommands:"
106
- puts
98
+ puts
107
99
 
108
100
  commands(prev).each do |command|
109
101
  directory = File.directory? dir[command].find
@@ -113,4 +105,4 @@ commands(prev).each do |command|
113
105
  puts " " << command
114
106
  end
115
107
  end
116
-
108
+
@@ -11,6 +11,8 @@ Show info from job
11
11
  $ #{$0} [<options>] <step_path>
12
12
 
13
13
  -h--help Print this help
14
+ -i--inputs Pretty print the inputs
15
+ -ri--recursive_inputs Pretty print the inputs (recursively)
14
16
  EOF
15
17
  if options[:help]
16
18
  if defined? scout_usage
@@ -25,17 +27,28 @@ path = ARGV.first
25
27
  raise MissingParameterException.new :step_path if path.nil?
26
28
  step = Step.load(path.dup)
27
29
 
28
- step.info.each do |k,v|
29
- case v
30
- when nil
30
+ if options[:inputs]
31
+ names, values = step.info.values_at :input_names, :inputs
32
+ names.zip(values).each do |name,value|
33
+ puts [Log.color(:title, name), Log.fingerprint(value)] * " = "
34
+ end if names
35
+ elsif options[:recursive_inputs]
36
+ step.recursive_inputs.each do |name,value|
37
+ puts [Log.color(:title, name), Log.fingerprint(value)] * " = "
38
+ end
39
+ else
40
+ step.info.each do |k,v|
41
+ case v
42
+ when nil
43
+ next
44
+ when Exception
45
+ puts Log.color(:title, "Exception")
46
+ Log.exception v
47
+ else
48
+ puts [Log.color(:title, k), Log.fingerprint(v)] * " = "
49
+ end
50
+ rescue
31
51
  next
32
- when Exception
33
- puts Log.color(:title, "Exception")
34
- Log.exception v
35
- else
36
- puts [Log.color(:title, k), Log.fingerprint(v)] * " = "
37
52
  end
38
- rescue
39
- next
40
53
  end
41
54
 
@@ -65,7 +65,7 @@ Misc.in_dir(workflow_dir) do
65
65
  Log.info "Installing: " + workflow
66
66
 
67
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/'
68
+ repo_base_url = Scout.etc.workflow_repo.exists? ? Scout.etc.workflow_repo.read.strip : 'https://github.com/Rbbt-Workflows/'
69
69
  else
70
70
  repo_base_url = base_repo
71
71
  end
@@ -16,10 +16,13 @@ Run a workflow job
16
16
  $ #{$0} [<options>] <workflow> <task>
17
17
 
18
18
  -h--help Print this help
19
+ --workflows* Other workflows to load
19
20
  --nostream Disable job streaming
20
21
  --update Update jobs with newer dependencies
21
22
  --deploy* Deploy mode: serial, local, queue, or SLURM (default 'serial')
23
+ --deploy_rules* Deployment rules; can be files of keywords
22
24
  --fork Fork and return path
25
+ --exec Exec and return output
23
26
  --load_inputs* Directory or file with inputs files to load
24
27
  --save_inputs* Directory or tar.gz file path to store inputs
25
28
  -jn--jobname* Name to use as job identifier
@@ -33,33 +36,45 @@ EOF
33
36
 
34
37
  workflow_name, task_name = ARGV
35
38
 
39
+
40
+ help, workflows, provenance, clean, recursive_clean, clean_task, load_inputs, save_inputs, jobname, printpath, deploy, deploy_rules, override_deps, do_fork, do_exec = IndiferentHash.process_options options,
41
+ :help, :workflows, :provenance, :clean, :recursive_clean, :clean_task, :load_inputs, :save_inputs, :jobname, :printpath, :deploy, :deploy_rules, :override_deps, :fork, :exec,
42
+ :deploy => 'serial'
43
+
36
44
  raise MissingParameterException.new :workflow if workflow_name.nil?
37
45
 
38
46
  workflow = Workflow.require_workflow workflow_name
47
+
48
+ workflows = workflows.split(/,\s*/) if workflows
49
+ workflows.each{|wf| Workflow.require_workflow wf } if workflows
50
+
39
51
  task_name = task_name.to_sym if task_name
40
52
  task = workflow.tasks[task_name.to_sym] if task_name
41
53
 
42
- options[:help] = true if task.nil?
43
-
44
- help, provenance, clean, recursive_clean, clean_task, load_inputs, save_inputs, jobname, printpath, deploy, override_deps, do_fork = IndiferentHash.process_options options,
45
- :help, :provenance, :clean, :recursive_clean, :clean_task, :load_inputs, :save_inputs, :jobname, :printpath, :deploy, :override_deps, :fork,
46
- :deploy => 'serial'
54
+ help = true if task.nil?
47
55
 
48
56
  if help
49
57
  if defined? scout_usage
50
- scout_usage
58
+ scout_usage
51
59
  else
52
60
  puts SOPT.doc
53
61
  end
54
62
 
55
63
  puts workflow.usage(task) if workflow
56
- exit 0
64
+
65
+ if task_name && task.nil?
66
+ exit -1
67
+ else
68
+ exit 0
69
+ end
57
70
  end
58
71
 
72
+ task = workflow.tasks[task_name]
73
+
59
74
  job_inputs = task.get_SOPT
60
75
 
61
76
  if load_inputs
62
- job_inputs = job_inputs.merge(workflow.tasks[task_name].load_inputs(load_inputs))
77
+ job_inputs = job_inputs.merge(task.load_inputs(load_inputs))
63
78
  end
64
79
 
65
80
  if override_deps
@@ -99,10 +114,21 @@ elsif do_fork
99
114
  job.fork
100
115
  puts job.path
101
116
  exit 0
117
+ elsif do_exec
118
+ puts job.exec
119
+ exit 0
102
120
  elsif save_inputs
103
121
  puts job.save_inputs(save_inputs)
104
122
  exit 0
105
123
  else
124
+ require 'scout/workflow/deployment'
125
+
126
+ if deploy_rules.nil?
127
+ rules = Workflow::Orchestrator.load_rules_for_job(job)
128
+ else
129
+ deploy_files = deploy_rules.split(/,\s*/)
130
+ rules = Workflow::Orchestrator.load_rules deploy_files
131
+ end
106
132
 
107
133
  case deploy
108
134
  when "queue"
@@ -112,28 +138,40 @@ else
112
138
  puts save_inputs
113
139
  exit
114
140
  end
141
+ when 'dry', 'dryrun', 'debug'
142
+ batches = Workflow::Orchestrator.job_batches rules, job
143
+ batches.each do |batch|
144
+ top = batch[:top_level]
145
+ jobs = batch[:jobs]
146
+ puts Log.color :title, Log.fingerprint(top)
147
+ puts batch[:rules].to_yaml
148
+ deps = batch[:deps].collect{|dep| dep[:top_level] }
149
+ provided_inputs = jobs.inject({}){|acc,j| acc = IndiferentHash.add_defaults acc, j.provided_inputs }
150
+ provided_inputs.each do |i,v|
151
+ puts Log.color :green, "#{i}: " + Log.color(:blue, Log.fingerprint(v))
152
+ end
153
+ other = jobs - [top]
154
+ puts Log.color :subtitle, 'Other jobs: ' + Log.color(:blue, other.collect{|d| d.short_path}.uniq * ', ' ) if other.any?
155
+ puts Log.color :subtitle, 'Dependencies: ' + Log.color(:blue, deps.collect{|d| d.short_path}.uniq * ', ' ) if deps.any?
156
+ end
157
+ exit 0
115
158
  when "serial"
116
159
  job.run(true)
117
160
  when "local"
118
- refresh = Scout::Config.get :refresh, :deploy, :local, :orchestrator, default: 0.5
119
- orchestrator = Workflow::Orchestrator.new refresh.to_f, "cpus" => Misc.processors
120
- orchestrator.process({}, job)
121
- when "slurm"
122
- require 'rbbt-scout'
123
- require_relative '../../modules/rbbt-util/lib/rbbt/hpc'
124
- slurm_options = {}
125
- HPC::BATCH_MODULE = HPC.batch_system "SLURM"
126
- HPC::BATCH_MODULE.orchestrate_job(job, slurm_options)
127
- job.grace
128
- else
129
- if deploy.end_with?('-slurm')
130
- server = deploy.sub('-slurm','')
131
- OffsiteStep.setup(job, server: server, slurm: true)
161
+ Workflow::LocalExecutor.produce job, rules
162
+ when 'batch', 'sched', 'cluster', "slurm", 'pbs', 'lsf'
163
+ Workflow::Scheduler.produce job, rules
164
+ exit 0
165
+ else
166
+ raise 'Use scout-camp instead of scout' unless defined? OffsiteStep
167
+ if deploy.end_with?('-batch')
168
+ server = deploy.sub('-batch','')
169
+ OffsiteStep.setup(job, server: server, batch: true)
132
170
  else
133
171
  OffsiteStep.setup(job, server: deploy)
134
172
  end
135
173
 
136
- job.run
174
+ job.run(true)
137
175
  end unless job.done?
138
176
 
139
177
  if printpath
@@ -147,5 +185,3 @@ else
147
185
  end
148
186
  end
149
187
  end
150
-
151
-
@@ -335,7 +335,7 @@ class TestEntityProperty < Test::Unit::TestCase
335
335
 
336
336
  def test_all_properties
337
337
  assert ReversableString.setup("TEST").all_properties.include?(:reverse_text_ary)
338
- assert_equal ReversableString.setup("TEST").all_properties, ReversableString.properties
338
+ assert_equal ReversableString.setup("TEST").all_properties.sort, ReversableString.properties.keys.sort
339
339
  end
340
340
 
341
341
  def test_times
@@ -31,5 +31,24 @@ Isa,IV
31
31
  end
32
32
  end
33
33
  end
34
+
35
+ def test_registry_identifiers_target
36
+ identifier =<<-EOF
37
+ #Alias,Initials
38
+ Clei,CC
39
+ Miki,MV
40
+ Guille,GC
41
+ Isa,IV
42
+ EOF
43
+ TmpFile.with_dir do |dir|
44
+ TmpFile.with_file(identifier) do |identifier_file|
45
+ identifiers = TSV.open(identifier_file, sep: ",", type: :single)
46
+ brothers = datafile_test(:person).brothers
47
+ kb = KnowledgeBase.new dir
48
+ kb.register :brothers, brothers, identifiers: identifiers
49
+ assert_include kb.get_index(:brothers, source: "=>Initials", target: "=>Initials"), "CC~GC"
50
+ end
51
+ end
52
+ end
34
53
  end
35
54
 
@@ -142,7 +142,7 @@ class TestWorkQueue < Test::Unit::TestCase
142
142
 
143
143
  res = []
144
144
  q.process do |out|
145
- raise ScoutException
145
+ raise ScoutException
146
146
  res << out
147
147
  end
148
148
 
@@ -156,7 +156,7 @@ class TestQueueWorker < Test::Unit::TestCase
156
156
  input = WorkQueue::Socket.new
157
157
  output = WorkQueue::Socket.new
158
158
 
159
- workers = 10.times.collect{ WorkQueue::Worker.new }
159
+ workers = 5.times.collect{ WorkQueue::Worker.new }
160
160
  workers.each do |w|
161
161
  w.process(input, output) do |obj|
162
162
  raise ScoutException
@@ -164,18 +164,19 @@ class TestQueueWorker < Test::Unit::TestCase
164
164
  end
165
165
  end
166
166
 
167
- read = Thread.new do
167
+ Open.purge_pipes(input.swrite, output.sread)
168
+ read = Thread.new do
168
169
  Thread.current.report_on_exception = false
169
- begin
170
- while obj = output.read
171
- if DoneProcessing === obj
172
- pid = obj.pid
173
- @worker_mutex.synchronize{ @workers.delete_if{|w| w.pid = pid } }
174
- break if workers.empty?
175
- end
176
- raise obj if Exception === obj
170
+ while obj = output.read
171
+ if DoneProcessing === obj
172
+ pid = obj.pid
173
+ @worker_mutex.synchronize{ @workers.delete_if{|w| w.pid = pid } }
174
+ break if workers.empty?
177
175
  end
176
+ raise obj if Exception === obj
178
177
  end
178
+ ensure
179
+ output.close_read
179
180
  end
180
181
 
181
182
  write = Thread.new do
@@ -187,6 +188,7 @@ class TestQueueWorker < Test::Unit::TestCase
187
188
  input.write DoneProcessing.new
188
189
  end
189
190
  input.close_write
191
+ rescue
190
192
  end
191
193
 
192
194
  write.join