jobmanager 1.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.
Files changed (43) hide show
  1. data/FAQ.txt +151 -0
  2. data/History.txt +2 -0
  3. data/LICENSE +20 -0
  4. data/Manifest.txt +42 -0
  5. data/README.txt +395 -0
  6. data/Rakefile +17 -0
  7. data/bin/jobmanager +20 -0
  8. data/examples/email_settings.rb +14 -0
  9. data/examples/example.rb +23 -0
  10. data/examples/jobmanager.yaml +66 -0
  11. data/examples/mysql_backup.rb +18 -0
  12. data/lib/jobmanager.rb +1 -0
  13. data/lib/jobmanager/application.rb +455 -0
  14. data/lib/jobmanager/applicationconfig.rb +89 -0
  15. data/lib/jobmanager/applicationlogger.rb +306 -0
  16. data/lib/jobmanager/applicationoptionparser.rb +163 -0
  17. data/lib/jobmanager/system.rb +240 -0
  18. data/lib/jobmanager/teestream.rb +78 -0
  19. data/lib/jobmanager/util.rb +25 -0
  20. data/test/configs/all_values.yaml +33 -0
  21. data/test/configs/bad_email_condition.yaml +7 -0
  22. data/test/configs/bad_no_central_log_file.yaml +7 -0
  23. data/test/configs/bad_number_of_job_logs.yaml +7 -0
  24. data/test/configs/bad_timeout_zero.yaml +7 -0
  25. data/test/configs/email_settings.rb +16 -0
  26. data/test/configs/incomplete_1.yaml +23 -0
  27. data/test/configs/jobmanager_1.yaml +9 -0
  28. data/test/configs/jobmanager_2.yaml +11 -0
  29. data/test/configs/jobmanager_3.yaml +13 -0
  30. data/test/configs/jobmanager_4_bad_central_log_file.yaml +9 -0
  31. data/test/configs/jobmanager_4_bad_email_settings_file.yaml +9 -0
  32. data/test/configs/jobmanager_4_bad_job_logs_directory_1.yaml +9 -0
  33. data/test/configs/jobmanager_4_bad_job_logs_directory_2.yaml +9 -0
  34. data/test/configs/minimum_plus_email_settings.yaml +9 -0
  35. data/test/configs/minimum_required.yaml +5 -0
  36. data/test/helpers.rb +7 -0
  37. data/test/mock_syslog.rb +68 -0
  38. data/test/test_applicationlogger.rb +145 -0
  39. data/test/test_config.rb +208 -0
  40. data/test/test_jobmanager.rb +443 -0
  41. data/test/test_system.rb +206 -0
  42. data/test/test_teestream.rb +55 -0
  43. metadata +172 -0
@@ -0,0 +1,443 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'yaml'
4
+ require 'stringio'
5
+ require 'logger'
6
+ require 'zlib'
7
+ require 'fileutils'
8
+
9
+ require 'rubygems'
10
+ require 'relative'
11
+ require 'assertions'
12
+ require 'sys/host'
13
+
14
+ require 'configtoolkit'
15
+ require 'configtoolkit/yamlreader'
16
+ require 'configtoolkit/yamlwriter'
17
+ require 'configtoolkit/overridereader'
18
+
19
+ require 'jobmanager'
20
+
21
+ require 'test/unit'
22
+ require_relative('helpers')
23
+ require 'mock_syslog'
24
+
25
+ #
26
+ # This class essentially tests the bin/jobmanager application since
27
+ # the bin/jobmanager application does little more than call into the
28
+ # JobManager::Application class, which this test class directly tests.
29
+ #
30
+
31
+ class TestJobManager < Test::Unit::TestCase
32
+ include TestHelpers
33
+
34
+ CONFIG_DIR = PathRelativeToCaller.new("./configs")
35
+
36
+ LOG_DIR = "#{TEMP_DIR}/logs"
37
+
38
+ PROGRAM_NAME = $0
39
+ USER_NAME = Etc.getpwuid(Process::Sys.getuid()).name()
40
+ HOST_NAME = Sys::Host.hostname
41
+
42
+ # override the interactive shell calculation, and set to false
43
+ INTERACTIVE_SHELL_OVERRIDE = false
44
+
45
+ def setup
46
+ teardown()
47
+
48
+ FileUtils.mkdir_p(TEMP_DIR)
49
+ FileUtils.mkdir_p(LOG_DIR)
50
+
51
+ ActionMailer::Base.delivery_method = :test
52
+ ActionMailer::Base.deliveries = []
53
+ end
54
+
55
+ def teardown
56
+ FileUtils::rm_r(TEMP_DIR, :force => true)
57
+ end
58
+
59
+ # Invoke the JobManager::Application a number of times to launch the
60
+ # echo command. Confirm the output logs produced (the job log file
61
+ # and the central log file). Also, confirm that the job logs are
62
+ # properly rotated.
63
+ def test_jobmanager_1
64
+ config_file = File.join(CONFIG_DIR, "jobmanager_1.yaml")
65
+ config = File.open(config_file) { |fs| YAML::load(fs) }
66
+
67
+ user_name = USER_NAME
68
+ central_log_file = ERB.new(config["central_log_file"]).result(binding)
69
+ job_logs_directory = ERB.new(config["job_logs_directory"]).result(binding)
70
+
71
+ 1.upto(config["number_of_job_logs"] + 1) do |iteration|
72
+ args = [ "echo #{iteration}" ]
73
+
74
+ jobmanager = JobManager::Application.new(PROGRAM_NAME,
75
+ args,
76
+ config_file,
77
+ INTERACTIVE_SHELL_OVERRIDE)
78
+ jobmanager.run()
79
+
80
+ # Confirm that nothing was logged via syslog - The central log
81
+ # should be written to a file, not via syslog!
82
+ assert_equal("", $test_syslog_logger.string())
83
+ STDERR.print "\nJob Manager Pre Log Contents #1:\n"
84
+ STDERR.print $test_syslog_logger.string(), "\n"
85
+
86
+ jobmanager_log_contents = File.read(central_log_file)
87
+
88
+ print "\nJob Manager Log Contents #1:\n"
89
+ print jobmanager_log_contents, "\n"
90
+
91
+ lines = jobmanager_log_contents.split("\n")
92
+ assert_match(/^I, .* INFO .* \[#{USER_NAME}, echo\] Exited successfully$/, lines[1])
93
+
94
+ lines.each { |line| assert_no_match(/^ERROR/, line) }
95
+
96
+ # confirm correctness of the job log file.
97
+ job_log_file = "#{job_logs_directory}/echo.log.1"
98
+ assert(File.file?(job_log_file))
99
+
100
+ print "\nContents of #{job_log_file}:\n"
101
+ print File.read(job_log_file), "\n"
102
+
103
+ expected_contents = "#{iteration}\n"
104
+ assert_equal(expected_contents, File.read(job_log_file))
105
+ end
106
+
107
+ # confirm only number_of_job_logs log files have been kept (the
108
+ # rest discarded via the log rotation mechanism inside
109
+ # JobManager::Application).
110
+ assert_equal(config["number_of_job_logs"],
111
+ Dir.glob("#{job_logs_directory}/echo.log.*").length)
112
+ end
113
+
114
+ # Invoke the JobManager::Application to launch the echo command.
115
+ # Confirm the output logs produced (the job log file and the central
116
+ # log) are correct. This test configures JobManager::Application to
117
+ # log central log information via syslog, which has been mocked out
118
+ # for testing purposes. Confirm the email generated is correct, and
119
+ # that the job log is properly rotated and zipped.
120
+ def test_jobmanager_2
121
+ config_file = File.join(CONFIG_DIR, "jobmanager_2.yaml")
122
+ command_line_args = [ "-j", "ze_echoer",
123
+ "echo 1"
124
+ ]
125
+
126
+ # Load the ApplicationConfig class ourselves (the
127
+ # JobManager::Application class will also load the configuration
128
+ # separately).
129
+ yaml_reader = ConfigToolkit::YAMLReader.new(config_file)
130
+ command_parameters_hash = JobManager::ApplicationOptionParser.parse(PROGRAM_NAME, command_line_args.dup())
131
+ hash_reader = ConfigToolkit::HashReader.new(command_parameters_hash)
132
+ override_reader = ConfigToolkit::OverrideReader.new(yaml_reader, hash_reader)
133
+ config = JobManager::ApplicationConfig.load(override_reader)
134
+
135
+ # We need to test embedding the user_name variable in the
136
+ # email_settings_file parameter. Edit the email_settings_file to
137
+ # include this variable, and then write the new configuration to a
138
+ # temporary location. We will then pass this newly created
139
+ # configuration file to the JobManager::Application class.
140
+ config.email_settings_file = File.expand_path(TEMP_DIR) + "/<%=user_name%>/email_settings.rb"
141
+ new_config_file = "#{TEMP_DIR}/jobmanager_2.yaml"
142
+
143
+ # write the new config to a temporary location
144
+ File.open(new_config_file, "w") do |file_stream|
145
+ config.dump(ConfigToolkit::YAMLWriter.new(file_stream, true))
146
+ end
147
+
148
+ # copy the email settings file in the standard config directory to
149
+ # the email settings file referenced in the new config.
150
+ user_name = USER_NAME
151
+ evaluated_file = ERB.new(config.email_settings_file).result(binding)
152
+ FileUtils.mkdir_p(File.dirname(evaluated_file))
153
+ FileUtils.cp("#{CONFIG_DIR}/email_settings.rb", evaluated_file)
154
+
155
+ jobmanager = JobManager::Application.new(PROGRAM_NAME,
156
+ command_line_args.dup(),
157
+ new_config_file,
158
+ INTERACTIVE_SHELL_OVERRIDE)
159
+ jobmanager.run()
160
+
161
+ user_name = USER_NAME
162
+ job_logs_directory = ERB.new(config.job_logs_directory).result(binding)
163
+
164
+ # confirm correctness of the central log.
165
+ jobmanager_log_contents = $test_syslog_logger.string()
166
+
167
+ print "\nJob Manager Log Contents #2:\n"
168
+ print jobmanager_log_contents, "\n"
169
+
170
+ lines = jobmanager_log_contents.split("\n")
171
+ assert_match(/INFO \[#{USER_NAME}, ze_echoer\] Exited successfully$/, lines[1])
172
+ lines.each { |line| assert_no_match(/ERROR/, line) }
173
+
174
+ # confirm the correctness of the job log file.
175
+ job_log_files = Dir.glob("#{job_logs_directory}/ze_echoer.log.*.gz")
176
+
177
+ assert_equal(1, job_log_files.length)
178
+ job_log_file = job_log_files[0]
179
+
180
+ Zlib::GzipReader.open(job_log_file) do |gz|
181
+ expected_contents = "1\n"
182
+ actual_contents = gz.read
183
+ assert_equal(expected_contents, actual_contents)
184
+
185
+ print "\nContents of #{job_log_file}:\n"
186
+ print actual_contents, "\n"
187
+ end
188
+
189
+ #confirm the email generated is correct.
190
+ deliveries = ActionMailer::Base.deliveries
191
+ assert_equal(1, deliveries.length)
192
+
193
+ delivery = deliveries[0]
194
+
195
+ assert_equal("jobmanager results for job ze_echoer, command echo 1, user janet, host #{HOST_NAME}, result Success",
196
+ delivery.subject)
197
+ assert_match(/^INFO \[#{USER_NAME}, ze_echoer\] Exited successfully$/, delivery.body)
198
+ end
199
+
200
+ # test config w/ email + date extensions, command that exists but fails
201
+
202
+ # Invoke the JobManager::Application to launch the cat command with
203
+ # a bogus file, which will cause the command to fail. Confirm the
204
+ # output logs produced (the job log file and the central log) are
205
+ # correct. Confirm the email generated is correct.
206
+ def test_jobmanager_3
207
+ config_file = File.join(CONFIG_DIR, "jobmanager_3.yaml")
208
+ config = File.open(config_file) { |fs| YAML::load(fs) }
209
+
210
+ assert(JobManager::System.which("cat"))
211
+ args = [ "cat #{TEMP_DIR}/no_file" ]
212
+ jobmanager = JobManager::Application.new(PROGRAM_NAME,
213
+ args,
214
+ config_file,
215
+ INTERACTIVE_SHELL_OVERRIDE)
216
+ jobmanager.run()
217
+
218
+ # confirm the correctness of jobmanager.log.
219
+ jobmanager_log_contents = $test_syslog_logger.string()
220
+
221
+ print "\nJob Manager Log Contents #3:\n"
222
+ print jobmanager_log_contents, "\n"
223
+
224
+ lines = jobmanager_log_contents.split("\n")
225
+ assert_match(/^ERROR \[janet, cat\] Failed! - exited normally with exit code:/, jobmanager_log_contents)
226
+ lines.each { |line| assert_no_match(/Exited successfully/, line) }
227
+
228
+ # confirm the email generated is correct.
229
+ deliveries = ActionMailer::Base.deliveries
230
+ assert_equal(1, deliveries.length)
231
+
232
+ delivery = deliveries[0]
233
+
234
+ assert_equal("jobmanager results for cat : Failure", delivery.subject)
235
+ assert_match(/^ERROR \[#{USER_NAME}, cat\] Failed! - exited normally with exit code:/,
236
+ delivery.body)
237
+
238
+ end
239
+
240
+ #
241
+ # Test the following error cases:
242
+ # 1) The central log file can't be created/opened.
243
+ # 2) The email results file can't be created/opened.
244
+ # 3) The job logs directory can't be created.
245
+ # 4) The job logs directory exists but is permissioned such that a file can't be created inside.
246
+ #
247
+ def test_jobmanager_exceptions()
248
+ jobmanager_exception_bad_central_log_file()
249
+ teardown(); setup();
250
+
251
+ jobmanager_exception_bad_email_settings_file()
252
+ teardown(); setup();
253
+
254
+ jobmanager_exception_bad_job_logs_directory_1()
255
+ teardown(); setup();
256
+
257
+ jobmanager_exception_bad_job_logs_directory_2()
258
+
259
+ end
260
+
261
+ # In this test case, the job logs directory can't be created.
262
+ # Test that the error is properly raised, logged, and emailed.
263
+ def jobmanager_exception_bad_job_logs_directory_1()
264
+
265
+ # Permission the directory so that the central log file can't be created inside this directory.
266
+ FileUtils.mkdir_p("#{TEMP_DIR}/permissioned_directory")
267
+ FileUtils.chmod(0000, "#{TEMP_DIR}/permissioned_directory")
268
+
269
+ config_file = File.join(CONFIG_DIR, "jobmanager_4_bad_job_logs_directory_1.yaml")
270
+
271
+ assert_raise_message("Error creating job_logs_directory", JobManager::Application::ComposedError) do
272
+ jobmanager = JobManager::Application.new(PROGRAM_NAME,
273
+ args = [ "ls" ],
274
+ config_file,
275
+ INTERACTIVE_SHELL_OVERRIDE)
276
+
277
+ jobmanager.run()
278
+ end
279
+
280
+ # return the permissions
281
+ FileUtils.chmod(0755, "#{TEMP_DIR}/permissioned_directory")
282
+
283
+ # confirm nothing was written via syslog.
284
+ assert_equal("", $test_syslog_logger.string())
285
+
286
+ jobmanager_log_contents = File.read("temp/logs/jobmanager.log")
287
+
288
+ print "\nJob Manager Log Contents #4 (jobmanager_4_bad_job_logs_directory_1.yaml):\n"
289
+ print jobmanager_log_contents, "\n"
290
+
291
+ lines = jobmanager_log_contents.split("\n")
292
+ assert_match(/^E, .* : \[#{USER_NAME}, ls\] Error creating job_logs_directory: Error \(Errno::EACCES\): Permission denied - temp\/permissioned_directory\/job_logs_directory/,
293
+ lines[0])
294
+
295
+ # confirm the email generated is correct.
296
+ deliveries = ActionMailer::Base.deliveries
297
+ assert_equal(1, deliveries.length)
298
+
299
+ delivery = deliveries[0]
300
+
301
+ assert_equal("jobmanager results for ls on #{HOST_NAME} : Failure", delivery.subject)
302
+ assert_match(/^E, .* : \[#{USER_NAME}, ls\] Error creating job_logs_directory: Error \(Errno::EACCES\): Permission denied - temp\/permissioned_directory\/job_logs_directory/,
303
+ delivery.body)
304
+
305
+ end
306
+
307
+
308
+ # In this test case, the job logs directory exists but permissions prevent a job log from being created.
309
+ # Test that the error is properly raised, logged, and emailed.
310
+ def jobmanager_exception_bad_job_logs_directory_2()
311
+
312
+ # Permission the directory so that the central log file can't be created inside this directory.
313
+ FileUtils.mkdir_p("#{TEMP_DIR}/permissioned_directory")
314
+ FileUtils.chmod(0000, "#{TEMP_DIR}/permissioned_directory")
315
+
316
+ config_file = File.join(CONFIG_DIR, "jobmanager_4_bad_job_logs_directory_2.yaml")
317
+
318
+ assert_raise_message("Error opening job log file", JobManager::Application::ComposedError) do
319
+ jobmanager = JobManager::Application.new(PROGRAM_NAME,
320
+ args = [ "ls" ],
321
+ config_file,
322
+ INTERACTIVE_SHELL_OVERRIDE)
323
+
324
+ jobmanager.run()
325
+ end
326
+
327
+ # return the permissions
328
+ FileUtils.chmod(0755, "#{TEMP_DIR}/permissioned_directory")
329
+
330
+ # confirm nothing was written via syslog.
331
+ assert_equal("", $test_syslog_logger.string())
332
+
333
+ jobmanager_log_contents = File.read("temp/logs/jobmanager.log")
334
+
335
+ print "\nJob Manager Log Contents #4 (jobmanager_4_bad_job_logs_directory_2.yaml):\n"
336
+ print jobmanager_log_contents, "\n"
337
+
338
+ lines = jobmanager_log_contents.split("\n")
339
+ assert_match(/^E, .* : \[#{USER_NAME}, ls\] Error opening job log file: Error \(Errno::EACCES\): Permission denied - temp\/permissioned_directory\/ls\.log/,
340
+ lines[0])
341
+
342
+ # confirm the email generated is correct.
343
+ deliveries = ActionMailer::Base.deliveries
344
+ assert_equal(1, deliveries.length)
345
+
346
+ delivery = deliveries[0]
347
+
348
+ assert_equal("jobmanager results for ls on #{HOST_NAME} : Failure", delivery.subject)
349
+ assert_match(/^E, .* : \[#{USER_NAME}, ls\] Error opening job log file: Error \(Errno::EACCES\): Permission denied - temp\/permissioned_directory\/ls\.log/,
350
+ delivery.body)
351
+
352
+ end
353
+
354
+
355
+ # In this test case, the email settings file can't be opened.
356
+ # Test that the error is properly raised, logged, and not emailed.
357
+ def jobmanager_exception_bad_email_settings_file()
358
+
359
+ # Permission the directory so that the central log file can't be
360
+ # created inside this directory.
361
+ FileUtils.mkdir_p("#{TEMP_DIR}/permissioned_directory")
362
+ FileUtils.chmod(0000, "#{TEMP_DIR}/permissioned_directory")
363
+
364
+ config_file = File.join(CONFIG_DIR, "jobmanager_4_bad_email_settings_file.yaml")
365
+
366
+ assert(JobManager::System.which("cat"))
367
+
368
+ assert_raise_message("email_settings_file (/no_directory/no_file.rb) does not exist or is not readable.\n", JobManager::Application::Error) do
369
+ jobmanager = JobManager::Application.new(PROGRAM_NAME,
370
+ args = [ "ls" ],
371
+ config_file,
372
+ INTERACTIVE_SHELL_OVERRIDE)
373
+
374
+ jobmanager.run()
375
+ end
376
+
377
+ # return the permissions
378
+ FileUtils.chmod(0755, "#{TEMP_DIR}/permissioned_directory")
379
+
380
+ # confirm correctness of syslog.
381
+ jobmanager_log_contents = $test_syslog_logger.string()
382
+
383
+ print "\nJob Manager Log Contents #4 (jobmanager_4_bad_email_settings_file.yaml):\n"
384
+ print jobmanager_log_contents, "\n"
385
+
386
+ lines = jobmanager_log_contents.split("\n")
387
+ assert_equal("ERROR [janet, UNKNOWN] email_settings_file (/no_directory/no_file.rb) does not exist or is not readable.",
388
+ lines[0])
389
+
390
+ # confirm no email was generated.
391
+ deliveries = ActionMailer::Base.deliveries
392
+ assert_equal(0, deliveries.length)
393
+ end
394
+
395
+ # In this test case, the central log file can't be opened/created.
396
+ # Test that the error is properly raised, logged, and emailed.
397
+ def jobmanager_exception_bad_central_log_file()
398
+
399
+ # Permission the directory so that the central log file can't be created inside this directory.
400
+ FileUtils.mkdir_p("#{TEMP_DIR}/permissioned_directory")
401
+ FileUtils.chmod(0000, "#{TEMP_DIR}/permissioned_directory")
402
+
403
+ config_file = File.join(CONFIG_DIR, "jobmanager_4_bad_central_log_file.yaml")
404
+
405
+ assert_raise_message("Error Initializing Central Log",
406
+ JobManager::Application::ComposedError) do
407
+ jobmanager = JobManager::Application.new(PROGRAM_NAME,
408
+ args = [ "ls" ],
409
+ config_file,
410
+ INTERACTIVE_SHELL_OVERRIDE)
411
+
412
+ jobmanager.run()
413
+ end
414
+
415
+ # return the permissions
416
+ FileUtils.chmod(0755, "#{TEMP_DIR}/permissioned_directory")
417
+
418
+ # confirm correctness of syslog.
419
+ jobmanager_log_contents = $test_syslog_logger.string()
420
+
421
+ print "\nJob Manager Log Contents #4 (jobmanager_4_bad_central_log_file.yaml):\n"
422
+ print jobmanager_log_contents, "\n"
423
+
424
+ lines = jobmanager_log_contents.split("\n")
425
+ assert_equal("ERROR [#{USER_NAME}, UNKNOWN] Error Initializing Central Log: Error (Errno::EACCES): Permission denied - temp/permissioned_directory/jobmanager.log",
426
+ lines[0])
427
+
428
+ # confirm the email generated is correct.
429
+ deliveries = ActionMailer::Base.deliveries
430
+ assert_equal(1, deliveries.length)
431
+
432
+ delivery = deliveries[0]
433
+
434
+ assert_equal("jobmanager results for ls on #{HOST_NAME} : Failure", delivery.subject)
435
+ assert_match(/ERROR \[#{USER_NAME}, UNKNOWN\] Error Initializing Central Log: Error \(Errno::EACCES\): Permission denied - temp\/permissioned_directory\/jobmanager.log/,
436
+ delivery.body)
437
+
438
+ end
439
+
440
+ end
441
+
442
+
443
+
@@ -0,0 +1,206 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'stringio'
4
+ require 'fileutils'
5
+
6
+ require 'rubygems'
7
+ require 'relative'
8
+
9
+ require 'test/unit'
10
+ require_relative('helpers')
11
+ require_relative('mock_syslog')
12
+
13
+ require 'jobmanager/system'
14
+ require 'jobmanager/applicationlogger'
15
+
16
+ #
17
+ # This class tests the JobManager::System module.
18
+ #
19
+
20
+ class TestSystem < Test::Unit::TestCase
21
+ include TestHelpers
22
+
23
+ SAMPLE_DIR = "#{TEMP_DIR}/samples"
24
+
25
+ SAMPLE_FILE = File.join(SAMPLE_DIR, "sample.dat")
26
+ EXPECTED_SAMPLE_CONTENTS = (1..10000).map { "This is a sample file." }.join("\n")
27
+
28
+ USER_NAME = Etc.getpwuid(Process::Sys.getuid()).name()
29
+
30
+ def setup
31
+ teardown()
32
+
33
+ FileUtils.mkdir_p(TEMP_DIR)
34
+ FileUtils.mkdir_p(SAMPLE_DIR)
35
+
36
+ File.open(SAMPLE_FILE, "w") do |file_stream|
37
+ file_stream << EXPECTED_SAMPLE_CONTENTS
38
+ end
39
+ end
40
+
41
+ def teardown
42
+ FileUtils::rm_r(TEMP_DIR, :force => true)
43
+ end
44
+
45
+ # Command w/ relative path (cat) - success
46
+ def test_simple_cat_success
47
+ command = "cat #{SAMPLE_FILE}"
48
+ run_simple_cat(command)
49
+ end
50
+
51
+ # Command w/ absolute path (eg. /bin/cat) - success
52
+ def test_absolute_path_command_success
53
+ exe = JobManager::System.which("cat")
54
+ command = "#{exe} #{SAMPLE_FILE}"
55
+
56
+ run_simple_cat(command)
57
+ end
58
+
59
+ # Command (cat) w/ large timeout - success
60
+ def test_simple_cat_with_timeout_success
61
+ command = "cat #{SAMPLE_FILE}"
62
+ optional_args = { :timeout => 100 }
63
+
64
+ run_simple_cat(command)
65
+ end
66
+
67
+ # Command w/ relative path (cat) - options (good path)
68
+ def test_simple_cat_with_environment_path_specified_success
69
+ exe = JobManager::System.which("cat")
70
+ path = exe.split()[0]
71
+
72
+ command = "#{exe} #{SAMPLE_FILE}"
73
+ optional_args = { :command_path => path }
74
+
75
+ run_simple_cat(command)
76
+ end
77
+
78
+ def create_logger(job_name)
79
+ return JobManager::ApplicationSyslogLogger.new("job_manager",
80
+ USER_NAME,
81
+ job_name)
82
+ end
83
+
84
+ # Command (cat) - cat nonexistent file
85
+ def test_simple_cat__failure
86
+ command = "cat #{SAMPLE_DIR}/no_file.dat"
87
+ job = "catter"
88
+ log_stream = StringIO.new
89
+ logger = create_logger(job)
90
+ success = JobManager::System.invoke_command(command,
91
+ log_stream,
92
+ logger)
93
+
94
+ logger.close
95
+
96
+ control_log_lines = logger.string.split("\n")
97
+ print "\n", control_log_lines.join("\n"), "\n"
98
+
99
+ assert_equal(false, success)
100
+
101
+ assert_match(/ERROR \[#{USER_NAME}, catter\] Failed! - exited normally with exit code:/,
102
+ control_log_lines[-1])
103
+ end
104
+
105
+ # Command (cat) - options (bad path)
106
+ def test_simple_cat_with_environment_path_specified_failure
107
+ command = "cat #{SAMPLE_FILE}"
108
+ job = "catter"
109
+ log_stream = StringIO.new
110
+ logger = create_logger(job)
111
+ optional_args = { :command_path => "/bad_directory_1:/bad_directory_2" }
112
+
113
+ success = JobManager::System.invoke_command(command,
114
+ log_stream,
115
+ logger,
116
+ optional_args)
117
+
118
+ logger.close
119
+
120
+ control_log_lines = logger.string.split("\n")
121
+ print "\n", control_log_lines.join("\n"), "\n"
122
+
123
+ assert_equal(false, success)
124
+ assert_equal("", log_stream.string())
125
+
126
+ assert_match(/ERROR \[#{USER_NAME}, catter\] File cat does not exist in path .* or is not executable!/,
127
+ control_log_lines[-1])
128
+ end
129
+
130
+ def run_simple_cat(command, optional_args = {})
131
+ job = "catter"
132
+ log_stream = StringIO.new
133
+ logger = create_logger(job)
134
+
135
+ success = JobManager::System.invoke_command(command,
136
+ log_stream,
137
+ logger,
138
+ optional_args)
139
+
140
+ logger.close
141
+
142
+ control_log_lines = logger.string.split("\n")
143
+ print "\n", control_log_lines.join("\n"), "\n"
144
+
145
+ assert_equal(true, success)
146
+ assert_equal(EXPECTED_SAMPLE_CONTENTS, log_stream.string())
147
+
148
+ assert_match(/INFO \[#{USER_NAME}, catter\] Exited successfully/,
149
+ control_log_lines[-1])
150
+ end
151
+
152
+ # Launch a sleep command w/ a timeout shorter than the sleep time.
153
+ def test_sleep_past_timeout
154
+ command = "sleep 100"
155
+ job = "catter"
156
+ log_stream = StringIO.new
157
+ logger = create_logger(job)
158
+ optional_args = { :timeout => 1 }
159
+
160
+ success = JobManager::System.invoke_command(command,
161
+ log_stream,
162
+ logger,
163
+ optional_args)
164
+
165
+ logger.close
166
+
167
+ control_log_lines = logger.string.split("\n")
168
+ print "\n", control_log_lines.join("\n"), "\n"
169
+
170
+ # verify that the sleep process has been timed out!
171
+ assert_equal(false, success)
172
+
173
+ assert_match(/ERROR \[#{USER_NAME}, catter\] Timed out after 1 seconds./,
174
+ control_log_lines[-3])
175
+ end
176
+
177
+ # Test whether the invoke_command properly recognizes when the process that has been
178
+ # forked has died due to a signal.
179
+ def test_sleep_and_kill
180
+ job_pid = nil
181
+
182
+ command = "sleep 1000"
183
+ job = "catter"
184
+ log_stream = StringIO.new
185
+ logger = create_logger(job)
186
+ optional_args = { :timeout => 100 }
187
+
188
+ success = JobManager::System.invoke_command(command,
189
+ log_stream,
190
+ logger,
191
+ optional_args) do |job_pid|
192
+ Process.kill("TERM", job_pid)
193
+ end
194
+
195
+ logger.close
196
+
197
+ control_log_lines = logger.string.split("\n")
198
+ print "\n", control_log_lines.join("\n"), "\n"
199
+
200
+ assert_equal(false, success)
201
+
202
+ assert_match(/ERROR \[#{USER_NAME}, catter\] Failed! - exited abnormally due to signal:/,
203
+ control_log_lines[-1])
204
+ end
205
+ end
206
+