diff options
Diffstat (limited to 'spec/unit')
53 files changed, 1777 insertions, 1270 deletions
diff --git a/spec/unit/api_client_spec.rb b/spec/unit/api_client_spec.rb index bc4b38848b..a0e399b470 100644 --- a/spec/unit/api_client_spec.rb +++ b/spec/unit/api_client_spec.rb @@ -21,6 +21,11 @@ require 'spec_helper' require 'chef/api_client' require 'tempfile' +# DEPRECATION NOTE +# +# This code will be removed in Chef 13 in favor of the code in Chef::ApiClientV1, +# which will be moved to this namespace. New development should occur in +# Chef::ApiClientV1 until the time before Chef 13. describe Chef::ApiClient do before(:each) do @client = Chef::ApiClient.new @@ -53,20 +58,6 @@ describe Chef::ApiClient do expect { @client.admin(Hash.new) }.to raise_error(ArgumentError) end - it "has an create_key flag attribute" do - @client.create_key(true) - expect(@client.create_key).to be_truthy - end - - it "create_key defaults to false" do - expect(@client.create_key).to be_falsey - end - - it "allows only boolean values for the create_key flag" do - expect { @client.create_key(false) }.not_to raise_error - expect { @client.create_key(Hash.new) }.to raise_error(ArgumentError) - end - it "has a 'validator' flag attribute" do @client.validator(true) expect(@client.validator).to be_truthy @@ -129,12 +120,6 @@ describe Chef::ApiClient do expect(@json).to include(%q{"validator":false}) end - it "includes the 'create_key' flag when present" do - @client.create_key(true) - @json = @client.to_json - expect(@json).to include(%q{"create_key":true}) - end - it "includes the private key when present" do @client.private_key("monkeypants") expect(@client.to_json).to include(%q{"private_key":"monkeypants"}) @@ -143,15 +128,11 @@ describe Chef::ApiClient do it "does not include the private key if not present" do expect(@json).not_to include("private_key") end - - include_examples "to_json equivalent to Chef::JSONCompat.to_json" do - let(:jsonable) { @client } - end end describe "when deserializing from JSON (string) using ApiClient#from_json" do let(:client_string) do - "{\"name\":\"black\",\"public_key\":\"crowes\",\"private_key\":\"monkeypants\",\"admin\":true,\"validator\":true,\"create_key\":true}" + "{\"name\":\"black\",\"public_key\":\"crowes\",\"private_key\":\"monkeypants\",\"admin\":true,\"validator\":true}" end let(:client) do @@ -178,10 +159,6 @@ describe Chef::ApiClient do expect(client.admin).to be_truthy end - it "preserves the create_key status" do - expect(client.create_key).to be_truthy - end - it "preserves the 'validator' status" do expect(client.validator).to be_truthy end @@ -199,7 +176,6 @@ describe Chef::ApiClient do "private_key" => "monkeypants", "admin" => true, "validator" => true, - "create_key" => true, "json_class" => "Chef::ApiClient" } end @@ -224,10 +200,6 @@ describe Chef::ApiClient do expect(client.admin).to be_truthy end - it "preserves the create_key status" do - expect(client.create_key).to be_truthy - end - it "preserves the 'validator' status" do expect(client.validator).to be_truthy end @@ -243,18 +215,16 @@ describe Chef::ApiClient do before(:each) do client = { - "name" => "black", - "clientname" => "black", - "public_key" => "crowes", - "private_key" => "monkeypants", - "admin" => true, - "create_key" => true, - "validator" => true, - "json_class" => "Chef::ApiClient" + "name" => "black", + "clientname" => "black", + "public_key" => "crowes", + "private_key" => "monkeypants", + "admin" => true, + "validator" => true, + "json_class" => "Chef::ApiClient" } - - @http_client = double("Chef::REST mock") - allow(Chef::REST).to receive(:new).and_return(@http_client) + @http_client = double("Chef::ServerAPI mock") + allow(Chef::ServerAPI).to receive(:new).and_return(@http_client) expect(@http_client).to receive(:get).with("clients/black").and_return(client) @client = Chef::ApiClient.load(client['name']) end @@ -275,10 +245,6 @@ describe Chef::ApiClient do expect(@client.admin).to be_a_kind_of(TrueClass) end - it "preserves the create_key status" do - expect(@client.create_key).to be_a_kind_of(TrueClass) - end - it "preserves the 'validator' status" do expect(@client.validator).to be_a_kind_of(TrueClass) end @@ -304,18 +270,13 @@ describe Chef::ApiClient do File.open(Chef::Config[:client_key], "r") {|f| f.read.chomp } end - it "has an HTTP client configured with default credentials" do - expect(@client.http_api).to be_a_kind_of(Chef::REST) - expect(@client.http_api.client_name).to eq("silent-bob") - expect(@client.http_api.signing_key.to_s).to eq(private_key_data) - end end describe "when requesting a new key" do before do @http_client = double("Chef::REST mock") - allow(Chef::REST).to receive(:new).and_return(@http_client) + allow(Chef::ServerAPI).to receive(:new).and_return(@http_client) end context "and the client does not exist on the server" do @@ -332,34 +293,24 @@ describe Chef::ApiClient do end context "and the client exists" do - let(:chef_rest_v0_mock) { double('chef rest root v0 object') } - let(:payload) { - {:name => "lost-my-key", :admin => false, :validator => false, :private_key => true} - } - before do @api_client_without_key = Chef::ApiClient.new @api_client_without_key.name("lost-my-key") - allow(@api_client_without_key).to receive(:chef_rest_v0).and_return(chef_rest_v0_mock) - #allow(@api_client_with_key).to receive(:http_api).and_return(_api_mock) - - allow(chef_rest_v0_mock).to receive(:put).with("clients/lost-my-key", payload).and_return(@api_client_with_key) - allow(chef_rest_v0_mock).to receive(:get).with("clients/lost-my-key").and_return(@api_client_without_key) - allow(@http_client).to receive(:get).with("clients/lost-my-key").and_return(@api_client_without_key) + expect(@http_client).to receive(:get).with("clients/lost-my-key").and_return(@api_client_without_key) end + context "and the client exists on a Chef 11-like server" do before do @api_client_with_key = Chef::ApiClient.new @api_client_with_key.name("lost-my-key") @api_client_with_key.private_key("the new private key") - allow(@api_client_with_key).to receive(:chef_rest_v0).and_return(chef_rest_v0_mock) + expect(@http_client).to receive(:put). + with("clients/lost-my-key", :name => "lost-my-key", :admin => false, :validator => false, :private_key => true). + and_return(@api_client_with_key) end it "returns an ApiClient with a private key" do - expect(chef_rest_v0_mock).to receive(:put).with("clients/lost-my-key", payload). - and_return(@api_client_with_key) - response = Chef::ApiClient.reregister("lost-my-key") # no sane == method for ApiClient :'( expect(response).to eq(@api_client_without_key) @@ -372,7 +323,7 @@ describe Chef::ApiClient do context "and the client exists on a Chef 10-like server" do before do @api_client_with_key = {"name" => "lost-my-key", "private_key" => "the new private key"} - expect(chef_rest_v0_mock).to receive(:put). + expect(@http_client).to receive(:put). with("clients/lost-my-key", :name => "lost-my-key", :admin => false, :validator => false, :private_key => true). and_return(@api_client_with_key) end @@ -390,134 +341,4 @@ describe Chef::ApiClient do end end - - describe "Versioned API Interactions" do - let(:response_406) { OpenStruct.new(:code => '406') } - let(:exception_406) { Net::HTTPServerException.new("406 Not Acceptable", response_406) } - let(:payload) { - { - :name => "some_name", - :validator => true, - :admin => true - } - } - - before do - @client = Chef::ApiClient.new - allow(@client).to receive(:chef_rest_v0).and_return(double('chef rest root v0 object')) - allow(@client).to receive(:chef_rest_v1).and_return(double('chef rest root v1 object')) - @client.name "some_name" - @client.validator true - @client.admin true - end - - describe "create" do - - # from spec/support/shared/unit/user_and_client_shared.rb - it_should_behave_like "user or client create" do - let(:object) { @client } - let(:error) { Chef::Exceptions::InvalidClientAttribute } - let(:rest_v0) { @client.chef_rest_v0 } - let(:rest_v1) { @client.chef_rest_v1 } - let(:url) { "clients" } - end - - context "when API V1 is not supported by the server" do - # from spec/support/shared/unit/api_versioning.rb - it_should_behave_like "version handling" do - let(:object) { @client } - let(:method) { :create } - let(:http_verb) { :post } - let(:rest_v1) { @client.chef_rest_v1 } - end - end - - end # create - - describe "update" do - context "when a valid client is defined" do - - shared_examples_for "client updating" do - it "updates the client" do - expect(rest). to receive(:put).with("clients/some_name", payload) - @client.update - end - - context "when only the name field exists" do - - before do - # needed since there is no way to set to nil via code - @client.instance_variable_set(:@validator, nil) - @client.instance_variable_set(:@admin, nil) - end - - after do - @client.validator true - @client.admin true - end - - it "updates the client with only the name" do - expect(rest). to receive(:put).with("clients/some_name", {:name => "some_name"}) - @client.update - end - end - - end - - context "when API V1 is supported by the server" do - - it_should_behave_like "client updating" do - let(:rest) { @client.chef_rest_v1 } - end - - end # when API V1 is supported by the server - - context "when API V1 is not supported by the server" do - context "when no version is supported" do - # from spec/support/shared/unit/api_versioning.rb - it_should_behave_like "version handling" do - let(:object) { @client } - let(:method) { :create } - let(:http_verb) { :post } - let(:rest_v1) { @client.chef_rest_v1 } - end - end # when no version is supported - - context "when API V0 is supported" do - - before do - allow(@client.chef_rest_v1).to receive(:put).and_raise(exception_406) - allow(@client).to receive(:server_client_api_version_intersection).and_return([0]) - end - - it_should_behave_like "client updating" do - let(:rest) { @client.chef_rest_v0 } - end - - end - - end # when API V1 is not supported by the server - end # when a valid client is defined - end # update - - # DEPRECATION - # This can be removed after API V0 support is gone - describe "reregister" do - context "when server API V0 is valid on the Chef Server receiving the request" do - it "creates a new object via the API" do - expect(@client.chef_rest_v0).to receive(:put).with("clients/#{@client.name}", payload.merge({:private_key => true})).and_return({}) - @client.reregister - end - end # when server API V0 is valid on the Chef Server receiving the request - - context "when server API V0 is not supported by the Chef Server" do - # from spec/support/shared/unit/api_versioning.rb - it_should_behave_like "user and client reregister" do - let(:object) { @client } - let(:rest_v0) { @client.chef_rest_v0 } - end - end # when server API V0 is not supported by the Chef Server - end # reregister - - end end diff --git a/spec/unit/api_client_v1_spec.rb b/spec/unit/api_client_v1_spec.rb new file mode 100644 index 0000000000..17aba8c3af --- /dev/null +++ b/spec/unit/api_client_v1_spec.rb @@ -0,0 +1,457 @@ +# +# Author:: Adam Jacob (<adam@opscode.com>) +# Copyright:: Copyright (c) 2008 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 'chef/api_client_v1' +require 'tempfile' + +describe Chef::ApiClientV1 do + before(:each) do + @client = Chef::ApiClientV1.new + end + + it "has a name attribute" do + @client.name("ops_master") + expect(@client.name).to eq("ops_master") + end + + it "does not allow spaces in the name" do + expect { @client.name "ops master" }.to raise_error(ArgumentError) + end + + it "only allows string values for the name" do + expect { @client.name Hash.new }.to raise_error(ArgumentError) + end + + it "has an admin flag attribute" do + @client.admin(true) + expect(@client.admin).to be_truthy + end + + it "defaults to non-admin" do + expect(@client.admin).to be_falsey + end + + it "allows only boolean values for the admin flag" do + expect { @client.admin(false) }.not_to raise_error + expect { @client.admin(Hash.new) }.to raise_error(ArgumentError) + end + + it "has an create_key flag attribute" do + @client.create_key(true) + expect(@client.create_key).to be_truthy + end + + it "create_key defaults to false" do + expect(@client.create_key).to be_falsey + end + + it "allows only boolean values for the create_key flag" do + expect { @client.create_key(false) }.not_to raise_error + expect { @client.create_key(Hash.new) }.to raise_error(ArgumentError) + end + + it "has a 'validator' flag attribute" do + @client.validator(true) + expect(@client.validator).to be_truthy + end + + it "defaults to non-validator" do + expect(@client.validator).to be_falsey + end + + it "allows only boolean values for the 'validator' flag" do + expect { @client.validator(false) }.not_to raise_error + expect { @client.validator(Hash.new) }.to raise_error(ArgumentError) + end + + it "has a public key attribute" do + @client.public_key("super public") + expect(@client.public_key).to eq("super public") + end + + it "accepts only String values for the public key" do + expect { @client.public_key "" }.not_to raise_error + expect { @client.public_key Hash.new }.to raise_error(ArgumentError) + end + + + it "has a private key attribute" do + @client.private_key("super private") + expect(@client.private_key).to eq("super private") + end + + it "accepts only String values for the private key" do + expect { @client.private_key "" }.not_to raise_error + expect { @client.private_key Hash.new }.to raise_error(ArgumentError) + end + + describe "when serializing to JSON" do + before(:each) do + @client.name("black") + @client.public_key("crowes") + @json = @client.to_json + end + + it "serializes as a JSON object" do + expect(@json).to match(/^\{.+\}$/) + end + + it "includes the name value" do + expect(@json).to include(%q{"name":"black"}) + end + + it "includes the public key value" do + expect(@json).to include(%{"public_key":"crowes"}) + end + + it "includes the 'admin' flag" do + expect(@json).to include(%q{"admin":false}) + end + + it "includes the 'validator' flag" do + expect(@json).to include(%q{"validator":false}) + end + + it "includes the 'create_key' flag when present" do + @client.create_key(true) + @json = @client.to_json + expect(@json).to include(%q{"create_key":true}) + end + + it "includes the private key when present" do + @client.private_key("monkeypants") + expect(@client.to_json).to include(%q{"private_key":"monkeypants"}) + end + + it "does not include the private key if not present" do + expect(@json).not_to include("private_key") + end + + include_examples "to_json equivalent to Chef::JSONCompat.to_json" do + let(:jsonable) { @client } + end + end + + describe "when deserializing from JSON (string) using ApiClient#from_json" do + let(:client_string) do + "{\"name\":\"black\",\"public_key\":\"crowes\",\"private_key\":\"monkeypants\",\"admin\":true,\"validator\":true,\"create_key\":true}" + end + + let(:client) do + Chef::ApiClientV1.from_json(client_string) + end + + it "does not require a 'json_class' string" do + expect(Chef::JSONCompat.parse(client_string)["json_class"]).to eq(nil) + end + + it "should deserialize to a Chef::ApiClientV1 object" do + expect(client).to be_a_kind_of(Chef::ApiClientV1) + end + + it "preserves the name" do + expect(client.name).to eq("black") + end + + it "preserves the public key" do + expect(client.public_key).to eq("crowes") + end + + it "preserves the admin status" do + expect(client.admin).to be_truthy + end + + it "preserves the create_key status" do + expect(client.create_key).to be_truthy + end + + it "preserves the 'validator' status" do + expect(client.validator).to be_truthy + end + + it "includes the private key if present" do + expect(client.private_key).to eq("monkeypants") + end + end + + describe "when deserializing from JSON (hash) using ApiClientV1#from_json" do + let(:client_hash) do + { + "name" => "black", + "public_key" => "crowes", + "private_key" => "monkeypants", + "admin" => true, + "validator" => true, + "create_key" => true + } + end + + let(:client) do + Chef::ApiClientV1.from_json(Chef::JSONCompat.to_json(client_hash)) + end + + it "should deserialize to a Chef::ApiClientV1 object" do + expect(client).to be_a_kind_of(Chef::ApiClientV1) + end + + it "preserves the name" do + expect(client.name).to eq("black") + end + + it "preserves the public key" do + expect(client.public_key).to eq("crowes") + end + + it "preserves the admin status" do + expect(client.admin).to be_truthy + end + + it "preserves the create_key status" do + expect(client.create_key).to be_truthy + end + + it "preserves the 'validator' status" do + expect(client.validator).to be_truthy + end + + it "includes the private key if present" do + expect(client.private_key).to eq("monkeypants") + end + end + + describe "when loading from JSON" do + before do + end + + before(:each) do + client = { + "name" => "black", + "clientname" => "black", + "public_key" => "crowes", + "private_key" => "monkeypants", + "admin" => true, + "create_key" => true, + "validator" => true + } + + @http_client = double("Chef::ServerAPI mock") + allow(Chef::ServerAPI).to receive(:new).and_return(@http_client) + expect(@http_client).to receive(:get).with("clients/black").and_return(client) + @client = Chef::ApiClientV1.load(client['name']) + end + + it "should deserialize to a Chef::ApiClientV1 object" do + expect(@client).to be_a_kind_of(Chef::ApiClientV1) + end + + it "preserves the name" do + expect(@client.name).to eq("black") + end + + it "preserves the public key" do + expect(@client.public_key).to eq("crowes") + end + + it "preserves the admin status" do + expect(@client.admin).to be_a_kind_of(TrueClass) + end + + it "preserves the create_key status" do + expect(@client.create_key).to be_a_kind_of(TrueClass) + end + + it "preserves the 'validator' status" do + expect(@client.validator).to be_a_kind_of(TrueClass) + end + + it "includes the private key if present" do + expect(@client.private_key).to eq("monkeypants") + end + + end + + describe "with correctly configured API credentials" do + before do + Chef::Config[:node_name] = "silent-bob" + Chef::Config[:client_key] = File.expand_path('ssl/private_key.pem', CHEF_SPEC_DATA) + end + + after do + Chef::Config[:node_name] = nil + Chef::Config[:client_key] = nil + end + + let :private_key_data do + File.open(Chef::Config[:client_key], "r") {|f| f.read.chomp } + end + + end + + + describe "when requesting a new key" do + before do + @http_client = double("Chef::ServerAPI mock") + allow(Chef::ServerAPI).to receive(:new).and_return(@http_client) + end + + context "and the client does not exist on the server" do + before do + @a_404_response = Net::HTTPNotFound.new("404 not found and such", nil, nil) + @a_404_exception = Net::HTTPServerException.new("404 not found exception", @a_404_response) + + expect(@http_client).to receive(:get).with("clients/lost-my-key").and_raise(@a_404_exception) + end + + it "raises a 404 error" do + expect { Chef::ApiClientV1.reregister("lost-my-key") }.to raise_error(Net::HTTPServerException) + end + end + end + + describe "Versioned API Interactions" do + let(:response_406) { OpenStruct.new(:code => '406') } + let(:exception_406) { Net::HTTPServerException.new("406 Not Acceptable", response_406) } + let(:payload) { + { + :name => "some_name", + :validator => true, + :admin => true + } + } + + before do + @client = Chef::ApiClientV1.new + allow(@client).to receive(:chef_rest_v0).and_return(double('chef rest root v0 object')) + allow(@client).to receive(:chef_rest_v1).and_return(double('chef rest root v1 object')) + @client.name "some_name" + @client.validator true + @client.admin true + end + + describe "create" do + + # from spec/support/shared/unit/user_and_client_shared.rb + it_should_behave_like "user or client create" do + let(:object) { @client } + let(:error) { Chef::Exceptions::InvalidClientAttribute } + let(:rest_v0) { @client.chef_rest_v0 } + let(:rest_v1) { @client.chef_rest_v1 } + let(:url) { "clients" } + end + + context "when API V1 is not supported by the server" do + # from spec/support/shared/unit/api_versioning.rb + it_should_behave_like "version handling" do + let(:object) { @client } + let(:method) { :create } + let(:http_verb) { :post } + let(:rest_v1) { @client.chef_rest_v1 } + end + end + + end # create + + describe "update" do + context "when a valid client is defined" do + + shared_examples_for "client updating" do + it "updates the client" do + expect(rest). to receive(:put).with("clients/some_name", payload).and_return(payload) + @client.update + end + + context "when only the name field exists" do + + before do + # needed since there is no way to set to nil via code + @client.instance_variable_set(:@validator, nil) + @client.instance_variable_set(:@admin, nil) + end + + after do + @client.validator true + @client.admin true + end + + it "updates the client with only the name" do + expect(rest). to receive(:put).with("clients/some_name", {:name => "some_name"}).and_return({:name => "some_name"}) + @client.update + end + end + + end + + context "when API V1 is supported by the server" do + + it_should_behave_like "client updating" do + let(:rest) { @client.chef_rest_v1 } + end + + end # when API V1 is supported by the server + + context "when API V1 is not supported by the server" do + context "when no version is supported" do + # from spec/support/shared/unit/api_versioning.rb + it_should_behave_like "version handling" do + let(:object) { @client } + let(:method) { :create } + let(:http_verb) { :post } + let(:rest_v1) { @client.chef_rest_v1 } + end + end # when no version is supported + + context "when API V0 is supported" do + + before do + allow(@client.chef_rest_v1).to receive(:put).and_raise(exception_406) + allow(@client).to receive(:server_client_api_version_intersection).and_return([0]) + end + + it_should_behave_like "client updating" do + let(:rest) { @client.chef_rest_v0 } + end + + end + + end # when API V1 is not supported by the server + end # when a valid client is defined + end # update + + # DEPRECATION + # This can be removed after API V0 support is gone + describe "reregister" do + context "when server API V0 is valid on the Chef Server receiving the request" do + it "creates a new object via the API" do + expect(@client.chef_rest_v0).to receive(:put).with("clients/#{@client.name}", payload.merge({:private_key => true})).and_return({}) + @client.reregister + end + end # when server API V0 is valid on the Chef Server receiving the request + + context "when server API V0 is not supported by the Chef Server" do + # from spec/support/shared/unit/api_versioning.rb + it_should_behave_like "user and client reregister" do + let(:object) { @client } + let(:rest_v0) { @client.chef_rest_v0 } + end + end # when server API V0 is not supported by the Chef Server + end # reregister + + end +end diff --git a/spec/unit/knife/client_bulk_delete_spec.rb b/spec/unit/knife/client_bulk_delete_spec.rb index 45bb4dd16c..1a6317ac00 100644 --- a/spec/unit/knife/client_bulk_delete_spec.rb +++ b/spec/unit/knife/client_bulk_delete_spec.rb @@ -45,7 +45,7 @@ describe Chef::Knife::ClientBulkDelete do clients = Hash.new nonvalidator_client_names.each do |client_name| - client = Chef::ApiClient.new() + client = Chef::ApiClientV1.new() client.name(client_name) allow(client).to receive(:destroy).and_return(true) clients[client_name] = client @@ -59,7 +59,7 @@ describe Chef::Knife::ClientBulkDelete do clients = Hash.new validator_client_names.each do |validator_client_name| - validator_client = Chef::ApiClient.new() + validator_client = Chef::ApiClientV1.new() validator_client.name(validator_client_name) allow(validator_client).to receive(:validator).and_return(true) allow(validator_client).to receive(:destroy).and_return(true) @@ -75,7 +75,7 @@ describe Chef::Knife::ClientBulkDelete do } before(:each) do - allow(Chef::ApiClient).to receive(:list).and_return(clients) + allow(Chef::ApiClientV1).to receive(:list).and_return(clients) end describe "run" do @@ -89,7 +89,7 @@ describe Chef::Knife::ClientBulkDelete do describe "with any clients" do it "should get the list of the clients" do - expect(Chef::ApiClient).to receive(:list) + expect(Chef::ApiClientV1).to receive(:list) knife.run end diff --git a/spec/unit/knife/client_create_spec.rb b/spec/unit/knife/client_create_spec.rb index 8fecfc885f..a1dcc564e2 100644 --- a/spec/unit/knife/client_create_spec.rb +++ b/spec/unit/knife/client_create_spec.rb @@ -34,7 +34,7 @@ describe Chef::Knife::ClientCreate do end let(:client) do - Chef::ApiClient.new + Chef::ApiClientV1.new end let(:knife) do diff --git a/spec/unit/knife/client_delete_spec.rb b/spec/unit/knife/client_delete_spec.rb index 0fb5e0bab7..619009979b 100644 --- a/spec/unit/knife/client_delete_spec.rb +++ b/spec/unit/knife/client_delete_spec.rb @@ -30,7 +30,7 @@ describe Chef::Knife::ClientDelete do describe 'run' do it 'should delete the client' do - expect(@knife).to receive(:delete_object).with(Chef::ApiClient, 'adam', 'client') + expect(@knife).to receive(:delete_object).with(Chef::ApiClientV1, 'adam', 'client') @knife.run end @@ -46,8 +46,8 @@ describe Chef::Knife::ClientDelete do before(:each) do allow(Chef::Knife::UI).to receive(:confirm).and_return(true) allow(@knife).to receive(:confirm).and_return(true) - @client = Chef::ApiClient.new - expect(Chef::ApiClient).to receive(:load).and_return(@client) + @client = Chef::ApiClientV1.new + expect(Chef::ApiClientV1).to receive(:load).and_return(@client) end it 'should delete non-validator client if --delete-validators is not set' do diff --git a/spec/unit/knife/client_edit_spec.rb b/spec/unit/knife/client_edit_spec.rb index c040c5e2f2..ad56d9212d 100644 --- a/spec/unit/knife/client_edit_spec.rb +++ b/spec/unit/knife/client_edit_spec.rb @@ -17,16 +17,29 @@ # require 'spec_helper' +require 'chef/api_client_v1' describe Chef::Knife::ClientEdit do before(:each) do @knife = Chef::Knife::ClientEdit.new @knife.name_args = [ 'adam' ] + @knife.config[:disable_editing] = true end describe 'run' do + let(:data) { + { + "name" => "adam", + "validator" => false, + "admin" => false, + "chef_type" => "client", + "create_key" => true + } + } + it 'should edit the client' do - expect(@knife).to receive(:edit_object).with(Chef::ApiClient, 'adam') + allow(Chef::ApiClientV1).to receive(:load).with('adam').and_return(data) + expect(@knife).to receive(:edit_data).with(data).and_return(data) @knife.run end diff --git a/spec/unit/knife/client_list_spec.rb b/spec/unit/knife/client_list_spec.rb index eff01da4e9..ce0fa4f5e8 100644 --- a/spec/unit/knife/client_list_spec.rb +++ b/spec/unit/knife/client_list_spec.rb @@ -26,7 +26,7 @@ describe Chef::Knife::ClientList do describe 'run' do it 'should list the clients' do - expect(Chef::ApiClient).to receive(:list) + expect(Chef::ApiClientV1).to receive(:list) expect(@knife).to receive(:format_list_for_display) @knife.run end diff --git a/spec/unit/knife/client_reregister_spec.rb b/spec/unit/knife/client_reregister_spec.rb index f1be4ed570..7e763242e4 100644 --- a/spec/unit/knife/client_reregister_spec.rb +++ b/spec/unit/knife/client_reregister_spec.rb @@ -41,7 +41,7 @@ describe Chef::Knife::ClientReregister do context 'when not configured for file output' do it 'reregisters the client and prints the key' do - expect(Chef::ApiClient).to receive(:reregister).with('adam').and_return(@client_mock) + expect(Chef::ApiClientV1).to receive(:reregister).with('adam').and_return(@client_mock) @knife.run expect(@stdout.string).to match( /foo_key/ ) end @@ -49,7 +49,7 @@ describe Chef::Knife::ClientReregister do context 'when configured for file output' do it 'should write the private key to a file' do - expect(Chef::ApiClient).to receive(:reregister).with('adam').and_return(@client_mock) + expect(Chef::ApiClientV1).to receive(:reregister).with('adam').and_return(@client_mock) @knife.config[:file] = '/tmp/monkeypants' filehandle = StringIO.new diff --git a/spec/unit/knife/client_show_spec.rb b/spec/unit/knife/client_show_spec.rb index 8404e8d019..73a876cee0 100644 --- a/spec/unit/knife/client_show_spec.rb +++ b/spec/unit/knife/client_show_spec.rb @@ -27,7 +27,7 @@ describe Chef::Knife::ClientShow do describe 'run' do it 'should list the client' do - expect(Chef::ApiClient).to receive(:load).with('adam').and_return(@client_mock) + expect(Chef::ApiClientV1).to receive(:load).with('adam').and_return(@client_mock) expect(@knife).to receive(:format_for_display).with(@client_mock) @knife.run end @@ -37,7 +37,7 @@ describe Chef::Knife::ClientShow do @stdout = StringIO.new allow(@knife.ui).to receive(:stdout).and_return(@stdout) fake_client_contents = {"foo"=>"bar", "baz"=>"qux"} - expect(Chef::ApiClient).to receive(:load).with('adam').and_return(fake_client_contents) + expect(Chef::ApiClientV1).to receive(:load).with('adam').and_return(fake_client_contents) @knife.run expect(@stdout.string).to eql("{\n \"foo\": \"bar\",\n \"baz\": \"qux\"\n}\n") end diff --git a/spec/unit/knife/osc_user_create_spec.rb b/spec/unit/knife/osc_user_create_spec.rb index 1b17d0d22f..e4ed78fe2b 100644 --- a/spec/unit/knife/osc_user_create_spec.rb +++ b/spec/unit/knife/osc_user_create_spec.rb @@ -36,19 +36,19 @@ describe Chef::Knife::OscUserCreate do @knife.name_args = [ 'a_user' ] @knife.config[:user_password] = "foobar" - @user = Chef::OscUser.new + @user = Chef::User.new @user.name "a_user" - @user_with_private_key = Chef::OscUser.new + @user_with_private_key = Chef::User.new @user_with_private_key.name "a_user" @user_with_private_key.private_key 'private_key' allow(@user).to receive(:create).and_return(@user_with_private_key) - allow(Chef::OscUser).to receive(:new).and_return(@user) - allow(Chef::OscUser).to receive(:from_hash).and_return(@user) + allow(Chef::User).to receive(:new).and_return(@user) + allow(Chef::User).to receive(:from_hash).and_return(@user) allow(@knife).to receive(:edit_data).and_return(@user.to_hash) end it "creates a new user" do - expect(Chef::OscUser).to receive(:new).and_return(@user) + expect(Chef::User).to receive(:new).and_return(@user) expect(@user).to receive(:create) @knife.run expect(@stderr.string).to match /created user.+a_user/i diff --git a/spec/unit/knife/osc_user_delete_spec.rb b/spec/unit/knife/osc_user_delete_spec.rb index 0e16393ffe..4a3ec4228f 100644 --- a/spec/unit/knife/osc_user_delete_spec.rb +++ b/spec/unit/knife/osc_user_delete_spec.rb @@ -31,7 +31,7 @@ describe Chef::Knife::OscUserDelete do end it 'deletes the user' do - expect(@knife).to receive(:delete_object).with(Chef::OscUser, 'my_user') + expect(@knife).to receive(:delete_object).with(Chef::User, 'my_user') @knife.run end diff --git a/spec/unit/knife/osc_user_edit_spec.rb b/spec/unit/knife/osc_user_edit_spec.rb index 71a9192389..279f2e30ef 100644 --- a/spec/unit/knife/osc_user_edit_spec.rb +++ b/spec/unit/knife/osc_user_edit_spec.rb @@ -38,7 +38,7 @@ describe Chef::Knife::OscUserEdit do it 'loads and edits the user' do data = { :name => "my_user" } - allow(Chef::OscUser).to receive(:load).with("my_user").and_return(data) + allow(Chef::User).to receive(:load).with("my_user").and_return(data) expect(@knife).to receive(:edit_data).with(data).and_return(data) @knife.run end diff --git a/spec/unit/knife/osc_user_list_spec.rb b/spec/unit/knife/osc_user_list_spec.rb index 59a15be058..f496a414b8 100644 --- a/spec/unit/knife/osc_user_list_spec.rb +++ b/spec/unit/knife/osc_user_list_spec.rb @@ -30,7 +30,7 @@ describe Chef::Knife::OscUserList do end it 'lists the users' do - expect(Chef::OscUser).to receive(:list) + expect(Chef::User).to receive(:list) expect(@knife).to receive(:format_list_for_display) @knife.run end diff --git a/spec/unit/knife/osc_user_reregister_spec.rb b/spec/unit/knife/osc_user_reregister_spec.rb index 406bbf1f3e..989eb180f1 100644 --- a/spec/unit/knife/osc_user_reregister_spec.rb +++ b/spec/unit/knife/osc_user_reregister_spec.rb @@ -29,7 +29,7 @@ describe Chef::Knife::OscUserReregister do @knife = Chef::Knife::OscUserReregister.new @knife.name_args = [ 'a_user' ] @user_mock = double('user_mock', :private_key => "private_key") - allow(Chef::OscUser).to receive(:load).and_return(@user_mock) + allow(Chef::User).to receive(:load).and_return(@user_mock) @stdout = StringIO.new allow(@knife.ui).to receive(:stdout).and_return(@stdout) end diff --git a/spec/unit/knife/osc_user_show_spec.rb b/spec/unit/knife/osc_user_show_spec.rb index 67b9b45809..18d2086099 100644 --- a/spec/unit/knife/osc_user_show_spec.rb +++ b/spec/unit/knife/osc_user_show_spec.rb @@ -32,7 +32,7 @@ describe Chef::Knife::OscUserShow do end it 'loads and displays the user' do - expect(Chef::OscUser).to receive(:load).with('my_user').and_return(@user_mock) + expect(Chef::User).to receive(:load).with('my_user').and_return(@user_mock) expect(@knife).to receive(:format_for_display).with(@user_mock) @knife.run end diff --git a/spec/unit/knife/user_create_spec.rb b/spec/unit/knife/user_create_spec.rb index 49d62cc2d7..fa5c8324b4 100644 --- a/spec/unit/knife/user_create_spec.rb +++ b/spec/unit/knife/user_create_spec.rb @@ -186,7 +186,7 @@ describe Chef::Knife::UserCreate do context "when a private_key is returned" do before do - allow(knife).to receive(:create_user_from_hash).and_return(Chef::User.from_hash(knife.user.to_hash.merge({"private_key" => "some_private_key"}))) + allow(knife).to receive(:create_user_from_hash).and_return(Chef::UserV1.from_hash(knife.user.to_hash.merge({"private_key" => "some_private_key"}))) end context "when --file is passed" do diff --git a/spec/unit/knife/user_delete_spec.rb b/spec/unit/knife/user_delete_spec.rb index e49c781358..a24160624a 100644 --- a/spec/unit/knife/user_delete_spec.rb +++ b/spec/unit/knife/user_delete_spec.rb @@ -26,7 +26,7 @@ describe Chef::Knife::UserDelete do before(:each) do Chef::Knife::UserDelete.load_deps knife.name_args = [ 'my_user' ] - allow(Chef::User).to receive(:load).and_return(user) + allow(Chef::UserV1).to receive(:load).and_return(user) allow(user).to receive(:username).and_return('my_user') allow(knife.ui).to receive(:stderr).and_return(stdout) allow(knife.ui).to receive(:stdout).and_return(stdout) @@ -51,7 +51,7 @@ describe Chef::Knife::UserDelete do end it 'deletes the user' do - #expect(knife).to receive(:delete_object).with(Chef::User, 'my_user') + #expect(knife).to receive(:delete_object).with(Chef::UserV1, 'my_user') expect(knife).to receive(:delete_object).with('my_user') knife.run end diff --git a/spec/unit/knife/user_edit_spec.rb b/spec/unit/knife/user_edit_spec.rb index 15a7726b20..a21d982d29 100644 --- a/spec/unit/knife/user_edit_spec.rb +++ b/spec/unit/knife/user_edit_spec.rb @@ -36,7 +36,7 @@ describe Chef::Knife::UserEdit do context "when the username field is not supported by the server" do before do allow(knife).to receive(:run_osc_11_user_edit).and_raise(SystemExit) - allow(Chef::User).to receive(:load).and_return({"username" => nil}) + allow(Chef::UserV1).to receive(:load).and_return({"username" => nil}) end it "displays the osc warning" do @@ -52,7 +52,7 @@ describe Chef::Knife::UserEdit do it 'loads and edits the user' do data = { "username" => "my_user" } - allow(Chef::User).to receive(:load).with("my_user").and_return(data) + allow(Chef::UserV1).to receive(:load).with("my_user").and_return(data) expect(knife).to receive(:edit_data).with(data).and_return(data) knife.run end diff --git a/spec/unit/knife/user_list_spec.rb b/spec/unit/knife/user_list_spec.rb index 9990cc802d..fa2bac426e 100644 --- a/spec/unit/knife/user_list_spec.rb +++ b/spec/unit/knife/user_list_spec.rb @@ -29,7 +29,7 @@ describe Chef::Knife::UserList do end it 'lists the users' do - expect(Chef::User).to receive(:list) + expect(Chef::UserV1).to receive(:list) expect(knife).to receive(:format_list_for_display) knife.run end diff --git a/spec/unit/knife/user_reregister_spec.rb b/spec/unit/knife/user_reregister_spec.rb index 412a6ec374..89aa6726cd 100644 --- a/spec/unit/knife/user_reregister_spec.rb +++ b/spec/unit/knife/user_reregister_spec.rb @@ -26,7 +26,7 @@ describe Chef::Knife::UserReregister do before do Chef::Knife::UserReregister.load_deps knife.name_args = [ 'a_user' ] - allow(Chef::User).to receive(:load).and_return(user_mock) + allow(Chef::UserV1).to receive(:load).and_return(user_mock) allow(knife.ui).to receive(:stdout).and_return(stdout) allow(knife.ui).to receive(:stderr).and_return(stdout) allow(user_mock).to receive(:username).and_return('a_user') diff --git a/spec/unit/knife/user_show_spec.rb b/spec/unit/knife/user_show_spec.rb index 43392a3a5c..7c39e428c0 100644 --- a/spec/unit/knife/user_show_spec.rb +++ b/spec/unit/knife/user_show_spec.rb @@ -35,7 +35,7 @@ describe Chef::Knife::UserShow do context "when the username field is not supported by the server" do before do allow(knife).to receive(:run_osc_11_user_show).and_raise(SystemExit) - allow(Chef::User).to receive(:load).with('my_user').and_return(user_mock) + allow(Chef::UserV1).to receive(:load).with('my_user').and_return(user_mock) allow(user_mock).to receive(:username).and_return(nil) end @@ -51,7 +51,7 @@ describe Chef::Knife::UserShow do end it 'loads and displays the user' do - expect(Chef::User).to receive(:load).with('my_user').and_return(user_mock) + expect(Chef::UserV1).to receive(:load).with('my_user').and_return(user_mock) expect(knife).to receive(:format_for_display).with(user_mock) knife.run end diff --git a/spec/unit/lwrp_spec.rb b/spec/unit/lwrp_spec.rb index 784ff966cd..bcb64cb21e 100644 --- a/spec/unit/lwrp_spec.rb +++ b/spec/unit/lwrp_spec.rb @@ -163,7 +163,7 @@ describe "LWRP" do it "Should load the old content, and not the new" do resource = Chef::ResourceResolver.resolve(:lwrp_foo) expect(resource).to eq @original_resource - expect(resource.default_action).to eq(:pass_buck) + expect(resource.default_action).to eq([:pass_buck]) expect(Chef.method_defined?(:method_created_by_override_lwrp_foo)).to be_falsey end end @@ -177,10 +177,6 @@ describe "LWRP" do end end - it "should load the resource into a properly-named class and emit a warning when it is initialized" do - expect { Chef::Resource::LwrpFoo.new('hi') }.to raise_error(Chef::Exceptions::DeprecatedFeatureError) - end - it "should be resolvable with Chef::ResourceResolver.resolve(:lwrp_foo)" do expect(Chef::ResourceResolver.resolve(:lwrp_foo, node: Chef::Node.new)).to eq(get_lwrp(:lwrp_foo)) end @@ -202,7 +198,7 @@ describe "LWRP" do end it "should set the specified action as the default action" do - expect(get_lwrp(:lwrp_foo).new("blah").action).to eq(:pass_buck) + expect(get_lwrp(:lwrp_foo).new("blah").action).to eq([:pass_buck]) end it "should create a method for each attribute" do @@ -228,127 +224,6 @@ describe "LWRP" do expect(cls.node[:penguin_name]).to eql("jackass") end - context "resource class created" do - before do - @old_treat_deprecation_warnings_as_errors = Chef::Config[:treat_deprecation_warnings_as_errors] - Chef::Config[:treat_deprecation_warnings_as_errors] = false - end - after do - Chef::Config[:treat_deprecation_warnings_as_errors] = @old_treat_deprecation_warnings_as_errors - end - - it "should load the resource into a properly-named class" do - expect(Chef::Resource::LwrpFoo).to be_kind_of(Class) - expect(Chef::Resource::LwrpFoo <= Chef::Resource::LWRPBase).to be_truthy - end - - it "get_lwrp(:lwrp_foo).new is a Chef::Resource::LwrpFoo" do - lwrp = get_lwrp(:lwrp_foo).new('hi') - expect(lwrp.kind_of?(Chef::Resource::LwrpFoo)).to be_truthy - expect(lwrp.is_a?(Chef::Resource::LwrpFoo)).to be_truthy - expect(get_lwrp(:lwrp_foo) === lwrp).to be_truthy - expect(Chef::Resource::LwrpFoo === lwrp).to be_truthy - end - - it "Chef::Resource::LwrpFoo.new is a get_lwrp(:lwrp_foo)" do - lwrp = Chef::Resource::LwrpFoo.new('hi') - expect(lwrp.kind_of?(get_lwrp(:lwrp_foo))).to be_truthy - expect(lwrp.is_a?(get_lwrp(:lwrp_foo))).to be_truthy - expect(get_lwrp(:lwrp_foo) === lwrp).to be_truthy - expect(Chef::Resource::LwrpFoo === lwrp).to be_truthy - end - - it "works even if LwrpFoo exists in the top level" do - module ::LwrpFoo - end - expect(Chef::Resource::LwrpFoo).not_to eq(::LwrpFoo) - end - - context "with a subclass of get_lwrp(:lwrp_foo)" do - let(:subclass) do - Class.new(get_lwrp(:lwrp_foo)) - end - - it "subclass.new is a subclass" do - lwrp = subclass.new('hi') - expect(lwrp.kind_of?(subclass)).to be_truthy - expect(lwrp.is_a?(subclass)).to be_truthy - expect(subclass === lwrp).to be_truthy - expect(lwrp.class === subclass) - end - it "subclass.new is a Chef::Resource::LwrpFoo" do - lwrp = subclass.new('hi') - expect(lwrp.kind_of?(Chef::Resource::LwrpFoo)).to be_truthy - expect(lwrp.is_a?(Chef::Resource::LwrpFoo)).to be_truthy - expect(Chef::Resource::LwrpFoo === lwrp).to be_truthy - expect(lwrp.class === Chef::Resource::LwrpFoo) - end - it "subclass.new is a get_lwrp(:lwrp_foo)" do - lwrp = subclass.new('hi') - expect(lwrp.kind_of?(get_lwrp(:lwrp_foo))).to be_truthy - expect(lwrp.is_a?(get_lwrp(:lwrp_foo))).to be_truthy - expect(get_lwrp(:lwrp_foo) === lwrp).to be_truthy - expect(lwrp.class === get_lwrp(:lwrp_foo)) - end - it "Chef::Resource::LwrpFoo.new is *not* a subclass" do - lwrp = Chef::Resource::LwrpFoo.new('hi') - expect(lwrp.kind_of?(subclass)).to be_falsey - expect(lwrp.is_a?(subclass)).to be_falsey - expect(subclass === lwrp.class).to be_falsey - expect(subclass === Chef::Resource::LwrpFoo).to be_falsey - end - it "get_lwrp(:lwrp_foo).new is *not* a subclass" do - lwrp = get_lwrp(:lwrp_foo).new('hi') - expect(lwrp.kind_of?(subclass)).to be_falsey - expect(lwrp.is_a?(subclass)).to be_falsey - expect(subclass === lwrp.class).to be_falsey - expect(subclass === get_lwrp(:lwrp_foo)).to be_falsey - end - end - - context "with a subclass of Chef::Resource::LwrpFoo" do - let(:subclass) do - Class.new(Chef::Resource::LwrpFoo) - end - - it "subclass.new is a subclass" do - lwrp = subclass.new('hi') - expect(lwrp.kind_of?(subclass)).to be_truthy - expect(lwrp.is_a?(subclass)).to be_truthy - expect(subclass === lwrp).to be_truthy - expect(lwrp.class === subclass) - end - it "subclass.new is a Chef::Resource::LwrpFoo" do - lwrp = subclass.new('hi') - expect(lwrp.kind_of?(Chef::Resource::LwrpFoo)).to be_truthy - expect(lwrp.is_a?(Chef::Resource::LwrpFoo)).to be_truthy - expect(Chef::Resource::LwrpFoo === lwrp).to be_truthy - expect(lwrp.class === Chef::Resource::LwrpFoo) - end - it "subclass.new is a get_lwrp(:lwrp_foo)" do - lwrp = subclass.new('hi') - expect(lwrp.kind_of?(get_lwrp(:lwrp_foo))).to be_truthy - expect(lwrp.is_a?(get_lwrp(:lwrp_foo))).to be_truthy - expect(get_lwrp(:lwrp_foo) === lwrp).to be_truthy - expect(lwrp.class === get_lwrp(:lwrp_foo)) - end - it "Chef::Resource::LwrpFoo.new is *not* a subclass" do - lwrp = Chef::Resource::LwrpFoo.new('hi') - expect(lwrp.kind_of?(subclass)).to be_falsey - expect(lwrp.is_a?(subclass)).to be_falsey - expect(subclass === lwrp.class).to be_falsey - expect(subclass === Chef::Resource::LwrpFoo).to be_falsey - end - it "get_lwrp(:lwrp_foo).new is *not* a subclass" do - lwrp = get_lwrp(:lwrp_foo).new('hi') - expect(lwrp.kind_of?(subclass)).to be_falsey - expect(lwrp.is_a?(subclass)).to be_falsey - expect(subclass === lwrp.class).to be_falsey - expect(subclass === get_lwrp(:lwrp_foo)).to be_falsey - end - end - end - context "resource_name" do let(:klass) { Class.new(Chef::Resource::LWRPBase) } @@ -419,7 +294,7 @@ describe "LWRP" do end it "delegates #default_action to the parent" do - expect(child.default_action).to eq(:eat) + expect(child.default_action).to eq([:eat]) end end @@ -436,7 +311,7 @@ describe "LWRP" do end it "does not delegate #default_action to the parent" do - expect(child.default_action).to eq(:dont_eat) + expect(child.default_action).to eq([:dont_eat]) end end @@ -564,7 +439,7 @@ describe "LWRP" do end it "sets itself as a provider for a resource of the same name" do - found_providers = Chef::Platform::ProviderPriorityMap.instance.list_handlers(node, :lwrp_buck_passer) + found_providers = Chef::Platform::ProviderHandlerMap.instance.list(node, :lwrp_buck_passer) # we bypass the per-file loading to get the file to load each time, # which creates the LWRP class repeatedly. New things get prepended to # the list of providers. @@ -576,7 +451,7 @@ describe "LWRP" do let(:lwrp_cookbok_name) { "l_w_r_p" } it "sets itself as a provider for a resource of the same name" do - found_providers = Chef::Platform::ProviderPriorityMap.instance.list_handlers(node, :l_w_r_p_buck_passer) + found_providers = Chef::Platform::ProviderHandlerMap.instance.list(node, :l_w_r_p_buck_passer) expect(found_providers.size).to eq(1) expect(found_providers.last).to eq(get_lwrp_provider(:l_w_r_p_buck_passer)) end @@ -587,10 +462,10 @@ describe "LWRP" do let(:lwrp_cookbok_name) { "l-w-r-p" } it "sets itself as a provider for a resource of the same name" do - incorrect_providers = Chef::Platform::ProviderPriorityMap.instance.list_handlers(node, :'l-w-r-p_buck_passer') + incorrect_providers = Chef::Platform::ProviderHandlerMap.instance.list(node, :'l-w-r-p_buck_passer') expect(incorrect_providers).to eq([]) - found_providers = Chef::Platform::ProviderPriorityMap.instance.list_handlers(node, :l_w_r_p_buck_passer) + found_providers = Chef::Platform::ProviderHandlerMap.instance.list(node, :l_w_r_p_buck_passer) expect(found_providers.first).to eq(get_lwrp_provider(:l_w_r_p_buck_passer)) end end @@ -704,7 +579,144 @@ describe "LWRP" do end end - end + context "resource class created" do + before(:context) do + @tmpdir = Dir.mktmpdir("lwrp_test") + resource_path = File.join(@tmpdir, "once.rb") + IO.write(resource_path, "default_action :create") + + @old_treat_deprecation_warnings_as_errors = Chef::Config[:treat_deprecation_warnings_as_errors] + Chef::Config[:treat_deprecation_warnings_as_errors] = false + Chef::Resource::LWRPBase.build_from_file("lwrp", resource_path, nil) + end + + after(:context) do + FileUtils.remove_entry @tmpdir + Chef::Config[:treat_deprecation_warnings_as_errors] = @old_treat_deprecation_warnings_as_errors + end + + it "should load the resource into a properly-named class" do + expect(Chef::Resource::LwrpOnce).to be_kind_of(Class) + expect(Chef::Resource::LwrpOnce <= Chef::Resource::LWRPBase).to be_truthy + end + + it "get_lwrp(:lwrp_once).new is a Chef::Resource::LwrpOnce" do + lwrp = get_lwrp(:lwrp_once).new('hi') + expect(lwrp.kind_of?(Chef::Resource::LwrpOnce)).to be_truthy + expect(lwrp.is_a?(Chef::Resource::LwrpOnce)).to be_truthy + expect(get_lwrp(:lwrp_once) === lwrp).to be_truthy + expect(Chef::Resource::LwrpOnce === lwrp).to be_truthy + end + + it "Chef::Resource::LwrpOnce.new is a get_lwrp(:lwrp_once)" do + lwrp = Chef::Resource::LwrpOnce.new('hi') + expect(lwrp.kind_of?(get_lwrp(:lwrp_once))).to be_truthy + expect(lwrp.is_a?(get_lwrp(:lwrp_once))).to be_truthy + expect(get_lwrp(:lwrp_once) === lwrp).to be_truthy + expect(Chef::Resource::LwrpOnce === lwrp).to be_truthy + end + + it "works even if LwrpOnce exists in the top level" do + module ::LwrpOnce + end + expect(Chef::Resource::LwrpOnce).not_to eq(::LwrpOnce) + end + + it "allows monkey patching of the lwrp through Chef::Resource" do + monkey = Module.new do + def issue_3607 + end + end + Chef::Resource::LwrpOnce.send(:include, monkey) + expect { get_lwrp(:lwrp_once).new("blah").issue_3607 }.not_to raise_error + end + + context "with a subclass of get_lwrp(:lwrp_once)" do + let(:subclass) do + Class.new(get_lwrp(:lwrp_once)) + end + + it "subclass.new is a subclass" do + lwrp = subclass.new('hi') + expect(lwrp.kind_of?(subclass)).to be_truthy + expect(lwrp.is_a?(subclass)).to be_truthy + expect(subclass === lwrp).to be_truthy + expect(lwrp.class === subclass) + end + it "subclass.new is a Chef::Resource::LwrpOnce" do + lwrp = subclass.new('hi') + expect(lwrp.kind_of?(Chef::Resource::LwrpOnce)).to be_truthy + expect(lwrp.is_a?(Chef::Resource::LwrpOnce)).to be_truthy + expect(Chef::Resource::LwrpOnce === lwrp).to be_truthy + expect(lwrp.class === Chef::Resource::LwrpOnce) + end + it "subclass.new is a get_lwrp(:lwrp_once)" do + lwrp = subclass.new('hi') + expect(lwrp.kind_of?(get_lwrp(:lwrp_once))).to be_truthy + expect(lwrp.is_a?(get_lwrp(:lwrp_once))).to be_truthy + expect(get_lwrp(:lwrp_once) === lwrp).to be_truthy + expect(lwrp.class === get_lwrp(:lwrp_once)) + end + it "Chef::Resource::LwrpOnce.new is *not* a subclass" do + lwrp = Chef::Resource::LwrpOnce.new('hi') + expect(lwrp.kind_of?(subclass)).to be_falsey + expect(lwrp.is_a?(subclass)).to be_falsey + expect(subclass === lwrp.class).to be_falsey + expect(subclass === Chef::Resource::LwrpOnce).to be_falsey + end + it "get_lwrp(:lwrp_once).new is *not* a subclass" do + lwrp = get_lwrp(:lwrp_once).new('hi') + expect(lwrp.kind_of?(subclass)).to be_falsey + expect(lwrp.is_a?(subclass)).to be_falsey + expect(subclass === lwrp.class).to be_falsey + expect(subclass === get_lwrp(:lwrp_once)).to be_falsey + end + end + + context "with a subclass of Chef::Resource::LwrpOnce" do + let(:subclass) do + Class.new(Chef::Resource::LwrpOnce) + end + + it "subclass.new is a subclass" do + lwrp = subclass.new('hi') + expect(lwrp.kind_of?(subclass)).to be_truthy + expect(lwrp.is_a?(subclass)).to be_truthy + expect(subclass === lwrp).to be_truthy + expect(lwrp.class === subclass) + end + it "subclass.new is a Chef::Resource::LwrpOnce" do + lwrp = subclass.new('hi') + expect(lwrp.kind_of?(Chef::Resource::LwrpOnce)).to be_truthy + expect(lwrp.is_a?(Chef::Resource::LwrpOnce)).to be_truthy + expect(Chef::Resource::LwrpOnce === lwrp).to be_truthy + expect(lwrp.class === Chef::Resource::LwrpOnce) + end + it "subclass.new is a get_lwrp(:lwrp_once)" do + lwrp = subclass.new('hi') + expect(lwrp.kind_of?(get_lwrp(:lwrp_once))).to be_truthy + expect(lwrp.is_a?(get_lwrp(:lwrp_once))).to be_truthy + expect(get_lwrp(:lwrp_once) === lwrp).to be_truthy + expect(lwrp.class === get_lwrp(:lwrp_once)) + end + it "Chef::Resource::LwrpOnce.new is *not* a subclass" do + lwrp = Chef::Resource::LwrpOnce.new('hi') + expect(lwrp.kind_of?(subclass)).to be_falsey + expect(lwrp.is_a?(subclass)).to be_falsey + expect(subclass === lwrp.class).to be_falsey + expect(subclass === Chef::Resource::LwrpOnce).to be_falsey + end + it "get_lwrp(:lwrp_once).new is *not* a subclass" do + lwrp = get_lwrp(:lwrp_once).new('hi') + expect(lwrp.kind_of?(subclass)).to be_falsey + expect(lwrp.is_a?(subclass)).to be_falsey + expect(subclass === lwrp.class).to be_falsey + expect(subclass === get_lwrp(:lwrp_once)).to be_falsey + end + end + end end + + diff --git a/spec/unit/node_map_spec.rb b/spec/unit/node_map_spec.rb index 9b5ff5e8c6..7b37ea59f4 100644 --- a/spec/unit/node_map_spec.rb +++ b/spec/unit/node_map_spec.rb @@ -131,6 +131,18 @@ describe Chef::NodeMap do allow(node).to receive(:[]).with(:platform_version).and_return("6.0") expect(node_map.get(node, :thing)).to eql(nil) end + + context "when there is a less specific definition" do + before do + node_map.set(:thing, :bar, platform_family: "rhel") + end + + it "returns the value when the node matches" do + allow(node).to receive(:[]).with(:platform_family).and_return("rhel") + allow(node).to receive(:[]).with(:platform_version).and_return("7.0") + expect(node_map.get(node, :thing)).to eql(:foo) + end + end end describe "resource back-compat testing" do diff --git a/spec/unit/osc_user_spec.rb b/spec/unit/osc_user_spec.rb deleted file mode 100644 index 16731b47bd..0000000000 --- a/spec/unit/osc_user_spec.rb +++ /dev/null @@ -1,276 +0,0 @@ -# -# Author:: Steven Danna (steve@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. -# - -# DEPRECATION NOTE -# This code only remains to support users still operating with -# Open Source Chef Server 11 and should be removed once support -# for OSC 11 ends. New development should occur in user_spec.rb. - -require 'spec_helper' - -require 'chef/osc_user' -require 'tempfile' - -describe Chef::OscUser do - before(:each) do - @user = Chef::OscUser.new - end - - describe "initialize" do - it "should be a Chef::OscUser" do - expect(@user).to be_a_kind_of(Chef::OscUser) - end - end - - describe "name" do - it "should let you set the name to a string" do - expect(@user.name("ops_master")).to eq("ops_master") - end - - it "should return the current name" do - @user.name "ops_master" - expect(@user.name).to eq("ops_master") - end - - # It is not feasible to check all invalid characters. Here are a few - # that we probably care about. - it "should not accept invalid characters" do - # capital letters - expect { @user.name "Bar" }.to raise_error(ArgumentError) - # slashes - expect { @user.name "foo/bar" }.to raise_error(ArgumentError) - # ? - expect { @user.name "foo?" }.to raise_error(ArgumentError) - # & - expect { @user.name "foo&" }.to raise_error(ArgumentError) - end - - - it "should not accept spaces" do - expect { @user.name "ops master" }.to raise_error(ArgumentError) - end - - it "should throw an ArgumentError if you feed it anything but a string" do - expect { @user.name Hash.new }.to raise_error(ArgumentError) - end - end - - describe "admin" do - it "should let you set the admin bit" do - expect(@user.admin(true)).to eq(true) - end - - it "should return the current admin value" do - @user.admin true - expect(@user.admin).to eq(true) - end - - it "should default to false" do - expect(@user.admin).to eq(false) - end - - it "should throw an ArgumentError if you feed it anything but true or false" do - expect { @user.name Hash.new }.to raise_error(ArgumentError) - end - end - - describe "public_key" do - it "should let you set the public key" do - expect(@user.public_key("super public")).to eq("super public") - end - - it "should return the current public key" do - @user.public_key("super public") - expect(@user.public_key).to eq("super public") - end - - it "should throw an ArgumentError if you feed it something lame" do - expect { @user.public_key Hash.new }.to raise_error(ArgumentError) - end - end - - describe "private_key" do - it "should let you set the private key" do - expect(@user.private_key("super private")).to eq("super private") - end - - it "should return the private key" do - @user.private_key("super private") - expect(@user.private_key).to eq("super private") - end - - it "should throw an ArgumentError if you feed it something lame" do - expect { @user.private_key Hash.new }.to raise_error(ArgumentError) - end - end - - describe "when serializing to JSON" do - before(:each) do - @user.name("black") - @user.public_key("crowes") - @json = @user.to_json - end - - it "serializes as a JSON object" do - expect(@json).to match(/^\{.+\}$/) - end - - it "includes the name value" do - expect(@json).to include(%q{"name":"black"}) - end - - it "includes the public key value" do - expect(@json).to include(%{"public_key":"crowes"}) - end - - it "includes the 'admin' flag" do - expect(@json).to include(%q{"admin":false}) - end - - it "includes the private key when present" do - @user.private_key("monkeypants") - expect(@user.to_json).to include(%q{"private_key":"monkeypants"}) - end - - it "does not include the private key if not present" do - expect(@json).not_to include("private_key") - end - - it "includes the password if present" do - @user.password "password" - expect(@user.to_json).to include(%q{"password":"password"}) - end - - it "does not include the password if not present" do - expect(@json).not_to include("password") - end - - include_examples "to_json equivalent to Chef::JSONCompat.to_json" do - let(:jsonable) { @user } - end - end - - describe "when deserializing from JSON" do - before(:each) do - user = { "name" => "mr_spinks", - "public_key" => "turtles", - "private_key" => "pandas", - "password" => "password", - "admin" => true } - @user = Chef::OscUser.from_json(Chef::JSONCompat.to_json(user)) - end - - it "should deserialize to a Chef::OscUser object" do - expect(@user).to be_a_kind_of(Chef::OscUser) - end - - it "preserves the name" do - expect(@user.name).to eq("mr_spinks") - end - - it "preserves the public key" do - expect(@user.public_key).to eq("turtles") - end - - it "preserves the admin status" do - expect(@user.admin).to be_truthy - end - - it "includes the private key if present" do - expect(@user.private_key).to eq("pandas") - end - - it "includes the password if present" do - expect(@user.password).to eq("password") - end - - end - - describe "API Interactions" do - before (:each) do - @user = Chef::OscUser.new - @user.name "foobar" - @http_client = double("Chef::REST mock") - allow(Chef::REST).to receive(:new).and_return(@http_client) - end - - describe "list" do - before(:each) do - Chef::Config[:chef_server_url] = "http://www.example.com" - @osc_response = { "admin" => "http://www.example.com/users/admin"} - @ohc_response = [ { "user" => { "username" => "admin" }} ] - allow(Chef::OscUser).to receive(:load).with("admin").and_return(@user) - @osc_inflated_response = { "admin" => @user } - end - - it "lists all clients on an OSC server" do - allow(@http_client).to receive(:get_rest).with("users").and_return(@osc_response) - expect(Chef::OscUser.list).to eq(@osc_response) - end - - it "inflate all clients on an OSC server" do - allow(@http_client).to receive(:get_rest).with("users").and_return(@osc_response) - expect(Chef::OscUser.list(true)).to eq(@osc_inflated_response) - end - - it "lists all clients on an OHC/OPC server" do - allow(@http_client).to receive(:get_rest).with("users").and_return(@ohc_response) - # We expect that Chef::OscUser.list will give a consistent response - # so OHC API responses should be transformed to OSC-style output. - expect(Chef::OscUser.list).to eq(@osc_response) - end - - it "inflate all clients on an OHC/OPC server" do - allow(@http_client).to receive(:get_rest).with("users").and_return(@ohc_response) - expect(Chef::OscUser.list(true)).to eq(@osc_inflated_response) - end - end - - describe "create" do - it "creates a new user via the API" do - @user.password "password" - expect(@http_client).to receive(:post_rest).with("users", {:name => "foobar", :admin => false, :password => "password"}).and_return({}) - @user.create - end - end - - describe "read" do - it "loads a named user from the API" do - expect(@http_client).to receive(:get_rest).with("users/foobar").and_return({"name" => "foobar", "admin" => true, "public_key" => "pubkey"}) - user = Chef::OscUser.load("foobar") - expect(user.name).to eq("foobar") - expect(user.admin).to eq(true) - expect(user.public_key).to eq("pubkey") - end - end - - describe "update" do - it "updates an existing user on via the API" do - expect(@http_client).to receive(:put_rest).with("users/foobar", {:name => "foobar", :admin => false}).and_return({}) - @user.update - end - end - - describe "destroy" do - it "deletes the specified user via the API" do - expect(@http_client).to receive(:delete_rest).with("users/foobar") - @user.destroy - end - end - end -end diff --git a/spec/unit/platform_spec.rb b/spec/unit/platform_spec.rb index 36325d5411..34b46f657f 100644 --- a/spec/unit/platform_spec.rb +++ b/spec/unit/platform_spec.rb @@ -103,7 +103,7 @@ describe Chef::Platform do end it "should raise an exception if a provider cannot be found for a resource type" do - expect { Chef::Platform.find_provider("Darwin", "9.2.2", :coffee) }.to raise_error(ArgumentError) + expect { Chef::Platform.find_provider("Darwin", "9.2.2", :coffee) }.to raise_error(Chef::Exceptions::ProviderNotFound) end it "should look up a provider for a resource with a Chef::Resource object" do diff --git a/spec/unit/provider/deploy_spec.rb b/spec/unit/provider/deploy_spec.rb index 63658ac601..f6bb78823f 100644 --- a/spec/unit/provider/deploy_spec.rb +++ b/spec/unit/provider/deploy_spec.rb @@ -622,7 +622,7 @@ describe Chef::Provider::Deploy do gems = @provider.send(:gem_packages) - expect(gems.map { |g| g.action }).to eq([:install]) + expect(gems.map { |g| g.action }).to eq([%i{install}]) expect(gems.map { |g| g.name }).to eq(%w{eventmachine}) expect(gems.map { |g| g.version }).to eq(%w{0.12.9}) end diff --git a/spec/unit/provider/dsc_resource_spec.rb b/spec/unit/provider/dsc_resource_spec.rb index 0a6c22bdcf..65c1c019f0 100644 --- a/spec/unit/provider/dsc_resource_spec.rb +++ b/spec/unit/provider/dsc_resource_spec.rb @@ -35,10 +35,10 @@ describe Chef::Provider::DscResource do node } - it 'raises a NoProviderAvailable exception' do + it 'raises a ProviderNotFound exception' do expect(provider).not_to receive(:meta_configuration) expect{provider.run_action(:run)}.to raise_error( - Chef::Exceptions::NoProviderAvailable, /5\.0\.10018\.0/) + Chef::Exceptions::ProviderNotFound, /5\.0\.10018\.0/) end end @@ -56,7 +56,7 @@ describe Chef::Provider::DscResource do expect(provider).to receive(:meta_configuration).and_return( meta_configuration) expect { provider.run_action(:run) }.to raise_error( - Chef::Exceptions::NoProviderAvailable, /Disabled/) + Chef::Exceptions::ProviderNotFound, /Disabled/) end end diff --git a/spec/unit/provider/dsc_script_spec.rb b/spec/unit/provider/dsc_script_spec.rb index d4b2eb3b22..76589e71c1 100644 --- a/spec/unit/provider/dsc_script_spec.rb +++ b/spec/unit/provider/dsc_script_spec.rb @@ -158,14 +158,14 @@ describe Chef::Provider::DscScript do expect { provider.run_action(:run) - }.to raise_error(Chef::Exceptions::NoProviderAvailable) + }.to raise_error(Chef::Exceptions::ProviderNotFound) end end it 'raises an exception if Powershell is not present' do expect { provider.run_action(:run) - }.to raise_error(Chef::Exceptions::NoProviderAvailable) + }.to raise_error(Chef::Exceptions::ProviderNotFound) end end diff --git a/spec/unit/provider_resolver_spec.rb b/spec/unit/provider_resolver_spec.rb index cd3d7713a7..88df4a20cc 100644 --- a/spec/unit/provider_resolver_spec.rb +++ b/spec/unit/provider_resolver_spec.rb @@ -28,30 +28,37 @@ include Chef::Mixin::ConvertToClassName describe Chef::ProviderResolver do + let(:resource_name) { :service } + let(:provider) { nil } + let(:action) { :start } + let(:node) do node = Chef::Node.new - allow(node).to receive(:[]).with(:os).and_return(os) - allow(node).to receive(:[]).with(:platform_family).and_return(platform_family) - allow(node).to receive(:[]).with(:platform).and_return(platform) - allow(node).to receive(:[]).with(:platform_version).and_return(platform_version) - allow(node).to receive(:is_a?).and_return(Chef::Node) + node.automatic[:os] = os + node.automatic[:platform_family] = platform_family + node.automatic[:platform] = platform + node.automatic[:platform_version] = platform_version + node.automatic[:kernel] = { machine: 'i386' } node end + let(:run_context) { Chef::RunContext.new(node, nil, nil) } let(:provider_resolver) { Chef::ProviderResolver.new(node, resource, action) } + let(:resolved_provider) do + begin + resource ? resource.provider_for_action(action).class : nil + rescue Chef::Exceptions::ProviderNotFound + nil + end + end - let(:action) { :start } - - let(:resolved_provider) { provider_resolver.resolve } - - let(:provider) { nil } - - let(:resource_name) { :service } - - let(:resource) { double(Chef::Resource, provider: provider, resource_name: resource_name) } - - before do - allow(resource).to receive(:is_a?).with(Chef::Resource).and_return(true) + let(:resource) do + resource_class = Chef::ResourceResolver.resolve(resource_name, node: node) + if resource_class + resource = resource_class.new('test', run_context) + resource.provider = provider if provider + end + resource end def self.on_platform(platform, *tags, @@ -83,16 +90,41 @@ describe Chef::ProviderResolver do end def self.expect_providers(**providers) - providers.each do |name, provider| + providers.each do |name, expected| describe name.to_s do let(:resource_name) { name } - if provider - it "resolves to a #{provider}" do - expect(resolved_provider).to eql(provider) + + tags = [] + expected_provider = nil + expected_resource = nil + Array(expected).each do |p| + if p.is_a?(Class) && p <= Chef::Provider + expected_provider = p + elsif p.is_a?(Class) && p <= Chef::Resource + expected_resource = p + else + tags << p + end + end + + if expected_resource && expected_provider + it "'#{name}' resolves to resource #{expected_resource} and provider #{expected_provider}", *tags do + expect(resource.class).to eql(expected_resource) + provider = double(expected_provider, class: expected_provider) + expect(provider).to receive(:action=).with(action) + expect(expected_provider).to receive(:new).with(resource, run_context).and_return(provider) + expect(resolved_provider).to eql(expected_provider) + end + elsif expected_provider + it "'#{name}' resolves to provider #{expected_provider}", *tags do + provider = double(expected_provider) + expect(provider).to receive(:action=).with(action) + expect(expected_provider).to receive(:new).with(resource, run_context).and_return(provider) + expect(resolved_provider).to eql(expected_provider) end else - it "Fails to resolve (since #{name.inspect} is unsupported on #{platform} #{platform_version})" do - expect { resolved_provider }.to raise_error /Cannot find a provider/ + it "'#{name}' fails to resolve (since #{name.inspect} is unsupported on #{platform} #{platform_version})", *tags do + expect(resolved_provider).to be_nil end end end @@ -454,48 +486,48 @@ describe Chef::ProviderResolver do PROVIDERS = { - bash: Chef::Provider::Script, - breakpoint: Chef::Provider::Breakpoint, - chef_gem: Chef::Provider::Package::Rubygems, - cookbook_file: Chef::Provider::CookbookFile, - csh: Chef::Provider::Script, - deploy: Chef::Provider::Deploy::Timestamped, - deploy_revision: Chef::Provider::Deploy::Revision, - directory: Chef::Provider::Directory, - easy_install_package: Chef::Provider::Package::EasyInstall, - erl_call: Chef::Provider::ErlCall, - execute: Chef::Provider::Execute, - file: Chef::Provider::File, - gem_package: Chef::Provider::Package::Rubygems, - git: Chef::Provider::Git, - group: Chef::Provider::Group::Gpasswd, - homebrew_package: Chef::Provider::Package::Homebrew, - http_request: Chef::Provider::HttpRequest, - ifconfig: Chef::Provider::Ifconfig, - link: Chef::Provider::Link, - log: Chef::Provider::Log::ChefLog, - macports_package: Chef::Provider::Package::Macports, - mdadm: Chef::Provider::Mdadm, - mount: Chef::Provider::Mount::Mount, - perl: Chef::Provider::Script, - portage_package: Chef::Provider::Package::Portage, - python: Chef::Provider::Script, - remote_directory: Chef::Provider::RemoteDirectory, - route: Chef::Provider::Route, - ruby: Chef::Provider::Script, - ruby_block: Chef::Provider::RubyBlock, - script: Chef::Provider::Script, - subversion: Chef::Provider::Subversion, - template: Chef::Provider::Template, - timestamped_deploy: Chef::Provider::Deploy::Timestamped, - user: Chef::Provider::User::Useradd, - whyrun_safe_ruby_block: Chef::Provider::WhyrunSafeRubyBlock, + bash: [ Chef::Resource::Bash, Chef::Provider::Script ], + breakpoint: [ Chef::Resource::Breakpoint, Chef::Provider::Breakpoint ], + chef_gem: [ Chef::Resource::ChefGem, Chef::Provider::Package::Rubygems ], + cookbook_file: [ Chef::Resource::CookbookFile, Chef::Provider::CookbookFile ], + csh: [ Chef::Resource::Csh, Chef::Provider::Script ], + deploy: [ Chef::Resource::Deploy, Chef::Provider::Deploy::Timestamped ], + deploy_revision: [ Chef::Resource::DeployRevision, Chef::Provider::Deploy::Revision ], + directory: [ Chef::Resource::Directory, Chef::Provider::Directory ], + easy_install_package: [ Chef::Resource::EasyInstallPackage, Chef::Provider::Package::EasyInstall ], + erl_call: [ Chef::Resource::ErlCall, Chef::Provider::ErlCall ], + execute: [ Chef::Resource::Execute, Chef::Provider::Execute ], + file: [ Chef::Resource::File, Chef::Provider::File ], + gem_package: [ Chef::Resource::GemPackage, Chef::Provider::Package::Rubygems ], + git: [ Chef::Resource::Git, Chef::Provider::Git ], + group: [ Chef::Resource::Group, Chef::Provider::Group::Gpasswd ], + homebrew_package: [ Chef::Resource::HomebrewPackage, Chef::Provider::Package::Homebrew ], + http_request: [ Chef::Resource::HttpRequest, Chef::Provider::HttpRequest ], + ifconfig: [ Chef::Resource::Ifconfig, Chef::Provider::Ifconfig ], + link: [ Chef::Resource::Link, Chef::Provider::Link ], + log: [ Chef::Resource::Log, Chef::Provider::Log::ChefLog ], + macports_package: [ Chef::Resource::MacportsPackage, Chef::Provider::Package::Macports ], + mdadm: [ Chef::Resource::Mdadm, Chef::Provider::Mdadm ], + mount: [ Chef::Resource::Mount, Chef::Provider::Mount::Mount ], + perl: [ Chef::Resource::Perl, Chef::Provider::Script ], + portage_package: [ Chef::Resource::PortagePackage, Chef::Provider::Package::Portage ], + python: [ Chef::Resource::Python, Chef::Provider::Script ], + remote_directory: [ Chef::Resource::RemoteDirectory, Chef::Provider::RemoteDirectory ], + route: [ Chef::Resource::Route, Chef::Provider::Route ], + ruby: [ Chef::Resource::Ruby, Chef::Provider::Script ], + ruby_block: [ Chef::Resource::RubyBlock, Chef::Provider::RubyBlock ], + script: [ Chef::Resource::Script, Chef::Provider::Script ], + subversion: [ Chef::Resource::Subversion, Chef::Provider::Subversion ], + template: [ Chef::Resource::Template, Chef::Provider::Template ], + timestamped_deploy: [ Chef::Resource::TimestampedDeploy, Chef::Provider::Deploy::Timestamped ], + user: [ Chef::Resource::User, Chef::Provider::User::Useradd ], + whyrun_safe_ruby_block: [ Chef::Resource::WhyrunSafeRubyBlock, Chef::Provider::WhyrunSafeRubyBlock ], # We want to check that these are unsupported: apt_package: nil, bff_package: nil, - dsc_script: nil, dpkg_package: nil, + dsc_script: nil, ips_package: nil, pacman_package: nil, paludis_package: nil, @@ -507,61 +539,62 @@ describe Chef::ProviderResolver do windows_service: nil, "linux" => { - apt_package: Chef::Provider::Package::Apt, - dpkg_package: Chef::Provider::Package::Dpkg, - pacman_package: Chef::Provider::Package::Pacman, - paludis_package: Chef::Provider::Package::Paludis, - rpm_package: Chef::Provider::Package::Rpm, - yum_package: Chef::Provider::Package::Yum, + apt_package: [ Chef::Resource::AptPackage, Chef::Provider::Package::Apt ], + dpkg_package: [ Chef::Resource::DpkgPackage, Chef::Provider::Package::Dpkg ], + pacman_package: [ Chef::Resource::PacmanPackage, Chef::Provider::Package::Pacman ], + paludis_package: [ Chef::Resource::PaludisPackage, Chef::Provider::Package::Paludis ], + rpm_package: [ Chef::Resource::RpmPackage, Chef::Provider::Package::Rpm ], + yum_package: [ Chef::Resource::YumPackage, Chef::Provider::Package::Yum ], "debian" => { - ifconfig: Chef::Provider::Ifconfig::Debian, - package: Chef::Provider::Package::Apt, -# service: Chef::Provider::Service::Debian, + ifconfig: [ Chef::Resource::Ifconfig, Chef::Provider::Ifconfig::Debian ], + package: [ Chef::Resource::AptPackage, Chef::Provider::Package::Apt ], +# service: [ Chef::Resource::DebianService, Chef::Provider::Service::Debian ], "debian" => { "7.0" => { }, "6.0" => { - ifconfig: Chef::Provider::Ifconfig, -# service: Chef::Provider::Service::Insserv, + ifconfig: [ Chef::Resource::Ifconfig, Chef::Provider::Ifconfig ], +# service: [ Chef::Resource::InsservService, Chef::Provider::Service::Insserv ], }, "5.0" => { - ifconfig: Chef::Provider::Ifconfig, + ifconfig: [ Chef::Resource::Ifconfig, Chef::Provider::Ifconfig ], }, }, "gcel" => { "3.1.4" => { - ifconfig: Chef::Provider::Ifconfig, + ifconfig: [ Chef::Resource::Ifconfig, Chef::Provider::Ifconfig ], }, }, "linaro" => { "3.1.4" => { - ifconfig: Chef::Provider::Ifconfig, + ifconfig: [ Chef::Resource::Ifconfig, Chef::Provider::Ifconfig ], }, }, "linuxmint" => { "3.1.4" => { - ifconfig: Chef::Provider::Ifconfig, -# service: Chef::Provider::Service::Upstart, + ifconfig: [ Chef::Resource::Ifconfig, Chef::Provider::Ifconfig ], +# service: [ Chef::Resource::UpstartService, Chef::Provider::Service::Upstart ], }, }, "raspbian" => { "3.1.4" => { - ifconfig: Chef::Provider::Ifconfig, + ifconfig: [ Chef::Resource::Ifconfig, Chef::Provider::Ifconfig ], }, }, "ubuntu" => { "11.10" => { }, "10.04" => { - ifconfig: Chef::Provider::Ifconfig, + ifconfig: [ Chef::Resource::Ifconfig, Chef::Provider::Ifconfig ], }, }, }, "arch" => { - package: Chef::Provider::Package::Pacman, + # TODO should be Chef::Resource::PacmanPackage + package: [ Chef::Resource::Package, Chef::Provider::Package::Pacman ], "arch" => { "3.1.4" => { @@ -570,8 +603,8 @@ describe Chef::ProviderResolver do }, "freebsd" => { - group: Chef::Provider::Group::Pw, - user: Chef::Provider::User::Pw, + group: [ Chef::Resource::Group, Chef::Provider::Group::Pw ], + user: [ Chef::Resource::User, Chef::Provider::User::Pw ], "freebsd" => { "3.1.4" => { @@ -579,30 +612,31 @@ describe Chef::ProviderResolver do }, }, "suse" => { - group: Chef::Provider::Group::Gpasswd, + group: [ Chef::Resource::Group, Chef::Provider::Group::Gpasswd ], "suse" => { "12.0" => { }, %w(11.1 11.2 11.3) => { - group: Chef::Provider::Group::Suse, + group: [ Chef::Resource::Group, Chef::Provider::Group::Suse ], }, }, "opensuse" => { -# service: Chef::Provider::Service::Redhat, - package: Chef::Provider::Package::Zypper, - group: Chef::Provider::Group::Usermod, +# service: [ Chef::Resource::RedhatService, Chef::Provider::Service::Redhat ], + package: [ Chef::Resource::ZypperPackage, Chef::Provider::Package::Zypper ], + group: [ Chef::Resource::Group, Chef::Provider::Group::Usermod ], "12.3" => { }, "12.2" => { - group: Chef::Provider::Group::Suse, + group: [ Chef::Resource::Group, Chef::Provider::Group::Suse ], }, }, }, "gentoo" => { - package: Chef::Provider::Package::Portage, - portage_package: Chef::Provider::Package::Portage, -# service: Chef::Provider::Service::Gentoo, + # TODO should be Chef::Resource::PortagePackage + package: [ Chef::Resource::Package, Chef::Provider::Package::Portage ], + portage_package: [ Chef::Resource::PortagePackage, Chef::Provider::Package::Portage ], +# service: [ Chef::Resource::GentooService, Chef::Provider::Service::Gentoo ], "gentoo" => { "3.1.4" => { @@ -611,27 +645,27 @@ describe Chef::ProviderResolver do }, "rhel" => { -# service: Chef::Provider::Service::Systemd, - package: Chef::Provider::Package::Yum, - ifconfig: Chef::Provider::Ifconfig::Redhat, +# service: [ Chef::Resource::SystemdService, Chef::Provider::Service::Systemd ], + package: [ Chef::Resource::YumPackage, Chef::Provider::Package::Yum ], + ifconfig: [ Chef::Resource::Ifconfig, Chef::Provider::Ifconfig::Redhat ], %w(amazon xcp xenserver ibm_powerkvm cloudlinux parallels) => { "3.1.4" => { -# service: Chef::Provider::Service::Redhat, +# service: [ Chef::Resource::RedhatService, Chef::Provider::Service::Redhat ], }, }, %w(redhat centos scientific oracle) => { "7.0" => { }, "6.0" => { -# service: Chef::Provider::Service::Redhat, +# service: [ Chef::Resource::RedhatService, Chef::Provider::Service::Redhat ], }, }, "fedora" => { "15.0" => { }, "14.0" => { -# service: Chef::Provider::Service::Redhat, +# service: [ Chef::Resource::RedhatService, Chef::Provider::Service::Redhat ], }, }, }, @@ -640,9 +674,9 @@ describe Chef::ProviderResolver do "darwin" => { %w(mac_os_x mac_os_x_server) => { - group: Chef::Provider::Group::Dscl, - package: Chef::Provider::Package::Homebrew, - user: Chef::Provider::User::Dscl, + group: [ Chef::Resource::Group, Chef::Provider::Group::Dscl ], + package: [ Chef::Resource::HomebrewPackage, Chef::Provider::Package::Homebrew ], + user: [ Chef::Resource::User, Chef::Provider::User::Dscl ], "mac_os_x" => { "10.9.2" => { @@ -652,17 +686,17 @@ describe Chef::ProviderResolver do }, "windows" => { - batch: Chef::Provider::Batch, - dsc_script: Chef::Provider::DscScript, - env: Chef::Provider::Env::Windows, - group: Chef::Provider::Group::Windows, - mount: Chef::Provider::Mount::Windows, - package: Chef::Provider::Package::Windows, - powershell_script: Chef::Provider::PowershellScript, - service: Chef::Provider::Service::Windows, - user: Chef::Provider::User::Windows, - windows_package: Chef::Provider::Package::Windows, - windows_service: Chef::Provider::Service::Windows, + batch: [ Chef::Resource::Batch, Chef::Provider::Batch ], + dsc_script: [ Chef::Resource::DscScript, Chef::Provider::DscScript ], + env: [ Chef::Resource::Env, Chef::Provider::Env::Windows ], + group: [ Chef::Resource::Group, Chef::Provider::Group::Windows ], + mount: [ Chef::Resource::Mount, Chef::Provider::Mount::Windows ], + package: [ Chef::Resource::WindowsPackage, Chef::Provider::Package::Windows ], + powershell_script: [ Chef::Resource::PowershellScript, Chef::Provider::PowershellScript ], + service: [ Chef::Resource::WindowsService, Chef::Provider::Service::Windows ], + user: [ Chef::Resource::User, Chef::Provider::User::Windows ], + windows_package: [ Chef::Resource::WindowsPackage, Chef::Provider::Package::Windows ], + windows_service: [ Chef::Resource::WindowsService, Chef::Provider::Service::Windows ], "windows" => { %w(mswin mingw32 windows) => { @@ -673,15 +707,16 @@ describe Chef::ProviderResolver do }, "aix" => { - bff_package: Chef::Provider::Package::Aix, - cron: Chef::Provider::Cron::Aix, - group: Chef::Provider::Group::Aix, - ifconfig: Chef::Provider::Ifconfig::Aix, - mount: Chef::Provider::Mount::Aix, - package: Chef::Provider::Package::Aix, - rpm_package: Chef::Provider::Package::Rpm, - user: Chef::Provider::User::Aix, -# service: Chef::Provider::Service::Aix, + bff_package: [ Chef::Resource::BffPackage, Chef::Provider::Package::Aix ], + cron: [ Chef::Resource::Cron, Chef::Provider::Cron::Aix ], + group: [ Chef::Resource::Group, Chef::Provider::Group::Aix ], + ifconfig: [ Chef::Resource::Ifconfig, Chef::Provider::Ifconfig::Aix ], + mount: [ Chef::Resource::Mount, Chef::Provider::Mount::Aix ], + # TODO should be Chef::Resource::BffPackage + package: [ Chef::Resource::Package, Chef::Provider::Package::Aix ], + rpm_package: [ Chef::Resource::RpmPackage, Chef::Provider::Package::Rpm ], + user: [ Chef::Resource::User, Chef::Provider::User::Aix ], +# service: [ Chef::Resource::AixService, Chef::Provider::Service::Aix ], "aix" => { "aix" => { @@ -695,7 +730,7 @@ describe Chef::ProviderResolver do "hpux" => { "hpux" => { "3.1.4" => { - group: Chef::Provider::Group::Usermod + group: [ Chef::Resource::Group, Chef::Provider::Group::Usermod ] } } } @@ -705,15 +740,15 @@ describe Chef::ProviderResolver do "netbsd" => { "netbsd" => { "3.1.4" => { - group: Chef::Provider::Group::Groupmod, + group: [ Chef::Resource::Group, Chef::Provider::Group::Groupmod ], }, }, }, }, "openbsd" => { - group: Chef::Provider::Group::Usermod, - package: Chef::Provider::Package::Openbsd, + group: [ Chef::Resource::Group, Chef::Provider::Group::Usermod ], + package: [ Chef::Resource::OpenbsdPackage, Chef::Provider::Package::Openbsd ], "openbsd" => { "openbsd" => { @@ -724,15 +759,15 @@ describe Chef::ProviderResolver do }, "solaris2" => { - group: Chef::Provider::Group::Usermod, - ips_package: Chef::Provider::Package::Ips, - package: Chef::Provider::Package::Ips, - mount: Chef::Provider::Mount::Solaris, - solaris_package: Chef::Provider::Package::Solaris, + group: [ Chef::Resource::Group, Chef::Provider::Group::Usermod ], + ips_package: [ Chef::Resource::IpsPackage, Chef::Provider::Package::Ips ], + package: [ Chef::Resource::SolarisPackage, Chef::Provider::Package::Solaris ], + mount: [ Chef::Resource::Mount, Chef::Provider::Mount::Solaris ], + solaris_package: [ Chef::Resource::SolarisPackage, Chef::Provider::Package::Solaris ], "smartos" => { - smartos_package: Chef::Provider::Package::SmartOS, - package: Chef::Provider::Package::SmartOS, + smartos_package: [ Chef::Resource::SmartosPackage, Chef::Provider::Package::SmartOS ], + package: [ Chef::Resource::SmartosPackage, Chef::Provider::Package::SmartOS ], "smartos" => { "3.1.4" => { @@ -743,12 +778,11 @@ describe Chef::ProviderResolver do "solaris2" => { "nexentacore" => { "3.1.4" => { - package: Chef::Provider::Package::Solaris, }, }, "omnios" => { "3.1.4" => { - user: Chef::Provider::User::Solaris, + user: [ Chef::Resource::User, Chef::Provider::User::Solaris ], } }, "openindiana" => { @@ -760,11 +794,11 @@ describe Chef::ProviderResolver do }, }, "solaris2" => { - user: Chef::Provider::User::Solaris, + user: [ Chef::Resource::User, Chef::Provider::User::Solaris ], "5.11" => { + package: [ Chef::Resource::IpsPackage, Chef::Provider::Package::Ips ], }, "5.9" => { - package: Chef::Provider::Package::Solaris, }, }, }, @@ -784,7 +818,8 @@ describe Chef::ProviderResolver do "exherbo" => { "exherbo" => { "3.1.4" => { - package: Chef::Provider::Package::Paludis + # TODO should be Chef::Resource::PaludisPackage + package: [ Chef::Resource::Package, Chef::Provider::Package::Paludis ] } } } diff --git a/spec/unit/recipe_spec.rb b/spec/unit/recipe_spec.rb index 17ea498fe3..511e7e9397 100644 --- a/spec/unit/recipe_spec.rb +++ b/spec/unit/recipe_spec.rb @@ -409,8 +409,8 @@ describe Chef::Recipe do end it "does not copy the action from the first resource" do - expect(original_resource.action).to eq(:score) - expect(duplicated_resource.action).to eq(:nothing) + expect(original_resource.action).to eq([:score]) + expect(duplicated_resource.action).to eq([:nothing]) end it "does not copy the source location of the first resource" do @@ -505,7 +505,7 @@ describe Chef::Recipe do recipe.from_file(File.join(CHEF_SPEC_DATA, "recipes", "test.rb")) res = recipe.resources(:file => "/etc/nsswitch.conf") expect(res.name).to eql("/etc/nsswitch.conf") - expect(res.action).to eql(:create) + expect(res.action).to eql([:create]) expect(res.owner).to eql("root") expect(res.group).to eql("root") expect(res.mode).to eql(0644) diff --git a/spec/unit/resource/breakpoint_spec.rb b/spec/unit/resource/breakpoint_spec.rb index 9c867ebcc7..88ab34d568 100644 --- a/spec/unit/resource/breakpoint_spec.rb +++ b/spec/unit/resource/breakpoint_spec.rb @@ -37,7 +37,7 @@ describe Chef::Resource::Breakpoint do end it "defaults to the break action" do - expect(@breakpoint.action).to eq(:break) + expect(@breakpoint.action).to eq([:break]) end it "names itself after the line number of the file where it's created" do diff --git a/spec/unit/resource/cron_spec.rb b/spec/unit/resource/cron_spec.rb index 743552c1de..0978be6930 100644 --- a/spec/unit/resource/cron_spec.rb +++ b/spec/unit/resource/cron_spec.rb @@ -35,7 +35,7 @@ describe Chef::Resource::Cron do end it "should have a default action of 'create'" do - expect(@resource.action).to eql(:create) + expect(@resource.action).to eql([:create]) end it "should accept create or delete for action" do diff --git a/spec/unit/resource/directory_spec.rb b/spec/unit/resource/directory_spec.rb index c452b2a914..e9e80806db 100644 --- a/spec/unit/resource/directory_spec.rb +++ b/spec/unit/resource/directory_spec.rb @@ -35,7 +35,7 @@ describe Chef::Resource::Directory do end it "should have a default action of 'create'" do - expect(@resource.action).to eql(:create) + expect(@resource.action).to eql([:create]) end it "should accept create or delete for action" do diff --git a/spec/unit/resource/dsc_resource_spec.rb b/spec/unit/resource/dsc_resource_spec.rb index ae15f56eaf..06769d86ce 100644 --- a/spec/unit/resource/dsc_resource_spec.rb +++ b/spec/unit/resource/dsc_resource_spec.rb @@ -35,7 +35,7 @@ describe Chef::Resource::DscResource do } it "has a default action of `:run`" do - expect(dsc_test_resource.action).to eq(:run) + expect(dsc_test_resource.action).to eq([:run]) end it "has an allowed_actions attribute with only the `:run` and `:nothing` attributes" do diff --git a/spec/unit/resource/dsc_script_spec.rb b/spec/unit/resource/dsc_script_spec.rb index 71103ea590..4361b35b91 100644 --- a/spec/unit/resource/dsc_script_spec.rb +++ b/spec/unit/resource/dsc_script_spec.rb @@ -29,7 +29,7 @@ describe Chef::Resource::DscScript do Chef::RunContext.new(node, {}, empty_events) } let(:dsc_test_resource) { - Chef::Resource::DscScript.new(dsc_test_resource_name, dsc_test_run_context) + Chef::Resource::DscScript.new(dsc_test_resource_name, dsc_test_run_context) } let(:configuration_code) {'echo "This is supposed to create a configuration document."'} let(:configuration_path) {'c:/myconfigs/formatc.ps1'} @@ -38,7 +38,7 @@ describe Chef::Resource::DscScript do let(:configuration_data_script) { 'c:/myconfigs/data/safedata.psd1' } it "has a default action of `:run`" do - expect(dsc_test_resource.action).to eq(:run) + expect(dsc_test_resource.action).to eq([:run]) end it "has an allowed_actions attribute with only the `:run` and `:nothing` attributes" do diff --git a/spec/unit/resource/env_spec.rb b/spec/unit/resource/env_spec.rb index 566827a27e..9bee07c593 100644 --- a/spec/unit/resource/env_spec.rb +++ b/spec/unit/resource/env_spec.rb @@ -35,7 +35,7 @@ describe Chef::Resource::Env do end it "should have a default action of 'create'" do - expect(@resource.action).to eql(:create) + expect(@resource.action).to eql([:create]) end { :create => false, :delete => false, :modify => false, :flibber => true }.each do |action,bad_value| diff --git a/spec/unit/resource/erl_call_spec.rb b/spec/unit/resource/erl_call_spec.rb index 008d27372a..9abf2e7812 100644 --- a/spec/unit/resource/erl_call_spec.rb +++ b/spec/unit/resource/erl_call_spec.rb @@ -35,7 +35,7 @@ describe Chef::Resource::ErlCall do end it "should have a default action of run" do - expect(@resource.action).to eql(:run) + expect(@resource.action).to eql([:run]) end it "should accept run as an action" do diff --git a/spec/unit/resource/file_spec.rb b/spec/unit/resource/file_spec.rb index dd20f5f03a..76beaf15e1 100644 --- a/spec/unit/resource/file_spec.rb +++ b/spec/unit/resource/file_spec.rb @@ -29,7 +29,7 @@ describe Chef::Resource::File do end it "should have a default action of 'create'" do - expect(@resource.action).to eql(:create) + expect(@resource.action).to eql([:create]) end it "should have a default content of nil" do diff --git a/spec/unit/resource/group_spec.rb b/spec/unit/resource/group_spec.rb index bcf9205f7e..a4029fc911 100644 --- a/spec/unit/resource/group_spec.rb +++ b/spec/unit/resource/group_spec.rb @@ -50,7 +50,7 @@ describe Chef::Resource::Group, "initialize" do end it "should set action to :create" do - expect(@resource.action).to eql(:create) + expect(@resource.action).to eql([:create]) end %w{create remove modify manage}.each do |action| diff --git a/spec/unit/resource/link_spec.rb b/spec/unit/resource/link_spec.rb index 51221e0472..0246fcd13b 100644 --- a/spec/unit/resource/link_spec.rb +++ b/spec/unit/resource/link_spec.rb @@ -36,7 +36,7 @@ describe Chef::Resource::Link do end it "should have a default action of 'create'" do - expect(@resource.action).to eql(:create) + expect(@resource.action).to eql([:create]) end { :create => false, :delete => false, :blues => true }.each do |action,bad_value| diff --git a/spec/unit/resource/mdadm_spec.rb b/spec/unit/resource/mdadm_spec.rb index 866309ec5b..6ca99c58e5 100644 --- a/spec/unit/resource/mdadm_spec.rb +++ b/spec/unit/resource/mdadm_spec.rb @@ -35,7 +35,7 @@ describe Chef::Resource::Mdadm do end it "should have a default action of create" do - expect(@resource.action).to eql(:create) + expect(@resource.action).to eql([:create]) end it "should accept create, assemble, stop as actions" do diff --git a/spec/unit/resource/mount_spec.rb b/spec/unit/resource/mount_spec.rb index ad95c06e04..acce26dcab 100644 --- a/spec/unit/resource/mount_spec.rb +++ b/spec/unit/resource/mount_spec.rb @@ -38,7 +38,7 @@ describe Chef::Resource::Mount do end it "should have a default action of mount" do - expect(@resource.action).to eql(:mount) + expect(@resource.action).to eql([:mount]) end it "should accept mount, umount and remount as actions" do diff --git a/spec/unit/resource/ohai_spec.rb b/spec/unit/resource/ohai_spec.rb index fe29755abf..3bc21a41d2 100644 --- a/spec/unit/resource/ohai_spec.rb +++ b/spec/unit/resource/ohai_spec.rb @@ -34,7 +34,7 @@ describe Chef::Resource::Ohai do end it "should have a default action of create" do - expect(@resource.action).to eql(:reload) + expect(@resource.action).to eql([:reload]) end it "should allow you to set the plugin attribute" do diff --git a/spec/unit/resource/registry_key_spec.rb b/spec/unit/resource/registry_key_spec.rb index e2a864d73a..2e2811d026 100644 --- a/spec/unit/resource/registry_key_spec.rb +++ b/spec/unit/resource/registry_key_spec.rb @@ -45,7 +45,7 @@ describe Chef::Resource::RegistryKey, "initialize" do end it "should set action to :create" do - expect(@resource.action).to eql(:create) + expect(@resource.action).to eql([:create]) end %w{create create_if_missing delete delete_key}.each do |action| diff --git a/spec/unit/resource/route_spec.rb b/spec/unit/resource/route_spec.rb index ffb9304511..ec1d369932 100644 --- a/spec/unit/resource/route_spec.rb +++ b/spec/unit/resource/route_spec.rb @@ -35,7 +35,7 @@ describe Chef::Resource::Route do end it "should have a default action of 'add'" do - expect(@resource.action).to eql(:add) + expect(@resource.action).to eql([:add]) end it "should accept add or delete for action" do diff --git a/spec/unit/resource/ruby_block_spec.rb b/spec/unit/resource/ruby_block_spec.rb index 5d83f7e367..8664564ac5 100644 --- a/spec/unit/resource/ruby_block_spec.rb +++ b/spec/unit/resource/ruby_block_spec.rb @@ -30,8 +30,8 @@ describe Chef::Resource::RubyBlock do expect(@resource).to be_a_kind_of(Chef::Resource::RubyBlock) end - it "should have a default action of 'create'" do - expect(@resource.action).to eql(:run) + it "should have a default action of 'run'" do + expect(@resource.action).to eql([:run]) end it "should have a resource name of :ruby_block" do @@ -46,7 +46,7 @@ describe Chef::Resource::RubyBlock do it "allows the action to be 'create'" do @resource.action :create - expect(@resource.action).to eq(:create) + expect(@resource.action).to eq([:create]) end describe "when it has been initialized with block code" do diff --git a/spec/unit/resource/user_spec.rb b/spec/unit/resource/user_spec.rb index f05de94fe0..3bf7e6187b 100644 --- a/spec/unit/resource/user_spec.rb +++ b/spec/unit/resource/user_spec.rb @@ -43,7 +43,7 @@ describe Chef::Resource::User, "initialize" do end it "should set action to :create" do - expect(@resource.action).to eql(:create) + expect(@resource.action).to eql([:create]) end it "should set supports[:manage_home] to false" do diff --git a/spec/unit/resource/windows_service_spec.rb b/spec/unit/resource/windows_service_spec.rb index 8866cad1bf..45a295c24e 100644 --- a/spec/unit/resource/windows_service_spec.rb +++ b/spec/unit/resource/windows_service_spec.rb @@ -44,6 +44,6 @@ describe Chef::Resource::WindowsService, "initialize" do it "allows the action to be 'configure_startup'" do resource.action :configure_startup - expect(resource.action).to eq(:configure_startup) + expect(resource.action).to eq([:configure_startup]) end end diff --git a/spec/unit/resource_resolver_spec.rb b/spec/unit/resource_resolver_spec.rb index 09ff026575..b3bda9d945 100644 --- a/spec/unit/resource_resolver_spec.rb +++ b/spec/unit/resource_resolver_spec.rb @@ -31,19 +31,23 @@ describe Chef::ResourceResolver do context 'instance methods' do let(:resolver) do - described_class.new(Chef::Node.new, 'execute[echo]') + described_class.new(Chef::Node.new, 'execute') end it '#resolve' do - expect(resolver.resolve).to be_nil + expect(resolver.resolve).to eq Chef::Resource::Execute end it '#list' do - expect(resolver.list).to be_empty + expect(resolver.list).to eq [ Chef::Resource::Execute ] end - it '#provided_by?' do + it '#provided_by? returns true when resource class is in the list' do expect(resolver.provided_by?(Chef::Resource::Execute)).to be_truthy end + + it '#provided_by? returns false when resource class is not in the list' do + expect(resolver.provided_by?(Chef::Resource::File)).to be_falsey + end end end diff --git a/spec/unit/resource_spec.rb b/spec/unit/resource_spec.rb index 8b0baff921..e0aee58d41 100644 --- a/spec/unit/resource_spec.rb +++ b/spec/unit/resource_spec.rb @@ -810,21 +810,21 @@ describe Chef::Resource do end it 'adds mappings for a single platform' do - expect(Chef.resource_priority_map).to receive(:set).with( + expect(Chef.resource_handler_map).to receive(:set).with( :dinobot, Chef::Resource::Klz, { platform: ['autobots'] } ) klz.provides :dinobot, platform: ['autobots'] end it 'adds mappings for multiple platforms' do - expect(Chef.resource_priority_map).to receive(:set).with( + expect(Chef.resource_handler_map).to receive(:set).with( :energy, Chef::Resource::Klz, { platform: ['autobots', 'decepticons']} ) klz.provides :energy, platform: ['autobots', 'decepticons'] end it 'adds mappings for all platforms' do - expect(Chef.resource_priority_map).to receive(:set).with( + expect(Chef.resource_handler_map).to receive(:set).with( :tape_deck, Chef::Resource::Klz, {} ) klz.provides :tape_deck @@ -977,4 +977,90 @@ describe Chef::Resource do end end + + describe "#action" do + let(:resource_class) do + Class.new(described_class) do + allowed_actions(%i{one two}) + end + end + let(:resource) { resource_class.new('test', nil) } + subject { resource.action } + + context "with a no action" do + it { is_expected.to eq [:nothing] } + end + + context "with a default action" do + let(:resource_class) do + Class.new(described_class) do + default_action(:one) + end + end + it { is_expected.to eq [:one] } + end + + context "with a symbol action" do + before { resource.action(:one) } + it { is_expected.to eq [:one] } + end + + context "with a string action" do + before { resource.action('two') } + it { is_expected.to eq [:two] } + end + + context "with an array action" do + before { resource.action([:two, :one]) } + it { is_expected.to eq [:two, :one] } + end + + context "with an assignment" do + before { resource.action = :one } + it { is_expected.to eq [:one] } + end + + context "with an array assignment" do + before { resource.action = [:two, :one] } + it { is_expected.to eq [:two, :one] } + end + + context "with an invalid action" do + it { expect { resource.action(:three) }.to raise_error Chef::Exceptions::ValidationFailed } + end + + context "with an invalid assignment action" do + it { expect { resource.action = :three }.to raise_error Chef::Exceptions::ValidationFailed } + end + end + + describe ".default_action" do + let(:default_action) { } + let(:resource_class) do + actions = default_action + Class.new(described_class) do + default_action(actions) if actions + end + end + subject { resource_class.default_action } + + context "with no default actions" do + it { is_expected.to eq [:nothing] } + end + + context "with a symbol default action" do + let(:default_action) { :one } + it { is_expected.to eq [:one] } + end + + context "with a string default action" do + let(:default_action) { 'one' } + it { is_expected.to eq [:one] } + end + + context "with an array default action" do + let(:default_action) { [:two, :one] } + it { is_expected.to eq [:two, :one] } + end + end end diff --git a/spec/unit/run_list/versioned_recipe_list_spec.rb b/spec/unit/run_list/versioned_recipe_list_spec.rb index 209ac37fc1..9c3ecaa0dd 100644 --- a/spec/unit/run_list/versioned_recipe_list_spec.rb +++ b/spec/unit/run_list/versioned_recipe_list_spec.rb @@ -26,98 +26,165 @@ describe Chef::RunList::VersionedRecipeList do end end + let(:list) { described_class.new } + + let(:versioned_recipes) { [] } + + let(:recipes) { [] } + + before do + recipes.each { |r| list << r } + versioned_recipes.each {|r| list.add_recipe r[:name], r[:version]} + end + describe "add_recipe" do - before(:each) do - @list = Chef::RunList::VersionedRecipeList.new - @list << "apt" - @list << "god" - @list << "apache2" - end + + let(:recipes) { %w[ apt god apache2 ] } it "should append the recipe to the end of the list" do - @list.add_recipe "rails" - expect(@list).to eq(["apt", "god", "apache2", "rails"]) + list.add_recipe "rails" + expect(list).to eq(["apt", "god", "apache2", "rails"]) end it "should not duplicate entries" do - @list.add_recipe "apt" - expect(@list).to eq(["apt", "god", "apache2"]) + list.add_recipe "apt" + expect(list).to eq(["apt", "god", "apache2"]) end it "should allow you to specify a version" do - @list.add_recipe "rails", "1.0.0" - expect(@list).to eq(["apt", "god", "apache2", "rails"]) - expect(@list.with_versions).to include({:name => "rails", :version => "1.0.0"}) + list.add_recipe "rails", "1.0.0" + expect(list).to eq(["apt", "god", "apache2", "rails"]) + expect(list.with_versions).to include({:name => "rails", :version => "1.0.0"}) end it "should allow you to specify a version for a recipe that already exists" do - @list.add_recipe "apt", "1.2.3" - expect(@list).to eq(["apt", "god", "apache2"]) - expect(@list.with_versions).to include({:name => "apt", :version => "1.2.3"}) + list.add_recipe "apt", "1.2.3" + expect(list).to eq(["apt", "god", "apache2"]) + expect(list.with_versions).to include({:name => "apt", :version => "1.2.3"}) end it "should allow you to specify the same version of a recipe twice" do - @list.add_recipe "rails", "1.0.0" - @list.add_recipe "rails", "1.0.0" - expect(@list.with_versions).to include({:name => "rails", :version => "1.0.0"}) + list.add_recipe "rails", "1.0.0" + list.add_recipe "rails", "1.0.0" + expect(list.with_versions).to include({:name => "rails", :version => "1.0.0"}) end it "should allow you to spcify no version, even when a version already exists" do - @list.add_recipe "rails", "1.0.0" - @list.add_recipe "rails" - expect(@list.with_versions).to include({:name => "rails", :version => "1.0.0"}) + list.add_recipe "rails", "1.0.0" + list.add_recipe "rails" + expect(list.with_versions).to include({:name => "rails", :version => "1.0.0"}) end it "should not allow multiple versions of the same recipe" do - @list.add_recipe "rails", "1.0.0" - expect {@list.add_recipe "rails", "0.1.0"}.to raise_error Chef::Exceptions::CookbookVersionConflict + list.add_recipe "rails", "1.0.0" + expect {list.add_recipe "rails", "0.1.0"}.to raise_error Chef::Exceptions::CookbookVersionConflict end end describe "with_versions" do - before(:each) do - @recipes = [ + + let(:versioned_recipes) do + [ {:name => "apt", :version => "1.0.0"}, {:name => "god", :version => nil}, {:name => "apache2", :version => "0.0.1"} ] - @list = Chef::RunList::VersionedRecipeList.new - @recipes.each {|i| @list.add_recipe i[:name], i[:version]} end - it "should return an array of hashes with :name and :version" do - expect(@list.with_versions).to eq(@recipes) + expect(list.with_versions).to eq(versioned_recipes) end it "should retain the same order as the version-less list" do - with_versions = @list.with_versions - @list.each_with_index do |item, index| + with_versions = list.with_versions + list.each_with_index do |item, index| expect(with_versions[index][:name]).to eq(item) end end end describe "with_version_constraints" do - before(:each) do - @recipes = [ - {:name => "apt", :version => "~> 1.2.0"}, - {:name => "god", :version => nil}, - {:name => "apache2", :version => "0.0.1"} - ] - @list = Chef::RunList::VersionedRecipeList.new - @recipes.each {|i| @list.add_recipe i[:name], i[:version]} - @constraints = @recipes.map do |x| - { :name => x[:name], - :version_constraint => Chef::VersionConstraint.new(x[:version]) - } - end + + let(:versioned_recipes) do + [ + {:name => "apt", :version => "~> 1.2.0"}, + {:name => "god", :version => nil}, + {:name => "apache2", :version => "0.0.1"} + ] end + it "should return an array of hashes with :name and :version_constraint" do - @list.with_version_constraints.each do |x| - expect(x).to have_key :name - expect(x[:version_constraint]).not_to be nil + list.with_version_constraints.each_with_index do |recipe_spec, i| + + expected_recipe = versioned_recipes[i] + + expect(recipe_spec[:name]).to eq(expected_recipe[:name]) + expect(recipe_spec[:version_constraint]).to eq(Chef::VersionConstraint.new(expected_recipe[:version])) end end end + + describe "with_fully_qualified_names_and_version_constraints" do + + let(:fq_names) { list.with_fully_qualified_names_and_version_constraints } + + context "with bare cookbook names" do + + let(:recipes) { %w[ apache2 ] } + + it "gives $cookbook_name::default" do + expect(fq_names).to eq( %w[ apache2::default ] ) + end + + end + + context "with qualified recipe names but no versions" do + + let(:recipes) { %w[ mysql::server ] } + + it "returns the qualified recipe names" do + expect(fq_names).to eq( %w[ mysql::server ] ) + end + + end + + context "with unqualified names that have version constraints" do + + let(:versioned_recipes) do + [ + {:name => "apt", :version => "~> 1.2.0"}, + ] + end + + it "gives qualified names with their versions" do + expect(fq_names).to eq([ "apt::default@~> 1.2.0" ]) + end + + it "does not mutate the recipe name" do + expect(fq_names).to eq([ "apt::default@~> 1.2.0" ]) + expect(list).to eq( [ "apt" ] ) + end + + end + + context "with fully qualified names that have version constraints" do + + let(:versioned_recipes) do + [ + {:name => "apt::cacher", :version => "~> 1.2.0"}, + ] + end + + it "gives qualified names with their versions" do + expect(fq_names).to eq([ "apt::cacher@~> 1.2.0" ]) + end + + it "does not mutate the recipe name" do + expect(fq_names).to eq([ "apt::cacher@~> 1.2.0" ]) + expect(list).to eq( [ "apt::cacher" ] ) + end + + end + end + end diff --git a/spec/unit/user_spec.rb b/spec/unit/user_spec.rb index 5222c951b3..97cc32eb3e 100644 --- a/spec/unit/user_spec.rb +++ b/spec/unit/user_spec.rb @@ -16,6 +16,11 @@ # limitations under the License. # +# DEPRECATION NOTE +# This code only remains to support users still operating with +# Open Source Chef Server 11 and should be removed once support +# for OSC 11 ends. New development should occur in user_spec.rb. + require 'spec_helper' require 'chef/user' @@ -26,141 +31,98 @@ describe Chef::User do @user = Chef::User.new end - shared_examples_for "string fields with no contraints" do - it "should let you set the public key" do - expect(@user.send(method, "some_string")).to eq("some_string") - end - - it "should return the current public key" do - @user.send(method, "some_string") - expect(@user.send(method)).to eq("some_string") - end - - it "should throw an ArgumentError if you feed it something lame" do - expect { @user.send(method, Hash.new) }.to raise_error(ArgumentError) - end - end - - shared_examples_for "boolean fields with no constraints" do - it "should let you set the field" do - expect(@user.send(method, true)).to eq(true) - end - - it "should return the current field value" do - @user.send(method, true) - expect(@user.send(method)).to eq(true) - end - - it "should return the false value when false" do - @user.send(method, false) - expect(@user.send(method)).to eq(false) - end - - it "should throw an ArgumentError if you feed it anything but true or false" do - expect { @user.send(method, Hash.new) }.to raise_error(ArgumentError) - end - end - describe "initialize" do it "should be a Chef::User" do expect(@user).to be_a_kind_of(Chef::User) end end - describe "username" do - it "should let you set the username to a string" do - expect(@user.username("ops_master")).to eq("ops_master") + describe "name" do + it "should let you set the name to a string" do + expect(@user.name("ops_master")).to eq("ops_master") end - it "should return the current username" do - @user.username "ops_master" - expect(@user.username).to eq("ops_master") + it "should return the current name" do + @user.name "ops_master" + expect(@user.name).to eq("ops_master") end # It is not feasible to check all invalid characters. Here are a few # that we probably care about. it "should not accept invalid characters" do # capital letters - expect { @user.username "Bar" }.to raise_error(ArgumentError) + expect { @user.name "Bar" }.to raise_error(ArgumentError) # slashes - expect { @user.username "foo/bar" }.to raise_error(ArgumentError) + expect { @user.name "foo/bar" }.to raise_error(ArgumentError) # ? - expect { @user.username "foo?" }.to raise_error(ArgumentError) + expect { @user.name "foo?" }.to raise_error(ArgumentError) # & - expect { @user.username "foo&" }.to raise_error(ArgumentError) + expect { @user.name "foo&" }.to raise_error(ArgumentError) end it "should not accept spaces" do - expect { @user.username "ops master" }.to raise_error(ArgumentError) + expect { @user.name "ops master" }.to raise_error(ArgumentError) end it "should throw an ArgumentError if you feed it anything but a string" do - expect { @user.username Hash.new }.to raise_error(ArgumentError) + expect { @user.name Hash.new }.to raise_error(ArgumentError) end end - describe "boolean fields" do - describe "create_key" do - it_should_behave_like "boolean fields with no constraints" do - let(:method) { :create_key } - end + describe "admin" do + it "should let you set the admin bit" do + expect(@user.admin(true)).to eq(true) end - end - describe "string fields" do - describe "public_key" do - it_should_behave_like "string fields with no contraints" do - let(:method) { :public_key } - end + it "should return the current admin value" do + @user.admin true + expect(@user.admin).to eq(true) end - describe "private_key" do - it_should_behave_like "string fields with no contraints" do - let(:method) { :private_key } - end + it "should default to false" do + expect(@user.admin).to eq(false) end - describe "display_name" do - it_should_behave_like "string fields with no contraints" do - let(:method) { :display_name } - end + it "should throw an ArgumentError if you feed it anything but true or false" do + expect { @user.name Hash.new }.to raise_error(ArgumentError) end + end - describe "first_name" do - it_should_behave_like "string fields with no contraints" do - let(:method) { :first_name } - end + describe "public_key" do + it "should let you set the public key" do + expect(@user.public_key("super public")).to eq("super public") end - describe "middle_name" do - it_should_behave_like "string fields with no contraints" do - let(:method) { :middle_name } - end + it "should return the current public key" do + @user.public_key("super public") + expect(@user.public_key).to eq("super public") end - describe "last_name" do - it_should_behave_like "string fields with no contraints" do - let(:method) { :last_name } - end + it "should throw an ArgumentError if you feed it something lame" do + expect { @user.public_key Hash.new }.to raise_error(ArgumentError) end + end - describe "email" do - it_should_behave_like "string fields with no contraints" do - let(:method) { :email } - end + describe "private_key" do + it "should let you set the private key" do + expect(@user.private_key("super private")).to eq("super private") end - describe "password" do - it_should_behave_like "string fields with no contraints" do - let(:method) { :password } - end + it "should return the private key" do + @user.private_key("super private") + expect(@user.private_key).to eq("super private") + end + + it "should throw an ArgumentError if you feed it something lame" do + expect { @user.private_key Hash.new }.to raise_error(ArgumentError) end end describe "when serializing to JSON" do before(:each) do - @user.username("black") + @user.name("black") + @user.public_key("crowes") @json = @user.to_json end @@ -168,62 +130,16 @@ describe Chef::User do expect(@json).to match(/^\{.+\}$/) end - it "includes the username value" do - expect(@json).to include(%q{"username":"black"}) - end - - it "includes the display name when present" do - @user.display_name("get_displayed") - expect(@user.to_json).to include(%{"display_name":"get_displayed"}) - end - - it "does not include the display name if not present" do - expect(@json).not_to include("display_name") - end - - it "includes the first name when present" do - @user.first_name("char") - expect(@user.to_json).to include(%{"first_name":"char"}) - end - - it "does not include the first name if not present" do - expect(@json).not_to include("first_name") - end - - it "includes the middle name when present" do - @user.middle_name("man") - expect(@user.to_json).to include(%{"middle_name":"man"}) - end - - it "does not include the middle name if not present" do - expect(@json).not_to include("middle_name") - end - - it "includes the last name when present" do - @user.last_name("der") - expect(@user.to_json).to include(%{"last_name":"der"}) - end - - it "does not include the last name if not present" do - expect(@json).not_to include("last_name") - end - - it "includes the email when present" do - @user.email("charmander@pokemon.poke") - expect(@user.to_json).to include(%{"email":"charmander@pokemon.poke"}) - end - - it "does not include the email if not present" do - expect(@json).not_to include("email") + it "includes the name value" do + expect(@json).to include(%q{"name":"black"}) end - it "includes the public key when present" do - @user.public_key("crowes") - expect(@user.to_json).to include(%{"public_key":"crowes"}) + it "includes the public key value" do + expect(@json).to include(%{"public_key":"crowes"}) end - it "does not include the public key if not present" do - expect(@json).not_to include("public_key") + it "includes the 'admin' flag" do + expect(@json).to include(%q{"admin":false}) end it "includes the private key when present" do @@ -251,18 +167,11 @@ describe Chef::User do describe "when deserializing from JSON" do before(:each) do - user = { - "username" => "mr_spinks", - "display_name" => "displayed", - "first_name" => "char", - "middle_name" => "man", - "last_name" => "der", - "email" => "charmander@pokemon.poke", - "password" => "password", + user = { "name" => "mr_spinks", "public_key" => "turtles", "private_key" => "pandas", - "create_key" => false - } + "password" => "password", + "admin" => true } @user = Chef::User.from_json(Chef::JSONCompat.to_json(user)) end @@ -270,277 +179,34 @@ describe Chef::User do expect(@user).to be_a_kind_of(Chef::User) end - it "preserves the username" do - expect(@user.username).to eq("mr_spinks") - end - - it "preserves the display name if present" do - expect(@user.display_name).to eq("displayed") + it "preserves the name" do + expect(@user.name).to eq("mr_spinks") end - it "preserves the first name if present" do - expect(@user.first_name).to eq("char") - end - - it "preserves the middle name if present" do - expect(@user.middle_name).to eq("man") + it "preserves the public key" do + expect(@user.public_key).to eq("turtles") end - it "preserves the last name if present" do - expect(@user.last_name).to eq("der") + it "preserves the admin status" do + expect(@user.admin).to be_truthy end - it "preserves the email if present" do - expect(@user.email).to eq("charmander@pokemon.poke") + it "includes the private key if present" do + expect(@user.private_key).to eq("pandas") end it "includes the password if present" do expect(@user.password).to eq("password") end - it "preserves the public key if present" do - expect(@user.public_key).to eq("turtles") - end - - it "includes the private key if present" do - expect(@user.private_key).to eq("pandas") - end - - it "includes the create key status if not nil" do - expect(@user.create_key).to be_falsey - end end - describe "Versioned API Interactions" do - let(:response_406) { OpenStruct.new(:code => '406') } - let(:exception_406) { Net::HTTPServerException.new("406 Not Acceptable", response_406) } - - before (:each) do - @user = Chef::User.new - allow(@user).to receive(:chef_root_rest_v0).and_return(double('chef rest root v0 object')) - allow(@user).to receive(:chef_root_rest_v1).and_return(double('chef rest root v1 object')) - end - - describe "update" do - before do - # populate all fields that are valid between V0 and V1 - @user.username "some_username" - @user.display_name "some_display_name" - @user.first_name "some_first_name" - @user.middle_name "some_middle_name" - @user.last_name "some_last_name" - @user.email "some_email" - @user.password "some_password" - end - - let(:payload) { - { - :username => "some_username", - :display_name => "some_display_name", - :first_name => "some_first_name", - :middle_name => "some_middle_name", - :last_name => "some_last_name", - :email => "some_email", - :password => "some_password" - } - } - - context "when server API V1 is valid on the Chef Server receiving the request" do - context "when the user submits valid data" do - it "properly updates the user" do - expect(@user.chef_root_rest_v1).to receive(:put).with("users/some_username", payload).and_return({}) - @user.update - end - end - end - - context "when server API V1 is not valid on the Chef Server receiving the request" do - let(:payload) { - { - :username => "some_username", - :display_name => "some_display_name", - :first_name => "some_first_name", - :middle_name => "some_middle_name", - :last_name => "some_last_name", - :email => "some_email", - :password => "some_password", - :public_key => "some_public_key" - } - } - - before do - @user.public_key "some_public_key" - allow(@user.chef_root_rest_v1).to receive(:put) - end - - context "when the server returns a 400" do - let(:response_400) { OpenStruct.new(:code => '400') } - let(:exception_400) { Net::HTTPServerException.new("400 Bad Request", response_400) } - - context "when the 400 was due to public / private key fields no longer being supported" do - let(:response_body_400) { '{"error":["Since Server API v1, all keys must be updated via the keys endpoint. "]}' } - - before do - allow(response_400).to receive(:body).and_return(response_body_400) - allow(@user.chef_root_rest_v1).to receive(:put).and_raise(exception_400) - end - - it "proceeds with the V0 PUT since it can handle public / private key fields" do - expect(@user.chef_root_rest_v0).to receive(:put).with("users/some_username", payload).and_return({}) - @user.update - end - - it "does not call server_client_api_version_intersection, since we know to proceed with V0 in this case" do - expect(@user).to_not receive(:server_client_api_version_intersection) - allow(@user.chef_root_rest_v0).to receive(:put).and_return({}) - @user.update - end - end # when the 400 was due to public / private key fields - - context "when the 400 was NOT due to public / private key fields no longer being supported" do - let(:response_body_400) { '{"error":["Some other error. "]}' } - - before do - allow(response_400).to receive(:body).and_return(response_body_400) - allow(@user.chef_root_rest_v1).to receive(:put).and_raise(exception_400) - end - - it "will not proceed with the V0 PUT since the original bad request was not key related" do - expect(@user.chef_root_rest_v0).to_not receive(:put).with("users/some_username", payload) - expect { @user.update }.to raise_error(exception_400) - end - - it "raises the original error" do - expect { @user.update }.to raise_error(exception_400) - end - - end - end # when the server returns a 400 - - context "when the server returns a 406" do - # from spec/support/shared/unit/api_versioning.rb - it_should_behave_like "version handling" do - let(:object) { @user } - let(:method) { :update } - let(:http_verb) { :put } - let(:rest_v1) { @user.chef_root_rest_v1 } - end - - context "when the server supports API V0" do - before do - allow(@user).to receive(:server_client_api_version_intersection).and_return([0]) - allow(@user.chef_root_rest_v1).to receive(:put).and_raise(exception_406) - end - - it "properly updates the user" do - expect(@user.chef_root_rest_v0).to receive(:put).with("users/some_username", payload).and_return({}) - @user.update - end - end # when the server supports API V0 - end # when the server returns a 406 - - end # when server API V1 is not valid on the Chef Server receiving the request - end # update - - describe "create" do - let(:payload) { - { - :username => "some_username", - :display_name => "some_display_name", - :first_name => "some_first_name", - :last_name => "some_last_name", - :email => "some_email", - :password => "some_password" - } - } - before do - @user.username "some_username" - @user.display_name "some_display_name" - @user.first_name "some_first_name" - @user.last_name "some_last_name" - @user.email "some_email" - @user.password "some_password" - end - - # from spec/support/shared/unit/user_and_client_shared.rb - it_should_behave_like "user or client create" do - let(:object) { @user } - let(:error) { Chef::Exceptions::InvalidUserAttribute } - let(:rest_v0) { @user.chef_root_rest_v0 } - let(:rest_v1) { @user.chef_root_rest_v1 } - let(:url) { "users" } - end - - context "when handling API V1" do - it "creates a new user via the API with a middle_name when it exists" do - @user.middle_name "some_middle_name" - expect(@user.chef_root_rest_v1).to receive(:post).with("users", payload.merge({:middle_name => "some_middle_name"})).and_return({}) - @user.create - end - end # when server API V1 is valid on the Chef Server receiving the request - - context "when API V1 is not supported by the server" do - # from spec/support/shared/unit/api_versioning.rb - it_should_behave_like "version handling" do - let(:object) { @user } - let(:method) { :create } - let(:http_verb) { :post } - let(:rest_v1) { @user.chef_root_rest_v1 } - end - end - - context "when handling API V0" do - before do - allow(@user).to receive(:server_client_api_version_intersection).and_return([0]) - allow(@user.chef_root_rest_v1).to receive(:post).and_raise(exception_406) - end - - it "creates a new user via the API with a middle_name when it exists" do - @user.middle_name "some_middle_name" - expect(@user.chef_root_rest_v0).to receive(:post).with("users", payload.merge({:middle_name => "some_middle_name"})).and_return({}) - @user.create - end - end # when server API V1 is not valid on the Chef Server receiving the request - - end # create - - # DEPRECATION - # This can be removed after API V0 support is gone - describe "reregister" do - let(:payload) { - { - "username" => "some_username", - } - } - - before do - @user.username "some_username" - end - - context "when server API V0 is valid on the Chef Server receiving the request" do - it "creates a new object via the API" do - expect(@user.chef_root_rest_v0).to receive(:put).with("users/#{@user.username}", payload.merge({"private_key" => true})).and_return({}) - @user.reregister - end - end # when server API V0 is valid on the Chef Server receiving the request - - context "when server API V0 is not supported by the Chef Server" do - # from spec/support/shared/unit/api_versioning.rb - it_should_behave_like "user and client reregister" do - let(:object) { @user } - let(:rest_v0) { @user.chef_root_rest_v0 } - end - end # when server API V0 is not supported by the Chef Server - end # reregister - - end # Versioned API Interactions - describe "API Interactions" do before (:each) do @user = Chef::User.new - @user.username "foobar" - @http_client = double("Chef::REST mock") - allow(Chef::REST).to receive(:new).and_return(@http_client) + @user.name "foobar" + @http_client = double("Chef::ServerAPI mock") + allow(Chef::ServerAPI).to receive(:new).and_return(@http_client) end describe "list" do @@ -552,6 +218,16 @@ describe Chef::User do @osc_inflated_response = { "admin" => @user } end + it "lists all clients on an OSC server" do + allow(@http_client).to receive(:get).with("users").and_return(@osc_response) + expect(Chef::User.list).to eq(@osc_response) + end + + it "inflate all clients on an OSC server" do + allow(@http_client).to receive(:get).with("users").and_return(@osc_response) + expect(Chef::User.list(true)).to eq(@osc_inflated_response) + end + it "lists all clients on an OHC/OPC server" do allow(@http_client).to receive(:get).with("users").and_return(@ohc_response) # We expect that Chef::User.list will give a consistent response @@ -565,15 +241,31 @@ describe Chef::User do end end + describe "create" do + it "creates a new user via the API" do + @user.password "password" + expect(@http_client).to receive(:post).with("users", {:name => "foobar", :admin => false, :password => "password"}).and_return({}) + @user.create + end + end + describe "read" do it "loads a named user from the API" do - expect(@http_client).to receive(:get).with("users/foobar").and_return({"username" => "foobar", "admin" => true, "public_key" => "pubkey"}) + expect(@http_client).to receive(:get).with("users/foobar").and_return({"name" => "foobar", "admin" => true, "public_key" => "pubkey"}) user = Chef::User.load("foobar") - expect(user.username).to eq("foobar") + expect(user.name).to eq("foobar") + expect(user.admin).to eq(true) expect(user.public_key).to eq("pubkey") end end + describe "update" do + it "updates an existing user on via the API" do + expect(@http_client).to receive(:put).with("users/foobar", {:name => "foobar", :admin => false}).and_return({}) + @user.update + end + end + describe "destroy" do it "deletes the specified user via the API" do expect(@http_client).to receive(:delete).with("users/foobar") diff --git a/spec/unit/user_v1_spec.rb b/spec/unit/user_v1_spec.rb new file mode 100644 index 0000000000..8fd370a010 --- /dev/null +++ b/spec/unit/user_v1_spec.rb @@ -0,0 +1,584 @@ +# +# Author:: Steven Danna (steve@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 'chef/user_v1' +require 'tempfile' + +describe Chef::UserV1 do + before(:each) do + @user = Chef::UserV1.new + end + + shared_examples_for "string fields with no contraints" do + it "should let you set the public key" do + expect(@user.send(method, "some_string")).to eq("some_string") + end + + it "should return the current public key" do + @user.send(method, "some_string") + expect(@user.send(method)).to eq("some_string") + end + + it "should throw an ArgumentError if you feed it something lame" do + expect { @user.send(method, Hash.new) }.to raise_error(ArgumentError) + end + end + + shared_examples_for "boolean fields with no constraints" do + it "should let you set the field" do + expect(@user.send(method, true)).to eq(true) + end + + it "should return the current field value" do + @user.send(method, true) + expect(@user.send(method)).to eq(true) + end + + it "should return the false value when false" do + @user.send(method, false) + expect(@user.send(method)).to eq(false) + end + + it "should throw an ArgumentError if you feed it anything but true or false" do + expect { @user.send(method, Hash.new) }.to raise_error(ArgumentError) + end + end + + describe "initialize" do + it "should be a Chef::UserV1" do + expect(@user).to be_a_kind_of(Chef::UserV1) + end + end + + describe "username" do + it "should let you set the username to a string" do + expect(@user.username("ops_master")).to eq("ops_master") + end + + it "should return the current username" do + @user.username "ops_master" + expect(@user.username).to eq("ops_master") + end + + # It is not feasible to check all invalid characters. Here are a few + # that we probably care about. + it "should not accept invalid characters" do + # capital letters + expect { @user.username "Bar" }.to raise_error(ArgumentError) + # slashes + expect { @user.username "foo/bar" }.to raise_error(ArgumentError) + # ? + expect { @user.username "foo?" }.to raise_error(ArgumentError) + # & + expect { @user.username "foo&" }.to raise_error(ArgumentError) + end + + + it "should not accept spaces" do + expect { @user.username "ops master" }.to raise_error(ArgumentError) + end + + it "should throw an ArgumentError if you feed it anything but a string" do + expect { @user.username Hash.new }.to raise_error(ArgumentError) + end + end + + describe "boolean fields" do + describe "create_key" do + it_should_behave_like "boolean fields with no constraints" do + let(:method) { :create_key } + end + end + end + + describe "string fields" do + describe "public_key" do + it_should_behave_like "string fields with no contraints" do + let(:method) { :public_key } + end + end + + describe "private_key" do + it_should_behave_like "string fields with no contraints" do + let(:method) { :private_key } + end + end + + describe "display_name" do + it_should_behave_like "string fields with no contraints" do + let(:method) { :display_name } + end + end + + describe "first_name" do + it_should_behave_like "string fields with no contraints" do + let(:method) { :first_name } + end + end + + describe "middle_name" do + it_should_behave_like "string fields with no contraints" do + let(:method) { :middle_name } + end + end + + describe "last_name" do + it_should_behave_like "string fields with no contraints" do + let(:method) { :last_name } + end + end + + describe "email" do + it_should_behave_like "string fields with no contraints" do + let(:method) { :email } + end + end + + describe "password" do + it_should_behave_like "string fields with no contraints" do + let(:method) { :password } + end + end + end + + describe "when serializing to JSON" do + before(:each) do + @user.username("black") + @json = @user.to_json + end + + it "serializes as a JSON object" do + expect(@json).to match(/^\{.+\}$/) + end + + it "includes the username value" do + expect(@json).to include(%q{"username":"black"}) + end + + it "includes the display name when present" do + @user.display_name("get_displayed") + expect(@user.to_json).to include(%{"display_name":"get_displayed"}) + end + + it "does not include the display name if not present" do + expect(@json).not_to include("display_name") + end + + it "includes the first name when present" do + @user.first_name("char") + expect(@user.to_json).to include(%{"first_name":"char"}) + end + + it "does not include the first name if not present" do + expect(@json).not_to include("first_name") + end + + it "includes the middle name when present" do + @user.middle_name("man") + expect(@user.to_json).to include(%{"middle_name":"man"}) + end + + it "does not include the middle name if not present" do + expect(@json).not_to include("middle_name") + end + + it "includes the last name when present" do + @user.last_name("der") + expect(@user.to_json).to include(%{"last_name":"der"}) + end + + it "does not include the last name if not present" do + expect(@json).not_to include("last_name") + end + + it "includes the email when present" do + @user.email("charmander@pokemon.poke") + expect(@user.to_json).to include(%{"email":"charmander@pokemon.poke"}) + end + + it "does not include the email if not present" do + expect(@json).not_to include("email") + end + + it "includes the public key when present" do + @user.public_key("crowes") + expect(@user.to_json).to include(%{"public_key":"crowes"}) + end + + it "does not include the public key if not present" do + expect(@json).not_to include("public_key") + end + + it "includes the private key when present" do + @user.private_key("monkeypants") + expect(@user.to_json).to include(%q{"private_key":"monkeypants"}) + end + + it "does not include the private key if not present" do + expect(@json).not_to include("private_key") + end + + it "includes the password if present" do + @user.password "password" + expect(@user.to_json).to include(%q{"password":"password"}) + end + + it "does not include the password if not present" do + expect(@json).not_to include("password") + end + + include_examples "to_json equivalent to Chef::JSONCompat.to_json" do + let(:jsonable) { @user } + end + end + + describe "when deserializing from JSON" do + before(:each) do + user = { + "username" => "mr_spinks", + "display_name" => "displayed", + "first_name" => "char", + "middle_name" => "man", + "last_name" => "der", + "email" => "charmander@pokemon.poke", + "password" => "password", + "public_key" => "turtles", + "private_key" => "pandas", + "create_key" => false + } + @user = Chef::UserV1.from_json(Chef::JSONCompat.to_json(user)) + end + + it "should deserialize to a Chef::UserV1 object" do + expect(@user).to be_a_kind_of(Chef::UserV1) + end + + it "preserves the username" do + expect(@user.username).to eq("mr_spinks") + end + + it "preserves the display name if present" do + expect(@user.display_name).to eq("displayed") + end + + it "preserves the first name if present" do + expect(@user.first_name).to eq("char") + end + + it "preserves the middle name if present" do + expect(@user.middle_name).to eq("man") + end + + it "preserves the last name if present" do + expect(@user.last_name).to eq("der") + end + + it "preserves the email if present" do + expect(@user.email).to eq("charmander@pokemon.poke") + end + + it "includes the password if present" do + expect(@user.password).to eq("password") + end + + it "preserves the public key if present" do + expect(@user.public_key).to eq("turtles") + end + + it "includes the private key if present" do + expect(@user.private_key).to eq("pandas") + end + + it "includes the create key status if not nil" do + expect(@user.create_key).to be_falsey + end + end + + describe "Versioned API Interactions" do + let(:response_406) { OpenStruct.new(:code => '406') } + let(:exception_406) { Net::HTTPServerException.new("406 Not Acceptable", response_406) } + + before (:each) do + @user = Chef::UserV1.new + allow(@user).to receive(:chef_root_rest_v0).and_return(double('chef rest root v0 object')) + allow(@user).to receive(:chef_root_rest_v1).and_return(double('chef rest root v1 object')) + end + + describe "update" do + before do + # populate all fields that are valid between V0 and V1 + @user.username "some_username" + @user.display_name "some_display_name" + @user.first_name "some_first_name" + @user.middle_name "some_middle_name" + @user.last_name "some_last_name" + @user.email "some_email" + @user.password "some_password" + end + + let(:payload) { + { + :username => "some_username", + :display_name => "some_display_name", + :first_name => "some_first_name", + :middle_name => "some_middle_name", + :last_name => "some_last_name", + :email => "some_email", + :password => "some_password" + } + } + + context "when server API V1 is valid on the Chef Server receiving the request" do + context "when the user submits valid data" do + it "properly updates the user" do + expect(@user.chef_root_rest_v1).to receive(:put).with("users/some_username", payload).and_return({}) + @user.update + end + end + end + + context "when server API V1 is not valid on the Chef Server receiving the request" do + let(:payload) { + { + :username => "some_username", + :display_name => "some_display_name", + :first_name => "some_first_name", + :middle_name => "some_middle_name", + :last_name => "some_last_name", + :email => "some_email", + :password => "some_password", + :public_key => "some_public_key" + } + } + + before do + @user.public_key "some_public_key" + allow(@user.chef_root_rest_v1).to receive(:put) + end + + context "when the server returns a 400" do + let(:response_400) { OpenStruct.new(:code => '400') } + let(:exception_400) { Net::HTTPServerException.new("400 Bad Request", response_400) } + + context "when the 400 was due to public / private key fields no longer being supported" do + let(:response_body_400) { '{"error":["Since Server API v1, all keys must be updated via the keys endpoint. "]}' } + + before do + allow(response_400).to receive(:body).and_return(response_body_400) + allow(@user.chef_root_rest_v1).to receive(:put).and_raise(exception_400) + end + + it "proceeds with the V0 PUT since it can handle public / private key fields" do + expect(@user.chef_root_rest_v0).to receive(:put).with("users/some_username", payload).and_return({}) + @user.update + end + + it "does not call server_client_api_version_intersection, since we know to proceed with V0 in this case" do + expect(@user).to_not receive(:server_client_api_version_intersection) + allow(@user.chef_root_rest_v0).to receive(:put).and_return({}) + @user.update + end + end # when the 400 was due to public / private key fields + + context "when the 400 was NOT due to public / private key fields no longer being supported" do + let(:response_body_400) { '{"error":["Some other error. "]}' } + + before do + allow(response_400).to receive(:body).and_return(response_body_400) + allow(@user.chef_root_rest_v1).to receive(:put).and_raise(exception_400) + end + + it "will not proceed with the V0 PUT since the original bad request was not key related" do + expect(@user.chef_root_rest_v0).to_not receive(:put).with("users/some_username", payload) + expect { @user.update }.to raise_error(exception_400) + end + + it "raises the original error" do + expect { @user.update }.to raise_error(exception_400) + end + + end + end # when the server returns a 400 + + context "when the server returns a 406" do + # from spec/support/shared/unit/api_versioning.rb + it_should_behave_like "version handling" do + let(:object) { @user } + let(:method) { :update } + let(:http_verb) { :put } + let(:rest_v1) { @user.chef_root_rest_v1 } + end + + context "when the server supports API V0" do + before do + allow(@user).to receive(:server_client_api_version_intersection).and_return([0]) + allow(@user.chef_root_rest_v1).to receive(:put).and_raise(exception_406) + end + + it "properly updates the user" do + expect(@user.chef_root_rest_v0).to receive(:put).with("users/some_username", payload).and_return({}) + @user.update + end + end # when the server supports API V0 + end # when the server returns a 406 + + end # when server API V1 is not valid on the Chef Server receiving the request + end # update + + describe "create" do + let(:payload) { + { + :username => "some_username", + :display_name => "some_display_name", + :first_name => "some_first_name", + :last_name => "some_last_name", + :email => "some_email", + :password => "some_password" + } + } + before do + @user.username "some_username" + @user.display_name "some_display_name" + @user.first_name "some_first_name" + @user.last_name "some_last_name" + @user.email "some_email" + @user.password "some_password" + end + + # from spec/support/shared/unit/user_and_client_shared.rb + it_should_behave_like "user or client create" do + let(:object) { @user } + let(:error) { Chef::Exceptions::InvalidUserAttribute } + let(:rest_v0) { @user.chef_root_rest_v0 } + let(:rest_v1) { @user.chef_root_rest_v1 } + let(:url) { "users" } + end + + context "when handling API V1" do + it "creates a new user via the API with a middle_name when it exists" do + @user.middle_name "some_middle_name" + expect(@user.chef_root_rest_v1).to receive(:post).with("users", payload.merge({:middle_name => "some_middle_name"})).and_return({}) + @user.create + end + end # when server API V1 is valid on the Chef Server receiving the request + + context "when API V1 is not supported by the server" do + # from spec/support/shared/unit/api_versioning.rb + it_should_behave_like "version handling" do + let(:object) { @user } + let(:method) { :create } + let(:http_verb) { :post } + let(:rest_v1) { @user.chef_root_rest_v1 } + end + end + + context "when handling API V0" do + before do + allow(@user).to receive(:server_client_api_version_intersection).and_return([0]) + allow(@user.chef_root_rest_v1).to receive(:post).and_raise(exception_406) + end + + it "creates a new user via the API with a middle_name when it exists" do + @user.middle_name "some_middle_name" + expect(@user.chef_root_rest_v0).to receive(:post).with("users", payload.merge({:middle_name => "some_middle_name"})).and_return({}) + @user.create + end + end # when server API V1 is not valid on the Chef Server receiving the request + + end # create + + # DEPRECATION + # This can be removed after API V0 support is gone + describe "reregister" do + let(:payload) { + { + "username" => "some_username", + } + } + + before do + @user.username "some_username" + end + + context "when server API V0 is valid on the Chef Server receiving the request" do + it "creates a new object via the API" do + expect(@user.chef_root_rest_v0).to receive(:put).with("users/#{@user.username}", payload.merge({"private_key" => true})).and_return({}) + @user.reregister + end + end # when server API V0 is valid on the Chef Server receiving the request + + context "when server API V0 is not supported by the Chef Server" do + # from spec/support/shared/unit/api_versioning.rb + it_should_behave_like "user and client reregister" do + let(:object) { @user } + let(:rest_v0) { @user.chef_root_rest_v0 } + end + end # when server API V0 is not supported by the Chef Server + end # reregister + + end # Versioned API Interactions + + describe "API Interactions" do + before (:each) do + @user = Chef::UserV1.new + @user.username "foobar" + @http_client = double("Chef::REST mock") + allow(Chef::REST).to receive(:new).and_return(@http_client) + end + + describe "list" do + before(:each) do + Chef::Config[:chef_server_url] = "http://www.example.com" + @osc_response = { "admin" => "http://www.example.com/users/admin"} + @ohc_response = [ { "user" => { "username" => "admin" }} ] + allow(Chef::UserV1).to receive(:load).with("admin").and_return(@user) + @osc_inflated_response = { "admin" => @user } + end + + it "lists all clients on an OHC/OPC server" do + allow(@http_client).to receive(:get).with("users").and_return(@ohc_response) + # We expect that Chef::UserV1.list will give a consistent response + # so OHC API responses should be transformed to OSC-style output. + expect(Chef::UserV1.list).to eq(@osc_response) + end + + it "inflate all clients on an OHC/OPC server" do + allow(@http_client).to receive(:get).with("users").and_return(@ohc_response) + expect(Chef::UserV1.list(true)).to eq(@osc_inflated_response) + end + end + + describe "read" do + it "loads a named user from the API" do + expect(@http_client).to receive(:get).with("users/foobar").and_return({"username" => "foobar", "admin" => true, "public_key" => "pubkey"}) + user = Chef::UserV1.load("foobar") + expect(user.username).to eq("foobar") + expect(user.public_key).to eq("pubkey") + end + end + + describe "destroy" do + it "deletes the specified user via the API" do + expect(@http_client).to receive(:delete).with("users/foobar") + @user.destroy + end + end + end +end |