summaryrefslogtreecommitdiff
path: root/spec
diff options
context:
space:
mode:
authorAdam Jacob <adam@hjksolutions.com>2008-06-09 18:53:32 -0700
committerAdam Jacob <adam@hjksolutions.com>2008-06-09 18:53:32 -0700
commitaf843190f9be71469c4a20ef8f9021b292c05588 (patch)
treea38199db4baeaa3380ed41ec6e5e4c30b54b0685 /spec
parentd373915a1ac9ea25fcb52ac8468e4670425e3376 (diff)
downloadchef-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.rb63
-rw-r--r--spec/unit/compile_spec.rb4
-rw-r--r--spec/unit/cookbook_loader_spec.rb4
-rw-r--r--spec/unit/couchdb_spec.rb214
-rw-r--r--spec/unit/file_store_spec.rb9
-rw-r--r--spec/unit/node_spec.rb223
-rw-r--r--spec/unit/openid_registration_spec.rb154
-rw-r--r--spec/unit/rest_spec.rb182
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