#!/usr/bin/env ruby
$:.unshift("../../lib") if __FILE__ =~ /\.rb$/
require 'puppettest'
require 'mocha'
require 'puppettest/fileparsing'
require 'puppet/util/filetype'
require 'puppet/provider/parsedfile'
require 'facter'
class TestParsedFile < Test::Unit::TestCase
include PuppetTest
include PuppetTest::FileParsing
Puppet::Type.newtype(:testparsedfiletype) do
ensurable
newproperty(:one) do
newvalue(:a)
newvalue(:b)
end
newproperty(:two) do
newvalue(:c)
newvalue(:d)
end
newparam(:name) do
end
# The target should always be a property, not a parameter.
newproperty(:target) do
defaultto { @parent.class.defaultprovider.default_target }
end
end
# A simple block to skip the complexity of a full transaction.
def apply(model)
[:one, :two, :ensure].each do |st|
Puppet.info "Setting %s: %s => %s" %
[model[:name], st, model.should(st)]
model.provider.send(st.to_s + "=", model.should(st))
end
end
def mkmodel(name, options = {})
options[:one] ||= "a"
options[:two] ||= "c"
options[:name] ||= name
model = @type.create(options)
end
def mkprovider(name = :parsed)
@provider = @type.provide(name, :parent => Puppet::Provider::ParsedFile,
:filetype => :ram, :default_target => "yayness") do
record_line name, :fields => %w{name one two}
end
end
def setup
super
@type = Puppet::Type.type(:testparsedfiletype)
end
def teardown
if defined? @provider
@type.unprovide(@provider.name)
@provider = nil
end
super
end
def test_create_provider
assert_nothing_raised do
mkprovider
end
end
def test_model_attributes
prov = nil
assert_nothing_raised do
prov = mkprovider
end
[:one, :two, :name].each do |attr|
assert(prov.method_defined?(attr), "Did not define %s" % attr)
end
# Now make sure they stay around
fakemodel = fakemodel(:testparsedfiletype, "yay")
file = prov.new(fakemodel)
assert_nothing_raised do
file.name = :yayness
end
# The provider converts to strings
assert_equal(:yayness, file.name)
end
def test_filetype
prov = mkprovider
flat = Puppet::Util::FileType.filetype(:flat)
ram = Puppet::Util::FileType.filetype(:ram)
assert_nothing_raised do
prov.filetype = :flat
end
assert_equal(flat, prov.filetype)
assert_nothing_raised do
prov.filetype = ram
end
assert_equal(ram, prov.filetype)
end
# Make sure we correctly create a new filetype object, but only when
# necessary.
def test_fileobject
prov = mkprovider
path = tempfile()
obj = nil
assert_nothing_raised do
obj = prov.target_object(path)
end
# The default filetype is 'ram'
assert_instance_of(Puppet::Util::FileType.filetype(:ram), obj)
newobj = nil
assert_nothing_raised do
newobj = prov.target_object(path)
end
assert_equal(obj, newobj, "did not reuse file object")
# now make sure clear does the right thing
assert_nothing_raised do
prov.clear
end
assert_nothing_raised do
newobj = prov.target_object(path)
end
assert(obj != newobj, "did not reuse file object")
end
def test_retrieve
prov = mkprovider
prov.filetype = :ram
# Override the parse method with our own
prov.meta_def(:parse) do |text|
return [text]
end
path = :yayness
file = prov.target_object(path)
text = "a test"
file.write(text)
ret = nil
assert_nothing_raised do
ret = prov.retrieve(path)
end
assert_equal([text], ret)
# Now set the text to nil and make sure we get an empty array
file.write(nil)
assert_nothing_raised do
ret = prov.retrieve(path)
end
assert_equal([], ret)
# And the empty string should return an empty array
file.write("")
assert_nothing_raised do
ret = prov.retrieve(path)
end
assert_equal([], ret)
end
# Verify that prefetch will parse the file, create any necessary instances,
# and set the 'is' values appropriately.
def test_prefetch
prov = mkprovider
prov.filetype = :ram
prov.default_target = :default
# Create a couple of demo files
prov.target_object(:file1).write "bill b c"
prov.target_object(:file2).write "jill b d"
prov.target_object(:default).write "will b d"
# Create some models for some of those demo files
model = mkmodel "bill", :target => :file1
default = mkmodel "will", :target => :default
assert_nothing_raised do
prov.prefetch
end
# Make sure we prefetched our models.
assert_equal("b", model.provider.one)
assert_equal("b", default.provider.one)
assert_equal("d", default.provider.two)
# Now list all of them and make sure we get everything back
hashes = nil
assert_nothing_raised do
hashes = prov.list
end
names = nil
assert_nothing_raised do
names = prov.list_by_name
end
%w{bill jill will}.each do |name|
assert(hashes.find { |r| r[:name] == name},
"Did not return %s in list" % name)
assert(names.include?(name),
"Did not return %s in list_by_name" % name)
end
end
# Make sure we can correctly prefetch on a target.
def test_prefetch_target
prov = mkprovider
prov.filetype = :ram
target = :yayness
prov.target_object(target).write "yay b d"
model = mkmodel "yay", :target => :yayness
assert_nothing_raised do
prov.prefetch_target(:yayness)
end
# Now make sure we correctly got the hash
mprov = model.provider
assert_equal("b", mprov.one)
assert_equal("d", mprov.two)
end
def test_prefetch_match
prov = mkprovider
prov.meta_def(:match) do |record|
# Look for matches on :one
self.model.find do |m|
m.should(:one).to_s == record[:one].to_s
end
end
prov.filetype = :ram
target = :yayness
prov.target_object(target).write "foo b d"
model = mkmodel "yay", :target => :yayness, :one => "b"
assert_nothing_raised do
prov.prefetch_target(:yayness)
end
# Now make sure we correctly got the hash
mprov = model.provider
assert_equal("yay", model[:name])
assert_equal("b", mprov.one)
assert_equal("d", mprov.two)
end
# We need to test that we're retrieving files from all three locations:
# from any existing target_objects, from the default file location, and
# from any existing model instances.
def test_targets
prov = mkprovider
files = {}
# Set the default target
default = tempfile()
files[:default] = default
prov.default_target = default
# Create a file object
inmem = tempfile()
files[:inmemory] = inmem
prov.target_object(inmem).write("inmem yay ness")
# Lastly, create a model with separate is and should values
mtarget = tempfile()
istarget = tempfile()
files[:models] = mtarget
files[:ismodels] = istarget
model = mkmodel "yay", :target => mtarget
model.is = [:target, istarget]
assert(model.should(:target), "Did not get a value for target")
assert(model.is(:target), "Did not get a value for target")
list = nil
assert_nothing_raised do
list = prov.targets
end
files.each do |name, file|
assert(list.include?(file), "Provider did not find %s file" % name)
end
end
# Make sure that flushing behaves correctly. This is what actually writes
# the data out to disk.
def test_flush
prov = mkprovider
prov.filetype = :ram
prov.default_target = :yayness
# Create some models.
one = mkmodel "one", :one => "a", :two => "c", :target => :yayness
two = mkmodel "two", :one => "b", :two => "d", :target => :yayness
# Write out a file with different data.
prov.target_object(:yayness).write "one b d\ntwo a c"
prov.prefetch
# Apply and flush the first model.
assert_nothing_raised do
apply(one)
end
assert_nothing_raised { one.flush }
# Make sure it changed our file
assert_equal(:a, one.provider.one)
assert_equal(:c, one.provider.two)
# And make sure it's right on disk
assert(prov.target_object(:yayness).read.include?("one a c"),
"Did not write out correct data")
# Make sure the second model has not been modified
assert_equal("a", two.provider.one, "Two was flushed early")
assert_equal("c", two.provider.two, "Two was flushed early")
# And on disk
assert(prov.target_object(:yayness).read.include?("two a c"),
"Wrote out other model")
# Now fetch the data again and make sure we're still right
assert_nothing_raised { prov.prefetch }
assert_equal("a", one.provider.one)
assert_equal("a", two.provider.one)
# Now flush the second model and make sure it goes well
assert_nothing_raised { apply(two) }
assert_nothing_raised { two.flush }
assert_equal(:b, two.provider.one)
end
def test_creating_file
prov = mkprovider
prov.clear
prov.default_target = :basic
model = mkmodel "yay", :target => :basic, :one => "a", :two => "c"
assert_equal(:present, model.should(:ensure))
apply(model)
assert_nothing_raised do
model.flush
end
assert(prov.target_object(:basic).read.include?("yay a c"),
"Did not create file")
# Make a change
model.provider.one = "b"
# Flush it
assert_nothing_raised do
model.flush
end
# And make sure our model doesn't appear twice in the file.
assert_equal("yay b c\n",
prov.target_object(:basic).read)
end
# Make sure a record can switch targets.
def test_switching_targets
prov = mkprovider
prov.filetype = :ram
prov.default_target = :first
# Make three models, one for each target and one to switch
first = mkmodel "first", :target => :first
second = mkmodel "second", :target => :second
mover = mkmodel "mover", :target => :first
[first, second, mover].each do |m|
assert_nothing_raised("Could not apply %s" % m[:name]) do
apply(m)
end
end
# Flush.
[first, second, mover].each do |m|
assert_nothing_raised do
m.flush
end
end
check = proc do |target, name|
assert(prov.target_object(target).read.include?("%s a c" % name),
"Did not sync %s" % name)
end
# Make sure the data is there
check.call(:first, :first)
check.call(:second, :second)
check.call(:first, :mover)
# Now change the target for the mover
mover[:target] = :second
# Apply it
assert_nothing_raised do
apply(mover)
end
# Flush
assert_nothing_raised do
mover.flush
end
# Make sure the data is there
check.call(:first, :first)
check.call(:second, :second)
check.call(:second, :mover)
# And make sure the mover is no longer in the first file
assert(prov.target_object(:first) !~ /mover/,
"Mover was not removed from first file")
end
# Make sure that 'ensure' correctly calls 'sync' on all properties.
def test_ensure
prov = mkprovider
prov.filetype = :ram
prov.default_target = :first
# Make two models, one that starts on disk and one that doesn't
ondisk = mkmodel "ondisk", :target => :first
notdisk = mkmodel "notdisk", :target => :first
prov.target_object(:first).write "ondisk a c\n"
prov.prefetch
assert_equal(:present, notdisk.should(:ensure),
"Did not get default ensure value")
# Try creating the object
assert_nothing_raised { notdisk.provider.create() }
# Now make sure all of the data is copied over correctly.
notdisk.class.validproperties.each do |property|
assert_equal(notdisk.should(property), notdisk.provider.property_hash[property],
"%s was not copied over during creation" % property)
end
# Flush it to disk and make sure it got copied down
assert_nothing_raised do
notdisk.flush
end
assert(prov.target_object(:first).read =~ /^notdisk/,
"Did not write out object to disk")
assert(prov.target_object(:first).read =~ /^ondisk/,
"Lost object on disk")
# Make sure our on-disk model behaves appropriately.
assert_equal(:present, ondisk.provider.ensure)
# Now destroy the object
assert_nothing_raised { notdisk.provider.destroy() }
assert_nothing_raised { notdisk.flush }
# And make sure it's no longer present
assert(prov.target_object(:first).read !~ /^notdisk/,
"Did not remove thing from disk")
assert(prov.target_object(:first).read =~ /^ondisk/,
"Lost object on disk")
assert_equal(:present, ondisk.provider.ensure)
end
def test_absent_fields
prov = @type.provide(:record, :parent => Puppet::Provider::ParsedFile) do
record_line :record, :fields => %w{name one two},
:separator => "\s"
end
cleanup { @type.unprovide(:record) }
line = prov.parse_line("a d")
assert_equal("a", line[:name], "field name was not set")
assert_equal(:absent, line[:one], "field one was not set to absent")
# Now use a different provider with a non-blank "absent"
prov = @type.provide(:cronstyle, :parent => Puppet::Provider::ParsedFile) do
record_line :cronstyle, :fields => %w{name one two},
:separator => "\s", :absent => "*"
end
cleanup { @type.unprovide(:cronstyle) }
line = prov.parse_line("a * d")
assert_equal("a", line[:name], "field name was not set")
assert_equal(:absent, line[:one], "field one was not set to absent")
end
# This test is because in x2puppet I was having problems where multiple
# retrievals somehow destroyed the 'is' values.
def test_value_retrieval
prov = mkprovider
prov.default_target = :yayness
prov.target_object(:yayness).write "bill a c\njill b d"
list = @type.list
bill = list.find { |r| r[:name] == "bill" }
jill = list.find { |r| r[:name] == "jill" }
assert(bill, "Could not find bill")
assert(jill, "Could not find jill")
prov = bill.provider
4.times do |i|
assert(prov.one, "Did not get a value for 'one' on try %s" % (i + 1))
end
# First make sure we can retrieve values multiple times from the
# provider
assert(bill.is(:one), "Bill does not have a value for 'one'")
assert(bill.is(:one), "Bill does not have a value for 'one' on second try")
assert_nothing_raised do
bill.retrieve
end
assert(bill.is(:one), "bill's value for 'one' disappeared")
end
# Make sure that creating a new model finds existing records in memory
def test_initialize_finds_records
prov = mkprovider
prov.default_target = :yayness
prov.target_object(:yayness).write "bill a c\njill b d"
prov.prefetch
# Now make a model
bill = nil
assert_nothing_raised do
bill = @type.create :name => "bill"
end
assert_equal("a", bill.provider.one,
"Record was not found in memory")
end
# Make sure invalid fields always show up as insync
def test_invalid_fields
prov = @type.provide(:test, :parent => Puppet::Provider::ParsedFile,
:filetype => :ram, :default_target => :yayness) do
record_line :test, :fields => %w{name two}
end
cleanup do @type.unprovide(:test) end
bill = nil
assert_nothing_raised do
bill = @type.create :name => "bill",
:one => "a", :two => "c"
end
assert_apply(bill)
prov.prefetch
assert_nothing_raised do
bill.retrieve
end
assert(bill.insync?,
"An invalid field marked the record out of sync")
end
# Make sure we call the prefetch hook at the right place.
def test_prefetch_hook
prov = @type.provide(:test, :parent => Puppet::Provider::ParsedFile,
:filetype => :ram, :default_target => :yayness) do
def self.prefetch_hook(records)
records
end
record_line :test, :fields => %w{name two}
end
cleanup do @type.unprovide(:test) end
target = "target"
records = [{:target => "nope"}]
targeted = {:target => "target"}
prov.send(:instance_variable_set, "@records", records)
prov.expects(:retrieve).with(target).returns([targeted])
prov.expects(:target_records).with(target).returns([targeted])
prov.expects(:prefetch_hook).with([targeted]).returns([targeted])
prov.prefetch_target(target)
end
# #529
def test_keep_content_with_target
mkprovider
@provider.filetype = :flat
dpath = tempfile
opath = tempfile
@provider.default_target = dpath
dtarget = @provider.target_object(dpath)
otarget = @provider.target_object(opath)
dtarget.write("dname a c\n")
otarget.write("oname b d\n")
# Now make a resource that targets elsewhat.
res = @type.create(:name => "test", :one => "a", :two => "c",
:target => opath)
assert(res.property(:target), "Target is a parameter, not a property")
assert_apply(res)
assert_equal("oname b d\ntest a c\n", otarget.read,
"did not get correct results in specified target")
end
end
# $Id: parsedfile.rb 2290 2007-03-18 18:00:26Z luke $
syntax highlighted by Code2HTML, v. 0.9.1