miga-base 0.6.4.2 → 0.7.0.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.
@@ -1,6 +1,4 @@
1
1
 
2
- require 'daemons'
3
- require 'date'
4
2
  require 'shellwords'
5
3
 
6
4
  class MiGA::Daemon < MiGA::MiGA
@@ -55,21 +53,5 @@ module MiGA::Daemon::Base
55
53
  # complete
56
54
  def shutdown_when_done?() !!runopts(:shutdown_when_done); end
57
55
 
58
- ##
59
- # Initializes the daemon with +opts+
60
- def start(opts = []) daemon('start', opts); end
61
-
62
- ##
63
- # Stops the daemon with +opts+
64
- def stop(opts = []) daemon('stop', opts); end
65
-
66
- ##
67
- # Restarts the daemon with +opts+
68
- def restart(opts = []) daemon('restart', opts); end
69
-
70
- ##
71
- # Returns the status of the daemon with +opts+.
72
- def status(opts = []) daemon('status', opts); end
73
-
74
56
  end
75
57
 
data/lib/miga/lair.rb CHANGED
@@ -1,20 +1,14 @@
1
1
  # @package MiGA
2
2
  # @license Artistic-2.0
3
3
 
4
- require 'daemons'
5
4
  require 'miga/daemon'
5
+ require 'miga/common/with_daemon'
6
6
 
7
7
  ##
8
8
  # Lair of MiGA Daemons handling job submissions
9
9
  class MiGA::Lair < MiGA::MiGA
10
- ##
11
- # When was the last time the chief daemon in this lair was seen active?
12
- # Returns Time
13
- def self.last_alive(path)
14
- f = File.expand_path('.lair-alive', path)
15
- return nil unless File.exist? f
16
- Time.parse(File.read(f))
17
- end
10
+ include MiGA::Common::WithDaemon
11
+ extend MiGA::Common::WithDaemonClass
18
12
 
19
13
  # Absolute path to the directory where the projects are located
20
14
  attr_reader :path
@@ -22,69 +16,81 @@ class MiGA::Lair < MiGA::MiGA
22
16
  # Options used to setup the chief daemon
23
17
  attr_accessor :options
24
18
 
25
- # Integer indicating the current iteration
26
- attr_reader :loop_i
27
-
28
19
  ##
29
20
  # Initialize an inactive daemon for the directory at +path+. See #daemon
30
21
  # to wake the chief daemon. Supported options include:
31
22
  # - json: json definition for all children daemons, by default: nil
32
23
  # - latency: time to wait between iterations in seconds, by default: 120
33
24
  # - wait_for: time to wait for a daemon to report being alive in seconds,
34
- # by default: 900
25
+ # by default: 30
35
26
  # - keep_inactive: boolean indicating if daemons should stay alive even when
36
27
  # inactive (when all tasks are complete), by default: false
37
28
  # - name: A name for the chief daemon process, by default: basename of +path+
29
+ # - trust_timestamp: boolean indicating if the +modified+ timestamp of the
30
+ # project is to be trusted to determine changes in the project,
31
+ # by default: true
32
+ # - dry: Only report when daemons would be launched, but don't actually launch
33
+ # them
38
34
  def initialize(path, opts = {})
39
35
  @path = File.expand_path(path)
40
36
  @options = opts
41
- @loop_i = -1
42
37
  {
43
38
  json: nil,
44
- latency: 120,
45
- wait_for: 900,
39
+ latency: 30,
40
+ wait_for: 30,
46
41
  keep_inactive: false,
47
- name: File.basename(@path)
42
+ trust_timestamp: true,
43
+ name: File.basename(@path),
44
+ dry: false
48
45
  }.each { |k, v| @options[k] = v if @options[k].nil? }
49
46
  end
50
47
 
51
48
  ##
52
- # When was the last time the chief daemon for was seen active here?
53
- # Returns Time.
54
- def last_alive
55
- MiGA::Lair.last_alive path
49
+ # Path to the lair's chief daemon's home
50
+ alias daemon_home path
51
+
52
+ ##
53
+ # Name of the lair's chief daemon
54
+ def daemon_name
55
+ "MiGA:#{options[:name]}"
56
+ end
57
+
58
+ ##
59
+ # First loop of the lair's chief daemon
60
+ def daemon_first_loop
61
+ say '-----------------------------------'
62
+ say '%s launched' % daemon_name
63
+ say '-----------------------------------'
64
+ say 'Configuration options:'
65
+ say options.to_s
56
66
  end
57
67
 
58
68
  ##
59
- # Returns Hash containing the default options for the daemon.
60
- def default_options
61
- { dir_mode: :normal, dir: path, multiple: false, log_output: true }
69
+ # Run one loop step. Returns a Boolean indicating if the loop should continue.
70
+ def daemon_loop
71
+ check_directories
72
+ return false if options[:dry]
73
+ sleep(options[:latency])
74
+ true
62
75
  end
63
76
 
64
77
  ##
65
- # Launches the +task+ with options +opts+ (as command-line arguments) and
66
- # returns the process ID as an Integer. If +wait+ it waits for the process to
67
- # complete, immediately returns otherwise.
68
- # Supported tasks: start, stop, restart, status.
69
- def daemon(task, opts = [], wait = true)
70
- MiGA.DEBUG "Lair.daemon #{task} #{opts}"
71
- config = default_options
72
- opts.unshift(task.to_s)
73
- config[:ARGV] = opts
74
- # This additional degree of separation below was introduced so the Daemons
75
- # package doesn't kill the parent process in workflows.
76
- pid = fork do
77
- Daemons.run_proc("MiGA:#{options[:name]}", config) { while in_loop; end }
78
+ # Terminate all daemons in the lair (including the chief daemon)
79
+ def terminate_daemons
80
+ terminate_daemon(self)
81
+ each_project do |project|
82
+ terminate_daemon(MiGA::Daemon.new(project))
78
83
  end
79
- Process.wait(pid) if wait
80
- pid
81
84
  end
82
85
 
83
86
  ##
84
- # Tell the world that you're alive.
85
- def declare_alive
86
- File.open(File.join(path, '.lair-alive'), 'w') do |fh|
87
- fh.print Time.now.to_s
87
+ # Send termination message to +daemon+, an object implementing
88
+ # +MiGA::Common::WithDaemon+
89
+ def terminate_daemon(daemon)
90
+ say "Probing #{daemon.class} #{daemon.daemon_home}"
91
+ if daemon.active?
92
+ say 'Sending termination message'
93
+ FileUtils.touch(daemon.terminate_file)
88
94
  end
89
95
  end
90
96
 
@@ -94,13 +100,14 @@ class MiGA::Lair < MiGA::MiGA
94
100
  # Searches for MiGA projects recursively in all
95
101
  # subdirectories that are not MiGA projects.
96
102
  def each_project(dir = path)
97
- Dir.children(dir).each do |f|
103
+ Dir.entries(dir).each do |f|
104
+ next if %w[. ..].include?(f) # Ruby <= 2.3 doesn't have Dir.children
98
105
  f = File.join(dir, f)
99
106
  if MiGA::Project.exist? f
100
107
  project = MiGA::Project.load(f)
101
108
  raise "Cannot load project: #{f}" if project.nil?
102
109
  yield(project)
103
- elsif Dir.exists? f
110
+ elsif Dir.exist? f
104
111
  each_project(f) { |project| yield(project) }
105
112
  end
106
113
  end
@@ -110,8 +117,13 @@ class MiGA::Lair < MiGA::MiGA
110
117
  # Traverse directories checking MiGA projects
111
118
  def check_directories
112
119
  each_project do |project|
113
- alive = MiGA::Daemon.last_alive(project)
114
- next if !alive.nil? && alive > Time.now - options[:wait_for]
120
+ d = MiGA::Daemon.new(project)
121
+ next if d.active?
122
+ l_alive = d.last_alive
123
+ unless l_alive.nil?
124
+ next if options[:trust_timestamp] && project.metadata.updated < l_alive
125
+ next if l_alive > Time.now - options[:wait_for]
126
+ end
115
127
  launch_daemon(project)
116
128
  end
117
129
  end
@@ -122,32 +134,9 @@ class MiGA::Lair < MiGA::MiGA
122
134
  say "Launching daemon: #{project.path}"
123
135
  d = MiGA::Daemon.new(project, options[:json])
124
136
  d.runopts(:shutdown_when_done, true) unless options[:keep_inactive]
125
- d.daemon(:start, [], false)
126
- end
127
-
128
- ##
129
- # Run one loop step. Returns a Boolean indicating if the loop should continue.
130
- def in_loop
131
- declare_alive
132
- if loop_i == -1
133
- say '-----------------------------------'
134
- say 'MiGA:%s launched' % options[:name]
135
- say '-----------------------------------'
136
- say 'Configuration options:'
137
- say options.to_s
138
- @loop_i = 0
137
+ unless options[:dry]
138
+ d.start
139
+ sleep(1) # <- to make sure the daemon started up (it takes about 0.1 secs)
139
140
  end
140
- @loop_i += 1
141
- check_directories
142
- sleep(options[:latency])
143
- true
144
- end
145
-
146
- ##
147
- # Terminates a chief daemon
148
- def terminate
149
- say 'Terminating chief daemon...'
150
- f = File.expand_path('.lair-alive', project.path)
151
- File.unlink(f) if File.exist? f
152
141
  end
153
142
  end
data/lib/miga/metadata.rb CHANGED
@@ -135,6 +135,18 @@ class MiGA::Metadata < MiGA::MiGA
135
135
  data.each { |k, v| blk.call(k, v) }
136
136
  end
137
137
 
138
+ ##
139
+ # Time of last update
140
+ def updated
141
+ Time.parse(self[:updated]) unless self[:updated].nil?
142
+ end
143
+
144
+ ##
145
+ # Time of creation
146
+ def created
147
+ Time.parse(self[:created]) unless self[:created].nil?
148
+ end
149
+
138
150
  ##
139
151
  # Show contents in JSON format as a String
140
152
  def to_json
data/lib/miga/version.rb CHANGED
@@ -10,7 +10,7 @@ module MiGA
10
10
  # - Float representing the major.minor version.
11
11
  # - Integer representing gem releases of the current version.
12
12
  # - Integer representing minor changes that require new version number.
13
- VERSION = [0.6, 4, 2]
13
+ VERSION = [0.7, 0, 0]
14
14
 
15
15
  ##
16
16
  # Nickname for the current major.minor version.
@@ -18,7 +18,7 @@ module MiGA
18
18
 
19
19
  ##
20
20
  # Date of the current gem release.
21
- VERSION_DATE = Date.new(2020, 4, 15)
21
+ VERSION_DATE = Date.new(2020, 4, 18)
22
22
 
23
23
  ##
24
24
  # Reference of MiGA.
data/test/common_test.rb CHANGED
@@ -33,7 +33,7 @@ class CommonTest < Test::Unit::TestCase
33
33
  err = capture_stderr do
34
34
  MiGA::MiGA.DEBUG 'Dandadi'
35
35
  end
36
- assert(err.string =~ /Dandadi\n .*block in test_debug_trace/)
36
+ assert_match(/Dandadi\n .*block in test_debug_trace/, err.string)
37
37
  MiGA::MiGA.DEBUG_TRACE_OFF
38
38
  err = capture_stderr do
39
39
  MiGA::MiGA.DEBUG 'Dandada'
@@ -66,7 +66,7 @@ class CommonTest < Test::Unit::TestCase
66
66
  assert_raise do
67
67
  File.generic_transfer(hello, world, :monkey)
68
68
  end
69
- assert(!File.exist?(world), 'A monkey shouldn\'t create files.')
69
+ assert_path_not_exist(world, 'A monkey shouldn\'t create files.')
70
70
  ensure
71
71
  FileUtils.rm_rf $tmp
72
72
  end
@@ -75,8 +75,8 @@ class CommonTest < Test::Unit::TestCase
75
75
  assert_equal('Xa sp. C', 'Xa_sp__C'.unmiga_name)
76
76
  assert_equal('X_______', 'X^*.!{}!'.miga_name)
77
77
  assert_equal('aB09', 'aB09'.miga_name)
78
- assert('R2D2'.miga_name?)
79
- assert(!'C3-PO'.miga_name?)
78
+ assert_predicate('R2D2', :miga_name?)
79
+ assert_not_predicate('C3-PO', :miga_name?)
80
80
  assert_equal("123\n1\n", '1231'.wrap_width(3))
81
81
  end
82
82
 
data/test/daemon_test.rb CHANGED
@@ -42,8 +42,8 @@ class DaemonTest < Test::Unit::TestCase
42
42
  def test_check_project
43
43
  d1 = $d1
44
44
  helper_datasets_with_results.first.inactivate!
45
- out = capture_stdout { d1.check_project }
46
- assert(out.string =~ /Queueing miga-project:p/)
45
+ out = capture_stderr { d1.check_project }
46
+ assert_match(/Queueing miga-project:p/, out.string)
47
47
  assert_equal(1, d1.jobs_to_run.size)
48
48
  assert_equal(:p, d1.jobs_to_run.first[:job])
49
49
  assert_equal('project1:p:miga-project', d1.get_job(:p)[:task_name])
@@ -53,10 +53,10 @@ class DaemonTest < Test::Unit::TestCase
53
53
  p = $p1
54
54
  d = $d1
55
55
  d.runopts(:maxjobs, 0, true)
56
- assert(d.jobs_to_run.empty?)
56
+ assert_empty(d.jobs_to_run)
57
57
  ds = p.add_dataset('ds1')
58
58
  d.check_datasets
59
- assert(d.jobs_to_run.empty?)
59
+ assert_empty(d.jobs_to_run)
60
60
  FileUtils.cp(
61
61
  File.expand_path('daemon/daemon.json', p.path),
62
62
  File.expand_path('data/01.raw_reads/ds1.1.fastq', p.path)
@@ -66,10 +66,10 @@ class DaemonTest < Test::Unit::TestCase
66
66
  File.expand_path('data/01.raw_reads/ds1.done', p.path)
67
67
  )
68
68
  ds.first_preprocessing(true)
69
- out = capture_stdout do
69
+ out = capture_stderr do
70
70
  d.check_datasets
71
71
  end
72
- assert(out.string =~ /Queueing #{ds.name}:d/)
72
+ assert_match(/Queueing #{ds.name}:d/, out.string)
73
73
  assert_equal(1, d.jobs_to_run.size)
74
74
  assert_equal('echo project1:d:ds1 >/dev/null', d.jobs_to_run.first[:cmd])
75
75
  assert_equal(d.jobs_to_run.first, d.get_job(:d, ds))
@@ -79,15 +79,15 @@ class DaemonTest < Test::Unit::TestCase
79
79
  p = $p1
80
80
  d = $d1
81
81
  d.runopts(:latency, 0, true)
82
- assert_equal(-1, d.loop_i)
82
+ assert_nil(d.loop_i)
83
83
  assert_nil(d.last_alive)
84
- out = capture_stdout { d.in_loop }
84
+ out = capture_stderr { d.in_loop }.string
85
85
  assert_equal(Time, d.last_alive.class)
86
- assert(out.string =~ /-{20}\n.*MiGA:#{p.name} launched/)
87
- 10.times{ d.in_loop }
86
+ assert_match(/-{20}\n.*MiGA:#{p.name} launched/, out)
87
+ 11.times { d.in_loop }
88
88
  assert_equal(11, d.loop_i)
89
- out = capture_stdout { d.in_loop }
90
- assert(out.string =~ /Probing running jobs/)
89
+ out = capture_stderr { d.in_loop }.string
90
+ assert_match(/Probing running jobs/, out)
91
91
  assert_equal(0, d.loop_i)
92
92
  end
93
93
 
@@ -98,25 +98,24 @@ class DaemonTest < Test::Unit::TestCase
98
98
  assert_equal(0, d.latency)
99
99
  omit_if($jruby_tests, 'JRuby doesn\'t implement fork.')
100
100
  child = $child = d.daemon(:start, ['--shush'])
101
- assert(child.is_a? Integer)
102
- assert(child != 0, 'The daemond process should have non-zero PID')
101
+ assert_not_nil(child)
102
+ assert_gt(child, 1)
103
103
  assert_equal(0, `ps -p "#{child}" -o ppid=`.strip.to_i,
104
104
  'The daemon process should be detached')
105
105
  sleep(3)
106
- dpath = File.join(p.path, 'daemon', "MiGA:#{p.name}")
107
- assert(File.exist?("#{dpath}.pid"))
108
- out = capture_stdout { d.stop }
106
+ assert_path_exist(d.pid_file)
107
+ out = capture_stderr { d.stop }.string
109
108
  assert_raise(Errno::ESRCH) { Process.kill(0, child) }
110
- assert_equal('', out.string)
111
- assert(!File.exist?("#{dpath}.pid"))
112
- assert(File.exist?("#{dpath}.output"))
113
- File.open("#{dpath}.output", "r") do |fh|
114
- l = fh.each_line.to_a
115
- assert(l[0] =~ /-{20}\n/)
116
- assert(l[1] =~ /MiGA:#{p.name} launched/)
117
- assert(l[2] =~ /-{20}\n/)
118
- assert(l[5] =~ /Probing running jobs\n/)
119
- end
109
+ assert_match(/Sending termination message/, out)
110
+ assert_path_not_exist(d.pid_file)
111
+ assert_path_exist(d.output_file)
112
+ l = File.readlines(d.output_file)
113
+ {
114
+ 0 => /-{20}\n/,
115
+ 1 => /MiGA:#{p.name} launched/,
116
+ 2 => /-{20}\n/,
117
+ 5 => /Probing running jobs\n/
118
+ }.each { |k, v| assert_match(v, l[k], "unexpected line: #{k}") }
120
119
  ensure
121
120
  begin
122
121
  Process.kill('KILL', $child) if !$child.nil?
@@ -129,8 +128,9 @@ class DaemonTest < Test::Unit::TestCase
129
128
  p = MiGA::Project.new(File.expand_path('last_alive', $tmp))
130
129
  d = MiGA::Daemon.new(p)
131
130
  assert_nil(d.last_alive)
131
+ omit_if($jruby_tests, 'JRuby doesn\'t implement fork.')
132
132
  d.declare_alive
133
- assert(d.last_alive - Time.now < 1)
133
+ assert_lt(d.last_alive, Time.now)
134
134
  end
135
135
 
136
136
  def test_options
@@ -150,17 +150,28 @@ class DaemonTest < Test::Unit::TestCase
150
150
  end
151
151
 
152
152
  def test_say
153
- out = capture_stdout { $d1.say 'Olm' }
154
- assert(out.string =~ /^\[.*\] Olm/)
153
+ out = capture_stderr { $d1.say 'Olm' }.string
154
+ assert_match(/^\[.*\] Olm/, out)
155
155
  end
156
156
 
157
157
  def test_terminate
158
158
  d = $d1
159
+ assert_not_predicate(d, :active?)
160
+ assert_path_not_exist(d.alive_file)
161
+ assert_path_not_exist(d.terminated_file)
162
+
163
+ omit_if($jruby_tests, 'JRuby doesn\'t implement fork.')
159
164
  d.declare_alive
165
+ assert_predicate(d, :active?)
166
+ assert_not_nil(d.last_alive)
167
+ assert_path_exist(d.alive_file)
168
+ assert_path_not_exist(d.terminated_file)
169
+
170
+ d.terminate
171
+ assert_path_not_exist(d.alive_file)
172
+ assert_path_exist(d.terminated_file)
173
+ assert_not_predicate(d, :active?)
160
174
  assert_not_nil(d.last_alive)
161
- out = capture_stdout { d.terminate }
162
- assert(out.string =~ /Terminating daemon/)
163
- assert_nil(d.last_alive)
164
175
  end
165
176
 
166
177
  def test_maxjobs_json
@@ -168,7 +179,7 @@ class DaemonTest < Test::Unit::TestCase
168
179
  helper_datasets_with_results(3)
169
180
  assert_equal(0, d1.jobs_running.size)
170
181
  assert_equal(0, d1.jobs_to_run.size)
171
- capture_stdout { d1.in_loop }
182
+ capture_stderr { d1.in_loop }
172
183
  assert_equal(1, d1.jobs_running.size)
173
184
  assert_equal(2, d1.jobs_to_run.size)
174
185
  end
@@ -179,7 +190,7 @@ class DaemonTest < Test::Unit::TestCase
179
190
  d1.runopts(:maxjobs, 2)
180
191
  assert_equal(0, d1.jobs_running.size)
181
192
  assert_equal(0, d1.jobs_to_run.size)
182
- capture_stdout { d1.in_loop }
193
+ capture_stderr { d1.in_loop }
183
194
  assert_equal(2, d1.jobs_running.size)
184
195
  assert_equal(1, d1.jobs_to_run.size)
185
196
  end
@@ -195,9 +206,9 @@ class DaemonTest < Test::Unit::TestCase
195
206
  File.open(f, 'w') do |h|
196
207
  h.puts '{"jobs_running":[{"ds":1,"ds_name":"d1"},{}],"jobs_to_run":[]}'
197
208
  end
198
- out = capture_stdout { d1.load_status }
209
+ out = capture_stderr { d1.load_status }.string
199
210
  assert_equal(2, d1.jobs_running.size)
200
- assert(out.string =~ /Loading previous status/)
211
+ assert_match(/Loading previous status/, out)
201
212
  assert_equal(MiGA::Dataset, d1.jobs_running[0][:ds].class)
202
213
  assert_nil(d1.jobs_running[1][:ds])
203
214
  end
@@ -215,10 +226,10 @@ class DaemonTest < Test::Unit::TestCase
215
226
  '{"job":"trimmed_reads","ds":1,"ds_name":"d0"}]' \
216
227
  ',"jobs_to_run":[]}'
217
228
  end
218
- capture_stdout { d1.load_status }
229
+ capture_stderr { d1.load_status }
219
230
  assert_equal(3, d1.jobs_running.size)
220
- out = capture_stdout { d1.flush! }
221
- assert(out.string =~ /Completed pid:/)
231
+ out = capture_stderr { d1.flush! }.string
232
+ assert_match(/Completed pid:/, out)
222
233
  assert_equal([], d1.jobs_running)
223
234
  end
224
235
 
@@ -227,8 +238,8 @@ class DaemonTest < Test::Unit::TestCase
227
238
  f = File.join($tmp, 'nodes.txt')
228
239
  File.open(f, 'w') { |h| h.puts 'localhost' }
229
240
  assert_equal(true, d1.next_host)
230
- out = capture_stdout { d1.runopts(:nodelist, f) }
231
- assert(out.string =~ /Reading node list:/)
241
+ out = capture_stderr { d1.runopts(:nodelist, f) }.string
242
+ assert_match(/Reading node list:/, out)
232
243
  assert_equal(true, d1.next_host)
233
244
  d1.runopts(:type, 'ssh')
234
245
  assert_equal(0, d1.next_host)
@@ -236,14 +247,14 @@ class DaemonTest < Test::Unit::TestCase
236
247
  File.open(f, 'w') do |h|
237
248
  h.puts '{"jobs_running":[{"job":"p","hostk":0}], "jobs_to_run":[]}'
238
249
  end
239
- capture_stdout { d1.load_status }
250
+ capture_stderr { d1.load_status }
240
251
  assert_nil(d1.next_host)
241
252
  end
242
253
 
243
254
  def test_shutdown_when_done
244
255
  $d1.runopts(:shutdown_when_done, true)
245
- out = capture_stdout { assert(!$d1.in_loop) }
246
- assert(out.string =~ /Nothing else to do/)
256
+ out = capture_stderr { assert { !$d1.in_loop } }.string
257
+ assert_match(/Nothing else to do/, out)
247
258
  end
248
259
 
249
260
  def test_update_format_0
@@ -276,7 +287,7 @@ class DaemonTest < Test::Unit::TestCase
276
287
  d1.runopts(:nodelist, '$MIGA_TEST_NODELIST')
277
288
  end
278
289
  ENV['MIGA_TEST_NODELIST'] = f
279
- capture_stdout { d1.runopts(:nodelist, '$MIGA_TEST_NODELIST') }
290
+ capture_stderr { d1.runopts(:nodelist, '$MIGA_TEST_NODELIST') }
280
291
  helper_daemon_launch_job
281
292
  assert_equal("project1:p:miga-project\n", File.read(t))
282
293
  end
@@ -293,20 +304,22 @@ class DaemonTest < Test::Unit::TestCase
293
304
  d1.runopts(:type, 'qsub')
294
305
  d1.runopts(:cmd, 'echo ""')
295
306
  helper_datasets_with_results.first.inactivate!
296
- capture_stdout { d1.check_project }
297
- out = capture_stdout { d1.launch_job(d1.jobs_to_run.shift) }
298
- assert(out.string =~ /Unsuccessful project1:p:miga-project, rescheduling/)
307
+ capture_stderr { d1.check_project }
308
+ omit_if($jruby_tests, 'JRuby doesn\'t implement fork.')
309
+ out = capture_stderr { d1.launch_job(d1.jobs_to_run.shift) }.string
310
+ assert_match(/Unsuccessful project1:p:miga-project, rescheduling/, out)
299
311
  assert_equal(0, d1.jobs_running.size)
300
312
  assert_equal(1, d1.jobs_to_run.size)
301
313
  end
302
314
 
303
315
  def helper_daemon_launch_job
316
+ omit_if($jruby_tests, 'JRuby doesn\'t implement fork.')
304
317
  d1 = $d1
305
318
  helper_datasets_with_results.first.inactivate!
306
319
  assert_equal(0, d1.jobs_to_run.size, 'The queue should be empty')
307
- capture_stdout { d1.check_project }
320
+ capture_stderr { d1.check_project }
308
321
  assert_equal(1, d1.jobs_to_run.size, 'The queue should have one job')
309
- capture_stdout { d1.flush! }
322
+ capture_stderr { d1.flush! }
310
323
  sleep(1)
311
324
  assert_equal(0, d1.jobs_to_run.size, 'There should be nothing running')
312
325
  assert_equal(1, d1.jobs_running.size, 'There should be one job running')