diff options
author | Adam Jacob <adam@hjksolutions.com> | 2008-06-09 18:53:32 -0700 |
---|---|---|
committer | Adam Jacob <adam@hjksolutions.com> | 2008-06-09 18:53:32 -0700 |
commit | af843190f9be71469c4a20ef8f9021b292c05588 (patch) | |
tree | a38199db4baeaa3380ed41ec6e5e4c30b54b0685 /spec | |
parent | d373915a1ac9ea25fcb52ac8468e4670425e3376 (diff) | |
download | chef-af843190f9be71469c4a20ef8f9021b292c05588.tar.gz |
Huge amount of work, covering openid, clients, and all sorts of server stuff
Diffstat (limited to 'spec')
-rw-r--r-- | spec/unit/client_spec.rb | 63 | ||||
-rw-r--r-- | spec/unit/compile_spec.rb | 4 | ||||
-rw-r--r-- | spec/unit/cookbook_loader_spec.rb | 4 | ||||
-rw-r--r-- | spec/unit/couchdb_spec.rb | 214 | ||||
-rw-r--r-- | spec/unit/file_store_spec.rb | 9 | ||||
-rw-r--r-- | spec/unit/node_spec.rb | 223 | ||||
-rw-r--r-- | spec/unit/openid_registration_spec.rb | 154 | ||||
-rw-r--r-- | spec/unit/rest_spec.rb | 182 |
8 files changed, 786 insertions, 67 deletions
diff --git a/spec/unit/client_spec.rb b/spec/unit/client_spec.rb new file mode 100644 index 0000000000..f0129ad9fc --- /dev/null +++ b/spec/unit/client_spec.rb @@ -0,0 +1,63 @@ +# +# Author:: Adam Jacob (<adam@hjksolutions.com>) +# Copyright:: Copyright (c) 2008 HJK Solutions, LLC +# License:: GNU General Public License version 2 or later +# +# This program and entire repository is free software; you can +# redistribute it and/or modify it under the terms of the GNU +# General Public License as published by the Free Software +# Foundation; either version 2 of the License, or any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +# + +require File.expand_path(File.join(File.dirname(__FILE__), "..", "spec_helper")) + +describe Chef::Client, "initialize" do + it "should create a new Chef::Client object" do + Chef::Client.new.should be_kind_of(Chef::Client) + end +end + +describe Chef::Client, "build_node" do + before(:each) do + @mock_facter_fqdn = mock("Facter FQDN") + @mock_facter_fqdn.stub!(:value).and_return("foo.bar.com") + @mock_facter_hostname = mock("Facter Hostname") + @mock_facter_hostname.stub!(:value).and_return("foo") + Facter.stub!(:[]).with("fqdn").and_return(@mock_facter_fqdn) + Facter.stub!(:[]).with("hostname").and_return(@mock_facter_hostname) + Facter.stub!(:each).and_return(true) + @client = Chef::Client.new + end + + it "should set the name equal to the FQDN" do + @client.build_node + @client.node.name.should eql("foo.bar.com") + end + + it "should set the name equal to the hostname if FQDN is not available" do + @mock_facter_fqdn.stub!(:value).and_return(nil) + @client.build_node + @client.node.name.should eql("foo") + end +end + +describe Chef::Client, "register" do + before(:each) do + @client = Chef::Client.new + end + + it "should check to see if it's already registered" + + it "should create a new passphrase if not registered" + + it "should create a new registration if it has not registered" +end
\ No newline at end of file diff --git a/spec/unit/compile_spec.rb b/spec/unit/compile_spec.rb index b6cde6582c..d042837606 100644 --- a/spec/unit/compile_spec.rb +++ b/spec/unit/compile_spec.rb @@ -43,6 +43,8 @@ describe Chef::Compile do end it "should load a node by name" do + node = Chef::Node.new + Chef::Node.stub!(:load).and_return(node) lambda { @compile.load_node("compile") }.should_not raise_error @@ -55,6 +57,8 @@ describe Chef::Compile do end it "should load all the recipes specified for this node" do + node = Chef::Node.new + Chef::Node.stub!(:load).and_return(node) @compile.load_node("compile") @compile.load_definitions lambda { @compile.load_recipes }.should_not raise_error diff --git a/spec/unit/cookbook_loader_spec.rb b/spec/unit/cookbook_loader_spec.rb index d66034ce7d..10f976cb05 100644 --- a/spec/unit/cookbook_loader_spec.rb +++ b/spec/unit/cookbook_loader_spec.rb @@ -37,6 +37,10 @@ describe Chef::CookbookLoader do @cl[:openldap].should be_a_kind_of(Chef::Cookbook) end + it "should raise an exception if it cannot find a cookbook with []" do + lambda { @cl[:monkeypoop] }.should raise_error(ArgumentError) + end + it "should allow you to look up available cookbooks with [] and a symbol" do @cl[:openldap].name.should eql(:openldap) end diff --git a/spec/unit/couchdb_spec.rb b/spec/unit/couchdb_spec.rb new file mode 100644 index 0000000000..e94302a217 --- /dev/null +++ b/spec/unit/couchdb_spec.rb @@ -0,0 +1,214 @@ +# +# Author:: Adam Jacob (<adam@hjksolutions.com>) +# Copyright:: Copyright (c) 2008 HJK Solutions, LLC +# License:: GNU General Public License version 2 or later +# +# This program and entire repository is free software; you can +# redistribute it and/or modify it under the terms of the GNU +# General Public License as published by the Free Software +# Foundation; either version 2 of the License, or any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +# + +require File.expand_path(File.join(File.dirname(__FILE__), "..", "spec_helper")) + +describe Chef::CouchDB, "new" do + it "should create a new Chef::REST object from the default url" do + Chef::Config[:couchdb_url] = "http://monkey" + Chef::REST.should_receive(:new).with("http://monkey").and_return(true) + Chef::CouchDB.new + end + + it "should create a new Chef::REST object from a provided url" do + Chef::REST.should_receive(:new).with("http://monkeypants").and_return(true) + Chef::CouchDB.new("http://monkeypants") + end +end + +describe Chef::CouchDB, "create_db" do + before(:each) do + @mock_rest = mock("Chef::REST", :null_object => true) + @mock_rest.stub!(:get_rest).and_return([ "chef" ]) + @mock_rest.stub!(:put_rest).and_return(true) + Chef::REST.stub!(:new).and_return(@mock_rest) + end + + def do_create_db + couch = Chef::CouchDB.new + couch.create_db + end + + it "should get a list of current databases" do + @mock_rest.should_receive(:get_rest).and_return(["chef"]) + do_create_db + end + + it "should create the chef database if it does not exist" do + @mock_rest.stub!(:get_rest).and_return([]) + @mock_rest.should_receive(:put_rest).with("chef", {}).and_return(true) + do_create_db + end + + it "should not create the chef database if it does exist" do + @mock_rest.stub!(:get_rest).and_return(["chef"]) + @mock_rest.should_not_receive(:put_rest) + do_create_db + end + + it "should return 'chef'" do + do_create_db.should eql("chef") + end +end + +describe Chef::CouchDB, "create_design_document" do + before(:each) do + @mock_rest = mock("Chef::REST", :null_object => true) + @mock_design = { + "version" => 1, + "_rev" => 1 + } + @mock_data = { + "version" => 1, + "language" => "javascript", + "views" => { + "all" => { + "map" => <<-EOJS + function(doc) { + if (doc.chef_type == "node") { + emit(doc.name, doc); + } + } + EOJS + }, + } + } + @mock_rest.stub!(:get_rest).and_return(@mock_design) + @mock_rest.stub!(:put_rest).and_return(true) + Chef::REST.stub!(:new).and_return(@mock_rest) + end + + def do_create_design_document + couchdb = Chef::CouchDB.new + couchdb.create_design_document("bob", @mock_data) + end + + it "should fetch the existing design document" do + @mock_rest.should_receive(:get_rest).with("chef/_design%2Fbob") + do_create_design_document + end + + it "should populate the _rev in the new design if the versions dont match" do + @mock_data["version"] = 2 + do_create_design_document + @mock_data["_rev"].should eql(1) + end + + it "should create the view if it requires updating" do + @mock_data["version"] = 2 + @mock_rest.should_receive(:put_rest).with("chef/_design%2Fbob", @mock_data) + do_create_design_document + end + + it "should not create the view if it does not require updating" do + @mock_data["version"] = 1 + @mock_rest.should_not_receive(:put_rest) + do_create_design_document + end +end + +describe Chef::CouchDB, "store" do + it "should put the object into couchdb" do + @mock_rest = mock("Chef::REST", :null_object => true) + @mock_rest.should_receive(:put_rest).with("chef/node_bob", {}).and_return(true) + Chef::REST.stub!(:new).and_return(@mock_rest) + Chef::CouchDB.new.store("node", "bob", {}) + end +end + +describe Chef::CouchDB, "load" do + it "should load the object from couchdb" do + @mock_rest = mock("Chef::REST", :null_object => true) + @mock_rest.should_receive(:get_rest).with("chef/node_bob").and_return(true) + Chef::REST.stub!(:new).and_return(@mock_rest) + Chef::CouchDB.new.load("node", "bob").should eql(true) + end +end + +describe Chef::CouchDB, "delete" do + before(:each) do + @mock_current = { + "version" => 1, + "_rev" => 1 + } + @mock_rest = mock("Chef::REST", :null_object => true) + @mock_rest.stub!(:get_rest).and_return(@mock_current) + @mock_rest.stub!(:delete_rest).and_return(true) + Chef::REST.stub!(:new).and_return(@mock_rest) + end + + def do_delete(rev=nil) + Chef::REST.stub!(:new).and_return(@mock_rest) + Chef::CouchDB.new.delete("node", "bob", rev) + end + + it "should remove the object from couchdb with a specific revision" do + @mock_rest.should_receive(:delete_rest).with("chef/node_bob?rev=1") + do_delete(1) + end + + it "should remove the object from couchdb based on the couchdb_rev of the current obj" do + mock_real = mock("Inflated Object") + mock_real.stub!(:respond_to?).and_return(true) + mock_real.stub!(:couchdb_rev).and_return(2) + @mock_rest.should_receive(:get_rest).with("chef/node_bob").and_return(mock_real) + @mock_rest.should_receive(:delete_rest).with("chef/node_bob?rev=2") + do_delete + end + + it "should remove the object from couchdb based on the current objects rev" do + @mock_rest.should_receive(:delete_rest).with("chef/node_bob?rev=1") + do_delete + end +end + +describe Chef::CouchDB, "list" do + before(:each) do + @mock_rest = mock("Chef::REST", :null_object => true) + Chef::REST.stub!(:new).and_return(@mock_rest) + end + + it "should get the view for all objects if inflate is true" do + @mock_rest.should_receive(:get_rest).with("chef/_view/node/all").and_return(true) + Chef::CouchDB.new.list("node", true) + end + + it "should get the view for just the object id's if inflate is false" do + @mock_rest.should_receive(:get_rest).with("chef/_view/node/all_id").and_return(true) + Chef::CouchDB.new.list("node", false) + end +end + +describe Chef::CouchDB, "has_key?" do + before(:each) do + @mock_rest = mock("Chef::REST", :null_object => true) + Chef::REST.stub!(:new).and_return(@mock_rest) + end + + it "should return true if the object exists" do + @mock_rest.should_receive(:get_rest).and_return(true) + Chef::CouchDB.new.has_key?("node", "bob").should eql(true) + end + + it "should return false if the object does not exist" do + @mock_rest.should_receive(:get_rest).and_raise(ArgumentError) + Chef::CouchDB.new.has_key?("node", "bob").should eql(false) + end +end diff --git a/spec/unit/file_store_spec.rb b/spec/unit/file_store_spec.rb index e7371653f1..6f12f7cec9 100644 --- a/spec/unit/file_store_spec.rb +++ b/spec/unit/file_store_spec.rb @@ -92,10 +92,11 @@ describe Chef::FileStore do Chef::FileStore.list("node").should eql(["pool"]) end - it "should let you test whether a key exists for an object type with has_key?" do - Dir.should_receive(:[]).with("/tmp/chef-test/node/**/*").and_return(["pool"]) - File.should_receive(:file?).with("pool").and_return(true) - Chef::FileStore.has_key?("node", "pool").should eql(true) + it "should return all the documents of a particular type with list and inflate" do + Dir.stub!(:[]).and_return(["/foo/pool"]) + File.stub!(:file?).and_return(true) + Chef::FileStore.should_receive(:load).with("node", "pool").and_return("monkey") + Chef::FileStore.list("node", true).should eql(["monkey"]) end it "should let you test whether a key doesnt exist for an object type with has_key?" do diff --git a/spec/unit/node_spec.rb b/spec/unit/node_spec.rb index 753d056404..e41c2235a3 100644 --- a/spec/unit/node_spec.rb +++ b/spec/unit/node_spec.rb @@ -20,7 +20,7 @@ require File.expand_path(File.join(File.dirname(__FILE__), "..", "spec_helper")) -describe Chef::Node do +describe Chef::Node, "new method" do before(:each) do Chef::Config.node_path(File.join(File.dirname(__FILE__), "..", "data", "nodes")) @node = Chef::Node.new() @@ -29,7 +29,14 @@ describe Chef::Node do it "should create a new Chef::Node" do @node.should be_a_kind_of(Chef::Node) end +end +describe Chef::Node, "name" do + before(:each) do + Chef::Config.node_path(File.join(File.dirname(__FILE__), "..", "data", "nodes")) + @node = Chef::Node.new() + end + it "should allow you to set a name with name(something)" do lambda { @node.name("latte") }.should_not raise_error end @@ -43,6 +50,14 @@ describe Chef::Node do lambda { @node.name(Hash.new) }.should raise_error(ArgumentError) end +end + +describe Chef::Node, "attributes" do + before(:each) do + Chef::Config.node_path(File.join(File.dirname(__FILE__), "..", "data", "nodes")) + @node = Chef::Node.new() + end + it "should have attributes" do @node.attribute.should be_a_kind_of(Hash) end @@ -67,6 +82,41 @@ describe Chef::Node do @node.attribute?("locust").should eql(true) @node.attribute?("no dice").should eql(false) end + + it "should allow you to set an attribute via method_missing" do + @node.sunshine "is bright" + @node.attribute[:sunshine].should eql("is bright") + end + + it "should allow you get get an attribute via method_missing" do + @node.sunshine "is bright" + @node.sunshine.should eql("is bright") + end + + it "should raise an ArgumentError if you ask for an attribute that doesn't exist via method_missing" do + lambda { @node.sunshine }.should raise_error(ArgumentError) + end + + it "should allow you to iterate over attributes with each_attribute" do + @node.sunshine "is bright" + @node.canada "is a nice place" + seen_attributes = Hash.new + @node.each_attribute do |a,v| + seen_attributes[a] = v + end + seen_attributes.should have_key(:sunshine) + seen_attributes.should have_key(:canada) + seen_attributes[:sunshine].should == "is bright" + seen_attributes[:canada].should == "is a nice place" + end + +end + +describe Chef::Node, "recipes" do + before(:each) do + Chef::Config.node_path(File.join(File.dirname(__FILE__), "..", "data", "nodes")) + @node = Chef::Node.new() + end it "should have an array of recipes that should be applied" do @node.recipes.should be_a_kind_of(Array) @@ -84,18 +134,12 @@ describe Chef::Node do @node.recipe?("two").should eql(true) end - it "should allow you to set an attribute via method_missing" do - @node.sunshine "is bright" - @node.attribute[:sunshine].should eql("is bright") - end - - it "should allow you get get an attribute via method_missing" do - @node.sunshine "is bright" - @node.sunshine.should eql("is bright") - end - - it "should raise an ArgumentError if you ask for an attribute that doesn't exist via method_missing" do - lambda { @node.sunshine }.should raise_error(ArgumentError) +end + +describe Chef::Node, "from file" do + before(:each) do + Chef::Config.node_path(File.join(File.dirname(__FILE__), "..", "data", "nodes")) + @node = Chef::Node.new() end it "should load a node from a ruby file" do @@ -109,38 +153,32 @@ describe Chef::Node do it "should raise an exception if the file cannot be found or read" do lambda { @node.from_file("/tmp/monkeydiving") }.should raise_error(IOError) end - - it "should allow you to iterate over attributes with each_attribute" do - @node.sunshine "is bright" - @node.canada "is a nice place" - seen_attributes = Hash.new - @node.each_attribute do |a,v| - seen_attributes[a] = v - end - seen_attributes.should have_key(:sunshine) - seen_attributes.should have_key(:canada) - seen_attributes[:sunshine].should == "is bright" - seen_attributes[:canada].should == "is a nice place" +end + +describe Chef::Node, "find_file" do + before(:each) do + Chef::Config.node_path(File.join(File.dirname(__FILE__), "..", "data", "nodes")) + @node = Chef::Node.new() end - + it "should load a node from a file by fqdn" do - node = Chef::Node.find("test.example.com") - node.name.should == "test.example.com" + @node.find_file("test.example.com") + @node.name.should == "test.example.com" end it "should load a node from a file by hostname" do File.stub!(:exists?).and_return(true) File.should_receive(:exists?).with(File.join(Chef::Config[:node_path], "test.example.com.rb")).and_return(false) - node = Chef::Node.find("test.example.com") - node.name.should == "test.example.com short" + @node.find_file("test.example.com") + @node.name.should == "test.example.com short" end it "should load a node from the default file" do File.stub!(:exists?).and_return(true) File.should_receive(:exists?).with(File.join(Chef::Config[:node_path], "test.example.com.rb")).and_return(false) File.should_receive(:exists?).with(File.join(Chef::Config[:node_path], "test.rb")).and_return(false) - node = Chef::Node.find("test.example.com") - node.name.should == "test.example.com default" + @node.find_file("test.example.com") + @node.name.should == "test.example.com default" end it "should raise an ArgumentError if it cannot find any node file at all" do @@ -148,12 +186,19 @@ describe Chef::Node do File.should_receive(:exists?).with(File.join(Chef::Config[:node_path], "test.example.com.rb")).and_return(false) File.should_receive(:exists?).with(File.join(Chef::Config[:node_path], "test.rb")).and_return(false) File.should_receive(:exists?).with(File.join(Chef::Config[:node_path], "default.rb")).and_return(false) - lambda { Chef::Node.find("test.example.com") }.should raise_error(ArgumentError) + lambda { @node.find_file("test.example.com") }.should raise_error(ArgumentError) end +end +describe Chef::Node, "json" do + before(:each) do + Chef::Config.node_path(File.join(File.dirname(__FILE__), "..", "data", "nodes")) + @node = Chef::Node.new() + end + it "should serialize itself as json" do - node = Chef::Node.find("test.example.com") - json = node.to_json() + @node.find_file("test.example.com") + json = @node.to_json() json.should =~ /json_class/ json.should =~ /name/ json.should =~ /attributes/ @@ -161,28 +206,110 @@ describe Chef::Node do end it "should deserialize itself from json" do - original_node = Chef::Node.find("test.example.com") - json = original_node.to_json + @node.find_file("test.example.com") + json = @node.to_json serialized_node = JSON.parse(json) serialized_node.should be_a_kind_of(Chef::Node) - serialized_node.name.should eql(original_node.name) - original_node.each_attribute do |k,v| + serialized_node.name.should eql(@node.name) + @node.each_attribute do |k,v| serialized_node[k].should eql(v) end - serialized_node.recipes.should eql(original_node.recipes) - end - - it "should return a list of node names based on which files are in the node_path" do - list = Chef::Node.list - list.should be_a_kind_of(Array) - list[0].should == "default" - list[1].should == "test.example.com" - list[2].should == "test" + serialized_node.recipes.should eql(@node.recipes) end +end + +describe Chef::Node, "to_s" do + before(:each) do + Chef::Config.node_path(File.join(File.dirname(__FILE__), "..", "data", "nodes")) + @node = Chef::Node.new() + end + it "should turn into a string like node[name]" do @node.name("airplane") @node.to_s.should eql("node[airplane]") end +end +describe Chef::Node, "list" do + before(:each) do + mock_couch = mock("Chef::CouchDB") + mock_couch.stub!(:list).and_return( + { + "rows" => [ + { + "value" => "a", + "key" => "avenue" + } + ] + } + ) + Chef::CouchDB.stub!(:new).and_return(mock_couch) + end + + it "should retrieve a list of nodes from CouchDB" do + Chef::Node.list.should eql(["avenue"]) + end + + it "should return just the ids if inflate is false" do + Chef::Node.list(false).should eql(["avenue"]) + end + + it "should return the full objects if inflate is true" do + Chef::Node.list(true).should eql(["a"]) + end +end + +describe Chef::Node, "load" do + it "should load a node from couchdb by name" do + mock_couch = mock("Chef::CouchDB") + mock_couch.should_receive(:load).with("node", "coffee").and_return(true) + Chef::CouchDB.stub!(:new).and_return(mock_couch) + Chef::Node.load("coffee") + end +end + +describe Chef::Node, "destroy" do + it "should delete this node from couchdb" do + mock_couch = mock("Chef::CouchDB") + mock_couch.should_receive(:delete).with("node", "bob", 1).and_return(true) + Chef::CouchDB.stub!(:new).and_return(mock_couch) + node = Chef::Node.new + node.name "bob" + node.couchdb_rev = 1 + Chef::Queue.should_receive(:send_msg).with(:queue, :node_remove, node) + node.destroy + end +end + +describe Chef::Node, "save" do + before(:each) do + @mock_couch = mock("Chef::CouchDB") + @mock_couch.stub!(:store).and_return({ "rev" => 33 }) + Chef::CouchDB.stub!(:new).and_return(@mock_couch) + Chef::Queue.stub!(:send_msg).and_return(true) + @node = Chef::Node.new + @node.name "bob" + @node.couchdb_rev = 1 + end + + it "should save the node to couchdb" do + Chef::Queue.should_receive(:send_msg).with(:queue, :node_index, @node) + @mock_couch.should_receive(:store).with("node", "bob", @node).and_return({ "rev" => 33 }) + @node.save + end + + it "should store the new couchdb_rev" do + @node.save + @node.couchdb_rev.should eql(33) + end +end + +describe Chef::Node, "create_design_document" do + it "should create our design document" do + mock_couch = mock("Chef::CouchDB") + mock_couch.should_receive(:create_design_document).with("nodes", Chef::Node::DESIGN_DOCUMENT) + Chef::CouchDB.stub!(:new).and_return(mock_couch) + Chef::Node.create_design_document + end end
\ No newline at end of file diff --git a/spec/unit/openid_registration_spec.rb b/spec/unit/openid_registration_spec.rb new file mode 100644 index 0000000000..4f8db8a36c --- /dev/null +++ b/spec/unit/openid_registration_spec.rb @@ -0,0 +1,154 @@ +# +# Author:: Adam Jacob (<adam@hjksolutions.com>) +# Copyright:: Copyright (c) 2008 HJK Solutions, LLC +# License:: GNU General Public License version 2 or later +# +# This program and entire repository is free software; you can +# redistribute it and/or modify it under the terms of the GNU +# General Public License as published by the Free Software +# Foundation; either version 2 of the License, or any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +# + +require File.expand_path(File.join(File.dirname(__FILE__), "..", "spec_helper")) + +describe Chef::OpenIDRegistration, "initialize" do + it "should return a new Chef::OpenIDRegistration object" do + Chef::OpenIDRegistration.new.should be_kind_of(Chef::OpenIDRegistration) + end +end + +describe Chef::OpenIDRegistration, "set_password" do + it "should generate a salt for this object" do + oreg = Chef::OpenIDRegistration.new + oreg.salt.should eql(nil) + oreg.set_password("foolio") + oreg.salt.should_not eql(nil) + end + + it "should encrypt the password with the salt and the plaintext password" do + oreg = Chef::OpenIDRegistration.new + oreg.set_password("foolio") + oreg.password.should_not eql(nil) + end +end + +describe Chef::OpenIDRegistration, "to_json" do + it "should serialize itself as json" do + oreg = Chef::OpenIDRegistration.new + oreg.set_password("monkey") + json = oreg.to_json + %w{json_class chef_type name salt password validated}.each do |verify| + json.should =~ /#{verify}/ + end + end +end + +describe Chef::OpenIDRegistration, "from_json" do + it "should serialize itself as json" do + oreg = Chef::OpenIDRegistration.new + oreg.set_password("monkey") + oreg_json = oreg.to_json + nreg = JSON.parse(oreg_json) + nreg.should be_a_kind_of(Chef::OpenIDRegistration) + %w{name salt password validated}.each do |verify| + nreg.send(verify.to_sym).should eql(oreg.send(verify.to_sym)) + end + end +end + +describe Chef::OpenIDRegistration, "list" do + before(:each) do + @mock_couch = mock("Chef::CouchDB") + @mock_couch.stub!(:list).and_return({ + "rows" => [ + { + "value" => "a", + "key" => "avenue" + } + ] + }) + Chef::CouchDB.stub!(:new).and_return(@mock_couch) + end + + it "should retrieve a list of nodes from CouchDB" do + Chef::OpenIDRegistration.list.should eql(["avenue"]) + end + + it "should return just the ids if inflate is false" do + Chef::OpenIDRegistration.list(false).should eql(["avenue"]) + end + + it "should return the full objects if inflate is true" do + Chef::OpenIDRegistration.list(true).should eql(["a"]) + end +end + +describe Chef::OpenIDRegistration, "load" do + it "should load a registration from couchdb by name" do + @mock_couch = mock("Chef::CouchDB") + Chef::CouchDB.stub!(:new).and_return(@mock_couch) + @mock_couch.should_receive(:load).with("openid_registration", "coffee").and_return(true) + Chef::OpenIDRegistration.load("coffee") + end +end + +describe Chef::OpenIDRegistration, "destroy" do + it "should delete this registration from couchdb" do + @mock_couch = mock("Chef::CouchDB") + @mock_couch.should_receive(:delete).with("openid_registration", "bob", 1).and_return(true) + Chef::CouchDB.stub!(:new).and_return(@mock_couch) + reg = Chef::OpenIDRegistration.new + reg.name = "bob" + reg.couchdb_rev = 1 + reg.destroy + end +end + +describe Chef::OpenIDRegistration, "save" do + before(:each) do + @mock_couch = mock("Chef::CouchDB") + Chef::CouchDB.stub!(:new).and_return(@mock_couch) + @reg = Chef::OpenIDRegistration.new + @reg.name = "bob" + @reg.couchdb_rev = 1 + end + + it "should save the registration to couchdb" do + @mock_couch.should_receive(:store).with("openid_registration", "bob", @reg).and_return({ "rev" => 33 }) + @reg.save + end + + it "should store the new couchdb_rev" do + @mock_couch.stub!(:store).with("openid_registration", "bob", @reg).and_return({ "rev" => 33 }) + @reg.save + @reg.couchdb_rev.should eql(33) + end +end + +describe Chef::OpenIDRegistration, "create_design_document" do + it "should create our design document" do + mock_couch = mock("Chef::CouchDB") + mock_couch.should_receive(:create_design_document).with("registrations", Chef::OpenIDRegistration::DESIGN_DOCUMENT) + Chef::CouchDB.stub!(:new).and_return(mock_couch) + Chef::OpenIDRegistration.create_design_document + end +end + +describe Chef::OpenIDRegistration, "has_key?" do + it "should check with CouchDB for a registration with this key" do + @mock_couch = mock("Chef::CouchDB") + @mock_couch.should_receive(:has_key?).with("openid_registration", "bob").and_return(true) + Chef::CouchDB.stub!(:new).and_return(@mock_couch) + Chef::OpenIDRegistration.has_key?("bob") + end +end + diff --git a/spec/unit/rest_spec.rb b/spec/unit/rest_spec.rb index df77d163e9..96238a6c2c 100644 --- a/spec/unit/rest_spec.rb +++ b/spec/unit/rest_spec.rb @@ -19,34 +19,186 @@ # require File.expand_path(File.join(File.dirname(__FILE__), "..", "spec_helper")) +require 'uri' +require 'net/https' -describe Chef::REST do +describe Chef::REST, "initialize method" do + it "should create a new Chef::REST" do + Chef::REST.new("url").should be_kind_of(Chef::REST) + end +end + +describe Chef::REST, "get_rest method" do + it "should create a url from the path and base url" do + URI.should_receive(:parse).with("url/monkey") + r = Chef::REST.new("url") + r.stub!(:run_request) + r.get_rest("monkey") + end + + it "should call run_request :GET with the composed url object" do + URI.stub!(:parse).and_return(true) + r = Chef::REST.new("url") + r.should_receive(:run_request).with(:GET, true).and_return(true) + r.get_rest("monkey") + end +end + +describe Chef::REST, "delete_rest method" do + it "should create a url from the path and base url" do + URI.should_receive(:parse).with("url/monkey") + r = Chef::REST.new("url") + r.stub!(:run_request) + r.delete_rest("monkey") + end + + it "should call run_request :DELETE with the composed url object" do + URI.stub!(:parse).and_return(true) + r = Chef::REST.new("url") + r.should_receive(:run_request).with(:DELETE, true).and_return(true) + r.delete_rest("monkey") + end +end + +describe Chef::REST, "post_rest method" do + it "should create a url from the path and base url" do + URI.should_receive(:parse).with("url/monkey") + r = Chef::REST.new("url") + r.stub!(:run_request) + r.post_rest("monkey", "data") + end + + it "should call run_request :POST with the composed url object and data" do + URI.stub!(:parse).and_return(true) + r = Chef::REST.new("url") + r.should_receive(:run_request).with(:POST, true, "data").and_return(true) + r.post_rest("monkey", "data") + end +end + +describe Chef::REST, "put_rest method" do + it "should create a url from the path and base url" do + URI.should_receive(:parse).with("url/monkey") + r = Chef::REST.new("url") + r.stub!(:run_request) + r.put_rest("monkey", "data") + end + + it "should call run_request :PUT with the composed url object and data" do + URI.stub!(:parse).and_return(true) + r = Chef::REST.new("url") + r.should_receive(:run_request).with(:PUT, true, "data").and_return(true) + r.put_rest("monkey", "data") + end +end - it "should make a connection to an http server" do - +describe Chef::REST, "run_request method" do + before(:each) do + @r = Chef::REST.new("url") + @url_mock = mock("URI", :null_object => true) + @url_mock.stub!(:host).and_return("one") + @url_mock.stub!(:port).and_return("80") + @url_mock.stub!(:path).and_return("/") + @url_mock.stub!(:query).and_return("foo=bar") + @url_mock.stub!(:scheme).and_return("https") + @http_response_mock = mock("Net::HTTPSuccess", :null_object => true) + @http_response_mock.stub!(:kind_of?).with(Net::HTTPSuccess).and_return(true) + @http_response_mock.stub!(:body).and_return("ninja") + @http_mock = mock("Net::HTTP", :null_object => true) + @http_mock.stub!(:verify_mode=).and_return(true) + @http_mock.stub!(:read_timeout=).and_return(true) + @http_mock.stub!(:use_ssl=).with(true).and_return(true) + @data_mock = mock("Data", :null_object => true) + @data_mock.stub!(:to_json).and_return('{ "one": "two" }') + @request_mock = mock("Request", :null_object => true) + @request_mock.stub!(:body=).and_return(true) + @http_mock.stub!(:request).and_return(@http_response_mock) end - it "should make a connection to an https server" do + def do_run_request(method=:GET, data=false, limit=10) + Net::HTTP.stub!(:new).and_return(@http_mock) + @r.run_request(method, @url_mock, data, limit) end - it "should authenticate if given a redirect" do - + it "should raise an exception if the redirect limit is 0" do + lambda { @r.run_request(:GET, "/", false, 0)}.should raise_error(ArgumentError) end - it "should GET a URL" do - + it "should use SSL if the url starts with https" do + @url_mock.should_receive(:scheme).and_return("https") + @http_mock.should_receive(:use_ssl=).with(true).and_return(true) + do_run_request end - it "should PUT to an URL " do - + it "should set the OpenSSL Verify Mode to verify_none if requested" do + @http_mock.should_receive(:verify_mode=).and_return(true) + do_run_request end - it "should POST to an URL" do - + it "should set a read timeout based on the rest_timeout config option" do + Chef::Config[:rest_timeout] = 10 + @http_mock.should_receive(:read_timeout=).with(10).and_return(true) + do_run_request end - it "should DELETE an URL" do - + it "should build a new HTTP GET request" do + Net::HTTP::Get.should_receive(:new).with("/?foo=bar", + { 'Accept' => 'application/json', "Content-Type" => 'application/json' } + ).and_return(true) + do_run_request end -end
\ No newline at end of file + it "should build a new HTTP POST request" do + Net::HTTP::Post.should_receive(:new).with("/", + { 'Accept' => 'application/json', "Content-Type" => 'application/json' } + ).and_return(@request_mock) + do_run_request(:POST, @data_mock) + end + + it "should build a new HTTP PUT request" do + Net::HTTP::Put.should_receive(:new).with("/", + { 'Accept' => 'application/json', "Content-Type" => 'application/json' } + ).and_return(@request_mock) + do_run_request(:PUT, @data_mock) + end + + it "should build a new HTTP DELETE request" do + Net::HTTP::Delete.should_receive(:new).with("/?foo=bar", + { 'Accept' => 'application/json', "Content-Type" => 'application/json' } + ).and_return(true) + do_run_request(:DELETE) + end + + it "should raise an error if the method is not GET/PUT/POST/DELETE" do + lambda { do_run_request(:MONKEY) }.should raise_error(ArgumentError) + end + + it "should run an http request" do + @http_mock.should_receive(:request).and_return(@http_response_mock) + do_run_request + end + + it "should return the body of the response on success" do + do_run_request.should eql("ninja") + end + + it "should inflate the body as to an object if JSON is returned" do + @http_response_mock.stub!(:[]).with('content-type').and_return("application/json") + JSON.should_receive(:parse).with("ninja").and_return(true) + do_run_request + end + + it "should call run_request again on a Redirect response" do + @http_response_mock.stub!(:kind_of?).with(Net::HTTPSuccess).and_return(false) + @http_response_mock.stub!(:kind_of?).with(Net::HTTPRedirection).and_return(true) + @http_response_mock.stub!(:[]).with('location').and_return(@url_mock) + lambda { do_run_request(method=:GET, data=false, limit=1) }.should raise_error(ArgumentError) + end + + it "should raise an exception on an unsuccessful request" do + @http_response_mock.stub!(:kind_of?).with(Net::HTTPSuccess).and_return(false) + @http_response_mock.stub!(:kind_of?).with(Net::HTTPRedirection).and_return(false) + @http_response_mock.should_receive(:error!) + do_run_request + end +end |