diff --git a/test/network/authstore.rb b/test/network/authstore.rb index e3c185302..c7e963ac2 100755 --- a/test/network/authstore.rb +++ b/test/network/authstore.rb @@ -1,540 +1,538 @@ #!/usr/bin/env ruby require File.expand_path(File.dirname(__FILE__) + '/../lib/puppettest') require 'puppettest' require 'mocha' require 'puppet/network/authstore' class TestAuthStore < Test::Unit::TestCase include PuppetTest Declaration = Puppet::Network::AuthStore::Declaration def mkstore store = nil assert_nothing_raised { store = Puppet::Network::AuthStore.new } store end def setup super @store = mkstore end def test_localallow Puppet[:trace] = false assert_nothing_raised { assert(@store.allowed?(nil, nil), "Store disallowed local access") } assert_raise(Puppet::DevError) { @store.allowed?("kirby.madstop.com", nil) } assert_raise(Puppet::DevError) { @store.allowed?(nil, "192.168.0.1") } end def test_simpleips %w{ 192.168.0.5 7.0.48.7 }.each { |ip| assert_nothing_raised("Failed to @store IP address #{ip}") { @store.allow(ip) } assert(@store.allowed?("hosttest.com", ip), "IP #{ip} not allowed") } #assert_raise(Puppet::AuthStoreError) { # @store.allow("192.168.674.0") #} end def test_ipranges %w{ 192.168.0.* 192.168.1.0/24 192.178.* 193.179.0.0/8 }.each { |range| assert_nothing_raised("Failed to @store IP range #{range}") { @store.allow(range) } } %w{ 192.168.0.1 192.168.1.5 192.178.0.5 193.0.0.1 }.each { |ip| assert(@store.allowed?("fakename.com", ip), "IP #{ip} is not allowed") } end def test_iprangedenials assert_nothing_raised("Failed to @store overlapping IP ranges") { @store.allow("192.168.0.0/16") @store.deny("192.168.0.0/24") } assert(@store.allowed?("fake.name", "192.168.1.50"), "/16 ip not allowed") assert(! @store.allowed?("fake.name", "192.168.0.50"), "/24 ip allowed") end def test_subdomaindenails assert_nothing_raised("Failed to @store overlapping IP ranges") { @store.allow("*.madstop.com") @store.deny("*.sub.madstop.com") } assert( @store.allowed?("hostname.madstop.com", "192.168.1.50"), "hostname not allowed") assert( ! @store.allowed?("name.sub.madstop.com", "192.168.0.50"), "subname name allowed") end def test_orderingstuff assert_nothing_raised("Failed to @store overlapping IP ranges") { @store.allow("*.madstop.com") @store.deny("192.168.0.0/24") } assert( @store.allowed?("hostname.madstop.com", "192.168.1.50"), "hostname not allowed") assert( ! @store.allowed?("hostname.madstop.com", "192.168.0.50"), "Host allowed over IP") end def test_globalallow assert_nothing_raised("Failed to add global allow") { @store.allow("*") } [ %w{hostname.com 192.168.0.4}, %w{localhost 192.168.0.1}, %w{localhost 127.0.0.1} ].each { |ary| assert(@store.allowed?(*ary), "Failed to allow #{ary.join(",")}") } end def test_store assert_nothing_raised do assert_nil( @store.send(:store, :allow, "*.host.com"), "store did not return nil") end assert_equal([Declaration.new(:allow, "*.host.com")], @store.send(:instance_variable_get, "@declarations"), "Did not store declaration") # Now add another one and make sure it gets sorted appropriately assert_nothing_raised do assert_nil( @store.send(:store, :allow, "me.host.com"), "store did not return nil") end assert_equal( [ Declaration.new(:allow, "me.host.com"), Declaration.new(:allow, "*.host.com") ], @store.send(:instance_variable_get, "@declarations"), "Did not sort declarations") end def test_allow_and_deny store = Puppet::Network::AuthStore.new store.expects(:store).with(:allow, "host.com") store.allow("host.com") store = Puppet::Network::AuthStore.new store.expects(:store).with(:deny, "host.com") store.deny("host.com") store = Puppet::Network::AuthStore.new assert_nothing_raised do assert_nil( store.allow("*"), "allow did not return nil") end assert( store.globalallow?, "did not enable global allow") end def test_hostnames Puppet[:trace] = false %w{ kirby.madstop.com luke.madstop.net name-other.madstop.net }.each { |name| assert_nothing_raised("Failed to @store simple name #{name}") { @store.allow(name) } assert(@store.allowed?(name, "192.168.0.1"), "Name #{name} not allowed") } %w{ ^invalid! inval$id }.each { |pat| assert_raise( Puppet::AuthStoreError, "name '#{pat}' was allowed") { @store.allow(pat) } } end def test_domains assert_nothing_raised("Failed to @store domains") { @store.allow("*.a.very.long.domain.name.com") @store.allow("*.madstop.com") @store.allow("*.some-other.net") @store.allow("*.much.longer.more-other.net") } %w{ madstop.com culain.madstop.com kirby.madstop.com funtest.some-other.net ya-test.madstop.com some.much.much.longer.more-other.net }.each { |name| assert(@store.allowed?(name, "192.168.0.1"), "Host #{name} not allowed") } assert_raise(Puppet::AuthStoreError) { @store.allow("domain.*.com") } assert( !@store.allowed?("very.long.domain.name.com", "1.2.3.4"), "Long hostname allowed") assert_raise(Puppet::AuthStoreError) { @store.allow("domain.*.other.com") } end # #531 def test_case_insensitivity @store.allow("hostname.com") %w{hostname.com Hostname.COM hostname.Com HOSTNAME.COM}.each do |name| assert(@store.allowed?(name, "127.0.0.1"), "did not allow #{name}") end end def test_allowed? Puppet[:trace] = false assert( @store.allowed?(nil, nil), "Did not default to true for local checks") assert_raise(Puppet::DevError, "did not fail on one input") do @store.allowed?("host.com", nil) end assert_raise(Puppet::DevError, "did not fail on one input") do @store.allowed?(nil, "192.168.0.1") end end # Make sure more specific allows and denies win over generalities def test_specific_overrides @store.allow("host.madstop.com") @store.deny("*.madstop.com") assert( @store.allowed?("host.madstop.com", "192.168.0.1"), "More specific allowal by name failed") @store.allow("192.168.0.1") @store.deny("192.168.0.0/24") assert( @store.allowed?("host.madstop.com", "192.168.0.1"), "More specific allowal by ip failed") end def test_dynamic_backreferences @store.allow("$1.madstop.com") assert_nothing_raised { @store.interpolate([nil, "host"]) } assert(@store.allowed?("host.madstop.com", "192.168.0.1"), "interpolation failed") assert_nothing_raised { @store.reset_interpolation } end def test_dynamic_ip @store.allow("192.168.0.$1") assert_nothing_raised { @store.interpolate([nil, "12"]) } assert(@store.allowed?("host.madstop.com", "192.168.0.12"), "interpolation failed") assert_nothing_raised { @store.reset_interpolation } end def test_multiple_dynamic_backreferences @store.allow("$1.$2") assert_nothing_raised { @store.interpolate([nil, "host", "madstop.com"]) } assert(@store.allowed?("host.madstop.com", "192.168.0.1"), "interpolation failed") assert_nothing_raised { @store.reset_interpolation } end def test_multithreaded_allow_with_dynamic_backreferences @store.allow("$1.madstop.com") threads = [] 9.times { |a| threads << Thread.new { 9.times { |b| Thread.pass @store.interpolate([nil, "a#{b}", "madstop.com"]) Thread.pass assert( @store.allowed?("a#{b}.madstop.com", "192.168.0.1") ) Thread.pass @store.reset_interpolation Thread.pass } } } threads.each { |th| th.join } end end class TestAuthStoreDeclaration < PuppetTest::TestCase include PuppetTest Declaration = Puppet::Network::AuthStore::Declaration def setup super @decl = Declaration.new(:allow, "hostname.com") end def test_parse { "192.168.0.1" => [:ip, IPAddr.new("192.168.0.1"), nil], "2001:700:300:1800::" => [:ip, IPAddr.new("2001:700:300:1800::"), nil], "2001:700:300:1800::/64" => [:ip, IPAddr.new("2001:700:300:1800::/64"), 64], "192.168.0.1/32" => [:ip, IPAddr.new("192.168.0.1/32"), 32], "192.168.0.1/24" => [:ip, IPAddr.new("192.168.0.1/24"), 24], "192.*" => [:ip, IPAddr.new("192.0.0.0/8"), 8], "192.168.*" => [:ip, IPAddr.new("192.168.0.0/16"), 16], "192.168.0.*" => [:ip, IPAddr.new("192.168.0.0/24"), 24], "hostname.com" => [:domain, %w{com hostname}, nil], "Hostname.COM" => [:domain, %w{com hostname}, nil], "billy.Hostname.COM" => [:domain, %w{com hostname billy}, nil], "billy-jean.Hostname.COM" => [:domain, %w{com hostname billy-jean}, nil], "*.hostname.COM" => [:domain, %w{com hostname}, 2], "*.hostname.COM" => [:domain, %w{com hostname}, 2], "$1.hostname.COM" => [:dynamic, %w{com hostname $1}, nil], "192.168.$1.$2" => [:dynamic, %w{$2 $1 168 192}, nil], "8A5BC90C-B8FD-4CBC-81DA-BAD84D551791" => [:opaque, %w{8A5BC90C-B8FD-4CBC-81DA-BAD84D551791}, nil] }.each do |input, output| # Create a new decl each time, so values aren't cached. assert_nothing_raised do @decl = Declaration.new(:allow, input) end [:name, :pattern, :length].zip(output).each do |method, value| assert_equal(value, @decl.send(method), "Got incorrect value for #{method} from #{input}") end end %w{-hostname.com hostname.*}.each do |input| assert_raise(Puppet::AuthStoreError, "Did not fail on #{input}") do @decl.pattern = input end end ["hostname .com", "192.168 .0.1"].each do |input| assert_raise(Puppet::AuthStoreError, "Did not fail on #{input}") do @decl.pattern = input end end end def test_result ["allow", :allow].each do |val| assert_nothing_raised { @decl.type = val } assert_equal(true, @decl.result, "did not result to true with #{val.inspect}") end [:deny, "deny"].each do |val| assert_nothing_raised { @decl.type = val } assert_equal( false, @decl.result, "did not result to false with #{val.inspect}") end - ["yay", 1, nil, false, true].each do |val| - assert_raise(ArgumentError, "Did not fail on #{val.inspect}") do - @decl.type = val - end + assert_raise(ArgumentError, "Did not fail on incorrect type") do + @decl.type = "nope" end end def test_munge_name { "hostname.com" => %w{com hostname}, "alley.hostname.com" => %w{com hostname alley}, "*.hostname.com" => %w{com hostname *}, "*.HOSTNAME.Com" => %w{com hostname *}, "*.HOSTNAME.Com" => %w{com hostname *}, }.each do |input, output| assert_equal(output, @decl.send(:munge_name, input), "munged #{input} incorrectly") end end # Make sure people can specify TLDs def test_match_tlds assert_nothing_raised { @decl.pattern = "*.tld" } assert_equal(%w{tld}, @decl.pattern, "Failed to allow custom tld") end # Make sure we sort correctly. def test_sorting # Make sure declarations with no length sort first. host_exact = Declaration.new(:allow, "host.com") host_range = Declaration.new(:allow, "*.host.com") ip_exact = Declaration.new(:allow, "192.168.0.1") ip_range = Declaration.new(:allow, "192.168.0.*") assert_equal( -1, host_exact <=> host_range, "exact name match did not sort first") assert_equal( -1, ip_exact <=> ip_range, "exact ip match did not sort first") # Next make sure we sort by length ip_long = Declaration.new(:allow, "192.168.*") assert_equal(-1, ip_range <=> ip_long, "/16 sorted before /24 in ip") # Now try it using masks ip24 = Declaration.new(:allow, "192.168.0.0/24") ip16 = Declaration.new(:allow, "192.168.0.0/16") assert_equal(-1, ip24 <=> ip16, "/16 sorted before /24 in ip with masks") # Make sure ip checks sort before host checks assert_equal(-1, ip_exact <=> host_exact, "IP exact did not sort before host exact") assert_equal( -1, ip_range <=> host_range, "IP range did not sort before host range") host_long = Declaration.new(:allow, "*.domain.host.com") assert_equal(-1, host_long <=> host_range, "did not sort by domain length") # Now make sure denies sort before allows, for equivalent # declarations. host_deny = Declaration.new(:deny, "host.com") assert_equal(-1, host_deny <=> host_exact, "deny did not sort before allow when exact") host_range_deny = Declaration.new(:deny, "*.host.com") assert_equal(-1, host_range_deny <=> host_range, "deny did not sort before allow when ranged") ip_allow = Declaration.new(:allow, "192.168.0.0/16") ip_deny = Declaration.new(:deny, "192.168.0.0/16") assert_equal( -1, ip_deny <=> ip_allow, "deny did not sort before allow in ip range") %w{host.com *.domain.com 192.168.0.1 192.168.0.1/24}.each do |decl| assert_equal(0, Declaration.new(:allow, decl) <=> Declaration.new(:allow, decl), "Equivalent declarations for #{decl} were considered different" ) end end def test_match? host = Declaration.new(:allow, "host.com") host.expects(:matchname?).with("host.com") host.match?("host.com", "192.168.0.1") ip = Declaration.new(:allow, "192.168.0.1") ip.pattern.expects(:include?) ip.match?("host.com", "192.168.0.1") end def test_matchname? host = Declaration.new(:allow, "host.com") assert(host.send(:matchname?, "host.com"), "exact did not match") assert(! host.send(:matchname?, "yay.com"), "incorrect match") domain = Declaration.new(:allow, "*.domain.com") %w{host.domain.com domain.com very.long.domain.com very-long.domain.com }.each do |name| assert(domain.send(:matchname?, name), "Did not match #{name}") end end end diff --git a/test/util/fileparsing.rb b/test/util/fileparsing.rb index 831f19bdb..fe52bf2de 100755 --- a/test/util/fileparsing.rb +++ b/test/util/fileparsing.rb @@ -1,725 +1,721 @@ #!/usr/bin/env ruby require File.expand_path(File.dirname(__FILE__) + '/../lib/puppettest') require 'puppettest' require 'puppettest/fileparsing' require 'puppet' require 'puppet/util/fileparsing' class TestUtilFileParsing < Test::Unit::TestCase include PuppetTest include PuppetTest::FileParsing class FParser include Puppet::Util::FileParsing end def setup super @parser = FParser.new end def test_lines assert_equal("\n", @parser.line_separator, "Default separator was incorrect") {"\n" => ["one two\nthree four", "one two\nthree four\n"], "\t" => ["one two\tthree four", "one two\tthree four\t"], }.each do |sep, tests| assert_nothing_raised do @parser.line_separator = sep end assert_equal( sep, @parser.line_separator, "Did not set separator") tests.each do |test| assert_equal(["one two", "three four"], @parser.lines(test), "Incorrectly parsed #{test.inspect}") end end end # Make sure parse calls the appropriate methods or errors out def test_parse @parser.meta_def(:parse_line) do |line| line.split(/\s+/) end text = "one line\ntwo line" should = [%w{one line}, %w{two line}] ret = nil assert_nothing_raised do ret = @parser.parse(text) end assert_equal(should, ret) end # Make sure we correctly handle different kinds of text lines. def test_text_line comment = "# this is a comment" # Make sure it fails if no regex is passed assert_raise(ArgumentError) do @parser.text_line :comment end # define a text matching comment record assert_nothing_raised do @parser.text_line :comment, :match => /^#/ end # Make sure it matches assert_nothing_raised do assert_equal( {:record_type => :comment, :line => comment}, @parser.parse_line(comment)) end # But not something else assert_nothing_raised do assert_nil(@parser.parse_line("some other text")) end # Now define another type and make sure we get the right one back assert_nothing_raised do @parser.text_line :blank, :match => /^\s*$/ end # The comment should still match assert_nothing_raised do assert_equal( {:record_type => :comment, :line => comment}, @parser.parse_line(comment)) end # As should our new line type assert_nothing_raised do assert_equal( {:record_type => :blank, :line => ""}, @parser.parse_line("")) end end def test_parse_line Puppet[:trace] = false comment = "# this is a comment" # Make sure it fails if we don't have any record types defined assert_raise(Puppet::DevError) do @parser.parse_line(comment) end # Now define a text matching comment record assert_nothing_raised do @parser.text_line :comment, :match => /^#/ end # And make sure we can't define another one with the same name assert_raise(ArgumentError) do @parser.text_line :comment, :match => /^"/ end result = nil assert_nothing_raised("Did not parse text line") do result = @parser.parse_line comment end assert_equal({:record_type => :comment, :line => comment}, result) # Make sure we just return nil on unmatched lines. assert_nothing_raised("Did not parse text line") do result = @parser.parse_line "No match for this" end assert_nil(result, "Somehow matched an empty line") # Now define another type of comment, and make sure both types get # correctly returned as comments assert_nothing_raised do @parser.text_line :comment2, :match => /^"/ end assert_nothing_raised("Did not parse old comment") do assert_equal({:record_type => :comment, :line => comment}, @parser.parse_line(comment)) end comment = '" another type of comment' assert_nothing_raised("Did not parse new comment") do assert_equal({:record_type => :comment2, :line => comment}, @parser.parse_line(comment)) end # Now define two overlapping record types and make sure we keep the # correct order. We do first match, not longest match. assert_nothing_raised do @parser.text_line :one, :match => /^y/ @parser.text_line :two, :match => /^yay/ end assert_nothing_raised do assert_equal({:record_type => :one, :line => "yayness"}, @parser.parse_line("yayness")) end end def test_record_line tabrecord = "tab separated content" spacerecord = "space separated content" # Make sure we always require an appropriate set of options [{:separator => "\t"}, {}, {:fields => %w{record_type}}].each do |opts| assert_raise(ArgumentError, "Accepted #{opts.inspect}") do @parser.record_line :record, opts end end # Verify that our default separator is tabs tabs = nil assert_nothing_raised do tabs = @parser.record_line :tabs, :fields => [:name, :first, :second] end # Make sure out tab line gets matched tabshould = {:record_type => :tabs, :name => "tab", :first => "separated", :second => "content"} assert_nothing_raised do assert_equal(tabshould, @parser.handle_record_line(tabrecord, tabs)) end # Now add our space-separated record type spaces = nil assert_nothing_raised do spaces = @parser.record_line :spaces, :fields => [:name, :first, :second] end # Now make sure both lines parse correctly spaceshould = {:record_type => :spaces, :name => "space", :first => "separated", :second => "content"} assert_nothing_raised do assert_equal(tabshould, @parser.handle_record_line(tabrecord, tabs)) assert_equal(spaceshould, @parser.handle_record_line(spacerecord, spaces)) end end def test_to_line @parser.text_line :comment, :match => /^#/ @parser.text_line :blank, :match => /^\s*$/ @parser.record_line :record, :fields => %w{name one two}, :joiner => "\t" johnny = {:record_type => :record, :name => "johnny", :one => "home", :two => "yay"} bill = {:record_type => :record, :name => "bill", :one => "work", :two => "boo"} records = { :comment => {:record_type => :comment, :line => "# This is a file"}, :blank => {:record_type => :blank, :line => ""}, :johnny => johnny, :bill => bill } lines = { :comment => "# This is a file", :blank => "", :johnny => "johnny home yay", :bill => "bill work boo" } records.each do |name, details| result = nil assert_nothing_raised do result = @parser.to_line(details) end assert_equal(lines[name], result) end order = [:comment, :blank, :johnny, :bill] file = order.collect { |name| lines[name] }.join("\n") ordered_records = order.collect { |name| records[name] } # Make sure we default to a trailing separator assert_equal(true, @parser.trailing_separator, "Did not default to a trailing separtor") # Start without a trailing separator @parser.trailing_separator = false assert_nothing_raised do assert_equal(file, @parser.to_file(ordered_records)) end # Now with a trailing separator file += "\n" @parser.trailing_separator = true assert_nothing_raised do assert_equal(file, @parser.to_file(ordered_records)) end # Now try it with a different separator, so we're not just catching # defaults file.gsub!("\n", "\t") @parser.line_separator = "\t" assert_nothing_raised do assert_equal(file, @parser.to_file(ordered_records)) end end # Make sure fields that are marked absent get replaced with the appropriate # string. def test_absent_fields record = nil assert_nothing_raised do record = @parser.record_line :record, :fields => %w{one two three}, :optional => %w{two three} end assert_equal("", record.absent, "Did not set a default absent string") result = nil assert_nothing_raised do result = @parser.to_line( :record_type => :record, :one => "a", :two => :absent, :three => "b") end assert_equal("a b", result, "Absent was not correctly replaced") # Now try using a different replacement character record.absent = "*" # Because cron is a pain in my ass assert_nothing_raised do result = @parser.to_line(:record_type => :record, :one => "a", :two => :absent, :three => "b") end assert_equal("a * b", result, "Absent was not correctly replaced") # Make sure we deal correctly with the string 'absent' assert_nothing_raised do result = @parser.to_line( :record_type => :record, :one => "a", :two => "b", :three => 'absent') end assert_equal("a b absent", result, "Replaced string 'absent'") # And, of course, make sure we can swap things around. assert_nothing_raised do result = @parser.to_line( :record_type => :record, :one => "a", :two => "b", :three => :absent) end assert_equal("a b *", result, "Absent was not correctly replaced") end # Make sure we can specify a different join character than split character def test_split_join_record_line check = proc do |start, record, final| # Check parsing first result = @parser.parse_line(start) [:one, :two].each do |param| assert_equal( record[param], result[param], "Did not correctly parse #{start.inspect}") end # And generating assert_equal(final, @parser.to_line(result), "Did not correctly generate #{final.inspect} from #{record.inspect}") end # First try it with symmetric characters @parser.record_line :symmetric, :fields => %w{one two}, :separator => " " check.call "a b", {:one => "a", :two => "b"}, "a b" @parser.clear_records # Now assymetric but both strings @parser.record_line :asymmetric, :fields => %w{one two}, :separator => "\t", :joiner => " " check.call "a\tb", {:one => "a", :two => "b"}, "a b" @parser.clear_records # And assymmetric with a regex @parser.record_line :asymmetric2, :fields => %w{one two}, :separator => /\s+/, :joiner => " " check.call "a\tb", {:one => "a", :two => "b"}, "a b" check.call "a b", {:one => "a", :two => "b"}, "a b" end # Make sure we correctly regenerate files. def test_to_file @parser.text_line :comment, :match => /^#/ @parser.text_line :blank, :match => /^\s*$/ @parser.record_line :record, :fields => %w{name one two} text = "# This is a comment johnny one two billy three four\n" # Just parse and generate, to make sure it's isomorphic. assert_nothing_raised do assert_equal(text, @parser.to_file(@parser.parse(text)), "parsing was not isomorphic") end end def test_valid_attrs @parser.record_line :record, :fields => %w{one two three} assert( @parser.valid_attr?(:record, :one), "one was considered invalid") assert( @parser.valid_attr?(:record, :ensure), "ensure was considered invalid") assert( ! @parser.valid_attr?(:record, :four), "four was considered valid") end def test_record_blocks options = nil assert_nothing_raised do # Just do a simple test options = @parser.record_line :record, :fields => %w{name alias info} do |line| line = line.dup ret = {} if line.sub!(/(\w+)\s*/, '') ret[:name] = $1 else return nil end if line.sub!(/(#.+)/, '') desc = $1.sub(/^#\s*/, '') ret[:description] = desc unless desc == "" end ret[:alias] = line.split(/\s+/) if line != "" return ret end end values = { :name => "tcpmux", :description => "TCP port service multiplexer", :alias => ["sink"] } { "tcpmux " => [:name], "tcpmux" => [:name], "tcpmux sink" => [:name, :port, :protocols, :alias], "tcpmux # TCP port service multiplexer" => [:name, :description, :port, :protocols], "tcpmux sink # TCP port service multiplexer" => [:name, :description, :port, :alias, :protocols], "tcpmux sink null # TCP port service multiplexer" => [:name, :description, :port, :alias, :protocols], }.each do |line, should| result = nil assert_nothing_raised do result = @parser.handle_record_line(line, options) end assert(result, "Did not get a result back for '#{line}'") should.each do |field| if field == :alias and line =~ /null/ assert_equal(%w{sink null}, result[field], "Field #{field} was not right in '#{line}'") else assert_equal(values[field], result[field], "Field #{field} was not right in '#{line}'") end end end end # Make sure we correctly handle optional fields. We'll skip this # functionality until we really know we need it. def test_optional_fields assert_nothing_raised do @parser.record_line :record, :fields => %w{one two three four}, :optional => %w{three four}, :absent => "*", :separator => " " # A single space end { "a b c d" => [], "a b * d" => [:three], "a b * *" => [:three, :four], "a b c *" => [:four] }.each do |line, absentees| record = nil assert_nothing_raised do record = @parser.parse_line(line) end # Absent field is :absent, not "*" inside the record absentees.each do |absentee| assert_equal(:absent, record[absentee]) end # Now regenerate the line newline = nil assert_nothing_raised do newline = @parser.to_line(record) end # And make sure they're equal assert_equal(line, newline) end # Now make sure it pukes if we don't provide the required fields assert_raise(ArgumentError) do @parser.to_line(:record_type => :record, :one => "yay") end end def test_record_rts # Start with the default assert_nothing_raised do @parser.record_line :record, :fields => %w{one two three four}, :optional => %w{three four} end assert_equal( "a b ", @parser.to_line(:record_type => :record, :one => "a", :two => "b") ) # Now say yes to removing @parser.clear_records assert_nothing_raised do @parser.record_line :record, :fields => %w{one two three four}, :optional => %w{three four}, :rts => true end assert_equal( "a b", @parser.to_line(:record_type => :record, :one => "a", :two => "b") ) # Lastly, try a regex @parser.clear_records assert_nothing_raised do @parser.record_line :record, :fields => %w{one two three four}, :optional => %w{three four}, :absent => "*", :rts => /[ *]+$/ end assert_equal( "a b", @parser.to_line(:record_type => :record, :one => "a", :two => "b") ) end # Make sure the last field can contain the separator, as crontabs do, and # that we roll them all up by default. def test_field_rollups @parser.record_line :yes, :fields => %w{name one two} result = nil assert_nothing_raised do result = @parser.send(:parse_line, "Name One Two Three") end assert_equal( "Two Three", result[:two], "Did not roll up last fields by default") @parser = FParser.new assert_nothing_raised("Could not create record that rolls up fields") do @parser.record_line :no, :fields => %w{name one two}, :rollup => false end result = nil assert_nothing_raised do result = @parser.send(:parse_line, "Name One Two Three") end assert_equal( "Two", result[:two], "Rolled up last fields when rollup => false") end def test_text_blocks record = nil assert_nothing_raised do record = @parser.text_line :name, :match => %r{^#} do |line| {:line => line.upcase} end end assert( record.respond_to?(:process), "Block was not used with text line") assert_equal("YAYNESS", record.process("yayness")[:line], "Did not call process method") end def test_hooks record = nil # First try it with a normal record assert_nothing_raised("Could not set hooks") do record = @parser.record_line :yay, :fields => %w{one two}, :post_parse => proc { |hash| hash[:posted] = true }, :pre_gen => proc { |hash| hash[:one] = hash[:one].upcase }, :to_line => proc { |hash| "# Line\n" + join(hash) } end assert(record.respond_to?(:post_parse), "did not create method for post-hook") assert(record.respond_to?(:pre_gen), "did not create method for pre-hook") result = nil assert_nothing_raised("Could not process line with hooks") do result = @parser.parse_line("one two") end assert(result[:posted], "Did not run post-hook") old_result = result # Now make sure our pre-gen hook is called assert_nothing_raised("Could not generate line with hooks") do result = @parser.to_line(result) end assert_equal("# Line\nONE two", result, "did not call pre-gen hook") assert_equal("one", old_result[:one], "passed original hash to pre hook") end end class TestUtilFileRecord < Test::Unit::TestCase include PuppetTest include PuppetTest::FileParsing Record = Puppet::Util::FileParsing::FileRecord def test_new_filerecord - [ [:fake, {}], - [nil, ] - ].each do |args| - assert_raise(ArgumentError, "Did not fail on #{args.inspect}") do - Record.new(*args) - end + assert_raise(ArgumentError, "Did not fail on unknown record type") do + Record.new(:fake, {}) end # Make sure the fields get turned into symbols record = nil assert_nothing_raised do record = Record.new(:record, :fields => %w{one two}) end assert_equal([:one, :two], record.fields, "Did not symbolize fields") # Make sure we fail on invalid fields [:record_type, :target, :on_disk].each do |field| assert_raise(ArgumentError, "Did not fail on invalid field #{field}") { Record.new(:record, :fields => [field]) } end end def test_defaults record = Record.new(:text, :match => %r{^#}) [:absent, :separator, :joiner, :optional].each do |field| assert_nil(record.send(field), "#{field} was not nil") end record = Record.new(:record, :fields => %w{fields}) {:absent => "", :separator => /\s+/, :joiner => " ", :optional => []}.each do |field, default| assert_equal(default, record.send(field), "#{field} was not default") end end def test_block record = nil assert_nothing_raised("Could not pass a block when creating record") do record = Record.new(:record, :fields => %w{one}) do |line| return line.upcase end end line = "This is a line" assert( record.respond_to?(:process), "Record did not define :process method") assert_equal( line.upcase, record.process(line), "Record did not process line correctly") end # Make sure we can declare that we want the block to be instance-eval'ed instead of # defining the 'process' method. def test_instance_block record = nil assert_nothing_raised("Could not pass a block when creating record") do record = Record.new(:record, :block_eval => :instance, :fields => %w{one}) do def process(line) line.upcase end def to_line(details) details.upcase end end end assert(record.respond_to?(:process), "Block was not instance-eval'ed and process was not defined") assert(record.respond_to?(:to_line), "Block was not instance-eval'ed and to_line was not defined") line = "some text" assert_equal(line.upcase, record.process(line), "Instance-eval'ed record did not call :process correctly") assert_equal(line.upcase, record.to_line(line), "Instance-eval'ed record did not call :to_line correctly") end end