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.
- data/FAQ.txt +151 -0
- data/History.txt +2 -0
- data/LICENSE +20 -0
- data/Manifest.txt +42 -0
- data/README.txt +395 -0
- data/Rakefile +17 -0
- data/bin/jobmanager +20 -0
- data/examples/email_settings.rb +14 -0
- data/examples/example.rb +23 -0
- data/examples/jobmanager.yaml +66 -0
- data/examples/mysql_backup.rb +18 -0
- data/lib/jobmanager.rb +1 -0
- data/lib/jobmanager/application.rb +455 -0
- data/lib/jobmanager/applicationconfig.rb +89 -0
- data/lib/jobmanager/applicationlogger.rb +306 -0
- data/lib/jobmanager/applicationoptionparser.rb +163 -0
- data/lib/jobmanager/system.rb +240 -0
- data/lib/jobmanager/teestream.rb +78 -0
- data/lib/jobmanager/util.rb +25 -0
- data/test/configs/all_values.yaml +33 -0
- data/test/configs/bad_email_condition.yaml +7 -0
- data/test/configs/bad_no_central_log_file.yaml +7 -0
- data/test/configs/bad_number_of_job_logs.yaml +7 -0
- data/test/configs/bad_timeout_zero.yaml +7 -0
- data/test/configs/email_settings.rb +16 -0
- data/test/configs/incomplete_1.yaml +23 -0
- data/test/configs/jobmanager_1.yaml +9 -0
- data/test/configs/jobmanager_2.yaml +11 -0
- data/test/configs/jobmanager_3.yaml +13 -0
- data/test/configs/jobmanager_4_bad_central_log_file.yaml +9 -0
- data/test/configs/jobmanager_4_bad_email_settings_file.yaml +9 -0
- data/test/configs/jobmanager_4_bad_job_logs_directory_1.yaml +9 -0
- data/test/configs/jobmanager_4_bad_job_logs_directory_2.yaml +9 -0
- data/test/configs/minimum_plus_email_settings.yaml +9 -0
- data/test/configs/minimum_required.yaml +5 -0
- data/test/helpers.rb +7 -0
- data/test/mock_syslog.rb +68 -0
- data/test/test_applicationlogger.rb +145 -0
- data/test/test_config.rb +208 -0
- data/test/test_jobmanager.rb +443 -0
- data/test/test_system.rb +206 -0
- data/test/test_teestream.rb +55 -0
- 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
|
+
|
data/test/test_system.rb
ADDED
@@ -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
|
+
|