diff --git a/spec/unit/indirector/active_record_spec.rb b/spec/unit/indirector/active_record_spec.rb index 4765cc5ea..4fab17da2 100755 --- a/spec/unit/indirector/active_record_spec.rb +++ b/spec/unit/indirector/active_record_spec.rb @@ -1,77 +1,76 @@ #!/usr/bin/env ruby require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper') require 'puppet/rails' require 'puppet/indirector/active_record' describe Puppet::Indirector::ActiveRecord do before do Puppet::Rails.stubs(:init) Puppet::Indirector::Terminus.stubs(:register_terminus_class) @model = mock 'model' @indirection = stub 'indirection', :name => :mystuff, :register_terminus_type => nil, :model => @model Puppet::Indirector::Indirection.stubs(:instance).returns(@indirection) - @active_record_class = Class.new(Puppet::Indirector::ActiveRecord) do - def self.to_s - "Mystuff::Testing" - end + module Testing; end + @active_record_class = class Testing::MyActiveRecord < Puppet::Indirector::ActiveRecord + self end @ar_model = mock 'ar_model' @active_record_class.use_ar_model @ar_model @terminus = @active_record_class.new @name = "me" @instance = stub 'instance', :name => @name @request = stub 'request', :key => @name, :instance => @instance end it "should allow declaration of an ActiveRecord model to use" do @active_record_class.use_ar_model "foo" @active_record_class.ar_model.should == "foo" end describe "when initializing" do it "should init Rails" do Puppet::Rails.expects(:init) @active_record_class.new end end describe "when finding an instance" do it "should use the ActiveRecord model to find the instance" do @ar_model.expects(:find_by_name).with(@name) @terminus.find(@request) end it "should return nil if no instance is found" do @ar_model.expects(:find_by_name).with(@name).returns nil @terminus.find(@request).should be_nil end it "should convert the instance to a Puppet object if it is found" do instance = mock 'rails_instance' instance.expects(:to_puppet).returns "mypuppet" @ar_model.expects(:find_by_name).with(@name).returns instance @terminus.find(@request).should == "mypuppet" end end describe "when saving an instance" do it "should use the ActiveRecord model to convert the instance into a Rails object and then save that rails object" do rails_object = mock 'rails_object' @ar_model.expects(:from_puppet).with(@instance).returns rails_object rails_object.expects(:save) @terminus.save(@request) end end end diff --git a/spec/unit/indirector/code_spec.rb b/spec/unit/indirector/code_spec.rb index 452d009f8..1c9e4d2f1 100755 --- a/spec/unit/indirector/code_spec.rb +++ b/spec/unit/indirector/code_spec.rb @@ -1,33 +1,32 @@ #!/usr/bin/env ruby require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper') require 'puppet/indirector/code' describe Puppet::Indirector::Code do - before do + before :all do Puppet::Indirector::Terminus.stubs(:register_terminus_class) @model = mock 'model' @indirection = stub 'indirection', :name => :mystuff, :register_terminus_type => nil, :model => @model Puppet::Indirector::Indirection.stubs(:instance).returns(@indirection) - @code_class = Class.new(Puppet::Indirector::Code) do - def self.to_s - "Mystuff::Testing" - end + module Testing; end + @code_class = class Testing::MyCode < Puppet::Indirector::Code + self end @searcher = @code_class.new end it "should not have a find() method defined" do @searcher.should_not respond_to(:find) end it "should not have a save() method defined" do @searcher.should_not respond_to(:save) end it "should not have a destroy() method defined" do @searcher.should_not respond_to(:destroy) end end diff --git a/spec/unit/indirector/direct_file_server_spec.rb b/spec/unit/indirector/direct_file_server_spec.rb index 8eab4ad76..5d9af626f 100755 --- a/spec/unit/indirector/direct_file_server_spec.rb +++ b/spec/unit/indirector/direct_file_server_spec.rb @@ -1,84 +1,83 @@ #!/usr/bin/env ruby # # Created by Luke Kanies on 2007-10-24. # Copyright (c) 2007. All rights reserved. require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper') require 'puppet/indirector/direct_file_server' describe Puppet::Indirector::DirectFileServer do - before :each do + before :all do Puppet::Indirector::Terminus.stubs(:register_terminus_class) @model = mock 'model' @indirection = stub 'indirection', :name => :mystuff, :register_terminus_type => nil, :model => @model Puppet::Indirector::Indirection.stubs(:instance).returns(@indirection) - @direct_file_class = Class.new(Puppet::Indirector::DirectFileServer) do - def self.to_s - "Testing::Mytype" - end + module Testing; end + @direct_file_class = class Testing::Mytype < Puppet::Indirector::DirectFileServer + self end @server = @direct_file_class.new @uri = "file:///my/local" @request = Puppet::Indirector::Request.new(:mytype, :find, @uri) end describe Puppet::Indirector::DirectFileServer, "when finding a single file" do it "should return nil if the file does not exist" do FileTest.expects(:exists?).with("/my/local").returns false @server.find(@request).should be_nil end it "should return a Content instance created with the full path to the file if the file exists" do FileTest.expects(:exists?).with("/my/local").returns true @model.expects(:new).returns(:mycontent) @server.find(@request).should == :mycontent end end describe Puppet::Indirector::DirectFileServer, "when creating the instance for a single found file" do before do @data = mock 'content' @data.stubs(:collect) FileTest.expects(:exists?).with("/my/local").returns true end it "should pass the full path to the instance" do @model.expects(:new).with { |key, options| key == "/my/local" }.returns(@data) @server.find(@request) end it "should pass the :links setting on to the created Content instance if the file exists and there is a value for :links" do @model.expects(:new).returns(@data) @data.expects(:links=).with(:manage) @request.stubs(:options).returns(:links => :manage) @server.find(@request) end end describe Puppet::Indirector::DirectFileServer, "when searching for multiple files" do it "should return nil if the file does not exist" do FileTest.expects(:exists?).with("/my/local").returns false @server.find(@request).should be_nil end it "should use :path2instances from the terminus_helper to return instances if the file exists" do FileTest.expects(:exists?).with("/my/local").returns true @server.expects(:path2instances) @server.search(@request) end it "should pass the original request to :path2instances" do FileTest.expects(:exists?).with("/my/local").returns true @server.expects(:path2instances).with(@request, "/my/local") @server.search(@request) end end end diff --git a/spec/unit/indirector/exec_spec.rb b/spec/unit/indirector/exec_spec.rb index d4fb22443..5abb00ae9 100755 --- a/spec/unit/indirector/exec_spec.rb +++ b/spec/unit/indirector/exec_spec.rb @@ -1,55 +1,55 @@ #!/usr/bin/env ruby require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper') require 'puppet/indirector/exec' describe Puppet::Indirector::Exec do - before do + before :all do @indirection = stub 'indirection', :name => :testing Puppet::Indirector::Indirection.expects(:instance).with(:testing).returns(@indirection) - @exec_class = Class.new(Puppet::Indirector::Exec) do - def self.to_s - "Testing::Mytype" - end - + module Testing; end + @exec_class = class Testing::MyTesting < Puppet::Indirector::Exec attr_accessor :command + self end + end + before :each do @searcher = @exec_class.new @searcher.command = ["/echo"] @request = stub 'request', :key => "foo" end it "should throw an exception if the command is not an array" do @searcher.command = "/usr/bin/echo" proc { @searcher.find(@request) }.should raise_error(Puppet::DevError) end it "should throw an exception if the command is not fully qualified" do @searcher.command = ["mycommand"] proc { @searcher.find(@request) }.should raise_error(ArgumentError) end it "should execute the command with the object name as the only argument" do @searcher.expects(:execute).with(%w{/echo foo}) @searcher.find(@request) end it "should return the output of the script" do @searcher.expects(:execute).with(%w{/echo foo}).returns("whatever") @searcher.find(@request).should == "whatever" end it "should return nil when the command produces no output" do @searcher.expects(:execute).with(%w{/echo foo}).returns(nil) @searcher.find(@request).should be_nil end it "should raise an exception if there's an execution failure" do @searcher.expects(:execute).with(%w{/echo foo}).raises(Puppet::ExecutionFailure.new("message")) lambda {@searcher.find(@request)}.should raise_exception(Puppet::Error, 'Failed to find foo via exec: message') end end diff --git a/spec/unit/indirector/file_server_spec.rb b/spec/unit/indirector/file_server_spec.rb index a81d50487..079eba0ae 100755 --- a/spec/unit/indirector/file_server_spec.rb +++ b/spec/unit/indirector/file_server_spec.rb @@ -1,266 +1,267 @@ #!/usr/bin/env ruby # # Created by Luke Kanies on 2007-10-19. # Copyright (c) 2007. All rights reserved. require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper') require 'puppet/indirector/file_server' require 'puppet/file_serving/configuration' describe Puppet::Indirector::FileServer do - before :each do + before :all do Puppet::Indirector::Terminus.stubs(:register_terminus_class) @model = mock 'model' @indirection = stub 'indirection', :name => :mystuff, :register_terminus_type => nil, :model => @model Puppet::Indirector::Indirection.stubs(:instance).returns(@indirection) - @file_server_class = Class.new(Puppet::Indirector::FileServer) do - def self.to_s - "Testing::Mytype" - end + module Testing; end + @file_server_class = class Testing::MyFileServer < Puppet::Indirector::FileServer + self end + end + before :each do @file_server = @file_server_class.new @uri = "puppet://host/my/local/file" @configuration = mock 'configuration' Puppet::FileServing::Configuration.stubs(:create).returns(@configuration) @request = Puppet::Indirector::Request.new(:myind, :mymethod, @uri, :environment => "myenv") end describe "when finding files" do before do @mount = stub 'mount', :find => nil @instance = stub('instance', :links= => nil, :collect => nil) end it "should use the configuration to find the mount and relative path" do @configuration.expects(:split_path).with(@request) @file_server.find(@request) end it "should return nil if it cannot find the mount" do @configuration.expects(:split_path).with(@request).returns(nil, nil) @file_server.find(@request).should be_nil end it "should use the mount to find the full path" do @configuration.expects(:split_path).with(@request).returns([@mount, "rel/path"]) @mount.expects(:find).with { |key, request| key == "rel/path" } @file_server.find(@request) end it "should pass the request when finding a file" do @configuration.expects(:split_path).with(@request).returns([@mount, "rel/path"]) @mount.expects(:find).with { |key, request| request == @request } @file_server.find(@request) end it "should return nil if it cannot find a full path" do @configuration.expects(:split_path).with(@request).returns([@mount, "rel/path"]) @mount.expects(:find).with { |key, request| key == "rel/path" }.returns nil @file_server.find(@request).should be_nil end it "should create an instance with the found path" do @configuration.expects(:split_path).with(@request).returns([@mount, "rel/path"]) @mount.expects(:find).with { |key, request| key == "rel/path" }.returns "/my/file" @model.expects(:new).with("/my/file").returns @instance @file_server.find(@request).should equal(@instance) end it "should set 'links' on the instance if it is set in the request options" do @request.options[:links] = true @configuration.expects(:split_path).with(@request).returns([@mount, "rel/path"]) @mount.expects(:find).with { |key, request| key == "rel/path" }.returns "/my/file" @model.expects(:new).with("/my/file").returns @instance @instance.expects(:links=).with(true) @file_server.find(@request).should equal(@instance) end it "should collect the instance" do @request.options[:links] = true @configuration.expects(:split_path).with(@request).returns([@mount, "rel/path"]) @mount.expects(:find).with { |key, request| key == "rel/path" }.returns "/my/file" @model.expects(:new).with("/my/file").returns @instance @instance.expects(:collect) @file_server.find(@request).should equal(@instance) end end describe "when searching for instances" do before do @mount = stub 'mount', :search => nil @instance = stub('instance', :links= => nil, :collect => nil) end it "should use the configuration to search the mount and relative path" do @configuration.expects(:split_path).with(@request) @file_server.search(@request) end it "should return nil if it cannot search the mount" do @configuration.expects(:split_path).with(@request).returns(nil, nil) @file_server.search(@request).should be_nil end it "should use the mount to search for the full paths" do @configuration.expects(:split_path).with(@request).returns([@mount, "rel/path"]) @mount.expects(:search).with { |key, request| key == "rel/path" } @file_server.search(@request) end it "should pass the request" do @configuration.stubs(:split_path).returns([@mount, "rel/path"]) @mount.expects(:search).with { |key, request| request == @request } @file_server.search(@request) end it "should return nil if searching does not find any full paths" do @configuration.expects(:split_path).with(@request).returns([@mount, "rel/path"]) @mount.expects(:search).with { |key, request| key == "rel/path" }.returns nil @file_server.search(@request).should be_nil end it "should create a fileset with each returned path and merge them" do @configuration.expects(:split_path).with(@request).returns([@mount, "rel/path"]) @mount.expects(:search).with { |key, request| key == "rel/path" }.returns %w{/one /two} FileTest.stubs(:exist?).returns true one = mock 'fileset_one' Puppet::FileServing::Fileset.expects(:new).with("/one", @request).returns(one) two = mock 'fileset_two' Puppet::FileServing::Fileset.expects(:new).with("/two", @request).returns(two) Puppet::FileServing::Fileset.expects(:merge).with(one, two).returns [] @file_server.search(@request) end it "should create an instance with each path resulting from the merger of the filesets" do @configuration.expects(:split_path).with(@request).returns([@mount, "rel/path"]) @mount.expects(:search).with { |key, request| key == "rel/path" }.returns [] FileTest.stubs(:exist?).returns true Puppet::FileServing::Fileset.expects(:merge).returns("one" => "/one", "two" => "/two") one = stub 'one', :collect => nil @model.expects(:new).with("/one", :relative_path => "one").returns one two = stub 'two', :collect => nil @model.expects(:new).with("/two", :relative_path => "two").returns two # order can't be guaranteed result = @file_server.search(@request) result.should be_include(one) result.should be_include(two) result.length.should == 2 end it "should set 'links' on the instances if it is set in the request options" do @configuration.expects(:split_path).with(@request).returns([@mount, "rel/path"]) @mount.expects(:search).with { |key, request| key == "rel/path" }.returns [] FileTest.stubs(:exist?).returns true Puppet::FileServing::Fileset.expects(:merge).returns("one" => "/one") one = stub 'one', :collect => nil @model.expects(:new).with("/one", :relative_path => "one").returns one one.expects(:links=).with true @request.options[:links] = true @file_server.search(@request) end it "should collect the instances" do @configuration.expects(:split_path).with(@request).returns([@mount, "rel/path"]) @mount.expects(:search).with { |key, options| key == "rel/path" }.returns [] FileTest.stubs(:exist?).returns true Puppet::FileServing::Fileset.expects(:merge).returns("one" => "/one") one = mock 'one' @model.expects(:new).with("/one", :relative_path => "one").returns one one.expects(:collect) @file_server.search(@request) end end describe "when checking authorization" do before do @request.method = :find @mount = stub 'mount' @configuration.stubs(:split_path).with(@request).returns([@mount, "rel/path"]) @request.stubs(:node).returns("mynode") @request.stubs(:ip).returns("myip") @mount.stubs(:allowed?).with("mynode", "myip").returns "something" end it "should return false when destroying" do @request.method = :destroy @file_server.should_not be_authorized(@request) end it "should return false when saving" do @request.method = :save @file_server.should_not be_authorized(@request) end it "should use the configuration to find the mount and relative path" do @configuration.expects(:split_path).with(@request) @file_server.authorized?(@request) end it "should return false if it cannot find the mount" do @configuration.expects(:split_path).with(@request).returns(nil, nil) @file_server.should_not be_authorized(@request) end it "should return the results of asking the mount whether the node and IP are authorized" do @file_server.authorized?(@request).should == "something" end end end diff --git a/spec/unit/indirector/file_spec.rb b/spec/unit/indirector/file_spec.rb index 8fd197eac..96d5b2ae7 100755 --- a/spec/unit/indirector/file_spec.rb +++ b/spec/unit/indirector/file_spec.rb @@ -1,181 +1,180 @@ #!/usr/bin/env ruby require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper') require 'puppet/indirector/file' describe Puppet::Indirector::File do - before :each do + before :all do Puppet::Indirector::Terminus.stubs(:register_terminus_class) @model = mock 'model' @indirection = stub 'indirection', :name => :mystuff, :register_terminus_type => nil, :model => @model Puppet::Indirector::Indirection.stubs(:instance).returns(@indirection) - @file_class = Class.new(Puppet::Indirector::File) do - def self.to_s - "Testing::Mytype" - end + module Testing; end + @file_class = class Testing::MyFile < Puppet::Indirector::File + self end @searcher = @file_class.new @path = "/my/file" @dir = "/my" @request = stub 'request', :key => @path end describe "when finding files" do it "should provide a method to return file contents at a specified path" do @searcher.should respond_to(:find) end it "should use the server data directory plus the indirection name if the run_mode is master" do Puppet.run_mode.expects(:master?).returns true Puppet.settings.expects(:value).with(:server_datadir).returns "/my/dir" @searcher.data_directory.should == File.join("/my/dir", "mystuff") end it "should use the client data directory plus the indirection name if the run_mode is not master" do Puppet.run_mode.expects(:master?).returns false Puppet.settings.expects(:value).with(:client_datadir).returns "/my/dir" @searcher.data_directory.should == File.join("/my/dir", "mystuff") end it "should use the newest file in the data directory matching the indirection key without extension" do @searcher.expects(:data_directory).returns "/data/dir" @request.stubs(:key).returns "foo" Dir.expects(:glob).with("/data/dir/foo.*").returns %w{/data1.stuff /data2.stuff} stat1 = stub 'data1', :mtime => (Time.now - 5) stat2 = stub 'data2', :mtime => Time.now File.expects(:stat).with("/data1.stuff").returns stat1 File.expects(:stat).with("/data2.stuff").returns stat2 @searcher.latest_path(@request).should == "/data2.stuff" end it "should return nil when no files are found" do @searcher.stubs(:latest_path).returns nil @searcher.find(@request).should be_nil end it "should determine the file format from the file extension" do @searcher.file_format("/data2.pson").should == "pson" end it "should fail if the model does not support the file format" do @searcher.stubs(:latest_path).returns "/my/file.pson" @model.expects(:support_format?).with("pson").returns false lambda { @searcher.find(@request) }.should raise_error(ArgumentError) end end describe "when saving files" do before do @content = "my content" @file = stub 'file', :content => @content, :path => @path, :name => @path, :render => "mydata" @request.stubs(:instance).returns @file end it "should provide a method to save file contents at a specified path" do @searcher.should respond_to(:save) end it "should choose the file extension based on the default format of the model" do @model.expects(:default_format).returns "pson" @searcher.serialization_format.should == "pson" end it "should place the file in the data directory, named after the indirection, key, and format" do @searcher.stubs(:data_directory).returns "/my/dir" @searcher.stubs(:serialization_format).returns "pson" @request.stubs(:key).returns "foo" @searcher.file_path(@request).should == File.join("/my/dir", "foo.pson") end it "should fail intelligently if the file's parent directory does not exist" do @searcher.stubs(:file_path).returns "/my/dir/file.pson" @searcher.stubs(:serialization_format).returns "pson" @request.stubs(:key).returns "foo" File.expects(:directory?).with(File.join("/my/dir")).returns(false) proc { @searcher.save(@request) }.should raise_error(Puppet::Error) end it "should render the instance using the file format and print it to the file path" do @searcher.stubs(:file_path).returns "/my/file.pson" @searcher.stubs(:serialization_format).returns "pson" File.stubs(:directory?).returns true @request.instance.expects(:render).with("pson").returns "data" fh = mock 'filehandle' File.expects(:open).with("/my/file.pson", "w").yields fh fh.expects(:print).with("data") @searcher.save(@request) end it "should fail intelligently if a file cannot be written" do filehandle = mock 'file' File.stubs(:directory?).returns(true) File.stubs(:open).yields(filehandle) filehandle.expects(:print).raises(ArgumentError) @searcher.stubs(:file_path).returns "/my/file.pson" @model.stubs(:default_format).returns "pson" @instance.stubs(:render).returns "stuff" proc { @searcher.save(@request) }.should raise_error(Puppet::Error) end end describe "when removing files" do it "should provide a method to remove files" do @searcher.should respond_to(:destroy) end it "should remove files in all formats found in the data directory that match the request key" do @searcher.stubs(:data_directory).returns "/my/dir" @request.stubs(:key).returns "me" Dir.expects(:glob).with(File.join("/my/dir", "me.*")).returns %w{/one /two} File.expects(:unlink).with("/one") File.expects(:unlink).with("/two") @searcher.destroy(@request) end it "should throw an exception if no file is found" do @searcher.stubs(:data_directory).returns "/my/dir" @request.stubs(:key).returns "me" Dir.expects(:glob).with(File.join("/my/dir", "me.*")).returns [] proc { @searcher.destroy(@request) }.should raise_error(Puppet::Error) end it "should fail intelligently if a file cannot be removed" do @searcher.stubs(:data_directory).returns "/my/dir" @request.stubs(:key).returns "me" Dir.expects(:glob).with(File.join("/my/dir", "me.*")).returns %w{/one} File.expects(:unlink).with("/one").raises ArgumentError proc { @searcher.destroy(@request) }.should raise_error(Puppet::Error) end end end diff --git a/spec/unit/indirector/ldap_spec.rb b/spec/unit/indirector/ldap_spec.rb index 2178a8709..ab5dab9ce 100755 --- a/spec/unit/indirector/ldap_spec.rb +++ b/spec/unit/indirector/ldap_spec.rb @@ -1,139 +1,138 @@ #!/usr/bin/env ruby require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper') require 'puppet/indirector/ldap' describe Puppet::Indirector::Ldap do before do @indirection = stub 'indirection', :name => :testing Puppet::Indirector::Indirection.stubs(:instance).returns(@indirection) - @ldap_class = Class.new(Puppet::Indirector::Ldap) do - def self.to_s - "Testing::Mytype" - end + module Testing; end + @ldap_class = class Testing::MyLdap < Puppet::Indirector::Ldap + self end @connection = mock 'ldap' @searcher = @ldap_class.new end describe "when searching ldap" do before do # Stub everything, and we can selectively replace with an expect as # we need to for testing. @searcher.stubs(:connection).returns(@connection) @searcher.stubs(:search_filter).returns(:filter) @searcher.stubs(:search_base).returns(:base) @searcher.stubs(:process) @request = stub 'request', :key => "yay" end it "should call the ldapsearch method with the search filter" do @searcher.expects(:search_filter).with("yay").returns("yay's filter") @searcher.expects(:ldapsearch).with("yay's filter") @searcher.find @request end it "should fail if no block is passed to the ldapsearch method" do proc { @searcher.ldapsearch("blah") }.should raise_error(ArgumentError) end it "should use the results of the ldapbase method as the ldap search base" do @searcher.stubs(:search_base).returns("mybase") @connection.expects(:search).with do |*args| args[0].should == "mybase" true end @searcher.find @request end it "should default to the value of the :search_base setting as the result of the ldapbase method" do Puppet.expects(:[]).with(:ldapbase).returns("myldapbase") searcher = @ldap_class.new searcher.search_base.should == "myldapbase" end it "should use the results of the :search_attributes method as the list of attributes to return" do @searcher.stubs(:search_attributes).returns(:myattrs) @connection.expects(:search).with do |*args| args[3].should == :myattrs true end @searcher.find @request end it "should use depth 2 when searching" do @connection.expects(:search).with do |*args| args[1].should == 2 true end @searcher.find @request end it "should call process() on the first found entry" do @connection.expects(:search).yields("myresult") @searcher.expects(:process).with("myresult") @searcher.find @request end it "should reconnect and retry the search if there is a failure" do run = false @connection.stubs(:search).with do |*args| if run true else run = true raise "failed" end end.yields("myresult") @searcher.expects(:process).with("myresult") @searcher.find @request end it "should not reconnect on failure more than once" do count = 0 @connection.stubs(:search).with do |*args| count += 1 raise ArgumentError, "yay" end proc { @searcher.find(@request) }.should raise_error(Puppet::Error) count.should == 2 end it "should return true if an entry is found" do @connection.expects(:search).yields("result") @searcher.ldapsearch("whatever") { |r| }.should be_true end end describe "when connecting to ldap", :if => Puppet.features.ldap? do it "should create and start a Util::Ldap::Connection instance" do conn = mock 'connection', :connection => "myconn", :start => nil Puppet::Util::Ldap::Connection.expects(:instance).returns conn @searcher.connection.should == "myconn" end it "should only create the ldap connection when asked for it the first time" do conn = mock 'connection', :connection => "myconn", :start => nil Puppet::Util::Ldap::Connection.expects(:instance).returns conn @searcher.connection end it "should cache the connection" do conn = mock 'connection', :connection => "myconn", :start => nil Puppet::Util::Ldap::Connection.expects(:instance).returns conn @searcher.connection.should equal(@searcher.connection) end end describe "when reconnecting to ldap", :if => (Puppet.features.root? and Facter.value("hostname") == "culain") do it "should reconnect to ldap when connections are lost" end end diff --git a/spec/unit/indirector/memory_spec.rb b/spec/unit/indirector/memory_spec.rb index f9010326f..751adb1b6 100755 --- a/spec/unit/indirector/memory_spec.rb +++ b/spec/unit/indirector/memory_spec.rb @@ -1,29 +1,28 @@ #!/usr/bin/env ruby require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper') require 'puppet/indirector/memory' require 'shared_behaviours/memory_terminus' describe Puppet::Indirector::Memory do it_should_behave_like "A Memory Terminus" before do Puppet::Indirector::Terminus.stubs(:register_terminus_class) @model = mock 'model' @indirection = stub 'indirection', :name => :mystuff, :register_terminus_type => nil, :model => @model Puppet::Indirector::Indirection.stubs(:instance).returns(@indirection) - @memory_class = Class.new(Puppet::Indirector::Memory) do - def self.to_s - "Mystuff::Testing" - end + module Testing; end + @memory_class = class Testing::MyMemory < Puppet::Indirector::Memory + self end @searcher = @memory_class.new @name = "me" @instance = stub 'instance', :name => @name @request = stub 'request', :key => @name, :instance => @instance end end diff --git a/spec/unit/indirector/plain_spec.rb b/spec/unit/indirector/plain_spec.rb index 54c0233f8..dfaa701bd 100755 --- a/spec/unit/indirector/plain_spec.rb +++ b/spec/unit/indirector/plain_spec.rb @@ -1,29 +1,28 @@ #!/usr/bin/env ruby require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper') require 'puppet/indirector/plain' describe Puppet::Indirector::Plain do before do Puppet::Indirector::Terminus.stubs(:register_terminus_class) @model = mock 'model' @indirection = stub 'indirection', :name => :mystuff, :register_terminus_type => nil, :model => @model Puppet::Indirector::Indirection.stubs(:instance).returns(@indirection) - @plain_class = Class.new(Puppet::Indirector::Plain) do - def self.to_s - "Mystuff::Testing" - end + module Testing; end + @plain_class = class Testing::MyPlain < Puppet::Indirector::Plain + self end @searcher = @plain_class.new @request = stub 'request', :key => "yay" end it "should return return an instance of the indirected model" do object = mock 'object' @model.expects(:new).with(@request.key).returns object @searcher.find(@request).should equal(object) end end diff --git a/spec/unit/indirector/queue_spec.rb b/spec/unit/indirector/queue_spec.rb index 49e5e1015..6f5b44b4c 100755 --- a/spec/unit/indirector/queue_spec.rb +++ b/spec/unit/indirector/queue_spec.rb @@ -1,123 +1,122 @@ #!/usr/bin/env ruby require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper') require 'puppet/indirector/queue' class Puppet::Indirector::Queue::TestClient end class FooExampleData attr_accessor :name def self.pson_create(pson) new(pson['data'].to_sym) end def initialize(name = nil) @name = name if name end def render(format = :pson) to_pson end def to_pson(*args) {:type => self.class.to_s, :data => name}.to_pson(*args) end end describe Puppet::Indirector::Queue, :if => Puppet.features.pson? do before :each do @model = mock 'model' @indirection = stub 'indirection', :name => :my_queue, :register_terminus_type => nil, :model => @model Puppet::Indirector::Indirection.stubs(:instance).with(:my_queue).returns(@indirection) - @store_class = Class.new(Puppet::Indirector::Queue) do - def self.to_s - 'MyQueue::MyType' - end + module MyQueue; end + @store_class = class MyQueue::MyType < Puppet::Indirector::Queue + self end @store = @store_class.new @subject_class = FooExampleData @subject = @subject_class.new @subject.name = :me Puppet[:queue_type] = :test_client Puppet::Util::Queue.stubs(:queue_type_to_class).with(:test_client).returns(Puppet::Indirector::Queue::TestClient) @request = stub 'request', :key => :me, :instance => @subject end it "should require PSON" do Puppet.features.expects(:pson?).returns false lambda { @store_class.new }.should raise_error(ArgumentError) end it 'should use the correct client type and queue' do @store.queue.should == :my_queue @store.client.should be_an_instance_of(Puppet::Indirector::Queue::TestClient) end describe "when saving" do it 'should render the instance using pson' do @subject.expects(:render).with(:pson) @store.client.stubs(:send_message) @store.save(@request) end it "should send the rendered message to the appropriate queue on the client" do @subject.expects(:render).returns "mypson" @store.client.expects(:send_message).with(:my_queue, "mypson") @store.save(@request) end it "should catch any exceptions raised" do @store.client.expects(:send_message).raises ArgumentError lambda { @store.save(@request) }.should raise_error(Puppet::Error) end end describe "when subscribing to the queue" do before do @store_class.stubs(:model).returns @model end it "should use the model's Format support to intern the message from pson" do @model.expects(:convert_from).with(:pson, "mymessage") @store_class.client.expects(:subscribe).yields("mymessage") @store_class.subscribe {|o| o } end it "should yield each interned received message" do @model.stubs(:convert_from).returns "something" @subject_two = @subject_class.new @subject_two.name = :too @store_class.client.expects(:subscribe).with(:my_queue).multiple_yields(@subject, @subject_two) received = [] @store_class.subscribe do |obj| received.push(obj) end received.should == %w{something something} end it "should log but not propagate errors" do @store_class.client.expects(:subscribe).yields("foo") @store_class.expects(:intern).raises(ArgumentError) expect { @store_class.subscribe {|o| o } }.should_not raise_error @logs.length.should == 1 @logs.first.message.should =~ /Error occured with subscription to queue my_queue for indirection my_queue: ArgumentError/ @logs.first.level.should == :err end end end diff --git a/spec/unit/indirector/rest_spec.rb b/spec/unit/indirector/rest_spec.rb index 547e68dd3..326d85f9d 100755 --- a/spec/unit/indirector/rest_spec.rb +++ b/spec/unit/indirector/rest_spec.rb @@ -1,491 +1,499 @@ #!/usr/bin/env ruby require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper') require 'puppet/indirector/rest' shared_examples_for "a REST http call" do it "should accept a path" do lambda { @search.send(@method, *@arguments) }.should_not raise_error(ArgumentError) end it "should require a path" do lambda { @searcher.send(@method) }.should raise_error(ArgumentError) end it "should return the results of deserializing the response to the request" do conn = mock 'connection' conn.stubs(:put).returns @response conn.stubs(:delete).returns @response conn.stubs(:get).returns @response Puppet::Network::HttpPool.stubs(:http_instance).returns conn @searcher.expects(:deserialize).with(@response).returns "myobject" @searcher.send(@method, *@arguments).should == 'myobject' end end describe Puppet::Indirector::REST do - before do + before :all do Puppet::Indirector::Terminus.stubs(:register_terminus_class) @model = stub('model', :supported_formats => %w{}, :convert_from => nil) @instance = stub('model instance', :name= => nil) @indirection = stub('indirection', :name => :mystuff, :register_terminus_type => nil, :model => @model) - Puppet::Indirector::Indirection.stubs(:instance).returns(@indirection) + Puppet::Indirector::Indirection.expects(:instance).returns(@indirection) - @rest_class = Class.new(Puppet::Indirector::REST) do - def self.to_s - "This::Is::A::Test::Class" + module This + module Is + module A + module Test + end + end end end + @rest_class = class This::Is::A::Test::Class < Puppet::Indirector::REST + self + end + end + before :each do @response = stub('mock response', :body => 'result', :code => "200") @response.stubs(:[]).with('content-type').returns "text/plain" @response.stubs(:[]).with('content-encoding').returns nil @searcher = @rest_class.new @searcher.stubs(:model).returns @model end it "should include the v1 REST API module" do Puppet::Indirector::REST.ancestors.should be_include(Puppet::Network::HTTP::API::V1) end it "should have a method for specifying what setting a subclass should use to retrieve its server" do @rest_class.should respond_to(:use_server_setting) end it "should use any specified setting to pick the server" do @rest_class.expects(:server_setting).returns :servset Puppet.settings.expects(:value).with(:servset).returns "myserver" @rest_class.server.should == "myserver" end it "should default to :server for the server setting" do @rest_class.expects(:server_setting).returns nil Puppet.settings.expects(:value).with(:server).returns "myserver" @rest_class.server.should == "myserver" end it "should have a method for specifying what setting a subclass should use to retrieve its port" do @rest_class.should respond_to(:use_port_setting) end it "should use any specified setting to pick the port" do @rest_class.expects(:port_setting).returns :servset Puppet.settings.expects(:value).with(:servset).returns "321" @rest_class.port.should == 321 end it "should default to :port for the port setting" do @rest_class.expects(:port_setting).returns nil Puppet.settings.expects(:value).with(:masterport).returns "543" @rest_class.port.should == 543 end describe "when deserializing responses" do it "should return nil if the response code is 404" do response = mock 'response' response.expects(:code).returns "404" @searcher.deserialize(response).should be_nil end [300,400,403,405,500,501,502,503,504].each { |rc| describe "when the response code is #{rc}" do before :each do @model.expects(:convert_from).never @response = mock 'response' @response.stubs(:code).returns rc.to_s @response.stubs(:[]).with('content-encoding').returns nil @response.stubs(:message).returns "There was a problem (header)" end it "should fail" do @response.stubs(:body).returns nil lambda { @searcher.deserialize(@response) }.should raise_error(Net::HTTPError) end it "should take the error message from the body, if present" do @response.stubs(:body).returns "There was a problem (body)" lambda { @searcher.deserialize(@response) }.should raise_error(Net::HTTPError,"Error #{rc} on SERVER: There was a problem (body)") end it "should take the error message from the response header if the body is empty" do @response.stubs(:body).returns "" lambda { @searcher.deserialize(@response) }.should raise_error(Net::HTTPError,"Error #{rc} on SERVER: There was a problem (header)") end it "should take the error message from the response header if the body is absent" do @response.stubs(:body).returns nil lambda { @searcher.deserialize(@response) }.should raise_error(Net::HTTPError,"Error #{rc} on SERVER: There was a problem (header)") end describe "and with http compression" do it "should uncompress the body" do @response.stubs(:body).returns("compressed body") @searcher.expects(:uncompress_body).with(@response).returns("uncompressed") lambda { @searcher.deserialize(@response) }.should raise_error { |e| e.message =~ /uncompressed/ } end end end } it "should return the results of converting from the format specified by the content-type header if the response code is in the 200s" do @model.expects(:convert_from).with("myformat", "mydata").returns "myobject" response = mock 'response' response.stubs(:[]).with("content-type").returns "myformat" response.stubs(:[]).with("content-encoding").returns nil response.stubs(:body).returns "mydata" response.stubs(:code).returns "200" @searcher.deserialize(response).should == "myobject" end it "should convert and return multiple instances if the return code is in the 200s and 'multiple' is specified" do @model.expects(:convert_from_multiple).with("myformat", "mydata").returns "myobjects" response = mock 'response' response.stubs(:[]).with("content-type").returns "myformat" response.stubs(:[]).with("content-encoding").returns nil response.stubs(:body).returns "mydata" response.stubs(:code).returns "200" @searcher.deserialize(response, true).should == "myobjects" end it "should strip the content-type header to keep only the mime-type" do @model.expects(:convert_from).with("text/plain", "mydata").returns "myobject" response = mock 'response' response.stubs(:[]).with("content-type").returns "text/plain; charset=utf-8" response.stubs(:[]).with("content-encoding").returns nil response.stubs(:body).returns "mydata" response.stubs(:code).returns "200" @searcher.deserialize(response) end it "should uncompress the body" do @model.expects(:convert_from).with("myformat", "uncompressed mydata").returns "myobject" response = mock 'response' response.stubs(:[]).with("content-type").returns "myformat" response.stubs(:body).returns "compressed mydata" response.stubs(:code).returns "200" @searcher.expects(:uncompress_body).with(response).returns("uncompressed mydata") @searcher.deserialize(response).should == "myobject" end end describe "when creating an HTTP client" do before do Puppet.settings.stubs(:value).returns("rest_testing") end it "should use the class's server and port if the indirection request provides neither" do @request = stub 'request', :key => "foo", :server => nil, :port => nil @searcher.class.expects(:port).returns 321 @searcher.class.expects(:server).returns "myserver" Puppet::Network::HttpPool.expects(:http_instance).with("myserver", 321).returns "myconn" @searcher.network(@request).should == "myconn" end it "should use the server from the indirection request if one is present" do @request = stub 'request', :key => "foo", :server => "myserver", :port => nil @searcher.class.stubs(:port).returns 321 Puppet::Network::HttpPool.expects(:http_instance).with("myserver", 321).returns "myconn" @searcher.network(@request).should == "myconn" end it "should use the port from the indirection request if one is present" do @request = stub 'request', :key => "foo", :server => nil, :port => 321 @searcher.class.stubs(:server).returns "myserver" Puppet::Network::HttpPool.expects(:http_instance).with("myserver", 321).returns "myconn" @searcher.network(@request).should == "myconn" end end describe "when doing a find" do before :each do @connection = stub('mock http connection', :get => @response) @searcher.stubs(:network).returns(@connection) # neuter the network connection # Use a key with spaces, so we can test escaping @request = Puppet::Indirector::Request.new(:foo, :find, "foo bar") end it "should call the GET http method on a network connection" do @searcher.expects(:network).returns @connection @connection.expects(:get).returns @response @searcher.find(@request) end it "should deserialize and return the http response, setting name" do @connection.expects(:get).returns @response instance = stub 'object' instance.expects(:name=) @searcher.expects(:deserialize).with(@response).returns instance @searcher.find(@request).should == instance end it "should deserialize and return the http response, and not require name=" do @connection.expects(:get).returns @response instance = stub 'object' @searcher.expects(:deserialize).with(@response).returns instance @searcher.find(@request).should == instance end it "should use the URI generated by the Handler module" do @searcher.expects(:indirection2uri).with(@request).returns "/my/uri" @connection.expects(:get).with { |path, args| path == "/my/uri" }.returns(@response) @searcher.find(@request) end it "should provide an Accept header containing the list of supported formats joined with commas" do @connection.expects(:get).with { |path, args| args["Accept"] == "supported, formats" }.returns(@response) @searcher.model.expects(:supported_formats).returns %w{supported formats} @searcher.find(@request) end it "should add Accept-Encoding header" do @searcher.expects(:add_accept_encoding).returns({"accept-encoding" => "gzip"}) @connection.expects(:get).with { |path, args| args["accept-encoding"] == "gzip" }.returns(@response) @searcher.find(@request) end it "should deserialize and return the network response" do @searcher.expects(:deserialize).with(@response).returns @instance @searcher.find(@request).should equal(@instance) end it "should set the name of the resulting instance to the asked-for name" do @searcher.expects(:deserialize).with(@response).returns @instance @instance.expects(:name=).with "foo bar" @searcher.find(@request) end it "should generate an error when result data deserializes fails" do @searcher.expects(:deserialize).raises(ArgumentError) lambda { @searcher.find(@request) }.should raise_error(ArgumentError) end end describe "when doing a head" do before :each do @connection = stub('mock http connection', :head => @response) @searcher.stubs(:network).returns(@connection) # Use a key with spaces, so we can test escaping @request = Puppet::Indirector::Request.new(:foo, :head, "foo bar") end it "should call the HEAD http method on a network connection" do @searcher.expects(:network).returns @connection @connection.expects(:head).returns @response @searcher.head(@request) end it "should return true if there was a successful http response" do @connection.expects(:head).returns @response @response.stubs(:code).returns "200" @searcher.head(@request).should == true end it "should return false if there was a successful http response" do @connection.expects(:head).returns @response @response.stubs(:code).returns "404" @searcher.head(@request).should == false end it "should use the URI generated by the Handler module" do @searcher.expects(:indirection2uri).with(@request).returns "/my/uri" @connection.expects(:head).with { |path, args| path == "/my/uri" }.returns(@response) @searcher.head(@request) end end describe "when doing a search" do before :each do @connection = stub('mock http connection', :get => @response) @searcher.stubs(:network).returns(@connection) # neuter the network connection @model.stubs(:convert_from_multiple) @request = Puppet::Indirector::Request.new(:foo, :search, "foo bar") end it "should call the GET http method on a network connection" do @searcher.expects(:network).returns @connection @connection.expects(:get).returns @response @searcher.search(@request) end it "should deserialize as multiple instances and return the http response" do @connection.expects(:get).returns @response @searcher.expects(:deserialize).with(@response, true).returns "myobject" @searcher.search(@request).should == 'myobject' end it "should use the URI generated by the Handler module" do @searcher.expects(:indirection2uri).with(@request).returns "/mys/uri" @connection.expects(:get).with { |path, args| path == "/mys/uri" }.returns(@response) @searcher.search(@request) end it "should provide an Accept header containing the list of supported formats joined with commas" do @connection.expects(:get).with { |path, args| args["Accept"] == "supported, formats" }.returns(@response) @searcher.model.expects(:supported_formats).returns %w{supported formats} @searcher.search(@request) end it "should return an empty array if serialization returns nil" do @model.stubs(:convert_from_multiple).returns nil @searcher.search(@request).should == [] end it "should generate an error when result data deserializes fails" do @searcher.expects(:deserialize).raises(ArgumentError) lambda { @searcher.search(@request) }.should raise_error(ArgumentError) end end describe "when doing a destroy" do before :each do @connection = stub('mock http connection', :delete => @response) @searcher.stubs(:network).returns(@connection) # neuter the network connection @request = Puppet::Indirector::Request.new(:foo, :destroy, "foo bar") end it "should call the DELETE http method on a network connection" do @searcher.expects(:network).returns @connection @connection.expects(:delete).returns @response @searcher.destroy(@request) end it "should fail if any options are provided, since DELETE apparently does not support query options" do @request.stubs(:options).returns(:one => "two", :three => "four") lambda { @searcher.destroy(@request) }.should raise_error(ArgumentError) end it "should deserialize and return the http response" do @connection.expects(:delete).returns @response @searcher.expects(:deserialize).with(@response).returns "myobject" @searcher.destroy(@request).should == 'myobject' end it "should use the URI generated by the Handler module" do @searcher.expects(:indirection2uri).with(@request).returns "/my/uri" @connection.expects(:delete).with { |path, args| path == "/my/uri" }.returns(@response) @searcher.destroy(@request) end it "should not include the query string" do @connection.stubs(:delete).returns @response @searcher.destroy(@request) end it "should provide an Accept header containing the list of supported formats joined with commas" do @connection.expects(:delete).with { |path, args| args["Accept"] == "supported, formats" }.returns(@response) @searcher.model.expects(:supported_formats).returns %w{supported formats} @searcher.destroy(@request) end it "should deserialize and return the network response" do @searcher.expects(:deserialize).with(@response).returns @instance @searcher.destroy(@request).should equal(@instance) end it "should generate an error when result data deserializes fails" do @searcher.expects(:deserialize).raises(ArgumentError) lambda { @searcher.destroy(@request) }.should raise_error(ArgumentError) end end describe "when doing a save" do before :each do @connection = stub('mock http connection', :put => @response) @searcher.stubs(:network).returns(@connection) # neuter the network connection @instance = stub 'instance', :render => "mydata", :mime => "mime" @request = Puppet::Indirector::Request.new(:foo, :save, "foo bar") @request.instance = @instance end it "should call the PUT http method on a network connection" do @searcher.expects(:network).returns @connection @connection.expects(:put).returns @response @searcher.save(@request) end it "should fail if any options are provided, since DELETE apparently does not support query options" do @request.stubs(:options).returns(:one => "two", :three => "four") lambda { @searcher.save(@request) }.should raise_error(ArgumentError) end it "should use the URI generated by the Handler module" do @searcher.expects(:indirection2uri).with(@request).returns "/my/uri" @connection.expects(:put).with { |path, args| path == "/my/uri" }.returns(@response) @searcher.save(@request) end it "should serialize the instance using the default format and pass the result as the body of the request" do @instance.expects(:render).returns "serial_instance" @connection.expects(:put).with { |path, data, args| data == "serial_instance" }.returns @response @searcher.save(@request) end it "should deserialize and return the http response" do @connection.expects(:put).returns @response @searcher.expects(:deserialize).with(@response).returns "myobject" @searcher.save(@request).should == 'myobject' end it "should provide an Accept header containing the list of supported formats joined with commas" do @connection.expects(:put).with { |path, data, args| args["Accept"] == "supported, formats" }.returns(@response) @searcher.model.expects(:supported_formats).returns %w{supported formats} @searcher.save(@request) end it "should provide a Content-Type header containing the mime-type of the sent object" do @connection.expects(:put).with { |path, data, args| args['Content-Type'] == "mime" }.returns(@response) @instance.expects(:mime).returns "mime" @searcher.save(@request) end it "should deserialize and return the network response" do @searcher.expects(:deserialize).with(@response).returns @instance @searcher.save(@request).should equal(@instance) end it "should generate an error when result data deserializes fails" do @searcher.expects(:deserialize).raises(ArgumentError) lambda { @searcher.save(@request) }.should raise_error(ArgumentError) end end end diff --git a/spec/unit/indirector/ssl_file_spec.rb b/spec/unit/indirector/ssl_file_spec.rb index 4549127f9..ca97cf49e 100755 --- a/spec/unit/indirector/ssl_file_spec.rb +++ b/spec/unit/indirector/ssl_file_spec.rb @@ -1,281 +1,282 @@ #!/usr/bin/env ruby # # Created by Luke Kanies on 2008-3-10. # Copyright (c) 2007. All rights reserved. require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper') require 'puppet/indirector/ssl_file' describe Puppet::Indirector::SslFile do - before do - @model = mock 'model' + before :all do @indirection = stub 'indirection', :name => :testing, :model => @model Puppet::Indirector::Indirection.expects(:instance).with(:testing).returns(@indirection) - @file_class = Class.new(Puppet::Indirector::SslFile) do - def self.to_s - "Testing::Mytype" - end + module Testing; end + @file_class = class Testing::MyType < Puppet::Indirector::SslFile + self end + end + before :each do + @model = mock 'model' @setting = :certdir @file_class.store_in @setting @path = "/tmp/my_directory" Puppet[:noop] = false Puppet[@setting] = @path Puppet[:trace] = false end it "should use :main and :ssl upon initialization" do Puppet.settings.expects(:use).with(:main, :ssl) @file_class.new end it "should return a nil collection directory if no directory setting has been provided" do @file_class.store_in nil @file_class.collection_directory.should be_nil end it "should return a nil file location if no location has been provided" do @file_class.store_at nil @file_class.file_location.should be_nil end it "should fail if no store directory or file location has been set" do @file_class.store_in nil @file_class.store_at nil lambda { @file_class.new }.should raise_error(Puppet::DevError) end describe "when managing ssl files" do before do Puppet.settings.stubs(:use) @searcher = @file_class.new @cert = stub 'certificate', :name => "myname" @certpath = File.join(@path, "myname.pem") @request = stub 'request', :key => @cert.name, :instance => @cert end it "should consider the file a ca file if the name is equal to what the SSL::Host class says is the CA name" do Puppet::SSL::Host.expects(:ca_name).returns "amaca" @searcher.should be_ca("amaca") end describe "when choosing the location for certificates" do it "should set them at the ca setting's path if a ca setting is available and the name resolves to the CA name" do @file_class.store_in nil @file_class.store_at :mysetting @file_class.store_ca_at :casetting Puppet.settings.stubs(:value).with(:casetting).returns "/ca/file" @searcher.expects(:ca?).with(@cert.name).returns true @searcher.path(@cert.name).should == "/ca/file" end it "should set them at the file location if a file setting is available" do @file_class.store_in nil @file_class.store_at :mysetting Puppet.settings.stubs(:value).with(:mysetting).returns "/some/file" @searcher.path(@cert.name).should == "/some/file" end it "should set them in the setting directory, with the certificate name plus '.pem', if a directory setting is available" do @searcher.path(@cert.name).should == @certpath end end describe "when finding certificates on disk" do describe "and no certificate is present" do before do # Stub things so the case management bits work. FileTest.stubs(:exist?).with(File.dirname(@certpath)).returns false FileTest.expects(:exist?).with(@certpath).returns false end it "should return nil" do @searcher.find(@request).should be_nil end end describe "and a certificate is present" do before do FileTest.expects(:exist?).with(@certpath).returns true end it "should return an instance of the model, which it should use to read the certificate" do cert = mock 'cert' model = mock 'model' @file_class.stubs(:model).returns model model.expects(:new).with("myname").returns cert cert.expects(:read).with(@certpath) @searcher.find(@request).should equal(cert) end end describe "and a certificate is present but has uppercase letters" do before do @request = stub 'request', :key => "myhost" end # This is kind of more an integration test; it's for #1382, until # the support for upper-case certs can be removed around mid-2009. it "should rename the existing file to the lower-case path" do @path = @searcher.path("myhost") FileTest.expects(:exist?).with(@path).returns(false) dir, file = File.split(@path) FileTest.expects(:exist?).with(dir).returns true Dir.expects(:entries).with(dir).returns [".", "..", "something.pem", file.upcase] File.expects(:rename).with(File.join(dir, file.upcase), @path) cert = mock 'cert' model = mock 'model' @searcher.stubs(:model).returns model @searcher.model.expects(:new).with("myhost").returns cert cert.expects(:read).with(@path) @searcher.find(@request) end end end describe "when saving certificates to disk" do before do FileTest.stubs(:directory?).returns true FileTest.stubs(:writable?).returns true end it "should fail if the directory is absent" do FileTest.expects(:directory?).with(File.dirname(@certpath)).returns false lambda { @searcher.save(@request) }.should raise_error(Puppet::Error) end it "should fail if the directory is not writeable" do FileTest.stubs(:directory?).returns true FileTest.expects(:writable?).with(File.dirname(@certpath)).returns false lambda { @searcher.save(@request) }.should raise_error(Puppet::Error) end it "should save to the path the output of converting the certificate to a string" do fh = mock 'filehandle' fh.expects(:print).with("mycert") @searcher.stubs(:write).yields fh @cert.expects(:to_s).returns "mycert" @searcher.save(@request) end describe "and a directory setting is set" do it "should use the Settings class to write the file" do @searcher.class.store_in @setting fh = mock 'filehandle' fh.stubs :print Puppet.settings.expects(:writesub).with(@setting, @certpath).yields fh @searcher.save(@request) end end describe "and a file location is set" do it "should use the filehandle provided by the Settings" do @searcher.class.store_at @setting fh = mock 'filehandle' fh.stubs :print Puppet.settings.expects(:write).with(@setting).yields fh @searcher.save(@request) end end describe "and the name is the CA name and a ca setting is set" do it "should use the filehandle provided by the Settings" do @searcher.class.store_at @setting @searcher.class.store_ca_at :castuff Puppet.settings.stubs(:value).with(:castuff).returns "castuff stub" fh = mock 'filehandle' fh.stubs :print Puppet.settings.expects(:write).with(:castuff).yields fh @searcher.stubs(:ca?).returns true @searcher.save(@request) end end end describe "when destroying certificates" do describe "that do not exist" do before do FileTest.expects(:exist?).with(@certpath).returns false end it "should return false" do @searcher.destroy(@request).should be_false end end describe "that exist" do before do FileTest.expects(:exist?).with(@certpath).returns true end it "should unlink the certificate file" do File.expects(:unlink).with(@certpath) @searcher.destroy(@request) end it "should log that is removing the file" do File.stubs(:exist?).returns true File.stubs(:unlink) Puppet.expects(:notice) @searcher.destroy(@request) end end end describe "when searching for certificates" do before do @model = mock 'model' @file_class.stubs(:model).returns @model end it "should return a certificate instance for all files that exist" do Dir.expects(:entries).with(@path).returns %w{one.pem two.pem} one = stub 'one', :read => nil two = stub 'two', :read => nil @model.expects(:new).with("one").returns one @model.expects(:new).with("two").returns two @searcher.search(@request).should == [one, two] end it "should read each certificate in using the model's :read method" do Dir.expects(:entries).with(@path).returns %w{one.pem} one = stub 'one' one.expects(:read).with(File.join(@path, "one.pem")) @model.expects(:new).with("one").returns one @searcher.search(@request) end it "should skip any files that do not match /\.pem$/" do Dir.expects(:entries).with(@path).returns %w{. .. one.pem} one = stub 'one', :read => nil @model.expects(:new).with("one").returns one @searcher.search(@request) end end end end diff --git a/spec/unit/indirector/yaml_spec.rb b/spec/unit/indirector/yaml_spec.rb index 35017991b..188e300d6 100755 --- a/spec/unit/indirector/yaml_spec.rb +++ b/spec/unit/indirector/yaml_spec.rb @@ -1,158 +1,159 @@ #!/usr/bin/env ruby require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper') require 'puppet/indirector/yaml' describe Puppet::Indirector::Yaml, " when choosing file location" do - before :each do + before :all do @indirection = stub 'indirection', :name => :my_yaml, :register_terminus_type => nil - Puppet::Indirector::Indirection.stubs(:instance).with(:my_yaml).returns(@indirection) - @store_class = Class.new(Puppet::Indirector::Yaml) do - def self.to_s - "MyYaml::MyType" - end + Puppet::Indirector::Indirection.expects(:instance).with(:my_yaml).returns(@indirection) + module MyYaml; end + @store_class = class MyYaml::MyType < Puppet::Indirector::Yaml + self end + end + before :each do @store = @store_class.new @subject = Object.new @subject.singleton_class.send(:attr_accessor, :name) @subject.name = :me @dir = "/what/ever" Puppet.settings.stubs(:value).returns("fakesettingdata") Puppet.settings.stubs(:value).with(:clientyamldir).returns(@dir) Puppet.run_mode.stubs(:master?).returns false @request = stub 'request', :key => :me, :instance => @subject end describe Puppet::Indirector::Yaml, " when choosing file location" do it "should use the server_datadir if the run_mode is master" do Puppet.run_mode.expects(:master?).returns true Puppet.settings.expects(:value).with(:yamldir).returns "/server/yaml/dir" @store.path(:me).should =~ %r{^/server/yaml/dir} end it "should use the client yamldir if the run_mode is not master" do Puppet.run_mode.expects(:master?).returns false Puppet.settings.expects(:value).with(:clientyamldir).returns "/client/yaml/dir" @store.path(:me).should =~ %r{^/client/yaml/dir} end it "should use the extension if one is specified" do Puppet.run_mode.expects(:master?).returns true Puppet.settings.expects(:value).with(:yamldir).returns "/server/yaml/dir" @store.path(:me,'.farfignewton').should =~ %r{\.farfignewton$} end it "should assume an extension of .yaml if none is specified" do Puppet.run_mode.expects(:master?).returns true Puppet.settings.expects(:value).with(:yamldir).returns "/server/yaml/dir" @store.path(:me).should =~ %r{\.yaml$} end it "should store all files in a single file root set in the Puppet defaults" do @store.path(:me).should =~ %r{^#{@dir}} end it "should use the terminus name for choosing the subdirectory" do @store.path(:me).should =~ %r{^#{@dir}/my_yaml} end it "should use the object's name to determine the file name" do @store.path(:me).should =~ %r{me.yaml$} end end describe Puppet::Indirector::Yaml, " when storing objects as YAML" do it "should only store objects that respond to :name" do @request.stubs(:instance).returns Object.new proc { @store.save(@request) }.should raise_error(ArgumentError) end it "should convert Ruby objects to YAML and write them to disk using a write lock" do yaml = @subject.to_yaml file = mock 'file' path = @store.send(:path, @subject.name) FileTest.expects(:exist?).with(File.dirname(path)).returns(true) @store.expects(:writelock).with(path, 0660).yields(file) file.expects(:print).with(yaml) @store.save(@request) end it "should create the indirection subdirectory if it does not exist" do yaml = @subject.to_yaml file = mock 'file' path = @store.send(:path, @subject.name) dir = File.dirname(path) FileTest.expects(:exist?).with(dir).returns(false) Dir.expects(:mkdir).with(dir) @store.expects(:writelock).yields(file) file.expects(:print).with(yaml) @store.save(@request) end end describe Puppet::Indirector::Yaml, " when retrieving YAML" do it "should read YAML in from disk using a read lock and convert it to Ruby objects" do path = @store.send(:path, @subject.name) yaml = @subject.to_yaml FileTest.expects(:exist?).with(path).returns(true) fh = mock 'filehandle' @store.expects(:readlock).with(path).yields fh fh.expects(:read).returns yaml @store.find(@request).instance_variable_get("@name").should == :me end it "should fail coherently when the stored YAML is invalid" do path = @store.send(:path, @subject.name) FileTest.expects(:exist?).with(path).returns(true) # Something that will fail in yaml yaml = "--- !ruby/object:Hash" fh = mock 'filehandle' @store.expects(:readlock).yields fh fh.expects(:read).returns yaml proc { @store.find(@request) }.should raise_error(Puppet::Error) end end describe Puppet::Indirector::Yaml, " when searching" do it "should return an array of fact instances with one instance for each file when globbing *" do @request = stub 'request', :key => "*", :instance => @subject @one = mock 'one' @two = mock 'two' @store.expects(:path).with(@request.key,'').returns :glob Dir.expects(:glob).with(:glob).returns(%w{one.yaml two.yaml}) YAML.expects(:load_file).with("one.yaml").returns @one; YAML.expects(:load_file).with("two.yaml").returns @two; @store.search(@request).should == [@one, @two] end it "should return an array containing a single instance of fact when globbing 'one*'" do @request = stub 'request', :key => "one*", :instance => @subject @one = mock 'one' @store.expects(:path).with(@request.key,'').returns :glob Dir.expects(:glob).with(:glob).returns(%w{one.yaml}) YAML.expects(:load_file).with("one.yaml").returns @one; @store.search(@request).should == [@one] end it "should return an empty array when the glob doesn't match anything" do @request = stub 'request', :key => "f*ilglobcanfail*", :instance => @subject @store.expects(:path).with(@request.key,'').returns :glob Dir.expects(:glob).with(:glob).returns [] @store.search(@request).should == [] end end end