diff options
| author | Luke Kanies <luke@madstop.com> | 2008-09-23 23:50:43 -0500 |
|---|---|---|
| committer | Luke Kanies <luke@madstop.com> | 2008-09-23 23:50:43 -0500 |
| commit | bb23861e334e617b544c11bc75a35c40b36185a2 (patch) | |
| tree | 18da91858e4fded78a56d673fc69014fdf266676 /spec | |
| parent | e31df2f7f5e98c524b68cd724cfaa3e308e7b9a1 (diff) | |
| parent | ac5db5ec115455e54090542870847820357739a2 (diff) | |
| download | puppet-bb23861e334e617b544c11bc75a35c40b36185a2.tar.gz puppet-bb23861e334e617b544c11bc75a35c40b36185a2.tar.xz puppet-bb23861e334e617b544c11bc75a35c40b36185a2.zip | |
Merge branch 'feature/master/1481'
This merges in the new fileserving code -- we're now using
REST to do fileserving, rather than xmlrpc.
Conflicts:
lib/puppet/parameter.rb
lib/puppet/type/file.rb
spec/unit/type/file.rb
Diffstat (limited to 'spec')
34 files changed, 1540 insertions, 438 deletions
diff --git a/spec/integration/file_serving/configuration.rb b/spec/integration/file_serving/configuration.rb index cb5a23d3b..dfdda402d 100755 --- a/spec/integration/file_serving/configuration.rb +++ b/spec/integration/file_serving/configuration.rb @@ -29,12 +29,12 @@ describe Puppet::FileServing::Configuration, " when finding files with Puppet::F it "should return nil if the file does not exist" do FileTest.expects(:exists?).with("/my/path/my/file").returns(false) - @config.file_path("/mymount/my/file").should be_nil + @config.file_path("mymount/my/file").should be_nil end it "should return the full file path if the file exists" do FileTest.expects(:exists?).with("/my/path/my/file").returns(true) - @config.file_path("/mymount/my/file").should == "/my/path/my/file" + @config.file_path("mymount/my/file").should == "/my/path/my/file" end after do diff --git a/spec/integration/file_serving/content.rb b/spec/integration/file_serving/content.rb index aee2a9f2d..af0181393 100755 --- a/spec/integration/file_serving/content.rb +++ b/spec/integration/file_serving/content.rb @@ -15,4 +15,6 @@ describe Puppet::FileServing::Content, " when finding files" do @test_class = Puppet::FileServing::Content @indirection = Puppet::FileServing::Content.indirection end + + after { Puppet::Util::Cacher.invalidate } end diff --git a/spec/integration/file_serving/fileset.rb b/spec/integration/file_serving/fileset.rb new file mode 100755 index 000000000..80bf0f376 --- /dev/null +++ b/spec/integration/file_serving/fileset.rb @@ -0,0 +1,14 @@ +#!/usr/bin/env ruby + +require File.dirname(__FILE__) + '/../../spec_helper' + +require 'puppet/file_serving/fileset' + +describe Puppet::FileServing::Fileset do + it "should be able to recurse on a single file" do + @path = Tempfile.new("fileset_integration") + + fileset = Puppet::FileServing::Fileset.new(@path.path) + lambda { fileset.files }.should_not raise_error + end +end diff --git a/spec/integration/file_serving/metadata.rb b/spec/integration/file_serving/metadata.rb index 067cb566a..af3e16324 100755 --- a/spec/integration/file_serving/metadata.rb +++ b/spec/integration/file_serving/metadata.rb @@ -15,4 +15,6 @@ describe Puppet::FileServing::Metadata, " when finding files" do @test_class = Puppet::FileServing::Metadata @indirection = Puppet::FileServing::Metadata.indirection end + + after { Puppet::Util::Cacher.invalidate } end diff --git a/spec/integration/file_serving/terminus_helper.rb b/spec/integration/file_serving/terminus_helper.rb new file mode 100755 index 000000000..7d2587af1 --- /dev/null +++ b/spec/integration/file_serving/terminus_helper.rb @@ -0,0 +1,22 @@ +#!/usr/bin/env ruby + +require File.dirname(__FILE__) + '/../../spec_helper' + +require 'puppet/file_serving/terminus_helper' + +class TerminusHelperIntegrationTester + include Puppet::FileServing::TerminusHelper + def model + Puppet::FileServing::Metadata + end +end + +describe Puppet::FileServing::TerminusHelper do + it "should be able to recurse on a single file" do + @path = Tempfile.new("fileset_integration") + request = Puppet::Indirector::Request.new(:metadata, :find, @path.path, :recurse => true) + + tester = TerminusHelperIntegrationTester.new + lambda { tester.path2instances(request, @path.path) }.should_not raise_error + end +end diff --git a/spec/integration/indirector/direct_file_server.rb b/spec/integration/indirector/direct_file_server.rb index 40b753a6c..417d661e8 100755 --- a/spec/integration/indirector/direct_file_server.rb +++ b/spec/integration/indirector/direct_file_server.rb @@ -37,21 +37,19 @@ describe Puppet::Indirector::DirectFileServer, " when interacting with FileServi before do @terminus = Puppet::Indirector::FileContent::File.new - @filepath = "/my/file" - FileTest.stubs(:exists?).with(@filepath).returns(true) + @path = Tempfile.new("direct_file_server_testing") + @path.close! + @path = @path.path - stat = stub 'stat', :directory? => true - File.stubs(:lstat).with(@filepath).returns(stat) + Dir.mkdir(@path) + File.open(File.join(@path, "one"), "w") { |f| f.print "one content" } + File.open(File.join(@path, "two"), "w") { |f| f.print "two content" } - @subfiles = %w{one two} - @subfiles.each do |f| - path = File.join(@filepath, f) - FileTest.stubs(:exists?).with(@path).returns(true) - end - - Dir.expects(:entries).with(@filepath).returns @subfiles + @request = @terminus.indirection.request(:search, "file:///%s" % @path, :recurse => true) + end - @request = @terminus.indirection.request(:search, "file:///my/file", :recurse => true) + after do + system("rm -rf %s" % @path) end it "should return an instance for every file in the fileset" do @@ -62,18 +60,13 @@ describe Puppet::Indirector::DirectFileServer, " when interacting with FileServi end it "should return instances capable of returning their content" do - @subfiles.each do |name| - File.stubs(:lstat).with(File.join(@filepath, name)).returns stub("#{name} stat", :ftype => "file", :directory? => false) - File.expects(:read).with(File.join(@filepath, name)).returns("#{name} content") - end - @terminus.search(@request).each do |instance| - case instance.key + case instance.full_path when /one/: instance.content.should == "one content" when /two/: instance.content.should == "two content" when /\.$/: else - raise "No valid key for %s" % instance.key.inspect + raise "No valid key for %s" % instance.path.inspect end end end diff --git a/spec/integration/indirector/module_files.rb b/spec/integration/indirector/module_files.rb index ae14aa5a7..a54588ec5 100755 --- a/spec/integration/indirector/module_files.rb +++ b/spec/integration/indirector/module_files.rb @@ -20,7 +20,7 @@ describe Puppet::Indirector::ModuleFiles, " when interacting with Puppet::Module FileTest.expects(:exists?).with(filepath).returns(true) - @request = Puppet::Indirector::Request.new(:content, :find, "puppetmounts://host/modules/mymod/myfile") + @request = Puppet::Indirector::Request.new(:content, :find, "puppet://host/modules/mymod/myfile") @terminus.find(@request).should be_instance_of(Puppet::FileServing::Content) end @@ -30,24 +30,24 @@ describe Puppet::Indirector::ModuleFiles, " when interacting with FileServing::F it "should return an instance for every file in the fileset" do Puppet::Node::Environment.stubs(:new).returns(stub('env', :name => "myenv")) @terminus = Puppet::Indirector::FileContent::Modules.new - @module = Puppet::Module.new("mymod", "/some/path/mymod") - Puppet::Module.expects(:find).with("mymod", "myenv").returns(@module) - filepath = "/some/path/mymod/files/myfile" - FileTest.stubs(:exists?).with(filepath).returns(true) + @path = Tempfile.new("module_file_testing") + @path.close! + @path = @path.path - stat = stub 'stat', :directory? => true - File.stubs(:lstat).with(filepath).returns(stat) + Dir.mkdir(@path) + Dir.mkdir(File.join(@path, "files")) - subfiles = %w{one two} - subfiles.each do |f| - path = File.join(filepath, f) - FileTest.stubs(:exists?).with(path).returns(true) - end + basedir = File.join(@path, "files", "myfile") + Dir.mkdir(basedir) - Dir.expects(:entries).with(filepath).returns(%w{one two}) + File.open(File.join(basedir, "one"), "w") { |f| f.print "one content" } + File.open(File.join(basedir, "two"), "w") { |f| f.print "two content" } + + @module = Puppet::Module.new("mymod", @path) + Puppet::Module.expects(:find).with("mymod", "myenv").returns(@module) - @request = Puppet::Indirector::Request.new(:content, :search, "puppetmounts://host/modules/mymod/myfile", :recurse => true) + @request = Puppet::Indirector::Request.new(:content, :search, "puppet://host/modules/mymod/myfile", :recurse => true) result = @terminus.search(@request) result.should be_instance_of(Array) diff --git a/spec/integration/type/file.rb b/spec/integration/type/file.rb new file mode 100755 index 000000000..b59fa3294 --- /dev/null +++ b/spec/integration/type/file.rb @@ -0,0 +1,128 @@ +#!/usr/bin/env ruby + +require File.dirname(__FILE__) + '/../../spec_helper' + +describe Puppet::Type.type(:file), "when recursing" do + def mkdir + end + + def build_path(dir) + Dir.mkdir(dir) + File.chmod(0750, dir) + + @dirs = [dir] + @files = [] + + %w{one two}.each do |subdir| + fdir = File.join(dir, subdir) + Dir.mkdir(fdir) + File.chmod(0750, fdir) + @dirs << fdir + + %w{three}.each do |file| + ffile = File.join(fdir, file) + @files << ffile + File.open(ffile, "w") { |f| f.puts "test %s" % file } + File.chmod(0640, ffile) + end + end + end + + it "should be able to recurse over a nonexistent file" do + @path = Tempfile.new("file_integration_tests") + @path.close!() + @path = @path.path + + @file = Puppet::Type::File.create(:name => @path, :mode => 0644, :recurse => true) + + @catalog = Puppet::Node::Catalog.new + @catalog.add_resource @file + + lambda { @file.eval_generate }.should_not raise_error + end + + it "should be able to recursively set properties on existing files" do + @path = Tempfile.new("file_integration_tests") + @path.close!() + @path = @path.path + + build_path(@path) + + @file = Puppet::Type::File.create(:name => @path, :mode => 0644, :recurse => true) + + @catalog = Puppet::Node::Catalog.new + @catalog.add_resource @file + + @catalog.apply + + @dirs.each do |path| + (File.stat(path).mode & 007777).should == 0755 + end + + @files.each do |path| + (File.stat(path).mode & 007777).should == 0644 + end + end + + it "should be able to recursively make links to other files" do + source = Tempfile.new("file_link_integration_source") + source.close!() + source = source.path + + build_path(source) + + dest = Tempfile.new("file_link_integration_dest") + dest.close!() + dest = dest.path + + @file = Puppet::Type::File.create(:name => dest, :target => source, :recurse => true, :ensure => :link) + + @catalog = Puppet::Node::Catalog.new + @catalog.add_resource @file + + @catalog.apply + + @dirs.each do |path| + link_path = path.sub(source, dest) + + File.lstat(link_path).should be_directory + end + + @files.each do |path| + link_path = path.sub(source, dest) + + File.lstat(link_path).ftype.should == "link" + end + end + + it "should be able to recursively copy files" do + source = Tempfile.new("file_source_integration_source") + source.close!() + source = source.path + + build_path(source) + + dest = Tempfile.new("file_source_integration_dest") + dest.close!() + dest = dest.path + + @file = Puppet::Type::File.create(:name => dest, :source => source, :recurse => true) + + @catalog = Puppet::Node::Catalog.new + @catalog.add_resource @file + + @catalog.apply + + @dirs.each do |path| + newpath = path.sub(source, dest) + + File.lstat(newpath).should be_directory + end + + @files.each do |path| + newpath = path.sub(source, dest) + + File.lstat(newpath).ftype.should == "file" + end + end +end diff --git a/spec/shared_behaviours/file_server_terminus.rb b/spec/shared_behaviours/file_server_terminus.rb index 0230d39e8..fc5673a65 100644 --- a/spec/shared_behaviours/file_server_terminus.rb +++ b/spec/shared_behaviours/file_server_terminus.rb @@ -8,14 +8,19 @@ describe "Puppet::Indirector::FileServerTerminus", :shared => true do # the 'before' block in the including context. before do Puppet::Util::Cacher.invalidate + FileTest.stubs(:exists?).returns true FileTest.stubs(:exists?).with(Puppet[:fileserverconfig]).returns(true) - FileTest.stubs(:exists?).with("/my/mount/path").returns(true) - FileTest.stubs(:directory?).with("/my/mount/path").returns(true) - FileTest.stubs(:readable?).with("/my/mount/path").returns(true) + + @path = Tempfile.new("file_server_testing") + @path.close! + @path = @path.path + + Dir.mkdir(@path) + File.open(File.join(@path, "myfile"), "w") { |f| f.print "my content" } # Use a real mount, so the integration is a bit deeper. @mount1 = Puppet::FileServing::Configuration::Mount.new("one") - @mount1.path = "/my/mount/path" + @mount1.path = @path @parser = stub 'parser', :changed? => false @parser.stubs(:parse).returns("one" => @mount1) @@ -25,17 +30,14 @@ describe "Puppet::Indirector::FileServerTerminus", :shared => true do # Stub out the modules terminus @modules = mock 'modules terminus' - @request = Puppet::Indirector::Request.new(:indirection, :method, "puppetmounts://myhost/one/my/file") + @request = Puppet::Indirector::Request.new(:indirection, :method, "puppet://myhost/one/myfile") end it "should use the file server configuration to find files" do @modules.stubs(:find).returns(nil) @terminus.indirection.stubs(:terminus).with(:modules).returns(@modules) - path = "/my/mount/path/my/file" - FileTest.stubs(:exists?).with(path).returns(true) - FileTest.stubs(:exists?).with("/my/mount/path").returns(true) - @mount1.expects(:file).with("my/file", :node => nil).returns(path) + path = File.join(@path, "myfile") @terminus.find(@request).should be_instance_of(@test_class) end diff --git a/spec/shared_behaviours/file_serving.rb b/spec/shared_behaviours/file_serving.rb index ba01f75a1..99994b99a 100644 --- a/spec/shared_behaviours/file_serving.rb +++ b/spec/shared_behaviours/file_serving.rb @@ -6,12 +6,18 @@ describe "Puppet::FileServing::Files", :shared => true do it "should use the rest terminus when the 'puppet' URI scheme is used and a host name is present" do uri = "puppet://myhost/fakemod/my/file" - @indirection.terminus(:rest).expects(:find) + + # It appears that the mocking somehow interferes with the caching subsystem. + # This mock somehow causes another terminus to get generated. + term = @indirection.terminus(:rest) + @indirection.stubs(:terminus).with(:rest).returns term + term.expects(:find) @test_class.find(uri) end it "should use the rest terminus when the 'puppet' URI scheme is used, no host name is present, and the process name is not 'puppet'" do uri = "puppet:///fakemod/my/file" + Puppet.settings.stubs(:value).returns "foo" Puppet.settings.stubs(:value).with(:name).returns("puppetd") Puppet.settings.stubs(:value).with(:modulepath).returns("") @indirection.terminus(:rest).expects(:find) @@ -21,19 +27,9 @@ describe "Puppet::FileServing::Files", :shared => true do it "should use the file_server terminus when the 'puppet' URI scheme is used, no host name is present, and the process name is 'puppet'" do uri = "puppet:///fakemod/my/file" Puppet::Node::Environment.stubs(:new).returns(stub("env", :name => "testing")) + Puppet.settings.stubs(:value).returns "" Puppet.settings.stubs(:value).with(:name).returns("puppet") - Puppet.settings.stubs(:value).with(:modulepath, "testing").returns("") - Puppet.settings.stubs(:value).with(:modulepath).returns("") - Puppet.settings.stubs(:value).with(:libdir).returns("") Puppet.settings.stubs(:value).with(:fileserverconfig).returns("/whatever") - Puppet.settings.stubs(:value).with(:environment).returns("") - @indirection.terminus(:file_server).expects(:find) - @indirection.terminus(:file_server).stubs(:authorized?).returns(true) - @test_class.find(uri) - end - - it "should use the file_server terminus when the 'puppetmounts' URI scheme is used" do - uri = "puppetmounts:///fakemod/my/file" @indirection.terminus(:file_server).expects(:find) @indirection.terminus(:file_server).stubs(:authorized?).returns(true) @test_class.find(uri) @@ -52,7 +48,7 @@ describe "Puppet::FileServing::Files", :shared => true do end it "should use the configuration to test whether the request is allowed" do - uri = "puppetmounts:///fakemod/my/file" + uri = "fakemod/my/file" config = mock 'configuration' @indirection.terminus(:file_server).stubs(:configuration).returns config @@ -61,4 +57,3 @@ describe "Puppet::FileServing::Files", :shared => true do @test_class.find(uri, :node => "foo", :ip => "bar") end end - diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 52aed5b62..41b5e7443 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -39,3 +39,9 @@ end # have to be correctly mocked. Puppet[:confdir] = "/dev/null" Puppet[:vardir] = "/dev/null" + +# We need this because the RAL uses 'should' as a method. This +# allows us the same behaviour but with a different method name. +class Object + alias :must :should +end diff --git a/spec/unit/file_serving/file_base.rb b/spec/unit/file_serving/base.rb index ded6ae4a8..6a76d81e9 100755 --- a/spec/unit/file_serving/file_base.rb +++ b/spec/unit/file_serving/base.rb @@ -2,67 +2,66 @@ require File.dirname(__FILE__) + '/../../spec_helper' -require 'puppet/file_serving/file_base' +require 'puppet/file_serving/base' -describe Puppet::FileServing::FileBase do - it "should accept a key in the form of a URI" do - Puppet::FileServing::FileBase.new("puppet://host/module/dir/file").key.should == "puppet://host/module/dir/file" +describe Puppet::FileServing::Base do + it "should accept a path" do + Puppet::FileServing::Base.new("/module/dir/file").path.should == "/module/dir/file" + end + + it "should require that paths be fully qualified" do + lambda { Puppet::FileServing::Base.new("module/dir/file") }.should raise_error(ArgumentError) end it "should allow specification of whether links should be managed" do - Puppet::FileServing::FileBase.new("puppet://host/module/dir/file", :links => :manage).links.should == :manage + Puppet::FileServing::Base.new("/module/dir/file", :links => :manage).links.should == :manage + end + + it "should have a :source attribute" do + file = Puppet::FileServing::Base.new("/module/dir/file") + file.should respond_to(:source) + file.should respond_to(:source=) end it "should consider :ignore links equivalent to :manage links" do - Puppet::FileServing::FileBase.new("puppet://host/module/dir/file", :links => :ignore).links.should == :manage + Puppet::FileServing::Base.new("/module/dir/file", :links => :ignore).links.should == :manage end it "should fail if :links is set to anything other than :manage, :follow, or :ignore" do - proc { Puppet::FileServing::FileBase.new("puppet://host/module/dir/file", :links => :else) }.should raise_error(ArgumentError) + proc { Puppet::FileServing::Base.new("/module/dir/file", :links => :else) }.should raise_error(ArgumentError) end it "should default to :manage for :links" do - Puppet::FileServing::FileBase.new("puppet://host/module/dir/file").links.should == :manage + Puppet::FileServing::Base.new("/module/dir/file").links.should == :manage end it "should allow specification of a path" do FileTest.stubs(:exists?).returns(true) - Puppet::FileServing::FileBase.new("puppet://host/module/dir/file", :path => "/my/file").path.should == "/my/file" + Puppet::FileServing::Base.new("/module/dir/file", :path => "/my/file").path.should == "/my/file" end it "should allow specification of a relative path" do FileTest.stubs(:exists?).returns(true) - Puppet::FileServing::FileBase.new("puppet://host/module/dir/file", :relative_path => "my/file").relative_path.should == "my/file" + Puppet::FileServing::Base.new("/module/dir/file", :relative_path => "my/file").relative_path.should == "my/file" end it "should have a means of determining if the file exists" do - Puppet::FileServing::FileBase.new("blah").should respond_to(:exist?) + Puppet::FileServing::Base.new("/blah").should respond_to(:exist?) end it "should correctly indicate if the file is present" do File.expects(:lstat).with("/my/file").returns(mock("stat")) - Puppet::FileServing::FileBase.new("blah", :path => "/my/file").exist?.should be_true + Puppet::FileServing::Base.new("/my/file").exist?.should be_true end - it "should correctly indicate if the file is asbsent" do + it "should correctly indicate if the file is absent" do File.expects(:lstat).with("/my/file").raises RuntimeError - Puppet::FileServing::FileBase.new("blah", :path => "/my/file").exist?.should be_false - end - - describe "when setting the base path" do - before do - @file = Puppet::FileServing::FileBase.new("puppet://host/module/dir/file") - end - - it "should require that the base path be fully qualified" do - FileTest.stubs(:exists?).returns(true) - proc { @file.path = "unqualified/file" }.should raise_error(ArgumentError) - end + Puppet::FileServing::Base.new("/my/file").exist?.should be_false end describe "when setting the relative path" do it "should require that the relative path be unqualified" do - @file = Puppet::FileServing::FileBase.new("puppet://host/module/dir/file") + @file = Puppet::FileServing::Base.new("/module/dir/file") FileTest.stubs(:exists?).returns(true) proc { @file.relative_path = "/qualified/file" }.should raise_error(ArgumentError) end @@ -70,7 +69,7 @@ describe Puppet::FileServing::FileBase do describe "when determining the full file path" do before do - @file = Puppet::FileServing::FileBase.new("mykey", :path => "/this/file") + @file = Puppet::FileServing::Base.new("/this/file") end it "should return the path if there is no relative path" do @@ -82,20 +81,20 @@ describe Puppet::FileServing::FileBase do @file.full_path.should == "/this/file" end + it "should return the path if the relative_path is set to '.'" do + @file.relative_path = "." + @file.full_path.should == "/this/file" + end + it "should return the path joined with the relative path if there is a relative path and it is not set to '/' or ''" do @file.relative_path = "not/qualified" @file.full_path.should == "/this/file/not/qualified" end - - it "should should fail if there is no path set" do - @file = Puppet::FileServing::FileBase.new("not/qualified") - proc { @file.full_path }.should raise_error(ArgumentError) - end end describe "when stat'ing files" do before do - @file = Puppet::FileServing::FileBase.new("mykey", :path => "/this/file") + @file = Puppet::FileServing::Base.new("/this/file") end it "should stat the file's full path" do diff --git a/spec/unit/file_serving/configuration.rb b/spec/unit/file_serving/configuration.rb index d51fa70b2..741e3bc1d 100755 --- a/spec/unit/file_serving/configuration.rb +++ b/spec/unit/file_serving/configuration.rb @@ -35,7 +35,7 @@ describe Puppet::FileServing::Configuration do Puppet::Util::Cacher.invalidate end - describe Puppet::FileServing::Configuration, " when initializing" do + describe Puppet::FileServing::Configuration, "when initializing" do it "should work without a configuration file" do FileTest.stubs(:exists?).with(@path).returns(false) @@ -55,7 +55,7 @@ describe Puppet::FileServing::Configuration do end end - describe Puppet::FileServing::Configuration, " when parsing the configuration file" do + describe Puppet::FileServing::Configuration, "when parsing the configuration file" do before do FileTest.stubs(:exists?).with(@path).returns(true) @@ -95,7 +95,7 @@ describe Puppet::FileServing::Configuration do end end - describe Puppet::FileServing::Configuration, " when finding files" do + describe Puppet::FileServing::Configuration, "when finding files" do before do @parser = mock 'parser' @@ -111,55 +111,60 @@ describe Puppet::FileServing::Configuration do @config = Puppet::FileServing::Configuration.create end - it "should fail if the uri does not match a leading slash followed by a valid mount name" do + it "should fail if the uri has a leading slash" do @parser.expects(:parse).returns(@mounts) - proc { @config.file_path("something") }.should raise_error(ArgumentError) + proc { @config.file_path("/something") }.should raise_error(ArgumentError) + end + + it "should fail if the uri does not start with a valid mount name" do + @parser.expects(:parse).returns(@mounts) + proc { @config.file_path("some.thing") }.should raise_error(ArgumentError) end it "should use the first term after the first slash for the mount name" do @parser.expects(:parse).returns(@mounts) FileTest.stubs(:exists?).returns(true) @mount1.expects(:file) - @config.file_path("/one") + @config.file_path("one") end it "should use the remainder of the URI after the mount name as the file name" do @parser.expects(:parse).returns(@mounts) @mount1.expects(:file).with("something/else", {}) FileTest.stubs(:exists?).returns(true) - @config.file_path("/one/something/else") + @config.file_path("one/something/else") end it "should treat a bare name as a mount and no relative file" do @parser.expects(:parse).returns(@mounts) @mount1.expects(:file).with(nil, {}) FileTest.stubs(:exists?).returns(true) - @config.file_path("/one") + @config.file_path("one") end it "should treat a name with a trailing slash equivalently to a name with no trailing slash" do @parser.expects(:parse).returns(@mounts) @mount1.expects(:file).with(nil, {}) FileTest.stubs(:exists?).returns(true) - @config.file_path("/one/") + @config.file_path("one/") end it "should return nil if the mount cannot be found" do @parser.expects(:changed?).returns(true) @parser.expects(:parse).returns({}) - @config.file_path("/one/something").should be_nil + @config.file_path("one/something").should be_nil end it "should return nil if the mount does not contain the file" do @parser.expects(:parse).returns(@mounts) @mount1.expects(:file).with("something/else", {}).returns(nil) - @config.file_path("/one/something/else").should be_nil + @config.file_path("one/something/else").should be_nil end it "should return the fully qualified path if the mount exists" do @parser.expects(:parse).returns(@mounts) @mount1.expects(:file).with("something/else", {}).returns("/full/path") - @config.file_path("/one/something/else").should == "/full/path" + @config.file_path("one/something/else").should == "/full/path" end it "should reparse the configuration file when it has changed" do @@ -167,15 +172,15 @@ describe Puppet::FileServing::Configuration do @parser.expects(:changed?).returns(true) @parser.expects(:parse).returns(@mounts) FileTest.stubs(:exists?).returns(true) - @config.file_path("/one/something") + @config.file_path("one/something") @parser.expects(:changed?).returns(true) @parser.expects(:parse).returns({}) - @config.file_path("/one/something").should be_nil + @config.file_path("one/something").should be_nil end end - describe Puppet::FileServing::Configuration, " when checking authorization" do + describe Puppet::FileServing::Configuration, "when checking authorization" do before do @parser = mock 'parser' @@ -193,32 +198,32 @@ describe Puppet::FileServing::Configuration do end it "should return false if the mount cannot be found" do - @config.authorized?("/nope/my/file").should be_false + @config.authorized?("nope/my/file").should be_false end it "should use the mount to determine authorization" do @mount1.expects(:allowed?) - @config.authorized?("/one/my/file") + @config.authorized?("one/my/file") end it "should pass the client's name to the mount if provided" do @mount1.expects(:allowed?).with("myhost", nil) - @config.authorized?("/one/my/file", :node => "myhost") + @config.authorized?("one/my/file", :node => "myhost") end it "should pass the client's IP to the mount if provided" do @mount1.expects(:allowed?).with("myhost", "myip") - @config.authorized?("/one/my/file", :node => "myhost", :ipaddress => "myip") + @config.authorized?("one/my/file", :node => "myhost", :ipaddress => "myip") end it "should return true if the mount allows the client" do @mount1.expects(:allowed?).returns(true) - @config.authorized?("/one/my/file").should be_true + @config.authorized?("one/my/file").should be_true end it "should return false if the mount denies the client" do @mount1.expects(:allowed?).returns(false) - @config.authorized?("/one/my/file").should be_false + @config.authorized?("one/my/file").should be_false end end end diff --git a/spec/unit/file_serving/content.rb b/spec/unit/file_serving/content.rb index 89d786295..eacaff89f 100755 --- a/spec/unit/file_serving/content.rb +++ b/spec/unit/file_serving/content.rb @@ -5,8 +5,8 @@ require File.dirname(__FILE__) + '/../../spec_helper' require 'puppet/file_serving/content' describe Puppet::FileServing::Content do - it "should should be a subclass of FileBase" do - Puppet::FileServing::Content.superclass.should equal(Puppet::FileServing::FileBase) + it "should should be a subclass of Base" do + Puppet::FileServing::Content.superclass.should equal(Puppet::FileServing::Base) end it "should indirect file_content" do @@ -16,12 +16,66 @@ describe Puppet::FileServing::Content do it "should should include the IndirectionHooks module in its indirection" do Puppet::FileServing::Content.indirection.metaclass.included_modules.should include(Puppet::FileServing::IndirectionHooks) end + + it "should only support the raw format" do + Puppet::FileServing::Content.supported_formats.should == [:raw] + end + + it "should have a method for collecting its attributes" do + Puppet::FileServing::Content.new("/path").should respond_to(:collect) + end + + it "should retrieve and store its contents when its attributes are collected if the file is a normal file" do + content = Puppet::FileServing::Content.new("/path") + + result = "foo" + File.stubs(:lstat).returns(stub("stat", :ftype => "file")) + File.expects(:read).with("/path").returns result + content.collect + + content.instance_variable_get("@content").should_not be_nil + end + + it "should not attempt to retrieve its contents if the file is a directory" do + content = Puppet::FileServing::Content.new("/path") + + result = "foo" + File.stubs(:lstat).returns(stub("stat", :ftype => "directory")) + File.expects(:read).with("/path").never + content.collect + + content.instance_variable_get("@content").should be_nil + end + + it "should have a method for setting its content" do + content = Puppet::FileServing::Content.new("/path") + content.should respond_to(:content=) + end + + it "should make content available when set externally" do + content = Puppet::FileServing::Content.new("/path") + content.content = "foo/bar" + content.content.should == "foo/bar" + end + + it "should be able to create a content instance from raw file contents" do + Puppet::FileServing::Content.should respond_to(:from_raw) + end + + it "should create an instance with a fake file name and correct content when converting from raw" do + instance = mock 'instance' + Puppet::FileServing::Content.expects(:new).with("/this/is/a/fake/path").returns instance + + instance.expects(:content=).with "foo/bar" + + Puppet::FileServing::Content.from_raw("foo/bar").should equal(instance) + end end -describe Puppet::FileServing::Content, " when returning the contents" do +describe Puppet::FileServing::Content, "when returning the contents" do before do - @path = "/my/base" - @content = Puppet::FileServing::Content.new("sub/path", :links => :follow, :path => @path) + @path = "/my/path" + @content = Puppet::FileServing::Content.new(@path, :links => :follow) end it "should fail if the file is a symlink and links are set to :manage" do @@ -44,28 +98,13 @@ describe Puppet::FileServing::Content, " when returning the contents" do File.expects(:read).with(@path).returns(:mycontent) @content.content.should == :mycontent end -end - -describe Puppet::FileServing::Content, " when converting to yaml" do - it "should fail if no path has been set" do - @content = Puppet::FileServing::Content.new("some/key") - proc { @content.to_yaml }.should raise_error(ArgumentError) - end - it "should return the file contents" do - @content = Puppet::FileServing::Content.new("some/path") - @content.path = "/base/path" - @content.expects(:content).returns(:content) - @content.to_yaml.should == :content - end -end + it "should cache the returned contents" do + File.expects(:stat).with(@path).returns stub("stat", :ftype => "file") + File.expects(:read).with(@path).returns(:mycontent) + @content.content -describe Puppet::FileServing::Content, " when converting from yaml" do - # LAK:FIXME This isn't in the right place, but we need some kind of - # control somewhere that requires that all REST connections only pull - # from the file-server, thus guaranteeing they go through our authorization - # hook. - it "should set the URI scheme to 'puppetmounts'" do - pending "We need to figure out where this should be" + # The second run would throw a failure if the content weren't being cached. + @content.content end end diff --git a/spec/unit/file_serving/fileset.rb b/spec/unit/file_serving/fileset.rb index 2cd3e83dd..f95271050 100755 --- a/spec/unit/file_serving/fileset.rb +++ b/spec/unit/file_serving/fileset.rb @@ -149,6 +149,13 @@ describe Puppet::FileServing::Fileset, " when recursing" do @fileset.files.sort.should == @files.sort end + it "should function if the :ignore value provided is nil" do + mock_dir_structure(@path) + @fileset.recurse = true + @fileset.ignore = nil + lambda { @fileset.files }.should_not raise_error + end + it "should ignore files that match a single pattern in the ignore list" do mock_dir_structure(@path) @fileset.recurse = true diff --git a/spec/unit/file_serving/indirection_hooks.rb b/spec/unit/file_serving/indirection_hooks.rb index 160e3ff0a..83ff5848f 100755 --- a/spec/unit/file_serving/indirection_hooks.rb +++ b/spec/unit/file_serving/indirection_hooks.rb @@ -12,113 +12,113 @@ describe Puppet::FileServing::IndirectionHooks do @object = Object.new @object.extend(Puppet::FileServing::IndirectionHooks) - @request = stub 'request', :key => "http://myhost/blah", :options => {:node => "whatever"} + @request = stub 'request', :key => "mymod/myfile", :options => {:node => "whatever"}, :server => nil, :protocol => nil end describe "when being used to select termini" do - it "should escape the key before parsing" do - uri = stub 'uri', :scheme => "puppet", :host => "blah", :path => "/something" - URI.expects(:escape).with("http://myhost/blah").returns("escaped_blah") - URI.expects(:parse).with("escaped_blah").returns(uri) - @object.select_terminus(@request) + it "should return :file if the request key is fully qualified" do + @request.expects(:key).returns "#{File::SEPARATOR}foo" + @object.select_terminus(@request).should == :file end - it "should use the URI class to parse the key" do - uri = stub 'uri', :scheme => "puppet", :host => "blah", :path => "/something" - URI.expects(:parse).with("http://myhost/blah").returns(uri) - @object.select_terminus @request + it "should return :file if the URI protocol is set to 'file'" do + @request.expects(:protocol).returns "file" + @object.select_terminus(@request).should == :file end - it "should choose :rest when the protocol is 'puppet'" do - @request.stubs(:key).returns "puppet://host/module/file" - @object.select_terminus(@request).should == :rest + it "should fail when a protocol other than :puppet or :file is used" do + @request.stubs(:protocol).returns "http" + proc { @object.select_terminus(@request) }.should raise_error(ArgumentError) end - it "should choose :file_server when the protocol is 'puppetmounts' and the mount name is not 'modules'" do - modules = mock 'modules' - @object.stubs(:terminus).with(:modules).returns(modules) - modules.stubs(:find_module).returns(nil) + describe "and the protocol is 'puppet'" do + before do + @request.stubs(:protocol).returns "puppet" + end - @request.stubs(:key).returns "puppetmounts://host/notmodules/file" + it "should choose :rest when a server is specified" do + @request.stubs(:protocol).returns "puppet" + @request.expects(:server).returns "foo" + @object.select_terminus(@request).should == :rest + end - @object.select_terminus(@request).should == :file_server - end + # This is so a given file location works when bootstrapping with no server. + it "should choose :rest when the Settings name isn't 'puppet'" do + @request.stubs(:protocol).returns "puppet" + @request.stubs(:server).returns "foo" + Puppet.settings.stubs(:value).with(:name).returns "foo" + @object.select_terminus(@request).should == :rest + end - it "should choose :file_server when no server name is provided, the process name is 'puppet', and the mount name is not 'modules'" do - modules = mock 'modules' - @object.stubs(:terminus).with(:modules).returns(modules) - modules.stubs(:find_module).returns(nil) + it "should not choose :rest when the settings name is 'puppet' and no server is specified" do + modules = mock 'modules' - Puppet.settings.expects(:value).with(:name).returns("puppet") - @request.stubs(:key).returns "puppet:///notmodules/file" - @object.select_terminus(@request).should == :file_server - end + @object.stubs(:terminus).with(:modules).returns(modules) + modules.stubs(:find_module).with("mymod", @request.options[:node]).returns nil - it "should choose :modules if it would normally choose :file_server but the mount name is 'modules'" do - @request.stubs(:key).returns "puppetmounts://host/modules/mymod/file" - @object.select_terminus(@request).should == :modules + @request.expects(:protocol).returns "puppet" + @request.expects(:server).returns nil + Puppet.settings.expects(:value).with(:name).returns "puppet" + @object.select_terminus(@request).should_not == :rest + end end - it "should choose :modules if it would normally choose :file_server but a module exists with the mount name" do - modules = mock 'modules' + describe "and the terminus is not :rest or :file" do + before do + @request.stubs(:protocol).returns nil + end - @object.expects(:terminus).with(:modules).returns(modules) - modules.expects(:find_module).with("mymod", @request.options[:node]).returns(:thing) + it "should choose :modules if the mount name is 'modules'" do + @request.stubs(:key).returns "modules/mymod/file" + @object.select_terminus(@request).should == :modules + end - @request.stubs(:key).returns "puppetmounts://host/mymod/file" - @object.select_terminus(@request).should == :modules - end + it "should choose :modules and provide a deprecation notice if a module exists with the mount name" do + modules = mock 'modules' - it "should choose :rest when no server name is provided and the process name is not 'puppet'" do - Puppet.settings.expects(:value).with(:name).returns("puppetd") - @request.stubs(:key).returns "puppet:///module/file" - @object.select_terminus(@request).should == :rest - end + @object.expects(:terminus).with(:modules).returns(modules) + modules.expects(:find_module).with("mymod", @request.options[:node]).returns(:thing) - it "should choose :file when the protocol is 'file'" do - @request.stubs(:key).returns "file://host/module/file" - @object.select_terminus(@request).should == :file - end + Puppet.expects(:warning) - it "should choose :file when the URI is a normal path name" do - @request.stubs(:key).returns "/module/file" - @object.select_terminus(@request).should == :file - end + @request.stubs(:key).returns "mymod/file" + @object.select_terminus(@request).should == :modules + end - # This is so that we only choose modules over mounts, not file - it "should choose :file when the protocol is 'file' and the fully qualified path starts with '/modules'" do - @request.stubs(:key).returns "/module/file" - @object.select_terminus(@request).should == :file - end + it "should choose :file_server if the mount name is not 'modules' nor matches a module name" do + modules = mock 'modules' + @object.stubs(:terminus).with(:modules).returns(modules) + modules.stubs(:find_module).returns(nil) - it "should fail when a protocol other than :puppet, :file, or :puppetmounts is used" do - @request.stubs(:key).returns "http:///module/file" - proc { @object.select_terminus(@request) }.should raise_error(ArgumentError) + @request.stubs(:key).returns "notmodules/file" + + @object.select_terminus(@request).should == :file_server + end end - end - describe "when looking for a module whose name matches the mount name" do - before do - @modules = mock 'modules' - @object.stubs(:terminus).with(:modules).returns(@modules) + describe "when looking for a module whose name matches the mount name" do + before do + @modules = mock 'modules' + @object.stubs(:terminus).with(:modules).returns(@modules) - @request.stubs(:key).returns "puppetmounts://host/mymod/file" - end + @request.stubs(:key).returns "mymod/file" + end - it "should use the modules terminus to look up the module" do - @modules.expects(:find_module).with("mymod", @request.options[:node]) - @object.select_terminus @request - end + it "should use the modules terminus to look up the module" do + @modules.expects(:find_module).with("mymod", @request.options[:node]) + @object.select_terminus @request + end - it "should pass the node name to the modules terminus" do - @modules.expects(:find_module).with("mymod", @request.options[:node]) - @object.select_terminus @request - end + it "should pass the node name to the modules terminus" do + @modules.expects(:find_module).with("mymod", @request.options[:node]) + @object.select_terminus @request + end - it "should log a deprecation warning if a module is found" do - @modules.expects(:find_module).with("mymod", @request.options[:node]).returns(:something) - Puppet.expects(:warning) - @object.select_terminus @request + it "should log a deprecation warning if a module is found" do + @modules.expects(:find_module).with("mymod", @request.options[:node]).returns(:something) + Puppet.expects(:warning) + @object.select_terminus @request + end end end end diff --git a/spec/unit/file_serving/metadata.rb b/spec/unit/file_serving/metadata.rb index 9743370c1..768a7c56d 100755 --- a/spec/unit/file_serving/metadata.rb +++ b/spec/unit/file_serving/metadata.rb @@ -5,8 +5,8 @@ require File.dirname(__FILE__) + '/../../spec_helper' require 'puppet/file_serving/metadata' describe Puppet::FileServing::Metadata do - it "should should be a subclass of FileBase" do - Puppet::FileServing::Metadata.superclass.should equal(Puppet::FileServing::FileBase) + it "should should be a subclass of Base" do + Puppet::FileServing::Metadata.superclass.should equal(Puppet::FileServing::Base) end it "should indirect file_metadata" do @@ -16,39 +16,40 @@ describe Puppet::FileServing::Metadata do it "should should include the IndirectionHooks module in its indirection" do Puppet::FileServing::Metadata.indirection.metaclass.included_modules.should include(Puppet::FileServing::IndirectionHooks) end + + it "should have a method that triggers attribute collection" do + Puppet::FileServing::Metadata.new("/foo/bar").should respond_to(:collect) + end end describe Puppet::FileServing::Metadata, " when finding the file to use for setting attributes" do before do - @metadata = Puppet::FileServing::Metadata.new("my/path") - - @full = "/base/path/my/path" - - @metadata.path = @full + @path = "/my/path" + @metadata = Puppet::FileServing::Metadata.new(@path) # Use a link because it's easier to test -- no checksumming @stat = stub "stat", :uid => 10, :gid => 20, :mode => 0755, :ftype => "link" end it "should accept a base path path to which the file should be relative" do - File.expects(:lstat).with(@full).returns @stat - File.expects(:readlink).with(@full).returns "/what/ever" - @metadata.collect_attributes + File.expects(:lstat).with(@path).returns @stat + File.expects(:readlink).with(@path).returns "/what/ever" + @metadata.collect end it "should use the set base path if one is not provided" do - File.expects(:lstat).with(@full).returns @stat - File.expects(:readlink).with(@full).returns "/what/ever" - @metadata.collect_attributes() + File.expects(:lstat).with(@path).returns @stat + File.expects(:readlink).with(@path).returns "/what/ever" + @metadata.collect() end it "should fail if a base path is neither set nor provided" do - proc { @metadata.collect_attributes() }.should raise_error(Errno::ENOENT) + proc { @metadata.collect() }.should raise_error(Errno::ENOENT) end it "should raise an exception if the file does not exist" do - File.expects(:lstat).with(@full).raises(Errno::ENOENT) - proc { @metadata.collect_attributes()}.should raise_error(Errno::ENOENT) + File.expects(:lstat).with(@path).raises(Errno::ENOENT) + proc { @metadata.collect()}.should raise_error(Errno::ENOENT) end end @@ -59,9 +60,9 @@ describe Puppet::FileServing::Metadata, " when collecting attributes" do @stat = stub 'stat', :uid => 10, :gid => 20, :mode => 33261, :ftype => "file" File.stubs(:lstat).returns(@stat) @checksum = Digest::MD5.hexdigest("some content\n") - @metadata = Puppet::FileServing::Metadata.new("file", :path => "/my/file") + @metadata = Puppet::FileServing::Metadata.new("/my/file") @metadata.stubs(:md5_file).returns(@checksum) - @metadata.collect_attributes + @metadata.collect end it "should be able to produce xmlrpc-style attribute information" do @@ -109,7 +110,7 @@ describe Puppet::FileServing::Metadata, " when collecting attributes" do @stat.stubs(:ftype).returns("directory") @time = Time.now @metadata.expects(:ctime_file).returns(@time) - @metadata.collect_attributes + @metadata.collect end it "should only use checksums of type 'ctime' for directories" do @@ -125,7 +126,7 @@ describe Puppet::FileServing::Metadata, " when collecting attributes" do before do @stat.stubs(:ftype).returns("link") File.expects(:readlink).with("/my/file").returns("/path/to/link") - @metadata.collect_attributes + @metadata.collect end it "should read links instead of returning their checksums" do @@ -140,32 +141,22 @@ end describe Puppet::FileServing::Metadata, " when pointing to a link" do it "should store the destination of the link in :destination if links are :manage" do - file = Puppet::FileServing::Metadata.new("mykey", :links => :manage, :path => "/base/path/my/file") + file = Puppet::FileServing::Metadata.new("/base/path/my/file", :links => :manage) File.expects(:lstat).with("/base/path/my/file").returns stub("stat", :uid => 1, :gid => 2, :ftype => "link", :mode => 0755) File.expects(:readlink).with("/base/path/my/file").returns "/some/other/path" - file.collect_attributes + file.collect file.destination.should == "/some/other/path" end it "should not collect the checksum" do - file = Puppet::FileServing::Metadata.new("my/file", :links => :manage, :path => "/base/path/my/file") + file = Puppet::FileServing::Metadata.new("/base/path/my/file", :links => :manage) File.expects(:lstat).with("/base/path/my/file").returns stub("stat", :uid => 1, :gid => 2, :ftype => "link", :mode => 0755) File.expects(:readlink).with("/base/path/my/file").returns "/some/other/path" - file.collect_attributes + file.collect file.checksum.should be_nil end end - -describe Puppet::FileServing::Metadata, " when converting from yaml" do - # LAK:FIXME This isn't in the right place, but we need some kind of - # control somewhere that requires that all REST connections only pull - # from the file-server, thus guaranteeing they go through our authorization - # hook. - it "should set the URI scheme to 'puppetmounts'" do - pending "We need to figure out where this should be" - end -end diff --git a/spec/unit/file_serving/terminus_helper.rb b/spec/unit/file_serving/terminus_helper.rb index 763ce9eb0..7f08aeb7e 100755 --- a/spec/unit/file_serving/terminus_helper.rb +++ b/spec/unit/file_serving/terminus_helper.rb @@ -31,46 +31,73 @@ describe Puppet::FileServing::TerminusHelper do @helper.path2instances(@request, "/my/file") end + it "should pass :recurse, :ignore, and :links settings on to the fileset if present with the keys stored as strings" do + fileset = mock 'fileset', :files => [] + Puppet::FileServing::Fileset.expects(:new).with("/my/file", :links => :a, :ignore => :b, :recurse => :c).returns(fileset) + @request.stubs(:options).returns("links" => :a, "ignore" => :b, "recurse" => :c) + @helper.path2instances(@request, "/my/file") + end + + it "should convert the string 'true' to the boolean true when setting options" do + fileset = mock 'fileset', :files => [] + Puppet::FileServing::Fileset.expects(:new).with("/my/file", :recurse => true).returns(fileset) + @request.stubs(:options).returns(:recurse => "true") + @helper.path2instances(@request, "/my/file") + end + + it "should convert the string 'false' to the boolean false when setting options" do + fileset = mock 'fileset', :files => [] + Puppet::FileServing::Fileset.expects(:new).with("/my/file", :recurse => false).returns(fileset) + @request.stubs(:options).returns(:recurse => "false") + @helper.path2instances(@request, "/my/file") + end + describe "when creating instances" do before do @request.stubs(:key).returns "puppet://host/mount/dir" + @one = stub 'one', :links= => nil, :collect => nil + @two = stub 'two', :links= => nil, :collect => nil + @fileset = mock 'fileset', :files => %w{one two} Puppet::FileServing::Fileset.expects(:new).returns(@fileset) end it "should create an instance of the model for each path returned by the fileset" do - @model.expects(:new).returns(:one) - @model.expects(:new).returns(:two) + @model.expects(:new).returns(@one) + @model.expects(:new).returns(@two) @helper.path2instances(@request, "/my/file").length.should == 2 end - it "should set each instance's key to be the original key plus the file-specific path" do - @model.expects(:new).with { |key, options| key == @request.key + "/one" }.returns(:one) - @model.expects(:new).with { |key, options| key == @request.key + "/two" }.returns(:two) - @helper.path2instances(@request, "/my/file") - end - it "should set each returned instance's path to the original path" do - @model.expects(:new).with { |key, options| options[:path] == "/my/file" }.returns(:one) - @model.expects(:new).with { |key, options| options[:path] == "/my/file" }.returns(:two) + @model.expects(:new).with { |key, options| key == "/my/file" }.returns(@one) + @model.expects(:new).with { |key, options| key == "/my/file" }.returns(@two) @helper.path2instances(@request, "/my/file") end it "should set each returned instance's relative path to the file-specific path" do - @model.expects(:new).with { |key, options| options[:relative_path] == "one" }.returns(:one) - @model.expects(:new).with { |key, options| options[:relative_path] == "two" }.returns(:two) + @model.expects(:new).with { |key, options| options[:relative_path] == "one" }.returns(@one) + @model.expects(:new).with { |key, options| options[:relative_path] == "two" }.returns(@two) @helper.path2instances(@request, "/my/file") end it "should set the links value on each instance if one is provided" do - one = mock 'one', :links= => :manage - two = mock 'two', :links= => :manage - @model.expects(:new).returns(one) - @model.expects(:new).returns(two) + @one.expects(:links=).with :manage + @two.expects(:links=).with :manage + @model.expects(:new).returns(@one) + @model.expects(:new).returns(@two) @request.options[:links] = :manage @helper.path2instances(@request, "/my/file") end + + it "should collect the instance's attributes" do + @one.expects(:collect) + @two.expects(:collect) + @model.expects(:new).returns(@one) + @model.expects(:new).returns(@two) + + @helper.path2instances(@request, "/my/file") + end end end diff --git a/spec/unit/indirector/direct_file_server.rb b/spec/unit/indirector/direct_file_server.rb index 0753f1bbe..e32fe6678 100755 --- a/spec/unit/indirector/direct_file_server.rb +++ b/spec/unit/indirector/direct_file_server.rb @@ -24,7 +24,7 @@ describe Puppet::Indirector::DirectFileServer do @uri = "file:///my/local" - @request = stub 'request', :key => @uri, :options => {} + @request = Puppet::Indirector::Request.new(:mytype, :find, @uri) end describe Puppet::Indirector::DirectFileServer, "when finding a single file" do @@ -45,17 +45,12 @@ describe Puppet::Indirector::DirectFileServer do before do @data = mock 'content' - @data.stubs(:collect_attributes) + @data.stubs(:collect) FileTest.expects(:exists?).with("/my/local").returns true end - it "should create the Content instance with the original key as the key" do - @model.expects(:new).with { |key, options| key == @uri }.returns(@data) - @server.find(@request) - end - it "should pass the full path to the instance" do - @model.expects(:new).with { |key, options| options[:path] == "/my/local" }.returns(@data) + @model.expects(:new).with { |key, options| key == "/my/local" }.returns(@data) @server.find(@request) end diff --git a/spec/unit/indirector/file_metadata/file.rb b/spec/unit/indirector/file_metadata/file.rb index 9474620c7..a096d469d 100755 --- a/spec/unit/indirector/file_metadata/file.rb +++ b/spec/unit/indirector/file_metadata/file.rb @@ -21,14 +21,14 @@ describe Puppet::Indirector::FileMetadata::File do @metadata = Puppet::Indirector::FileMetadata::File.new @uri = "file:///my/local" @data = mock 'metadata' - @data.stubs(:collect_attributes) + @data.stubs(:collect) FileTest.expects(:exists?).with("/my/local").returns true - @request = stub 'request', :key => @uri, :options => {} + @request = Puppet::Indirector::Request.new(:file_metadata, :find, @uri) end it "should collect its attributes when a file is found" do - @data.expects(:collect_attributes) + @data.expects(:collect) Puppet::FileServing::Metadata.expects(:new).returns(@data) @metadata.find(@request).should == @data @@ -40,12 +40,12 @@ describe Puppet::Indirector::FileMetadata::File do @metadata = Puppet::Indirector::FileMetadata::File.new @uri = "file:///my/local" - @request = stub 'request', :key => @uri, :options => {} + @request = Puppet::Indirector::Request.new(:file_metadata, :find, @uri) end it "should collect the attributes of the instances returned" do FileTest.expects(:exists?).with("/my/local").returns true - @metadata.expects(:path2instances).returns( [mock("one", :collect_attributes => nil), mock("two", :collect_attributes => nil)] ) + @metadata.expects(:path2instances).returns( [mock("one", :collect => nil), mock("two", :collect => nil)] ) @metadata.search(@request) end end diff --git a/spec/unit/indirector/file_metadata/modules.rb b/spec/unit/indirector/file_metadata/modules.rb index 3905a49ad..7e5113df5 100755 --- a/spec/unit/indirector/file_metadata/modules.rb +++ b/spec/unit/indirector/file_metadata/modules.rb @@ -24,7 +24,7 @@ describe Puppet::Indirector::FileMetadata::Modules, " when finding metadata" do @module = Puppet::Module.new("mymod", "/path/to") @finder.stubs(:find_module).returns(@module) - @request = Puppet::Indirector::Request.new(:metadata, :find, "puppetmounts://hostname/modules/mymod/my/file") + @request = Puppet::Indirector::Request.new(:metadata, :find, "puppet://hostname/modules/mymod/my/file") end it "should return nil if the file is not found" do @@ -36,7 +36,7 @@ describe Puppet::Indirector::FileMetadata::Modules, " when finding metadata" do FileTest.expects(:exists?).with("/path/to/files/my/file").returns true instance = mock 'metadta' Puppet::FileServing::Metadata.expects(:new).returns instance - instance.expects :collect_attributes + instance.expects :collect @finder.find(@request) end end diff --git a/spec/unit/indirector/file_server.rb b/spec/unit/indirector/file_server.rb index ba951737a..e17deecf9 100755 --- a/spec/unit/indirector/file_server.rb +++ b/spec/unit/indirector/file_server.rb @@ -24,7 +24,7 @@ describe Puppet::Indirector::FileServer do @file_server = @file_server_class.new - @uri = "puppetmounts://host/my/local/file" + @uri = "puppet://host/my/local/file" @configuration = mock 'configuration' Puppet::FileServing::Configuration.stubs(:create).returns(@configuration) @@ -34,46 +34,42 @@ describe Puppet::Indirector::FileServer do describe Puppet::Indirector::FileServer, " when finding files" do it "should use the path portion of the URI as the file name" do - @configuration.expects(:file_path).with("/my/local/file", :node => nil) + @configuration.expects(:file_path).with("my/local/file", :node => nil) @file_server.find(@request) end it "should use the FileServing configuration to convert the file name to a fully qualified path" do - @configuration.expects(:file_path).with("/my/local/file", :node => nil) + @configuration.expects(:file_path).with("my/local/file", :node => nil) @file_server.find(@request) end it "should pass the node name to the FileServing configuration if one is provided" do - @configuration.expects(:file_path).with("/my/local/file", :node => "testing") + @configuration.expects(:file_path).with("my/local/file", :node => "testing") @request.node = "testing" @file_server.find(@request) end it "should return nil if no fully qualified path is found" do - @configuration.expects(:file_path).with("/my/local/file", :node => nil).returns(nil) + @configuration.expects(:file_path).with("my/local/file", :node => nil).returns(nil) @file_server.find(@request).should be_nil end it "should return an instance of the model created with the full path if a file is found" do - @configuration.expects(:file_path).with("/my/local/file", :node => nil).returns("/some/file") - @model.expects(:new).returns(:myinstance) - @file_server.find(@request).should == :myinstance + @configuration.expects(:file_path).with("my/local/file", :node => nil).returns("/some/file") + instance = stub("instance", :collect => nil) + @model.expects(:new).returns instance + @file_server.find(@request).should equal(instance) end end describe Puppet::Indirector::FileServer, " when returning instances" do before :each do - @configuration.expects(:file_path).with("/my/local/file", :node => nil).returns("/some/file") - @instance = mock 'instance' - end - - it "should create the instance with the key used to find the instance" do - @model.expects(:new).with { |key, *options| key == @uri } - @file_server.find(@request) + @configuration.expects(:file_path).with("my/local/file", :node => nil).returns("/some/file") + @instance = stub 'instance', :collect => nil end it "should create the instance with the path at which the instance was found" do - @model.expects(:new).with { |key, options| options[:path] == "/some/file" } + @model.expects(:new).with { |key, options| key == "/some/file" }.returns @instance @file_server.find(@request) end @@ -88,6 +84,12 @@ describe Puppet::Indirector::FileServer do @model.expects(:new).returns(@instance) @file_server.find(@request) end + + it "should collect each instance's attributes before returning" do + @instance.expects(:collect) + @model.expects(:new).returns @instance + @file_server.find(@request) + end end describe Puppet::Indirector::FileServer, " when checking authorization" do @@ -108,7 +110,6 @@ describe Puppet::Indirector::FileServer do describe "and finding file information" do before do - @request.key = "puppetmounts://host/my/file" @request.method = :find end @@ -118,7 +119,7 @@ describe Puppet::Indirector::FileServer do end it "should pass the file path from the URI to the file server configuration" do - @configuration.expects(:authorized?).with { |uri, *args| uri == "/my/file" } + @configuration.expects(:authorized?).with { |uri, *args| uri == "my/local/file" } @file_server.authorized?(@request) end @@ -149,36 +150,42 @@ describe Puppet::Indirector::FileServer do describe Puppet::Indirector::FileServer, " when searching for files" do it "should use the path portion of the URI as the file name" do - @configuration.expects(:file_path).with("/my/local/file", :node => nil) + @configuration.expects(:file_path).with("my/local/file", :node => nil) @file_server.search(@request) end it "should use the FileServing configuration to convert the file name to a fully qualified path" do - @configuration.expects(:file_path).with("/my/local/file", :node => nil) + @configuration.expects(:file_path).with("my/local/file", :node => nil) @file_server.search(@request) end it "should pass the node name to the FileServing configuration if one is provided" do - @configuration.expects(:file_path).with("/my/local/file", :node => "testing") + @configuration.expects(:file_path).with("my/local/file", :node => "testing") @request.node = "testing" @file_server.search(@request) end it "should return nil if no fully qualified path is found" do - @configuration.expects(:file_path).with("/my/local/file", :node => nil).returns(nil) + @configuration.expects(:file_path).with("my/local/file", :node => nil).returns(nil) @file_server.search(@request).should be_nil end it "should use :path2instances from the terminus_helper to return instances if a module is found and the file exists" do - @configuration.expects(:file_path).with("/my/local/file", :node => nil).returns("/my/file") + @configuration.expects(:file_path).with("my/local/file", :node => nil).returns("my/file") @file_server.expects(:path2instances) @file_server.search(@request) end it "should pass the request on to :path2instances" do - @configuration.expects(:file_path).with("/my/local/file", :node => nil).returns("/my/file") - @file_server.expects(:path2instances).with(@request, "/my/file") + @configuration.expects(:file_path).with("my/local/file", :node => nil).returns("my/file") + @file_server.expects(:path2instances).with(@request, "my/file").returns [] @file_server.search(@request) end + + it "should return the result of :path2instances" do + @configuration.expects(:file_path).with("my/local/file", :node => nil).returns("my/file") + @file_server.expects(:path2instances).with(@request, "my/file").returns :footest + @file_server.search(@request).should == :footest + end end end diff --git a/spec/unit/indirector/indirection.rb b/spec/unit/indirector/indirection.rb index e52be31e1..166065ecf 100755 --- a/spec/unit/indirector/indirection.rb +++ b/spec/unit/indirector/indirection.rb @@ -34,6 +34,22 @@ describe "Indirection Delegator", :shared => true do @indirection.send(@method, "me") end + it "should fail if the :select_terminus hook does not return a terminus name" do + # Define the method, so our respond_to? hook matches. + class << @indirection + def select_terminus(request) + end + end + + request = stub 'request', :key => "me", :options => {} + + @indirection.stubs(:request).returns request + + @indirection.expects(:select_terminus).with(request).returns nil + + lambda { @indirection.send(@method, "me") }.should raise_error(ArgumentError) + end + it "should choose the terminus returned by the :terminus_class method if no :select_terminus method is available" do @indirection.expects(:terminus_class).returns :test_terminus diff --git a/spec/unit/indirector/module_files.rb b/spec/unit/indirector/module_files.rb index 32dedd4f1..f5f9527df 100755 --- a/spec/unit/indirector/module_files.rb +++ b/spec/unit/indirector/module_files.rb @@ -25,49 +25,47 @@ describe Puppet::Indirector::ModuleFiles do @module_files = @module_files_class.new - @uri = "puppetmounts://host/modules/my/local/file" @module = Puppet::Module.new("mymod", "/module/path") - @request = stub 'request', :key => @uri, :options => {}, :node => nil, :ip => nil, :method => :find + @request = Puppet::Indirector::Request.new(:mytype, :find, "puppet://host/modules/mymod/local/file") end describe Puppet::Indirector::ModuleFiles, " when finding files" do + before do + Puppet::Module.stubs(:find).returns @module + end - it "should strip off the leading '/modules' mount name" do - Puppet::Module.expects(:find).with('my', "myenv").returns @module + it "should strip off the leading 'modules/' mount name" do + Puppet::Module.expects(:find).with { |key, env| key == 'mymod' }.returns @module @module_files.find(@request) end - it "should not strip off leading terms that start with '/modules' but are longer words" do - @request.stubs(:key).returns "puppetmounts://host/modulestart/my/local/file" - Puppet::Module.expects(:find).with('modulestart', "myenv").returns nil + it "should not strip off leading terms that start with 'modules' but are longer words" do + @request.stubs(:key).returns "modulestart/mymod/local/file" + Puppet::Module.expects(:find).with { |key, env| key == 'modulestart'}.returns nil @module_files.find(@request) end it "should search for a module whose name is the first term in the remaining file path" do - Puppet::Module.expects(:find).with('my', "myenv").returns @module @module_files.find(@request) end it "should search for a file relative to the module's files directory" do - Puppet::Module.expects(:find).with('my', "myenv").returns @module FileTest.expects(:exists?).with("/module/path/files/local/file") @module_files.find(@request) end it "should return nil if the module does not exist" do - Puppet::Module.expects(:find).with('my', "myenv").returns nil + Puppet::Module.expects(:find).returns nil @module_files.find(@request).should be_nil end it "should return nil if the module exists but the file does not" do - Puppet::Module.expects(:find).with('my', "myenv").returns @module FileTest.expects(:exists?).with("/module/path/files/local/file").returns(false) @module_files.find(@request).should be_nil end it "should return an instance of the model if a module is found and the file exists" do - Puppet::Module.expects(:find).with('my', "myenv").returns @module FileTest.expects(:exists?).with("/module/path/files/local/file").returns(true) @model.expects(:new).returns(:myinstance) @module_files.find(@request).should == :myinstance @@ -76,7 +74,7 @@ describe Puppet::Indirector::ModuleFiles do it "should use the node's environment to look up the module if the node name is provided" do node = stub "node", :environment => "testing" Puppet::Node.expects(:find).with("mynode").returns(node) - Puppet::Module.expects(:find).with('my', "testing") + Puppet::Module.expects(:find).with('mymod', "testing") @request.stubs(:node).returns "mynode" @module_files.find(@request) @@ -85,7 +83,7 @@ describe Puppet::Indirector::ModuleFiles do it "should use the default environment setting to look up the module if the node name is not provided" do env = stub "environment", :name => "testing" Puppet::Node::Environment.stubs(:new).returns(env) - Puppet::Module.expects(:find).with('my', "testing") + Puppet::Module.expects(:find).with('mymod', "testing") @module_files.find(@request) end end @@ -93,18 +91,13 @@ describe Puppet::Indirector::ModuleFiles do describe Puppet::Indirector::ModuleFiles, " when returning instances" do before do - Puppet::Module.expects(:find).with('my', "myenv").returns @module + Puppet::Module.expects(:find).with('mymod', "myenv").returns @module FileTest.expects(:exists?).with("/module/path/files/local/file").returns(true) @instance = mock 'instance' end - it "should create the instance with the key used to find the instance" do - @model.expects(:new).with { |key, *options| key == @uri } - @module_files.find(@request) - end - it "should create the instance with the path at which the instance was found" do - @model.expects(:new).with { |key, options| options[:path] == "/module/path/files/local/file" } + @model.expects(:new).with { |key, options| key == "/module/path/files/local/file" } @module_files.find(@request) end @@ -149,19 +142,19 @@ describe Puppet::Indirector::ModuleFiles do end it "should use the path directly from the URI if it already includes /modules" do - @request.expects(:key).returns "puppetmounts://host/modules/my/file" - @configuration.expects(:authorized?).with { |uri, *args| uri == "/modules/my/file" } + @request.expects(:key).returns "modules/my/file" + @configuration.expects(:authorized?).with { |uri, *args| uri == "modules/my/file" } @module_files.authorized?(@request) end - it "should add /modules to the file path if it's not included in the URI" do - @request.expects(:key).returns "puppetmounts://host/my/file" - @configuration.expects(:authorized?).with { |uri, *args| uri == "/modules/my/file" } + it "should add modules/ to the file path if it's not included in the URI" do + @request.expects(:key).returns "my/file" + @configuration.expects(:authorized?).with { |uri, *args| uri == "modules/my/file" } @module_files.authorized?(@request) end it "should pass the node name to the file server configuration" do - @request.expects(:key).returns "puppetmounts://host/my/file" + @request.expects(:key).returns "my/file" @configuration.expects(:authorized?).with { |key, options| options[:node] == "mynode" } @request.stubs(:node).returns "mynode" @module_files.authorized?(@request) @@ -186,41 +179,41 @@ describe Puppet::Indirector::ModuleFiles do describe Puppet::Indirector::ModuleFiles, " when searching for files" do - it "should strip off the leading '/modules' mount name" do + it "should strip off the leading 'modules/' mount name" do Puppet::Node::Environment.stubs(:new).returns(stub('env', :name => "myenv")) - Puppet::Module.expects(:find).with('my', "myenv").returns @module + Puppet::Module.expects(:find).with { |key, env| key == 'mymod'}.returns @module @module_files.search(@request) end it "should not strip off leading terms that start with '/modules' but are longer words" do Puppet::Node::Environment.stubs(:new).returns(stub('env', :name => "myenv")) Puppet::Module.expects(:find).with('modulestart', "myenv").returns nil - @request.stubs(:key).returns "puppetmounts://host/modulestart/my/local/file" + @request.stubs(:key).returns "modulestart/my/local/file" @module_files.search @request end it "should search for a module whose name is the first term in the remaining file path" do Puppet::Node::Environment.stubs(:new).returns(stub('env', :name => "myenv")) - Puppet::Module.expects(:find).with('my', "myenv").returns @module + Puppet::Module.expects(:find).with('mymod', "myenv").returns @module @module_files.search(@request) end it "should search for a file relative to the module's files directory" do Puppet::Node::Environment.stubs(:new).returns(stub('env', :name => "myenv")) - Puppet::Module.expects(:find).with('my', "myenv").returns @module + Puppet::Module.expects(:find).with('mymod', "myenv").returns @module FileTest.expects(:exists?).with("/module/path/files/local/file") @module_files.search(@request) end it "should return nil if the module does not exist" do Puppet::Node::Environment.stubs(:new).returns(stub('env', :name => "myenv")) - Puppet::Module.expects(:find).with('my', "myenv").returns nil + Puppet::Module.expects(:find).with('mymod', "myenv").returns nil @module_files.search(@request).should be_nil end it "should return nil if the module exists but the file does not" do Puppet::Node::Environment.stubs(:new).returns(stub('env', :name => "myenv")) - Puppet::Module.expects(:find).with('my', "myenv").returns @module + Puppet::Module.expects(:find).with('mymod', "myenv").returns @module FileTest.expects(:exists?).with("/module/path/files/local/file").returns(false) @module_files.search(@request).should be_nil end @@ -228,7 +221,7 @@ describe Puppet::Indirector::ModuleFiles do it "should use the node's environment to look up the module if the node name is provided" do node = stub "node", :environment => "testing" Puppet::Node.expects(:find).with("mynode").returns(node) - Puppet::Module.expects(:find).with('my', "testing") + Puppet::Module.expects(:find).with('mymod', "testing") @request.stubs(:node).returns "mynode" @module_files.search(@request) end @@ -236,13 +229,13 @@ describe Puppet::Indirector::ModuleFiles do it "should use the default environment setting to look up the module if the node name is not provided and the environment is not set to ''" do env = stub 'env', :name => "testing" Puppet::Node::Environment.stubs(:new).returns(env) - Puppet::Module.expects(:find).with('my', "testing") + Puppet::Module.expects(:find).with('mymod', "testing") @module_files.search(@request) end it "should use :path2instances from the terminus_helper to return instances if a module is found and the file exists" do Puppet::Node::Environment.stubs(:new).returns(stub('env', :name => "myenv")) - Puppet::Module.expects(:find).with('my', "myenv").returns @module + Puppet::Module.expects(:find).with('mymod', "myenv").returns @module FileTest.expects(:exists?).with("/module/path/files/local/file").returns(true) @module_files.expects(:path2instances).with(@request, "/module/path/files/local/file") @module_files.search(@request) @@ -250,7 +243,7 @@ describe Puppet::Indirector::ModuleFiles do it "should pass the request directly to :path2instances" do Puppet::Node::Environment.stubs(:new).returns(stub('env', :name => "myenv")) - Puppet::Module.expects(:find).with('my', "myenv").returns @module + Puppet::Module.expects(:find).with('mymod', "myenv").returns @module FileTest.expects(:exists?).with("/module/path/files/local/file").returns(true) @module_files.expects(:path2instances).with(@request, "/module/path/files/local/file") @module_files.search(@request) diff --git a/spec/unit/indirector/request.rb b/spec/unit/indirector/request.rb index f7702f821..18f625946 100755 --- a/spec/unit/indirector/request.rb +++ b/spec/unit/indirector/request.rb @@ -75,6 +75,57 @@ describe Puppet::Indirector::Request do 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 + + 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") + end + + it "should set the request key to the full file path" do @request.key.should == "/my/file" 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 unqualified path from the URI" do + Puppet::Indirector::Request.new(:ind, :method, "http:///stuff").key.should == "stuff" + 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 end it "should look use the Indirection class to return the appropriate indirection" do @@ -84,4 +135,16 @@ describe Puppet::Indirector::Request do request.indirection.should equal(ind) 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 end diff --git a/spec/unit/indirector/rest.rb b/spec/unit/indirector/rest.rb index 3bd63359d..e7afbb5b2 100755 --- a/spec/unit/indirector/rest.rb +++ b/spec/unit/indirector/rest.rb @@ -45,6 +45,38 @@ describe Puppet::Indirector::REST do @searcher = @rest_class.new 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' @@ -91,40 +123,26 @@ describe Puppet::Indirector::REST do Puppet.settings.stubs(:value).returns("rest_testing") end - describe "and the request key is not a URL" do - it "should use the :server setting as the host and the :masterport setting (as an Integer) as the port" do - @request = stub 'request', :key => "foo" - Puppet.settings.expects(:value).with(:server).returns "myserver" - Puppet.settings.expects(:value).with(:masterport).returns "1234" - Puppet::Network::HttpPool.expects(:http_instance).with("myserver", 1234).returns "myconn" - @searcher.network(@request).should == "myconn" - 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 - describe "and the request key is a URL" do - it "should use the :server setting and masterport setting, as an Integer, as the host if no values are provided" do - @request = stub 'request', :key => "puppet:///key" - - Puppet.settings.expects(:value).with(:server).returns "myserver" - Puppet.settings.expects(:value).with(:masterport).returns "1234" - Puppet::Network::HttpPool.expects(:http_instance).with("myserver", 1234).returns "myconn" - @searcher.network(@request).should == "myconn" - end - - it "should use the server if one is provided" do - @request.stubs(:key).returns "puppet://host/key" - - Puppet.settings.expects(:value).with(:masterport).returns "1234" - Puppet::Network::HttpPool.expects(:http_instance).with("host", 1234).returns "myconn" - @searcher.network(@request).should == "myconn" - end - - it "should use the server and port if they are provided" do - @request.stubs(:key).returns "puppet://host:123/key" + 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 - Puppet::Network::HttpPool.expects(:http_instance).with("host", 123).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 @@ -158,7 +176,7 @@ describe Puppet::Indirector::REST do it "should include all options in the query string" do @request.stubs(:options).returns(:one => "two", :three => "four") should_path = "/%s/%s" % [@indirection.name.to_s, "foo"] - @connection.expects(:get).with { |path, args| path =~ /\?one=two&three=four$/ }.returns(@response) + @connection.expects(:get).with { |path, args| path =~ /\?one=two&three=four$/ or path =~ /\?three=four&one=two$/ }.returns(@response) @searcher.find(@request) end @@ -220,7 +238,7 @@ describe Puppet::Indirector::REST do @request.stubs(:options).returns(:one => "two", :three => "four") should_path = "/%s/%s" % [@indirection.name.to_s, "foo"] - @connection.expects(:get).with { |path, args| path =~ /\?one=two&three=four$/ }.returns(@response) + @connection.expects(:get).with { |path, args| path =~ /\?one=two&three=four$/ or path =~ /\?three=four&one=two$/ }.returns(@response) @searcher.search(@request) end diff --git a/spec/unit/network/format.rb b/spec/unit/network/format.rb index b960a3f73..244bff306 100755 --- a/spec/unit/network/format.rb +++ b/spec/unit/network/format.rb @@ -74,10 +74,27 @@ describe Puppet::Network::Format do Puppet::Network::Format.new(:yaml).should_not be_supported(String) end + it "should not consider a class supported unless the format is suitable" do + @format.expects(:suitable?).returns false + @format.should_not be_supported(FormatRenderer) + end + it "should always downcase mimetypes" do @format.mime = "Foo/Bar" @format.mime.should == "foo/bar" end + + it "should support having a weight" do + @format.should respond_to(:weight) + end + + it "should default to a weight of of 5" do + @format.weight.should == 5 + end + + it "should be able to override its weight at initialization" do + Puppet::Network::Format.new(:foo, :weight => 1).weight.should == 1 + end end describe "when converting between instances and formatted text" do diff --git a/spec/unit/network/format_handler.rb b/spec/unit/network/format_handler.rb index 35e996516..3dcff6199 100755 --- a/spec/unit/network/format_handler.rb +++ b/spec/unit/network/format_handler.rb @@ -21,18 +21,31 @@ describe Puppet::Network::FormatHandler do end it "should include all supported formats" do - one = stub 'supported', :supported? => true, :name => "one" - two = stub 'supported', :supported? => false, :name => "two" - three = stub 'supported', :supported? => true, :name => "three" - four = stub 'supported', :supported? => false, :name => "four" - Puppet::Network::FormatHandler.expects(:formats).returns %w{one two three four} - Puppet::Network::FormatHandler.expects(:format).with("one").returns one - Puppet::Network::FormatHandler.expects(:format).with("two").returns two - Puppet::Network::FormatHandler.expects(:format).with("three").returns three - Puppet::Network::FormatHandler.expects(:format).with("four").returns four + one = stub 'supported', :supported? => true, :name => "one", :weight => 1 + two = stub 'supported', :supported? => false, :name => "two", :weight => 1 + three = stub 'supported', :supported? => true, :name => "three", :weight => 1 + four = stub 'supported', :supported? => false, :name => "four", :weight => 1 + Puppet::Network::FormatHandler.stubs(:formats).returns %w{one two three four} + Puppet::Network::FormatHandler.stubs(:format).with("one").returns one + Puppet::Network::FormatHandler.stubs(:format).with("two").returns two + Puppet::Network::FormatHandler.stubs(:format).with("three").returns three + Puppet::Network::FormatHandler.stubs(:format).with("four").returns four FormatTester.supported_formats.sort.should == %w{one three}.sort end + it "should return the supported formats in decreasing order of weight" do + one = stub 'supported', :supported? => true, :name => "one", :weight => 1 + two = stub 'supported', :supported? => true, :name => "two", :weight => 6 + three = stub 'supported', :supported? => true, :name => "three", :weight => 2 + four = stub 'supported', :supported? => true, :name => "four", :weight => 8 + Puppet::Network::FormatHandler.stubs(:formats).returns %w{one two three four} + Puppet::Network::FormatHandler.stubs(:format).with("one").returns one + Puppet::Network::FormatHandler.stubs(:format).with("two").returns two + Puppet::Network::FormatHandler.stubs(:format).with("three").returns three + Puppet::Network::FormatHandler.stubs(:format).with("four").returns four + FormatTester.supported_formats.should == %w{four two three one} + end + it "should return the first format as the default format" do FormatTester.expects(:supported_formats).returns %w{one two} FormatTester.default_format.should == "one" diff --git a/spec/unit/network/formats.rb b/spec/unit/network/formats.rb index f7493360d..0e21fefa7 100755 --- a/spec/unit/network/formats.rb +++ b/spec/unit/network/formats.rb @@ -99,4 +99,34 @@ describe "Puppet Network Format" do @text.mime.should == "text/plain" end end + + describe Puppet::Network::FormatHandler.format(:raw) do + before do + @format = Puppet::Network::FormatHandler.format(:raw) + end + + it "should exist" do + @format.should_not be_nil + end + + it "should have its mimetype set to application/x-raw" do + @format.mime.should == "application/x-raw" + end + + it "should always be supported" do + @format.should be_supported(String) + end + + it "should fail if its multiple_render method is used" do + lambda { @format.render_multiple("foo") }.should raise_error(NotImplementedError) + end + + it "should fail if its multiple_intern method is used" do + lambda { @format.intern_multiple(String, "foo") }.should raise_error(NotImplementedError) + end + + it "should have a weight of 1" do + @format.weight.should == 1 + end + end end diff --git a/spec/unit/network/http/handler.rb b/spec/unit/network/http/handler.rb index 6fc932091..ed0f25121 100755 --- a/spec/unit/network/http/handler.rb +++ b/spec/unit/network/http/handler.rb @@ -224,6 +224,9 @@ describe Puppet::Network::HTTP::Handler do @handler.stubs(:singular?).returns(true) @handler.stubs(:request_key).returns('key') @model_class.stubs(:find).returns @result + + @format = stub 'format', :suitable? => true + Puppet::Network::FormatHandler.stubs(:format).returns @format end it "should fail to find model if key is not specified" do @@ -246,6 +249,28 @@ describe Puppet::Network::HTTP::Handler do @handler.do_find(@request, @response) end + it "should fail if no accept header is provided" do + @handler.expects(:accept_header).with(@request).returns nil + lambda { @handler.do_find(@request, @response) }.should raise_error(ArgumentError) + end + + it "should fail if the accept header does not contain a valid format" do + @handler.expects(:accept_header).with(@request).returns "" + lambda { @handler.do_find(@request, @response) }.should raise_error(RuntimeError) + end + + it "should not use an unsuitable format" do + @handler.expects(:accept_header).with(@request).returns "foo,bar" + foo = mock 'foo', :suitable? => false + bar = mock 'bar', :suitable? => true + Puppet::Network::FormatHandler.expects(:format).with("foo").returns foo + Puppet::Network::FormatHandler.expects(:format).with("bar").returns bar + + @handler.expects(:set_content_type).with(@response, "bar") # the suitable one + + @handler.do_find(@request, @response) + end + it "should render the result using the first format specified in the accept header" do @handler.expects(:accept_header).with(@request).returns "one,two" @result.expects(:render).with("one") @@ -298,6 +323,9 @@ describe Puppet::Network::HTTP::Handler do @result = [@result1, @result2] @model_class.stubs(:render_multiple).returns "my rendered instances" @model_class.stubs(:search).returns(@result) + + @format = stub 'format', :suitable? => true + Puppet::Network::FormatHandler.stubs(:format).returns @format end it "should use a common method for determining the request parameters" do @@ -409,6 +437,9 @@ describe Puppet::Network::HTTP::Handler do @model_instance = stub('indirected model instance', :save => true) @model_class.stubs(:convert_from).returns(@model_instance) + + @format = stub 'format', :suitable? => true + Puppet::Network::FormatHandler.stubs(:format).returns @format end it "should use the 'body' hook to retrieve the body of the request" do diff --git a/spec/unit/network/http/mongrel/rest.rb b/spec/unit/network/http/mongrel/rest.rb index 3b248dcfe..9dbc1c9ab 100755 --- a/spec/unit/network/http/mongrel/rest.rb +++ b/spec/unit/network/http/mongrel/rest.rb @@ -53,9 +53,9 @@ describe "Puppet::Network::HTTP::MongrelREST" do @handler.path(@request).should == "/foo" end - it "should use the second part of the request path as the request key" do - @params.expects(:[]).with(Mongrel::Const::REQUEST_PATH).returns "/foo/bar" - @handler.request_key(@request).should == "bar" + it "should use the remainder of the request path as the request key" do + @params.expects(:[]).with(Mongrel::Const::REQUEST_PATH).returns "/foo/bar/baz" + @handler.request_key(@request).should == "bar/baz" end it "should return nil as the request key if no second field is present" do diff --git a/spec/unit/network/http/webrick/rest.rb b/spec/unit/network/http/webrick/rest.rb index 620201472..1f4ccbe29 100755 --- a/spec/unit/network/http/webrick/rest.rb +++ b/spec/unit/network/http/webrick/rest.rb @@ -47,9 +47,9 @@ describe Puppet::Network::HTTP::WEBrickREST do @handler.path(@request).should == "/foo" end - it "should return the second field in the path as the request key" do - @request.expects(:path).returns "/foo/bar" - @handler.request_key(@request).should == "bar" + it "should return the remainder of the path as the request key" do + @request.expects(:path).returns "/foo/bar/baz" + @handler.request_key(@request).should == "bar/baz" end it "should return nil as the request key if there is no second field" do diff --git a/spec/unit/type/file.rb b/spec/unit/type/file.rb index 663c5dc15..f0ebb49e2 100755 --- a/spec/unit/type/file.rb +++ b/spec/unit/type/file.rb @@ -8,6 +8,10 @@ describe Puppet::Type.type(:file) do @path.close!() @path = @path.path @file = Puppet::Type::File.create(:name => @path) + + @catalog = mock 'catalog' + @catalog.stub_everything + @file.catalog = @catalog end describe "when used with content and replace=>false" do @@ -31,52 +35,6 @@ describe Puppet::Type.type(:file) do end end - describe "when specifying a source" do - before do - @file[:source] = "/bar" - end - - it "should raise if source doesn't exist" do - @file.property(:source).expects(:found?).returns(false) - lambda { @file.retrieve }.should raise_error(Puppet::Error) - end - - end - - describe "when retrieving remote files" do - before do - @filesource = Puppet::Type::File::FileSource.new - @filesource.server = mock 'fileserver' - - @file.stubs(:uri2obj).returns(@filesource) - - @file[:source] = "puppet:///test" - end - - it "should fail without writing if it cannot retrieve remote contents" do - # create the file, because we only get the problem when it starts - # out absent. - File.open(@file[:path], "w") { |f| f.puts "a" } - @file.expects(:write).never - - @filesource.server.stubs(:describe).returns("493\tfile\t100\t0\t{md5}3f5fef3bddbc4398c46a7bd7ba7b3af7") - @filesource.server.stubs(:retrieve).raises(RuntimeError) - @file.property(:source).retrieve - lambda { @file.property(:source).sync }.should raise_error(Puppet::Error) - end - - it "should fail if it cannot describe remote contents" do - @filesource.server.stubs(:describe).raises(Puppet::Network::XMLRPCClientError.new("Testing")) - lambda { @file.retrieve }.should raise_error(Puppet::Error) - end - - it "should fail during eval_generate if no remote sources exist" do - file = Puppet::Type.type(:file).create :path => "/foobar", :source => "/this/file/does/not/exist", :recurse => true - - lambda { file.eval_generate }.should raise_error(Puppet::Error) - end - end - describe "when managing links" do require 'puppettest/support/assertions' include PuppetTest @@ -116,4 +74,451 @@ describe Puppet::Type.type(:file) do ("%o" % (File.stat(@file).mode & 007777)).should == "%o" % 0755 end end + + describe "when flushing" do + it "should flush all properties that respond to :flush" do + @resource = Puppet.type(:file).create(:path => "/foo/bar", :source => "/bar/foo") + @resource.property(:source).expects(:flush) + @resource.flush + end + end + + it "should have a method for performing recursion" do + @file.must respond_to(:perform_recursion) + end + + describe "when executing a recursive search" do + it "should use Metadata to do its recursion" do + Puppet::FileServing::Metadata.expects(:search) + @file.perform_recursion(@file[:path]) + end + + it "should use the provided path as the key to the search" do + Puppet::FileServing::Metadata.expects(:search).with { |key, options| key == "/foo" } + @file.perform_recursion("/foo") + end + + it "should return the results of the metadata search" do + Puppet::FileServing::Metadata.expects(:search).returns "foobar" + @file.perform_recursion(@file[:path]).should == "foobar" + end + + it "should pass its recursion value to the search" do + @file[:recurse] = 10 + Puppet::FileServing::Metadata.expects(:search).with { |key, options| options[:recurse] == 10 } + @file.perform_recursion(@file[:path]) + end + + it "should configure the search to ignore or manage links" do + @file[:links] = :manage + Puppet::FileServing::Metadata.expects(:search).with { |key, options| options[:links] == :manage } + @file.perform_recursion(@file[:path]) + end + + it "should pass its 'ignore' setting to the search if it has one" do + @file[:ignore] = %w{.svn CVS} + Puppet::FileServing::Metadata.expects(:search).with { |key, options| options[:ignore] == %w{.svn CVS} } + @file.perform_recursion(@file[:path]) + end + end + + it "should have a method for performing local recursion" do + @file.must respond_to(:recurse_local) + end + + describe "when doing local recursion" do + before do + @metadata = stub 'metadata', :relative_path => "my/file" + end + + it "should pass its to the :perform_recursion method" do + @file.expects(:perform_recursion).with(@file[:path]).returns [@metadata] + @file.stubs(:newchild) + @file.recurse_local + end + + it "should return an empty hash if the recursion returns nothing" do + @file.expects(:perform_recursion).returns nil + @file.recurse_local.should == {} + end + + it "should create a new child resource with each generated metadata instance's relative path" do + @file.expects(:perform_recursion).returns [@metadata] + @file.expects(:newchild).with(@metadata.relative_path).returns "fiebar" + @file.recurse_local + end + + it "should not create a new child resource for the '.' directory" do + @metadata.stubs(:relative_path).returns "." + + @file.expects(:perform_recursion).returns [@metadata] + @file.expects(:newchild).never + @file.recurse_local + end + + it "should return a hash of the created resources with the relative paths as the hash keys" do + @file.expects(:perform_recursion).returns [@metadata] + @file.expects(:newchild).with("my/file").returns "fiebar" + @file.recurse_local.should == {"my/file" => "fiebar"} + end + end + + it "should have a method for performing link recursion" do + @file.must respond_to(:recurse_link) + end + + describe "when doing link recursion" do + before do + @first = stub 'first', :relative_path => "first", :full_path => "/my/first", :ftype => "directory" + @second = stub 'second', :relative_path => "second", :full_path => "/my/second", :ftype => "file" + + @resource = stub 'file', :[]= => nil + end + + it "should pass its target to the :perform_recursion method" do + @file[:target] = "mylinks" + @file.expects(:perform_recursion).with("mylinks").returns [@first] + @file.stubs(:newchild).returns @resource + @file.recurse_link({}) + end + + it "should ignore the recursively-found '.' file and configure the top-level file to create a directory" do + @first.stubs(:relative_path).returns "." + @file[:target] = "mylinks" + @file.expects(:perform_recursion).with("mylinks").returns [@first] + @file.stubs(:newchild).never + @file.expects(:[]=).with(:ensure, :directory) + @file.recurse_link({}) + end + + it "should create a new child resource for each generated metadata instance's relative path that doesn't already exist in the children hash" do + @file.expects(:perform_recursion).returns [@first, @second] + @file.expects(:newchild).with(@first.relative_path).returns @resource + @file.recurse_link("second" => @resource) + end + + it "should not create a new child resource for paths that already exist in the children hash" do + @file.expects(:perform_recursion).returns [@first] + @file.expects(:newchild).never + @file.recurse_link("first" => @resource) + end + + it "should set the target to the full path of discovered file and set :ensure to :link if the file is not a directory" do + file = stub 'file' + file.expects(:[]=).with(:target, "/my/second") + file.expects(:[]=).with(:ensure, :link) + + @file.stubs(:perform_recursion).returns [@first, @second] + @file.recurse_link("first" => @resource, "second" => file) + end + + it "should :ensure to :directory if the file is a directory" do + file = stub 'file' + file.expects(:[]=).with(:ensure, :directory) + + @file.stubs(:perform_recursion).returns [@first, @second] + @file.recurse_link("first" => file, "second" => @resource) + end + + it "should return a hash with both created and existing resources with the relative paths as the hash keys" do + file = stub 'file', :[]= => nil + + @file.expects(:perform_recursion).returns [@first, @second] + @file.stubs(:newchild).returns file + @file.recurse_link("second" => @resource).should == {"second" => @resource, "first" => file} + end + end + + it "should have a method for performing remote recursion" do + @file.must respond_to(:recurse_remote) + end + + describe "when doing remote recursion" do + before do + @file[:source] = "puppet://foo/bar" + + @first = Puppet::FileServing::Metadata.new("/my", :relative_path => "first") + @second = Puppet::FileServing::Metadata.new("/my", :relative_path => "second") + + @property = stub 'property', :metadata= => nil + @resource = stub 'file', :[]= => nil, :property => @property + end + + it "should pass its source to the :perform_recursion method" do + data = Puppet::FileServing::Metadata.new("/whatever", :relative_path => "foobar") + @file.expects(:perform_recursion).with("puppet://foo/bar").returns [data] + @file.stubs(:newchild).returns @resource + @file.recurse_remote({}) + end + + it "should set the source of each returned file to the searched-for URI plus the found relative path" do + @first.expects(:source=).with File.join("puppet://foo/bar", @first.relative_path) + @file.expects(:perform_recursion).returns [@first] + @file.stubs(:newchild).returns @resource + @file.recurse_remote({}) + end + + it "should create a new resource for any relative file paths that do not already have a resource" do + @file.stubs(:perform_recursion).returns [@first] + @file.expects(:newchild).with("first").returns @resource + @file.recurse_remote({}).should == {"first" => @resource} + end + + it "should not create a new resource for any relative file paths that do already have a resource" do + @file.stubs(:perform_recursion).returns [@first] + @file.expects(:newchild).never + @file.recurse_remote("first" => @resource) + end + + it "should set the source of each resource to the source of the metadata" do + @file.stubs(:perform_recursion).returns [@first] + @resource.stubs(:[]=) + @resource.expects(:[]=).with(:source, File.join("puppet://foo/bar", @first.relative_path)) + @file.recurse_remote("first" => @resource) + end + + # LAK:FIXME This is a bug, but I can't think of a fix for it. Fortunately it's already + # filed, and when it's fixed, we'll just fix the whole flow. + it "should set the checksum type to :md5 if the remote file is a file" do + @first.stubs(:ftype).returns "file" + @file.stubs(:perform_recursion).returns [@first] + @resource.stubs(:[]=) + @resource.expects(:[]=).with(:checksum, :md5) + @file.recurse_remote("first" => @resource) + end + + it "should store the metadata in the source property for each resource so the source does not have to requery the metadata" do + @file.stubs(:perform_recursion).returns [@first] + @resource.expects(:property).with(:source).returns @property + + @property.expects(:metadata=).with(@first) + + @file.recurse_remote("first" => @resource) + end + + it "should not create a new resource for the '.' file" do + @first.stubs(:relative_path).returns "." + @file.stubs(:perform_recursion).returns [@first] + + @file.expects(:newchild).never + + @file.recurse_remote({}) + end + + it "should store the metadata in the main file's source property if the relative path is '.'" do + @first.stubs(:relative_path).returns "." + @file.stubs(:perform_recursion).returns [@first] + + @file.property(:source).expects(:metadata=).with @first + + @file.recurse_remote("first" => @resource) + end + + describe "and purging is enabled" do + before do + @file[:purge] = true + end + + it "should configure each file not on the remote system to be removed" do + @file.stubs(:perform_recursion).returns [@second] + + @resource.expects(:[]=).with(:ensure, :absent) + + @file.expects(:newchild).returns stub('secondfile', :[]= => nil, :property => @property) + + @file.recurse_remote("first" => @resource) + end + end + + describe "and multiple sources are provided" do + describe "and :sourceselect is set to :first" do + it "should create file instances for the results for the first source to return any values" do + data = Puppet::FileServing::Metadata.new("/whatever", :relative_path => "foobar") + @file[:source] = %w{/one /two /three /four} + @file.expects(:perform_recursion).with("/one").returns nil + @file.expects(:perform_recursion).with("/two").returns [] + @file.expects(:perform_recursion).with("/three").returns [data] + @file.expects(:perform_recursion).with("/four").never + @file.expects(:newchild).with("foobar").returns @resource + @file.recurse_remote({}) + end + end + + describe "and :sourceselect is set to :all" do + before do + @file[:sourceselect] = :all + end + + it "should return every found file that is not in a previous source" do + klass = Puppet::FileServing::Metadata + @file[:source] = %w{/one /two /three /four} + @file.stubs(:newchild).returns @resource + + one = [klass.new("/one", :relative_path => "a")] + @file.expects(:perform_recursion).with("/one").returns one + @file.expects(:newchild).with("a").returns @resource + + two = [klass.new("/two", :relative_path => "a"), klass.new("/two", :relative_path => "b")] + @file.expects(:perform_recursion).with("/two").returns two + @file.expects(:newchild).with("b").returns @resource + + three = [klass.new("/three", :relative_path => "a"), klass.new("/three", :relative_path => "c")] + @file.expects(:perform_recursion).with("/three").returns three + @file.expects(:newchild).with("c").returns @resource + + @file.expects(:perform_recursion).with("/four").returns [] + + @file.recurse_remote({}) + end + end + end + end + + describe "when returning resources with :eval_generate" do + before do + @catalog = mock 'catalog' + @catalog.stub_everything + + @graph = stub 'graph', :add_edge => nil + @catalog.stubs(:relationship_graph).returns @graph + + @file.catalog = @catalog + @file[:recurse] = true + end + + it "should recurse if recursion is enabled" do + resource = stub('resource', :[] => "resource") + @file.expects(:recurse?).returns true + @file.expects(:recurse).returns [resource] + @file.eval_generate.should == [resource] + end + + it "should not recurse if recursion is disabled" do + @file.expects(:recurse?).returns false + @file.expects(:recurse).never + @file.eval_generate.should be_nil + end + + it "should fail if no catalog is set" do + @file.catalog = nil + lambda { @file.eval_generate }.should raise_error(Puppet::DevError) + end + + it "should skip resources that are already in the catalog" do + foo = stub 'foo', :[] => "/foo" + bar = stub 'bar', :[] => "/bar" + bar2 = stub 'bar2', :[] => "/bar" + + @catalog.expects(:resource).with(:file, "/foo").returns nil + @catalog.expects(:resource).with(:file, "/bar").returns bar2 + + @file.expects(:recurse).returns [foo, bar] + + @file.eval_generate.should == [foo] + end + + it "should add each resource to the catalog" do + foo = stub 'foo', :[] => "/foo" + bar = stub 'bar', :[] => "/bar" + bar2 = stub 'bar2', :[] => "/bar" + + @catalog.expects(:add_resource).with(foo) + @catalog.expects(:add_resource).with(bar) + + @file.expects(:recurse).returns [foo, bar] + + @file.eval_generate + end + + it "should add a relationshp edge for each returned resource" do + foo = stub 'foo', :[] => "/foo" + + @file.expects(:recurse).returns [foo] + + graph = mock 'graph' + @catalog.stubs(:relationship_graph).returns graph + + graph.expects(:add_edge).with(@file, foo) + + @file.eval_generate + end + end + + describe "when recursing" do + before do + @file[:recurse] = true + @metadata = Puppet::FileServing::Metadata + end + + describe "and a source is set" do + before { @file[:source] = "/my/source" } + + it "should pass the already-discovered resources to recurse_remote" do + @file.stubs(:recurse_local).returns(:foo => "bar") + @file.expects(:recurse_remote).with(:foo => "bar").returns [] + @file.recurse + end + end + + describe "and a target is set" do + before { @file[:target] = "/link/target" } + + it "should use recurse_link" do + @file.stubs(:recurse_local).returns(:foo => "bar") + @file.expects(:recurse_link).with(:foo => "bar").returns [] + @file.recurse + end + end + + it "should use recurse_local" do + @file.expects(:recurse_local).returns({}) + @file.recurse + end + + it "should return the generated resources as an array sorted by file path" do + one = stub 'one', :[] => "/one" + two = stub 'two', :[] => "/one/two" + three = stub 'three', :[] => "/three" + @file.expects(:recurse_local).returns(:one => one, :two => two, :three => three) + @file.recurse.should == [one, two, three] + end + + describe "and making a new child resource" do + it "should create an implicit resource using the provided relative path joined with the file's path" do + path = File.join(@file[:path], "my/path") + Puppet::Type.type(:file).expects(:create).with { |options| options[:implicit] == true and options[:path] == path } + @file.newchild("my/path") + end + + it "should copy most of the parent resource's 'should' values to the new resource" do + @file.expects(:to_hash).returns :foo => "bar", :fee => "fum" + Puppet::Type.type(:file).expects(:create).with { |options| options[:foo] == "bar" and options[:fee] == "fum" } + @file.newchild("my/path") + end + + it "should not copy the parent resource's parent" do + @file.expects(:to_hash).returns :parent => "foo" + Puppet::Type.type(:file).expects(:create).with { |options| ! options.include?(:parent) } + @file.newchild("my/path") + end + + it "should not copy the parent resource's recurse value" do + @file.expects(:to_hash).returns :recurse => true + Puppet::Type.type(:file).expects(:create).with { |options| ! options.include?(:recurse) } + @file.newchild("my/path") + end + + it "should not copy the parent resource's target value" do + @file.expects(:to_hash).returns :target => "foo" + Puppet::Type.type(:file).expects(:create).with { |options| ! options.include?(:target) } + @file.newchild("my/path") + end + + it "should not copy any nil values from the parent" do + @file.expects(:to_hash).returns :ensure => nil + Puppet::Type.type(:file).expects(:create).with { |options| ! options.include?(:ensure) } + @file.newchild("my/path") + end + end + end end diff --git a/spec/unit/type/file/source.rb b/spec/unit/type/file/source.rb new file mode 100755 index 000000000..2883e9c6b --- /dev/null +++ b/spec/unit/type/file/source.rb @@ -0,0 +1,282 @@ +#!/usr/bin/env ruby + +Dir.chdir(File.dirname(__FILE__)) { (s = lambda { |f| File.exist?(f) ? require(f) : Dir.chdir("..") { s.call(f) } }).call("spec/spec_helper.rb") } + +source = Puppet::Type.type(:file).attrclass(:source) +describe Puppet::Type.type(:file).attrclass(:source) do + before do + # Wow that's a messy interface to the resource. + @resource = stub 'resource', :uri2obj => true, :[]= => nil, :property => nil + end + + it "should be a subclass of Property" do + source.superclass.must == Puppet::Property + end + + describe "when initializing" do + it "should fail if the 'should' values are not URLs" do + s = source.new(:resource => @resource) + URI.expects(:parse).with('foo').raises RuntimeError + + lambda { s.should = %w{foo} }.must raise_error(Puppet::Error) + end + + it "should fail if the URI is not a local file, file URI, or puppet URI" do + s = source.new(:resource => @resource) + + lambda { s.should = %w{http://foo/bar} }.must raise_error(Puppet::Error) + end + end + + it "should have a method for retrieving its metadata" do + source.new(:resource => @resource).must respond_to(:metadata) + end + + it "should have a method for setting its metadata" do + source.new(:resource => @resource).must respond_to(:metadata=) + end + + describe "when returning the metadata" do + before do + @metadata = stub 'metadata', :source= => nil + end + + it "should return already-available metadata" do + @source = source.new(:resource => @resource) + @source.metadata = "foo" + @source.metadata.should == "foo" + end + + it "should return nil if no @should value is set and no metadata is available" do + @source = source.new(:resource => @resource) + @source.metadata.should be_nil + end + + it "should collect its metadata using the Metadata class if it is not already set" do + @source = source.new(:resource => @resource, :should => "/foo/bar") + Puppet::FileServing::Metadata.expects(:find).with("/foo/bar").returns @metadata + @source.metadata + end + + it "should use the metadata from the first found source" do + metadata = stub 'metadata', :source= => nil + @source = source.new(:resource => @resource, :should => ["/foo/bar", "/fee/booz"]) + Puppet::FileServing::Metadata.expects(:find).with("/foo/bar").returns nil + Puppet::FileServing::Metadata.expects(:find).with("/fee/booz").returns metadata + @source.metadata.should equal(metadata) + end + + it "should store the found source as the metadata's source" do + metadata = mock 'metadata' + @source = source.new(:resource => @resource, :should => "/foo/bar") + Puppet::FileServing::Metadata.expects(:find).with("/foo/bar").returns metadata + + metadata.expects(:source=).with("/foo/bar") + @source.metadata + end + + it "should fail intelligently if an exception is encountered while querying for metadata" do + @source = source.new(:resource => @resource, :should => "/foo/bar") + Puppet::FileServing::Metadata.expects(:find).with("/foo/bar").raises RuntimeError + + @source.expects(:fail).raises ArgumentError + lambda { @source.metadata }.should raise_error(ArgumentError) + end + + it "should fail if no specified sources can be found" do + @source = source.new(:resource => @resource, :should => "/foo/bar") + Puppet::FileServing::Metadata.expects(:find).with("/foo/bar").returns nil + + @source.expects(:fail).raises RuntimeError + + lambda { @source.metadata }.should raise_error(RuntimeError) + end + end + + it "should have a method for setting the desired values on the resource" do + source.new(:resource => @resource).must respond_to(:copy_source_values) + end + + describe "when copying the source values" do + before do + @metadata = stub 'metadata', :owner => 100, :group => 200, :mode => 123, :checksum => "{md5}asdfasdf" + + @source = source.new(:resource => @resource) + @source.metadata = @metadata + + @resource.stubs(:deleting?).returns false + end + + it "should fail if there is no metadata" do + @source.metadata = nil + @source.expects(:devfail).raises ArgumentError + lambda { @source.copy_source_values }.should raise_error(ArgumentError) + end + + it "should set :ensure to the file type" do + @resource.stubs(:[]) + @resource.stubs(:[]=) + @metadata.stubs(:ftype).returns "foobar" + + @resource.expects(:[]=).with(:ensure, "foobar") + @source.copy_source_values + end + + describe "and the source is a file" do + before do + @metadata.stubs(:ftype).returns "file" + end + + it "should copy the metadata's owner, group, and mode to the resource if they are not set on the resource" do + @resource.stubs(:[]).returns nil + + Puppet::Util::SUIDManager.expects(:uid).returns 0 + + @resource.expects(:[]=).with(:owner, 100) + @resource.expects(:[]=).with(:group, 200) + @resource.expects(:[]=).with(:mode, 123) + @resource.expects(:[]=).with(:checksum, "{md5}asdfasdf") + + @source.copy_source_values + end + + it "should copy the metadata's owner, group, and mode to the resource if they are set to :absent on the resource" do + @resource.stubs(:[]).returns :absent + + Puppet::Util::SUIDManager.expects(:uid).returns 0 + + @resource.expects(:[]=).with(:owner, 100) + @resource.expects(:[]=).with(:group, 200) + @resource.expects(:[]=).with(:mode, 123) + @resource.expects(:[]=).with(:checksum, "{md5}asdfasdf") + + @source.copy_source_values + end + + it "should not copy the metadata's owner to the resource if it is already set" do + @resource.stubs(:[]).returns "value" + @resource.expects(:[]).returns "value" + + @resource.expects(:[]=).never + + @source.copy_source_values + end + + describe "and puppet is not running as root" do + it "should not try to set the owner" do + @resource.stubs(:[]).returns nil + @resource.stubs(:[]=) + + @resource.expects(:[]=).with(:owner, 100).never + + Puppet::Util::SUIDManager.expects(:uid).returns 100 + + @source.copy_source_values + end + end + end + + describe "and the source is a link" do + it "should set the target to the link destination" do + @metadata.stubs(:ftype).returns "link" + @resource.stubs(:[]) + @resource.stubs(:[]=) + + @metadata.expects(:destination).returns "/path/to/symlink" + + @resource.expects(:[]=).with(:target, "/path/to/symlink") + @source.copy_source_values + end + end + end + + describe "when retrieving the property state" do + it "should copy all metadata to the resource" do + @source = source.new(:resource => @resource) + @source.expects(:copy_source_values) + + @source.retrieve + end + end + + describe "when flushing" do + it "should set its metadata to nil" do + @source = source.new(:resource => @resource) + @source.metadata = "foo" + @source.flush + @source.instance_variable_get("@metadata").should be_nil + end + + it "should reset its content" do + @source = source.new(:resource => @resource) + @source.instance_variable_set("@content", "foo") + @source.flush + @source.instance_variable_get("@content").should be_nil + end + end + + it "should have a method for returning the content" do + source.new(:resource => @resource).must respond_to(:content) + end + + describe "when looking up the content" do + before do + @source = source.new(:resource => @resource) + @metadata = stub 'metadata', :source => "/my/source" + @source.metadata = @metadata + + @content = stub 'content', :content => "foobar" + end + + it "should fail if the metadata does not have a source set" do + @metadata.stubs(:source).returns nil + lambda { @source.content }.should raise_error(Puppet::DevError) + end + + it "should look the content up from the Content class using the metadata source if no content is set" do + Puppet::FileServing::Content.expects(:find).with("/my/source").returns @content + @source.content.should == "foobar" + end + + it "should return previously found content" do + Puppet::FileServing::Content.expects(:find).with("/my/source").returns @content + @source.content.should == "foobar" + @source.content.should == "foobar" + end + + it "should fail if no content can be retrieved" do + Puppet::FileServing::Content.expects(:find).with("/my/source").returns nil + @source.expects(:fail).raises RuntimeError + lambda { @source.content }.should raise_error(RuntimeError) + end + end + + describe "when changing the content" do + before do + @source = source.new(:resource => @resource) + @source.stubs(:content).returns "foobar" + + @metadata = stub 'metadata', :checksum => 123 + @source.metadata = @metadata + @resource.stubs(:[]).with(:path).returns "/boo" + end + + it "should use the file's :write method to write the content" do + @resource.expects(:write).with("foobar", :source, 123) + + @source.sync + end + + it "should return :file_changed if the file already existed" do + @resource.stubs(:write) + FileTest.expects(:exist?).with("/boo").returns true + @source.sync.should == :file_changed + end + + it "should return :file_created if the file already existed" do + @resource.stubs(:write) + FileTest.expects(:exist?).with("/boo").returns false + @source.sync.should == :file_created + end + end +end |
