diff options
| author | Markus Roberts <Markus@reality.com> | 2010-07-09 18:12:17 -0700 |
|---|---|---|
| committer | Markus Roberts <Markus@reality.com> | 2010-07-09 18:12:17 -0700 |
| commit | 3180b9d9b2c844dade1d361326600f7001ec66dd (patch) | |
| tree | 98fe7c5ac7eb942aac9c39f019a17b0b3f5a57f4 /spec/unit/network | |
| parent | 543225970225de5697734bfaf0a6eee996802c04 (diff) | |
| download | puppet-3180b9d9b2c844dade1d361326600f7001ec66dd.tar.gz puppet-3180b9d9b2c844dade1d361326600f7001ec66dd.tar.xz puppet-3180b9d9b2c844dade1d361326600f7001ec66dd.zip | |
Code smell: Two space indentation
Replaced 106806 occurances of ^( +)(.*$) with
The ruby community almost universally (i.e. everyone but Luke, Markus, and the other eleven people
who learned ruby in the 1900s) uses two-space indentation.
3 Examples:
The code:
end
# Tell getopt which arguments are valid
def test_get_getopt_args
element = Setting.new :name => "foo", :desc => "anything", :settings => Puppet::Util::Settings.new
assert_equal([["--foo", GetoptLong::REQUIRED_ARGUMENT]], element.getopt_args, "Did not produce appropriate getopt args")
becomes:
end
# Tell getopt which arguments are valid
def test_get_getopt_args
element = Setting.new :name => "foo", :desc => "anything", :settings => Puppet::Util::Settings.new
assert_equal([["--foo", GetoptLong::REQUIRED_ARGUMENT]], element.getopt_args, "Did not produce appropriate getopt args")
The code:
assert_equal(str, val)
assert_instance_of(Float, result)
end
# Now test it with a passed object
becomes:
assert_equal(str, val)
assert_instance_of(Float, result)
end
# Now test it with a passed object
The code:
end
assert_nothing_raised do
klass[:Yay] = "boo"
klass["Cool"] = :yayness
end
becomes:
end
assert_nothing_raised do
klass[:Yay] = "boo"
klass["Cool"] = :yayness
end
Diffstat (limited to 'spec/unit/network')
24 files changed, 4449 insertions, 4449 deletions
diff --git a/spec/unit/network/authconfig_spec.rb b/spec/unit/network/authconfig_spec.rb index 2bf9ee138..e10458b1a 100755 --- a/spec/unit/network/authconfig_spec.rb +++ b/spec/unit/network/authconfig_spec.rb @@ -5,288 +5,288 @@ require File.dirname(__FILE__) + '/../../spec_helper' require 'puppet/network/authconfig' describe Puppet::Network::AuthConfig do - before do - @rights = stubs 'rights' - Puppet::Network::Rights.stubs(:new).returns(@rights) - @rights.stubs(:each).returns([]) + before do + @rights = stubs 'rights' + Puppet::Network::Rights.stubs(:new).returns(@rights) + @rights.stubs(:each).returns([]) - FileTest.stubs(:exists?).returns(true) - File.stubs(:stat).returns(stub('stat', :ctime => :now)) - Time.stubs(:now).returns :now + FileTest.stubs(:exists?).returns(true) + File.stubs(:stat).returns(stub('stat', :ctime => :now)) + Time.stubs(:now).returns :now - @authconfig = Puppet::Network::AuthConfig.new("dummy", false) - end - - describe "when initializing" do - before :each do - Puppet::Network::AuthConfig.any_instance.stubs(:read) - end + @authconfig = Puppet::Network::AuthConfig.new("dummy", false) + end - it "should use the authconfig default pathname if none provided" do - Puppet.expects(:[]).with(:authconfig).returns("dummy") + describe "when initializing" do + before :each do + Puppet::Network::AuthConfig.any_instance.stubs(:read) + end - Puppet::Network::AuthConfig.new - end + it "should use the authconfig default pathname if none provided" do + Puppet.expects(:[]).with(:authconfig).returns("dummy") - it "should raise an error if no file is defined finally" do - Puppet.stubs(:[]).with(:authconfig).returns(nil) + Puppet::Network::AuthConfig.new + end - lambda { Puppet::Network::AuthConfig.new }.should raise_error(Puppet::DevError) - end + it "should raise an error if no file is defined finally" do + Puppet.stubs(:[]).with(:authconfig).returns(nil) - it "should read and parse the file if parsenow is true" do - Puppet::Network::AuthConfig.any_instance.expects(:read) + lambda { Puppet::Network::AuthConfig.new }.should raise_error(Puppet::DevError) + end - Puppet::Network::AuthConfig.new("dummy", true) - end + it "should read and parse the file if parsenow is true" do + Puppet::Network::AuthConfig.any_instance.expects(:read) + Puppet::Network::AuthConfig.new("dummy", true) end - describe "when checking authorization" do - before :each do - @authconfig.stubs(:read) - @call = stub 'call', :intern => "name" - @handler = stub 'handler', :intern => "handler" - @method = stub_everything 'method' - @request = stub 'request', :call => @call, :handler => @handler, :method => @method, :name => "me", :ip => "1.2.3.4" - end + end - it "should attempt to read the authconfig file" do - @rights.stubs(:include?) + describe "when checking authorization" do + before :each do + @authconfig.stubs(:read) + @call = stub 'call', :intern => "name" + @handler = stub 'handler', :intern => "handler" + @method = stub_everything 'method' + @request = stub 'request', :call => @call, :handler => @handler, :method => @method, :name => "me", :ip => "1.2.3.4" + end - @authconfig.expects(:read) + it "should attempt to read the authconfig file" do + @rights.stubs(:include?) - @authconfig.allowed?(@request) - end + @authconfig.expects(:read) - it "should use a name right if it exists" do - right = stub 'right' + @authconfig.allowed?(@request) + end - @rights.stubs(:include?).with("name").returns(true) - @rights.stubs(:[]).with("name").returns(right) + it "should use a name right if it exists" do + right = stub 'right' - right.expects(:allowed?).with("me", "1.2.3.4") + @rights.stubs(:include?).with("name").returns(true) + @rights.stubs(:[]).with("name").returns(right) - @authconfig.allowed?(@request) - end + right.expects(:allowed?).with("me", "1.2.3.4") - it "should use a namespace right otherwise" do - right = stub 'right' + @authconfig.allowed?(@request) + end - @rights.stubs(:include?).with("name").returns(false) - @rights.stubs(:include?).with("handler").returns(true) - @rights.stubs(:[]).with("handler").returns(right) + it "should use a namespace right otherwise" do + right = stub 'right' - right.expects(:allowed?).with("me", "1.2.3.4") + @rights.stubs(:include?).with("name").returns(false) + @rights.stubs(:include?).with("handler").returns(true) + @rights.stubs(:[]).with("handler").returns(right) - @authconfig.allowed?(@request) - end + right.expects(:allowed?).with("me", "1.2.3.4") - it "should return whatever the found rights returns" do - right = stub 'right' + @authconfig.allowed?(@request) + end - @rights.stubs(:include?).with("name").returns(true) - @rights.stubs(:[]).with("name").returns(right) + it "should return whatever the found rights returns" do + right = stub 'right' - right.stubs(:allowed?).with("me", "1.2.3.4").returns(:returned) + @rights.stubs(:include?).with("name").returns(true) + @rights.stubs(:[]).with("name").returns(right) - @authconfig.allowed?(@request).should == :returned - end + right.stubs(:allowed?).with("me", "1.2.3.4").returns(:returned) + @authconfig.allowed?(@request).should == :returned end - describe "when parsing authconfig file" do - before :each do - @fd = stub 'fd' - File.stubs(:open).yields(@fd) - @rights.stubs(:include?).returns(false) - @rights.stubs(:[]) - end + end - it "should skip comments" do - @fd.stubs(:each).yields(' # comment') + describe "when parsing authconfig file" do + before :each do + @fd = stub 'fd' + File.stubs(:open).yields(@fd) + @rights.stubs(:include?).returns(false) + @rights.stubs(:[]) + end - @rights.expects(:newright).never + it "should skip comments" do + @fd.stubs(:each).yields(' # comment') - @authconfig.read - end + @rights.expects(:newright).never - it "should increment line number even on commented lines" do - @fd.stubs(:each).multiple_yields(' # comment','[puppetca]') + @authconfig.read + end - @rights.expects(:newright).with('[puppetca]', 2, 'dummy') + it "should increment line number even on commented lines" do + @fd.stubs(:each).multiple_yields(' # comment','[puppetca]') - @authconfig.read - end + @rights.expects(:newright).with('[puppetca]', 2, 'dummy') - it "should skip blank lines" do - @fd.stubs(:each).yields(' ') + @authconfig.read + end - @rights.expects(:newright).never + it "should skip blank lines" do + @fd.stubs(:each).yields(' ') - @authconfig.read - end + @rights.expects(:newright).never - it "should increment line number even on blank lines" do - @fd.stubs(:each).multiple_yields(' ','[puppetca]') + @authconfig.read + end - @rights.expects(:newright).with('[puppetca]', 2, 'dummy') + it "should increment line number even on blank lines" do + @fd.stubs(:each).multiple_yields(' ','[puppetca]') - @authconfig.read - end + @rights.expects(:newright).with('[puppetca]', 2, 'dummy') - it "should throw an error if the current namespace right already exist" do - @fd.stubs(:each).yields('[puppetca]') + @authconfig.read + end - @rights.stubs(:include?).with("puppetca").returns(true) + it "should throw an error if the current namespace right already exist" do + @fd.stubs(:each).yields('[puppetca]') - lambda { @authconfig.read }.should raise_error - end + @rights.stubs(:include?).with("puppetca").returns(true) - it "should not throw an error if the current path right already exist" do - @fd.stubs(:each).yields('path /hello') + lambda { @authconfig.read }.should raise_error + end - @rights.stubs(:newright).with("/hello",1, 'dummy') - @rights.stubs(:include?).with("/hello").returns(true) + it "should not throw an error if the current path right already exist" do + @fd.stubs(:each).yields('path /hello') - lambda { @authconfig.read }.should_not raise_error - end + @rights.stubs(:newright).with("/hello",1, 'dummy') + @rights.stubs(:include?).with("/hello").returns(true) - it "should create a new right for found namespaces" do - @fd.stubs(:each).yields('[puppetca]') + lambda { @authconfig.read }.should_not raise_error + end - @rights.expects(:newright).with("[puppetca]", 1, 'dummy') + it "should create a new right for found namespaces" do + @fd.stubs(:each).yields('[puppetca]') - @authconfig.read - end + @rights.expects(:newright).with("[puppetca]", 1, 'dummy') - it "should create a new right for each found namespace line" do - @fd.stubs(:each).multiple_yields('[puppetca]', '[fileserver]') + @authconfig.read + end - @rights.expects(:newright).with("[puppetca]", 1, 'dummy') - @rights.expects(:newright).with("[fileserver]", 2, 'dummy') + it "should create a new right for each found namespace line" do + @fd.stubs(:each).multiple_yields('[puppetca]', '[fileserver]') - @authconfig.read - end + @rights.expects(:newright).with("[puppetca]", 1, 'dummy') + @rights.expects(:newright).with("[fileserver]", 2, 'dummy') - it "should create a new right for each found path line" do - @fd.stubs(:each).multiple_yields('path /certificates') + @authconfig.read + end - @rights.expects(:newright).with("/certificates", 1, 'dummy') + it "should create a new right for each found path line" do + @fd.stubs(:each).multiple_yields('path /certificates') - @authconfig.read - end + @rights.expects(:newright).with("/certificates", 1, 'dummy') - it "should create a new right for each found regex line" do - @fd.stubs(:each).multiple_yields('path ~ .rb$') + @authconfig.read + end - @rights.expects(:newright).with("~ .rb$", 1, 'dummy') + it "should create a new right for each found regex line" do + @fd.stubs(:each).multiple_yields('path ~ .rb$') - @authconfig.read - end + @rights.expects(:newright).with("~ .rb$", 1, 'dummy') - it "should create an allow ACE on each subsequent allow" do - acl = stub 'acl', :info + @authconfig.read + end - @fd.stubs(:each).multiple_yields('[puppetca]', 'allow 127.0.0.1') - @rights.stubs(:newright).with("[puppetca]", 1, 'dummy').returns(acl) + it "should create an allow ACE on each subsequent allow" do + acl = stub 'acl', :info - acl.expects(:allow).with('127.0.0.1') + @fd.stubs(:each).multiple_yields('[puppetca]', 'allow 127.0.0.1') + @rights.stubs(:newright).with("[puppetca]", 1, 'dummy').returns(acl) - @authconfig.read - end + acl.expects(:allow).with('127.0.0.1') - it "should create a deny ACE on each subsequent deny" do - acl = stub 'acl', :info + @authconfig.read + end - @fd.stubs(:each).multiple_yields('[puppetca]', 'deny 127.0.0.1') - @rights.stubs(:newright).with("[puppetca]", 1, 'dummy').returns(acl) + it "should create a deny ACE on each subsequent deny" do + acl = stub 'acl', :info - acl.expects(:deny).with('127.0.0.1') + @fd.stubs(:each).multiple_yields('[puppetca]', 'deny 127.0.0.1') + @rights.stubs(:newright).with("[puppetca]", 1, 'dummy').returns(acl) - @authconfig.read - end + acl.expects(:deny).with('127.0.0.1') - it "should inform the current ACL if we get the 'method' directive" do - acl = stub 'acl', :info - acl.stubs(:acl_type).returns(:regex) + @authconfig.read + end - @fd.stubs(:each).multiple_yields('path /certificates', 'method search,find') - @rights.stubs(:newright).with("/certificates", 1, 'dummy').returns(acl) + it "should inform the current ACL if we get the 'method' directive" do + acl = stub 'acl', :info + acl.stubs(:acl_type).returns(:regex) - acl.expects(:restrict_method).with('search') - acl.expects(:restrict_method).with('find') + @fd.stubs(:each).multiple_yields('path /certificates', 'method search,find') + @rights.stubs(:newright).with("/certificates", 1, 'dummy').returns(acl) - @authconfig.read - end + acl.expects(:restrict_method).with('search') + acl.expects(:restrict_method).with('find') - it "should raise an error if the 'method' directive is used in a right different than a path/regex one" do - acl = stub 'acl', :info - acl.stubs(:acl_type).returns(:regex) + @authconfig.read + end - @fd.stubs(:each).multiple_yields('[puppetca]', 'method search,find') - @rights.stubs(:newright).with("puppetca", 1, 'dummy').returns(acl) + it "should raise an error if the 'method' directive is used in a right different than a path/regex one" do + acl = stub 'acl', :info + acl.stubs(:acl_type).returns(:regex) - lambda { @authconfig.read }.should raise_error - end + @fd.stubs(:each).multiple_yields('[puppetca]', 'method search,find') + @rights.stubs(:newright).with("puppetca", 1, 'dummy').returns(acl) - it "should inform the current ACL if we get the 'environment' directive" do - acl = stub 'acl', :info - acl.stubs(:acl_type).returns(:regex) + lambda { @authconfig.read }.should raise_error + end - @fd.stubs(:each).multiple_yields('path /certificates', 'environment production,development') - @rights.stubs(:newright).with("/certificates", 1, 'dummy').returns(acl) + it "should inform the current ACL if we get the 'environment' directive" do + acl = stub 'acl', :info + acl.stubs(:acl_type).returns(:regex) - acl.expects(:restrict_environment).with('production') - acl.expects(:restrict_environment).with('development') + @fd.stubs(:each).multiple_yields('path /certificates', 'environment production,development') + @rights.stubs(:newright).with("/certificates", 1, 'dummy').returns(acl) - @authconfig.read - end + acl.expects(:restrict_environment).with('production') + acl.expects(:restrict_environment).with('development') - it "should raise an error if the 'environment' directive is used in a right different than a path/regex one" do - acl = stub 'acl', :info - acl.stubs(:acl_type).returns(:regex) + @authconfig.read + end - @fd.stubs(:each).multiple_yields('[puppetca]', 'environment env') - @rights.stubs(:newright).with("puppetca", 1, 'dummy').returns(acl) + it "should raise an error if the 'environment' directive is used in a right different than a path/regex one" do + acl = stub 'acl', :info + acl.stubs(:acl_type).returns(:regex) - lambda { @authconfig.read }.should raise_error - end + @fd.stubs(:each).multiple_yields('[puppetca]', 'environment env') + @rights.stubs(:newright).with("puppetca", 1, 'dummy').returns(acl) - it "should inform the current ACL if we get the 'auth' directive" do - acl = stub 'acl', :info - acl.stubs(:acl_type).returns(:regex) + lambda { @authconfig.read }.should raise_error + end - @fd.stubs(:each).multiple_yields('path /certificates', 'auth yes') - @rights.stubs(:newright).with("/certificates", 1, 'dummy').returns(acl) + it "should inform the current ACL if we get the 'auth' directive" do + acl = stub 'acl', :info + acl.stubs(:acl_type).returns(:regex) - acl.expects(:restrict_authenticated).with('yes') + @fd.stubs(:each).multiple_yields('path /certificates', 'auth yes') + @rights.stubs(:newright).with("/certificates", 1, 'dummy').returns(acl) - @authconfig.read - end + acl.expects(:restrict_authenticated).with('yes') - it "should also allow the longest 'authenticated' directive" do - acl = stub 'acl', :info - acl.stubs(:acl_type).returns(:regex) + @authconfig.read + end - @fd.stubs(:each).multiple_yields('path /certificates', 'authenticated yes') - @rights.stubs(:newright).with("/certificates", 1, 'dummy').returns(acl) + it "should also allow the longest 'authenticated' directive" do + acl = stub 'acl', :info + acl.stubs(:acl_type).returns(:regex) - acl.expects(:restrict_authenticated).with('yes') + @fd.stubs(:each).multiple_yields('path /certificates', 'authenticated yes') + @rights.stubs(:newright).with("/certificates", 1, 'dummy').returns(acl) - @authconfig.read - end + acl.expects(:restrict_authenticated).with('yes') - it "should raise an error if the 'auth' directive is used in a right different than a path/regex one" do - acl = stub 'acl', :info - acl.stubs(:acl_type).returns(:regex) + @authconfig.read + end - @fd.stubs(:each).multiple_yields('[puppetca]', 'auth yes') - @rights.stubs(:newright).with("puppetca", 1, 'dummy').returns(acl) + it "should raise an error if the 'auth' directive is used in a right different than a path/regex one" do + acl = stub 'acl', :info + acl.stubs(:acl_type).returns(:regex) - lambda { @authconfig.read }.should raise_error - end + @fd.stubs(:each).multiple_yields('[puppetca]', 'auth yes') + @rights.stubs(:newright).with("puppetca", 1, 'dummy').returns(acl) + lambda { @authconfig.read }.should raise_error end + end + end diff --git a/spec/unit/network/authstore_spec.rb b/spec/unit/network/authstore_spec.rb index e3f819479..094352c63 100644 --- a/spec/unit/network/authstore_spec.rb +++ b/spec/unit/network/authstore_spec.rb @@ -5,366 +5,366 @@ require File.dirname(__FILE__) + '/../../spec_helper' require 'puppet/network/authconfig' describe Puppet::Network::AuthStore do - describe "when checking if the acl has some entries" do - before :each do - @authstore = Puppet::Network::AuthStore.new - end + describe "when checking if the acl has some entries" do + before :each do + @authstore = Puppet::Network::AuthStore.new + end - it "should be empty if no ACE have been entered" do - @authstore.should be_empty - end + it "should be empty if no ACE have been entered" do + @authstore.should be_empty + end - it "should not be empty if it is a global allow" do - @authstore.allow('*') + it "should not be empty if it is a global allow" do + @authstore.allow('*') - @authstore.should_not be_empty - end + @authstore.should_not be_empty + end - it "should not be empty if at least one allow has been entered" do - @authstore.allow('1.1.1.*') + it "should not be empty if at least one allow has been entered" do + @authstore.allow('1.1.1.*') - @authstore.should_not be_empty - end + @authstore.should_not be_empty + end - it "should not be empty if at least one deny has been entered" do - @authstore.deny('1.1.1.*') + it "should not be empty if at least one deny has been entered" do + @authstore.deny('1.1.1.*') - @authstore.should_not be_empty - end + @authstore.should_not be_empty end + end end describe Puppet::Network::AuthStore::Declaration do - ['100.101.99.98','100.100.100.100','1.2.3.4','11.22.33.44'].each { |ip| - describe "when the pattern is a simple numeric IP such as #{ip}" do - before :each do - @declaration = Puppet::Network::AuthStore::Declaration.new(:allow,ip) - end - it "should match the specified IP" do - @declaration.should be_match('www.testsite.org',ip) - end - it "should not match other IPs" do - @declaration.should_not be_match('www.testsite.org','200.101.99.98') - end - end - - (1..3).each { |n| - describe "when the pattern is a IP mask with #{n} numeric segments and a *" do - before :each do - @ip_pattern = ip.split('.')[0,n].join('.')+'.*' - @declaration = Puppet::Network::AuthStore::Declaration.new(:allow,@ip_pattern) - end - it "should match an IP in the range" do - @declaration.should be_match('www.testsite.org',ip) - end - it "should not match other IPs" do - @declaration.should_not be_match('www.testsite.org','200.101.99.98') - end - it "should not match IPs that differ in the last non-wildcard segment" do - other = ip.split('.') - other[n-1].succ! - @declaration.should_not be_match('www.testsite.org',other.join('.')) - end - end - } - } + ['100.101.99.98','100.100.100.100','1.2.3.4','11.22.33.44'].each { |ip| + describe "when the pattern is a simple numeric IP such as #{ip}" do + before :each do + @declaration = Puppet::Network::AuthStore::Declaration.new(:allow,ip) + end + it "should match the specified IP" do + @declaration.should be_match('www.testsite.org',ip) + end + it "should not match other IPs" do + @declaration.should_not be_match('www.testsite.org','200.101.99.98') + end + end - describe "when the pattern is a numeric IP with a back reference" do + (1..3).each { |n| + describe "when the pattern is a IP mask with #{n} numeric segments and a *" do before :each do - @ip = '100.101.$1' - @declaration = Puppet::Network::AuthStore::Declaration.new(:allow,@ip).interpolate('12.34'.match(/(.*)/)) + @ip_pattern = ip.split('.')[0,n].join('.')+'.*' + @declaration = Puppet::Network::AuthStore::Declaration.new(:allow,@ip_pattern) end - it "should match an IP with the appropriate interpolation" do - @declaration.should be_match('www.testsite.org',@ip.sub(/\$1/,'12.34')) + it "should match an IP in the range" do + @declaration.should be_match('www.testsite.org',ip) end it "should not match other IPs" do - @declaration.should_not be_match('www.testsite.org',@ip.sub(/\$1/,'66.34')) + @declaration.should_not be_match('www.testsite.org','200.101.99.98') end - end - - [ - "02001:0000:1234:0000:0000:C1C0:ABCD:0876", - "2001:0000:1234:0000:00001:C1C0:ABCD:0876", - " 2001:0000:1234:0000:0000:C1C0:ABCD:0876 0", - "2001:0000:1234: 0000:0000:C1C0:ABCD:0876", - "3ffe:0b00:0000:0001:0000:0000:000a", - "FF02:0000:0000:0000:0000:0000:0000:0000:0001", - "3ffe:b00::1::a", - "1:2:3::4:5::7:8", - "12345::6:7:8", - "1::5:400.2.3.4", - "1::5:260.2.3.4", - "1::5:256.2.3.4", - "1::5:1.256.3.4", - "1::5:1.2.256.4", - "1::5:1.2.3.256", - "1::5:300.2.3.4", - "1::5:1.300.3.4", - "1::5:1.2.300.4", - "1::5:1.2.3.300", - "1::5:900.2.3.4", - "1::5:1.900.3.4", - "1::5:1.2.900.4", - "1::5:1.2.3.900", - "1::5:300.300.300.300", - "1::5:3000.30.30.30", - "1::400.2.3.4", - "1::260.2.3.4", - "1::256.2.3.4", - "1::1.256.3.4", - "1::1.2.256.4", - "1::1.2.3.256", - "1::300.2.3.4", - "1::1.300.3.4", - "1::1.2.300.4", - "1::1.2.3.300", - "1::900.2.3.4", - "1::1.900.3.4", - "1::1.2.900.4", - "1::1.2.3.900", - "1::300.300.300.300", - "1::3000.30.30.30", - "::400.2.3.4", - "::260.2.3.4", - "::256.2.3.4", - "::1.256.3.4", - "::1.2.256.4", - "::1.2.3.256", - "::300.2.3.4", - "::1.300.3.4", - "::1.2.300.4", - "::1.2.3.300", - "::900.2.3.4", - "::1.900.3.4", - "::1.2.900.4", - "::1.2.3.900", - "::300.300.300.300", - "::3000.30.30.30", - "2001:DB8:0:0:8:800:200C:417A:221", # unicast, full - "FF01::101::2" # multicast, compressed - ].each { |invalid_ip| - describe "when the pattern is an invalid IPv6 address such as #{invalid_ip}" do - it "should raise an exception" do - lambda { Puppet::Network::AuthStore::Declaration.new(:allow,invalid_ip) }.should raise_error - end + it "should not match IPs that differ in the last non-wildcard segment" do + other = ip.split('.') + other[n-1].succ! + @declaration.should_not be_match('www.testsite.org',other.join('.')) end + end } + } - [ - "1.2.3.4", - "2001:0000:1234:0000:0000:C1C0:ABCD:0876", - "3ffe:0b00:0000:0000:0001:0000:0000:000a", - "FF02:0000:0000:0000:0000:0000:0000:0001", - "0000:0000:0000:0000:0000:0000:0000:0001", - "0000:0000:0000:0000:0000:0000:0000:0000", - "::ffff:192.168.1.26", - "2::10", - "ff02::1", - "fe80::", - "2002::", - "2001:db8::", - "2001:0db8:1234::", - "::ffff:0:0", - "::1", - "::ffff:192.168.1.1", - "1:2:3:4:5:6:7:8", - "1:2:3:4:5:6::8", - "1:2:3:4:5::8", - "1:2:3:4::8", - "1:2:3::8", - "1:2::8", - "1::8", - "1::2:3:4:5:6:7", - "1::2:3:4:5:6", - "1::2:3:4:5", - "1::2:3:4", - "1::2:3", - "1::8", - "::2:3:4:5:6:7:8", - "::2:3:4:5:6:7", - "::2:3:4:5:6", - "::2:3:4:5", - "::2:3:4", - "::2:3", - "::8", - "1:2:3:4:5:6::", - "1:2:3:4:5::", - "1:2:3:4::", - "1:2:3::", - "1:2::", - "1::", - "1:2:3:4:5::7:8", - "1:2:3:4::7:8", - "1:2:3::7:8", - "1:2::7:8", - "1::7:8", - "1:2:3:4:5:6:1.2.3.4", - "1:2:3:4:5::1.2.3.4", - "1:2:3:4::1.2.3.4", - "1:2:3::1.2.3.4", - "1:2::1.2.3.4", - "1::1.2.3.4", - "1:2:3:4::5:1.2.3.4", - "1:2:3::5:1.2.3.4", - "1:2::5:1.2.3.4", - "1::5:1.2.3.4", - "1::5:11.22.33.44", - "fe80::217:f2ff:254.7.237.98", - "fe80::217:f2ff:fe07:ed62", - "2001:DB8:0:0:8:800:200C:417A", # unicast, full - "FF01:0:0:0:0:0:0:101", # multicast, full - "0:0:0:0:0:0:0:1", # loopback, full - "0:0:0:0:0:0:0:0", # unspecified, full - "2001:DB8::8:800:200C:417A", # unicast, compressed - "FF01::101", # multicast, compressed - "::1", # loopback, compressed, non-routable - "::", # unspecified, compressed, non-routable - "0:0:0:0:0:0:13.1.68.3", # IPv4-compatible IPv6 address, full, deprecated - "0:0:0:0:0:FFFF:129.144.52.38", # IPv4-mapped IPv6 address, full - "::13.1.68.3", # IPv4-compatible IPv6 address, compressed, deprecated - "::FFFF:129.144.52.38", # IPv4-mapped IPv6 address, compressed - "2001:0DB8:0000:CD30:0000:0000:0000:0000/60", # full, with prefix - "2001:0DB8::CD30:0:0:0:0/60", # compressed, with prefix - "2001:0DB8:0:CD30::/60", # compressed, with prefix #2 - "::/128", # compressed, unspecified address type, non-routable - "::1/128", # compressed, loopback address type, non-routable - "FF00::/8", # compressed, multicast address type - "FE80::/10", # compressed, link-local unicast, non-routable - "FEC0::/10", # compressed, site-local unicast, deprecated - "127.0.0.1", # standard IPv4, loopback, non-routable - "0.0.0.0", # standard IPv4, unspecified, non-routable - "255.255.255.255", # standard IPv4 - "fe80:0000:0000:0000:0204:61ff:fe9d:f156", - "fe80:0:0:0:204:61ff:fe9d:f156", - "fe80::204:61ff:fe9d:f156", - "fe80:0000:0000:0000:0204:61ff:254.157.241.086", - "fe80:0:0:0:204:61ff:254.157.241.86", - "fe80::204:61ff:254.157.241.86", - "::1", - "fe80::", - "fe80::1" - ].each { |ip| - describe "when the pattern is a valid IP such as #{ip}" do - before :each do - @declaration = Puppet::Network::AuthStore::Declaration.new(:allow,ip) - end - it "should match the specified IP" do - @declaration.should be_match('www.testsite.org',ip) - end - it "should not match other IPs" do - @declaration.should_not be_match('www.testsite.org','200.101.99.98') - end - end unless ip =~ /:.*\./ # Hybrid IPs aren't supported by ruby's ipaddr - } + describe "when the pattern is a numeric IP with a back reference" do + before :each do + @ip = '100.101.$1' + @declaration = Puppet::Network::AuthStore::Declaration.new(:allow,@ip).interpolate('12.34'.match(/(.*)/)) + end + it "should match an IP with the appropriate interpolation" do + @declaration.should be_match('www.testsite.org',@ip.sub(/\$1/,'12.34')) + end + it "should not match other IPs" do + @declaration.should_not be_match('www.testsite.org',@ip.sub(/\$1/,'66.34')) + end + end - { - 'spirit.mars.nasa.gov' => 'a PQDN', - 'ratchet.2ndsiteinc.com' => 'a PQDN with digits', - 'a.c.ru' => 'a PQDN with short segments', - }.each {|pqdn,desc| - describe "when the pattern is #{desc}" do - before :each do - @host = pqdn - @declaration = Puppet::Network::AuthStore::Declaration.new(:allow,@host) - end - it "should match the specified PQDN" do - @declaration.should be_match(@host,'200.101.99.98') - end - it "should not match a similar FQDN" do - pending "FQDN consensus" - @declaration.should_not be_match(@host+'.','200.101.99.98') - end - end - } + [ + "02001:0000:1234:0000:0000:C1C0:ABCD:0876", + "2001:0000:1234:0000:00001:C1C0:ABCD:0876", + " 2001:0000:1234:0000:0000:C1C0:ABCD:0876 0", + "2001:0000:1234: 0000:0000:C1C0:ABCD:0876", + "3ffe:0b00:0000:0001:0000:0000:000a", + "FF02:0000:0000:0000:0000:0000:0000:0000:0001", + "3ffe:b00::1::a", + "1:2:3::4:5::7:8", + "12345::6:7:8", + "1::5:400.2.3.4", + "1::5:260.2.3.4", + "1::5:256.2.3.4", + "1::5:1.256.3.4", + "1::5:1.2.256.4", + "1::5:1.2.3.256", + "1::5:300.2.3.4", + "1::5:1.300.3.4", + "1::5:1.2.300.4", + "1::5:1.2.3.300", + "1::5:900.2.3.4", + "1::5:1.900.3.4", + "1::5:1.2.900.4", + "1::5:1.2.3.900", + "1::5:300.300.300.300", + "1::5:3000.30.30.30", + "1::400.2.3.4", + "1::260.2.3.4", + "1::256.2.3.4", + "1::1.256.3.4", + "1::1.2.256.4", + "1::1.2.3.256", + "1::300.2.3.4", + "1::1.300.3.4", + "1::1.2.300.4", + "1::1.2.3.300", + "1::900.2.3.4", + "1::1.900.3.4", + "1::1.2.900.4", + "1::1.2.3.900", + "1::300.300.300.300", + "1::3000.30.30.30", + "::400.2.3.4", + "::260.2.3.4", + "::256.2.3.4", + "::1.256.3.4", + "::1.2.256.4", + "::1.2.3.256", + "::300.2.3.4", + "::1.300.3.4", + "::1.2.300.4", + "::1.2.3.300", + "::900.2.3.4", + "::1.900.3.4", + "::1.2.900.4", + "::1.2.3.900", + "::300.300.300.300", + "::3000.30.30.30", + "2001:DB8:0:0:8:800:200C:417A:221", # unicast, full + "FF01::101::2" # multicast, compressed + ].each { |invalid_ip| + describe "when the pattern is an invalid IPv6 address such as #{invalid_ip}" do + it "should raise an exception" do + lambda { Puppet::Network::AuthStore::Declaration.new(:allow,invalid_ip) }.should raise_error + end + end + } - ['abc.12seps.edu.phisher.biz','www.google.com','slashdot.org'].each { |host| - (1...(host.split('.').length)).each { |n| - describe "when the pattern is #{"*."+host.split('.')[-n,n].join('.')}" do - before :each do - @pattern = "*."+host.split('.')[-n,n].join('.') - @declaration = Puppet::Network::AuthStore::Declaration.new(:allow,@pattern) - end - it "should match #{host}" do - @declaration.should be_match(host,'1.2.3.4') - end - it "should not match www.testsite.gov" do - @declaration.should_not be_match('www.testsite.gov','200.101.99.98') - end - it "should not match hosts that differ in the first non-wildcard segment" do - other = host.split('.') - other[-n].succ! - @declaration.should_not be_match(other.join('.'),'1.2.3.4') - end - end - } - } + [ + "1.2.3.4", + "2001:0000:1234:0000:0000:C1C0:ABCD:0876", + "3ffe:0b00:0000:0000:0001:0000:0000:000a", + "FF02:0000:0000:0000:0000:0000:0000:0001", + "0000:0000:0000:0000:0000:0000:0000:0001", + "0000:0000:0000:0000:0000:0000:0000:0000", + "::ffff:192.168.1.26", + "2::10", + "ff02::1", + "fe80::", + "2002::", + "2001:db8::", + "2001:0db8:1234::", + "::ffff:0:0", + "::1", + "::ffff:192.168.1.1", + "1:2:3:4:5:6:7:8", + "1:2:3:4:5:6::8", + "1:2:3:4:5::8", + "1:2:3:4::8", + "1:2:3::8", + "1:2::8", + "1::8", + "1::2:3:4:5:6:7", + "1::2:3:4:5:6", + "1::2:3:4:5", + "1::2:3:4", + "1::2:3", + "1::8", + "::2:3:4:5:6:7:8", + "::2:3:4:5:6:7", + "::2:3:4:5:6", + "::2:3:4:5", + "::2:3:4", + "::2:3", + "::8", + "1:2:3:4:5:6::", + "1:2:3:4:5::", + "1:2:3:4::", + "1:2:3::", + "1:2::", + "1::", + "1:2:3:4:5::7:8", + "1:2:3:4::7:8", + "1:2:3::7:8", + "1:2::7:8", + "1::7:8", + "1:2:3:4:5:6:1.2.3.4", + "1:2:3:4:5::1.2.3.4", + "1:2:3:4::1.2.3.4", + "1:2:3::1.2.3.4", + "1:2::1.2.3.4", + "1::1.2.3.4", + "1:2:3:4::5:1.2.3.4", + "1:2:3::5:1.2.3.4", + "1:2::5:1.2.3.4", + "1::5:1.2.3.4", + "1::5:11.22.33.44", + "fe80::217:f2ff:254.7.237.98", + "fe80::217:f2ff:fe07:ed62", + "2001:DB8:0:0:8:800:200C:417A", # unicast, full + "FF01:0:0:0:0:0:0:101", # multicast, full + "0:0:0:0:0:0:0:1", # loopback, full + "0:0:0:0:0:0:0:0", # unspecified, full + "2001:DB8::8:800:200C:417A", # unicast, compressed + "FF01::101", # multicast, compressed + "::1", # loopback, compressed, non-routable + "::", # unspecified, compressed, non-routable + "0:0:0:0:0:0:13.1.68.3", # IPv4-compatible IPv6 address, full, deprecated + "0:0:0:0:0:FFFF:129.144.52.38", # IPv4-mapped IPv6 address, full + "::13.1.68.3", # IPv4-compatible IPv6 address, compressed, deprecated + "::FFFF:129.144.52.38", # IPv4-mapped IPv6 address, compressed + "2001:0DB8:0000:CD30:0000:0000:0000:0000/60", # full, with prefix + "2001:0DB8::CD30:0:0:0:0/60", # compressed, with prefix + "2001:0DB8:0:CD30::/60", # compressed, with prefix #2 + "::/128", # compressed, unspecified address type, non-routable + "::1/128", # compressed, loopback address type, non-routable + "FF00::/8", # compressed, multicast address type + "FE80::/10", # compressed, link-local unicast, non-routable + "FEC0::/10", # compressed, site-local unicast, deprecated + "127.0.0.1", # standard IPv4, loopback, non-routable + "0.0.0.0", # standard IPv4, unspecified, non-routable + "255.255.255.255", # standard IPv4 + "fe80:0000:0000:0000:0204:61ff:fe9d:f156", + "fe80:0:0:0:204:61ff:fe9d:f156", + "fe80::204:61ff:fe9d:f156", + "fe80:0000:0000:0000:0204:61ff:254.157.241.086", + "fe80:0:0:0:204:61ff:254.157.241.86", + "fe80::204:61ff:254.157.241.86", + "::1", + "fe80::", + "fe80::1" + ].each { |ip| + describe "when the pattern is a valid IP such as #{ip}" do + before :each do + @declaration = Puppet::Network::AuthStore::Declaration.new(:allow,ip) + end + it "should match the specified IP" do + @declaration.should be_match('www.testsite.org',ip) + end + it "should not match other IPs" do + @declaration.should_not be_match('www.testsite.org','200.101.99.98') + end + end unless ip =~ /:.*\./ # Hybrid IPs aren't supported by ruby's ipaddr + } + + { + 'spirit.mars.nasa.gov' => 'a PQDN', + 'ratchet.2ndsiteinc.com' => 'a PQDN with digits', + 'a.c.ru' => 'a PQDN with short segments', + }.each {|pqdn,desc| + describe "when the pattern is #{desc}" do + before :each do + @host = pqdn + @declaration = Puppet::Network::AuthStore::Declaration.new(:allow,@host) + end + it "should match the specified PQDN" do + @declaration.should be_match(@host,'200.101.99.98') + end + it "should not match a similar FQDN" do + pending "FQDN consensus" + @declaration.should_not be_match(@host+'.','200.101.99.98') + end + end + } - describe "when the pattern is a FQDN" do + ['abc.12seps.edu.phisher.biz','www.google.com','slashdot.org'].each { |host| + (1...(host.split('.').length)).each { |n| + describe "when the pattern is #{"*."+host.split('.')[-n,n].join('.')}" do before :each do - @host = 'spirit.mars.nasa.gov.' - @declaration = Puppet::Network::AuthStore::Declaration.new(:allow,@host) + @pattern = "*."+host.split('.')[-n,n].join('.') + @declaration = Puppet::Network::AuthStore::Declaration.new(:allow,@pattern) end - it "should match the specified FQDN" do - pending "FQDN consensus" - @declaration.should be_match(@host,'200.101.99.98') + it "should match #{host}" do + @declaration.should be_match(host,'1.2.3.4') end - it "should not match a similar PQDN" do - @declaration.should_not be_match(@host[0..-2],'200.101.99.98') + it "should not match www.testsite.gov" do + @declaration.should_not be_match('www.testsite.gov','200.101.99.98') end + it "should not match hosts that differ in the first non-wildcard segment" do + other = host.split('.') + other[-n].succ! + @declaration.should_not be_match(other.join('.'),'1.2.3.4') + end + end + } + } + + describe "when the pattern is a FQDN" do + before :each do + @host = 'spirit.mars.nasa.gov.' + @declaration = Puppet::Network::AuthStore::Declaration.new(:allow,@host) + end + it "should match the specified FQDN" do + pending "FQDN consensus" + @declaration.should be_match(@host,'200.101.99.98') end + it "should not match a similar PQDN" do + @declaration.should_not be_match(@host[0..-2],'200.101.99.98') + end + end - describe "when the pattern is an opaque string with a back reference" do - before :each do - @host = 'c216f41a-f902-4bfb-a222-850dd957bebb' - @item = "/catalog/#{@host}" - @pattern = %{^/catalog/([^/]+)$} - @declaration = Puppet::Network::AuthStore::Declaration.new(:allow,'$1') - end - it "should match an IP with the appropriate interpolation" do - @declaration.interpolate(@item.match(@pattern)).should be_match(@host,'10.0.0.5') - end + describe "when the pattern is an opaque string with a back reference" do + before :each do + @host = 'c216f41a-f902-4bfb-a222-850dd957bebb' + @item = "/catalog/#{@host}" + @pattern = %{^/catalog/([^/]+)$} + @declaration = Puppet::Network::AuthStore::Declaration.new(:allow,'$1') + end + it "should match an IP with the appropriate interpolation" do + @declaration.interpolate(@item.match(@pattern)).should be_match(@host,'10.0.0.5') end + end - describe "when the pattern is an opaque string with a back reference and the matched data contains dots" do - before :each do - @host = 'admin.mgmt.nym1' - @item = "/catalog/#{@host}" - @pattern = %{^/catalog/([^/]+)$} - @declaration = Puppet::Network::AuthStore::Declaration.new(:allow,'$1') - end - it "should match a name with the appropriate interpolation" do - @declaration.interpolate(@item.match(@pattern)).should be_match(@host,'10.0.0.5') - end + describe "when the pattern is an opaque string with a back reference and the matched data contains dots" do + before :each do + @host = 'admin.mgmt.nym1' + @item = "/catalog/#{@host}" + @pattern = %{^/catalog/([^/]+)$} + @declaration = Puppet::Network::AuthStore::Declaration.new(:allow,'$1') + end + it "should match a name with the appropriate interpolation" do + @declaration.interpolate(@item.match(@pattern)).should be_match(@host,'10.0.0.5') end + end - describe "when the pattern is an opaque string with a back reference and the matched data contains dots with an initial prefix that looks like an IP address" do - before :each do - @host = '01.admin.mgmt.nym1' - @item = "/catalog/#{@host}" - @pattern = %{^/catalog/([^/]+)$} - @declaration = Puppet::Network::AuthStore::Declaration.new(:allow,'$1') - end - it "should match a name with the appropriate interpolation" do - @declaration.interpolate(@item.match(@pattern)).should be_match(@host,'10.0.0.5') - end + describe "when the pattern is an opaque string with a back reference and the matched data contains dots with an initial prefix that looks like an IP address" do + before :each do + @host = '01.admin.mgmt.nym1' + @item = "/catalog/#{@host}" + @pattern = %{^/catalog/([^/]+)$} + @declaration = Puppet::Network::AuthStore::Declaration.new(:allow,'$1') end + it "should match a name with the appropriate interpolation" do + @declaration.interpolate(@item.match(@pattern)).should be_match(@host,'10.0.0.5') + end + end - describe "when comparing patterns" do - before :each do - @ip = Puppet::Network::AuthStore::Declaration.new(:allow,'127.0.0.1') - @host_name = Puppet::Network::AuthStore::Declaration.new(:allow,'www.hard_knocks.edu') - @opaque = Puppet::Network::AuthStore::Declaration.new(:allow,'hey_dude') - end - it "should consider ip addresses before host names" do - (@ip < @host_name).should be_true - end - it "should consider ip addresses before opaque strings" do - (@ip < @opaque).should be_true - end - it "should consider host_names before opaque strings" do - (@host_name < @opaque).should be_true - end + describe "when comparing patterns" do + before :each do + @ip = Puppet::Network::AuthStore::Declaration.new(:allow,'127.0.0.1') + @host_name = Puppet::Network::AuthStore::Declaration.new(:allow,'www.hard_knocks.edu') + @opaque = Puppet::Network::AuthStore::Declaration.new(:allow,'hey_dude') + end + it "should consider ip addresses before host names" do + (@ip < @host_name).should be_true + end + it "should consider ip addresses before opaque strings" do + (@ip < @opaque).should be_true + end + it "should consider host_names before opaque strings" do + (@host_name < @opaque).should be_true end + end end diff --git a/spec/unit/network/client_spec.rb b/spec/unit/network/client_spec.rb index cea71d1e5..f42bd78b9 100755 --- a/spec/unit/network/client_spec.rb +++ b/spec/unit/network/client_spec.rb @@ -8,38 +8,38 @@ require File.dirname(__FILE__) + '/../../spec_helper' require 'puppet/network/client' describe Puppet::Network::Client do + before do + Puppet.settings.stubs(:use).returns(true) + Puppet::Network::HttpPool.stubs(:cert_setup) + end + + describe "when keep-alive is enabled" do before do - Puppet.settings.stubs(:use).returns(true) - Puppet::Network::HttpPool.stubs(:cert_setup) + Puppet::Network::HttpPool.stubs(:keep_alive?).returns true end + it "should start the http client up on creation" do + http = mock 'http' + http.stub_everything + http.expects(:start) + Net::HTTP.stubs(:new).returns http - describe "when keep-alive is enabled" do - before do - Puppet::Network::HttpPool.stubs(:keep_alive?).returns true - end - it "should start the http client up on creation" do - http = mock 'http' - http.stub_everything - http.expects(:start) - Net::HTTP.stubs(:new).returns http - - # Pick a random subclass... - Puppet::Network::Client.runner.new :Server => Puppet[:server] - end + # Pick a random subclass... + Puppet::Network::Client.runner.new :Server => Puppet[:server] end + end - describe "when keep-alive is disabled" do - before do - Puppet::Network::HttpPool.stubs(:keep_alive?).returns false - end - it "should not start the http client up on creation" do - http = mock 'http' - http.stub_everything - http.expects(:start).never - Net::HTTP.stubs(:new).returns http + describe "when keep-alive is disabled" do + before do + Puppet::Network::HttpPool.stubs(:keep_alive?).returns false + end + it "should not start the http client up on creation" do + http = mock 'http' + http.stub_everything + http.expects(:start).never + Net::HTTP.stubs(:new).returns http - # Pick a random subclass... - Puppet::Network::Client.runner.new :Server => Puppet[:server] - end + # Pick a random subclass... + Puppet::Network::Client.runner.new :Server => Puppet[:server] end + end end diff --git a/spec/unit/network/format_handler_spec.rb b/spec/unit/network/format_handler_spec.rb index 13a9b8300..64cca8239 100755 --- a/spec/unit/network/format_handler_spec.rb +++ b/spec/unit/network/format_handler_spec.rb @@ -5,332 +5,332 @@ require File.dirname(__FILE__) + '/../../spec_helper' require 'puppet/network/format_handler' class FormatTester - extend Puppet::Network::FormatHandler + extend Puppet::Network::FormatHandler end describe Puppet::Network::FormatHandler do - after do - formats = Puppet::Network::FormatHandler.instance_variable_get("@formats") - formats.each do |name, format| - formats.delete(name) unless format.is_a?(Puppet::Network::Format) - end - end - - it "should be able to list supported formats" do - FormatTester.should respond_to(:supported_formats) - end - - it "should include all supported formats" do - 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 [: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 - result = FormatTester.supported_formats - result.length.should == 2 - result.should be_include(:one) - result.should be_include(:three) - 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 [: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 == [:four, :two, :three, :one] - end - - - describe "with a preferred serialization format setting" do - before do - one = stub 'supported', :supported? => true, :name => :one, :weight => 1 - two = stub 'supported', :supported? => true, :name => :two, :weight => 6 - Puppet::Network::FormatHandler.stubs(:formats).returns [:one, :two] - Puppet::Network::FormatHandler.stubs(:format).with(:one).returns one - Puppet::Network::FormatHandler.stubs(:format).with(:two).returns two - end - describe "that is supported" do - before do - Puppet.settings.expects(:value).with(:preferred_serialization_format).returns :one - end - it "should return the preferred serialization format first" do - FormatTester.supported_formats.should == [:one, :two] - end - end - describe "that is not supported" do - before do - Puppet.settings.expects(:value).with(:preferred_serialization_format).returns :unsupported - end - it "should still return the default format first" do - FormatTester.supported_formats.should == [:two, :one] - end - it "should log a debug message" do - Puppet.expects(:debug).with("Value of 'preferred_serialization_format' (unsupported) is invalid for FormatTester, using default (two)") - Puppet.expects(:debug).with("FormatTester supports formats: one two; using two") - FormatTester.supported_formats - end - end - end - - it "should return the first format as the default format" do - FormatTester.expects(:supported_formats).returns [:one, :two] - FormatTester.default_format.should == :one - end - - it "should be able to use a protected format for better logging on errors" do - Puppet::Network::FormatHandler.should respond_to(:protected_format) - end - - it "should delegate all methods from the informative format to the specified format" do - format = mock 'format' - format.stubs(:name).returns(:myformat) - Puppet::Network::FormatHandler.expects(:format).twice.with(:myformat).returns format - - format.expects(:render).with("foo").returns "yay" - Puppet::Network::FormatHandler.protected_format(:myformat).render("foo").should == "yay" - end - - it "should provide better logging if a failure is encountered when delegating from the informative format to the real format" do - format = mock 'format' - format.stubs(:name).returns(:myformat) - Puppet::Network::FormatHandler.expects(:format).twice.with(:myformat).returns format - - format.expects(:render).with("foo").raises "foo" - lambda { Puppet::Network::FormatHandler.protected_format(:myformat).render("foo") }.should raise_error(Puppet::Network::FormatHandler::FormatError) - end - - it "should raise an error if we couldn't find a format by name or mime-type" do - Puppet::Network::FormatHandler.stubs(:format).with(:myformat).returns nil - lambda { Puppet::Network::FormatHandler.protected_format(:myformat) }.should raise_error - end - - describe "when using formats" do - before do - @format = mock 'format' - @format.stubs(:supported?).returns true - @format.stubs(:name).returns :my_format - Puppet::Network::FormatHandler.stubs(:format).with(:my_format).returns @format - Puppet::Network::FormatHandler.stubs(:mime).with("text/myformat").returns @format - Puppet::Network::Format.stubs(:===).returns false - Puppet::Network::Format.stubs(:===).with(@format).returns true - end - - it "should be able to test whether a format is supported" do - FormatTester.should respond_to(:support_format?) - end - - it "should use the Format to determine whether a given format is supported" do - @format.expects(:supported?).with(FormatTester) - FormatTester.support_format?(:my_format) - end - - it "should be able to convert from a given format" do - FormatTester.should respond_to(:convert_from) - end - - it "should call the format-specific converter when asked to convert from a given format" do - @format.expects(:intern).with(FormatTester, "mydata") - FormatTester.convert_from(:my_format, "mydata") - end - - it "should call the format-specific converter when asked to convert from a given format by mime-type" do - @format.expects(:intern).with(FormatTester, "mydata") - FormatTester.convert_from("text/myformat", "mydata") - end - - it "should call the format-specific converter when asked to convert from a given format by format instance" do - @format.expects(:intern).with(FormatTester, "mydata") - FormatTester.convert_from(@format, "mydata") - end - - it "should raise a FormatError when an exception is encountered when converting from a format" do - @format.expects(:intern).with(FormatTester, "mydata").raises "foo" - lambda { FormatTester.convert_from(:my_format, "mydata") }.should raise_error(Puppet::Network::FormatHandler::FormatError) - end - - it "should be able to use a specific hook for converting into multiple instances" do - @format.expects(:intern_multiple).with(FormatTester, "mydata") - - FormatTester.convert_from_multiple(:my_format, "mydata") - end - - it "should raise a FormatError when an exception is encountered when converting multiple items from a format" do - @format.expects(:intern_multiple).with(FormatTester, "mydata").raises "foo" - lambda { FormatTester.convert_from_multiple(:my_format, "mydata") }.should raise_error(Puppet::Network::FormatHandler::FormatError) - end - - it "should be able to use a specific hook for rendering multiple instances" do - @format.expects(:render_multiple).with("mydata") - - FormatTester.render_multiple(:my_format, "mydata") - end + after do + formats = Puppet::Network::FormatHandler.instance_variable_get("@formats") + formats.each do |name, format| + formats.delete(name) unless format.is_a?(Puppet::Network::Format) + end + end + + it "should be able to list supported formats" do + FormatTester.should respond_to(:supported_formats) + end + + it "should include all supported formats" do + 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 [: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 + result = FormatTester.supported_formats + result.length.should == 2 + result.should be_include(:one) + result.should be_include(:three) + 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 [: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 == [:four, :two, :three, :one] + end + + + describe "with a preferred serialization format setting" do + before do + one = stub 'supported', :supported? => true, :name => :one, :weight => 1 + two = stub 'supported', :supported? => true, :name => :two, :weight => 6 + Puppet::Network::FormatHandler.stubs(:formats).returns [:one, :two] + Puppet::Network::FormatHandler.stubs(:format).with(:one).returns one + Puppet::Network::FormatHandler.stubs(:format).with(:two).returns two + end + describe "that is supported" do + before do + Puppet.settings.expects(:value).with(:preferred_serialization_format).returns :one + end + it "should return the preferred serialization format first" do + FormatTester.supported_formats.should == [:one, :two] + end + end + describe "that is not supported" do + before do + Puppet.settings.expects(:value).with(:preferred_serialization_format).returns :unsupported + end + it "should still return the default format first" do + FormatTester.supported_formats.should == [:two, :one] + end + it "should log a debug message" do + Puppet.expects(:debug).with("Value of 'preferred_serialization_format' (unsupported) is invalid for FormatTester, using default (two)") + Puppet.expects(:debug).with("FormatTester supports formats: one two; using two") + FormatTester.supported_formats + end + end + end + + it "should return the first format as the default format" do + FormatTester.expects(:supported_formats).returns [:one, :two] + FormatTester.default_format.should == :one + end + + it "should be able to use a protected format for better logging on errors" do + Puppet::Network::FormatHandler.should respond_to(:protected_format) + end + + it "should delegate all methods from the informative format to the specified format" do + format = mock 'format' + format.stubs(:name).returns(:myformat) + Puppet::Network::FormatHandler.expects(:format).twice.with(:myformat).returns format + + format.expects(:render).with("foo").returns "yay" + Puppet::Network::FormatHandler.protected_format(:myformat).render("foo").should == "yay" + end + + it "should provide better logging if a failure is encountered when delegating from the informative format to the real format" do + format = mock 'format' + format.stubs(:name).returns(:myformat) + Puppet::Network::FormatHandler.expects(:format).twice.with(:myformat).returns format + + format.expects(:render).with("foo").raises "foo" + lambda { Puppet::Network::FormatHandler.protected_format(:myformat).render("foo") }.should raise_error(Puppet::Network::FormatHandler::FormatError) + end + + it "should raise an error if we couldn't find a format by name or mime-type" do + Puppet::Network::FormatHandler.stubs(:format).with(:myformat).returns nil + lambda { Puppet::Network::FormatHandler.protected_format(:myformat) }.should raise_error + end + + describe "when using formats" do + before do + @format = mock 'format' + @format.stubs(:supported?).returns true + @format.stubs(:name).returns :my_format + Puppet::Network::FormatHandler.stubs(:format).with(:my_format).returns @format + Puppet::Network::FormatHandler.stubs(:mime).with("text/myformat").returns @format + Puppet::Network::Format.stubs(:===).returns false + Puppet::Network::Format.stubs(:===).with(@format).returns true + end + + it "should be able to test whether a format is supported" do + FormatTester.should respond_to(:support_format?) + end + + it "should use the Format to determine whether a given format is supported" do + @format.expects(:supported?).with(FormatTester) + FormatTester.support_format?(:my_format) + end + + it "should be able to convert from a given format" do + FormatTester.should respond_to(:convert_from) + end + + it "should call the format-specific converter when asked to convert from a given format" do + @format.expects(:intern).with(FormatTester, "mydata") + FormatTester.convert_from(:my_format, "mydata") + end + + it "should call the format-specific converter when asked to convert from a given format by mime-type" do + @format.expects(:intern).with(FormatTester, "mydata") + FormatTester.convert_from("text/myformat", "mydata") + end + + it "should call the format-specific converter when asked to convert from a given format by format instance" do + @format.expects(:intern).with(FormatTester, "mydata") + FormatTester.convert_from(@format, "mydata") + end + + it "should raise a FormatError when an exception is encountered when converting from a format" do + @format.expects(:intern).with(FormatTester, "mydata").raises "foo" + lambda { FormatTester.convert_from(:my_format, "mydata") }.should raise_error(Puppet::Network::FormatHandler::FormatError) + end + + it "should be able to use a specific hook for converting into multiple instances" do + @format.expects(:intern_multiple).with(FormatTester, "mydata") + + FormatTester.convert_from_multiple(:my_format, "mydata") + end + + it "should raise a FormatError when an exception is encountered when converting multiple items from a format" do + @format.expects(:intern_multiple).with(FormatTester, "mydata").raises "foo" + lambda { FormatTester.convert_from_multiple(:my_format, "mydata") }.should raise_error(Puppet::Network::FormatHandler::FormatError) + end + + it "should be able to use a specific hook for rendering multiple instances" do + @format.expects(:render_multiple).with("mydata") - it "should raise a FormatError when an exception is encountered when rendering multiple items into a format" do - @format.expects(:render_multiple).with("mydata").raises "foo" - lambda { FormatTester.render_multiple(:my_format, "mydata") }.should raise_error(Puppet::Network::FormatHandler::FormatError) - end + FormatTester.render_multiple(:my_format, "mydata") end - describe "when managing formats" do - it "should have a method for defining a new format" do - Puppet::Network::FormatHandler.should respond_to(:create) - end + it "should raise a FormatError when an exception is encountered when rendering multiple items into a format" do + @format.expects(:render_multiple).with("mydata").raises "foo" + lambda { FormatTester.render_multiple(:my_format, "mydata") }.should raise_error(Puppet::Network::FormatHandler::FormatError) + end + end - it "should create a format instance when asked" do - format = stub 'format', :name => :foo - Puppet::Network::Format.expects(:new).with(:foo).returns format - Puppet::Network::FormatHandler.create(:foo) - end - - it "should instance_eval any block provided when creating a format" do - format = stub 'format', :name => :instance_eval - format.expects(:yayness) - Puppet::Network::Format.expects(:new).returns format - Puppet::Network::FormatHandler.create(:instance_eval) do - yayness - end - end - - it "should be able to retrieve a format by name" do - format = Puppet::Network::FormatHandler.create(:by_name) - Puppet::Network::FormatHandler.format(:by_name).should equal(format) - end - - it "should be able to retrieve a format by extension" do - format = Puppet::Network::FormatHandler.create(:by_extension, :extension => "foo") - Puppet::Network::FormatHandler.format_by_extension("foo").should equal(format) - end - - it "should return nil if asked to return a format by an unknown extension" do - Puppet::Network::FormatHandler.format_by_extension("yayness").should be_nil - end - - it "should be able to retrieve formats by name irrespective of case and class" do - format = Puppet::Network::FormatHandler.create(:by_name) - Puppet::Network::FormatHandler.format(:By_Name).should equal(format) - end + describe "when managing formats" do + it "should have a method for defining a new format" do + Puppet::Network::FormatHandler.should respond_to(:create) + end - it "should be able to retrieve a format by mime type" do - format = Puppet::Network::FormatHandler.create(:by_name, :mime => "foo/bar") - Puppet::Network::FormatHandler.mime("foo/bar").should equal(format) - end + it "should create a format instance when asked" do + format = stub 'format', :name => :foo + Puppet::Network::Format.expects(:new).with(:foo).returns format + Puppet::Network::FormatHandler.create(:foo) + end - it "should be able to retrieve a format by mime type irrespective of case" do - format = Puppet::Network::FormatHandler.create(:by_name, :mime => "foo/bar") - Puppet::Network::FormatHandler.mime("Foo/Bar").should equal(format) - end + it "should instance_eval any block provided when creating a format" do + format = stub 'format', :name => :instance_eval + format.expects(:yayness) + Puppet::Network::Format.expects(:new).returns format + Puppet::Network::FormatHandler.create(:instance_eval) do + yayness + end + end - it "should be able to return all formats" do - one = stub 'one', :name => :one - two = stub 'two', :name => :two - Puppet::Network::Format.expects(:new).with(:one).returns(one) - Puppet::Network::Format.expects(:new).with(:two).returns(two) + it "should be able to retrieve a format by name" do + format = Puppet::Network::FormatHandler.create(:by_name) + Puppet::Network::FormatHandler.format(:by_name).should equal(format) + end - Puppet::Network::FormatHandler.create(:one) - Puppet::Network::FormatHandler.create(:two) + it "should be able to retrieve a format by extension" do + format = Puppet::Network::FormatHandler.create(:by_extension, :extension => "foo") + Puppet::Network::FormatHandler.format_by_extension("foo").should equal(format) + end - list = Puppet::Network::FormatHandler.formats - list.should be_include(:one) - list.should be_include(:two) - end + it "should return nil if asked to return a format by an unknown extension" do + Puppet::Network::FormatHandler.format_by_extension("yayness").should be_nil end - describe "when an instance" do - it "should be able to test whether a format is supported" do - FormatTester.new.should respond_to(:support_format?) - end + it "should be able to retrieve formats by name irrespective of case and class" do + format = Puppet::Network::FormatHandler.create(:by_name) + Puppet::Network::FormatHandler.format(:By_Name).should equal(format) + end - it "should be able to convert to a given format" do - FormatTester.new.should respond_to(:render) - end + it "should be able to retrieve a format by mime type" do + format = Puppet::Network::FormatHandler.create(:by_name, :mime => "foo/bar") + Puppet::Network::FormatHandler.mime("foo/bar").should equal(format) + end - it "should be able to get a format mime-type" do - FormatTester.new.should respond_to(:mime) - end + it "should be able to retrieve a format by mime type irrespective of case" do + format = Puppet::Network::FormatHandler.create(:by_name, :mime => "foo/bar") + Puppet::Network::FormatHandler.mime("Foo/Bar").should equal(format) + end - it "should raise a FormatError when a rendering error is encountered" do - format = stub 'rendering format', :supported? => true, :name => :foo - Puppet::Network::FormatHandler.stubs(:format).with(:foo).returns format + it "should be able to return all formats" do + one = stub 'one', :name => :one + two = stub 'two', :name => :two + Puppet::Network::Format.expects(:new).with(:one).returns(one) + Puppet::Network::Format.expects(:new).with(:two).returns(two) - tester = FormatTester.new - format.expects(:render).with(tester).raises "eh" + Puppet::Network::FormatHandler.create(:one) + Puppet::Network::FormatHandler.create(:two) - lambda { tester.render(:foo) }.should raise_error(Puppet::Network::FormatHandler::FormatError) - end + list = Puppet::Network::FormatHandler.formats + list.should be_include(:one) + list.should be_include(:two) + end + end - it "should call the format-specific converter when asked to convert to a given format" do - format = stub 'rendering format', :supported? => true, :name => :foo + describe "when an instance" do + it "should be able to test whether a format is supported" do + FormatTester.new.should respond_to(:support_format?) + end - Puppet::Network::FormatHandler.stubs(:format).with(:foo).returns format + it "should be able to convert to a given format" do + FormatTester.new.should respond_to(:render) + end - tester = FormatTester.new - format.expects(:render).with(tester).returns "foo" + it "should be able to get a format mime-type" do + FormatTester.new.should respond_to(:mime) + end - tester.render(:foo).should == "foo" - end + it "should raise a FormatError when a rendering error is encountered" do + format = stub 'rendering format', :supported? => true, :name => :foo + Puppet::Network::FormatHandler.stubs(:format).with(:foo).returns format - it "should call the format-specific converter when asked to convert to a given format by mime-type" do - format = stub 'rendering format', :supported? => true, :name => :foo - Puppet::Network::FormatHandler.stubs(:mime).with("text/foo").returns format - Puppet::Network::FormatHandler.stubs(:format).with(:foo).returns format + tester = FormatTester.new + format.expects(:render).with(tester).raises "eh" - tester = FormatTester.new - format.expects(:render).with(tester).returns "foo" + lambda { tester.render(:foo) }.should raise_error(Puppet::Network::FormatHandler::FormatError) + end + + it "should call the format-specific converter when asked to convert to a given format" do + format = stub 'rendering format', :supported? => true, :name => :foo + + Puppet::Network::FormatHandler.stubs(:format).with(:foo).returns format + + tester = FormatTester.new + format.expects(:render).with(tester).returns "foo" + + tester.render(:foo).should == "foo" + end - tester.render("text/foo").should == "foo" - end + it "should call the format-specific converter when asked to convert to a given format by mime-type" do + format = stub 'rendering format', :supported? => true, :name => :foo + Puppet::Network::FormatHandler.stubs(:mime).with("text/foo").returns format + Puppet::Network::FormatHandler.stubs(:format).with(:foo).returns format - it "should call the format converter when asked to convert to a given format instance" do - format = stub 'rendering format', :supported? => true, :name => :foo - Puppet::Network::Format.stubs(:===).with(format).returns(true) - Puppet::Network::FormatHandler.stubs(:format).with(:foo).returns format + tester = FormatTester.new + format.expects(:render).with(tester).returns "foo" - tester = FormatTester.new - format.expects(:render).with(tester).returns "foo" + tester.render("text/foo").should == "foo" + end + + it "should call the format converter when asked to convert to a given format instance" do + format = stub 'rendering format', :supported? => true, :name => :foo + Puppet::Network::Format.stubs(:===).with(format).returns(true) + Puppet::Network::FormatHandler.stubs(:format).with(:foo).returns format + + tester = FormatTester.new + format.expects(:render).with(tester).returns "foo" - tester.render(format).should == "foo" - end + tester.render(format).should == "foo" + end - it "should render to the default format if no format is provided when rendering" do - format = stub 'rendering format', :supported? => true, :name => :foo - Puppet::Network::FormatHandler.stubs(:format).with(:foo).returns format + it "should render to the default format if no format is provided when rendering" do + format = stub 'rendering format', :supported? => true, :name => :foo + Puppet::Network::FormatHandler.stubs(:format).with(:foo).returns format - FormatTester.expects(:default_format).returns :foo - tester = FormatTester.new + FormatTester.expects(:default_format).returns :foo + tester = FormatTester.new - format.expects(:render).with(tester) - tester.render - end + format.expects(:render).with(tester) + tester.render + end - it "should call the format-specific converter when asked for the mime-type of a given format" do - format = stub 'rendering format', :supported? => true, :name => :foo + it "should call the format-specific converter when asked for the mime-type of a given format" do + format = stub 'rendering format', :supported? => true, :name => :foo - Puppet::Network::FormatHandler.stubs(:format).with(:foo).returns format + Puppet::Network::FormatHandler.stubs(:format).with(:foo).returns format - tester = FormatTester.new - format.expects(:mime).returns "text/foo" + tester = FormatTester.new + format.expects(:mime).returns "text/foo" - tester.mime(:foo).should == "text/foo" - end + tester.mime(:foo).should == "text/foo" + end - it "should return the default format mime-type if no format is provided" do - format = stub 'rendering format', :supported? => true, :name => :foo - Puppet::Network::FormatHandler.stubs(:format).with(:foo).returns format + it "should return the default format mime-type if no format is provided" do + format = stub 'rendering format', :supported? => true, :name => :foo + Puppet::Network::FormatHandler.stubs(:format).with(:foo).returns format - FormatTester.expects(:default_format).returns :foo - tester = FormatTester.new + FormatTester.expects(:default_format).returns :foo + tester = FormatTester.new - format.expects(:mime).returns "text/foo" - tester.mime.should == "text/foo" - end + format.expects(:mime).returns "text/foo" + tester.mime.should == "text/foo" end + end end diff --git a/spec/unit/network/format_spec.rb b/spec/unit/network/format_spec.rb index 73530b9d7..bcb084156 100755 --- a/spec/unit/network/format_spec.rb +++ b/spec/unit/network/format_spec.rb @@ -7,192 +7,192 @@ require 'puppet/network/format' # A class with all of the necessary # hooks. class FormatRenderer - def self.to_multiple_my_format(list) + def self.to_multiple_my_format(list) + end + + def self.from_multiple_my_format(text) + end + + def self.from_my_format(text) + end + + def to_my_format + end +end + +describe Puppet::Network::Format do + describe "when initializing" do + it "should require a name" do + lambda { Puppet::Network::Format.new }.should raise_error(ArgumentError) end - def self.from_multiple_my_format(text) + it "should be able to provide its name" do + Puppet::Network::Format.new(:my_format).name.should == :my_format end - def self.from_my_format(text) + it "should always convert its name to a downcased symbol" do + Puppet::Network::Format.new(:My_Format).name.should == :my_format end - def to_my_format + it "should be able to set its downcased mime type at initialization" do + format = Puppet::Network::Format.new(:my_format, :mime => "Foo/Bar") + format.mime.should == "foo/bar" end -end -describe Puppet::Network::Format do - describe "when initializing" do - it "should require a name" do - lambda { Puppet::Network::Format.new }.should raise_error(ArgumentError) - end - - it "should be able to provide its name" do - Puppet::Network::Format.new(:my_format).name.should == :my_format - end - - it "should always convert its name to a downcased symbol" do - Puppet::Network::Format.new(:My_Format).name.should == :my_format - end - - it "should be able to set its downcased mime type at initialization" do - format = Puppet::Network::Format.new(:my_format, :mime => "Foo/Bar") - format.mime.should == "foo/bar" - end - - it "should default to text plus the name of the format as the mime type" do - Puppet::Network::Format.new(:my_format).mime.should == "text/my_format" - end - - it "should fail if unsupported options are provided" do - lambda { Puppet::Network::Format.new(:my_format, :foo => "bar") }.should raise_error(ArgumentError) - end - end - - describe "instances" do - before do - @format = Puppet::Network::Format.new(:my_format) - end - - it "should support being confined" do - @format.should respond_to(:confine) - end - - it "should not be considered suitable if confinement conditions are not met" do - @format.confine :true => false - @format.should_not be_suitable - end - - it "should be able to determine if a class is supported" do - @format.should respond_to(:supported?) - end - - it "should consider a class to be supported if it has the individual and multiple methods for rendering and interning" do - @format.should be_supported(FormatRenderer) - end - - it "should default to its required methods being the individual and multiple methods for rendering and interning" do - Puppet::Network::Format.new(:foo).required_methods.sort { |a,b| a.to_s <=> b.to_s }.should == [:intern_method, :intern_multiple_method, :render_multiple_method, :render_method].sort { |a,b| a.to_s <=> b.to_s } - end - - it "should consider a class supported if the provided class has all required methods present" do - format = Puppet::Network::Format.new(:foo) - [:intern_method, :intern_multiple_method, :render_multiple_method, :render_method].each do |method| - format.expects(:required_method_present?).with { |name, klass, type| name == method and klass == String }.returns true - end - - format.should be_required_methods_present(String) - end - - it "should consider a class not supported if any required methods are missing from the provided class" do - format = Puppet::Network::Format.new(:foo) - format.stubs(:required_method_present?).returns true - format.expects(:required_method_present?).with { |name, *args| name == :intern_method }.returns false - format.should_not be_required_methods_present(String) - end - - it "should be able to specify the methods required for support" do - Puppet::Network::Format.new(:foo, :required_methods => [:render_method, :intern_method]).required_methods.should == [:render_method, :intern_method] - end - - it "should only test for required methods if specific methods are specified as required" do - format = Puppet::Network::Format.new(:foo, :required_methods => [:intern_method]) - format.expects(:required_method_present?).with { |name, klass, type| name == :intern_method } - - format.required_methods_present?(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 - - it "should default to its extension being equal to its name" do - Puppet::Network::Format.new(:foo).extension.should == "foo" - end - - it "should support overriding the extension" do - Puppet::Network::Format.new(:foo, :extension => "bar").extension.should == "bar" - end - [:intern_method, :intern_multiple_method, :render_multiple_method, :render_method].each do |method| - it "should allow assignment of the #{method}" do - Puppet::Network::Format.new(:foo, method => :foo).send(method).should == :foo - end - end - end - - describe "when converting between instances and formatted text" do - before do - @format = Puppet::Network::Format.new(:my_format) - @instance = FormatRenderer.new - end - - it "should have a method for rendering a single instance" do - @format.should respond_to(:render) - end - - it "should have a method for rendering multiple instances" do - @format.should respond_to(:render_multiple) - end - - it "should have a method for interning text" do - @format.should respond_to(:intern) - end - - it "should have a method for interning text into multiple instances" do - @format.should respond_to(:intern_multiple) - end - - it "should return the results of calling the instance-specific render method if the method is present" do - @instance.expects(:to_my_format).returns "foo" - @format.render(@instance).should == "foo" - end - - it "should return the results of calling the class-specific render_multiple method if the method is present" do - @instance.class.expects(:to_multiple_my_format).returns ["foo"] - @format.render_multiple([@instance]).should == ["foo"] - end - - it "should return the results of calling the class-specific intern method if the method is present" do - FormatRenderer.expects(:from_my_format).with("foo").returns @instance - @format.intern(FormatRenderer, "foo").should equal(@instance) - end - - it "should return the results of calling the class-specific intern_multiple method if the method is present" do - FormatRenderer.expects(:from_multiple_my_format).with("foo").returns [@instance] - @format.intern_multiple(FormatRenderer, "foo").should == [@instance] - end - - it "should fail if asked to render and the instance does not respond to 'to_<format>'" do - lambda { @format.render("foo") }.should raise_error(NotImplementedError) - end - - it "should fail if asked to intern and the class does not respond to 'from_<format>'" do - lambda { @format.intern(String, "foo") }.should raise_error(NotImplementedError) - end - - it "should fail if asked to intern multiple and the class does not respond to 'from_multiple_<format>'" do - lambda { @format.intern_multiple(String, "foo") }.should raise_error(NotImplementedError) - end - - it "should fail if asked to render multiple and the instance does not respond to 'to_multiple_<format>'" do - lambda { @format.render_multiple(["foo", "bar"]) }.should raise_error(NotImplementedError) - end + it "should default to text plus the name of the format as the mime type" do + Puppet::Network::Format.new(:my_format).mime.should == "text/my_format" + end + + it "should fail if unsupported options are provided" do + lambda { Puppet::Network::Format.new(:my_format, :foo => "bar") }.should raise_error(ArgumentError) + end + end + + describe "instances" do + before do + @format = Puppet::Network::Format.new(:my_format) + end + + it "should support being confined" do + @format.should respond_to(:confine) + end + + it "should not be considered suitable if confinement conditions are not met" do + @format.confine :true => false + @format.should_not be_suitable + end + + it "should be able to determine if a class is supported" do + @format.should respond_to(:supported?) + end + + it "should consider a class to be supported if it has the individual and multiple methods for rendering and interning" do + @format.should be_supported(FormatRenderer) + end + + it "should default to its required methods being the individual and multiple methods for rendering and interning" do + Puppet::Network::Format.new(:foo).required_methods.sort { |a,b| a.to_s <=> b.to_s }.should == [:intern_method, :intern_multiple_method, :render_multiple_method, :render_method].sort { |a,b| a.to_s <=> b.to_s } + end + + it "should consider a class supported if the provided class has all required methods present" do + format = Puppet::Network::Format.new(:foo) + [:intern_method, :intern_multiple_method, :render_multiple_method, :render_method].each do |method| + format.expects(:required_method_present?).with { |name, klass, type| name == method and klass == String }.returns true + end + + format.should be_required_methods_present(String) + end + + it "should consider a class not supported if any required methods are missing from the provided class" do + format = Puppet::Network::Format.new(:foo) + format.stubs(:required_method_present?).returns true + format.expects(:required_method_present?).with { |name, *args| name == :intern_method }.returns false + format.should_not be_required_methods_present(String) + end + + it "should be able to specify the methods required for support" do + Puppet::Network::Format.new(:foo, :required_methods => [:render_method, :intern_method]).required_methods.should == [:render_method, :intern_method] + end + + it "should only test for required methods if specific methods are specified as required" do + format = Puppet::Network::Format.new(:foo, :required_methods => [:intern_method]) + format.expects(:required_method_present?).with { |name, klass, type| name == :intern_method } + + format.required_methods_present?(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 + + it "should default to its extension being equal to its name" do + Puppet::Network::Format.new(:foo).extension.should == "foo" + end + + it "should support overriding the extension" do + Puppet::Network::Format.new(:foo, :extension => "bar").extension.should == "bar" + end + [:intern_method, :intern_multiple_method, :render_multiple_method, :render_method].each do |method| + it "should allow assignment of the #{method}" do + Puppet::Network::Format.new(:foo, method => :foo).send(method).should == :foo + end + end + end + + describe "when converting between instances and formatted text" do + before do + @format = Puppet::Network::Format.new(:my_format) + @instance = FormatRenderer.new + end + + it "should have a method for rendering a single instance" do + @format.should respond_to(:render) + end + + it "should have a method for rendering multiple instances" do + @format.should respond_to(:render_multiple) + end + + it "should have a method for interning text" do + @format.should respond_to(:intern) + end + + it "should have a method for interning text into multiple instances" do + @format.should respond_to(:intern_multiple) + end + + it "should return the results of calling the instance-specific render method if the method is present" do + @instance.expects(:to_my_format).returns "foo" + @format.render(@instance).should == "foo" + end + + it "should return the results of calling the class-specific render_multiple method if the method is present" do + @instance.class.expects(:to_multiple_my_format).returns ["foo"] + @format.render_multiple([@instance]).should == ["foo"] + end + + it "should return the results of calling the class-specific intern method if the method is present" do + FormatRenderer.expects(:from_my_format).with("foo").returns @instance + @format.intern(FormatRenderer, "foo").should equal(@instance) + end + + it "should return the results of calling the class-specific intern_multiple method if the method is present" do + FormatRenderer.expects(:from_multiple_my_format).with("foo").returns [@instance] + @format.intern_multiple(FormatRenderer, "foo").should == [@instance] + end + + it "should fail if asked to render and the instance does not respond to 'to_<format>'" do + lambda { @format.render("foo") }.should raise_error(NotImplementedError) + end + + it "should fail if asked to intern and the class does not respond to 'from_<format>'" do + lambda { @format.intern(String, "foo") }.should raise_error(NotImplementedError) + end + + it "should fail if asked to intern multiple and the class does not respond to 'from_multiple_<format>'" do + lambda { @format.intern_multiple(String, "foo") }.should raise_error(NotImplementedError) + end + + it "should fail if asked to render multiple and the instance does not respond to 'to_multiple_<format>'" do + lambda { @format.render_multiple(["foo", "bar"]) }.should raise_error(NotImplementedError) end + end end diff --git a/spec/unit/network/formats_spec.rb b/spec/unit/network/formats_spec.rb index 0811d61ce..7c8e7b1f4 100755 --- a/spec/unit/network/formats_spec.rb +++ b/spec/unit/network/formats_spec.rb @@ -5,333 +5,333 @@ require File.dirname(__FILE__) + '/../../spec_helper' require 'puppet/network/formats' class PsonTest - attr_accessor :string - def ==(other) - string == other.string + attr_accessor :string + def ==(other) + string == other.string + end + + def self.from_pson(data) + new(data) + end + + def initialize(string) + @string = string + end + + def to_pson(*args) + { + 'type' => self.class.name, + 'data' => @string + }.to_pson(*args) + end +end + +describe "Puppet Network Format" do + it "should include a yaml format" do + Puppet::Network::FormatHandler.format(:yaml).should_not be_nil + end + + describe "yaml" do + before do + @yaml = Puppet::Network::FormatHandler.format(:yaml) end - def self.from_pson(data) - new(data) + it "should have its mime type set to text/yaml" do + @yaml.mime.should == "text/yaml" end - def initialize(string) - @string = string + it "should be supported on Strings" do + @yaml.should be_supported(String) end - def to_pson(*args) - { - 'type' => self.class.name, - 'data' => @string - }.to_pson(*args) + it "should render by calling 'to_yaml' on the instance" do + instance = mock 'instance' + instance.expects(:to_yaml).returns "foo" + @yaml.render(instance).should == "foo" end -end -describe "Puppet Network Format" do - it "should include a yaml format" do - Puppet::Network::FormatHandler.format(:yaml).should_not be_nil - end - - describe "yaml" do - before do - @yaml = Puppet::Network::FormatHandler.format(:yaml) - end - - it "should have its mime type set to text/yaml" do - @yaml.mime.should == "text/yaml" - end - - it "should be supported on Strings" do - @yaml.should be_supported(String) - end - - it "should render by calling 'to_yaml' on the instance" do - instance = mock 'instance' - instance.expects(:to_yaml).returns "foo" - @yaml.render(instance).should == "foo" - end - - it "should render multiple instances by calling 'to_yaml' on the array" do - instances = [mock('instance')] - instances.expects(:to_yaml).returns "foo" - @yaml.render_multiple(instances).should == "foo" - end - - it "should intern by calling 'YAML.load'" do - text = "foo" - YAML.expects(:load).with("foo").returns "bar" - @yaml.intern(String, text).should == "bar" - end - - it "should intern multiples by calling 'YAML.load'" do - text = "foo" - YAML.expects(:load).with("foo").returns "bar" - @yaml.intern_multiple(String, text).should == "bar" - end + it "should render multiple instances by calling 'to_yaml' on the array" do + instances = [mock('instance')] + instances.expects(:to_yaml).returns "foo" + @yaml.render_multiple(instances).should == "foo" end - describe "base64 compressed yaml" do - yaml = Puppet::Network::FormatHandler.format(:b64_zlib_yaml) - confine "We must have zlib" => Puppet.features.zlib? + it "should intern by calling 'YAML.load'" do + text = "foo" + YAML.expects(:load).with("foo").returns "bar" + @yaml.intern(String, text).should == "bar" + end + + it "should intern multiples by calling 'YAML.load'" do + text = "foo" + YAML.expects(:load).with("foo").returns "bar" + @yaml.intern_multiple(String, text).should == "bar" + end + end - before do - @yaml = Puppet::Network::FormatHandler.format(:b64_zlib_yaml) - end + describe "base64 compressed yaml" do + yaml = Puppet::Network::FormatHandler.format(:b64_zlib_yaml) + confine "We must have zlib" => Puppet.features.zlib? + + before do + @yaml = Puppet::Network::FormatHandler.format(:b64_zlib_yaml) + end - it "should have its mime type set to text/b64_zlib_yaml" do - @yaml.mime.should == "text/b64_zlib_yaml" - end + it "should have its mime type set to text/b64_zlib_yaml" do + @yaml.mime.should == "text/b64_zlib_yaml" + end - it "should render by calling 'to_yaml' on the instance" do - instance = mock 'instance' - instance.expects(:to_yaml).returns "foo" - @yaml.render(instance) - end - - it "should encode generated yaml on render" do - instance = mock 'instance', :to_yaml => "foo" + it "should render by calling 'to_yaml' on the instance" do + instance = mock 'instance' + instance.expects(:to_yaml).returns "foo" + @yaml.render(instance) + end - @yaml.expects(:encode).with("foo").returns "bar" - - @yaml.render(instance).should == "bar" - end - - it "should render multiple instances by calling 'to_yaml' on the array" do - instances = [mock('instance')] - instances.expects(:to_yaml).returns "foo" - @yaml.render_multiple(instances) - end - - it "should encode generated yaml on render" do - instances = [mock('instance')] - instances.stubs(:to_yaml).returns "foo" - - @yaml.expects(:encode).with("foo").returns "bar" - - @yaml.render(instances).should == "bar" - end - - it "should intern by calling decode" do - text = "foo" - @yaml.expects(:decode).with("foo").returns "bar" - @yaml.intern(String, text).should == "bar" - end - - it "should intern multiples by calling 'decode'" do - text = "foo" - @yaml.expects(:decode).with("foo").returns "bar" - @yaml.intern_multiple(String, text).should == "bar" - end + it "should encode generated yaml on render" do + instance = mock 'instance', :to_yaml => "foo" - it "should decode by base64 decoding, uncompressing and Yaml loading" do - Base64.expects(:decode64).with("zorg").returns "foo" - Zlib::Inflate.expects(:inflate).with("foo").returns "baz" - YAML.expects(:load).with("baz").returns "bar" - @yaml.decode("zorg").should == "bar" - end - - it "should encode by compressing and base64 encoding" do - Zlib::Deflate.expects(:deflate).with("foo", Zlib::BEST_COMPRESSION).returns "bar" - Base64.expects(:encode64).with("bar").returns "baz" - @yaml.encode("foo").should == "baz" - end - - describe "when zlib is disabled" do - before do - Puppet[:zlib] = false - end + @yaml.expects(:encode).with("foo").returns "bar" - it "use_zlib? should return false" do - @yaml.use_zlib?.should == false - end + @yaml.render(instance).should == "bar" + end - it "should refuse to encode" do - lambda{ @yaml.encode("foo") }.should raise_error - end + it "should render multiple instances by calling 'to_yaml' on the array" do + instances = [mock('instance')] + instances.expects(:to_yaml).returns "foo" + @yaml.render_multiple(instances) + end - it "should refuse to decode" do - lambda{ @yaml.decode("foo") }.should raise_error - end - end + it "should encode generated yaml on render" do + instances = [mock('instance')] + instances.stubs(:to_yaml).returns "foo" - describe "when zlib is not installed" do - it "use_zlib? should return false" do - Puppet[:zlib] = true - Puppet.features.expects(:zlib?).returns(false) + @yaml.expects(:encode).with("foo").returns "bar" - @yaml.use_zlib?.should == false - end - end + @yaml.render(instances).should == "bar" + end + it "should intern by calling decode" do + text = "foo" + @yaml.expects(:decode).with("foo").returns "bar" + @yaml.intern(String, text).should == "bar" end - it "should include a marshal format" do - Puppet::Network::FormatHandler.format(:marshal).should_not be_nil + it "should intern multiples by calling 'decode'" do + text = "foo" + @yaml.expects(:decode).with("foo").returns "bar" + @yaml.intern_multiple(String, text).should == "bar" end - describe "marshal" do - before do - @marshal = Puppet::Network::FormatHandler.format(:marshal) - end + it "should decode by base64 decoding, uncompressing and Yaml loading" do + Base64.expects(:decode64).with("zorg").returns "foo" + Zlib::Inflate.expects(:inflate).with("foo").returns "baz" + YAML.expects(:load).with("baz").returns "bar" + @yaml.decode("zorg").should == "bar" + end - it "should have its mime type set to text/marshal" do - Puppet::Network::FormatHandler.format(:marshal).mime.should == "text/marshal" - end + it "should encode by compressing and base64 encoding" do + Zlib::Deflate.expects(:deflate).with("foo", Zlib::BEST_COMPRESSION).returns "bar" + Base64.expects(:encode64).with("bar").returns "baz" + @yaml.encode("foo").should == "baz" + end - it "should be supported on Strings" do - @marshal.should be_supported(String) - end + describe "when zlib is disabled" do + before do + Puppet[:zlib] = false + end - it "should render by calling 'Marshal.dump' on the instance" do - instance = mock 'instance' - Marshal.expects(:dump).with(instance).returns "foo" - @marshal.render(instance).should == "foo" - end + it "use_zlib? should return false" do + @yaml.use_zlib?.should == false + end - it "should render multiple instances by calling 'to_marshal' on the array" do - instances = [mock('instance')] + it "should refuse to encode" do + lambda{ @yaml.encode("foo") }.should raise_error + end - Marshal.expects(:dump).with(instances).returns "foo" - @marshal.render_multiple(instances).should == "foo" - end + it "should refuse to decode" do + lambda{ @yaml.decode("foo") }.should raise_error + end + end - it "should intern by calling 'Marshal.load'" do - text = "foo" - Marshal.expects(:load).with("foo").returns "bar" - @marshal.intern(String, text).should == "bar" - end + describe "when zlib is not installed" do + it "use_zlib? should return false" do + Puppet[:zlib] = true + Puppet.features.expects(:zlib?).returns(false) - it "should intern multiples by calling 'Marshal.load'" do - text = "foo" - Marshal.expects(:load).with("foo").returns "bar" - @marshal.intern_multiple(String, text).should == "bar" - end + @yaml.use_zlib?.should == false + end end - describe "plaintext" do - before do - @text = Puppet::Network::FormatHandler.format(:s) - end + end - it "should have its mimetype set to text/plain" do - @text.mime.should == "text/plain" - end + it "should include a marshal format" do + Puppet::Network::FormatHandler.format(:marshal).should_not be_nil + end - it "should use 'txt' as its extension" do - @text.extension.should == "txt" - end + describe "marshal" do + before do + @marshal = Puppet::Network::FormatHandler.format(:marshal) end - describe "dot" do - before do - @dot = Puppet::Network::FormatHandler.format(:dot) - end + it "should have its mime type set to text/marshal" do + Puppet::Network::FormatHandler.format(:marshal).mime.should == "text/marshal" + end - it "should have its mimetype set to text/dot" do - @dot.mime.should == "text/dot" - end + it "should be supported on Strings" do + @marshal.should be_supported(String) end - describe Puppet::Network::FormatHandler.format(:raw) do - before do - @format = Puppet::Network::FormatHandler.format(:raw) - end + it "should render by calling 'Marshal.dump' on the instance" do + instance = mock 'instance' + Marshal.expects(:dump).with(instance).returns "foo" + @marshal.render(instance).should == "foo" + end - it "should exist" do - @format.should_not be_nil - end + it "should render multiple instances by calling 'to_marshal' on the array" do + instances = [mock('instance')] - it "should have its mimetype set to application/x-raw" do - @format.mime.should == "application/x-raw" - end + Marshal.expects(:dump).with(instances).returns "foo" + @marshal.render_multiple(instances).should == "foo" + end - it "should always be supported" do - @format.should be_supported(String) - end + it "should intern by calling 'Marshal.load'" do + text = "foo" + Marshal.expects(:load).with("foo").returns "bar" + @marshal.intern(String, text).should == "bar" + end - it "should fail if its multiple_render method is used" do - lambda { @format.render_multiple("foo") }.should raise_error(NotImplementedError) - end + it "should intern multiples by calling 'Marshal.load'" do + text = "foo" + Marshal.expects(:load).with("foo").returns "bar" + @marshal.intern_multiple(String, text).should == "bar" + end + end - it "should fail if its multiple_intern method is used" do - lambda { @format.intern_multiple(String, "foo") }.should raise_error(NotImplementedError) - end + describe "plaintext" do + before do + @text = Puppet::Network::FormatHandler.format(:s) + end - it "should have a weight of 1" do - @format.weight.should == 1 - end + it "should have its mimetype set to text/plain" do + @text.mime.should == "text/plain" end - it "should include a pson format" do - Puppet::Network::FormatHandler.format(:pson).should_not be_nil + it "should use 'txt' as its extension" do + @text.extension.should == "txt" end + end - describe "pson" do - confine "Missing 'pson' library" => Puppet.features.pson? + describe "dot" do + before do + @dot = Puppet::Network::FormatHandler.format(:dot) + end - before do - @pson = Puppet::Network::FormatHandler.format(:pson) - end + it "should have its mimetype set to text/dot" do + @dot.mime.should == "text/dot" + end + end - it "should have its mime type set to text/pson" do - Puppet::Network::FormatHandler.format(:pson).mime.should == "text/pson" - end + describe Puppet::Network::FormatHandler.format(:raw) do + before do + @format = Puppet::Network::FormatHandler.format(:raw) + end - it "should require the :render_method" do - Puppet::Network::FormatHandler.format(:pson).required_methods.should be_include(:render_method) - end + it "should exist" do + @format.should_not be_nil + end - it "should require the :intern_method" do - Puppet::Network::FormatHandler.format(:pson).required_methods.should be_include(:intern_method) - end + it "should have its mimetype set to application/x-raw" do + @format.mime.should == "application/x-raw" + end - it "should have a weight of 10" do - @pson.weight.should == 10 - end + it "should always be supported" do + @format.should be_supported(String) + end - describe "when supported" do - it "should render by calling 'to_pson' on the instance" do - instance = PsonTest.new("foo") - instance.expects(:to_pson).returns "foo" - @pson.render(instance).should == "foo" - end - - it "should render multiple instances by calling 'to_pson' on the array" do - instances = [mock('instance')] + it "should fail if its multiple_render method is used" do + lambda { @format.render_multiple("foo") }.should raise_error(NotImplementedError) + end - instances.expects(:to_pson).returns "foo" + it "should fail if its multiple_intern method is used" do + lambda { @format.intern_multiple(String, "foo") }.should raise_error(NotImplementedError) + end - @pson.render_multiple(instances).should == "foo" - end + it "should have a weight of 1" do + @format.weight.should == 1 + end + end + + it "should include a pson format" do + Puppet::Network::FormatHandler.format(:pson).should_not be_nil + end + + describe "pson" do + confine "Missing 'pson' library" => Puppet.features.pson? + + before do + @pson = Puppet::Network::FormatHandler.format(:pson) + end - it "should intern by calling 'PSON.parse' on the text and then using from_pson to convert the data into an instance" do - text = "foo" - PSON.expects(:parse).with("foo").returns("type" => "PsonTest", "data" => "foo") - PsonTest.expects(:from_pson).with("foo").returns "parsed_pson" - @pson.intern(PsonTest, text).should == "parsed_pson" - end + it "should have its mime type set to text/pson" do + Puppet::Network::FormatHandler.format(:pson).mime.should == "text/pson" + end - it "should not render twice if 'PSON.parse' creates the appropriate instance" do - text = "foo" - instance = PsonTest.new("foo") - PSON.expects(:parse).with("foo").returns(instance) - PsonTest.expects(:from_pson).never - @pson.intern(PsonTest, text).should equal(instance) - end + it "should require the :render_method" do + Puppet::Network::FormatHandler.format(:pson).required_methods.should be_include(:render_method) + end - it "should intern by calling 'PSON.parse' on the text and then using from_pson to convert the actual into an instance if the pson has no class/data separation" do - text = "foo" - PSON.expects(:parse).with("foo").returns("foo") - PsonTest.expects(:from_pson).with("foo").returns "parsed_pson" - @pson.intern(PsonTest, text).should == "parsed_pson" - end + it "should require the :intern_method" do + Puppet::Network::FormatHandler.format(:pson).required_methods.should be_include(:intern_method) + end + + it "should have a weight of 10" do + @pson.weight.should == 10 + end - it "should intern multiples by parsing the text and using 'class.intern' on each resulting data structure" do - text = "foo" - PSON.expects(:parse).with("foo").returns ["bar", "baz"] - PsonTest.expects(:from_pson).with("bar").returns "BAR" - PsonTest.expects(:from_pson).with("baz").returns "BAZ" - @pson.intern_multiple(PsonTest, text).should == %w{BAR BAZ} - end - end + describe "when supported" do + it "should render by calling 'to_pson' on the instance" do + instance = PsonTest.new("foo") + instance.expects(:to_pson).returns "foo" + @pson.render(instance).should == "foo" + end + + it "should render multiple instances by calling 'to_pson' on the array" do + instances = [mock('instance')] + + instances.expects(:to_pson).returns "foo" + + @pson.render_multiple(instances).should == "foo" + end + + it "should intern by calling 'PSON.parse' on the text and then using from_pson to convert the data into an instance" do + text = "foo" + PSON.expects(:parse).with("foo").returns("type" => "PsonTest", "data" => "foo") + PsonTest.expects(:from_pson).with("foo").returns "parsed_pson" + @pson.intern(PsonTest, text).should == "parsed_pson" + end + + it "should not render twice if 'PSON.parse' creates the appropriate instance" do + text = "foo" + instance = PsonTest.new("foo") + PSON.expects(:parse).with("foo").returns(instance) + PsonTest.expects(:from_pson).never + @pson.intern(PsonTest, text).should equal(instance) + end + + it "should intern by calling 'PSON.parse' on the text and then using from_pson to convert the actual into an instance if the pson has no class/data separation" do + text = "foo" + PSON.expects(:parse).with("foo").returns("foo") + PsonTest.expects(:from_pson).with("foo").returns "parsed_pson" + @pson.intern(PsonTest, text).should == "parsed_pson" + end + + it "should intern multiples by parsing the text and using 'class.intern' on each resulting data structure" do + text = "foo" + PSON.expects(:parse).with("foo").returns ["bar", "baz"] + PsonTest.expects(:from_pson).with("bar").returns "BAR" + PsonTest.expects(:from_pson).with("baz").returns "BAZ" + @pson.intern_multiple(PsonTest, text).should == %w{BAR BAZ} + end end + end end diff --git a/spec/unit/network/handler/fileserver_spec.rb b/spec/unit/network/handler/fileserver_spec.rb index 371e75d24..40d1e57cd 100644 --- a/spec/unit/network/handler/fileserver_spec.rb +++ b/spec/unit/network/handler/fileserver_spec.rb @@ -6,167 +6,167 @@ require 'puppet/network/handler/fileserver' describe Puppet::Network::Handler::FileServer do - require 'tmpdir' - - def create_file(filename) - File.open(filename, "w") { |f| f.puts filename} - end - - def create_nested_file - dirname = File.join(@basedir, "nested_dir") - Dir.mkdir(dirname) - file = File.join(dirname, "nested_dir_file") - create_file(file) - end - - before do - @basedir = File.join(Dir.tmpdir, "test_network_handler") - Dir.mkdir(@basedir) - @file = File.join(@basedir, "aFile") - @link = File.join(@basedir, "aLink") - create_file(@file) - @mount = Puppet::Network::Handler::FileServer::Mount.new("some_path", @basedir) - end - - it "should list a single directory" do - @mount.list("/", false, false).should == [["/", "directory"]] - end - - it "should list a file within a directory when given the file path" do - @mount.list("/aFile", false, "false").should == [["/", "file"]] + require 'tmpdir' + + def create_file(filename) + File.open(filename, "w") { |f| f.puts filename} + end + + def create_nested_file + dirname = File.join(@basedir, "nested_dir") + Dir.mkdir(dirname) + file = File.join(dirname, "nested_dir_file") + create_file(file) + end + + before do + @basedir = File.join(Dir.tmpdir, "test_network_handler") + Dir.mkdir(@basedir) + @file = File.join(@basedir, "aFile") + @link = File.join(@basedir, "aLink") + create_file(@file) + @mount = Puppet::Network::Handler::FileServer::Mount.new("some_path", @basedir) + end + + it "should list a single directory" do + @mount.list("/", false, false).should == [["/", "directory"]] + end + + it "should list a file within a directory when given the file path" do + @mount.list("/aFile", false, "false").should == [["/", "file"]] + end + + it "should list a file within a directory when given the file path with recursion" do + @mount.list("/aFile", true, "false").should == [["/", "file"]] + end + + it "should return nil for a non-existent path" do + @mount.list("/no_such_file", false, false).should be(nil) + end + + it "should list a symbolic link as a file when given the link path" do + File.symlink(@file, @link) + @mount.list("/aLink", false, false).should == [["/", "file"]] + end + + it "should return nil for a dangling symbolic link when given the link path" do + File.symlink("/some/where", @link) + @mount.list("/aLink", false, false).should be(nil) + end + + it "should list directory contents of a flat directory structure when asked to recurse" do + list = @mount.list("/", true, false) + list.should include(["/aFile", "file"]) + list.should include(["/", "directory"]) + list.should have(2).items + end + + it "should list the contents of a nested directory" do + create_nested_file + list = @mount.list("/", true, false) + list.sort.should == [ ["/aFile", "file"], ["/", "directory"] , ["/nested_dir", "directory"], ["/nested_dir/nested_dir_file", "file"]].sort + end + + it "should list the contents of a directory ignoring files that match" do + create_nested_file + list = @mount.list("/", true, "*File") + list.sort.should == [ ["/", "directory"] , ["/nested_dir", "directory"], ["/nested_dir/nested_dir_file", "file"]].sort + end + + it "should list the contents of a directory ignoring directories that match" do + create_nested_file + list = @mount.list("/", true, "*nested_dir") + list.sort.should == [ ["/aFile", "file"], ["/", "directory"] ].sort + end + + it "should list the contents of a directory ignoring all ignore patterns that match" do + create_nested_file + list = @mount.list("/", true, ["*File" , "*nested_dir"]) + list.should == [ ["/", "directory"] ] + end + + it "should list the directory when recursing to a depth of zero" do + create_nested_file + list = @mount.list("/", 0, false) + list.should == [["/", "directory"]] + end + + it "should list the base directory and files and nested directory to a depth of one" do + create_nested_file + list = @mount.list("/", 1, false) + list.sort.should == [ ["/aFile", "file"], ["/nested_dir", "directory"], ["/", "directory"] ].sort + end + + it "should list the base directory and files and nested directory to a depth of two" do + create_nested_file + list = @mount.list("/", 2, false) + list.sort.should == [ ["/aFile", "file"], ["/", "directory"] , ["/nested_dir", "directory"], ["/nested_dir/nested_dir_file", "file"]].sort + end + + it "should list the base directory and files and nested directory to a depth greater than the directory structure" do + create_nested_file + list = @mount.list("/", 42, false) + list.sort.should == [ ["/aFile", "file"], ["/", "directory"] , ["/nested_dir", "directory"], ["/nested_dir/nested_dir_file", "file"]].sort + end + + it "should list a valid symbolic link as a file when recursing base dir" do + File.symlink(@file, @link) + list = @mount.list("/", true, false) + list.sort.should == [ ["/", "directory"], ["/aFile", "file"], ["/aLink", "file"] ].sort + end + + it "should not error when a dangling symlink is present" do + File.symlink("/some/where", @link) + lambda { @mount.list("/", true, false) }.should_not raise_error + end + + it "should return the directory contents of valid entries when a dangling symlink is present" do + File.symlink("/some/where", @link) + list = @mount.list("/", true, false) + list.sort.should == [ ["/aFile", "file"], ["/", "directory"] ].sort + end + + describe Puppet::Network::Handler::FileServer::PluginMount do + PLUGINS = Puppet::Network::Handler::FileServer::PLUGINS + + # create a module plugin hierarchy + def create_plugin(mod, plugin) + dirname = File.join(@basedir, mod) + Dir.mkdir(dirname) + plugins = File.join(dirname, PLUGINS) + Dir.mkdir(plugins) + facter = File.join(plugins, plugin) + Dir.mkdir(facter) + create_file(File.join(facter,"fact.rb")) + end + + before :each do + @modules = ["one","two"] + @modules.each { |m| create_plugin(m, "facter") } + + Puppet::Node::Environment.new.stubs(:modulepath).returns @basedir + + @mount = Puppet::Network::Handler::FileServer::PluginMount.new(PLUGINS) + @mount.allow("*") end it "should list a file within a directory when given the file path with recursion" do - @mount.list("/aFile", true, "false").should == [["/", "file"]] + @mount.list("facter/fact.rb", true, "false").should == [["/", "file"], ["/", "file"]] end - it "should return nil for a non-existent path" do - @mount.list("/no_such_file", false, false).should be(nil) + it "should return a merged view of all plugins for all modules" do + list = @mount.list("facter",true,false) + list.should == [["/", "directory"], ["/fact.rb", "file"], ["/", "directory"], ["/fact.rb", "file"]] end - it "should list a symbolic link as a file when given the link path" do - File.symlink(@file, @link) - @mount.list("/aLink", false, false).should == [["/", "file"]] + it "should not fail for inexistant plugins type" do + lambda { @mount.list("puppet/parser",true,false) }.should_not raise_error end - it "should return nil for a dangling symbolic link when given the link path" do - File.symlink("/some/where", @link) - @mount.list("/aLink", false, false).should be(nil) - end - - it "should list directory contents of a flat directory structure when asked to recurse" do - list = @mount.list("/", true, false) - list.should include(["/aFile", "file"]) - list.should include(["/", "directory"]) - list.should have(2).items - end + end - it "should list the contents of a nested directory" do - create_nested_file - list = @mount.list("/", true, false) - list.sort.should == [ ["/aFile", "file"], ["/", "directory"] , ["/nested_dir", "directory"], ["/nested_dir/nested_dir_file", "file"]].sort - end - - it "should list the contents of a directory ignoring files that match" do - create_nested_file - list = @mount.list("/", true, "*File") - list.sort.should == [ ["/", "directory"] , ["/nested_dir", "directory"], ["/nested_dir/nested_dir_file", "file"]].sort - end - - it "should list the contents of a directory ignoring directories that match" do - create_nested_file - list = @mount.list("/", true, "*nested_dir") - list.sort.should == [ ["/aFile", "file"], ["/", "directory"] ].sort - end - - it "should list the contents of a directory ignoring all ignore patterns that match" do - create_nested_file - list = @mount.list("/", true, ["*File" , "*nested_dir"]) - list.should == [ ["/", "directory"] ] - end - - it "should list the directory when recursing to a depth of zero" do - create_nested_file - list = @mount.list("/", 0, false) - list.should == [["/", "directory"]] - end - - it "should list the base directory and files and nested directory to a depth of one" do - create_nested_file - list = @mount.list("/", 1, false) - list.sort.should == [ ["/aFile", "file"], ["/nested_dir", "directory"], ["/", "directory"] ].sort - end - - it "should list the base directory and files and nested directory to a depth of two" do - create_nested_file - list = @mount.list("/", 2, false) - list.sort.should == [ ["/aFile", "file"], ["/", "directory"] , ["/nested_dir", "directory"], ["/nested_dir/nested_dir_file", "file"]].sort - end - - it "should list the base directory and files and nested directory to a depth greater than the directory structure" do - create_nested_file - list = @mount.list("/", 42, false) - list.sort.should == [ ["/aFile", "file"], ["/", "directory"] , ["/nested_dir", "directory"], ["/nested_dir/nested_dir_file", "file"]].sort - end - - it "should list a valid symbolic link as a file when recursing base dir" do - File.symlink(@file, @link) - list = @mount.list("/", true, false) - list.sort.should == [ ["/", "directory"], ["/aFile", "file"], ["/aLink", "file"] ].sort - end - - it "should not error when a dangling symlink is present" do - File.symlink("/some/where", @link) - lambda { @mount.list("/", true, false) }.should_not raise_error - end - - it "should return the directory contents of valid entries when a dangling symlink is present" do - File.symlink("/some/where", @link) - list = @mount.list("/", true, false) - list.sort.should == [ ["/aFile", "file"], ["/", "directory"] ].sort - end - - describe Puppet::Network::Handler::FileServer::PluginMount do - PLUGINS = Puppet::Network::Handler::FileServer::PLUGINS - - # create a module plugin hierarchy - def create_plugin(mod, plugin) - dirname = File.join(@basedir, mod) - Dir.mkdir(dirname) - plugins = File.join(dirname, PLUGINS) - Dir.mkdir(plugins) - facter = File.join(plugins, plugin) - Dir.mkdir(facter) - create_file(File.join(facter,"fact.rb")) - end - - before :each do - @modules = ["one","two"] - @modules.each { |m| create_plugin(m, "facter") } - - Puppet::Node::Environment.new.stubs(:modulepath).returns @basedir - - @mount = Puppet::Network::Handler::FileServer::PluginMount.new(PLUGINS) - @mount.allow("*") - end - - it "should list a file within a directory when given the file path with recursion" do - @mount.list("facter/fact.rb", true, "false").should == [["/", "file"], ["/", "file"]] - end - - it "should return a merged view of all plugins for all modules" do - list = @mount.list("facter",true,false) - list.should == [["/", "directory"], ["/fact.rb", "file"], ["/", "directory"], ["/fact.rb", "file"]] - end - - it "should not fail for inexistant plugins type" do - lambda { @mount.list("puppet/parser",true,false) }.should_not raise_error - end - - end - - after do - FileUtils.rm_rf(@basedir) - end + after do + FileUtils.rm_rf(@basedir) + end end diff --git a/spec/unit/network/http/api/v1_spec.rb b/spec/unit/network/http/api/v1_spec.rb index fc284de82..c593242c0 100644 --- a/spec/unit/network/http/api/v1_spec.rb +++ b/spec/unit/network/http/api/v1_spec.rb @@ -5,118 +5,118 @@ Dir.chdir(File.dirname(__FILE__)) { (s = lambda { |f| File.exist?(f) ? require(f require 'puppet/network/http/api/v1' class V1RestApiTester - include Puppet::Network::HTTP::API::V1 + include Puppet::Network::HTTP::API::V1 end describe Puppet::Network::HTTP::API::V1 do + before do + @tester = V1RestApiTester.new + end + + it "should be able to convert a URI into a request" do + @tester.should respond_to(:uri2indirection) + end + + it "should be able to convert a request into a URI" do + @tester.should respond_to(:indirection2uri) + end + + describe "when converting a URI into a request" do before do - @tester = V1RestApiTester.new + @tester.stubs(:handler).returns "foo" end - it "should be able to convert a URI into a request" do - @tester.should respond_to(:uri2indirection) + it "should require the http method, the URI, and the query parameters" do + # Not a terribly useful test, but an important statement for the spec + lambda { @tester.uri2indirection("/foo") }.should raise_error(ArgumentError) end - it "should be able to convert a request into a URI" do - @tester.should respond_to(:indirection2uri) + it "should use the first field of the URI as the environment" do + @tester.uri2indirection("GET", "/env/foo/bar", {}).environment.should == Puppet::Node::Environment.new("env") end - describe "when converting a URI into a request" do - before do - @tester.stubs(:handler).returns "foo" - end - - it "should require the http method, the URI, and the query parameters" do - # Not a terribly useful test, but an important statement for the spec - lambda { @tester.uri2indirection("/foo") }.should raise_error(ArgumentError) - end - - it "should use the first field of the URI as the environment" do - @tester.uri2indirection("GET", "/env/foo/bar", {}).environment.should == Puppet::Node::Environment.new("env") - end - - it "should fail if the environment is not alphanumeric" do - lambda { @tester.uri2indirection("GET", "/env ness/foo/bar", {}) }.should raise_error(ArgumentError) - end + it "should fail if the environment is not alphanumeric" do + lambda { @tester.uri2indirection("GET", "/env ness/foo/bar", {}) }.should raise_error(ArgumentError) + end - it "should use the environment from the URI even if one is specified in the parameters" do - @tester.uri2indirection("GET", "/env/foo/bar", {:environment => "otherenv"}).environment.should == Puppet::Node::Environment.new("env") - end + it "should use the environment from the URI even if one is specified in the parameters" do + @tester.uri2indirection("GET", "/env/foo/bar", {:environment => "otherenv"}).environment.should == Puppet::Node::Environment.new("env") + end - it "should use the second field of the URI as the indirection name" do - @tester.uri2indirection("GET", "/env/foo/bar", {}).indirection_name.should == :foo - end + it "should use the second field of the URI as the indirection name" do + @tester.uri2indirection("GET", "/env/foo/bar", {}).indirection_name.should == :foo + end - it "should fail if the indirection name is not alphanumeric" do - lambda { @tester.uri2indirection("GET", "/env/foo ness/bar", {}) }.should raise_error(ArgumentError) - end + it "should fail if the indirection name is not alphanumeric" do + lambda { @tester.uri2indirection("GET", "/env/foo ness/bar", {}) }.should raise_error(ArgumentError) + end - it "should use the remainder of the URI as the indirection key" do - @tester.uri2indirection("GET", "/env/foo/bar", {}).key.should == "bar" - end + it "should use the remainder of the URI as the indirection key" do + @tester.uri2indirection("GET", "/env/foo/bar", {}).key.should == "bar" + end - it "should support the indirection key being a /-separated file path" do - @tester.uri2indirection("GET", "/env/foo/bee/baz/bomb", {}).key.should == "bee/baz/bomb" - end + it "should support the indirection key being a /-separated file path" do + @tester.uri2indirection("GET", "/env/foo/bee/baz/bomb", {}).key.should == "bee/baz/bomb" + end - it "should fail if no indirection key is specified" do - lambda { @tester.uri2indirection("GET", "/env/foo/", {}) }.should raise_error(ArgumentError) - lambda { @tester.uri2indirection("GET", "/env/foo", {}) }.should raise_error(ArgumentError) - end + it "should fail if no indirection key is specified" do + lambda { @tester.uri2indirection("GET", "/env/foo/", {}) }.should raise_error(ArgumentError) + lambda { @tester.uri2indirection("GET", "/env/foo", {}) }.should raise_error(ArgumentError) + end - it "should choose 'find' as the indirection method if the http method is a GET and the indirection name is singular" do - @tester.uri2indirection("GET", "/env/foo/bar", {}).method.should == :find - end + it "should choose 'find' as the indirection method if the http method is a GET and the indirection name is singular" do + @tester.uri2indirection("GET", "/env/foo/bar", {}).method.should == :find + end - it "should choose 'search' as the indirection method if the http method is a GET and the indirection name is plural" do - @tester.uri2indirection("GET", "/env/foos/bar", {}).method.should == :search - end + it "should choose 'search' as the indirection method if the http method is a GET and the indirection name is plural" do + @tester.uri2indirection("GET", "/env/foos/bar", {}).method.should == :search + end - it "should choose 'delete' as the indirection method if the http method is a DELETE and the indirection name is singular" do - @tester.uri2indirection("DELETE", "/env/foo/bar", {}).method.should == :destroy - end + it "should choose 'delete' as the indirection method if the http method is a DELETE and the indirection name is singular" do + @tester.uri2indirection("DELETE", "/env/foo/bar", {}).method.should == :destroy + end - it "should choose 'save' as the indirection method if the http method is a PUT and the indirection name is singular" do - @tester.uri2indirection("PUT", "/env/foo/bar", {}).method.should == :save - end + it "should choose 'save' as the indirection method if the http method is a PUT and the indirection name is singular" do + @tester.uri2indirection("PUT", "/env/foo/bar", {}).method.should == :save + end - it "should fail if an indirection method cannot be picked" do - lambda { @tester.uri2indirection("UPDATE", "/env/foo/bar", {}) }.should raise_error(ArgumentError) - end + it "should fail if an indirection method cannot be picked" do + lambda { @tester.uri2indirection("UPDATE", "/env/foo/bar", {}) }.should raise_error(ArgumentError) + end - it "should URI unescape the indirection key" do - escaped = URI.escape("foo bar") - @tester.uri2indirection("GET", "/env/foo/#{escaped}", {}).key.should == "foo bar" - end + it "should URI unescape the indirection key" do + escaped = URI.escape("foo bar") + @tester.uri2indirection("GET", "/env/foo/#{escaped}", {}).key.should == "foo bar" end + end - describe "when converting a request into a URI" do - before do - @request = Puppet::Indirector::Request.new(:foo, :find, "with spaces", :foo => :bar, :environment => "myenv") - end + describe "when converting a request into a URI" do + before do + @request = Puppet::Indirector::Request.new(:foo, :find, "with spaces", :foo => :bar, :environment => "myenv") + end - it "should use the environment as the first field of the URI" do - @tester.indirection2uri(@request).split("/")[1].should == "myenv" - end + it "should use the environment as the first field of the URI" do + @tester.indirection2uri(@request).split("/")[1].should == "myenv" + end - it "should use the indirection as the second field of the URI" do - @tester.indirection2uri(@request).split("/")[2].should == "foo" - end + it "should use the indirection as the second field of the URI" do + @tester.indirection2uri(@request).split("/")[2].should == "foo" + end - it "should pluralize the indirection name if the method is 'search'" do - @request.stubs(:method).returns :search - @tester.indirection2uri(@request).split("/")[2].should == "foos" - end + it "should pluralize the indirection name if the method is 'search'" do + @request.stubs(:method).returns :search + @tester.indirection2uri(@request).split("/")[2].should == "foos" + end - it "should use the escaped key as the remainder of the URI" do - escaped = URI.escape("with spaces") - @tester.indirection2uri(@request).split("/")[3].sub(/\?.+/, '').should == escaped - end + it "should use the escaped key as the remainder of the URI" do + escaped = URI.escape("with spaces") + @tester.indirection2uri(@request).split("/")[3].sub(/\?.+/, '').should == escaped + end - it "should add the query string to the URI" do - @request.expects(:query_string).returns "?query" - @tester.indirection2uri(@request).should =~ /\?query$/ - end + it "should add the query string to the URI" do + @request.expects(:query_string).returns "?query" + @tester.indirection2uri(@request).should =~ /\?query$/ end + end end diff --git a/spec/unit/network/http/compression_spec.rb b/spec/unit/network/http/compression_spec.rb index ace1f353a..b46941f46 100644 --- a/spec/unit/network/http/compression_spec.rb +++ b/spec/unit/network/http/compression_spec.rb @@ -4,196 +4,196 @@ require File.dirname(__FILE__) + '/../../../spec_helper' describe "http compression" do - describe "when zlib is not available" do - before(:each) do - Puppet.features.stubs(:zlib?).returns false + describe "when zlib is not available" do + before(:each) do + Puppet.features.stubs(:zlib?).returns false - require 'puppet/network/http/compression' - class HttpUncompressor - include Puppet::Network::HTTP::Compression::None - end + require 'puppet/network/http/compression' + class HttpUncompressor + include Puppet::Network::HTTP::Compression::None + end - @uncompressor = HttpUncompressor.new - end + @uncompressor = HttpUncompressor.new + end - it "should have a module function that returns the None underlying module" do - Puppet::Network::HTTP::Compression.module.should == Puppet::Network::HTTP::Compression::None - end + it "should have a module function that returns the None underlying module" do + Puppet::Network::HTTP::Compression.module.should == Puppet::Network::HTTP::Compression::None + end - it "should not add any Accept-Encoding header" do - @uncompressor.add_accept_encoding({}).should == {} - end + it "should not add any Accept-Encoding header" do + @uncompressor.add_accept_encoding({}).should == {} + end - it "should not tamper the body" do - response = stub 'response', :body => "data" - @uncompressor.uncompress_body(response).should == "data" - end + it "should not tamper the body" do + response = stub 'response', :body => "data" + @uncompressor.uncompress_body(response).should == "data" + end - it "should yield an identity uncompressor" do - response = stub 'response' - @uncompressor.uncompress(response) { |u| - u.should be_instance_of(Puppet::Network::HTTP::Compression::IdentityAdapter) - } - end + it "should yield an identity uncompressor" do + response = stub 'response' + @uncompressor.uncompress(response) { |u| + u.should be_instance_of(Puppet::Network::HTTP::Compression::IdentityAdapter) + } end + end - describe "when zlib is available" do - confine "Zlib is missing" => Puppet.features.zlib? + describe "when zlib is available" do + confine "Zlib is missing" => Puppet.features.zlib? - before(:each) do - Puppet.features.stubs(:zlib?).returns true + before(:each) do + Puppet.features.stubs(:zlib?).returns true - require 'puppet/network/http/compression' - class HttpUncompressor - include Puppet::Network::HTTP::Compression::Active - end + require 'puppet/network/http/compression' + class HttpUncompressor + include Puppet::Network::HTTP::Compression::Active + end - @uncompressor = HttpUncompressor.new - end + @uncompressor = HttpUncompressor.new + end - it "should have a module function that returns the Active underlying module" do - Puppet::Network::HTTP::Compression.module.should == Puppet::Network::HTTP::Compression::Active - end + it "should have a module function that returns the Active underlying module" do + Puppet::Network::HTTP::Compression.module.should == Puppet::Network::HTTP::Compression::Active + end - it "should add an Accept-Encoding header when http compression is available" do - Puppet.settings.expects(:[]).with(:http_compression).returns(true) - headers = @uncompressor.add_accept_encoding({}) - headers.should have_key('accept-encoding') - headers['accept-encoding'].should =~ /gzip/ - headers['accept-encoding'].should =~ /deflate/ - headers['accept-encoding'].should =~ /identity/ - end + it "should add an Accept-Encoding header when http compression is available" do + Puppet.settings.expects(:[]).with(:http_compression).returns(true) + headers = @uncompressor.add_accept_encoding({}) + headers.should have_key('accept-encoding') + headers['accept-encoding'].should =~ /gzip/ + headers['accept-encoding'].should =~ /deflate/ + headers['accept-encoding'].should =~ /identity/ + end - it "should not add Accept-Encoding header if http compression is not available" do - Puppet.settings.stubs(:[]).with(:http_compression).returns(false) - @uncompressor.add_accept_encoding({}).should == {} - end + it "should not add Accept-Encoding header if http compression is not available" do + Puppet.settings.stubs(:[]).with(:http_compression).returns(false) + @uncompressor.add_accept_encoding({}).should == {} + end - describe "when uncompressing response body" do - before do - @response = stub 'response' - @response.stubs(:[]).with('content-encoding') - @response.stubs(:body).returns("mydata") - end + describe "when uncompressing response body" do + before do + @response = stub 'response' + @response.stubs(:[]).with('content-encoding') + @response.stubs(:body).returns("mydata") + end - it "should return untransformed response body with no content-encoding" do - @uncompressor.uncompress_body(@response).should == "mydata" - end + it "should return untransformed response body with no content-encoding" do + @uncompressor.uncompress_body(@response).should == "mydata" + end - it "should return untransformed response body with 'identity' content-encoding" do - @response.stubs(:[]).with('content-encoding').returns('identity') - @uncompressor.uncompress_body(@response).should == "mydata" - end + it "should return untransformed response body with 'identity' content-encoding" do + @response.stubs(:[]).with('content-encoding').returns('identity') + @uncompressor.uncompress_body(@response).should == "mydata" + end - it "should use a Zlib inflater with 'deflate' content-encoding" do - @response.stubs(:[]).with('content-encoding').returns('deflate') + it "should use a Zlib inflater with 'deflate' content-encoding" do + @response.stubs(:[]).with('content-encoding').returns('deflate') - inflater = stub 'inflater' - Zlib::Inflate.expects(:new).returns(inflater) - inflater.expects(:inflate).with("mydata").returns "uncompresseddata" + inflater = stub 'inflater' + Zlib::Inflate.expects(:new).returns(inflater) + inflater.expects(:inflate).with("mydata").returns "uncompresseddata" - @uncompressor.uncompress_body(@response).should == "uncompresseddata" - end + @uncompressor.uncompress_body(@response).should == "uncompresseddata" + end - it "should use a GzipReader with 'gzip' content-encoding" do - @response.stubs(:[]).with('content-encoding').returns('gzip') + it "should use a GzipReader with 'gzip' content-encoding" do + @response.stubs(:[]).with('content-encoding').returns('gzip') - io = stub 'io' - StringIO.expects(:new).with("mydata").returns io + io = stub 'io' + StringIO.expects(:new).with("mydata").returns io - reader = stub 'gzip reader' - Zlib::GzipReader.expects(:new).with(io).returns(reader) - reader.expects(:read).returns "uncompresseddata" + reader = stub 'gzip reader' + Zlib::GzipReader.expects(:new).with(io).returns(reader) + reader.expects(:read).returns "uncompresseddata" - @uncompressor.uncompress_body(@response).should == "uncompresseddata" - end - end + @uncompressor.uncompress_body(@response).should == "uncompresseddata" + end + end - describe "when uncompressing by chunk" do - before do - @response = stub 'response' - @response.stubs(:[]).with('content-encoding') - - @inflater = stub_everything 'inflater' - Zlib::Inflate.stubs(:new).returns(@inflater) - end - - it "should yield an identity uncompressor with no content-encoding" do - @uncompressor.uncompress(@response) { |u| - u.should be_instance_of(Puppet::Network::HTTP::Compression::IdentityAdapter) - } - end - - it "should yield an identity uncompressor with 'identity' content-encoding" do - @response.stubs(:[]).with('content-encoding').returns 'identity' - @uncompressor.uncompress(@response) { |u| - u.should be_instance_of(Puppet::Network::HTTP::Compression::IdentityAdapter) - } - end - - %w{gzip deflate}.each do |c| - it "should yield a Zlib uncompressor with '#{c}' content-encoding" do - @response.stubs(:[]).with('content-encoding').returns c - @uncompressor.uncompress(@response) { |u| - u.should be_instance_of(Puppet::Network::HTTP::Compression::Active::ZlibAdapter) - } - end - end - - it "should close the underlying adapter" do - adapter = stub_everything 'adapter' - Puppet::Network::HTTP::Compression::IdentityAdapter.expects(:new).returns(adapter) - - adapter.expects(:close) - @uncompressor.uncompress(@response) { |u| } - end + describe "when uncompressing by chunk" do + before do + @response = stub 'response' + @response.stubs(:[]).with('content-encoding') + + @inflater = stub_everything 'inflater' + Zlib::Inflate.stubs(:new).returns(@inflater) + end + + it "should yield an identity uncompressor with no content-encoding" do + @uncompressor.uncompress(@response) { |u| + u.should be_instance_of(Puppet::Network::HTTP::Compression::IdentityAdapter) + } + end + + it "should yield an identity uncompressor with 'identity' content-encoding" do + @response.stubs(:[]).with('content-encoding').returns 'identity' + @uncompressor.uncompress(@response) { |u| + u.should be_instance_of(Puppet::Network::HTTP::Compression::IdentityAdapter) + } + end + + %w{gzip deflate}.each do |c| + it "should yield a Zlib uncompressor with '#{c}' content-encoding" do + @response.stubs(:[]).with('content-encoding').returns c + @uncompressor.uncompress(@response) { |u| + u.should be_instance_of(Puppet::Network::HTTP::Compression::Active::ZlibAdapter) + } end + end - describe "zlib adapter" do - before do - @inflater = stub_everything 'inflater' - Zlib::Inflate.stubs(:new).returns(@inflater) - @adapter = Puppet::Network::HTTP::Compression::Active::ZlibAdapter.new - end - - it "should initialize the underlying inflater with gzip/zlib header parsing" do - Zlib::Inflate.expects(:new).with(15+32) - Puppet::Network::HTTP::Compression::Active::ZlibAdapter.new - end - - it "should inflate the given chunk" do - @inflater.expects(:inflate).with("chunk") - @adapter.uncompress("chunk") - end - - it "should return the inflated chunk" do - @inflater.stubs(:inflate).with("chunk").returns("uncompressed") - @adapter.uncompress("chunk").should == "uncompressed" - end - - it "should try a 'regular' inflater on Zlib::DataError" do - @inflater.expects(:inflate).raises(Zlib::DataError.new("not a zlib stream")) - inflater = stub_everything 'inflater2' - inflater.expects(:inflate).with("chunk").returns("uncompressed") - Zlib::Inflate.expects(:new).with.returns(inflater) - @adapter.uncompress("chunk") - end - - it "should raise the error the second time" do - @inflater.expects(:inflate).raises(Zlib::DataError.new("not a zlib stream")) - Zlib::Inflate.expects(:new).with.returns(@inflater) - lambda { @adapter.uncompress("chunk") }.should raise_error - end - - it "should finish the stream on close" do - @inflater.expects(:finish) - @adapter.close - end - - it "should close the stream on close" do - @inflater.expects(:close) - @adapter.close - end - end + it "should close the underlying adapter" do + adapter = stub_everything 'adapter' + Puppet::Network::HTTP::Compression::IdentityAdapter.expects(:new).returns(adapter) + + adapter.expects(:close) + @uncompressor.uncompress(@response) { |u| } + end + end + + describe "zlib adapter" do + before do + @inflater = stub_everything 'inflater' + Zlib::Inflate.stubs(:new).returns(@inflater) + @adapter = Puppet::Network::HTTP::Compression::Active::ZlibAdapter.new + end + + it "should initialize the underlying inflater with gzip/zlib header parsing" do + Zlib::Inflate.expects(:new).with(15+32) + Puppet::Network::HTTP::Compression::Active::ZlibAdapter.new + end + + it "should inflate the given chunk" do + @inflater.expects(:inflate).with("chunk") + @adapter.uncompress("chunk") + end + + it "should return the inflated chunk" do + @inflater.stubs(:inflate).with("chunk").returns("uncompressed") + @adapter.uncompress("chunk").should == "uncompressed" + end + + it "should try a 'regular' inflater on Zlib::DataError" do + @inflater.expects(:inflate).raises(Zlib::DataError.new("not a zlib stream")) + inflater = stub_everything 'inflater2' + inflater.expects(:inflate).with("chunk").returns("uncompressed") + Zlib::Inflate.expects(:new).with.returns(inflater) + @adapter.uncompress("chunk") + end + + it "should raise the error the second time" do + @inflater.expects(:inflate).raises(Zlib::DataError.new("not a zlib stream")) + Zlib::Inflate.expects(:new).with.returns(@inflater) + lambda { @adapter.uncompress("chunk") }.should raise_error + end + + it "should finish the stream on close" do + @inflater.expects(:finish) + @adapter.close + end + + it "should close the stream on close" do + @inflater.expects(:close) + @adapter.close + end end + end end diff --git a/spec/unit/network/http/handler_spec.rb b/spec/unit/network/http/handler_spec.rb index e6dd88130..76a9c5530 100755 --- a/spec/unit/network/http/handler_spec.rb +++ b/spec/unit/network/http/handler_spec.rb @@ -5,451 +5,451 @@ require 'puppet/network/http/handler' require 'puppet/network/rest_authorization' class HttpHandled - include Puppet::Network::HTTP::Handler + include Puppet::Network::HTTP::Handler end describe Puppet::Network::HTTP::Handler do - before do - @handler = HttpHandled.new - end + before do + @handler = HttpHandled.new + end - it "should include the v1 REST API" do - Puppet::Network::HTTP::Handler.ancestors.should be_include(Puppet::Network::HTTP::API::V1) - end + it "should include the v1 REST API" do + Puppet::Network::HTTP::Handler.ancestors.should be_include(Puppet::Network::HTTP::API::V1) + end - it "should include the Rest Authorization system" do - Puppet::Network::HTTP::Handler.ancestors.should be_include(Puppet::Network::RestAuthorization) + it "should include the Rest Authorization system" do + Puppet::Network::HTTP::Handler.ancestors.should be_include(Puppet::Network::RestAuthorization) + end + + it "should have a method for initializing" do + @handler.should respond_to(:initialize_for_puppet) + end + + describe "when initializing" do + it "should fail when no server type has been provided" do + lambda { @handler.initialize_for_puppet }.should raise_error(ArgumentError) end - it "should have a method for initializing" do - @handler.should respond_to(:initialize_for_puppet) + it "should set server type" do + @handler.initialize_for_puppet("foo") + @handler.server.should == "foo" end + end - describe "when initializing" do - it "should fail when no server type has been provided" do - lambda { @handler.initialize_for_puppet }.should raise_error(ArgumentError) - end + it "should be able to process requests" do + @handler.should respond_to(:process) + end - it "should set server type" do - @handler.initialize_for_puppet("foo") - @handler.server.should == "foo" - end + describe "when processing a request" do + before do + @request = stub('http request') + @request.stubs(:[]).returns "foo" + @response = stub('http response') + @model_class = stub('indirected model class') + + @result = stub 'result', :render => "mytext" + + @handler.stubs(:check_authorization) + + stub_server_interface end - it "should be able to process requests" do - @handler.should respond_to(:process) + # Stub out the interface we require our including classes to + # implement. + def stub_server_interface + @handler.stubs(:accept_header ).returns "format_one,format_two" + @handler.stubs(:content_type_header).returns "text/yaml" + @handler.stubs(:set_content_type ).returns "my_result" + @handler.stubs(:set_response ).returns "my_result" + @handler.stubs(:path ).returns "/my_handler/my_result" + @handler.stubs(:http_method ).returns("GET") + @handler.stubs(:params ).returns({}) + @handler.stubs(:content_type ).returns("text/plain") end - describe "when processing a request" do - before do - @request = stub('http request') - @request.stubs(:[]).returns "foo" - @response = stub('http response') - @model_class = stub('indirected model class') + it "should create an indirection request from the path, parameters, and http method" do + @handler.expects(:path).with(@request).returns "mypath" + @handler.expects(:http_method).with(@request).returns "mymethod" + @handler.expects(:params).with(@request).returns "myparams" - @result = stub 'result', :render => "mytext" + @handler.expects(:uri2indirection).with("mymethod", "mypath", "myparams").returns stub("request", :method => :find) - @handler.stubs(:check_authorization) + @handler.stubs(:do_find) - stub_server_interface - end + @handler.process(@request, @response) + end - # Stub out the interface we require our including classes to - # implement. - def stub_server_interface - @handler.stubs(:accept_header ).returns "format_one,format_two" - @handler.stubs(:content_type_header).returns "text/yaml" - @handler.stubs(:set_content_type ).returns "my_result" - @handler.stubs(:set_response ).returns "my_result" - @handler.stubs(:path ).returns "/my_handler/my_result" - @handler.stubs(:http_method ).returns("GET") - @handler.stubs(:params ).returns({}) - @handler.stubs(:content_type ).returns("text/plain") - end + it "should call the 'do' method associated with the indirection method" do + request = stub 'request' + @handler.expects(:uri2indirection).returns request - it "should create an indirection request from the path, parameters, and http method" do - @handler.expects(:path).with(@request).returns "mypath" - @handler.expects(:http_method).with(@request).returns "mymethod" - @handler.expects(:params).with(@request).returns "myparams" + request.expects(:method).returns "mymethod" - @handler.expects(:uri2indirection).with("mymethod", "mypath", "myparams").returns stub("request", :method => :find) + @handler.expects(:do_mymethod).with(request, @request, @response) - @handler.stubs(:do_find) + @handler.process(@request, @response) + end - @handler.process(@request, @response) - end + it "should delegate authorization to the RestAuthorization layer" do + request = stub 'request' + @handler.expects(:uri2indirection).returns request - it "should call the 'do' method associated with the indirection method" do - request = stub 'request' - @handler.expects(:uri2indirection).returns request + request.expects(:method).returns "mymethod" - request.expects(:method).returns "mymethod" + @handler.expects(:do_mymethod).with(request, @request, @response) - @handler.expects(:do_mymethod).with(request, @request, @response) + @handler.expects(:check_authorization).with(request) - @handler.process(@request, @response) - end + @handler.process(@request, @response) + end - it "should delegate authorization to the RestAuthorization layer" do - request = stub 'request' - @handler.expects(:uri2indirection).returns request + it "should return 403 if the request is not authorized" do + request = stub 'request' + @handler.expects(:uri2indirection).returns request - request.expects(:method).returns "mymethod" + @handler.expects(:do_mymethod).never - @handler.expects(:do_mymethod).with(request, @request, @response) + @handler.expects(:check_authorization).with(request).raises(Puppet::Network::AuthorizationError.new("forbindden")) - @handler.expects(:check_authorization).with(request) + @handler.expects(:set_response).with { |response, body, status| status == 403 } - @handler.process(@request, @response) - end + @handler.process(@request, @response) + end - it "should return 403 if the request is not authorized" do - request = stub 'request' - @handler.expects(:uri2indirection).returns request + it "should serialize a controller exception when an exception is thrown while finding the model instance" do + @handler.expects(:uri2indirection).returns stub("request", :method => :find) - @handler.expects(:do_mymethod).never + @handler.expects(:do_find).raises(ArgumentError, "The exception") + @handler.expects(:set_response).with { |response, body, status| body == "The exception" and status == 400 } + @handler.process(@request, @response) + end - @handler.expects(:check_authorization).with(request).raises(Puppet::Network::AuthorizationError.new("forbindden")) + it "should set the format to text/plain when serializing an exception" do + @handler.expects(:set_content_type).with(@response, "text/plain") + @handler.do_exception(@response, "A test", 404) + end - @handler.expects(:set_response).with { |response, body, status| status == 403 } + it "should raise an error if the request is formatted in an unknown format" do + @handler.stubs(:content_type_header).returns "unknown format" + lambda { @handler.request_format(@request) }.should raise_error + end - @handler.process(@request, @response) - end + it "should still find the correct format if content type contains charset information" do + @handler.stubs(:content_type_header).returns "text/plain; charset=UTF-8" + @handler.request_format(@request).should == "s" + end - it "should serialize a controller exception when an exception is thrown while finding the model instance" do - @handler.expects(:uri2indirection).returns stub("request", :method => :find) + describe "when finding a model instance" do + before do + @irequest = stub 'indirection_request', :method => :find, :indirection_name => "my_handler", :to_hash => {}, :key => "my_result", :model => @model_class - @handler.expects(:do_find).raises(ArgumentError, "The exception") - @handler.expects(:set_response).with { |response, body, status| body == "The exception" and status == 400 } - @handler.process(@request, @response) - end + @model_class.stubs(:find).returns @result - it "should set the format to text/plain when serializing an exception" do - @handler.expects(:set_content_type).with(@response, "text/plain") - @handler.do_exception(@response, "A test", 404) - end + @format = stub 'format', :suitable? => true, :mime => "text/format", :name => "format" + Puppet::Network::FormatHandler.stubs(:format).returns @format - it "should raise an error if the request is formatted in an unknown format" do - @handler.stubs(:content_type_header).returns "unknown format" - lambda { @handler.request_format(@request) }.should raise_error - end + @oneformat = stub 'one', :suitable? => true, :mime => "text/one", :name => "one" + Puppet::Network::FormatHandler.stubs(:format).with("one").returns @oneformat + end - it "should still find the correct format if content type contains charset information" do - @handler.stubs(:content_type_header).returns "text/plain; charset=UTF-8" - @handler.request_format(@request).should == "s" - end + it "should use the indirection request to find the model class" do + @irequest.expects(:model).returns @model_class - describe "when finding a model instance" do - before do - @irequest = stub 'indirection_request', :method => :find, :indirection_name => "my_handler", :to_hash => {}, :key => "my_result", :model => @model_class + @handler.do_find(@irequest, @request, @response) + end - @model_class.stubs(:find).returns @result + it "should use the escaped request key" do + @model_class.expects(:find).with do |key, args| + key == "my_result" + end.returns @result + @handler.do_find(@irequest, @request, @response) + end - @format = stub 'format', :suitable? => true, :mime => "text/format", :name => "format" - Puppet::Network::FormatHandler.stubs(:format).returns @format + it "should use a common method for determining the request parameters" do + @irequest.stubs(:to_hash).returns(:foo => :baz, :bar => :xyzzy) + @model_class.expects(:find).with do |key, args| + args[:foo] == :baz and args[:bar] == :xyzzy + end.returns @result + @handler.do_find(@irequest, @request, @response) + end - @oneformat = stub 'one', :suitable? => true, :mime => "text/one", :name => "one" - Puppet::Network::FormatHandler.stubs(:format).with("one").returns @oneformat - end + it "should set the content type to the first format specified in the accept header" do + @handler.expects(:accept_header).with(@request).returns "one,two" + @handler.expects(:set_content_type).with(@response, @oneformat) + @handler.do_find(@irequest, @request, @response) + end - it "should use the indirection request to find the model class" do - @irequest.expects(:model).returns @model_class + it "should fail if no accept header is provided" do + @handler.expects(:accept_header).with(@request).returns nil + lambda { @handler.do_find(@irequest, @request, @response) }.should raise_error(ArgumentError) + end - @handler.do_find(@irequest, @request, @response) - 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(@irequest, @request, @response) }.should raise_error(RuntimeError) + end - it "should use the escaped request key" do - @model_class.expects(:find).with do |key, args| - key == "my_result" - end.returns @result - @handler.do_find(@irequest, @request, @response) - 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 - it "should use a common method for determining the request parameters" do - @irequest.stubs(:to_hash).returns(:foo => :baz, :bar => :xyzzy) - @model_class.expects(:find).with do |key, args| - args[:foo] == :baz and args[:bar] == :xyzzy - end.returns @result - @handler.do_find(@irequest, @request, @response) - end + @handler.expects(:set_content_type).with(@response, bar) # the suitable one - it "should set the content type to the first format specified in the accept header" do - @handler.expects(:accept_header).with(@request).returns "one,two" - @handler.expects(:set_content_type).with(@response, @oneformat) - @handler.do_find(@irequest, @request, @response) - end + @handler.do_find(@irequest, @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(@irequest, @request, @response) }.should raise_error(ArgumentError) - end + it "should render the result using the first format specified in the accept header" do - 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(@irequest, @request, @response) }.should raise_error(RuntimeError) - end + @handler.expects(:accept_header).with(@request).returns "one,two" + @result.expects(:render).with(@oneformat) - 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.do_find(@irequest, @request, @response) + end - @handler.expects(:set_content_type).with(@response, bar) # the suitable one + it "should use the default status when a model find call succeeds" do + @handler.expects(:set_response).with { |response, body, status| status.nil? } + @handler.do_find(@irequest, @request, @response) + end - @handler.do_find(@irequest, @request, @response) - end + it "should return a serialized object when a model find call succeeds" do + @model_instance = stub('model instance') + @model_instance.expects(:render).returns "my_rendered_object" - it "should render the result using the first format specified in the accept header" do + @handler.expects(:set_response).with { |response, body, status| body == "my_rendered_object" } + @model_class.stubs(:find).returns(@model_instance) + @handler.do_find(@irequest, @request, @response) + end - @handler.expects(:accept_header).with(@request).returns "one,two" - @result.expects(:render).with(@oneformat) + it "should return a 404 when no model instance can be found" do + @model_class.stubs(:name).returns "my name" + @handler.expects(:set_response).with { |response, body, status| status == 404 } + @model_class.stubs(:find).returns(nil) + @handler.do_find(@irequest, @request, @response) + end - @handler.do_find(@irequest, @request, @response) - end + it "should write a log message when no model instance can be found" do + @model_class.stubs(:name).returns "my name" + @model_class.stubs(:find).returns(nil) - it "should use the default status when a model find call succeeds" do - @handler.expects(:set_response).with { |response, body, status| status.nil? } - @handler.do_find(@irequest, @request, @response) - end + Puppet.expects(:info).with("Could not find my_handler for 'my_result'") - it "should return a serialized object when a model find call succeeds" do - @model_instance = stub('model instance') - @model_instance.expects(:render).returns "my_rendered_object" + @handler.do_find(@irequest, @request, @response) + end - @handler.expects(:set_response).with { |response, body, status| body == "my_rendered_object" } - @model_class.stubs(:find).returns(@model_instance) - @handler.do_find(@irequest, @request, @response) - end - it "should return a 404 when no model instance can be found" do - @model_class.stubs(:name).returns "my name" - @handler.expects(:set_response).with { |response, body, status| status == 404 } - @model_class.stubs(:find).returns(nil) - @handler.do_find(@irequest, @request, @response) - end + it "should serialize the result in with the appropriate format" do + @model_instance = stub('model instance') + + @handler.expects(:format_to_use).returns(@oneformat) + @model_instance.expects(:render).with(@oneformat).returns "my_rendered_object" + @model_class.stubs(:find).returns(@model_instance) + @handler.do_find(@irequest, @request, @response) + end + end - it "should write a log message when no model instance can be found" do - @model_class.stubs(:name).returns "my name" - @model_class.stubs(:find).returns(nil) + describe "when searching for model instances" do + before do + @irequest = stub 'indirection_request', :method => :find, :indirection_name => "my_handler", :to_hash => {}, :key => "key", :model => @model_class - Puppet.expects(:info).with("Could not find my_handler for 'my_result'") + @result1 = mock 'result1' + @result2 = mock 'results' - @handler.do_find(@irequest, @request, @response) - end + @result = [@result1, @result2] + @model_class.stubs(:render_multiple).returns "my rendered instances" + @model_class.stubs(:search).returns(@result) + @format = stub 'format', :suitable? => true, :mime => "text/format", :name => "format" + Puppet::Network::FormatHandler.stubs(:format).returns @format - it "should serialize the result in with the appropriate format" do - @model_instance = stub('model instance') - - @handler.expects(:format_to_use).returns(@oneformat) - @model_instance.expects(:render).with(@oneformat).returns "my_rendered_object" - @model_class.stubs(:find).returns(@model_instance) - @handler.do_find(@irequest, @request, @response) - end - end + @oneformat = stub 'one', :suitable? => true, :mime => "text/one", :name => "one" + Puppet::Network::FormatHandler.stubs(:format).with("one").returns @oneformat + end - describe "when searching for model instances" do - before do - @irequest = stub 'indirection_request', :method => :find, :indirection_name => "my_handler", :to_hash => {}, :key => "key", :model => @model_class + it "should use the indirection request to find the model" do + @irequest.expects(:model).returns @model_class - @result1 = mock 'result1' - @result2 = mock 'results' + @handler.do_search(@irequest, @request, @response) + end - @result = [@result1, @result2] - @model_class.stubs(:render_multiple).returns "my rendered instances" - @model_class.stubs(:search).returns(@result) + it "should use a common method for determining the request parameters" do + @irequest.stubs(:to_hash).returns(:foo => :baz, :bar => :xyzzy) + @model_class.expects(:search).with do |key, args| + args[:foo] == :baz and args[:bar] == :xyzzy + end.returns @result + @handler.do_search(@irequest, @request, @response) + end - @format = stub 'format', :suitable? => true, :mime => "text/format", :name => "format" - Puppet::Network::FormatHandler.stubs(:format).returns @format + it "should use the default status when a model search call succeeds" do + @model_class.stubs(:search).returns(@result) + @handler.do_search(@irequest, @request, @response) + end - @oneformat = stub 'one', :suitable? => true, :mime => "text/one", :name => "one" - Puppet::Network::FormatHandler.stubs(:format).with("one").returns @oneformat - end + it "should set the content type to the first format returned by the accept header" do + @handler.expects(:accept_header).with(@request).returns "one,two" + @handler.expects(:set_content_type).with(@response, @oneformat) - it "should use the indirection request to find the model" do - @irequest.expects(:model).returns @model_class + @handler.do_search(@irequest, @request, @response) + end - @handler.do_search(@irequest, @request, @response) - end + it "should return a list of serialized objects when a model search call succeeds" do + @handler.expects(:accept_header).with(@request).returns "one,two" - it "should use a common method for determining the request parameters" do - @irequest.stubs(:to_hash).returns(:foo => :baz, :bar => :xyzzy) - @model_class.expects(:search).with do |key, args| - args[:foo] == :baz and args[:bar] == :xyzzy - end.returns @result - @handler.do_search(@irequest, @request, @response) - end + @model_class.stubs(:search).returns(@result) - it "should use the default status when a model search call succeeds" do - @model_class.stubs(:search).returns(@result) - @handler.do_search(@irequest, @request, @response) - end + @model_class.expects(:render_multiple).with(@oneformat, @result).returns "my rendered instances" - it "should set the content type to the first format returned by the accept header" do - @handler.expects(:accept_header).with(@request).returns "one,two" - @handler.expects(:set_content_type).with(@response, @oneformat) + @handler.expects(:set_response).with { |response, data| data == "my rendered instances" } + @handler.do_search(@irequest, @request, @response) + end - @handler.do_search(@irequest, @request, @response) - end + it "should return a 404 when searching returns an empty array" do + @model_class.stubs(:name).returns "my name" + @handler.expects(:set_response).with { |response, body, status| status == 404 } + @model_class.stubs(:search).returns([]) + @handler.do_search(@irequest, @request, @response) + end - it "should return a list of serialized objects when a model search call succeeds" do - @handler.expects(:accept_header).with(@request).returns "one,two" + it "should return a 404 when searching returns nil" do + @model_class.stubs(:name).returns "my name" + @handler.expects(:set_response).with { |response, body, status| status == 404 } + @model_class.stubs(:search).returns([]) + @handler.do_search(@irequest, @request, @response) + end + end - @model_class.stubs(:search).returns(@result) + describe "when destroying a model instance" do + before do + @irequest = stub 'indirection_request', :method => :destroy, :indirection_name => "my_handler", :to_hash => {}, :key => "key", :model => @model_class - @model_class.expects(:render_multiple).with(@oneformat, @result).returns "my rendered instances" + @result = stub 'result', :render => "the result" + @model_class.stubs(:destroy).returns @result + end - @handler.expects(:set_response).with { |response, data| data == "my rendered instances" } - @handler.do_search(@irequest, @request, @response) - end + it "should use the indirection request to find the model" do + @irequest.expects(:model).returns @model_class - it "should return a 404 when searching returns an empty array" do - @model_class.stubs(:name).returns "my name" - @handler.expects(:set_response).with { |response, body, status| status == 404 } - @model_class.stubs(:search).returns([]) - @handler.do_search(@irequest, @request, @response) - end + @handler.do_destroy(@irequest, @request, @response) + end - it "should return a 404 when searching returns nil" do - @model_class.stubs(:name).returns "my name" - @handler.expects(:set_response).with { |response, body, status| status == 404 } - @model_class.stubs(:search).returns([]) - @handler.do_search(@irequest, @request, @response) - end + it "should use the escaped request key to destroy the instance in the model" do + @irequest.expects(:key).returns "foo bar" + @model_class.expects(:destroy).with do |key, args| + key == "foo bar" end + @handler.do_destroy(@irequest, @request, @response) + end - describe "when destroying a model instance" do - before do - @irequest = stub 'indirection_request', :method => :destroy, :indirection_name => "my_handler", :to_hash => {}, :key => "key", :model => @model_class - - @result = stub 'result', :render => "the result" - @model_class.stubs(:destroy).returns @result - end - - it "should use the indirection request to find the model" do - @irequest.expects(:model).returns @model_class - - @handler.do_destroy(@irequest, @request, @response) - end - - it "should use the escaped request key to destroy the instance in the model" do - @irequest.expects(:key).returns "foo bar" - @model_class.expects(:destroy).with do |key, args| - key == "foo bar" - end - @handler.do_destroy(@irequest, @request, @response) - end - - it "should use a common method for determining the request parameters" do - @irequest.stubs(:to_hash).returns(:foo => :baz, :bar => :xyzzy) - @model_class.expects(:destroy).with do |key, args| - args[:foo] == :baz and args[:bar] == :xyzzy - end - @handler.do_destroy(@irequest, @request, @response) - end - - it "should use the default status code a model destroy call succeeds" do - @handler.expects(:set_response).with { |response, body, status| status.nil? } - @handler.do_destroy(@irequest, @request, @response) - end - - it "should return a yaml-encoded result when a model destroy call succeeds" do - @result = stub 'result', :to_yaml => "the result" - @model_class.expects(:destroy).returns(@result) - - @handler.expects(:set_response).with { |response, body, status| body == "the result" } - - @handler.do_destroy(@irequest, @request, @response) - end + it "should use a common method for determining the request parameters" do + @irequest.stubs(:to_hash).returns(:foo => :baz, :bar => :xyzzy) + @model_class.expects(:destroy).with do |key, args| + args[:foo] == :baz and args[:bar] == :xyzzy end + @handler.do_destroy(@irequest, @request, @response) + end - describe "when saving a model instance" do - before do - @irequest = stub 'indirection_request', :method => :save, :indirection_name => "my_handler", :to_hash => {}, :key => "key", :model => @model_class - @handler.stubs(:body).returns('my stuff') - @handler.stubs(:content_type_header).returns("text/yaml") + it "should use the default status code a model destroy call succeeds" do + @handler.expects(:set_response).with { |response, body, status| status.nil? } + @handler.do_destroy(@irequest, @request, @response) + end - @result = stub 'result', :render => "the result" + it "should return a yaml-encoded result when a model destroy call succeeds" do + @result = stub 'result', :to_yaml => "the result" + @model_class.expects(:destroy).returns(@result) - @model_instance = stub('indirected model instance', :save => true) - @model_class.stubs(:convert_from).returns(@model_instance) + @handler.expects(:set_response).with { |response, body, status| body == "the result" } - @format = stub 'format', :suitable? => true, :name => "format", :mime => "text/format" - Puppet::Network::FormatHandler.stubs(:format).returns @format - @yamlformat = stub 'yaml', :suitable? => true, :name => "yaml", :mime => "text/yaml" - Puppet::Network::FormatHandler.stubs(:format).with("yaml").returns @yamlformat - end + @handler.do_destroy(@irequest, @request, @response) + end + end - it "should use the indirection request to find the model" do - @irequest.expects(:model).returns @model_class + describe "when saving a model instance" do + before do + @irequest = stub 'indirection_request', :method => :save, :indirection_name => "my_handler", :to_hash => {}, :key => "key", :model => @model_class + @handler.stubs(:body).returns('my stuff') + @handler.stubs(:content_type_header).returns("text/yaml") - @handler.do_save(@irequest, @request, @response) - end + @result = stub 'result', :render => "the result" - it "should use the 'body' hook to retrieve the body of the request" do - @handler.expects(:body).returns "my body" - @model_class.expects(:convert_from).with { |format, body| body == "my body" }.returns @model_instance + @model_instance = stub('indirected model instance', :save => true) + @model_class.stubs(:convert_from).returns(@model_instance) - @handler.do_save(@irequest, @request, @response) - end + @format = stub 'format', :suitable? => true, :name => "format", :mime => "text/format" + Puppet::Network::FormatHandler.stubs(:format).returns @format + @yamlformat = stub 'yaml', :suitable? => true, :name => "yaml", :mime => "text/yaml" + Puppet::Network::FormatHandler.stubs(:format).with("yaml").returns @yamlformat + end - it "should fail to save model if data is not specified" do - @handler.stubs(:body).returns('') + it "should use the indirection request to find the model" do + @irequest.expects(:model).returns @model_class - lambda { @handler.do_save(@irequest, @request, @response) }.should raise_error(ArgumentError) - end + @handler.do_save(@irequest, @request, @response) + end - it "should use a common method for determining the request parameters" do - @model_instance.expects(:save).with('key').once - @handler.do_save(@irequest, @request, @response) - end + it "should use the 'body' hook to retrieve the body of the request" do + @handler.expects(:body).returns "my body" + @model_class.expects(:convert_from).with { |format, body| body == "my body" }.returns @model_instance - it "should use the default status when a model save call succeeds" do - @handler.expects(:set_response).with { |response, body, status| status.nil? } - @handler.do_save(@irequest, @request, @response) - end + @handler.do_save(@irequest, @request, @response) + end - it "should return the yaml-serialized result when a model save call succeeds" do - @model_instance.stubs(:save).returns(@model_instance) - @model_instance.expects(:to_yaml).returns('foo') - @handler.do_save(@irequest, @request, @response) - end + it "should fail to save model if data is not specified" do + @handler.stubs(:body).returns('') - it "should set the content to yaml" do - @handler.expects(:set_content_type).with(@response, @yamlformat) - @handler.do_save(@irequest, @request, @response) - end + lambda { @handler.do_save(@irequest, @request, @response) }.should raise_error(ArgumentError) + end - it "should use the content-type header to know the body format" do - @handler.expects(:content_type_header).returns("text/format") - Puppet::Network::FormatHandler.stubs(:mime).with("text/format").returns @format + it "should use a common method for determining the request parameters" do + @model_instance.expects(:save).with('key').once + @handler.do_save(@irequest, @request, @response) + end - @model_class.expects(:convert_from).with { |format, body| format == "format" }.returns @model_instance + it "should use the default status when a model save call succeeds" do + @handler.expects(:set_response).with { |response, body, status| status.nil? } + @handler.do_save(@irequest, @request, @response) + end - @handler.do_save(@irequest, @request, @response) - end - end + it "should return the yaml-serialized result when a model save call succeeds" do + @model_instance.stubs(:save).returns(@model_instance) + @model_instance.expects(:to_yaml).returns('foo') + @handler.do_save(@irequest, @request, @response) + end + + it "should set the content to yaml" do + @handler.expects(:set_content_type).with(@response, @yamlformat) + @handler.do_save(@irequest, @request, @response) + end + + it "should use the content-type header to know the body format" do + @handler.expects(:content_type_header).returns("text/format") + Puppet::Network::FormatHandler.stubs(:mime).with("text/format").returns @format + + @model_class.expects(:convert_from).with { |format, body| format == "format" }.returns @model_instance + + @handler.do_save(@irequest, @request, @response) + end end + end - describe "when resolving node" do - it "should use a look-up from the ip address" do - Resolv.expects(:getname).with("1.2.3.4").returns("host.domain.com") + describe "when resolving node" do + it "should use a look-up from the ip address" do + Resolv.expects(:getname).with("1.2.3.4").returns("host.domain.com") - @handler.resolve_node(:ip => "1.2.3.4") - end + @handler.resolve_node(:ip => "1.2.3.4") + end - it "should return the look-up result" do - Resolv.stubs(:getname).with("1.2.3.4").returns("host.domain.com") + it "should return the look-up result" do + Resolv.stubs(:getname).with("1.2.3.4").returns("host.domain.com") - @handler.resolve_node(:ip => "1.2.3.4").should == "host.domain.com" - end + @handler.resolve_node(:ip => "1.2.3.4").should == "host.domain.com" + end - it "should return the ip address if resolving fails" do - Resolv.stubs(:getname).with("1.2.3.4").raises(RuntimeError, "no such host") + it "should return the ip address if resolving fails" do + Resolv.stubs(:getname).with("1.2.3.4").raises(RuntimeError, "no such host") - @handler.resolve_node(:ip => "1.2.3.4").should == "1.2.3.4" - end + @handler.resolve_node(:ip => "1.2.3.4").should == "1.2.3.4" end + end end diff --git a/spec/unit/network/http/mongrel/rest_spec.rb b/spec/unit/network/http/mongrel/rest_spec.rb index 55b6172d3..92a81a10b 100755 --- a/spec/unit/network/http/mongrel/rest_spec.rb +++ b/spec/unit/network/http/mongrel/rest_spec.rb @@ -5,245 +5,245 @@ require File.dirname(__FILE__) + '/../../../../spec_helper' require 'puppet/network/http' describe "Puppet::Network::HTTP::MongrelREST" do - confine "Mongrel is not available" => Puppet.features.mongrel? - before do - require 'puppet/network/http/mongrel/rest' - end + confine "Mongrel is not available" => Puppet.features.mongrel? + before do + require 'puppet/network/http/mongrel/rest' + end + + it "should include the Puppet::Network::HTTP::Handler module" do + Puppet::Network::HTTP::MongrelREST.ancestors.should be_include(Puppet::Network::HTTP::Handler) + end - it "should include the Puppet::Network::HTTP::Handler module" do - Puppet::Network::HTTP::MongrelREST.ancestors.should be_include(Puppet::Network::HTTP::Handler) + describe "when initializing" do + it "should call the Handler's initialization hook with its provided arguments as the server and handler" do + Puppet::Network::HTTP::MongrelREST.any_instance.expects(:initialize_for_puppet).with(:server => "my", :handler => "arguments") + Puppet::Network::HTTP::MongrelREST.new(:server => "my", :handler => "arguments") end + end - describe "when initializing" do - it "should call the Handler's initialization hook with its provided arguments as the server and handler" do - Puppet::Network::HTTP::MongrelREST.any_instance.expects(:initialize_for_puppet).with(:server => "my", :handler => "arguments") - Puppet::Network::HTTP::MongrelREST.new(:server => "my", :handler => "arguments") - end + describe "when receiving a request" do + before do + @params = {} + @request = stub('mongrel http request', :params => @params) + + @head = stub('response head') + @body = stub('response body', :write => true) + @response = stub('mongrel http response') + @response.stubs(:start).yields(@head, @body) + @model_class = stub('indirected model class') + @mongrel = stub('mongrel http server', :register => true) + Puppet::Indirector::Indirection.stubs(:model).with(:foo).returns(@model_class) + @handler = Puppet::Network::HTTP::MongrelREST.new(:server => @mongrel, :handler => :foo) end - describe "when receiving a request" do - before do - @params = {} - @request = stub('mongrel http request', :params => @params) - - @head = stub('response head') - @body = stub('response body', :write => true) - @response = stub('mongrel http response') - @response.stubs(:start).yields(@head, @body) - @model_class = stub('indirected model class') - @mongrel = stub('mongrel http server', :register => true) - Puppet::Indirector::Indirection.stubs(:model).with(:foo).returns(@model_class) - @handler = Puppet::Network::HTTP::MongrelREST.new(:server => @mongrel, :handler => :foo) + describe "and using the HTTP Handler interface" do + it "should return the HTTP_ACCEPT parameter as the accept header" do + @params.expects(:[]).with("HTTP_ACCEPT").returns "myaccept" + @handler.accept_header(@request).should == "myaccept" + end + + it "should return the Content-Type parameter as the Content-Type header" do + @params.expects(:[]).with("HTTP_CONTENT_TYPE").returns "mycontent" + @handler.content_type_header(@request).should == "mycontent" + end + + it "should use the REQUEST_METHOD as the http method" do + @params.expects(:[]).with(Mongrel::Const::REQUEST_METHOD).returns "mymethod" + @handler.http_method(@request).should == "mymethod" + end + + it "should return the request path as the path" do + @params.expects(:[]).with(Mongrel::Const::REQUEST_PATH).returns "/foo/bar" + @handler.path(@request).should == "/foo/bar" + end + + it "should return the request body as the body" do + @request.expects(:body).returns StringIO.new("mybody") + @handler.body(@request).should == "mybody" + end + + it "should set the response's content-type header when setting the content type" do + @header = mock 'header' + @response.expects(:header).returns @header + @header.expects(:[]=).with('Content-Type', "mytype") + + @handler.set_content_type(@response, "mytype") + end + + it "should set the status and write the body when setting the response for a successful request" do + head = mock 'head' + body = mock 'body' + @response.expects(:start).with(200).yields(head, body) + + body.expects(:write).with("mybody") + + @handler.set_response(@response, "mybody", 200) + end + + describe "when the result is a File" do + it "should use response send_file" do + head = mock 'head' + body = mock 'body' + stat = stub 'stat', :size => 100 + file = stub 'file', :stat => stat, :path => "/tmp/path" + file.stubs(:is_a?).with(File).returns(true) + + @response.expects(:start).with(200).yields(head, body) + @response.expects(:send_status).with(100) + @response.expects(:send_header) + @response.expects(:send_file).with("/tmp/path") + + @handler.set_response(@response, file, 200) end + end - describe "and using the HTTP Handler interface" do - it "should return the HTTP_ACCEPT parameter as the accept header" do - @params.expects(:[]).with("HTTP_ACCEPT").returns "myaccept" - @handler.accept_header(@request).should == "myaccept" - end - - it "should return the Content-Type parameter as the Content-Type header" do - @params.expects(:[]).with("HTTP_CONTENT_TYPE").returns "mycontent" - @handler.content_type_header(@request).should == "mycontent" - end - - it "should use the REQUEST_METHOD as the http method" do - @params.expects(:[]).with(Mongrel::Const::REQUEST_METHOD).returns "mymethod" - @handler.http_method(@request).should == "mymethod" - end - - it "should return the request path as the path" do - @params.expects(:[]).with(Mongrel::Const::REQUEST_PATH).returns "/foo/bar" - @handler.path(@request).should == "/foo/bar" - end - - it "should return the request body as the body" do - @request.expects(:body).returns StringIO.new("mybody") - @handler.body(@request).should == "mybody" - end - - it "should set the response's content-type header when setting the content type" do - @header = mock 'header' - @response.expects(:header).returns @header - @header.expects(:[]=).with('Content-Type', "mytype") - - @handler.set_content_type(@response, "mytype") - end - - it "should set the status and write the body when setting the response for a successful request" do - head = mock 'head' - body = mock 'body' - @response.expects(:start).with(200).yields(head, body) - - body.expects(:write).with("mybody") - - @handler.set_response(@response, "mybody", 200) - end - - describe "when the result is a File" do - it "should use response send_file" do - head = mock 'head' - body = mock 'body' - stat = stub 'stat', :size => 100 - file = stub 'file', :stat => stat, :path => "/tmp/path" - file.stubs(:is_a?).with(File).returns(true) - - @response.expects(:start).with(200).yields(head, body) - @response.expects(:send_status).with(100) - @response.expects(:send_header) - @response.expects(:send_file).with("/tmp/path") - - @handler.set_response(@response, file, 200) - end - end - - it "should set the status and reason and write the body when setting the response for a successful request" do - head = mock 'head' - body = mock 'body' - @response.expects(:start).with(400, false, "mybody").yields(head, body) - - body.expects(:write).with("mybody") - - @handler.set_response(@response, "mybody", 400) - end - end + it "should set the status and reason and write the body when setting the response for a successful request" do + head = mock 'head' + body = mock 'body' + @response.expects(:start).with(400, false, "mybody").yields(head, body) - describe "and determining the request parameters" do - before do - @request.stubs(:params).returns({}) - end - - it "should skip empty parameter values" do - @request.expects(:params).returns('QUERY_STRING' => "&=") - lambda { @handler.params(@request) }.should_not raise_error - end - - it "should include the HTTP request parameters, with the keys as symbols" do - @request.expects(:params).returns('QUERY_STRING' => 'foo=baz&bar=xyzzy') - result = @handler.params(@request) - result[:foo].should == "baz" - result[:bar].should == "xyzzy" - end - - it "should CGI-decode the HTTP parameters" do - encoding = CGI.escape("foo bar") - @request.expects(:params).returns('QUERY_STRING' => "foo=#{encoding}") - result = @handler.params(@request) - result[:foo].should == "foo bar" - end - - it "should convert the string 'true' to the boolean" do - @request.expects(:params).returns('QUERY_STRING' => 'foo=true') - result = @handler.params(@request) - result[:foo].should be_true - end - - it "should convert the string 'false' to the boolean" do - @request.expects(:params).returns('QUERY_STRING' => 'foo=false') - result = @handler.params(@request) - result[:foo].should be_false - end - - it "should convert integer arguments to Integers" do - @request.expects(:params).returns('QUERY_STRING' => 'foo=15') - result = @handler.params(@request) - result[:foo].should == 15 - end - - it "should convert floating point arguments to Floats" do - @request.expects(:params).returns('QUERY_STRING' => 'foo=1.5') - result = @handler.params(@request) - result[:foo].should == 1.5 - end - - it "should YAML-load and URI-decode values that are YAML-encoded" do - escaping = CGI.escape(YAML.dump(%w{one two})) - @request.expects(:params).returns('QUERY_STRING' => "foo=#{escaping}") - result = @handler.params(@request) - result[:foo].should == %w{one two} - end - - it "should not allow the client to set the node via the query string" do - @request.stubs(:params).returns('QUERY_STRING' => "node=foo") - @handler.params(@request)[:node].should be_nil - end - - it "should not allow the client to set the IP address via the query string" do - @request.stubs(:params).returns('QUERY_STRING' => "ip=foo") - @handler.params(@request)[:ip].should be_nil - end - - it "should pass the client's ip address to model find" do - @request.stubs(:params).returns("REMOTE_ADDR" => "ipaddress") - @handler.params(@request)[:ip].should == "ipaddress" - end - - it "should pass the client's provided X-Forwared-For value as the ip" do - @request.stubs(:params).returns("HTTP_X_FORWARDED_FOR" => "ipaddress") - @handler.params(@request)[:ip].should == "ipaddress" - end - - it "should pass the client's provided X-Forwared-For first value as the ip" do - @request.stubs(:params).returns("HTTP_X_FORWARDED_FOR" => "ipproxy1,ipproxy2,ipaddress") - @handler.params(@request)[:ip].should == "ipaddress" - end - - it "should pass the client's provided X-Forwared-For value as the ip instead of the REMOTE_ADDR" do - @request.stubs(:params).returns("REMOTE_ADDR" => "remote_addr") - @request.stubs(:params).returns("HTTP_X_FORWARDED_FOR" => "ipaddress") - @handler.params(@request)[:ip].should == "ipaddress" - end - - it "should use the :ssl_client_header to determine the parameter when looking for the certificate" do - Puppet.settings.stubs(:value).returns "eh" - Puppet.settings.expects(:value).with(:ssl_client_header).returns "myheader" - @request.stubs(:params).returns("myheader" => "/CN=host.domain.com") - @handler.params(@request) - end - - it "should retrieve the hostname by matching the certificate parameter" do - Puppet.settings.stubs(:value).returns "eh" - Puppet.settings.expects(:value).with(:ssl_client_header).returns "myheader" - @request.stubs(:params).returns("myheader" => "/CN=host.domain.com") - @handler.params(@request)[:node].should == "host.domain.com" - end - - it "should use the :ssl_client_header to determine the parameter for checking whether the host certificate is valid" do - Puppet.settings.stubs(:value).with(:ssl_client_header).returns "certheader" - Puppet.settings.expects(:value).with(:ssl_client_verify_header).returns "myheader" - @request.stubs(:params).returns("myheader" => "SUCCESS", "certheader" => "/CN=host.domain.com") - @handler.params(@request) - end - - it "should consider the host authenticated if the validity parameter contains 'SUCCESS'" do - Puppet.settings.stubs(:value).with(:ssl_client_header).returns "certheader" - Puppet.settings.stubs(:value).with(:ssl_client_verify_header).returns "myheader" - @request.stubs(:params).returns("myheader" => "SUCCESS", "certheader" => "/CN=host.domain.com") - @handler.params(@request)[:authenticated].should be_true - end - - it "should consider the host unauthenticated if the validity parameter does not contain 'SUCCESS'" do - Puppet.settings.stubs(:value).with(:ssl_client_header).returns "certheader" - Puppet.settings.stubs(:value).with(:ssl_client_verify_header).returns "myheader" - @request.stubs(:params).returns("myheader" => "whatever", "certheader" => "/CN=host.domain.com") - @handler.params(@request)[:authenticated].should be_false - end - - it "should consider the host unauthenticated if no certificate information is present" do - Puppet.settings.stubs(:value).with(:ssl_client_header).returns "certheader" - Puppet.settings.stubs(:value).with(:ssl_client_verify_header).returns "myheader" - @request.stubs(:params).returns("myheader" => nil, "certheader" => "SUCCESS") - @handler.params(@request)[:authenticated].should be_false - end - - it "should resolve the node name with an ip address look-up if no certificate is present" do - Puppet.settings.stubs(:value).returns "eh" - Puppet.settings.expects(:value).with(:ssl_client_header).returns "myheader" - @request.stubs(:params).returns("myheader" => nil) - @handler.expects(:resolve_node).returns("host.domain.com") - @handler.params(@request)[:node].should == "host.domain.com" - end - end + body.expects(:write).with("mybody") + + @handler.set_response(@response, "mybody", 400) + end + end + + describe "and determining the request parameters" do + before do + @request.stubs(:params).returns({}) + end + + it "should skip empty parameter values" do + @request.expects(:params).returns('QUERY_STRING' => "&=") + lambda { @handler.params(@request) }.should_not raise_error + end + + it "should include the HTTP request parameters, with the keys as symbols" do + @request.expects(:params).returns('QUERY_STRING' => 'foo=baz&bar=xyzzy') + result = @handler.params(@request) + result[:foo].should == "baz" + result[:bar].should == "xyzzy" + end + + it "should CGI-decode the HTTP parameters" do + encoding = CGI.escape("foo bar") + @request.expects(:params).returns('QUERY_STRING' => "foo=#{encoding}") + result = @handler.params(@request) + result[:foo].should == "foo bar" + end + + it "should convert the string 'true' to the boolean" do + @request.expects(:params).returns('QUERY_STRING' => 'foo=true') + result = @handler.params(@request) + result[:foo].should be_true + end + + it "should convert the string 'false' to the boolean" do + @request.expects(:params).returns('QUERY_STRING' => 'foo=false') + result = @handler.params(@request) + result[:foo].should be_false + end + + it "should convert integer arguments to Integers" do + @request.expects(:params).returns('QUERY_STRING' => 'foo=15') + result = @handler.params(@request) + result[:foo].should == 15 + end + + it "should convert floating point arguments to Floats" do + @request.expects(:params).returns('QUERY_STRING' => 'foo=1.5') + result = @handler.params(@request) + result[:foo].should == 1.5 + end + + it "should YAML-load and URI-decode values that are YAML-encoded" do + escaping = CGI.escape(YAML.dump(%w{one two})) + @request.expects(:params).returns('QUERY_STRING' => "foo=#{escaping}") + result = @handler.params(@request) + result[:foo].should == %w{one two} + end + + it "should not allow the client to set the node via the query string" do + @request.stubs(:params).returns('QUERY_STRING' => "node=foo") + @handler.params(@request)[:node].should be_nil + end + + it "should not allow the client to set the IP address via the query string" do + @request.stubs(:params).returns('QUERY_STRING' => "ip=foo") + @handler.params(@request)[:ip].should be_nil + end + + it "should pass the client's ip address to model find" do + @request.stubs(:params).returns("REMOTE_ADDR" => "ipaddress") + @handler.params(@request)[:ip].should == "ipaddress" + end + + it "should pass the client's provided X-Forwared-For value as the ip" do + @request.stubs(:params).returns("HTTP_X_FORWARDED_FOR" => "ipaddress") + @handler.params(@request)[:ip].should == "ipaddress" + end + + it "should pass the client's provided X-Forwared-For first value as the ip" do + @request.stubs(:params).returns("HTTP_X_FORWARDED_FOR" => "ipproxy1,ipproxy2,ipaddress") + @handler.params(@request)[:ip].should == "ipaddress" + end + + it "should pass the client's provided X-Forwared-For value as the ip instead of the REMOTE_ADDR" do + @request.stubs(:params).returns("REMOTE_ADDR" => "remote_addr") + @request.stubs(:params).returns("HTTP_X_FORWARDED_FOR" => "ipaddress") + @handler.params(@request)[:ip].should == "ipaddress" + end + + it "should use the :ssl_client_header to determine the parameter when looking for the certificate" do + Puppet.settings.stubs(:value).returns "eh" + Puppet.settings.expects(:value).with(:ssl_client_header).returns "myheader" + @request.stubs(:params).returns("myheader" => "/CN=host.domain.com") + @handler.params(@request) + end + + it "should retrieve the hostname by matching the certificate parameter" do + Puppet.settings.stubs(:value).returns "eh" + Puppet.settings.expects(:value).with(:ssl_client_header).returns "myheader" + @request.stubs(:params).returns("myheader" => "/CN=host.domain.com") + @handler.params(@request)[:node].should == "host.domain.com" + end + + it "should use the :ssl_client_header to determine the parameter for checking whether the host certificate is valid" do + Puppet.settings.stubs(:value).with(:ssl_client_header).returns "certheader" + Puppet.settings.expects(:value).with(:ssl_client_verify_header).returns "myheader" + @request.stubs(:params).returns("myheader" => "SUCCESS", "certheader" => "/CN=host.domain.com") + @handler.params(@request) + end + + it "should consider the host authenticated if the validity parameter contains 'SUCCESS'" do + Puppet.settings.stubs(:value).with(:ssl_client_header).returns "certheader" + Puppet.settings.stubs(:value).with(:ssl_client_verify_header).returns "myheader" + @request.stubs(:params).returns("myheader" => "SUCCESS", "certheader" => "/CN=host.domain.com") + @handler.params(@request)[:authenticated].should be_true + end + + it "should consider the host unauthenticated if the validity parameter does not contain 'SUCCESS'" do + Puppet.settings.stubs(:value).with(:ssl_client_header).returns "certheader" + Puppet.settings.stubs(:value).with(:ssl_client_verify_header).returns "myheader" + @request.stubs(:params).returns("myheader" => "whatever", "certheader" => "/CN=host.domain.com") + @handler.params(@request)[:authenticated].should be_false + end + + it "should consider the host unauthenticated if no certificate information is present" do + Puppet.settings.stubs(:value).with(:ssl_client_header).returns "certheader" + Puppet.settings.stubs(:value).with(:ssl_client_verify_header).returns "myheader" + @request.stubs(:params).returns("myheader" => nil, "certheader" => "SUCCESS") + @handler.params(@request)[:authenticated].should be_false + end + + it "should resolve the node name with an ip address look-up if no certificate is present" do + Puppet.settings.stubs(:value).returns "eh" + Puppet.settings.expects(:value).with(:ssl_client_header).returns "myheader" + @request.stubs(:params).returns("myheader" => nil) + @handler.expects(:resolve_node).returns("host.domain.com") + @handler.params(@request)[:node].should == "host.domain.com" + end end + end end diff --git a/spec/unit/network/http/mongrel_spec.rb b/spec/unit/network/http/mongrel_spec.rb index c0ca68e43..ac3d72bae 100755 --- a/spec/unit/network/http/mongrel_spec.rb +++ b/spec/unit/network/http/mongrel_spec.rb @@ -7,125 +7,125 @@ require File.dirname(__FILE__) + '/../../../spec_helper' require 'puppet/network/http' describe "Puppet::Network::HTTP::Mongrel", "after initializing" do - confine "Mongrel is not available" => Puppet.features.mongrel? + confine "Mongrel is not available" => Puppet.features.mongrel? - it "should not be listening" do - require 'puppet/network/http/mongrel' + it "should not be listening" do + require 'puppet/network/http/mongrel' - Puppet::Network::HTTP::Mongrel.new.should_not be_listening - end + Puppet::Network::HTTP::Mongrel.new.should_not be_listening + end end describe "Puppet::Network::HTTP::Mongrel", "when turning on listening" do - confine "Mongrel is not available" => Puppet.features.mongrel? - - before do - require 'puppet/network/http/mongrel' - - @server = Puppet::Network::HTTP::Mongrel.new - @mock_mongrel = mock('mongrel') - @mock_mongrel.stubs(:run) - @mock_mongrel.stubs(:register) - Mongrel::HttpServer.stubs(:new).returns(@mock_mongrel) - - @mock_puppet_mongrel = mock('puppet_mongrel') - Puppet::Network::HTTPServer::Mongrel.stubs(:new).returns(@mock_puppet_mongrel) - - @listen_params = { :address => "127.0.0.1", :port => 31337, :protocols => [ :rest, :xmlrpc ], :xmlrpc_handlers => [ :status, :fileserver ] } - end - - it "should fail if already listening" do - @server.listen(@listen_params) - Proc.new { @server.listen(@listen_params) }.should raise_error(RuntimeError) - end - - it "should require at least one protocol" do - Proc.new { @server.listen(@listen_params.delete_if {|k,v| :protocols == k}) }.should raise_error(ArgumentError) - end - - it "should require a listening address to be specified" do - Proc.new { @server.listen(@listen_params.delete_if {|k,v| :address == k})}.should raise_error(ArgumentError) - end - - it "should require a listening port to be specified" do - Proc.new { @server.listen(@listen_params.delete_if {|k,v| :port == k})}.should raise_error(ArgumentError) + confine "Mongrel is not available" => Puppet.features.mongrel? + + before do + require 'puppet/network/http/mongrel' + + @server = Puppet::Network::HTTP::Mongrel.new + @mock_mongrel = mock('mongrel') + @mock_mongrel.stubs(:run) + @mock_mongrel.stubs(:register) + Mongrel::HttpServer.stubs(:new).returns(@mock_mongrel) + + @mock_puppet_mongrel = mock('puppet_mongrel') + Puppet::Network::HTTPServer::Mongrel.stubs(:new).returns(@mock_puppet_mongrel) + + @listen_params = { :address => "127.0.0.1", :port => 31337, :protocols => [ :rest, :xmlrpc ], :xmlrpc_handlers => [ :status, :fileserver ] } + end + + it "should fail if already listening" do + @server.listen(@listen_params) + Proc.new { @server.listen(@listen_params) }.should raise_error(RuntimeError) + end + + it "should require at least one protocol" do + Proc.new { @server.listen(@listen_params.delete_if {|k,v| :protocols == k}) }.should raise_error(ArgumentError) + end + + it "should require a listening address to be specified" do + Proc.new { @server.listen(@listen_params.delete_if {|k,v| :address == k})}.should raise_error(ArgumentError) + end + + it "should require a listening port to be specified" do + Proc.new { @server.listen(@listen_params.delete_if {|k,v| :port == k})}.should raise_error(ArgumentError) + end + + it "should order a mongrel server to start" do + @mock_mongrel.expects(:run) + @server.listen(@listen_params) + end + + it "should tell mongrel to listen on the specified address and port" do + Mongrel::HttpServer.expects(:new).with("127.0.0.1", 31337).returns(@mock_mongrel) + @server.listen(@listen_params) + end + + it "should be listening" do + Mongrel::HttpServer.expects(:new).returns(@mock_mongrel) + @server.listen(@listen_params) + @server.should be_listening + end + + describe "when providing REST services" do + it "should instantiate a handler at / for handling REST calls" do + Puppet::Network::HTTP::MongrelREST.expects(:new).returns "myhandler" + @mock_mongrel.expects(:register).with("/", "myhandler") + + @server.listen(@listen_params) end - it "should order a mongrel server to start" do - @mock_mongrel.expects(:run) - @server.listen(@listen_params) + it "should use a Mongrel + REST class to configure Mongrel when REST services are requested" do + @server.expects(:class_for_protocol).with(:rest).at_least_once.returns(Puppet::Network::HTTP::MongrelREST) + @server.listen(@listen_params) end + end - it "should tell mongrel to listen on the specified address and port" do - Mongrel::HttpServer.expects(:new).with("127.0.0.1", 31337).returns(@mock_mongrel) - @server.listen(@listen_params) + describe "when providing XMLRPC services" do + it "should do nothing if no xmlrpc handlers have been provided" do + Puppet::Network::HTTPServer::Mongrel.expects(:new).never + @server.listen(@listen_params.merge(:xmlrpc_handlers => [])) end - it "should be listening" do - Mongrel::HttpServer.expects(:new).returns(@mock_mongrel) - @server.listen(@listen_params) - @server.should be_listening + it "should create an instance of the existing Mongrel http server with the right handlers" do + Puppet::Network::HTTPServer::Mongrel.expects(:new).with([:status, :master]).returns(@mock_puppet_mongrel) + @server.listen(@listen_params.merge(:xmlrpc_handlers => [:status, :master])) end - describe "when providing REST services" do - it "should instantiate a handler at / for handling REST calls" do - Puppet::Network::HTTP::MongrelREST.expects(:new).returns "myhandler" - @mock_mongrel.expects(:register).with("/", "myhandler") + it "should register the Mongrel server instance at /RPC2" do + @mock_mongrel.expects(:register).with("/RPC2", @mock_puppet_mongrel) - @server.listen(@listen_params) - end - - it "should use a Mongrel + REST class to configure Mongrel when REST services are requested" do - @server.expects(:class_for_protocol).with(:rest).at_least_once.returns(Puppet::Network::HTTP::MongrelREST) - @server.listen(@listen_params) - end - end - - describe "when providing XMLRPC services" do - it "should do nothing if no xmlrpc handlers have been provided" do - Puppet::Network::HTTPServer::Mongrel.expects(:new).never - @server.listen(@listen_params.merge(:xmlrpc_handlers => [])) - end - - it "should create an instance of the existing Mongrel http server with the right handlers" do - Puppet::Network::HTTPServer::Mongrel.expects(:new).with([:status, :master]).returns(@mock_puppet_mongrel) - @server.listen(@listen_params.merge(:xmlrpc_handlers => [:status, :master])) - end - - it "should register the Mongrel server instance at /RPC2" do - @mock_mongrel.expects(:register).with("/RPC2", @mock_puppet_mongrel) - - @server.listen(@listen_params.merge(:xmlrpc_handlers => [:status, :master])) - end + @server.listen(@listen_params.merge(:xmlrpc_handlers => [:status, :master])) end + end end describe "Puppet::Network::HTTP::Mongrel", "when turning off listening" do - confine "Mongrel is not available" => Puppet.features.mongrel? - - before do - @mock_mongrel = mock('mongrel httpserver') - @mock_mongrel.stubs(:run) - @mock_mongrel.stubs(:register) - Mongrel::HttpServer.stubs(:new).returns(@mock_mongrel) - @server = Puppet::Network::HTTP::Mongrel.new - @listen_params = { :address => "127.0.0.1", :port => 31337, :handlers => [ :node, :catalog ], :protocols => [ :rest ] } - end - - it "should fail unless listening" do - Proc.new { @server.unlisten }.should raise_error(RuntimeError) - end - - it "should order mongrel server to stop" do - @server.listen(@listen_params) - @mock_mongrel.expects(:stop) - @server.unlisten - end - - it "should not be listening" do - @server.listen(@listen_params) - @mock_mongrel.stubs(:stop) - @server.unlisten - @server.should_not be_listening - end + confine "Mongrel is not available" => Puppet.features.mongrel? + + before do + @mock_mongrel = mock('mongrel httpserver') + @mock_mongrel.stubs(:run) + @mock_mongrel.stubs(:register) + Mongrel::HttpServer.stubs(:new).returns(@mock_mongrel) + @server = Puppet::Network::HTTP::Mongrel.new + @listen_params = { :address => "127.0.0.1", :port => 31337, :handlers => [ :node, :catalog ], :protocols => [ :rest ] } + end + + it "should fail unless listening" do + Proc.new { @server.unlisten }.should raise_error(RuntimeError) + end + + it "should order mongrel server to stop" do + @server.listen(@listen_params) + @mock_mongrel.expects(:stop) + @server.unlisten + end + + it "should not be listening" do + @server.listen(@listen_params) + @mock_mongrel.stubs(:stop) + @server.unlisten + @server.should_not be_listening + end end diff --git a/spec/unit/network/http/rack/rest_spec.rb b/spec/unit/network/http/rack/rest_spec.rb index fb4917d41..9b3e1e59f 100755 --- a/spec/unit/network/http/rack/rest_spec.rb +++ b/spec/unit/network/http/rack/rest_spec.rb @@ -5,245 +5,245 @@ require 'puppet/network/http/rack' if Puppet.features.rack? require 'puppet/network/http/rack/rest' describe "Puppet::Network::HTTP::RackREST" do - confine "Rack is not available" => Puppet.features.rack? + confine "Rack is not available" => Puppet.features.rack? - it "should include the Puppet::Network::HTTP::Handler module" do - Puppet::Network::HTTP::RackREST.ancestors.should be_include(Puppet::Network::HTTP::Handler) + it "should include the Puppet::Network::HTTP::Handler module" do + Puppet::Network::HTTP::RackREST.ancestors.should be_include(Puppet::Network::HTTP::Handler) + end + + describe "when initializing" do + it "should call the Handler's initialization hook with its provided arguments" do + Puppet::Network::HTTP::RackREST.any_instance.expects(:initialize_for_puppet).with(:server => "my", :handler => "arguments") + Puppet::Network::HTTP::RackREST.new(:server => "my", :handler => "arguments") end + end - describe "when initializing" do - it "should call the Handler's initialization hook with its provided arguments" do - Puppet::Network::HTTP::RackREST.any_instance.expects(:initialize_for_puppet).with(:server => "my", :handler => "arguments") - Puppet::Network::HTTP::RackREST.new(:server => "my", :handler => "arguments") - end + describe "when serving a request" do + before :all do + @model_class = stub('indirected model class') + Puppet::Indirector::Indirection.stubs(:model).with(:foo).returns(@model_class) + @handler = Puppet::Network::HTTP::RackREST.new(:handler => :foo) end - describe "when serving a request" do - before :all do - @model_class = stub('indirected model class') - Puppet::Indirector::Indirection.stubs(:model).with(:foo).returns(@model_class) - @handler = Puppet::Network::HTTP::RackREST.new(:handler => :foo) - end + before :each do + @response = Rack::Response.new + end + + def mk_req(uri, opts = {}) + env = Rack::MockRequest.env_for(uri, opts) + Rack::Request.new(env) + end + + describe "and using the HTTP Handler interface" do + it "should return the HTTP_ACCEPT parameter as the accept header" do + req = mk_req('/', 'HTTP_ACCEPT' => 'myaccept') + @handler.accept_header(req).should == "myaccept" + end + + it "should return the CONTENT_TYPE parameter as the content type header" do + req = mk_req('/', 'CONTENT_TYPE' => 'mycontent') + @handler.content_type_header(req).should == "mycontent" + end + + it "should use the REQUEST_METHOD as the http method" do + req = mk_req('/', :method => 'MYMETHOD') + @handler.http_method(req).should == "MYMETHOD" + end + + it "should return the request path as the path" do + req = mk_req('/foo/bar') + @handler.path(req).should == "/foo/bar" + end + + it "should return the request body as the body" do + req = mk_req('/foo/bar', :input => 'mybody') + @handler.body(req).should == "mybody" + end + + it "should set the response's content-type header when setting the content type" do + @header = mock 'header' + @response.expects(:header).returns @header + @header.expects(:[]=).with('Content-Type', "mytype") + @handler.set_content_type(@response, "mytype") + end + + it "should set the status and write the body when setting the response for a request" do + @response.expects(:status=).with(400) + @response.expects(:write).with("mybody") + + @handler.set_response(@response, "mybody", 400) + end + + describe "when result is a File" do before :each do - @response = Rack::Response.new + stat = stub 'stat', :size => 100 + @file = stub 'file', :stat => stat, :path => "/tmp/path" + @file.stubs(:is_a?).with(File).returns(true) end - def mk_req(uri, opts = {}) - env = Rack::MockRequest.env_for(uri, opts) - Rack::Request.new(env) - end + it "should set the Content-Length header" do + @response.expects(:[]=).with("Content-Length", 100) - describe "and using the HTTP Handler interface" do - it "should return the HTTP_ACCEPT parameter as the accept header" do - req = mk_req('/', 'HTTP_ACCEPT' => 'myaccept') - @handler.accept_header(req).should == "myaccept" - end - - it "should return the CONTENT_TYPE parameter as the content type header" do - req = mk_req('/', 'CONTENT_TYPE' => 'mycontent') - @handler.content_type_header(req).should == "mycontent" - end - - it "should use the REQUEST_METHOD as the http method" do - req = mk_req('/', :method => 'MYMETHOD') - @handler.http_method(req).should == "MYMETHOD" - end - - it "should return the request path as the path" do - req = mk_req('/foo/bar') - @handler.path(req).should == "/foo/bar" - end - - it "should return the request body as the body" do - req = mk_req('/foo/bar', :input => 'mybody') - @handler.body(req).should == "mybody" - end - - it "should set the response's content-type header when setting the content type" do - @header = mock 'header' - @response.expects(:header).returns @header - @header.expects(:[]=).with('Content-Type', "mytype") - - @handler.set_content_type(@response, "mytype") - end - - it "should set the status and write the body when setting the response for a request" do - @response.expects(:status=).with(400) - @response.expects(:write).with("mybody") - - @handler.set_response(@response, "mybody", 400) - end - - describe "when result is a File" do - before :each do - stat = stub 'stat', :size => 100 - @file = stub 'file', :stat => stat, :path => "/tmp/path" - @file.stubs(:is_a?).with(File).returns(true) - end - - it "should set the Content-Length header" do - @response.expects(:[]=).with("Content-Length", 100) - - @handler.set_response(@response, @file, 200) - end - - it "should return a RackFile adapter as body" do - @response.expects(:body=).with { |val| val.is_a?(Puppet::Network::HTTP::RackREST::RackFile) } - - @handler.set_response(@response, @file, 200) - end - end + @handler.set_response(@response, @file, 200) end - describe "and determining the request parameters" do - it "should include the HTTP request parameters, with the keys as symbols" do - req = mk_req('/?foo=baz&bar=xyzzy') - result = @handler.params(req) - result[:foo].should == "baz" - result[:bar].should == "xyzzy" - end - - it "should CGI-decode the HTTP parameters" do - encoding = CGI.escape("foo bar") - req = mk_req("/?foo=#{encoding}") - result = @handler.params(req) - result[:foo].should == "foo bar" - end - - it "should convert the string 'true' to the boolean" do - req = mk_req("/?foo=true") - result = @handler.params(req) - result[:foo].should be_true - end - - it "should convert the string 'false' to the boolean" do - req = mk_req("/?foo=false") - result = @handler.params(req) - result[:foo].should be_false - end - - it "should convert integer arguments to Integers" do - req = mk_req("/?foo=15") - result = @handler.params(req) - result[:foo].should == 15 - end - - it "should convert floating point arguments to Floats" do - req = mk_req("/?foo=1.5") - result = @handler.params(req) - result[:foo].should == 1.5 - end - - it "should YAML-load and CGI-decode values that are YAML-encoded" do - escaping = CGI.escape(YAML.dump(%w{one two})) - req = mk_req("/?foo=#{escaping}") - result = @handler.params(req) - result[:foo].should == %w{one two} - end - - it "should not allow the client to set the node via the query string" do - req = mk_req("/?node=foo") - @handler.params(req)[:node].should be_nil - end - - it "should not allow the client to set the IP address via the query string" do - req = mk_req("/?ip=foo") - @handler.params(req)[:ip].should be_nil - end - - it "should pass the client's ip address to model find" do - req = mk_req("/", 'REMOTE_ADDR' => 'ipaddress') - @handler.params(req)[:ip].should == "ipaddress" - end - - it "should set 'authenticated' to false if no certificate is present" do - req = mk_req('/') - @handler.params(req)[:authenticated].should be_false - end - end + it "should return a RackFile adapter as body" do + @response.expects(:body=).with { |val| val.is_a?(Puppet::Network::HTTP::RackREST::RackFile) } - describe "with pre-validated certificates" do - - it "should use the :ssl_client_header to determine the parameter when looking for the certificate" do - Puppet.settings.stubs(:value).returns "eh" - Puppet.settings.expects(:value).with(:ssl_client_header).returns "myheader" - req = mk_req('/', "myheader" => "/CN=host.domain.com") - @handler.params(req) - end - - it "should retrieve the hostname by matching the certificate parameter" do - Puppet.settings.stubs(:value).returns "eh" - Puppet.settings.expects(:value).with(:ssl_client_header).returns "myheader" - req = mk_req('/', "myheader" => "/CN=host.domain.com") - @handler.params(req)[:node].should == "host.domain.com" - end - - it "should use the :ssl_client_header to determine the parameter for checking whether the host certificate is valid" do - Puppet.settings.stubs(:value).with(:ssl_client_header).returns "certheader" - Puppet.settings.expects(:value).with(:ssl_client_verify_header).returns "myheader" - req = mk_req('/', "myheader" => "SUCCESS", "certheader" => "/CN=host.domain.com") - @handler.params(req) - end - - it "should consider the host authenticated if the validity parameter contains 'SUCCESS'" do - Puppet.settings.stubs(:value).with(:ssl_client_header).returns "certheader" - Puppet.settings.stubs(:value).with(:ssl_client_verify_header).returns "myheader" - req = mk_req('/', "myheader" => "SUCCESS", "certheader" => "/CN=host.domain.com") - @handler.params(req)[:authenticated].should be_true - end - - it "should consider the host unauthenticated if the validity parameter does not contain 'SUCCESS'" do - Puppet.settings.stubs(:value).with(:ssl_client_header).returns "certheader" - Puppet.settings.stubs(:value).with(:ssl_client_verify_header).returns "myheader" - req = mk_req('/', "myheader" => "whatever", "certheader" => "/CN=host.domain.com") - @handler.params(req)[:authenticated].should be_false - end - - it "should consider the host unauthenticated if no certificate information is present" do - Puppet.settings.stubs(:value).with(:ssl_client_header).returns "certheader" - Puppet.settings.stubs(:value).with(:ssl_client_verify_header).returns "myheader" - req = mk_req('/', "myheader" => nil, "certheader" => "/CN=host.domain.com") - @handler.params(req)[:authenticated].should be_false - end - - it "should resolve the node name with an ip address look-up if no certificate is present" do - Puppet.settings.stubs(:value).returns "eh" - Puppet.settings.expects(:value).with(:ssl_client_header).returns "myheader" - req = mk_req('/', "myheader" => nil) - @handler.expects(:resolve_node).returns("host.domain.com") - @handler.params(req)[:node].should == "host.domain.com" - end + @handler.set_response(@response, @file, 200) end + end end -end -describe Puppet::Network::HTTP::RackREST::RackFile do - before(:each) do - stat = stub 'stat', :size => 100 - @file = stub 'file', :stat => stat, :path => "/tmp/path" - @rackfile = Puppet::Network::HTTP::RackREST::RackFile.new(@file) + describe "and determining the request parameters" do + it "should include the HTTP request parameters, with the keys as symbols" do + req = mk_req('/?foo=baz&bar=xyzzy') + result = @handler.params(req) + result[:foo].should == "baz" + result[:bar].should == "xyzzy" + end + + it "should CGI-decode the HTTP parameters" do + encoding = CGI.escape("foo bar") + req = mk_req("/?foo=#{encoding}") + result = @handler.params(req) + result[:foo].should == "foo bar" + end + + it "should convert the string 'true' to the boolean" do + req = mk_req("/?foo=true") + result = @handler.params(req) + result[:foo].should be_true + end + + it "should convert the string 'false' to the boolean" do + req = mk_req("/?foo=false") + result = @handler.params(req) + result[:foo].should be_false + end + + it "should convert integer arguments to Integers" do + req = mk_req("/?foo=15") + result = @handler.params(req) + result[:foo].should == 15 + end + + it "should convert floating point arguments to Floats" do + req = mk_req("/?foo=1.5") + result = @handler.params(req) + result[:foo].should == 1.5 + end + + it "should YAML-load and CGI-decode values that are YAML-encoded" do + escaping = CGI.escape(YAML.dump(%w{one two})) + req = mk_req("/?foo=#{escaping}") + result = @handler.params(req) + result[:foo].should == %w{one two} + end + + it "should not allow the client to set the node via the query string" do + req = mk_req("/?node=foo") + @handler.params(req)[:node].should be_nil + end + + it "should not allow the client to set the IP address via the query string" do + req = mk_req("/?ip=foo") + @handler.params(req)[:ip].should be_nil + end + + it "should pass the client's ip address to model find" do + req = mk_req("/", 'REMOTE_ADDR' => 'ipaddress') + @handler.params(req)[:ip].should == "ipaddress" + end + + it "should set 'authenticated' to false if no certificate is present" do + req = mk_req('/') + @handler.params(req)[:authenticated].should be_false + end end - it "should have an each method" do - @rackfile.should be_respond_to(:each) + describe "with pre-validated certificates" do + + it "should use the :ssl_client_header to determine the parameter when looking for the certificate" do + Puppet.settings.stubs(:value).returns "eh" + Puppet.settings.expects(:value).with(:ssl_client_header).returns "myheader" + req = mk_req('/', "myheader" => "/CN=host.domain.com") + @handler.params(req) + end + + it "should retrieve the hostname by matching the certificate parameter" do + Puppet.settings.stubs(:value).returns "eh" + Puppet.settings.expects(:value).with(:ssl_client_header).returns "myheader" + req = mk_req('/', "myheader" => "/CN=host.domain.com") + @handler.params(req)[:node].should == "host.domain.com" + end + + it "should use the :ssl_client_header to determine the parameter for checking whether the host certificate is valid" do + Puppet.settings.stubs(:value).with(:ssl_client_header).returns "certheader" + Puppet.settings.expects(:value).with(:ssl_client_verify_header).returns "myheader" + req = mk_req('/', "myheader" => "SUCCESS", "certheader" => "/CN=host.domain.com") + @handler.params(req) + end + + it "should consider the host authenticated if the validity parameter contains 'SUCCESS'" do + Puppet.settings.stubs(:value).with(:ssl_client_header).returns "certheader" + Puppet.settings.stubs(:value).with(:ssl_client_verify_header).returns "myheader" + req = mk_req('/', "myheader" => "SUCCESS", "certheader" => "/CN=host.domain.com") + @handler.params(req)[:authenticated].should be_true + end + + it "should consider the host unauthenticated if the validity parameter does not contain 'SUCCESS'" do + Puppet.settings.stubs(:value).with(:ssl_client_header).returns "certheader" + Puppet.settings.stubs(:value).with(:ssl_client_verify_header).returns "myheader" + req = mk_req('/', "myheader" => "whatever", "certheader" => "/CN=host.domain.com") + @handler.params(req)[:authenticated].should be_false + end + + it "should consider the host unauthenticated if no certificate information is present" do + Puppet.settings.stubs(:value).with(:ssl_client_header).returns "certheader" + Puppet.settings.stubs(:value).with(:ssl_client_verify_header).returns "myheader" + req = mk_req('/', "myheader" => nil, "certheader" => "/CN=host.domain.com") + @handler.params(req)[:authenticated].should be_false + end + + it "should resolve the node name with an ip address look-up if no certificate is present" do + Puppet.settings.stubs(:value).returns "eh" + Puppet.settings.expects(:value).with(:ssl_client_header).returns "myheader" + req = mk_req('/', "myheader" => nil) + @handler.expects(:resolve_node).returns("host.domain.com") + @handler.params(req)[:node].should == "host.domain.com" + end end + end +end - it "should yield file chunks by chunks" do - @file.expects(:read).times(3).with(8192).returns("1", "2", nil) - i = 1 - @rackfile.each do |chunk| - chunk.to_i.should == i - i += 1 - end +describe Puppet::Network::HTTP::RackREST::RackFile do + before(:each) do + stat = stub 'stat', :size => 100 + @file = stub 'file', :stat => stat, :path => "/tmp/path" + @rackfile = Puppet::Network::HTTP::RackREST::RackFile.new(@file) + end + + it "should have an each method" do + @rackfile.should be_respond_to(:each) + end + + it "should yield file chunks by chunks" do + @file.expects(:read).times(3).with(8192).returns("1", "2", nil) + i = 1 + @rackfile.each do |chunk| + chunk.to_i.should == i + i += 1 end + end - it "should have a close method" do - @rackfile.should be_respond_to(:close) - end + it "should have a close method" do + @rackfile.should be_respond_to(:close) + end - it "should delegate close to File close" do - @file.expects(:close) - @rackfile.close - end + it "should delegate close to File close" do + @file.expects(:close) + @rackfile.close + end end
\ No newline at end of file diff --git a/spec/unit/network/http/rack/xmlrpc_spec.rb b/spec/unit/network/http/rack/xmlrpc_spec.rb index f91f48390..63ba28bf2 100755 --- a/spec/unit/network/http/rack/xmlrpc_spec.rb +++ b/spec/unit/network/http/rack/xmlrpc_spec.rb @@ -5,153 +5,153 @@ require 'puppet/network/http/rack' if Puppet.features.rack? require 'puppet/network/http/rack/xmlrpc' if Puppet.features.rack? describe "Puppet::Network::HTTP::RackXMLRPC" do - confine "Rack is not available" => Puppet.features.rack? - - describe "when initializing" do - it "should create an Puppet::Network::XMLRPCServer" do - Puppet::Network::XMLRPCServer.expects(:new).returns stub_everything - Puppet::Network::HTTP::RackXMLRPC.new([]) - end - - it "should create each handler" do - handler = stub_everything 'handler' - Puppet::Network::XMLRPCServer.any_instance.stubs(:add_handler) - Puppet::Network::Handler.expects(:handler).returns(handler).times(2) - Puppet::Network::HTTP::RackXMLRPC.new([:foo, :bar]) - end - - it "should add each handler to the XMLRPCserver" do - handler = stub_everything 'handler' - Puppet::Network::Handler.stubs(:handler).returns(handler) - Puppet::Network::XMLRPCServer.any_instance.expects(:add_handler).times(2) - Puppet::Network::HTTP::RackXMLRPC.new([:foo, :bar]) - end + confine "Rack is not available" => Puppet.features.rack? + + describe "when initializing" do + it "should create an Puppet::Network::XMLRPCServer" do + Puppet::Network::XMLRPCServer.expects(:new).returns stub_everything + Puppet::Network::HTTP::RackXMLRPC.new([]) + end + + it "should create each handler" do + handler = stub_everything 'handler' + Puppet::Network::XMLRPCServer.any_instance.stubs(:add_handler) + Puppet::Network::Handler.expects(:handler).returns(handler).times(2) + Puppet::Network::HTTP::RackXMLRPC.new([:foo, :bar]) + end + + it "should add each handler to the XMLRPCserver" do + handler = stub_everything 'handler' + Puppet::Network::Handler.stubs(:handler).returns(handler) + Puppet::Network::XMLRPCServer.any_instance.expects(:add_handler).times(2) + Puppet::Network::HTTP::RackXMLRPC.new([:foo, :bar]) + end + end + + describe "when serving a request" do + + before :each do + foo_handler = stub_everything 'foo_handler' + Puppet::Network::Handler.stubs(:handler).with(:foo).returns foo_handler + Puppet::Network::XMLRPCServer.any_instance.stubs(:add_handler) + Puppet::Network::XMLRPCServer.any_instance.stubs(:process).returns('<xml/>') + @handler = Puppet::Network::HTTP::RackXMLRPC.new([:foo]) + end + + before :each do + @response = Rack::Response.new + end + + def mk_req(opts = {}) + opts[:method] = 'POST' if !opts[:method] + opts['CONTENT_TYPE'] = 'text/xml; foo=bar' if !opts['CONTENT_TYPE'] + env = Rack::MockRequest.env_for('/RPC2', opts) + Rack::Request.new(env) + end + + it "should reject non-POST requests" do + req = mk_req :method => 'PUT' + @handler.process(req, @response) + @response.status.should == 405 + end + + it "should reject non text/xml requests" do + req = mk_req 'CONTENT_TYPE' => 'yadda/plain' + end + + it "should create a ClientRequest" do + cr = Puppet::Network::ClientRequest.new(nil, '127.0.0.1', false) + Puppet::Network::ClientRequest.expects(:new).returns cr + req = mk_req + @handler.process(req, @response) + end + + it "should let xmlrpcserver process the request" do + Puppet::Network::XMLRPCServer.any_instance.expects(:process).returns('yay') + req = mk_req + @handler.process(req, @response) + end + + it "should report the response as OK" do + req = mk_req + @handler.process(req, @response) + @response.status.should == 200 + end + + it "should report the response with the correct content type" do + req = mk_req + @handler.process(req, @response) + @response['Content-Type'].should == 'text/xml; charset=utf-8' + end + + it "should set 'authenticated' to false if no certificate is present" do + req = mk_req + Puppet::Network::ClientRequest.expects(:new).with { |node,ip,authenticated| authenticated == false } + @handler.process(req, @response) + end + + it "should use the client's ip address" do + req = mk_req 'REMOTE_ADDR' => 'ipaddress' + Puppet::Network::ClientRequest.expects(:new).with { |node,ip,authenticated| ip == 'ipaddress' } + @handler.process(req, @response) end - describe "when serving a request" do - - before :each do - foo_handler = stub_everything 'foo_handler' - Puppet::Network::Handler.stubs(:handler).with(:foo).returns foo_handler - Puppet::Network::XMLRPCServer.any_instance.stubs(:add_handler) - Puppet::Network::XMLRPCServer.any_instance.stubs(:process).returns('<xml/>') - @handler = Puppet::Network::HTTP::RackXMLRPC.new([:foo]) - end - - before :each do - @response = Rack::Response.new - end - - def mk_req(opts = {}) - opts[:method] = 'POST' if !opts[:method] - opts['CONTENT_TYPE'] = 'text/xml; foo=bar' if !opts['CONTENT_TYPE'] - env = Rack::MockRequest.env_for('/RPC2', opts) - Rack::Request.new(env) - end - - it "should reject non-POST requests" do - req = mk_req :method => 'PUT' - @handler.process(req, @response) - @response.status.should == 405 - end - - it "should reject non text/xml requests" do - req = mk_req 'CONTENT_TYPE' => 'yadda/plain' - end - - it "should create a ClientRequest" do - cr = Puppet::Network::ClientRequest.new(nil, '127.0.0.1', false) - Puppet::Network::ClientRequest.expects(:new).returns cr - req = mk_req - @handler.process(req, @response) - end - - it "should let xmlrpcserver process the request" do - Puppet::Network::XMLRPCServer.any_instance.expects(:process).returns('yay') - req = mk_req - @handler.process(req, @response) - end - - it "should report the response as OK" do - req = mk_req - @handler.process(req, @response) - @response.status.should == 200 - end - - it "should report the response with the correct content type" do - req = mk_req - @handler.process(req, @response) - @response['Content-Type'].should == 'text/xml; charset=utf-8' - end - - it "should set 'authenticated' to false if no certificate is present" do - req = mk_req - Puppet::Network::ClientRequest.expects(:new).with { |node,ip,authenticated| authenticated == false } - @handler.process(req, @response) - end - - it "should use the client's ip address" do - req = mk_req 'REMOTE_ADDR' => 'ipaddress' - Puppet::Network::ClientRequest.expects(:new).with { |node,ip,authenticated| ip == 'ipaddress' } - @handler.process(req, @response) - end - - describe "with pre-validated certificates" do - - it "should use the :ssl_client_header to determine the parameter when looking for the certificate" do - Puppet.settings.stubs(:value).returns "eh" - Puppet.settings.expects(:value).with(:ssl_client_header).returns "myheader" - req = mk_req "myheader" => "/CN=host.domain.com" - @handler.process(req, @response) - end - - it "should retrieve the hostname by matching the certificate parameter" do - Puppet.settings.stubs(:value).returns "eh" - Puppet.settings.expects(:value).with(:ssl_client_header).returns "myheader" - Puppet::Network::ClientRequest.expects(:new).with { |node,ip,authenticated| node == "host.domain.com" } - req = mk_req "myheader" => "/CN=host.domain.com" - @handler.process(req, @response) - end - - it "should use the :ssl_client_header to determine the parameter for checking whether the host certificate is valid" do - Puppet.settings.stubs(:value).with(:ssl_client_header).returns "certheader" - Puppet.settings.expects(:value).with(:ssl_client_verify_header).returns "myheader" - req = mk_req "myheader" => "SUCCESS", "certheader" => "/CN=host.domain.com" - @handler.process(req, @response) - end - - it "should consider the host authenticated if the validity parameter contains 'SUCCESS'" do - Puppet.settings.stubs(:value).with(:ssl_client_header).returns "certheader" - Puppet.settings.stubs(:value).with(:ssl_client_verify_header).returns "myheader" - Puppet::Network::ClientRequest.expects(:new).with { |node,ip,authenticated| authenticated == true } - req = mk_req "myheader" => "SUCCESS", "certheader" => "/CN=host.domain.com" - @handler.process(req, @response) - end - - it "should consider the host unauthenticated if the validity parameter does not contain 'SUCCESS'" do - Puppet.settings.stubs(:value).with(:ssl_client_header).returns "certheader" - Puppet.settings.stubs(:value).with(:ssl_client_verify_header).returns "myheader" - Puppet::Network::ClientRequest.expects(:new).with { |node,ip,authenticated| authenticated == false } - req = mk_req "myheader" => "whatever", "certheader" => "/CN=host.domain.com" - @handler.process(req, @response) - end - - it "should consider the host unauthenticated if no certificate information is present" do - Puppet.settings.stubs(:value).with(:ssl_client_header).returns "certheader" - Puppet.settings.stubs(:value).with(:ssl_client_verify_header).returns "myheader" - Puppet::Network::ClientRequest.expects(:new).with { |node,ip,authenticated| authenticated == false } - req = mk_req "myheader" => nil, "certheader" => "/CN=host.domain.com" - @handler.process(req, @response) - end - - it "should resolve the node name with an ip address look-up if no certificate is present" do - Puppet.settings.stubs(:value).returns "eh" - Puppet.settings.expects(:value).with(:ssl_client_header).returns "myheader" - Resolv.any_instance.expects(:getname).returns("host.domain.com") - Puppet::Network::ClientRequest.expects(:new).with { |node,ip,authenticated| node == "host.domain.com" } - req = mk_req "myheader" => nil - @handler.process(req, @response) - end - end + describe "with pre-validated certificates" do + + it "should use the :ssl_client_header to determine the parameter when looking for the certificate" do + Puppet.settings.stubs(:value).returns "eh" + Puppet.settings.expects(:value).with(:ssl_client_header).returns "myheader" + req = mk_req "myheader" => "/CN=host.domain.com" + @handler.process(req, @response) + end + + it "should retrieve the hostname by matching the certificate parameter" do + Puppet.settings.stubs(:value).returns "eh" + Puppet.settings.expects(:value).with(:ssl_client_header).returns "myheader" + Puppet::Network::ClientRequest.expects(:new).with { |node,ip,authenticated| node == "host.domain.com" } + req = mk_req "myheader" => "/CN=host.domain.com" + @handler.process(req, @response) + end + + it "should use the :ssl_client_header to determine the parameter for checking whether the host certificate is valid" do + Puppet.settings.stubs(:value).with(:ssl_client_header).returns "certheader" + Puppet.settings.expects(:value).with(:ssl_client_verify_header).returns "myheader" + req = mk_req "myheader" => "SUCCESS", "certheader" => "/CN=host.domain.com" + @handler.process(req, @response) + end + + it "should consider the host authenticated if the validity parameter contains 'SUCCESS'" do + Puppet.settings.stubs(:value).with(:ssl_client_header).returns "certheader" + Puppet.settings.stubs(:value).with(:ssl_client_verify_header).returns "myheader" + Puppet::Network::ClientRequest.expects(:new).with { |node,ip,authenticated| authenticated == true } + req = mk_req "myheader" => "SUCCESS", "certheader" => "/CN=host.domain.com" + @handler.process(req, @response) + end + + it "should consider the host unauthenticated if the validity parameter does not contain 'SUCCESS'" do + Puppet.settings.stubs(:value).with(:ssl_client_header).returns "certheader" + Puppet.settings.stubs(:value).with(:ssl_client_verify_header).returns "myheader" + Puppet::Network::ClientRequest.expects(:new).with { |node,ip,authenticated| authenticated == false } + req = mk_req "myheader" => "whatever", "certheader" => "/CN=host.domain.com" + @handler.process(req, @response) + end + + it "should consider the host unauthenticated if no certificate information is present" do + Puppet.settings.stubs(:value).with(:ssl_client_header).returns "certheader" + Puppet.settings.stubs(:value).with(:ssl_client_verify_header).returns "myheader" + Puppet::Network::ClientRequest.expects(:new).with { |node,ip,authenticated| authenticated == false } + req = mk_req "myheader" => nil, "certheader" => "/CN=host.domain.com" + @handler.process(req, @response) + end + + it "should resolve the node name with an ip address look-up if no certificate is present" do + Puppet.settings.stubs(:value).returns "eh" + Puppet.settings.expects(:value).with(:ssl_client_header).returns "myheader" + Resolv.any_instance.expects(:getname).returns("host.domain.com") + Puppet::Network::ClientRequest.expects(:new).with { |node,ip,authenticated| node == "host.domain.com" } + req = mk_req "myheader" => nil + @handler.process(req, @response) + end end + end end diff --git a/spec/unit/network/http/rack_spec.rb b/spec/unit/network/http/rack_spec.rb index cd2961a3a..df42a1ffa 100755 --- a/spec/unit/network/http/rack_spec.rb +++ b/spec/unit/network/http/rack_spec.rb @@ -4,99 +4,99 @@ require File.dirname(__FILE__) + '/../../../spec_helper' require 'puppet/network/http/rack' if Puppet.features.rack? describe "Puppet::Network::HTTP::Rack" do - confine "Rack is not available" => Puppet.features.rack? + confine "Rack is not available" => Puppet.features.rack? - describe "while initializing" do + describe "while initializing" do - it "should require a protocol specification" do - Proc.new { Puppet::Network::HTTP::Rack.new({}) }.should raise_error(ArgumentError) - end - - it "should not accept imaginary protocols" do - Proc.new { Puppet::Network::HTTP::Rack.new({:protocols => [:foo]}) }.should raise_error(ArgumentError) - end + it "should require a protocol specification" do + Proc.new { Puppet::Network::HTTP::Rack.new({}) }.should raise_error(ArgumentError) + end - it "should accept the REST protocol" do - Proc.new { Puppet::Network::HTTP::Rack.new({:protocols => [:rest]}) }.should_not raise_error(ArgumentError) - end + it "should not accept imaginary protocols" do + Proc.new { Puppet::Network::HTTP::Rack.new({:protocols => [:foo]}) }.should raise_error(ArgumentError) + end - it "should create a RackREST instance" do - Puppet::Network::HTTP::RackREST.expects(:new) - Puppet::Network::HTTP::Rack.new({:protocols => [:rest]}) - end + it "should accept the REST protocol" do + Proc.new { Puppet::Network::HTTP::Rack.new({:protocols => [:rest]}) }.should_not raise_error(ArgumentError) + end - describe "with XMLRPC enabled" do + it "should create a RackREST instance" do + Puppet::Network::HTTP::RackREST.expects(:new) + Puppet::Network::HTTP::Rack.new({:protocols => [:rest]}) + end - it "should require XMLRPC handlers" do - Proc.new { Puppet::Network::HTTP::Rack.new({:protocols => [:xmlrpc]}) }.should raise_error(ArgumentError) - end + describe "with XMLRPC enabled" do - it "should create a RackXMLRPC instance" do - Puppet::Network::HTTP::RackXMLRPC.expects(:new) - Puppet::Network::HTTP::Rack.new({:protocols => [:xmlrpc], :xmlrpc_handlers => [:Status]}) - end + it "should require XMLRPC handlers" do + Proc.new { Puppet::Network::HTTP::Rack.new({:protocols => [:xmlrpc]}) }.should raise_error(ArgumentError) + end - end + it "should create a RackXMLRPC instance" do + Puppet::Network::HTTP::RackXMLRPC.expects(:new) + Puppet::Network::HTTP::Rack.new({:protocols => [:xmlrpc], :xmlrpc_handlers => [:Status]}) + end end - describe "when called" do + end - before :all do - @app = Puppet::Network::HTTP::Rack.new({:protocols => [:rest]}) - # let's use Rack::Lint to verify that we're OK with the rack specification - @linted = Rack::Lint.new(@app) - end + describe "when called" do - before :each do - @env = Rack::MockRequest.env_for('/') - end + before :all do + @app = Puppet::Network::HTTP::Rack.new({:protocols => [:rest]}) + # let's use Rack::Lint to verify that we're OK with the rack specification + @linted = Rack::Lint.new(@app) + end - it "should create a Request object" do - request = Rack::Request.new(@env) - Rack::Request.expects(:new).returns request - @linted.call(@env) - end + before :each do + @env = Rack::MockRequest.env_for('/') + end - it "should create a Response object" do - Rack::Response.expects(:new).returns stub_everything - @app.call(@env) # can't lint when Rack::Response is a stub - end + it "should create a Request object" do + request = Rack::Request.new(@env) + Rack::Request.expects(:new).returns request + @linted.call(@env) + end - it "should let RackREST process the request" do - Puppet::Network::HTTP::RackREST.any_instance.expects(:process).once - @linted.call(@env) - end + it "should create a Response object" do + Rack::Response.expects(:new).returns stub_everything + @app.call(@env) # can't lint when Rack::Response is a stub + end - it "should catch unhandled exceptions from RackREST" do - Puppet::Network::HTTP::RackREST.any_instance.expects(:process).raises(ArgumentError, 'test error') - Proc.new { @linted.call(@env) }.should_not raise_error - end + it "should let RackREST process the request" do + Puppet::Network::HTTP::RackREST.any_instance.expects(:process).once + @linted.call(@env) + end - it "should finish() the Response" do - Rack::Response.any_instance.expects(:finish).once - @app.call(@env) # can't lint when finish is a stub - end + it "should catch unhandled exceptions from RackREST" do + Puppet::Network::HTTP::RackREST.any_instance.expects(:process).raises(ArgumentError, 'test error') + Proc.new { @linted.call(@env) }.should_not raise_error + end + it "should finish() the Response" do + Rack::Response.any_instance.expects(:finish).once + @app.call(@env) # can't lint when finish is a stub end - describe "when serving XMLRPC" do + end - before :all do - @app = Puppet::Network::HTTP::Rack.new({:protocols => [:rest, :xmlrpc], :xmlrpc_handlers => [:Status]}) - @linted = Rack::Lint.new(@app) - end + describe "when serving XMLRPC" do - before :each do - @env = Rack::MockRequest.env_for('/RPC2', :method => 'POST') - end + before :all do + @app = Puppet::Network::HTTP::Rack.new({:protocols => [:rest, :xmlrpc], :xmlrpc_handlers => [:Status]}) + @linted = Rack::Lint.new(@app) + end - it "should use RackXMLRPC to serve /RPC2 requests" do - Puppet::Network::HTTP::RackXMLRPC.any_instance.expects(:process).once - @linted.call(@env) - end + before :each do + @env = Rack::MockRequest.env_for('/RPC2', :method => 'POST') + end + it "should use RackXMLRPC to serve /RPC2 requests" do + Puppet::Network::HTTP::RackXMLRPC.any_instance.expects(:process).once + @linted.call(@env) end + end + end diff --git a/spec/unit/network/http/webrick/rest_spec.rb b/spec/unit/network/http/webrick/rest_spec.rb index f726fd9a7..aa2b93176 100755 --- a/spec/unit/network/http/webrick/rest_spec.rb +++ b/spec/unit/network/http/webrick/rest_spec.rb @@ -5,176 +5,176 @@ require 'puppet/network/http' require 'puppet/network/http/webrick/rest' describe Puppet::Network::HTTP::WEBrickREST do - it "should include the Puppet::Network::HTTP::Handler module" do - Puppet::Network::HTTP::WEBrickREST.ancestors.should be_include(Puppet::Network::HTTP::Handler) + it "should include the Puppet::Network::HTTP::Handler module" do + Puppet::Network::HTTP::WEBrickREST.ancestors.should be_include(Puppet::Network::HTTP::Handler) + end + + describe "when initializing" do + it "should call the Handler's initialization hook with its provided arguments as the server and handler" do + Puppet::Network::HTTP::WEBrickREST.any_instance.expects(:initialize_for_puppet).with(:server => "my", :handler => "arguments") + Puppet::Network::HTTP::WEBrickREST.new("my", "arguments") + end + end + + describe "when receiving a request" do + before do + @request = stub('webrick http request', :query => {}, :peeraddr => %w{eh boo host ip}, :client_cert => nil) + @response = stub('webrick http response', :status= => true, :body= => true) + @model_class = stub('indirected model class') + @webrick = stub('webrick http server', :mount => true, :[] => {}) + Puppet::Indirector::Indirection.stubs(:model).with(:foo).returns(@model_class) + @handler = Puppet::Network::HTTP::WEBrickREST.new(@webrick, :foo) end - describe "when initializing" do - it "should call the Handler's initialization hook with its provided arguments as the server and handler" do - Puppet::Network::HTTP::WEBrickREST.any_instance.expects(:initialize_for_puppet).with(:server => "my", :handler => "arguments") - Puppet::Network::HTTP::WEBrickREST.new("my", "arguments") - end + it "should delegate its :service method to its :process method" do + @handler.expects(:process).with(@request, @response).returns "stuff" + @handler.service(@request, @response).should == "stuff" end - describe "when receiving a request" do - before do - @request = stub('webrick http request', :query => {}, :peeraddr => %w{eh boo host ip}, :client_cert => nil) - @response = stub('webrick http response', :status= => true, :body= => true) - @model_class = stub('indirected model class') - @webrick = stub('webrick http server', :mount => true, :[] => {}) - Puppet::Indirector::Indirection.stubs(:model).with(:foo).returns(@model_class) - @handler = Puppet::Network::HTTP::WEBrickREST.new(@webrick, :foo) + describe "when using the Handler interface" do + it "should use the 'accept' request parameter as the Accept header" do + @request.expects(:[]).with("accept").returns "foobar" + @handler.accept_header(@request).should == "foobar" + end + + it "should use the 'content-type' request header as the Content-Type header" do + @request.expects(:[]).with("content-type").returns "foobar" + @handler.content_type_header(@request).should == "foobar" + end + + it "should use the request method as the http method" do + @request.expects(:request_method).returns "FOO" + @handler.http_method(@request).should == "FOO" + end + + it "should return the request path as the path" do + @request.expects(:path).returns "/foo/bar" + @handler.path(@request).should == "/foo/bar" + end + + it "should return the request body as the body" do + @request.expects(:body).returns "my body" + @handler.body(@request).should == "my body" + end + + it "should set the response's 'content-type' header when setting the content type" do + @response.expects(:[]=).with("content-type", "text/html") + @handler.set_content_type(@response, "text/html") + end + + it "should set the status and body on the response when setting the response for a successful query" do + @response.expects(:status=).with 200 + @response.expects(:body=).with "mybody" + + @handler.set_response(@response, "mybody", 200) + end + + describe "when the result is a File" do + before(:each) do + stat = stub 'stat', :size => 100 + @file = stub 'file', :stat => stat, :path => "/tmp/path" + @file.stubs(:is_a?).with(File).returns(true) end - it "should delegate its :service method to its :process method" do - @handler.expects(:process).with(@request, @response).returns "stuff" - @handler.service(@request, @response).should == "stuff" - end + it "should serve it" do + @response.stubs(:[]=) - describe "when using the Handler interface" do - it "should use the 'accept' request parameter as the Accept header" do - @request.expects(:[]).with("accept").returns "foobar" - @handler.accept_header(@request).should == "foobar" - end - - it "should use the 'content-type' request header as the Content-Type header" do - @request.expects(:[]).with("content-type").returns "foobar" - @handler.content_type_header(@request).should == "foobar" - end - - it "should use the request method as the http method" do - @request.expects(:request_method).returns "FOO" - @handler.http_method(@request).should == "FOO" - end - - it "should return the request path as the path" do - @request.expects(:path).returns "/foo/bar" - @handler.path(@request).should == "/foo/bar" - end - - it "should return the request body as the body" do - @request.expects(:body).returns "my body" - @handler.body(@request).should == "my body" - end - - it "should set the response's 'content-type' header when setting the content type" do - @response.expects(:[]=).with("content-type", "text/html") - @handler.set_content_type(@response, "text/html") - end - - it "should set the status and body on the response when setting the response for a successful query" do - @response.expects(:status=).with 200 - @response.expects(:body=).with "mybody" - - @handler.set_response(@response, "mybody", 200) - end - - describe "when the result is a File" do - before(:each) do - stat = stub 'stat', :size => 100 - @file = stub 'file', :stat => stat, :path => "/tmp/path" - @file.stubs(:is_a?).with(File).returns(true) - end - - it "should serve it" do - @response.stubs(:[]=) - - @response.expects(:status=).with 200 - @response.expects(:body=).with @file - - @handler.set_response(@response, @file, 200) - end - - it "should set the Content-Length header" do - @response.expects(:[]=).with('content-length', 100) - - @handler.set_response(@response, @file, 200) - end - end - - it "should set the status and message on the response when setting the response for a failed query" do - @response.expects(:status=).with 400 - @response.expects(:reason_phrase=).with "mybody" - - @handler.set_response(@response, "mybody", 400) - end + @response.expects(:status=).with 200 + @response.expects(:body=).with @file + + @handler.set_response(@response, @file, 200) end - describe "and determining the request parameters" do - it "should include the HTTP request parameters, with the keys as symbols" do - @request.stubs(:query).returns("foo" => "baz", "bar" => "xyzzy") - result = @handler.params(@request) - result[:foo].should == "baz" - result[:bar].should == "xyzzy" - end - - it "should CGI-decode the HTTP parameters" do - encoding = CGI.escape("foo bar") - @request.expects(:query).returns('foo' => encoding) - result = @handler.params(@request) - result[:foo].should == "foo bar" - end - - it "should convert the string 'true' to the boolean" do - @request.expects(:query).returns('foo' => "true") - result = @handler.params(@request) - result[:foo].should be_true - end - - it "should convert the string 'false' to the boolean" do - @request.expects(:query).returns('foo' => "false") - result = @handler.params(@request) - result[:foo].should be_false - end - - it "should YAML-load and CGI-decode values that are YAML-encoded" do - escaping = CGI.escape(YAML.dump(%w{one two})) - @request.expects(:query).returns('foo' => escaping) - result = @handler.params(@request) - result[:foo].should == %w{one two} - end - - it "should not allow clients to set the node via the request parameters" do - @request.stubs(:query).returns("node" => "foo") - @handler.stubs(:resolve_node) - - @handler.params(@request)[:node].should be_nil - end - - it "should not allow clients to set the IP via the request parameters" do - @request.stubs(:query).returns("ip" => "foo") - @handler.params(@request)[:ip].should_not == "foo" - end - - it "should pass the client's ip address to model find" do - @request.stubs(:peeraddr).returns(%w{noidea dunno hostname ipaddress}) - @handler.params(@request)[:ip].should == "ipaddress" - end - - it "should set 'authenticated' to true if a certificate is present" do - cert = stub 'cert', :subject => [%w{CN host.domain.com}] - @request.stubs(:client_cert).returns cert - @handler.params(@request)[:authenticated].should be_true - end - - it "should set 'authenticated' to false if no certificate is present" do - @request.stubs(:client_cert).returns nil - @handler.params(@request)[:authenticated].should be_false - end - - it "should pass the client's certificate name to model method if a certificate is present" do - cert = stub 'cert', :subject => [%w{CN host.domain.com}] - @request.stubs(:client_cert).returns cert - @handler.params(@request)[:node].should == "host.domain.com" - end - - it "should resolve the node name with an ip address look-up if no certificate is present" do - @request.stubs(:client_cert).returns nil - - @handler.expects(:resolve_node).returns(:resolved_node) - - @handler.params(@request)[:node].should == :resolved_node - end + it "should set the Content-Length header" do + @response.expects(:[]=).with('content-length', 100) + + @handler.set_response(@response, @file, 200) end + end + + it "should set the status and message on the response when setting the response for a failed query" do + @response.expects(:status=).with 400 + @response.expects(:reason_phrase=).with "mybody" + + @handler.set_response(@response, "mybody", 400) + end + end + + describe "and determining the request parameters" do + it "should include the HTTP request parameters, with the keys as symbols" do + @request.stubs(:query).returns("foo" => "baz", "bar" => "xyzzy") + result = @handler.params(@request) + result[:foo].should == "baz" + result[:bar].should == "xyzzy" + end + + it "should CGI-decode the HTTP parameters" do + encoding = CGI.escape("foo bar") + @request.expects(:query).returns('foo' => encoding) + result = @handler.params(@request) + result[:foo].should == "foo bar" + end + + it "should convert the string 'true' to the boolean" do + @request.expects(:query).returns('foo' => "true") + result = @handler.params(@request) + result[:foo].should be_true + end + + it "should convert the string 'false' to the boolean" do + @request.expects(:query).returns('foo' => "false") + result = @handler.params(@request) + result[:foo].should be_false + end + + it "should YAML-load and CGI-decode values that are YAML-encoded" do + escaping = CGI.escape(YAML.dump(%w{one two})) + @request.expects(:query).returns('foo' => escaping) + result = @handler.params(@request) + result[:foo].should == %w{one two} + end + + it "should not allow clients to set the node via the request parameters" do + @request.stubs(:query).returns("node" => "foo") + @handler.stubs(:resolve_node) + + @handler.params(@request)[:node].should be_nil + end + + it "should not allow clients to set the IP via the request parameters" do + @request.stubs(:query).returns("ip" => "foo") + @handler.params(@request)[:ip].should_not == "foo" + end + + it "should pass the client's ip address to model find" do + @request.stubs(:peeraddr).returns(%w{noidea dunno hostname ipaddress}) + @handler.params(@request)[:ip].should == "ipaddress" + end + + it "should set 'authenticated' to true if a certificate is present" do + cert = stub 'cert', :subject => [%w{CN host.domain.com}] + @request.stubs(:client_cert).returns cert + @handler.params(@request)[:authenticated].should be_true + end + + it "should set 'authenticated' to false if no certificate is present" do + @request.stubs(:client_cert).returns nil + @handler.params(@request)[:authenticated].should be_false + end + + it "should pass the client's certificate name to model method if a certificate is present" do + cert = stub 'cert', :subject => [%w{CN host.domain.com}] + @request.stubs(:client_cert).returns cert + @handler.params(@request)[:node].should == "host.domain.com" + end + + it "should resolve the node name with an ip address look-up if no certificate is present" do + @request.stubs(:client_cert).returns nil + + @handler.expects(:resolve_node).returns(:resolved_node) + + @handler.params(@request)[:node].should == :resolved_node + end end + end end diff --git a/spec/unit/network/http/webrick_spec.rb b/spec/unit/network/http/webrick_spec.rb index 34abc6909..2a6ef2268 100755 --- a/spec/unit/network/http/webrick_spec.rb +++ b/spec/unit/network/http/webrick_spec.rb @@ -8,332 +8,332 @@ require 'puppet/network/http' require 'puppet/network/http/webrick' describe Puppet::Network::HTTP::WEBrick, "after initializing" do - it "should not be listening" do - Puppet::Network::HTTP::WEBrick.new.should_not be_listening - end + it "should not be listening" do + Puppet::Network::HTTP::WEBrick.new.should_not be_listening + end end describe Puppet::Network::HTTP::WEBrick, "when turning on listening" do - before do - @mock_webrick = stub('webrick', :[] => {}, :listeners => [], :status => :Running) - [:mount, :start, :shutdown].each {|meth| @mock_webrick.stubs(meth)} - WEBrick::HTTPServer.stubs(:new).returns(@mock_webrick) - @server = Puppet::Network::HTTP::WEBrick.new - [:setup_logger, :setup_ssl].each {|meth| @server.stubs(meth).returns({})} # the empty hash is required because of how we're merging - @listen_params = { :address => "127.0.0.1", :port => 31337, :xmlrpc_handlers => [], :protocols => [ :rest ] } + before do + @mock_webrick = stub('webrick', :[] => {}, :listeners => [], :status => :Running) + [:mount, :start, :shutdown].each {|meth| @mock_webrick.stubs(meth)} + WEBrick::HTTPServer.stubs(:new).returns(@mock_webrick) + @server = Puppet::Network::HTTP::WEBrick.new + [:setup_logger, :setup_ssl].each {|meth| @server.stubs(meth).returns({})} # the empty hash is required because of how we're merging + @listen_params = { :address => "127.0.0.1", :port => 31337, :xmlrpc_handlers => [], :protocols => [ :rest ] } + end + + it "should fail if already listening" do + @server.listen(@listen_params) + Proc.new { @server.listen(@listen_params) }.should raise_error(RuntimeError) + end + + it "should require at least one protocol" do + Proc.new { @server.listen(@listen_params.delete_if {|k,v| :protocols == k}) }.should raise_error(ArgumentError) + end + + it "should require a listening address to be specified" do + Proc.new { @server.listen(@listen_params.delete_if {|k,v| :address == k})}.should raise_error(ArgumentError) + end + + it "should require a listening port to be specified" do + Proc.new { @server.listen(@listen_params.delete_if {|k,v| :port == k})}.should raise_error(ArgumentError) + end + + it "should order a webrick server to start in a separate thread" do + @mock_webrick.expects(:start) + # If you remove this you'll sometimes get race condition problems + Thread.expects(:new).yields + @server.listen(@listen_params) + end + + it "should tell webrick to listen on the specified address and port" do + WEBrick::HTTPServer.expects(:new).with {|args| + args[:Port] == 31337 and args[:BindAddress] == "127.0.0.1" + }.returns(@mock_webrick) + @server.listen(@listen_params) + end + + it "should configure a logger for webrick" do + @server.expects(:setup_logger).returns(:Logger => :mylogger) + + WEBrick::HTTPServer.expects(:new).with {|args| + args[:Logger] == :mylogger + }.returns(@mock_webrick) + + @server.listen(@listen_params) + end + + it "should configure SSL for webrick" do + @server.expects(:setup_ssl).returns(:Ssl => :testing, :Other => :yay) + + WEBrick::HTTPServer.expects(:new).with {|args| + args[:Ssl] == :testing and args[:Other] == :yay + }.returns(@mock_webrick) + + @server.listen(@listen_params) + end + + it "should be listening" do + @server.listen(@listen_params) + @server.should be_listening + end + + describe "when the REST protocol is requested" do + it "should register the REST handler at /" do + # We don't care about the options here. + @mock_webrick.expects(:mount).with { |path, klass, options| path == "/" and klass == Puppet::Network::HTTP::WEBrickREST } + + @server.listen(@listen_params.merge(:protocols => [:rest])) end + end - it "should fail if already listening" do - @server.listen(@listen_params) - Proc.new { @server.listen(@listen_params) }.should raise_error(RuntimeError) - end + describe "when the XMLRPC protocol is requested" do + before do + @servlet = mock 'servlet' - it "should require at least one protocol" do - Proc.new { @server.listen(@listen_params.delete_if {|k,v| :protocols == k}) }.should raise_error(ArgumentError) - end + Puppet::Network::XMLRPC::WEBrickServlet.stubs(:new).returns @servlet - it "should require a listening address to be specified" do - Proc.new { @server.listen(@listen_params.delete_if {|k,v| :address == k})}.should raise_error(ArgumentError) - end + @master_handler = mock('master_handler') + @file_handler = mock('file_handler') - it "should require a listening port to be specified" do - Proc.new { @server.listen(@listen_params.delete_if {|k,v| :port == k})}.should raise_error(ArgumentError) - end + @master = mock 'master' + @file = mock 'file' + @master_handler.stubs(:new).returns @master + @file_handler.stubs(:new).returns @file - it "should order a webrick server to start in a separate thread" do - @mock_webrick.expects(:start) - # If you remove this you'll sometimes get race condition problems - Thread.expects(:new).yields - @server.listen(@listen_params) + Puppet::Network::Handler.stubs(:handler).with(:master).returns @master_handler + Puppet::Network::Handler.stubs(:handler).with(:fileserver).returns @file_handler end - it "should tell webrick to listen on the specified address and port" do - WEBrick::HTTPServer.expects(:new).with {|args| - args[:Port] == 31337 and args[:BindAddress] == "127.0.0.1" - }.returns(@mock_webrick) - @server.listen(@listen_params) - end + it "should do nothing if no xmlrpc handlers have been specified" do + Puppet::Network::Handler.expects(:handler).never - it "should configure a logger for webrick" do - @server.expects(:setup_logger).returns(:Logger => :mylogger) - - WEBrick::HTTPServer.expects(:new).with {|args| - args[:Logger] == :mylogger - }.returns(@mock_webrick) - - @server.listen(@listen_params) + @server.listen(@listen_params.merge(:protocols => [:xmlrpc], :xmlrpc_handlers => [])) end - it "should configure SSL for webrick" do - @server.expects(:setup_ssl).returns(:Ssl => :testing, :Other => :yay) + it "should look the handler classes up via their base class" do + Puppet::Network::Handler.expects(:handler).with(:master).returns @master_handler + Puppet::Network::Handler.expects(:handler).with(:fileserver).returns @file_handler - WEBrick::HTTPServer.expects(:new).with {|args| - args[:Ssl] == :testing and args[:Other] == :yay - }.returns(@mock_webrick) - - @server.listen(@listen_params) + @server.listen(@listen_params.merge(:protocols => [:xmlrpc], :xmlrpc_handlers => [:master, :fileserver])) end - it "should be listening" do - @server.listen(@listen_params) - @server.should be_listening - end + it "should create an instance for each requested xmlrpc handler" do + @master_handler.expects(:new).returns @master + @file_handler.expects(:new).returns @file - describe "when the REST protocol is requested" do - it "should register the REST handler at /" do - # We don't care about the options here. - @mock_webrick.expects(:mount).with { |path, klass, options| path == "/" and klass == Puppet::Network::HTTP::WEBrickREST } - - @server.listen(@listen_params.merge(:protocols => [:rest])) - end + @server.listen(@listen_params.merge(:protocols => [:xmlrpc], :xmlrpc_handlers => [:master, :fileserver])) end - describe "when the XMLRPC protocol is requested" do - before do - @servlet = mock 'servlet' - - Puppet::Network::XMLRPC::WEBrickServlet.stubs(:new).returns @servlet - - @master_handler = mock('master_handler') - @file_handler = mock('file_handler') + it "should create a webrick servlet with the xmlrpc handler instances" do + Puppet::Network::XMLRPC::WEBrickServlet.expects(:new).with([@master, @file]).returns @servlet - @master = mock 'master' - @file = mock 'file' - @master_handler.stubs(:new).returns @master - @file_handler.stubs(:new).returns @file - - Puppet::Network::Handler.stubs(:handler).with(:master).returns @master_handler - Puppet::Network::Handler.stubs(:handler).with(:fileserver).returns @file_handler - end - - it "should do nothing if no xmlrpc handlers have been specified" do - Puppet::Network::Handler.expects(:handler).never - - @server.listen(@listen_params.merge(:protocols => [:xmlrpc], :xmlrpc_handlers => [])) - end - - it "should look the handler classes up via their base class" do - Puppet::Network::Handler.expects(:handler).with(:master).returns @master_handler - Puppet::Network::Handler.expects(:handler).with(:fileserver).returns @file_handler - - @server.listen(@listen_params.merge(:protocols => [:xmlrpc], :xmlrpc_handlers => [:master, :fileserver])) - end - - it "should create an instance for each requested xmlrpc handler" do - @master_handler.expects(:new).returns @master - @file_handler.expects(:new).returns @file - - @server.listen(@listen_params.merge(:protocols => [:xmlrpc], :xmlrpc_handlers => [:master, :fileserver])) - end - - it "should create a webrick servlet with the xmlrpc handler instances" do - Puppet::Network::XMLRPC::WEBrickServlet.expects(:new).with([@master, @file]).returns @servlet - - @server.listen(@listen_params.merge(:protocols => [:xmlrpc], :xmlrpc_handlers => [:master, :fileserver])) - end + @server.listen(@listen_params.merge(:protocols => [:xmlrpc], :xmlrpc_handlers => [:master, :fileserver])) + end - it "should mount the webrick servlet at /RPC2" do - @mock_webrick.stubs(:mount) - @mock_webrick.expects(:mount).with("/RPC2", @servlet) + it "should mount the webrick servlet at /RPC2" do + @mock_webrick.stubs(:mount) + @mock_webrick.expects(:mount).with("/RPC2", @servlet) - @server.listen(@listen_params.merge(:protocols => [:xmlrpc], :xmlrpc_handlers => [:master, :fileserver])) - end + @server.listen(@listen_params.merge(:protocols => [:xmlrpc], :xmlrpc_handlers => [:master, :fileserver])) end + end end describe Puppet::Network::HTTP::WEBrick, "when looking up the class to handle a protocol" do - it "should require a protocol" do - lambda { Puppet::Network::HTTP::WEBrick.class_for_protocol }.should raise_error(ArgumentError) - end + it "should require a protocol" do + lambda { Puppet::Network::HTTP::WEBrick.class_for_protocol }.should raise_error(ArgumentError) + end - it "should accept a protocol" do - lambda { Puppet::Network::HTTP::WEBrick.class_for_protocol("bob") }.should_not raise_error(ArgumentError) - end + it "should accept a protocol" do + lambda { Puppet::Network::HTTP::WEBrick.class_for_protocol("bob") }.should_not raise_error(ArgumentError) + end - it "should use a WEBrick + REST class when a REST protocol is specified" do - Puppet::Network::HTTP::WEBrick.class_for_protocol("rest").should == Puppet::Network::HTTP::WEBrickREST - end + it "should use a WEBrick + REST class when a REST protocol is specified" do + Puppet::Network::HTTP::WEBrick.class_for_protocol("rest").should == Puppet::Network::HTTP::WEBrickREST + end - it "should fail when an unknown protocol is specified" do - lambda { Puppet::Network::HTTP::WEBrick.class_for_protocol("abcdefg") }.should raise_error - end + it "should fail when an unknown protocol is specified" do + lambda { Puppet::Network::HTTP::WEBrick.class_for_protocol("abcdefg") }.should raise_error + end end describe Puppet::Network::HTTP::WEBrick, "when turning off listening" do - before do - @mock_webrick = stub('webrick', :[] => {}, :listeners => [], :status => :Running) - [:mount, :start, :shutdown].each {|meth| @mock_webrick.stubs(meth)} - WEBrick::HTTPServer.stubs(:new).returns(@mock_webrick) - @server = Puppet::Network::HTTP::WEBrick.new - [:setup_logger, :setup_ssl].each {|meth| @server.stubs(meth).returns({})} # the empty hash is required because of how we're merging - @listen_params = { :address => "127.0.0.1", :port => 31337, :handlers => [ :node, :catalog ], :protocols => [ :rest ] } - end - - it "should fail unless listening" do - Proc.new { @server.unlisten }.should raise_error(RuntimeError) - end - - it "should order webrick server to stop" do - @mock_webrick.expects(:shutdown) - @server.listen(@listen_params) - @server.unlisten - end - - it "should no longer be listening" do - @server.listen(@listen_params) - @server.unlisten - @server.should_not be_listening - end + before do + @mock_webrick = stub('webrick', :[] => {}, :listeners => [], :status => :Running) + [:mount, :start, :shutdown].each {|meth| @mock_webrick.stubs(meth)} + WEBrick::HTTPServer.stubs(:new).returns(@mock_webrick) + @server = Puppet::Network::HTTP::WEBrick.new + [:setup_logger, :setup_ssl].each {|meth| @server.stubs(meth).returns({})} # the empty hash is required because of how we're merging + @listen_params = { :address => "127.0.0.1", :port => 31337, :handlers => [ :node, :catalog ], :protocols => [ :rest ] } + end + + it "should fail unless listening" do + Proc.new { @server.unlisten }.should raise_error(RuntimeError) + end + + it "should order webrick server to stop" do + @mock_webrick.expects(:shutdown) + @server.listen(@listen_params) + @server.unlisten + end + + it "should no longer be listening" do + @server.listen(@listen_params) + @server.unlisten + @server.should_not be_listening + end end describe Puppet::Network::HTTP::WEBrick do + before do + @mock_webrick = stub('webrick', :[] => {}) + [:mount, :start, :shutdown].each {|meth| @mock_webrick.stubs(meth)} + WEBrick::HTTPServer.stubs(:new).returns(@mock_webrick) + @server = Puppet::Network::HTTP::WEBrick.new + end + + describe "when configuring an http logger" do before do - @mock_webrick = stub('webrick', :[] => {}) - [:mount, :start, :shutdown].each {|meth| @mock_webrick.stubs(meth)} - WEBrick::HTTPServer.stubs(:new).returns(@mock_webrick) - @server = Puppet::Network::HTTP::WEBrick.new - end + Puppet.settings.stubs(:value).returns "something" + Puppet.settings.stubs(:use) + @filehandle = stub 'handle', :fcntl => nil, :sync => nil - describe "when configuring an http logger" do - before do - Puppet.settings.stubs(:value).returns "something" - Puppet.settings.stubs(:use) - @filehandle = stub 'handle', :fcntl => nil, :sync => nil - - File.stubs(:open).returns @filehandle - end + File.stubs(:open).returns @filehandle + end - it "should use the settings for :main, :ssl, and the process name" do - Puppet.settings.stubs(:value).with(:name).returns "myname" - Puppet.settings.expects(:use).with(:main, :ssl, "myname") + it "should use the settings for :main, :ssl, and the process name" do + Puppet.settings.stubs(:value).with(:name).returns "myname" + Puppet.settings.expects(:use).with(:main, :ssl, "myname") - @server.setup_logger - end + @server.setup_logger + end - it "should use the masterlog if the run_mode is master" do - Puppet.run_mode.stubs(:master?).returns(true) - Puppet.settings.expects(:value).with(:masterhttplog).returns "/master/log" + it "should use the masterlog if the run_mode is master" do + Puppet.run_mode.stubs(:master?).returns(true) + Puppet.settings.expects(:value).with(:masterhttplog).returns "/master/log" - File.expects(:open).with("/master/log", "a+").returns @filehandle + File.expects(:open).with("/master/log", "a+").returns @filehandle - @server.setup_logger - end + @server.setup_logger + end - it "should use the httplog if the run_mode is not master" do - Puppet.run_mode.stubs(:master?).returns(false) - Puppet.settings.expects(:value).with(:httplog).returns "/other/log" + it "should use the httplog if the run_mode is not master" do + Puppet.run_mode.stubs(:master?).returns(false) + Puppet.settings.expects(:value).with(:httplog).returns "/other/log" - File.expects(:open).with("/other/log", "a+").returns @filehandle + File.expects(:open).with("/other/log", "a+").returns @filehandle - @server.setup_logger - end + @server.setup_logger + end - describe "and creating the logging filehandle" do - it "should set fcntl to 'Fcntl::F_SETFD, Fcntl::FD_CLOEXEC'" do - @filehandle.expects(:fcntl).with(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC) + describe "and creating the logging filehandle" do + it "should set fcntl to 'Fcntl::F_SETFD, Fcntl::FD_CLOEXEC'" do + @filehandle.expects(:fcntl).with(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC) - @server.setup_logger - end + @server.setup_logger + end - it "should sync the filehandle" do - @filehandle.expects(:sync) + it "should sync the filehandle" do + @filehandle.expects(:sync) - @server.setup_logger - end - end + @server.setup_logger + end + end - it "should create a new WEBrick::Log instance with the open filehandle" do - WEBrick::Log.expects(:new).with(@filehandle) + it "should create a new WEBrick::Log instance with the open filehandle" do + WEBrick::Log.expects(:new).with(@filehandle) - @server.setup_logger - end + @server.setup_logger + end - it "should set debugging if the current loglevel is :debug" do - Puppet::Util::Log.expects(:level).returns :debug + it "should set debugging if the current loglevel is :debug" do + Puppet::Util::Log.expects(:level).returns :debug - WEBrick::Log.expects(:new).with { |handle, debug| debug == WEBrick::Log::DEBUG } + WEBrick::Log.expects(:new).with { |handle, debug| debug == WEBrick::Log::DEBUG } - @server.setup_logger - end + @server.setup_logger + end - it "should return the logger as the main log" do - logger = mock 'logger' - WEBrick::Log.expects(:new).returns logger + it "should return the logger as the main log" do + logger = mock 'logger' + WEBrick::Log.expects(:new).returns logger - @server.setup_logger[:Logger].should == logger - end + @server.setup_logger[:Logger].should == logger + end - it "should return the logger as the access log using both the Common and Referer log format" do - logger = mock 'logger' - WEBrick::Log.expects(:new).returns logger + it "should return the logger as the access log using both the Common and Referer log format" do + logger = mock 'logger' + WEBrick::Log.expects(:new).returns logger - @server.setup_logger[:AccessLog].should == [ - [logger, WEBrick::AccessLog::COMMON_LOG_FORMAT], - [logger, WEBrick::AccessLog::REFERER_LOG_FORMAT] - ] - end + @server.setup_logger[:AccessLog].should == [ + [logger, WEBrick::AccessLog::COMMON_LOG_FORMAT], + [logger, WEBrick::AccessLog::REFERER_LOG_FORMAT] + ] end + end - describe "when configuring ssl" do - before do - @key = stub 'key', :content => "mykey" - @cert = stub 'cert', :content => "mycert" - @host = stub 'host', :key => @key, :certificate => @cert, :name => "yay", :ssl_store => "mystore" + describe "when configuring ssl" do + before do + @key = stub 'key', :content => "mykey" + @cert = stub 'cert', :content => "mycert" + @host = stub 'host', :key => @key, :certificate => @cert, :name => "yay", :ssl_store => "mystore" - Puppet::SSL::Certificate.stubs(:find).with('ca').returns @cert + Puppet::SSL::Certificate.stubs(:find).with('ca').returns @cert - Puppet::SSL::Host.stubs(:localhost).returns @host - end + Puppet::SSL::Host.stubs(:localhost).returns @host + end - it "should use the key from the localhost SSL::Host instance" do - Puppet::SSL::Host.expects(:localhost).returns @host - @host.expects(:key).returns @key + it "should use the key from the localhost SSL::Host instance" do + Puppet::SSL::Host.expects(:localhost).returns @host + @host.expects(:key).returns @key - @server.setup_ssl[:SSLPrivateKey].should == "mykey" - end + @server.setup_ssl[:SSLPrivateKey].should == "mykey" + end - it "should configure the certificate" do - @server.setup_ssl[:SSLCertificate].should == "mycert" - end + it "should configure the certificate" do + @server.setup_ssl[:SSLCertificate].should == "mycert" + end - it "should fail if no CA certificate can be found" do - Puppet::SSL::Certificate.stubs(:find).with('ca').returns nil + it "should fail if no CA certificate can be found" do + Puppet::SSL::Certificate.stubs(:find).with('ca').returns nil - lambda { @server.setup_ssl }.should raise_error(Puppet::Error) - end + lambda { @server.setup_ssl }.should raise_error(Puppet::Error) + end - it "should specify the path to the CA certificate" do - Puppet.settings.stubs(:value).returns "whatever" - Puppet.settings.stubs(:value).with(:hostcrl).returns 'false' - Puppet.settings.stubs(:value).with(:localcacert).returns '/ca/crt' + it "should specify the path to the CA certificate" do + Puppet.settings.stubs(:value).returns "whatever" + Puppet.settings.stubs(:value).with(:hostcrl).returns 'false' + Puppet.settings.stubs(:value).with(:localcacert).returns '/ca/crt' - @server.setup_ssl[:SSLCACertificateFile].should == "/ca/crt" - end + @server.setup_ssl[:SSLCACertificateFile].should == "/ca/crt" + end - it "should start ssl immediately" do - @server.setup_ssl[:SSLStartImmediately].should be_true - end + it "should start ssl immediately" do + @server.setup_ssl[:SSLStartImmediately].should be_true + end - it "should enable ssl" do - @server.setup_ssl[:SSLEnable].should be_true - end + it "should enable ssl" do + @server.setup_ssl[:SSLEnable].should be_true + end - it "should configure the verification method as 'OpenSSL::SSL::VERIFY_PEER'" do - @server.setup_ssl[:SSLVerifyClient].should == OpenSSL::SSL::VERIFY_PEER - end + it "should configure the verification method as 'OpenSSL::SSL::VERIFY_PEER'" do + @server.setup_ssl[:SSLVerifyClient].should == OpenSSL::SSL::VERIFY_PEER + end - it "should add an x509 store" do - Puppet.settings.stubs(:value).returns "whatever" - Puppet.settings.stubs(:value).with(:hostcrl).returns '/my/crl' + it "should add an x509 store" do + Puppet.settings.stubs(:value).returns "whatever" + Puppet.settings.stubs(:value).with(:hostcrl).returns '/my/crl' - @host.expects(:ssl_store).returns "mystore" + @host.expects(:ssl_store).returns "mystore" - @server.setup_ssl[:SSLCertificateStore].should == "mystore" - end + @server.setup_ssl[:SSLCertificateStore].should == "mystore" + end - it "should set the certificate name to 'nil'" do - @server.setup_ssl[:SSLCertName].should be_nil - end + it "should set the certificate name to 'nil'" do + @server.setup_ssl[:SSLCertName].should be_nil end + end end diff --git a/spec/unit/network/http_pool_spec.rb b/spec/unit/network/http_pool_spec.rb index 1d64f9c9c..8fa7de8f9 100755 --- a/spec/unit/network/http_pool_spec.rb +++ b/spec/unit/network/http_pool_spec.rb @@ -7,200 +7,200 @@ require File.dirname(__FILE__) + '/../../spec_helper' require 'puppet/network/http_pool' describe Puppet::Network::HttpPool do - after do - Puppet::Util::Cacher.expire + after do + Puppet::Util::Cacher.expire + Puppet::Network::HttpPool.clear_http_instances + Puppet::Network::HttpPool.instance_variable_set("@ssl_host", nil) + end + + it "should have keep-alive disabled" do + Puppet::Network::HttpPool::HTTP_KEEP_ALIVE.should be_false + end + + it "should use the global SSL::Host instance to get its certificate information" do + host = mock 'host' + Puppet::SSL::Host.expects(:localhost).with.returns host + Puppet::Network::HttpPool.ssl_host.should equal(host) + end + + describe "when managing http instances" do + def stub_settings(settings) + settings.each do |param, value| + Puppet.settings.stubs(:value).with(param).returns(value) + end + end + + before do + # All of the cert stuff is tested elsewhere + Puppet::Network::HttpPool.stubs(:cert_setup) + end + + it "should return an http instance created with the passed host and port" do + http = stub 'http', :use_ssl= => nil, :read_timeout= => nil, :open_timeout= => nil, :started? => false + Net::HTTP.expects(:new).with("me", 54321, nil, nil).returns(http) + Puppet::Network::HttpPool.http_instance("me", 54321).should equal(http) + end + + it "should enable ssl on the http instance" do + Puppet::Network::HttpPool.http_instance("me", 54321).instance_variable_get("@use_ssl").should be_true + end + + it "should set the read timeout" do + Puppet::Network::HttpPool.http_instance("me", 54321).read_timeout.should == 120 + end + + it "should set the open timeout" do + Puppet::Network::HttpPool.http_instance("me", 54321).open_timeout.should == 120 + end + + it "should create the http instance with the proxy host and port set if the http_proxy is not set to 'none'" do + stub_settings :http_proxy_host => "myhost", :http_proxy_port => 432, :configtimeout => 120 + Puppet::Network::HttpPool.http_instance("me", 54321).open_timeout.should == 120 + end + + describe "and http keep-alive is enabled" do + before do + Puppet::Network::HttpPool.stubs(:keep_alive?).returns true + end + + it "should cache http instances" do + stub_settings :http_proxy_host => "myhost", :http_proxy_port => 432, :configtimeout => 120 + old = Puppet::Network::HttpPool.http_instance("me", 54321) + Puppet::Network::HttpPool.http_instance("me", 54321).should equal(old) + end + + it "should have a mechanism for getting a new http instance instead of the cached instance" do + stub_settings :http_proxy_host => "myhost", :http_proxy_port => 432, :configtimeout => 120 + old = Puppet::Network::HttpPool.http_instance("me", 54321) + Puppet::Network::HttpPool.http_instance("me", 54321, true).should_not equal(old) + end + + it "should close existing, open connections when requesting a new connection" do + stub_settings :http_proxy_host => "myhost", :http_proxy_port => 432, :configtimeout => 120 + old = Puppet::Network::HttpPool.http_instance("me", 54321) + old.expects(:started?).returns(true) + old.expects(:finish) + Puppet::Network::HttpPool.http_instance("me", 54321, true) + end + + it "should have a mechanism for clearing the http cache" do + stub_settings :http_proxy_host => "myhost", :http_proxy_port => 432, :configtimeout => 120 + old = Puppet::Network::HttpPool.http_instance("me", 54321) + Puppet::Network::HttpPool.http_instance("me", 54321).should equal(old) + old = Puppet::Network::HttpPool.http_instance("me", 54321) + Puppet::Network::HttpPool.clear_http_instances + Puppet::Network::HttpPool.http_instance("me", 54321).should_not equal(old) + end + + it "should close open http connections when clearing the cache" do + stub_settings :http_proxy_host => "myhost", :http_proxy_port => 432, :configtimeout => 120 + one = Puppet::Network::HttpPool.http_instance("me", 54321) + one.expects(:started?).returns(true) + one.expects(:finish).returns(true) + Puppet::Network::HttpPool.clear_http_instances + end + + it "should not close unopened http connections when clearing the cache" do + stub_settings :http_proxy_host => "myhost", :http_proxy_port => 432, :configtimeout => 120 + one = Puppet::Network::HttpPool.http_instance("me", 54321) + one.expects(:started?).returns(false) + one.expects(:finish).never Puppet::Network::HttpPool.clear_http_instances - Puppet::Network::HttpPool.instance_variable_set("@ssl_host", nil) - end - - it "should have keep-alive disabled" do - Puppet::Network::HttpPool::HTTP_KEEP_ALIVE.should be_false - end - - it "should use the global SSL::Host instance to get its certificate information" do - host = mock 'host' - Puppet::SSL::Host.expects(:localhost).with.returns host - Puppet::Network::HttpPool.ssl_host.should equal(host) - end - - describe "when managing http instances" do - def stub_settings(settings) - settings.each do |param, value| - Puppet.settings.stubs(:value).with(param).returns(value) - end - end - - before do - # All of the cert stuff is tested elsewhere - Puppet::Network::HttpPool.stubs(:cert_setup) - end - - it "should return an http instance created with the passed host and port" do - http = stub 'http', :use_ssl= => nil, :read_timeout= => nil, :open_timeout= => nil, :started? => false - Net::HTTP.expects(:new).with("me", 54321, nil, nil).returns(http) - Puppet::Network::HttpPool.http_instance("me", 54321).should equal(http) - end - - it "should enable ssl on the http instance" do - Puppet::Network::HttpPool.http_instance("me", 54321).instance_variable_get("@use_ssl").should be_true - end - - it "should set the read timeout" do - Puppet::Network::HttpPool.http_instance("me", 54321).read_timeout.should == 120 - end - - it "should set the open timeout" do - Puppet::Network::HttpPool.http_instance("me", 54321).open_timeout.should == 120 - end - - it "should create the http instance with the proxy host and port set if the http_proxy is not set to 'none'" do - stub_settings :http_proxy_host => "myhost", :http_proxy_port => 432, :configtimeout => 120 - Puppet::Network::HttpPool.http_instance("me", 54321).open_timeout.should == 120 - end - - describe "and http keep-alive is enabled" do - before do - Puppet::Network::HttpPool.stubs(:keep_alive?).returns true - end - - it "should cache http instances" do - stub_settings :http_proxy_host => "myhost", :http_proxy_port => 432, :configtimeout => 120 - old = Puppet::Network::HttpPool.http_instance("me", 54321) - Puppet::Network::HttpPool.http_instance("me", 54321).should equal(old) - end - - it "should have a mechanism for getting a new http instance instead of the cached instance" do - stub_settings :http_proxy_host => "myhost", :http_proxy_port => 432, :configtimeout => 120 - old = Puppet::Network::HttpPool.http_instance("me", 54321) - Puppet::Network::HttpPool.http_instance("me", 54321, true).should_not equal(old) - end - - it "should close existing, open connections when requesting a new connection" do - stub_settings :http_proxy_host => "myhost", :http_proxy_port => 432, :configtimeout => 120 - old = Puppet::Network::HttpPool.http_instance("me", 54321) - old.expects(:started?).returns(true) - old.expects(:finish) - Puppet::Network::HttpPool.http_instance("me", 54321, true) - end - - it "should have a mechanism for clearing the http cache" do - stub_settings :http_proxy_host => "myhost", :http_proxy_port => 432, :configtimeout => 120 - old = Puppet::Network::HttpPool.http_instance("me", 54321) - Puppet::Network::HttpPool.http_instance("me", 54321).should equal(old) - old = Puppet::Network::HttpPool.http_instance("me", 54321) - Puppet::Network::HttpPool.clear_http_instances - Puppet::Network::HttpPool.http_instance("me", 54321).should_not equal(old) - end - - it "should close open http connections when clearing the cache" do - stub_settings :http_proxy_host => "myhost", :http_proxy_port => 432, :configtimeout => 120 - one = Puppet::Network::HttpPool.http_instance("me", 54321) - one.expects(:started?).returns(true) - one.expects(:finish).returns(true) - Puppet::Network::HttpPool.clear_http_instances - end - - it "should not close unopened http connections when clearing the cache" do - stub_settings :http_proxy_host => "myhost", :http_proxy_port => 432, :configtimeout => 120 - one = Puppet::Network::HttpPool.http_instance("me", 54321) - one.expects(:started?).returns(false) - one.expects(:finish).never - Puppet::Network::HttpPool.clear_http_instances - end - end - - describe "and http keep-alive is disabled" do - before do - Puppet::Network::HttpPool.stubs(:keep_alive?).returns false - end - - it "should not cache http instances" do - stub_settings :http_proxy_host => "myhost", :http_proxy_port => 432, :configtimeout => 120 - old = Puppet::Network::HttpPool.http_instance("me", 54321) - Puppet::Network::HttpPool.http_instance("me", 54321).should_not equal(old) - end - end - - after do - Puppet::Network::HttpPool.clear_http_instances - end - end - - describe "when adding certificate information to http instances" do - before do - @http = mock 'http' - [:cert_store=, :verify_mode=, :ca_file=, :cert=, :key=].each { |m| @http.stubs(m) } - @store = stub 'store' - - @cert = stub 'cert', :content => "real_cert" - @key = stub 'key', :content => "real_key" - @host = stub 'host', :certificate => @cert, :key => @key, :ssl_store => @store - - Puppet[:confdir] = "/sometthing/else" - Puppet.settings.stubs(:value).returns "/some/file" - Puppet.settings.stubs(:value).with(:hostcert).returns "/host/cert" - Puppet.settings.stubs(:value).with(:localcacert).returns "/local/ca/cert" - - FileTest.stubs(:exist?).with("/host/cert").returns true - FileTest.stubs(:exist?).with("/local/ca/cert").returns true - - Puppet::Network::HttpPool.stubs(:ssl_host).returns @host - end - - after do - Puppet.settings.clear - end - - it "should do nothing if no host certificate is on disk" do - FileTest.expects(:exist?).with("/host/cert").returns false - @http.expects(:cert=).never - Puppet::Network::HttpPool.cert_setup(@http) - end - - it "should do nothing if no local certificate is on disk" do - FileTest.expects(:exist?).with("/local/ca/cert").returns false - @http.expects(:cert=).never - Puppet::Network::HttpPool.cert_setup(@http) - end - - it "should add a certificate store from the ssl host" do - @http.expects(:cert_store=).with(@store) - - Puppet::Network::HttpPool.cert_setup(@http) - end - - it "should add the client certificate" do - @http.expects(:cert=).with("real_cert") - - Puppet::Network::HttpPool.cert_setup(@http) - end - - it "should add the client key" do - @http.expects(:key=).with("real_key") - - Puppet::Network::HttpPool.cert_setup(@http) - end - - it "should set the verify mode to OpenSSL::SSL::VERIFY_PEER" do - @http.expects(:verify_mode=).with(OpenSSL::SSL::VERIFY_PEER) - - Puppet::Network::HttpPool.cert_setup(@http) - end - - it "should set the ca file" do - Puppet.settings.stubs(:value).returns "/some/file" - FileTest.stubs(:exist?).with(Puppet[:hostcert]).returns true - - Puppet.settings.stubs(:value).with(:localcacert).returns "/ca/cert/file" - FileTest.stubs(:exist?).with("/ca/cert/file").returns true - @http.expects(:ca_file=).with("/ca/cert/file") - - Puppet::Network::HttpPool.cert_setup(@http) - end + end + end + + describe "and http keep-alive is disabled" do + before do + Puppet::Network::HttpPool.stubs(:keep_alive?).returns false + end + + it "should not cache http instances" do + stub_settings :http_proxy_host => "myhost", :http_proxy_port => 432, :configtimeout => 120 + old = Puppet::Network::HttpPool.http_instance("me", 54321) + Puppet::Network::HttpPool.http_instance("me", 54321).should_not equal(old) + end + end + + after do + Puppet::Network::HttpPool.clear_http_instances + end + end + + describe "when adding certificate information to http instances" do + before do + @http = mock 'http' + [:cert_store=, :verify_mode=, :ca_file=, :cert=, :key=].each { |m| @http.stubs(m) } + @store = stub 'store' + + @cert = stub 'cert', :content => "real_cert" + @key = stub 'key', :content => "real_key" + @host = stub 'host', :certificate => @cert, :key => @key, :ssl_store => @store + + Puppet[:confdir] = "/sometthing/else" + Puppet.settings.stubs(:value).returns "/some/file" + Puppet.settings.stubs(:value).with(:hostcert).returns "/host/cert" + Puppet.settings.stubs(:value).with(:localcacert).returns "/local/ca/cert" + + FileTest.stubs(:exist?).with("/host/cert").returns true + FileTest.stubs(:exist?).with("/local/ca/cert").returns true + + Puppet::Network::HttpPool.stubs(:ssl_host).returns @host + end + + after do + Puppet.settings.clear + end + + it "should do nothing if no host certificate is on disk" do + FileTest.expects(:exist?).with("/host/cert").returns false + @http.expects(:cert=).never + Puppet::Network::HttpPool.cert_setup(@http) + end + + it "should do nothing if no local certificate is on disk" do + FileTest.expects(:exist?).with("/local/ca/cert").returns false + @http.expects(:cert=).never + Puppet::Network::HttpPool.cert_setup(@http) + end + + it "should add a certificate store from the ssl host" do + @http.expects(:cert_store=).with(@store) + + Puppet::Network::HttpPool.cert_setup(@http) + end + + it "should add the client certificate" do + @http.expects(:cert=).with("real_cert") + + Puppet::Network::HttpPool.cert_setup(@http) + end + + it "should add the client key" do + @http.expects(:key=).with("real_key") + + Puppet::Network::HttpPool.cert_setup(@http) + end + + it "should set the verify mode to OpenSSL::SSL::VERIFY_PEER" do + @http.expects(:verify_mode=).with(OpenSSL::SSL::VERIFY_PEER) + + Puppet::Network::HttpPool.cert_setup(@http) + end + + it "should set the ca file" do + Puppet.settings.stubs(:value).returns "/some/file" + FileTest.stubs(:exist?).with(Puppet[:hostcert]).returns true + + Puppet.settings.stubs(:value).with(:localcacert).returns "/ca/cert/file" + FileTest.stubs(:exist?).with("/ca/cert/file").returns true + @http.expects(:ca_file=).with("/ca/cert/file") + + Puppet::Network::HttpPool.cert_setup(@http) + end - it "should set up certificate information when creating http instances" do - Puppet::Network::HttpPool.expects(:cert_setup).with { |i| i.is_a?(Net::HTTP) } - Puppet::Network::HttpPool.http_instance("one", "two") - end + it "should set up certificate information when creating http instances" do + Puppet::Network::HttpPool.expects(:cert_setup).with { |i| i.is_a?(Net::HTTP) } + Puppet::Network::HttpPool.http_instance("one", "two") end + end end diff --git a/spec/unit/network/http_spec.rb b/spec/unit/network/http_spec.rb index 220726788..e1d0d2269 100755 --- a/spec/unit/network/http_spec.rb +++ b/spec/unit/network/http_spec.rb @@ -8,28 +8,28 @@ require File.dirname(__FILE__) + '/../../spec_helper' require 'puppet/network/http' describe Puppet::Network::HTTP do - it "should return the webrick HTTP server class when asked for a webrick server" do - Puppet::Network::HTTP.server_class_by_type(:webrick).should be(Puppet::Network::HTTP::WEBrick) - end + it "should return the webrick HTTP server class when asked for a webrick server" do + Puppet::Network::HTTP.server_class_by_type(:webrick).should be(Puppet::Network::HTTP::WEBrick) + end - describe "when asked for a mongrel server" do - if Puppet.features.mongrel? - it "should return the mongrel server class" do - Puppet::Network::HTTP.server_class_by_type(:mongrel).should be(Puppet::Network::HTTP::Mongrel) - end - else - it "should fail" do - lambda { Puppet::Network::HTTP.server_class_by_type(:mongrel) }.should raise_error(ArgumentError) - end - end + describe "when asked for a mongrel server" do + if Puppet.features.mongrel? + it "should return the mongrel server class" do + Puppet::Network::HTTP.server_class_by_type(:mongrel).should be(Puppet::Network::HTTP::Mongrel) + end + else + it "should fail" do + lambda { Puppet::Network::HTTP.server_class_by_type(:mongrel) }.should raise_error(ArgumentError) + end end + end - it "should fail to return the mongrel HTTP server class if mongrel is not available " do - Puppet.features.expects(:mongrel?).returns(false) - Proc.new { Puppet::Network::HTTP.server_class_by_type(:mongrel) }.should raise_error(ArgumentError) - end + it "should fail to return the mongrel HTTP server class if mongrel is not available " do + Puppet.features.expects(:mongrel?).returns(false) + Proc.new { Puppet::Network::HTTP.server_class_by_type(:mongrel) }.should raise_error(ArgumentError) + end - it "should return an error when asked for an unknown server" do - Proc.new { Puppet::Network::HTTP.server_class_by_type :foo }.should raise_error(ArgumentError) - end + it "should return an error when asked for an unknown server" do + Proc.new { Puppet::Network::HTTP.server_class_by_type :foo }.should raise_error(ArgumentError) + end end diff --git a/spec/unit/network/rest_authconfig_spec.rb b/spec/unit/network/rest_authconfig_spec.rb index 79fa968e8..351f3f040 100755 --- a/spec/unit/network/rest_authconfig_spec.rb +++ b/spec/unit/network/rest_authconfig_spec.rb @@ -6,143 +6,143 @@ require 'puppet/network/rest_authconfig' describe Puppet::Network::RestAuthConfig do - DEFAULT_ACL = [ - { :acl => "~ ^\/catalog\/([^\/]+)$", :method => :find, :allow => '$1', :authenticated => true }, - # this one will allow all file access, and thus delegate - # to fileserver.conf - { :acl => "/file" }, - { :acl => "/certificate_revocation_list/ca", :method => :find, :authenticated => true }, - { :acl => "/report", :method => :save, :authenticated => true }, - { :acl => "/certificate/ca", :method => :find, :authenticated => false }, - { :acl => "/certificate/", :method => :find, :authenticated => false }, - { :acl => "/certificate_request", :method => [:find, :save], :authenticated => false }, - { :acl => "/status", :method => [:find], :authenticated => true }, - { :acl => "/resource", :method => [:find, :save, :search], :authenticated => true }, - ] - - before :each do - FileTest.stubs(:exists?).returns(true) - File.stubs(:stat).returns(stub('stat', :ctime => :now)) - Time.stubs(:now).returns :now - - @authconfig = Puppet::Network::RestAuthConfig.new("dummy", false) - @authconfig.stubs(:read) - - @acl = stub_everything 'rights' - @authconfig.rights = @acl - - @request = stub 'request', :indirection_name => "path", :key => "to/resource", :ip => "127.0.0.1", - :node => "me", :method => :save, :environment => :env, :authenticated => true + DEFAULT_ACL = [ + { :acl => "~ ^\/catalog\/([^\/]+)$", :method => :find, :allow => '$1', :authenticated => true }, + # this one will allow all file access, and thus delegate + # to fileserver.conf + { :acl => "/file" }, + { :acl => "/certificate_revocation_list/ca", :method => :find, :authenticated => true }, + { :acl => "/report", :method => :save, :authenticated => true }, + { :acl => "/certificate/ca", :method => :find, :authenticated => false }, + { :acl => "/certificate/", :method => :find, :authenticated => false }, + { :acl => "/certificate_request", :method => [:find, :save], :authenticated => false }, + { :acl => "/status", :method => [:find], :authenticated => true }, + { :acl => "/resource", :method => [:find, :save, :search], :authenticated => true }, + ] + + before :each do + FileTest.stubs(:exists?).returns(true) + File.stubs(:stat).returns(stub('stat', :ctime => :now)) + Time.stubs(:now).returns :now + + @authconfig = Puppet::Network::RestAuthConfig.new("dummy", false) + @authconfig.stubs(:read) + + @acl = stub_everything 'rights' + @authconfig.rights = @acl + + @request = stub 'request', :indirection_name => "path", :key => "to/resource", :ip => "127.0.0.1", + :node => "me", :method => :save, :environment => :env, :authenticated => true + end + + it "should use the puppet default rest authorization file" do + Puppet.expects(:[]).with(:rest_authconfig).returns("dummy") + + Puppet::Network::RestAuthConfig.new(nil, false) + end + + it "should read the config file when needed" do + @authconfig.expects(:read) + + @authconfig.allowed?(@request) + end + + it "should ask for authorization to the ACL subsystem" do + @acl.expects(:fail_on_deny).with("/path/to/resource", :node => "me", :ip => "127.0.0.1", :method => :save, :environment => :env, :authenticated => true) + + @authconfig.allowed?(@request) + end + + describe "when defining an acl with mk_acl" do + it "should create a new right for each default acl" do + @acl.expects(:newright).with(:path) + @authconfig.mk_acl(:acl => :path) end - it "should use the puppet default rest authorization file" do - Puppet.expects(:[]).with(:rest_authconfig).returns("dummy") - - Puppet::Network::RestAuthConfig.new(nil, false) + it "should allow everyone for each default right" do + @acl.expects(:allow).with(:path, "*") + @authconfig.mk_acl(:acl => :path) end - it "should read the config file when needed" do - @authconfig.expects(:read) - - @authconfig.allowed?(@request) + it "should restrict the ACL to a method" do + @acl.expects(:restrict_method).with(:path, :method) + @authconfig.mk_acl(:acl => :path, :method => :method) end - it "should ask for authorization to the ACL subsystem" do - @acl.expects(:fail_on_deny).with("/path/to/resource", :node => "me", :ip => "127.0.0.1", :method => :save, :environment => :env, :authenticated => true) - - @authconfig.allowed?(@request) + it "should restrict the ACL to a specific authentication state" do + @acl.expects(:restrict_authenticated).with(:path, :authentication) + @authconfig.mk_acl(:acl => :path, :authenticated => :authentication) end + end - describe "when defining an acl with mk_acl" do - it "should create a new right for each default acl" do - @acl.expects(:newright).with(:path) - @authconfig.mk_acl(:acl => :path) - end - - it "should allow everyone for each default right" do - @acl.expects(:allow).with(:path, "*") - @authconfig.mk_acl(:acl => :path) - end - - it "should restrict the ACL to a method" do - @acl.expects(:restrict_method).with(:path, :method) - @authconfig.mk_acl(:acl => :path, :method => :method) - end - - it "should restrict the ACL to a specific authentication state" do - @acl.expects(:restrict_authenticated).with(:path, :authentication) - @authconfig.mk_acl(:acl => :path, :authenticated => :authentication) - end - end + describe "when parsing the configuration file" do + it "should check for missing ACL after reading the authconfig file" do + File.stubs(:open) - describe "when parsing the configuration file" do - it "should check for missing ACL after reading the authconfig file" do - File.stubs(:open) + @authconfig.expects(:insert_default_acl) - @authconfig.expects(:insert_default_acl) - - @authconfig.parse - end + @authconfig.parse end + end - DEFAULT_ACL.each do |acl| - it "should insert #{acl[:acl]} if not present" do - @authconfig.rights.stubs(:[]).returns(true) - @authconfig.rights.stubs(:[]).with(acl[:acl]).returns(nil) + DEFAULT_ACL.each do |acl| + it "should insert #{acl[:acl]} if not present" do + @authconfig.rights.stubs(:[]).returns(true) + @authconfig.rights.stubs(:[]).with(acl[:acl]).returns(nil) - @authconfig.expects(:mk_acl).with { |h| h[:acl] == acl[:acl] } + @authconfig.expects(:mk_acl).with { |h| h[:acl] == acl[:acl] } - @authconfig.insert_default_acl - end + @authconfig.insert_default_acl + end - it "should not insert #{acl[:acl]} if present" do - @authconfig.rights.stubs(:[]).returns(true) - @authconfig.rights.stubs(:[]).with(acl).returns(true) + it "should not insert #{acl[:acl]} if present" do + @authconfig.rights.stubs(:[]).returns(true) + @authconfig.rights.stubs(:[]).with(acl).returns(true) - @authconfig.expects(:mk_acl).never + @authconfig.expects(:mk_acl).never - @authconfig.insert_default_acl - end + @authconfig.insert_default_acl end + end - it "should create default ACL entries if no file have been read" do - Puppet::Network::RestAuthConfig.any_instance.stubs(:exists?).returns(false) + it "should create default ACL entries if no file have been read" do + Puppet::Network::RestAuthConfig.any_instance.stubs(:exists?).returns(false) - Puppet::Network::RestAuthConfig.any_instance.expects(:insert_default_acl) + Puppet::Network::RestAuthConfig.any_instance.expects(:insert_default_acl) - Puppet::Network::RestAuthConfig.main - end - - describe "when adding default ACLs" do + Puppet::Network::RestAuthConfig.main + end - DEFAULT_ACL.each do |acl| - it "should create a default right for #{acl[:acl]}" do - @authconfig.stubs(:mk_acl) - @authconfig.expects(:mk_acl).with(acl) - @authconfig.insert_default_acl - end - end + describe "when adding default ACLs" do - it "should log at info loglevel" do - Puppet.expects(:info).at_least_once - @authconfig.insert_default_acl - end + DEFAULT_ACL.each do |acl| + it "should create a default right for #{acl[:acl]}" do + @authconfig.stubs(:mk_acl) + @authconfig.expects(:mk_acl).with(acl) + @authconfig.insert_default_acl + end + end - it "should create a last catch-all deny all rule" do - @authconfig.stubs(:mk_acl) - @acl.expects(:newright).with("/") - @authconfig.insert_default_acl - end + it "should log at info loglevel" do + Puppet.expects(:info).at_least_once + @authconfig.insert_default_acl + end - it "should create a last catch-all deny all rule for any authenticated request state" do - @authconfig.stubs(:mk_acl) - @acl.stubs(:newright).with("/") + it "should create a last catch-all deny all rule" do + @authconfig.stubs(:mk_acl) + @acl.expects(:newright).with("/") + @authconfig.insert_default_acl + end - @acl.expects(:restrict_authenticated).with("/", :any) + it "should create a last catch-all deny all rule for any authenticated request state" do + @authconfig.stubs(:mk_acl) + @acl.stubs(:newright).with("/") - @authconfig.insert_default_acl - end + @acl.expects(:restrict_authenticated).with("/", :any) + @authconfig.insert_default_acl end + end + end diff --git a/spec/unit/network/rest_authorization_spec.rb b/spec/unit/network/rest_authorization_spec.rb index 4703c181f..0cb0bcee9 100755 --- a/spec/unit/network/rest_authorization_spec.rb +++ b/spec/unit/network/rest_authorization_spec.rb @@ -5,39 +5,39 @@ require File.dirname(__FILE__) + '/../../spec_helper' require 'puppet/network/rest_authorization' class RestAuthorized - include Puppet::Network::RestAuthorization + include Puppet::Network::RestAuthorization end describe Puppet::Network::RestAuthorization do - before :each do - @auth = RestAuthorized.new - @authconig = stub 'authconfig' - @auth.stubs(:authconfig).returns(@authconfig) - - @request = stub_everything 'request' - @request.stubs(:method).returns(:find) - @request.stubs(:node).returns("node") - @request.stubs(:ip).returns("ip") + before :each do + @auth = RestAuthorized.new + @authconig = stub 'authconfig' + @auth.stubs(:authconfig).returns(@authconfig) + + @request = stub_everything 'request' + @request.stubs(:method).returns(:find) + @request.stubs(:node).returns("node") + @request.stubs(:ip).returns("ip") + end + + describe "when testing request authorization" do + it "should delegate to the current rest authconfig" do + @authconfig.expects(:allowed?).with(@request).returns(true) + + @auth.check_authorization(@request) end - describe "when testing request authorization" do - it "should delegate to the current rest authconfig" do - @authconfig.expects(:allowed?).with(@request).returns(true) + it "should raise an AuthorizationError if authconfig raises an AuthorizationError" do + @authconfig.expects(:allowed?).with(@request).raises(Puppet::Network::AuthorizationError.new("forbidden")) - @auth.check_authorization(@request) - end - - it "should raise an AuthorizationError if authconfig raises an AuthorizationError" do - @authconfig.expects(:allowed?).with(@request).raises(Puppet::Network::AuthorizationError.new("forbidden")) - - lambda { @auth.check_authorization(@request) }.should raise_error(Puppet::Network::AuthorizationError) - end + lambda { @auth.check_authorization(@request) }.should raise_error(Puppet::Network::AuthorizationError) + end - it "should not raise an AuthorizationError if request is allowed" do - @authconfig.expects(:allowed?).with(@request).returns(true) + it "should not raise an AuthorizationError if request is allowed" do + @authconfig.expects(:allowed?).with(@request).returns(true) - lambda { @auth.check_authorization(@request) }.should_not raise_error(Puppet::Network::AuthorizationError) - end + lambda { @auth.check_authorization(@request) }.should_not raise_error(Puppet::Network::AuthorizationError) end + end end diff --git a/spec/unit/network/rights_spec.rb b/spec/unit/network/rights_spec.rb index 7f00891ac..969fc189e 100755 --- a/spec/unit/network/rights_spec.rb +++ b/spec/unit/network/rights_spec.rb @@ -5,515 +5,515 @@ require File.dirname(__FILE__) + '/../../spec_helper' require 'puppet/network/rights' describe Puppet::Network::Rights do - before do - @right = Puppet::Network::Rights.new - end + before do + @right = Puppet::Network::Rights.new + end - [:allow, :deny, :restrict_method, :restrict_environment, :restrict_authenticated].each do |m| - it "should have a #{m} method" do - @right.should respond_to(m) - end + [:allow, :deny, :restrict_method, :restrict_environment, :restrict_authenticated].each do |m| + it "should have a #{m} method" do + @right.should respond_to(m) + end - describe "when using #{m}" do - it "should delegate to the correct acl" do - acl = stub 'acl' - @right.stubs(:[]).returns(acl) + describe "when using #{m}" do + it "should delegate to the correct acl" do + acl = stub 'acl' + @right.stubs(:[]).returns(acl) - acl.expects(m).with("me") + acl.expects(m).with("me") - @right.send(m, 'thisacl', "me") - end - end + @right.send(m, 'thisacl', "me") + end end + end - it "should throw an error if type can't be determined" do - lambda { @right.newright("name") }.should raise_error - end + it "should throw an error if type can't be determined" do + lambda { @right.newright("name") }.should raise_error + end - describe "when creating new namespace ACLs" do + describe "when creating new namespace ACLs" do - it "should throw an error if the ACL already exists" do - @right.newright("[name]") + it "should throw an error if the ACL already exists" do + @right.newright("[name]") - lambda { @right.newright("[name]") }.should raise_error - end + lambda { @right.newright("[name]") }.should raise_error + end - it "should create a new ACL with the correct name" do - @right.newright("[name]") + it "should create a new ACL with the correct name" do + @right.newright("[name]") - @right["name"].key.should == :name - end + @right["name"].key.should == :name + end - it "should create an ACL of type Puppet::Network::AuthStore" do - @right.newright("[name]") + it "should create an ACL of type Puppet::Network::AuthStore" do + @right.newright("[name]") - @right["name"].should be_a_kind_of(Puppet::Network::AuthStore) - end + @right["name"].should be_a_kind_of(Puppet::Network::AuthStore) end + end - describe "when creating new path ACLs" do - it "should not throw an error if the ACL already exists" do - @right.newright("/name") + describe "when creating new path ACLs" do + it "should not throw an error if the ACL already exists" do + @right.newright("/name") - lambda { @right.newright("/name")}.should_not raise_error - end + lambda { @right.newright("/name")}.should_not raise_error + end - it "should throw an error if the acl uri path is not absolute" do - lambda { @right.newright("name")}.should raise_error - end + it "should throw an error if the acl uri path is not absolute" do + lambda { @right.newright("name")}.should raise_error + end - it "should create a new ACL with the correct path" do - @right.newright("/name") + it "should create a new ACL with the correct path" do + @right.newright("/name") - @right["/name"].should_not be_nil - end + @right["/name"].should_not be_nil + end - it "should create an ACL of type Puppet::Network::AuthStore" do - @right.newright("/name") + it "should create an ACL of type Puppet::Network::AuthStore" do + @right.newright("/name") - @right["/name"].should be_a_kind_of(Puppet::Network::AuthStore) - end + @right["/name"].should be_a_kind_of(Puppet::Network::AuthStore) end + end - describe "when creating new regex ACLs" do - it "should not throw an error if the ACL already exists" do - @right.newright("~ .rb$") + describe "when creating new regex ACLs" do + it "should not throw an error if the ACL already exists" do + @right.newright("~ .rb$") - lambda { @right.newright("~ .rb$")}.should_not raise_error - end + lambda { @right.newright("~ .rb$")}.should_not raise_error + end - it "should create a new ACL with the correct regex" do - @right.newright("~ .rb$") + it "should create a new ACL with the correct regex" do + @right.newright("~ .rb$") - @right.include?(".rb$").should_not be_nil - end + @right.include?(".rb$").should_not be_nil + end - it "should be able to lookup the regex" do - @right.newright("~ .rb$") + it "should be able to lookup the regex" do + @right.newright("~ .rb$") - @right[".rb$"].should_not be_nil - end + @right[".rb$"].should_not be_nil + end - it "should be able to lookup the regex by its full name" do - @right.newright("~ .rb$") + it "should be able to lookup the regex by its full name" do + @right.newright("~ .rb$") - @right["~ .rb$"].should_not be_nil - end + @right["~ .rb$"].should_not be_nil + end - it "should create an ACL of type Puppet::Network::AuthStore" do - @right.newright("~ .rb$").should be_a_kind_of(Puppet::Network::AuthStore) - end + it "should create an ACL of type Puppet::Network::AuthStore" do + @right.newright("~ .rb$").should be_a_kind_of(Puppet::Network::AuthStore) end + end - describe "when checking ACLs existence" do - it "should return false if there are no matching rights" do - @right.include?("name").should be_false - end + describe "when checking ACLs existence" do + it "should return false if there are no matching rights" do + @right.include?("name").should be_false + end - it "should return true if a namespace rights exist" do - @right.newright("[name]") + it "should return true if a namespace rights exist" do + @right.newright("[name]") - @right.include?("name").should be_true - end + @right.include?("name").should be_true + end - it "should return false if no matching namespace rights exist" do - @right.newright("[name]") + it "should return false if no matching namespace rights exist" do + @right.newright("[name]") - @right.include?("notname").should be_false - end + @right.include?("notname").should be_false + end - it "should return true if a path right exists" do - @right.newright("/name") + it "should return true if a path right exists" do + @right.newright("/name") - @right.include?("/name").should be_true - end + @right.include?("/name").should be_true + end - it "should return false if no matching path rights exist" do - @right.newright("/name") + it "should return false if no matching path rights exist" do + @right.newright("/name") - @right.include?("/differentname").should be_false - end + @right.include?("/differentname").should be_false + end - it "should return true if a regex right exists" do - @right.newright("~ .rb$") + it "should return true if a regex right exists" do + @right.newright("~ .rb$") - @right.include?(".rb$").should be_true - end + @right.include?(".rb$").should be_true + end - it "should return false if no matching path rights exist" do - @right.newright("~ .rb$") + it "should return false if no matching path rights exist" do + @right.newright("~ .rb$") - @right.include?(".pp$").should be_false - end + @right.include?(".pp$").should be_false end + end - describe "when checking if right is allowed" do - before :each do - @right.stubs(:right).returns(nil) + describe "when checking if right is allowed" do + before :each do + @right.stubs(:right).returns(nil) - @pathacl = stub 'pathacl', :acl_type => :regex, :"<=>" => 1, :line => 0, :file => 'dummy' - Puppet::Network::Rights::Right.stubs(:new).returns(@pathacl) - end + @pathacl = stub 'pathacl', :acl_type => :regex, :"<=>" => 1, :line => 0, :file => 'dummy' + Puppet::Network::Rights::Right.stubs(:new).returns(@pathacl) + end - it "should delegate to fail_on_deny" do - @right.expects(:fail_on_deny).with("namespace", :node => "host.domain.com", :ip => "127.0.0.1") + it "should delegate to fail_on_deny" do + @right.expects(:fail_on_deny).with("namespace", :node => "host.domain.com", :ip => "127.0.0.1") - @right.allowed?("namespace", "host.domain.com", "127.0.0.1") - end + @right.allowed?("namespace", "host.domain.com", "127.0.0.1") + end - it "should return true if fail_on_deny doesn't fail" do - @right.stubs(:fail_on_deny) - @right.allowed?("namespace", :args).should be_true - end + it "should return true if fail_on_deny doesn't fail" do + @right.stubs(:fail_on_deny) + @right.allowed?("namespace", :args).should be_true + end - it "should return false if fail_on_deny raises an AuthorizationError" do - @right.stubs(:fail_on_deny).raises(Puppet::Network::AuthorizationError.new("forbidden")) - @right.allowed?("namespace", :args1, :args2).should be_false - end + it "should return false if fail_on_deny raises an AuthorizationError" do + @right.stubs(:fail_on_deny).raises(Puppet::Network::AuthorizationError.new("forbidden")) + @right.allowed?("namespace", :args1, :args2).should be_false + end - it "should first check namespace rights" do - acl = stub 'acl', :acl_type => :name, :key => :namespace - Puppet::Network::Rights::Right.stubs(:new).returns(acl) + it "should first check namespace rights" do + acl = stub 'acl', :acl_type => :name, :key => :namespace + Puppet::Network::Rights::Right.stubs(:new).returns(acl) - @right.newright("[namespace]") - acl.expects(:match?).returns(true) - acl.expects(:allowed?).with { |node,ip,h| node == "node" and ip == "ip" }.returns(true) + @right.newright("[namespace]") + acl.expects(:match?).returns(true) + acl.expects(:allowed?).with { |node,ip,h| node == "node" and ip == "ip" }.returns(true) - @right.fail_on_deny("namespace", { :node => "node", :ip => "ip" } ) - end + @right.fail_on_deny("namespace", { :node => "node", :ip => "ip" } ) + end - it "should then check for path rights if no namespace match" do - acl = stub 'nmacl', :acl_type => :name, :key => :namespace, :"<=>" => -1, :line => 0, :file => 'dummy' - acl.stubs(:match?).returns(false) - Puppet::Network::Rights::Right.stubs(:new).with("[namespace]").returns(acl) + it "should then check for path rights if no namespace match" do + acl = stub 'nmacl', :acl_type => :name, :key => :namespace, :"<=>" => -1, :line => 0, :file => 'dummy' + acl.stubs(:match?).returns(false) + Puppet::Network::Rights::Right.stubs(:new).with("[namespace]").returns(acl) - @right.newright("[namespace]") - @right.newright("/path/to/there", 0, nil) + @right.newright("[namespace]") + @right.newright("/path/to/there", 0, nil) - @pathacl.stubs(:match?).returns(true) + @pathacl.stubs(:match?).returns(true) - acl.expects(:allowed?).never - @pathacl.expects(:allowed?).returns(true) + acl.expects(:allowed?).never + @pathacl.expects(:allowed?).returns(true) - @right.fail_on_deny("/path/to/there", {}) - end + @right.fail_on_deny("/path/to/there", {}) + end - it "should pass the match? return to allowed?" do - @right.newright("/path/to/there") + it "should pass the match? return to allowed?" do + @right.newright("/path/to/there") - @pathacl.expects(:match?).returns(:match) - @pathacl.expects(:allowed?).with { |node,ip,h| h[:match] == :match }.returns(true) + @pathacl.expects(:match?).returns(:match) + @pathacl.expects(:allowed?).with { |node,ip,h| h[:match] == :match }.returns(true) - @right.fail_on_deny("/path/to/there", {}) - end + @right.fail_on_deny("/path/to/there", {}) + end - describe "with namespace acls" do - it "should raise an error if this namespace right doesn't exist" do - lambda{ @right.fail_on_deny("namespace") }.should raise_error - end - end + describe "with namespace acls" do + it "should raise an error if this namespace right doesn't exist" do + lambda{ @right.fail_on_deny("namespace") }.should raise_error + end + end - describe "with path acls" do - before :each do - @long_acl = stub 'longpathacl', :name => "/path/to/there", :acl_type => :regex, :line => 0, :file => 'dummy' - Puppet::Network::Rights::Right.stubs(:new).with("/path/to/there", 0, nil).returns(@long_acl) + describe "with path acls" do + before :each do + @long_acl = stub 'longpathacl', :name => "/path/to/there", :acl_type => :regex, :line => 0, :file => 'dummy' + Puppet::Network::Rights::Right.stubs(:new).with("/path/to/there", 0, nil).returns(@long_acl) - @short_acl = stub 'shortpathacl', :name => "/path/to", :acl_type => :regex, :line => 0, :file => 'dummy' - Puppet::Network::Rights::Right.stubs(:new).with("/path/to", 0, nil).returns(@short_acl) + @short_acl = stub 'shortpathacl', :name => "/path/to", :acl_type => :regex, :line => 0, :file => 'dummy' + Puppet::Network::Rights::Right.stubs(:new).with("/path/to", 0, nil).returns(@short_acl) - @long_acl.stubs(:"<=>").with(@short_acl).returns(0) - @short_acl.stubs(:"<=>").with(@long_acl).returns(0) - end + @long_acl.stubs(:"<=>").with(@short_acl).returns(0) + @short_acl.stubs(:"<=>").with(@long_acl).returns(0) + end - it "should select the first match" do - @right.newright("/path/to/there", 0) - @right.newright("/path/to", 0) + it "should select the first match" do + @right.newright("/path/to/there", 0) + @right.newright("/path/to", 0) - @long_acl.stubs(:match?).returns(true) - @short_acl.stubs(:match?).returns(true) + @long_acl.stubs(:match?).returns(true) + @short_acl.stubs(:match?).returns(true) - @long_acl.expects(:allowed?).returns(true) - @short_acl.expects(:allowed?).never + @long_acl.expects(:allowed?).returns(true) + @short_acl.expects(:allowed?).never - @right.fail_on_deny("/path/to/there/and/there", {}) - end + @right.fail_on_deny("/path/to/there/and/there", {}) + end - it "should select the first match that doesn't return :dunno" do - @right.newright("/path/to/there", 0, nil) - @right.newright("/path/to", 0, nil) + it "should select the first match that doesn't return :dunno" do + @right.newright("/path/to/there", 0, nil) + @right.newright("/path/to", 0, nil) - @long_acl.stubs(:match?).returns(true) - @short_acl.stubs(:match?).returns(true) + @long_acl.stubs(:match?).returns(true) + @short_acl.stubs(:match?).returns(true) - @long_acl.expects(:allowed?).returns(:dunno) - @short_acl.expects(:allowed?).returns(true) + @long_acl.expects(:allowed?).returns(:dunno) + @short_acl.expects(:allowed?).returns(true) - @right.fail_on_deny("/path/to/there/and/there", {}) - end + @right.fail_on_deny("/path/to/there/and/there", {}) + end - it "should not select an ACL that doesn't match" do - @right.newright("/path/to/there", 0) - @right.newright("/path/to", 0) + it "should not select an ACL that doesn't match" do + @right.newright("/path/to/there", 0) + @right.newright("/path/to", 0) - @long_acl.stubs(:match?).returns(false) - @short_acl.stubs(:match?).returns(true) + @long_acl.stubs(:match?).returns(false) + @short_acl.stubs(:match?).returns(true) - @long_acl.expects(:allowed?).never - @short_acl.expects(:allowed?).returns(true) + @long_acl.expects(:allowed?).never + @short_acl.expects(:allowed?).returns(true) - @right.fail_on_deny("/path/to/there/and/there", {}) - end + @right.fail_on_deny("/path/to/there/and/there", {}) + end - it "should not raise an AuthorizationError if allowed" do - @right.newright("/path/to/there", 0) + it "should not raise an AuthorizationError if allowed" do + @right.newright("/path/to/there", 0) - @long_acl.stubs(:match?).returns(true) - @long_acl.stubs(:allowed?).returns(true) + @long_acl.stubs(:match?).returns(true) + @long_acl.stubs(:allowed?).returns(true) - lambda { @right.fail_on_deny("/path/to/there/and/there", {}) }.should_not raise_error(Puppet::Network::AuthorizationError) - end + lambda { @right.fail_on_deny("/path/to/there/and/there", {}) }.should_not raise_error(Puppet::Network::AuthorizationError) + end - it "should raise an AuthorizationError if the match is denied" do - @right.newright("/path/to/there", 0, nil) + it "should raise an AuthorizationError if the match is denied" do + @right.newright("/path/to/there", 0, nil) - @long_acl.stubs(:match?).returns(true) - @long_acl.stubs(:allowed?).returns(false) + @long_acl.stubs(:match?).returns(true) + @long_acl.stubs(:allowed?).returns(false) - lambda{ @right.fail_on_deny("/path/to/there", {}) }.should raise_error(Puppet::Network::AuthorizationError) - end + lambda{ @right.fail_on_deny("/path/to/there", {}) }.should raise_error(Puppet::Network::AuthorizationError) + end - it "should raise an AuthorizationError if no path match" do - lambda { @right.fail_on_deny("/nomatch", {}) }.should raise_error(Puppet::Network::AuthorizationError) - end - end + it "should raise an AuthorizationError if no path match" do + lambda { @right.fail_on_deny("/nomatch", {}) }.should raise_error(Puppet::Network::AuthorizationError) + end + end - describe "with regex acls" do - before :each do - @regex_acl1 = stub 'regex_acl1', :name => "/files/(.*)/myfile", :acl_type => :regex, :line => 0, :file => 'dummy' - Puppet::Network::Rights::Right.stubs(:new).with("~ /files/(.*)/myfile", 0, nil).returns(@regex_acl1) + describe "with regex acls" do + before :each do + @regex_acl1 = stub 'regex_acl1', :name => "/files/(.*)/myfile", :acl_type => :regex, :line => 0, :file => 'dummy' + Puppet::Network::Rights::Right.stubs(:new).with("~ /files/(.*)/myfile", 0, nil).returns(@regex_acl1) - @regex_acl2 = stub 'regex_acl2', :name => "/files/(.*)/myfile/", :acl_type => :regex, :line => 0, :file => 'dummy' - Puppet::Network::Rights::Right.stubs(:new).with("~ /files/(.*)/myfile/", 0, nil).returns(@regex_acl2) + @regex_acl2 = stub 'regex_acl2', :name => "/files/(.*)/myfile/", :acl_type => :regex, :line => 0, :file => 'dummy' + Puppet::Network::Rights::Right.stubs(:new).with("~ /files/(.*)/myfile/", 0, nil).returns(@regex_acl2) - @regex_acl1.stubs(:"<=>").with(@regex_acl2).returns(0) - @regex_acl2.stubs(:"<=>").with(@regex_acl1).returns(0) - end + @regex_acl1.stubs(:"<=>").with(@regex_acl2).returns(0) + @regex_acl2.stubs(:"<=>").with(@regex_acl1).returns(0) + end - it "should select the first match" do - @right.newright("~ /files/(.*)/myfile", 0) - @right.newright("~ /files/(.*)/myfile/", 0) + it "should select the first match" do + @right.newright("~ /files/(.*)/myfile", 0) + @right.newright("~ /files/(.*)/myfile/", 0) - @regex_acl1.stubs(:match?).returns(true) - @regex_acl2.stubs(:match?).returns(true) + @regex_acl1.stubs(:match?).returns(true) + @regex_acl2.stubs(:match?).returns(true) - @regex_acl1.expects(:allowed?).returns(true) - @regex_acl2.expects(:allowed?).never + @regex_acl1.expects(:allowed?).returns(true) + @regex_acl2.expects(:allowed?).never - @right.fail_on_deny("/files/repository/myfile/other", {}) - end + @right.fail_on_deny("/files/repository/myfile/other", {}) + end - it "should select the first match that doesn't return :dunno" do - @right.newright("~ /files/(.*)/myfile", 0) - @right.newright("~ /files/(.*)/myfile/", 0) + it "should select the first match that doesn't return :dunno" do + @right.newright("~ /files/(.*)/myfile", 0) + @right.newright("~ /files/(.*)/myfile/", 0) - @regex_acl1.stubs(:match?).returns(true) - @regex_acl2.stubs(:match?).returns(true) + @regex_acl1.stubs(:match?).returns(true) + @regex_acl2.stubs(:match?).returns(true) - @regex_acl1.expects(:allowed?).returns(:dunno) - @regex_acl2.expects(:allowed?).returns(true) + @regex_acl1.expects(:allowed?).returns(:dunno) + @regex_acl2.expects(:allowed?).returns(true) - @right.fail_on_deny("/files/repository/myfile/other", {}) - end + @right.fail_on_deny("/files/repository/myfile/other", {}) + end - it "should not select an ACL that doesn't match" do - @right.newright("~ /files/(.*)/myfile", 0) - @right.newright("~ /files/(.*)/myfile/", 0) + it "should not select an ACL that doesn't match" do + @right.newright("~ /files/(.*)/myfile", 0) + @right.newright("~ /files/(.*)/myfile/", 0) - @regex_acl1.stubs(:match?).returns(false) - @regex_acl2.stubs(:match?).returns(true) + @regex_acl1.stubs(:match?).returns(false) + @regex_acl2.stubs(:match?).returns(true) - @regex_acl1.expects(:allowed?).never - @regex_acl2.expects(:allowed?).returns(true) + @regex_acl1.expects(:allowed?).never + @regex_acl2.expects(:allowed?).returns(true) - @right.fail_on_deny("/files/repository/myfile/other", {}) - end + @right.fail_on_deny("/files/repository/myfile/other", {}) + end - it "should not raise an AuthorizationError if allowed" do - @right.newright("~ /files/(.*)/myfile", 0) + it "should not raise an AuthorizationError if allowed" do + @right.newright("~ /files/(.*)/myfile", 0) - @regex_acl1.stubs(:match?).returns(true) - @regex_acl1.stubs(:allowed?).returns(true) + @regex_acl1.stubs(:match?).returns(true) + @regex_acl1.stubs(:allowed?).returns(true) - lambda { @right.fail_on_deny("/files/repository/myfile/other", {}) }.should_not raise_error(Puppet::Network::AuthorizationError) - end + lambda { @right.fail_on_deny("/files/repository/myfile/other", {}) }.should_not raise_error(Puppet::Network::AuthorizationError) + end - it "should raise an error if no regex acl match" do - lambda{ @right.fail_on_deny("/path", {}) }.should raise_error(Puppet::Network::AuthorizationError) - end + it "should raise an error if no regex acl match" do + lambda{ @right.fail_on_deny("/path", {}) }.should raise_error(Puppet::Network::AuthorizationError) + end - it "should raise an AuthorizedError on deny" do - lambda { @right.fail_on_deny("/path", {}) }.should raise_error(Puppet::Network::AuthorizationError) - end + it "should raise an AuthorizedError on deny" do + lambda { @right.fail_on_deny("/path", {}) }.should raise_error(Puppet::Network::AuthorizationError) + end - end end + end - describe Puppet::Network::Rights::Right do - before :each do - @acl = Puppet::Network::Rights::Right.new("/path",0, nil) - end + describe Puppet::Network::Rights::Right do + before :each do + @acl = Puppet::Network::Rights::Right.new("/path",0, nil) + end - describe "with path" do - it "should say it's a regex ACL" do - @acl.acl_type.should == :regex - end + describe "with path" do + it "should say it's a regex ACL" do + @acl.acl_type.should == :regex + end - it "should match up to its path length" do - @acl.match?("/path/that/works").should_not be_nil - end + it "should match up to its path length" do + @acl.match?("/path/that/works").should_not be_nil + end - it "should match up to its path length" do - @acl.match?("/paththatalsoworks").should_not be_nil - end + it "should match up to its path length" do + @acl.match?("/paththatalsoworks").should_not be_nil + end - it "should return nil if no match" do - @acl.match?("/notpath").should be_nil - end - end + it "should return nil if no match" do + @acl.match?("/notpath").should be_nil + end + end - describe "with regex" do - before :each do - @acl = Puppet::Network::Rights::Right.new("~ .rb$",0, nil) - end + describe "with regex" do + before :each do + @acl = Puppet::Network::Rights::Right.new("~ .rb$",0, nil) + end - it "should say it's a regex ACL" do - @acl.acl_type.should == :regex - end + it "should say it's a regex ACL" do + @acl.acl_type.should == :regex + end - it "should match as a regex" do - @acl.match?("this should work.rb").should_not be_nil - end + it "should match as a regex" do + @acl.match?("this should work.rb").should_not be_nil + end - it "should return nil if no match" do - @acl.match?("do not match").should be_nil - end - end + it "should return nil if no match" do + @acl.match?("do not match").should be_nil + end + end - it "should allow all rest methods by default" do - @acl.methods.should == Puppet::Network::Rights::Right::ALL - end + it "should allow all rest methods by default" do + @acl.methods.should == Puppet::Network::Rights::Right::ALL + end - it "should allow only authenticated request by default" do - @acl.authentication.should be_true - end + it "should allow only authenticated request by default" do + @acl.authentication.should be_true + end - it "should allow modification of the methods filters" do - @acl.restrict_method(:save) + it "should allow modification of the methods filters" do + @acl.restrict_method(:save) - @acl.methods.should == [:save] - end + @acl.methods.should == [:save] + end - it "should stack methods filters" do - @acl.restrict_method(:save) - @acl.restrict_method(:destroy) + it "should stack methods filters" do + @acl.restrict_method(:save) + @acl.restrict_method(:destroy) - @acl.methods.should == [:save, :destroy] - end + @acl.methods.should == [:save, :destroy] + end - it "should raise an error if the method is already filtered" do - @acl.restrict_method(:save) + it "should raise an error if the method is already filtered" do + @acl.restrict_method(:save) - lambda { @acl.restrict_method(:save) }.should raise_error - end + lambda { @acl.restrict_method(:save) }.should raise_error + end - it "should allow setting an environment filters" do - Puppet::Node::Environment.stubs(:new).with(:environment).returns(:env) + it "should allow setting an environment filters" do + Puppet::Node::Environment.stubs(:new).with(:environment).returns(:env) - @acl.restrict_environment(:environment) + @acl.restrict_environment(:environment) - @acl.environment.should == [:env] - end + @acl.environment.should == [:env] + end - ["on", "yes", "true", true].each do |auth| - it "should allow filtering on authenticated requests with '#{auth}'" do - @acl.restrict_authenticated(auth) + ["on", "yes", "true", true].each do |auth| + it "should allow filtering on authenticated requests with '#{auth}'" do + @acl.restrict_authenticated(auth) - @acl.authentication.should be_true - end - end + @acl.authentication.should be_true + end + end - ["off", "no", "false", false].each do |auth| - it "should allow filtering on unauthenticated requests with '#{auth}'" do - @acl.restrict_authenticated(auth) + ["off", "no", "false", false].each do |auth| + it "should allow filtering on unauthenticated requests with '#{auth}'" do + @acl.restrict_authenticated(auth) - @acl.authentication.should be_false - end - end + @acl.authentication.should be_false + end + end - ["all", "any", :all, :any].each do |auth| - it "should not use request authenticated state filtering with '#{auth}'" do - @acl.restrict_authenticated(auth) + ["all", "any", :all, :any].each do |auth| + it "should not use request authenticated state filtering with '#{auth}'" do + @acl.restrict_authenticated(auth) - @acl.authentication.should be_nil - end - end + @acl.authentication.should be_nil + end + end - describe "when checking right authorization" do - it "should return :dunno if this right is not restricted to the given method" do - @acl.restrict_method(:destroy) + describe "when checking right authorization" do + it "should return :dunno if this right is not restricted to the given method" do + @acl.restrict_method(:destroy) - @acl.allowed?("me","127.0.0.1", { :method => :save } ).should == :dunno - end + @acl.allowed?("me","127.0.0.1", { :method => :save } ).should == :dunno + end - it "should return allow/deny if this right is restricted to the given method" do - @acl.restrict_method(:save) - @acl.allow("127.0.0.1") + it "should return allow/deny if this right is restricted to the given method" do + @acl.restrict_method(:save) + @acl.allow("127.0.0.1") - @acl.allowed?("me","127.0.0.1", { :method => :save }).should be_true - end + @acl.allowed?("me","127.0.0.1", { :method => :save }).should be_true + end - it "should return :dunno if this right is not restricted to the given environment" do - Puppet::Node::Environment.stubs(:new).returns(:production) + it "should return :dunno if this right is not restricted to the given environment" do + Puppet::Node::Environment.stubs(:new).returns(:production) - @acl.restrict_environment(:production) + @acl.restrict_environment(:production) - @acl.allowed?("me","127.0.0.1", { :method => :save, :environment => :development }).should == :dunno - end + @acl.allowed?("me","127.0.0.1", { :method => :save, :environment => :development }).should == :dunno + end - it "should return :dunno if this right is not restricted to the given request authentication state" do - @acl.restrict_authenticated(true) + it "should return :dunno if this right is not restricted to the given request authentication state" do + @acl.restrict_authenticated(true) - @acl.allowed?("me","127.0.0.1", { :method => :save, :authenticated => false }).should == :dunno - end + @acl.allowed?("me","127.0.0.1", { :method => :save, :authenticated => false }).should == :dunno + end - it "should return allow/deny if this right is restricted to the given request authentication state" do - @acl.restrict_authenticated(false) - @acl.allow("127.0.0.1") + it "should return allow/deny if this right is restricted to the given request authentication state" do + @acl.restrict_authenticated(false) + @acl.allow("127.0.0.1") - @acl.allowed?("me","127.0.0.1", { :authenticated => false }).should be_true - end + @acl.allowed?("me","127.0.0.1", { :authenticated => false }).should be_true + end - it "should interpolate allow/deny patterns with the given match" do - @acl.expects(:interpolate).with(:match) + it "should interpolate allow/deny patterns with the given match" do + @acl.expects(:interpolate).with(:match) - @acl.allowed?("me","127.0.0.1", { :method => :save, :match => :match, :authenticated => true }) - end + @acl.allowed?("me","127.0.0.1", { :method => :save, :match => :match, :authenticated => true }) + end - it "should reset interpolation after the match" do - @acl.expects(:reset_interpolation) + it "should reset interpolation after the match" do + @acl.expects(:reset_interpolation) - @acl.allowed?("me","127.0.0.1", { :method => :save, :match => :match, :authenticated => true }) - end + @acl.allowed?("me","127.0.0.1", { :method => :save, :match => :match, :authenticated => true }) + end - # mocha doesn't allow testing super... - # it "should delegate to the AuthStore for the result" do - # @acl.method(:save) - # - # @acl.expects(:allowed?).with("me","127.0.0.1") - # - # @acl.allowed?("me","127.0.0.1", :save) - # end - end + # mocha doesn't allow testing super... + # it "should delegate to the AuthStore for the result" do + # @acl.method(:save) + # + # @acl.expects(:allowed?).with("me","127.0.0.1") + # + # @acl.allowed?("me","127.0.0.1", :save) + # end end + end end diff --git a/spec/unit/network/server_spec.rb b/spec/unit/network/server_spec.rb index 4ebbe0846..ccd9c082e 100755 --- a/spec/unit/network/server_spec.rb +++ b/spec/unit/network/server_spec.rb @@ -7,528 +7,528 @@ require File.dirname(__FILE__) + '/../../spec_helper' require 'puppet/network/server' describe Puppet::Network::Server do + before do + @mock_http_server_class = mock('http server class') + Puppet.settings.stubs(:use) + Puppet.settings.stubs(:value).with(:name).returns("me") + Puppet.settings.stubs(:value).with(:servertype).returns(:suparserver) + Puppet.settings.stubs(:value).with(:bindaddress).returns("") + Puppet.settings.stubs(:value).with(:masterport).returns(8140) + Puppet::Network::HTTP.stubs(:server_class_by_type).returns(@mock_http_server_class) + Puppet.settings.stubs(:value).with(:servertype).returns(:suparserver) + @server = Puppet::Network::Server.new(:port => 31337) + end + + describe "when initializing" do before do - @mock_http_server_class = mock('http server class') - Puppet.settings.stubs(:use) - Puppet.settings.stubs(:value).with(:name).returns("me") - Puppet.settings.stubs(:value).with(:servertype).returns(:suparserver) - Puppet.settings.stubs(:value).with(:bindaddress).returns("") - Puppet.settings.stubs(:value).with(:masterport).returns(8140) - Puppet::Network::HTTP.stubs(:server_class_by_type).returns(@mock_http_server_class) - Puppet.settings.stubs(:value).with(:servertype).returns(:suparserver) - @server = Puppet::Network::Server.new(:port => 31337) - end - - describe "when initializing" do - before do - Puppet::Indirector::Indirection.stubs(:model).returns mock('indirection') - Puppet::Network::Handler.stubs(:handler).returns mock('xmlrpc_handler') - Puppet.settings.stubs(:value).with(:bindaddress).returns("") - Puppet.settings.stubs(:value).with(:masterport).returns('') - end - - it 'should fail if an unknown option is provided' do - lambda { Puppet::Network::Server.new(:foo => 31337) }.should raise_error(ArgumentError) - end - - it "should allow specifying a listening port" do - Puppet.settings.stubs(:value).with(:bindaddress).returns('') - @server = Puppet::Network::Server.new(:port => 31337) - @server.port.should == 31337 - end - - it "should use the :bindaddress setting to determine the default listening address" do - Puppet.settings.stubs(:value).with(:masterport).returns('') - Puppet.settings.expects(:value).with(:bindaddress).returns("10.0.0.1") - @server = Puppet::Network::Server.new - @server.address.should == "10.0.0.1" - end - - it "should set the bind address to '127.0.0.1' if the default address is an empty string and the server type is mongrel" do - Puppet.settings.stubs(:value).with(:servertype).returns("mongrel") - Puppet.settings.expects(:value).with(:bindaddress).returns("") - @server = Puppet::Network::Server.new - @server.address.should == '127.0.0.1' - end - - it "should set the bind address to '0.0.0.0' if the default address is an empty string and the server type is webrick" do - Puppet.settings.stubs(:value).with(:servertype).returns("webrick") - Puppet.settings.expects(:value).with(:bindaddress).returns("") - @server = Puppet::Network::Server.new - @server.address.should == '0.0.0.0' - end - - it "should use the Puppet configurator to find a default listening port" do - Puppet.settings.stubs(:value).with(:bindaddress).returns('') - Puppet.settings.expects(:value).with(:masterport).returns(6667) - @server = Puppet::Network::Server.new - @server.port.should == 6667 - end - - it "should fail to initialize if no listening port can be found" do - Puppet.settings.stubs(:value).with(:bindaddress).returns("127.0.0.1") - Puppet.settings.stubs(:value).with(:masterport).returns(nil) - lambda { Puppet::Network::Server.new }.should raise_error(ArgumentError) - end - - it "should use the Puppet configurator to determine which HTTP server will be used to provide access to clients" do - Puppet.settings.expects(:value).with(:servertype).returns(:suparserver) - @server = Puppet::Network::Server.new(:port => 31337) - @server.server_type.should == :suparserver - end - - it "should fail to initialize if there is no HTTP server known to the Puppet configurator" do - Puppet.settings.expects(:value).with(:servertype).returns(nil) - lambda { Puppet::Network::Server.new(:port => 31337) }.should raise_error - end - - it "should ask the Puppet::Network::HTTP class to fetch the proper HTTP server class" do - Puppet::Network::HTTP.expects(:server_class_by_type).with(:suparserver).returns(@mock_http_server_class) - @server = Puppet::Network::Server.new(:port => 31337) - end - - it "should fail if the HTTP server class is unknown" do - Puppet::Network::HTTP.stubs(:server_class_by_type).returns(nil) - lambda { Puppet::Network::Server.new(:port => 31337) }.should raise_error(ArgumentError) - end - - it "should allow registering REST handlers" do - @server = Puppet::Network::Server.new(:port => 31337, :handlers => [ :foo, :bar, :baz]) - lambda { @server.unregister(:foo, :bar, :baz) }.should_not raise_error - end - - it "should allow registering XMLRPC handlers" do - @server = Puppet::Network::Server.new(:port => 31337, :xmlrpc_handlers => [ :foo, :bar, :baz]) - lambda { @server.unregister_xmlrpc(:foo, :bar, :baz) }.should_not raise_error - end - - it "should not be listening after initialization" do - Puppet::Network::Server.new(:port => 31337).should_not be_listening - end - - it "should use the :main setting section" do - Puppet.settings.expects(:use).with { |*args| args.include?(:main) } - @server = Puppet::Network::Server.new(:port => 31337, :xmlrpc_handlers => [ :foo, :bar, :baz]) - end - - it "should use the Puppet[:name] setting section" do - Puppet.settings.expects(:value).with(:name).returns "me" - Puppet.settings.expects(:use).with { |*args| args.include?("me") } - - @server = Puppet::Network::Server.new(:port => 31337, :xmlrpc_handlers => [ :foo, :bar, :baz]) - end + Puppet::Indirector::Indirection.stubs(:model).returns mock('indirection') + Puppet::Network::Handler.stubs(:handler).returns mock('xmlrpc_handler') + Puppet.settings.stubs(:value).with(:bindaddress).returns("") + Puppet.settings.stubs(:value).with(:masterport).returns('') end - # We don't test the method, because it's too much of a Unix-y pain. - it "should be able to daemonize" do - @server.should respond_to(:daemonize) - end - - describe "when being started" do - before do - @server.stubs(:listen) - @server.stubs(:create_pidfile) - end - - it "should listen" do - @server.expects(:listen) - @server.start - end + it 'should fail if an unknown option is provided' do + lambda { Puppet::Network::Server.new(:foo => 31337) }.should raise_error(ArgumentError) + end + + it "should allow specifying a listening port" do + Puppet.settings.stubs(:value).with(:bindaddress).returns('') + @server = Puppet::Network::Server.new(:port => 31337) + @server.port.should == 31337 + end + + it "should use the :bindaddress setting to determine the default listening address" do + Puppet.settings.stubs(:value).with(:masterport).returns('') + Puppet.settings.expects(:value).with(:bindaddress).returns("10.0.0.1") + @server = Puppet::Network::Server.new + @server.address.should == "10.0.0.1" + end + + it "should set the bind address to '127.0.0.1' if the default address is an empty string and the server type is mongrel" do + Puppet.settings.stubs(:value).with(:servertype).returns("mongrel") + Puppet.settings.expects(:value).with(:bindaddress).returns("") + @server = Puppet::Network::Server.new + @server.address.should == '127.0.0.1' + end - it "should create its PID file" do - @server.expects(:create_pidfile) - @server.start - end + it "should set the bind address to '0.0.0.0' if the default address is an empty string and the server type is webrick" do + Puppet.settings.stubs(:value).with(:servertype).returns("webrick") + Puppet.settings.expects(:value).with(:bindaddress).returns("") + @server = Puppet::Network::Server.new + @server.address.should == '0.0.0.0' end - describe "when being stopped" do - before do - @server.stubs(:unlisten) - @server.stubs(:remove_pidfile) - end + it "should use the Puppet configurator to find a default listening port" do + Puppet.settings.stubs(:value).with(:bindaddress).returns('') + Puppet.settings.expects(:value).with(:masterport).returns(6667) + @server = Puppet::Network::Server.new + @server.port.should == 6667 + end - it "should unlisten" do - @server.expects(:unlisten) - @server.stop - end + it "should fail to initialize if no listening port can be found" do + Puppet.settings.stubs(:value).with(:bindaddress).returns("127.0.0.1") + Puppet.settings.stubs(:value).with(:masterport).returns(nil) + lambda { Puppet::Network::Server.new }.should raise_error(ArgumentError) + end - it "should remove its PID file" do - @server.expects(:remove_pidfile) - @server.stop - end + it "should use the Puppet configurator to determine which HTTP server will be used to provide access to clients" do + Puppet.settings.expects(:value).with(:servertype).returns(:suparserver) + @server = Puppet::Network::Server.new(:port => 31337) + @server.server_type.should == :suparserver end - describe "when creating its pidfile" do - it "should use an exclusive mutex" do - Puppet.settings.expects(:value).with(:name).returns "me" + it "should fail to initialize if there is no HTTP server known to the Puppet configurator" do + Puppet.settings.expects(:value).with(:servertype).returns(nil) + lambda { Puppet::Network::Server.new(:port => 31337) }.should raise_error + end - sync = mock 'sync' - Puppet::Util.expects(:sync).with("me").returns sync + it "should ask the Puppet::Network::HTTP class to fetch the proper HTTP server class" do + Puppet::Network::HTTP.expects(:server_class_by_type).with(:suparserver).returns(@mock_http_server_class) + @server = Puppet::Network::Server.new(:port => 31337) + end - sync.expects(:synchronize).with(Sync::EX) - @server.create_pidfile - end + it "should fail if the HTTP server class is unknown" do + Puppet::Network::HTTP.stubs(:server_class_by_type).returns(nil) + lambda { Puppet::Network::Server.new(:port => 31337) }.should raise_error(ArgumentError) + end - it "should lock the pidfile using the Pidlock class" do - pidfile = mock 'pidfile' + it "should allow registering REST handlers" do + @server = Puppet::Network::Server.new(:port => 31337, :handlers => [ :foo, :bar, :baz]) + lambda { @server.unregister(:foo, :bar, :baz) }.should_not raise_error + end - Puppet.settings.stubs(:value).with(:name).returns "eh" - Puppet.settings.expects(:value).with(:pidfile).returns "/my/file" + it "should allow registering XMLRPC handlers" do + @server = Puppet::Network::Server.new(:port => 31337, :xmlrpc_handlers => [ :foo, :bar, :baz]) + lambda { @server.unregister_xmlrpc(:foo, :bar, :baz) }.should_not raise_error + end + + it "should not be listening after initialization" do + Puppet::Network::Server.new(:port => 31337).should_not be_listening + end + + it "should use the :main setting section" do + Puppet.settings.expects(:use).with { |*args| args.include?(:main) } + @server = Puppet::Network::Server.new(:port => 31337, :xmlrpc_handlers => [ :foo, :bar, :baz]) + end + + it "should use the Puppet[:name] setting section" do + Puppet.settings.expects(:value).with(:name).returns "me" + Puppet.settings.expects(:use).with { |*args| args.include?("me") } + + @server = Puppet::Network::Server.new(:port => 31337, :xmlrpc_handlers => [ :foo, :bar, :baz]) + end + end + + # We don't test the method, because it's too much of a Unix-y pain. + it "should be able to daemonize" do + @server.should respond_to(:daemonize) + end + + describe "when being started" do + before do + @server.stubs(:listen) + @server.stubs(:create_pidfile) + end + + it "should listen" do + @server.expects(:listen) + @server.start + end - Puppet::Util::Pidlock.expects(:new).with("/my/file").returns pidfile + it "should create its PID file" do + @server.expects(:create_pidfile) + @server.start + end + end - pidfile.expects(:lock).returns true - @server.create_pidfile - end + describe "when being stopped" do + before do + @server.stubs(:unlisten) + @server.stubs(:remove_pidfile) + end - it "should fail if it cannot lock" do - pidfile = mock 'pidfile' + it "should unlisten" do + @server.expects(:unlisten) + @server.stop + end - Puppet.settings.stubs(:value).with(:name).returns "eh" - Puppet.settings.stubs(:value).with(:pidfile).returns "/my/file" + it "should remove its PID file" do + @server.expects(:remove_pidfile) + @server.stop + end + end - Puppet::Util::Pidlock.expects(:new).with("/my/file").returns pidfile + describe "when creating its pidfile" do + it "should use an exclusive mutex" do + Puppet.settings.expects(:value).with(:name).returns "me" - pidfile.expects(:lock).returns false + sync = mock 'sync' + Puppet::Util.expects(:sync).with("me").returns sync - lambda { @server.create_pidfile }.should raise_error - end + sync.expects(:synchronize).with(Sync::EX) + @server.create_pidfile end - describe "when removing its pidfile" do - it "should use an exclusive mutex" do - Puppet.settings.expects(:value).with(:name).returns "me" + it "should lock the pidfile using the Pidlock class" do + pidfile = mock 'pidfile' - sync = mock 'sync' - Puppet::Util.expects(:sync).with("me").returns sync + Puppet.settings.stubs(:value).with(:name).returns "eh" + Puppet.settings.expects(:value).with(:pidfile).returns "/my/file" - sync.expects(:synchronize).with(Sync::EX) - @server.remove_pidfile - end + Puppet::Util::Pidlock.expects(:new).with("/my/file").returns pidfile - it "should do nothing if the pidfile is not present" do - pidfile = mock 'pidfile', :locked? => false - Puppet::Util::Pidlock.expects(:new).with("/my/file").returns pidfile + pidfile.expects(:lock).returns true + @server.create_pidfile + end - Puppet.settings.stubs(:value).with(:name).returns "eh" - Puppet.settings.stubs(:value).with(:pidfile).returns "/my/file" + it "should fail if it cannot lock" do + pidfile = mock 'pidfile' - pidfile.expects(:unlock).never - @server.remove_pidfile - end + Puppet.settings.stubs(:value).with(:name).returns "eh" + Puppet.settings.stubs(:value).with(:pidfile).returns "/my/file" - it "should unlock the pidfile using the Pidlock class" do - pidfile = mock 'pidfile', :locked? => true - Puppet::Util::Pidlock.expects(:new).with("/my/file").returns pidfile - pidfile.expects(:unlock).returns true + Puppet::Util::Pidlock.expects(:new).with("/my/file").returns pidfile - Puppet.settings.stubs(:value).with(:name).returns "eh" - Puppet.settings.stubs(:value).with(:pidfile).returns "/my/file" + pidfile.expects(:lock).returns false - @server.remove_pidfile - end + lambda { @server.create_pidfile }.should raise_error + end + end - it "should warn if it cannot remove the pidfile" do - pidfile = mock 'pidfile', :locked? => true - Puppet::Util::Pidlock.expects(:new).with("/my/file").returns pidfile - pidfile.expects(:unlock).returns false + describe "when removing its pidfile" do + it "should use an exclusive mutex" do + Puppet.settings.expects(:value).with(:name).returns "me" - Puppet.settings.stubs(:value).with(:name).returns "eh" - Puppet.settings.stubs(:value).with(:pidfile).returns "/my/file" + sync = mock 'sync' + Puppet::Util.expects(:sync).with("me").returns sync - Puppet.expects :err - @server.remove_pidfile - end + sync.expects(:synchronize).with(Sync::EX) + @server.remove_pidfile end - describe "when managing indirection registrations" do - before do - Puppet::Indirector::Indirection.stubs(:model).returns mock('indirection') - end + it "should do nothing if the pidfile is not present" do + pidfile = mock 'pidfile', :locked? => false + Puppet::Util::Pidlock.expects(:new).with("/my/file").returns pidfile - it "should allow registering an indirection for client access by specifying its indirection name" do - lambda { @server.register(:foo) }.should_not raise_error - end + Puppet.settings.stubs(:value).with(:name).returns "eh" + Puppet.settings.stubs(:value).with(:pidfile).returns "/my/file" - it "should require that the indirection be valid" do - Puppet::Indirector::Indirection.expects(:model).with(:foo).returns nil - lambda { @server.register(:foo) }.should raise_error(ArgumentError) - end + pidfile.expects(:unlock).never + @server.remove_pidfile + end - it "should require at least one indirection name when registering indirections for client access" do - lambda { @server.register }.should raise_error(ArgumentError) - end + it "should unlock the pidfile using the Pidlock class" do + pidfile = mock 'pidfile', :locked? => true + Puppet::Util::Pidlock.expects(:new).with("/my/file").returns pidfile + pidfile.expects(:unlock).returns true - it "should allow for numerous indirections to be registered at once for client access" do - lambda { @server.register(:foo, :bar, :baz) }.should_not raise_error - end + Puppet.settings.stubs(:value).with(:name).returns "eh" + Puppet.settings.stubs(:value).with(:pidfile).returns "/my/file" - it "should allow the use of indirection names to specify which indirections are to be no longer accessible to clients" do - @server.register(:foo) - lambda { @server.unregister(:foo) }.should_not raise_error - end + @server.remove_pidfile + end - it "should leave other indirections accessible to clients when turning off indirections" do - @server.register(:foo, :bar) - @server.unregister(:foo) - lambda { @server.unregister(:bar)}.should_not raise_error - end + it "should warn if it cannot remove the pidfile" do + pidfile = mock 'pidfile', :locked? => true + Puppet::Util::Pidlock.expects(:new).with("/my/file").returns pidfile + pidfile.expects(:unlock).returns false - it "should allow specifying numerous indirections which are to be no longer accessible to clients" do - @server.register(:foo, :bar) - lambda { @server.unregister(:foo, :bar) }.should_not raise_error - end + Puppet.settings.stubs(:value).with(:name).returns "eh" + Puppet.settings.stubs(:value).with(:pidfile).returns "/my/file" - it "should not turn off any indirections if given unknown indirection names to turn off" do - @server.register(:foo, :bar) - lambda { @server.unregister(:foo, :bar, :baz) }.should raise_error(ArgumentError) - lambda { @server.unregister(:foo, :bar) }.should_not raise_error - end + Puppet.expects :err + @server.remove_pidfile + end + end - it "should not allow turning off unknown indirection names" do - @server.register(:foo, :bar) - lambda { @server.unregister(:baz) }.should raise_error(ArgumentError) - end + describe "when managing indirection registrations" do + before do + Puppet::Indirector::Indirection.stubs(:model).returns mock('indirection') + end - it "should disable client access immediately when turning off indirections" do - @server.register(:foo, :bar) - @server.unregister(:foo) - lambda { @server.unregister(:foo) }.should raise_error(ArgumentError) - end + it "should allow registering an indirection for client access by specifying its indirection name" do + lambda { @server.register(:foo) }.should_not raise_error + end - it "should allow turning off all indirections at once" do - @server.register(:foo, :bar) - @server.unregister - [ :foo, :bar, :baz].each do |indirection| - lambda { @server.unregister(indirection) }.should raise_error(ArgumentError) - end - end + it "should require that the indirection be valid" do + Puppet::Indirector::Indirection.expects(:model).with(:foo).returns nil + lambda { @server.register(:foo) }.should raise_error(ArgumentError) end - it "should provide a means of determining whether it is listening" do - @server.should respond_to(:listening?) + it "should require at least one indirection name when registering indirections for client access" do + lambda { @server.register }.should raise_error(ArgumentError) end - it "should provide a means of determining which HTTP server will be used to provide access to clients" do - @server.server_type.should == :suparserver + it "should allow for numerous indirections to be registered at once for client access" do + lambda { @server.register(:foo, :bar, :baz) }.should_not raise_error end - it "should provide a means of determining which protocols are in use" do - @server.should respond_to(:protocols) + it "should allow the use of indirection names to specify which indirections are to be no longer accessible to clients" do + @server.register(:foo) + lambda { @server.unregister(:foo) }.should_not raise_error end - it "should set the protocols to :rest and :xmlrpc" do - @server.protocols.should == [ :rest, :xmlrpc ] + it "should leave other indirections accessible to clients when turning off indirections" do + @server.register(:foo, :bar) + @server.unregister(:foo) + lambda { @server.unregister(:bar)}.should_not raise_error end - it "should provide a means of determining the listening address" do - @server.address.should == "127.0.0.1" + it "should allow specifying numerous indirections which are to be no longer accessible to clients" do + @server.register(:foo, :bar) + lambda { @server.unregister(:foo, :bar) }.should_not raise_error end - it "should provide a means of determining the listening port" do - @server.port.should == 31337 + it "should not turn off any indirections if given unknown indirection names to turn off" do + @server.register(:foo, :bar) + lambda { @server.unregister(:foo, :bar, :baz) }.should raise_error(ArgumentError) + lambda { @server.unregister(:foo, :bar) }.should_not raise_error end - it "should allow for multiple configurations, each handling different indirections" do - Puppet::Indirector::Indirection.stubs(:model).returns mock('indirection') + it "should not allow turning off unknown indirection names" do + @server.register(:foo, :bar) + lambda { @server.unregister(:baz) }.should raise_error(ArgumentError) + end - @server2 = Puppet::Network::Server.new(:port => 31337) - @server.register(:foo, :bar) - @server2.register(:foo, :xyzzy) - @server.unregister(:foo, :bar) - @server2.unregister(:foo, :xyzzy) - lambda { @server.unregister(:xyzzy) }.should raise_error(ArgumentError) - lambda { @server2.unregister(:bar) }.should raise_error(ArgumentError) + it "should disable client access immediately when turning off indirections" do + @server.register(:foo, :bar) + @server.unregister(:foo) + lambda { @server.unregister(:foo) }.should raise_error(ArgumentError) end - describe "when managing xmlrpc registrations" do - before do - Puppet::Network::Handler.stubs(:handler).returns mock('xmlrpc_handler') - end + it "should allow turning off all indirections at once" do + @server.register(:foo, :bar) + @server.unregister + [ :foo, :bar, :baz].each do |indirection| + lambda { @server.unregister(indirection) }.should raise_error(ArgumentError) + end + end + end - it "should allow registering an xmlrpc handler by specifying its namespace" do - lambda { @server.register_xmlrpc(:foo) }.should_not raise_error - end + it "should provide a means of determining whether it is listening" do + @server.should respond_to(:listening?) + end - it "should require that the xmlrpc namespace be valid" do - Puppet::Network::Handler.stubs(:handler).returns nil + it "should provide a means of determining which HTTP server will be used to provide access to clients" do + @server.server_type.should == :suparserver + end - lambda { @server.register_xmlrpc(:foo) }.should raise_error(ArgumentError) - end + it "should provide a means of determining which protocols are in use" do + @server.should respond_to(:protocols) + end - it "should require at least one namespace" do - lambda { @server.register_xmlrpc }.should raise_error(ArgumentError) - end + it "should set the protocols to :rest and :xmlrpc" do + @server.protocols.should == [ :rest, :xmlrpc ] + end - it "should allow multiple namespaces to be registered at once" do - lambda { @server.register_xmlrpc(:foo, :bar) }.should_not raise_error - end + it "should provide a means of determining the listening address" do + @server.address.should == "127.0.0.1" + end - it "should allow the use of namespaces to specify which are no longer accessible to clients" do - @server.register_xmlrpc(:foo, :bar) - end + it "should provide a means of determining the listening port" do + @server.port.should == 31337 + end - it "should leave other namespaces accessible to clients when turning off xmlrpc namespaces" do - @server.register_xmlrpc(:foo, :bar) - @server.unregister_xmlrpc(:foo) - lambda { @server.unregister_xmlrpc(:bar)}.should_not raise_error - end + it "should allow for multiple configurations, each handling different indirections" do + Puppet::Indirector::Indirection.stubs(:model).returns mock('indirection') - it "should allow specifying numerous namespaces which are to be no longer accessible to clients" do - @server.register_xmlrpc(:foo, :bar) - lambda { @server.unregister_xmlrpc(:foo, :bar) }.should_not raise_error - end + @server2 = Puppet::Network::Server.new(:port => 31337) + @server.register(:foo, :bar) + @server2.register(:foo, :xyzzy) + @server.unregister(:foo, :bar) + @server2.unregister(:foo, :xyzzy) + lambda { @server.unregister(:xyzzy) }.should raise_error(ArgumentError) + lambda { @server2.unregister(:bar) }.should raise_error(ArgumentError) + end - it "should not turn off any indirections if given unknown namespaces to turn off" do - @server.register_xmlrpc(:foo, :bar) - lambda { @server.unregister_xmlrpc(:foo, :bar, :baz) }.should raise_error(ArgumentError) - lambda { @server.unregister_xmlrpc(:foo, :bar) }.should_not raise_error - end + describe "when managing xmlrpc registrations" do + before do + Puppet::Network::Handler.stubs(:handler).returns mock('xmlrpc_handler') + end - it "should not allow turning off unknown namespaces" do - @server.register_xmlrpc(:foo, :bar) - lambda { @server.unregister_xmlrpc(:baz) }.should raise_error(ArgumentError) - end + it "should allow registering an xmlrpc handler by specifying its namespace" do + lambda { @server.register_xmlrpc(:foo) }.should_not raise_error + end - it "should disable client access immediately when turning off namespaces" do - @server.register_xmlrpc(:foo, :bar) - @server.unregister_xmlrpc(:foo) - lambda { @server.unregister_xmlrpc(:foo) }.should raise_error(ArgumentError) - end + it "should require that the xmlrpc namespace be valid" do + Puppet::Network::Handler.stubs(:handler).returns nil - it "should allow turning off all namespaces at once" do - @server.register_xmlrpc(:foo, :bar) - @server.unregister_xmlrpc - [ :foo, :bar, :baz].each do |indirection| - lambda { @server.unregister_xmlrpc(indirection) }.should raise_error(ArgumentError) - end - end + lambda { @server.register_xmlrpc(:foo) }.should raise_error(ArgumentError) end - - describe "when listening is off" do - before do - @mock_http_server = mock('http server') - @mock_http_server.stubs(:listen) - @server.stubs(:http_server).returns(@mock_http_server) - end - - it "should indicate that it is not listening" do - @server.should_not be_listening - end - - it "should not allow listening to be turned off" do - lambda { @server.unlisten }.should raise_error(RuntimeError) - end - - it "should allow listening to be turned on" do - lambda { @server.listen }.should_not raise_error - end - - end - - describe "when listening is on" do - before do - @mock_http_server = mock('http server') - @mock_http_server.stubs(:listen) - @mock_http_server.stubs(:unlisten) - @server.stubs(:http_server).returns(@mock_http_server) - @server.listen - end - - it "should indicate that it is listening" do - @server.should be_listening - end - - it "should not allow listening to be turned on" do - lambda { @server.listen }.should raise_error(RuntimeError) - end - - it "should allow listening to be turned off" do - lambda { @server.unlisten }.should_not raise_error - end - end - - describe "when listening is being turned on" do - before do - Puppet::Indirector::Indirection.stubs(:model).returns mock('indirection') - Puppet::Network::Handler.stubs(:handler).returns mock('xmlrpc_handler') - - @server = Puppet::Network::Server.new(:port => 31337, :handlers => [:node], :xmlrpc_handlers => [:master]) - @mock_http_server = mock('http server') - @mock_http_server.stubs(:listen) - end - - it "should fetch an instance of an HTTP server" do - @server.stubs(:http_server_class).returns(@mock_http_server_class) - @mock_http_server_class.expects(:new).returns(@mock_http_server) - @server.listen - end - - it "should cause the HTTP server to listen" do - @server.stubs(:http_server).returns(@mock_http_server) - @mock_http_server.expects(:listen) - @server.listen - end - - it "should pass the listening address to the HTTP server" do - @server.stubs(:http_server).returns(@mock_http_server) - @mock_http_server.expects(:listen).with do |args| - args[:address] == '127.0.0.1' - end - @server.listen - end - - it "should pass the listening port to the HTTP server" do - @server.stubs(:http_server).returns(@mock_http_server) - @mock_http_server.expects(:listen).with do |args| - args[:port] == 31337 - end - @server.listen - end - - it "should pass a list of REST handlers to the HTTP server" do - @server.stubs(:http_server).returns(@mock_http_server) - @mock_http_server.expects(:listen).with do |args| - args[:handlers] == [ :node ] - end - @server.listen - end - - it "should pass a list of XMLRPC handlers to the HTTP server" do - @server.stubs(:http_server).returns(@mock_http_server) - @mock_http_server.expects(:listen).with do |args| - args[:xmlrpc_handlers] == [ :master ] - end - @server.listen - end - - it "should pass a list of protocols to the HTTP server" do - @server.stubs(:http_server).returns(@mock_http_server) - @mock_http_server.expects(:listen).with do |args| - args[:protocols] == [ :rest, :xmlrpc ] - end - @server.listen - end - end - - describe "when listening is being turned off" do - before do - @mock_http_server = mock('http server') - @mock_http_server.stubs(:listen) - @server.stubs(:http_server).returns(@mock_http_server) - @server.listen - end - - it "should cause the HTTP server to stop listening" do - @mock_http_server.expects(:unlisten) - @server.unlisten - end - - it "should not allow for indirections to be turned off" do - Puppet::Indirector::Indirection.stubs(:model).returns mock('indirection') - - @server.register(:foo) - lambda { @server.unregister(:foo) }.should raise_error(RuntimeError) - end + + it "should require at least one namespace" do + lambda { @server.register_xmlrpc }.should raise_error(ArgumentError) + end + + it "should allow multiple namespaces to be registered at once" do + lambda { @server.register_xmlrpc(:foo, :bar) }.should_not raise_error + end + + it "should allow the use of namespaces to specify which are no longer accessible to clients" do + @server.register_xmlrpc(:foo, :bar) + end + + it "should leave other namespaces accessible to clients when turning off xmlrpc namespaces" do + @server.register_xmlrpc(:foo, :bar) + @server.unregister_xmlrpc(:foo) + lambda { @server.unregister_xmlrpc(:bar)}.should_not raise_error + end + + it "should allow specifying numerous namespaces which are to be no longer accessible to clients" do + @server.register_xmlrpc(:foo, :bar) + lambda { @server.unregister_xmlrpc(:foo, :bar) }.should_not raise_error + end + + it "should not turn off any indirections if given unknown namespaces to turn off" do + @server.register_xmlrpc(:foo, :bar) + lambda { @server.unregister_xmlrpc(:foo, :bar, :baz) }.should raise_error(ArgumentError) + lambda { @server.unregister_xmlrpc(:foo, :bar) }.should_not raise_error + end + + it "should not allow turning off unknown namespaces" do + @server.register_xmlrpc(:foo, :bar) + lambda { @server.unregister_xmlrpc(:baz) }.should raise_error(ArgumentError) + end + + it "should disable client access immediately when turning off namespaces" do + @server.register_xmlrpc(:foo, :bar) + @server.unregister_xmlrpc(:foo) + lambda { @server.unregister_xmlrpc(:foo) }.should raise_error(ArgumentError) + end + + it "should allow turning off all namespaces at once" do + @server.register_xmlrpc(:foo, :bar) + @server.unregister_xmlrpc + [ :foo, :bar, :baz].each do |indirection| + lambda { @server.unregister_xmlrpc(indirection) }.should raise_error(ArgumentError) + end + end + end + + describe "when listening is off" do + before do + @mock_http_server = mock('http server') + @mock_http_server.stubs(:listen) + @server.stubs(:http_server).returns(@mock_http_server) + end + + it "should indicate that it is not listening" do + @server.should_not be_listening + end + + it "should not allow listening to be turned off" do + lambda { @server.unlisten }.should raise_error(RuntimeError) + end + + it "should allow listening to be turned on" do + lambda { @server.listen }.should_not raise_error + end + + end + + describe "when listening is on" do + before do + @mock_http_server = mock('http server') + @mock_http_server.stubs(:listen) + @mock_http_server.stubs(:unlisten) + @server.stubs(:http_server).returns(@mock_http_server) + @server.listen + end + + it "should indicate that it is listening" do + @server.should be_listening + end + + it "should not allow listening to be turned on" do + lambda { @server.listen }.should raise_error(RuntimeError) + end + + it "should allow listening to be turned off" do + lambda { @server.unlisten }.should_not raise_error + end + end + + describe "when listening is being turned on" do + before do + Puppet::Indirector::Indirection.stubs(:model).returns mock('indirection') + Puppet::Network::Handler.stubs(:handler).returns mock('xmlrpc_handler') + + @server = Puppet::Network::Server.new(:port => 31337, :handlers => [:node], :xmlrpc_handlers => [:master]) + @mock_http_server = mock('http server') + @mock_http_server.stubs(:listen) + end + + it "should fetch an instance of an HTTP server" do + @server.stubs(:http_server_class).returns(@mock_http_server_class) + @mock_http_server_class.expects(:new).returns(@mock_http_server) + @server.listen + end + + it "should cause the HTTP server to listen" do + @server.stubs(:http_server).returns(@mock_http_server) + @mock_http_server.expects(:listen) + @server.listen + end + + it "should pass the listening address to the HTTP server" do + @server.stubs(:http_server).returns(@mock_http_server) + @mock_http_server.expects(:listen).with do |args| + args[:address] == '127.0.0.1' + end + @server.listen + end + + it "should pass the listening port to the HTTP server" do + @server.stubs(:http_server).returns(@mock_http_server) + @mock_http_server.expects(:listen).with do |args| + args[:port] == 31337 + end + @server.listen + end + + it "should pass a list of REST handlers to the HTTP server" do + @server.stubs(:http_server).returns(@mock_http_server) + @mock_http_server.expects(:listen).with do |args| + args[:handlers] == [ :node ] + end + @server.listen + end + + it "should pass a list of XMLRPC handlers to the HTTP server" do + @server.stubs(:http_server).returns(@mock_http_server) + @mock_http_server.expects(:listen).with do |args| + args[:xmlrpc_handlers] == [ :master ] + end + @server.listen + end + + it "should pass a list of protocols to the HTTP server" do + @server.stubs(:http_server).returns(@mock_http_server) + @mock_http_server.expects(:listen).with do |args| + args[:protocols] == [ :rest, :xmlrpc ] + end + @server.listen + end + end + + describe "when listening is being turned off" do + before do + @mock_http_server = mock('http server') + @mock_http_server.stubs(:listen) + @server.stubs(:http_server).returns(@mock_http_server) + @server.listen + end + + it "should cause the HTTP server to stop listening" do + @mock_http_server.expects(:unlisten) + @server.unlisten + end + + it "should not allow for indirections to be turned off" do + Puppet::Indirector::Indirection.stubs(:model).returns mock('indirection') + + @server.register(:foo) + lambda { @server.unregister(:foo) }.should raise_error(RuntimeError) end + end end diff --git a/spec/unit/network/xmlrpc/client_spec.rb b/spec/unit/network/xmlrpc/client_spec.rb index 1b97583a7..0b9b2b095 100755 --- a/spec/unit/network/xmlrpc/client_spec.rb +++ b/spec/unit/network/xmlrpc/client_spec.rb @@ -3,169 +3,169 @@ Dir.chdir(File.dirname(__FILE__)) { (s = lambda { |f| File.exist?(f) ? require(f) : Dir.chdir("..") { s.call(f) } }).call("spec/spec_helper.rb") } describe Puppet::Network::XMLRPCClient do - describe "when performing the rpc call" do - before do - Puppet::SSL::Host.any_instance.stubs(:certificate_matches_key?).returns true - @client = Puppet::Network::Client.report.xmlrpc_client.new - @client.stubs(:call).returns "foo" - end + describe "when performing the rpc call" do + before do + Puppet::SSL::Host.any_instance.stubs(:certificate_matches_key?).returns true + @client = Puppet::Network::Client.report.xmlrpc_client.new + @client.stubs(:call).returns "foo" + end - it "should call the specified namespace and method, with the specified arguments" do - @client.expects(:call).with("puppetreports.report", "eh").returns "foo" - @client.report("eh") - end + it "should call the specified namespace and method, with the specified arguments" do + @client.expects(:call).with("puppetreports.report", "eh").returns "foo" + @client.report("eh") + end - it "should return the results from the call" do - @client.expects(:call).returns "foo" - @client.report("eh").should == "foo" - end + it "should return the results from the call" do + @client.expects(:call).returns "foo" + @client.report("eh").should == "foo" + end - it "should always close the http connection if it is still open after the call" do - http = mock 'http' - @client.stubs(:http).returns http + it "should always close the http connection if it is still open after the call" do + http = mock 'http' + @client.stubs(:http).returns http - http.expects(:started?).returns true - http.expects(:finish) + http.expects(:started?).returns true + http.expects(:finish) - @client.report("eh").should == "foo" - end + @client.report("eh").should == "foo" + end - it "should always close the http connection if it is still open after a call that raises an exception" do - http = mock 'http' - @client.stubs(:http).returns http + it "should always close the http connection if it is still open after a call that raises an exception" do + http = mock 'http' + @client.stubs(:http).returns http - @client.expects(:call).raises RuntimeError + @client.expects(:call).raises RuntimeError - http.expects(:started?).returns true - http.expects(:finish) + http.expects(:started?).returns true + http.expects(:finish) - lambda { @client.report("eh") }.should raise_error - end + lambda { @client.report("eh") }.should raise_error + end - describe "when returning the http instance" do - it "should use the http pool to create the instance" do - @client.instance_variable_set("@http", nil) - @client.expects(:host).returns "myhost" - @client.expects(:port).returns "myport" - Puppet::Network::HttpPool.expects(:http_instance).with("myhost", "myport", true).returns "http" + describe "when returning the http instance" do + it "should use the http pool to create the instance" do + @client.instance_variable_set("@http", nil) + @client.expects(:host).returns "myhost" + @client.expects(:port).returns "myport" + Puppet::Network::HttpPool.expects(:http_instance).with("myhost", "myport", true).returns "http" - @client.http.should == "http" - end + @client.http.should == "http" + end - it "should reuse existing instances" do - @client.http.should equal(@client.http) - end - end + it "should reuse existing instances" do + @client.http.should equal(@client.http) + end + end - describe "when recycling the connection" do - it "should close the existing instance if it's open" do - http = mock 'http' - @client.stubs(:http).returns http + describe "when recycling the connection" do + it "should close the existing instance if it's open" do + http = mock 'http' + @client.stubs(:http).returns http - http.expects(:started?).returns true - http.expects(:finish) + http.expects(:started?).returns true + http.expects(:finish) - @client.recycle_connection - end + @client.recycle_connection + end - it "should force creation of a new instance" do - Puppet::Network::HttpPool.expects(:http_instance).returns "second_http" + it "should force creation of a new instance" do + Puppet::Network::HttpPool.expects(:http_instance).returns "second_http" - @client.recycle_connection + @client.recycle_connection - @client.http.should == "second_http" - end - end + @client.http.should == "second_http" + end + end - describe "and an exception is raised" do - it "should raise XMLRPCClientError if XMLRPC::FaultException is raised" do - error = XMLRPC::FaultException.new("foo", "bar") + describe "and an exception is raised" do + it "should raise XMLRPCClientError if XMLRPC::FaultException is raised" do + error = XMLRPC::FaultException.new("foo", "bar") - @client.expects(:call).raises(error) + @client.expects(:call).raises(error) - lambda { @client.report("eh") }.should raise_error(Puppet::Network::XMLRPCClientError) - end + lambda { @client.report("eh") }.should raise_error(Puppet::Network::XMLRPCClientError) + end - it "should raise XMLRPCClientError if Errno::ECONNREFUSED is raised" do - @client.expects(:call).raises(Errno::ECONNREFUSED) + it "should raise XMLRPCClientError if Errno::ECONNREFUSED is raised" do + @client.expects(:call).raises(Errno::ECONNREFUSED) - lambda { @client.report("eh") }.should raise_error(Puppet::Network::XMLRPCClientError) - end + lambda { @client.report("eh") }.should raise_error(Puppet::Network::XMLRPCClientError) + end - it "should log and raise XMLRPCClientError if Timeout::Error is raised" do - Puppet.expects(:err) - @client.expects(:call).raises(Timeout::Error) + it "should log and raise XMLRPCClientError if Timeout::Error is raised" do + Puppet.expects(:err) + @client.expects(:call).raises(Timeout::Error) - lambda { @client.report("eh") }.should raise_error(Puppet::Network::XMLRPCClientError) - end + lambda { @client.report("eh") }.should raise_error(Puppet::Network::XMLRPCClientError) + end - it "should log and raise XMLRPCClientError if SocketError is raised" do - Puppet.expects(:err) - @client.expects(:call).raises(SocketError) + it "should log and raise XMLRPCClientError if SocketError is raised" do + Puppet.expects(:err) + @client.expects(:call).raises(SocketError) - lambda { @client.report("eh") }.should raise_error(Puppet::Network::XMLRPCClientError) - end + lambda { @client.report("eh") }.should raise_error(Puppet::Network::XMLRPCClientError) + end - it "should log, recycle the connection, and retry if Errno::EPIPE is raised" do - @client.expects(:call).times(2).raises(Errno::EPIPE).then.returns "eh" + it "should log, recycle the connection, and retry if Errno::EPIPE is raised" do + @client.expects(:call).times(2).raises(Errno::EPIPE).then.returns "eh" - Puppet.expects(:info) - @client.expects(:recycle_connection) + Puppet.expects(:info) + @client.expects(:recycle_connection) - @client.report("eh") - end + @client.report("eh") + end - it "should log, recycle the connection, and retry if EOFError is raised" do - @client.expects(:call).times(2).raises(EOFError).then.returns "eh" + it "should log, recycle the connection, and retry if EOFError is raised" do + @client.expects(:call).times(2).raises(EOFError).then.returns "eh" - Puppet.expects(:info) - @client.expects(:recycle_connection) + Puppet.expects(:info) + @client.expects(:recycle_connection) - @client.report("eh") - end + @client.report("eh") + end - it "should log and retry if an exception containing 'Wrong size' is raised" do - error = RuntimeError.new("Wrong size. Was 15, should be 30") - @client.expects(:call).times(2).raises(error).then.returns "eh" + it "should log and retry if an exception containing 'Wrong size' is raised" do + error = RuntimeError.new("Wrong size. Was 15, should be 30") + @client.expects(:call).times(2).raises(error).then.returns "eh" - Puppet.expects(:warning) + Puppet.expects(:warning) - @client.report("eh") - end + @client.report("eh") + end - it "should raise XMLRPCClientError if OpenSSL::SSL::SSLError is raised" do - @client.expects(:call).raises(OpenSSL::SSL::SSLError) + it "should raise XMLRPCClientError if OpenSSL::SSL::SSLError is raised" do + @client.expects(:call).raises(OpenSSL::SSL::SSLError) - lambda { @client.report("eh") }.should raise_error(Puppet::Network::XMLRPCClientError) - end + lambda { @client.report("eh") }.should raise_error(Puppet::Network::XMLRPCClientError) + end - it "should log and raise XMLRPCClientError if OpenSSL::SSL::SSLError is raised with certificate issues" do - error = OpenSSL::SSL::SSLError.new("hostname was not match") - @client.expects(:call).raises(error) + it "should log and raise XMLRPCClientError if OpenSSL::SSL::SSLError is raised with certificate issues" do + error = OpenSSL::SSL::SSLError.new("hostname was not match") + @client.expects(:call).raises(error) - Puppet.expects(:warning) + Puppet.expects(:warning) - lambda { @client.report("eh") }.should raise_error(Puppet::Network::XMLRPCClientError) - end + lambda { @client.report("eh") }.should raise_error(Puppet::Network::XMLRPCClientError) + end - it "should log, recycle the connection, and retry if OpenSSL::SSL::SSLError is raised containing 'bad write retry'" do - error = OpenSSL::SSL::SSLError.new("bad write retry") - @client.expects(:call).times(2).raises(error).then.returns "eh" + it "should log, recycle the connection, and retry if OpenSSL::SSL::SSLError is raised containing 'bad write retry'" do + error = OpenSSL::SSL::SSLError.new("bad write retry") + @client.expects(:call).times(2).raises(error).then.returns "eh" - @client.expects(:recycle_connection) + @client.expects(:recycle_connection) - Puppet.expects(:warning) + Puppet.expects(:warning) - @client.report("eh") - end + @client.report("eh") + end - it "should log and raise XMLRPCClientError if any other exception is raised" do - @client.expects(:call).raises(RuntimeError) + it "should log and raise XMLRPCClientError if any other exception is raised" do + @client.expects(:call).raises(RuntimeError) - Puppet.expects(:err) + Puppet.expects(:err) - lambda { @client.report("eh") }.should raise_error(Puppet::Network::XMLRPCClientError) - end - end + lambda { @client.report("eh") }.should raise_error(Puppet::Network::XMLRPCClientError) + end end + end end |
