summaryrefslogtreecommitdiff
path: root/spec/unit
diff options
context:
space:
mode:
authordanielsdeleo <dan@opscode.com>2012-12-18 10:47:24 -0800
committerdanielsdeleo <dan@opscode.com>2012-12-18 17:10:05 -0800
commita61c9865684466adcc9c933f05eebc1090624ea0 (patch)
tree224e1719aa7a49a2cd3e1e3c7265d204701121b5 /spec/unit
parent2de707d27251f38790a71043843749a570302aaf (diff)
downloadchef-a61c9865684466adcc9c933f05eebc1090624ea0.tar.gz
[CHEF-3689] Extract registration to a class
Diffstat (limited to 'spec/unit')
-rw-r--r--spec/unit/api_client/registration_spec.rb171
-rw-r--r--spec/unit/api_client_spec.rb12
2 files changed, 172 insertions, 11 deletions
diff --git a/spec/unit/api_client/registration_spec.rb b/spec/unit/api_client/registration_spec.rb
new file mode 100644
index 0000000000..513fa43a98
--- /dev/null
+++ b/spec/unit/api_client/registration_spec.rb
@@ -0,0 +1,171 @@
+#
+# Author:: Daniel DeLeo (<dan@opscode.com>)
+# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require 'spec_helper'
+require 'tempfile'
+
+require 'chef/api_client/registration'
+
+describe Chef::ApiClient::Registration do
+ let(:key_location) do
+ path = Tempfile.open("client-registration-key") {|f| f.path }
+ File.unlink(path)
+ path
+ end
+
+ let(:registration) { Chef::ApiClient::Registration.new("silent-bob", key_location) }
+
+ let :private_key_data do
+ File.open(Chef::Config[:validation_key], "rb") {|f| f.read.chomp }
+ end
+
+ before do
+ Chef::Config[:validation_client_name] = "test-validator"
+ Chef::Config[:validation_key] = File.expand_path('ssl/private_key.pem', CHEF_SPEC_DATA)
+ end
+
+ after do
+ File.unlink(key_location) if File.exist?(key_location)
+ Chef::Config[:validation_client_name] = nil
+ Chef::Config[:validation_key] = nil
+ end
+
+ it "has an HTTP client configured with validator credentials" do
+ registration.http_api.should be_a_kind_of(Chef::REST)
+ registration.http_api.client_name.should == "test-validator"
+ registration.http_api.signing_key.should == private_key_data
+ end
+
+ describe "when creating/updating the client on the server" do
+ let(:http_mock) { mock("Chef::REST mock") }
+
+ before do
+ registration.stub!(:http_api).and_return(http_mock)
+ end
+
+ it "creates a new ApiClient on the server using the validator identity" do
+ response = {"uri" => "https://chef.local/clients/silent-bob",
+ "private_key" => "--begin rsa key etc--"}
+ http_mock.should_receive(:post).
+ with("clients", :name => 'silent-bob', :admin => false).
+ and_return(response)
+ registration.create_or_update.should == response
+ registration.private_key.should == "--begin rsa key etc--"
+ end
+
+ context "and the client already exists on a Chef 10 server" do
+ it "requests a new key from the server and saves it" do
+ response = {"name" => "silent-bob", "private_key" => "--begin rsa key etc--" }
+
+ response_409 = Net::HTTPConflict.new("1.1", "409", "Conflict")
+ exception_409 = Net::HTTPServerException.new("409 conflict", response_409)
+
+ http_mock.should_receive(:post).and_raise(exception_409)
+ http_mock.should_receive(:put).
+ with("clients/silent-bob", :name => 'silent-bob', :admin => false, :private_key => true).
+ and_return(response)
+ registration.create_or_update.should == response
+ registration.private_key.should == "--begin rsa key etc--"
+ end
+ end
+
+ context "and the client already exists on a Chef 11 server" do
+ it "requests a new key from the server and saves it" do
+ response = Chef::ApiClient.new
+ response.name("silent-bob")
+ response.private_key("--begin rsa key etc--")
+
+ response_409 = Net::HTTPConflict.new("1.1", "409", "Conflict")
+ exception_409 = Net::HTTPServerException.new("409 conflict", response_409)
+
+ http_mock.should_receive(:post).and_raise(exception_409)
+ http_mock.should_receive(:put).
+ with("clients/silent-bob", :name => 'silent-bob', :admin => false, :private_key => true).
+ and_return(response)
+ registration.create_or_update.should == response
+ registration.private_key.should == "--begin rsa key etc--"
+ end
+ end
+ end
+
+ describe "when writing the private key to disk" do
+ before do
+ registration.stub!(:private_key).and_return('--begin rsa key etc--')
+ end
+
+ it "creates the file with 0600 permissions" do
+ File.should_not exist(key_location)
+ registration.write_key
+ File.should exist(key_location)
+ stat = File.stat(key_location)
+ (stat.mode & 07777).should == 0600
+ end
+
+ it "writes the private key content to the file" do
+ registration.write_key
+ IO.read(key_location).should == "--begin rsa key etc--"
+ end
+ end
+
+ describe "when registering a client" do
+
+ let(:http_mock) { mock("Chef::REST mock") }
+
+ before do
+ registration.stub!(:http_api).and_return(http_mock)
+ end
+
+ it "creates the client on the server and writes the key" do
+ response = {"uri" => "http://chef.local/clients/silent-bob",
+ "private_key" => "--begin rsa key etc--" }
+ http_mock.should_receive(:post).ordered.and_return(response)
+ registration.run
+ IO.read(key_location).should == "--begin rsa key etc--"
+ end
+
+ it "retries up to 5 times" do
+ response_500 = Net::HTTPInternalServerError.new("1.1", "500", "Internal Server Error")
+ exception_500 = Net::HTTPFatalError.new("500 Internal Server Error", response_500)
+
+ http_mock.should_receive(:post).ordered.and_raise(exception_500) # 1
+ http_mock.should_receive(:post).ordered.and_raise(exception_500) # 2
+ http_mock.should_receive(:post).ordered.and_raise(exception_500) # 3
+ http_mock.should_receive(:post).ordered.and_raise(exception_500) # 4
+ http_mock.should_receive(:post).ordered.and_raise(exception_500) # 5
+
+ response = {"uri" => "http://chef.local/clients/silent-bob",
+ "private_key" => "--begin rsa key etc--" }
+ http_mock.should_receive(:post).ordered.and_return(response)
+ registration.run
+ IO.read(key_location).should == "--begin rsa key etc--"
+ end
+
+ it "gives up retrying after the max attempts" do
+ response_500 = Net::HTTPInternalServerError.new("1.1", "500", "Internal Server Error")
+ exception_500 = Net::HTTPFatalError.new("500 Internal Server Error", response_500)
+
+ http_mock.should_receive(:post).exactly(6).times.and_raise(exception_500)
+
+ lambda {registration.run}.should raise_error(Net::HTTPFatalError)
+ end
+
+ end
+
+end
+
+
diff --git a/spec/unit/api_client_spec.rb b/spec/unit/api_client_spec.rb
index b47df6ad5c..6368082815 100644
--- a/spec/unit/api_client_spec.rb
+++ b/spec/unit/api_client_spec.rb
@@ -146,8 +146,6 @@ describe Chef::ApiClient do
before do
Chef::Config[:node_name] = "silent-bob"
Chef::Config[:client_key] = File.expand_path('ssl/private_key.pem', CHEF_SPEC_DATA)
- Chef::Config[:validation_client_name] = "test-validator"
- Chef::Config[:validation_key] = File.expand_path('ssl/private_key.pem', CHEF_SPEC_DATA)
end
after do
@@ -155,23 +153,15 @@ describe Chef::ApiClient do
Chef::Config[:client_key] = nil
end
- let :private_key_data do
- File.open(Chef::Config[:client_key], "rb") {|f| f.read.chomp }
- end
-
it "has an HTTP client configured with default credentials" do
@client.http_api.should be_a_kind_of(Chef::REST)
@client.http_api.client_name.should == "silent-bob"
@client.http_api.signing_key.to_s.should == private_key_data
end
- it "has an HTTP client configured with validator credentials" do
- @client.http_api_as_validator.should be_a_kind_of(Chef::REST)
- @client.http_api_as_validator.client_name.should == "test-validator"
- @client.http_api_as_validator.signing_key.should == private_key_data
- end
end
+
describe "when requesting a new key" do
before do
@http_client = mock("Chef::REST mock")