3
require File.dirname(__FILE__) + '/../../../lib/puppettest'
7
require 'puppettest/fileparsing'
9
class TestCronParsedProvider < Test::Unit::TestCase
11
include PuppetTest::FileParsing
15
:crontab => %w{command minute hour month monthday weekday}.collect { |o| o.intern },
16
:freebsd_special => %w{special command}.collect { |o| o.intern },
17
:environment => [:line],
22
# These are potentially multi-line records; there's no one-to-one map, but they model
23
# a full cron job. These tests assume individual record types will always be correctly
26
unless defined? @sample_crons
27
@sample_crons = YAML.load(File.read(File.join(@crondir, "crontab_collections.yaml")))
32
# These are simple lines that can appear in the files; there is a one to one
33
# mapping between records and lines. We have plenty of redundancy here because
34
# we use these records to build up our complex, multi-line cron jobs below.
36
unless defined? @sample_records
37
@sample_records = YAML.load(File.read(File.join(@crondir, "crontab_sample_records.yaml")))
44
@type = Puppet::Type.type(:cron)
45
@provider = @type.provider(:crontab)
47
@crondir = datadir(File.join(%w{providers cron}))
49
@oldfiletype = @provider.filetype
53
Puppet::Util::FileType.filetype(:ram).clear
58
# Make sure a cron job matches up. Any non-passed fields are considered absent.
59
def assert_cron_equal(msg, cron, options)
60
assert_instance_of(@provider, cron, "not an instance of provider in %s" % msg)
61
options.each do |param, value|
62
assert_equal(value, cron.send(param), "%s was not equal in %s" % [param, msg])
64
%w{command environment minute hour month monthday weekday}.each do |var|
65
unless options.include?(var.intern)
66
assert_equal(:absent, cron.send(var), "%s was not parsed absent in %s" % [var, msg])
71
# Make sure a cron record matches. This only works for crontab records.
72
def assert_record_equal(msg, record, options)
73
unless options.include?(:record_type)
74
raise ArgumentError, "You must pass the required record type"
76
assert_instance_of(Hash, record, "not an instance of a hash in %s" % msg)
77
options.each do |param, value|
78
assert_equal(value, record[param], "%s was not equal in %s" % [param, msg])
80
FIELDS[record[:record_type]].each do |var|
81
unless options.include?(var)
82
assert_equal(:absent, record[var], "%s was not parsed absent in %s" % [var, msg])
87
def assert_header(file)
89
file.gsub! /^(# HEADER: .+$)\n/ do
93
assert_equal(4, header.length, "Did not get four header lines")
96
# This handles parsing every possible iteration of cron records. Note that this is only
97
# single-line stuff and doesn't include multi-line values (e.g., with names and/or envs).
98
# Those have separate tests.
100
# First just do each sample record one by one
101
sample_records.each do |name, options|
103
assert_nothing_raised("Could not parse %s: '%s'" % [name, options[:text]]) do
104
result = @provider.parse_line(options[:text])
106
assert_record_equal("record for %s" % name, result, options[:record])
109
# Then do them all at once.
112
sample_records.each do |name, options|
113
records << options[:record]
114
text += options[:text] + "\n"
118
assert_nothing_raised("Could not match all records in one file") do
119
result = @provider.parse(text)
122
records.zip(result).each do |should, record|
123
assert_record_equal("record for %s in full match" % should.inspect, record, should)
127
# Here we test that each record generates to the correct text.
128
def test_generate_line
129
# First just do each sample record one by one
130
sample_records.each do |name, options|
132
assert_nothing_raised("Could not generate %s: '%s'" % [name, options[:record]]) do
133
result = @provider.to_line(options[:record])
135
assert_equal(options[:text], result, "Did not generate correct text for %s" % name)
138
# Then do them all at once.
141
sample_records.each do |name, options|
142
records << options[:record]
143
text += options[:text] + "\n"
147
assert_nothing_raised("Could not match all records in one file") do
148
result = @provider.to_file(records)
151
assert_header(result)
153
assert_equal(text, result, "Did not generate correct full crontab")
156
# Test cronjobs that are made up from multiple records.
157
def test_multi_line_cronjobs
160
sample_crons.each do |name, record_names|
161
records = record_names.collect do |record_name|
162
unless record = sample_records[record_name]
163
raise "Could not find sample record %s" % record_name
168
text = records.collect { |r| r[:text] }.join("\n") + "\n"
169
record_list = records.collect { |r| r[:record] }
171
# Add it to our full collection
172
all_records += record_list
175
# First make sure we generate each one correctly
177
assert_nothing_raised("Could not generate multi-line cronjob %s" % [name]) do
178
result = @provider.to_file(record_list)
180
assert_header(result)
181
assert_equal(text, result, "Did not generate correct text for multi-line cronjob %s" % name)
183
# Now make sure we parse each one correctly
184
assert_nothing_raised("Could not parse multi-line cronjob %s" % [name]) do
185
result = @provider.parse(text)
187
record_list.zip(result).each do |should, record|
188
assert_record_equal("multiline cronjob %s" % name, record, should)
192
# Make sure we can generate it all correctly
194
assert_nothing_raised("Could not generate all multi-line cronjobs") do
195
result = @provider.to_file(all_records)
197
assert_header(result)
198
assert_equal(fulltext, result, "Did not generate correct text for all multi-line cronjobs")
200
# Now make sure we parse them all correctly
201
assert_nothing_raised("Could not parse multi-line cronjobs") do
202
result = @provider.parse(fulltext)
204
all_records.zip(result).each do |should, record|
205
assert_record_equal("multiline cronjob %s", record, should)
209
# Take our sample files, and make sure we can entirely parse them,
210
# then that we can generate them again and we get the same data.
211
def test_parse_and_generate_sample_files
212
@provider.stubs(:filetype).returns(Puppet::Util::FileType.filetype(:ram))
213
crondir = datadir(File.join(%w{providers cron}))
214
files = Dir.glob("%s/crontab.*" % crondir)
217
@provider.default_target = @me
218
target = @provider.target_object(@me)
221
assert_nothing_raised("could not load %s" % file) do
222
str, args = YAML.load(File.read(file))
227
hash.each do |param, value|
228
if param.is_a?(String) and param =~ /^:/
230
param = param.sub(/^:/,'').intern
234
if value.is_a?(String) and value =~ /^:/
235
value = value.sub(/^:/,'').intern
241
assert_nothing_raised("could not parse %s" % file) do
244
records = @provider.send(:instance_variable_get, "@records")
246
args.zip(records) do |should, sis|
247
# Make the values a bit more equal.
248
should[:target] = @me
249
should[:ensure] = :present
250
#should[:environment] ||= []
251
should[:on_disk] = true
253
sis.dup.each do |p,v|
254
is.delete(p) if v == :absent
256
assert_equal(should, is,
257
"Did not parse %s correctly" % file)
260
assert_nothing_raised("could not generate %s" % file) do
261
@provider.flush_target(@me)
264
assert_equal(str, target.read, "%s changed" % file)
269
# A simple test to see if we can load the cron from disk.
273
assert_nothing_raised {
274
records = @provider.retrieve(@me)
276
assert_instance_of(Array, records, "did not get correct response")
279
# Test that a cron job turns out as expected, by creating one and generating
281
def test_simple_to_cron
286
args = {:name => name,
287
:command => "date > /dev/null",
290
:record_type => :crontab
294
assert_nothing_raised {
295
str = @provider.to_line(args)
298
assert_equal("# Puppet Name: #{name}\n30 * * * * date > /dev/null", str,
299
"Cron did not generate correctly")
302
# Test that comments are correctly retained
303
def test_retain_comments
304
str = "# this is a comment\n#and another comment\n"
307
@provider.stubs(:filetype).returns(Puppet::Util::FileType.filetype(:ram))
308
target = @provider.target_object(user)
310
assert_nothing_raised {
314
assert_nothing_raised {
315
newstr = @provider.flush_target(user)
316
assert(target.read.include?(str), "Comments were lost")
320
def test_simpleparsing
321
@provider.stubs(:filetype).returns(Puppet::Util::FileType.filetype(:ram))
322
text = "5 1,2 * 1 0 /bin/echo funtest"
325
assert_nothing_raised {
326
records = @provider.parse(text)
332
:monthday => :absent,
335
:command => "/bin/echo funtest"
339
assert(is, "Did not get record")
341
should.each do |p, v|
342
assert_equal(v, is[p], "did not parse %s correctly" % p)
346
# Make sure we can create a cron in an empty tab.
347
# LAK:FIXME This actually modifies the user's crontab,
348
# which is pretty heinous.
349
def test_mkcron_if_empty
351
@provider.filetype = @oldfiletype
353
records = @provider.retrieve(@me)
355
target = @provider.target_object(@me)
358
if records.length == 0
361
target.write(@provider.to_file(records))
366
assert_nothing_raised("Could not remove cron tab") do
370
@provider.flush :target => @me, :command => "/do/something",
371
:record_type => :crontab
372
created = @provider.retrieve(@me)
373
assert(created.detect { |r| r[:command] == "/do/something" },
374
"Did not create cron tab")
377
# Make sure we correctly bidirectionally parse things.
378
def test_records_and_strings
379
@provider.stubs(:filetype).returns(Puppet::Util::FileType.filetype(:ram))
382
target = @provider.target_object(@me)
385
"* * * * * /some/command",
386
"0,30 * * * * /some/command",
387
"0-30 * * * * /some/command",
388
"# Puppet Name: name\n0-30 * * * * /some/command",
389
"# Puppet Name: name\nVAR=VALUE\n0-30 * * * * /some/command",
390
"# Puppet Name: name\nVAR=VALUE\nC=D\n0-30 * * * * /some/command",
391
"0 * * * * /some/command"
396
assert_equal(str, target.read,
397
"Did not write correctly")
398
assert_nothing_raised("Could not prefetch with %s" % str.inspect) do
401
assert_nothing_raised("Could not flush with %s" % str.inspect) do
402
@provider.flush_target(@me)
405
assert_equal(str, target.read,
406
"Changed in read/write")
412
# Test that a specified cron job will be matched against an existing job
413
# with no name, as long as all fields match
415
mecron = "0,30 * * * * date
422
youcron = "0,30 * * * * date
429
@provider.stubs(:filetype).returns(Puppet::Util::FileType.filetype(:ram))
432
# Write the same tab to multiple targets
433
@provider.target_object(@me).write(mecron.gsub(/^\s+/, ''))
434
@provider.target_object(you).write(youcron.gsub(/^\s+/, ''))
436
# Now make some crons that should match
446
:command => "yaytest",
456
:command => "fooness",
457
:user => @me # wrong target
461
:command => "funtest",
462
:user => you # wrong target for this cron
466
# Create another cron so we prefetch two of them
467
@type.create(:name => "testing", :minute => 30, :command => "whatever", :user => "you")
469
assert_nothing_raised("Could not prefetch cron") do
470
@provider.prefetch([matchers, nonmatchers].flatten.inject({}) { |crons, cron| crons[cron.name] = cron; crons })
473
matchers.each do |cron|
474
assert_equal(:present, cron.provider.ensure, "Cron %s was not matched" % cron.name)
475
if value = cron.value(:minute) and value == "*"
478
assert_equal(value, cron.provider.minute, "Minutes were not retrieved, so cron was not matched")
479
assert_equal(cron.value(:target), cron.provider.target, "Cron %s was matched from the wrong target" % cron.name)
482
nonmatchers.each do |cron|
483
assert_equal(:absent, cron.provider.ensure, "Cron %s was incorrectly matched" % cron.name)
489
@provider.stubs(:filetype).returns(Puppet::Util::FileType.filetype(:ram))
490
target = @provider.target_object(@me)
491
fakedata("data/providers/cron/examples").each do |file|
492
text = File.read(file)
495
assert_nothing_raised("Could not parse %s" % file) do
498
# mark the provider modified
499
@provider.modified(@me)
505
assert_nothing_raised("Could not generate %s" % file) do
506
@provider.flush_target(@me)
509
# Ignore whitespace differences, since those don't affect function.
510
modtext = text.gsub(/[ \t]+/, " ")
511
modtarget = target.read.gsub(/[ \t]+/, " ")
512
assert_equal(modtext, modtarget,
513
"File was not rewritten the same")
519
# Match freebsd's annoying @daily stuff.
520
def test_match_freebsd_special
521
@provider.stubs(:filetype).returns(Puppet::Util::FileType.filetype(:ram))
524
target = @provider.target_object(@me)
527
"@daily /some/command",
528
"@daily /some/command more"
533
assert_nothing_raised("Could not prefetch with %s" % str.inspect) do
536
records = @provider.send(:instance_variable_get, "@records")
538
assert_equal(:freebsd_special, r[:record_type],
539
"Did not create lines as freebsd lines")
541
assert_nothing_raised("Could not flush with %s" % str.inspect) do
542
@provider.flush_target(@me)
545
assert_equal(str, target.read,
546
"Changed in read/write")
553
def test_write_freebsd_special
554
assert_equal(@provider.to_line(:record_type => :crontab, :ensure => :present, :special => "reboot", :command => "/bin/echo something"), "@reboot /bin/echo something")
558
cron = @type.create :command => "/bin/echo yay", :name => "test", :hour => 4
560
assert_nothing_raised("Could not prefetch cron") do
561
cron.provider.class.prefetch("test" => cron)
566
def test_environment_settings
567
@provider.stubs(:filetype).returns(Puppet::Util::FileType.filetype(:ram))
570
target = @provider.target_object(@me)
572
# First with no env settings
573
resource = @type.create :command => "/bin/echo yay", :name => "test", :hour => 4
574
cron = resource.provider
576
cron.ensure = :present
577
cron.command = "/bin/echo yay"
582
assert_equal("# Puppet Name: test\n* 4 * * * /bin/echo yay\n", result, "Did not write cron out correctly")
585
cron.environment = "TEST=foo"
589
assert_equal("# Puppet Name: test\nTEST=foo\n* 4 * * * /bin/echo yay\n", result, "Did not write out environment setting")
592
cron.environment = ["TEST=foo", "BLAH=yay"]
596
assert_equal("# Puppet Name: test\nTEST=foo\nBLAH=yay\n* 4 * * * /bin/echo yay\n", result, "Did not write out environment setting")
599
cron.environment = :absent
603
assert_equal("# Puppet Name: test\n* 4 * * * /bin/echo yay\n", result, "Did not write out environment setting")
607
def test_strange_lines
608
@provider.stubs(:filetype).returns(Puppet::Util::FileType.filetype(:ram))
609
text = " 5 \t\t 1,2 * 1 0 /bin/echo funtest"
612
assert_nothing_raised {
613
records = @provider.parse(text)
619
:monthday => :absent,
622
:command => "/bin/echo funtest"
626
assert(is, "Did not get record")
628
should.each do |p, v|
629
assert_equal(v, is[p], "did not parse %s correctly" % p)