summaryrefslogtreecommitdiffstats
path: root/spec/unit
diff options
context:
space:
mode:
Diffstat (limited to 'spec/unit')
-rwxr-xr-xspec/unit/executables/client/certhandler.rb21
-rwxr-xr-xspec/unit/file_serving/configuration.rb6
-rwxr-xr-xspec/unit/file_serving/mount.rb8
-rwxr-xr-xspec/unit/indirector/certificate/ca.rb28
-rwxr-xr-xspec/unit/indirector/certificate/file.rb28
-rwxr-xr-xspec/unit/indirector/certificate/rest.rb15
-rwxr-xr-xspec/unit/indirector/certificate_request/ca.rb19
-rwxr-xr-xspec/unit/indirector/certificate_request/file.rb19
-rwxr-xr-xspec/unit/indirector/certificate_request/rest.rb15
-rwxr-xr-xspec/unit/indirector/certificate_revocation_list/ca.rb21
-rwxr-xr-xspec/unit/indirector/certificate_revocation_list/file.rb20
-rwxr-xr-xspec/unit/indirector/certificate_revocation_list/rest.rb15
-rwxr-xr-xspec/unit/indirector/indirection.rb26
-rwxr-xr-xspec/unit/indirector/key/ca.rb34
-rwxr-xr-xspec/unit/indirector/key/file.rb104
-rwxr-xr-xspec/unit/indirector/rest.rb623
-rwxr-xr-xspec/unit/indirector/ssl_file.rb244
-rwxr-xr-xspec/unit/indirector/ssl_rsa/file.rb116
-rwxr-xr-xspec/unit/network/http/mongrel.rb47
-rwxr-xr-xspec/unit/network/http/webrick.rb285
-rwxr-xr-xspec/unit/network/http_pool.rb198
-rwxr-xr-xspec/unit/network/server.rb728
-rwxr-xr-xspec/unit/node.rb18
-rwxr-xr-xspec/unit/node/catalog.rb62
-rwxr-xr-xspec/unit/node/facts.rb8
-rwxr-xr-xspec/unit/other/transbucket.rb4
-rwxr-xr-xspec/unit/provider/mount/parsed.rb4
-rwxr-xr-xspec/unit/rails.rb2
-rwxr-xr-xspec/unit/resource_reference.rb12
-rwxr-xr-xspec/unit/ssl/certificate.rb82
-rwxr-xr-xspec/unit/ssl/certificate_authority.rb735
-rwxr-xr-xspec/unit/ssl/certificate_authority/interface.rb265
-rwxr-xr-xspec/unit/ssl/certificate_factory.rb107
-rwxr-xr-xspec/unit/ssl/certificate_request.rb167
-rwxr-xr-xspec/unit/ssl/certificate_revocation_list.rb166
-rwxr-xr-xspec/unit/ssl/host.rb431
-rwxr-xr-xspec/unit/ssl/inventory.rb180
-rwxr-xr-xspec/unit/ssl/key.rb190
-rwxr-xr-xspec/unit/transaction/report.rb2
-rwxr-xr-xspec/unit/type/file.rb4
-rwxr-xr-xspec/unit/type/interface.rb2
-rwxr-xr-xspec/unit/type/mount.rb8
-rwxr-xr-xspec/unit/type/noop_metaparam.rb2
-rwxr-xr-xspec/unit/type/package.rb10
-rwxr-xr-xspec/unit/type/schedule.rb6
-rwxr-xr-xspec/unit/type/service.rb10
-rwxr-xr-xspec/unit/type/ssh_authorized_key.rb2
-rwxr-xr-xspec/unit/util/cacher.rb158
-rwxr-xr-xspec/unit/util/settings.rb50
49 files changed, 4286 insertions, 1021 deletions
diff --git a/spec/unit/executables/client/certhandler.rb b/spec/unit/executables/client/certhandler.rb
index 4f8f8139c..5950aa4dc 100755
--- a/spec/unit/executables/client/certhandler.rb
+++ b/spec/unit/executables/client/certhandler.rb
@@ -14,6 +14,19 @@ describe cert_handler, "when handling certificates" do
Puppet::Network::Client.stubs(:ca).returns(caclient_class)
end
+ it "should return true if the certificate exists" do
+ @caclient.expects(:read_cert).returns(true)
+ cert_handler.new(1,true).read_retrieve.should be_true
+ end
+
+ it "should return false when getting a new cert" do
+ @caclient.expects(:read_cert).returns(true)
+ @caclient.stubs(:request_cert).returns(true)
+ ch = cert_handler.new(1,true)
+ ch.stubs(:read_cert).returns(false)
+ ch.read_retrieve.should be_false
+ end
+
describe "when reading or retrieving the certificate" do
before do
@handler = cert_handler.new(1,true)
@@ -24,8 +37,8 @@ describe cert_handler, "when handling certificates" do
@handler.read_retrieve
end
- it "should delegate to Puppet::Network::HttpPool to read the certificate" do
- Puppet::Network::HttpPool.expects(:read_cert).returns(true)
+ it "should delegate to the ca client to read the certificate" do
+ @caclient.expects(:read_cert).returns(true)
@handler.read_retrieve
end
@@ -55,7 +68,7 @@ describe cert_handler, "when handling certificates" do
it "should return false when getting a new cert" do
#This is the second call to httppool that happens in 'read_new_cert'
- Puppet::Network::HttpPool.expects(:read_cert).returns(true)
+ @caclient.expects(:read_cert).returns(true)
@caclient.stubs(:request_cert).returns(true)
@handler.stubs(:read_cert).returns(false)
@handler.read_retrieve.should be_false
@@ -114,7 +127,7 @@ describe cert_handler, "when handling certificates" do
it "should exit if the new cert can't be read" do
@caclient.stubs(:request_cert).returns(true)
#this is the second, call to httppool inside read_new_cert
- Puppet::Network::HttpPool.stubs(:read_cert).returns(false)
+ @caclient.stubs(:read_cert).returns(false)
@handler.expects(:exit).with(34).raises(SystemExit)
lambda { @handler.retrieve_cert }.should raise_error(SystemExit)
end
diff --git a/spec/unit/file_serving/configuration.rb b/spec/unit/file_serving/configuration.rb
index a0710e20d..d51fa70b2 100755
--- a/spec/unit/file_serving/configuration.rb
+++ b/spec/unit/file_serving/configuration.rb
@@ -15,12 +15,12 @@ describe Puppet::FileServing::Configuration do
it "should have a method for removing the current configuration instance" do
old = Puppet::FileServing::Configuration.create
- Puppet::FileServing::Configuration.clear_cache
+ Puppet::Util::Cacher.invalidate
Puppet::FileServing::Configuration.create.should_not equal(old)
end
after do
- Puppet::FileServing::Configuration.clear_cache
+ Puppet::Util::Cacher.invalidate
end
end
@@ -32,7 +32,7 @@ describe Puppet::FileServing::Configuration do
end
after :each do
- Puppet::FileServing::Configuration.clear_cache
+ Puppet::Util::Cacher.invalidate
end
describe Puppet::FileServing::Configuration, " when initializing" do
diff --git a/spec/unit/file_serving/mount.rb b/spec/unit/file_serving/mount.rb
index ebe058301..6f491e3b2 100755
--- a/spec/unit/file_serving/mount.rb
+++ b/spec/unit/file_serving/mount.rb
@@ -12,9 +12,9 @@ end
describe Puppet::FileServing::Mount do
it "should provide a method for clearing its cached host information" do
- Puppet::FileServing::Mount.new("whatever").send(:localmap)
- Puppet::FileServing::Mount.clear_cache
- Puppet::FileServing::Mount.send(:class_variable_get, "@@localmap").should be_nil
+ old = Puppet::FileServing::Mount.localmap
+ Puppet::Util::Cacher.invalidate
+ Puppet::FileServing::Mount.localmap.should_not equal(old)
end
end
@@ -106,7 +106,7 @@ describe Puppet::FileServing::Mount, " when finding files" do
end
after do
- Puppet::FileServing::Mount.clear_cache
+ Puppet::Util::Cacher.invalidate
end
end
diff --git a/spec/unit/indirector/certificate/ca.rb b/spec/unit/indirector/certificate/ca.rb
new file mode 100755
index 000000000..0158a8d90
--- /dev/null
+++ b/spec/unit/indirector/certificate/ca.rb
@@ -0,0 +1,28 @@
+#!/usr/bin/env ruby
+#
+# Created by Luke Kanies on 2008-3-7.
+# Copyright (c) 2007. All rights reserved.
+
+require File.dirname(__FILE__) + '/../../../spec_helper'
+
+require 'puppet/indirector/certificate/ca'
+
+describe Puppet::SSL::Certificate::Ca do
+ it "should have documentation" do
+ Puppet::SSL::Certificate::Ca.doc.should be_instance_of(String)
+ end
+
+ it "should use the :signeddir as the collection directory" do
+ Puppet.settings.expects(:value).with(:signeddir).returns "/cert/dir"
+ Puppet::SSL::Certificate::Ca.collection_directory.should == "/cert/dir"
+ end
+
+ it "should store the ca certificate at the :cacert location" do
+ Puppet.settings.stubs(:use)
+ Puppet.settings.stubs(:value).returns "whatever"
+ Puppet.settings.stubs(:value).with(:cacert).returns "/ca/cert"
+ file = Puppet::SSL::Certificate::Ca.new
+ file.stubs(:ca?).returns true
+ file.path("whatever").should == "/ca/cert"
+ end
+end
diff --git a/spec/unit/indirector/certificate/file.rb b/spec/unit/indirector/certificate/file.rb
new file mode 100755
index 000000000..6fb00f1ca
--- /dev/null
+++ b/spec/unit/indirector/certificate/file.rb
@@ -0,0 +1,28 @@
+#!/usr/bin/env ruby
+#
+# Created by Luke Kanies on 2008-3-7.
+# Copyright (c) 2007. All rights reserved.
+
+require File.dirname(__FILE__) + '/../../../spec_helper'
+
+require 'puppet/indirector/certificate/file'
+
+describe Puppet::SSL::Certificate::File do
+ it "should have documentation" do
+ Puppet::SSL::Certificate::File.doc.should be_instance_of(String)
+ end
+
+ it "should use the :certdir as the collection directory" do
+ Puppet.settings.expects(:value).with(:certdir).returns "/cert/dir"
+ Puppet::SSL::Certificate::File.collection_directory.should == "/cert/dir"
+ end
+
+ it "should store the ca certificate at the :localcacert location" do
+ Puppet.settings.stubs(:use)
+ Puppet.settings.stubs(:value).returns "whatever"
+ Puppet.settings.stubs(:value).with(:localcacert).returns "/ca/cert"
+ file = Puppet::SSL::Certificate::File.new
+ file.stubs(:ca?).returns true
+ file.path("whatever").should == "/ca/cert"
+ end
+end
diff --git a/spec/unit/indirector/certificate/rest.rb b/spec/unit/indirector/certificate/rest.rb
new file mode 100755
index 000000000..62b1ef543
--- /dev/null
+++ b/spec/unit/indirector/certificate/rest.rb
@@ -0,0 +1,15 @@
+#!/usr/bin/env ruby
+
+require File.dirname(__FILE__) + '/../../../spec_helper'
+
+require 'puppet/indirector/certificate/rest'
+
+describe Puppet::SSL::Certificate::Rest do
+ before do
+ @searcher = Puppet::SSL::Certificate::Rest.new
+ end
+
+ it "should be a sublcass of Puppet::Indirector::REST" do
+ Puppet::SSL::Certificate::Rest.superclass.should equal(Puppet::Indirector::REST)
+ end
+end
diff --git a/spec/unit/indirector/certificate_request/ca.rb b/spec/unit/indirector/certificate_request/ca.rb
new file mode 100755
index 000000000..b35d8b474
--- /dev/null
+++ b/spec/unit/indirector/certificate_request/ca.rb
@@ -0,0 +1,19 @@
+#!/usr/bin/env ruby
+#
+# Created by Luke Kanies on 2008-3-7.
+# Copyright (c) 2007. All rights reserved.
+
+require File.dirname(__FILE__) + '/../../../spec_helper'
+
+require 'puppet/indirector/certificate_request/ca'
+
+describe Puppet::SSL::CertificateRequest::Ca do
+ it "should have documentation" do
+ Puppet::SSL::CertificateRequest::Ca.doc.should be_instance_of(String)
+ end
+
+ it "should use the :csrdir as the collection directory" do
+ Puppet.settings.expects(:value).with(:csrdir).returns "/request/dir"
+ Puppet::SSL::CertificateRequest::Ca.collection_directory.should == "/request/dir"
+ end
+end
diff --git a/spec/unit/indirector/certificate_request/file.rb b/spec/unit/indirector/certificate_request/file.rb
new file mode 100755
index 000000000..e1f442e2a
--- /dev/null
+++ b/spec/unit/indirector/certificate_request/file.rb
@@ -0,0 +1,19 @@
+#!/usr/bin/env ruby
+#
+# Created by Luke Kanies on 2008-3-7.
+# Copyright (c) 2007. All rights reserved.
+
+require File.dirname(__FILE__) + '/../../../spec_helper'
+
+require 'puppet/indirector/certificate_request/file'
+
+describe Puppet::SSL::CertificateRequest::File do
+ it "should have documentation" do
+ Puppet::SSL::CertificateRequest::File.doc.should be_instance_of(String)
+ end
+
+ it "should use the :requestdir as the collection directory" do
+ Puppet.settings.expects(:value).with(:requestdir).returns "/request/dir"
+ Puppet::SSL::CertificateRequest::File.collection_directory.should == "/request/dir"
+ end
+end
diff --git a/spec/unit/indirector/certificate_request/rest.rb b/spec/unit/indirector/certificate_request/rest.rb
new file mode 100755
index 000000000..cbd525f17
--- /dev/null
+++ b/spec/unit/indirector/certificate_request/rest.rb
@@ -0,0 +1,15 @@
+#!/usr/bin/env ruby
+
+require File.dirname(__FILE__) + '/../../../spec_helper'
+
+require 'puppet/indirector/certificate_request/rest'
+
+describe Puppet::SSL::CertificateRequest::Rest do
+ before do
+ @searcher = Puppet::SSL::CertificateRequest::Rest.new
+ end
+
+ it "should be a sublcass of Puppet::Indirector::REST" do
+ Puppet::SSL::CertificateRequest::Rest.superclass.should equal(Puppet::Indirector::REST)
+ end
+end
diff --git a/spec/unit/indirector/certificate_revocation_list/ca.rb b/spec/unit/indirector/certificate_revocation_list/ca.rb
new file mode 100755
index 000000000..f6da86861
--- /dev/null
+++ b/spec/unit/indirector/certificate_revocation_list/ca.rb
@@ -0,0 +1,21 @@
+#!/usr/bin/env ruby
+#
+# Created by Luke Kanies on 2008-3-7.
+# Copyright (c) 2007. All rights reserved.
+
+require File.dirname(__FILE__) + '/../../../spec_helper'
+
+require 'puppet/indirector/certificate_revocation_list/ca'
+
+describe Puppet::SSL::CertificateRevocationList::Ca do
+ it "should have documentation" do
+ Puppet::SSL::CertificateRevocationList::Ca.doc.should be_instance_of(String)
+ end
+
+ it "should use the :cacrl setting as the crl location" do
+ Puppet.settings.stubs(:value).returns "whatever"
+ Puppet.settings.stubs(:use)
+ Puppet.settings.stubs(:value).with(:cacrl).returns "/request/dir"
+ Puppet::SSL::CertificateRevocationList::Ca.new.path("whatever").should == "/request/dir"
+ end
+end
diff --git a/spec/unit/indirector/certificate_revocation_list/file.rb b/spec/unit/indirector/certificate_revocation_list/file.rb
new file mode 100755
index 000000000..5db4f8c06
--- /dev/null
+++ b/spec/unit/indirector/certificate_revocation_list/file.rb
@@ -0,0 +1,20 @@
+#!/usr/bin/env ruby
+#
+# Created by Luke Kanies on 2008-3-7.
+# Copyright (c) 2007. All rights reserved.
+
+require File.dirname(__FILE__) + '/../../../spec_helper'
+
+require 'puppet/indirector/certificate_revocation_list/file'
+
+describe Puppet::SSL::CertificateRevocationList::File do
+ it "should have documentation" do
+ Puppet::SSL::CertificateRevocationList::File.doc.should be_instance_of(String)
+ end
+
+ it "should always store the file to :hostcrl location" do
+ Puppet.settings.expects(:value).with(:hostcrl).returns "/host/crl"
+ Puppet.settings.stubs(:use)
+ Puppet::SSL::CertificateRevocationList::File.file_location.should == "/host/crl"
+ end
+end
diff --git a/spec/unit/indirector/certificate_revocation_list/rest.rb b/spec/unit/indirector/certificate_revocation_list/rest.rb
new file mode 100755
index 000000000..f6f493c37
--- /dev/null
+++ b/spec/unit/indirector/certificate_revocation_list/rest.rb
@@ -0,0 +1,15 @@
+#!/usr/bin/env ruby
+
+require File.dirname(__FILE__) + '/../../../spec_helper'
+
+require 'puppet/indirector/certificate_revocation_list/rest'
+
+describe Puppet::SSL::CertificateRevocationList::Rest do
+ before do
+ @searcher = Puppet::SSL::CertificateRevocationList::Rest.new
+ end
+
+ it "should be a sublcass of Puppet::Indirector::REST" do
+ Puppet::SSL::CertificateRevocationList::Rest.superclass.should equal(Puppet::Indirector::REST)
+ end
+end
diff --git a/spec/unit/indirector/indirection.rb b/spec/unit/indirector/indirection.rb
index 5d4539e95..e52be31e1 100755
--- a/spec/unit/indirector/indirection.rb
+++ b/spec/unit/indirector/indirection.rb
@@ -87,6 +87,9 @@ describe "Delegation Authorizer", :shared => true do
end
describe Puppet::Indirector::Indirection do
+ after do
+ Puppet::Util::Cacher.invalidate
+ end
describe "when initializing" do
# (LAK) I've no idea how to test this, really.
it "should store a reference to itself before it consumes its options" do
@@ -494,7 +497,7 @@ describe Puppet::Indirector::Indirection do
after :each do
@indirection.delete
- Puppet::Indirector::Indirection.clear_cache
+ Puppet::Util::Cacher.invalidate
end
end
@@ -615,15 +618,6 @@ describe Puppet::Indirector::Indirection do
@indirection.terminus(:foo).should equal(@terminus)
end
- it "should allow the clearance of cached terminus instances" do
- terminus1 = mock 'terminus1'
- terminus2 = mock 'terminus2'
- @terminus_class.stubs(:new).returns(terminus1, terminus2, ArgumentError)
- @indirection.terminus(:foo).should equal(terminus1)
- @indirection.class.clear_cache
- @indirection.terminus(:foo).should equal(terminus2)
- end
-
# Make sure it caches the terminus.
it "should return the same terminus instance each time for a given name" do
@terminus_class.stubs(:new).returns(@terminus)
@@ -638,7 +632,6 @@ describe Puppet::Indirector::Indirection do
after do
@indirection.delete
- Puppet::Indirector::Indirection.clear_cache
end
end
@@ -675,7 +668,6 @@ describe Puppet::Indirector::Indirection do
after do
@indirection.delete
- Puppet::Indirector::Indirection.clear_cache
end
end
@@ -706,15 +698,6 @@ describe Puppet::Indirector::Indirection do
@indirection.cache.should equal(@cache)
@indirection.cache.should equal(@cache)
end
-
- it "should remove the cache terminus when all other terminus instances are cleared" do
- cache2 = mock 'cache2'
- @cache_class.stubs(:new).returns(@cache, cache2)
- @indirection.cache_class = :cache_terminus
- @indirection.cache.should equal(@cache)
- @indirection.clear_cache
- @indirection.cache.should equal(cache2)
- end
end
describe "and saving" do
@@ -725,7 +708,6 @@ describe Puppet::Indirector::Indirection do
after :each do
@indirection.delete
- Puppet::Indirector::Indirection.clear_cache
end
end
end
diff --git a/spec/unit/indirector/key/ca.rb b/spec/unit/indirector/key/ca.rb
new file mode 100755
index 000000000..579617f71
--- /dev/null
+++ b/spec/unit/indirector/key/ca.rb
@@ -0,0 +1,34 @@
+#!/usr/bin/env ruby
+#
+# Created by Luke Kanies on 2008-3-7.
+# Copyright (c) 2007. All rights reserved.
+
+require File.dirname(__FILE__) + '/../../../spec_helper'
+
+require 'puppet/indirector/key/ca'
+
+describe Puppet::SSL::Key::Ca do
+ it "should have documentation" do
+ Puppet::SSL::Key::Ca.doc.should be_instance_of(String)
+ end
+
+ it "should store the ca key at the :cakey location" do
+ Puppet.settings.stubs(:use)
+ Puppet.settings.stubs(:value).returns "whatever"
+ Puppet.settings.stubs(:value).with(:cakey).returns "/ca/key"
+ file = Puppet::SSL::Key::Ca.new
+ file.stubs(:ca?).returns true
+ file.path("whatever").should == "/ca/key"
+ end
+
+ describe "when choosing the path for the public key" do
+ it "should fail if the key is not for the CA" do
+ Puppet.settings.stubs(:use)
+ Puppet.settings.stubs(:value).returns "whatever"
+ Puppet.settings.stubs(:value).with(:cakey).returns "/ca/key"
+ file = Puppet::SSL::Key::Ca.new
+ file.stubs(:ca?).returns false
+ lambda { file.path("whatever") }.should raise_error(ArgumentError)
+ end
+ end
+end
diff --git a/spec/unit/indirector/key/file.rb b/spec/unit/indirector/key/file.rb
new file mode 100755
index 000000000..8a1cb04bd
--- /dev/null
+++ b/spec/unit/indirector/key/file.rb
@@ -0,0 +1,104 @@
+#!/usr/bin/env ruby
+#
+# Created by Luke Kanies on 2008-3-7.
+# Copyright (c) 2007. All rights reserved.
+
+require File.dirname(__FILE__) + '/../../../spec_helper'
+
+require 'puppet/indirector/key/file'
+
+describe Puppet::SSL::Key::File do
+ it "should have documentation" do
+ Puppet::SSL::Key::File.doc.should be_instance_of(String)
+ end
+
+ it "should use the :privatekeydir as the collection directory" do
+ Puppet.settings.expects(:value).with(:privatekeydir).returns "/key/dir"
+ Puppet::SSL::Key::File.collection_directory.should == "/key/dir"
+ end
+
+ it "should store the ca key at the :cakey location" do
+ Puppet.settings.stubs(:use)
+ Puppet.settings.stubs(:value).returns "whatever"
+ Puppet.settings.stubs(:value).with(:cakey).returns "/ca/key"
+ file = Puppet::SSL::Key::File.new
+ file.stubs(:ca?).returns true
+ file.path("whatever").should == "/ca/key"
+ end
+
+ describe "when choosing the path for the public key" do
+ it "should use the :capub setting location if the key is for the certificate authority" do
+ Puppet.settings.stubs(:value).returns "/fake/dir"
+ Puppet.settings.stubs(:value).with(:capub).returns "/ca/pubkey"
+ Puppet.settings.stubs(:use)
+
+ @searcher = Puppet::SSL::Key::File.new
+ @searcher.stubs(:ca?).returns true
+ @searcher.public_key_path("whatever").should == "/ca/pubkey"
+ end
+
+ it "should use the host name plus '.pem' in :publickeydir for normal hosts" do
+ Puppet.settings.stubs(:value).with(:privatekeydir).returns "/private/key/dir"
+ Puppet.settings.stubs(:value).with(:publickeydir).returns "/public/key/dir"
+ Puppet.settings.stubs(:use)
+
+ @searcher = Puppet::SSL::Key::File.new
+ @searcher.stubs(:ca?).returns false
+ @searcher.public_key_path("whatever").should == "/public/key/dir/whatever.pem"
+ end
+ end
+
+ describe "when managing private keys" do
+ before do
+ @searcher = Puppet::SSL::Key::File.new
+
+ @private_key_path = File.join("/fake/key/path")
+ @public_key_path = File.join("/other/fake/key/path")
+
+ @searcher.stubs(:public_key_path).returns @public_key_path
+ @searcher.stubs(:path).returns @private_key_path
+
+ FileTest.stubs(:directory?).returns true
+ FileTest.stubs(:writable?).returns true
+
+ @public_key = stub 'public_key'
+ @real_key = stub 'sslkey', :public_key => @public_key
+
+ @key = stub 'key', :name => "myname", :content => @real_key
+
+ @request = stub 'request', :key => "myname", :instance => @key
+ end
+
+ it "should save the public key when saving the private key" do
+ File.stubs(:open).with(@private_key_path, "w")
+
+ fh = mock 'filehandle'
+
+ File.expects(:open).with(@public_key_path, "w").yields fh
+ @public_key.expects(:to_pem).returns "my pem"
+
+ fh.expects(:print).with "my pem"
+
+ @searcher.save(@request)
+ end
+
+ it "should destroy the public key when destroying the private key" do
+ File.stubs(:unlink).with(@private_key_path)
+ FileTest.stubs(:exist?).with(@private_key_path).returns true
+ FileTest.expects(:exist?).with(@public_key_path).returns true
+ File.expects(:unlink).with(@public_key_path)
+
+ @searcher.destroy(@request)
+ end
+
+ it "should not fail if the public key does not exist when deleting the private key" do
+ File.stubs(:unlink).with(@private_key_path)
+
+ FileTest.stubs(:exist?).with(@private_key_path).returns true
+ FileTest.expects(:exist?).with(@public_key_path).returns false
+ File.expects(:unlink).with(@public_key_path).never
+
+ @searcher.destroy(@request)
+ end
+ end
+end
diff --git a/spec/unit/indirector/rest.rb b/spec/unit/indirector/rest.rb
index 1a1064491..1f802b603 100755
--- a/spec/unit/indirector/rest.rb
+++ b/spec/unit/indirector/rest.rb
@@ -3,6 +3,39 @@
require File.dirname(__FILE__) + '/../../spec_helper'
require 'puppet/indirector/rest'
+describe "a REST http call", :shared => true do
+ it "should accept a path" do
+ lambda { @search.send(@method, *@arguments) }.should_not raise_error(ArgumentError)
+ end
+
+ it "should require a path" do
+ lambda { @searcher.send(@method) }.should raise_error(ArgumentError)
+ end
+
+ it "should use the Http Pool with the remote server and port looked up from the REST terminus" do
+ @searcher.expects(:rest_connection_details).returns(@details)
+
+ conn = mock 'connection'
+ result = stub 'result', :body => "body"
+ conn.stubs(:put).returns result
+ conn.stubs(:delete).returns result
+ conn.stubs(:get).returns result
+ Puppet::Network::HttpPool.expects(:http_instance).with(@details[:host], @details[:port]).returns conn
+ @searcher.send(@method, *@arguments)
+ end
+
+ it "should return the results of the request" do
+ conn = mock 'connection'
+ result = stub 'result', :body => "result"
+ conn.stubs(:put).returns result
+ conn.stubs(:delete).returns result
+ conn.stubs(:get).returns result
+ Puppet::Network::HttpPool.stubs(:http_instance).returns conn
+
+ @searcher.send(@method, *@arguments).should == 'result'
+ end
+end
+
describe Puppet::Indirector::REST do
before do
Puppet::Indirector::Terminus.stubs(:register_terminus_class)
@@ -19,354 +52,280 @@ describe Puppet::Indirector::REST do
@searcher = @rest_class.new
end
-
- describe "when locating the REST connection" do
- before do
- Puppet.settings.stubs(:value).returns("whatever")
- end
-
- it "should return the :server setting as the host" do
- Puppet.settings.expects(:value).with(:server).returns "myserver"
- @searcher.rest_connection_details[:host].should == "myserver"
- end
-
- it "should return the :masterport (as an Integer) as the port" do
- Puppet.settings.expects(:value).with(:masterport).returns "1234"
- @searcher.rest_connection_details[:port].should == 1234
- end
+
+ describe "when configuring the REST http call" do
+ before do
+ Puppet.settings.stubs(:value).returns("rest_testing")
+ end
+
+ it "should return the :server setting as the host" do
+ Puppet.settings.expects(:value).with(:server).returns "myserver"
+ @searcher.rest_connection_details[:host].should == "myserver"
+ end
+
+ it "should return the :masterport (as an Integer) as the port" do
+ Puppet.settings.expects(:value).with(:masterport).returns "1234"
+ @searcher.rest_connection_details[:port].should == 1234
+ end
end
-
+
describe "when doing a network fetch" do
- before :each do
- Net::HTTP.stubs(:start).returns('result')
- @details = { :host => '127.0.0.1', :port => 34343 }
- @searcher.stubs(:rest_connection_details).returns(@details)
- end
-
- it "should accept a path" do
- lambda { @search.network_fetch('foo') }.should_not raise_error(ArgumentError)
- end
-
- it "should require a path" do
- lambda { @searcher.network_fetch }.should raise_error(ArgumentError)
- end
-
- it "should look up connection details" do
- @searcher.expects(:rest_connection_details).returns(@details)
- @searcher.network_fetch('foo')
- end
-
- it "should use the GET http method" do
- @mock_result = stub('mock result', :body => 'result')
- @mock_connection = mock('mock http connection', :get => @mock_result)
- @searcher.stubs(:network).yields(@mock_connection)
- @searcher.network_fetch('foo')
- end
-
- it "should use the appropriate remote server" do
- Net::HTTP.expects(:start).with {|host, port| host == @details[:host] }
- @searcher.network_fetch('foo')
- end
-
- it "should use the appropriate remote port" do
- Net::HTTP.expects(:start).with {|host, port| port == @details[:port] }
- @searcher.network_fetch('foo')
- end
-
- it "should use the provided path" do
- @mock_result = stub('mock result', :body => 'result')
- @mock_connection = stub('mock http connection')
- @mock_connection.expects(:get).with('/foo').returns(@mock_result)
- @searcher.stubs(:network).yields(@mock_connection)
- @searcher.network_fetch('foo')
- end
-
- it "should return the results of the GET request" do
- @searcher.network_fetch('foo').should == 'result'
- end
+ before :each do
+ Net::HTTP.stubs(:start).returns('result')
+ @details = { :host => '127.0.0.1', :port => 34343 }
+ @searcher.stubs(:rest_connection_details).returns(@details)
+
+ @method = :network_fetch
+ @arguments = "foo"
+ end
+
+ it_should_behave_like "a REST http call"
+
+ it "should use the GET http method" do
+ @mock_result = stub('mock result', :body => 'result')
+ @mock_connection = mock('mock http connection', :get => @mock_result)
+ @searcher.stubs(:network).returns(@mock_connection)
+ @searcher.network_fetch('foo')
+ end
+
+ it "should use the provided path" do
+ @mock_result = stub('mock result', :body => 'result')
+ @mock_connection = stub('mock http connection')
+ @mock_connection.expects(:get).with('/foo').returns(@mock_result)
+ @searcher.stubs(:network).returns(@mock_connection)
+ @searcher.network_fetch('foo')
+ end
end
describe "when doing a network delete" do
- before :each do
- Net::HTTP.stubs(:start).returns('result')
- @details = { :host => '127.0.0.1', :port => 34343 }
- @searcher.stubs(:rest_connection_details).returns(@details)
- end
-
- it "should accept a path" do
- lambda { @search.network_delete('foo') }.should_not raise_error(ArgumentError)
- end
-
- it "should require a path" do
- lambda { @searcher.network_delete }.should raise_error(ArgumentError)
- end
-
- it "should look up connection details" do
- @searcher.expects(:rest_connection_details).returns(@details)
- @searcher.network_delete('foo')
- end
-
- it "should use the DELETE http method" do
- @mock_result = stub('mock result', :body => 'result')
- @mock_connection = mock('mock http connection', :delete => @mock_result)
- @searcher.stubs(:network).yields(@mock_connection)
- @searcher.network_delete('foo')
- end
-
- it "should use the appropriate remote server" do
- Net::HTTP.expects(:start).with {|host, port| host == @details[:host] }
- @searcher.network_delete('foo')
- end
-
- it "should use the appropriate remote port" do
- Net::HTTP.expects(:start).with {|host, port| port == @details[:port] }
- @searcher.network_delete('foo')
- end
-
- it "should use the provided path" do
- @mock_result = stub('mock result', :body => 'result')
- @mock_connection = stub('mock http connection')
- @mock_connection.expects(:delete).with('/foo').returns(@mock_result)
- @searcher.stubs(:network).yields(@mock_connection)
- @searcher.network_delete('foo')
- end
-
- it "should return the results of the DELETE request" do
- @searcher.network_delete('foo').should == 'result'
- end
+ before :each do
+ Net::HTTP.stubs(:start).returns('result')
+ @details = { :host => '127.0.0.1', :port => 34343 }
+ @searcher.stubs(:rest_connection_details).returns(@details)
+
+ @method = :network_delete
+ @arguments = "foo"
+ end
+
+ it_should_behave_like "a REST http call"
+
+ it "should use the DELETE http method" do
+ @mock_result = stub('mock result', :body => 'result')
+ @mock_connection = mock('mock http connection', :delete => @mock_result)
+ @searcher.stubs(:network).returns(@mock_connection)
+ @searcher.network_delete('foo')
+ end
end
-
+
describe "when doing a network put" do
- before :each do
- Net::HTTP.stubs(:start).returns('result')
- @details = { :host => '127.0.0.1', :port => 34343 }
- @data = { :foo => 'bar' }
- @searcher.stubs(:rest_connection_details).returns(@details)
- end
-
- it "should accept a path and data" do
- lambda { @search.network_put('foo', @data) }.should_not raise_error(ArgumentError)
- end
-
- it "should require a path and data" do
- lambda { @searcher.network_put('foo') }.should raise_error(ArgumentError)
- end
-
- it "should look up connection details" do
- @searcher.expects(:rest_connection_details).returns(@details)
- @searcher.network_put('foo', @data)
- end
-
- it "should use the appropriate remote server" do
- Net::HTTP.expects(:start).with {|host, port| host == @details[:host] }
- @searcher.network_put('foo', @data)
- end
-
- it "should use the appropriate remote port" do
- Net::HTTP.expects(:start).with {|host, port| port == @details[:port] }
- @searcher.network_put('foo', @data)
- end
-
- it "should use the PUT http method" do
- @mock_result = stub('mock result', :body => 'result')
- @mock_connection = mock('mock http connection', :put => @mock_result)
- @searcher.stubs(:network).yields(@mock_connection)
- @searcher.network_put('foo', @data)
- end
-
- it "should use the provided path" do
- @mock_result = stub('mock result', :body => 'result')
- @mock_connection = stub('mock http connection')
- @mock_connection.expects(:put).with {|path, data| path == '/foo' }.returns(@mock_result)
- @searcher.stubs(:network).yields(@mock_connection)
- @searcher.network_put('foo', @data)
- end
-
- it "should use the provided data" do
- @mock_result = stub('mock result', :body => 'result')
- @mock_connection = stub('mock http connection')
- @mock_connection.expects(:put).with {|path, data| data == @data }.returns(@mock_result)
- @searcher.stubs(:network).yields(@mock_connection)
- @searcher.network_put('foo', @data)
- end
-
- it "should return the results of the PUT request" do
- @searcher.network_put('foo', @data).should == 'result'
- end
+ before :each do
+ Net::HTTP.stubs(:start).returns('result')
+ @details = { :host => '127.0.0.1', :port => 34343 }
+ @data = { :foo => 'bar' }
+ @searcher.stubs(:rest_connection_details).returns(@details)
+
+ @method = :network_put
+ @arguments = ["foo", @data]
+ end
+
+ it_should_behave_like "a REST http call"
+
+ it "should use the PUT http method" do
+ @mock_result = stub('mock result', :body => 'result')
+ @mock_connection = mock('mock http connection', :put => @mock_result)
+ @searcher.stubs(:network).returns(@mock_connection)
+ @searcher.network_put('foo', @data)
+ end
+
+ it "should use the provided path" do
+ @mock_result = stub('mock result', :body => 'result')
+ @mock_connection = stub('mock http connection')
+ @mock_connection.expects(:put).with {|path, data| path == '/foo' }.returns(@mock_result)
+ @searcher.stubs(:network).returns(@mock_connection)
+ @searcher.network_put('foo', @data)
+ end
+
+ it "should use the provided data" do
+ @mock_result = stub('mock result', :body => 'result')
+ @mock_connection = stub('mock http connection')
+ @mock_connection.expects(:put).with {|path, data| data == @data }.returns(@mock_result)
+ @searcher.stubs(:network).returns(@mock_connection)
+ @searcher.network_put('foo', @data)
+ end
end
describe "when doing a find" do
- before :each do
- @result = { :foo => 'bar'}.to_yaml
- @searcher.stubs(:network_fetch).returns(@result) # neuter the network connection
- @model.stubs(:from_yaml).returns(@instance)
-
- @request = stub 'request', :key => 'foo'
- end
-
- it "should look up the model instance over the network" do
- @searcher.expects(:network_fetch).returns(@result)
- @searcher.find(@request)
- end
-
- it "should look up the model instance using the named indirection" do
- @searcher.expects(:network_fetch).with {|path| path =~ %r{^#{@indirection.name.to_s}/} }.returns(@result)
- @searcher.find(@request)
- end
-
- it "should look up the model instance using the provided key" do
- @searcher.expects(:network_fetch).with {|path| path =~ %r{/foo$} }.returns(@result)
- @searcher.find(@request)
- end
-
- it "should deserialize result data to a Model instance" do
- @model.expects(:from_yaml)
- @searcher.find(@request)
- end
-
- it "should return the deserialized Model instance" do
- @searcher.find(@request).should == @instance
- end
-
- it "should return nil when deserialized model instance is nil" do
- @model.stubs(:from_yaml).returns(nil)
- @searcher.find(@request).should be_nil
- end
-
- it "should generate an error when result data deserializes improperly" do
- @model.stubs(:from_yaml).raises(ArgumentError)
- lambda { @searcher.find(@request) }.should raise_error(ArgumentError)
- end
-
- it "should generate an error when result data specifies an error" do
- @searcher.stubs(:network_fetch).returns(RuntimeError.new("bogus").to_yaml)
- lambda { @searcher.find(@request) }.should raise_error(RuntimeError)
- end
+ before :each do
+ @result = { :foo => 'bar'}.to_yaml
+ @searcher.stubs(:network_fetch).returns(@result) # neuter the network connection
+ @model.stubs(:from_yaml).returns(@instance)
+
+ @request = stub 'request', :key => 'foo'
+ end
+
+ it "should look up the model instance over the network" do
+ @searcher.expects(:network_fetch).returns(@result)
+ @searcher.find(@request)
+ end
+
+ it "should look up the model instance using the named indirection" do
+ @searcher.expects(:network_fetch).with {|path| path =~ %r{^#{@indirection.name.to_s}/} }.returns(@result)
+ @searcher.find(@request)
+ end
+
+ it "should look up the model instance using the provided key" do
+ @searcher.expects(:network_fetch).with {|path| path =~ %r{/foo$} }.returns(@result)
+ @searcher.find(@request)
+ end
+
+ it "should deserialize result data to a Model instance" do
+ @model.expects(:from_yaml)
+ @searcher.find(@request)
+ end
+
+ it "should return the deserialized Model instance" do
+ @searcher.find(@request).should == @instance
+ end
+
+ it "should return nil when deserialized model instance is nil" do
+ @model.stubs(:from_yaml).returns(nil)
+ @searcher.find(@request).should be_nil
+ end
+
+ it "should generate an error when result data deserializes improperly" do
+ @model.stubs(:from_yaml).raises(ArgumentError)
+ lambda { @searcher.find(@request) }.should raise_error(ArgumentError)
+ end
+
+ it "should generate an error when result data specifies an error" do
+ @searcher.stubs(:network_fetch).returns(RuntimeError.new("bogus").to_yaml)
+ lambda { @searcher.find(@request) }.should raise_error(RuntimeError)
+ end
end
describe "when doing a search" do
- before :each do
- @result = [1, 2].to_yaml
- @searcher.stubs(:network_fetch).returns(@result)
- @model.stubs(:from_yaml).returns(@instance)
-
- @request = stub 'request', :key => 'foo'
- end
-
- it "should look up the model data over the network" do
- @searcher.expects(:network_fetch).returns(@result)
- @searcher.search(@request)
- end
-
- it "should look up the model instance using the named indirection" do
- @searcher.expects(:network_fetch).with {|path| path =~ %r{^#{@indirection.name.to_s}s/} }.returns(@result)
- @searcher.search(@request)
- end
-
- it "should look up the model instance using the provided key" do
- @searcher.expects(:network_fetch).with {|path| path =~ %r{/foo$} }.returns(@result)
- @searcher.search(@request)
- end
-
- it "should deserialize result data into a list of Model instances" do
- @model.expects(:from_yaml).at_least(2)
- @searcher.search(@request)
- end
-
- it "should generate an error when result data deserializes improperly" do
- @model.stubs(:from_yaml).raises(ArgumentError)
- lambda { @searcher.search(@request) }.should raise_error(ArgumentError)
- end
-
- it "should generate an error when result data specifies an error" do
- @searcher.stubs(:network_fetch).returns(RuntimeError.new("bogus").to_yaml)
- lambda { @searcher.search(@request) }.should raise_error(RuntimeError)
- end
- end
-
+ before :each do
+ @result = [1, 2].to_yaml
+ @searcher.stubs(:network_fetch).returns(@result)
+ @model.stubs(:from_yaml).returns(@instance)
+
+ @request = stub 'request', :key => 'foo'
+ end
+
+ it "should look up the model data over the network" do
+ @searcher.expects(:network_fetch).returns(@result)
+ @searcher.search(@request)
+ end
+
+ it "should look up the model instance using the plural of the named indirection" do
+ @searcher.expects(:network_fetch).with {|path| path =~ %r{^#{@indirection.name.to_s}s/} }.returns(@result)
+ @searcher.search(@request)
+ end
+
+ it "should look up the model instance using the provided key" do
+ @searcher.expects(:network_fetch).with {|path| path =~ %r{/foo$} }.returns(@result)
+ @searcher.search(@request)
+ end
+
+ it "should deserialize result data into a list of Model instances" do
+ @model.expects(:from_yaml).at_least(2)
+ @searcher.search(@request)
+ end
+
+ it "should generate an error when result data deserializes improperly" do
+ @model.stubs(:from_yaml).raises(ArgumentError)
+ lambda { @searcher.search(@request) }.should raise_error(ArgumentError)
+ end
+
+ it "should generate an error when result data specifies an error" do
+ @searcher.stubs(:network_fetch).returns(RuntimeError.new("bogus").to_yaml)
+ lambda { @searcher.search(@request) }.should raise_error(RuntimeError)
+ end
+ end
+
describe "when doing a destroy" do
- before :each do
- @result = true.to_yaml
- @searcher.stubs(:network_delete).returns(@result) # neuter the network connection
- @model.stubs(:from_yaml).returns(@instance)
-
- @request = stub 'request', :key => 'foo'
- end
-
- it "should look up the model instance over the network" do
- @searcher.expects(:network_delete).returns(@result)
- @searcher.destroy(@request)
- end
-
- it "should look up the model instance using the named indirection" do
- @searcher.expects(:network_delete).with {|path| path =~ %r{^#{@indirection.name.to_s}/} }.returns(@result)
- @searcher.destroy(@request)
- end
-
- it "should look up the model instance using the provided key" do
- @searcher.expects(:network_delete).with {|path| path =~ %r{/foo$} }.returns(@result)
- @searcher.destroy(@request)
- end
-
- it "should deserialize result data" do
- YAML.expects(:load).with(@result)
- @searcher.destroy(@request)
- end
-
- it "should return deserialized result data" do
- @searcher.destroy(@request).should == true
- end
-
- it "should generate an error when result data specifies an error" do
- @searcher.stubs(:network_delete).returns(RuntimeError.new("bogus").to_yaml)
- lambda { @searcher.destroy(@request) }.should raise_error(RuntimeError)
- end
+ before :each do
+ @result = true.to_yaml
+ @searcher.stubs(:network_delete).returns(@result) # neuter the network connection
+ @model.stubs(:from_yaml).returns(@instance)
+
+ @request = stub 'request', :key => 'foo'
+ end
+
+ it "should look up the model instance over the network" do
+ @searcher.expects(:network_delete).returns(@result)
+ @searcher.destroy(@request)
+ end
+
+ it "should look up the model instance using the named indirection" do
+ @searcher.expects(:network_delete).with {|path| path =~ %r{^#{@indirection.name.to_s}/} }.returns(@result)
+ @searcher.destroy(@request)
+ end
+
+ it "should look up the model instance using the provided key" do
+ @searcher.expects(:network_delete).with {|path| path =~ %r{/foo$} }.returns(@result)
+ @searcher.destroy(@request)
+ end
+
+ it "should deserialize result data" do
+ YAML.expects(:load).with(@result)
+ @searcher.destroy(@request)
+ end
+
+ it "should return deserialized result data" do
+ @searcher.destroy(@request).should == true
+ end
+
+ it "should generate an error when result data specifies an error" do
+ @searcher.stubs(:network_delete).returns(RuntimeError.new("bogus").to_yaml)
+ lambda { @searcher.destroy(@request) }.should raise_error(RuntimeError)
+ end
end
describe "when doing a save" do
- before :each do
- @result = { :foo => 'bar'}.to_yaml
- @searcher.stubs(:network_put).returns(@result) # neuter the network connection
- @model.stubs(:from_yaml).returns(@instance)
-
- @request = stub 'request', :instance => @instance
- end
-
- it "should save the model instance over the network" do
- @searcher.expects(:network_put).returns(@result)
- @searcher.save(@request)
- end
-
- it "should save the model instance using the named indirection" do
- @searcher.expects(:network_put).with do |path, data|
- path =~ %r{^#{@indirection.name.to_s}/} and
- data == @instance.to_yaml
- end.returns(@result)
- @searcher.save(@request)
- end
-
- it "should deserialize result data to a Model instance" do
- @model.expects(:from_yaml)
- @searcher.save(@request)
- end
-
- it "should return the resulting deserialized Model instance" do
- @searcher.save(@request).should == @instance
- end
-
- it "should return nil when deserialized model instance is nil" do
- @model.stubs(:from_yaml).returns(nil)
- @searcher.save(@request).should be_nil
- end
-
- it "should generate an error when result data deserializes improperly" do
- @model.stubs(:from_yaml).raises(ArgumentError)
- lambda { @searcher.save(@request) }.should raise_error(ArgumentError)
- end
-
- it "should generate an error when result data specifies an error" do
- @searcher.stubs(:network_put).returns(RuntimeError.new("bogus").to_yaml)
- lambda { @searcher.save(@request) }.should raise_error(RuntimeError)
- end
+ before :each do
+ @result = { :foo => 'bar'}.to_yaml
+ @searcher.stubs(:network_put).returns(@result) # neuter the network connection
+ @model.stubs(:from_yaml).returns(@instance)
+
+ @request = stub 'request', :instance => @instance
+ end
+
+ it "should save the model instance over the network" do
+ @searcher.expects(:network_put).returns(@result)
+ @searcher.save(@request)
+ end
+
+ it "should save the model instance using the named indirection" do
+ @searcher.expects(:network_put).with do |path, data|
+ path =~ %r{^#{@indirection.name.to_s}/} and
+ data == @instance.to_yaml
+ end.returns(@result)
+ @searcher.save(@request)
+ end
+
+ it "should deserialize result data to a Model instance" do
+ @model.expects(:from_yaml)
+ @searcher.save(@request)
+ end
+
+ it "should return the resulting deserialized Model instance" do
+ @searcher.save(@request).should == @instance
+ end
+
+ it "should return nil when deserialized model instance is nil" do
+ @model.stubs(:from_yaml).returns(nil)
+ @searcher.save(@request).should be_nil
+ end
+
+ it "should generate an error when result data deserializes improperly" do
+ @model.stubs(:from_yaml).raises(ArgumentError)
+ lambda { @searcher.save(@request) }.should raise_error(ArgumentError)
+ end
+
+ it "should generate an error when result data specifies an error" do
+ @searcher.stubs(:network_put).returns(RuntimeError.new("bogus").to_yaml)
+ lambda { @searcher.save(@request) }.should raise_error(RuntimeError)
+ end
end
end
diff --git a/spec/unit/indirector/ssl_file.rb b/spec/unit/indirector/ssl_file.rb
new file mode 100755
index 000000000..864ba1420
--- /dev/null
+++ b/spec/unit/indirector/ssl_file.rb
@@ -0,0 +1,244 @@
+#!/usr/bin/env ruby
+#
+# Created by Luke Kanies on 2008-3-10.
+# Copyright (c) 2007. All rights reserved.
+
+require File.dirname(__FILE__) + '/../../spec_helper'
+
+require 'puppet/indirector/ssl_file'
+
+describe Puppet::Indirector::SslFile do
+ before do
+ @indirection = stub 'indirection', :name => :testing
+ Puppet::Indirector::Indirection.expects(:instance).with(:testing).returns(@indirection)
+ @file_class = Class.new(Puppet::Indirector::SslFile) do
+ def self.to_s
+ "Testing::Mytype"
+ end
+ end
+
+ @setting = :mydir
+ @file_class.store_in @setting
+ @path = "/my/directory"
+ Puppet.settings.stubs(:value).returns "stubbed_setting"
+ Puppet.settings.stubs(:value).with(@setting).returns(@path)
+ Puppet.settings.stubs(:value).with(:trace).returns(false)
+ end
+
+ it "should use :main and :ssl upon initialization" do
+ Puppet.settings.expects(:use).with(:main, :ssl)
+ @file_class.new
+ end
+
+ it "should return a nil collection directory if no directory setting has been provided" do
+ @file_class.store_in nil
+ @file_class.collection_directory.should be_nil
+ end
+
+ it "should return a nil file location if no location has been provided" do
+ @file_class.store_at nil
+ @file_class.file_location.should be_nil
+ end
+
+ it "should fail if no store directory or file location has been set" do
+ @file_class.store_in nil
+ @file_class.store_at nil
+ lambda { @file_class.new }.should raise_error(Puppet::DevError)
+ end
+
+ describe "when managing ssl files" do
+ before do
+ Puppet.settings.stubs(:use)
+ @searcher = @file_class.new
+
+ @cert = stub 'certificate', :name => "myname"
+ @certpath = File.join(@path, "myname" + ".pem")
+
+ @request = stub 'request', :key => @cert.name, :instance => @cert
+ end
+
+ it "should consider the file a ca file if the name is equal to what the SSL::Host class says is the CA name" do
+ Puppet::SSL::Host.expects(:ca_name).returns "amaca"
+ @searcher.should be_ca("amaca")
+ end
+
+ describe "when choosing the location for certificates" do
+ it "should set them at the ca setting's path if a ca setting is available and the name resolves to the CA name" do
+ @file_class.store_in nil
+ @file_class.store_at :mysetting
+ @file_class.store_ca_at :casetting
+
+ Puppet.settings.stubs(:value).with(:casetting).returns "/ca/file"
+
+ @searcher.expects(:ca?).with(@cert.name).returns true
+ @searcher.path(@cert.name).should == "/ca/file"
+ end
+
+ it "should set them at the file location if a file setting is available" do
+ @file_class.store_in nil
+ @file_class.store_at :mysetting
+
+ Puppet.settings.stubs(:value).with(:mysetting).returns "/some/file"
+
+ @searcher.path(@cert.name).should == "/some/file"
+ end
+
+ it "should set them in the setting directory, with the certificate name plus '.pem', if a directory setting is available" do
+ @searcher.path(@cert.name).should == @certpath
+ end
+ end
+
+ describe "when finding certificates on disk" do
+ describe "and no certificate is present" do
+ before do
+ FileTest.expects(:exist?).with(@certpath).returns false
+ end
+
+ it "should return nil" do
+ @searcher.find(@request).should be_nil
+ end
+ end
+
+ describe "and a certificate is present" do
+ before do
+ FileTest.expects(:exist?).with(@certpath).returns true
+ end
+
+ it "should return an instance of the model, which it should use to read the certificate" do
+ cert = mock 'cert'
+ model = mock 'model'
+ @file_class.stubs(:model).returns model
+
+ model.expects(:new).with("myname").returns cert
+ cert.expects(:read).with(@certpath)
+ @searcher.find(@request).should equal(cert)
+ end
+ end
+ end
+
+ describe "when saving certificates to disk" do
+ before do
+ FileTest.stubs(:directory?).returns true
+ FileTest.stubs(:writable?).returns true
+ end
+
+ it "should fail if the directory is absent" do
+ FileTest.expects(:directory?).with(File.dirname(@certpath)).returns false
+ lambda { @searcher.save(@request) }.should raise_error(Puppet::Error)
+ end
+
+ it "should fail if the directory is not writeable" do
+ FileTest.stubs(:directory?).returns true
+ FileTest.expects(:writable?).with(File.dirname(@certpath)).returns false
+ lambda { @searcher.save(@request) }.should raise_error(Puppet::Error)
+ end
+
+ it "should save to the path the output of converting the certificate to a string" do
+ fh = mock 'filehandle'
+ fh.expects(:print).with("mycert")
+
+ @searcher.stubs(:write).yields fh
+ @cert.expects(:to_s).returns "mycert"
+
+ @searcher.save(@request)
+ end
+
+ describe "and a directory setting is set" do
+ it "should open the file in write mode" do
+ @searcher.class.store_in @setting
+ fh = mock 'filehandle'
+ fh.stubs :print
+ File.expects(:open).with(@certpath, "w").yields(fh)
+
+ @searcher.save(@request)
+ end
+ end
+
+ describe "and a file location is set" do
+ it "should use the filehandle provided by the Settings" do
+ @searcher.class.store_at @setting
+
+ fh = mock 'filehandle'
+ fh.stubs :print
+ Puppet.settings.expects(:write).with(@setting).yields fh
+ @searcher.save(@request)
+ end
+ end
+
+ describe "and the name is the CA name and a ca setting is set" do
+ it "should use the filehandle provided by the Settings" do
+ @searcher.class.store_at @setting
+ @searcher.class.store_ca_at :castuff
+
+ fh = mock 'filehandle'
+ fh.stubs :print
+ Puppet.settings.expects(:write).with(:castuff).yields fh
+ @searcher.stubs(:ca?).returns true
+ @searcher.save(@request)
+ end
+ end
+ end
+
+ describe "when destroying certificates" do
+ describe "that do not exist" do
+ before do
+ FileTest.expects(:exist?).with(@certpath).returns false
+ end
+
+ it "should return false" do
+ @searcher.destroy(@request).should be_false
+ end
+ end
+
+ describe "that exist" do
+ before do
+ FileTest.expects(:exist?).with(@certpath).returns true
+ end
+
+ it "should unlink the certificate file" do
+ File.expects(:unlink).with(@certpath)
+ @searcher.destroy(@request)
+ end
+ end
+ end
+
+ describe "when searching for certificates" do
+ before do
+ @model = mock 'model'
+ @file_class.stubs(:model).returns @model
+ end
+ it "should return a certificate instance for all files that exist" do
+ Dir.expects(:entries).with(@path).returns %w{one.pem two.pem}
+
+ one = stub 'one', :read => nil
+ two = stub 'two', :read => nil
+
+ @model.expects(:new).with("one").returns one
+ @model.expects(:new).with("two").returns two
+
+ @searcher.search(@request).should == [one, two]
+ end
+
+ it "should read each certificate in using the model's :read method" do
+ Dir.expects(:entries).with(@path).returns %w{one.pem}
+
+ one = stub 'one'
+ one.expects(:read).with(File.join(@path, "one.pem"))
+
+ @model.expects(:new).with("one").returns one
+
+ @searcher.search(@request)
+ end
+
+ it "should skip any files that do not match /\.pem$/" do
+ Dir.expects(:entries).with(@path).returns %w{. .. one.pem}
+
+ one = stub 'one', :read => nil
+
+ @model.expects(:new).with("one").returns one
+
+ @searcher.search(@request)
+ end
+ end
+ end
+end
diff --git a/spec/unit/indirector/ssl_rsa/file.rb b/spec/unit/indirector/ssl_rsa/file.rb
deleted file mode 100755
index 76e5e3a94..000000000
--- a/spec/unit/indirector/ssl_rsa/file.rb
+++ /dev/null
@@ -1,116 +0,0 @@
-#!/usr/bin/env ruby
-#
-# Created by Luke Kanies on 2007-9-22.
-# Copyright (c) 2007. All rights reserved.
-
-require File.dirname(__FILE__) + '/../../../spec_helper'
-
-require 'puppet/sslcertificates/monkey_patch'
-require 'puppet/indirector/ssl_rsa/file'
-
-
-describe Puppet::Indirector::SslRsa::File do
-
- it "should be a subclass of the File terminus class" do
- Puppet::Indirector::SslRsa::File.superclass.should equal(Puppet::Indirector::File)
- end
-
- it "should have documentation" do
- Puppet::Indirector::SslRsa::File.doc.should be_instance_of(String)
- end
-end
-
-describe Puppet::Indirector::SslRsa::File, " when choosing a path for a ca key" do
- before do
- @file = Puppet::Indirector::SslRsa::File.new
- @name = :ca
- end
-
- it "should use the cadir" do
- Puppet.settings.stubs(:value).with(:cadir).returns("/dir")
- @file.path(@name).should =~ /^\/dir/
- end
-
- it "should use 'ca_key.pem' as the file name" do
- @file.path(@name).should =~ /ca_key\.pem$/
- end
-end
-
-describe Puppet::Indirector::SslRsa::File, " when choosing a path for a non-ca key" do
- before do
- @file = Puppet::Indirector::SslRsa::File.new
- @name = :publickey
- end
-
- it "should use the publickeydir" do
- Puppet.settings.stubs(:value).with(:publickeydir).returns("/dir")
- @file.path(@name).should =~ /^\/dir/
- end
-
- it "should use the key name with the pem file extension" do
- @file.path(@name).should =~ /#{@name}\.pem$/
- end
-end
-
-describe Puppet::Indirector::SslRsa::File, " when saving" do
- before do
- @file = Puppet::Indirector::SslRsa::File.new
-
- Puppet.settings.stubs(:value).with(:publickeydir).returns("/dir")
- @key = stub "key", :name => "foo"
- end
-
- it "should store the rsa key to disk in pem format" do
- @key.expects(:to_pem).returns(:data)
- @path = "/dir/foo.pem"
- filehandle = mock "filehandle"
- File.expects(:open).with(@path, "w").yields(filehandle)
- filehandle.expects(:print).with(:data)
- @file.save(@key)
- end
-end
-
-describe Puppet::Indirector::SslRsa::File, " when finding a key by name" do
- before do
- @file = Puppet::Indirector::SslRsa::File.new
-
- Puppet.settings.stubs(:value).with(:publickeydir).returns("/dir")
- @name = "foo"
- end
-
- it "should return the key as a key object on success" do
- @path = "/dir/foo.pem"
- FileTest.stubs(:exists?).with(@path).returns(true)
- File.stubs(:read).with(@path).returns(:data)
- OpenSSL::PKey::RSA.expects(:new).with(:data).returns(:mykey)
- @file.find(@name).should == :mykey
- end
-
- it "should return 'nil' on failure" do
- @path = "/dir/foo.pem"
- FileTest.stubs(:exists?).with(@path).returns(false)
- @file.find(@name).should == nil
- end
-end
-
-describe Puppet::Indirector::SslRsa::File, " when removing a key" do
- before do
- @file = Puppet::Indirector::SslRsa::File.new
-
- Puppet.settings.stubs(:value).with(:publickeydir).returns("/dir")
- @name = "foo"
- end
-
- it "should remove the key from disk and return true" do
- @path = "/dir/foo.pem"
- FileTest.stubs(:exists?).with(@path).returns(true)
- File.stubs(:unlink).with(@path).returns(true)
- @file.destroy(@name).should == true
- end
-
- it "should return an exception on failure" do
- @path = "/dir/foo.pem"
- FileTest.stubs(:exists?).with(@path).returns(false)
- @file.destroy(@name).should == nil
- end
-end
diff --git a/spec/unit/network/http/mongrel.rb b/spec/unit/network/http/mongrel.rb
index ccfca2f55..1f87fd943 100755
--- a/spec/unit/network/http/mongrel.rb
+++ b/spec/unit/network/http/mongrel.rb
@@ -23,7 +23,14 @@ describe Puppet::Network::HTTP::Mongrel, "when turning on listening" do
@mock_mongrel.stubs(:run)
@mock_mongrel.stubs(:register)
Mongrel::HttpServer.stubs(:new).returns(@mock_mongrel)
- @listen_params = { :address => "127.0.0.1", :port => 31337, :handlers => [ :node, :catalog ], :protocols => [ :rest ] }
+
+ @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,
+ :handlers => [ :node, :catalog ], :protocols => [ :rest, :xmlrpc ],
+ :xmlrpc_handlers => [ :status, :fileserver ]
+ }
end
it "should fail if already listening" do
@@ -63,18 +70,38 @@ describe Puppet::Network::HTTP::Mongrel, "when turning on listening" do
@server.should be_listening
end
- it "should instantiate a handler for each protocol+handler pair to configure web server routing" do
- @listen_params[:protocols].each do |protocol|
- @listen_params[:handlers].each do |handler|
- @mock_mongrel.expects(:register)
+ describe "when providing REST services" do
+ it "should instantiate a handler for each protocol+handler pair to configure web server routing" do
+ @listen_params[:protocols].each do |protocol|
+ @listen_params[:handlers].each do |handler|
+ @mock_mongrel.expects(:register)
+ end
end
+ @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
- @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)
+
+ 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
end
it "should fail if services from an unknown protocol are requested" do
diff --git a/spec/unit/network/http/webrick.rb b/spec/unit/network/http/webrick.rb
index 78bd39145..e3c3b81c0 100755
--- a/spec/unit/network/http/webrick.rb
+++ b/spec/unit/network/http/webrick.rb
@@ -18,18 +18,21 @@ describe Puppet::Network::HTTP::WEBrick, "when turning on listening" do
[:mount, :start, :shutdown].each {|meth| @mock_webrick.stubs(meth)}
WEBrick::HTTPServer.stubs(:new).returns(@mock_webrick)
@server = Puppet::Network::HTTP::WEBrick.new
- @listen_params = { :address => "127.0.0.1", :port => 31337, :handlers => [ :node, :catalog ], :protocols => [ :rest ] }
+ [: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 ], :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 handler" do
Proc.new { @server.listen(@listen_params.delete_if {|k,v| :handlers == k}) }.should raise_error(ArgumentError)
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
@@ -37,7 +40,7 @@ describe Puppet::Network::HTTP::WEBrick, "when turning on listening" do
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
@@ -46,35 +49,107 @@ describe Puppet::Network::HTTP::WEBrick, "when turning on listening" do
@mock_webrick.expects(:start)
@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
-
- it "should instantiate a handler for each protocol+handler pair to configure web server routing" do
- @listen_params[:protocols].each do |protocol|
- mock_handler = mock("handler instance for [#{protocol}]")
- mock_handler_class = mock("handler class for [#{protocol}]")
- @listen_params[:handlers].each do |handler|
- @mock_webrick.expects(:mount)
+
+ describe "when the REST protocol is requested" do
+ it "should use a WEBrick + REST class to configure WEBrick" do
+ Puppet::Network::HTTP::WEBrick.expects(:class_for_protocol).with(:rest).at_least_once
+ @server.listen(@listen_params.merge(:protocols => [:rest]))
+ end
+
+ it "should instantiate a handler for each protocol+handler pair to configure web server routing" do
+ @listen_params[:protocols].each do |protocol|
+ @listen_params[:handlers].each do |handler|
+ @mock_webrick.expects(:mount)
+ end
end
+ @server.listen(@listen_params)
end
- @server.listen(@listen_params)
end
- it "should use a WEBrick + REST class to configure WEBrick when REST services are requested" do
- Puppet::Network::HTTP::WEBrick.expects(:class_for_protocol).with(:rest).at_least_once
- @server.listen(@listen_params.merge(:protocols => [:rest]))
+ 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')
+
+ @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
+
+ 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
end
-
+
it "should fail if services from an unknown protocol are requested" do
Proc.new { @server.listen(@listen_params.merge(:protocols => [ :foo ]))}.should raise_error
end
@@ -85,15 +160,15 @@ describe Puppet::Network::HTTP::WEBrick, "when looking up the class to handle a
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 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
@@ -105,22 +180,182 @@ describe Puppet::Network::HTTP::WEBrick, "when turning off listening" do
[: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
+ Puppet.settings.stubs(:value).returns "something"
+ Puppet.settings.stubs(:use)
+ @filehandle = stub 'handle', :fcntl => nil, :sync => nil
+
+ 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")
+
+ @server.setup_logger
+ end
+
+ it "should use the masterlog if the process name is 'puppetmasterd'" do
+ Puppet.settings.stubs(:value).with(:name).returns "puppetmasterd"
+ Puppet.settings.expects(:value).with(:masterhttplog).returns "/master/log"
+
+ File.expects(:open).with("/master/log", "a+").returns @filehandle
+
+ @server.setup_logger
+ end
+
+ it "should use the httplog if the process name is not 'puppetmasterd'" do
+ Puppet.settings.stubs(:value).with(:name).returns "other"
+ Puppet.settings.expects(:value).with(:httplog).returns "/other/log"
+
+ File.expects(:open).with("/other/log", "a+").returns @filehandle
+
+ @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)
+
+ @server.setup_logger
+ end
+
+ it "should sync the filehandle" do
+ @filehandle.expects(:sync)
+
+ @server.setup_logger
+ end
+ end
+
+ it "should create a new WEBrick::Log instance with the open filehandle" do
+ WEBrick::Log.expects(:new).with(@filehandle)
+
+ @server.setup_logger
+ end
+
+ 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 }
+
+ @server.setup_logger
+ end
+
+ 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
+
+ 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
+ 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"
+
+ Puppet::SSL::Certificate.stubs(:find).with('ca').returns @cert
+
+ Puppet::SSL::Host.stubs(:new).returns @host
+ end
+
+ it "should use the key from an SSL::Host instance created with the default name" do
+ Puppet::SSL::Host.expects(:new).returns @host
+ @host.expects(:key).returns @key
+
+ @server.setup_ssl[:SSLPrivateKey].should == "mykey"
+ end
+
+ it "should generate its files if no certificate can be found" do
+ @host.expects(:certificate).times(2).returns(nil).then.returns(@cert)
+
+ @host.expects(:generate)
+
+ @server.setup_ssl
+ 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
+
+ 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'
+
+ @server.setup_ssl[:SSLCACertificateFile].should == "/ca/crt"
+ 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 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'
+
+ @host.expects(:ssl_store).returns "mystore"
+
+ @server.setup_ssl[:SSLCertificateStore].should == "mystore"
+ 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.rb b/spec/unit/network/http_pool.rb
index 0c67082c6..a986292f6 100755
--- a/spec/unit/network/http_pool.rb
+++ b/spec/unit/network/http_pool.rb
@@ -6,105 +6,28 @@
require File.dirname(__FILE__) + '/../../spec_helper'
require 'puppet/network/http_pool'
-describe Puppet::Network::HttpPool, " 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'
- [:add_file,:purpose=].each { |m| @store.stubs(m) }
+describe Puppet::Network::HttpPool do
+ after do
+ Puppet::Util::Cacher.invalidate
+ 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 do nothing if no certificate is available" do
- Puppet::Network::HttpPool.expects(:read_cert).returns(false)
- @http.expects(:cert=).never
- Puppet::Network::HttpPool.cert_setup(@http)
- end
-
- it "should add a certificate store" do
- Puppet::Network::HttpPool.stubs(:read_cert).returns(true)
- Puppet::Network::HttpPool.stubs(:key).returns(:mykey)
- OpenSSL::X509::Store.expects(:new).returns(@store)
- @http.expects(:cert_store=).with(@store)
-
- Puppet::Network::HttpPool.cert_setup(@http)
- end
-
- it "should add the local CA cert to the certificate store" do
- Puppet::Network::HttpPool.stubs(:read_cert).returns(true)
- OpenSSL::X509::Store.expects(:new).returns(@store)
- Puppet.settings.stubs(:value).with(:localcacert).returns("/some/file")
- Puppet.settings.stubs(:value).with(:localcacert).returns("/some/file")
- @store.expects(:add_file).with("/some/file")
-
- Puppet::Network::HttpPool.stubs(:key).returns(:whatever)
-
- Puppet::Network::HttpPool.cert_setup(@http)
- end
-
- it "should set the purpose of the cert store to OpenSSL::X509::PURPOSE_SSL_CLIENT" do
- Puppet::Network::HttpPool.stubs(:read_cert).returns(true)
- Puppet::Network::HttpPool.stubs(:key).returns(:mykey)
- OpenSSL::X509::Store.expects(:new).returns(@store)
-
- @store.expects(:purpose=).with(OpenSSL::X509::PURPOSE_SSL_CLIENT)
-
- Puppet::Network::HttpPool.cert_setup(@http)
- end
-
- it "should add the client certificate" do
- Puppet::Network::HttpPool.stubs(:read_cert).returns(true)
- Puppet::Network::HttpPool.stubs(:cert).returns(:mycert)
- Puppet::Network::HttpPool.stubs(:key).returns(:mykey)
- OpenSSL::X509::Store.expects(:new).returns(@store)
-
- @http.expects(:cert=).with(:mycert)
-
- Puppet::Network::HttpPool.cert_setup(@http)
- end
-
- it "should add the client key" do
- Puppet::Network::HttpPool.stubs(:read_cert).returns(true)
- Puppet::Network::HttpPool.stubs(:key).returns(:mykey)
- OpenSSL::X509::Store.expects(:new).returns(@store)
-
- @http.expects(:key=).with(:mykey)
-
- Puppet::Network::HttpPool.cert_setup(@http)
+ it "should use an SSL::Host instance to get its certificate information" do
+ host = mock 'host'
+ Puppet::SSL::Host.expects(:new).with().returns host
+ Puppet::Network::HttpPool.ssl_host.should equal(host)
end
- it "should set the verify mode to OpenSSL::SSL::VERIFY_PEER" do
- Puppet::Network::HttpPool.stubs(:read_cert).returns(true)
- Puppet::Network::HttpPool.stubs(:key).returns(:mykey)
- OpenSSL::X509::Store.expects(:new).returns(@store)
-
- @http.expects(:verify_mode=).with(OpenSSL::SSL::VERIFY_PEER)
-
- Puppet::Network::HttpPool.cert_setup(@http)
- end
-
- it "should set the ca file" do
- Puppet::Network::HttpPool.stubs(:read_cert).returns(true)
- Puppet.settings.stubs(:value).with(:localcacert).returns("/some/file")
- OpenSSL::X509::Store.expects(:new).returns(@store)
-
- @http.expects(:ca_file=).with("/some/file")
-
- Puppet::Network::HttpPool.stubs(:key).returns(:whatever)
-
- 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
-
- after do
- Puppet::Network::HttpPool.clear_http_instances
+ it "should reuse the same host instance" do
+ host = mock 'host'
+ Puppet::SSL::Host.expects(:new).with().once.returns host
+ Puppet::Network::HttpPool.ssl_host.should equal(host)
+ Puppet::Network::HttpPool.ssl_host.should equal(host)
end
describe "when managing http instances" do
@@ -115,7 +38,7 @@ describe Puppet::Network::HttpPool, " when adding certificate information to htt
end
before do
- # All of hte cert stuff is tested elsewhere
+ # All of the cert stuff is tested elsewhere
Puppet::Network::HttpPool.stubs(:cert_setup)
end
@@ -150,7 +73,7 @@ describe Puppet::Network::HttpPool, " when adding certificate information to htt
Puppet::Network::HttpPool.http_instance("me", 54321).open_timeout.should == 120
end
- describe "when http keep-alive is enabled" do
+ describe "and http keep-alive is enabled" do
before do
Puppet::Network::HttpPool.stubs(:keep_alive?).returns true
end
@@ -199,9 +122,19 @@ describe Puppet::Network::HttpPool, " when adding certificate information to htt
one.expects(:finish).never
Puppet::Network::HttpPool.clear_http_instances
end
+
+ it "should reset its ssl host when clearing the cache" do
+ stub_settings :http_proxy_host => "myhost", :http_proxy_port => 432, :configtimeout => 120, :http_enable_post_connection_check => true, :certname => "a"
+ one = Puppet::Network::HttpPool.http_instance("me", 54321)
+ one.expects(:started?).returns(false)
+ one.expects(:finish).never
+ id = Puppet::Network::HttpPool.ssl_host.object_id
+ Puppet::Network::HttpPool.clear_http_instances
+ Puppet::Network::HttpPool.ssl_host.object_id.should_not == id
+ end
end
- describe "when http keep-alive is disabled" do
+ describe "and http keep-alive is disabled" do
before do
Puppet::Network::HttpPool.stubs(:keep_alive?).returns false
end
@@ -213,26 +146,73 @@ describe Puppet::Network::HttpPool, " when adding certificate information to htt
end
end
- # We mostly have to do this for testing, since in real life people
- # won't change certs within a single process.
- it "should remove its loaded certificate when clearing the cache" do
- Puppet::Network::HttpPool.instance_variable_set("@cert", :yay)
+ after do
Puppet::Network::HttpPool.clear_http_instances
- # Can't use the accessor, because it will read the cert in
- Puppet::Network::HttpPool.instance_variable_get("@cert").should be_nil
end
+ end
- # We mostly have to do this for testing, since in real life people
- # won't change certs within a single process.
- it "should remove its loaded key when clearing the cache" do
- Puppet::Network::HttpPool.instance_variable_set("@key", :yay)
- Puppet::Network::HttpPool.clear_http_instances
- # Can't use the accessor, because it will read the cert in
- Puppet::Network::HttpPool.instance_variable_get("@key").should be_nil
+ 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"
+
+ FileTest.stubs(:exist?).with("/host/cert").returns true
+
+ Puppet::Network::HttpPool.stubs(:ssl_host).returns @host
end
- after do
- Puppet::Network::HttpPool.clear_http_instances
+ it "should do nothing if no 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 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"
+ @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
end
end
diff --git a/spec/unit/network/server.rb b/spec/unit/network/server.rb
index 4e47c22fd..5332964c6 100755
--- a/spec/unit/network/server.rb
+++ b/spec/unit/network/server.rb
@@ -6,311 +6,527 @@
require File.dirname(__FILE__) + '/../../spec_helper'
require 'puppet/network/server'
-describe Puppet::Network::Server, "when initializing" do
+describe Puppet::Network::Server do
before do
@mock_http_server_class = mock('http server class')
- Puppet.stubs(:[]).with(:servertype).returns(:suparserver)
+ Puppet.settings.stubs(:use)
+ Puppet.settings.stubs(:value).with(:name).returns("me")
+ Puppet.settings.stubs(:value).with(:servertype).returns(:suparserver)
Puppet::Network::HTTP.stubs(:server_class_by_type).returns(@mock_http_server_class)
- end
-
- it "should allow specifying a listening address" do
- Puppet.stubs(:[]).with(:masterport).returns('')
- @server = Puppet::Network::Server.new(:address => "127.0.0.1")
- @server.address.should == "127.0.0.1"
+ Puppet.settings.stubs(:value).with(:servertype).returns(:suparserver)
+ @server = Puppet::Network::Server.new(:address => "127.0.0.1", :port => 31337)
end
- it "should allow specifying a listening port" do
- Puppet.stubs(:[]).with(:bindaddress).returns('')
- @server = Puppet::Network::Server.new(:port => 31337)
- @server.port.should == 31337
- end
-
- it "should use the Puppet configurator to find a default listening address" do
- Puppet.stubs(:[]).with(:masterport).returns('')
- Puppet.expects(:[]).with(:bindaddress).returns("10.0.0.1")
- @server = Puppet::Network::Server.new
- @server.address.should == "10.0.0.1"
- end
+ describe "when initializing" do
+ before do
+ Puppet::Indirector::Indirection.stubs(:model).returns mock('indirection')
+ Puppet::Network::Handler.stubs(:handler).returns mock('xmlrpc_handler')
+ end
- it "should use the Puppet configurator to find a default listening port" do
- Puppet.stubs(:[]).with(:bindaddress).returns('')
- Puppet.expects(:[]).with(:masterport).returns(6667)
- @server = Puppet::Network::Server.new
- @server.port.should == 6667
- end
+ it "should allow specifying a listening address" do
+ Puppet.settings.stubs(:value).with(:masterport).returns('')
+ @server = Puppet::Network::Server.new(:address => "127.0.0.1")
+ @server.address.should == "127.0.0.1"
+ end
- it "should fail to initialize if no listening address can be found" do
- Puppet.stubs(:[]).with(:masterport).returns(6667)
- Puppet.stubs(:[]).with(:bindaddress).returns(nil)
- Proc.new { Puppet::Network::Server.new }.should raise_error(ArgumentError)
- end
-
- it "should fail to initialize if no listening port can be found" do
- Puppet.stubs(:[]).with(:bindaddress).returns("127.0.0.1")
- Puppet.stubs(:[]).with(:masterport).returns(nil)
- Proc.new { Puppet::Network::Server.new }.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 Puppet configurator to determine which HTTP server will be used to provide access to clients" do
- Puppet.expects(:[]).with(:servertype).returns(:suparserver)
- @server = Puppet::Network::Server.new(:address => "127.0.0.1", :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.expects(:[]).with(:servertype).returns(nil)
- Proc.new { Puppet::Network::Server.new(:address => "127.0.0.1", :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(:address => "127.0.0.1", :port => 31337)
- end
-
- it "should fail if the HTTP server class is unknown" do
- Puppet::Network::HTTP.stubs(:server_class_by_type).returns(nil)
- Proc.new { Puppet::Network::Server.new(:address => "127.0.0.1", :port => 31337) }.should raise_error(ArgumentError)
- end
-
- it "should allow registering indirections" do
- @server = Puppet::Network::Server.new(:address => "127.0.0.1", :port => 31337, :handlers => [ :foo, :bar, :baz])
- Proc.new { @server.unregister(:foo, :bar, :baz) }.should_not raise_error
- end
-
- it "should not be listening after initialization" do
- Puppet::Network::Server.new(:address => "127.0.0.1", :port => 31337).should_not be_listening
- end
-end
+ it "should use the Puppet configurator to find a 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
-describe Puppet::Network::Server, "in general" do
- before do
- @mock_http_server_class = mock('http server class')
- Puppet::Network::HTTP.stubs(:server_class_by_type).returns(@mock_http_server_class)
- Puppet.stubs(:[]).with(:servertype).returns(:suparserver)
- @server = Puppet::Network::Server.new(:address => "127.0.0.1", :port => 31337)
- end
-
- it "should allow registering an indirection for client access by specifying its indirection name" do
- Proc.new { @server.register(:foo) }.should_not raise_error
- end
-
- it "should require at least one indirection name when registering indirections for client access" do
- Proc.new { @server.register }.should raise_error(ArgumentError)
- end
-
- it "should allow for numerous indirections to be registered at once for client access" do
- Proc.new { @server.register(:foo, :bar, :baz) }.should_not raise_error
- 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 address can be found" do
+ Puppet.settings.stubs(:value).with(:masterport).returns(6667)
+ Puppet.settings.stubs(:value).with(:bindaddress).returns(nil)
+ lambda { Puppet::Network::Server.new }.should raise_error(ArgumentError)
+ 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(:address => "127.0.0.1", :port => 31337)
+ @server.server_type.should == :suparserver
+ end
- it "should allow the use of indirection names to specify which indirections are to be no longer accessible to clients" do
- @server.register(:foo)
- Proc.new { @server.unregister(:foo) }.should_not raise_error
+ 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(:address => "127.0.0.1", :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(:address => "127.0.0.1", :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(:address => "127.0.0.1", :port => 31337) }.should raise_error(ArgumentError)
+ end
+
+ it "should allow registering REST handlers" do
+ @server = Puppet::Network::Server.new(:address => "127.0.0.1", :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(:address => "127.0.0.1", :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(:address => "127.0.0.1", :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(:address => "127.0.0.1", :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(:address => "127.0.0.1", :port => 31337, :xmlrpc_handlers => [ :foo, :bar, :baz])
+ end
end
- it "should leave other indirections accessible to clients when turning off indirections" do
- @server.register(:foo, :bar)
- @server.unregister(:foo)
- Proc.new { @server.unregister(:bar)}.should_not raise_error
+ # 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
-
- it "should allow specifying numerous indirections which are to be no longer accessible to clients" do
- @server.register(:foo, :bar)
- Proc.new { @server.unregister(:foo, :bar) }.should_not raise_error
+
+ 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 create its PID file" do
+ @server.expects(:create_pidfile)
+ @server.start
+ end
end
-
- it "should not turn off any indirections if given unknown indirection names to turn off" do
- @server.register(:foo, :bar)
- Proc.new { @server.unregister(:foo, :bar, :baz) }.should raise_error(ArgumentError)
- Proc.new { @server.unregister(:foo, :bar) }.should_not raise_error
+
+ describe "when being stopped" do
+ before do
+ @server.stubs(:unlisten)
+ @server.stubs(:remove_pidfile)
+ end
+
+ it "should unlisten" do
+ @server.expects(:unlisten)
+ @server.stop
+ end
+
+ it "should remove its PID file" do
+ @server.expects(:remove_pidfile)
+ @server.stop
+ end
end
-
- it "should not allow turning off unknown indirection names" do
- @server.register(:foo, :bar)
- Proc.new { @server.unregister(:baz) }.should raise_error(ArgumentError)
+
+ describe "when creating its pidfile" do
+ it "should use an exclusive mutex" do
+ Puppet.settings.expects(:value).with(:name).returns "me"
+
+ sync = mock 'sync'
+ Puppet::Util.expects(:sync).with("me").returns sync
+
+ sync.expects(:synchronize).with(Sync::EX)
+ @server.create_pidfile
+ end
+
+ it "should lock the pidfile using the Pidlock class" do
+ pidfile = mock 'pidfile'
+
+ Puppet.settings.stubs(:value).with(:name).returns "eh"
+ Puppet.settings.expects(:value).with(:pidfile).returns "/my/file"
+
+ Puppet::Util::Pidlock.expects(:new).with("/my/file").returns pidfile
+
+ pidfile.expects(:lock).returns true
+ @server.create_pidfile
+ end
+
+ it "should fail if it cannot lock" do
+ pidfile = mock 'pidfile'
+
+ Puppet.settings.stubs(:value).with(:name).returns "eh"
+ Puppet.settings.stubs(:value).with(:pidfile).returns "/my/file"
+
+ Puppet::Util::Pidlock.expects(:new).with("/my/file").returns pidfile
+
+ pidfile.expects(:lock).returns false
+
+ lambda { @server.create_pidfile }.should raise_error
+ end
end
-
- it "should disable client access immediately when turning off indirections" do
- @server.register(:foo, :bar)
- @server.unregister(:foo)
- Proc.new { @server.unregister(:foo) }.should raise_error(ArgumentError)
+
+ describe "when removing its pidfile" do
+ it "should use an exclusive mutex" do
+ Puppet.settings.expects(:value).with(:name).returns "me"
+
+ sync = mock 'sync'
+ Puppet::Util.expects(:sync).with("me").returns sync
+
+ sync.expects(:synchronize).with(Sync::EX)
+ @server.remove_pidfile
+ 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
+
+ Puppet.settings.stubs(:value).with(:name).returns "eh"
+ Puppet.settings.stubs(:value).with(:pidfile).returns "/my/file"
+
+ pidfile.expects(:unlock).never
+ @server.remove_pidfile
+ 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
+
+ Puppet.settings.stubs(:value).with(:name).returns "eh"
+ Puppet.settings.stubs(:value).with(:pidfile).returns "/my/file"
+
+ @server.remove_pidfile
+ 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
+
+ Puppet.settings.stubs(:value).with(:name).returns "eh"
+ Puppet.settings.stubs(:value).with(:pidfile).returns "/my/file"
+
+ Puppet.expects :err
+ @server.remove_pidfile
+ end
end
-
- it "should allow turning off all indirections at once" do
- @server.register(:foo, :bar)
- @server.unregister
- [ :foo, :bar, :baz].each do |indirection|
- Proc.new { @server.unregister(indirection) }.should raise_error(ArgumentError)
+
+ describe "when managing indirection registrations" do
+ before do
+ Puppet::Indirector::Indirection.stubs(:model).returns mock('indirection')
+ 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 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 require at least one indirection name when registering indirections for client access" do
+ lambda { @server.register }.should raise_error(ArgumentError)
+ end
+
+ 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 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 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 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 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 not allow turning off unknown indirection names" do
+ @server.register(:foo, :bar)
+ lambda { @server.unregister(:baz) }.should raise_error(ArgumentError)
+ 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 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 provide a means of determining whether it is listening" do
@server.should respond_to(:listening?)
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
end
-
- it "should allow for multiple configurations, each handling different indirections" do
- @server2 = Puppet::Network::Server.new(:address => "127.0.0.1", :port => 31337)
- @server.register(:foo, :bar)
- @server2.register(:foo, :xyzzy)
- @server.unregister(:foo, :bar)
- @server2.unregister(:foo, :xyzzy)
- Proc.new { @server.unregister(:xyzzy) }.should raise_error(ArgumentError)
- Proc.new { @server2.unregister(:bar) }.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 only support the REST protocol at this time" do
- @server.protocols.should == [ :rest ]
+
+ it "should set the protocols to :rest and :xmlrpc" do
+ @server.protocols.should == [ :rest, :xmlrpc ]
end
-
+
it "should provide a means of determining the listening address" do
@server.address.should == "127.0.0.1"
end
-
+
it "should provide a means of determining the listening port" do
@server.port.should == 31337
end
-end
-describe Puppet::Network::Server, "when listening is off" do
- before do
- @mock_http_server_class = mock('http server class')
- Puppet::Network::HTTP.stubs(:server_class_by_type).returns(@mock_http_server_class)
- Puppet.stubs(:[]).with(:servertype).returns(:suparserver)
- @server = Puppet::Network::Server.new(:address => "127.0.0.1", :port => 31337)
- @mock_http_server = mock('http server')
- @mock_http_server.stubs(:listen)
- @server.stubs(:http_server).returns(@mock_http_server)
- end
+ it "should allow for multiple configurations, each handling different indirections" do
+ Puppet::Indirector::Indirection.stubs(:model).returns mock('indirection')
- it "should indicate that it is not listening" do
- @server.should_not be_listening
+ @server2 = Puppet::Network::Server.new(:address => "127.0.0.1", :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 allow listening to be turned off" do
- Proc.new { @server.unlisten }.should raise_error(RuntimeError)
- end
-
- it "should allow listening to be turned on" do
- Proc.new { @server.listen }.should_not raise_error
- end
-
-end
-describe Puppet::Network::Server, "when listening is on" do
- before do
- @mock_http_server_class = mock('http server class')
- Puppet::Network::HTTP.stubs(:server_class_by_type).returns(@mock_http_server_class)
- Puppet.stubs(:[]).with(:servertype).returns(:suparserver)
- @server = Puppet::Network::Server.new(:address => "127.0.0.1", :port => 31337)
- @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 listening is turned off" do
- @server.should be_listening
- end
-
- it "should not allow listening to be turned on" do
- Proc.new { @server.listen }.should raise_error(RuntimeError)
- end
-
- it "should allow listening to be turned off" do
- Proc.new { @server.unlisten }.should_not raise_error
- end
-end
-
-describe Puppet::Network::Server, "when listening is being turned on" do
- before do
- @mock_http_server_class = mock('http server class')
- Puppet::Network::HTTP.stubs(:server_class_by_type).returns(@mock_http_server_class)
- Puppet.stubs(:[]).with(:servertype).returns(:suparserver)
- @server = Puppet::Network::Server.new(:address => "127.0.0.1", :port => 31337, :handlers => [:node])
- @mock_http_server = mock('http server')
- @mock_http_server.stubs(:listen)
- end
+ describe "when managing xmlrpc registrations" do
+ before do
+ Puppet::Network::Handler.stubs(:handler).returns mock('xmlrpc_handler')
+ 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 allow registering an xmlrpc handler by specifying its namespace" do
+ lambda { @server.register_xmlrpc(:foo) }.should_not raise_error
+ 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 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
+ it "should require that the xmlrpc namespace be valid" do
+ Puppet::Network::Handler.stubs(:handler).returns nil
+
+ lambda { @server.register_xmlrpc(:foo) }.should raise_error(ArgumentError)
+ 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
-
- 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 ]
- end
- @server.listen
+
+ 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
-end
-describe Puppet::Network::Server, "when listening is being turned off" do
- before do
- @mock_http_server_class = mock('http server class')
- Puppet::Network::HTTP.stubs(:server_class_by_type).returns(@mock_http_server_class)
- Puppet.stubs(:[]).with(:servertype).returns(:suparserver)
- @server = Puppet::Network::Server.new(:address => "127.0.0.1", :port => 31337)
- @mock_http_server = mock('http server')
- @mock_http_server.stubs(:listen)
- @server.stubs(:http_server).returns(@mock_http_server)
- @server.listen
+ 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
- it "should cause the HTTP server to stop listening when listening is turned off" do
- @mock_http_server.expects(:unlisten)
- @server.unlisten
+ 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(:address => "127.0.0.1", :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
- it "should not allow for indirections to be turned off" do
- @server.register(:foo)
- Proc.new { @server.unregister(:foo) }.should raise_error(RuntimeError)
+ 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
-
-describe Class.new, "put these somewhere" do
- it "should have the ability to use a class-level from_ hook (from_yaml, from_text, etc.) that can be called, based on content-type header, to allow for different deserializations of an object"
- it "should allow from_* on the inbound :data packet (look at its content_type) when doing a PUT/.new.save"
- it "should prepend a rest version number on the path (w00t)"
- it "should ... on server side, .save should from_yaml, then foo.save(args) instead of just Foo.new.save(args)"
+
+ describe Class.new, "put these somewhere" do
+ it "should have the ability to use a class-level from_ hook (from_yaml, from_text, etc.) that can be called, based on content-type header, to allow for different deserializations of an object"
+ it "should allow from_* on the inbound :data packet (look at its content_type) when doing a PUT/.new.save"
+ it "should prepend a rest version number on the path (w00t)"
+ it "should ... on server side, .save should from_yaml, then foo.save(args) instead of just Foo.new.save(args)"
+ end
end
diff --git a/spec/unit/node.rb b/spec/unit/node.rb
index 6603f6b58..4a41dadf9 100755
--- a/spec/unit/node.rb
+++ b/spec/unit/node.rb
@@ -113,6 +113,22 @@ describe Puppet::Node, "when merging facts" do
@node.merge "two" => "three"
@node.parameters["two"].should == "three"
end
+
+ it "should add the environment to the list of parameters" do
+ Puppet.settings.stubs(:value).with(:environments).returns("one,two")
+ Puppet.settings.stubs(:value).with(:environment).returns("one")
+ @node = Puppet::Node.new("testnode", :environment => "one")
+ @node.merge "two" => "three"
+ @node.parameters["environment"].should == "one"
+ end
+
+ it "should not set the environment if it is already set in the parameters" do
+ Puppet.settings.stubs(:value).with(:environments).returns("one,two")
+ Puppet.settings.stubs(:value).with(:environment).returns("one")
+ @node = Puppet::Node.new("testnode", :environment => "one")
+ @node.merge "environment" => "two"
+ @node.parameters["environment"].should == "two"
+ end
end
describe Puppet::Node, "when indirecting" do
@@ -132,7 +148,7 @@ describe Puppet::Node, "when indirecting" do
end
after do
- Puppet::Indirector::Indirection.clear_cache
+ Puppet::Util::Cacher.invalidate
end
end
diff --git a/spec/unit/node/catalog.rb b/spec/unit/node/catalog.rb
index ff9ab6930..f5f092824 100755
--- a/spec/unit/node/catalog.rb
+++ b/spec/unit/node/catalog.rb
@@ -330,8 +330,6 @@ describe Puppet::Node::Catalog, " when converting to a RAL catalog" do
newconfig = nil
- Puppet::Type.allclear
-
proc { @catalog = config.to_ral }.should_not raise_error
@catalog.resource("Test[changer2]").should equal(resource)
end
@@ -345,9 +343,9 @@ end
describe Puppet::Node::Catalog, " when functioning as a resource container" do
before do
@catalog = Puppet::Node::Catalog.new("host")
- @one = stub 'resource1', :ref => "Me[one]", :catalog= => nil
- @two = stub 'resource2', :ref => "Me[two]", :catalog= => nil
- @dupe = stub 'resource3', :ref => "Me[one]", :catalog= => nil
+ @one = stub 'resource1', :ref => "Me[one]", :catalog= => nil, :title => "one", :[] => "one"
+ @two = stub 'resource2', :ref => "Me[two]", :catalog= => nil, :title => "two", :[] => "two"
+ @dupe = stub 'resource3', :ref => "Me[one]", :catalog= => nil, :title => "one", :[] => "one"
end
it "should provide a method to add one or more resources" do
@@ -465,6 +463,28 @@ describe Puppet::Node::Catalog, " when functioning as a resource container" do
@catalog.resource("me", "other").should equal(@one)
end
+ it "should ignore conflicting aliases that point to the aliased resource" do
+ @catalog.alias(@one, "other")
+ lambda { @catalog.alias(@one, "other") }.should_not raise_error
+ end
+
+ it "should create aliases for resources isomorphic resources whose names do not match their titles" do
+ resource = Puppet::Type::File.create(:title => "testing", :path => "/something")
+
+ @catalog.add_resource(resource)
+
+ @catalog.resource(:file, "/something").should equal(resource)
+ end
+
+ it "should not create aliases for resources non-isomorphic resources whose names do not match their titles" do
+ resource = Puppet::Type.type(:exec).create(:title => "testing", :command => "echo", :path => %w{/bin /usr/bin /usr/local/bin})
+
+ @catalog.add_resource(resource)
+
+ # Yay, I've already got a 'should' method
+ @catalog.resource(:exec, "echo").object_id.should == nil.object_id
+ end
+
# This test is the same as the previous, but the behaviour should be explicit.
it "should alias using the class name from the resource reference, not the resource class name" do
@catalog.add_resource @one
@@ -472,7 +492,7 @@ describe Puppet::Node::Catalog, " when functioning as a resource container" do
@catalog.resource("me", "other").should equal(@one)
end
- it "should fail to add an alias if the aliased name already exists" do
+ it "should fail to add an alias if the aliased name already exists as a resource" do
@catalog.add_resource @one
proc { @catalog.alias @two, "one" }.should raise_error(ArgumentError)
end
@@ -514,10 +534,6 @@ describe Puppet::Node::Catalog, " when functioning as a resource container" do
raise "Aliased non-isomorphic resource"
end
end
-
- after do
- Puppet::Type.allclear
- end
end
describe Puppet::Node::Catalog do
@@ -648,13 +664,14 @@ describe Puppet::Node::Catalog, " when creating a relationship graph" do
@file = Puppet::Type.type(:file)
@one = @file.create :path => "/one"
@two = @file.create :path => "/two"
+ @sub = @file.create :path => "/two/subdir"
@catalog.add_edge @compone, @one
@catalog.add_edge @comptwo, @two
@three = @file.create :path => "/three"
@four = @file.create :path => "/four", :require => ["file", "/three"]
@five = @file.create :path => "/five"
- @catalog.add_resource @compone, @comptwo, @one, @two, @three, @four, @five
+ @catalog.add_resource @compone, @comptwo, @one, @two, @three, @four, @five, @sub
@relationships = @catalog.relationship_graph
end
@@ -689,6 +706,10 @@ describe Puppet::Node::Catalog, " when creating a relationship graph" do
@relationships.edge?(@one, @two).should be_true
end
+ it "should add automatic relationships to the relationship graph" do
+ @relationships.edge?(@two, @sub).should be_true
+ end
+
it "should get removed when the catalog is cleaned up" do
@relationships.expects(:clear).with(false)
@catalog.clear
@@ -702,14 +723,14 @@ describe Puppet::Node::Catalog, " when creating a relationship graph" do
end
it "should look up resources in the relationship graph if not found in the main catalog" do
- five = stub 'five', :ref => "File[five]", :catalog= => nil
+ five = stub 'five', :ref => "File[five]", :catalog= => nil, :title => "five", :[] => "five"
@relationships.add_resource five
@catalog.resource(five.ref).should equal(five)
end
it "should provide a method to create additional resources that also registers the resource" do
args = {:name => "/yay", :ensure => :file}
- resource = stub 'file', :ref => "File[/yay]", :catalog= => @catalog
+ resource = stub 'file', :ref => "File[/yay]", :catalog= => @catalog, :title => "/yay", :[] => "/yay"
Puppet::Type.type(:file).expects(:create).with(args).returns(resource)
@catalog.create_resource :file, args
@catalog.resource("File[/yay]").should equal(resource)
@@ -717,7 +738,7 @@ describe Puppet::Node::Catalog, " when creating a relationship graph" do
it "should provide a mechanism for creating implicit resources" do
args = {:name => "/yay", :ensure => :file}
- resource = stub 'file', :ref => "File[/yay]", :catalog= => @catalog
+ resource = stub 'file', :ref => "File[/yay]", :catalog= => @catalog, :title => "/yay", :[] => "/yay"
Puppet::Type.type(:file).expects(:create).with(args).returns(resource)
resource.expects(:implicit=).with(true)
@catalog.create_implicit_resource :file, args
@@ -726,7 +747,7 @@ describe Puppet::Node::Catalog, " when creating a relationship graph" do
it "should add implicit resources to the relationship graph if there is one" do
args = {:name => "/yay", :ensure => :file}
- resource = stub 'file', :ref => "File[/yay]", :catalog= => @catalog
+ resource = stub 'file', :ref => "File[/yay]", :catalog= => @catalog, :title => "/yay", :[] => "/yay"
resource.expects(:implicit=).with(true)
Puppet::Type.type(:file).expects(:create).with(args).returns(resource)
# build the graph
@@ -738,7 +759,7 @@ describe Puppet::Node::Catalog, " when creating a relationship graph" do
it "should remove resources created mid-transaction" do
args = {:name => "/yay", :ensure => :file}
- resource = stub 'file', :ref => "File[/yay]", :catalog= => @catalog
+ resource = stub 'file', :ref => "File[/yay]", :catalog= => @catalog, :title => "/yay", :[] => "/yay"
@transaction = mock 'transaction'
Puppet::Transaction.stubs(:new).returns(@transaction)
@transaction.stubs(:evaluate)
@@ -757,10 +778,6 @@ describe Puppet::Node::Catalog, " when creating a relationship graph" do
@catalog.remove_resource(@one)
@catalog.relationship_graph.vertex?(@one).should be_false
end
-
- after do
- Puppet::Type.allclear
- end
end
describe Puppet::Node::Catalog, " when writing dot files" do
@@ -800,7 +817,7 @@ describe Puppet::Node::Catalog, " when indirecting" do
before do
@indirection = stub 'indirection', :name => :catalog
- Puppet::Indirector::Indirection.clear_cache
+ Puppet::Util::Cacher.invalidate
end
it "should redirect to the indirection for retrieval" do
@@ -814,8 +831,7 @@ describe Puppet::Node::Catalog, " when indirecting" do
end
after do
- mocha_verify
- Puppet::Indirector::Indirection.clear_cache
+ Puppet::Util::Cacher.invalidate
end
end
diff --git a/spec/unit/node/facts.rb b/spec/unit/node/facts.rb
index 1bfccd32e..69b8e4483 100755
--- a/spec/unit/node/facts.rb
+++ b/spec/unit/node/facts.rb
@@ -10,7 +10,8 @@ describe Puppet::Node::Facts, " when indirecting" do
# We have to clear the cache so that the facts ask for our indirection stub,
# instead of anything that might be cached.
- Puppet::Indirector::Indirection.clear_cache
+ Puppet::Util::Cacher.invalidate
+
@facts = Puppet::Node::Facts.new("me", "one" => "two")
end
@@ -29,11 +30,6 @@ describe Puppet::Node::Facts, " when indirecting" do
it "should default to the 'facter' terminus" do
Puppet::Node::Facts.indirection.terminus_class.should == :facter
end
-
- after do
- mocha_verify
- Puppet::Indirector::Indirection.clear_cache
- end
end
describe Puppet::Node::Facts, " when storing and retrieving" do
diff --git a/spec/unit/other/transbucket.rb b/spec/unit/other/transbucket.rb
index 4494f2abb..e447c78a2 100755
--- a/spec/unit/other/transbucket.rb
+++ b/spec/unit/other/transbucket.rb
@@ -91,10 +91,6 @@ describe Puppet::TransBucket, " when generating a catalog" do
@fakes = %w{Fake[bottom] Fake[middle] Fake[top]}
end
- after do
- Puppet::Type.allclear
- end
-
it "should convert all transportable objects to RAL resources" do
@catalog = @top.to_catalog
@users.each do |name|
diff --git a/spec/unit/provider/mount/parsed.rb b/spec/unit/provider/mount/parsed.rb
index ba65b70a4..8d043f97f 100755
--- a/spec/unit/provider/mount/parsed.rb
+++ b/spec/unit/provider/mount/parsed.rb
@@ -167,10 +167,6 @@ describe provider_class do
@provider_class.prefetch("/" => @mount)
@mount.provider.should be_mounted
end
-
- after do
- Puppet::Type.allclear
- end
end
describe provider_class, " when mounting and unmounting" do
diff --git a/spec/unit/rails.rb b/spec/unit/rails.rb
index bb2f991ca..4a4667543 100755
--- a/spec/unit/rails.rb
+++ b/spec/unit/rails.rb
@@ -7,7 +7,7 @@ describe Puppet::Rails, "when initializing any connection" do
confine Puppet.features.rails? => "Cannot test without ActiveRecord"
before do
- @logger = mock 'logger'
+ @logger = stub 'logger', :level= => nil
@logger.stub_everything
Logger.stubs(:new).returns(@logger)
diff --git a/spec/unit/resource_reference.rb b/spec/unit/resource_reference.rb
index cbbd6ef51..ee71a5077 100755
--- a/spec/unit/resource_reference.rb
+++ b/spec/unit/resource_reference.rb
@@ -48,18 +48,6 @@ describe Puppet::ResourceReference do
end
end
-describe Puppet::ResourceReference, "when resolving resources without a catalog" do
- it "should be able to resolve builtin resources from their types" do
- Puppet::Type.type(:file).expects(:[]).with("myfile").returns(:myfile)
- Puppet::ResourceReference.new(:file, "myfile").resolve.should == :myfile
- end
-
- it "should be able to resolve defined resources from Components" do
- Puppet::Type.type(:component).expects(:[]).with("Foo::Bar[yay]").returns(:mything)
- Puppet::ResourceReference.new("foo::bar", "yay").resolve.should == :mything
- end
-end
-
describe Puppet::ResourceReference, "when resolving resources with a catalog" do
it "should resolve all resources using the catalog" do
config = mock 'catalog'
diff --git a/spec/unit/ssl/certificate.rb b/spec/unit/ssl/certificate.rb
new file mode 100755
index 000000000..1cb164d3f
--- /dev/null
+++ b/spec/unit/ssl/certificate.rb
@@ -0,0 +1,82 @@
+#!/usr/bin/env ruby
+
+require File.dirname(__FILE__) + '/../../spec_helper'
+
+require 'puppet/ssl/certificate'
+
+describe Puppet::SSL::Certificate do
+ before do
+ @class = Puppet::SSL::Certificate
+ end
+
+ after do
+ @class.instance_variable_set("@ca_location", nil)
+ end
+
+ it "should be extended with the Indirector module" do
+ @class.metaclass.should be_include(Puppet::Indirector)
+ end
+
+ it "should indirect certificate" do
+ @class.indirection.name.should == :certificate
+ end
+
+ it "should default to the :file terminus" do
+ @class.indirection.terminus_class.should == :file
+ end
+
+ describe "when managing instances" do
+ before do
+ @certificate = @class.new("myname")
+ end
+
+ it "should have a name attribute" do
+ @certificate.name.should == "myname"
+ end
+
+ it "should have a content attribute" do
+ @certificate.should respond_to(:content)
+ end
+
+ it "should return a nil expiration if there is no actual certificate" do
+ @certificate.stubs(:content).returns nil
+
+ @certificate.expiration.should be_nil
+ end
+
+ it "should use the expiration of the certificate as its expiration date" do
+ cert = stub 'cert'
+ @certificate.stubs(:content).returns cert
+
+ cert.expects(:not_after).returns "sometime"
+
+ @certificate.expiration.should == "sometime"
+ end
+
+ it "should be able to read certificates from disk" do
+ path = "/my/path"
+ File.expects(:read).with(path).returns("my certificate")
+ certificate = mock 'certificate'
+ OpenSSL::X509::Certificate.expects(:new).with("my certificate").returns(certificate)
+ @certificate.read(path).should equal(certificate)
+ @certificate.content.should equal(certificate)
+ end
+
+ it "should return an empty string when converted to a string with no certificate" do
+ @certificate.to_s.should == ""
+ end
+
+ it "should convert the certificate to pem format when converted to a string" do
+ certificate = mock 'certificate', :to_pem => "pem"
+ @certificate.content = certificate
+ @certificate.to_s.should == "pem"
+ end
+
+ it "should have a :to_text method that it delegates to the actual key" do
+ real_certificate = mock 'certificate'
+ real_certificate.expects(:to_text).returns "certificatetext"
+ @certificate.content = real_certificate
+ @certificate.to_text.should == "certificatetext"
+ end
+ end
+end
diff --git a/spec/unit/ssl/certificate_authority.rb b/spec/unit/ssl/certificate_authority.rb
new file mode 100755
index 000000000..2ff324a6a
--- /dev/null
+++ b/spec/unit/ssl/certificate_authority.rb
@@ -0,0 +1,735 @@
+#!/usr/bin/env ruby
+
+require File.dirname(__FILE__) + '/../../spec_helper'
+
+require 'puppet/ssl/certificate_authority'
+
+describe Puppet::SSL::CertificateAuthority do
+ after do
+ Puppet::Util::Cacher.invalidate
+ Puppet.settings.clearused
+ end
+
+ def stub_ca_host
+ @key = mock 'key'
+ @key.stubs(:content).returns "cakey"
+ @cacert = mock 'certificate'
+ @cacert.stubs(:content).returns "cacertificate"
+
+ @host = stub 'ssl_host', :key => @key, :certificate => @cacert, :name => Puppet::SSL::Host.ca_name
+ end
+
+ it "should have a class method for returning a singleton instance" do
+ Puppet::SSL::CertificateAuthority.should respond_to(:instance)
+ end
+
+ describe "when finding an existing instance" do
+ describe "and the host is a CA host and the proces name is 'puppetmasterd'" do
+ before do
+ Puppet.settings.stubs(:value).with(:ca).returns true
+ Puppet.settings.stubs(:value).with(:name).returns "puppetmasterd"
+
+ @ca = mock('ca')
+ Puppet::SSL::CertificateAuthority.stubs(:new).returns @ca
+ end
+
+ it "should return an instance" do
+ Puppet::SSL::CertificateAuthority.instance.should equal(@ca)
+ end
+
+ it "should always return the same instance" do
+ Puppet::SSL::CertificateAuthority.instance.should equal(Puppet::SSL::CertificateAuthority.instance)
+ end
+ end
+
+ describe "and the host is not a CA host" do
+ it "should return nil" do
+ Puppet.settings.stubs(:value).with(:ca).returns false
+ Puppet.settings.stubs(:value).with(:name).returns "puppetmasterd"
+
+ ca = mock('ca')
+ Puppet::SSL::CertificateAuthority.expects(:new).never
+ Puppet::SSL::CertificateAuthority.instance.should be_nil
+ end
+ end
+
+ describe "and the process name is not 'puppetmasterd'" do
+ it "should return nil" do
+ Puppet.settings.stubs(:value).with(:ca).returns true
+ Puppet.settings.stubs(:value).with(:name).returns "puppetd"
+
+ ca = mock('ca')
+ Puppet::SSL::CertificateAuthority.expects(:new).never
+ Puppet::SSL::CertificateAuthority.instance.should be_nil
+ end
+ end
+ end
+
+ describe "when initializing" do
+ before do
+ Puppet.settings.stubs(:use)
+ Puppet.settings.stubs(:value).returns "ca_testing"
+
+ Puppet::SSL::CertificateAuthority.any_instance.stubs(:setup)
+ end
+
+ it "should always set its name to the value of :certname" do
+ Puppet.settings.expects(:value).with(:certname).returns "ca_testing"
+
+ Puppet::SSL::CertificateAuthority.new.name.should == "ca_testing"
+ end
+
+ it "should create an SSL::Host instance whose name is the 'ca_name'" do
+ Puppet::SSL::Host.expects(:ca_name).returns "caname"
+
+ host = stub 'host'
+ Puppet::SSL::Host.expects(:new).with("caname").returns host
+
+ Puppet::SSL::CertificateAuthority.new
+ end
+
+ it "should use the :main, :ca, and :ssl settings sections" do
+ Puppet.settings.expects(:use).with(:main, :ssl, :ca)
+ Puppet::SSL::CertificateAuthority.new
+ end
+
+ it "should create an inventory instance" do
+ Puppet::SSL::Inventory.expects(:new).returns "inventory"
+
+ Puppet::SSL::CertificateAuthority.new.inventory.should == "inventory"
+ end
+
+ it "should make sure the CA is set up" do
+ Puppet::SSL::CertificateAuthority.any_instance.expects(:setup)
+
+ Puppet::SSL::CertificateAuthority.new
+ end
+ end
+
+ describe "when setting itself up" do
+ it "should generate the CA certificate if it does not have one" do
+ Puppet.settings.stubs :use
+
+ host = stub 'host'
+ Puppet::SSL::Host.stubs(:new).returns host
+
+ host.expects(:certificate).returns nil
+
+ Puppet::SSL::CertificateAuthority.any_instance.expects(:generate_ca_certificate)
+ Puppet::SSL::CertificateAuthority.new
+ end
+ end
+
+ describe "when retrieving the certificate revocation list" do
+ before do
+ Puppet.settings.stubs(:use)
+ Puppet.settings.stubs(:value).returns "ca_testing"
+ Puppet.settings.stubs(:value).with(:cacrl).returns "/my/crl"
+
+ cert = stub("certificate", :content => "real_cert")
+ key = stub("key", :content => "real_key")
+ @host = stub 'host', :certificate => cert, :name => "hostname", :key => key
+
+ Puppet::SSL::CertificateAuthority.any_instance.stubs(:setup)
+ @ca = Puppet::SSL::CertificateAuthority.new
+
+ @ca.stubs(:host).returns @host
+ end
+
+ it "should return any found CRL instance" do
+ crl = mock 'crl'
+ Puppet::SSL::CertificateRevocationList.expects(:find).returns crl
+ @ca.crl.should equal(crl)
+ end
+
+ it "should create, generate, and save a new CRL instance of no CRL can be found" do
+ crl = mock 'crl'
+ Puppet::SSL::CertificateRevocationList.expects(:find).returns nil
+
+ Puppet::SSL::CertificateRevocationList.expects(:new).returns crl
+
+ crl.expects(:generate).with(@ca.host.certificate.content, @ca.host.key.content)
+ crl.expects(:save)
+
+ @ca.crl.should equal(crl)
+ end
+ end
+
+ describe "when generating a self-signed CA certificate" do
+ before do
+ Puppet.settings.stubs(:use)
+ Puppet.settings.stubs(:value).returns "ca_testing"
+
+ Puppet::SSL::CertificateAuthority.any_instance.stubs(:setup)
+ Puppet::SSL::CertificateAuthority.any_instance.stubs(:crl)
+ @ca = Puppet::SSL::CertificateAuthority.new
+
+ @host = stub 'host', :key => mock("key"), :name => "hostname", :certificate => mock('certificate')
+
+ Puppet::SSL::CertificateRequest.any_instance.stubs(:generate)
+
+ @ca.stubs(:host).returns @host
+ end
+
+ it "should create and store a password at :capass" do
+ Puppet.settings.expects(:value).with(:capass).returns "/path/to/pass"
+
+ FileTest.expects(:exist?).with("/path/to/pass").returns false
+
+ fh = mock 'filehandle'
+ Puppet.settings.expects(:write).with(:capass).yields fh
+
+ fh.expects(:print).with { |s| s.length > 18 }
+
+ @ca.stubs(:sign)
+
+ @ca.generate_ca_certificate
+ end
+
+ it "should generate a key if one does not exist" do
+ @ca.stubs :generate_password
+ @ca.stubs :sign
+
+ @ca.host.expects(:key).returns nil
+ @ca.host.expects(:generate_key)
+
+ @ca.generate_ca_certificate
+ end
+
+ it "should create and sign a self-signed cert using the CA name" do
+ request = mock 'request'
+ Puppet::SSL::CertificateRequest.expects(:new).with(@ca.host.name).returns request
+ request.expects(:generate).with(@ca.host.key)
+
+ @ca.expects(:sign).with(@host.name, :ca, request)
+
+ @ca.stubs :generate_password
+
+ @ca.generate_ca_certificate
+ end
+
+ it "should generate its CRL" do
+ @ca.stubs :generate_password
+ @ca.stubs :sign
+
+ @ca.host.expects(:key).returns nil
+ @ca.host.expects(:generate_key)
+
+ @ca.expects(:crl)
+
+ @ca.generate_ca_certificate
+ end
+ end
+
+ describe "when signing" do
+ before do
+ Puppet.settings.stubs(:use)
+
+ Puppet::SSL::CertificateAuthority.any_instance.stubs(:password?).returns true
+
+ stub_ca_host
+
+ Puppet::SSL::Host.expects(:new).with(Puppet::SSL::Host.ca_name).returns @host
+
+ @ca = Puppet::SSL::CertificateAuthority.new
+
+ @name = "myhost"
+ @real_cert = stub 'realcert', :sign => nil
+ @cert = stub 'certificate', :content => @real_cert
+
+ Puppet::SSL::Certificate.stubs(:new).returns @cert
+
+ @cert.stubs(:content=)
+ @cert.stubs(:save)
+
+ # Stub out the factory
+ @factory = stub 'factory', :result => "my real cert"
+ Puppet::SSL::CertificateFactory.stubs(:new).returns @factory
+
+ @request = stub 'request', :content => "myrequest", :name => @name
+
+ # And the inventory
+ @inventory = stub 'inventory', :add => nil
+ @ca.stubs(:inventory).returns @inventory
+
+ Puppet::SSL::CertificateRequest.stubs(:destroy)
+ end
+
+ describe "and calculating the next certificate serial number" do
+ before do
+ @path = "/path/to/serial"
+ Puppet.settings.stubs(:value).with(:serial).returns @path
+
+ @filehandle = stub 'filehandle', :<< => @filehandle
+ Puppet.settings.stubs(:readwritelock).with(:serial).yields @filehandle
+ end
+
+ it "should default to 0x0 for the first serial number" do
+ @ca.next_serial.should == 0x0
+ end
+
+ it "should return the current content of the serial file" do
+ FileTest.stubs(:exist?).with(@path).returns true
+ File.expects(:read).with(@path).returns "0002"
+
+ @ca.next_serial.should == 2
+ end
+
+ it "should write the next serial number to the serial file as hex" do
+ @filehandle.expects(:<<).with("0001")
+
+ @ca.next_serial
+ end
+
+ it "should lock the serial file while writing" do
+ Puppet.settings.expects(:readwritelock).with(:serial)
+
+ @ca.next_serial
+ end
+ end
+
+ describe "its own certificate" do
+ before do
+ @serial = 10
+ @ca.stubs(:next_serial).returns @serial
+ end
+
+ it "should not look up a certificate request for the host" do
+ Puppet::SSL::CertificateRequest.expects(:find).never
+
+ @ca.sign(@name, :ca, @request)
+ end
+
+ it "should use a certificate type of :ca" do
+ Puppet::SSL::CertificateFactory.expects(:new).with do |*args|
+ args[0] == :ca
+ end.returns @factory
+ @ca.sign(@name, :ca, @request)
+ end
+
+ it "should pass the provided CSR as the CSR" do
+ Puppet::SSL::CertificateFactory.expects(:new).with do |*args|
+ args[1] == "myrequest"
+ end.returns @factory
+ @ca.sign(@name, :ca, @request)
+ end
+
+ it "should use the provided CSR's content as the issuer" do
+ Puppet::SSL::CertificateFactory.expects(:new).with do |*args|
+ args[2] == "myrequest"
+ end.returns @factory
+ @ca.sign(@name, :ca, @request)
+ end
+
+ it "should pass the next serial as the serial number" do
+ Puppet::SSL::CertificateFactory.expects(:new).with do |*args|
+ args[3] == @serial
+ end.returns @factory
+ @ca.sign(@name, :ca, @request)
+ end
+
+ it "should save the resulting certificate" do
+ @cert.expects(:save)
+
+ @ca.sign(@name, :ca, @request)
+ end
+ end
+
+ describe "another host's certificate" do
+ before do
+ @serial = 10
+ @ca.stubs(:next_serial).returns @serial
+
+ Puppet::SSL::CertificateRequest.stubs(:find).with(@name).returns @request
+ @cert.stubs :save
+ end
+
+ it "should use a certificate type of :server" do
+ Puppet::SSL::CertificateFactory.expects(:new).with do |*args|
+ args[0] == :server
+ end.returns @factory
+
+ @ca.sign(@name)
+ end
+
+ it "should use look up a CSR for the host in the :ca_file terminus" do
+ Puppet::SSL::CertificateRequest.expects(:find).with(@name).returns @request
+
+ @ca.sign(@name)
+ end
+
+ it "should fail if no CSR can be found for the host" do
+ Puppet::SSL::CertificateRequest.expects(:find).with(@name).returns nil
+
+ lambda { @ca.sign(@name) }.should raise_error(ArgumentError)
+ end
+
+ it "should use the CA certificate as the issuer" do
+ Puppet::SSL::CertificateFactory.expects(:new).with do |*args|
+ args[2] == @cacert.content
+ end.returns @factory
+ @ca.sign(@name)
+ end
+
+ it "should pass the next serial as the serial number" do
+ Puppet::SSL::CertificateFactory.expects(:new).with do |*args|
+ args[3] == @serial
+ end.returns @factory
+ @ca.sign(@name)
+ end
+
+ it "should sign the resulting certificate using its real key and a digest" do
+ digest = mock 'digest'
+ OpenSSL::Digest::SHA1.expects(:new).returns digest
+
+ key = stub 'key', :content => "real_key"
+ @ca.host.stubs(:key).returns key
+
+ @cert.content.expects(:sign).with("real_key", digest)
+ @ca.sign(@name)
+ end
+
+ it "should save the resulting certificate" do
+ @cert.expects(:save)
+ @ca.sign(@name)
+ end
+
+ it "should remove the host's certificate request" do
+ Puppet::SSL::CertificateRequest.expects(:destroy).with(@name)
+
+ @ca.sign(@name)
+ end
+ end
+
+ it "should create a certificate instance with the content set to the newly signed x509 certificate" do
+ @serial = 10
+ @ca.stubs(:next_serial).returns @serial
+
+ Puppet::SSL::CertificateRequest.stubs(:find).with(@name).returns @request
+ @cert.stubs :save
+ Puppet::SSL::Certificate.expects(:new).with(@name).returns @cert
+
+ @ca.sign(@name)
+ end
+
+ it "should return the certificate instance" do
+ @ca.stubs(:next_serial).returns @serial
+ Puppet::SSL::CertificateRequest.stubs(:find).with(@name).returns @request
+ @cert.stubs :save
+ @ca.sign(@name).should equal(@cert)
+ end
+
+ it "should add the certificate to its inventory" do
+ @ca.stubs(:next_serial).returns @serial
+ @inventory.expects(:add).with(@cert)
+
+ Puppet::SSL::CertificateRequest.stubs(:find).with(@name).returns @request
+ @cert.stubs :save
+ @ca.sign(@name)
+ end
+
+ it "should have a method for triggering autosigning of available CSRs" do
+ @ca.should respond_to(:autosign)
+ end
+
+ describe "when autosigning certificates" do
+ it "should do nothing if autosign is disabled" do
+ Puppet.settings.expects(:value).with(:autosign).returns 'false'
+
+ Puppet::SSL::CertificateRequest.expects(:search).never
+ @ca.autosign
+ end
+
+ it "should do nothing if no autosign.conf exists" do
+ Puppet.settings.expects(:value).with(:autosign).returns '/auto/sign'
+ FileTest.expects(:exist?).with("/auto/sign").returns false
+
+ Puppet::SSL::CertificateRequest.expects(:search).never
+ @ca.autosign
+ end
+
+ describe "and autosign is enabled and the autosign.conf file exists" do
+ before do
+ Puppet.settings.stubs(:value).with(:autosign).returns '/auto/sign'
+ FileTest.stubs(:exist?).with("/auto/sign").returns true
+ File.stubs(:readlines).with("/auto/sign").returns ["one\n", "two\n"]
+
+ Puppet::SSL::CertificateRequest.stubs(:search).returns []
+
+ @store = stub 'store', :allow => nil
+ Puppet::Network::AuthStore.stubs(:new).returns @store
+ end
+
+ describe "when creating the AuthStore instance to verify autosigning" do
+ it "should create an AuthStore with each line in the configuration file allowed to be autosigned" do
+ Puppet::Network::AuthStore.expects(:new).returns @store
+
+ @store.expects(:allow).with("one")
+ @store.expects(:allow).with("two")
+
+ @ca.autosign
+ end
+
+ it "should reparse the autosign configuration on each call" do
+ Puppet::Network::AuthStore.expects(:new).times(2).returns @store
+
+ @ca.autosign
+ @ca.autosign
+ end
+
+ it "should ignore comments" do
+ File.stubs(:readlines).with("/auto/sign").returns ["one\n", "#two\n"]
+
+ @store.expects(:allow).with("one")
+ @ca.autosign
+ end
+
+ it "should ignore blank lines" do
+ File.stubs(:readlines).with("/auto/sign").returns ["one\n", "\n"]
+
+ @store.expects(:allow).with("one")
+ @ca.autosign
+ end
+ end
+
+ it "should sign all CSRs whose hostname matches the autosign configuration" do
+ csr1 = mock 'csr1'
+ csr2 = mock 'csr2'
+ Puppet::SSL::CertificateRequest.stubs(:search).returns [csr1, csr2]
+ end
+
+ it "should not sign CSRs whose hostname does not match the autosign configuration" do
+ csr1 = mock 'csr1'
+ csr2 = mock 'csr2'
+ Puppet::SSL::CertificateRequest.stubs(:search).returns [csr1, csr2]
+ end
+ end
+ end
+ end
+
+ describe "when managing certificate clients" do
+ before do
+ Puppet.settings.stubs(:use)
+
+ Puppet::SSL::CertificateAuthority.any_instance.stubs(:password?).returns true
+
+ stub_ca_host
+
+ Puppet::SSL::Host.expects(:new).returns @host
+ Puppet::SSL::CertificateAuthority.any_instance.stubs(:host).returns @host
+
+ @cacert = mock 'certificate'
+ @cacert.stubs(:content).returns "cacertificate"
+ @ca = Puppet::SSL::CertificateAuthority.new
+ end
+
+ it "should have a method for acting on the SSL files" do
+ @ca.should respond_to(:apply)
+ end
+
+ describe "when applying a method to a set of hosts" do
+ it "should fail if no subjects have been specified" do
+ lambda { @ca.apply(:generate) }.should raise_error(ArgumentError)
+ end
+
+ it "should create an Interface instance with the specified method and the subjects" do
+ Puppet::SSL::CertificateAuthority::Interface.expects(:new).with(:generate, :hosts).returns(stub('applier', :apply => nil))
+ @ca.apply(:generate, :to => :hosts)
+ end
+
+ it "should apply the Interface with itself as the argument" do
+ applier = stub('applier')
+ applier.expects(:apply).with(@ca)
+ Puppet::SSL::CertificateAuthority::Interface.expects(:new).returns applier
+ @ca.apply(:generate, :to => :ca_testing)
+ end
+ end
+
+ it "should be able to list waiting certificate requests" do
+ req1 = stub 'req1', :name => "one"
+ req2 = stub 'req2', :name => "two"
+ Puppet::SSL::CertificateRequest.expects(:search).with("*").returns [req1, req2]
+
+ @ca.waiting?.should == %w{one two}
+ end
+
+ it "should delegate removing hosts to the Host class" do
+ Puppet::SSL::Host.expects(:destroy).with("myhost")
+
+ @ca.destroy("myhost")
+ end
+
+ it "should be able to verify certificates" do
+ @ca.should respond_to(:verify)
+ end
+
+ it "should list certificates as the sorted list of all existing signed certificates" do
+ cert1 = stub 'cert1', :name => "cert1"
+ cert2 = stub 'cert2', :name => "cert2"
+ Puppet::SSL::Certificate.expects(:search).with("*").returns [cert1, cert2]
+ @ca.list.should == %w{cert1 cert2}
+ end
+
+ describe "and printing certificates" do
+ it "should return nil if the certificate cannot be found" do
+ Puppet::SSL::Certificate.expects(:find).with("myhost").returns nil
+ @ca.print("myhost").should be_nil
+ end
+
+ it "should print certificates by calling :to_text on the host's certificate" do
+ cert1 = stub 'cert1', :name => "cert1", :to_text => "mytext"
+ Puppet::SSL::Certificate.expects(:find).with("myhost").returns cert1
+ @ca.print("myhost").should == "mytext"
+ end
+ end
+
+ describe "and verifying certificates" do
+ before do
+ @store = stub 'store', :verify => true, :add_file => nil, :purpose= => nil, :add_crl => true
+
+ OpenSSL::X509::Store.stubs(:new).returns @store
+
+ Puppet.settings.stubs(:value).returns "crtstuff"
+
+ @cert = stub 'cert', :content => "mycert"
+ Puppet::SSL::Certificate.stubs(:find).returns @cert
+
+ @crl = stub('crl', :content => "mycrl")
+
+ @ca.stubs(:crl).returns @crl
+ end
+
+ it "should fail if the host's certificate cannot be found" do
+ Puppet::SSL::Certificate.expects(:find).with("me").returns(nil)
+
+ lambda { @ca.verify("me") }.should raise_error(ArgumentError)
+ end
+
+ it "should create an SSL Store to verify" do
+ OpenSSL::X509::Store.expects(:new).returns @store
+
+ @ca.verify("me")
+ end
+
+ it "should add the CA Certificate to the store" do
+ Puppet.settings.stubs(:value).with(:cacert).returns "/ca/cert"
+ @store.expects(:add_file).with "/ca/cert"
+
+ @ca.verify("me")
+ end
+
+ it "should add the CRL to the store if the crl is enabled" do
+ @store.expects(:add_crl).with "mycrl"
+
+ @ca.verify("me")
+ end
+
+ it "should set the store purpose to OpenSSL::X509::PURPOSE_SSL_CLIENT" do
+ Puppet.settings.stubs(:value).with(:cacert).returns "/ca/cert"
+ @store.expects(:add_file).with "/ca/cert"
+
+ @ca.verify("me")
+ end
+
+ it "should use the store to verify the certificate" do
+ @cert.expects(:content).returns "mycert"
+
+ @store.expects(:verify).with("mycert").returns true
+
+ @ca.verify("me")
+ end
+
+ it "should fail if the verification returns false" do
+ @cert.expects(:content).returns "mycert"
+
+ @store.expects(:verify).with("mycert").returns false
+
+ lambda { @ca.verify("me") }.should raise_error
+ end
+ end
+
+ describe "and revoking certificates" do
+ before do
+ @crl = mock 'crl'
+ @ca.stubs(:crl).returns @crl
+
+ @ca.stubs(:next_serial).returns 10
+
+ @real_cert = stub 'real_cert', :serial => 15
+ @cert = stub 'cert', :content => @real_cert
+ Puppet::SSL::Certificate.stubs(:find).returns @cert
+
+ end
+
+ it "should fail if the certificate revocation list is disabled" do
+ @ca.stubs(:crl).returns false
+
+ lambda { @ca.revoke('ca_testing') }.should raise_error(ArgumentError)
+
+ end
+
+ it "should delegate the revocation to its CRL" do
+ @ca.crl.expects(:revoke)
+
+ @ca.revoke('host')
+ end
+
+ it "should get the serial number from the local certificate if it exists" do
+ @ca.crl.expects(:revoke).with { |serial, key| serial == 15 }
+
+ Puppet::SSL::Certificate.expects(:find).with("host").returns @cert
+
+ @ca.revoke('host')
+ end
+
+ it "should get the serial number from inventory if no local certificate exists" do
+ real_cert = stub 'real_cert', :serial => 15
+ cert = stub 'cert', :content => real_cert
+ Puppet::SSL::Certificate.expects(:find).with("host").returns nil
+
+ @ca.inventory.expects(:serial).with("host").returns 16
+
+ @ca.crl.expects(:revoke).with { |serial, key| serial == 16 }
+ @ca.revoke('host')
+ end
+ end
+
+ it "should be able to generate a complete new SSL host" do
+ @ca.should respond_to(:generate)
+ end
+
+ describe "and generating certificates" do
+ before do
+ @host = stub 'host', :generate_certificate_request => nil
+ Puppet::SSL::Host.stubs(:new).returns @host
+ Puppet::SSL::Certificate.stubs(:find).returns nil
+
+ @ca.stubs(:sign)
+ end
+
+ it "should fail if a certificate already exists for the host" do
+ Puppet::SSL::Certificate.expects(:find).with("him").returns "something"
+
+ lambda { @ca.generate("him") }.should raise_error(ArgumentError)
+ end
+
+ it "should create a new Host instance with the correct name" do
+ Puppet::SSL::Host.expects(:new).with("him").returns @host
+
+ @ca.generate("him")
+ end
+
+ it "should use the Host to generate the certificate request" do
+ @host.expects :generate_certificate_request
+
+ @ca.generate("him")
+ end
+
+ it "should sign the generated request" do
+ @ca.expects(:sign).with("him")
+
+ @ca.generate("him")
+ end
+ end
+ end
+end
diff --git a/spec/unit/ssl/certificate_authority/interface.rb b/spec/unit/ssl/certificate_authority/interface.rb
new file mode 100755
index 000000000..617cfa6ba
--- /dev/null
+++ b/spec/unit/ssl/certificate_authority/interface.rb
@@ -0,0 +1,265 @@
+#!/usr/bin/env ruby
+
+require File.dirname(__FILE__) + '/../../../spec_helper'
+
+require 'puppet/ssl/certificate_authority'
+
+describe "a normal interface method", :shared => true do
+ it "should call the method on the CA for each host specified if an array was provided" do
+ @ca.expects(@method).with("host1")
+ @ca.expects(@method).with("host2")
+
+ @applier = Puppet::SSL::CertificateAuthority::Interface.new(@method, %w{host1 host2})
+
+ @applier.apply(@ca)
+ end
+
+ it "should call the method on the CA for all existing certificates if :all was provided" do
+ @ca.expects(:list).returns %w{host1 host2}
+
+ @ca.expects(@method).with("host1")
+ @ca.expects(@method).with("host2")
+
+ @applier = Puppet::SSL::CertificateAuthority::Interface.new(@method, :all)
+
+ @applier.apply(@ca)
+ end
+end
+
+describe Puppet::SSL::CertificateAuthority::Interface do
+ before do
+ @class = Puppet::SSL::CertificateAuthority::Interface
+ end
+ describe "when initializing" do
+ it "should set its method using its settor" do
+ @class.any_instance.expects(:method=).with(:generate)
+ @class.new(:generate, :all)
+ end
+
+ it "should set its subjects using the settor" do
+ @class.any_instance.expects(:subjects=).with(:all)
+ @class.new(:generate, :all)
+ end
+ end
+
+ describe "when setting the method" do
+ it "should set the method" do
+ @class.new(:generate, :all).method.should == :generate
+ end
+
+ it "should fail if the method isn't a member of the INTERFACE_METHODS array" do
+ Puppet::SSL::CertificateAuthority::Interface::INTERFACE_METHODS.expects(:include?).with(:thing).returns false
+
+ lambda { @class.new(:thing, :all) }.should raise_error(ArgumentError)
+ end
+ end
+
+ describe "when setting the subjects" do
+ it "should set the subjects" do
+ @class.new(:generate, :all).subjects.should == :all
+ end
+
+ it "should fail if the subjects setting isn't :all or an array" do
+ lambda { @class.new(:generate, "other") }.should raise_error(ArgumentError)
+ end
+ end
+
+ it "should have a method for triggering the application" do
+ @class.new(:generate, :all).should respond_to(:apply)
+ end
+
+ describe "when applying" do
+ before do
+ # We use a real object here, because :verify can't be stubbed, apparently.
+ @ca = Object.new
+ end
+
+ it "should raise InterfaceErrors" do
+ @applier = @class.new(:revoke, :all)
+
+ @ca.expects(:list).raises Puppet::SSL::CertificateAuthority::Interface::InterfaceError
+
+ lambda { @applier.apply(@ca) }.should raise_error(Puppet::SSL::CertificateAuthority::Interface::InterfaceError)
+ end
+
+ it "should log non-Interface failures rather than failing" do
+ @applier = @class.new(:revoke, :all)
+
+ @ca.expects(:list).raises ArgumentError
+
+ Puppet.expects(:err)
+
+ lambda { @applier.apply(@ca) }.should_not raise_error
+ end
+
+ describe "with an empty array specified and the method is not list" do
+ it "should fail" do
+ @applier = @class.new(:sign, [])
+ lambda { @applier.apply(@ca) }.should raise_error(ArgumentError)
+ end
+ end
+
+ describe ":generate" do
+ it "should fail if :all was specified" do
+ @applier = @class.new(:generate, :all)
+ lambda { @applier.apply(@ca) }.should raise_error(ArgumentError)
+ end
+
+ it "should call :generate on the CA for each host specified" do
+ @applier = @class.new(:generate, %w{host1 host2})
+
+ @ca.expects(:generate).with("host1")
+ @ca.expects(:generate).with("host2")
+
+ @applier.apply(@ca)
+ end
+ end
+
+ describe ":verify" do
+ before { @method = :verify }
+ #it_should_behave_like "a normal interface method"
+
+ it "should call the method on the CA for each host specified if an array was provided" do
+ # LAK:NOTE Mocha apparently doesn't allow you to mock :verify, but I'm confident this works in real life.
+ end
+
+ it "should call the method on the CA for all existing certificates if :all was provided" do
+ # LAK:NOTE Mocha apparently doesn't allow you to mock :verify, but I'm confident this works in real life.
+ end
+ end
+
+ describe ":destroy" do
+ before { @method = :destroy }
+ it_should_behave_like "a normal interface method"
+ end
+
+ describe ":revoke" do
+ before { @method = :revoke }
+ it_should_behave_like "a normal interface method"
+ end
+
+ describe ":sign" do
+ describe "and an array of names was provided" do
+ before do
+ @applier = @class.new(:sign, %w{host1 host2})
+ end
+
+ it "should sign the specified waiting certificate requests" do
+ @ca.expects(:sign).with("host1")
+ @ca.expects(:sign).with("host2")
+
+ @applier.apply(@ca)
+ end
+ end
+
+ describe "and :all was provided" do
+ it "should sign all waiting certificate requests" do
+ @ca.stubs(:waiting?).returns(%w{cert1 cert2})
+
+ @ca.expects(:sign).with("cert1")
+ @ca.expects(:sign).with("cert2")
+
+ @applier = @class.new(:sign, :all)
+ @applier.apply(@ca)
+ end
+
+ it "should fail if there are no waiting certificate requests" do
+ @ca.stubs(:waiting?).returns([])
+
+ @applier = @class.new(:sign, :all)
+ lambda { @applier.apply(@ca) }.should raise_error(Puppet::SSL::CertificateAuthority::Interface::InterfaceError)
+ end
+ end
+ end
+
+ describe ":list" do
+ describe "and an empty array was provided" do
+ it "should print a string containing all certificate requests" do
+ @ca.expects(:waiting?).returns %w{host1 host2}
+
+ @applier = @class.new(:list, [])
+
+ @applier.expects(:puts).with "host1\nhost2"
+
+ @applier.apply(@ca)
+ end
+ end
+
+ describe "and :all was provided" do
+ it "should print a string containing all certificate requests and certificates" do
+ @ca.expects(:waiting?).returns %w{host1 host2}
+ @ca.expects(:list).returns %w{host3 host4}
+
+ @applier = @class.new(:list, :all)
+
+ @applier.expects(:puts).with "host1"
+ @applier.expects(:puts).with "host2"
+ @applier.expects(:puts).with "+ host3"
+ @applier.expects(:puts).with "+ host4"
+
+ @applier.apply(@ca)
+ end
+ end
+
+ describe "and an array of names was provided" do
+ it "should print a string of all named hosts that have a waiting request" do
+ @ca.expects(:waiting?).returns %w{host1 host2}
+ @ca.expects(:list).returns %w{host3 host4}
+
+ @applier = @class.new(:list, %w{host1 host2 host3 host4})
+
+ @applier.expects(:puts).with "host1"
+ @applier.expects(:puts).with "host2"
+ @applier.expects(:puts).with "+ host3"
+ @applier.expects(:puts).with "+ host4"
+
+ @applier.apply(@ca)
+ end
+ end
+ end
+
+ describe ":print" do
+ describe "and :all was provided" do
+ it "should print all certificates" do
+ @ca.expects(:list).returns %w{host1 host2}
+
+ @applier = @class.new(:print, :all)
+
+ @ca.expects(:print).with("host1").returns "h1"
+ @applier.expects(:puts).with "h1"
+
+ @ca.expects(:print).with("host2").returns "h2"
+ @applier.expects(:puts).with "h2"
+
+ @applier.apply(@ca)
+ end
+ end
+
+ describe "and an array of names was provided" do
+ it "should print each named certificate if found" do
+ @applier = @class.new(:print, %w{host1 host2})
+
+ @ca.expects(:print).with("host1").returns "h1"
+ @applier.expects(:puts).with "h1"
+
+ @ca.expects(:print).with("host2").returns "h2"
+ @applier.expects(:puts).with "h2"
+
+ @applier.apply(@ca)
+ end
+
+ it "should log any named but not found certificates" do
+ @applier = @class.new(:print, %w{host1 host2})
+
+ @ca.expects(:print).with("host1").returns "h1"
+ @applier.expects(:puts).with "h1"
+
+ @ca.expects(:print).with("host2").returns nil
+ Puppet.expects(:err).with { |msg| msg.include?("host2") }
+
+ @applier.apply(@ca)
+ end
+ end
+ end
+ end
+end
diff --git a/spec/unit/ssl/certificate_factory.rb b/spec/unit/ssl/certificate_factory.rb
new file mode 100755
index 000000000..822b330f2
--- /dev/null
+++ b/spec/unit/ssl/certificate_factory.rb
@@ -0,0 +1,107 @@
+#!/usr/bin/env ruby
+
+require File.dirname(__FILE__) + '/../../spec_helper'
+
+require 'puppet/ssl/certificate_factory'
+
+describe Puppet::SSL::CertificateFactory do
+ before do
+ @cert_type = mock 'cert_type'
+ @name = mock 'name'
+ @csr = stub 'csr', :subject => @name
+ @issuer = mock 'issuer'
+ @serial = mock 'serial'
+
+ @factory = Puppet::SSL::CertificateFactory.new(@cert_type, @csr, @issuer, @serial)
+ end
+
+ describe "when initializing" do
+ it "should set its :cert_type to its first argument" do
+ @factory.cert_type.should equal(@cert_type)
+ end
+
+ it "should set its :csr to its second argument" do
+ @factory.csr.should equal(@csr)
+ end
+
+ it "should set its :issuer to its third argument" do
+ @factory.issuer.should equal(@issuer)
+ end
+
+ it "should set its :serial to its fourth argument" do
+ @factory.serial.should equal(@serial)
+ end
+
+ it "should set its name to the subject of the csr" do
+ @factory.name.should equal(@name)
+ end
+ end
+
+ describe "when generating the certificate" do
+ before do
+ @cert = mock 'cert'
+
+ @cert.stub_everything
+
+ @factory.stubs :build_extensions
+
+ @factory.stubs :set_ttl
+
+ @issuer_name = mock 'issuer_name'
+ @issuer.stubs(:subject).returns @issuer_name
+
+ @public_key = mock 'public_key'
+ @csr.stubs(:public_key).returns @public_key
+
+ OpenSSL::X509::Certificate.stubs(:new).returns @cert
+ end
+
+ it "should return a new X509 certificate" do
+ OpenSSL::X509::Certificate.expects(:new).returns @cert
+ @factory.result.should equal(@cert)
+ end
+
+ it "should set the certificate's version to 2" do
+ @cert.expects(:version=).with 2
+ @factory.result
+ end
+
+ it "should set the certificate's subject to the CSR's subject" do
+ @cert.expects(:subject=).with @name
+ @factory.result
+ end
+
+ it "should set the certificate's issuer to the Issuer's subject" do
+ @cert.expects(:issuer=).with @issuer_name
+ @factory.result
+ end
+
+ it "should set the certificate's public key to the CSR's public key" do
+ @cert.expects(:public_key=).with @public_key
+ @factory.result
+ end
+
+ it "should set the certificate's serial number to the provided serial number" do
+ @cert.expects(:serial=).with @serial
+ @factory.result
+ end
+
+ it "should build extensions for the certificate" do
+ @factory.expects(:build_extensions)
+ @factory.result
+ end
+
+ it "should set the ttl of the certificate" do
+ @factory.expects(:set_ttl)
+ @factory.result
+ end
+ end
+
+ describe "when building extensions" do
+ it "should have tests"
+ end
+
+ describe "when setting the ttl" do
+ it "should have tests"
+ end
+end
diff --git a/spec/unit/ssl/certificate_request.rb b/spec/unit/ssl/certificate_request.rb
new file mode 100755
index 000000000..351e5bbd5
--- /dev/null
+++ b/spec/unit/ssl/certificate_request.rb
@@ -0,0 +1,167 @@
+#!/usr/bin/env ruby
+
+require File.dirname(__FILE__) + '/../../spec_helper'
+
+require 'puppet/ssl/certificate_request'
+require 'puppet/ssl/key'
+
+describe Puppet::SSL::CertificateRequest do
+ before do
+ @class = Puppet::SSL::CertificateRequest
+ end
+
+ it "should be extended with the Indirector module" do
+ @class.metaclass.should be_include(Puppet::Indirector)
+ end
+
+ it "should indirect certificate_request" do
+ @class.indirection.name.should == :certificate_request
+ end
+
+ it "should use any provided name as its name" do
+ @class.new("myname").name.should == "myname"
+ end
+
+ it "should default to the :file terminus" do
+ @class.indirection.terminus_class.should == :file
+ end
+
+ describe "when managing instances" do
+ before do
+ @request = @class.new("myname")
+ end
+
+ it "should have a name attribute" do
+ @request.name.should == "myname"
+ end
+
+ it "should have a content attribute" do
+ @request.should respond_to(:content)
+ end
+
+ it "should be able to read requests from disk" do
+ path = "/my/path"
+ File.expects(:read).with(path).returns("my request")
+ request = mock 'request'
+ OpenSSL::X509::Request.expects(:new).with("my request").returns(request)
+ @request.read(path).should equal(request)
+ @request.content.should equal(request)
+ end
+
+ it "should return an empty string when converted to a string with no request" do
+ @request.to_s.should == ""
+ end
+
+ it "should convert the request to pem format when converted to a string" do
+ request = mock 'request', :to_pem => "pem"
+ @request.content = request
+ @request.to_s.should == "pem"
+ end
+
+ it "should have a :to_text method that it delegates to the actual key" do
+ real_request = mock 'request'
+ real_request.expects(:to_text).returns "requesttext"
+ @request.content = real_request
+ @request.to_text.should == "requesttext"
+ end
+ end
+
+ describe "when generating" do
+ before do
+ @instance = @class.new("myname")
+
+ key = Puppet::SSL::Key.new("myname")
+ @key = key.generate
+
+ @request = OpenSSL::X509::Request.new
+ OpenSSL::X509::Request.expects(:new).returns(@request)
+
+ @request.stubs(:verify).returns(true)
+ end
+
+ it "should use the content of the provided key if the key is a Puppet::SSL::Key instance" do
+ key = Puppet::SSL::Key.new("test")
+ key.expects(:content).returns @key
+
+ @request.expects(:sign).with{ |key, digest| key == @key }
+ @instance.generate(key)
+ end
+
+ it "should log that it is creating a new certificate request" do
+ Puppet.expects(:info)
+ @instance.generate(@key)
+ end
+
+ it "should set the subject to [CN, name]" do
+ subject = mock 'subject'
+ OpenSSL::X509::Name.expects(:new).with([["CN", @instance.name]]).returns(subject)
+ @request.expects(:subject=).with(subject)
+ @instance.generate(@key)
+ end
+
+ it "should set the version to 0" do
+ @request.expects(:version=).with(0)
+ @instance.generate(@key)
+ end
+
+ it "should set the public key to the provided key's public key" do
+ # Yay, the private key extracts a new key each time.
+ pubkey = @key.public_key
+ @key.stubs(:public_key).returns pubkey
+ @request.expects(:public_key=).with(@key.public_key)
+ @instance.generate(@key)
+ end
+
+ it "should sign the csr with the provided key and a digest" do
+ digest = mock 'digest'
+ OpenSSL::Digest::MD5.expects(:new).returns(digest)
+ @request.expects(:sign).with(@key, digest)
+ @instance.generate(@key)
+ end
+
+ it "should verify the generated request using the public key" do
+ @request.expects(:verify).with(@key.public_key)
+ @instance.generate(@key)
+ end
+
+ it "should fail if verification fails" do
+ @request.expects(:verify).returns false
+
+ lambda { @instance.generate(@key) }.should raise_error(Puppet::Error)
+ end
+
+ it "should return the generated request" do
+ @instance.generate(@key).should equal(@request)
+ end
+
+ it "should set its content to the generated request" do
+ @instance.generate(@key)
+ @instance.content.should equal(@request)
+ end
+ end
+
+ describe "when a CSR is saved" do
+ describe "and a CA is available" do
+ it "should save the CSR and trigger autosigning" do
+ ca = mock 'ca', :autosign
+ Puppet::SSL::CertificateAuthority.expects(:instance).returns ca
+
+ csr = Puppet::SSL::CertificateRequest.new("me")
+ Puppet::SSL::CertificateRequest.indirection.expects(:save).with(csr)
+
+ csr.save
+ end
+ end
+
+ describe "and a CA is not available" do
+ it "should save the CSR" do
+ Puppet::SSL::CertificateAuthority.expects(:instance).returns nil
+
+ csr = Puppet::SSL::CertificateRequest.new("me")
+ Puppet::SSL::CertificateRequest.indirection.expects(:save).with(csr)
+
+ csr.save
+ end
+ end
+ end
+end
diff --git a/spec/unit/ssl/certificate_revocation_list.rb b/spec/unit/ssl/certificate_revocation_list.rb
new file mode 100755
index 000000000..13febf744
--- /dev/null
+++ b/spec/unit/ssl/certificate_revocation_list.rb
@@ -0,0 +1,166 @@
+#!/usr/bin/env ruby
+
+require File.dirname(__FILE__) + '/../../spec_helper'
+
+require 'puppet/ssl/certificate_revocation_list'
+
+describe Puppet::SSL::CertificateRevocationList do
+ before do
+ @cert = stub 'cert', :subject => "mysubject"
+ @key = stub 'key', :private? => true
+
+ @class = Puppet::SSL::CertificateRevocationList
+ end
+
+ it "should default to the :file terminus" do
+ @class.indirection.terminus_class.should == :file
+ end
+
+ describe "when an instance" do
+ before do
+ @class.any_instance.stubs(:read_or_generate)
+
+ @crl = @class.new("whatever")
+ end
+
+ it "should always use 'crl' for its name" do
+ @crl.name.should == "crl"
+ end
+
+ it "should have a content attribute" do
+ @crl.should respond_to(:content)
+ end
+ end
+
+ describe "when initializing" do
+ it "should fail if :cacrl is set to false" do
+ Puppet.settings.expects(:value).with(:cacrl).returns false
+ lambda { @class.new("crl") }.should raise_error(Puppet::Error)
+ end
+
+ it "should fail if :cacrl is set to the string 'false'" do
+ Puppet.settings.expects(:value).with(:cacrl).returns "false"
+ lambda { @class.new("crl") }.should raise_error(Puppet::Error)
+ end
+ end
+
+ describe "when generating the crl" do
+ before do
+ @real_crl = mock 'crl'
+ @real_crl.stub_everything
+
+ OpenSSL::X509::CRL.stubs(:new).returns(@real_crl)
+
+ @class.any_instance.stubs(:read_or_generate)
+
+ @crl = @class.new("crl")
+ end
+
+ it "should set its issuer to the subject of the passed certificate" do
+ @real_crl.expects(:issuer=).with(@cert.subject)
+
+ @crl.generate(@cert, @key)
+ end
+
+ it "should set its version to 1" do
+ @real_crl.expects(:version=).with(1)
+
+ @crl.generate(@cert, @key)
+ end
+
+ it "should create an instance of OpenSSL::X509::CRL" do
+ OpenSSL::X509::CRL.expects(:new).returns(@real_crl)
+
+ @crl.generate(@cert, @key)
+ end
+
+ # The next three tests aren't good, but at least they
+ # specify the behaviour.
+ it "should add an extension for the CRL number" do
+ @real_crl.expects(:extensions=)
+ @crl.generate(@cert, @key)
+ end
+
+ it "should set the last update time" do
+ @real_crl.expects(:last_update=)
+ @crl.generate(@cert, @key)
+ end
+
+ it "should set the next update time" do
+ @real_crl.expects(:next_update=)
+ @crl.generate(@cert, @key)
+ end
+
+ it "should sign the CRL" do
+ @real_crl.expects(:sign).with { |key, digest| key == @key }
+ @crl.generate(@cert, @key)
+ end
+
+ it "should set the content to the generated crl" do
+ @crl.generate(@cert, @key)
+ @crl.content.should equal(@real_crl)
+ end
+
+ it "should return the generated crl" do
+ @crl.generate(@cert, @key).should equal(@real_crl)
+ end
+ end
+
+ # This test suite isn't exactly complete, because the
+ # SSL stuff is very complicated. It just hits the high points.
+ describe "when revoking a certificate" do
+ before do
+ @class.wrapped_class.any_instance.stubs(:issuer=)
+ @class.wrapped_class.any_instance.stubs(:sign)
+
+ @crl = @class.new("crl")
+ @crl.generate(@cert, @key)
+ @crl.content.stubs(:sign)
+
+ @crl.stubs :save
+
+ @key = mock 'key'
+ end
+
+ it "should require a serial number and the CA's private key" do
+ lambda { @crl.revoke }.should raise_error(ArgumentError)
+ end
+
+ it "should default to OpenSSL::OCSP::REVOKED_STATUS_KEYCOMPROMISE as the revocation reason" do
+ # This makes it a bit more of an integration test than we'd normally like, but that's life
+ # with openssl.
+ reason = OpenSSL::ASN1::Enumerated(OpenSSL::OCSP::REVOKED_STATUS_KEYCOMPROMISE)
+ OpenSSL::ASN1.expects(:Enumerated).with(OpenSSL::OCSP::REVOKED_STATUS_KEYCOMPROMISE).returns reason
+
+ @crl.revoke(1, @key)
+ end
+
+ it "should mark the CRL as updated" do
+ time = Time.now
+ Time.stubs(:now).returns time
+
+ @crl.content.expects(:last_update=).with(time)
+
+ @crl.revoke(1, @key)
+ end
+
+ it "should mark the CRL valid for five years" do
+ time = Time.now
+ Time.stubs(:now).returns time
+
+ @crl.content.expects(:next_update=).with(time + (5 * 365*24*60*60))
+
+ @crl.revoke(1, @key)
+ end
+
+ it "should sign the CRL with the CA's private key and a digest instance" do
+ @crl.content.expects(:sign).with { |key, digest| key == @key and digest.is_a?(OpenSSL::Digest::SHA1) }
+ @crl.revoke(1, @key)
+ end
+
+ it "should save the CRL" do
+ @crl.expects :save
+ @crl.revoke(1, @key)
+ end
+ end
+end
diff --git a/spec/unit/ssl/host.rb b/spec/unit/ssl/host.rb
new file mode 100755
index 000000000..b717da80e
--- /dev/null
+++ b/spec/unit/ssl/host.rb
@@ -0,0 +1,431 @@
+#!/usr/bin/env ruby
+
+require File.dirname(__FILE__) + '/../../spec_helper'
+
+require 'puppet/ssl/host'
+
+describe Puppet::SSL::Host do
+ before do
+ @class = Puppet::SSL::Host
+ @host = @class.new("myname")
+ end
+
+ it "should use any provided name as its name" do
+ @host.name.should == "myname"
+ end
+
+ it "should retrieve its public key from its private key" do
+ realkey = mock 'realkey'
+ key = stub 'key', :content => realkey
+ Puppet::SSL::Key.stubs(:find).returns(key)
+ pubkey = mock 'public_key'
+ realkey.expects(:public_key).returns pubkey
+
+ @host.public_key.should equal(pubkey)
+ end
+
+ it "should default to being a non-ca host" do
+ @host.ca?.should be_false
+ end
+
+ it "should be a ca host if its name matches the CA_NAME" do
+ Puppet::SSL::Host.stubs(:ca_name).returns "yayca"
+ Puppet::SSL::Host.new("yayca").should be_ca
+ end
+
+ it "should have a method for determining the CA location" do
+ Puppet::SSL::Host.should respond_to(:ca_location)
+ end
+
+ it "should have a method for specifying the CA location" do
+ Puppet::SSL::Host.should respond_to(:ca_location=)
+ end
+
+ describe "when specifying the CA location" do
+ before do
+ [Puppet::SSL::Key, Puppet::SSL::Certificate, Puppet::SSL::CertificateRequest, Puppet::SSL::CertificateRevocationList].each do |klass|
+ klass.stubs(:terminus_class=)
+ klass.stubs(:cache_class=)
+ end
+ end
+
+ it "should support the location ':local'" do
+ lambda { Puppet::SSL::Host.ca_location = :local }.should_not raise_error
+ end
+
+ it "should support the location ':remote'" do
+ lambda { Puppet::SSL::Host.ca_location = :remote }.should_not raise_error
+ end
+
+ it "should support the location ':none'" do
+ lambda { Puppet::SSL::Host.ca_location = :none }.should_not raise_error
+ end
+
+ it "should not support other modes" do
+ lambda { Puppet::SSL::Host.ca_location = :whatever }.should raise_error(ArgumentError)
+ end
+
+ describe "as 'local'" do
+ it "should set the cache class for Certificate, CertificateRevocationList, and CertificateRequest as :file" do
+ Puppet::SSL::Certificate.expects(:cache_class=).with :file
+ Puppet::SSL::CertificateRequest.expects(:cache_class=).with :file
+ Puppet::SSL::CertificateRevocationList.expects(:cache_class=).with :file
+
+ Puppet::SSL::Host.ca_location = :local
+ end
+
+ it "should set the terminus class for Key as :file" do
+ Puppet::SSL::Key.expects(:terminus_class=).with :file
+
+ Puppet::SSL::Host.ca_location = :local
+ end
+
+ it "should set the terminus class for Certificate, CertificateRevocationList, and CertificateRequest as :ca" do
+ Puppet::SSL::Certificate.expects(:terminus_class=).with :ca
+ Puppet::SSL::CertificateRequest.expects(:terminus_class=).with :ca
+ Puppet::SSL::CertificateRevocationList.expects(:terminus_class=).with :ca
+
+ Puppet::SSL::Host.ca_location = :local
+ end
+ end
+
+ describe "as 'remote'" do
+ it "should set the cache class for Certificate, CertificateRevocationList, and CertificateRequest as :file" do
+ Puppet::SSL::Certificate.expects(:cache_class=).with :file
+ Puppet::SSL::CertificateRequest.expects(:cache_class=).with :file
+ Puppet::SSL::CertificateRevocationList.expects(:cache_class=).with :file
+
+ Puppet::SSL::Host.ca_location = :remote
+ end
+
+ it "should set the terminus class for Key as :file" do
+ Puppet::SSL::Key.expects(:terminus_class=).with :file
+
+ Puppet::SSL::Host.ca_location = :remote
+ end
+
+ it "should set the terminus class for Certificate, CertificateRevocationList, and CertificateRequest as :rest" do
+ Puppet::SSL::Certificate.expects(:terminus_class=).with :rest
+ Puppet::SSL::CertificateRequest.expects(:terminus_class=).with :rest
+ Puppet::SSL::CertificateRevocationList.expects(:terminus_class=).with :rest
+
+ Puppet::SSL::Host.ca_location = :remote
+ end
+ end
+
+ describe "as 'none'" do
+ it "should set the terminus class for Key, Certificate, CertificateRevocationList, and CertificateRequest as :file" do
+ Puppet::SSL::Key.expects(:terminus_class=).with :file
+ Puppet::SSL::Certificate.expects(:terminus_class=).with :file
+ Puppet::SSL::CertificateRequest.expects(:terminus_class=).with :file
+ Puppet::SSL::CertificateRevocationList.expects(:terminus_class=).with :file
+
+ Puppet::SSL::Host.ca_location = :none
+ end
+ end
+ end
+
+ it "should have a class method for destroying all files related to a given host" do
+ Puppet::SSL::Host.should respond_to(:destroy)
+ end
+
+ describe "when destroying a host's SSL files" do
+ before do
+ Puppet::SSL::Key.stubs(:destroy).returns false
+ Puppet::SSL::Certificate.stubs(:destroy).returns false
+ Puppet::SSL::CertificateRequest.stubs(:destroy).returns false
+ end
+
+ it "should destroy its certificate, certificate request, and key" do
+ Puppet::SSL::Key.expects(:destroy).with("myhost")
+ Puppet::SSL::Certificate.expects(:destroy).with("myhost")
+ Puppet::SSL::CertificateRequest.expects(:destroy).with("myhost")
+
+ Puppet::SSL::Host.destroy("myhost")
+ end
+
+ it "should return true if any of the classes returned true" do
+ Puppet::SSL::Certificate.expects(:destroy).with("myhost").returns true
+
+ Puppet::SSL::Host.destroy("myhost").should be_true
+ end
+
+ it "should return false if none of the classes returned true" do
+ Puppet::SSL::Host.destroy("myhost").should be_false
+ end
+ end
+
+ describe "when initializing" do
+ it "should default its name to the :certname setting" do
+ Puppet.settings.expects(:value).with(:certname).returns "myname"
+
+ Puppet::SSL::Host.new.name.should == "myname"
+ end
+
+ it "should indicate that it is a CA host if its name matches the ca_name constant" do
+ Puppet::SSL::Host.stubs(:ca_name).returns "myca"
+ Puppet::SSL::Host.new("myca").should be_ca
+ end
+ end
+
+ describe "when managing its private key" do
+ before do
+ @realkey = "mykey"
+ @key = stub 'key', :content => @realkey
+ end
+
+ it "should return nil if the key is not set and cannot be found" do
+ Puppet::SSL::Key.expects(:find).with("myname").returns(nil)
+ @host.key.should be_nil
+ end
+
+ it "should find the key in the Key class and return the Puppet instance" do
+ Puppet::SSL::Key.expects(:find).with("myname").returns(@key)
+ @host.key.should equal(@key)
+ end
+
+ it "should be able to generate and save a new key" do
+ Puppet::SSL::Key.expects(:new).with("myname").returns(@key)
+
+ @key.expects(:generate)
+ @key.expects(:save)
+
+ @host.generate_key.should be_true
+ @host.key.should equal(@key)
+ end
+
+ it "should return any previously found key without requerying" do
+ Puppet::SSL::Key.expects(:find).with("myname").returns(@key).once
+ @host.key.should equal(@key)
+ @host.key.should equal(@key)
+ end
+ end
+
+ describe "when managing its certificate request" do
+ before do
+ @realrequest = "real request"
+ @request = stub 'request', :content => @realrequest
+ end
+
+ it "should return nil if the key is not set and cannot be found" do
+ Puppet::SSL::CertificateRequest.expects(:find).with("myname").returns(nil)
+ @host.certificate_request.should be_nil
+ end
+
+ it "should find the request in the Key class and return it and return the Puppet SSL request" do
+ Puppet::SSL::CertificateRequest.expects(:find).with("myname").returns @request
+
+ @host.certificate_request.should equal(@request)
+ end
+
+ it "should generate a new key when generating the cert request if no key exists" do
+ Puppet::SSL::CertificateRequest.expects(:new).with("myname").returns @request
+
+ key = stub 'key', :public_key => mock("public_key"), :content => "mycontent"
+
+ @host.expects(:key).times(2).returns(nil).then.returns(key)
+ @host.expects(:generate_key).returns(key)
+
+ @request.stubs(:generate)
+ @request.stubs(:save)
+
+ @host.generate_certificate_request
+ end
+
+ it "should be able to generate and save a new request using the private key" do
+ Puppet::SSL::CertificateRequest.expects(:new).with("myname").returns @request
+
+ key = stub 'key', :public_key => mock("public_key"), :content => "mycontent"
+ @host.stubs(:key).returns(key)
+ @request.expects(:generate).with("mycontent")
+ @request.expects(:save)
+
+ @host.generate_certificate_request.should be_true
+ @host.certificate_request.should equal(@request)
+ end
+
+ it "should return any previously found request without requerying" do
+ Puppet::SSL::CertificateRequest.expects(:find).with("myname").returns(@request).once
+
+ @host.certificate_request.should equal(@request)
+ @host.certificate_request.should equal(@request)
+ end
+ end
+
+ describe "when managing its certificate" do
+ before do
+ @realcert = mock 'certificate'
+ @cert = stub 'cert', :content => @realcert
+ end
+
+ it "should find the certificate in the Certificate class and return the Puppet certificate instance" do
+ Puppet::SSL::Certificate.expects(:find).with("myname").returns @cert
+
+ @host.certificate.should equal(@cert)
+ end
+
+ it "should return any previously found certificate" do
+ Puppet::SSL::Certificate.expects(:find).with("myname").returns(@cert).once
+
+ @host.certificate.should equal(@cert)
+ @host.certificate.should equal(@cert)
+ end
+ end
+
+ it "should have a method for listing certificate hosts" do
+ Puppet::SSL::Host.should respond_to(:search)
+ end
+
+ describe "when listing certificate hosts" do
+ it "should default to listing all clients with any file types" do
+ Puppet::SSL::Key.expects(:search).returns []
+ Puppet::SSL::Certificate.expects(:search).returns []
+ Puppet::SSL::CertificateRequest.expects(:search).returns []
+ Puppet::SSL::Host.search
+ end
+
+ it "should be able to list only clients with a key" do
+ Puppet::SSL::Key.expects(:search).returns []
+ Puppet::SSL::Certificate.expects(:search).never
+ Puppet::SSL::CertificateRequest.expects(:search).never
+ Puppet::SSL::Host.search :for => Puppet::SSL::Key
+ end
+
+ it "should be able to list only clients with a certificate" do
+ Puppet::SSL::Key.expects(:search).never
+ Puppet::SSL::Certificate.expects(:search).returns []
+ Puppet::SSL::CertificateRequest.expects(:search).never
+ Puppet::SSL::Host.search :for => Puppet::SSL::Certificate
+ end
+
+ it "should be able to list only clients with a certificate request" do
+ Puppet::SSL::Key.expects(:search).never
+ Puppet::SSL::Certificate.expects(:search).never
+ Puppet::SSL::CertificateRequest.expects(:search).returns []
+ Puppet::SSL::Host.search :for => Puppet::SSL::CertificateRequest
+ end
+
+ it "should return a Host instance created with the name of each found instance" do
+ key = stub 'key', :name => "key"
+ cert = stub 'cert', :name => "cert"
+ csr = stub 'csr', :name => "csr"
+
+ Puppet::SSL::Key.expects(:search).returns [key]
+ Puppet::SSL::Certificate.expects(:search).returns [cert]
+ Puppet::SSL::CertificateRequest.expects(:search).returns [csr]
+
+ returned = []
+ %w{key cert csr}.each do |name|
+ result = mock(name)
+ returned << result
+ Puppet::SSL::Host.expects(:new).with(name).returns result
+ end
+
+ result = Puppet::SSL::Host.search
+ returned.each do |r|
+ result.should be_include(r)
+ end
+ end
+ end
+
+ it "should have a method for generating all necessary files" do
+ Puppet::SSL::Host.new("me").should respond_to(:generate)
+ end
+
+ describe "when generating files" do
+ before do
+ @host = Puppet::SSL::Host.new("me")
+ @host.stubs(:generate_key)
+ @host.stubs(:generate_certificate_request)
+ end
+
+ it "should generate a key if one is not present" do
+ @host.expects(:key).returns nil
+ @host.expects(:generate_key)
+
+ @host.generate
+ end
+
+ it "should generate a certificate request if one is not present" do
+ @host.expects(:certificate_request).returns nil
+ @host.expects(:generate_certificate_request)
+
+ @host.generate
+ end
+
+ describe "and it can create a certificate authority" do
+ before do
+ @ca = mock 'ca'
+ Puppet::SSL::CertificateAuthority.stubs(:instance).returns @ca
+ end
+
+ it "should use the CA to sign its certificate request if it does not have a certificate" do
+ @host.expects(:certificate).returns nil
+
+ @ca.expects(:sign).with(@host.name)
+
+ @host.generate
+ end
+ end
+
+ describe "and it cannot create a certificate authority" do
+ before do
+ Puppet::SSL::CertificateAuthority.stubs(:instance).returns nil
+ end
+
+ it "should seek its certificate" do
+ @host.expects(:certificate)
+
+ @host.generate
+ end
+ end
+ end
+
+ it "should have a method for creating an SSL store" do
+ Puppet::SSL::Host.new("me").should respond_to(:ssl_store)
+ end
+
+ describe "when creating an SSL store" do
+ before do
+ @host = Puppet::SSL::Host.new("me")
+ @store = mock 'store'
+ @store.stub_everything
+ OpenSSL::X509::Store.stubs(:new).returns @store
+
+ Puppet.settings.stubs(:value).returns "ssl_host_testing"
+ end
+
+ it "should accept a purpose" do
+ @store.expects(:purpose=).with "my special purpose"
+ @host.ssl_store("my special purpose")
+ end
+
+ it "should default to OpenSSL::X509::PURPOSE_ANY as the purpose" do
+ @store.expects(:purpose=).with OpenSSL::X509::PURPOSE_ANY
+ @host.ssl_store
+ end
+
+ it "should add the local CA cert file" do
+ Puppet.settings.stubs(:value).with(:localcacert).returns "/ca/cert/file"
+ @store.expects(:add_file).with "/ca/cert/file"
+ @host.ssl_store
+ end
+
+ describe "and a CRL is available" do
+ before do
+ @crl = stub 'crl', :content => "real_crl"
+ Puppet::SSL::CertificateRevocationList.stubs(:find).returns @crl
+ end
+
+ it "should add the CRL" do
+ @store.expects(:add_crl).with "real_crl"
+ @host.ssl_store
+ end
+
+ it "should set the flags to OpenSSL::X509::V_FLAG_CRL_CHECK_ALL|OpenSSL::X509::V_FLAG_CRL_CHECK" do
+ @store.expects(:flags=).with OpenSSL::X509::V_FLAG_CRL_CHECK_ALL|OpenSSL::X509::V_FLAG_CRL_CHECK
+ @host.ssl_store
+ end
+ end
+ end
+end
diff --git a/spec/unit/ssl/inventory.rb b/spec/unit/ssl/inventory.rb
new file mode 100755
index 000000000..bf1dbfb48
--- /dev/null
+++ b/spec/unit/ssl/inventory.rb
@@ -0,0 +1,180 @@
+#!/usr/bin/env ruby
+
+require File.dirname(__FILE__) + '/../../spec_helper'
+
+require 'puppet/ssl/inventory'
+
+describe Puppet::SSL::Inventory do
+ before do
+ @class = Puppet::SSL::Inventory
+ end
+
+ it "should use the :certinventory setting for the path to the inventory file" do
+ Puppet.settings.expects(:value).with(:cert_inventory).returns "/inven/tory"
+
+ @class.any_instance.stubs(:rebuild)
+
+ @class.new.path.should == "/inven/tory"
+ end
+
+ describe "when initializing" do
+ it "should set its path to the inventory file" do
+ Puppet.settings.stubs(:value).with(:cert_inventory).returns "/inven/tory"
+ @class.new.path.should == "/inven/tory"
+ end
+ end
+
+ describe "when managing an inventory" do
+ before do
+ Puppet.settings.stubs(:value).with(:cert_inventory).returns "/inven/tory"
+
+ FileTest.stubs(:exist?).with("/inven/tory").returns true
+
+ @inventory = @class.new
+
+ @cert = mock 'cert'
+ end
+
+ describe "and creating the inventory file" do
+ before do
+ Puppet.settings.stubs(:write)
+ FileTest.stubs(:exist?).with("/inven/tory").returns false
+
+ Puppet::SSL::Certificate.stubs(:search).returns []
+ end
+
+ it "should log that it is building a new inventory file" do
+ Puppet.expects(:notice)
+
+ @inventory.rebuild
+ end
+
+ it "should use the Settings to write to the file" do
+ Puppet.settings.expects(:write).with(:cert_inventory)
+
+ @inventory.rebuild
+ end
+
+ it "should add a header to the file" do
+ fh = mock 'filehandle'
+ Puppet.settings.stubs(:write).yields fh
+ fh.expects(:print).with { |str| str =~ /^#/ }
+
+ @inventory.rebuild
+ end
+
+ it "should add formatted information on all existing certificates" do
+ cert1 = mock 'cert1'
+ cert2 = mock 'cert2'
+
+ Puppet::SSL::Certificate.expects(:search).with("*").returns [cert1, cert2]
+
+ @class.any_instance.expects(:add).with(cert1)
+ @class.any_instance.expects(:add).with(cert2)
+
+ @inventory.rebuild
+ end
+ end
+
+ describe "and adding a certificate" do
+ it "should build the inventory file if one does not exist" do
+ Puppet.settings.stubs(:value).with(:cert_inventory).returns "/inven/tory"
+ Puppet.settings.stubs(:write)
+
+ FileTest.expects(:exist?).with("/inven/tory").returns false
+
+ @inventory.expects(:rebuild)
+
+ @inventory.add(@cert)
+ end
+
+ it "should use the Settings to write to the file" do
+ Puppet.settings.expects(:write).with(:cert_inventory, "a")
+
+ @inventory.add(@cert)
+ end
+
+ it "should use the actual certificate if it was passed a Puppet certificate" do
+ cert = Puppet::SSL::Certificate.new("mycert")
+ cert.content = @cert
+
+ fh = stub 'filehandle', :print => nil
+ Puppet.settings.stubs(:write).yields fh
+
+ @inventory.expects(:format).with(@cert)
+
+ @inventory.add(@cert)
+ end
+
+ it "should add formatted certificate information to the end of the file" do
+ fh = mock 'filehandle'
+
+ Puppet.settings.stubs(:write).yields fh
+
+ @inventory.expects(:format).with(@cert).returns "myformat"
+
+ fh.expects(:print).with("myformat")
+
+ @inventory.add(@cert)
+ end
+ end
+
+ describe "and formatting a certificate" do
+ before do
+ @cert = stub 'cert', :not_before => Time.now, :not_after => Time.now, :subject => "mycert", :serial => 15
+ end
+
+ it "should print the serial number as a 4 digit hex number in the first field" do
+ @inventory.format(@cert).split[0].should == "0x000f" # 15 in hex
+ end
+
+ it "should print the not_before date in '%Y-%m-%dT%H:%M:%S%Z' format in the second field" do
+ @cert.not_before.expects(:strftime).with('%Y-%m-%dT%H:%M:%S%Z').returns "before_time"
+
+ @inventory.format(@cert).split[1].should == "before_time"
+ end
+
+ it "should print the not_after date in '%Y-%m-%dT%H:%M:%S%Z' format in the third field" do
+ @cert.not_after.expects(:strftime).with('%Y-%m-%dT%H:%M:%S%Z').returns "after_time"
+
+ @inventory.format(@cert).split[2].should == "after_time"
+ end
+
+ it "should print the subject in the fourth field" do
+ @inventory.format(@cert).split[3].should == "mycert"
+ end
+
+ it "should add a carriage return" do
+ @inventory.format(@cert).should =~ /\n$/
+ end
+
+ it "should produce a line consisting of the serial number, start date, expiration date, and subject" do
+ # Just make sure our serial and subject bracket the lines.
+ @inventory.format(@cert).should =~ /^0x.+mycert$/
+ end
+ end
+
+ it "should be able to find a given host's serial number" do
+ @inventory.should respond_to(:serial)
+ end
+
+ describe "and finding a serial number" do
+ it "should return nil if the inventory file is missing" do
+ FileTest.expects(:exist?).with("/inven/tory").returns false
+ @inventory.serial(:whatever).should be_nil
+ end
+
+ it "should return the serial number from the line matching the provided name" do
+ File.expects(:readlines).with("/inven/tory").returns ["0x00f blah blah /CN=me\n", "0x001 blah blah /CN=you\n"]
+
+ @inventory.serial("me").should == 15
+ end
+
+ it "should return the number as an integer" do
+ File.expects(:readlines).with("/inven/tory").returns ["0x00f blah blah /CN=me\n", "0x001 blah blah /CN=you\n"]
+
+ @inventory.serial("me").should == 15
+ end
+ end
+ end
+end
diff --git a/spec/unit/ssl/key.rb b/spec/unit/ssl/key.rb
new file mode 100755
index 000000000..4cd8e856d
--- /dev/null
+++ b/spec/unit/ssl/key.rb
@@ -0,0 +1,190 @@
+#!/usr/bin/env ruby
+
+require File.dirname(__FILE__) + '/../../spec_helper'
+
+require 'puppet/ssl/key'
+
+describe Puppet::SSL::Key do
+ before do
+ @class = Puppet::SSL::Key
+ end
+
+ it "should be extended with the Indirector module" do
+ @class.metaclass.should be_include(Puppet::Indirector)
+ end
+
+ it "should indirect key" do
+ @class.indirection.name.should == :key
+ end
+
+ it "should default to the :file terminus" do
+ @class.indirection.terminus_class.should == :file
+ end
+
+ it "should have a method for determining whether it's a CA key" do
+ @class.new("test").should respond_to(:ca?)
+ end
+
+ it "should consider itself a ca key if its name matches the CA_NAME" do
+ @class.new(Puppet::SSL::Host.ca_name).should be_ca
+ end
+
+ describe "when initializing" do
+ it "should set its password file to the :capass if it's a CA key" do
+ Puppet.settings.stubs(:value).returns "whatever"
+ Puppet.settings.stubs(:value).with(:capass).returns "/ca/pass"
+
+ key = Puppet::SSL::Key.new(Puppet::SSL::Host.ca_name)
+ key.password_file.should == "/ca/pass"
+ end
+
+ it "should set its password file to the default password file if it is not the CA key" do
+ Puppet.settings.stubs(:value).returns "whatever"
+ Puppet.settings.stubs(:value).with(:passfile).returns "/normal/pass"
+
+ key = Puppet::SSL::Key.new("notca")
+ key.password_file.should == "/normal/pass"
+ end
+ end
+
+ describe "when managing instances" do
+ before do
+ @key = @class.new("myname")
+ end
+
+ it "should have a name attribute" do
+ @key.name.should == "myname"
+ end
+
+ it "should have a content attribute" do
+ @key.should respond_to(:content)
+ end
+
+ it "should be able to read keys from disk" do
+ path = "/my/path"
+ File.expects(:read).with(path).returns("my key")
+ key = mock 'key'
+ OpenSSL::PKey::RSA.expects(:new).returns(key)
+ @key.read(path).should equal(key)
+ @key.content.should equal(key)
+ end
+
+ it "should not try to use the provided password file if the file does not exist" do
+ FileTest.stubs(:exist?).returns false
+ @key.password_file = "/path/to/password"
+
+ path = "/my/path"
+
+ File.stubs(:read).with(path).returns("my key")
+ OpenSSL::PKey::RSA.expects(:new).with("my key", nil).returns(mock('key'))
+ File.expects(:read).with("/path/to/password").never
+
+ @key.read(path)
+ end
+
+ it "should read the key with the password retrieved from the password file if one is provided" do
+ FileTest.stubs(:exist?).returns true
+ @key.password_file = "/path/to/password"
+
+ path = "/my/path"
+ File.expects(:read).with(path).returns("my key")
+ File.expects(:read).with("/path/to/password").returns("my password")
+
+ key = mock 'key'
+ OpenSSL::PKey::RSA.expects(:new).with("my key", "my password").returns(key)
+ @key.read(path).should equal(key)
+ @key.content.should equal(key)
+ end
+
+ it "should return an empty string when converted to a string with no key" do
+ @key.to_s.should == ""
+ end
+
+ it "should convert the key to pem format when converted to a string" do
+ key = mock 'key', :to_pem => "pem"
+ @key.content = key
+ @key.to_s.should == "pem"
+ end
+
+ it "should have a :to_text method that it delegates to the actual key" do
+ real_key = mock 'key'
+ real_key.expects(:to_text).returns "keytext"
+ @key.content = real_key
+ @key.to_text.should == "keytext"
+ end
+ end
+
+ describe "when generating the private key" do
+ before do
+ @instance = @class.new("test")
+
+ @key = mock 'key'
+ end
+
+ it "should create an instance of OpenSSL::PKey::RSA" do
+ OpenSSL::PKey::RSA.expects(:new).returns(@key)
+
+ @instance.generate
+ end
+
+ it "should create the private key with the keylength specified in the settings" do
+ Puppet.settings.expects(:value).with(:keylength).returns("50")
+ OpenSSL::PKey::RSA.expects(:new).with(50).returns(@key)
+
+ @instance.generate
+ end
+
+ it "should set the content to the generated key" do
+ OpenSSL::PKey::RSA.stubs(:new).returns(@key)
+ @instance.generate
+ @instance.content.should equal(@key)
+ end
+
+ it "should return the generated key" do
+ OpenSSL::PKey::RSA.stubs(:new).returns(@key)
+ @instance.generate.should equal(@key)
+ end
+
+ it "should return the key in pem format" do
+ @instance.generate
+ @instance.content.expects(:to_pem).returns "my normal key"
+ @instance.to_s.should == "my normal key"
+ end
+
+ describe "with a password file set" do
+ it "should return a nil password if the password file does not exist" do
+ FileTest.expects(:exist?).with("/path/to/pass").returns false
+ File.expects(:read).with("/path/to/pass").never
+
+ @instance.password_file = "/path/to/pass"
+
+ @instance.password.should be_nil
+ end
+
+ it "should return the contents of the password file as its password" do
+ FileTest.expects(:exist?).with("/path/to/pass").returns true
+ File.expects(:read).with("/path/to/pass").returns "my password"
+
+ @instance.password_file = "/path/to/pass"
+
+ @instance.password.should == "my password"
+ end
+
+ it "should export the private key to text using the password" do
+ Puppet.settings.stubs(:value).with(:keylength).returns("50")
+
+ @instance.password_file = "/path/to/pass"
+ @instance.stubs(:password).returns "my password"
+
+ OpenSSL::PKey::RSA.expects(:new).returns(@key)
+ @instance.generate
+
+ cipher = mock 'cipher'
+ OpenSSL::Cipher::DES.expects(:new).with(:EDE3, :CBC).returns cipher
+ @key.expects(:export).with(cipher, "my password").returns "my encrypted key"
+
+ @instance.to_s.should == "my encrypted key"
+ end
+ end
+ end
+end
diff --git a/spec/unit/transaction/report.rb b/spec/unit/transaction/report.rb
index 644f8d709..8d49b16a0 100755
--- a/spec/unit/transaction/report.rb
+++ b/spec/unit/transaction/report.rb
@@ -35,6 +35,6 @@ describe Puppet::Transaction::Report, " when being indirect" do
end
after do
- Puppet::Indirector::Indirection.clear_cache
+ Puppet::Util::Cacher.invalidate
end
end
diff --git a/spec/unit/type/file.rb b/spec/unit/type/file.rb
index 12b806d88..d6add8609 100755
--- a/spec/unit/type/file.rb
+++ b/spec/unit/type/file.rb
@@ -93,8 +93,4 @@ describe Puppet::Type.type(:file) do
("%o" % (File.stat(@file).mode & 007777)).should == "%o" % 0755
end
end
-
- after do
- Puppet::Type::File.clear
- end
end
diff --git a/spec/unit/type/interface.rb b/spec/unit/type/interface.rb
index 27f34b7e0..4e27e35ea 100755
--- a/spec/unit/type/interface.rb
+++ b/spec/unit/type/interface.rb
@@ -90,6 +90,4 @@ describe interface do
it "should have a target parameter" do
@class.attrtype(:target).should == :param
end
-
- after { @class.clear }
end
diff --git a/spec/unit/type/mount.rb b/spec/unit/type/mount.rb
index a9b78672e..9d09225cc 100755
--- a/spec/unit/type/mount.rb
+++ b/spec/unit/type/mount.rb
@@ -11,8 +11,6 @@ describe Puppet::Type.type(:mount) do
mount = Puppet::Type.type(:mount).create(:name => "yay")
mount.should(:ensure).should be_nil
end
-
- after { Puppet::Type.type(:mount).clear }
end
describe Puppet::Type.type(:mount), "when validating attributes" do
@@ -51,8 +49,6 @@ describe Puppet::Type.type(:mount)::Ensure, "when validating values" do
it "should support :mounted as a value to :ensure" do
Puppet::Type.type(:mount).create(:name => "yay", :ensure => :mounted)
end
-
- after { Puppet::Type.type(:mount).clear }
end
describe Puppet::Type.type(:mount)::Ensure do
@@ -64,10 +60,6 @@ describe Puppet::Type.type(:mount)::Ensure do
@ensure = @mount.property(:ensure)
end
- after :each do
- Puppet::Type.type(:mount).clear
- end
-
def mount_stub(params)
Puppet::Type.type(:mount).validproperties.each do |prop|
unless params[prop]
diff --git a/spec/unit/type/noop_metaparam.rb b/spec/unit/type/noop_metaparam.rb
index 2a3e0160d..540603ef9 100755
--- a/spec/unit/type/noop_metaparam.rb
+++ b/spec/unit/type/noop_metaparam.rb
@@ -9,8 +9,6 @@ describe Puppet::Type.type(:file).attrclass(:noop) do
@file = Puppet::Type.newfile :path => "/what/ever"
end
- after { Puppet::Type::File.clear }
-
it "should accept true as a value" do
lambda { @file[:noop] = true }.should_not raise_error
end
diff --git a/spec/unit/type/package.rb b/spec/unit/type/package.rb
index 335910c63..d2fc85ed1 100755
--- a/spec/unit/type/package.rb
+++ b/spec/unit/type/package.rb
@@ -29,8 +29,6 @@ describe Puppet::Type::Package do
pkg = Puppet::Type::Package.create(:name => "yay")
pkg.should(:ensure).should == :present
end
-
- after { Puppet::Type::Package.clear }
end
describe Puppet::Type::Package, "when validating attributes" do
@@ -97,8 +95,6 @@ describe Puppet::Type::Package, "when validating attribute values" do
it "should accept any string as an argument to :source" do
proc { Puppet::Type::Package.create(:name => "yay", :source => "stuff") }.should_not raise_error(Puppet::Error)
end
-
- after { Puppet::Type::Package.clear }
end
module PackageEvaluationTesting
@@ -116,12 +112,6 @@ describe Puppet::Type::Package do
@catalog = Puppet::Node::Catalog.new
@catalog.add_resource(@package)
end
-
- after :each do
- @catalog.clear(true)
- Puppet::Type::Package.clear
- end
-
describe Puppet::Type::Package, "when it should be purged" do
include PackageEvaluationTesting
diff --git a/spec/unit/type/schedule.rb b/spec/unit/type/schedule.rb
index da38f68a9..b533d17e4 100755
--- a/spec/unit/type/schedule.rb
+++ b/spec/unit/type/schedule.rb
@@ -42,18 +42,12 @@ module ScheduleTesting
end
describe Puppet::Type::Schedule do
-
before :each do
Puppet.settings.stubs(:value).with(:ignoreschedules).returns(false)
@schedule = Puppet::Type::Schedule.create(:name => "testing")
end
- after :each do
- Puppet::Type::Schedule.clear
- end
-
-
describe Puppet::Type::Schedule do
include ScheduleTesting
diff --git a/spec/unit/type/service.rb b/spec/unit/type/service.rb
index e8358cb22..1a57bdd41 100755
--- a/spec/unit/type/service.rb
+++ b/spec/unit/type/service.rb
@@ -117,8 +117,6 @@ describe Puppet::Type::Service, "when validating attribute values" do
svc = Puppet::Type::Service.create(:name => "yay", :path => ["/one:/two", "/three:/four"])
svc[:path].should == %w{/one /two /three /four}
end
-
- after { Puppet::Type::Service.clear }
end
describe Puppet::Type::Service, "when setting default attribute values" do
@@ -148,8 +146,6 @@ describe Puppet::Type::Service, "when setting default attribute values" do
svc = Puppet::Type::Service.create(:name => "nfs.client")
svc[:control].should == "NFS_CLIENT_START"
end
-
- after { Puppet::Type::Service.clear }
end
describe Puppet::Type::Service, "when retrieving the host's current state" do
@@ -169,8 +165,6 @@ describe Puppet::Type::Service, "when retrieving the host's current state" do
@service[:enable] = true
@service.property(:enable).retrieve.should == :yepper
end
-
- after { Puppet::Type::Service.clear }
end
describe Puppet::Type::Service, "when changing the host" do
@@ -217,8 +211,6 @@ describe Puppet::Type::Service, "when changing the host" do
@service.property(:ensure).sync
end
-
- after { Puppet::Type::Service.clear }
end
describe Puppet::Type::Service, "when refreshing the service" do
@@ -251,6 +243,4 @@ describe Puppet::Type::Service, "when refreshing the service" do
@service.provider.expects(:restart)
@service.refresh
end
-
- after { Puppet::Type::Service.clear }
end
diff --git a/spec/unit/type/ssh_authorized_key.rb b/spec/unit/type/ssh_authorized_key.rb
index 0e869747d..1bdd86f37 100755
--- a/spec/unit/type/ssh_authorized_key.rb
+++ b/spec/unit/type/ssh_authorized_key.rb
@@ -75,6 +75,4 @@ describe ssh_authorized_key do
it "should have a target property" do
@class.attrtype(:target).should == :property
end
-
- after { @class.clear }
end
diff --git a/spec/unit/util/cacher.rb b/spec/unit/util/cacher.rb
new file mode 100755
index 000000000..73e449588
--- /dev/null
+++ b/spec/unit/util/cacher.rb
@@ -0,0 +1,158 @@
+#!/usr/bin/env ruby
+
+require File.dirname(__FILE__) + '/../../spec_helper'
+
+require 'puppet/util/cacher'
+
+class CacheClassTest
+ include Puppet::Util::Cacher
+
+ cached_attr(:testing) { Time.now }
+
+ def sa_cache
+ attr_cache(:ca_cache) { Time.now }
+ end
+end
+
+class CacheInstanceTest
+ extend Puppet::Util::Cacher
+
+ def self.sa_cache
+ attr_cache(:ca_cache) { Time.now }
+ end
+end
+
+describe "a cacher user using cached values", :shared => true do
+ it "should use the block to generate a new value if none is present" do
+ now = Time.now
+ Time.stubs(:now).returns now
+ @object.sa_cache.should equal(now)
+ end
+
+ it "should not test for validity if it is creating the value" do
+ # This is only necessary in the class, since it has this value kicking
+ # around.
+ @object.instance_variable_set("@cacher_caches", nil)
+ Puppet::Util::Cacher.expects(:valid?).never
+ @object.sa_cache
+ end
+
+ it "should not consider cached false values to be missing values" do
+ Puppet::Util::Cacher.stubs(:valid?).returns true
+
+ # This is only necessary in the class, since it has this value kicking
+ # around.
+ @object.instance_variable_set("@cacher_caches", nil)
+ Time.stubs(:now).returns false
+ @object.sa_cache
+ @object.sa_cache.should be_false
+ end
+
+ it "should return cached values if they are still valid" do
+ Puppet::Util::Cacher.stubs(:valid?).returns true
+
+ @object.sa_cache.should equal(@object.sa_cache)
+ end
+
+ it "should use the block to generate new values if the cached values are invalid" do
+ Puppet::Util::Cacher.stubs(:valid?).returns false
+
+ @object.sa_cache.should_not equal(@object.sa_cache)
+ end
+
+ it "should still cache values after an invalidation" do
+ # Load the cache
+ @object.sa_cache
+
+ Puppet::Util::Cacher.invalidate
+ @object.sa_cache.should equal(@object.sa_cache)
+ end
+end
+
+describe Puppet::Util::Cacher do
+ before do
+ Puppet::Util::Cacher.invalidate
+ end
+ after do
+ Puppet::Util::Cacher.invalidate
+ end
+
+ it "should have a method for invalidating caches" do
+ Puppet::Util::Cacher.should respond_to(:invalidate)
+ end
+
+ it "should have a method for determining whether a cached value is valid" do
+ Puppet::Util::Cacher.should respond_to(:valid?)
+ end
+
+ it "should consider cached values valid if the cached value was created and there was never an invalidation" do
+ Puppet::Util::Cacher.instance_variable_set("@timestamp", nil)
+
+ Puppet::Util::Cacher.should be_valid(Time.now)
+ end
+
+ it "should consider cached values valid if the cached value was created since the last invalidation" do
+ Puppet::Util::Cacher.invalidate
+
+ Puppet::Util::Cacher.should be_valid(Time.now + 1)
+ end
+
+ it "should consider cached values invalid if the cache was invalidated after the cached value was created" do
+ Puppet::Util::Cacher.invalidate
+
+ Puppet::Util::Cacher.should_not be_valid(Time.now - 1)
+ end
+
+ describe "when used to extend a class" do
+ before do
+ @object = CacheClassTest.new
+ end
+
+ it_should_behave_like "a cacher user using cached values"
+
+ it "should provide a class method for defining cached attributes" do
+ CacheClassTest.private_methods.should be_include("cached_attr")
+ end
+
+ describe "and defining cached attributes" do
+ it "should create an accessor for the cached attribute" do
+ @object.should respond_to(:testing)
+ end
+
+ it "should return a value calculated from the provided block" do
+ time = Time.now
+ Time.stubs(:now).returns time
+ @object.testing.should equal(time)
+ end
+
+ it "should return the cached value from the getter if the value is still valid" do
+ value = @object.testing
+ Puppet::Util::Cacher.expects(:valid?).returns true
+ @object.testing.should equal(value)
+ end
+
+ it "should regenerate and return a new value using the provided block if the value is no longer valid" do
+ value = @object.testing
+ Puppet::Util::Cacher.expects(:valid?).returns false
+ @object.testing.should_not equal(value)
+ end
+ end
+
+ it "should provide a private instance method for caching values" do
+ @object.private_methods.should be_include("attr_cache")
+ end
+
+ end
+
+ describe "when included in a class" do
+ before do
+ @object = CacheInstanceTest
+ end
+
+ it "should provide a private instance method for caching values" do
+ CacheInstanceTest.private_methods.should be_include("attr_cache")
+ end
+
+ it_should_behave_like "a cacher user using cached values"
+ end
+end
diff --git a/spec/unit/util/settings.rb b/spec/unit/util/settings.rb
index a6b358462..ca533ef9a 100755
--- a/spec/unit/util/settings.rb
+++ b/spec/unit/util/settings.rb
@@ -93,6 +93,11 @@ describe Puppet::Util::Settings, " when setting values" do
@settings[:myval].should == "yay"
end
+ it "should clear the list of used sections" do
+ @settings.expects(:clearused)
+ @settings[:myval] = "yay"
+ end
+
it "should call passed blocks when values are set" do
values = []
@settings.setdefaults(:section, :hooker => {:default => "yay", :desc => "boo", :hook => lambda { |v| values << v }})
@@ -284,11 +289,6 @@ describe Puppet::Util::Settings, " when parsing its configuration" do
lambda { @settings.parse(file) }.should_not raise_error
end
- it "should support an old parse method when per-executable configuration files still exist" do
- # I'm not going to bother testing this method.
- @settings.should respond_to(:old_parse)
- end
-
it "should convert booleans in the configuration file into Ruby booleans" do
text = "[main]
one = true
@@ -481,7 +481,7 @@ describe Puppet::Util::Settings, " when being used to manage the host machine" d
def stub_transaction
@bucket = mock 'bucket'
- @config = mock 'config', :clear => nil
+ @config = mock 'config'
@trans = mock 'transaction'
@settings.expects(:to_transportable).with(:whatever).returns(@bucket)
@@ -597,14 +597,6 @@ describe Puppet::Util::Settings, " when being used to manage the host machine" d
file.should be_nil
end
- it "should not try to manage files in memory" do
- main = Puppet::Type.type(:file).create(:path => "/maindir")
-
- trans = @settings.to_transportable
-
- lambda { trans.to_catalog }.should_not raise_error
- end
-
it "should do nothing if a catalog cannot be created" do
bucket = mock 'bucket'
catalog = mock 'catalog'
@@ -616,34 +608,6 @@ describe Puppet::Util::Settings, " when being used to manage the host machine" d
@settings.use(:mysection)
end
- it "should clear the catalog after applying" do
- bucket = mock 'bucket'
- catalog = mock 'catalog'
-
- @settings.expects(:to_transportable).returns bucket
- bucket.expects(:to_catalog).returns catalog
- catalog.stubs(:host_config=)
- catalog.stubs(:apply)
- catalog.expects(:clear)
-
- @settings.use(:mysection)
- end
-
- it "should clear the catalog even if there is an exception during applying" do
- bucket = mock 'bucket'
- catalog = mock 'catalog'
-
- @settings.expects(:to_transportable).returns bucket
- bucket.expects(:to_catalog).returns catalog
- catalog.stubs(:host_config=)
- catalog.expects(:apply).raises(ArgumentError)
- catalog.expects(:clear)
-
- # We don't care about the raised exception, we just care that
- # we clear the catalog even with the exception
- lambda { @settings.use(:mysection) }.should raise_error
- end
-
it "should do nothing if all specified sections have already been used" do
bucket = mock 'bucket'
catalog = mock 'catalog'
@@ -701,6 +665,4 @@ describe Puppet::Util::Settings, " when being used to manage the host machine" d
proc { @settings.use(:whatever) }.should raise_error(RuntimeError)
end
-
- after { Puppet::Type.allclear }
end