jobmanager 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
|