diff options
| author | Luke Kanies <luke@madstop.com> | 2008-05-05 22:25:42 -0500 |
|---|---|---|
| committer | Luke Kanies <luke@madstop.com> | 2008-05-05 22:25:42 -0500 |
| commit | 6e0d6ddf5ef1cd6b23a672020bb657744b5a2c59 (patch) | |
| tree | 472d2c2b9880e214ad0057954bb499446769827a | |
| parent | 51ce6746bc4c865b307af77b0967b345bf095aa8 (diff) | |
| download | puppet-6e0d6ddf5ef1cd6b23a672020bb657744b5a2c59.tar.gz puppet-6e0d6ddf5ef1cd6b23a672020bb657744b5a2c59.tar.xz puppet-6e0d6ddf5ef1cd6b23a672020bb657744b5a2c59.zip | |
The REST infrastructure now correctly the SSL certificates.
I don't think the whole thing is done, but at least the
basic flows are in place. Now it's just a question of
doing real-world tests and fleshing out the unit tests
as necessary.
| -rw-r--r-- | lib/puppet/indirector/rest.rb | 11 | ||||
| -rw-r--r-- | lib/puppet/network/http/mongrel/rest.rb | 10 | ||||
| -rw-r--r-- | lib/puppet/network/http_pool.rb | 2 | ||||
| -rwxr-xr-x[-rw-r--r--] | spec/integration/indirector/rest.rb | 836 | ||||
| -rwxr-xr-x | spec/unit/indirector/rest.rb | 623 |
5 files changed, 729 insertions, 753 deletions
diff --git a/lib/puppet/indirector/rest.rb b/lib/puppet/indirector/rest.rb index d33150fc2..77dd0538b 100644 --- a/lib/puppet/indirector/rest.rb +++ b/lib/puppet/indirector/rest.rb @@ -3,21 +3,20 @@ require 'uri' # Access objects via REST class Puppet::Indirector::REST < Puppet::Indirector::Terminus - def rest_connection_details { :host => Puppet[:server], :port => Puppet[:masterport].to_i } end def network_fetch(path) - network {|conn| conn.get("/#{path}").body } + network.get("/#{path}").body end def network_delete(path) - network {|conn| conn.delete("/#{path}").body } + network.delete("/#{path}").body end def network_put(path, data) - network {|conn| conn.put("/#{path}", data).body } + network.put("/#{path}", data).body end def find(request) @@ -46,8 +45,8 @@ class Puppet::Indirector::REST < Puppet::Indirector::Terminus private - def network(&block) - Net::HTTP.start(rest_connection_details[:host], rest_connection_details[:port]) {|conn| yield(conn) } + def network + Puppet::Network::HttpPool.http_instance(rest_connection_details[:host], rest_connection_details[:port]) end def exception?(yaml_string) diff --git a/lib/puppet/network/http/mongrel/rest.rb b/lib/puppet/network/http/mongrel/rest.rb index 2a3d4f143..a471a62bf 100644 --- a/lib/puppet/network/http/mongrel/rest.rb +++ b/lib/puppet/network/http/mongrel/rest.rb @@ -2,12 +2,12 @@ require 'puppet/network/http/handler' class Puppet::Network::HTTP::MongrelREST < Mongrel::HttpHandler - include Puppet::Network::HTTP::Handler + include Puppet::Network::HTTP::Handler - def initialize(args={}) - super() - initialize_for_puppet(args) - end + def initialize(args={}) + super() + initialize_for_puppet(args) + end private diff --git a/lib/puppet/network/http_pool.rb b/lib/puppet/network/http_pool.rb index 8c73adba6..9dd4a576a 100644 --- a/lib/puppet/network/http_pool.rb +++ b/lib/puppet/network/http_pool.rb @@ -23,8 +23,6 @@ module Puppet::Network::HttpPool @ssl_host end - # This handles reading in the key and such-like. - extend Puppet::SSLCertificates::Support @http_cache = {} # Clear our http cache, closing all connections. diff --git a/spec/integration/indirector/rest.rb b/spec/integration/indirector/rest.rb index 4c28f91cc..2db3b31fd 100644..100755 --- a/spec/integration/indirector/rest.rb +++ b/spec/integration/indirector/rest.rb @@ -1,3 +1,5 @@ +#!/usr/bin/env ruby + require File.dirname(__FILE__) + '/../../spec_helper' require 'puppet/network/server' require 'puppet/indirector' @@ -5,460 +7,478 @@ require 'puppet/indirector/rest' # a fake class that will be indirected via REST class Puppet::TestIndirectedFoo - extend Puppet::Indirector - indirects :test_indirected_foo, :terminus_setting => :test_indirected_foo_terminus - - attr_reader :value - - def initialize(value = 0) - @value = value - end - - def self.from_yaml(yaml) - YAML.load(yaml) - end - - def name - "bob" - end + extend Puppet::Indirector + indirects :test_indirected_foo, :terminus_setting => :test_indirected_foo_terminus + + attr_reader :value + + def initialize(value = 0) + @value = value + end + + def self.from_yaml(yaml) + YAML.load(yaml) + end + + def name + "bob" + end end # empty Terminus class -- this would normally have to be in a directory findable by the autoloader, but we short-circuit that below class Puppet::TestIndirectedFoo::Rest < Puppet::Indirector::REST end +# This way the retrieval of the class by name works. +Puppet::Indirector::Terminus.register_terminus_class(Puppet::TestIndirectedFoo::Rest) describe Puppet::Indirector::REST do - describe "when using webrick" do - before :each do - Puppet[:servertype] = 'webrick' - @params = { :address => "127.0.0.1", :port => 34343, :handlers => [ :test_indirected_foo ] } - @server = Puppet::Network::Server.new(@params) - - # LAK:NOTE For now, stub out the certificate setup. This will need to be undone when the client side expects - # to speak ssl, also. - Puppet::Network::HTTP::WEBrick.any_instance.stubs(:setup_ssl).returns({}) + before do + Puppet[:masterport] = 34343 + Puppet[:server] = "localhost" + + # Get a safe temporary file + @tmpfile = Tempfile.new("webrick_integration_testing") + @dir = @tmpfile.path + "_dir" - @server.listen + Puppet.settings[:confdir] = @dir + Puppet.settings[:vardir] = @dir + Puppet.settings[:http_enable_post_connection_check] = false - Puppet::Indirector::Terminus.stubs(:terminus_class).returns(Puppet::TestIndirectedFoo::Rest) - Puppet::TestIndirectedFoo.indirection.stubs(:terminus_class).returns :rest + Puppet::SSL::Host.ca_location = :local - # Stub the connection information. - Puppet::TestIndirectedFoo.indirection.terminus(:rest).stubs(:rest_connection_details).returns(:host => "localhost", :port => 34343) + Puppet::TestIndirectedFoo.terminus_class = :rest + Puppet::TestIndirectedFoo.indirection.terminus.stubs(:rest_connection_details).returns(:host => "127.0.0.1", :port => "34343") end - - describe "when finding a model instance over REST" do - describe "when a matching model instance can be found" do - before :each do - @model_instance = Puppet::TestIndirectedFoo.new(23) - @mock_model = stub('faked model', :find => @model_instance) - Puppet::Network::HTTP::WEBrickREST.any_instance.stubs(:model).returns(@mock_model) - end - - it "should not fail" do - Puppet::TestIndirectedFoo.find('bar') - lambda { Puppet::TestIndirectedFoo.find('bar') }.should_not raise_error - end - - it 'should return an instance of the model class' do - Puppet::TestIndirectedFoo.find('bar').class.should == Puppet::TestIndirectedFoo - end - - it 'should return the instance of the model class associated with the provided lookup key' do - Puppet::TestIndirectedFoo.find('bar').value.should == @model_instance.value - end - - it 'should set an expiration on model instance' do - Puppet::TestIndirectedFoo.find('bar').expiration.should_not be_nil - end - end - - describe "when no matching model instance can be found" do - before :each do - @mock_model = stub('faked model', :find => nil) - Puppet::Network::HTTP::WEBrickREST.any_instance.stubs(:model).returns(@mock_model) - end - - it "should return nil" do - Puppet::TestIndirectedFoo.find('bar').should be_nil - end - end - - describe "when an exception is encountered in looking up a model instance" do - before :each do - @mock_model = stub('faked model') - @mock_model.stubs(:find).raises(RuntimeError) - Puppet::Network::HTTP::WEBrickREST.any_instance.stubs(:model).returns(@mock_model) - end - - it "should raise an exception" do - lambda { Puppet::TestIndirectedFoo.find('bar') }.should raise_error(RuntimeError) - end - end + + after do + Puppet::Network::HttpPool.instance_variable_set("@ssl_host", nil) end - describe "when searching for model instances over REST" do - describe "when matching model instances can be found" do + describe "when using webrick" do before :each do - @model_instances = [ Puppet::TestIndirectedFoo.new(23), Puppet::TestIndirectedFoo.new(24) ] - @mock_model = stub('faked model', :search => @model_instances) - Puppet::Network::HTTP::WEBrickREST.any_instance.stubs(:model).returns(@mock_model) - end - - it "should not fail" do - lambda { Puppet::TestIndirectedFoo.search('bar') }.should_not raise_error - end - - it 'should return all matching results' do - Puppet::TestIndirectedFoo.search('bar').length.should == @model_instances.length - end - - it 'should return model instances' do - Puppet::TestIndirectedFoo.search('bar').each do |result| - result.class.should == Puppet::TestIndirectedFoo - end + Puppet[:servertype] = 'webrick' + Puppet[:server] = '127.0.0.1' + Puppet[:certname] = '127.0.0.1' + + ca = Puppet::SSL::CertificateAuthority.new + ca.generate(Puppet[:certname]) unless Puppet::SSL::Certificate.find(Puppet[:certname]) + + @params = { :address => "127.0.0.1", :port => 34343, :handlers => [ :test_indirected_foo ], :xmlrpc_handlers => [ :status ] } + @server = Puppet::Network::Server.new(@params) + @server.listen end - - it 'should return the instance of the model class associated with the provided lookup key' do - Puppet::TestIndirectedFoo.search('bar').collect(&:value).should == @model_instances.collect(&:value) + + after do + @server.unlisten + @tmpfile.delete + Puppet.settings.clear + + # This is necessary so the terminus instances don't lie around. + Puppet::SSL::Key.indirection.clear_cache + Puppet::SSL::Certificate.indirection.clear_cache + Puppet::SSL::CertificateRequest.indirection.clear_cache end - - it 'should set a version timestamp on model instances' do - pending("Luke looking at why this version magic might not be working") do - Puppet::TestIndirectedFoo.search('bar').each do |result| - result.version.should_not be_nil + + describe "when finding a model instance over REST" do + describe "when a matching model instance can be found" do + before :each do + @model_instance = Puppet::TestIndirectedFoo.new(23) + @mock_model = stub('faked model', :find => @model_instance) + Puppet::Network::HTTP::WEBrickREST.any_instance.stubs(:model).returns(@mock_model) + end + + it "should not fail" do + Puppet::TestIndirectedFoo.find('bar') + lambda { Puppet::TestIndirectedFoo.find('bar') }.should_not raise_error + end + + it 'should return an instance of the model class' do + Puppet::TestIndirectedFoo.find('bar').class.should == Puppet::TestIndirectedFoo + end + + it 'should return the instance of the model class associated with the provided lookup key' do + Puppet::TestIndirectedFoo.find('bar').value.should == @model_instance.value + end + + it 'should set an expiration on model instance' do + Puppet::TestIndirectedFoo.find('bar').expiration.should_not be_nil + end + end + + describe "when no matching model instance can be found" do + before :each do + @mock_model = stub('faked model', :find => nil) + Puppet::Network::HTTP::WEBrickREST.any_instance.stubs(:model).returns(@mock_model) + end + + it "should return nil" do + Puppet::TestIndirectedFoo.find('bar').should be_nil + end + end + + describe "when an exception is encountered in looking up a model instance" do + before :each do + @mock_model = stub('faked model') + @mock_model.stubs(:find).raises(RuntimeError) + Puppet::Network::HTTP::WEBrickREST.any_instance.stubs(:model).returns(@mock_model) + end + + it "should raise an exception" do + lambda { Puppet::TestIndirectedFoo.find('bar') }.should raise_error(RuntimeError) + end end - end end - end + + describe "when searching for model instances over REST" do + describe "when matching model instances can be found" do + before :each do + @model_instances = [ Puppet::TestIndirectedFoo.new(23), Puppet::TestIndirectedFoo.new(24) ] + @mock_model = stub('faked model', :search => @model_instances) + Puppet::Network::HTTP::WEBrickREST.any_instance.stubs(:model).returns(@mock_model) + end + + it "should not fail" do + lambda { Puppet::TestIndirectedFoo.search('bar') }.should_not raise_error + end - describe "when no matching model instance can be found" do - before :each do - @mock_model = stub('faked model', :find => nil) - Puppet::Network::HTTP::WEBrickREST.any_instance.stubs(:model).returns(@mock_model) - end - - it "should return nil" do - Puppet::TestIndirectedFoo.find('bar').should be_nil - end - end + it 'should return all matching results' do + Puppet::TestIndirectedFoo.search('bar').length.should == @model_instances.length + end - describe "when an exception is encountered in looking up a model instance" do - before :each do - @mock_model = stub('faked model') - @mock_model.stubs(:find).raises(RuntimeError) - Puppet::Network::HTTP::WEBrickREST.any_instance.stubs(:model).returns(@mock_model) - end - - it "should raise an exception" do - lambda { Puppet::TestIndirectedFoo.find('bar') }.should raise_error(RuntimeError) + it 'should return model instances' do + Puppet::TestIndirectedFoo.search('bar').each do |result| + result.class.should == Puppet::TestIndirectedFoo + end + end + + it 'should return the instance of the model class associated with the provided lookup key' do + Puppet::TestIndirectedFoo.search('bar').collect(&:value).should == @model_instances.collect(&:value) + end + end + + describe "when no matching model instance can be found" do + before :each do + @mock_model = stub('faked model', :find => nil) + Puppet::Network::HTTP::WEBrickREST.any_instance.stubs(:model).returns(@mock_model) + end + + it "should return nil" do + Puppet::TestIndirectedFoo.find('bar').should be_nil + end + end + + describe "when an exception is encountered in looking up a model instance" do + before :each do + @mock_model = stub('faked model') + @mock_model.stubs(:find).raises(RuntimeError) + Puppet::Network::HTTP::WEBrickREST.any_instance.stubs(:model).returns(@mock_model) + end + + it "should raise an exception" do + lambda { Puppet::TestIndirectedFoo.find('bar') }.should raise_error(RuntimeError) + end + end end - end - end - describe "when destroying a model instance over REST" do - describe "when a matching model instance can be found" do - before :each do - @mock_model = stub('faked model', :destroy => true) - Puppet::Network::HTTP::WEBrickREST.any_instance.stubs(:model).returns(@mock_model) - end - - it "should not fail" do - lambda { Puppet::TestIndirectedFoo.destroy('bar') }.should_not raise_error - end - - it 'should return success' do - Puppet::TestIndirectedFoo.destroy('bar').should == true - end - end + describe "when destroying a model instance over REST" do + describe "when a matching model instance can be found" do + before :each do + @mock_model = stub('faked model', :destroy => true) + Puppet::Network::HTTP::WEBrickREST.any_instance.stubs(:model).returns(@mock_model) + end + + it "should not fail" do + lambda { Puppet::TestIndirectedFoo.destroy('bar') }.should_not raise_error + end - describe "when no matching model instance can be found" do - before :each do - @mock_model = stub('faked model', :destroy => false) - Puppet::Network::HTTP::WEBrickREST.any_instance.stubs(:model).returns(@mock_model) - end - - it "should return failure" do - Puppet::TestIndirectedFoo.destroy('bar').should == false + it 'should return success' do + Puppet::TestIndirectedFoo.destroy('bar').should == true + end + end + + describe "when no matching model instance can be found" do + before :each do + @mock_model = stub('faked model', :destroy => false) + Puppet::Network::HTTP::WEBrickREST.any_instance.stubs(:model).returns(@mock_model) + end + + it "should return failure" do + Puppet::TestIndirectedFoo.destroy('bar').should == false + end + end + + describe "when an exception is encountered in destroying a model instance" do + before :each do + @mock_model = stub('faked model') + @mock_model.stubs(:destroy).raises(RuntimeError) + Puppet::Network::HTTP::WEBrickREST.any_instance.stubs(:model).returns(@mock_model) + end + + it "should raise an exception" do + lambda { Puppet::TestIndirectedFoo.destroy('bar') }.should raise_error(RuntimeError) + end + end end - end + + describe "when saving a model instance over REST" do + before :each do + @instance = Puppet::TestIndirectedFoo.new(42) + @mock_model = stub('faked model', :from_yaml => @instance) + Puppet::Network::HTTP::WEBrickREST.any_instance.stubs(:model).returns(@mock_model) + Puppet::Network::HTTP::WEBrickREST.any_instance.stubs(:save_object).returns(@instance) + end + + describe "when a successful save can be performed" do + before :each do + end + + it "should not fail" do + lambda { @instance.save }.should_not raise_error + end - describe "when an exception is encountered in destroying a model instance" do - before :each do - @mock_model = stub('faked model') - @mock_model.stubs(:destroy).raises(RuntimeError) - Puppet::Network::HTTP::WEBrickREST.any_instance.stubs(:model).returns(@mock_model) - end - - it "should raise an exception" do - lambda { Puppet::TestIndirectedFoo.destroy('bar') }.should raise_error(RuntimeError) + it 'should return an instance of the model class' do + @instance.save.class.should == Puppet::TestIndirectedFoo + end + + it 'should return a matching instance of the model class' do + @instance.save.value.should == @instance.value + end + end + + describe "when a save cannot be completed" do + before :each do + Puppet::Network::HTTP::WEBrickREST.any_instance.stubs(:save_object).returns(false) + end + + it "should return failure" do + @instance.save.should == false + end + end + + describe "when an exception is encountered in performing a save" do + before :each do + Puppet::Network::HTTP::WEBrickREST.any_instance.stubs(:save_object).raises(RuntimeError) + end + + it "should raise an exception" do + lambda { @instance.save }.should raise_error(RuntimeError) + end + end end - end end - describe "when saving a model instance over REST" do - before :each do - @instance = Puppet::TestIndirectedFoo.new(42) - @mock_model = stub('faked model', :from_yaml => @instance) - Puppet::Network::HTTP::WEBrickREST.any_instance.stubs(:model).returns(@mock_model) - Puppet::Network::HTTP::WEBrickREST.any_instance.stubs(:save_object).returns(@instance) - end - - describe "when a successful save can be performed" do + describe "when using mongrel" do + confine "Mongrel is not available" => Puppet.features.mongrel? + before :each do - end - - it "should not fail" do - lambda { @instance.save }.should_not raise_error - end - - it 'should return an instance of the model class' do - @instance.save.class.should == Puppet::TestIndirectedFoo - end - - it 'should return a matching instance of the model class' do - @instance.save.value.should == @instance.value - end - end - - describe "when a save cannot be completed" do - before :each do - Puppet::Network::HTTP::WEBrickREST.any_instance.stubs(:save_object).returns(false) - end - - it "should return failure" do - @instance.save.should == false - end - end - - describe "when an exception is encountered in performing a save" do - before :each do - Puppet::Network::HTTP::WEBrickREST.any_instance.stubs(:save_object).raises(RuntimeError) - end - - it "should raise an exception" do - lambda { @instance.save }.should raise_error(RuntimeError) - end - end - end + Puppet[:servertype] = 'mongrel' + @params = { :address => "127.0.0.1", :port => 34343, :handlers => [ :test_indirected_foo ] } - after :each do - @server.unlisten - end - end - - describe "when using mongrel" do - confine "Mongrel is not available" => Puppet.features.mongrel? - - before :each do - Puppet[:servertype] = 'mongrel' - @params = { :address => "127.0.0.1", :port => 34343, :handlers => [ :test_indirected_foo ] } - @server = Puppet::Network::Server.new(@params) - @server.listen + # Make sure we never get a cert, since mongrel can't speak ssl + Puppet::SSL::Certificate.stubs(:find).returns nil - # the autoloader was clearly not written test-first. We subvert the integration test to get around its bullshit. - Puppet::Indirector::Terminus.stubs(:terminus_class).returns(Puppet::TestIndirectedFoo::Rest) - Puppet::TestIndirectedFoo.indirection.stubs(:terminus_class).returns :rest + # We stub ssl to be off, since mongrel can't speak ssl + Net::HTTP.any_instance.stubs(:use_ssl?).returns false - # Stub the connection information. - Puppet::TestIndirectedFoo.indirection.terminus(:rest).stubs(:rest_connection_details).returns(:host => "localhost", :port => 34343) - end - - describe "when finding a model instance over REST" do - describe "when a matching model instance can be found" do - before :each do - @model_instance = Puppet::TestIndirectedFoo.new(23) - @mock_model = stub('faked model', :find => @model_instance) - Puppet::Network::HTTP::MongrelREST.any_instance.stubs(:model).returns(@mock_model) - end - - it "should not fail" do - lambda { Puppet::TestIndirectedFoo.find('bar') }.should_not raise_error - end - - it 'should return an instance of the model class' do - Puppet::TestIndirectedFoo.find('bar').class.should == Puppet::TestIndirectedFoo + @server = Puppet::Network::Server.new(@params) + @server.listen end - - it 'should return the instance of the model class associated with the provided lookup key' do - Puppet::TestIndirectedFoo.find('bar').value.should == @model_instance.value - end - - it 'should set an expiration on model instance' do - Puppet::TestIndirectedFoo.find('bar').expiration.should_not be_nil + + after :each do + @server.unlisten end - end - describe "when no matching model instance can be found" do - before :each do - @mock_model = stub('faked model', :find => nil) - Puppet::Network::HTTP::MongrelREST.any_instance.stubs(:model).returns(@mock_model) - end - - it "should return nil" do - Puppet::TestIndirectedFoo.find('bar').should be_nil - end - end + describe "when finding a model instance over REST" do + describe "when a matching model instance can be found" do + before :each do + @model_instance = Puppet::TestIndirectedFoo.new(23) + @mock_model = stub('faked model', :find => @model_instance) + Puppet::Network::HTTP::MongrelREST.any_instance.stubs(:model).returns(@mock_model) + end + + it "should not fail" do + lambda { Puppet::TestIndirectedFoo.find('bar') }.should_not raise_error + end - describe "when an exception is encountered in looking up a model instance" do - before :each do - @mock_model = stub('faked model') - @mock_model.stubs(:find).raises(RuntimeError) - Puppet::Network::HTTP::MongrelREST.any_instance.stubs(:model).returns(@mock_model) - end - - it "should raise an exception" do - lambda { Puppet::TestIndirectedFoo.find('bar') }.should raise_error(RuntimeError) - end - end - end - - describe "when searching for model instances over REST" do - describe "when matching model instances can be found" do - before :each do - @model_instances = [ Puppet::TestIndirectedFoo.new(23), Puppet::TestIndirectedFoo.new(24) ] - @mock_model = stub('faked model', :search => @model_instances) - Puppet::Network::HTTP::MongrelREST.any_instance.stubs(:model).returns(@mock_model) - end - - it "should not fail" do - lambda { Puppet::TestIndirectedFoo.search('bar') }.should_not raise_error - end - - it 'should return all matching results' do - Puppet::TestIndirectedFoo.search('bar').length.should == @model_instances.length - end - - it 'should return model instances' do - Puppet::TestIndirectedFoo.search('bar').each do |result| - result.class.should == Puppet::TestIndirectedFoo - end - end - - it 'should return the instance of the model class associated with the provided lookup key' do - Puppet::TestIndirectedFoo.search('bar').collect(&:value).should == @model_instances.collect(&:value) - end - - it 'should set an expiration on model instances' do - Puppet::TestIndirectedFoo.search('bar').each do |result| - result.expiration.should_not be_nil - end - end - end + it 'should return an instance of the model class' do + Puppet::TestIndirectedFoo.find('bar').class.should == Puppet::TestIndirectedFoo + end - describe "when no matching model instance can be found" do - before :each do - @mock_model = stub('faked model', :find => nil) - Puppet::Network::HTTP::MongrelREST.any_instance.stubs(:model).returns(@mock_model) - end - - it "should return nil" do - Puppet::TestIndirectedFoo.find('bar').should be_nil - end - end + it 'should return the instance of the model class associated with the provided lookup key' do + Puppet::TestIndirectedFoo.find('bar').value.should == @model_instance.value + end - describe "when an exception is encountered in looking up a model instance" do - before :each do - @mock_model = stub('faked model') - @mock_model.stubs(:find).raises(RuntimeError) - Puppet::Network::HTTP::MongrelREST.any_instance.stubs(:model).returns(@mock_model) - end - - it "should raise an exception" do - lambda { Puppet::TestIndirectedFoo.find('bar') }.should raise_error(RuntimeError) + it 'should set an expiration on model instance' do + Puppet::TestIndirectedFoo.find('bar').expiration.should_not be_nil + end + end + + describe "when no matching model instance can be found" do + before :each do + @mock_model = stub('faked model', :find => nil) + Puppet::Network::HTTP::MongrelREST.any_instance.stubs(:model).returns(@mock_model) + end + + it "should return nil" do + Puppet::TestIndirectedFoo.find('bar').should be_nil + end + end + + describe "when an exception is encountered in looking up a model instance" do + before :each do + @mock_model = stub('faked model') + @mock_model.stubs(:find).raises(RuntimeError) + Puppet::Network::HTTP::MongrelREST.any_instance.stubs(:model).returns(@mock_model) + end + + it "should raise an exception" do + lambda { Puppet::TestIndirectedFoo.find('bar') }.should raise_error(RuntimeError) + end + end end - end - end - describe "when destroying a model instance over REST" do - describe "when a matching model instance can be found" do - before :each do - @mock_model = stub('faked model', :destroy => true) - Puppet::Network::HTTP::MongrelREST.any_instance.stubs(:model).returns(@mock_model) - end - - it "should not fail" do - lambda { Puppet::TestIndirectedFoo.destroy('bar') }.should_not raise_error - end - - it 'should return success' do - Puppet::TestIndirectedFoo.destroy('bar').should == true - end - end + describe "when searching for model instances over REST" do + describe "when matching model instances can be found" do + before :each do + @model_instances = [ Puppet::TestIndirectedFoo.new(23), Puppet::TestIndirectedFoo.new(24) ] + @mock_model = stub('faked model', :search => @model_instances) + Puppet::Network::HTTP::MongrelREST.any_instance.stubs(:model).returns(@mock_model) + end + + it "should not fail" do + lambda { Puppet::TestIndirectedFoo.search('bar') }.should_not raise_error + end - describe "when no matching model instance can be found" do - before :each do - @mock_model = stub('faked model', :destroy => false) - Puppet::Network::HTTP::MongrelREST.any_instance.stubs(:model).returns(@mock_model) - end - - it "should return failure" do - Puppet::TestIndirectedFoo.destroy('bar').should == false - end - end + it 'should return all matching results' do + Puppet::TestIndirectedFoo.search('bar').length.should == @model_instances.length + end - describe "when an exception is encountered in destroying a model instance" do - before :each do - @mock_model = stub('faked model') - @mock_model.stubs(:destroy).raises(RuntimeError) - Puppet::Network::HTTP::MongrelREST.any_instance.stubs(:model).returns(@mock_model) - end - - it "should raise an exception" do - lambda { Puppet::TestIndirectedFoo.destroy('bar') }.should raise_error(RuntimeError) + it 'should return model instances' do + Puppet::TestIndirectedFoo.search('bar').each do |result| + result.class.should == Puppet::TestIndirectedFoo + end + end + + it 'should return the instance of the model class associated with the provided lookup key' do + Puppet::TestIndirectedFoo.search('bar').collect(&:value).should == @model_instances.collect(&:value) + end + + it 'should set an expiration on model instances' do + Puppet::TestIndirectedFoo.search('bar').each do |result| + result.expiration.should_not be_nil + end + end + end + + describe "when no matching model instance can be found" do + before :each do + @mock_model = stub('faked model', :find => nil) + Puppet::Network::HTTP::MongrelREST.any_instance.stubs(:model).returns(@mock_model) + end + + it "should return nil" do + Puppet::TestIndirectedFoo.find('bar').should be_nil + end + end + + describe "when an exception is encountered in looking up a model instance" do + before :each do + @mock_model = stub('faked model') + @mock_model.stubs(:find).raises(RuntimeError) + Puppet::Network::HTTP::MongrelREST.any_instance.stubs(:model).returns(@mock_model) + end + + it "should raise an exception" do + lambda { Puppet::TestIndirectedFoo.find('bar') }.should raise_error(RuntimeError) + end + end end - end - end - describe "when saving a model instance over REST" do - before :each do - @instance = Puppet::TestIndirectedFoo.new(42) - @mock_model = stub('faked model', :from_yaml => @instance) - Puppet::Network::HTTP::MongrelREST.any_instance.stubs(:model).returns(@mock_model) - Puppet::Network::HTTP::MongrelREST.any_instance.stubs(:save_object).returns(@instance) - end - - describe "when a successful save can be performed" do - before :each do - end - - it "should not fail" do - lambda { @instance.save }.should_not raise_error - end - - it 'should return an instance of the model class' do - @instance.save.class.should == Puppet::TestIndirectedFoo - end - - it 'should return a matching instance of the model class' do - @instance.save.value.should == @instance.value - end - end - - describe "when a save cannot be completed" do - before :each do - Puppet::Network::HTTP::MongrelREST.any_instance.stubs(:save_object).returns(false) - end - - it "should return failure" do - @instance.save.should == false - end - end - - describe "when an exception is encountered in performing a save" do - before :each do - Puppet::Network::HTTP::MongrelREST.any_instance.stubs(:save_object).raises(RuntimeError) - end - - it "should raise an exception" do - lambda { @instance.save }.should raise_error(RuntimeError) + describe "when destroying a model instance over REST" do + describe "when a matching model instance can be found" do + before :each do + @mock_model = stub('faked model', :destroy => true) + Puppet::Network::HTTP::MongrelREST.any_instance.stubs(:model).returns(@mock_model) + end + + it "should not fail" do + lambda { Puppet::TestIndirectedFoo.destroy('bar') }.should_not raise_error + end + + it 'should return success' do + Puppet::TestIndirectedFoo.destroy('bar').should == true + end + end + + describe "when no matching model instance can be found" do + before :each do + @mock_model = stub('faked model', :destroy => false) + Puppet::Network::HTTP::MongrelREST.any_instance.stubs(:model).returns(@mock_model) + end + + it "should return failure" do + Puppet::TestIndirectedFoo.destroy('bar').should == false + end + end + + describe "when an exception is encountered in destroying a model instance" do + before :each do + @mock_model = stub('faked model') + @mock_model.stubs(:destroy).raises(RuntimeError) + Puppet::Network::HTTP::MongrelREST.any_instance.stubs(:model).returns(@mock_model) + end + + it "should raise an exception" do + lambda { Puppet::TestIndirectedFoo.destroy('bar') }.should raise_error(RuntimeError) + end + end end - end - end - after :each do - @server.unlisten + describe "when saving a model instance over REST" do + before :each do + @instance = Puppet::TestIndirectedFoo.new(42) + @mock_model = stub('faked model', :from_yaml => @instance) + Puppet::Network::HTTP::MongrelREST.any_instance.stubs(:model).returns(@mock_model) + Puppet::Network::HTTP::MongrelREST.any_instance.stubs(:save_object).returns(@instance) + end + + describe "when a successful save can be performed" do + before :each do + end + + it "should not fail" do + lambda { @instance.save }.should_not raise_error + end + + it 'should return an instance of the model class' do + @instance.save.class.should == Puppet::TestIndirectedFoo + end + + it 'should return a matching instance of the model class' do + @instance.save.value.should == @instance.value + end + end + + describe "when a save cannot be completed" do + before :each do + Puppet::Network::HTTP::MongrelREST.any_instance.stubs(:save_object).returns(false) + end + + it "should return failure" do + @instance.save.should == false + end + end + + describe "when an exception is encountered in performing a save" do + before :each do + Puppet::Network::HTTP::MongrelREST.any_instance.stubs(:save_object).raises(RuntimeError) + end + + it "should raise an exception" do + lambda { @instance.save }.should raise_error(RuntimeError) + end + end + end 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 |
