diff --git a/spec/lib/matchers/json.rb b/spec/lib/matchers/json.rb new file mode 100644 index 000000000..798e4cd21 --- /dev/null +++ b/spec/lib/matchers/json.rb @@ -0,0 +1,111 @@ +RSpec::Matchers.define :set_json_attribute do |*attributes| + def format + @format ||= Puppet::Network::FormatHandler.format('pson') + end + + chain :to do |value| + @value = value + end + + def json(instance) + PSON.parse(instance.to_pson) + end + + def attr_value(attrs, instance) + attrs = attrs.dup + hash = json(instance)['data'] + while attrs.length > 0 + name = attrs.shift + hash = hash[name] + end + hash + end + + match do |instance| + result = attr_value(attributes, instance) + if @value + result == @value + else + ! result.nil? + end + end + + failure_message_for_should do |instance| + if @value + "expected #{instance.inspect} to set #{attributes.inspect} to #{@value.inspect}; got #{attr_value(attributes, instance).inspect}" + else + "expected #{instance.inspect} to set #{attributes.inspect} but was nil" + end + end + + failure_message_for_should_not do |instance| + if @value + "expected #{instance.inspect} not to set #{attributes.inspect} to #{@value.inspect}" + else + "expected #{instance.inspect} not to set #{attributes.inspect} to nil" + end + end +end + +RSpec::Matchers.define :set_json_document_type_to do |type| + def format + @format ||= Puppet::Network::FormatHandler.format('pson') + end + + match do |instance| + json(instance)['document_type'] == type + end + + def json(instance) + PSON.parse(instance.to_pson) + end + + failure_message_for_should do |instance| + "expected #{instance.inspect} to set document_type to #{type.inspect}; got #{json(instance)['document_type'].inspect}" + end + + failure_message_for_should_not do |instance| + "expected #{instance.inspect} not to set document_type to #{type.inspect}" + end +end + +RSpec::Matchers.define :read_json_attribute do |attribute| + def format + @format ||= Puppet::Network::FormatHandler.format('pson') + end + + chain :from do |value| + @json = value + end + + chain :as do |as| + @value = as + end + + match do |klass| + raise "Must specify json with 'from'" unless @json + + @instance = format.intern(klass, @json) + if @value + @instance.send(attribute) == @value + else + ! @instance.send(attribute).nil? + end + end + + failure_message_for_should do |klass| + if @value + "expected #{klass} to read #{attribute} from #{@json} as #{@value.inspect}; got #{@instance.send(attribute).inspect}" + else + "expected #{klass} to read #{attribute} from #{@json} but was nil" + end + end + + failure_message_for_should_not do |klass| + if @value + "expected #{klass} not to set #{attribute} to #{@value}" + else + "expected #{klass} not to set #{attribute} to nil" + end + end +end diff --git a/spec/unit/indirector/request_spec.rb b/spec/unit/indirector/request_spec.rb index 4dabb3147..ba7dc815e 100755 --- a/spec/unit/indirector/request_spec.rb +++ b/spec/unit/indirector/request_spec.rb @@ -1,402 +1,399 @@ #!/usr/bin/env rspec require 'spec_helper' +require 'matchers/json' require 'puppet/indirector/request' describe Puppet::Indirector::Request do describe "when initializing" do it "should require an indirection name, a key, and a method" do lambda { Puppet::Indirector::Request.new }.should raise_error(ArgumentError) end it "should always convert the indirection name to a symbol" do Puppet::Indirector::Request.new("ind", :method, "mykey").indirection_name.should == :ind end it "should use provided value as the key if it is a string" do Puppet::Indirector::Request.new(:ind, :method, "mykey").key.should == "mykey" end it "should use provided value as the key if it is a symbol" do Puppet::Indirector::Request.new(:ind, :method, :mykey).key.should == :mykey end it "should use the name of the provided instance as its key if an instance is provided as the key instead of a string" do instance = mock 'instance', :name => "mykey" request = Puppet::Indirector::Request.new(:ind, :method, instance) request.key.should == "mykey" request.instance.should equal(instance) end it "should support options specified as a hash" do lambda { Puppet::Indirector::Request.new(:ind, :method, :key, :one => :two) }.should_not raise_error(ArgumentError) end it "should support nil options" do lambda { Puppet::Indirector::Request.new(:ind, :method, :key, nil) }.should_not raise_error(ArgumentError) end it "should support unspecified options" do lambda { Puppet::Indirector::Request.new(:ind, :method, :key) }.should_not raise_error(ArgumentError) end it "should use an empty options hash if nil was provided" do Puppet::Indirector::Request.new(:ind, :method, :key, nil).options.should == {} end it "should default to a nil node" do Puppet::Indirector::Request.new(:ind, :method, :key, nil).node.should be_nil end it "should set its node attribute if provided in the options" do Puppet::Indirector::Request.new(:ind, :method, :key, :node => "foo.com").node.should == "foo.com" end it "should default to a nil ip" do Puppet::Indirector::Request.new(:ind, :method, :key, nil).ip.should be_nil end it "should set its ip attribute if provided in the options" do Puppet::Indirector::Request.new(:ind, :method, :key, :ip => "192.168.0.1").ip.should == "192.168.0.1" end it "should default to being unauthenticated" do Puppet::Indirector::Request.new(:ind, :method, :key, nil).should_not be_authenticated end it "should set be marked authenticated if configured in the options" do Puppet::Indirector::Request.new(:ind, :method, :key, :authenticated => "eh").should be_authenticated end it "should keep its options as a hash even if a node is specified" do Puppet::Indirector::Request.new(:ind, :method, :key, :node => "eh").options.should be_instance_of(Hash) end it "should keep its options as a hash even if another option is specified" do Puppet::Indirector::Request.new(:ind, :method, :key, :foo => "bar").options.should be_instance_of(Hash) end it "should treat options other than :ip, :node, and :authenticated as options rather than attributes" do Puppet::Indirector::Request.new(:ind, :method, :key, :server => "bar").options[:server].should == "bar" end it "should normalize options to use symbols as keys" do Puppet::Indirector::Request.new(:ind, :method, :key, "foo" => "bar").options[:foo].should == "bar" end describe "and the request key is a URI" do describe "and the URI is a 'file' URI" do before do @request = Puppet::Indirector::Request.new(:ind, :method, "file:///my/file with spaces") end it "should set the request key to the unescaped full file path" do @request.key.should == "/my/file with spaces" end it "should not set the protocol" do @request.protocol.should be_nil end it "should not set the port" do @request.port.should be_nil end it "should not set the server" do @request.server.should be_nil end end it "should set the protocol to the URI scheme" do Puppet::Indirector::Request.new(:ind, :method, "http://host/stuff").protocol.should == "http" end it "should set the server if a server is provided" do Puppet::Indirector::Request.new(:ind, :method, "http://host/stuff").server.should == "host" end it "should set the server and port if both are provided" do Puppet::Indirector::Request.new(:ind, :method, "http://host:543/stuff").port.should == 543 end it "should default to the masterport if the URI scheme is 'puppet'" do Puppet.settings.expects(:value).with(:masterport).returns "321" Puppet::Indirector::Request.new(:ind, :method, "puppet://host/stuff").port.should == 321 end it "should use the provided port if the URI scheme is not 'puppet'" do Puppet::Indirector::Request.new(:ind, :method, "http://host/stuff").port.should == 80 end it "should set the request key to the unescaped key part path from the URI" do Puppet::Indirector::Request.new(:ind, :method, "http://host/environment/terminus/stuff with spaces").key.should == "stuff with spaces" end it "should set the :uri attribute to the full URI" do Puppet::Indirector::Request.new(:ind, :method, "http:///stuff").uri.should == "http:///stuff" end end it "should allow indication that it should not read a cached instance" do Puppet::Indirector::Request.new(:ind, :method, :key, :ignore_cache => true).should be_ignore_cache end it "should default to not ignoring the cache" do Puppet::Indirector::Request.new(:ind, :method, :key).should_not be_ignore_cache end it "should allow indication that it should not not read an instance from the terminus" do Puppet::Indirector::Request.new(:ind, :method, :key, :ignore_terminus => true).should be_ignore_terminus end it "should default to not ignoring the terminus" do Puppet::Indirector::Request.new(:ind, :method, :key).should_not be_ignore_terminus end end it "should look use the Indirection class to return the appropriate indirection" do ind = mock 'indirection' Puppet::Indirector::Indirection.expects(:instance).with(:myind).returns ind request = Puppet::Indirector::Request.new(:myind, :method, :key) request.indirection.should equal(ind) end it "should use its indirection to look up the appropriate model" do ind = mock 'indirection' Puppet::Indirector::Indirection.expects(:instance).with(:myind).returns ind request = Puppet::Indirector::Request.new(:myind, :method, :key) ind.expects(:model).returns "mymodel" request.model.should == "mymodel" end it "should fail intelligently when asked to find a model but the indirection cannot be found" do Puppet::Indirector::Indirection.expects(:instance).with(:myind).returns nil request = Puppet::Indirector::Request.new(:myind, :method, :key) lambda { request.model }.should raise_error(ArgumentError) end it "should have a method for determining if the request is plural or singular" do Puppet::Indirector::Request.new(:myind, :method, :key).should respond_to(:plural?) end it "should be considered plural if the method is 'search'" do Puppet::Indirector::Request.new(:myind, :search, :key).should be_plural end it "should not be considered plural if the method is not 'search'" do Puppet::Indirector::Request.new(:myind, :find, :key).should_not be_plural end it "should use its uri, if it has one, as its string representation" do Puppet::Indirector::Request.new(:myind, :find, "foo://bar/baz").to_s.should == "foo://bar/baz" end it "should use its indirection name and key, if it has no uri, as its string representation" do Puppet::Indirector::Request.new(:myind, :find, "key") == "/myind/key" end it "should be able to return the URI-escaped key" do Puppet::Indirector::Request.new(:myind, :find, "my key").escaped_key.should == URI.escape("my key") end it "should have an environment accessor" do Puppet::Indirector::Request.new(:myind, :find, "my key", :environment => "foo").should respond_to(:environment) end it "should set its environment to an environment instance when a string is specified as its environment" do Puppet::Indirector::Request.new(:myind, :find, "my key", :environment => "foo").environment.should == Puppet::Node::Environment.new("foo") end it "should use any passed in environment instances as its environment" do env = Puppet::Node::Environment.new("foo") Puppet::Indirector::Request.new(:myind, :find, "my key", :environment => env).environment.should equal(env) end it "should use the default environment when none is provided" do Puppet::Indirector::Request.new(:myind, :find, "my key" ).environment.should equal(Puppet::Node::Environment.new) end it "should support converting its options to a hash" do Puppet::Indirector::Request.new(:myind, :find, "my key" ).should respond_to(:to_hash) end it "should include all of its attributes when its options are converted to a hash" do Puppet::Indirector::Request.new(:myind, :find, "my key", :node => 'foo').to_hash[:node].should == 'foo' end describe "when building a query string from its options" do before do @request = Puppet::Indirector::Request.new(:myind, :find, "my key") end it "should return an empty query string if there are no options" do @request.stubs(:options).returns nil @request.query_string.should == "" end it "should return an empty query string if the options are empty" do @request.stubs(:options).returns({}) @request.query_string.should == "" end it "should prefix the query string with '?'" do @request.stubs(:options).returns(:one => "two") @request.query_string.should =~ /^\?/ end it "should include all options in the query string, separated by '&'" do @request.stubs(:options).returns(:one => "two", :three => "four") @request.query_string.sub(/^\?/, '').split("&").sort.should == %w{one=two three=four}.sort end it "should ignore nil options" do @request.stubs(:options).returns(:one => "two", :three => nil) @request.query_string.should_not be_include("three") end it "should convert 'true' option values into strings" do @request.stubs(:options).returns(:one => true) @request.query_string.should == "?one=true" end it "should convert 'false' option values into strings" do @request.stubs(:options).returns(:one => false) @request.query_string.should == "?one=false" end it "should convert to a string all option values that are integers" do @request.stubs(:options).returns(:one => 50) @request.query_string.should == "?one=50" end it "should convert to a string all option values that are floating point numbers" do @request.stubs(:options).returns(:one => 1.2) @request.query_string.should == "?one=1.2" end it "should CGI-escape all option values that are strings" do escaping = CGI.escape("one two") @request.stubs(:options).returns(:one => "one two") @request.query_string.should == "?one=#{escaping}" end it "should YAML-dump and CGI-escape arrays" do escaping = CGI.escape(YAML.dump(%w{one two})) @request.stubs(:options).returns(:one => %w{one two}) @request.query_string.should == "?one=#{escaping}" end it "should convert to a string and CGI-escape all option values that are symbols" do escaping = CGI.escape("sym bol") @request.stubs(:options).returns(:one => :"sym bol") @request.query_string.should == "?one=#{escaping}" end it "should fail if options other than booleans or strings are provided" do @request.stubs(:options).returns(:one => {:one => :two}) lambda { @request.query_string }.should raise_error(ArgumentError) end end describe "when converting to json" do before do @request = Puppet::Indirector::Request.new(:facts, :find, "foo") end it "should produce a hash with the document_type set to 'request'" do - PSON.parse(@request.to_pson)["document_type"].should == "Puppet::Indirector::Request" - end - - it "should add its data under the 'data' attribute in the hash" do - PSON.parse(@request.to_pson)["data"].should be_instance_of(Hash) + @request.should set_json_document_type_to("Puppet::Indirector::Request") end it "should set the 'key'" do - PSON.parse(@request.to_pson)["data"]['key'].should == "foo" + @request.should set_json_attribute("key").to("foo") end it "should include an attribute for its indirection name" do - PSON.parse(@request.to_pson)["data"]['type'].should == "facts" + @request.should set_json_attribute("type").to("facts") end it "should include a 'method' attribute set to its method" do - PSON.parse(@request.to_pson)["data"]['method'].should == "find" + @request.should set_json_attribute("method").to("find") end it "should add all attributes under the 'attributes' attribute" do @request.ip = "127.0.0.1" - PSON.parse(@request.to_pson)["data"]['attributes']['ip'].should == "127.0.0.1" + @request.should set_json_attribute("attributes", "ip").to("127.0.0.1") end it "should add all options under the 'attributes' attribute" do @request.options["opt"] = "value" PSON.parse(@request.to_pson)["data"]['attributes']['opt'].should == "value" end it "should include the instance if provided" do facts = Puppet::Node::Facts.new("foo") @request.instance = facts PSON.parse(@request.to_pson)["data"]['instance'].should be_instance_of(Puppet::Node::Facts) end end describe "when converting from json" do before do @request = Puppet::Indirector::Request.new(:facts, :find, "foo") @klass = Puppet::Indirector::Request @format = Puppet::Network::FormatHandler.format('pson') end def from_json(json) @format.intern(Puppet::Indirector::Request, json) end it "should set the 'key'" do from_json(@request.to_pson).key.should == "foo" end it "should fail if no key is provided" do json = PSON.parse(@request.to_pson) json['data'].delete("key") lambda { from_json(json.to_pson) }.should raise_error(ArgumentError) end it "should set its indirector name" do from_json(@request.to_pson).indirection_name.should == :facts end it "should fail if no type is provided" do json = PSON.parse(@request.to_pson) json['data'].delete("type") lambda { from_json(json.to_pson) }.should raise_error(ArgumentError) end it "should set its method" do from_json(@request.to_pson).method.should == "find" end it "should fail if no method is provided" do json = PSON.parse(@request.to_pson) json['data'].delete("method") lambda { from_json(json.to_pson) }.should raise_error(ArgumentError) end it "should initialize with all attributes and options" do @request.ip = "127.0.0.1" @request.options["opt"] = "value" result = from_json(@request.to_pson) result.options[:opt].should == "value" result.ip.should == "127.0.0.1" end it "should set its instance as an instance if one is provided" do facts = Puppet::Node::Facts.new("foo") @request.instance = facts result = from_json(@request.to_pson) result.instance.should be_instance_of(Puppet::Node::Facts) end end end diff --git a/spec/unit/node/facts_spec.rb b/spec/unit/node/facts_spec.rb index 3c7c9d08b..0a5948cfa 100755 --- a/spec/unit/node/facts_spec.rb +++ b/spec/unit/node/facts_spec.rb @@ -1,148 +1,151 @@ #!/usr/bin/env rspec require 'spec_helper' - +require 'matchers/json' require 'puppet/node/facts' describe Puppet::Node::Facts, "when indirecting" do before do @facts = Puppet::Node::Facts.new("me") end it "should be able to convert all fact values to strings" do @facts.values["one"] = 1 @facts.stringify @facts.values["one"].should == "1" end it "should add the node's certificate name as the 'clientcert' fact when adding local facts" do @facts.add_local_facts @facts.values["clientcert"].should == Puppet.settings[:certname] end it "should add the Puppet version as a 'clientversion' fact when adding local facts" do @facts.add_local_facts @facts.values["clientversion"].should == Puppet.version.to_s end it "should add the current environment as a fact if one is not set when adding local facts" do @facts.add_local_facts @facts.values["environment"].should == Puppet[:environment] end it "should not replace any existing environment fact when adding local facts" do @facts.values["environment"] = "foo" @facts.add_local_facts @facts.values["environment"].should == "foo" end it "should be able to downcase fact values" do Puppet.settings.stubs(:value).returns "eh" Puppet.settings.expects(:value).with(:downcasefacts).returns true @facts.values["one"] = "Two" @facts.downcase_if_necessary @facts.values["one"].should == "two" end it "should only try to downcase strings" do Puppet.settings.stubs(:value).returns "eh" Puppet.settings.expects(:value).with(:downcasefacts).returns true @facts.values["now"] = Time.now @facts.downcase_if_necessary @facts.values["now"].should be_instance_of(Time) end it "should not downcase facts if not configured to do so" do Puppet.settings.stubs(:value).returns "eh" Puppet.settings.expects(:value).with(:downcasefacts).returns false @facts.values["one"] = "Two" @facts.downcase_if_necessary @facts.values["one"].should == "Two" end describe "when indirecting" do before do @indirection = stub 'indirection', :request => mock('request'), :name => :facts # We have to clear the cache so that the facts ask for our indirection stub, # instead of anything that might be cached. Puppet::Util::Cacher.expire @facts = Puppet::Node::Facts.new("me", "one" => "two") end it "should redirect to the specified fact store for storage" do Puppet::Node::Facts.stubs(:indirection).returns(@indirection) @indirection.expects(:save) Puppet::Node::Facts.indirection.save(@facts) end describe "when the Puppet application is 'master'" do it "should default to the 'yaml' terminus" do pending "Cannot test the behavior of defaults in defaults.rb" # Puppet::Node::Facts.indirection.terminus_class.should == :yaml end end describe "when the Puppet application is not 'master'" do it "should default to the 'facter' terminus" do pending "Cannot test the behavior of defaults in defaults.rb" # Puppet::Node::Facts.indirection.terminus_class.should == :facter end end end describe "when storing and retrieving" do it "should add metadata to the facts" do facts = Puppet::Node::Facts.new("me", "one" => "two", "three" => "four") facts.values[:_timestamp].should be_instance_of(Time) end describe "using pson" do before :each do @timestamp = Time.parse("Thu Oct 28 11:16:31 -0700 2010") @expiration = Time.parse("Thu Oct 28 11:21:31 -0700 2010") end it "should accept properly formatted pson" do facts = Puppet::Node::Facts.new("foo") facts.values = {"a" => "1", "b" => "2", "c" => "3"} facts.expiration = Time.now #pson = %Q({"document_type": "Puppet::Node::Facts", "data: {"name": "foo", "expiration": "#{@expiration}", "timestamp": "#{@timestamp}", "values": {"a": "1", "b": "2", "c": "3"}}}) pson = %Q({"data": {"name":"foo", "expiration":"#{@expiration}", "timestamp": "#{@timestamp}", "values":{"a":"1","b":"2","c":"3"}}, "document_type":"Puppet::Node::Facts"}) format = Puppet::Network::FormatHandler.format('pson') facts = format.intern(Puppet::Node::Facts,pson) facts.name.should == 'foo' facts.expiration.should == @expiration facts.values.should == {'a' => '1', 'b' => '2', 'c' => '3', :_timestamp => @timestamp} end it "should generate properly formatted pson" do Time.stubs(:now).returns(@timestamp) facts = Puppet::Node::Facts.new("foo", {'a' => 1, 'b' => 2, 'c' => 3}) facts.expiration = @expiration - pson = PSON.parse(facts.to_pson) - pson.should == {"name"=>"foo", "timestamp"=>@timestamp.to_s, "expiration"=>@expiration.to_s, "values"=>{"a"=>1, "b"=>2, "c"=>3}} + facts.to_pson.should == %Q[{"data":{"name":"foo","timestamp":"Thu Oct 28 11:16:31 -0700 2010","expiration":"Thu Oct 28 11:21:31 -0700 2010","values":{"a":1,"b":2,"c":3}},"document_type":"Puppet::Node::Facts"}] end it "should not include nil values" do facts = Puppet::Node::Facts.new("foo", {'a' => 1, 'b' => 2, 'c' => 3}) - pson = PSON.parse(facts.to_pson) - pson.should_not be_include("expiration") + + # XXX:LAK For some reason this is resurrection the full instance, instead + # of just returning the hash. This code works, but I can't figure out what's + # going on. + newfacts = PSON.parse(facts.to_pson) + newfacts.expiration.should be_nil end it "should be able to handle nil values" do pson = %Q({"name": "foo", "values": {"a": "1", "b": "2", "c": "3"}}) format = Puppet::Network::FormatHandler.format('pson') facts = format.intern(Puppet::Node::Facts,pson) facts.name.should == 'foo' facts.expiration.should be_nil end end end end diff --git a/spec/unit/node_spec.rb b/spec/unit/node_spec.rb index af3110f45..e8f826dca 100755 --- a/spec/unit/node_spec.rb +++ b/spec/unit/node_spec.rb @@ -1,265 +1,266 @@ #!/usr/bin/env rspec require 'spec_helper' +require 'matchers/json' describe Puppet::Node do describe "when managing its environment" do it "should use any set environment" do Puppet::Node.new("foo", :environment => "bar").environment.name.should == :bar end it "should support providing an actual environment instance" do Puppet::Node.new("foo", :environment => Puppet::Node::Environment.new(:bar)).environment.name.should == :bar end it "should determine its environment from its parameters if no environment is set" do Puppet::Node.new("foo", :parameters => {"environment" => :bar}).environment.name.should == :bar end it "should use the default environment if no environment is provided" do Puppet::Node.new("foo").environment.name.should == Puppet::Node::Environment.new.name end it "should always return an environment instance rather than a string" do Puppet::Node.new("foo").environment.should be_instance_of(Puppet::Node::Environment) end it "should allow the environment to be set after initialization" do node = Puppet::Node.new("foo") node.environment = :bar node.environment.name.should == :bar end it "should allow its environment to be set by parameters after initialization" do node = Puppet::Node.new("foo") node.parameters["environment"] = :bar node.environment.name.should == :bar end end describe "when converting to json" do before do @node = Puppet::Node.new("mynode") end it "should provide its name" do - PSON.parse(@node.to_pson)['data']['name'].should == "mynode" + @node.should set_json_attribute('name').to("mynode") end it "should include the classes if set" do @node.classes = %w{a b c} - PSON.parse(@node.to_pson)['data']['classes'].should == %w{a b c} + @node.should set_json_attribute("classes").to(%w{a b c}) end it "should not include the classes if there are none" do - PSON.parse(@node.to_pson)['data'].should_not be_include('classes') + @node.should_not set_json_attribute('classes') end it "should include parameters if set" do @node.parameters = {"a" => "b", "c" => "d"} - PSON.parse(@node.to_pson)['data']['parameters'].should == {"a" => "b", "c" => "d"} + @node.should set_json_attribute('parameters').to({"a" => "b", "c" => "d"}) end it "should not include the parameters if there are none" do - PSON.parse(@node.to_pson)['data'].should_not be_include('parameters') + @node.should_not set_json_attribute('parameters') end it "should include the environment" do @node.environment = "production" - PSON.parse(@node.to_pson)['data']['environment'].should == "production" + @node.should set_json_attribute('environment').to('production') end end describe "when converting from json" do before do @node = Puppet::Node.new("mynode") @format = Puppet::Network::FormatHandler.format('pson') end def from_json(json) @format.intern(Puppet::Node, json) end it "should set its name" do - from_json(@node.to_pson).name.should == "mynode" + Puppet::Node.should read_json_attribute('name').from(@node.to_pson).as("mynode") end it "should include the classes if set" do @node.classes = %w{a b c} - from_json(@node.to_pson).classes.should == %w{a b c} + Puppet::Node.should read_json_attribute('classes').from(@node.to_pson).as(%w{a b c}) end it "should include parameters if set" do @node.parameters = {"a" => "b", "c" => "d"} - from_json(@node.to_pson).parameters.should == {"a" => "b", "c" => "d"} + Puppet::Node.should read_json_attribute('parameters').from(@node.to_pson).as({"a" => "b", "c" => "d"}) end it "should include the environment" do @node.environment = "production" - from_json(@node.to_pson).environment.name.should == :production + Puppet::Node.should read_json_attribute('environment').from(@node.to_pson).as(Puppet::Node::Environment.new(:production)) end end end describe Puppet::Node, "when initializing" do before do @node = Puppet::Node.new("testnode") end it "should set the node name" do @node.name.should == "testnode" end it "should not allow nil node names" do proc { Puppet::Node.new(nil) }.should raise_error(ArgumentError) end it "should default to an empty parameter hash" do @node.parameters.should == {} end it "should default to an empty class array" do @node.classes.should == [] end it "should note its creation time" do @node.time.should be_instance_of(Time) end it "should accept parameters passed in during initialization" do params = {"a" => "b"} @node = Puppet::Node.new("testing", :parameters => params) @node.parameters.should == params end it "should accept classes passed in during initialization" do classes = %w{one two} @node = Puppet::Node.new("testing", :classes => classes) @node.classes.should == classes end it "should always return classes as an array" do @node = Puppet::Node.new("testing", :classes => "myclass") @node.classes.should == ["myclass"] end end describe Puppet::Node, "when merging facts" do before do @node = Puppet::Node.new("testnode") Puppet::Node::Facts.indirection.stubs(:find).with(@node.name).returns(Puppet::Node::Facts.new(@node.name, "one" => "c", "two" => "b")) end it "should fail intelligently if it cannot find facts" do Puppet::Node::Facts.indirection.expects(:find).with(@node.name).raises "foo" lambda { @node.fact_merge }.should raise_error(Puppet::Error) end it "should prefer parameters already set on the node over facts from the node" do @node = Puppet::Node.new("testnode", :parameters => {"one" => "a"}) @node.fact_merge @node.parameters["one"].should == "a" end it "should add passed parameters to the parameter list" do @node = Puppet::Node.new("testnode", :parameters => {"one" => "a"}) @node.fact_merge @node.parameters["two"].should == "b" end it "should accept arbitrary parameters to merge into its parameters" do @node = Puppet::Node.new("testnode", :parameters => {"one" => "a"}) @node.merge "two" => "three" @node.parameters["two"].should == "three" end it "should add the environment to the list of parameters" do Puppet.settings.stubs(:value).with(:environments).returns("one,two") Puppet.settings.stubs(:value).with(:environment).returns("one") @node = Puppet::Node.new("testnode", :environment => "one") @node.merge "two" => "three" @node.parameters["environment"].should == "one" end it "should not set the environment if it is already set in the parameters" do Puppet.settings.stubs(:value).with(:environments).returns("one,two") Puppet.settings.stubs(:value).with(:environment).returns("one") @node = Puppet::Node.new("testnode", :environment => "one") @node.merge "environment" => "two" @node.parameters["environment"].should == "two" end end describe Puppet::Node, "when indirecting" do it "should default to the 'plain' node terminus" do Puppet::Node.indirection.terminus_class.should == :plain end it "should not have a cache class defined" do Puppet::Node.indirection.cache_class.should be_nil end after do Puppet::Util::Cacher.expire end end describe Puppet::Node, "when generating the list of names to search through" do before do @node = Puppet::Node.new("foo.domain.com", :parameters => {"hostname" => "yay", "domain" => "domain.com"}) end it "should return an array of names" do @node.names.should be_instance_of(Array) end describe "and the node name is fully qualified" do it "should contain an entry for each part of the node name" do @node.names.should be_include("foo.domain.com") @node.names.should be_include("foo.domain") @node.names.should be_include("foo") end end it "should include the node's fqdn" do @node.names.should be_include("yay.domain.com") end it "should combine and include the node's hostname and domain if no fqdn is available" do @node.names.should be_include("yay.domain.com") end it "should contain an entry for each name available by stripping a segment of the fqdn" do @node.parameters["fqdn"] = "foo.deep.sub.domain.com" @node.names.should be_include("foo.deep.sub.domain") @node.names.should be_include("foo.deep.sub") end describe "and :node_name is set to 'cert'" do before do Puppet.settings.stubs(:value).with(:strict_hostname_checking).returns false Puppet.settings.stubs(:value).with(:node_name).returns "cert" end it "should use the passed-in key as the first value" do @node.names[0].should == "foo.domain.com" end describe "and strict hostname checking is enabled" do it "should only use the passed-in key" do Puppet.settings.expects(:value).with(:strict_hostname_checking).returns true @node.names.should == ["foo.domain.com"] end end end describe "and :node_name is set to 'facter'" do before do Puppet.settings.stubs(:value).with(:strict_hostname_checking).returns false Puppet.settings.stubs(:value).with(:node_name).returns "facter" end it "should use the node's 'hostname' fact as the first value" do @node.names[0].should == "yay" end end end