diff --git a/spec/unit/type/host_spec.rb b/spec/unit/type/host_spec.rb index 3cbe56943..1b24ac8f0 100755 --- a/spec/unit/type/host_spec.rb +++ b/spec/unit/type/host_spec.rb @@ -1,656 +1,665 @@ #!/usr/bin/env rspec require 'spec_helper' host = Puppet::Type.type(:host) describe host do + FakeHostProvider = Struct.new(:ip, :host_aliases, :comment) before do @class = host @catalog = Puppet::Resource::Catalog.new - @provider = stub 'provider' + @provider = FakeHostProvider.new @resource = stub 'resource', :resource => nil, :provider => @provider end it "should have :name be its namevar" do @class.key_attributes.should == [:name] end describe "when validating attributes" do [:name, :provider ].each do |param| it "should have a #{param} parameter" do @class.attrtype(param).should == :param end end [:ip, :target, :host_aliases, :comment, :ensure].each do |property| it "should have a #{property} property" do @class.attrtype(property).should == :property end end it "should have a list host_aliases" do @class.attrclass(:host_aliases).ancestors.should be_include(Puppet::Property::OrderedList) end end describe "when validating values" do it "should support present as a value for ensure" do proc { @class.new(:name => "foo", :ensure => :present) }.should_not raise_error end it "should support absent as a value for ensure" do proc { @class.new(:name => "foo", :ensure => :absent) }.should_not raise_error end it "should accept IPv4 addresses" do proc { @class.new(:name => "foo", :ip => '10.96.0.1') }.should_not raise_error end it "should accept long IPv6 addresses" do # Taken from wikipedia article about ipv6 proc { @class.new(:name => "foo", :ip => '2001:0db8:85a3:08d3:1319:8a2e:0370:7344') }.should_not raise_error end it "should accept one host_alias" do proc { @class.new(:name => "foo", :host_aliases => 'alias1') }.should_not raise_error end it "should accept multiple host_aliases" do proc { @class.new(:name => "foo", :host_aliases => [ 'alias1', 'alias2' ]) }.should_not raise_error end it "should accept shortened IPv6 addresses" do proc { @class.new(:name => "foo", :ip => '2001:db8:0:8d3:0:8a2e:70:7344') }.should_not raise_error proc { @class.new(:name => "foo", :ip => '::ffff:192.0.2.128') }.should_not raise_error proc { @class.new(:name => "foo", :ip => '::1') }.should_not raise_error end it "should not accept malformed IPv4 addresses like 192.168.0.300" do proc { @class.new(:name => "foo", :ip => '192.168.0.300') }.should raise_error end it "should reject over-long IPv4 addresses" do expect { @class.new(:name => "foo", :ip => '10.10.10.10.10') }.to raise_error end it "should not accept malformed IP addresses like 2001:0dg8:85a3:08d3:1319:8a2e:0370:7344" do proc { @class.new(:name => "foo", :ip => '2001:0dg8:85a3:08d3:1319:8a2e:0370:7344') }.should raise_error end # Assorted, annotated IPv6 passes. ["::1", # loopback, compressed, non-routable "::", # unspecified, compressed, non-routable "0:0:0:0:0:0:0:1", # loopback, full "0:0:0:0:0:0:0:0", # unspecified, full "2001:DB8:0:0:8:800:200C:417A", # unicast, full "FF01:0:0:0:0:0:0:101", # multicast, full "2001:DB8::8:800:200C:417A", # unicast, compressed "FF01::101", # multicast, compressed # Some more test cases that should pass. "2001:0000:1234:0000:0000:C1C0:ABCD:0876", "3ffe:0b00:0000:0000:0001:0000:0000:000a", "FF02:0000:0000:0000:0000:0000:0000:0001", "0000:0000:0000:0000:0000:0000:0000:0001", "0000:0000:0000:0000:0000:0000:0000:0000", # Assorted valid, compressed IPv6 addresses. "2::10", "ff02::1", "fe80::", "2002::", "2001:db8::", "2001:0db8:1234::", "::ffff:0:0", "::1", "1:2:3:4:5:6:7:8", "1:2:3:4:5:6::8", "1:2:3:4:5::8", "1:2:3:4::8", "1:2:3::8", "1:2::8", "1::8", "1::2:3:4:5:6:7", "1::2:3:4:5:6", "1::2:3:4:5", "1::2:3:4", "1::2:3", "1::8", "::2:3:4:5:6:7:8", "::2:3:4:5:6:7", "::2:3:4:5:6", "::2:3:4:5", "::2:3:4", "::2:3", "::8", "1:2:3:4:5:6::", "1:2:3:4:5::", "1:2:3:4::", "1:2:3::", "1:2::", "1::", "1:2:3:4:5::7:8", "1:2:3:4::7:8", "1:2:3::7:8", "1:2::7:8", "1::7:8", # IPv4 addresses as dotted-quads "1:2:3:4:5:6:1.2.3.4", "1:2:3:4:5::1.2.3.4", "1:2:3:4::1.2.3.4", "1:2:3::1.2.3.4", "1:2::1.2.3.4", "1::1.2.3.4", "1:2:3:4::5:1.2.3.4", "1:2:3::5:1.2.3.4", "1:2::5:1.2.3.4", "1::5:1.2.3.4", "1::5:11.22.33.44", "fe80::217:f2ff:254.7.237.98", "::ffff:192.168.1.26", "::ffff:192.168.1.1", "0:0:0:0:0:0:13.1.68.3", # IPv4-compatible IPv6 address, full, deprecated "0:0:0:0:0:FFFF:129.144.52.38", # IPv4-mapped IPv6 address, full "::13.1.68.3", # IPv4-compatible IPv6 address, compressed, deprecated "::FFFF:129.144.52.38", # IPv4-mapped IPv6 address, compressed "fe80:0:0:0:204:61ff:254.157.241.86", "fe80::204:61ff:254.157.241.86", "::ffff:12.34.56.78", "::ffff:192.0.2.128", # this is OK, since there's a single zero digit in IPv4 "fe80:0000:0000:0000:0204:61ff:fe9d:f156", "fe80:0:0:0:204:61ff:fe9d:f156", "fe80::204:61ff:fe9d:f156", "::1", "fe80::", "fe80::1", "::ffff:c000:280", # Additional test cases from http://rt.cpan.org/Public/Bug/Display.html?id=50693 "2001:0db8:85a3:0000:0000:8a2e:0370:7334", "2001:db8:85a3:0:0:8a2e:370:7334", "2001:db8:85a3::8a2e:370:7334", "2001:0db8:0000:0000:0000:0000:1428:57ab", "2001:0db8:0000:0000:0000::1428:57ab", "2001:0db8:0:0:0:0:1428:57ab", "2001:0db8:0:0::1428:57ab", "2001:0db8::1428:57ab", "2001:db8::1428:57ab", "0000:0000:0000:0000:0000:0000:0000:0001", "::1", "::ffff:0c22:384e", "2001:0db8:1234:0000:0000:0000:0000:0000", "2001:0db8:1234:ffff:ffff:ffff:ffff:ffff", "2001:db8:a::123", "fe80::", "1111:2222:3333:4444:5555:6666:7777:8888", "1111:2222:3333:4444:5555:6666:7777::", "1111:2222:3333:4444:5555:6666::", "1111:2222:3333:4444:5555::", "1111:2222:3333:4444::", "1111:2222:3333::", "1111:2222::", "1111::", "1111:2222:3333:4444:5555:6666::8888", "1111:2222:3333:4444:5555::8888", "1111:2222:3333:4444::8888", "1111:2222:3333::8888", "1111:2222::8888", "1111::8888", "::8888", "1111:2222:3333:4444:5555::7777:8888", "1111:2222:3333:4444::7777:8888", "1111:2222:3333::7777:8888", "1111:2222::7777:8888", "1111::7777:8888", "::7777:8888", "1111:2222:3333:4444::6666:7777:8888", "1111:2222:3333::6666:7777:8888", "1111:2222::6666:7777:8888", "1111::6666:7777:8888", "::6666:7777:8888", "1111:2222:3333::5555:6666:7777:8888", "1111:2222::5555:6666:7777:8888", "1111::5555:6666:7777:8888", "::5555:6666:7777:8888", "1111:2222::4444:5555:6666:7777:8888", "1111::4444:5555:6666:7777:8888", "::4444:5555:6666:7777:8888", "1111::3333:4444:5555:6666:7777:8888", "::3333:4444:5555:6666:7777:8888", "::2222:3333:4444:5555:6666:7777:8888", "1111:2222:3333:4444:5555:6666:123.123.123.123", "1111:2222:3333:4444:5555::123.123.123.123", "1111:2222:3333:4444::123.123.123.123", "1111:2222:3333::123.123.123.123", "1111:2222::123.123.123.123", "1111::123.123.123.123", "::123.123.123.123", "1111:2222:3333:4444::6666:123.123.123.123", "1111:2222:3333::6666:123.123.123.123", "1111:2222::6666:123.123.123.123", "1111::6666:123.123.123.123", "::6666:123.123.123.123", "1111:2222:3333::5555:6666:123.123.123.123", "1111:2222::5555:6666:123.123.123.123", "1111::5555:6666:123.123.123.123", "::5555:6666:123.123.123.123", "1111:2222::4444:5555:6666:123.123.123.123", "1111::4444:5555:6666:123.123.123.123", "::4444:5555:6666:123.123.123.123", "1111::3333:4444:5555:6666:123.123.123.123", "::2222:3333:4444:5555:6666:123.123.123.123", # Playing with combinations of "0" and "::"; these are all sytactically # correct, but are bad form because "0" adjacent to "::" should be # combined into "::" "::0:0:0:0:0:0:0", "::0:0:0:0:0:0", "::0:0:0:0:0", "::0:0:0:0", "::0:0:0", "::0:0", "::0", "0:0:0:0:0:0:0::", "0:0:0:0:0:0::", "0:0:0:0:0::", "0:0:0:0::", "0:0:0::", "0:0::", "0::", # Additional cases: http://crisp.tweakblogs.net/blog/2031/ipv6-validation-%28and-caveats%29.html "0:a:b:c:d:e:f::", "::0:a:b:c:d:e:f", # syntactically correct, but bad form (::0:... could be combined) "a:b:c:d:e:f:0::", ].each do |ip| it "should accept #{ip.inspect} as an IPv6 address" do expect { @class.new(:name => "foo", :ip => ip) }.not_to raise_error end end # ...aaaand, some failure cases. [":", "02001:0000:1234:0000:0000:C1C0:ABCD:0876", # extra 0 not allowed! "2001:0000:1234:0000:00001:C1C0:ABCD:0876", # extra 0 not allowed! "2001:0000:1234:0000:0000:C1C0:ABCD:0876 0", # junk after valid address "2001:0000:1234: 0000:0000:C1C0:ABCD:0876", # internal space "3ffe:0b00:0000:0001:0000:0000:000a", # seven segments "FF02:0000:0000:0000:0000:0000:0000:0000:0001", # nine segments "3ffe:b00::1::a", # double "::" "::1111:2222:3333:4444:5555:6666::", # double "::" "1:2:3::4:5::7:8", # Double "::" "12345::6:7:8", # IPv4 embedded, but bad... "1::5:400.2.3.4", "1::5:260.2.3.4", "1::5:256.2.3.4", "1::5:1.256.3.4", "1::5:1.2.256.4", "1::5:1.2.3.256", "1::5:300.2.3.4", "1::5:1.300.3.4", "1::5:1.2.300.4", "1::5:1.2.3.300", "1::5:900.2.3.4", "1::5:1.900.3.4", "1::5:1.2.900.4", "1::5:1.2.3.900", "1::5:300.300.300.300", "1::5:3000.30.30.30", "1::400.2.3.4", "1::260.2.3.4", "1::256.2.3.4", "1::1.256.3.4", "1::1.2.256.4", "1::1.2.3.256", "1::300.2.3.4", "1::1.300.3.4", "1::1.2.300.4", "1::1.2.3.300", "1::900.2.3.4", "1::1.900.3.4", "1::1.2.900.4", "1::1.2.3.900", "1::300.300.300.300", "1::3000.30.30.30", "::400.2.3.4", "::260.2.3.4", "::256.2.3.4", "::1.256.3.4", "::1.2.256.4", "::1.2.3.256", "::300.2.3.4", "::1.300.3.4", "::1.2.300.4", "::1.2.3.300", "::900.2.3.4", "::1.900.3.4", "::1.2.900.4", "::1.2.3.900", "::300.300.300.300", "::3000.30.30.30", "2001:1:1:1:1:1:255Z255X255Y255", # garbage instead of "." in IPv4 "::ffff:192x168.1.26", # ditto "::ffff:2.3.4", "::ffff:257.1.2.3", "1.2.3.4:1111:2222:3333:4444::5555", "1.2.3.4:1111:2222:3333::5555", "1.2.3.4:1111:2222::5555", "1.2.3.4:1111::5555", "1.2.3.4::5555", "1.2.3.4::", # Testing IPv4 addresses represented as dotted-quads Leading zero's in # IPv4 addresses not allowed: some systems treat the leading "0" in # ".086" as the start of an octal number Update: The BNF in RFC-3986 # explicitly defines the dec-octet (for IPv4 addresses) not to have a # leading zero "fe80:0000:0000:0000:0204:61ff:254.157.241.086", "XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:1.2.3.4", "1111:2222:3333:4444:5555:6666:00.00.00.00", "1111:2222:3333:4444:5555:6666:000.000.000.000", "1111:2222:3333:4444:5555:6666:256.256.256.256", "1111:2222:3333:4444::5555:", "1111:2222:3333::5555:", "1111:2222::5555:", "1111::5555:", "::5555:", ":::", "1111:", ":", ":1111:2222:3333:4444::5555", ":1111:2222:3333::5555", ":1111:2222::5555", ":1111::5555", ":::5555", ":::", # Additional test cases from http://rt.cpan.org/Public/Bug/Display.html?id=50693 "123", "ldkfj", "2001::FFD3::57ab", "2001:db8:85a3::8a2e:37023:7334", "2001:db8:85a3::8a2e:370k:7334", "1:2:3:4:5:6:7:8:9", "1::2::3", "1:::3:4:5", "1:2:3::4:5:6:7:8:9", # Invalid data "XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX", # Too many components "1111:2222:3333:4444:5555:6666:7777:8888:9999", "1111:2222:3333:4444:5555:6666:7777:8888::", "::2222:3333:4444:5555:6666:7777:8888:9999", # Too few components "1111:2222:3333:4444:5555:6666:7777", "1111:2222:3333:4444:5555:6666", "1111:2222:3333:4444:5555", "1111:2222:3333:4444", "1111:2222:3333", "1111:2222", "1111", # Missing : "11112222:3333:4444:5555:6666:7777:8888", "1111:22223333:4444:5555:6666:7777:8888", "1111:2222:33334444:5555:6666:7777:8888", "1111:2222:3333:44445555:6666:7777:8888", "1111:2222:3333:4444:55556666:7777:8888", "1111:2222:3333:4444:5555:66667777:8888", "1111:2222:3333:4444:5555:6666:77778888", # Missing : intended for :: "1111:2222:3333:4444:5555:6666:7777:8888:", "1111:2222:3333:4444:5555:6666:7777:", "1111:2222:3333:4444:5555:6666:", "1111:2222:3333:4444:5555:", "1111:2222:3333:4444:", "1111:2222:3333:", "1111:2222:", "1111:", ":", ":8888", ":7777:8888", ":6666:7777:8888", ":5555:6666:7777:8888", ":4444:5555:6666:7777:8888", ":3333:4444:5555:6666:7777:8888", ":2222:3333:4444:5555:6666:7777:8888", ":1111:2222:3333:4444:5555:6666:7777:8888", # ::: ":::2222:3333:4444:5555:6666:7777:8888", "1111:::3333:4444:5555:6666:7777:8888", "1111:2222:::4444:5555:6666:7777:8888", "1111:2222:3333:::5555:6666:7777:8888", "1111:2222:3333:4444:::6666:7777:8888", "1111:2222:3333:4444:5555:::7777:8888", "1111:2222:3333:4444:5555:6666:::8888", "1111:2222:3333:4444:5555:6666:7777:::", # Double ::", "::2222::4444:5555:6666:7777:8888", "::2222:3333::5555:6666:7777:8888", "::2222:3333:4444::6666:7777:8888", "::2222:3333:4444:5555::7777:8888", "::2222:3333:4444:5555:7777::8888", "::2222:3333:4444:5555:7777:8888::", "1111::3333::5555:6666:7777:8888", "1111::3333:4444::6666:7777:8888", "1111::3333:4444:5555::7777:8888", "1111::3333:4444:5555:6666::8888", "1111::3333:4444:5555:6666:7777::", "1111:2222::4444::6666:7777:8888", "1111:2222::4444:5555::7777:8888", "1111:2222::4444:5555:6666::8888", "1111:2222::4444:5555:6666:7777::", "1111:2222:3333::5555::7777:8888", "1111:2222:3333::5555:6666::8888", "1111:2222:3333::5555:6666:7777::", "1111:2222:3333:4444::6666::8888", "1111:2222:3333:4444::6666:7777::", "1111:2222:3333:4444:5555::7777::", # Too many components" "1111:2222:3333:4444:5555:6666:7777:8888:1.2.3.4", "1111:2222:3333:4444:5555:6666:7777:1.2.3.4", "1111:2222:3333:4444:5555:6666::1.2.3.4", "::2222:3333:4444:5555:6666:7777:1.2.3.4", "1111:2222:3333:4444:5555:6666:1.2.3.4.5", # Too few components "1111:2222:3333:4444:5555:1.2.3.4", "1111:2222:3333:4444:1.2.3.4", "1111:2222:3333:1.2.3.4", "1111:2222:1.2.3.4", "1111:1.2.3.4", # Missing : "11112222:3333:4444:5555:6666:1.2.3.4", "1111:22223333:4444:5555:6666:1.2.3.4", "1111:2222:33334444:5555:6666:1.2.3.4", "1111:2222:3333:44445555:6666:1.2.3.4", "1111:2222:3333:4444:55556666:1.2.3.4", "1111:2222:3333:4444:5555:66661.2.3.4", # Missing . "1111:2222:3333:4444:5555:6666:255255.255.255", "1111:2222:3333:4444:5555:6666:255.255255.255", "1111:2222:3333:4444:5555:6666:255.255.255255", # Missing : intended for :: ":1.2.3.4", ":6666:1.2.3.4", ":5555:6666:1.2.3.4", ":4444:5555:6666:1.2.3.4", ":3333:4444:5555:6666:1.2.3.4", ":2222:3333:4444:5555:6666:1.2.3.4", ":1111:2222:3333:4444:5555:6666:1.2.3.4", # ::: ":::2222:3333:4444:5555:6666:1.2.3.4", "1111:::3333:4444:5555:6666:1.2.3.4", "1111:2222:::4444:5555:6666:1.2.3.4", "1111:2222:3333:::5555:6666:1.2.3.4", "1111:2222:3333:4444:::6666:1.2.3.4", "1111:2222:3333:4444:5555:::1.2.3.4", # Double :: "::2222::4444:5555:6666:1.2.3.4", "::2222:3333::5555:6666:1.2.3.4", "::2222:3333:4444::6666:1.2.3.4", "::2222:3333:4444:5555::1.2.3.4", "1111::3333::5555:6666:1.2.3.4", "1111::3333:4444::6666:1.2.3.4", "1111::3333:4444:5555::1.2.3.4", "1111:2222::4444::6666:1.2.3.4", "1111:2222::4444:5555::1.2.3.4", "1111:2222:3333::5555::1.2.3.4", # Missing parts "::.", "::..", "::...", "::1...", "::1.2..", "::1.2.3.", "::.2..", "::.2.3.", "::.2.3.4", "::..3.", "::..3.4", "::...4", # Extra : in front ":1111:2222:3333:4444:5555:6666:7777::", ":1111:2222:3333:4444:5555:6666::", ":1111:2222:3333:4444:5555::", ":1111:2222:3333:4444::", ":1111:2222:3333::", ":1111:2222::", ":1111::", ":::", ":1111:2222:3333:4444:5555:6666::8888", ":1111:2222:3333:4444:5555::8888", ":1111:2222:3333:4444::8888", ":1111:2222:3333::8888", ":1111:2222::8888", ":1111::8888", ":::8888", ":1111:2222:3333:4444:5555::7777:8888", ":1111:2222:3333:4444::7777:8888", ":1111:2222:3333::7777:8888", ":1111:2222::7777:8888", ":1111::7777:8888", ":::7777:8888", ":1111:2222:3333:4444::6666:7777:8888", ":1111:2222:3333::6666:7777:8888", ":1111:2222::6666:7777:8888", ":1111::6666:7777:8888", ":::6666:7777:8888", ":1111:2222:3333::5555:6666:7777:8888", ":1111:2222::5555:6666:7777:8888", ":1111::5555:6666:7777:8888", ":::5555:6666:7777:8888", ":1111:2222::4444:5555:6666:7777:8888", ":1111::4444:5555:6666:7777:8888", ":::4444:5555:6666:7777:8888", ":1111::3333:4444:5555:6666:7777:8888", ":::3333:4444:5555:6666:7777:8888", ":::2222:3333:4444:5555:6666:7777:8888", ":1111:2222:3333:4444:5555:6666:1.2.3.4", ":1111:2222:3333:4444:5555::1.2.3.4", ":1111:2222:3333:4444::1.2.3.4", ":1111:2222:3333::1.2.3.4", ":1111:2222::1.2.3.4", ":1111::1.2.3.4", ":::1.2.3.4", ":1111:2222:3333:4444::6666:1.2.3.4", ":1111:2222:3333::6666:1.2.3.4", ":1111:2222::6666:1.2.3.4", ":1111::6666:1.2.3.4", ":::6666:1.2.3.4", ":1111:2222:3333::5555:6666:1.2.3.4", ":1111:2222::5555:6666:1.2.3.4", ":1111::5555:6666:1.2.3.4", ":::5555:6666:1.2.3.4", ":1111:2222::4444:5555:6666:1.2.3.4", ":1111::4444:5555:6666:1.2.3.4", ":::4444:5555:6666:1.2.3.4", ":1111::3333:4444:5555:6666:1.2.3.4", ":::2222:3333:4444:5555:6666:1.2.3.4", # Extra : at end "1111:2222:3333:4444:5555:6666:7777:::", "1111:2222:3333:4444:5555:6666:::", "1111:2222:3333:4444:5555:::", "1111:2222:3333:4444:::", "1111:2222:3333:::", "1111:2222:::", "1111:::", ":::", "1111:2222:3333:4444:5555:6666::8888:", "1111:2222:3333:4444:5555::8888:", "1111:2222:3333:4444::8888:", "1111:2222:3333::8888:", "1111:2222::8888:", "1111::8888:", "::8888:", "1111:2222:3333:4444:5555::7777:8888:", "1111:2222:3333:4444::7777:8888:", "1111:2222:3333::7777:8888:", "1111:2222::7777:8888:", "1111::7777:8888:", "::7777:8888:", "1111:2222:3333:4444::6666:7777:8888:", "1111:2222:3333::6666:7777:8888:", "1111:2222::6666:7777:8888:", "1111::6666:7777:8888:", "::6666:7777:8888:", "1111:2222:3333::5555:6666:7777:8888:", "1111:2222::5555:6666:7777:8888:", "1111::5555:6666:7777:8888:", "::5555:6666:7777:8888:", "1111:2222::4444:5555:6666:7777:8888:", "1111::4444:5555:6666:7777:8888:", "::4444:5555:6666:7777:8888:", "1111::3333:4444:5555:6666:7777:8888:", "::3333:4444:5555:6666:7777:8888:", "::2222:3333:4444:5555:6666:7777:8888:", ].each do |ip| it "should reject #{ip.inspect} as an IPv6 address" do expect { @class.new(:name => "foo", :ip => ip) }.to raise_error end end it "should not accept spaces in resourcename" do proc { @class.new(:name => "foo bar") }.should raise_error end it "should not accept host_aliases with spaces" do proc { @class.new(:name => "foo", :host_aliases => [ 'well_formed', 'not wellformed' ]) }.should raise_error end it "should not accept empty host_aliases" do proc { @class.new(:name => "foo", :host_aliases => ['alias1','']) }.should raise_error end end describe "when syncing" do it "should send the first value to the provider for ip property" do @ip = @class.attrclass(:ip).new(:resource => @resource, :should => %w{192.168.0.1 192.168.0.2}) - @provider.expects(:ip=).with '192.168.0.1' + @ip.sync + + @provider.ip.should == '192.168.0.1' end it "should send the first value to the provider for comment property" do @comment = @class.attrclass(:comment).new(:resource => @resource, :should => %w{Bazinga Notme}) - @provider.expects(:comment=).with 'Bazinga' + @comment.sync + + @provider.comment.should == 'Bazinga' end it "should send the joined array to the provider for host_alias" do @host_aliases = @class.attrclass(:host_aliases).new(:resource => @resource, :should => %w{foo bar}) - @provider.expects(:host_aliases=).with 'foo bar' + @host_aliases.sync + + @provider.host_aliases.should == 'foo bar' end it "should also use the specified delimiter for joining" do @host_aliases = @class.attrclass(:host_aliases).new(:resource => @resource, :should => %w{foo bar}) @host_aliases.stubs(:delimiter).returns "\t" - @provider.expects(:host_aliases=).with "foo\tbar" + @host_aliases.sync + + @provider.host_aliases.should == "foo\tbar" end it "should care about the order of host_aliases" do @host_aliases = @class.attrclass(:host_aliases).new(:resource => @resource, :should => %w{foo bar}) @host_aliases.insync?(%w{foo bar}).should == true @host_aliases.insync?(%w{bar foo}).should == false end it "should not consider aliases to be in sync if should is a subset of current" do @host_aliases = @class.attrclass(:host_aliases).new(:resource => @resource, :should => %w{foo bar}) @host_aliases.insync?(%w{foo bar anotherone}).should == false end end end diff --git a/spec/unit/type/mount_spec.rb b/spec/unit/type/mount_spec.rb index 82eb563e9..d06ccc90d 100755 --- a/spec/unit/type/mount_spec.rb +++ b/spec/unit/type/mount_spec.rb @@ -1,329 +1,337 @@ #!/usr/bin/env rspec require 'spec_helper' describe Puppet::Type.type(:mount), :unless => Puppet.features.microsoft_windows? do it "should have a :refreshable feature that requires the :remount method" do Puppet::Type.type(:mount).provider_feature(:refreshable).methods.should == [:remount] end it "should have no default value for :ensure" do mount = Puppet::Type.type(:mount).new(:name => "yay") mount.should(:ensure).should be_nil end it "should have :name as the only keyattribut" do Puppet::Type.type(:mount).key_attributes.should == [:name] end end describe Puppet::Type.type(:mount), "when validating attributes" do [:name, :remounts, :provider].each do |param| it "should have a #{param} parameter" do Puppet::Type.type(:mount).attrtype(param).should == :param end end [:ensure, :device, :blockdevice, :fstype, :options, :pass, :dump, :atboot, :target].each do |param| it "should have a #{param} property" do Puppet::Type.type(:mount).attrtype(param).should == :property end end end describe Puppet::Type.type(:mount)::Ensure, "when validating values", :unless => Puppet.features.microsoft_windows? do before do @provider = stub 'provider', :class => Puppet::Type.type(:mount).defaultprovider, :clear => nil Puppet::Type.type(:mount).defaultprovider.expects(:new).returns(@provider) end it "should alias :present to :defined as a value to :ensure" do mount = Puppet::Type.type(:mount).new(:name => "yay", :ensure => :present) mount.should(:ensure).should == :defined end it "should support :present as a value to :ensure" do Puppet::Type.type(:mount).new(:name => "yay", :ensure => :present) end it "should support :defined as a value to :ensure" do Puppet::Type.type(:mount).new(:name => "yay", :ensure => :defined) end it "should support :unmounted as a value to :ensure" do Puppet::Type.type(:mount).new(:name => "yay", :ensure => :unmounted) end it "should support :absent as a value to :ensure" do Puppet::Type.type(:mount).new(:name => "yay", :ensure => :absent) end it "should support :mounted as a value to :ensure" do Puppet::Type.type(:mount).new(:name => "yay", :ensure => :mounted) end end describe Puppet::Type.type(:mount)::Ensure, :unless => Puppet.features.microsoft_windows? do before :each do provider_properties = {} @provider = stub 'provider', :class => Puppet::Type.type(:mount).defaultprovider, :clear => nil, :satisfies? => true, :name => :mock, :property_hash => provider_properties Puppet::Type.type(:mount).defaultprovider.stubs(:new).returns(@provider) @mount = Puppet::Type.type(:mount).new(:name => "yay", :check => :ensure) @ensure = @mount.property(:ensure) end def mount_stub(params) Puppet::Type.type(:mount).validproperties.each do |prop| unless params[prop] params[prop] = :absent @mount[prop] = :absent end end params.each do |param, value| @provider.stubs(param).returns(value) end end describe Puppet::Type.type(:mount)::Ensure, "when changing the host" do def test_ensure_change(options) @provider.stubs(:get).with(:ensure).returns options[:from] @provider.stubs(:ensure).returns options[:from] @provider.stubs(:mounted?).returns([:mounted,:ghost].include? options[:from]) @provider.expects(:create).times(options[:create] || 0) @provider.expects(:destroy).times(options[:destroy] || 0) @provider.expects(:mount).never @provider.expects(:unmount).times(options[:unmount] || 0) @ensure.stubs(:syncothers) @ensure.should = options[:to] @ensure.sync (!!@provider.property_hash[:needs_mount]).should == (!!options[:mount]) end it "should create itself when changing from :ghost to :present" do test_ensure_change(:from => :ghost, :to => :present, :create => 1) end it "should create itself when changing from :absent to :present" do test_ensure_change(:from => :absent, :to => :present, :create => 1) end it "should create itself and unmount when changing from :ghost to :unmounted" do test_ensure_change(:from => :ghost, :to => :unmounted, :create => 1, :unmount => 1) end it "should unmount resource when changing from :mounted to :unmounted" do test_ensure_change(:from => :mounted, :to => :unmounted, :unmount => 1) end it "should create itself when changing from :absent to :unmounted" do test_ensure_change(:from => :absent, :to => :unmounted, :create => 1) end it "should unmount resource when changing from :ghost to :absent" do test_ensure_change(:from => :ghost, :to => :absent, :unmount => 1) end it "should unmount and destroy itself when changing from :mounted to :absent" do test_ensure_change(:from => :mounted, :to => :absent, :destroy => 1, :unmount => 1) end it "should destroy itself when changing from :unmounted to :absent" do test_ensure_change(:from => :unmounted, :to => :absent, :destroy => 1) end it "should create itself when changing from :ghost to :mounted" do test_ensure_change(:from => :ghost, :to => :mounted, :create => 1) end it "should create itself and mount when changing from :absent to :mounted" do test_ensure_change(:from => :absent, :to => :mounted, :create => 1, :mount => 1) end it "should mount resource when changing from :unmounted to :mounted" do test_ensure_change(:from => :unmounted, :to => :mounted, :mount => 1) end it "should be in sync if it is :absent and should be :absent" do @ensure.should = :absent @ensure.safe_insync?(:absent).should == true end it "should be out of sync if it is :absent and should be :defined" do @ensure.should = :defined @ensure.safe_insync?(:absent).should == false end it "should be out of sync if it is :absent and should be :mounted" do @ensure.should = :mounted @ensure.safe_insync?(:absent).should == false end it "should be out of sync if it is :absent and should be :unmounted" do @ensure.should = :unmounted @ensure.safe_insync?(:absent).should == false end it "should be out of sync if it is :mounted and should be :absent" do @ensure.should = :absent @ensure.safe_insync?(:mounted).should == false end it "should be in sync if it is :mounted and should be :defined" do @ensure.should = :defined @ensure.safe_insync?(:mounted).should == true end it "should be in sync if it is :mounted and should be :mounted" do @ensure.should = :mounted @ensure.safe_insync?(:mounted).should == true end it "should be out in sync if it is :mounted and should be :unmounted" do @ensure.should = :unmounted @ensure.safe_insync?(:mounted).should == false end it "should be out of sync if it is :unmounted and should be :absent" do @ensure.should = :absent @ensure.safe_insync?(:unmounted).should == false end it "should be in sync if it is :unmounted and should be :defined" do @ensure.should = :defined @ensure.safe_insync?(:unmounted).should == true end it "should be out of sync if it is :unmounted and should be :mounted" do @ensure.should = :mounted @ensure.safe_insync?(:unmounted).should == false end it "should be in sync if it is :unmounted and should be :unmounted" do @ensure.should = :unmounted @ensure.safe_insync?(:unmounted).should == true end it "should be out of sync if it is :ghost and should be :absent" do @ensure.should = :absent @ensure.safe_insync?(:ghost).should == false end it "should be out of sync if it is :ghost and should be :defined" do @ensure.should = :defined @ensure.safe_insync?(:ghost).should == false end it "should be out of sync if it is :ghost and should be :mounted" do @ensure.should = :mounted @ensure.safe_insync?(:ghost).should == false end it "should be out of sync if it is :ghost and should be :unmounted" do @ensure.should = :unmounted @ensure.safe_insync?(:ghost).should == false end end describe Puppet::Type.type(:mount), "when responding to refresh" do pending "2.6.x specifies slightly different behavior and the desired behavior needs to be clarified and revisited. See ticket #4904" do it "should remount if it is supposed to be mounted" do @mount[:ensure] = "mounted" @provider.expects(:remount) @mount.refresh end it "should not remount if it is supposed to be present" do @mount[:ensure] = "present" @provider.expects(:remount).never @mount.refresh end it "should not remount if it is supposed to be absent" do @mount[:ensure] = "absent" @provider.expects(:remount).never @mount.refresh end it "should not remount if it is supposed to be defined" do @mount[:ensure] = "defined" @provider.expects(:remount).never @mount.refresh end it "should not remount if it is supposed to be unmounted" do @mount[:ensure] = "unmounted" @provider.expects(:remount).never @mount.refresh end it "should not remount swap filesystems" do @mount[:ensure] = "mounted" @mount[:fstype] = "swap" @provider.expects(:remount).never @mount.refresh end end end end describe Puppet::Type.type(:mount), "when modifying an existing mount entry", :unless => Puppet.features.microsoft_windows? do before do @provider = stub 'provider', :class => Puppet::Type.type(:mount).defaultprovider, :clear => nil, :satisfies? => true, :name => :mock, :remount => nil Puppet::Type.type(:mount).defaultprovider.stubs(:new).returns(@provider) + @mount = Puppet::Type.type(:mount).new(:name => "yay", :ensure => :mounted) {:device => "/foo/bar", :blockdevice => "/other/bar", :target => "/what/ever", :fstype => 'eh', :options => "", :pass => 0, :dump => 0, :atboot => 0, :ensure => :mounted}.each do |param, value| @mount.provider.stubs(param).returns value @mount[param] = value end @mount.provider.stubs(:mounted?).returns true # stub this to not try to create state.yaml Puppet::Util::Storage.stubs(:store) @catalog = Puppet::Resource::Catalog.new @catalog.add_resource @mount end it "should use the provider to change the dump value" do @mount.provider.expects(:dump).returns 0 @mount.provider.expects(:dump=).with(1) + @mount.provider.stubs(:respond_to?).returns(false) + @mount.provider.stubs(:respond_to?).with("dump=").returns(true) @mount[:dump] = 1 @catalog.apply end it "should umount before flushing changes to disk" do syncorder = sequence('syncorder') @mount.provider.expects(:options).returns 'soft' @mount.provider.expects(:ensure).returns :mounted + @mount.provider.stubs(:respond_to?).returns(false) + @mount.provider.stubs(:respond_to?).with("options=").returns(true) + @mount.provider.expects(:unmount).in_sequence(syncorder) @mount.provider.expects(:options=).in_sequence(syncorder).with 'hard' @mount.expects(:flush).in_sequence(syncorder) # Call inside syncothers @mount.expects(:flush).in_sequence(syncorder) # I guess transaction or anything calls flush again + @mount.provider.stubs(:respond_to?).with(:options=).returns(true) + @mount[:ensure] = :unmounted @mount[:options] = 'hard' @catalog.apply end end