summaryrefslogtreecommitdiff
path: root/spec/unit
diff options
context:
space:
mode:
Diffstat (limited to 'spec/unit')
-rw-r--r--spec/unit/api_client_spec.rb203
-rw-r--r--spec/unit/application/client_spec.rb9
-rw-r--r--spec/unit/audit/audit_reporter_spec.rb72
-rw-r--r--spec/unit/audit/logger_spec.rb42
-rw-r--r--spec/unit/audit/runner_spec.rb4
-rw-r--r--spec/unit/chef_fs/file_pattern_spec.rb18
-rw-r--r--spec/unit/client_spec.rb453
-rw-r--r--spec/unit/config_spec.rb544
-rw-r--r--spec/unit/cookbook/cookbook_version_loader_spec.rb2
-rw-r--r--spec/unit/cookbook/metadata_spec.rb15
-rw-r--r--spec/unit/cookbook/syntax_check_spec.rb2
-rw-r--r--spec/unit/cookbook_loader_spec.rb2
-rw-r--r--spec/unit/cookbook_site_streaming_uploader_spec.rb21
-rw-r--r--spec/unit/cookbook_spec.rb9
-rw-r--r--spec/unit/cookbook_version_spec.rb20
-rw-r--r--spec/unit/data_bag_spec.rb2
-rw-r--r--spec/unit/deprecation_spec.rb55
-rw-r--r--spec/unit/dsl/resources_spec.rb85
-rw-r--r--spec/unit/event_dispatch/dispatcher_spec.rb61
-rw-r--r--spec/unit/exceptions_spec.rb4
-rw-r--r--spec/unit/file_content_management/deploy/mv_windows_spec.rb60
-rw-r--r--spec/unit/formatters/doc_spec.rb46
-rw-r--r--spec/unit/formatters/error_inspectors/api_error_formatting_spec.rb77
-rw-r--r--spec/unit/formatters/error_inspectors/compile_error_inspector_spec.rb261
-rw-r--r--spec/unit/formatters/error_inspectors/resource_failure_inspector_spec.rb7
-rw-r--r--spec/unit/guard_interpreter/resource_guard_interpreter_spec.rb10
-rw-r--r--spec/unit/http/authenticator_spec.rb78
-rw-r--r--spec/unit/http/basic_client_spec.rb16
-rw-r--r--spec/unit/json_compat_spec.rb12
-rw-r--r--spec/unit/key_spec.rb634
-rw-r--r--spec/unit/knife/bootstrap_spec.rb15
-rw-r--r--spec/unit/knife/client_create_spec.rb173
-rw-r--r--spec/unit/knife/core/subcommand_loader_spec.rb24
-rw-r--r--spec/unit/knife/core/ui_spec.rb16
-rw-r--r--spec/unit/knife/data_bag_from_file_spec.rb2
-rw-r--r--spec/unit/knife/environment_from_file_spec.rb2
-rw-r--r--spec/unit/knife/key_create_spec.rb224
-rw-r--r--spec/unit/knife/key_delete_spec.rb135
-rw-r--r--spec/unit/knife/key_edit_spec.rb267
-rw-r--r--spec/unit/knife/key_helper.rb74
-rw-r--r--spec/unit/knife/key_list_spec.rb216
-rw-r--r--spec/unit/knife/key_show_spec.rb126
-rw-r--r--spec/unit/knife/osc_user_create_spec.rb93
-rw-r--r--spec/unit/knife/osc_user_delete_spec.rb44
-rw-r--r--spec/unit/knife/osc_user_edit_spec.rb52
-rw-r--r--spec/unit/knife/osc_user_list_spec.rb37
-rw-r--r--spec/unit/knife/osc_user_reregister_spec.rb58
-rw-r--r--spec/unit/knife/osc_user_show_spec.rb46
-rw-r--r--spec/unit/knife/ssh_spec.rb49
-rw-r--r--spec/unit/knife/user_create_spec.rb228
-rw-r--r--spec/unit/knife/user_delete_spec.rb42
-rw-r--r--spec/unit/knife/user_edit_spec.rb43
-rw-r--r--spec/unit/knife/user_list_spec.rb10
-rw-r--r--spec/unit/knife/user_reregister_spec.rb55
-rw-r--r--spec/unit/knife/user_show_spec.rb46
-rw-r--r--spec/unit/knife_spec.rb40
-rw-r--r--spec/unit/log/syslog_spec.rb53
-rw-r--r--spec/unit/log/winevt_spec.rb55
-rw-r--r--spec/unit/lwrp_spec.rb400
-rw-r--r--spec/unit/mixin/api_version_request_handling_spec.rb127
-rw-r--r--spec/unit/mixin/command_spec.rb3
-rw-r--r--spec/unit/mixin/path_sanity_spec.rb4
-rw-r--r--spec/unit/mixin/powershell_out_spec.rb70
-rw-r--r--spec/unit/mixin/template_spec.rb4
-rw-r--r--spec/unit/mixin/unformatter_spec.rb61
-rw-r--r--spec/unit/mixin/uris_spec.rb57
-rw-r--r--spec/unit/node_map_spec.rb5
-rw-r--r--spec/unit/osc_user_spec.rb276
-rw-r--r--spec/unit/platform/query_helpers_spec.rb2
-rw-r--r--spec/unit/platform_spec.rb60
-rw-r--r--spec/unit/policy_builder/policyfile_spec.rb10
-rw-r--r--spec/unit/provider/deploy/revision_spec.rb2
-rw-r--r--spec/unit/provider/deploy_spec.rb4
-rw-r--r--spec/unit/provider/directory_spec.rb334
-rw-r--r--spec/unit/provider/execute_spec.rb2
-rw-r--r--spec/unit/provider/ifconfig/debian_spec.rb10
-rw-r--r--spec/unit/provider/package/aix_spec.rb44
-rw-r--r--spec/unit/provider/package/dpkg_spec.rb4
-rw-r--r--spec/unit/provider/package/freebsd/pkg_spec.rb26
-rw-r--r--spec/unit/provider/package/freebsd/pkgng_spec.rb18
-rw-r--r--spec/unit/provider/package/freebsd/port_spec.rb14
-rw-r--r--spec/unit/provider/package/ips_spec.rb44
-rw-r--r--spec/unit/provider/package/macports_spec.rb20
-rw-r--r--spec/unit/provider/package/openbsd_spec.rb30
-rw-r--r--spec/unit/provider/package/pacman_spec.rb10
-rw-r--r--spec/unit/provider/package/rpm_spec.rb459
-rw-r--r--spec/unit/provider/package/rubygems_spec.rb54
-rw-r--r--spec/unit/provider/package/smartos_spec.rb90
-rw-r--r--spec/unit/provider/package/solaris_spec.rb22
-rw-r--r--spec/unit/provider/package/windows_spec.rb129
-rw-r--r--spec/unit/provider/package/yum_spec.rb112
-rw-r--r--spec/unit/provider/package/zypper_spec.rb215
-rw-r--r--spec/unit/provider/package_spec.rb40
-rw-r--r--spec/unit/provider/powershell_spec.rb64
-rw-r--r--spec/unit/provider/remote_directory_spec.rb4
-rw-r--r--spec/unit/provider/remote_file/fetcher_spec.rb21
-rw-r--r--spec/unit/provider/remote_file/local_file_spec.rb31
-rw-r--r--spec/unit/provider/remote_file/network_file_spec.rb45
-rw-r--r--spec/unit/provider/service/aix_service_spec.rb37
-rw-r--r--spec/unit/provider/service/freebsd_service_spec.rb12
-rw-r--r--spec/unit/provider/user/dscl_spec.rb2
-rw-r--r--spec/unit/provider/user_spec.rb6
-rw-r--r--spec/unit/provider_resolver_spec.rb794
-rw-r--r--spec/unit/provider_spec.rb20
-rw-r--r--spec/unit/recipe_spec.rb59
-rw-r--r--spec/unit/resource/batch_spec.rb1
-rw-r--r--spec/unit/resource/breakpoint_spec.rb2
-rw-r--r--spec/unit/resource/erl_call_spec.rb2
-rw-r--r--spec/unit/resource/file_spec.rb2
-rw-r--r--spec/unit/resource/ifconfig_spec.rb16
-rw-r--r--spec/unit/resource/powershell_spec.rb1
-rw-r--r--spec/unit/resource/remote_file_spec.rb15
-rw-r--r--spec/unit/resource/route_spec.rb2
-rw-r--r--spec/unit/resource/ruby_block_spec.rb4
-rw-r--r--spec/unit/resource/template_spec.rb2
-rw-r--r--spec/unit/resource/timestamped_deploy_spec.rb3
-rw-r--r--spec/unit/resource/windows_package_spec.rb18
-rw-r--r--spec/unit/resource/windows_service_spec.rb2
-rw-r--r--spec/unit/resource_spec.rb174
-rw-r--r--spec/unit/rest_spec.rb30
-rw-r--r--spec/unit/role_spec.rb2
-rw-r--r--spec/unit/run_context_spec.rb72
-rw-r--r--spec/unit/runner_spec.rb4
-rw-r--r--spec/unit/shell_spec.rb8
-rw-r--r--spec/unit/user_spec.rb499
-rw-r--r--spec/unit/util/path_helper_spec.rb255
126 files changed, 7115 insertions, 2905 deletions
diff --git a/spec/unit/api_client_spec.rb b/spec/unit/api_client_spec.rb
index 7668e31f5a..ba0eca3284 100644
--- a/spec/unit/api_client_spec.rb
+++ b/spec/unit/api_client_spec.rb
@@ -53,6 +53,20 @@ 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
@@ -115,6 +129,12 @@ 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"})
@@ -131,7 +151,7 @@ describe Chef::ApiClient do
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}"
+ "{\"name\":\"black\",\"public_key\":\"crowes\",\"private_key\":\"monkeypants\",\"admin\":true,\"validator\":true,\"create_key\":true}"
end
let(:client) do
@@ -158,6 +178,10 @@ 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
@@ -175,6 +199,7 @@ describe Chef::ApiClient do
"private_key" => "monkeypants",
"admin" => true,
"validator" => true,
+ "create_key" => true,
"json_class" => "Chef::ApiClient"
}
end
@@ -199,6 +224,10 @@ 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
@@ -214,14 +243,16 @@ describe Chef::ApiClient do
before(:each) do
client = {
- "name" => "black",
- "clientname" => "black",
- "public_key" => "crowes",
- "private_key" => "monkeypants",
- "admin" => true,
- "validator" => true,
- "json_class" => "Chef::ApiClient"
+ "name" => "black",
+ "clientname" => "black",
+ "public_key" => "crowes",
+ "private_key" => "monkeypants",
+ "admin" => true,
+ "create_key" => true,
+ "validator" => true,
+ "json_class" => "Chef::ApiClient"
}
+
@http_client = double("Chef::REST mock")
allow(Chef::REST).to receive(:new).and_return(@http_client)
expect(@http_client).to receive(:get).with("clients/black").and_return(client)
@@ -244,6 +275,10 @@ 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
@@ -297,24 +332,34 @@ 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")
- expect(@http_client).to receive(:get).with("clients/lost-my-key").and_return(@api_client_without_key)
- end
+ 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)
+ 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")
- 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)
+ allow(@api_client_with_key).to receive(:chef_rest_v0).and_return(chef_rest_v0_mock)
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)
@@ -327,7 +372,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(@http_client).to receive(:put).
+ expect(chef_rest_v0_mock).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
@@ -345,4 +390,134 @@ 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/application/client_spec.rb b/spec/unit/application/client_spec.rb
index c753ca0ab8..64a6bcc9d2 100644
--- a/spec/unit/application/client_spec.rb
+++ b/spec/unit/application/client_spec.rb
@@ -60,7 +60,7 @@ describe Chef::Application::Client, "reconfigure" do
context "when interval is given" do
before do
Chef::Config[:interval] = 600
- allow(Chef::Platform).to receive(:windows?).and_return(false)
+ allow(ChefConfig).to receive(:windows?).and_return(false)
end
it "should terminate with message" do
@@ -77,7 +77,7 @@ Enable chef-client interval runs by setting `:client_fork = true` in your config
context "when interval is given on windows" do
before do
Chef::Config[:interval] = 600
- allow(Chef::Platform).to receive(:windows?).and_return(true)
+ allow(ChefConfig).to receive(:windows?).and_return(true)
end
it "should not terminate" do
@@ -165,11 +165,6 @@ Enable chef-client interval runs by setting `:client_fork = true` in your config
before do
allow(Chef::Log).to receive(:warn)
end
-
- it "emits a warning that audit mode is an experimental feature" do
- expect(Chef::Log).to receive(:warn).with(/Audit mode is an experimental feature/)
- app.reconfigure
- end
end
shared_examples "unrecognized setting" do
diff --git a/spec/unit/audit/audit_reporter_spec.rb b/spec/unit/audit/audit_reporter_spec.rb
index 4bf889510a..46c2a96b4c 100644
--- a/spec/unit/audit/audit_reporter_spec.rb
+++ b/spec/unit/audit/audit_reporter_spec.rb
@@ -88,6 +88,29 @@ describe Chef::Audit::AuditReporter do
reporter.run_completed(node)
end
+ context "when audit phase failed" do
+
+ let(:audit_error) { double("AuditError", :class => "Chef::Exceptions::AuditError",
+ :message => "Audit phase failed with error message: derpderpderp",
+ :backtrace => ["/path/recipe.rb:57", "/path/library.rb:106"]) }
+
+ before do
+ reporter.instance_variable_set(:@audit_phase_error, audit_error)
+ end
+
+ it "reports an error" do
+ reporter.run_completed(node)
+ expect(run_data).to have_key(:error)
+ expect(run_data).to have_key(:error)
+ expect(run_data[:error]).to eq <<-EOM.strip!
+Chef::Exceptions::AuditError: Audit phase failed with error message: derpderpderp
+/path/recipe.rb:57
+/path/library.rb:106
+EOM
+ end
+
+ end
+
context "when unable to post to server" do
let(:error) do
@@ -215,9 +238,13 @@ describe Chef::Audit::AuditReporter do
let(:audit_data) { Chef::Audit::AuditData.new(node.name, run_id) }
let(:run_data) { audit_data.to_hash }
- let(:error) { double("AuditError", :class => "Chef::Exception::AuditError",
- :message => "Well that certainly didn't work",
- :backtrace => ["line 0", "line 1", "line 2"]) }
+ let(:audit_error) { double("AuditError", :class => "Chef::Exceptions::AuditError",
+ :message => "Audit phase failed with error message: derpderpderp",
+ :backtrace => ["/path/recipe.rb:57", "/path/library.rb:106"]) }
+
+ let(:run_error) { double("RunError", :class => "Chef::Exceptions::RunError",
+ :message => "This error shouldn't be reported.",
+ :backtrace => ["fix it", "fix it", "fix it"]) }
before do
allow(reporter).to receive(:auditing_enabled?).and_return(true)
@@ -226,15 +253,32 @@ describe Chef::Audit::AuditReporter do
allow(audit_data).to receive(:to_hash).and_return(run_data)
end
- it "adds the error information to the reported data" do
- expect(rest).to receive(:create_url)
- expect(rest).to receive(:post)
- reporter.run_failed(error)
- expect(run_data).to have_key(:error)
- expect(run_data[:error]).to eq "Chef::Exception::AuditError: Well that certainly didn't work\n" +
- "line 0\nline 1\nline 2"
+ context "when no prior exception is stored" do
+ it "reports no error" do
+ expect(rest).to receive(:create_url)
+ expect(rest).to receive(:post)
+ reporter.run_failed(run_error)
+ expect(run_data).to_not have_key(:error)
+ end
end
+ context "when some prior exception is stored" do
+ before do
+ reporter.instance_variable_set(:@audit_phase_error, audit_error)
+ end
+
+ it "reports the prior error" do
+ expect(rest).to receive(:create_url)
+ expect(rest).to receive(:post)
+ reporter.run_failed(run_error)
+ expect(run_data).to have_key(:error)
+ expect(run_data[:error]).to eq <<-EOM.strip!
+Chef::Exceptions::AuditError: Audit phase failed with error message: derpderpderp
+/path/recipe.rb:57
+/path/library.rb:106
+EOM
+ end
+ end
end
shared_context "audit data" do
@@ -270,14 +314,14 @@ describe Chef::Audit::AuditReporter do
it "notifies audit phase finished to debug log" do
expect(Chef::Log).to receive(:debug).with(/Audit Reporter completed/)
- reporter.audit_phase_complete
+ reporter.audit_phase_complete("Output from audit mode")
end
it "collects audit data" do
ordered_control_groups.each do |_name, group|
expect(audit_data).to receive(:add_control_group).with(group)
end
- reporter.audit_phase_complete
+ reporter.audit_phase_complete("Output from audit mode")
end
end
@@ -288,14 +332,14 @@ describe Chef::Audit::AuditReporter do
it "notifies audit phase failed to debug log" do
expect(Chef::Log).to receive(:debug).with(/Audit Reporter failed/)
- reporter.audit_phase_failed(error)
+ reporter.audit_phase_failed(error, "Output from audit mode")
end
it "collects audit data" do
ordered_control_groups.each do |_name, group|
expect(audit_data).to receive(:add_control_group).with(group)
end
- reporter.audit_phase_failed(error)
+ reporter.audit_phase_failed(error, "Output from audit mode")
end
end
diff --git a/spec/unit/audit/logger_spec.rb b/spec/unit/audit/logger_spec.rb
new file mode 100644
index 0000000000..9dd9ce2cd9
--- /dev/null
+++ b/spec/unit/audit/logger_spec.rb
@@ -0,0 +1,42 @@
+#
+# Copyright:: Copyright (c) 2014 Chef Software, 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'
+
+describe Chef::Audit::Logger do
+
+ before(:each) do
+ Chef::Audit::Logger.instance_variable_set(:@buffer, nil)
+ end
+
+ it 'calling puts creates @buffer and adds the message' do
+ Chef::Audit::Logger.puts("Output message")
+ expect(Chef::Audit::Logger.read_buffer).to eq("Output message\n")
+ end
+
+ it 'calling puts multiple times adds to the message' do
+ Chef::Audit::Logger.puts("Output message")
+ Chef::Audit::Logger.puts("Output message")
+ Chef::Audit::Logger.puts("Output message")
+ expect(Chef::Audit::Logger.read_buffer).to eq("Output message\nOutput message\nOutput message\n")
+ end
+
+ it 'calling it before @buffer is set returns an empty string' do
+ expect(Chef::Audit::Logger.read_buffer).to eq("")
+ end
+
+end
diff --git a/spec/unit/audit/runner_spec.rb b/spec/unit/audit/runner_spec.rb
index 0bd4c18388..1de024260f 100644
--- a/spec/unit/audit/runner_spec.rb
+++ b/spec/unit/audit/runner_spec.rb
@@ -68,8 +68,8 @@ describe Chef::Audit::Runner do
in_sub_process do
runner.send(:setup)
- expect(RSpec.configuration.output_stream).to eq(log_location)
- expect(RSpec.configuration.error_stream).to eq(log_location)
+ expect(RSpec.configuration.output_stream).to eq(Chef::Audit::Logger)
+ expect(RSpec.configuration.error_stream).to eq(Chef::Audit::Logger)
expect(RSpec.configuration.formatters.size).to eq(2)
expect(RSpec.configuration.formatters).to include(instance_of(Chef::Audit::AuditEventProxy))
diff --git a/spec/unit/chef_fs/file_pattern_spec.rb b/spec/unit/chef_fs/file_pattern_spec.rb
index a9f06e8424..ed5f314605 100644
--- a/spec/unit/chef_fs/file_pattern_spec.rb
+++ b/spec/unit/chef_fs/file_pattern_spec.rb
@@ -157,7 +157,7 @@ describe Chef::ChefFS::FilePattern do
end
end
- context 'with simple pattern "a\*\b"', :pending => (Chef::Platform.windows?) do
+ context 'with simple pattern "a\*\b"', :skip => (Chef::Platform.windows?) do
let(:pattern) { Chef::ChefFS::FilePattern.new('a\*\b') }
it 'match?' do
expect(pattern.match?('a*b')).to be_truthy
@@ -264,7 +264,7 @@ describe Chef::ChefFS::FilePattern do
end
end
- context 'with star pattern "/abc/d[a-z][0-9]f/ghi"', :pending => (Chef::Platform.windows?) do
+ context 'with star pattern "/abc/d[a-z][0-9]f/ghi"', :skip => (Chef::Platform.windows?) do
let(:pattern) { Chef::ChefFS::FilePattern.new('/abc/d[a-z][0-9]f/ghi') }
it 'match?' do
expect(pattern.match?('/abc/de1f/ghi')).to be_truthy
@@ -352,11 +352,7 @@ describe Chef::ChefFS::FilePattern do
expect(pattern.could_match_children?('/abc/def/ghi')).to be_truthy
expect(pattern.could_match_children?('abc')).to be_falsey
end
- it 'could_match_children? /abc** returns false for /xyz' do
- pending 'Make could_match_children? more rigorous'
- # At the moment, we return false for this, but in the end it would be nice to return true:
- expect(pattern.could_match_children?('/xyz')).to be_falsey
- end
+
it 'exact_child_name_under' do
expect(pattern.exact_child_name_under('/')).to eq(nil)
expect(pattern.exact_child_name_under('/abc')).to eq(nil)
@@ -440,14 +436,6 @@ describe Chef::ChefFS::FilePattern do
expect(p('/.').exact_path).to eq('/')
expect(p('/.').match?('/')).to be_truthy
end
- it 'handles dot by itself', :pending => "decide what to do with dot by itself" do
- expect(p('.').normalized_pattern).to eq('.')
- expect(p('.').exact_path).to eq('.')
- expect(p('.').match?('.')).to be_truthy
- expect(p('./').normalized_pattern).to eq('.')
- expect(p('./').exact_path).to eq('.')
- expect(p('./').match?('.')).to be_truthy
- end
it 'handles dotdot' do
expect(p('abc/../def').normalized_pattern).to eq('def')
expect(p('abc/../def').exact_path).to eq('def')
diff --git a/spec/unit/client_spec.rb b/spec/unit/client_spec.rb
index fa8317744c..1e4bbb5c56 100644
--- a/spec/unit/client_spec.rb
+++ b/spec/unit/client_spec.rb
@@ -19,6 +19,8 @@
#
require 'spec_helper'
+require 'spec/support/shared/context/client'
+require 'spec/support/shared/examples/client'
require 'chef/run_context'
require 'chef/rest'
@@ -28,55 +30,7 @@ class FooError < RuntimeError
end
describe Chef::Client do
-
- let(:hostname) { "hostname" }
- let(:machinename) { "machinename.example.org" }
- let(:fqdn) { "hostname.example.org" }
-
- let(:ohai_data) do
- { :fqdn => fqdn,
- :hostname => hostname,
- :machinename => machinename,
- :platform => 'example-platform',
- :platform_version => 'example-platform-1.0',
- :data => {}
- }
- end
-
- let(:ohai_system) do
- ohai_system = double( "Ohai::System",
- :all_plugins => true,
- :data => ohai_data)
- allow(ohai_system).to receive(:[]) do |key|
- ohai_data[key]
- end
- ohai_system
- end
-
- let(:node) do
- Chef::Node.new.tap do |n|
- n.name(fqdn)
- n.chef_environment("_default")
- end
- end
-
- let(:json_attribs) { nil }
- let(:client_opts) { {} }
-
- let(:client) do
- Chef::Config[:event_loggers] = []
- Chef::Client.new(json_attribs, client_opts).tap do |c|
- c.node = node
- end
- end
-
- before do
- Chef::Log.logger = Logger.new(StringIO.new)
-
- # Node/Ohai data
- #Chef::Config[:node_name] = fqdn
- allow(Ohai::System).to receive(:new).and_return(ohai_system)
- end
+ include_context "client"
context "when minimal ohai is configured" do
before do
@@ -88,7 +42,6 @@ describe Chef::Client do
expect(ohai_system).to receive(:all_plugins).with(expected_filter)
client.run_ohai
end
-
end
describe "authentication protocol selection" do
@@ -117,7 +70,6 @@ describe Chef::Client do
describe "configuring output formatters" do
context "when no formatter has been configured" do
-
context "and STDOUT is a TTY" do
before do
allow(STDOUT).to receive(:tty?).and_return(true)
@@ -203,135 +155,12 @@ describe Chef::Client do
end
describe "a full client run" do
- shared_context "a client run" do
- let(:http_node_load) { double("Chef::REST (node)") }
- let(:http_cookbook_sync) { double("Chef::REST (cookbook sync)") }
- let(:http_node_save) { double("Chef::REST (node save)") }
- let(:runner) { double("Chef::Runner") }
- let(:audit_runner) { instance_double("Chef::Audit::Runner", :failed? => false) }
-
- let(:api_client_exists?) { false }
-
- let(:stdout) { StringIO.new }
- let(:stderr) { StringIO.new }
-
- let(:enable_fork) { false }
-
- def stub_for_register
- # --Client.register
- # Make sure Client#register thinks the client key doesn't
- # exist, so it tries to register and create one.
- allow(File).to receive(:exists?).and_call_original
- expect(File).to receive(:exists?).
- with(Chef::Config[:client_key]).
- exactly(:once).
- and_return(api_client_exists?)
-
- unless api_client_exists?
- # Client.register will register with the validation client name.
- expect_any_instance_of(Chef::ApiClient::Registration).to receive(:run)
- end
- end
-
- def stub_for_node_load
- # Client.register will then turn around create another
- # Chef::REST object, this time with the client key it got from the
- # previous step.
- expect(Chef::REST).to receive(:new).
- with(Chef::Config[:chef_server_url], fqdn, Chef::Config[:client_key]).
- exactly(:once).
- and_return(http_node_load)
-
- # --Client#build_node
- # looks up the node, which we will return, then later saves it.
- expect(Chef::Node).to receive(:find_or_create).with(fqdn).and_return(node)
-
- # --ResourceReporter#node_load_completed
- # gets a run id from the server for storing resource history
- # (has its own tests, so stubbing it here.)
- expect_any_instance_of(Chef::ResourceReporter).to receive(:node_load_completed)
- end
-
- def stub_for_sync_cookbooks
- # --Client#setup_run_context
- # ---Client#sync_cookbooks -- downloads the list of cookbooks to sync
- #
- expect_any_instance_of(Chef::CookbookSynchronizer).to receive(:sync_cookbooks)
- expect(Chef::REST).to receive(:new).with(Chef::Config[:chef_server_url]).and_return(http_cookbook_sync)
- expect(http_cookbook_sync).to receive(:post).
- with("environments/_default/cookbook_versions", {:run_list => []}).
- and_return({})
- end
-
- def stub_for_converge
- # --Client#converge
- expect(Chef::Runner).to receive(:new).and_return(runner)
- expect(runner).to receive(:converge).and_return(true)
- end
-
- def stub_for_audit
- # -- Client#run_audits
- expect(Chef::Audit::Runner).to receive(:new).and_return(audit_runner)
- expect(audit_runner).to receive(:run).and_return(true)
- end
-
- def stub_for_node_save
- allow(node).to receive(:data_for_save).and_return(node.for_json)
-
- # --Client#save_updated_node
- expect(Chef::REST).to receive(:new).with(Chef::Config[:chef_server_url]).and_return(http_node_save)
- expect(http_node_save).to receive(:put_rest).with("nodes/#{fqdn}", node.for_json).and_return(true)
- end
-
- def stub_for_run
- expect_any_instance_of(Chef::RunLock).to receive(:acquire)
- expect_any_instance_of(Chef::RunLock).to receive(:save_pid)
- expect_any_instance_of(Chef::RunLock).to receive(:release)
-
- # Post conditions: check that node has been filled in correctly
- expect(client).to receive(:run_started)
- expect(client).to receive(:run_completed_successfully)
-
- # --ResourceReporter#run_completed
- # updates the server with the resource history
- # (has its own tests, so stubbing it here.)
- expect_any_instance_of(Chef::ResourceReporter).to receive(:run_completed)
- # --AuditReporter#run_completed
- # posts the audit data to server.
- # (has its own tests, so stubbing it here.)
- expect_any_instance_of(Chef::Audit::AuditReporter).to receive(:run_completed)
- end
-
- before do
- Chef::Config[:client_fork] = enable_fork
- Chef::Config[:cache_path] = windows? ? 'C:\chef' : '/var/chef'
- Chef::Config[:why_run] = false
- Chef::Config[:audit_mode] = :enabled
-
- stub_const("Chef::Client::STDOUT_FD", stdout)
- stub_const("Chef::Client::STDERR_FD", stderr)
-
- stub_for_register
- stub_for_node_load
- stub_for_sync_cookbooks
- stub_for_converge
- stub_for_audit
- stub_for_node_save
- stub_for_run
- end
- end
-
shared_examples_for "a successful client run" do
include_context "a client run"
+ include_context "converge completed"
+ include_context "audit phase completed"
- it "runs ohai, sets up authentication, loads node state, synchronizes policy, converges, and runs audits" do
- # This is what we're testing.
- client.run
-
- # fork is stubbed, so we can see the outcome of the run
- expect(node.automatic_attrs[:platform]).to eq("example-platform")
- expect(node.automatic_attrs[:platform_version]).to eq("example-platform-1.0")
- end
+ include_examples "a completed run"
end
describe "when running chef-client without fork" do
@@ -339,24 +168,19 @@ describe Chef::Client do
end
describe "when the client key already exists" do
- let(:api_client_exists?) { true }
- include_examples "a successful client run"
+ include_examples "a successful client run" do
+ let(:api_client_exists?) { true }
+ end
end
- describe "when an override run list is given" do
- let(:client_opts) { {:override_runlist => "recipe[override_recipe]"} }
-
- it "should permit spaces in overriding run list" do
+ context "when an override run list is given" do
+ it "permits spaces in overriding run list" do
Chef::Client.new(nil, :override_runlist => 'role[a], role[b]')
end
- describe "when running the client" do
+ describe "calling run" do
include_examples "a successful client run" do
-
- before do
- # Client will try to compile and run override_recipe
- expect_any_instance_of(Chef::RunContext::CookbookCompiler).to receive(:compile)
- end
+ let(:client_opts) { {:override_runlist => "recipe[override_recipe]"} }
def stub_for_sync_cookbooks
# --Client#setup_run_context
@@ -373,13 +197,22 @@ describe Chef::Client do
# Expect NO node save
expect(node).not_to receive(:save)
end
+
+ before do
+ # Client will try to compile and run override_recipe
+ expect_any_instance_of(Chef::RunContext::CookbookCompiler).to receive(:compile)
+ end
end
end
end
describe "when a permanent run list is passed as an option" do
- include_examples "a successful client run" do
+ it "sets the new run list on the node" do
+ client.run
+ expect(node.run_list).to eq(Chef::RunList.new(new_runlist))
+ end
+ include_examples "a successful client run" do
let(:new_runlist) { "recipe[new_run_list_recipe]" }
let(:client_opts) { {:runlist => new_runlist} }
@@ -399,214 +232,61 @@ describe Chef::Client do
# do not create a fixture for this.
expect_any_instance_of(Chef::RunContext::CookbookCompiler).to receive(:compile)
end
-
- it "sets the new run list on the node" do
- client.run
- expect(node.run_list).to eq(Chef::RunList.new(new_runlist))
- end
end
end
- describe "when converge fails" do
- include_context "a client run" do
- let(:e) { Exception.new }
- def stub_for_converge
- expect(Chef::Runner).to receive(:new).and_return(runner)
- expect(runner).to receive(:converge).and_raise(e)
- expect(Chef::Application).to receive(:debug_stacktrace).with an_instance_of(Chef::Exceptions::RunFailedWrappingError)
- end
-
- def stub_for_node_save
- expect(client).to_not receive(:save_updated_node)
- end
-
- def stub_for_run
- expect_any_instance_of(Chef::RunLock).to receive(:acquire)
- expect_any_instance_of(Chef::RunLock).to receive(:save_pid)
- expect_any_instance_of(Chef::RunLock).to receive(:release)
-
- # Post conditions: check that node has been filled in correctly
- expect(client).to receive(:run_started)
- expect(client).to receive(:run_failed)
+ describe "when converge completes successfully" do
+ include_context "a client run"
+ include_context "converge completed"
- expect_any_instance_of(Chef::ResourceReporter).to receive(:run_failed)
- expect_any_instance_of(Chef::Audit::AuditReporter).to receive(:run_failed)
+ describe "when audit phase errors" do
+ include_context "audit phase failed with error"
+ include_examples "a completed run with audit failure" do
+ let(:run_errors) { [audit_error] }
end
end
- it "runs the audits and raises the error" do
- expect{ client.run }.to raise_error(Chef::Exceptions::RunFailedWrappingError) do |error|
- expect(error.wrapped_errors.size).to eq(1)
- expect(error.wrapped_errors[0]).to eq(e)
- end
+ describe "when audit phase completed" do
+ include_context "audit phase completed"
+ include_examples "a completed run"
end
- end
-
- describe "when the audit phase fails" do
- context "with an exception" do
- context "when audit mode is enabled" do
- include_context "a client run" do
- let(:e) { Exception.new }
- def stub_for_audit
- expect(Chef::Audit::Runner).to receive(:new).and_return(audit_runner)
- expect(audit_runner).to receive(:run).and_raise(e)
- expect(Chef::Application).to receive(:debug_stacktrace).with an_instance_of(Chef::Exceptions::RunFailedWrappingError)
- end
-
- def stub_for_run
- expect_any_instance_of(Chef::RunLock).to receive(:acquire)
- expect_any_instance_of(Chef::RunLock).to receive(:save_pid)
- expect_any_instance_of(Chef::RunLock).to receive(:release)
-
- # Post conditions: check that node has been filled in correctly
- expect(client).to receive(:run_started)
- expect(client).to receive(:run_failed)
-
- expect_any_instance_of(Chef::ResourceReporter).to receive(:run_failed)
- expect_any_instance_of(Chef::Audit::AuditReporter).to receive(:run_failed)
- end
- end
- it "should save the node after converge and raise exception" do
- expect{ client.run }.to raise_error(Chef::Exceptions::RunFailedWrappingError) do |error|
- expect(error.wrapped_errors.size).to eq(1)
- expect(error.wrapped_errors[0]).to eq(e)
- end
- end
- end
-
- context "when audit mode is disabled" do
- include_context "a client run" do
- before do
- Chef::Config[:audit_mode] = :disabled
- end
-
- let(:e) { FooError.new }
-
- def stub_for_audit
- expect(Chef::Audit::Runner).to_not receive(:new)
- end
-
- def stub_for_converge
- expect(Chef::Runner).to receive(:new).and_return(runner)
- expect(runner).to receive(:converge).and_raise(e)
- expect(Chef::Application).to receive(:debug_stacktrace).with an_instance_of(FooError)
- end
-
- def stub_for_node_save
- expect(client).to_not receive(:save_updated_node)
- end
-
- def stub_for_run
- expect_any_instance_of(Chef::RunLock).to receive(:acquire)
- expect_any_instance_of(Chef::RunLock).to receive(:save_pid)
- expect_any_instance_of(Chef::RunLock).to receive(:release)
-
-
- # Post conditions: check that node has been filled in correctly
- expect(client).to receive(:run_started)
- expect(client).to receive(:run_failed)
-
- expect_any_instance_of(Chef::ResourceReporter).to receive(:run_failed)
-
- end
-
- it "re-raises an unwrapped exception" do
- expect { client.run }.to raise_error(FooError)
- end
- end
- end
-
-
- end
-
- context "with failed audits" do
- include_context "a client run" do
- let(:audit_runner) do
- instance_double("Chef::Audit::Runner", :run => true, :failed? => true, :num_failed => 1, :num_total => 1)
- end
-
- def stub_for_audit
- expect(Chef::Audit::Runner).to receive(:new).and_return(audit_runner)
- expect(Chef::Application).to receive(:debug_stacktrace).with an_instance_of(Chef::Exceptions::RunFailedWrappingError)
- end
-
- def stub_for_run
- expect_any_instance_of(Chef::RunLock).to receive(:acquire)
- expect_any_instance_of(Chef::RunLock).to receive(:save_pid)
- expect_any_instance_of(Chef::RunLock).to receive(:release)
-
- # Post conditions: check that node has been filled in correctly
- expect(client).to receive(:run_started)
- expect(client).to receive(:run_failed)
-
- expect_any_instance_of(Chef::ResourceReporter).to receive(:run_failed)
- expect_any_instance_of(Chef::Audit::AuditReporter).to receive(:run_failed)
- end
- end
-
- it "should save the node after converge and raise exception" do
- expect{ client.run }.to raise_error(Chef::Exceptions::RunFailedWrappingError) do |error|
- expect(error.wrapped_errors.size).to eq(1)
- expect(error.wrapped_errors[0]).to be_instance_of(Chef::Exceptions::AuditsFailed)
- end
+ describe "when audit phase completed with failed controls" do
+ include_context "audit phase completed with failed controls"
+ include_examples "a completed run with audit failure" do
+ let(:run_errors) { [audit_error] }
end
end
end
- describe "when why_run mode is enabled" do
- include_context "a client run" do
-
- before do
- Chef::Config[:why_run] = true
- end
-
- def stub_for_audit
- expect(Chef::Audit::Runner).to_not receive(:new)
- end
-
- def stub_for_node_save
- # This is how we should be mocking external calls - not letting it fall all the way through to the
- # REST call
- expect(node).to receive(:save)
- end
-
- it "runs successfully without enabling the audit runner" do
- client.run
+ describe "when converge errors" do
+ include_context "a client run"
+ include_context "converge failed"
- # fork is stubbed, so we can see the outcome of the run
- expect(node.automatic_attrs[:platform]).to eq("example-platform")
- expect(node.automatic_attrs[:platform_version]).to eq("example-platform-1.0")
+ describe "when audit phase errors" do
+ include_context "audit phase failed with error"
+ include_examples "a failed run" do
+ let(:run_errors) { [converge_error, audit_error] }
end
end
- end
-
- describe "when audits are disabled" do
- include_context "a client run" do
- before do
- Chef::Config[:audit_mode] = :disabled
- end
-
- def stub_for_audit
- expect(Chef::Audit::Runner).to_not receive(:new)
+ describe "when audit phase completed" do
+ include_context "audit phase completed"
+ include_examples "a failed run" do
+ let(:run_errors) { [converge_error] }
end
+ end
- it "runs successfully without enabling the audit runner" do
- client.run
-
- # fork is stubbed, so we can see the outcome of the run
- expect(node.automatic_attrs[:platform]).to eq("example-platform")
- expect(node.automatic_attrs[:platform_version]).to eq("example-platform-1.0")
+ describe "when audit phase completed with failed controls" do
+ include_context "audit phase completed with failed controls"
+ include_examples "a failed run" do
+ let(:run_errors) { [converge_error, audit_error] }
end
end
end
-
end
-
describe "when handling run failures" do
-
it "should remove the run_lock on failure of #load_node" do
@run_lock = double("Chef::RunLock", :acquire => true)
allow(Chef::RunLock).to receive(:new).and_return(@run_lock)
@@ -680,6 +360,7 @@ describe Chef::Client do
# check pre-conditions.
expect(node[:roles]).to be_nil
expect(node[:recipes]).to be_nil
+ expect(node[:expanded_run_list]).to be_nil
allow(client.policy_builder).to receive(:node).and_return(node)
@@ -692,7 +373,10 @@ describe Chef::Client do
expect(node[:roles]).to include("role_containing_cookbook1")
expect(node[:recipes]).not_to be_nil
expect(node[:recipes].length).to eq(1)
- expect(node[:recipes]).to include("cookbook1")
+ expect(node[:recipes]).to include("cookbook1::default")
+ expect(node[:expanded_run_list]).not_to be_nil
+ expect(node[:expanded_run_list].length).to eq(1)
+ expect(node[:expanded_run_list]).to include("cookbook1::default")
end
it "should set the environment from the specified configuration value" do
@@ -715,7 +399,7 @@ describe Chef::Client do
describe "windows_admin_check" do
context "platform is not windows" do
before do
- allow(Chef::Platform).to receive(:windows?).and_return(false)
+ allow(ChefConfig).to receive(:windows?).and_return(false)
end
it "shouldn't be called" do
@@ -726,7 +410,7 @@ describe Chef::Client do
context "platform is windows" do
before do
- allow(Chef::Platform).to receive(:windows?).and_return(true)
+ allow(ChefConfig).to receive(:windows?).and_return(true)
end
it "should be called" do
@@ -775,6 +459,7 @@ describe Chef::Client do
Chef::Config[:solo] = true
Chef::Config[:cookbook_path] = ["/path/to/invalid/cookbook_path"]
end
+
context "when any directory of cookbook_path contains no cookbook" do
it "raises CookbookNotFound error" do
expect do
@@ -819,4 +504,20 @@ describe Chef::Client do
end
end
+
+ describe "always attempt to run handlers" do
+ subject { client }
+ before do
+ # fail on the first thing in begin block
+ allow_any_instance_of(Chef::RunLock).to receive(:save_pid).and_raise(NoMethodError)
+ end
+
+ it "should run exception handlers on early fail" do
+ expect(subject).to receive(:run_failed)
+ expect { subject.run }.to raise_error(Chef::Exceptions::RunFailedWrappingError) do |error|
+ expect(error.wrapped_errors.size).to eq 1
+ expect(error.wrapped_errors).to include(NoMethodError)
+ end
+ end
+ end
end
diff --git a/spec/unit/config_spec.rb b/spec/unit/config_spec.rb
deleted file mode 100644
index 6ea67246b5..0000000000
--- a/spec/unit/config_spec.rb
+++ /dev/null
@@ -1,544 +0,0 @@
-#
-# Author:: Adam Jacob (<adam@opscode.com>)
-# Author:: Kyle Goodwin (<kgoodwin@primerevenue.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/exceptions'
-require 'chef/util/path_helper'
-
-describe Chef::Config do
- describe "config attribute writer: chef_server_url" do
- before do
- Chef::Config.chef_server_url = "https://junglist.gen.nz"
- end
-
- it "sets the server url" do
- expect(Chef::Config.chef_server_url).to eq("https://junglist.gen.nz")
- end
-
- context "when the url has a leading space" do
- before do
- Chef::Config.chef_server_url = " https://junglist.gen.nz"
- end
-
- it "strips the space from the url when setting" do
- expect(Chef::Config.chef_server_url).to eq("https://junglist.gen.nz")
- end
-
- end
-
- context "when the url is a frozen string" do
- before do
- Chef::Config.chef_server_url = " https://junglist.gen.nz".freeze
- end
-
- it "strips the space from the url when setting without raising an error" do
- expect(Chef::Config.chef_server_url).to eq("https://junglist.gen.nz")
- end
- end
-
- end
-
- describe "when configuring formatters" do
- # if TTY and not(force-logger)
- # formatter = configured formatter or default formatter
- # formatter goes to STDOUT/ERR
- # if log file is writeable
- # log level is configured level or info
- # log location is file
- # else
- # log level is warn
- # log location is STDERR
- # end
- # elsif not(TTY) and force formatter
- # formatter = configured formatter or default formatter
- # if log_location specified
- # formatter goes to log_location
- # else
- # formatter goes to STDOUT/ERR
- # end
- # else
- # formatter = "null"
- # log_location = configured-value or defualt
- # log_level = info or defualt
- # end
- #
- it "has an empty list of formatters by default" do
- expect(Chef::Config.formatters).to eq([])
- end
-
- it "configures a formatter with a short name" do
- Chef::Config.add_formatter(:doc)
- expect(Chef::Config.formatters).to eq([[:doc, nil]])
- end
-
- it "configures a formatter with a file output" do
- Chef::Config.add_formatter(:doc, "/var/log/formatter.log")
- expect(Chef::Config.formatters).to eq([[:doc, "/var/log/formatter.log"]])
- end
-
- end
-
- describe "class method: manage_secret_key" do
- before do
- allow(Chef::FileCache).to receive(:load).and_return(true)
- allow(Chef::FileCache).to receive(:has_key?).with("chef_server_cookie_id").and_return(false)
- end
-
- it "should generate and store a chef server cookie id" do
- expect(Chef::FileCache).to receive(:store).with("chef_server_cookie_id", /\w{40}/).and_return(true)
- Chef::Config.manage_secret_key
- end
-
- describe "when the filecache has a chef server cookie id key" do
- before do
- allow(Chef::FileCache).to receive(:has_key?).with("chef_server_cookie_id").and_return(true)
- end
-
- it "should not generate and store a chef server cookie id" do
- expect(Chef::FileCache).not_to receive(:store).with("chef_server_cookie_id", /\w{40}/)
- Chef::Config.manage_secret_key
- end
- end
-
- end
-
- [ false, true ].each do |is_windows|
-
- context "On #{is_windows ? 'Windows' : 'Unix'}" do
- def to_platform(*args)
- Chef::Config.platform_specific_path(*args)
- end
-
- before :each do
- allow(Chef::Platform).to receive(:windows?).and_return(is_windows)
- end
-
- describe "class method: platform_specific_path" do
- if is_windows
- it "should return a windows path on windows systems" do
- path = "/etc/chef/cookbooks"
- allow(Chef::Config).to receive(:env).and_return({ 'SYSTEMDRIVE' => 'C:' })
- # match on a regex that looks for the base path with an optional
- # system drive at the beginning (c:)
- # system drive is not hardcoded b/c it can change and b/c it is not present on linux systems
- expect(Chef::Config.platform_specific_path(path)).to eq("C:\\chef\\cookbooks")
- end
- else
- it "should return given path on non-windows systems" do
- path = "/etc/chef/cookbooks"
- expect(Chef::Config.platform_specific_path(path)).to eq("/etc/chef/cookbooks")
- end
- end
- end
-
- describe "default values" do
- let :primary_cache_path do
- if is_windows
- "#{Chef::Config.env['SYSTEMDRIVE']}\\chef"
- else
- "/var/chef"
- end
- end
-
- let :secondary_cache_path do
- if is_windows
- "#{Chef::Config[:user_home]}\\.chef"
- else
- "#{Chef::Config[:user_home]}/.chef"
- end
- end
-
- before do
- if is_windows
- allow(Chef::Config).to receive(:env).and_return({ 'SYSTEMDRIVE' => 'C:' })
- Chef::Config[:user_home] = 'C:\Users\charlie'
- else
- Chef::Config[:user_home] = '/Users/charlie'
- end
-
- allow(Chef::Config).to receive(:path_accessible?).and_return(false)
- end
-
- describe "Chef::Config[:cache_path]" do
- context "when /var/chef exists and is accessible" do
- it "defaults to /var/chef" do
- allow(Chef::Config).to receive(:path_accessible?).with(to_platform("/var/chef")).and_return(true)
- expect(Chef::Config[:cache_path]).to eq(primary_cache_path)
- end
- end
-
- context "when /var/chef does not exist and /var is accessible" do
- it "defaults to /var/chef" do
- allow(File).to receive(:exists?).with(to_platform("/var/chef")).and_return(false)
- allow(Chef::Config).to receive(:path_accessible?).with(to_platform("/var")).and_return(true)
- expect(Chef::Config[:cache_path]).to eq(primary_cache_path)
- end
- end
-
- context "when /var/chef does not exist and /var is not accessible" do
- it "defaults to $HOME/.chef" do
- allow(File).to receive(:exists?).with(to_platform("/var/chef")).and_return(false)
- allow(Chef::Config).to receive(:path_accessible?).with(to_platform("/var")).and_return(false)
- expect(Chef::Config[:cache_path]).to eq(secondary_cache_path)
- end
- end
-
- context "when /var/chef exists and is not accessible" do
- it "defaults to $HOME/.chef" do
- allow(File).to receive(:exists?).with(to_platform("/var/chef")).and_return(true)
- allow(File).to receive(:readable?).with(to_platform("/var/chef")).and_return(true)
- allow(File).to receive(:writable?).with(to_platform("/var/chef")).and_return(false)
-
- expect(Chef::Config[:cache_path]).to eq(secondary_cache_path)
- end
- end
-
- context "when chef is running in local mode" do
- before do
- Chef::Config.local_mode = true
- end
-
- context "and config_dir is /a/b/c" do
- before do
- Chef::Config.config_dir to_platform('/a/b/c')
- end
-
- it "cache_path is /a/b/c/local-mode-cache" do
- expect(Chef::Config.cache_path).to eq(to_platform('/a/b/c/local-mode-cache'))
- end
- end
-
- context "and config_dir is /a/b/c/" do
- before do
- Chef::Config.config_dir to_platform('/a/b/c/')
- end
-
- it "cache_path is /a/b/c/local-mode-cache" do
- expect(Chef::Config.cache_path).to eq(to_platform('/a/b/c/local-mode-cache'))
- end
- end
- end
- end
-
- it "Chef::Config[:file_backup_path] defaults to /var/chef/backup" do
- allow(Chef::Config).to receive(:cache_path).and_return(primary_cache_path)
- backup_path = is_windows ? "#{primary_cache_path}\\backup" : "#{primary_cache_path}/backup"
- expect(Chef::Config[:file_backup_path]).to eq(backup_path)
- end
-
- it "Chef::Config[:ssl_verify_mode] defaults to :verify_peer" do
- expect(Chef::Config[:ssl_verify_mode]).to eq(:verify_peer)
- end
-
- it "Chef::Config[:ssl_ca_path] defaults to nil" do
- expect(Chef::Config[:ssl_ca_path]).to be_nil
- end
-
- # TODO can this be removed?
- if !is_windows
- it "Chef::Config[:ssl_ca_file] defaults to nil" do
- expect(Chef::Config[:ssl_ca_file]).to be_nil
- end
- end
-
- it "Chef::Config[:data_bag_path] defaults to /var/chef/data_bags" do
- allow(Chef::Config).to receive(:cache_path).and_return(primary_cache_path)
- data_bag_path = is_windows ? "#{primary_cache_path}\\data_bags" : "#{primary_cache_path}/data_bags"
- expect(Chef::Config[:data_bag_path]).to eq(data_bag_path)
- end
-
- it "Chef::Config[:environment_path] defaults to /var/chef/environments" do
- allow(Chef::Config).to receive(:cache_path).and_return(primary_cache_path)
- environment_path = is_windows ? "#{primary_cache_path}\\environments" : "#{primary_cache_path}/environments"
- expect(Chef::Config[:environment_path]).to eq(environment_path)
- end
-
- describe "setting the config dir" do
-
- context "when the config file is /etc/chef/client.rb" do
-
- before do
- Chef::Config.config_file = to_platform("/etc/chef/client.rb")
- end
-
- it "config_dir is /etc/chef" do
- expect(Chef::Config.config_dir).to eq(to_platform("/etc/chef"))
- end
-
- context "and chef is running in local mode" do
- before do
- Chef::Config.local_mode = true
- end
-
- it "config_dir is /etc/chef" do
- expect(Chef::Config.config_dir).to eq(to_platform("/etc/chef"))
- end
- end
-
- context "when config_dir is set to /other/config/dir/" do
- before do
- Chef::Config.config_dir = to_platform("/other/config/dir/")
- end
-
- it "yields the explicit value" do
- expect(Chef::Config.config_dir).to eq(to_platform("/other/config/dir/"))
- end
- end
-
- end
-
- context "when the user's home dir is /home/charlie/" do
- before do
- Chef::Config.user_home = to_platform("/home/charlie")
- end
-
- it "config_dir is /home/charlie/.chef/" do
- expect(Chef::Config.config_dir).to eq(Chef::Util::PathHelper.join(to_platform("/home/charlie/.chef"), ''))
- end
-
- context "and chef is running in local mode" do
- before do
- Chef::Config.local_mode = true
- end
-
- it "config_dir is /home/charlie/.chef/" do
- expect(Chef::Config.config_dir).to eq(Chef::Util::PathHelper.join(to_platform("/home/charlie/.chef"), ''))
- end
- end
- end
-
- end
-
- if is_windows
- describe "finding the windows embedded dir" do
- let(:default_config_location) { "c:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-11.6.0/lib/chef/config.rb" }
- let(:alternate_install_location) { "c:/my/alternate/install/place/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-11.6.0/lib/chef/config.rb" }
- let(:non_omnibus_location) { "c:/my/dev/stuff/lib/ruby/gems/1.9.1/gems/chef-11.6.0/lib/chef/config.rb" }
-
- let(:default_ca_file) { "c:/opscode/chef/embedded/ssl/certs/cacert.pem" }
-
- it "finds the embedded dir in the default location" do
- allow(Chef::Config).to receive(:_this_file).and_return(default_config_location)
- expect(Chef::Config.embedded_dir).to eq("c:/opscode/chef/embedded")
- end
-
- it "finds the embedded dir in a custom install location" do
- allow(Chef::Config).to receive(:_this_file).and_return(alternate_install_location)
- expect(Chef::Config.embedded_dir).to eq("c:/my/alternate/install/place/chef/embedded")
- end
-
- it "doesn't error when not in an omnibus install" do
- allow(Chef::Config).to receive(:_this_file).and_return(non_omnibus_location)
- expect(Chef::Config.embedded_dir).to be_nil
- end
-
- it "sets the ssl_ca_cert path if the cert file is available" do
- allow(Chef::Config).to receive(:_this_file).and_return(default_config_location)
- allow(File).to receive(:exist?).with(default_ca_file).and_return(true)
- expect(Chef::Config.ssl_ca_file).to eq(default_ca_file)
- end
- end
- end
- end
-
- describe "Chef::Config[:user_home]" do
- it "should set when HOME is provided" do
- expected = to_platform("/home/kitten")
- allow(Chef::Util::PathHelper).to receive(:home).and_return(expected)
- expect(Chef::Config[:user_home]).to eq(expected)
- end
-
- it "falls back to the current working directory when HOME and USERPROFILE is not set" do
- allow(Chef::Util::PathHelper).to receive(:home).and_return(nil)
- expect(Chef::Config[:user_home]).to eq(Dir.pwd)
- end
- end
-
- describe "Chef::Config[:encrypted_data_bag_secret]" do
- let(:db_secret_default_path){ to_platform("/etc/chef/encrypted_data_bag_secret") }
-
- before do
- allow(File).to receive(:exist?).with(db_secret_default_path).and_return(secret_exists)
- end
-
- context "/etc/chef/encrypted_data_bag_secret exists" do
- let(:secret_exists) { true }
- it "sets the value to /etc/chef/encrypted_data_bag_secret" do
- expect(Chef::Config[:encrypted_data_bag_secret]).to eq db_secret_default_path
- end
- end
-
- context "/etc/chef/encrypted_data_bag_secret does not exist" do
- let(:secret_exists) { false }
- it "sets the value to nil" do
- expect(Chef::Config[:encrypted_data_bag_secret]).to be_nil
- end
- end
- end
-
- describe "Chef::Config[:event_handlers]" do
- it "sets a event_handlers to an empty array by default" do
- expect(Chef::Config[:event_handlers]).to eq([])
- end
- it "should be able to add custom handlers" do
- o = Object.new
- Chef::Config[:event_handlers] << o
- expect(Chef::Config[:event_handlers]).to be_include(o)
- end
- end
-
- describe "Chef::Config[:user_valid_regex]" do
- context "on a platform that is not Windows" do
- it "allows one letter usernames" do
- any_match = Chef::Config[:user_valid_regex].any? { |regex| regex.match('a') }
- expect(any_match).to be_truthy
- end
- end
- end
-
- describe "Chef::Config[:internal_locale]" do
- let(:shell_out) do
- double("Chef::Mixin::ShellOut double", :exitstatus => 0, :stdout => locales)
- end
-
- let(:locales) { locale_array.join("\n") }
-
- before do
- allow(Chef::Config).to receive(:shell_out_with_systems_locale!).with("locale -a").and_return(shell_out)
- end
-
- shared_examples_for "a suitable locale" do
- it "returns an English UTF-8 locale" do
- expect(Chef::Log).to_not receive(:warn).with(/Please install an English UTF-8 locale for Chef to use/)
- expect(Chef::Log).to_not receive(:debug).with(/Defaulting to locale en_US.UTF-8 on Windows/)
- expect(Chef::Log).to_not receive(:debug).with(/No usable locale -a command found/)
- expect(Chef::Config.guess_internal_locale).to eq expected_locale
- end
- end
-
- context "when the result includes 'C.UTF-8'" do
- include_examples "a suitable locale" do
- let(:locale_array) { [expected_locale, "en_US.UTF-8"] }
- let(:expected_locale) { "C.UTF-8" }
- end
- end
-
- context "when the result includes 'en_US.UTF-8'" do
- include_examples "a suitable locale" do
- let(:locale_array) { ["en_CA.UTF-8", expected_locale, "en_NZ.UTF-8"] }
- let(:expected_locale) { "en_US.UTF-8" }
- end
- end
-
- context "when the result includes 'en_US.utf8'" do
- include_examples "a suitable locale" do
- let(:locale_array) { ["en_CA.utf8", "en_US.utf8", "en_NZ.utf8"] }
- let(:expected_locale) { "en_US.UTF-8" }
- end
- end
-
- context "when the result includes 'en.UTF-8'" do
- include_examples "a suitable locale" do
- let(:locale_array) { ["en.ISO8859-1", expected_locale] }
- let(:expected_locale) { "en.UTF-8" }
- end
- end
-
- context "when the result includes 'en_*.UTF-8'" do
- include_examples "a suitable locale" do
- let(:locale_array) { [expected_locale, "en_CA.UTF-8", "en_GB.UTF-8"] }
- let(:expected_locale) { "en_AU.UTF-8" }
- end
- end
-
- context "when the result includes 'en_*.utf8'" do
- include_examples "a suitable locale" do
- let(:locale_array) { ["en_AU.utf8", "en_CA.utf8", "en_GB.utf8"] }
- let(:expected_locale) { "en_AU.UTF-8" }
- end
- end
-
- context "when the result does not include 'en_*.UTF-8'" do
- let(:locale_array) { ["af_ZA", "af_ZA.ISO8859-1", "af_ZA.ISO8859-15", "af_ZA.UTF-8"] }
-
- it "should fall back to C locale" do
- expect(Chef::Log).to receive(:warn).with("Please install an English UTF-8 locale for Chef to use, falling back to C locale and disabling UTF-8 support.")
- expect(Chef::Config.guess_internal_locale).to eq 'C'
- end
- end
-
- context "on error" do
- let(:locale_array) { [] }
-
- before do
- allow(Chef::Config).to receive(:shell_out_with_systems_locale!).and_raise("THIS IS AN ERROR")
- end
-
- it "should default to 'en_US.UTF-8'" do
- if is_windows
- expect(Chef::Log).to receive(:debug).with("Defaulting to locale en_US.UTF-8 on Windows, until it matters that we do something else.")
- else
- expect(Chef::Log).to receive(:debug).with("No usable locale -a command found, assuming you have en_US.UTF-8 installed.")
- end
- expect(Chef::Config.guess_internal_locale).to eq "en_US.UTF-8"
- end
- end
- end
- end
- end
-
- describe "Treating deprecation warnings as errors" do
-
- context "when using our default RSpec configuration" do
-
- it "defaults to treating deprecation warnings as errors" do
- expect(Chef::Config[:treat_deprecation_warnings_as_errors]).to be(true)
- end
-
- it "sets CHEF_TREAT_DEPRECATION_WARNINGS_AS_ERRORS environment variable" do
- expect(ENV['CHEF_TREAT_DEPRECATION_WARNINGS_AS_ERRORS']).to eq("1")
- end
-
- it "treats deprecation warnings as errors in child processes when testing" do
- # Doing a full integration test where we launch a child process is slow
- # and liable to break for weird reasons (bundler env stuff, etc.), so
- # we're just checking that the presence of the environment variable
- # causes treat_deprecation_warnings_as_errors to be set to true after a
- # config reset.
- Chef::Config.reset
- expect(Chef::Config[:treat_deprecation_warnings_as_errors]).to be(true)
- end
-
- end
-
- context "outside of our test environment" do
-
- before do
- ENV.delete('CHEF_TREAT_DEPRECATION_WARNINGS_AS_ERRORS')
- Chef::Config.reset
- end
-
- it "defaults to NOT treating deprecation warnings as errors" do
- expect(Chef::Config[:treat_deprecation_warnings_as_errors]).to be(false)
- end
- end
-
-
- end
-end
diff --git a/spec/unit/cookbook/cookbook_version_loader_spec.rb b/spec/unit/cookbook/cookbook_version_loader_spec.rb
index 2c4ad11787..23ffc21f7f 100644
--- a/spec/unit/cookbook/cookbook_version_loader_spec.rb
+++ b/spec/unit/cookbook/cookbook_version_loader_spec.rb
@@ -20,7 +20,7 @@ require 'spec_helper'
describe Chef::Cookbook::CookbookVersionLoader do
before do
- allow(Chef::Platform).to receive(:windows?) { false }
+ allow(ChefConfig).to receive(:windows?) { false }
end
describe "loading a cookbook" do
diff --git a/spec/unit/cookbook/metadata_spec.rb b/spec/unit/cookbook/metadata_spec.rb
index 760ae5dd2a..d2954726e8 100644
--- a/spec/unit/cookbook/metadata_spec.rb
+++ b/spec/unit/cookbook/metadata_spec.rb
@@ -304,6 +304,21 @@ describe Chef::Cookbook::Metadata do
end
end
end
+
+ it "strips out self-dependencies", :chef_lt_13_only do
+ metadata.name('foo')
+ expect(Chef::Log).to receive(:warn).with(
+ "Ignoring self-dependency in cookbook foo, please remove it (in the future this will be fatal)."
+ )
+ metadata.depends('foo')
+ expect(metadata.dependencies).to eql({})
+ end
+
+ it "errors on self-dependencies", :chef_gte_13_only do
+ metadata.name('foo')
+ expect { metadata.depends('foo') }.to raise_error
+ # FIXME: add the error type
+ end
end
describe "attribute groupings" do
diff --git a/spec/unit/cookbook/syntax_check_spec.rb b/spec/unit/cookbook/syntax_check_spec.rb
index 471fc01831..ee4e0bed02 100644
--- a/spec/unit/cookbook/syntax_check_spec.rb
+++ b/spec/unit/cookbook/syntax_check_spec.rb
@@ -21,7 +21,7 @@ require "chef/cookbook/syntax_check"
describe Chef::Cookbook::SyntaxCheck do
before do
- allow(Chef::Platform).to receive(:windows?) { false }
+ allow(ChefConfig).to receive(:windows?) { false }
end
let(:cookbook_path) { File.join(CHEF_SPEC_DATA, 'cookbooks', 'openldap') }
diff --git a/spec/unit/cookbook_loader_spec.rb b/spec/unit/cookbook_loader_spec.rb
index 45a985bafd..b1384bffe7 100644
--- a/spec/unit/cookbook_loader_spec.rb
+++ b/spec/unit/cookbook_loader_spec.rb
@@ -20,7 +20,7 @@ require 'spec_helper'
describe Chef::CookbookLoader do
before do
- allow(Chef::Platform).to receive(:windows?) {false}
+ allow(ChefConfig).to receive(:windows?) {false}
end
let(:repo_paths) do
[
diff --git a/spec/unit/cookbook_site_streaming_uploader_spec.rb b/spec/unit/cookbook_site_streaming_uploader_spec.rb
index ef0f649163..0041a142dc 100644
--- a/spec/unit/cookbook_site_streaming_uploader_spec.rb
+++ b/spec/unit/cookbook_site_streaming_uploader_spec.rb
@@ -121,27 +121,6 @@ describe Chef::CookbookSiteStreamingUploader do
})
end
- describe "http verify mode" do
- before do
- @uri = "https://cookbooks.dummy.com/api/v1/cookbooks"
- uri_info = URI.parse(@uri)
- @http = Net::HTTP.new(uri_info.host, uri_info.port)
- expect(Net::HTTP).to receive(:new).with(uri_info.host, uri_info.port).and_return(@http)
- end
-
- it "should be VERIFY_NONE when ssl_verify_mode is :verify_none" do
- Chef::Config[:ssl_verify_mode] = :verify_none
- Chef::CookbookSiteStreamingUploader.make_request(:post, @uri, 'bill', @secret_filename)
- expect(@http.verify_mode).to eq(OpenSSL::SSL::VERIFY_NONE)
- end
-
- it "should be VERIFY_PEER when ssl_verify_mode is :verify_peer" do
- Chef::Config[:ssl_verify_mode] = :verify_peer
- Chef::CookbookSiteStreamingUploader.make_request(:post, @uri, 'bill', @secret_filename)
- expect(@http.verify_mode).to eq(OpenSSL::SSL::VERIFY_PEER)
- end
- end
-
end # make_request
describe "StreamPart" do
diff --git a/spec/unit/cookbook_spec.rb b/spec/unit/cookbook_spec.rb
index 7b3cda2af1..f36b031309 100644
--- a/spec/unit/cookbook_spec.rb
+++ b/spec/unit/cookbook_spec.rb
@@ -59,15 +59,6 @@ describe Chef::CookbookVersion do
expect(@cookbook.fully_qualified_recipe_names.include?("openldap::three")).to eq(true)
end
- it "should find a preferred file" do
- skip
- end
-
- it "should not return an unchanged preferred file" do
- pending
- expect(@cookbook.preferred_filename(@node, :files, 'a-filename', 'the-checksum')).to be_nil
- end
-
it "should raise an ArgumentException if you try to load a bad recipe name" do
expect { @cookbook.load_recipe("doesnt_exist", @node) }.to raise_error(ArgumentError)
end
diff --git a/spec/unit/cookbook_version_spec.rb b/spec/unit/cookbook_version_spec.rb
index 440dd9da6c..4990aef004 100644
--- a/spec/unit/cookbook_version_spec.rb
+++ b/spec/unit/cookbook_version_spec.rb
@@ -306,26 +306,6 @@ describe Chef::CookbookVersion do
subject(:cbv) { Chef::CookbookVersion.new("version validation", '/tmp/blah') }
- describe "HTTP Resource behaviors", pending: "will be deprected when CookbookManifest API is stablized" do
-
- it "errors on #save_url" do
- expect { cbv.save_url }.to raise_error(Chef::Exceptions::DeprecatedFeatureError)
- end
-
- it "errors on #force_save_url" do
- expect { cbv.force_save_url }.to raise_error(Chef::Exceptions::DeprecatedFeatureError)
- end
-
- it "errors on #to_hash" do
- expect { cbv.to_hash }.to raise_error(Chef::Exceptions::DeprecatedFeatureError)
- end
-
- it "errors on #to_json" do
- expect { cbv.to_json }.to raise_error(Chef::Exceptions::DeprecatedFeatureError)
- end
-
- end
-
it "errors on #status and #status=" do
expect { cbv.status = :wat }.to raise_error(Chef::Exceptions::DeprecatedFeatureError)
expect { cbv.status }.to raise_error(Chef::Exceptions::DeprecatedFeatureError)
diff --git a/spec/unit/data_bag_spec.rb b/spec/unit/data_bag_spec.rb
index f6db1e222a..bd9a99a1de 100644
--- a/spec/unit/data_bag_spec.rb
+++ b/spec/unit/data_bag_spec.rb
@@ -22,7 +22,7 @@ require 'chef/data_bag'
describe Chef::DataBag do
before(:each) do
@data_bag = Chef::DataBag.new
- allow(Chef::Platform)::to receive(:windows?) { false }
+ allow(ChefConfig).to receive(:windows?) { false }
end
describe "initialize" do
diff --git a/spec/unit/deprecation_spec.rb b/spec/unit/deprecation_spec.rb
index f824cb7c76..2e1f3c39f3 100644
--- a/spec/unit/deprecation_spec.rb
+++ b/spec/unit/deprecation_spec.rb
@@ -95,4 +95,59 @@ describe Chef::Deprecation do
expect { test_instance.deprecated_method(10) }.to raise_error(Chef::Exceptions::DeprecatedFeatureError)
end
+ context "When a class has deprecated_attr, _reader and _writer" do
+ before(:context) do
+ class DeprecatedAttrTest
+ extend Chef::Mixin::Deprecation
+ def initialize
+ @a = @r = @w = 1
+ end
+ deprecated_attr :a, "a"
+ deprecated_attr_reader :r, "r"
+ deprecated_attr_writer :w, "w"
+ end
+ end
+
+ it "The deprecated_attr emits warnings" do
+ test = DeprecatedAttrTest.new
+ expect { test.a = 10 }.to raise_error(Chef::Exceptions::DeprecatedFeatureError)
+ expect { test.a }.to raise_error(Chef::Exceptions::DeprecatedFeatureError)
+ end
+
+ it "The deprecated_attr_writer emits warnings, and does not create a reader" do
+ test = DeprecatedAttrTest.new
+ expect { test.w = 10 }.to raise_error(Chef::Exceptions::DeprecatedFeatureError)
+ expect { test.w }.to raise_error(NoMethodError)
+ end
+
+ it "The deprecated_attr_reader emits warnings, and does not create a writer" do
+ test = DeprecatedAttrTest.new
+ expect { test.r = 10 }.to raise_error(NoMethodError)
+ expect { test.r }.to raise_error(Chef::Exceptions::DeprecatedFeatureError)
+ end
+
+ context "With deprecation warnings not throwing exceptions" do
+ before do
+ Chef::Config[:treat_deprecation_warnings_as_errors] = false
+ end
+
+ it "The deprecated_attr can be written to and read from" do
+ test = DeprecatedAttrTest.new
+ test.a = 10
+ expect(test.a).to eq 10
+ end
+
+ it "The deprecated_attr_reader can be read from" do
+ test = DeprecatedAttrTest.new
+ expect(test.r).to eq 1
+ end
+
+ it "The deprecated_attr_writer can be written to" do
+ test = DeprecatedAttrTest.new
+ test.w = 10
+ expect(test.instance_eval { @w }).to eq 10
+ end
+ end
+ end
+
end
diff --git a/spec/unit/dsl/resources_spec.rb b/spec/unit/dsl/resources_spec.rb
new file mode 100644
index 0000000000..581c835290
--- /dev/null
+++ b/spec/unit/dsl/resources_spec.rb
@@ -0,0 +1,85 @@
+#
+# Author:: Noah Kantrowitz (<noah@coderanger.net>)
+# Copyright:: Copyright (c) 2015 Noah Kantrowitz
+# 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/dsl/resources'
+
+describe Chef::DSL::Resources do
+ let(:declared_resources) { [] }
+ let(:test_class) do
+ r = declared_resources
+ Class.new do
+ include Chef::DSL::Resources
+ define_method(:declare_resource) do |dsl_name, name, _created_at, &_block|
+ r << [dsl_name, name]
+ end
+ end
+ end
+ subject { declared_resources }
+ after do
+ # Always clean up after ourselves.
+ described_class.remove_resource_dsl(:test_resource)
+ end
+
+ context 'with a resource added' do
+ before do
+ Chef::DSL::Resources.add_resource_dsl(:test_resource)
+ test_class.new.instance_eval do
+ test_resource 'test_name' do
+ end
+ end
+ end
+ it { is_expected.to eq [[:test_resource, 'test_name']]}
+ end
+
+ context 'with no resource added' do
+ subject do
+ test_class.new.instance_eval do
+ test_resource 'test_name' do
+ end
+ end
+ end
+
+ it { expect { subject }.to raise_error NoMethodError }
+ end
+
+ context 'with a resource added and removed' do
+ before do
+ Chef::DSL::Resources.add_resource_dsl(:test_resource)
+ Chef::DSL::Resources.remove_resource_dsl(:test_resource)
+ end
+ subject do
+ test_class.new.instance_eval do
+ test_resource 'test_name' do
+ end
+ end
+ end
+
+ it { expect { subject }.to raise_error NoMethodError }
+ end
+
+ context 'with a nameless resource' do
+ before do
+ Chef::DSL::Resources.add_resource_dsl(:test_resource)
+ test_class.new.instance_eval do
+ test_resource { }
+ end
+ end
+ it { is_expected.to eq [[:test_resource, nil]]}
+ end
+end
diff --git a/spec/unit/event_dispatch/dispatcher_spec.rb b/spec/unit/event_dispatch/dispatcher_spec.rb
new file mode 100644
index 0000000000..7e43b1933f
--- /dev/null
+++ b/spec/unit/event_dispatch/dispatcher_spec.rb
@@ -0,0 +1,61 @@
+#
+# Author:: Daniel DeLeo (<dan@chef.io>)
+#
+# Copyright:: Copyright (c) 2015 Chef Software, 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/event_dispatch/dispatcher'
+
+describe Chef::EventDispatch::Dispatcher do
+
+ subject(:dispatcher) { Chef::EventDispatch::Dispatcher.new }
+
+ let(:event_sink) { instance_double("Chef::EventDispatch::Base") }
+
+ it "has no subscribers by default" do
+ expect(dispatcher.subscribers).to be_empty
+ end
+
+ context "when an event sink is registered" do
+
+ before do
+ dispatcher.register(event_sink)
+ end
+
+ it "it has the event sink as a subscriber" do
+ expect(dispatcher.subscribers.size).to eq(1)
+ expect(dispatcher.subscribers.first).to eq(event_sink)
+ end
+
+ it "forwards events to the subscribed event sink" do
+ # the events all have different arity and such so we just hit a few different events:
+
+ expect(event_sink).to receive(:run_start).with("12.4.0")
+ dispatcher.run_start("12.4.0")
+
+ expect(event_sink).to receive(:synchronized_cookbook).with("apache2")
+ dispatcher.synchronized_cookbook("apache2")
+
+ exception = StandardError.new("foo")
+ expect(event_sink).to receive(:recipe_file_load_failed).with("/path/to/file.rb", exception)
+ dispatcher.recipe_file_load_failed("/path/to/file.rb", exception)
+ end
+
+ end
+
+end
+
diff --git a/spec/unit/exceptions_spec.rb b/spec/unit/exceptions_spec.rb
index d35ecc8ec8..fd90aeab71 100644
--- a/spec/unit/exceptions_spec.rb
+++ b/spec/unit/exceptions_spec.rb
@@ -113,7 +113,7 @@ describe Chef::Exceptions do
context "initialized with 1 error and nil" do
let(:e) { Chef::Exceptions::RunFailedWrappingError.new(RuntimeError.new("foo"), nil) }
let(:num_errors) { 1 }
- let(:backtrace) { ["1) RuntimeError - foo", ""] }
+ let(:backtrace) { ["1) RuntimeError - foo"] }
include_examples "RunFailedWrappingError expectations"
end
@@ -121,7 +121,7 @@ describe Chef::Exceptions do
context "initialized with 2 errors" do
let(:e) { Chef::Exceptions::RunFailedWrappingError.new(RuntimeError.new("foo"), RuntimeError.new("bar")) }
let(:num_errors) { 2 }
- let(:backtrace) { ["1) RuntimeError - foo", "", "2) RuntimeError - bar", ""] }
+ let(:backtrace) { ["1) RuntimeError - foo", "", "2) RuntimeError - bar"] }
include_examples "RunFailedWrappingError expectations"
end
diff --git a/spec/unit/file_content_management/deploy/mv_windows_spec.rb b/spec/unit/file_content_management/deploy/mv_windows_spec.rb
index c52001cd26..2d1981befc 100644
--- a/spec/unit/file_content_management/deploy/mv_windows_spec.rb
+++ b/spec/unit/file_content_management/deploy/mv_windows_spec.rb
@@ -115,6 +115,66 @@ describe Chef::FileContentManagement::Deploy::MvWindows do
end
+ context "and the target file has null dacl and sacl" do
+
+ before do
+ allow(target_file_security_descriptor).to receive(:dacl_present?).and_return(true)
+ allow(target_file_security_descriptor).to receive(:dacl).and_return(nil)
+ allow(target_file_security_descriptor).to receive(:dacl_inherits?).and_return(false)
+
+ allow(target_file_security_descriptor).to receive(:sacl_present?).and_return(true)
+ allow(target_file_security_descriptor).to receive(:sacl).and_return(nil)
+ allow(target_file_security_descriptor).to receive(:sacl_inherits?).and_return(false)
+
+ expect(updated_target_security_object).to receive(:set_dacl).with(nil, false)
+ expect(updated_target_security_object).to receive(:set_sacl).with(nil, false)
+ end
+
+
+ it "fixes up permissions and moves the file into place" do
+ content_deployer.deploy(staging_file_path, target_file_path)
+ end
+
+ end
+
+ context "and the target has an empty dacl and sacl" do
+ let(:original_target_file_dacl) { [] }
+ let(:original_target_file_sacl) { [] }
+
+ let(:empty_dacl) { double("Windows ACL with no dacl ACEs") }
+ let(:empty_sacl) { double("Windows ACL with no sacl ACEs") }
+
+ before do
+ allow(target_file_security_descriptor).to receive(:dacl_present?).and_return(true)
+ allow(target_file_security_descriptor).to receive(:dacl_inherits?).and_return(false)
+
+ allow(target_file_security_descriptor).to receive(:dacl).and_return(original_target_file_dacl)
+ expect(Chef::ReservedNames::Win32::Security::ACL).
+ to receive(:create).
+ with([]).
+ and_return(empty_dacl)
+
+
+ allow(target_file_security_descriptor).to receive(:sacl_present?).and_return(true)
+ allow(target_file_security_descriptor).to receive(:sacl_inherits?).and_return(false)
+
+ allow(target_file_security_descriptor).to receive(:sacl).and_return(original_target_file_sacl)
+ expect(Chef::ReservedNames::Win32::Security::ACL).
+ to receive(:create).
+ with([]).
+ and_return(empty_sacl)
+
+
+ expect(updated_target_security_object).to receive(:set_dacl).with(empty_dacl, false)
+ expect(updated_target_security_object).to receive(:set_sacl).with(empty_sacl, false)
+ end
+
+
+ it "fixes up permissions and moves the file into place" do
+ content_deployer.deploy(staging_file_path, target_file_path)
+ end
+ end
+
context "and the target has a dacl and sacl" do
let(:inherited_dacl_ace) { double("Windows dacl ace (inherited)", :inherited? => true) }
let(:not_inherited_dacl_ace) { double("Windows dacl ace (not inherited)", :inherited? => false) }
diff --git a/spec/unit/formatters/doc_spec.rb b/spec/unit/formatters/doc_spec.rb
new file mode 100644
index 0000000000..d018207f49
--- /dev/null
+++ b/spec/unit/formatters/doc_spec.rb
@@ -0,0 +1,46 @@
+#
+# Author:: Daniel DeLeo (<dan@chef.io>)
+#
+# Copyright:: Copyright (c) 2015 Chef Software, 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'
+
+describe Chef::Formatters::Base do
+
+ let(:out) { StringIO.new }
+ let(:err) { StringIO.new }
+
+ subject(:formatter) { Chef::Formatters::Doc.new(out, err) }
+
+ it "prints a policyfile's name and revision ID" do
+ minimal_policyfile = {
+ "revision_id"=> "613f803bdd035d574df7fa6da525b38df45a74ca82b38b79655efed8a189e073",
+ "name"=> "jenkins",
+ "run_list"=> [
+ "recipe[apt::default]",
+ "recipe[java::default]",
+ "recipe[jenkins::master]",
+ "recipe[policyfile_demo::default]"
+ ],
+ "cookbook_locks"=> { }
+ }
+
+ formatter.policyfile_loaded(minimal_policyfile)
+ expect(out.string).to include("Using policy 'jenkins' at revision '613f803bdd035d574df7fa6da525b38df45a74ca82b38b79655efed8a189e073'")
+ end
+
+end
diff --git a/spec/unit/formatters/error_inspectors/api_error_formatting_spec.rb b/spec/unit/formatters/error_inspectors/api_error_formatting_spec.rb
new file mode 100644
index 0000000000..b8c2de2b8b
--- /dev/null
+++ b/spec/unit/formatters/error_inspectors/api_error_formatting_spec.rb
@@ -0,0 +1,77 @@
+#
+# Author:: Tyler Cloke (<tyler@chef.io>)
+# Copyright:: Copyright (c) 2015 Chef Software, 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/formatters/error_inspectors/api_error_formatting'
+
+describe Chef::Formatters::APIErrorFormatting do
+ let(:class_instance) { (Class.new { include Chef::Formatters::APIErrorFormatting }).new }
+ let(:error_description) { instance_double(Chef::Formatters::ErrorDescription) }
+ let(:response) { double("response") }
+ before do
+ allow(response).to receive(:body)
+ end
+
+
+ context "when describe_406_error is called" do
+ context "when response['x-ops-server-api-version'] exists" do
+ let(:min_version) { "2" }
+ let(:max_version) { "5" }
+ let(:request_version) { "30" }
+ let(:return_hash) {
+ {
+ "min_version" => min_version,
+ "max_version" => max_version,
+ "request_version" => request_version
+ }
+ }
+
+ before do
+ # mock out the header
+ allow(response).to receive(:[]).with('x-ops-server-api-version').and_return(Chef::JSONCompat.to_json(return_hash))
+ end
+
+ it "prints an error about client and server API version incompatibility with a min API version" do
+ expect(error_description).to receive(:section).with("Incompatible server API version:",/a min API version of #{min_version}/)
+ class_instance.describe_406_error(error_description, response)
+ end
+
+ it "prints an error about client and server API version incompatibility with a max API version" do
+ expect(error_description).to receive(:section).with("Incompatible server API version:",/a max API version of #{max_version}/)
+ class_instance.describe_406_error(error_description, response)
+ end
+
+ it "prints an error describing the request API version" do
+ expect(error_description).to receive(:section).with("Incompatible server API version:",/a request with an API version of #{request_version}/)
+ class_instance.describe_406_error(error_description, response)
+ end
+ end
+
+ context "when response.body['error'] != 'invalid-x-ops-server-api-version'" do
+
+ before do
+ allow(response).to receive(:[]).with('x-ops-server-api-version').and_return(nil)
+ end
+
+ it "forwards the error_description to describe_http_error" do
+ expect(class_instance).to receive(:describe_http_error).with(error_description)
+ class_instance.describe_406_error(error_description, response)
+ end
+ end
+ end
+end
diff --git a/spec/unit/formatters/error_inspectors/compile_error_inspector_spec.rb b/spec/unit/formatters/error_inspectors/compile_error_inspector_spec.rb
index ac19e91922..5f95beb259 100644
--- a/spec/unit/formatters/error_inspectors/compile_error_inspector_spec.rb
+++ b/spec/unit/formatters/error_inspectors/compile_error_inspector_spec.rb
@@ -37,69 +37,122 @@ end
E
describe Chef::Formatters::ErrorInspectors::CompileErrorInspector do
- before do
- @node_name = "test-node.example.com"
- @description = Chef::Formatters::ErrorDescription.new("Error Evaluating File:")
- @exception = NoMethodError.new("undefined method `this_is_not_a_valid_method' for Chef::Resource::File")
- @outputter = Chef::Formatters::IndentableOutputStream.new(StringIO.new, STDERR)
- #@outputter = Chef::Formatters::IndentableOutputStream.new(STDOUT, STDERR)
- end
+ let(:node_name) { "test-node.example.com" }
- describe "when scrubbing backtraces" do
- it "shows backtrace lines from cookbook files" do
- # Error inspector originally used file_cache_path which is incorrect on
- # chef-solo. Using cookbook_path should do the right thing for client and
- # solo.
- allow(Chef::Config).to receive(:cookbook_path).and_return([ "/home/someuser/dev-laptop/cookbooks" ])
- @trace = [
- "/home/someuser/dev-laptop/cookbooks/syntax-err/recipes/default.rb:14:in `from_file'",
- "/home/someuser/dev-laptop/cookbooks/syntax-err/recipes/default.rb:11:in `from_file'",
- "/home/someuser/.multiruby/gems/chef/lib/chef/client.rb:123:in `run'"
- ]
- @exception.set_backtrace(@trace)
- @path = "/var/chef/cache/cookbooks/syntax-err/recipes/default.rb"
- @inspector = described_class.new(@path, @exception)
+ let(:description) { Chef::Formatters::ErrorDescription.new("Error Evaluating File:") }
- @expected_filtered_trace = [
- "/home/someuser/dev-laptop/cookbooks/syntax-err/recipes/default.rb:14:in `from_file'",
- "/home/someuser/dev-laptop/cookbooks/syntax-err/recipes/default.rb:11:in `from_file'",
- ]
- expect(@inspector.filtered_bt).to eq(@expected_filtered_trace)
- end
+ let(:exception) do
+ e = NoMethodError.new("undefined method `this_is_not_a_valid_method' for Chef::Resource::File")
+ e.set_backtrace(trace)
+ e
end
- describe "when explaining an error in the compile phase" do
- before do
- allow(Chef::Config).to receive(:cookbook_path).and_return([ "/var/chef/cache/cookbooks" ])
- recipe_lines = BAD_RECIPE.split("\n").map {|l| l << "\n" }
- expect(IO).to receive(:readlines).with("/var/chef/cache/cookbooks/syntax-err/recipes/default.rb").and_return(recipe_lines)
- @trace = [
- "/var/chef/cache/cookbooks/syntax-err/recipes/default.rb:14:in `from_file'",
- "/var/chef/cache/cookbooks/syntax-err/recipes/default.rb:11:in `from_file'",
- "/usr/local/lib/ruby/gems/chef/lib/chef/client.rb:123:in `run'" # should not display
- ]
- @exception.set_backtrace(@trace)
- @path = "/var/chef/cache/cookbooks/syntax-err/recipes/default.rb"
- @inspector = described_class.new(@path, @exception)
- @inspector.add_explanation(@description)
- end
+ # Change to $stdout to print error messages for manual inspection
+ let(:stdout) { StringIO.new }
+
+ let(:outputter) { Chef::Formatters::IndentableOutputStream.new(StringIO.new, STDERR) }
- it "finds the line number of the error from the stacktrace" do
- expect(@inspector.culprit_line).to eq(14)
+ subject(:inspector) { described_class.new(path_to_failed_file, exception) }
+
+ describe "finding the code responsible for the error" do
+
+ context "when the stacktrace includes cookbook files" do
+
+ let(:trace) do
+ [
+ "/home/someuser/dev-laptop/cookbooks/syntax-err/recipes/default.rb:14:in `from_file'",
+ "/home/someuser/dev-laptop/cookbooks/syntax-err/recipes/default.rb:11:in `from_file'",
+ "/home/someuser/.multiruby/gems/chef/lib/chef/client.rb:123:in `run'"
+ ]
+ end
+
+ let(:expected_filtered_trace) do
+ [
+ "/home/someuser/dev-laptop/cookbooks/syntax-err/recipes/default.rb:14:in `from_file'",
+ "/home/someuser/dev-laptop/cookbooks/syntax-err/recipes/default.rb:11:in `from_file'",
+ ]
+ end
+
+ let(:path_to_failed_file) { "/home/someuser/dev-laptop/cookbooks/syntax-err/recipes/default.rb" }
+
+ before do
+ # Error inspector originally used file_cache_path which is incorrect on
+ # chef-solo. Using cookbook_path should do the right thing for client and
+ # solo.
+ allow(Chef::Config).to receive(:cookbook_path).and_return([ "/home/someuser/dev-laptop/cookbooks" ])
+ end
+
+ describe "when scrubbing backtraces" do
+ it "shows backtrace lines from cookbook files" do
+ expect(inspector.filtered_bt).to eq(expected_filtered_trace)
+ end
+ end
+
+ describe "when explaining an error in the compile phase" do
+ before do
+ recipe_lines = BAD_RECIPE.split("\n").map {|l| l << "\n" }
+ expect(IO).to receive(:readlines).with(path_to_failed_file).and_return(recipe_lines)
+ inspector.add_explanation(description)
+ end
+
+ it "reports the error was not located within cookbooks" do
+ expect(inspector.found_error_in_cookbooks?).to be(true)
+ end
+
+ it "finds the line number of the error from the stacktrace" do
+ expect(inspector.culprit_line).to eq(14)
+ end
+
+ it "prints a pretty message" do
+ description.display(outputter)
+ end
+ end
end
- it "prints a pretty message" do
- @description.display(@outputter)
+ context "when the error does not contain any lines from cookbooks" do
+
+ let(:trace) do
+ [
+ "/opt/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/run_context.rb:144:in `rescue in block in load_libraries'",
+ "/opt/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/run_context.rb:138:in `block in load_libraries'",
+ "/opt/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/run_context.rb:230:in `call'",
+ "/opt/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/run_context.rb:230:in `block (2 levels) in foreach_cookbook_load_segment'",
+ "/opt/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/run_context.rb:229:in `each'",
+ "/opt/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/run_context.rb:229:in `block in foreach_cookbook_load_segment'",
+ "/opt/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/run_context.rb:227:in `each'",
+ "/opt/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/run_context.rb:227:in `foreach_cookbook_load_segment'",
+ "/opt/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/run_context.rb:137:in `load_libraries'"
+ ]
+ end
+
+ let(:exception) do
+ e = Chef::Exceptions::RecipeNotFound.new("recipe nope:nope not found")
+ e.set_backtrace(trace)
+ e
+ end
+
+ let(:path_to_failed_file) { nil }
+
+ it "gives a full, non-filtered trace" do
+ expect(inspector.filtered_bt).to eq(trace)
+ end
+
+ it "does not error when displaying the error" do
+ expect { description.display(outputter) }.to_not raise_error
+ end
+
+ it "reports the error was not located within cookbooks" do
+ expect(inspector.found_error_in_cookbooks?).to be(false)
+ end
+
end
end
describe "when explaining an error on windows" do
- before do
- allow(Chef::Config).to receive(:cookbook_path).and_return([ "C:/opscode/chef/var/cache/cookbooks" ])
- recipe_lines = BAD_RECIPE.split("\n").map {|l| l << "\n" }
- expect(IO).to receive(:readlines).at_least(1).times.with(/:\/opscode\/chef\/var\/cache\/cookbooks\/foo\/recipes\/default.rb/).and_return(recipe_lines)
- @trace = [
+
+ let(:trace_with_upcase_drive) do
+ [
"C:/opscode/chef/var/cache/cookbooks/foo/recipes/default.rb:14 in `from_file'",
"C:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/run_context.rb:144:in `rescue in block in load_libraries'",
"C:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/run_context.rb:138:in `block in load_libraries'",
@@ -122,81 +175,65 @@ describe Chef::Formatters::ErrorInspectors::CompileErrorInspector do
"C:/opscode/chef/bin/chef-client:19:in `load'",
"C:/opscode/chef/bin/chef-client:19:in `<main>'"
]
- @exception.set_backtrace(@trace)
- @path = "/var/chef/cache/cookbooks/syntax-err/recipes/default.rb"
- @inspector = described_class.new(@path, @exception)
- @inspector.add_explanation(@description)
end
+ let(:trace) { trace_with_upcase_drive }
- describe "and examining the stack trace for a recipe" do
- it "find the culprit recipe name when the drive letter is upper case" do
- expect(@inspector.culprit_file).to eq("C:/opscode/chef/var/cache/cookbooks/foo/recipes/default.rb")
+ let(:path_to_failed_file) { "/var/cache/cookbooks/foo/recipes/default.rb" }
+
+ before do
+ allow(Chef::Config).to receive(:cookbook_path).and_return([ "C:/opscode/chef/var/cache/cookbooks" ])
+ recipe_lines = BAD_RECIPE.split("\n").map {|l| l << "\n" }
+ expect(IO).to receive(:readlines).at_least(1).times.with(full_path_to_failed_file).and_return(recipe_lines)
+ inspector.add_explanation(description)
+ end
+
+ context "when the drive letter in the path is uppercase" do
+
+ let(:full_path_to_failed_file) { "C:/opscode/chef#{path_to_failed_file}" }
+
+ it "reports the error was not located within cookbooks" do
+ expect(inspector.found_error_in_cookbooks?).to be(true)
end
- it "find the culprit recipe name when the drive letter is lower case" do
- @trace.each { |line| line.gsub!(/^C:/, "c:") }
- @exception.set_backtrace(@trace)
- @inspector = described_class.new(@path, @exception)
- @inspector.add_explanation(@description)
- expect(@inspector.culprit_file).to eq("c:/opscode/chef/var/cache/cookbooks/foo/recipes/default.rb")
+ it "finds the culprit recipe name" do
+ expect(inspector.culprit_file).to eq("C:/opscode/chef/var/cache/cookbooks/foo/recipes/default.rb")
end
- end
- it "finds the line number of the error from the stack trace" do
- expect(@inspector.culprit_line).to eq(14)
- end
+ it "finds the line number of the error from the stack trace" do
+ expect(inspector.culprit_line).to eq(14)
+ end
- it "prints a pretty message" do
- @description.display(@outputter)
+ it "prints a pretty message" do
+ description.display(outputter)
+ end
end
- end
- describe "when explaining an error on windows, and the backtrace lowercases the drive letter" do
- before do
- allow(Chef::Config).to receive(:cookbook_path).and_return([ "C:/opscode/chef/var/cache/cookbooks" ])
- recipe_lines = BAD_RECIPE.split("\n").map {|l| l << "\n" }
- expect(IO).to receive(:readlines).with("c:/opscode/chef/var/cache/cookbooks/foo/recipes/default.rb").and_return(recipe_lines)
- @trace = [
- "c:/opscode/chef/var/cache/cookbooks/foo/recipes/default.rb:14 in `from_file'",
- "c:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/run_context.rb:144:in `rescue in block in load_libraries'",
- "c:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/run_context.rb:138:in `block in load_libraries'",
- "c:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/run_context.rb:230:in `call'",
- "c:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/run_context.rb:230:in `block (2 levels) in foreach_cookbook_load_segment'",
- "c:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/run_context.rb:229:in `each'",
- "c:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/run_context.rb:229:in `block in foreach_cookbook_load_segment'",
- "c:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/run_context.rb:227:in `each'",
- "c:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/run_context.rb:227:in `foreach_cookbook_load_segment'",
- "c:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/run_context.rb:137:in `load_libraries'",
- "c:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/run_context.rb:62:in `load'",
- "c:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/client.rb:198:in `setup_run_context'",
- "c:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/client.rb:418:in `do_run'",
- "c:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/client.rb:176:in `run'",
- "c:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/application/client.rb:283:in `block in run_application'",
- "c:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/application/client.rb:270:in `loop'",
- "c:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/application/client.rb:270:in `run_application'",
- "c:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/application.rb:70:in `run'",
- "c:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/bin/chef-client:26:in `<top (required)>'",
- "c:/opscode/chef/bin/chef-client:19:in `load'",
- "c:/opscode/chef/bin/chef-client:19:in `<main>'"
- ]
- @exception.set_backtrace(@trace)
- @path = "/var/chef/cache/cookbooks/syntax-err/recipes/default.rb"
- @inspector = described_class.new(@path, @exception)
- @inspector.add_explanation(@description)
- end
+ context "when the drive letter in the path is lowercase" do
- it "finds the culprit recipe name from the stacktrace" do
- expect(@inspector.culprit_file).to eq("c:/opscode/chef/var/cache/cookbooks/foo/recipes/default.rb")
- end
+ let(:trace) do
+ trace_with_upcase_drive.map { |line| line.gsub(/^C:/, "c:") }
+ end
- it "finds the line number of the error from the stack trace" do
- expect(@inspector.culprit_line).to eq(14)
- end
+ let(:full_path_to_failed_file) { "c:/opscode/chef#{path_to_failed_file}" }
- it "prints a pretty message" do
- @description.display(@outputter)
+ it "reports the error was not located within cookbooks" do
+ expect(inspector.found_error_in_cookbooks?).to be(true)
+ end
+
+ it "finds the culprit recipe name from the stacktrace" do
+ expect(inspector.culprit_file).to eq("c:/opscode/chef/var/cache/cookbooks/foo/recipes/default.rb")
+ end
+
+ it "finds the line number of the error from the stack trace" do
+ expect(inspector.culprit_line).to eq(14)
+ end
+
+ it "prints a pretty message" do
+ description.display(outputter)
+ end
end
+
end
end
diff --git a/spec/unit/formatters/error_inspectors/resource_failure_inspector_spec.rb b/spec/unit/formatters/error_inspectors/resource_failure_inspector_spec.rb
index a42d234601..5594d6e18a 100644
--- a/spec/unit/formatters/error_inspectors/resource_failure_inspector_spec.rb
+++ b/spec/unit/formatters/error_inspectors/resource_failure_inspector_spec.rb
@@ -126,6 +126,13 @@ describe Chef::Formatters::ErrorInspectors::ResourceFailureInspector do
expect(@inspector.recipe_snippet).to match(/^# In C:\/Users\/btm/)
end
+ it "parses a Windows path" do
+ source_line = "C:\\Windows\\Temp\\packer\\cookbooks\\fake_file.rb:2: undefined local variable or method `non_existent' for main:Object (NameError)"
+ @resource.source_line = source_line
+ @inspector = Chef::Formatters::ErrorInspectors::ResourceFailureInspector.new(@resource, :create, @exception)
+ expect(@inspector.recipe_snippet).to match(/^# In C:\\Windows\\Temp\\packer\\/)
+ end
+
it "parses a unix path" do
source_line = "/home/btm/src/chef/chef/spec/unit/fake_file.rb:2: undefined local variable or method `non_existent' for main:Object (NameError)"
@resource.source_line = source_line
diff --git a/spec/unit/guard_interpreter/resource_guard_interpreter_spec.rb b/spec/unit/guard_interpreter/resource_guard_interpreter_spec.rb
index 4cf3ba827a..acf1b15fd8 100644
--- a/spec/unit/guard_interpreter/resource_guard_interpreter_spec.rb
+++ b/spec/unit/guard_interpreter/resource_guard_interpreter_spec.rb
@@ -24,6 +24,7 @@ describe Chef::GuardInterpreter::ResourceGuardInterpreter do
node.default["kernel"] = Hash.new
node.default["kernel"][:machine] = :x86_64.to_s
+ node.automatic[:os] = 'windows'
node
end
@@ -83,6 +84,14 @@ describe Chef::GuardInterpreter::ResourceGuardInterpreter do
expect(guard_interpreter.evaluate).to eq(true)
end
+ it "does not corrupt the run_context of the node" do
+ node_run_context_before_guard_execution = parent_resource.run_context
+ expect(node_run_context_before_guard_execution.object_id).to eq(parent_resource.node.run_context.object_id)
+ guard_interpreter.evaluate
+ node_run_context_after_guard_execution = parent_resource.run_context
+ expect(node_run_context_after_guard_execution.object_id).to eq(parent_resource.node.run_context.object_id)
+ end
+
describe "script command opts switch" do
let(:command_opts) { {} }
let(:guard_interpreter) { Chef::GuardInterpreter::ResourceGuardInterpreter.new(parent_resource, "exit 0", command_opts) }
@@ -144,4 +153,3 @@ describe Chef::GuardInterpreter::ResourceGuardInterpreter do
end
end
end
-
diff --git a/spec/unit/http/authenticator_spec.rb b/spec/unit/http/authenticator_spec.rb
new file mode 100644
index 0000000000..48bbdcf76c
--- /dev/null
+++ b/spec/unit/http/authenticator_spec.rb
@@ -0,0 +1,78 @@
+#
+# Author:: Tyler Cloke (<tyler@chef.io>)
+# Copyright:: Copyright (c) 2015 Chef Software, 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/http/authenticator'
+
+describe Chef::HTTP::Authenticator do
+ let(:class_instance) { Chef::HTTP::Authenticator.new }
+ let(:method) { double("method") }
+ let(:url) { double("url") }
+ let(:headers) { Hash.new }
+ let(:data) { double("data") }
+
+ before do
+ allow(class_instance).to receive(:authentication_headers).and_return({})
+ end
+
+ context "when handle_request is called" do
+ shared_examples_for "merging the server API version into the headers" do
+ it "merges the default version of X-Ops-Server-API-Version into the headers" do
+ # headers returned
+ expect(class_instance.handle_request(method, url, headers, data)[2]).
+ to include({'X-Ops-Server-API-Version' => Chef::HTTP::Authenticator::DEFAULT_SERVER_API_VERSION})
+ end
+
+ context "when api_version is set to something other than the default" do
+ let(:class_instance) { Chef::HTTP::Authenticator.new({:api_version => '-10'}) }
+
+ it "merges the requested version of X-Ops-Server-API-Version into the headers" do
+ expect(class_instance.handle_request(method, url, headers, data)[2]).
+ to include({'X-Ops-Server-API-Version' => '-10'})
+ end
+ end
+ end
+
+ context "when !sign_requests?" do
+ before do
+ allow(class_instance).to receive(:sign_requests?).and_return(false)
+ end
+
+ it_behaves_like "merging the server API version into the headers"
+
+ it "authentication_headers is not called" do
+ expect(class_instance).to_not receive(:authentication_headers)
+ class_instance.handle_request(method, url, headers, data)
+ end
+
+ end
+
+ context "when sign_requests?" do
+ before do
+ allow(class_instance).to receive(:sign_requests?).and_return(true)
+ end
+
+ it_behaves_like "merging the server API version into the headers"
+
+ it "calls authentication_headers with the proper input" do
+ expect(class_instance).to receive(:authentication_headers).with(method, url, data).and_return({})
+ class_instance.handle_request(method, url, headers, data)
+ end
+ end
+ end
+end
diff --git a/spec/unit/http/basic_client_spec.rb b/spec/unit/http/basic_client_spec.rb
index 32b32a5f4c..b7552f54aa 100644
--- a/spec/unit/http/basic_client_spec.rb
+++ b/spec/unit/http/basic_client_spec.rb
@@ -109,5 +109,21 @@ describe "HTTP Connection" do
end
end
+
+ context "when an empty proxy is set by the environment" do
+ let(:env) do
+ {
+ "https_proxy" => ""
+ }
+ end
+
+ before do
+ allow(subject).to receive(:env).and_return(env)
+ end
+
+ it "to not fail with URI parse exception" do
+ expect { subject.proxy_uri }.to_not raise_error
+ end
+ end
end
end
diff --git a/spec/unit/json_compat_spec.rb b/spec/unit/json_compat_spec.rb
index 4631429bd6..7482ba8a28 100644
--- a/spec/unit/json_compat_spec.rb
+++ b/spec/unit/json_compat_spec.rb
@@ -72,19 +72,19 @@ describe Chef::JSONCompat do
end
end
- # On FreeBSD 10.1 i386 rspec fails with a SystemStackError loading the expect line with more that 254 entries
+ # On FreeBSD 10.1 i386 rspec fails with a SystemStackError loading the expect line with more that 252 entries
# https://github.com/chef/chef/issues/3101
- describe "with a file with 254 or less nested entries" do
- let(:json) { IO.read(File.join(CHEF_SPEC_DATA, 'big.json')) }
+ describe "with the file with 252 or less nested entries" do
+ let(:json) { IO.read(File.join(CHEF_SPEC_DATA, 'nested.json')) }
let(:hash) { Chef::JSONCompat.from_json(json) }
- describe "when a 254 json file is loaded" do
+ describe "when the 252 json file is loaded" do
it "should create a Hash from the file" do
expect(hash).to be_kind_of(Hash)
end
- it "should has 'test' as a 254 nested value" do
- expect(hash['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']).to eq('test')
+ it "should has 'test' as a 252 nested value" do
+ expect(hash['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']).to eq('test')
end
end
end
diff --git a/spec/unit/key_spec.rb b/spec/unit/key_spec.rb
new file mode 100644
index 0000000000..94ebbf6ae8
--- /dev/null
+++ b/spec/unit/key_spec.rb
@@ -0,0 +1,634 @@
+#
+# Author:: Tyler Cloke (tyler@chef.io)
+# Copyright:: Copyright (c) 2015 Chef Software, 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/key'
+
+describe Chef::Key do
+ # whether user or client irrelevent to these tests
+ let(:key) { Chef::Key.new("original_actor", "user") }
+ let(:public_key_string) do
+ <<EOS
+-----BEGIN PUBLIC KEY-----
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvPo+oNPB7uuNkws0fC02
+KxSwdyqPLu0fhI1pOweNKAZeEIiEz2PkybathHWy8snSXGNxsITkf3eyvIIKa8OZ
+WrlqpI3yv/5DOP8HTMCxnFuMJQtDwMcevlqebX4bCxcByuBpNYDcAHjjfLGSfMjn
+E5lZpgYWwnpic4kSjYcL9ORK9nYvlWV9P/kCYmRhIjB4AhtpWRiOfY/TKi3P2LxT
+IjSmiN/ihHtlhV/VSnBJ5PzT/lRknlrJ4kACoz7Pq9jv+aAx5ft/xE9yDa2DYs0q
+Tfuc9dUYsFjptWYrV6pfEQ+bgo1OGBXORBFcFL+2D7u9JYquKrMgosznHoEkQNLo
+0wIDAQAB
+-----END PUBLIC KEY-----
+EOS
+ end
+
+ shared_examples_for "fields with username type validation" do
+ context "when invalid input is passed" do
+ # It is not feasible to check all invalid characters. Here are a few
+ # that we probably care about.
+ it "should raise an ArgumentError" do
+ # capital letters
+ expect { key.send(field, "Bar") }.to raise_error(ArgumentError)
+ # slashes
+ expect { key.send(field, "foo/bar") }.to raise_error(ArgumentError)
+ # ?
+ expect { key.send(field, "foo?") }.to raise_error(ArgumentError)
+ # &
+ expect { key.send(field, "foo&") }.to raise_error(ArgumentError)
+ # spaces
+ expect { key.send(field, "foo ") }.to raise_error(ArgumentError)
+ end
+ end
+ end
+
+ shared_examples_for "string fields that are settable" do
+ context "when it is set with valid input" do
+ it "should set the field" do
+ key.send(field, valid_input)
+ expect(key.send(field)).to eq(valid_input)
+ end
+ end
+
+ context "when you feed it anything but a string" do
+ it "should raise an ArgumentError" do
+ expect { key.send(field, Hash.new) }.to raise_error(ArgumentError)
+ end
+ end
+ end
+
+
+ describe "when a new Chef::Key object is initialized with invalid input" do
+ it "should raise an InvalidKeyArgument" do
+ expect { Chef::Key.new("original_actor", "not_a_user_or_client") }.to raise_error(Chef::Exceptions::InvalidKeyArgument)
+ end
+ end
+
+ describe "when a new Chef::Key object is initialized with valid input" do
+ it "should be a Chef::Key" do
+ expect(key).to be_a_kind_of(Chef::Key)
+ end
+
+ it "should properly set the actor" do
+ expect(key.actor).to eq("original_actor")
+ end
+ end
+
+ describe "when actor field is set" do
+ it_should_behave_like "string fields that are settable" do
+ let(:field) { :actor }
+ let(:valid_input) { "new_field_value" }
+ end
+
+ it_should_behave_like "fields with username type validation" do
+ let(:field) { :actor }
+ end
+ end
+
+ describe "when the name field is set" do
+ it_should_behave_like "string fields that are settable" do
+ let(:field) { :name }
+ let(:valid_input) { "new_field_value" }
+ end
+ end
+
+ describe "when the private_key field is set" do
+ it_should_behave_like "string fields that are settable" do
+ let(:field) { :private_key }
+ let(:valid_input) { "new_field_value" }
+ end
+ end
+
+ describe "when the public_key field is set" do
+ it_should_behave_like "string fields that are settable" do
+ let(:field) { :public_key }
+ let(:valid_input) { "new_field_value" }
+ end
+
+ context "when create_key is true" do
+ before do
+ key.create_key true
+ end
+
+ it "should raise an InvalidKeyAttribute" do
+ expect { key.public_key public_key_string }.to raise_error(Chef::Exceptions::InvalidKeyAttribute)
+ end
+ end
+ end
+
+ describe "when the create_key field is set" do
+ context "when it is set to true" do
+ it "should set the field" do
+ key.create_key(true)
+ expect(key.create_key).to eq(true)
+ end
+ end
+
+ context "when it is set to false" do
+ it "should set the field" do
+ key.create_key(false)
+ expect(key.create_key).to eq(false)
+ end
+ end
+
+ context "when anything but a TrueClass or FalseClass is passed" do
+ it "should raise an ArgumentError" do
+ expect { key.create_key "not_a_boolean" }.to raise_error(ArgumentError)
+ end
+ end
+
+ context "when public_key is defined" do
+ before do
+ key.public_key public_key_string
+ end
+
+ it "should raise an InvalidKeyAttribute" do
+ expect { key.create_key true }.to raise_error(Chef::Exceptions::InvalidKeyAttribute)
+ end
+ end
+ end
+
+ describe "when the expiration_date field is set" do
+ context "when a valid date is passed" do
+ it_should_behave_like "string fields that are settable" do
+ let(:field) { :public_key }
+ let(:valid_input) { "2020-12-24T21:00:00Z" }
+ end
+ end
+
+ context "when infinity is passed" do
+ it_should_behave_like "string fields that are settable" do
+ let(:field) { :public_key }
+ let(:valid_input) { "infinity" }
+ end
+ end
+
+ context "when an invalid date is passed" do
+ it "should raise an ArgumentError" do
+ expect { key.expiration_date "invalid_date" }.to raise_error(ArgumentError)
+ # wrong years
+ expect { key.expiration_date "20-12-24T21:00:00Z" }.to raise_error(ArgumentError)
+ end
+
+ context "when it is a valid UTC date missing a Z" do
+ it "should raise an ArgumentError" do
+ expect { key.expiration_date "2020-12-24T21:00:00" }.to raise_error(ArgumentError)
+ end
+ end
+ end
+ end # when the expiration_date field is set
+
+ describe "when serializing to JSON" do
+ shared_examples_for "common json operations" do
+ it "should serializes as a JSON object" do
+ expect(json).to match(/^\{.+\}$/)
+ end
+
+ it "should include the actor value under the key relative to the actor_field_name passed" do
+ expect(json).to include(%Q("#{new_key.actor_field_name}":"original_actor"))
+ end
+
+ it "should include the name field when present" do
+ new_key.name("monkeypants")
+ expect(new_key.to_json).to include(%q{"name":"monkeypants"})
+ end
+
+ it "should not include the name if not present" do
+ expect(json).to_not include("name")
+ end
+
+ it "should include the public_key field when present" do
+ new_key.public_key "this_public_key"
+ expect(new_key.to_json).to include(%q("public_key":"this_public_key"))
+ end
+
+ it "should not include the public_key if not present" do
+ expect(json).to_not include("public_key")
+ end
+
+ it "should include the private_key field when present" do
+ new_key.private_key "this_public_key"
+ expect(new_key.to_json).to include(%q("private_key":"this_public_key"))
+ end
+
+ it "should not include the private_key if not present" do
+ expect(json).to_not include("private_key")
+ end
+
+ it "should include the expiration_date field when present" do
+ new_key.expiration_date "2020-12-24T21:00:00Z"
+ expect(new_key.to_json).to include(%Q("expiration_date":"2020-12-24T21:00:00Z"))
+ end
+
+ it "should not include the expiration_date if not present" do
+ expect(json).to_not include("expiration_date")
+ end
+
+ it "should include the create_key field when present" do
+ new_key.create_key true
+ expect(new_key.to_json).to include(%q("create_key":true))
+ end
+
+ it "should not include the create_key if not present" do
+ expect(json).to_not include("create_key")
+ end
+ end
+
+ context "when key is for a user" do
+ it_should_behave_like "common json operations" do
+ let(:new_key) { Chef::Key.new("original_actor", "user") }
+ let(:json) do
+ new_key.to_json
+ end
+ end
+ end
+
+ context "when key is for a client" do
+ it_should_behave_like "common json operations" do
+ let(:new_key) { Chef::Key.new("original_actor", "client") }
+ let(:json) do
+ new_key.to_json
+ end
+ end
+ end
+
+ end # when serializing to JSON
+
+ describe "when deserializing from JSON" do
+ shared_examples_for "a deserializable object" do
+ it "deserializes to a Chef::Key object" do
+ expect(key).to be_a_kind_of(Chef::Key)
+ end
+
+ it "preserves the actor" do
+ expect(key.actor).to eq("turtle")
+ end
+
+ it "preserves the name" do
+ expect(key.name).to eq("key_name")
+ end
+
+ it "includes the public key if present" do
+ expect(key.public_key).to eq(public_key_string)
+ end
+
+ it "includes the expiration_date if present" do
+ expect(key.expiration_date).to eq("infinity")
+ end
+
+ it "includes the private_key if present" do
+ expect(key.private_key).to eq("some_private_key")
+ end
+
+ it "includes the create_key if present" do
+ expect(key_with_create_key_field.create_key).to eq(true)
+ end
+ end
+
+ context "when deserializing a key for a user" do
+ it_should_behave_like "a deserializable object" do
+ let(:key) do
+ o = { "user" => "turtle",
+ "name" => "key_name",
+ "public_key" => public_key_string,
+ "private_key" => "some_private_key",
+ "expiration_date" => "infinity"}
+ Chef::Key.from_json(o.to_json)
+ end
+ let(:key_with_create_key_field) do
+ o = { "user" => "turtle",
+ "create_key" => true }
+ Chef::Key.from_json(o.to_json)
+ end
+ end
+ end
+
+ context "when deserializing a key for a client" do
+ it_should_behave_like "a deserializable object" do
+ let(:key) do
+ o = { "client" => "turtle",
+ "name" => "key_name",
+ "public_key" => public_key_string,
+ "private_key" => "some_private_key",
+ "expiration_date" => "infinity"}
+ Chef::Key.from_json(o.to_json)
+ end
+ let(:key_with_create_key_field) do
+ o = { "client" => "turtle",
+ "create_key" => true }
+ Chef::Key.from_json(o.to_json)
+ end
+ end
+ end
+ end # when deserializing from JSON
+
+
+ describe "API Interactions" do
+ let(:rest) do
+ Chef::Config[:chef_server_root] = "http://www.example.com"
+ Chef::Config[:chef_server_url] = "http://www.example.com/organizations/test_org"
+ r = double('rest')
+ allow(Chef::REST).to receive(:new).and_return(r)
+ r
+ end
+
+ let(:user_key) do
+ o = Chef::Key.new("foobar", "user")
+ o
+ end
+
+ let(:client_key) do
+ o = Chef::Key.new("foobar", "client")
+ o
+ end
+
+ describe "list" do
+ context "when listing keys for a user" do
+ let(:response) { [{"uri" => "http://www.example.com/users/keys/foobar", "name"=>"foobar", "expired"=>false}] }
+ let(:inflated_response) { {"foobar" => user_key} }
+
+ it "lists all keys" do
+ expect(rest).to receive(:get_rest).with("users/#{user_key.actor}/keys").and_return(response)
+ expect(Chef::Key.list_by_user("foobar")).to eq(response)
+ end
+
+ it "inflate all keys" do
+ allow(Chef::Key).to receive(:load_by_user).with(user_key.actor, "foobar").and_return(user_key)
+ expect(rest).to receive(:get_rest).with("users/#{user_key.actor}/keys").and_return(response)
+ expect(Chef::Key.list_by_user("foobar", true)).to eq(inflated_response)
+ end
+
+ end
+
+ context "when listing keys for a client" do
+ let(:response) { [{"uri" => "http://www.example.com/users/keys/foobar", "name"=>"foobar", "expired"=>false}] }
+ let(:inflated_response) { {"foobar" => client_key} }
+
+ it "lists all keys" do
+ expect(rest).to receive(:get_rest).with("clients/#{client_key.actor}/keys").and_return(response)
+ expect(Chef::Key.list_by_client("foobar")).to eq(response)
+ end
+
+ it "inflate all keys" do
+ allow(Chef::Key).to receive(:load_by_client).with(client_key.actor, "foobar").and_return(client_key)
+ expect(rest).to receive(:get_rest).with("clients/#{user_key.actor}/keys").and_return(response)
+ expect(Chef::Key.list_by_client("foobar", true)).to eq(inflated_response)
+ end
+
+ end
+ end
+
+
+ describe "create" do
+ shared_examples_for "create key" do
+ context "when a field is missing" do
+ it "should raise a MissingKeyAttribute" do
+ expect { key.create }.to raise_error(Chef::Exceptions::MissingKeyAttribute)
+ end
+ end
+
+ context "when the name field is missing" do
+ before do
+ key.public_key public_key_string
+ key.expiration_date "2020-12-24T21:00:00Z"
+ end
+
+ it "creates a new key via the API with the fingerprint as the name" do
+ expect(rest).to receive(:post_rest).with(url,
+ {"name" => "12:3e:33:73:0b:f4:ec:72:dc:f0:4c:51:62:27:08:76:96:24:f4:4a",
+ "public_key" => key.public_key,
+ "expiration_date" => key.expiration_date}).and_return({})
+ key.create
+ end
+ end
+
+ context "when every field is populated" do
+ before do
+ key.name "key_name"
+ key.public_key public_key_string
+ key.expiration_date "2020-12-24T21:00:00Z"
+ key.create_key false
+ end
+
+ context "when create_key is false" do
+ it "creates a new key via the API" do
+ expect(rest).to receive(:post_rest).with(url,
+ {"name" => key.name,
+ "public_key" => key.public_key,
+ "expiration_date" => key.expiration_date}).and_return({})
+ key.create
+ end
+ end
+
+ context "when create_key is true and public_key is nil" do
+
+ before do
+ key.delete_public_key
+ key.create_key true
+ $expected_output = {
+ actor_type => "foobar",
+ "name" => key.name,
+ "create_key" => true,
+ "expiration_date" => key.expiration_date
+ }
+ $expected_input = {
+ "name" => key.name,
+ "create_key" => true,
+ "expiration_date" => key.expiration_date
+ }
+ end
+
+ it "should create a new key via the API" do
+ expect(rest).to receive(:post_rest).with(url, $expected_input).and_return({})
+ key.create
+ end
+
+ context "when the server returns the private_key via key.create" do
+ before do
+ allow(rest).to receive(:post_rest).with(url, $expected_input).and_return({"private_key" => "this_private_key"})
+ end
+
+ it "key.create returns the original key plus the private_key" do
+ expect(key.create.to_hash).to eq($expected_output.merge({"private_key" => "this_private_key"}))
+ end
+ end
+ end
+
+ context "when create_key is false and public_key is nil" do
+ before do
+ key.delete_public_key
+ key.create_key false
+ end
+ it "should raise an InvalidKeyArgument" do
+ expect { key.create }.to raise_error(Chef::Exceptions::MissingKeyAttribute)
+ end
+ end
+ end
+ end
+
+ context "when creating a user key" do
+ it_should_behave_like "create key" do
+ let(:url) { "users/#{key.actor}/keys" }
+ let(:key) { user_key }
+ let(:actor_type) { "user" }
+ end
+ end
+
+ context "when creating a client key" do
+ it_should_behave_like "create key" do
+ let(:url) { "clients/#{client_key.actor}/keys" }
+ let(:key) { client_key }
+ let(:actor_type) { "client" }
+ end
+ end
+ end # create
+
+ describe "update" do
+ shared_examples_for "update key" do
+ context "when name is missing and no argument was passed to update" do
+ it "should raise an MissingKeyAttribute" do
+ expect { key.update }.to raise_error(Chef::Exceptions::MissingKeyAttribute)
+ end
+ end
+
+ context "when some fields are populated" do
+ before do
+ key.name "key_name"
+ key.expiration_date "2020-12-24T21:00:00Z"
+ end
+
+ it "should update the key via the API" do
+ expect(rest).to receive(:put_rest).with(url, key.to_hash).and_return({})
+ key.update
+ end
+ end
+
+ context "when @name is not nil and a arg is passed to update" do
+ before do
+ key.name "new_name"
+ end
+
+ it "passes @name in the body and the arg in the PUT URL" do
+ expect(rest).to receive(:put_rest).with(update_name_url, key.to_hash).and_return({})
+ key.update("old_name")
+ end
+ end
+
+ context "when the server returns a public_key and create_key is true" do
+ before do
+ key.name "key_name"
+ key.create_key true
+ allow(rest).to receive(:put_rest).with(url, key.to_hash).and_return({
+ "key" => "key_name",
+ "public_key" => public_key_string
+ })
+
+ end
+
+ it "returns a key with public_key populated" do
+ new_key = key.update
+ expect(new_key.public_key).to eq(public_key_string)
+ end
+
+ it "returns a key without create_key set" do
+ new_key = key.update
+ expect(new_key.create_key).to be_nil
+ end
+ end
+ end
+
+ context "when updating a user key" do
+ it_should_behave_like "update key" do
+ let(:url) { "users/#{key.actor}/keys/#{key.name}" }
+ let(:update_name_url) { "users/#{key.actor}/keys/old_name" }
+ let(:key) { user_key }
+ end
+ end
+
+ context "when updating a client key" do
+ it_should_behave_like "update key" do
+ let(:url) { "clients/#{client_key.actor}/keys/#{key.name}" }
+ let(:update_name_url) { "clients/#{client_key.actor}/keys/old_name" }
+ let(:key) { client_key }
+ end
+ end
+
+ end #update
+
+ describe "load" do
+ shared_examples_for "load" do
+ it "should load a named key from the API" do
+ expect(rest).to receive(:get_rest).with(url).and_return({"user" => "foobar", "name" => "test_key_name", "public_key" => public_key_string, "expiration_date" => "infinity"})
+ key = Chef::Key.send(load_method, "foobar", "test_key_name")
+ expect(key.actor).to eq("foobar")
+ expect(key.name).to eq("test_key_name")
+ expect(key.public_key).to eq(public_key_string)
+ expect(key.expiration_date).to eq("infinity")
+ end
+ end
+
+ describe "load_by_user" do
+ it_should_behave_like "load" do
+ let(:load_method) { :load_by_user }
+ let(:url) { "users/foobar/keys/test_key_name" }
+ end
+ end
+
+ describe "load_by_client" do
+ it_should_behave_like "load" do
+ let(:load_method) { :load_by_client }
+ let(:url) { "clients/foobar/keys/test_key_name" }
+ end
+ end
+
+ end #load
+
+ describe "destroy" do
+ shared_examples_for "destroy key" do
+ context "when name is missing" do
+ it "should raise an MissingKeyAttribute" do
+ expect { Chef::Key.new("username", "user").destroy }.to raise_error(Chef::Exceptions::MissingKeyAttribute)
+ end
+ end
+
+ before do
+ key.name "key_name"
+ end
+ context "when name is not missing" do
+ it "should delete the key via the API" do
+ expect(rest).to receive(:delete_rest).with(url).and_return({})
+ key.destroy
+ end
+ end
+ end
+
+ context "when destroying a user key" do
+ it_should_behave_like "destroy key" do
+ let(:url) { "users/#{key.actor}/keys/#{key.name}" }
+ let(:key) { user_key }
+ end
+ end
+
+ context "when destroying a client key" do
+ it_should_behave_like "destroy key" do
+ let(:url) { "clients/#{client_key.actor}/keys/#{key.name}" }
+ let(:key) { client_key }
+ end
+ end
+ end
+ end # API Interactions
+end
diff --git a/spec/unit/knife/bootstrap_spec.rb b/spec/unit/knife/bootstrap_spec.rb
index f1ca510ed3..0195e6d406 100644
--- a/spec/unit/knife/bootstrap_spec.rb
+++ b/spec/unit/knife/bootstrap_spec.rb
@@ -23,7 +23,7 @@ require 'net/ssh'
describe Chef::Knife::Bootstrap do
before do
- allow(Chef::Platform).to receive(:windows?) { false }
+ allow(ChefConfig).to receive(:windows?) { false }
end
let(:knife) do
Chef::Log.logger = Logger.new(StringIO.new)
@@ -531,6 +531,7 @@ describe Chef::Knife::Bootstrap do
describe "when running the bootstrap" do
let(:knife_ssh) do
knife.name_args = ["foo.example.com"]
+ knife.config[:chef_node_name] = "foo.example.com"
knife.config[:ssh_user] = "rooty"
knife.config[:identity_file] = "~/.ssh/me.rsa"
allow(knife).to receive(:render_template).and_return("")
@@ -590,6 +591,12 @@ describe Chef::Knife::Bootstrap do
expect(knife.chef_vault_handler).not_to receive(:run).with(node_name: knife.config[:chef_node_name])
knife.run
end
+
+ it "raises an exception if the config[:chef_node_name] is not present" do
+ knife.config[:chef_node_name] = nil
+
+ expect { knife.run }.to raise_error(SystemExit)
+ end
end
context "when the validation key is not present" do
@@ -604,6 +611,12 @@ describe Chef::Knife::Bootstrap do
expect(knife.chef_vault_handler).to receive(:run).with(node_name: knife.config[:chef_node_name])
knife.run
end
+
+ it "raises an exception if the config[:chef_node_name] is not present" do
+ knife.config[:chef_node_name] = nil
+
+ expect { knife.run }.to raise_error(SystemExit)
+ end
end
context "when the validation_key is nil" do
diff --git a/spec/unit/knife/client_create_spec.rb b/spec/unit/knife/client_create_spec.rb
index 10d386b5ff..8fecfc885f 100644
--- a/spec/unit/knife/client_create_spec.rb
+++ b/spec/unit/knife/client_create_spec.rb
@@ -22,6 +22,8 @@ Chef::Knife::ClientCreate.load_deps
describe Chef::Knife::ClientCreate do
let(:stderr) { StringIO.new }
+ let(:stdout) { StringIO.new }
+
let(:default_client_hash) do
{
@@ -32,84 +34,153 @@ describe Chef::Knife::ClientCreate do
end
let(:client) do
- c = double("Chef::ApiClient")
- allow(c).to receive(:save).and_return({"private_key" => ""})
- allow(c).to receive(:to_s).and_return("client[adam]")
- c
+ Chef::ApiClient.new
end
let(:knife) do
k = Chef::Knife::ClientCreate.new
- k.name_args = [ "adam" ]
- k.ui.config[:disable_editing] = true
+ k.name_args = []
+ allow(k).to receive(:client).and_return(client)
+ allow(k).to receive(:edit_data).with(client).and_return(client)
allow(k.ui).to receive(:stderr).and_return(stderr)
- allow(k.ui).to receive(:stdout).and_return(stderr)
+ allow(k.ui).to receive(:stdout).and_return(stdout)
k
end
+ before do
+ allow(client).to receive(:to_s).and_return("client[adam]")
+ allow(knife).to receive(:create_client).and_return(client)
+ end
+
before(:each) do
Chef::Config[:node_name] = "webmonkey.example.com"
end
describe "run" do
- it "should create and save the ApiClient" do
- expect(Chef::ApiClient).to receive(:from_hash).and_return(client)
- expect(client).to receive(:save)
- knife.run
+ context "when nothing is passed" do
+ # from spec/support/shared/unit/knife_shared.rb
+ it_should_behave_like "mandatory field missing" do
+ let(:name_args) { [] }
+ let(:fieldname) { 'client name' }
+ end
end
- it "should print a message upon creation" do
- expect(Chef::ApiClient).to receive(:from_hash).and_return(client)
- expect(client).to receive(:save)
- knife.run
- expect(stderr.string).to match /Created client.*adam/i
- end
+ context "when clientname is passed" do
+ before do
+ knife.name_args = ['adam']
+ end
- it "should set the Client name" do
- expect(Chef::ApiClient).to receive(:from_hash).with(hash_including("name" => "adam")).and_return(client)
- knife.run
- end
+ context "when public_key and prevent_keygen are passed" do
+ before do
+ knife.config[:public_key] = "some_key"
+ knife.config[:prevent_keygen] = true
+ end
+
+ it "prints the usage" do
+ expect(knife).to receive(:show_usage)
+ expect { knife.run }.to raise_error(SystemExit)
+ end
+
+ it "prints a relevant error message" do
+ expect { knife.run }.to raise_error(SystemExit)
+ expect(stderr.string).to match /You cannot pass --public-key and --prevent-keygen/
+ end
+ end
- it "by default it is not an admin" do
- expect(Chef::ApiClient).to receive(:from_hash).with(hash_including("admin" => false)).and_return(client)
- knife.run
- end
+ it "should create the ApiClient" do
+ expect(knife).to receive(:create_client)
+ knife.run
+ end
- it "by default it is not a validator" do
- expect(Chef::ApiClient).to receive(:from_hash).with(hash_including("validator" => false)).and_return(client)
- knife.run
- end
+ it "should print a message upon creation" do
+ expect(knife).to receive(:create_client)
+ knife.run
+ expect(stderr.string).to match /Created client.*adam/i
+ end
- it "should allow you to edit the data" do
- expect(knife).to receive(:edit_hash).with(default_client_hash).and_return(default_client_hash)
- allow(Chef::ApiClient).to receive(:from_hash).and_return(client)
- knife.run
- end
+ it "should set the Client name" do
+ knife.run
+ expect(client.name).to eq("adam")
+ end
- describe "with -f or --file" do
- it "should write the private key to a file" do
- knife.config[:file] = "/tmp/monkeypants"
- allow_any_instance_of(Chef::ApiClient).to receive(:save).and_return({ 'private_key' => "woot" })
- filehandle = double("Filehandle")
- expect(filehandle).to receive(:print).with('woot')
- expect(File).to receive(:open).with("/tmp/monkeypants", "w").and_yield(filehandle)
+ it "by default it is not an admin" do
knife.run
+ expect(client.admin).to be_falsey
end
- end
- describe "with -a or --admin" do
- it "should create an admin client" do
- knife.config[:admin] = true
- expect(Chef::ApiClient).to receive(:from_hash).with(hash_including("admin" => true)).and_return(client)
+ it "by default it is not a validator" do
knife.run
+ expect(client.admin).to be_falsey
end
- end
- describe "with --validator" do
- it "should create an validator client" do
- knife.config[:validator] = true
- expect(Chef::ApiClient).to receive(:from_hash).with(hash_including("validator" => true)).and_return(client)
+ it "by default it should set create_key to true" do
knife.run
+ expect(client.create_key).to be_truthy
+ end
+
+ it "should allow you to edit the data" do
+ expect(knife).to receive(:edit_data).with(client).and_return(client)
+ knife.run
+ end
+
+ describe "with -f or --file" do
+ before do
+ client.private_key "woot"
+ end
+
+ it "should write the private key to a file" do
+ knife.config[:file] = "/tmp/monkeypants"
+ filehandle = double("Filehandle")
+ expect(filehandle).to receive(:print).with('woot')
+ expect(File).to receive(:open).with("/tmp/monkeypants", "w").and_yield(filehandle)
+ knife.run
+ end
+ end
+
+ describe "with -a or --admin" do
+ before do
+ knife.config[:admin] = true
+ end
+
+ it "should create an admin client" do
+ knife.run
+ expect(client.admin).to be_truthy
+ end
+ end
+
+ describe "with -p or --public-key" do
+ before do
+ knife.config[:public_key] = 'some_key'
+ allow(File).to receive(:read).and_return('some_key')
+ allow(File).to receive(:expand_path)
+ end
+
+ it "sets the public key" do
+ knife.run
+ expect(client.public_key).to eq('some_key')
+ end
+ end
+
+ describe "with -k or --prevent-keygen" do
+ before do
+ knife.config[:prevent_keygen] = true
+ end
+
+ it "does not set create_key" do
+ knife.run
+ expect(client.create_key).to be_falsey
+ end
+ end
+
+ describe "with --validator" do
+ before do
+ knife.config[:validator] = true
+ end
+
+ it "should create an validator client" do
+ knife.run
+ expect(client.validator).to be_truthy
+ end
end
end
end
diff --git a/spec/unit/knife/core/subcommand_loader_spec.rb b/spec/unit/knife/core/subcommand_loader_spec.rb
index 7f9308b28a..219a1f2906 100644
--- a/spec/unit/knife/core/subcommand_loader_spec.rb
+++ b/spec/unit/knife/core/subcommand_loader_spec.rb
@@ -22,14 +22,14 @@ describe Chef::Knife::SubcommandLoader do
let(:loader) { Chef::Knife::SubcommandLoader.new(File.join(CHEF_SPEC_DATA, 'knife-site-subcommands')) }
let(:home) { File.join(CHEF_SPEC_DATA, 'knife-home') }
let(:plugin_dir) { File.join(home, '.chef', 'plugins', 'knife') }
-
+
before do
- allow(Chef::Platform).to receive(:windows?) { false }
- Chef::Util::PathHelper.class_variable_set(:@@home_dir, home)
+ allow(ChefConfig).to receive(:windows?) { false }
+ Chef::Util::PathHelper.class_variable_set(:@@home_dir, home)
end
after do
- Chef::Util::PathHelper.class_variable_set(:@@home_dir, nil)
+ Chef::Util::PathHelper.class_variable_set(:@@home_dir, nil)
end
it "builds a list of the core subcommand file require paths" do
@@ -106,6 +106,18 @@ describe Chef::Knife::SubcommandLoader do
# Chef 12.0.0.rc.0 gem also:
"/opt/chefdk/embedded/lib/ruby/gems/2.1.0/gems/chef-#{Chef::VERSION}.rc.0/lib/chef/knife/thing.rb",
+ # Test that we ignore the platform suffix when checking for different
+ # gem versions.
+ "/opt/chefdk/embedded/lib/ruby/gems/2.1.0/gems/chef-#{Chef::VERSION}-x86-mingw32/lib/chef/knife/valid.rb",
+ "/opt/chefdk/embedded/lib/ruby/gems/2.1.0/gems/chef-#{Chef::VERSION}-i386-mingw64/lib/chef/knife/valid-too.rb",
+ "/opt/chefdk/embedded/lib/ruby/gems/2.1.0/gems/chef-#{Chef::VERSION}-mswin32/lib/chef/knife/also-valid.rb",
+ "/opt/chefdk/embedded/lib/ruby/gems/2.1.0/gems/chef-#{Chef::VERSION}-universal-mingw32/lib/chef/knife/universal-is-valid.rb",
+ # ...but don't ignore the .rc / .dev parts in the case when we have
+ # platform suffixes
+ "/opt/chefdk/embedded/lib/ruby/gems/2.1.0/gems/chef-#{Chef::VERSION}.rc.0-x86-mingw32/lib/chef/knife/invalid.rb",
+ "/opt/chefdk/embedded/lib/ruby/gems/2.1.0/gems/chef-#{Chef::VERSION}.dev-mswin32/lib/chef/knife/invalid-too.rb",
+ "/opt/chefdk/embedded/lib/ruby/gems/2.1.0/gems/chef-#{Chef::VERSION}.dev.0-x86-mingw64/lib/chef/knife/still-invalid.rb",
+
# This command is "extra" compared to what's in the embedded/apps/chef install:
"/opt/chefdk/embedded/lib/ruby/gems/2.1.0/gems/chef-1.0.0/lib/chef/knife/data_bag_secret_options.rb",
"/opt/chefdk/embedded/lib/ruby/gems/2.1.0/gems/chef-vault-2.2.4/lib/chef/knife/decrypt.rb",
@@ -133,6 +145,10 @@ describe Chef::Knife::SubcommandLoader do
"/opt/chefdk/embedded/apps/chef/lib/chef/knife/bootstrap.rb",
"/opt/chefdk/embedded/apps/chef/lib/chef/knife/client_bulk_delete.rb",
"/opt/chefdk/embedded/apps/chef/lib/chef/knife/client_create.rb",
+ "/opt/chefdk/embedded/lib/ruby/gems/2.1.0/gems/chef-#{Chef::VERSION}-x86-mingw32/lib/chef/knife/valid.rb",
+ "/opt/chefdk/embedded/lib/ruby/gems/2.1.0/gems/chef-#{Chef::VERSION}-i386-mingw64/lib/chef/knife/valid-too.rb",
+ "/opt/chefdk/embedded/lib/ruby/gems/2.1.0/gems/chef-#{Chef::VERSION}-mswin32/lib/chef/knife/also-valid.rb",
+ "/opt/chefdk/embedded/lib/ruby/gems/2.1.0/gems/chef-#{Chef::VERSION}-universal-mingw32/lib/chef/knife/universal-is-valid.rb",
"/opt/chefdk/embedded/lib/ruby/gems/2.1.0/gems/chef-vault-2.2.4/lib/chef/knife/decrypt.rb",
"/opt/chefdk/embedded/lib/ruby/gems/2.1.0/gems/knife-spork-1.4.1/lib/chef/knife/spork-bump.rb",
"/opt/chefdk/embedded/lib/ruby/gems/2.1.0/gems/chef-foo-#{Chef::VERSION}/lib/chef/knife/chef-foo.rb",
diff --git a/spec/unit/knife/core/ui_spec.rb b/spec/unit/knife/core/ui_spec.rb
index ac42ad6dd6..ab420518a3 100644
--- a/spec/unit/knife/core/ui_spec.rb
+++ b/spec/unit/knife/core/ui_spec.rb
@@ -368,6 +368,20 @@ EOM
@ui.config[:attribute] = "keys.keys"
expect(@ui.format_for_display(input)).to eq({ "sample-data-bag-item" => { "keys.keys" => "values" } })
end
+
+ it "should return the name attribute" do
+ allow_any_instance_of(Chef::Node).to receive(:name).and_return("chef.localdomain")
+ input = Chef::Node.new
+ @ui.config[:attribute] = "name"
+ expect(@ui.format_for_display(input)).to eq( {"chef.localdomain"=>{"name"=>"chef.localdomain"} })
+ end
+
+ it "returns nil when given an attribute path that isn't a name or attribute" do
+ input = { "keys" => {"keys" => "values"}, "hi" => "ho", "id" => "sample-data-bag-item" }
+ non_existing_path = "nope.nada.nothingtoseehere"
+ @ui.config[:attribute] = non_existing_path
+ expect(@ui.format_for_display(input)).to eq({ "sample-data-bag-item" => { non_existing_path => nil } })
+ end
end
describe "with --run-list passed" do
@@ -420,7 +434,7 @@ EOM
before(:each) do
stdout = double('StringIO', :tty? => true)
allow(@ui).to receive(:stdout).and_return(stdout)
- allow(Chef::Platform).to receive(:windows?) { true }
+ allow(ChefConfig).to receive(:windows?) { true }
Chef::Config.reset
end
diff --git a/spec/unit/knife/data_bag_from_file_spec.rb b/spec/unit/knife/data_bag_from_file_spec.rb
index 3882bff349..8b6502145c 100644
--- a/spec/unit/knife/data_bag_from_file_spec.rb
+++ b/spec/unit/knife/data_bag_from_file_spec.rb
@@ -26,7 +26,7 @@ Chef::Knife::DataBagFromFile.load_deps
describe Chef::Knife::DataBagFromFile do
before :each do
- allow(Chef::Platform).to receive(:windows?) { false }
+ allow(ChefConfig).to receive(:windows?) { false }
Chef::Config[:node_name] = "webmonkey.example.com"
FileUtils.mkdir_p([db_folder, db_folder2])
db_file.write(Chef::JSONCompat.to_json(plain_data))
diff --git a/spec/unit/knife/environment_from_file_spec.rb b/spec/unit/knife/environment_from_file_spec.rb
index d150e5ee64..11ad23c919 100644
--- a/spec/unit/knife/environment_from_file_spec.rb
+++ b/spec/unit/knife/environment_from_file_spec.rb
@@ -23,7 +23,7 @@ Chef::Knife::EnvironmentFromFile.load_deps
describe Chef::Knife::EnvironmentFromFile do
before(:each) do
- allow(Chef::Platform).to receive(:windows?) { false }
+ allow(ChefConfig).to receive(:windows?) { false }
@knife = Chef::Knife::EnvironmentFromFile.new
@stdout = StringIO.new
allow(@knife.ui).to receive(:stdout).and_return(@stdout)
diff --git a/spec/unit/knife/key_create_spec.rb b/spec/unit/knife/key_create_spec.rb
new file mode 100644
index 0000000000..5998e10274
--- /dev/null
+++ b/spec/unit/knife/key_create_spec.rb
@@ -0,0 +1,224 @@
+#
+# Author:: Tyler Cloke (<tyler@chef.io>)
+# Copyright:: Copyright (c) 2015 Chef Software, 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/knife/user_key_create'
+require 'chef/knife/client_key_create'
+require 'chef/knife/key_create'
+require 'chef/key'
+
+describe "key create commands that inherit knife" do
+ shared_examples_for "a key create command" do
+ let(:stderr) { StringIO.new }
+ let(:params) { [] }
+ let(:service_object) { instance_double(Chef::Knife::KeyCreate) }
+ let(:command) do
+ c = described_class.new([])
+ c.ui.config[:disable_editing] = true
+ allow(c.ui).to receive(:stderr).and_return(stderr)
+ allow(c.ui).to receive(:stdout).and_return(stderr)
+ allow(c).to receive(:show_usage)
+ c
+ end
+
+ context "after apply_params! is called with valid args" do
+ let(:params) { ["charmander"] }
+ before do
+ command.apply_params!(params)
+ end
+
+ context "when the service object is called" do
+ it "creates a new instance of Chef::Knife::KeyCreate with the correct args" do
+ expect(Chef::Knife::KeyCreate).to receive(:new).
+ with("charmander", command.actor_field_name, command.ui, command.config).
+ and_return(service_object)
+ command.service_object
+ end
+ end # when the service object is called
+ end # after apply_params! is called with valid args
+ end # a key create command
+
+ describe Chef::Knife::UserKeyCreate do
+ it_should_behave_like "a key create command"
+ # defined in key_helper.rb
+ it_should_behave_like "a knife key command" do
+ let(:service_object) { instance_double(Chef::Knife::KeyCreate) }
+ let(:params) { ["charmander"] }
+ end
+ end
+
+ describe Chef::Knife::ClientKeyCreate do
+ it_should_behave_like "a key create command"
+ # defined in key_helper.rb
+ it_should_behave_like "a knife key command" do
+ let(:service_object) { instance_double(Chef::Knife::KeyCreate) }
+ let(:params) { ["charmander"] }
+ end
+ end
+end
+
+describe Chef::Knife::KeyCreate do
+ let(:public_key) {
+ "-----BEGIN PUBLIC KEY-----
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvPo+oNPB7uuNkws0fC02
+KxSwdyqPLu0fhI1pOweNKAZeEIiEz2PkybathHWy8snSXGNxsITkf3eyvIIKa8OZ
+WrlqpI3yv/5DOP8HTMCxnFuMJQtDwMcevlqebX4bCxcByuBpNYDcAHjjfLGSfMjn
+E5lZpgYWwnpic4kSjYcL9ORK9nYvlWV9P/kCYmRhIjB4AhtpWRiOfY/TKi3P2LxT
+IjSmiN/ihHtlhV/VSnBJ5PzT/lRknlrJ4kACoz7Pq9jv+aAx5ft/xE9yDa2DYs0q
+Tfuc9dUYsFjptWYrV6pfEQ+bgo1OGBXORBFcFL+2D7u9JYquKrMgosznHoEkQNLo
+0wIDAQAB
+-----END PUBLIC KEY-----"
+ }
+ let(:config) { Hash.new }
+ let(:actor) { "charmander" }
+ let(:ui) { instance_double("Chef::Knife::UI") }
+
+ shared_examples_for "key create run command" do
+ let(:key_create_object) {
+ described_class.new(actor, actor_field_name, ui, config)
+ }
+
+ context "when public_key and key_name weren't passed" do
+ it "raises a Chef::Exceptions::KeyCommandInputError with the proper error message" do
+ expect{ key_create_object.run }.to raise_error(Chef::Exceptions::KeyCommandInputError, key_create_object.public_key_or_key_name_error_msg)
+ end
+ end
+
+ context "when the command is run" do
+ let(:expected_hash) {
+ {
+ actor_field_name => "charmander"
+ }
+ }
+
+ before do
+ allow(File).to receive(:read).and_return(public_key)
+ allow(File).to receive(:expand_path)
+
+ allow(key_create_object).to receive(:output_private_key_to_file)
+ allow(key_create_object).to receive(:display_private_key)
+ allow(key_create_object).to receive(:edit_data).and_return(expected_hash)
+ allow(key_create_object).to receive(:create_key_from_hash).and_return(Chef::Key.from_hash(expected_hash))
+ allow(key_create_object).to receive(:display_info)
+ end
+
+ context "when a valid hash is passed" do
+ let(:key_name) { "charmander-key" }
+ let(:valid_expiration_date) { "2020-12-24T21:00:00Z" }
+ let(:expected_hash) {
+ {
+ actor_field_name => "charmander",
+ "public_key" => public_key,
+ "expiration_date" => valid_expiration_date,
+ "key_name" => key_name
+ }
+ }
+ before do
+ key_create_object.config[:public_key] = "public_key_path"
+ key_create_object.config[:expiration_Date] = valid_expiration_date,
+ key_create_object.config[:key_name] = key_name
+ end
+
+ it "creates the proper hash" do
+ expect(key_create_object).to receive(:create_key_from_hash).with(expected_hash)
+ key_create_object.run
+ end
+ end
+
+ context "when public_key is passed" do
+ let(:expected_hash) {
+ {
+ actor_field_name => "charmander",
+ "public_key" => public_key
+ }
+ }
+ before do
+ key_create_object.config[:public_key] = "public_key_path"
+ end
+
+ it "calls File.expand_path with the public_key input" do
+ expect(File).to receive(:expand_path).with("public_key_path")
+ key_create_object.run
+ end
+ end # when public_key is passed
+
+ context "when public_key isn't passed and key_name is" do
+ let(:expected_hash) {
+ {
+ actor_field_name => "charmander",
+ "name" => "charmander-key",
+ "create_key" => true
+ }
+ }
+ before do
+ key_create_object.config[:key_name] = "charmander-key"
+ end
+
+ it "should set create_key to true" do
+ expect(key_create_object).to receive(:create_key_from_hash).with(expected_hash)
+ key_create_object.run
+ end
+ end
+
+ context "when the server returns a private key" do
+ let(:expected_hash) {
+ {
+ actor_field_name => "charmander",
+ "public_key" => public_key,
+ "private_key" => "super_private"
+ }
+ }
+
+ before do
+ key_create_object.config[:public_key] = "public_key_path"
+ end
+
+ context "when file is not passed" do
+ it "calls display_private_key with the private_key" do
+ expect(key_create_object).to receive(:display_private_key).with("super_private")
+ key_create_object.run
+ end
+ end
+
+ context "when file is passed" do
+ before do
+ key_create_object.config[:file] = "/fake/file"
+ end
+
+ it "calls output_private_key_to_file with the private_key" do
+ expect(key_create_object).to receive(:output_private_key_to_file).with("super_private")
+ key_create_object.run
+ end
+ end
+ end # when the server returns a private key
+ end # when the command is run
+ end #key create run command"
+
+ context "when actor_field_name is 'user'" do
+ it_should_behave_like "key create run command" do
+ let(:actor_field_name) { "user" }
+ end
+ end
+
+ context "when actor_field_name is 'client'" do
+ it_should_behave_like "key create run command" do
+ let(:actor_field_name) { "client" }
+ end
+ end
+end
+
diff --git a/spec/unit/knife/key_delete_spec.rb b/spec/unit/knife/key_delete_spec.rb
new file mode 100644
index 0000000000..1d4b9f825f
--- /dev/null
+++ b/spec/unit/knife/key_delete_spec.rb
@@ -0,0 +1,135 @@
+#
+# Author:: Tyler Cloke (<tyler@chef.io>)
+# Copyright:: Copyright (c) 2015 Chef Software, 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/knife/user_key_delete'
+require 'chef/knife/client_key_delete'
+require 'chef/knife/key_delete'
+require 'chef/key'
+
+describe "key delete commands that inherit knife" do
+ shared_examples_for "a key delete command" do
+ let(:stderr) { StringIO.new }
+ let(:params) { [] }
+ let(:service_object) { instance_double(Chef::Knife::KeyDelete) }
+ let(:command) do
+ c = described_class.new([])
+ c.ui.config[:disable_editing] = true
+ allow(c.ui).to receive(:stderr).and_return(stderr)
+ allow(c.ui).to receive(:stdout).and_return(stderr)
+ allow(c).to receive(:show_usage)
+ c
+ end
+
+ context "after apply_params! is called with valid args" do
+ let(:params) { ["charmander", "charmander-key"] }
+ before do
+ command.apply_params!(params)
+ end
+
+ context "when the service object is called" do
+ it "creates a new instance of Chef::Knife::KeyDelete with the correct args" do
+ expect(Chef::Knife::KeyDelete).to receive(:new).
+ with("charmander-key", "charmander", command.actor_field_name, command.ui).
+ and_return(service_object)
+ command.service_object
+ end
+ end # when the service object is called
+ end # after apply_params! is called with valid args
+ end # a key delete command
+
+ describe Chef::Knife::UserKeyDelete do
+ it_should_behave_like "a key delete command"
+ # defined in key_helpers.rb
+ it_should_behave_like "a knife key command with a keyname as the second arg"
+ it_should_behave_like "a knife key command" do
+ let(:service_object) { instance_double(Chef::Knife::KeyDelete) }
+ let(:params) { ["charmander", "charmander-key"] }
+ end
+ end
+
+ describe Chef::Knife::ClientKeyDelete do
+ it_should_behave_like "a key delete command"
+ # defined in key_helpers.rb
+ it_should_behave_like "a knife key command with a keyname as the second arg"
+ it_should_behave_like "a knife key command" do
+ let(:service_object) { instance_double(Chef::Knife::KeyDelete) }
+ let(:params) { ["charmander", "charmander-key"] }
+ end
+ end
+end
+
+describe Chef::Knife::KeyDelete do
+ let(:actor) { "charmander" }
+ let(:keyname) { "charmander-key" }
+ let(:ui) { instance_double("Chef::Knife::UI") }
+
+ shared_examples_for "key delete run command" do
+ let(:key_delete_object) {
+ described_class.new(keyname, actor, actor_field_name, ui)
+ }
+
+ before do
+ allow_any_instance_of(Chef::Key).to receive(:destroy)
+ allow(key_delete_object).to receive(:print_destroyed)
+ allow(key_delete_object).to receive(:confirm!)
+ end
+
+ context "when the command is run" do
+ it "calls Chef::Key.new with the proper input" do
+ expect(Chef::Key).to receive(:new).with(actor, actor_field_name).and_call_original
+ key_delete_object.run
+ end
+
+ it "calls name on the Chef::Key instance with the proper input" do
+ expect_any_instance_of(Chef::Key).to receive(:name).with(keyname)
+ key_delete_object.run
+ end
+
+ it "calls destroy on the Chef::Key instance" do
+ expect_any_instance_of(Chef::Key).to receive(:destroy).once
+ key_delete_object.run
+ end
+
+ it "calls confirm!" do
+ expect(key_delete_object).to receive(:confirm!)
+ key_delete_object.run
+ end
+
+ it "calls print_destroyed" do
+ expect(key_delete_object).to receive(:print_destroyed)
+ key_delete_object.run
+ end
+ end # when the command is run
+
+
+ end # key delete run command
+
+ context "when actor_field_name is 'user'" do
+ it_should_behave_like "key delete run command" do
+ let(:actor_field_name) { "user" }
+ end
+ end
+
+ context "when actor_field_name is 'client'" do
+ it_should_behave_like "key delete run command" do
+ let(:actor_field_name) { "client" }
+ end
+ end
+end
+
diff --git a/spec/unit/knife/key_edit_spec.rb b/spec/unit/knife/key_edit_spec.rb
new file mode 100644
index 0000000000..538b91de2d
--- /dev/null
+++ b/spec/unit/knife/key_edit_spec.rb
@@ -0,0 +1,267 @@
+#
+# Author:: Tyler Cloke (<tyler@chef.io>)
+# Copyright:: Copyright (c) 2015 Chef Software, 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/knife/user_key_edit'
+require 'chef/knife/client_key_edit'
+require 'chef/knife/key_edit'
+require 'chef/key'
+
+describe "key edit commands that inherit knife" do
+ shared_examples_for "a key edit command" do
+ let(:stderr) { StringIO.new }
+ let(:params) { [] }
+ let(:service_object) { instance_double(Chef::Knife::KeyEdit) }
+ let(:command) do
+ c = described_class.new([])
+ c.ui.config[:disable_editing] = true
+ allow(c.ui).to receive(:stderr).and_return(stderr)
+ allow(c.ui).to receive(:stdout).and_return(stderr)
+ allow(c).to receive(:show_usage)
+ c
+ end
+
+ context "after apply_params! is called with valid args" do
+ let(:params) { ["charmander", "charmander-key"] }
+ before do
+ command.apply_params!(params)
+ end
+
+ context "when the service object is called" do
+ it "creates a new instance of Chef::Knife::KeyEdit with the correct args" do
+ expect(Chef::Knife::KeyEdit).to receive(:new).
+ with("charmander-key", "charmander", command.actor_field_name, command.ui, command.config).
+ and_return(service_object)
+ command.service_object
+ end
+ end # when the service object is called
+ end # after apply_params! is called with valid args
+ end # a key edit command
+
+ describe Chef::Knife::UserKeyEdit do
+ it_should_behave_like "a key edit command"
+ # defined in key_helpers.rb
+ it_should_behave_like "a knife key command with a keyname as the second arg"
+ it_should_behave_like "a knife key command" do
+ let(:service_object) { instance_double(Chef::Knife::KeyEdit) }
+ let(:params) { ["charmander", "charmander-key"] }
+ end
+ end
+
+ describe Chef::Knife::ClientKeyEdit do
+ it_should_behave_like "a key edit command"
+ # defined in key_helpers.rb
+ it_should_behave_like "a knife key command with a keyname as the second arg"
+ it_should_behave_like "a knife key command" do
+ let(:service_object) { instance_double(Chef::Knife::KeyEdit) }
+ let(:params) { ["charmander", "charmander-key"] }
+ end
+ end
+end
+
+describe Chef::Knife::KeyEdit do
+ let(:public_key) {
+ "-----BEGIN PUBLIC KEY-----
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvPo+oNPB7uuNkws0fC02
+KxSwdyqPLu0fhI1pOweNKAZeEIiEz2PkybathHWy8snSXGNxsITkf3eyvIIKa8OZ
+WrlqpI3yv/5DOP8HTMCxnFuMJQtDwMcevlqebX4bCxcByuBpNYDcAHjjfLGSfMjn
+E5lZpgYWwnpic4kSjYcL9ORK9nYvlWV9P/kCYmRhIjB4AhtpWRiOfY/TKi3P2LxT
+IjSmiN/ihHtlhV/VSnBJ5PzT/lRknlrJ4kACoz7Pq9jv+aAx5ft/xE9yDa2DYs0q
+Tfuc9dUYsFjptWYrV6pfEQ+bgo1OGBXORBFcFL+2D7u9JYquKrMgosznHoEkQNLo
+0wIDAQAB
+-----END PUBLIC KEY-----"
+ }
+ let(:config) { Hash.new }
+ let(:actor) { "charmander" }
+ let(:keyname) { "charmander-key" }
+ let(:ui) { instance_double("Chef::Knife::UI") }
+
+ shared_examples_for "key edit run command" do
+ let(:key_edit_object) {
+ described_class.new(keyname, actor, actor_field_name, ui, config)
+ }
+
+ context "when the command is run" do
+ let(:expected_hash) {
+ {
+ actor_field_name => "charmander"
+ }
+ }
+ let(:new_keyname) { "charizard-key" }
+
+ before do
+ allow(File).to receive(:read).and_return(public_key)
+ allow(File).to receive(:expand_path)
+
+ allow(key_edit_object).to receive(:output_private_key_to_file)
+ allow(key_edit_object).to receive(:display_private_key)
+ allow(key_edit_object).to receive(:edit_data).and_return(expected_hash)
+ allow(key_edit_object).to receive(:display_info)
+ end
+
+
+ context "when public_key and create_key are passed" do
+ before do
+ key_edit_object.config[:public_key] = "public_key_path"
+ key_edit_object.config[:create_key] = true
+ end
+
+ it "raises a Chef::Exceptions::KeyCommandInputError with the proper error message" do
+ expect{ key_edit_object.run }.to raise_error(Chef::Exceptions::KeyCommandInputError, key_edit_object.public_key_and_create_key_error_msg)
+ end
+ end
+
+ context "when key_name is passed" do
+ let(:expected_hash) {
+ {
+ actor_field_name => "charmander",
+ "name" => new_keyname
+ }
+ }
+ before do
+ key_edit_object.config[:key_name] = new_keyname
+ allow_any_instance_of(Chef::Key).to receive(:update)
+ end
+
+ it "update_key_from_hash gets passed a hash with new key name" do
+ expect(key_edit_object).to receive(:update_key_from_hash).with(expected_hash).and_return(Chef::Key.from_hash(expected_hash))
+ key_edit_object.run
+ end
+
+ it "Chef::Key.update is passed a string containing the original keyname" do
+ expect_any_instance_of(Chef::Key).to receive(:update).with(/#{keyname}/).and_return(Chef::Key.from_hash(expected_hash))
+ key_edit_object.run
+ end
+
+ it "Chef::Key.update is not passed a string containing the new keyname" do
+ expect_any_instance_of(Chef::Key).not_to receive(:update).with(/#{new_keyname}/)
+ allow_any_instance_of(Chef::Key).to receive(:update).and_return(Chef::Key.from_hash(expected_hash))
+ key_edit_object.run
+ end
+ end
+
+ context "when public_key, key_name, and expiration_date are passed" do
+ let(:expected_hash) {
+ {
+ actor_field_name => "charmander",
+ "public_key" => public_key,
+ "name" => new_keyname,
+ "expiration_date" => "infinity"
+ }
+ }
+ before do
+ key_edit_object.config[:public_key] = "this-public-key"
+ key_edit_object.config[:key_name] = new_keyname
+ key_edit_object.config[:expiration_date] = "infinity"
+ allow(key_edit_object).to receive(:update_key_from_hash).and_return(Chef::Key.from_hash(expected_hash))
+ end
+
+ it "passes the right hash to update_key_from_hash" do
+ expect(key_edit_object).to receive(:update_key_from_hash).with(expected_hash)
+ key_edit_object.run
+ end
+ end
+
+ context "when create_key is passed" do
+ let(:expected_hash) {
+ {
+ actor_field_name => "charmander",
+ "create_key" => true
+ }
+ }
+
+ before do
+ key_edit_object.config[:create_key] = true
+ allow(key_edit_object).to receive(:update_key_from_hash).and_return(Chef::Key.from_hash(expected_hash))
+ end
+
+ it "passes the right hash to update_key_from_hash" do
+ expect(key_edit_object).to receive(:update_key_from_hash).with(expected_hash)
+ key_edit_object.run
+ end
+ end
+
+ context "when public_key is passed" do
+ let(:expected_hash) {
+ {
+ actor_field_name => "charmander",
+ "public_key" => public_key
+ }
+ }
+ before do
+ allow(key_edit_object).to receive(:update_key_from_hash).and_return(Chef::Key.from_hash(expected_hash))
+ key_edit_object.config[:public_key] = "public_key_path"
+ end
+
+ it "calls File.expand_path with the public_key input" do
+ expect(File).to receive(:expand_path).with("public_key_path")
+ key_edit_object.run
+ end
+ end # when public_key is passed
+
+ context "when the server returns a private key" do
+ let(:expected_hash) {
+ {
+ actor_field_name => "charmander",
+ "public_key" => public_key,
+ "private_key" => "super_private"
+ }
+ }
+
+ before do
+ allow(key_edit_object).to receive(:update_key_from_hash).and_return(Chef::Key.from_hash(expected_hash))
+ key_edit_object.config[:public_key] = "public_key_path"
+ end
+
+ context "when file is not passed" do
+ it "calls display_private_key with the private_key" do
+ expect(key_edit_object).to receive(:display_private_key).with("super_private")
+ key_edit_object.run
+ end
+ end
+
+ context "when file is passed" do
+ before do
+ key_edit_object.config[:file] = "/fake/file"
+ end
+
+ it "calls output_private_key_to_file with the private_key" do
+ expect(key_edit_object).to receive(:output_private_key_to_file).with("super_private")
+ key_edit_object.run
+ end
+ end
+ end # when the server returns a private key
+
+ end # when the command is run
+
+
+
+ end # key edit run command
+
+ context "when actor_field_name is 'user'" do
+ it_should_behave_like "key edit run command" do
+ let(:actor_field_name) { "user" }
+ end
+ end
+
+ context "when actor_field_name is 'client'" do
+ it_should_behave_like "key edit run command" do
+ let(:actor_field_name) { "client" }
+ end
+ end
+end
diff --git a/spec/unit/knife/key_helper.rb b/spec/unit/knife/key_helper.rb
new file mode 100644
index 0000000000..36ababc09a
--- /dev/null
+++ b/spec/unit/knife/key_helper.rb
@@ -0,0 +1,74 @@
+#
+# Author:: Tyler Cloke (<tyler@chef.io>)
+# Copyright:: Copyright (c) 2015 Chef Software, 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'
+
+shared_examples_for "a knife key command" do
+ let(:stderr) { StringIO.new }
+ let(:params) { [] }
+ let(:command) do
+ c = described_class.new([])
+ c.ui.config[:disable_editing] = true
+ allow(c.ui).to receive(:stderr).and_return(stderr)
+ allow(c.ui).to receive(:stdout).and_return(stderr)
+ allow(c).to receive(:show_usage)
+ c
+ end
+
+ context "before apply_params! is called" do
+ context "when apply_params! is called with invalid args" do
+ it "shows the usage" do
+ expect(command).to receive(:show_usage)
+ expect { command.apply_params!(params) }.to exit_with_code(1)
+ end
+
+ it "outputs the proper error" do
+ expect { command.apply_params!(params) }.to exit_with_code(1)
+ expect(stderr.string).to include(command.actor_missing_error)
+ end
+
+ it "exits 1" do
+ expect { command.apply_params!(params) }.to exit_with_code(1)
+ end
+ end
+ end # before apply_params! is called
+
+ context "after apply_params! is called with valid args" do
+ let(:params) { ["charmander"] }
+ before do
+ command.apply_params!(params)
+ end
+
+ it "properly defines the actor" do
+ expect(command.actor).to eq("charmander")
+ end
+ end # after apply_params! is called with valid args
+
+ context "when the command is run" do
+ before do
+ allow(command).to receive(:service_object).and_return(service_object)
+ allow(command).to receive(:name_args).and_return(["charmander"])
+ end
+
+ context "when the command is successful" do
+ before do
+ expect(service_object).to receive(:run)
+ end
+ end
+ end
+end # a knife key command
diff --git a/spec/unit/knife/key_list_spec.rb b/spec/unit/knife/key_list_spec.rb
new file mode 100644
index 0000000000..aabe02ac02
--- /dev/null
+++ b/spec/unit/knife/key_list_spec.rb
@@ -0,0 +1,216 @@
+#
+# Author:: Tyler Cloke (<tyler@chef.io>)
+# Copyright:: Copyright (c) 2015 Chef Software, 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/knife/user_key_list'
+require 'chef/knife/client_key_list'
+require 'chef/knife/key_list'
+require 'chef/key'
+
+describe "key list commands that inherit knife" do
+ shared_examples_for "a key list command" do
+ let(:stderr) { StringIO.new }
+ let(:params) { [] }
+ let(:service_object) { instance_double(Chef::Knife::KeyList) }
+ let(:command) do
+ c = described_class.new([])
+ c.ui.config[:disable_editing] = true
+ allow(c.ui).to receive(:stderr).and_return(stderr)
+ allow(c.ui).to receive(:stdout).and_return(stderr)
+ allow(c).to receive(:show_usage)
+ c
+ end
+
+ context "after apply_params! is called with valid args" do
+ let(:params) { ["charmander"] }
+ before do
+ command.apply_params!(params)
+ end
+
+ context "when the service object is called" do
+ it "creates a new instance of Chef::Knife::KeyList with the correct args" do
+ expect(Chef::Knife::KeyList).to receive(:new).
+ with("charmander", command.list_method, command.ui, command.config).
+ and_return(service_object)
+ command.service_object
+ end
+ end # when the service object is called
+ end # after apply_params! is called with valid args
+ end # a key list command
+
+ describe Chef::Knife::UserKeyList do
+ it_should_behave_like "a key list command"
+ # defined in key_helpers.rb
+ it_should_behave_like "a knife key command" do
+ let(:service_object) { instance_double(Chef::Knife::KeyList) }
+ let(:params) { ["charmander"] }
+ end
+ end
+
+ describe Chef::Knife::ClientKeyList do
+ it_should_behave_like "a key list command"
+ # defined in key_helpers.rb
+ it_should_behave_like "a knife key command" do
+ let(:service_object) { instance_double(Chef::Knife::KeyList) }
+ let(:params) { ["charmander"] }
+ end
+ end
+end
+
+describe Chef::Knife::KeyList do
+ let(:config) { Hash.new }
+ let(:actor) { "charmander" }
+ let(:ui) { instance_double("Chef::Knife::UI") }
+
+ shared_examples_for "key list run command" do
+ let(:key_list_object) {
+ described_class.new(actor, list_method, ui, config)
+ }
+
+ before do
+ allow(Chef::Key).to receive(list_method).and_return(http_response)
+ allow(key_list_object).to receive(:display_info)
+ # simply pass the string though that colorize takes in
+ allow(key_list_object).to receive(:colorize).with(kind_of(String)) do |input|
+ input
+ end
+ end
+
+ context "when only_expired and only_non_expired were both passed" do
+ before do
+ key_list_object.config[:only_expired] = true
+ key_list_object.config[:only_non_expired] = true
+ end
+
+ it "raises a Chef::Exceptions::KeyCommandInputError with the proper error message" do
+ expect{ key_list_object.run }.to raise_error(Chef::Exceptions::KeyCommandInputError, key_list_object.expired_and_non_expired_msg)
+ end
+ end
+
+ context "when the command is run" do
+ before do
+ key_list_object.config[:only_expired] = false
+ key_list_object.config[:only_non_expired] = false
+ key_list_object.config[:with_details] = false
+ end
+
+ it "calls Chef::Key with the proper list command and input" do
+ expect(Chef::Key).to receive(list_method).with(actor)
+ key_list_object.run
+ end
+
+ it "displays all the keys" do
+ expect(key_list_object).to receive(:display_info).with(/non-expired/).twice
+ expect(key_list_object).to receive(:display_info).with(/out-of-date/).once
+ key_list_object.run
+ end
+
+ context "when only_expired is called" do
+ before do
+ key_list_object.config[:only_expired] = true
+ end
+
+ it "excludes displaying non-expired keys" do
+ expect(key_list_object).to receive(:display_info).with(/non-expired/).exactly(0).times
+ key_list_object.run
+ end
+
+ it "displays the expired keys" do
+ expect(key_list_object).to receive(:display_info).with(/out-of-date/).once
+ key_list_object.run
+ end
+ end # when only_expired is called
+
+ context "when only_non_expired is called" do
+ before do
+ key_list_object.config[:only_non_expired] = true
+ end
+
+ it "excludes displaying expired keys" do
+ expect(key_list_object).to receive(:display_info).with(/out-of-date/).exactly(0).times
+ key_list_object.run
+ end
+
+ it "displays the non-expired keys" do
+ expect(key_list_object).to receive(:display_info).with(/non-expired/).twice
+ key_list_object.run
+ end
+ end # when only_expired is called
+
+ context "when with_details is false" do
+ before do
+ key_list_object.config[:with_details] = false
+ end
+
+ it "does not display the uri" do
+ expect(key_list_object).to receive(:display_info).with(/https/).exactly(0).times
+ key_list_object.run
+ end
+
+ it "does not display the expired status" do
+ expect(key_list_object).to receive(:display_info).with(/\(expired\)/).exactly(0).times
+ key_list_object.run
+ end
+ end # when with_details is false
+
+ context "when with_details is true" do
+ before do
+ key_list_object.config[:with_details] = true
+ end
+
+ it "displays the uri" do
+ expect(key_list_object).to receive(:display_info).with(/https/).exactly(3).times
+ key_list_object.run
+ end
+
+ it "displays the expired status" do
+ expect(key_list_object).to receive(:display_info).with(/\(expired\)/).once
+ key_list_object.run
+ end
+ end # when with_details is true
+
+ end # when the command is run
+
+ end # key list run command
+
+ context "when list_method is :list_by_user" do
+ it_should_behave_like "key list run command" do
+ let(:list_method) { :list_by_user }
+ let(:http_response) {
+ [
+ {"uri"=>"https://api.opscode.piab/users/charmander/keys/non-expired1", "name"=>"non-expired1", "expired"=>false},
+ {"uri"=>"https://api.opscode.piab/users/charmander/keys/non-expired2", "name"=>"non-expired2", "expired"=>false},
+ {"uri"=>"https://api.opscode.piab/users/mary/keys/out-of-date", "name"=>"out-of-date", "expired"=>true}
+ ]
+ }
+ end
+ end
+
+ context "when list_method is :list_by_client" do
+ it_should_behave_like "key list run command" do
+ let(:list_method) { :list_by_client }
+ let(:http_response) {
+ [
+ {"uri"=>"https://api.opscode.piab/organizations/pokemon/clients/charmander/keys/non-expired1", "name"=>"non-expired1", "expired"=>false},
+ {"uri"=>"https://api.opscode.piab/organizations/pokemon/clients/charmander/keys/non-expired2", "name"=>"non-expired2", "expired"=>false},
+ {"uri"=>"https://api.opscode.piab/organizations/pokemon/clients/mary/keys/out-of-date", "name"=>"out-of-date", "expired"=>true}
+ ]
+ }
+ end
+ end
+end
diff --git a/spec/unit/knife/key_show_spec.rb b/spec/unit/knife/key_show_spec.rb
new file mode 100644
index 0000000000..5a0d839e4f
--- /dev/null
+++ b/spec/unit/knife/key_show_spec.rb
@@ -0,0 +1,126 @@
+#
+# Author:: Tyler Cloke (<tyler@chef.io>)
+# Copyright:: Copyright (c) 2015 Chef Software, 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/knife/user_key_show'
+require 'chef/knife/client_key_show'
+require 'chef/knife/key_show'
+require 'chef/key'
+
+describe "key show commands that inherit knife" do
+ shared_examples_for "a key show command" do
+ let(:stderr) { StringIO.new }
+ let(:params) { [] }
+ let(:service_object) { instance_double(Chef::Knife::KeyShow) }
+ let(:command) do
+ c = described_class.new([])
+ c.ui.config[:disable_editing] = true
+ allow(c.ui).to receive(:stderr).and_return(stderr)
+ allow(c.ui).to receive(:stdout).and_return(stderr)
+ allow(c).to receive(:show_usage)
+ c
+ end
+
+ context "after apply_params! is called with valid args" do
+ let(:params) { ["charmander", "charmander-key"] }
+ before do
+ command.apply_params!(params)
+ end
+
+ context "when the service object is called" do
+ it "creates a new instance of Chef::Knife::KeyShow with the correct args" do
+ expect(Chef::Knife::KeyShow).to receive(:new).
+ with("charmander-key", "charmander", command.load_method, command.ui).
+ and_return(service_object)
+ command.service_object
+ end
+ end # when the service object is called
+ end # after apply_params! is called with valid args
+ end # a key show command
+
+ describe Chef::Knife::UserKeyShow do
+ it_should_behave_like "a key show command"
+ # defined in key_helpers.rb
+ it_should_behave_like "a knife key command with a keyname as the second arg"
+ it_should_behave_like "a knife key command" do
+ let(:service_object) { instance_double(Chef::Knife::KeyShow) }
+ let(:params) { ["charmander", "charmander-key"] }
+ end
+ end
+
+ describe Chef::Knife::ClientKeyShow do
+ it_should_behave_like "a key show command"
+ # defined in key_helpers.rb
+ it_should_behave_like "a knife key command with a keyname as the second arg"
+ it_should_behave_like "a knife key command" do
+ let(:service_object) { instance_double(Chef::Knife::KeyShow) }
+ let(:params) { ["charmander", "charmander-key"] }
+ end
+ end
+end
+
+describe Chef::Knife::KeyShow do
+ let(:actor) { "charmander" }
+ let(:keyname) { "charmander" }
+ let(:ui) { instance_double("Chef::Knife::UI") }
+ let(:expected_hash) {
+ {
+ actor_field_name => "charmander",
+ "name" => "charmander-key",
+ "public_key" => "some-public-key",
+ "expiration_date" => "infinity"
+ }
+ }
+
+ shared_examples_for "key show run command" do
+ let(:key_show_object) {
+ described_class.new(keyname, actor, load_method, ui)
+ }
+
+ before do
+ allow(key_show_object).to receive(:display_output)
+ allow(Chef::Key).to receive(load_method).and_return(Chef::Key.from_hash(expected_hash))
+ end
+
+ context "when the command is run" do
+ it "loads the key using the proper method and args" do
+ expect(Chef::Key).to receive(load_method).with(actor, keyname)
+ key_show_object.run
+ end
+
+ it "displays the key" do
+ expect(key_show_object).to receive(:display_output)
+ key_show_object.run
+ end
+ end
+ end
+
+ context "when load_method is :load_by_user" do
+ it_should_behave_like "key show run command" do
+ let(:load_method) { :load_by_user }
+ let(:actor_field_name) { 'user' }
+ end
+ end
+
+ context "when load_method is :load_by_client" do
+ it_should_behave_like "key show run command" do
+ let(:load_method) { :load_by_client }
+ let(:actor_field_name) { 'user' }
+ end
+ end
+end
diff --git a/spec/unit/knife/osc_user_create_spec.rb b/spec/unit/knife/osc_user_create_spec.rb
new file mode 100644
index 0000000000..1b17d0d22f
--- /dev/null
+++ b/spec/unit/knife/osc_user_create_spec.rb
@@ -0,0 +1,93 @@
+#
+# 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'
+
+Chef::Knife::OscUserCreate.load_deps
+
+# 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_create_spec.rb.
+
+describe Chef::Knife::OscUserCreate do
+ before(:each) do
+ @knife = Chef::Knife::OscUserCreate.new
+
+ @stdout = StringIO.new
+ @stderr = StringIO.new
+ allow(@knife.ui).to receive(:stdout).and_return(@stdout)
+ allow(@knife.ui).to receive(:stderr).and_return(@stderr)
+
+ @knife.name_args = [ 'a_user' ]
+ @knife.config[:user_password] = "foobar"
+ @user = Chef::OscUser.new
+ @user.name "a_user"
+ @user_with_private_key = Chef::OscUser.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(@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(@user).to receive(:create)
+ @knife.run
+ expect(@stderr.string).to match /created user.+a_user/i
+ end
+
+ it "sets the password" do
+ @knife.config[:user_password] = "a_password"
+ expect(@user).to receive(:password).with("a_password")
+ @knife.run
+ end
+
+ it "exits with an error if password is blank" do
+ @knife.config[:user_password] = ''
+ expect { @knife.run }.to raise_error SystemExit
+ expect(@stderr.string).to match /You must specify a non-blank password/
+ end
+
+ it "sets the user name" do
+ expect(@user).to receive(:name).with("a_user")
+ @knife.run
+ end
+
+ it "sets the public key if given" do
+ @knife.config[:user_key] = "/a/filename"
+ allow(File).to receive(:read).with(File.expand_path("/a/filename")).and_return("a_key")
+ expect(@user).to receive(:public_key).with("a_key")
+ @knife.run
+ end
+
+ it "allows you to edit the data" do
+ expect(@knife).to receive(:edit_data).with(@user)
+ @knife.run
+ end
+
+ it "writes the private key to a file when --file is specified" do
+ @knife.config[:file] = "/tmp/a_file"
+ filehandle = double("filehandle")
+ expect(filehandle).to receive(:print).with('private_key')
+ expect(File).to receive(:open).with("/tmp/a_file", "w").and_yield(filehandle)
+ @knife.run
+ end
+end
diff --git a/spec/unit/knife/osc_user_delete_spec.rb b/spec/unit/knife/osc_user_delete_spec.rb
new file mode 100644
index 0000000000..0e16393ffe
--- /dev/null
+++ b/spec/unit/knife/osc_user_delete_spec.rb
@@ -0,0 +1,44 @@
+#
+# 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'
+
+# 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_delete_spec.rb.
+
+describe Chef::Knife::OscUserDelete do
+ before(:each) do
+ Chef::Knife::OscUserDelete.load_deps
+ @knife = Chef::Knife::OscUserDelete.new
+ @knife.name_args = [ 'my_user' ]
+ end
+
+ it 'deletes the user' do
+ expect(@knife).to receive(:delete_object).with(Chef::OscUser, 'my_user')
+ @knife.run
+ end
+
+ it 'prints usage and exits when a user name is not provided' do
+ @knife.name_args = []
+ expect(@knife).to receive(:show_usage)
+ expect(@knife.ui).to receive(:fatal)
+ expect { @knife.run }.to raise_error(SystemExit)
+ end
+end
diff --git a/spec/unit/knife/osc_user_edit_spec.rb b/spec/unit/knife/osc_user_edit_spec.rb
new file mode 100644
index 0000000000..71a9192389
--- /dev/null
+++ b/spec/unit/knife/osc_user_edit_spec.rb
@@ -0,0 +1,52 @@
+#
+# 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'
+
+# 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_edit_spec.rb.
+
+describe Chef::Knife::OscUserEdit do
+ before(:each) do
+ @stderr = StringIO.new
+ @stdout = StringIO.new
+
+ Chef::Knife::OscUserEdit.load_deps
+ @knife = Chef::Knife::OscUserEdit.new
+ allow(@knife.ui).to receive(:stderr).and_return(@stderr)
+ allow(@knife.ui).to receive(:stdout).and_return(@stdout)
+ @knife.name_args = [ 'my_user' ]
+ @knife.config[:disable_editing] = true
+ end
+
+ it 'loads and edits the user' do
+ data = { :name => "my_user" }
+ allow(Chef::OscUser).to receive(:load).with("my_user").and_return(data)
+ expect(@knife).to receive(:edit_data).with(data).and_return(data)
+ @knife.run
+ end
+
+ it 'prints usage and exits when a user name is not provided' do
+ @knife.name_args = []
+ expect(@knife).to receive(:show_usage)
+ expect(@knife.ui).to receive(:fatal)
+ expect { @knife.run }.to raise_error(SystemExit)
+ end
+end
diff --git a/spec/unit/knife/osc_user_list_spec.rb b/spec/unit/knife/osc_user_list_spec.rb
new file mode 100644
index 0000000000..59a15be058
--- /dev/null
+++ b/spec/unit/knife/osc_user_list_spec.rb
@@ -0,0 +1,37 @@
+#
+# Author:: Steven Danna
+# 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'
+
+# 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_list_spec.rb.
+
+describe Chef::Knife::OscUserList do
+ before(:each) do
+ Chef::Knife::OscUserList.load_deps
+ @knife = Chef::Knife::OscUserList.new
+ end
+
+ it 'lists the users' do
+ expect(Chef::OscUser).to receive(:list)
+ expect(@knife).to receive(:format_list_for_display)
+ @knife.run
+ end
+end
diff --git a/spec/unit/knife/osc_user_reregister_spec.rb b/spec/unit/knife/osc_user_reregister_spec.rb
new file mode 100644
index 0000000000..406bbf1f3e
--- /dev/null
+++ b/spec/unit/knife/osc_user_reregister_spec.rb
@@ -0,0 +1,58 @@
+#
+# 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'
+
+# 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_reregister_spec.rb.
+
+describe Chef::Knife::OscUserReregister do
+ before(:each) do
+ Chef::Knife::OscUserReregister.load_deps
+ @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)
+ @stdout = StringIO.new
+ allow(@knife.ui).to receive(:stdout).and_return(@stdout)
+ end
+
+ it 'prints usage and exits when a user name is not provided' do
+ @knife.name_args = []
+ expect(@knife).to receive(:show_usage)
+ expect(@knife.ui).to receive(:fatal)
+ expect { @knife.run }.to raise_error(SystemExit)
+ end
+
+ it 'reregisters the user and prints the key' do
+ expect(@user_mock).to receive(:reregister).and_return(@user_mock)
+ @knife.run
+ expect(@stdout.string).to match( /private_key/ )
+ end
+
+ it 'writes the private key to a file when --file is specified' do
+ expect(@user_mock).to receive(:reregister).and_return(@user_mock)
+ @knife.config[:file] = '/tmp/a_file'
+ filehandle = StringIO.new
+ expect(File).to receive(:open).with('/tmp/a_file', 'w').and_yield(filehandle)
+ @knife.run
+ expect(filehandle.string).to eq("private_key")
+ end
+end
diff --git a/spec/unit/knife/osc_user_show_spec.rb b/spec/unit/knife/osc_user_show_spec.rb
new file mode 100644
index 0000000000..67b9b45809
--- /dev/null
+++ b/spec/unit/knife/osc_user_show_spec.rb
@@ -0,0 +1,46 @@
+#
+# 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'
+
+# 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 user_show_spec.rb.
+
+describe Chef::Knife::OscUserShow do
+ before(:each) do
+ Chef::Knife::OscUserShow.load_deps
+ @knife = Chef::Knife::OscUserShow.new
+ @knife.name_args = [ 'my_user' ]
+ @user_mock = double('user_mock')
+ end
+
+ it 'loads and displays the user' do
+ expect(Chef::OscUser).to receive(:load).with('my_user').and_return(@user_mock)
+ expect(@knife).to receive(:format_for_display).with(@user_mock)
+ @knife.run
+ end
+
+ it 'prints usage and exits when a user name is not provided' do
+ @knife.name_args = []
+ expect(@knife).to receive(:show_usage)
+ expect(@knife.ui).to receive(:fatal)
+ expect { @knife.run }.to raise_error(SystemExit)
+ end
+end
diff --git a/spec/unit/knife/ssh_spec.rb b/spec/unit/knife/ssh_spec.rb
index a838a21edc..723280bead 100644
--- a/spec/unit/knife/ssh_spec.rb
+++ b/spec/unit/knife/ssh_spec.rb
@@ -28,10 +28,10 @@ describe Chef::Knife::Ssh do
before do
@knife = Chef::Knife::Ssh.new
@knife.merge_configs
- @knife.config[:attribute] = "fqdn"
@node_foo = Chef::Node.new
@node_foo.automatic_attrs[:fqdn] = "foo.example.org"
@node_foo.automatic_attrs[:ipaddress] = "10.0.0.1"
+
@node_bar = Chef::Node.new
@node_bar.automatic_attrs[:fqdn] = "bar.example.org"
@node_bar.automatic_attrs[:ipaddress] = "10.0.0.2"
@@ -52,15 +52,15 @@ describe Chef::Knife::Ssh do
def self.should_return_specified_attributes
it "returns an array of the attributes specified on the command line OR config file, if only one is set" do
@knife.config[:attribute] = "ipaddress"
- @knife.config[:attribute_from_cli] = "ipaddress"
+ Chef::Config[:knife][:ssh_attribute] = "ipaddress" # this value will be in the config file
configure_query([@node_foo, @node_bar])
expect(@knife).to receive(:session_from_list).with([['10.0.0.1', nil], ['10.0.0.2', nil]])
@knife.configure_session
end
it "returns an array of the attributes specified on the command line even when a config value is set" do
- @knife.config[:attribute] = "config_file" # this value will be the config file
- @knife.config[:attribute_from_cli] = "ipaddress" # this is the value of the command line via #configure_attribute
+ Chef::Config[:knife][:ssh_attribute] = "config_file" # this value will be in the config file
+ @knife.config[:attribute] = "ipaddress" # this is the value of the command line via #configure_attribute
configure_query([@node_foo, @node_bar])
expect(@knife).to receive(:session_from_list).with([['10.0.0.1', nil], ['10.0.0.2', nil]])
@knife.configure_session
@@ -83,7 +83,6 @@ describe Chef::Knife::Ssh do
@node_foo.automatic_attrs[:cloud][:public_hostname] = "ec2-10-0-0-1.compute-1.amazonaws.com"
@node_bar.automatic_attrs[:cloud][:public_hostname] = "ec2-10-0-0-2.compute-1.amazonaws.com"
end
-
it "returns an array of cloud public hostnames" do
configure_query([@node_foo, @node_bar])
expect(@knife).to receive(:session_from_list).with([
@@ -150,42 +149,40 @@ describe Chef::Knife::Ssh do
end
end
- describe "#configure_attribute" do
+ describe "#get_ssh_attribute" do
+ # Order of precedence for ssh target
+ # 1) command line attribute
+ # 2) configuration file
+ # 3) cloud attribute
+ # 4) fqdn
before do
Chef::Config[:knife][:ssh_attribute] = nil
@knife.config[:attribute] = nil
+ @node_foo.automatic_attrs[:cloud][:public_hostname] = "ec2-10-0-0-1.compute-1.amazonaws.com"
+ @node_bar.automatic_attrs[:cloud][:public_hostname] = ''
end
it "should return fqdn by default" do
- @knife.configure_attribute
- expect(@knife.config[:attribute]).to eq("fqdn")
+ expect(@knife.get_ssh_attribute(Chef::Node.new)).to eq("fqdn")
end
- it "should return the value set in the configuration file" do
- Chef::Config[:knife][:ssh_attribute] = "config_file"
- @knife.configure_attribute
- expect(@knife.config[:attribute]).to eq("config_file")
+ it "should return cloud.public_hostname attribute if available" do
+ expect(@knife.get_ssh_attribute(@node_foo)).to eq("cloud.public_hostname")
end
- it "should return the value set on the command line" do
+ it "should favor to attribute_from_cli over config file and cloud" do
@knife.config[:attribute] = "command_line"
- @knife.configure_attribute
- expect(@knife.config[:attribute]).to eq("command_line")
+ Chef::Config[:knife][:ssh_attribute] = "config_file"
+ expect( @knife.get_ssh_attribute(@node_foo)).to eq("command_line")
end
- it "should set attribute_from_cli to the value of attribute from the command line" do
- @knife.config[:attribute] = "command_line"
- @knife.configure_attribute
- expect(@knife.config[:attribute]).to eq("command_line")
- expect(@knife.config[:attribute_from_cli]).to eq("command_line")
+ it "should favor config file over cloud and default" do
+ Chef::Config[:knife][:ssh_attribute] = "config_file"
+ expect( @knife.get_ssh_attribute(@node_foo)).to eq("config_file")
end
- it "should prefer the command line over the config file for the value of attribute_from_cli" do
- Chef::Config[:knife][:ssh_attribute] = "config_file"
- @knife.config[:attribute] = "command_line"
- @knife.configure_attribute
- expect(@knife.config[:attribute]).to eq("command_line")
- expect(@knife.config[:attribute_from_cli]).to eq("command_line")
+ it "should return fqdn if cloud.hostname is empty" do
+ expect( @knife.get_ssh_attribute(@node_bar)).to eq("fqdn")
end
end
diff --git a/spec/unit/knife/user_create_spec.rb b/spec/unit/knife/user_create_spec.rb
index ad8821cd0e..49d62cc2d7 100644
--- a/spec/unit/knife/user_create_spec.rb
+++ b/spec/unit/knife/user_create_spec.rb
@@ -1,6 +1,7 @@
#
-# Author:: Steven Danna (<steve@opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: Steven Danna (<steve@chef.io>)
+# Author:: Tyler Cloke (<tyler@chef.io>)
+# Copyright:: Copyright (c) 2012, 2015 Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -21,68 +22,193 @@ require 'spec_helper'
Chef::Knife::UserCreate.load_deps
describe Chef::Knife::UserCreate do
+ let(:knife) { Chef::Knife::UserCreate.new }
+
+ let(:stderr) {
+ StringIO.new
+ }
+
+ let(:stdout) {
+ StringIO.new
+ }
+
before(:each) do
- @knife = Chef::Knife::UserCreate.new
-
- @stdout = StringIO.new
- @stderr = StringIO.new
- allow(@knife.ui).to receive(:stdout).and_return(@stdout)
- allow(@knife.ui).to receive(:stderr).and_return(@stderr)
-
- @knife.name_args = [ 'a_user' ]
- @knife.config[:user_password] = "foobar"
- @user = Chef::User.new
- @user.name "a_user"
- @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::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)
+ allow(knife.ui).to receive(:stdout).and_return(stdout)
+ allow(knife.ui).to receive(:stderr).and_return(stderr)
+ allow(knife.ui).to receive(:warn)
end
- it "creates a new user" do
- 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
- end
+ # delete this once OSC11 support is gone
+ context "when only one name_arg is passed" do
+ before do
+ knife.name_args = ['some_user']
+ allow(knife).to receive(:run_osc_11_user_create).and_raise(SystemExit)
+ end
+
+ it "displays the osc warning" do
+ expect(knife.ui).to receive(:warn).with(knife.osc_11_warning)
+ expect{ knife.run }.to raise_error(SystemExit)
+ end
+
+ it "calls knife osc_user create" do
+ expect(knife).to receive(:run_osc_11_user_create)
+ expect{ knife.run }.to raise_error(SystemExit)
+ end
- it "sets the password" do
- @knife.config[:user_password] = "a_password"
- expect(@user).to receive(:password).with("a_password")
- @knife.run
end
- it "exits with an error if password is blank" do
- @knife.config[:user_password] = ''
- expect { @knife.run }.to raise_error SystemExit
- expect(@stderr.string).to match /You must specify a non-blank password/
+ context "when USERNAME isn't specified" do
+ # from spec/support/shared/unit/knife_shared.rb
+ it_should_behave_like "mandatory field missing" do
+ let(:name_args) { [] }
+ let(:fieldname) { 'username' }
+ end
end
- it "sets the user name" do
- expect(@user).to receive(:name).with("a_user")
- @knife.run
+ # uncomment once OSC11 support is gone,
+ # pending doesn't work for shared_examples_for by default
+ #
+ # context "when DISPLAY_NAME isn't specified" do
+ # # from spec/support/shared/unit/knife_shared.rb
+ # it_should_behave_like "mandatory field missing" do
+ # let(:name_args) { ['some_user'] }
+ # let(:fieldname) { 'display name' }
+ # end
+ # end
+
+ context "when FIRST_NAME isn't specified" do
+ # from spec/support/shared/unit/knife_shared.rb
+ it_should_behave_like "mandatory field missing" do
+ let(:name_args) { ['some_user', 'some_display_name'] }
+ let(:fieldname) { 'first name' }
+ end
end
- it "sets the public key if given" do
- @knife.config[:user_key] = "/a/filename"
- allow(File).to receive(:read).with(File.expand_path("/a/filename")).and_return("a_key")
- expect(@user).to receive(:public_key).with("a_key")
- @knife.run
+ context "when LAST_NAME isn't specified" do
+ # from spec/support/shared/unit/knife_shared.rb
+ it_should_behave_like "mandatory field missing" do
+ let(:name_args) { ['some_user', 'some_display_name', 'some_first_name'] }
+ let(:fieldname) { 'last name' }
+ end
end
- it "allows you to edit the data" do
- expect(@knife).to receive(:edit_data).with(@user)
- @knife.run
+ context "when EMAIL isn't specified" do
+ # from spec/support/shared/unit/knife_shared.rb
+ it_should_behave_like "mandatory field missing" do
+ let(:name_args) { ['some_user', 'some_display_name', 'some_first_name', 'some_last_name'] }
+ let(:fieldname) { 'email' }
+ end
end
- it "writes the private key to a file when --file is specified" do
- @knife.config[:file] = "/tmp/a_file"
- filehandle = double("filehandle")
- expect(filehandle).to receive(:print).with('private_key')
- expect(File).to receive(:open).with("/tmp/a_file", "w").and_yield(filehandle)
- @knife.run
+ context "when PASSWORD isn't specified" do
+ # from spec/support/shared/unit/knife_shared.rb
+ it_should_behave_like "mandatory field missing" do
+ let(:name_args) { ['some_user', 'some_display_name', 'some_first_name', 'some_last_name', 'some_email'] }
+ let(:fieldname) { 'password' }
+ end
end
+
+ context "when all mandatory fields are validly specified" do
+ before do
+ knife.name_args = ['some_user', 'some_display_name', 'some_first_name', 'some_last_name', 'some_email', 'some_password']
+ allow(knife).to receive(:edit_data).and_return(knife.user.to_hash)
+ allow(knife).to receive(:create_user_from_hash).and_return(knife.user)
+ end
+
+ before(:each) do
+ # reset the user field every run
+ knife.user_field = nil
+ end
+
+ it "sets all the mandatory fields" do
+ knife.run
+ expect(knife.user.username).to eq('some_user')
+ expect(knife.user.display_name).to eq('some_display_name')
+ expect(knife.user.first_name).to eq('some_first_name')
+ expect(knife.user.last_name).to eq('some_last_name')
+ expect(knife.user.email).to eq('some_email')
+ expect(knife.user.password).to eq('some_password')
+ end
+
+ context "when user_key and prevent_keygen are passed" do
+ before do
+ knife.config[:user_key] = "some_key"
+ knife.config[:prevent_keygen] = true
+ end
+ it "prints the usage" do
+ expect(knife).to receive(:show_usage)
+ expect { knife.run }.to raise_error(SystemExit)
+ end
+
+ it "prints a relevant error message" do
+ expect { knife.run }.to raise_error(SystemExit)
+ expect(stderr.string).to match /You cannot pass --user-key and --prevent-keygen/
+ end
+ end
+
+ context "when --prevent-keygen is passed" do
+ before do
+ knife.config[:prevent_keygen] = true
+ end
+
+ it "does not set user.create_key" do
+ knife.run
+ expect(knife.user.create_key).to be_falsey
+ end
+ end
+
+ context "when --prevent-keygen is not passed" do
+ it "sets user.create_key to true" do
+ knife.run
+ expect(knife.user.create_key).to be_truthy
+ end
+ end
+
+ context "when --user-key is passed" do
+ before do
+ knife.config[:user_key] = 'some_key'
+ allow(File).to receive(:read).and_return('some_key')
+ allow(File).to receive(:expand_path)
+ end
+
+ it "sets user.public_key" do
+ knife.run
+ expect(knife.user.public_key).to eq('some_key')
+ end
+ end
+
+ context "when --user-key is not passed" do
+ it "does not set user.public_key" do
+ knife.run
+ expect(knife.user.public_key).to be_nil
+ end
+ end
+
+ 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"})))
+ end
+
+ context "when --file is passed" do
+ before do
+ knife.config[:file] = '/some/path'
+ end
+
+ it "creates a new file of the path passed" do
+ filehandle = double('filehandle')
+ expect(filehandle).to receive(:print).with('some_private_key')
+ expect(File).to receive(:open).with('/some/path', 'w').and_yield(filehandle)
+ knife.run
+ end
+ end
+
+ context "when --file is not passed" do
+ it "prints the private key to stdout" do
+ expect(knife.ui).to receive(:msg).with('some_private_key')
+ knife.run
+ end
+ end
+ end
+
+ end # when all mandatory fields are validly specified
end
diff --git a/spec/unit/knife/user_delete_spec.rb b/spec/unit/knife/user_delete_spec.rb
index 94cfbf3db1..e49c781358 100644
--- a/spec/unit/knife/user_delete_spec.rb
+++ b/spec/unit/knife/user_delete_spec.rb
@@ -19,21 +19,47 @@
require 'spec_helper'
describe Chef::Knife::UserDelete do
+ let(:knife) { Chef::Knife::UserDelete.new }
+ let(:user) { double('user_object') }
+ let(:stdout) { StringIO.new }
+
before(:each) do
Chef::Knife::UserDelete.load_deps
- @knife = Chef::Knife::UserDelete.new
- @knife.name_args = [ 'my_user' ]
+ knife.name_args = [ 'my_user' ]
+ allow(Chef::User).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)
+ end
+
+ # delete this once OSC11 support is gone
+ context "when the username field is not supported by the server" do
+ before do
+ allow(knife).to receive(:run_osc_11_user_delete).and_raise(SystemExit)
+ allow(user).to receive(:username).and_return(nil)
+ end
+
+ it "displays the osc warning" do
+ expect(knife.ui).to receive(:warn).with(knife.osc_11_warning)
+ expect{ knife.run }.to raise_error(SystemExit)
+ end
+
+ it "forwards the command to knife osc_user edit" do
+ expect(knife).to receive(:run_osc_11_user_delete)
+ expect{ knife.run }.to raise_error(SystemExit)
+ end
end
it 'deletes the user' do
- expect(@knife).to receive(:delete_object).with(Chef::User, 'my_user')
- @knife.run
+ #expect(knife).to receive(:delete_object).with(Chef::User, 'my_user')
+ expect(knife).to receive(:delete_object).with('my_user')
+ knife.run
end
it 'prints usage and exits when a user name is not provided' do
- @knife.name_args = []
- expect(@knife).to receive(:show_usage)
- expect(@knife.ui).to receive(:fatal)
- expect { @knife.run }.to raise_error(SystemExit)
+ knife.name_args = []
+ expect(knife).to receive(:show_usage)
+ expect(knife.ui).to receive(:fatal)
+ expect { knife.run }.to raise_error(SystemExit)
end
end
diff --git a/spec/unit/knife/user_edit_spec.rb b/spec/unit/knife/user_edit_spec.rb
index 0eb75cfa9b..15a7726b20 100644
--- a/spec/unit/knife/user_edit_spec.rb
+++ b/spec/unit/knife/user_edit_spec.rb
@@ -19,29 +19,48 @@
require 'spec_helper'
describe Chef::Knife::UserEdit do
+ let(:knife) { Chef::Knife::UserEdit.new }
+
before(:each) do
@stderr = StringIO.new
@stdout = StringIO.new
Chef::Knife::UserEdit.load_deps
- @knife = Chef::Knife::UserEdit.new
- allow(@knife.ui).to receive(:stderr).and_return(@stderr)
- allow(@knife.ui).to receive(:stdout).and_return(@stdout)
- @knife.name_args = [ 'my_user' ]
- @knife.config[:disable_editing] = true
+ allow(knife.ui).to receive(:stderr).and_return(@stderr)
+ allow(knife.ui).to receive(:stdout).and_return(@stdout)
+ knife.name_args = [ 'my_user' ]
+ knife.config[:disable_editing] = true
+ end
+
+ # delete this once OSC11 support is gone
+ 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})
+ end
+
+ it "displays the osc warning" do
+ expect(knife.ui).to receive(:warn).with(knife.osc_11_warning)
+ expect{ knife.run }.to raise_error(SystemExit)
+ end
+
+ it "forwards the command to knife osc_user edit" do
+ expect(knife).to receive(:run_osc_11_user_edit)
+ expect{ knife.run }.to raise_error(SystemExit)
+ end
end
it 'loads and edits the user' do
- data = { :name => "my_user" }
+ data = { "username" => "my_user" }
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
+ expect(knife).to receive(:edit_data).with(data).and_return(data)
+ knife.run
end
it 'prints usage and exits when a user name is not provided' do
- @knife.name_args = []
- expect(@knife).to receive(:show_usage)
- expect(@knife.ui).to receive(:fatal)
- expect { @knife.run }.to raise_error(SystemExit)
+ knife.name_args = []
+ expect(knife).to receive(:show_usage)
+ expect(knife.ui).to receive(:fatal)
+ expect { knife.run }.to raise_error(SystemExit)
end
end
diff --git a/spec/unit/knife/user_list_spec.rb b/spec/unit/knife/user_list_spec.rb
index db097a5c16..9990cc802d 100644
--- a/spec/unit/knife/user_list_spec.rb
+++ b/spec/unit/knife/user_list_spec.rb
@@ -19,14 +19,18 @@
require 'spec_helper'
describe Chef::Knife::UserList do
+ let(:knife) { Chef::Knife::UserList.new }
+ let(:stdout) { StringIO.new }
+
before(:each) do
Chef::Knife::UserList.load_deps
- @knife = Chef::Knife::UserList.new
+ allow(knife.ui).to receive(:stderr).and_return(stdout)
+ allow(knife.ui).to receive(:stdout).and_return(stdout)
end
it 'lists the users' do
expect(Chef::User).to receive(:list)
- expect(@knife).to receive(:format_list_for_display)
- @knife.run
+ expect(knife).to receive(:format_list_for_display)
+ knife.run
end
end
diff --git a/spec/unit/knife/user_reregister_spec.rb b/spec/unit/knife/user_reregister_spec.rb
index 1268716f40..412a6ec374 100644
--- a/spec/unit/knife/user_reregister_spec.rb
+++ b/spec/unit/knife/user_reregister_spec.rb
@@ -19,35 +19,56 @@
require 'spec_helper'
describe Chef::Knife::UserReregister do
- before(:each) do
+ let(:knife) { Chef::Knife::UserReregister.new }
+ let(:user_mock) { double('user_mock', :private_key => "private_key") }
+ let(:stdout) { StringIO.new }
+
+ before do
Chef::Knife::UserReregister.load_deps
- @knife = Chef::Knife::UserReregister.new
- @knife.name_args = [ 'a_user' ]
- @user_mock = double('user_mock', :private_key => "private_key")
- allow(Chef::User).to receive(:load).and_return(@user_mock)
- @stdout = StringIO.new
- allow(@knife.ui).to receive(:stdout).and_return(@stdout)
+ knife.name_args = [ 'a_user' ]
+ allow(Chef::User).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')
+ end
+
+ # delete this once OSC11 support is gone
+ context "when the username field is not supported by the server" do
+ before do
+ allow(knife).to receive(:run_osc_11_user_reregister).and_raise(SystemExit)
+ allow(user_mock).to receive(:username).and_return(nil)
+ end
+
+ it "displays the osc warning" do
+ expect(knife.ui).to receive(:warn).with(knife.osc_11_warning)
+ expect{ knife.run }.to raise_error(SystemExit)
+ end
+
+ it "forwards the command to knife osc_user edit" do
+ expect(knife).to receive(:run_osc_11_user_reregister)
+ expect{ knife.run }.to raise_error(SystemExit)
+ end
end
it 'prints usage and exits when a user name is not provided' do
- @knife.name_args = []
- expect(@knife).to receive(:show_usage)
- expect(@knife.ui).to receive(:fatal)
- expect { @knife.run }.to raise_error(SystemExit)
+ knife.name_args = []
+ expect(knife).to receive(:show_usage)
+ expect(knife.ui).to receive(:fatal)
+ expect { knife.run }.to raise_error(SystemExit)
end
it 'reregisters the user and prints the key' do
- expect(@user_mock).to receive(:reregister).and_return(@user_mock)
- @knife.run
- expect(@stdout.string).to match( /private_key/ )
+ expect(user_mock).to receive(:reregister).and_return(user_mock)
+ knife.run
+ expect(stdout.string).to match( /private_key/ )
end
it 'writes the private key to a file when --file is specified' do
- expect(@user_mock).to receive(:reregister).and_return(@user_mock)
- @knife.config[:file] = '/tmp/a_file'
+ expect(user_mock).to receive(:reregister).and_return(user_mock)
+ knife.config[:file] = '/tmp/a_file'
filehandle = StringIO.new
expect(File).to receive(:open).with('/tmp/a_file', 'w').and_yield(filehandle)
- @knife.run
+ knife.run
expect(filehandle.string).to eq("private_key")
end
end
diff --git a/spec/unit/knife/user_show_spec.rb b/spec/unit/knife/user_show_spec.rb
index f97cbc3f13..43392a3a5c 100644
--- a/spec/unit/knife/user_show_spec.rb
+++ b/spec/unit/knife/user_show_spec.rb
@@ -19,23 +19,47 @@
require 'spec_helper'
describe Chef::Knife::UserShow do
- before(:each) do
+ let(:knife) { Chef::Knife::UserShow.new }
+ let(:user_mock) { double('user_mock') }
+ let(:stdout) { StringIO.new }
+
+ before do
Chef::Knife::UserShow.load_deps
- @knife = Chef::Knife::UserShow.new
- @knife.name_args = [ 'my_user' ]
- @user_mock = double('user_mock')
+ knife.name_args = [ 'my_user' ]
+ allow(user_mock).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)
+ end
+
+ # delete this once OSC11 support is gone
+ 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(user_mock).to receive(:username).and_return(nil)
+ end
+
+ it "displays the osc warning" do
+ expect(knife.ui).to receive(:warn).with(knife.osc_11_warning)
+ expect{ knife.run }.to raise_error(SystemExit)
+ end
+
+ it "forwards the command to knife osc_user edit" do
+ expect(knife).to receive(:run_osc_11_user_show)
+ expect{ knife.run }.to raise_error(SystemExit)
+ end
end
it 'loads and displays the user' do
- 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
+ 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
it 'prints usage and exits when a user name is not provided' do
- @knife.name_args = []
- expect(@knife).to receive(:show_usage)
- expect(@knife.ui).to receive(:fatal)
- expect { @knife.run }.to raise_error(SystemExit)
+ knife.name_args = []
+ expect(knife).to receive(:show_usage)
+ expect(knife.ui).to receive(:fatal)
+ expect { knife.run }.to raise_error(SystemExit)
end
end
diff --git a/spec/unit/knife_spec.rb b/spec/unit/knife_spec.rb
index b748232081..022256f370 100644
--- a/spec/unit/knife_spec.rb
+++ b/spec/unit/knife_spec.rb
@@ -30,11 +30,20 @@ describe Chef::Knife do
let(:knife) { Chef::Knife.new }
+ let(:config_location) { File.expand_path("~/.chef/config.rb") }
+
+ let(:config_loader) do
+ instance_double("WorkstationConfigLoader", load: nil, no_config_found?: false, config_location: config_location)
+ end
+
before(:each) do
Chef::Log.logger = Logger.new(StringIO.new)
Chef::Config[:node_name] = "webmonkey.example.com"
+ allow(Chef::WorkstationConfigLoader).to receive(:new).and_return(config_loader)
+ allow(config_loader).to receive(:explicit_config_file=)
+
# Prevent gratuitous code reloading:
allow(Chef::Knife).to receive(:load_commands)
allow(knife.ui).to receive(:puts)
@@ -130,7 +139,8 @@ describe Chef::Knife do
"Accept-Encoding"=>"gzip;q=1.0,deflate;q=0.6,identity;q=0.3",
'X-Chef-Version' => Chef::VERSION,
"Host"=>"api.opscode.piab",
- "X-REMOTE-REQUEST-ID"=>request_id}}
+ "X-REMOTE-REQUEST-ID"=>request_id,
+ 'X-Ops-Server-API-Version' => Chef::HTTP::Authenticator::DEFAULT_SERVER_API_VERSION}}
let(:request_id) {"1234"}
@@ -251,6 +261,18 @@ describe Chef::Knife do
:default => "default-value")
end
+ it "sets the default log_location to STDERR for Chef::Log warnings" do
+ knife_command = KnifeSpecs::TestYourself.new([])
+ knife_command.configure_chef
+ expect(Chef::Config[:log_location]).to eq(STDERR)
+ end
+
+ it "sets the default log_level to warn so we can issue Chef::Log.warn" do
+ knife_command = KnifeSpecs::TestYourself.new([])
+ knife_command.configure_chef
+ expect(Chef::Config[:log_level]).to eql(:warn)
+ end
+
it "prefers the default value if no config or command line value is present" do
knife_command = KnifeSpecs::TestYourself.new([]) #empty argv
knife_command.configure_chef
@@ -374,6 +396,22 @@ describe Chef::Knife do
expect(stderr.string).to match(%r[Response: nothing to see here])
end
+ it "formats 406s (non-supported API version error) nicely" do
+ response = Net::HTTPNotAcceptable.new("1.1", "406", "Not Acceptable")
+ response.instance_variable_set(:@read, true) # I hate you, net/http.
+
+ # set the header
+ response["x-ops-server-api-version"] = Chef::JSONCompat.to_json(:min_version => "0", :max_version => "1", :request_version => "10000000")
+
+ allow(response).to receive(:body).and_return(Chef::JSONCompat.to_json(:error => "sad trombone"))
+ allow(knife).to receive(:run).and_raise(Net::HTTPServerException.new("406 Not Acceptable", response))
+
+ knife.run_with_pretty_exceptions
+ expect(stderr.string).to include('The request that Knife sent was using API version 10000000')
+ expect(stderr.string).to include('The Chef server you sent the request to supports a min API verson of 0 and a max API version of 1')
+ expect(stderr.string).to include('Please either update your Chef client or server to be a compatible set')
+ end
+
it "formats 500s nicely" do
response = Net::HTTPInternalServerError.new("1.1", "500", "Internal Server Error")
response.instance_variable_set(:@read, true) # I hate you, net/http.
diff --git a/spec/unit/log/syslog_spec.rb b/spec/unit/log/syslog_spec.rb
new file mode 100644
index 0000000000..3db90e50c6
--- /dev/null
+++ b/spec/unit/log/syslog_spec.rb
@@ -0,0 +1,53 @@
+#
+# Author:: SAWANOBORI Yukihiko (<sawanoboriyu@higanworks.com>)
+# Copyright:: Copyright (c) 2015 Chef Software, 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'
+
+describe "Chef::Log::Syslog", :unix_only => true do
+ let(:syslog) { Chef::Log::Syslog.new }
+ let(:app) { Chef::Application.new }
+
+ before do
+ Chef::Log.init(MonoLogger.new(syslog))
+ @old_log_level = Chef::Log.level
+ Chef::Log.level = :info
+ @old_loggers = Chef::Log.loggers
+ Chef::Log.use_log_devices([syslog])
+ end
+
+ after do
+ Chef::Log.level = @old_log_level
+ Chef::Log.use_log_devices(@old_loggers)
+ end
+
+ it "should send message with severity info to syslog." do
+ expect(syslog).to receive(:info).with("*** Chef 12.4.0.dev.0 ***")
+ Chef::Log.info("*** Chef 12.4.0.dev.0 ***")
+ end
+
+ it "should send message with severity warning to syslog." do
+ expect(syslog).to receive(:warn).with("No config file found or specified on command line, using command line options.")
+ Chef::Log.warn("No config file found or specified on command line, using command line options.")
+ end
+
+ it "should fallback into send message with severity info to syslog when wrong format." do
+ expect(syslog).to receive(:info).with("chef message")
+ syslog.write("chef message")
+ end
+end
diff --git a/spec/unit/log/winevt_spec.rb b/spec/unit/log/winevt_spec.rb
new file mode 100644
index 0000000000..867ef55900
--- /dev/null
+++ b/spec/unit/log/winevt_spec.rb
@@ -0,0 +1,55 @@
+#
+# Author:: Jay Mundrawala (jdm@chef.io)
+# Author:: SAWANOBORI Yukihiko (<sawanoboriyu@higanworks.com>)
+# Copyright:: Copyright (c) 2015 Chef Software, 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'
+
+describe Chef::Log::WinEvt do
+ let(:evtlog) { instance_double("Win32::EventLog")}
+ let(:winevt) { Chef::Log::WinEvt.new(evtlog) }
+ let(:app) { Chef::Application.new }
+
+ before do
+
+ Chef::Log.init(MonoLogger.new(winevt))
+ @old_log_level = Chef::Log.level
+ Chef::Log.level = :info
+ @old_loggers = Chef::Log.loggers
+ Chef::Log.use_log_devices([winevt])
+ end
+
+ after do
+ Chef::Log.level = @old_log_level
+ Chef::Log.use_log_devices(@old_loggers)
+ end
+
+ it "should send message with severity info to Windows Event Log." do
+ expect(winevt).to receive(:info).with("*** Chef 12.4.0.dev.0 ***")
+ Chef::Log.info("*** Chef 12.4.0.dev.0 ***")
+ end
+
+ it "should send message with severity warning to Windows Event Log." do
+ expect(winevt).to receive(:warn).with("No config file found or specified on command line, using command line options.")
+ Chef::Log.warn("No config file found or specified on command line, using command line options.")
+ end
+
+ it "should fallback into send message with severity info to Windows Event Log when wrong format." do
+ expect(winevt).to receive(:info).with("chef message")
+ winevt.write("chef message")
+ end
+end
diff --git a/spec/unit/lwrp_spec.rb b/spec/unit/lwrp_spec.rb
index ec39174da6..34c6f6f1c5 100644
--- a/spec/unit/lwrp_spec.rb
+++ b/spec/unit/lwrp_spec.rb
@@ -17,20 +17,40 @@
#
require 'spec_helper'
+require 'tmpdir'
+require 'fileutils'
+require 'chef/mixin/convert_to_class_name'
module LwrpConstScopingConflict
end
describe "LWRP" do
+ include Chef::Mixin::ConvertToClassName
+
before do
@original_VERBOSE = $VERBOSE
$VERBOSE = nil
+ Chef::Resource::LWRPBase.class_eval { @loaded_lwrps = {} }
end
after do
$VERBOSE = @original_VERBOSE
end
+ def get_lwrp(name)
+ Chef::ResourceResolver.resolve(name)
+ end
+
+ def get_lwrp_provider(name)
+ old_treat_deprecation_warnings_as_errors = Chef::Config[:treat_deprecation_warnings_as_errors]
+ Chef::Config[:treat_deprecation_warnings_as_errors] = false
+ begin
+ Chef::Provider.const_get(convert_to_class_name(name.to_s))
+ ensure
+ Chef::Config[:treat_deprecation_warnings_as_errors] = old_treat_deprecation_warnings_as_errors
+ end
+ end
+
describe "when overriding an existing class" do
before :each do
allow($stderr).to receive(:write)
@@ -43,7 +63,6 @@ describe "LWRP" do
expect(Chef::Log).not_to receive(:debug).with(/anymore/)
Chef::Resource::LWRPBase.build_from_file("lwrp", file, nil)
Object.send(:remove_const, 'LwrpFoo')
- Chef::Resource.send(:remove_const, 'LwrpFoo')
end
it "should not skip loading a provider when there's a top level symbol of the same name" do
@@ -53,7 +72,6 @@ describe "LWRP" do
expect(Chef::Log).not_to receive(:debug).with(/anymore/)
Chef::Provider::LWRPBase.build_from_file("lwrp", file, nil)
Object.send(:remove_const, 'LwrpBuckPasser')
- Chef::Provider.send(:remove_const, 'LwrpBuckPasser')
end
# @todo: we need a before block to manually remove_const all of the LWRPs that we
@@ -67,7 +85,6 @@ describe "LWRP" do
Dir[File.expand_path( "lwrp/resources/*", CHEF_SPEC_DATA)].each do |file|
expect(Chef::Log).to receive(:info).with(/Skipping/)
- expect(Chef::Log).to receive(:debug).with(/anymore/)
Chef::Resource::LWRPBase.build_from_file("lwrp", file, nil)
end
end
@@ -79,7 +96,6 @@ describe "LWRP" do
Dir[File.expand_path( "lwrp/providers/*", CHEF_SPEC_DATA)].each do |file|
expect(Chef::Log).to receive(:info).with(/Skipping/)
- expect(Chef::Log).to receive(:debug).with(/anymore/)
Chef::Provider::LWRPBase.build_from_file("lwrp", file, nil)
end
end
@@ -90,7 +106,7 @@ describe "LWRP" do
Dir[File.expand_path( "lwrp/resources/*", CHEF_SPEC_DATA)].each do |file|
Chef::Resource::LWRPBase.build_from_file("lwrp", file, nil)
end
- first_lwr_foo_class = Chef::Resource::LwrpFoo
+ first_lwr_foo_class = get_lwrp(:lwrp_foo)
expect(Chef::Resource.resource_classes).to include(first_lwr_foo_class)
Dir[File.expand_path( "lwrp/resources/*", CHEF_SPEC_DATA)].each do |file|
Chef::Resource::LWRPBase.build_from_file("lwrp", file, nil)
@@ -106,40 +122,95 @@ describe "LWRP" do
end
+ context "When an LWRP resource in cookbook l-w-r-p is loaded" do
+ before do
+ @tmpdir = Dir.mktmpdir("lwrp_test")
+ resource_path = File.join(@tmpdir, "foo.rb")
+ IO.write(resource_path, "default_action :create")
+ provider_path = File.join(@tmpdir, "foo.rb")
+ IO.write(provider_path, <<-EOM)
+ action :create do
+ raise "hi"
+ end
+ EOM
+ end
+
+ it "Can find the resource at l_w_r_p_foo" do
+ end
+ end
+
+ context "When an LWRP resource lwrp_foo is loaded" do
+ before do
+ @tmpdir = Dir.mktmpdir("lwrp_test")
+ @lwrp_path = File.join(@tmpdir, "foo.rb")
+ content = IO.read(File.expand_path("../../data/lwrp/resources/foo.rb", __FILE__))
+ IO.write(@lwrp_path, content)
+ Chef::Resource::LWRPBase.build_from_file("lwrp", @lwrp_path, nil)
+ @original_resource = Chef::ResourceResolver.resolve(:lwrp_foo)
+ end
+
+ after do
+ FileUtils.remove_entry @tmpdir
+ end
+
+ context "And the LWRP is asked to load again, this time with different code" do
+ before do
+ content = IO.read(File.expand_path("../../data/lwrp_override/resources/foo.rb", __FILE__))
+ IO.write(@lwrp_path, content)
+ Chef::Resource::LWRPBase.build_from_file("lwrp", @lwrp_path, nil)
+ end
+
+ 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(Chef.method_defined?(:method_created_by_override_lwrp_foo)).to be_falsey
+ end
+ end
+ end
+
describe "Lightweight Chef::Resource" do
before do
Dir[File.expand_path(File.join(File.dirname(__FILE__), "..", "data", "lwrp", "resources", "*"))].each do |file|
Chef::Resource::LWRPBase.build_from_file("lwrp", file, nil)
end
+ end
- Dir[File.expand_path(File.join(File.dirname(__FILE__), "..", "data", "lwrp_override", "resources", "*"))].each do |file|
- Chef::Resource::LWRPBase.build_from_file("lwrp", file, nil)
- 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 load the resource into a properly-named class" do
- expect(Chef::Resource.const_get("LwrpFoo")).to be_kind_of(Class)
+ 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
it "should set resource_name" do
- expect(Chef::Resource::LwrpFoo.new("blah").resource_name).to eql(:lwrp_foo)
+ expect(get_lwrp(:lwrp_foo).new("blah").resource_name).to eql(:lwrp_foo)
+ end
+
+ it "should output the resource_name in .to_s" do
+ expect(get_lwrp(:lwrp_foo).new("blah").to_s).to eq "lwrp_foo[blah]"
+ end
+
+ it "should have a class that outputs a reasonable string" do
+ expect(get_lwrp(:lwrp_foo).to_s).to eq "LWRP resource lwrp_foo from cookbook lwrp"
end
it "should add the specified actions to the allowed_actions array" do
- expect(Chef::Resource::LwrpFoo.new("blah").allowed_actions).to include(:pass_buck, :twiddle_thumbs)
+ expect(get_lwrp(:lwrp_foo).new("blah").allowed_actions).to include(:pass_buck, :twiddle_thumbs)
end
it "should set the specified action as the default action" do
- expect(Chef::Resource::LwrpFoo.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
- expect(Chef::Resource::LwrpFoo.new("blah").methods.map{ |m| m.to_sym}).to include(:monkey)
+ expect(get_lwrp(:lwrp_foo).new("blah").methods.map{ |m| m.to_sym}).to include(:monkey)
end
it "should build attribute methods that respect validation rules" do
- expect { Chef::Resource::LwrpFoo.new("blah").monkey(42) }.to raise_error(ArgumentError)
+ expect { get_lwrp(:lwrp_foo).new("blah").monkey(42) }.to raise_error(ArgumentError)
end
it "should have access to the run context and node during class definition" do
@@ -151,12 +222,133 @@ describe "LWRP" do
Chef::Resource::LWRPBase.build_from_file("lwrp", file, run_context)
end
- cls = Chef::Resource.const_get("LwrpNodeattr")
+ cls = get_lwrp(:lwrp_nodeattr)
expect(cls.node).to be_kind_of(Chef::Node)
expect(cls.run_context).to be_kind_of(Chef::RunContext)
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) }
@@ -175,14 +367,6 @@ describe "LWRP" do
expect(klass.resource_name).to eq(:foo)
end
- context "when creating a new instance" do
- it "raises an exception if resource_name is nil" do
- expect {
- klass.new('blah')
- }.to raise_error(Chef::Exceptions::InvalidResourceSpecification)
- end
- end
-
context "lazy default values" do
let(:klass) do
Class.new(Chef::Resource::LWRPBase) do
@@ -281,102 +465,146 @@ describe "LWRP" do
end
describe "Lightweight Chef::Provider" do
- before do
- @node = Chef::Node.new
- @node.automatic[:platform] = :ubuntu
- @node.automatic[:platform_version] = '8.10'
- @events = Chef::EventDispatch::Dispatcher.new
- @run_context = Chef::RunContext.new(@node, Chef::CookbookCollection.new({}), @events)
- @runner = Chef::Runner.new(@run_context)
- end
- before(:each) do
- Dir[File.expand_path(File.join(File.dirname(__FILE__), "..", "data", "lwrp", "resources", "*"))].each do |file|
- Chef::Resource::LWRPBase.build_from_file("lwrp", file, @run_context)
+ let(:node) do
+ Chef::Node.new.tap do |n|
+ n.automatic[:platform] = :ubuntu
+ n.automatic[:platform_version] = '8.10'
end
+ end
- Dir[File.expand_path(File.join(File.dirname(__FILE__), "..", "data", "lwrp_override", "resources", "*"))].each do |file|
- Chef::Resource::LWRPBase.build_from_file("lwrp", file, @run_context)
- end
+ let(:events) { Chef::EventDispatch::Dispatcher.new }
- Dir[File.expand_path(File.join(File.dirname(__FILE__), "..", "data", "lwrp", "providers", "*"))].each do |file|
- Chef::Provider::LWRPBase.build_from_file("lwrp", file, @run_context)
- end
+ let(:run_context) { Chef::RunContext.new(node, Chef::CookbookCollection.new({}), events) }
+
+ let(:runner) { Chef::Runner.new(run_context) }
- Dir[File.expand_path(File.join(File.dirname(__FILE__), "..", "data", "lwrp_override", "providers", "*"))].each do |file|
- Chef::Provider::LWRPBase.build_from_file("lwrp", file, @run_context)
+ let(:lwrp_cookbok_name) { "lwrp" }
+
+ before do
+ Chef::Provider::LWRPBase.class_eval { @loaded_lwrps = {} }
+ end
+
+ before(:each) do
+ Dir[File.expand_path(File.expand_path("../../data/lwrp/resources/*", __FILE__))].each do |file|
+ Chef::Resource::LWRPBase.build_from_file(lwrp_cookbok_name, file, run_context)
end
+ Dir[File.expand_path(File.expand_path("../../data/lwrp/providers/*", __FILE__))].each do |file|
+ Chef::Provider::LWRPBase.build_from_file(lwrp_cookbok_name, file, run_context)
+ end
end
it "should properly handle a new_resource reference" do
- resource = Chef::Resource::LwrpFoo.new("morpheus")
+ resource = get_lwrp(:lwrp_foo).new("morpheus", run_context)
resource.monkey("bob")
- resource.provider(:lwrp_monkey_name_printer)
- resource.run_context = @run_context
+ resource.provider(get_lwrp_provider(:lwrp_monkey_name_printer))
provider = Chef::Platform.provider_for_resource(resource, :twiddle_thumbs)
provider.action_twiddle_thumbs
end
- it "should load the provider into a properly-named class" do
- expect(Chef::Provider.const_get("LwrpBuckPasser")).to be_kind_of(Class)
- end
+ context "provider 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
- it "should create a method for each attribute" do
- new_resource = double("new resource").as_null_object
- expect(Chef::Provider::LwrpBuckPasser.new(nil, new_resource).methods.map{|m|m.to_sym}).to include(:action_pass_buck)
- expect(Chef::Provider::LwrpThumbTwiddler.new(nil, new_resource).methods.map{|m|m.to_sym}).to include(:action_twiddle_thumbs)
+ after do
+ Chef::Config[:treat_deprecation_warnings_as_errors] = @old_treat_deprecation_warnings_as_errors
+ end
+
+ it "should load the provider into a properly-named class" do
+ expect(Chef::Provider.const_get("LwrpBuckPasser")).to be_kind_of(Class)
+ expect(Chef::Provider::LwrpBuckPasser <= Chef::Provider::LWRPBase).to be_truthy
+ end
+
+ it "should create a method for each action" do
+ expect(get_lwrp_provider(:lwrp_buck_passer).instance_methods).to include(:action_pass_buck)
+ expect(get_lwrp_provider(:lwrp_thumb_twiddler).instance_methods).to include(:action_twiddle_thumbs)
+ 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)
+ # 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.
+ expect(found_providers.first).to eq(get_lwrp_provider(:lwrp_buck_passer))
+ end
+
+ context "with a cookbook with an underscore in the name" 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)
+ expect(found_providers.size).to eq(1)
+ expect(found_providers.last).to eq(get_lwrp_provider(:l_w_r_p_buck_passer))
+ end
+ end
+
+ context "with a cookbook with a hypen in the name" 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')
+ expect(incorrect_providers).to eq([])
+
+ found_providers = Chef::Platform::ProviderPriorityMap.instance.list_handlers(node, :l_w_r_p_buck_passer)
+ expect(found_providers.first).to eq(get_lwrp_provider(:l_w_r_p_buck_passer))
+ end
+ end
end
it "should insert resources embedded in the provider into the middle of the resource collection" do
- injector = Chef::Resource::LwrpFoo.new("morpheus", @run_context)
+ injector = get_lwrp(:lwrp_foo).new("morpheus", run_context)
injector.action(:pass_buck)
- injector.provider(:lwrp_buck_passer)
- dummy = Chef::Resource::ZenMaster.new("keanu reeves", @run_context)
+ injector.provider(get_lwrp_provider(:lwrp_buck_passer))
+ dummy = Chef::Resource::ZenMaster.new("keanu reeves", run_context)
dummy.provider(Chef::Provider::Easy)
- @run_context.resource_collection.insert(injector)
- @run_context.resource_collection.insert(dummy)
+ run_context.resource_collection.insert(injector)
+ run_context.resource_collection.insert(dummy)
- Chef::Runner.new(@run_context).converge
+ Chef::Runner.new(run_context).converge
- expect(@run_context.resource_collection[0]).to eql(injector)
- expect(@run_context.resource_collection[1].name).to eql('prepared_thumbs')
- expect(@run_context.resource_collection[2].name).to eql('twiddled_thumbs')
- expect(@run_context.resource_collection[3]).to eql(dummy)
+ expect(run_context.resource_collection[0]).to eql(injector)
+ expect(run_context.resource_collection[1].name).to eql('prepared_thumbs')
+ expect(run_context.resource_collection[2].name).to eql('twiddled_thumbs')
+ expect(run_context.resource_collection[3]).to eql(dummy)
end
it "should insert embedded resources from multiple providers, including from the last position, properly into the resource collection" do
- injector = Chef::Resource::LwrpFoo.new("morpheus", @run_context)
+ injector = get_lwrp(:lwrp_foo).new("morpheus", run_context)
injector.action(:pass_buck)
- injector.provider(:lwrp_buck_passer)
+ injector.provider(get_lwrp_provider(:lwrp_buck_passer))
- injector2 = Chef::Resource::LwrpBar.new("tank", @run_context)
+ injector2 = get_lwrp(:lwrp_bar).new("tank", run_context)
injector2.action(:pass_buck)
- injector2.provider(:lwrp_buck_passer_2)
+ injector2.provider(get_lwrp_provider(:lwrp_buck_passer_2))
- dummy = Chef::Resource::ZenMaster.new("keanu reeves", @run_context)
+ dummy = Chef::Resource::ZenMaster.new("keanu reeves", run_context)
dummy.provider(Chef::Provider::Easy)
- @run_context.resource_collection.insert(injector)
- @run_context.resource_collection.insert(dummy)
- @run_context.resource_collection.insert(injector2)
+ run_context.resource_collection.insert(injector)
+ run_context.resource_collection.insert(dummy)
+ run_context.resource_collection.insert(injector2)
- Chef::Runner.new(@run_context).converge
+ Chef::Runner.new(run_context).converge
- expect(@run_context.resource_collection[0]).to eql(injector)
- expect(@run_context.resource_collection[1].name).to eql('prepared_thumbs')
- expect(@run_context.resource_collection[2].name).to eql('twiddled_thumbs')
- expect(@run_context.resource_collection[3]).to eql(dummy)
- expect(@run_context.resource_collection[4]).to eql(injector2)
- expect(@run_context.resource_collection[5].name).to eql('prepared_eyes')
- expect(@run_context.resource_collection[6].name).to eql('dried_paint_watched')
+ expect(run_context.resource_collection[0]).to eql(injector)
+ expect(run_context.resource_collection[1].name).to eql('prepared_thumbs')
+ expect(run_context.resource_collection[2].name).to eql('twiddled_thumbs')
+ expect(run_context.resource_collection[3]).to eql(dummy)
+ expect(run_context.resource_collection[4]).to eql(injector2)
+ expect(run_context.resource_collection[5].name).to eql('prepared_eyes')
+ expect(run_context.resource_collection[6].name).to eql('dried_paint_watched')
end
it "should properly handle a new_resource reference" do
- resource = Chef::Resource::LwrpFoo.new("morpheus", @run_context)
+ resource = get_lwrp(:lwrp_foo).new("morpheus", run_context)
resource.monkey("bob")
- resource.provider(:lwrp_monkey_name_printer)
+ resource.provider(get_lwrp_provider(:lwrp_monkey_name_printer))
provider = Chef::Platform.provider_for_resource(resource, :twiddle_thumbs)
provider.action_twiddle_thumbs
@@ -385,9 +613,9 @@ describe "LWRP" do
end
it "should properly handle an embedded Resource accessing the enclosing Provider's scope" do
- resource = Chef::Resource::LwrpFoo.new("morpheus", @run_context)
+ resource = get_lwrp(:lwrp_foo).new("morpheus", run_context)
resource.monkey("bob")
- resource.provider(:lwrp_embedded_resource_accesses_providers_scope)
+ resource.provider(get_lwrp_provider(:lwrp_embedded_resource_accesses_providers_scope))
provider = Chef::Platform.provider_for_resource(resource, :twiddle_thumbs)
#provider = @runner.build_provider(resource)
@@ -404,15 +632,15 @@ describe "LWRP" do
# Side effect of lwrp_inline_compiler provider for testing notifications.
$interior_ruby_block_2 = nil
# resource type doesn't matter, so make an existing resource type work with provider.
- @resource = Chef::Resource::LwrpFoo.new("morpheus", @run_context)
+ @resource = get_lwrp(:lwrp_foo).new("morpheus", run_context)
@resource.allowed_actions << :test
@resource.action(:test)
- @resource.provider(:lwrp_inline_compiler)
+ @resource.provider(get_lwrp_provider(:lwrp_inline_compiler))
end
it "does not add interior resources to the exterior resource collection" do
@resource.run_action(:test)
- expect(@run_context.resource_collection).to be_empty
+ expect(run_context.resource_collection).to be_empty
end
context "when interior resources are updated" do
diff --git a/spec/unit/mixin/api_version_request_handling_spec.rb b/spec/unit/mixin/api_version_request_handling_spec.rb
new file mode 100644
index 0000000000..cc5340e424
--- /dev/null
+++ b/spec/unit/mixin/api_version_request_handling_spec.rb
@@ -0,0 +1,127 @@
+#
+# Author:: Tyler Cloke (tyler@chef.io)
+# Copyright:: Copyright 2015 Chef Software, 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'
+
+describe Chef::Mixin::ApiVersionRequestHandling do
+ let(:dummy_class) { Class.new { include Chef::Mixin::ApiVersionRequestHandling } }
+ let(:object) { dummy_class.new }
+
+ describe ".server_client_api_version_intersection" do
+ let(:default_supported_client_versions) { [0,1,2] }
+
+
+ context "when the response code is not 406" do
+ let(:response) { OpenStruct.new(:code => '405') }
+ let(:exception) { Net::HTTPServerException.new("405 Something Else", response) }
+
+ it "returns nil" do
+ expect(object.server_client_api_version_intersection(exception, default_supported_client_versions)).
+ to be_nil
+ end
+
+ end # when the response code is not 406
+
+ context "when the response code is 406" do
+ let(:response) { OpenStruct.new(:code => '406') }
+ let(:exception) { Net::HTTPServerException.new("406 Not Acceptable", response) }
+
+ context "when x-ops-server-api-version header does not exist" do
+ it "returns nil" do
+ expect(object.server_client_api_version_intersection(exception, default_supported_client_versions)).
+ to be_nil
+ end
+ end # when x-ops-server-api-version header does not exist
+
+ context "when x-ops-server-api-version header exists" do
+ let(:min_server_version) { 2 }
+ let(:max_server_version) { 4 }
+ let(:return_hash) {
+ {
+ "min_version" => min_server_version,
+ "max_version" => max_server_version
+ }
+ }
+
+ before(:each) do
+ allow(response).to receive(:[]).with('x-ops-server-api-version').and_return(Chef::JSONCompat.to_json(return_hash))
+ end
+
+ context "when there is no intersection between client and server versions" do
+ shared_examples_for "no intersection between client and server versions" do
+ it "return an array" do
+ expect(object.server_client_api_version_intersection(exception, supported_client_versions)).
+ to be_a_kind_of(Array)
+ end
+
+ it "returns an empty array" do
+ expect(object.server_client_api_version_intersection(exception, supported_client_versions).length).
+ to eq(0)
+ end
+
+ end
+
+ context "when all the versions are higher than the max" do
+ it_should_behave_like "no intersection between client and server versions" do
+ let(:supported_client_versions) { [5,6,7] }
+ end
+ end
+
+ context "when all the versions are lower than the min" do
+ it_should_behave_like "no intersection between client and server versions" do
+ let(:supported_client_versions) { [0,1] }
+ end
+ end
+
+ end # when there is no intersection between client and server versions
+
+ context "when there is an intersection between client and server versions" do
+ context "when multiple versions intersect" do
+ let(:supported_client_versions) { [1,2,3,4,5] }
+
+ it "includes all of the intersection" do
+ expect(object.server_client_api_version_intersection(exception, supported_client_versions)).
+ to eq([2,3,4])
+ end
+ end # when multiple versions intersect
+
+ context "when only the min client version intersects" do
+ let(:supported_client_versions) { [0,1,2] }
+
+ it "includes the intersection" do
+ expect(object.server_client_api_version_intersection(exception, supported_client_versions)).
+ to eq([2])
+ end
+ end # when only the min client version intersects
+
+ context "when only the max client version intersects" do
+ let(:supported_client_versions) { [4,5,6] }
+
+ it "includes the intersection" do
+ expect(object.server_client_api_version_intersection(exception, supported_client_versions)).
+ to eq([4])
+ end
+ end # when only the max client version intersects
+
+ end # when there is an intersection between client and server versions
+
+ end # when x-ops-server-api-version header exists
+ end # when the response code is 406
+
+ end # .server_client_api_version_intersection
+end # Chef::Mixin::ApiVersionRequestHandling
diff --git a/spec/unit/mixin/command_spec.rb b/spec/unit/mixin/command_spec.rb
index e198e3addd..050b261256 100644
--- a/spec/unit/mixin/command_spec.rb
+++ b/spec/unit/mixin/command_spec.rb
@@ -22,7 +22,7 @@ describe Chef::Mixin::Command, :volatile do
if windows?
- pending("TODO MOVE: this is a platform specific integration test.")
+ skip("TODO MOVE: this is a platform specific integration test.")
else
@@ -61,7 +61,6 @@ describe Chef::Mixin::Command, :volatile do
it "returns immediately after the first child process exits" do
expect {Timeout.timeout(10) do
- pid, stdin,stdout,stderr = nil,nil,nil,nil
evil_forker="exit if fork; 10.times { sleep 1}"
popen4("ruby -e '#{evil_forker}'") do |pid,stdin,stdout,stderr|
end
diff --git a/spec/unit/mixin/path_sanity_spec.rb b/spec/unit/mixin/path_sanity_spec.rb
index ec8e182e3d..3a924b9538 100644
--- a/spec/unit/mixin/path_sanity_spec.rb
+++ b/spec/unit/mixin/path_sanity_spec.rb
@@ -35,7 +35,7 @@ describe Chef::Mixin::PathSanity do
@gem_bindir = '/some/gem/bin'
allow(Gem).to receive(:bindir).and_return(@gem_bindir)
allow(RbConfig::CONFIG).to receive(:[]).with('bindir').and_return(@ruby_bindir)
- allow(Chef::Platform).to receive(:windows?).and_return(false)
+ allow(ChefConfig).to receive(:windows?).and_return(false)
end
it "adds all useful PATHs even if environment is an empty hash" do
@@ -77,7 +77,7 @@ describe Chef::Mixin::PathSanity do
gem_bindir = 'C:\gems\bin'
allow(Gem).to receive(:bindir).and_return(gem_bindir)
allow(RbConfig::CONFIG).to receive(:[]).with('bindir').and_return(ruby_bindir)
- allow(Chef::Platform).to receive(:windows?).and_return(true)
+ allow(ChefConfig).to receive(:windows?).and_return(true)
env = {"PATH" => 'C:\Windows\system32;C:\mr\softie'}
@sanity.enforce_path_sanity(env)
expect(env["PATH"]).to eq("C:\\Windows\\system32;C:\\mr\\softie;#{ruby_bindir};#{gem_bindir}")
diff --git a/spec/unit/mixin/powershell_out_spec.rb b/spec/unit/mixin/powershell_out_spec.rb
new file mode 100644
index 0000000000..0fede582fa
--- /dev/null
+++ b/spec/unit/mixin/powershell_out_spec.rb
@@ -0,0 +1,70 @@
+#
+# Copyright:: Copyright (c) 2015 Chef Software, 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/mixin/powershell_out'
+
+describe Chef::Mixin::PowershellOut do
+ let(:shell_out_class) { Class.new { include Chef::Mixin::PowershellOut } }
+ subject(:object) { shell_out_class.new }
+ let(:architecture) { "something" }
+ let(:flags) {
+ "-NoLogo -NonInteractive -NoProfile -ExecutionPolicy Unrestricted -InputFormat None"
+ }
+
+ describe "#powershell_out" do
+ it "runs a command and returns the shell_out object" do
+ ret = double("Mixlib::ShellOut")
+ expect(object).to receive(:shell_out).with(
+ "powershell.exe #{flags} -Command \"Get-Process\"",
+ {}
+ ).and_return(ret)
+ expect(object.powershell_out("Get-Process")).to eql(ret)
+ end
+
+ it "passes options" do
+ ret = double("Mixlib::ShellOut")
+ expect(object).to receive(:shell_out).with(
+ "powershell.exe #{flags} -Command \"Get-Process\"",
+ timeout: 600
+ ).and_return(ret)
+ expect(object.powershell_out("Get-Process", timeout: 600)).to eql(ret)
+ end
+ end
+
+ describe "#powershell_out!" do
+ it "runs a command and returns the shell_out object" do
+ mixlib_shellout = double("Mixlib::ShellOut")
+ expect(object).to receive(:shell_out).with(
+ "powershell.exe #{flags} -Command \"Get-Process\"",
+ {}
+ ).and_return(mixlib_shellout)
+ expect(mixlib_shellout).to receive(:error!)
+ expect(object.powershell_out!("Get-Process")).to eql(mixlib_shellout)
+ end
+
+ it "passes options" do
+ mixlib_shellout = double("Mixlib::ShellOut")
+ expect(object).to receive(:shell_out).with(
+ "powershell.exe #{flags} -Command \"Get-Process\"",
+ timeout: 600
+ ).and_return(mixlib_shellout)
+ expect(mixlib_shellout).to receive(:error!)
+ expect(object.powershell_out!("Get-Process", timeout: 600)).to eql(mixlib_shellout)
+ end
+ end
+end
diff --git a/spec/unit/mixin/template_spec.rb b/spec/unit/mixin/template_spec.rb
index f02bd34b8f..6a867b5f9a 100644
--- a/spec/unit/mixin/template_spec.rb
+++ b/spec/unit/mixin/template_spec.rb
@@ -39,7 +39,7 @@ describe Chef::Mixin::Template, "render_template" do
describe "when running on windows" do
before do
- allow(Chef::Platform).to receive(:windows?).and_return(true)
+ allow(ChefConfig).to receive(:windows?).and_return(true)
end
it "should render the templates with windows line endings" do
@@ -54,7 +54,7 @@ describe Chef::Mixin::Template, "render_template" do
describe "when running on unix" do
before do
- allow(Chef::Platform).to receive(:windows?).and_return(false)
+ allow(ChefConfig).to receive(:windows?).and_return(false)
end
it "should render the templates with unix line endings" do
diff --git a/spec/unit/mixin/unformatter_spec.rb b/spec/unit/mixin/unformatter_spec.rb
new file mode 100644
index 0000000000..2eae0ac9bb
--- /dev/null
+++ b/spec/unit/mixin/unformatter_spec.rb
@@ -0,0 +1,61 @@
+#
+# Author:: Jay Mundrawala (<jdm@chef.io>)
+# Copyright:: Copyright (c) 2015 Chef Software
+# 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/mixin/unformatter'
+
+class Chef::UnformatterTest
+ include Chef::Mixin::Unformatter
+
+ def foo
+ end
+
+end
+
+describe Chef::Mixin::Unformatter do
+ let (:unformatter) { Chef::UnformatterTest.new }
+ let (:message) { "Test Message" }
+
+ describe "#write" do
+ context "with a timestamp" do
+ it "sends foo to itself when the message is of severity foo" do
+ expect(unformatter).to receive(:foo).with(message)
+ unformatter.write("[time] foo: #{message}")
+ end
+
+ it "sends foo to itself when the message is of severity FOO" do
+ expect(unformatter).to receive(:foo).with(message)
+ unformatter.write("[time] FOO: #{message}")
+ end
+ end
+
+ context "without a timestamp" do
+ it "sends foo to itself when the message is of severity foo" do
+ expect(unformatter).to receive(:foo).with(message)
+ unformatter.write("foo: #{message}")
+ end
+
+ it "sends foo to itself when the message is of severity FOO" do
+ expect(unformatter).to receive(:foo).with(message)
+ unformatter.write("FOO: #{message}")
+ end
+ end
+
+ end
+
+end
diff --git a/spec/unit/mixin/uris_spec.rb b/spec/unit/mixin/uris_spec.rb
new file mode 100644
index 0000000000..d4985c4f67
--- /dev/null
+++ b/spec/unit/mixin/uris_spec.rb
@@ -0,0 +1,57 @@
+#
+# Author:: Jay Mundrawala (<jdm@chef.io>)
+# Copyright:: Copyright (c) 2015 Chef Software, 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/mixin/uris'
+
+class Chef::UrisTest
+ include Chef::Mixin::Uris
+end
+
+describe Chef::Mixin::Uris do
+ let (:uris) { Chef::UrisTest.new }
+
+ describe "#uri_scheme?" do
+ it "matches 'scheme://foo.com'" do
+ expect(uris.uri_scheme?('scheme://foo.com')).to eq(true)
+ end
+
+ it "does not match 'c:/foo.com'" do
+ expect(uris.uri_scheme?('c:/foo.com')).to eq(false)
+ end
+
+ it "does not match '/usr/bin/foo.com'" do
+ expect(uris.uri_scheme?('/usr/bin/foo.com')).to eq(false)
+ end
+
+ it "does not match 'c:/foo.com://bar.com'" do
+ expect(uris.uri_scheme?('c:/foo.com://bar.com')).to eq(false)
+ end
+ end
+
+ describe "#as_uri" do
+ it "parses a file scheme uri with spaces" do
+ expect{ uris.as_uri("file:///c:/foo bar.txt") }.not_to raise_exception
+ end
+
+ it "returns a URI object" do
+ expect( uris.as_uri("file:///c:/foo bar.txt") ).to be_a(URI)
+ end
+ end
+
+end
diff --git a/spec/unit/node_map_spec.rb b/spec/unit/node_map_spec.rb
index fe7372961b..9b5ff5e8c6 100644
--- a/spec/unit/node_map_spec.rb
+++ b/spec/unit/node_map_spec.rb
@@ -134,6 +134,10 @@ describe Chef::NodeMap do
end
describe "resource back-compat testing" do
+ before :each do
+ Chef::Config[:treat_deprecation_warnings_as_errors] = false
+ end
+
it "should handle :on_platforms => :all" do
node_map.set(:chef_gem, :foo, :on_platforms => :all)
allow(node).to receive(:[]).with(:platform).and_return("windows")
@@ -152,4 +156,3 @@ describe Chef::NodeMap do
end
end
-
diff --git a/spec/unit/osc_user_spec.rb b/spec/unit/osc_user_spec.rb
new file mode 100644
index 0000000000..678486a16d
--- /dev/null
+++ b/spec/unit/osc_user_spec.rb
@@ -0,0 +1,276 @@
+#
+# 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 equalivent 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/query_helpers_spec.rb b/spec/unit/platform/query_helpers_spec.rb
index 1dbd07a021..33d4c2c3b7 100644
--- a/spec/unit/platform/query_helpers_spec.rb
+++ b/spec/unit/platform/query_helpers_spec.rb
@@ -20,7 +20,7 @@ require 'spec_helper'
describe "Chef::Platform#windows_server_2003?" do
it "returns false early when not on windows" do
- allow(Chef::Platform).to receive(:windows?).and_return(false)
+ allow(ChefConfig).to receive(:windows?).and_return(false)
expect(Chef::Platform).not_to receive(:require)
expect(Chef::Platform.windows_server_2003?).to be_falsey
end
diff --git a/spec/unit/platform_spec.rb b/spec/unit/platform_spec.rb
index e0115bc42a..36325d5411 100644
--- a/spec/unit/platform_spec.rb
+++ b/spec/unit/platform_spec.rb
@@ -18,29 +18,6 @@
require 'spec_helper'
-describe "Chef::Platform supports" do
- [
- :freebsd,
- :ubuntu,
- :debian,
- :centos,
- :fedora,
- :suse,
- :opensuse,
- :redhat,
- :oracle,
- :gentoo,
- :arch,
- :solaris,
- :gcel,
- :ibm_powerkvm
- ].each do |platform|
- it "#{platform}" do
- expect(Chef::Platform.platforms).to have_key(platform)
- end
- end
-end
-
describe Chef::Platform do
context "while testing with fake data" do
@@ -261,41 +238,4 @@ describe Chef::Platform do
end
- context "while testing the configured platform data" do
-
- it "should use the solaris package provider on Solaris <11" do
- pmap = Chef::Platform.find("Solaris2", "5.9")
- expect(pmap[:package]).to eql(Chef::Provider::Package::Solaris)
- end
-
- it "should use the IPS package provider on Solaris 11" do
- pmap = Chef::Platform.find("Solaris2", "5.11")
- expect(pmap[:package]).to eql(Chef::Provider::Package::Ips)
- end
-
- it "should use the Redhat service provider on SLES11" do
- 1.upto(3) do |sp|
- pmap = Chef::Platform.find("SUSE", "11.#{sp}")
- expect(pmap[:service]).to eql(Chef::Provider::Service::Redhat)
- end
- end
-
- it "should use the Systemd service provider on SLES12" do
- pmap = Chef::Platform.find("SUSE", "12.0")
- expect(pmap[:service]).to eql(Chef::Provider::Service::Systemd)
- end
-
- it "should use the SUSE group provider on SLES11" do
- 1.upto(3) do |sp|
- pmap = Chef::Platform.find("SUSE", "11.#{sp}")
- expect(pmap[:group]).to eql(Chef::Provider::Group::Suse)
- end
- end
-
- it "should use the Gpasswd group provider on SLES12" do
- pmap = Chef::Platform.find("SUSE", "12.0")
- expect(pmap[:group]).to eql(Chef::Provider::Group::Gpasswd)
- end
- end
-
end
diff --git a/spec/unit/policy_builder/policyfile_spec.rb b/spec/unit/policy_builder/policyfile_spec.rb
index e4f7388a1c..5fa00d8f2b 100644
--- a/spec/unit/policy_builder/policyfile_spec.rb
+++ b/spec/unit/policy_builder/policyfile_spec.rb
@@ -166,13 +166,17 @@ describe Chef::PolicyBuilder::Policyfile do
end
before do
- # TODO: agree on this name and logic.
+ Chef::Config[:policy_document_native_api] = false
Chef::Config[:deployment_group] = "example-policy-stage"
allow(policy_builder).to receive(:http_api).and_return(http_api)
end
describe "when using compatibility mode (policy_document_native_api == false)" do
+ before do
+ Chef::Config[:deployment_group] = "example-policy-stage"
+ end
+
context "when the deployment group cannot be loaded" do
let(:error404) { Net::HTTPServerException.new("404 message", :body) }
@@ -389,8 +393,8 @@ describe Chef::PolicyBuilder::Policyfile do
let(:example1_cookbook_data) { double("CookbookVersion Hash for example1 cookbook") }
let(:example2_cookbook_data) { double("CookbookVersion Hash for example2 cookbook") }
- let(:example1_cookbook_object) { double("Chef::CookbookVersion for example1 cookbook") }
- let(:example2_cookbook_object) { double("Chef::CookbookVersion for example2 cookbook") }
+ let(:example1_cookbook_object) { double("Chef::CookbookVersion for example1 cookbook", version: "0.1.2") }
+ let(:example2_cookbook_object) { double("Chef::CookbookVersion for example2 cookbook", version: "1.2.3") }
let(:expected_cookbook_hash) do
{ "example1" => example1_cookbook_object, "example2" => example2_cookbook_object }
diff --git a/spec/unit/provider/deploy/revision_spec.rb b/spec/unit/provider/deploy/revision_spec.rb
index 4ca64e3445..caa60878e1 100644
--- a/spec/unit/provider/deploy/revision_spec.rb
+++ b/spec/unit/provider/deploy/revision_spec.rb
@@ -21,7 +21,7 @@ require 'spec_helper'
describe Chef::Provider::Deploy::Revision do
before do
- allow(Chef::Platform).to receive(:windows?) { false }
+ allow(ChefConfig).to receive(:windows?) { false }
@temp_dir = Dir.mktmpdir
Chef::Config[:file_cache_path] = @temp_dir
@resource = Chef::Resource::Deploy.new("/my/deploy/dir")
diff --git a/spec/unit/provider/deploy_spec.rb b/spec/unit/provider/deploy_spec.rb
index c95a9b3d57..63658ac601 100644
--- a/spec/unit/provider/deploy_spec.rb
+++ b/spec/unit/provider/deploy_spec.rb
@@ -21,7 +21,7 @@ require 'spec_helper'
describe Chef::Provider::Deploy do
before do
- allow(Chef::Platform).to receive(:windows?) { false }
+ allow(ChefConfig).to receive(:windows?) { false }
@release_time = Time.utc( 2004, 8, 15, 16, 23, 42)
allow(Time).to receive(:now).and_return(@release_time)
@expected_release_dir = "/my/deploy/dir/releases/20040815162342"
@@ -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([: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/directory_spec.rb b/spec/unit/provider/directory_spec.rb
index 13c57bfe56..38d6db8320 100644
--- a/spec/unit/provider/directory_spec.rb
+++ b/spec/unit/provider/directory_spec.rb
@@ -16,173 +16,237 @@
# limitations under the License.
#
-require 'ostruct'
-
require 'spec_helper'
require 'tmpdir'
describe Chef::Provider::Directory do
- before(:each) do
- @new_resource = Chef::Resource::Directory.new(Dir.tmpdir)
- if !windows?
- @new_resource.owner(500)
- @new_resource.group(500)
- @new_resource.mode(0644)
+ let(:tmp_dir) { Dir.mktmpdir }
+ let(:new_resource) { Chef::Resource::Directory.new(tmp_dir) }
+ let(:node) { Chef::Node.new }
+ let(:events) { Chef::EventDispatch::Dispatcher.new }
+ let(:run_context) { Chef::RunContext.new(node, {}, events) }
+ let(:directory) { Chef::Provider::Directory.new(new_resource, run_context) }
+
+ describe "#load_current_resource" do
+ describe "scanning file security metadata"
+ describe "on unix", unix_only: true do
+ describe "when the directory exists" do
+ let(:dir_stat) { File::Stat.new(tmp_dir) }
+ let(:expected_uid) { dir_stat.uid }
+ let(:expected_gid) { dir_stat.gid }
+ let(:expected_mode) { "0%o" % ( dir_stat.mode & 007777 ) }
+ let(:expected_pwnam) { Etc.getpwuid(expected_uid).name }
+ let(:expected_grnam) { Etc.getgrgid(expected_gid).name }
+
+ it "describes the access mode as a String of octal integers" do
+ directory.load_current_resource
+ expect(directory.current_resource.mode).to eq(expected_mode)
+ end
+
+ it "when the new_resource.owner is numeric, describes the owner as a numeric uid" do
+ new_resource.owner(500)
+ directory.load_current_resource
+ expect(directory.current_resource.owner).to eql(expected_uid)
+ end
+
+ it "when the new_resource.group is numeric, describes the group as a numeric gid" do
+ new_resource.group(500)
+ directory.load_current_resource
+ expect(directory.current_resource.group).to eql(expected_gid)
+ end
+
+ it "when the new_resource.owner is a string, describes the owner as a string" do
+ new_resource.owner("foo")
+ directory.load_current_resource
+ expect(directory.current_resource.owner).to eql(expected_pwnam)
+ end
+
+ it "when the new_resource.group is a string, describes the group as a string" do
+ new_resource.group("bar")
+ directory.load_current_resource
+ expect(directory.current_resource.group).to eql(expected_grnam)
+ end
+ end
end
- @node = Chef::Node.new
- @events = Chef::EventDispatch::Dispatcher.new
- @run_context = Chef::RunContext.new(@node, {}, @events)
- @directory = Chef::Provider::Directory.new(@new_resource, @run_context)
- end
+ describe "on windows", windows_only: true do
+ describe "when the directory exists" do
+ it "the mode is always nil" do
+ directory.load_current_resource
+ expect(directory.current_resource.mode).to be nil
+ end
+
+ it "the owner is always nil" do
+ directory.load_current_resource
+ expect(directory.current_resource.owner).to be nil
+ end
+
+ it "the group is always nil" do
+ directory.load_current_resource
+ expect(directory.current_resource.group).to be nil
+ end
+
+ it "rights are always nil (incorrectly)" do
+ directory.load_current_resource
+ expect(directory.current_resource.rights).to be nil
+ end
+
+ it "inherits is always nil (incorrectly)" do
+ directory.load_current_resource
+ expect(directory.current_resource.inherits).to be nil
+ end
+ end
+ end
+ describe "when the directory does not exist" do
+ before do
+ FileUtils.rmdir tmp_dir
+ end
- describe "scanning file security metadata on windows" do
- before do
+ it "sets the mode, group and owner to nil" do
+ directory.load_current_resource
+ expect(directory.current_resource.mode).to eq(nil)
+ expect(directory.current_resource.group).to eq(nil)
+ expect(directory.current_resource.owner).to eq(nil)
+ end
end
- it "describes the directory's access rights" do
- skip
- end
end
- describe "scanning file security metadata on unix" do
- before do
- allow(Chef::Platform).to receive(:windows?).and_return(false)
- end
- let(:mock_stat) do
- cstats = double("stats")
- allow(cstats).to receive(:uid).and_return(500)
- allow(cstats).to receive(:gid).and_return(500)
- allow(cstats).to receive(:mode).and_return(0755)
- cstats
- end
+ describe "#define_resource_requirements" do
+ describe "on unix", unix_only: true do
+ it "raises an exception if the user does not exist" do
+ new_resource.owner("arglebargle_iv")
+ expect(Etc).to receive(:getpwnam).with("arglebargle_iv").and_raise(ArgumentError)
+ directory.action = :create
+ directory.load_current_resource
+ expect(directory.access_controls).to receive(:define_resource_requirements).and_call_original
+ directory.define_resource_requirements
+ expect { directory.process_resource_requirements }.to raise_error(ArgumentError)
+ end
- it "describes the access mode as a String of octal integers" do
- allow(File).to receive(:exists?).and_return(true)
- expect(File).to receive(:stat).and_return(mock_stat)
- @directory.load_current_resource
- expect(@directory.current_resource.mode).to eq("0755")
+ it "raises an exception if the group does not exist" do
+ new_resource.group("arglebargle_iv")
+ expect(Etc).to receive(:getgrnam).with("arglebargle_iv").and_raise(ArgumentError)
+ directory.action = :create
+ directory.load_current_resource
+ expect(directory.access_controls).to receive(:define_resource_requirements).and_call_original
+ directory.define_resource_requirements
+ expect { directory.process_resource_requirements }.to raise_error(ArgumentError)
+ end
end
+ end
- context "when user and group are specified with UID/GID" do
- it "describes the current owner and group as UID and GID" do
- allow(File).to receive(:exists?).and_return(true)
- expect(File).to receive(:stat).and_return(mock_stat)
- @directory.load_current_resource
- expect(@directory.current_resource.path).to eql(@new_resource.path)
- expect(@directory.current_resource.owner).to eql(500)
- expect(@directory.current_resource.group).to eql(500)
+ describe "#run_action(:create)" do
+ describe "when the directory exists" do
+ it "does not create the directory" do
+ expect(Dir).not_to receive(:mkdir).with(new_resource.path)
+ directory.run_action(:create)
+ end
+
+ it "should not set the resource as updated" do
+ directory.run_action(:create)
+ expect(new_resource).not_to be_updated
end
end
- context "when user/group are specified with user/group names" do
+ describe "when the directory does not exist" do
+ before do
+ FileUtils.rmdir tmp_dir
+ end
+
+ it "creates the directory" do
+ directory.run_action(:create)
+ expect(File.exist?(tmp_dir)).to be true
+ end
+
+ it "sets the new resource as updated" do
+ directory.run_action(:create)
+ expect(new_resource).to be_updated
+ end
end
- end
- # Unix only for now. While file security attribute reporting for windows is
- # disabled, unix and windows differ in the number of exists? calls that are
- # made by the provider.
- it "should create a new directory on create, setting updated to true", :unix_only do
- @new_resource.path "/tmp/foo"
+ describe "when the parent directory does not exist" do
+ before do
+ new_resource.path "#{tmp_dir}/foobar"
+ FileUtils.rmdir tmp_dir
+ end
- expect(File).to receive(:exists?).at_least(:once).and_return(false)
- expect(File).to receive(:directory?).with("/tmp").and_return(true)
- expect(Dir).to receive(:mkdir).with(@new_resource.path).once.and_return(true)
+ it "raises an exception when recursive is false" do
+ new_resource.recursive false
+ expect { directory.run_action(:create) }.to raise_error(Chef::Exceptions::EnclosingDirectoryDoesNotExist)
+ end
- expect(@directory).to receive(:do_acl_changes)
- allow(@directory).to receive(:do_selinux)
- @directory.run_action(:create)
- expect(@directory.new_resource).to be_updated
- end
+ it "creates the directories when recursive is true" do
+ new_resource.recursive true
+ directory.run_action(:create)
+ expect(new_resource).to be_updated
+ expect(File.exist?("#{tmp_dir}/foobar")).to be true
+ end
- it "should raise an exception if the parent directory does not exist and recursive is false" do
- @new_resource.path "/tmp/some/dir"
- @new_resource.recursive false
- expect { @directory.run_action(:create) }.to raise_error(Chef::Exceptions::EnclosingDirectoryDoesNotExist)
- end
+ it "raises an exception when the parent directory is a file and recursive is true" do
+ FileUtils.touch tmp_dir
+ new_resource.recursive true
+ expect { directory.run_action(:create) }.to raise_error
+ end
- # Unix only for now. While file security attribute reporting for windows is
- # disabled, unix and windows differ in the number of exists? calls that are
- # made by the provider.
- it "should create a new directory when parent directory does not exist if recursive is true and permissions are correct", :unix_only do
- @new_resource.path "/path/to/dir"
- @new_resource.recursive true
- expect(File).to receive(:exists?).with(@new_resource.path).ordered.and_return(false)
-
- expect(File).to receive(:exists?).with('/path/to').ordered.and_return(false)
- expect(File).to receive(:exists?).with('/path').ordered.and_return(true)
- expect(Chef::FileAccessControl).to receive(:writable?).with('/path').ordered.and_return(true)
- expect(File).to receive(:exists?).with(@new_resource.path).ordered.and_return(false)
-
- expect(FileUtils).to receive(:mkdir_p).with(@new_resource.path).and_return(true)
- expect(@directory).to receive(:do_acl_changes)
- allow(@directory).to receive(:do_selinux)
- @directory.run_action(:create)
- expect(@new_resource).to be_updated
+ it "raises the right exception when the parent directory is a file and recursive is true" do
+ pending "this seems to return the wrong error" # FIXME
+ FileUtils.touch tmp_dir
+ new_resource.recursive true
+ expect { directory.run_action(:create) }.to raise_error(Chef::Exceptions::EnclosingDirectoryDoesNotExist)
+ end
+ end
end
+ describe "#run_action(:create)" do
+ describe "when the directory exists" do
+ it "deletes the directory" do
+ directory.run_action(:delete)
+ expect(File.exist?(tmp_dir)).to be false
+ end
- it "should raise an error when creating a directory when parent directory is a file" do
- expect(File).to receive(:directory?).and_return(false)
- expect(Dir).not_to receive(:mkdir).with(@new_resource.path)
- expect { @directory.run_action(:create) }.to raise_error(Chef::Exceptions::EnclosingDirectoryDoesNotExist)
- expect(@directory.new_resource).not_to be_updated
- end
+ it "sets the new resource as updated" do
+ directory.run_action(:delete)
+ expect(new_resource).to be_updated
+ end
+ end
- # Unix only for now. While file security attribute reporting for windows is
- # disabled, unix and windows differ in the number of exists? calls that are
- # made by the provider.
- it "should not create the directory if it already exists", :unix_only do
- stub_file_cstats
- @new_resource.path "/tmp/foo"
- expect(File).to receive(:directory?).at_least(:once).and_return(true)
- expect(Chef::FileAccessControl).to receive(:writable?).with("/tmp").and_return(true)
- expect(File).to receive(:exists?).at_least(:once).and_return(true)
- expect(Dir).not_to receive(:mkdir).with(@new_resource.path)
- expect(@directory).to receive(:do_acl_changes)
- @directory.run_action(:create)
- end
+ describe "when the directory does not exist" do
+ before do
+ FileUtils.rmdir tmp_dir
+ end
- it "should delete the directory if it exists, and is writable with action_delete" do
- expect(File).to receive(:directory?).and_return(true)
- expect(Chef::FileAccessControl).to receive(:writable?).once.and_return(true)
- expect(Dir).to receive(:delete).with(@new_resource.path).once.and_return(true)
- @directory.run_action(:delete)
- end
+ it "does not delete the directory" do
+ expect(Dir).not_to receive(:delete).with(new_resource.path)
+ directory.run_action(:delete)
+ end
- it "should raise an exception if it cannot delete the directory due to bad permissions" do
- allow(File).to receive(:exists?).and_return(true)
- allow(Chef::FileAccessControl).to receive(:writable?).and_return(false)
- expect { @directory.run_action(:delete) }.to raise_error(RuntimeError)
- end
+ it "sets the new resource as updated" do
+ directory.run_action(:delete)
+ expect(new_resource).not_to be_updated
+ end
+ end
- it "should take no action when deleting a target directory that does not exist" do
- @new_resource.path "/an/invalid/path"
- allow(File).to receive(:exists?).and_return(false)
- expect(Dir).not_to receive(:delete).with(@new_resource.path)
- @directory.run_action(:delete)
- expect(@directory.new_resource).not_to be_updated
- end
+ describe "when the directory is not writable" do
+ before do
+ allow(Chef::FileAccessControl).to receive(:writable?).and_return(false)
+ end
- it "should raise an exception when deleting a directory when target directory is a file" do
- stub_file_cstats
- @new_resource.path "/an/invalid/path"
- allow(File).to receive(:exists?).and_return(true)
- expect(File).to receive(:directory?).and_return(false)
- expect(Dir).not_to receive(:delete).with(@new_resource.path)
- expect { @directory.run_action(:delete) }.to raise_error(RuntimeError)
- expect(@directory.new_resource).not_to be_updated
- end
+ it "cannot delete it and raises an exception" do
+ expect { directory.run_action(:delete) }.to raise_error(RuntimeError)
+ end
+ end
+
+ describe "when the target directory is a file" do
+ before do
+ FileUtils.rmdir tmp_dir
+ FileUtils.touch tmp_dir
+ end
- def stub_file_cstats
- cstats = double("stats")
- allow(cstats).to receive(:uid).and_return(500)
- allow(cstats).to receive(:gid).and_return(500)
- allow(cstats).to receive(:mode).and_return(0755)
- # File.stat is called in:
- # - Chef::Provider::File.load_current_resource_attrs
- # - Chef::ScanAccessControl via Chef::Provider::File.setup_acl
- allow(File).to receive(:stat).and_return(cstats)
+ it "cannot delete it and raises an exception" do
+ expect { directory.run_action(:delete) }.to raise_error(RuntimeError)
+ end
+ end
end
end
diff --git a/spec/unit/provider/execute_spec.rb b/spec/unit/provider/execute_spec.rb
index 51305b6225..1274203ce3 100644
--- a/spec/unit/provider/execute_spec.rb
+++ b/spec/unit/provider/execute_spec.rb
@@ -39,7 +39,7 @@ describe Chef::Provider::Execute do
let(:new_resource) { Chef::Resource::Execute.new("foo_resource", run_context) }
before do
- allow(Chef::Platform).to receive(:windows?) { false }
+ allow(ChefConfig).to receive(:windows?) { false }
@original_log_level = Chef::Log.level
Chef::Log.level = :info
allow(STDOUT).to receive(:tty?).and_return(true)
diff --git a/spec/unit/provider/ifconfig/debian_spec.rb b/spec/unit/provider/ifconfig/debian_spec.rb
index 351e734040..0c02ae9cd4 100644
--- a/spec/unit/provider/ifconfig/debian_spec.rb
+++ b/spec/unit/provider/ifconfig/debian_spec.rb
@@ -144,11 +144,6 @@ EOF
expect(IO.read(tempfile.path)).to eq(expected_string)
end
- it "should not mark the resource as updated" do
- provider.run_action(:add)
- pending "superclass ifconfig provider is not idempotent"
- expect(new_resource.updated_by_last_action?).to be_falsey
- end
end
context "when the /etc/network/interfaces file does not have the source line" do
@@ -280,11 +275,6 @@ another line
expect(IO.read(tempfile.path)).to eq(expected_string)
end
- it "should not mark the resource as updated" do
- provider.run_action(:add)
- pending "superclass ifconfig provider is not idempotent"
- expect(new_resource.updated_by_last_action?).to be_falsey
- end
end
context "when the /etc/network/interfaces file does not have the source line" do
diff --git a/spec/unit/provider/package/aix_spec.rb b/spec/unit/provider/package/aix_spec.rb
index 5bc861b849..13992cb8d1 100644
--- a/spec/unit/provider/package/aix_spec.rb
+++ b/spec/unit/provider/package/aix_spec.rb
@@ -36,23 +36,27 @@ describe Chef::Provider::Package::Aix do
@bffinfo ="/usr/lib/objrepos:samba.base:3.3.12.0::COMMITTED:I:Samba for AIX:
/etc/objrepos:samba.base:3.3.12.0::COMMITTED:I:Samba for AIX:"
- @status = double("Status", :stdout => "", :exitstatus => 0)
+ @empty_status = double("Status", :stdout => "", :exitstatus => 0)
end
it "should create a current resource with the name of new_resource" do
- allow(@provider).to receive(:shell_out).and_return(@status)
+ status = double("Status", :stdout => @bffinfo, :exitstatus => 0)
+ expect(@provider).to receive(:shell_out).with("installp -L -d /tmp/samba.base", timeout: 900).and_return(status)
+ expect(@provider).to receive(:shell_out).with("lslpp -lcq samba.base", timeout: 900).and_return(@empty_status)
@provider.load_current_resource
expect(@provider.current_resource.name).to eq("samba.base")
end
it "should set the current resource bff package name to the new resource bff package name" do
- allow(@provider).to receive(:shell_out).and_return(@status)
+ status = double("Status", :stdout => @bffinfo, :exitstatus => 0)
+ expect(@provider).to receive(:shell_out).with("installp -L -d /tmp/samba.base", timeout: 900).and_return(status)
+ expect(@provider).to receive(:shell_out).with("lslpp -lcq samba.base", timeout: 900).and_return(@empty_status)
@provider.load_current_resource
expect(@provider.current_resource.package_name).to eq("samba.base")
end
it "should raise an exception if a source is supplied but not found" do
- allow(@provider).to receive(:shell_out).and_return(@status)
+ allow(@provider).to receive(:shell_out).and_return(@empty_status)
allow(::File).to receive(:exists?).and_return(false)
@provider.load_current_resource
@provider.define_resource_requirements
@@ -61,8 +65,8 @@ describe Chef::Provider::Package::Aix do
it "should get the source package version from lslpp if provided" do
status = double("Status", :stdout => @bffinfo, :exitstatus => 0)
- expect(@provider).to receive(:shell_out).with("installp -L -d /tmp/samba.base").and_return(status)
- expect(@provider).to receive(:shell_out).with("lslpp -lcq samba.base").and_return(@status)
+ expect(@provider).to receive(:shell_out).with("installp -L -d /tmp/samba.base", timeout: 900).and_return(status)
+ expect(@provider).to receive(:shell_out).with("lslpp -lcq samba.base", timeout: 900).and_return(@empty_status)
@provider.load_current_resource
expect(@provider.current_resource.package_name).to eq("samba.base")
@@ -73,8 +77,8 @@ describe Chef::Provider::Package::Aix do
status = double("Status", :stdout => @bffinfo, :exitstatus => 0)
@stdout = StringIO.new(@bffinfo)
@stdin, @stderr = StringIO.new, StringIO.new
- expect(@provider).to receive(:shell_out).with("installp -L -d /tmp/samba.base").and_return(@status)
- expect(@provider).to receive(:shell_out).with("lslpp -lcq samba.base").and_return(status)
+ expect(@provider).to receive(:shell_out).with("installp -L -d /tmp/samba.base", timeout: 900).and_return(status)
+ expect(@provider).to receive(:shell_out).with("lslpp -lcq samba.base", timeout: 900).and_return(status)
@provider.load_current_resource
expect(@provider.current_resource.version).to eq("3.3.12.0")
end
@@ -94,12 +98,20 @@ describe Chef::Provider::Package::Aix do
end
it "should return a current resource with a nil version if the package is not found" do
- status = double(:stdout => "", :exitstatus => 0)
- expect(@provider).to receive(:shell_out).with("installp -L -d /tmp/samba.base").and_return(status)
- expect(@provider).to receive(:shell_out).with("lslpp -lcq samba.base").and_return(status)
+ status = double("Status", :stdout => @bffinfo, :exitstatus => 0)
+ expect(@provider).to receive(:shell_out).with("installp -L -d /tmp/samba.base", timeout: 900).and_return(status)
+ expect(@provider).to receive(:shell_out).with("lslpp -lcq samba.base", timeout: 900).and_return(@empty_status)
@provider.load_current_resource
expect(@provider.current_resource.version).to be_nil
end
+
+ it "should raise an exception if the source doesn't provide the requested package" do
+ wrongbffinfo = "/usr/lib/objrepos:openssl.base:0.9.8.2400::COMMITTED:I:Open Secure Socket Layer:
+/etc/objrepos:openssl.base:0.9.8.2400::COMMITTED:I:Open Secure Socket Layer:"
+ status = double("Status", :stdout => wrongbffinfo, :exitstatus => 0)
+ expect(@provider).to receive(:shell_out).with("installp -L -d /tmp/samba.base", timeout: 900).and_return(status)
+ expect { @provider.load_current_resource }.to raise_error(Chef::Exceptions::Package)
+ end
end
describe "candidate_version" do
@@ -125,7 +137,7 @@ describe Chef::Provider::Package::Aix do
describe "install and upgrade" do
it "should run installp -aYF -d with the package source to install" do
- expect(@provider).to receive(:shell_out!).with("installp -aYF -d /tmp/samba.base samba.base")
+ expect(@provider).to receive(:shell_out!).with("installp -aYF -d /tmp/samba.base samba.base", timeout: 900)
@provider.install_package("samba.base", "3.3.12.0")
end
@@ -133,26 +145,26 @@ describe Chef::Provider::Package::Aix do
@new_resource = Chef::Resource::Package.new("/tmp/samba.base")
@provider = Chef::Provider::Package::Aix.new(@new_resource, @run_context)
expect(@new_resource.source).to eq("/tmp/samba.base")
- expect(@provider).to receive(:shell_out!).with("installp -aYF -d /tmp/samba.base /tmp/samba.base")
+ expect(@provider).to receive(:shell_out!).with("installp -aYF -d /tmp/samba.base /tmp/samba.base", timeout: 900)
@provider.install_package("/tmp/samba.base", "3.3.12.0")
end
it "should run installp with -eLogfile option." do
allow(@new_resource).to receive(:options).and_return("-e/tmp/installp.log")
- expect(@provider).to receive(:shell_out!).with("installp -aYF -e/tmp/installp.log -d /tmp/samba.base samba.base")
+ expect(@provider).to receive(:shell_out!).with("installp -aYF -e/tmp/installp.log -d /tmp/samba.base samba.base", timeout: 900)
@provider.install_package("samba.base", "3.3.12.0")
end
end
describe "remove" do
it "should run installp -u samba.base to remove the package" do
- expect(@provider).to receive(:shell_out!).with("installp -u samba.base")
+ expect(@provider).to receive(:shell_out!).with("installp -u samba.base", timeout: 900)
@provider.remove_package("samba.base", "3.3.12.0")
end
it "should run installp -u -e/tmp/installp.log with options -e/tmp/installp.log" do
allow(@new_resource).to receive(:options).and_return("-e/tmp/installp.log")
- expect(@provider).to receive(:shell_out!).with("installp -u -e/tmp/installp.log samba.base")
+ expect(@provider).to receive(:shell_out!).with("installp -u -e/tmp/installp.log samba.base", timeout: 900)
@provider.remove_package("samba.base", "3.3.12.0")
end
diff --git a/spec/unit/provider/package/dpkg_spec.rb b/spec/unit/provider/package/dpkg_spec.rb
index 3fd86218d2..4974cff934 100644
--- a/spec/unit/provider/package/dpkg_spec.rb
+++ b/spec/unit/provider/package/dpkg_spec.rb
@@ -51,7 +51,7 @@ describe Chef::Provider::Package::Dpkg do
describe 'gets the source package version from dpkg-deb' do
def check_version(version)
@status = double(:stdout => "wget\t#{version}", :exitstatus => 0)
- allow(@provider).to receive(:shell_out).with("dpkg-deb -W #{@new_resource.source}").and_return(@status)
+ allow(@provider).to receive(:shell_out).with("dpkg-deb -W #{@new_resource.source}", timeout: 900).and_return(@status)
@provider.load_current_resource
expect(@provider.current_resource.package_name).to eq("wget")
expect(@new_resource.version).to eq(version)
@@ -106,7 +106,7 @@ Depends: libc6 (>= 2.8~20080505), libssl0.9.8 (>= 0.9.8f-5)
Conflicts: wget-ssl
DPKG_S
status = double(:stdout => stdout, :exitstatus => 1)
- allow(@provider).to receive(:shell_out).with("dpkg -s wget").and_return(status)
+ allow(@provider).to receive(:shell_out).with("dpkg -s wget", timeout: 900).and_return(status)
@provider.load_current_resource
expect(@provider.current_resource.version).to eq("1.11.4-1ubuntu1")
diff --git a/spec/unit/provider/package/freebsd/pkg_spec.rb b/spec/unit/provider/package/freebsd/pkg_spec.rb
index f67161930f..d1f5a649bc 100644
--- a/spec/unit/provider/package/freebsd/pkg_spec.rb
+++ b/spec/unit/provider/package/freebsd/pkg_spec.rb
@@ -77,7 +77,7 @@ describe Chef::Provider::Package::Freebsd::Pkg, "load_current_resource" do
it "should return the version number when it is installed" do
pkg_info = OpenStruct.new(:stdout => "zsh-4.3.6_7")
- expect(@provider).to receive(:shell_out!).with('pkg_info -E "zsh*"', :env => nil, :returns => [0,1]).and_return(pkg_info)
+ expect(@provider).to receive(:shell_out!).with('pkg_info -E "zsh*"', env: nil, returns: [0,1], timeout: 900).and_return(pkg_info)
#@provider.should_receive(:popen4).with('pkg_info -E "zsh*"').and_yield(@pid, @stdin, ["zsh-4.3.6_7"], @stderr).and_return(@status)
allow(@provider).to receive(:package_name).and_return("zsh")
expect(@provider.current_installed_version).to eq("4.3.6_7")
@@ -85,14 +85,14 @@ describe Chef::Provider::Package::Freebsd::Pkg, "load_current_resource" do
it "does not set the current version number when the package is not installed" do
pkg_info = OpenStruct.new(:stdout => "")
- expect(@provider).to receive(:shell_out!).with('pkg_info -E "zsh*"', :env => nil, :returns => [0,1]).and_return(pkg_info)
+ expect(@provider).to receive(:shell_out!).with('pkg_info -E "zsh*"', env: nil, returns: [0,1], timeout: 900).and_return(pkg_info)
allow(@provider).to receive(:package_name).and_return("zsh")
expect(@provider.current_installed_version).to be_nil
end
it "should return the port path for a valid port name" do
whereis = OpenStruct.new(:stdout => "zsh: /usr/ports/shells/zsh")
- expect(@provider).to receive(:shell_out!).with("whereis -s zsh", :env => nil).and_return(whereis)
+ expect(@provider).to receive(:shell_out!).with("whereis -s zsh", env: nil, timeout: 900).and_return(whereis)
#@provider.should_receive(:popen4).with("whereis -s zsh").and_yield(@pid, @stdin, ["zsh: /usr/ports/shells/zsh"], @stderr).and_return(@status)
allow(@provider).to receive(:port_name).and_return("zsh")
expect(@provider.port_path).to eq("/usr/ports/shells/zsh")
@@ -102,7 +102,7 @@ describe Chef::Provider::Package::Freebsd::Pkg, "load_current_resource" do
it "should return the ports candidate version when given a valid port path" do
allow(@provider).to receive(:port_path).and_return("/usr/ports/shells/zsh")
make_v = OpenStruct.new(:stdout => "4.3.6\n", :exitstatus => 0)
- expect(@provider).to receive(:shell_out!).with("make -V PORTVERSION", {:cwd=>"/usr/ports/shells/zsh", :returns=>[0, 1], :env=>nil}).and_return(make_v)
+ expect(@provider).to receive(:shell_out!).with("make -V PORTVERSION", {cwd: "/usr/ports/shells/zsh", returns: [0, 1], env: nil, timeout: 900}).and_return(make_v)
expect(@provider.ports_candidate_version).to eq("4.3.6")
end
@@ -110,7 +110,7 @@ describe Chef::Provider::Package::Freebsd::Pkg, "load_current_resource" do
allow(::File).to receive(:exist?).with('/usr/ports/Makefile').and_return(true)
allow(@provider).to receive(:port_path).and_return("/usr/ports/shells/zsh")
make_v = OpenStruct.new(:stdout => "zsh-4.3.6_7\n", :exitstatus => 0)
- expect(@provider).to receive(:shell_out!).with("make -V PKGNAME", {:cwd=>"/usr/ports/shells/zsh", :env=>nil, :returns=>[0, 1]}).and_return(make_v)
+ expect(@provider).to receive(:shell_out!).with("make -V PKGNAME", {cwd: "/usr/ports/shells/zsh", env: nil, returns: [0, 1], timeout: 900}).and_return(make_v)
#@provider.should_receive(:ports_makefile_variable_value).with("PKGNAME").and_return("zsh-4.3.6_7")
expect(@provider.package_name).to eq("zsh")
end
@@ -127,7 +127,7 @@ describe Chef::Provider::Package::Freebsd::Pkg, "load_current_resource" do
end
it "should run pkg_add -r with the package name" do
- expect(@provider).to receive(:shell_out!).with("pkg_add -r zsh", :env => nil).and_return(@cmd_result)
+ expect(@provider).to receive(:shell_out!).with("pkg_add -r zsh", env: nil, timeout: 900).and_return(@cmd_result)
@provider.install_package("zsh", "4.3.6_7")
end
end
@@ -142,7 +142,7 @@ describe Chef::Provider::Package::Freebsd::Pkg, "load_current_resource" do
it "should figure out the port path from the package_name using whereis" do
whereis = OpenStruct.new(:stdout => "zsh: /usr/ports/shells/zsh")
- expect(@provider).to receive(:shell_out!).with("whereis -s zsh", :env=>nil).and_return(whereis)
+ expect(@provider).to receive(:shell_out!).with("whereis -s zsh", env: nil, timeout: 900).and_return(whereis)
expect(@provider.port_path).to eq("/usr/ports/shells/zsh")
end
@@ -178,7 +178,7 @@ describe Chef::Provider::Package::Freebsd::Pkg, "load_current_resource" do
end
it "should run pkg_add -r with the package name" do
- expect(@provider).to receive(:shell_out!).with("pkg_add -r ruby18-iconv", :env => nil).and_return(@install_result)
+ expect(@provider).to receive(:shell_out!).with("pkg_add -r ruby18-iconv", env: nil, timeout: 900).and_return(@install_result)
@provider.install_package("ruby-iconv", "1.0")
end
end
@@ -193,7 +193,7 @@ describe Chef::Provider::Package::Freebsd::Pkg, "load_current_resource" do
end
it "should run pkg_delete with the package name and version" do
- expect(@provider).to receive(:shell_out!).with("pkg_delete zsh-4.3.6_7", :env => nil).and_return(@pkg_delete)
+ expect(@provider).to receive(:shell_out!).with("pkg_delete zsh-4.3.6_7", env: nil, timeout: 900).and_return(@pkg_delete)
@provider.remove_package("zsh", "4.3.6_7")
end
end
@@ -213,14 +213,14 @@ describe Chef::Provider::Package::Freebsd::Pkg, "load_current_resource" do
it "should return the port path for a valid port name" do
whereis = OpenStruct.new(:stdout => "bonnie++: /usr/ports/benchmarks/bonnie++")
- expect(@provider).to receive(:shell_out!).with("whereis -s bonnie++", :env => nil).and_return(whereis)
+ expect(@provider).to receive(:shell_out!).with("whereis -s bonnie++", env: nil, timeout: 900).and_return(whereis)
allow(@provider).to receive(:port_name).and_return("bonnie++")
expect(@provider.port_path).to eq("/usr/ports/benchmarks/bonnie++")
end
it "should return the version number when it is installed" do
pkg_info = OpenStruct.new(:stdout => "bonnie++-1.96")
- expect(@provider).to receive(:shell_out!).with('pkg_info -E "bonnie++*"', :env => nil, :returns => [0,1]).and_return(pkg_info)
+ expect(@provider).to receive(:shell_out!).with('pkg_info -E "bonnie++*"', env: nil, returns: [0,1], timeout: 900).and_return(pkg_info)
allow(@provider).to receive(:package_name).and_return("bonnie++")
expect(@provider.current_installed_version).to eq("1.96")
end
@@ -253,7 +253,7 @@ describe Chef::Provider::Package::Freebsd::Pkg, "load_current_resource" do
allow(@provider).to receive(:latest_link_name).and_return("perl")
cmd = OpenStruct.new(:status => true)
- expect(@provider).to receive(:shell_out!).with("pkg_add -r perl", :env => nil).and_return(cmd)
+ expect(@provider).to receive(:shell_out!).with("pkg_add -r perl", env: nil, timeout: 900).and_return(cmd)
@provider.install_package("perl5.8", "5.8.8_1")
end
@@ -267,7 +267,7 @@ describe Chef::Provider::Package::Freebsd::Pkg, "load_current_resource" do
allow(@provider).to receive(:latest_link_name).and_return("mysql50-server")
cmd = OpenStruct.new(:status => true)
- expect(@provider).to receive(:shell_out!).with("pkg_add -r mysql50-server", :env=>nil).and_return(cmd)
+ expect(@provider).to receive(:shell_out!).with("pkg_add -r mysql50-server", env: nil, timeout: 900).and_return(cmd)
@provider.install_package("mysql50-server", "5.0.45_1")
end
end
diff --git a/spec/unit/provider/package/freebsd/pkgng_spec.rb b/spec/unit/provider/package/freebsd/pkgng_spec.rb
index 0c1e89c7ab..59215f855b 100644
--- a/spec/unit/provider/package/freebsd/pkgng_spec.rb
+++ b/spec/unit/provider/package/freebsd/pkgng_spec.rb
@@ -71,7 +71,7 @@ describe Chef::Provider::Package::Freebsd::Port do
end
it "should query pkg database" do
- expect(@provider).to receive(:shell_out!).with('pkg info "zsh"', :env => nil, :returns => [0,70]).and_return(@pkg_info)
+ expect(@provider).to receive(:shell_out!).with('pkg info "zsh"', env: nil, returns: [0,70], timeout: 900).and_return(@pkg_info)
expect(@provider.current_installed_version).to eq("3.1.7")
end
end
@@ -80,14 +80,14 @@ describe Chef::Provider::Package::Freebsd::Port do
describe "determining candidate version" do
it "should query repository" do
pkg_query = OpenStruct.new(:stdout => "5.0.5\n", :exitstatus => 0)
- expect(@provider).to receive(:shell_out!).with("pkg rquery '%v' zsh", :env => nil).and_return(pkg_query)
+ expect(@provider).to receive(:shell_out!).with("pkg rquery '%v' zsh", env: nil, timeout: 900).and_return(pkg_query)
expect(@provider.candidate_version).to eq("5.0.5")
end
it "should query specified repository when given option" do
@provider.new_resource.options('-r LocalMirror') # This requires LocalMirror repo configuration.
pkg_query = OpenStruct.new(:stdout => "5.0.3\n", :exitstatus => 0)
- expect(@provider).to receive(:shell_out!).with("pkg rquery -r LocalMirror '%v' zsh", :env => nil).and_return(pkg_query)
+ expect(@provider).to receive(:shell_out!).with("pkg rquery -r LocalMirror '%v' zsh", env: nil, timeout: 900).and_return(pkg_query)
expect(@provider.candidate_version).to eq("5.0.3")
end
@@ -106,7 +106,7 @@ describe Chef::Provider::Package::Freebsd::Port do
it "should handle package source from file" do
@provider.new_resource.source("/nas/pkg/repo/zsh-5.0.1.txz")
expect(@provider).to receive(:shell_out!).
- with("pkg add /nas/pkg/repo/zsh-5.0.1.txz", :env => { 'LC_ALL' => nil }).
+ with("pkg add /nas/pkg/repo/zsh-5.0.1.txz", env: { 'LC_ALL' => nil }, timeout: 900).
and_return(@install_result)
@provider.install_package("zsh", "5.0.1")
end
@@ -114,21 +114,21 @@ describe Chef::Provider::Package::Freebsd::Port do
it "should handle package source over ftp or http" do
@provider.new_resource.source("http://repo.example.com/zsh-5.0.1.txz")
expect(@provider).to receive(:shell_out!).
- with("pkg add http://repo.example.com/zsh-5.0.1.txz", :env => { 'LC_ALL' => nil }).
+ with("pkg add http://repo.example.com/zsh-5.0.1.txz", env: { 'LC_ALL' => nil }, timeout: 900).
and_return(@install_result)
@provider.install_package("zsh", "5.0.1")
end
it "should handle a package name" do
expect(@provider).to receive(:shell_out!).
- with("pkg install -y zsh", :env => { 'LC_ALL' => nil }).and_return(@install_result)
+ with("pkg install -y zsh", env: { 'LC_ALL' => nil }, timeout: 900).and_return(@install_result)
@provider.install_package("zsh", "5.0.1")
end
it "should handle a package name with a specified repo" do
@provider.new_resource.options('-r LocalMirror') # This requires LocalMirror repo configuration.
expect(@provider).to receive(:shell_out!).
- with("pkg install -y -r LocalMirror zsh", :env => { 'LC_ALL' => nil }).and_return(@install_result)
+ with("pkg install -y -r LocalMirror zsh", env: { 'LC_ALL' => nil }, timeout: 900).and_return(@install_result)
@provider.install_package("zsh", "5.0.1")
end
end
@@ -141,14 +141,14 @@ describe Chef::Provider::Package::Freebsd::Port do
it "should call pkg delete" do
expect(@provider).to receive(:shell_out!).
- with("pkg delete -y zsh-5.0.1", :env => nil).and_return(@install_result)
+ with("pkg delete -y zsh-5.0.1", env: nil, timeout: 900).and_return(@install_result)
@provider.remove_package("zsh", "5.0.1")
end
it "should not include repo option in pkg delete" do
@provider.new_resource.options('-r LocalMirror') # This requires LocalMirror repo configuration.
expect(@provider).to receive(:shell_out!).
- with("pkg delete -y zsh-5.0.1", :env => nil).and_return(@install_result)
+ with("pkg delete -y zsh-5.0.1", env: nil, timeout: 900).and_return(@install_result)
@provider.remove_package("zsh", "5.0.1")
end
end
diff --git a/spec/unit/provider/package/freebsd/port_spec.rb b/spec/unit/provider/package/freebsd/port_spec.rb
index 2e32e88f97..4b23575740 100644
--- a/spec/unit/provider/package/freebsd/port_spec.rb
+++ b/spec/unit/provider/package/freebsd/port_spec.rb
@@ -72,7 +72,7 @@ describe Chef::Provider::Package::Freebsd::Port do
it "should check 'pkg_info' if system uses pkg_* tools" do
allow(@new_resource).to receive(:supports_pkgng?)
expect(@new_resource).to receive(:supports_pkgng?).and_return(false)
- expect(@provider).to receive(:shell_out!).with('pkg_info -E "zsh*"', :env => nil, :returns => [0,1]).and_return(@pkg_info)
+ expect(@provider).to receive(:shell_out!).with('pkg_info -E "zsh*"', env: nil, returns: [0,1], timeout: 900).and_return(@pkg_info)
expect(@provider.current_installed_version).to eq("3.1.7")
end
@@ -80,8 +80,8 @@ describe Chef::Provider::Package::Freebsd::Port do
pkg_enabled = OpenStruct.new(:stdout => "yes\n")
[1000016, 1000000, 901503, 902506, 802511].each do |__freebsd_version|
@node.automatic_attrs[:os_version] = __freebsd_version
- expect(@new_resource).to receive(:shell_out!).with('make -V WITH_PKGNG', :env => nil).and_return(pkg_enabled)
- expect(@provider).to receive(:shell_out!).with('pkg info "zsh"', :env => nil, :returns => [0,70]).and_return(@pkg_info)
+ expect(@new_resource).to receive(:shell_out!).with('make -V WITH_PKGNG', env: nil).and_return(pkg_enabled)
+ expect(@provider).to receive(:shell_out!).with('pkg info "zsh"', env: nil, returns: [0,70], timeout: 900).and_return(@pkg_info)
expect(@provider.current_installed_version).to eq("3.1.7")
end
end
@@ -89,7 +89,7 @@ describe Chef::Provider::Package::Freebsd::Port do
it "should check 'pkg info' if the freebsd version is greater than or equal to 1000017" do
__freebsd_version = 1000017
@node.automatic_attrs[:os_version] = __freebsd_version
- expect(@provider).to receive(:shell_out!).with('pkg info "zsh"', :env => nil, :returns => [0,70]).and_return(@pkg_info)
+ expect(@provider).to receive(:shell_out!).with('pkg info "zsh"', env: nil, returns: [0,70], timeout: 900).and_return(@pkg_info)
expect(@provider.current_installed_version).to eq("3.1.7")
end
end
@@ -102,7 +102,7 @@ describe Chef::Provider::Package::Freebsd::Port do
it "should return candidate version if port exists" do
allow(::File).to receive(:exist?).with('/usr/ports/Makefile').and_return(true)
allow(@provider).to receive(:port_dir).and_return('/usr/ports/shells/zsh')
- expect(@provider).to receive(:shell_out!).with("make -V PORTVERSION", :cwd => "/usr/ports/shells/zsh", :env => nil, :returns => [0,1]).
+ expect(@provider).to receive(:shell_out!).with("make -V PORTVERSION", cwd: "/usr/ports/shells/zsh", env: nil, returns: [0,1], timeout: 900).
and_return(@port_version)
expect(@provider.candidate_version).to eq("5.0.5")
end
@@ -127,13 +127,13 @@ describe Chef::Provider::Package::Freebsd::Port do
it "should query system for path given just a name" do
whereis = OpenStruct.new(:stdout => "zsh: /usr/ports/shells/zsh\n")
- expect(@provider).to receive(:shell_out!).with("whereis -s zsh", :env => nil).and_return(whereis)
+ expect(@provider).to receive(:shell_out!).with("whereis -s zsh", env: nil, timeout: 900).and_return(whereis)
expect(@provider.port_dir).to eq("/usr/ports/shells/zsh")
end
it "should raise exception if not found" do
whereis = OpenStruct.new(:stdout => "zsh:\n")
- expect(@provider).to receive(:shell_out!).with("whereis -s zsh", :env => nil).and_return(whereis)
+ expect(@provider).to receive(:shell_out!).with("whereis -s zsh", env: nil, timeout: 900).and_return(whereis)
expect { @provider.port_dir }.to raise_error(Chef::Exceptions::Package, "Could not find port with the name zsh")
end
end
diff --git a/spec/unit/provider/package/ips_spec.rb b/spec/unit/provider/package/ips_spec.rb
index 342ac4c040..ad69dffb10 100644
--- a/spec/unit/provider/package/ips_spec.rb
+++ b/spec/unit/provider/package/ips_spec.rb
@@ -65,28 +65,28 @@ PKG_STATUS
context "when loading current resource" do
it "should create a current resource with the name of the new_resource" do
- expect(@provider).to receive(:shell_out).with("pkg info #{@new_resource.package_name}").and_return(local_output)
- expect(@provider).to receive(:shell_out!).with("pkg info -r #{@new_resource.package_name}").and_return(remote_output)
+ expect(@provider).to receive(:shell_out).with("pkg info #{@new_resource.package_name}", timeout: 900).and_return(local_output)
+ expect(@provider).to receive(:shell_out!).with("pkg info -r #{@new_resource.package_name}", timeout: 900).and_return(remote_output)
expect(Chef::Resource::Package).to receive(:new).and_return(@current_resource)
@provider.load_current_resource
end
it "should set the current resources package name to the new resources package name" do
- expect(@provider).to receive(:shell_out).with("pkg info #{@new_resource.package_name}").and_return(local_output)
- expect(@provider).to receive(:shell_out!).with("pkg info -r #{@new_resource.package_name}").and_return(remote_output)
+ expect(@provider).to receive(:shell_out).with("pkg info #{@new_resource.package_name}", timeout: 900).and_return(local_output)
+ expect(@provider).to receive(:shell_out!).with("pkg info -r #{@new_resource.package_name}", timeout: 900).and_return(remote_output)
@provider.load_current_resource
expect(@current_resource.package_name).to eq(@new_resource.package_name)
end
it "should run pkg info with the package name" do
- expect(@provider).to receive(:shell_out).with("pkg info #{@new_resource.package_name}").and_return(local_output)
- expect(@provider).to receive(:shell_out!).with("pkg info -r #{@new_resource.package_name}").and_return(remote_output)
+ expect(@provider).to receive(:shell_out).with("pkg info #{@new_resource.package_name}", timeout: 900).and_return(local_output)
+ expect(@provider).to receive(:shell_out!).with("pkg info -r #{@new_resource.package_name}", timeout: 900).and_return(remote_output)
@provider.load_current_resource
end
it "should set the installed version to nil on the current resource if package state is not installed" do
- expect(@provider).to receive(:shell_out).with("pkg info #{@new_resource.package_name}").and_return(local_output)
- expect(@provider).to receive(:shell_out!).with("pkg info -r #{@new_resource.package_name}").and_return(remote_output)
+ expect(@provider).to receive(:shell_out).with("pkg info #{@new_resource.package_name}", timeout: 900).and_return(local_output)
+ expect(@provider).to receive(:shell_out!).with("pkg info -r #{@new_resource.package_name}", timeout: 900).and_return(remote_output)
@provider.load_current_resource
expect(@current_resource.version).to be_nil
end
@@ -108,27 +108,27 @@ Packaging Date: October 19, 2011 09:14:50 AM
Size: 8.07 MB
FMRI: pkg://solaris/crypto/gnupg@2.0.17,5.11-0.175.0.0.0.2.537:20111019T091450Z
INSTALLED
- expect(@provider).to receive(:shell_out).with("pkg info #{@new_resource.package_name}").and_return(local)
- expect(@provider).to receive(:shell_out!).with("pkg info -r #{@new_resource.package_name}").and_return(remote_output)
+ expect(@provider).to receive(:shell_out).with("pkg info #{@new_resource.package_name}", timeout: 900).and_return(local)
+ expect(@provider).to receive(:shell_out!).with("pkg info -r #{@new_resource.package_name}", timeout: 900).and_return(remote_output)
@provider.load_current_resource
expect(@current_resource.version).to eq("2.0.17")
end
it "should return the current resource" do
- expect(@provider).to receive(:shell_out).with("pkg info #{@new_resource.package_name}").and_return(local_output)
- expect(@provider).to receive(:shell_out!).with("pkg info -r #{@new_resource.package_name}").and_return(remote_output)
+ expect(@provider).to receive(:shell_out).with("pkg info #{@new_resource.package_name}", timeout: 900).and_return(local_output)
+ expect(@provider).to receive(:shell_out!).with("pkg info -r #{@new_resource.package_name}", timeout: 900).and_return(remote_output)
expect(@provider.load_current_resource).to eql(@current_resource)
end
end
context "when installing a package" do
it "should run pkg install with the package name and version" do
- expect(@provider).to receive(:shell_out).with("pkg install -q crypto/gnupg@2.0.17")
+ expect(@provider).to receive(:shell_out).with("pkg install -q crypto/gnupg@2.0.17", timeout: 900)
@provider.install_package("crypto/gnupg", "2.0.17")
end
it "should run pkg install with the package name and version and options if specified" do
- expect(@provider).to receive(:shell_out).with("pkg --no-refresh install -q crypto/gnupg@2.0.17")
+ expect(@provider).to receive(:shell_out).with("pkg --no-refresh install -q crypto/gnupg@2.0.17", timeout: 900)
allow(@new_resource).to receive(:options).and_return("--no-refresh")
@provider.install_package("crypto/gnupg", "2.0.17")
end
@@ -147,8 +147,8 @@ Packaging Date: April 1, 2012 05:55:52 PM
Size: 2.57 MB
FMRI: pkg://omnios/security/sudo@1.8.4.1,5.11-0.151002:20120401T175552Z
PKG_STATUS
- expect(@provider).to receive(:shell_out).with("pkg info #{@new_resource.package_name}").and_return(local_output)
- expect(@provider).to receive(:shell_out!).with("pkg info -r #{@new_resource.package_name}").and_return(remote)
+ expect(@provider).to receive(:shell_out).with("pkg info #{@new_resource.package_name}", timeout: 900).and_return(local_output)
+ expect(@provider).to receive(:shell_out!).with("pkg info -r #{@new_resource.package_name}", timeout: 900).and_return(remote)
@provider.load_current_resource
expect(@current_resource.version).to be_nil
expect(@provider.candidate_version).to eql("1.8.4.1")
@@ -188,8 +188,8 @@ Packaging Date: October 19, 2011 09:14:50 AM
FMRI: pkg://solaris/crypto/gnupg@2.0.18,5.11-0.175.0.0.0.2.537:20111019T091450Z
REMOTE
- expect(@provider).to receive(:shell_out).with("pkg info #{@new_resource.package_name}").and_return(local)
- expect(@provider).to receive(:shell_out!).with("pkg info -r #{@new_resource.package_name}").and_return(remote)
+ expect(@provider).to receive(:shell_out).with("pkg info #{@new_resource.package_name}", timeout: 900).and_return(local)
+ expect(@provider).to receive(:shell_out!).with("pkg info -r #{@new_resource.package_name}", timeout: 900).and_return(remote)
expect(@provider).to receive(:install_package).exactly(0).times
@provider.run_action(:install)
end
@@ -200,7 +200,7 @@ REMOTE
end
it "should run pkg install with the --accept flag" do
- expect(@provider).to receive(:shell_out).with("pkg install -q --accept crypto/gnupg@2.0.17")
+ expect(@provider).to receive(:shell_out).with("pkg install -q --accept crypto/gnupg@2.0.17", timeout: 900)
@provider.install_package("crypto/gnupg", "2.0.17")
end
end
@@ -208,19 +208,19 @@ REMOTE
context "when upgrading a package" do
it "should run pkg install with the package name and version" do
- expect(@provider).to receive(:shell_out).with("pkg install -q crypto/gnupg@2.0.17")
+ expect(@provider).to receive(:shell_out).with("pkg install -q crypto/gnupg@2.0.17", timeout: 900)
@provider.upgrade_package("crypto/gnupg", "2.0.17")
end
end
context "when uninstalling a package" do
it "should run pkg uninstall with the package name and version" do
- expect(@provider).to receive(:shell_out!).with("pkg uninstall -q crypto/gnupg@2.0.17")
+ expect(@provider).to receive(:shell_out!).with("pkg uninstall -q crypto/gnupg@2.0.17", timeout: 900)
@provider.remove_package("crypto/gnupg", "2.0.17")
end
it "should run pkg uninstall with the package name and version and options if specified" do
- expect(@provider).to receive(:shell_out!).with("pkg --no-refresh uninstall -q crypto/gnupg@2.0.17")
+ expect(@provider).to receive(:shell_out!).with("pkg --no-refresh uninstall -q crypto/gnupg@2.0.17", timeout: 900)
allow(@new_resource).to receive(:options).and_return("--no-refresh")
@provider.remove_package("crypto/gnupg", "2.0.17")
end
diff --git a/spec/unit/provider/package/macports_spec.rb b/spec/unit/provider/package/macports_spec.rb
index 9822fb3928..eef84113b4 100644
--- a/spec/unit/provider/package/macports_spec.rb
+++ b/spec/unit/provider/package/macports_spec.rb
@@ -105,7 +105,7 @@ EOF
it "should run the port install command with the correct version" do
expect(@current_resource).to receive(:version).and_return("4.1.6")
@provider.current_resource = @current_resource
- expect(@provider).to receive(:shell_out!).with("port install zsh @4.2.7")
+ expect(@provider).to receive(:shell_out!).with("port install zsh @4.2.7", timeout: 900)
@provider.install_package("zsh", "4.2.7")
end
@@ -122,7 +122,7 @@ EOF
expect(@current_resource).to receive(:version).and_return("4.1.6")
@provider.current_resource = @current_resource
allow(@new_resource).to receive(:options).and_return("-f")
- expect(@provider).to receive(:shell_out!).with("port -f install zsh @4.2.7")
+ expect(@provider).to receive(:shell_out!).with("port -f install zsh @4.2.7", timeout: 900)
@provider.install_package("zsh", "4.2.7")
end
@@ -130,36 +130,36 @@ EOF
describe "purge_package" do
it "should run the port uninstall command with the correct version" do
- expect(@provider).to receive(:shell_out!).with("port uninstall zsh @4.2.7")
+ expect(@provider).to receive(:shell_out!).with("port uninstall zsh @4.2.7", timeout: 900)
@provider.purge_package("zsh", "4.2.7")
end
it "should purge the currently active version if no explicit version is passed in" do
- expect(@provider).to receive(:shell_out!).with("port uninstall zsh")
+ expect(@provider).to receive(:shell_out!).with("port uninstall zsh", timeout: 900)
@provider.purge_package("zsh", nil)
end
it "should add options to the port command when specified" do
allow(@new_resource).to receive(:options).and_return("-f")
- expect(@provider).to receive(:shell_out!).with("port -f uninstall zsh @4.2.7")
+ expect(@provider).to receive(:shell_out!).with("port -f uninstall zsh @4.2.7", timeout: 900)
@provider.purge_package("zsh", "4.2.7")
end
end
describe "remove_package" do
it "should run the port deactivate command with the correct version" do
- expect(@provider).to receive(:shell_out!).with("port deactivate zsh @4.2.7")
+ expect(@provider).to receive(:shell_out!).with("port deactivate zsh @4.2.7", timeout: 900)
@provider.remove_package("zsh", "4.2.7")
end
it "should remove the currently active version if no explicit version is passed in" do
- expect(@provider).to receive(:shell_out!).with("port deactivate zsh")
+ expect(@provider).to receive(:shell_out!).with("port deactivate zsh", timeout: 900)
@provider.remove_package("zsh", nil)
end
it "should add options to the port command when specified" do
allow(@new_resource).to receive(:options).and_return("-f")
- expect(@provider).to receive(:shell_out!).with("port -f deactivate zsh @4.2.7")
+ expect(@provider).to receive(:shell_out!).with("port -f deactivate zsh @4.2.7", timeout: 900)
@provider.remove_package("zsh", "4.2.7")
end
end
@@ -169,7 +169,7 @@ EOF
expect(@current_resource).to receive(:version).at_least(:once).and_return("4.1.6")
@provider.current_resource = @current_resource
- expect(@provider).to receive(:shell_out!).with("port upgrade zsh @4.2.7")
+ expect(@provider).to receive(:shell_out!).with("port upgrade zsh @4.2.7", timeout: 900)
@provider.upgrade_package("zsh", "4.2.7")
end
@@ -195,7 +195,7 @@ EOF
expect(@current_resource).to receive(:version).at_least(:once).and_return("4.1.6")
@provider.current_resource = @current_resource
- expect(@provider).to receive(:shell_out!).with("port -f upgrade zsh @4.2.7")
+ expect(@provider).to receive(:shell_out!).with("port -f upgrade zsh @4.2.7", timeout: 900)
@provider.upgrade_package("zsh", "4.2.7")
end
diff --git a/spec/unit/provider/package/openbsd_spec.rb b/spec/unit/provider/package/openbsd_spec.rb
index b0cdb9969d..8407f83785 100644
--- a/spec/unit/provider/package/openbsd_spec.rb
+++ b/spec/unit/provider/package/openbsd_spec.rb
@@ -50,25 +50,13 @@ describe Chef::Provider::Package::Openbsd do
context 'when there is a single candidate' do
- context 'when installing from source' do
- it 'should run the installation command' do
- pending('Installing from source is not supported yet')
- # This is a consequence of load_current_resource being called before define_resource_requirements
- # It can be deleted once an implementation is provided
- allow(provider).to receive(:shell_out!).with("pkg_info -I \"#{name}\"", anything()).and_return(
- instance_double('shellout', :stdout => "#{name}-#{version}\n"))
- new_resource.source('/some/path/on/disk.tgz')
- provider.run_action(:install)
- end
- end
-
context 'when source is not provided' do
it 'should run the installation command' do
expect(provider).to receive(:shell_out!).with("pkg_info -I \"#{name}\"", anything()).and_return(
instance_double('shellout', :stdout => "#{name}-#{version}\n"))
expect(provider).to receive(:shell_out!).with(
"pkg_add -r #{name}-#{version}",
- {:env => {"PKG_PATH" => "http://ftp.OpenBSD.org/pub/OpenBSD/5.5/packages/amd64/"}}
+ {:env => {"PKG_PATH" => "http://ftp.OpenBSD.org/pub/OpenBSD/5.5/packages/amd64/"}, timeout: 900}
) {OpenStruct.new :status => true}
provider.run_action(:install)
end
@@ -100,21 +88,12 @@ describe Chef::Provider::Package::Openbsd do
instance_double('shellout', :stdout => "#{name}-#{version}-#{flavor}\n"))
expect(provider).to receive(:shell_out!).with(
"pkg_add -r #{name}-#{version}-#{flavor}",
- {:env => {"PKG_PATH" => "http://ftp.OpenBSD.org/pub/OpenBSD/5.5/packages/amd64/"}}
+ {env: {"PKG_PATH" => "http://ftp.OpenBSD.org/pub/OpenBSD/5.5/packages/amd64/"}, timeout: 900}
) {OpenStruct.new :status => true}
provider.run_action(:install)
end
end
- context 'if a version is specified' do
- it 'runs the installation command' do
- pending('Specifying both a version and flavor is not supported')
- new_resource.version(version)
- allow(provider).to receive(:shell_out!).with(/pkg_info -e/, anything()).and_return(instance_double('shellout', :stdout => ''))
- allow(provider).to receive(:candidate_version).and_return("#{package_name}-#{version}-#{flavor}")
- provider.run_action(:install)
- end
- end
end
context 'if a version is specified' do
@@ -125,7 +104,7 @@ describe Chef::Provider::Package::Openbsd do
new_resource.version("#{version}-#{flavor_b}")
expect(provider).to receive(:shell_out!).with(
"pkg_add -r #{name}-#{version}-#{flavor_b}",
- {:env => {"PKG_PATH" => "http://ftp.OpenBSD.org/pub/OpenBSD/5.5/packages/amd64/"}}
+ {env: {"PKG_PATH" => "http://ftp.OpenBSD.org/pub/OpenBSD/5.5/packages/amd64/"}, timeout: 900}
) {OpenStruct.new :status => true}
provider.run_action(:install)
end
@@ -144,11 +123,10 @@ describe Chef::Provider::Package::Openbsd do
end
it "should run the command to delete the installed package" do
expect(@provider).to receive(:shell_out!).with(
- "pkg_delete #{@name}", :env=>nil
+ "pkg_delete #{@name}", env: nil, timeout: 900
) {OpenStruct.new :status => true}
@provider.remove_package(@name, nil)
end
end
end
-
diff --git a/spec/unit/provider/package/pacman_spec.rb b/spec/unit/provider/package/pacman_spec.rb
index 3b8848c41b..fcb9f8a86c 100644
--- a/spec/unit/provider/package/pacman_spec.rb
+++ b/spec/unit/provider/package/pacman_spec.rb
@@ -51,7 +51,7 @@ ERR
end
it "should run pacman query with the package name" do
- expect(@provider).to receive(:shell_out).with("pacman -Qi #{@new_resource.package_name}").and_return(@status)
+ expect(@provider).to receive(:shell_out).with("pacman -Qi #{@new_resource.package_name}", {timeout: 900}).and_return(@status)
@provider.load_current_resource
end
@@ -152,12 +152,12 @@ PACMAN_CONF
describe Chef::Provider::Package::Pacman, "install_package" do
it "should run pacman install with the package name and version" do
- expect(@provider).to receive(:shell_out!).with("pacman --sync --noconfirm --noprogressbar nano")
+ expect(@provider).to receive(:shell_out!).with("pacman --sync --noconfirm --noprogressbar nano", {timeout: 900})
@provider.install_package("nano", "1.0")
end
it "should run pacman install with the package name and version and options if specified" do
- expect(@provider).to receive(:shell_out!).with("pacman --sync --noconfirm --noprogressbar --debug nano")
+ expect(@provider).to receive(:shell_out!).with("pacman --sync --noconfirm --noprogressbar --debug nano", {timeout: 900})
allow(@new_resource).to receive(:options).and_return("--debug")
@provider.install_package("nano", "1.0")
@@ -173,12 +173,12 @@ PACMAN_CONF
describe Chef::Provider::Package::Pacman, "remove_package" do
it "should run pacman remove with the package name" do
- expect(@provider).to receive(:shell_out!).with("pacman --remove --noconfirm --noprogressbar nano")
+ expect(@provider).to receive(:shell_out!).with("pacman --remove --noconfirm --noprogressbar nano", {timeout: 900})
@provider.remove_package("nano", "1.0")
end
it "should run pacman remove with the package name and options if specified" do
- expect(@provider).to receive(:shell_out!).with("pacman --remove --noconfirm --noprogressbar --debug nano")
+ expect(@provider).to receive(:shell_out!).with("pacman --remove --noconfirm --noprogressbar --debug nano", {timeout: 900})
allow(@new_resource).to receive(:options).and_return("--debug")
@provider.remove_package("nano", "1.0")
diff --git a/spec/unit/provider/package/rpm_spec.rb b/spec/unit/provider/package/rpm_spec.rb
index 411afd3755..e0e45d0b4f 100644
--- a/spec/unit/provider/package/rpm_spec.rb
+++ b/spec/unit/provider/package/rpm_spec.rb
@@ -23,183 +23,394 @@ describe Chef::Provider::Package::Rpm do
let(:node) { Chef::Node.new }
let(:events) { Chef::EventDispatch::Dispatcher.new }
let(:run_context) { Chef::RunContext.new(node, {}, events) }
+
+ let(:package_source) { "/tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm" }
+
+ let(:package_name) { "ImageMagick-c++" }
+
let(:new_resource) do
- Chef::Resource::Package.new("ImageMagick-c++").tap do |resource|
- resource.source "/tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm"
+ Chef::Resource::Package.new(package_name).tap do |resource|
+ resource.source(package_source)
end
end
- let(:exitstatus) { 0 }
- let(:stdout) { String.new('') }
- let(:status) { double('Process::Status', exitstatus: exitstatus, stdout: stdout) }
+
+ # `rpm -qp [stuff] $source`
+ let(:rpm_qp_status) { instance_double('Mixlib::ShellOut', exitstatus: rpm_qp_exitstatus, stdout: rpm_qp_stdout) }
+
+ # `rpm -q [stuff] $package_name`
+ let(:rpm_q_status) { instance_double('Mixlib::ShellOut', exitstatus: rpm_q_exitstatus, stdout: rpm_q_stdout) }
before(:each) do
- allow(::File).to receive(:exists?).and_return(true)
- allow(provider).to receive(:shell_out!).and_return(status)
+ allow(::File).to receive(:exists?).with("PLEASE STUB File.exists? EXACTLY").and_return(true)
+
+ # Ensure all shell out usage is stubbed with exact arguments
+ allow(provider).to receive(:shell_out!).with("PLEASE STUB YOUR SHELLOUT CALLS").and_return(nil)
+ allow(provider).to receive(:shell_out).with("PLEASE STUB YOUR SHELLOUT CALLS").and_return(nil)
end
- describe "when determining the current state of the package" do
- it "should create a current resource with the name of new_resource" do
- provider.load_current_resource
- expect(provider.current_resource.name).to eq("ImageMagick-c++")
- end
+ describe "when the package source is not valid" do
- it "should set the current reource package name to the new resource package name" do
- provider.load_current_resource
- expect(provider.current_resource.package_name).to eq('ImageMagick-c++')
- end
+ context "when source is not defiend" do
+ let(:new_resource) { Chef::Resource::Package.new("ImageMagick-c++") }
- it "should raise an exception if a source is supplied but not found" do
- allow(::File).to receive(:exists?).and_return(false)
- expect { provider.run_action(:any) }.to raise_error(Chef::Exceptions::Package)
+ it "should raise an exception when attempting any action" do
+ expect { provider.run_action(:any) }.to raise_error(Chef::Exceptions::Package)
+ end
end
- context "installation exists" do
- let(:stdout) { "ImageMagick-c++ 6.5.4.7-7.el6_5" }
+ context "when the source is a file that doesn't exist" do
- it "should get the source package version from rpm if provided" do
- expect(provider).to receive(:shell_out!).with("rpm -qp --queryformat '%{NAME} %{VERSION}-%{RELEASE}\n' /tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm").and_return(status)
- expect(provider).to receive(:shell_out).with("rpm -q --queryformat '%{NAME} %{VERSION}-%{RELEASE}\n' ImageMagick-c++").and_return(status)
- provider.load_current_resource
- expect(provider.current_resource.package_name).to eq("ImageMagick-c++")
- expect(provider.new_resource.version).to eq("6.5.4.7-7.el6_5")
+ it "should raise an exception when attempting any action" do
+ allow(::File).to receive(:exists?).with(package_source).and_return(false)
+ expect { provider.run_action(:any) }.to raise_error(Chef::Exceptions::Package)
end
+ end
- it "should return the current version installed if found by rpm" do
- expect(provider).to receive(:shell_out!).with("rpm -qp --queryformat '%{NAME} %{VERSION}-%{RELEASE}\n' /tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm").and_return(status)
- expect(provider).to receive(:shell_out).with("rpm -q --queryformat '%{NAME} %{VERSION}-%{RELEASE}\n' ImageMagick-c++").and_return(status)
- provider.load_current_resource
- expect(provider.current_resource.version).to eq("6.5.4.7-7.el6_5")
+ context "when the source is an unsupported URI scheme" do
+
+ let(:package_source) { "foobar://example.com/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm" }
+
+ it "should raise an exception if an uri formed source is non-supported scheme" do
+ allow(::File).to receive(:exists?).with(package_source).and_return(false)
+
+ # verify let bindings are as we expect
+ expect(new_resource.source).to eq("foobar://example.com/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm")
+ expect(provider.load_current_resource).to be_nil
+ expect { provider.run_action(:any) }.to raise_error(Chef::Exceptions::Package)
end
end
- context "source is uri formed" do
- before(:each) do
- allow(::File).to receive(:exists?).and_return(false)
+ end
+
+ describe "when the package source is valid" do
+
+ before do
+ expect(provider).to receive(:shell_out!).
+ with("rpm -qp --queryformat '%{NAME} %{VERSION}-%{RELEASE}\n' #{package_source}", timeout: 900).
+ and_return(rpm_qp_status)
+
+ expect(provider).to receive(:shell_out).
+ with("rpm -q --queryformat '%{NAME} %{VERSION}-%{RELEASE}\n' #{package_name}", timeout: 900).
+ and_return(rpm_q_status)
+ end
+
+ context "when rpm fails when querying package installed state" do
+
+ before do
+ allow(::File).to receive(:exists?).with(package_source).and_return(true)
end
- %w(http HTTP https HTTPS ftp FTP).each do |scheme|
- it "should accept uri formed source (#{scheme})" do
- new_resource.source "#{scheme}://example.com/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm"
- expect(provider.load_current_resource).not_to be_nil
+ let(:rpm_qp_stdout) { "ImageMagick-c++ 6.5.4.7-7.el6_5" }
+ let(:rpm_q_stdout) { "" }
+
+ let(:rpm_qp_exitstatus) { 0 }
+ let(:rpm_q_exitstatus) { -1 }
+
+ it "raises an exception when attempting any action" do
+ expected_message = "Unable to determine current version due to RPM failure."
+
+ expect { provider.run_action(:install) }.to raise_error do |error|
+ expect(error).to be_a_kind_of(Chef::Exceptions::Package)
+ expect(error.to_s).to include(expected_message)
end
end
+ end
+
+
+ context "when the package is installed" do
+
+ let(:rpm_qp_stdout) { "ImageMagick-c++ 6.5.4.7-7.el6_5" }
+ let(:rpm_q_stdout) { "ImageMagick-c++ 6.5.4.7-7.el6_5" }
+
+ let(:rpm_qp_exitstatus) { 0 }
+ let(:rpm_q_exitstatus) { 0 }
- %w(file FILE).each do |scheme|
- it "should accept uri formed source (#{scheme})" do
- new_resource.source "#{scheme}:///ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm"
- expect(provider.load_current_resource).not_to be_nil
+ let(:action) { :install }
+
+ context "when the source is a file system path" do
+
+ before do
+ allow(::File).to receive(:exists?).with(package_source).and_return(true)
+
+ provider.action = action
+
+ provider.load_current_resource
+ provider.define_resource_requirements
+ provider.process_resource_requirements
end
- end
- it "should raise an exception if an uri formed source is non-supported scheme" do
- new_resource.source "foobar://example.com/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm"
- expect(provider.load_current_resource).to be_nil
- expect { provider.run_action(:any) }.to raise_error(Chef::Exceptions::Package)
- end
- end
+ it "should get the source package version from rpm if provided" do
+ expect(provider.current_resource.package_name).to eq("ImageMagick-c++")
+ expect(provider.new_resource.version).to eq("6.5.4.7-7.el6_5")
+ end
- context "source is not defiend" do
- let(:new_resource) { Chef::Resource::Package.new("ImageMagick-c++") }
+ it "should return the current version installed if found by rpm" do
+ expect(provider.current_resource.version).to eq("6.5.4.7-7.el6_5")
+ end
+
+ describe "action install" do
+
+ context "when at the desired version already" do
+ it "does nothing when the correct version is installed" do
+ expect(provider).to_not receive(:shell_out!).with("rpm -i /tmp/imagemagick-c++-6.5.4.7-7.el6_5.x86_64.rpm", timeout: 900)
+
+ provider.action_install
+ end
+ end
+
+ context "when a newer version is desired" do
+
+ let(:rpm_q_stdout) { "imagemagick-c++ 0.5.4.7-7.el6_5" }
+
+ it "runs rpm -u with the package source to upgrade" do
+ expect(provider).to receive(:shell_out!).with("rpm -U /tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm", timeout: 900)
+ provider.action_install
+ end
+ end
+
+ context "when an older version is desired" do
+ let(:new_resource) do
+ Chef::Resource::RpmPackage.new(package_name).tap do |r|
+ r.source(package_source)
+ r.allow_downgrade(true)
+ end
+ end
+
+ let(:rpm_q_stdout) { "imagemagick-c++ 21.4-19.el6_5" }
+
+ it "should run rpm -u --oldpackage with the package source to downgrade" do
+ expect(provider).to receive(:shell_out!).with("rpm -U --oldpackage /tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm", timeout: 900)
+ provider.action_install
+ end
+
+ end
+
+ end
+
+ describe "action upgrade" do
+
+ let(:action) { :upgrade }
+
+ context "when at the desired version already" do
+ it "does nothing when the correct version is installed" do
+ expect(provider).to_not receive(:shell_out!).with("rpm -i /tmp/imagemagick-c++-6.5.4.7-7.el6_5.x86_64.rpm", timeout: 900)
+
+ provider.action_upgrade
+ end
+ end
+
+ context "when a newer version is desired" do
+
+ let(:rpm_q_stdout) { "imagemagick-c++ 0.5.4.7-7.el6_5" }
+
+ it "runs rpm -u with the package source to upgrade" do
+ expect(provider).to receive(:shell_out!).with("rpm -U /tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm", timeout: 900)
+ provider.action_upgrade
+ end
+ end
+
+ context "when an older version is desired" do
+ let(:new_resource) do
+ Chef::Resource::RpmPackage.new(package_name).tap do |r|
+ r.source(package_source)
+ r.allow_downgrade(true)
+ end
+ end
+
+ let(:rpm_q_stdout) { "imagemagick-c++ 21.4-19.el6_5" }
+
+ it "should run rpm -u --oldpackage with the package source to downgrade" do
+ expect(provider).to receive(:shell_out!).with("rpm -U --oldpackage /tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm", timeout: 900)
+ provider.action_upgrade
+ end
+
+ end
+ end
+
+ describe "action :remove" do
+
+ let(:action) { :remove }
+
+ it "should remove the package" do
+ expect(provider).to receive(:shell_out!).with("rpm -e ImageMagick-c++-6.5.4.7-7.el6_5", timeout: 900)
+ provider.action_remove
+ end
+ end
+
+
+ context "when the package name contains a tilde (chef#3503)" do
+
+ let(:package_name) { "supermarket" }
+
+ let(:package_source) { "/tmp/supermarket-1.10.1~alpha.0-1.el5.x86_64.rpm" }
+
+ let(:rpm_qp_stdout) { "supermarket 1.10.1~alpha.0-1.el5" }
+ let(:rpm_q_stdout) { "supermarket 1.10.1~alpha.0-1.el5" }
+
+ let(:rpm_qp_exitstatus) { 0 }
+ let(:rpm_q_exitstatus) { 0 }
+
+ it "should correctly determine the candidate version and installed version" do
+ expect(provider.current_resource.package_name).to eq("supermarket")
+ expect(provider.new_resource.version).to eq("1.10.1~alpha.0-1.el5")
+ end
+ end
- it "should raise an exception if the source is not set but we are installing" do
- expect { provider.run_action(:any) }.to raise_error(Chef::Exceptions::Package)
end
- end
- context "installation does not exist" do
- let(:stdout) { String.new("package openssh-askpass is not installed") }
- let(:exitstatus) { -1 }
- let(:new_resource) do
- Chef::Resource::Package.new("openssh-askpass").tap do |resource|
- resource.source "openssh-askpass"
+ context "when the source is given as an URI" do
+ before(:each) do
+ allow(::File).to receive(:exists?).with(package_source).and_return(false)
+
+ provider.action = action
+
+ provider.load_current_resource
+ provider.define_resource_requirements
+ provider.process_resource_requirements
+ end
+
+ %w(http HTTP https HTTPS ftp FTP file FILE).each do |scheme|
+
+ context "when the source URI uses protocol scheme '#{scheme}'" do
+
+ let(:package_source) { "#{scheme}://example.com/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm" }
+
+ it "should get the source package version from rpm if provided" do
+ expect(provider.current_resource.package_name).to eq("ImageMagick-c++")
+ expect(provider.new_resource.version).to eq("6.5.4.7-7.el6_5")
+ end
+
+ it "should return the current version installed if found by rpm" do
+ expect(provider.current_resource.version).to eq("6.5.4.7-7.el6_5")
+ end
+
+ end
end
+
end
- it "should raise an exception if rpm fails to run" do
- allow(provider).to receive(:shell_out).and_return(status)
- expect { provider.run_action(:any) }.to raise_error(Chef::Exceptions::Package)
+ end
+
+ context "when the package is not installed" do
+
+ let(:package_name) { "openssh-askpass" }
+
+ let(:package_source) { "/tmp/openssh-askpass-1.2.3-4.el6_5.x86_64.rpm" }
+
+ let(:rpm_qp_stdout) { "openssh-askpass 1.2.3-4.el6_5" }
+ let(:rpm_q_stdout) { "package openssh-askpass is not installed" }
+
+ let(:rpm_qp_exitstatus) { 0 }
+ let(:rpm_q_exitstatus) { 0 }
+
+ let(:action) { :install }
+
+ before do
+ allow(File).to receive(:exists?).with(package_source).and_return(true)
+
+ provider.action = action
+
+ provider.load_current_resource
+ provider.define_resource_requirements
+ provider.process_resource_requirements
end
it "should not detect the package name as version when not installed" do
- expect(provider).to receive(:shell_out!).with("rpm -qp --queryformat '%{NAME} %{VERSION}-%{RELEASE}\n' openssh-askpass").and_return(status)
- expect(provider).to receive(:shell_out).with("rpm -q --queryformat '%{NAME} %{VERSION}-%{RELEASE}\n' openssh-askpass").and_return(status)
- provider.load_current_resource
expect(provider.current_resource.version).to be_nil
end
- end
- end
- describe "after the current resource is loaded" do
- let(:current_resource) { Chef::Resource::Package.new("ImageMagick-c++") }
- let(:provider) do
- Chef::Provider::Package::Rpm.new(new_resource, run_context).tap do |provider|
- provider.current_resource = current_resource
- end
- end
+ context "when the package name contains a tilde (chef#3503)" do
- describe "when installing or upgrading" do
- it "should run rpm -i with the package source to install" do
- expect(provider).to receive(:shell_out!).with("rpm -i /tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm")
- provider.install_package("ImageMagick-c++", "6.5.4.7-7.el6_5")
- end
+ let(:package_name) { "supermarket" }
- it "should run rpm -U with the package source to upgrade" do
- current_resource.version("21.4-19.el5")
- expect(provider).to receive(:shell_out!).with("rpm -U /tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm")
- provider.upgrade_package("ImageMagick-c++", "6.5.4.7-7.el6_5")
- end
+ let(:package_source) { "/tmp/supermarket-1.10.1~alpha.0-1.el5.x86_64.rpm" }
- it "should install package if missing and set to upgrade" do
- current_resource.version("ImageMagick-c++")
- expect(provider).to receive(:shell_out!).with("rpm -U /tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm")
- provider.upgrade_package("ImageMagick-c++", "6.5.4.7-7.el6_5")
- end
+ let(:rpm_qp_stdout) { "supermarket 1.10.1~alpha.0-1.el5" }
+ let(:rpm_q_stdout) { "package supermarket is not installed" }
- context "allowing downgrade" do
- let(:new_resource) { Chef::Resource::RpmPackage.new("/tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm") }
- let(:current_resource) { Chef::Resource::RpmPackage.new("ImageMagick-c++") }
+ let(:rpm_qp_exitstatus) { 0 }
+ let(:rpm_q_exitstatus) { 0 }
- it "should run rpm -U --oldpackage with the package source to downgrade" do
- new_resource.allow_downgrade(true)
- current_resource.version("21.4-19.el5")
- expect(provider).to receive(:shell_out!).with("rpm -U --oldpackage /tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm")
- provider.upgrade_package("ImageMagick-c++", "6.5.4.7-7.el6_5")
+ it "should correctly determine the candidate version" do
+ expect(provider.new_resource.version).to eq("1.10.1~alpha.0-1.el5")
end
end
- context "installing when the name is a path" do
- let(:new_resource) { Chef::Resource::Package.new("/tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm") }
- let(:current_resource) { Chef::Resource::Package.new("ImageMagick-c++") }
+ describe "managing the package" do
+
+ describe "action install" do
+
+ it "installs the package" do
+ expect(provider).to receive(:shell_out!).with("rpm -i #{package_source}", timeout: 900)
- it "should install from a path when the package is a path and the source is nil" do
- expect(new_resource.source).to eq("/tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm")
- provider.current_resource = current_resource
- expect(provider).to receive(:shell_out!).with("rpm -i /tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm")
- provider.install_package("/tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm", "6.5.4.7-7.el6_5")
+ provider.action_install
+ end
+
+ context "when custom resource options are given" do
+ it "installs with custom options specified in the resource" do
+ new_resource.options("--dbpath /var/lib/rpm")
+ expect(provider).to receive(:shell_out!).with("rpm --dbpath /var/lib/rpm -i #{package_source}", timeout: 900)
+ provider.action_install
+ end
+ end
end
- it "should uprgrade from a path when the package is a path and the source is nil" do
- expect(new_resource.source).to eq("/tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm")
- current_resource.version("21.4-19.el5")
- provider.current_resource = current_resource
- expect(provider).to receive(:shell_out!).with("rpm -U /tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm")
- provider.upgrade_package("/tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm", "6.5.4.7-7.el6_5")
+ describe "action upgrade" do
+
+ let(:action) { :upgrade }
+
+ it "installs the package" do
+ expect(provider).to receive(:shell_out!).with("rpm -i #{package_source}", timeout: 900)
+
+ provider.action_upgrade
+ end
+ end
+
+ describe "when removing the package" do
+
+ let(:action) { :remove }
+
+ it "should do nothing" do
+ expect(provider).to_not receive(:shell_out!).with("rpm -e ImageMagick-c++-6.5.4.7-7.el6_5", timeout: 900)
+ provider.action_remove
+ end
end
- end
- it "installs with custom options specified in the resource" do
- provider.candidate_version = '11'
- new_resource.options("--dbpath /var/lib/rpm")
- expect(provider).to receive(:shell_out!).with("rpm --dbpath /var/lib/rpm -i /tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm")
- provider.install_package(new_resource.name, provider.candidate_version)
end
+
+
end
+ end
- describe "when removing the package" do
- it "should run rpm -e to remove the package" do
- expect(provider).to receive(:shell_out!).with("rpm -e ImageMagick-c++-6.5.4.7-7.el6_5")
- provider.remove_package("ImageMagick-c++", "6.5.4.7-7.el6_5")
- end
+ context "when the resource name is the path to the package" do
+
+ let(:new_resource) do
+ # When we pass a source in as the name, then #initialize in the
+ # provider will call File.exists?. Because of the ordering in our
+ # let() bindings and such, we have to set the stub here and not in a
+ # before block.
+ allow(::File).to receive(:exists?).with(package_source).and_return(true)
+ Chef::Resource::Package.new("/tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm")
+ end
+
+ let(:current_resource) { Chef::Resource::Package.new("ImageMagick-c++") }
+
+ it "should install from a path when the package is a path and the source is nil" do
+ expect(new_resource.source).to eq("/tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm")
+ provider.current_resource = current_resource
+ expect(provider).to receive(:shell_out!).with("rpm -i /tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm", timeout: 900)
+ provider.install_package("/tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm", "6.5.4.7-7.el6_5")
+ end
+
+ it "should uprgrade from a path when the package is a path and the source is nil" do
+ expect(new_resource.source).to eq("/tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm")
+ current_resource.version("21.4-19.el5")
+ provider.current_resource = current_resource
+ expect(provider).to receive(:shell_out!).with("rpm -U /tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm", timeout: 900)
+ provider.upgrade_package("/tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm", "6.5.4.7-7.el6_5")
end
end
+
+
end
+
diff --git a/spec/unit/provider/package/rubygems_spec.rb b/spec/unit/provider/package/rubygems_spec.rb
index 380572499c..67ffb7bb9e 100644
--- a/spec/unit/provider/package/rubygems_spec.rb
+++ b/spec/unit/provider/package/rubygems_spec.rb
@@ -107,38 +107,6 @@ describe Chef::Provider::Package::Rubygems::CurrentGemEnvironment do
expect(@gem_env.candidate_version_from_remote(Gem::Dependency.new('rspec', '>= 0'))).to eq(Gem::Version.new('1.3.0'))
end
- context "when rubygems was upgraded from 1.8->2.0" do
- # https://github.com/rubygems/rubygems/issues/404
- # tl;dr rubygems 1.8 and 2.0 can both be in the load path, which means that
- # require "rubygems/format" will load even though rubygems 2.0 doesn't have
- # that file.
-
- before do
- if defined?(Gem::Format)
- # tests are running under rubygems 1.8, or 2.0 upgraded from 1.8
- @remove_gem_format = false
- else
- Gem.const_set(:Format, Object.new)
- @remove_gem_format = true
- end
- allow(Gem::Package).to receive(:respond_to?).and_call_original
- allow(Gem::Package).to receive(:respond_to?).with(:open).and_return(false)
- end
-
- after do
- if @remove_gem_format
- Gem.send(:remove_const, :Format)
- end
- end
-
- it "finds a matching gem candidate version on rubygems 2.0+ with some rubygems 1.8 code loaded" do
- package = double("Gem::Package", :spec => "a gemspec from package")
- expect(Gem::Package).to receive(:new).with("/path/to/package.gem").and_return(package)
- expect(@gem_env.spec_from_file("/path/to/package.gem")).to eq("a gemspec from package")
- end
-
- end
-
it "gives the candidate version as nil if none is found" do
dep = Gem::Dependency.new('rspec', '>= 0')
latest = []
@@ -222,8 +190,6 @@ describe Chef::Provider::Package::Rubygems::AlternateGemEnvironment do
end
it "uses the cached result for gem paths when available" do
- gem_env_output = ['/path/to/gems', '/another/path/to/gems'].join(File::PATH_SEPARATOR)
- shell_out_result = OpenStruct.new(:stdout => gem_env_output)
expect(@gem_env).not_to receive(:shell_out!)
expected = ['/path/to/gems', '/another/path/to/gems']
Chef::Provider::Package::Rubygems::AlternateGemEnvironment.gempath_cache['/usr/weird/bin/gem']= expected
@@ -261,7 +227,7 @@ describe Chef::Provider::Package::Rubygems::AlternateGemEnvironment do
else
`which gem`.strip
end
- pending("cant find your gem executable") if path_to_gem.empty?
+ skip("cant find your gem executable") if path_to_gem.empty?
gem_env = Chef::Provider::Package::Rubygems::AlternateGemEnvironment.new(path_to_gem)
expected = ['rspec-core', Gem::Version.new(RSpec::Core::Version::STRING)]
actual = gem_env.installed_versions(Gem::Dependency.new('rspec-core', nil)).map { |s| [s.name, s.version] }
@@ -542,7 +508,7 @@ describe Chef::Provider::Package::Rubygems do
it "installs the gem by shelling out when options are provided as a String" do
@new_resource.options('-i /alt/install/location')
expected ="gem install rspec-core -q --no-rdoc --no-ri -v \"#{@spec_version}\" -i /alt/install/location"
- expect(@provider).to receive(:shell_out!).with(expected, :env => nil)
+ expect(@provider).to receive(:shell_out!).with(expected, env: nil, timeout: 900)
@provider.run_action(:install)
expect(@new_resource).to be_updated_by_last_action
end
@@ -551,7 +517,7 @@ describe Chef::Provider::Package::Rubygems do
@new_resource.gem_binary('/foo/bar')
@new_resource.source('http://mirror.ops.rhcloud.com/mirror/ruby')
expected ="/foo/bar install rspec-core -q --no-rdoc --no-ri -v \"#{@spec_version}\" --source=#{@new_resource.source} --source=https://rubygems.org"
- expect(@provider).to receive(:shell_out!).with(expected, :env => nil)
+ expect(@provider).to receive(:shell_out!).with(expected, env: nil, timeout: 900)
@provider.run_action(:install)
expect(@new_resource).to be_updated_by_last_action
end
@@ -561,7 +527,7 @@ describe Chef::Provider::Package::Rubygems do
@new_resource.source('http://mirror.ops.rhcloud.com/mirror/ruby')
@new_resource.clear_sources(true)
expected ="/foo/bar install rspec-core -q --no-rdoc --no-ri -v \"#{@spec_version}\" --clear-sources --source=#{@new_resource.source}"
- expect(@provider).to receive(:shell_out!).with(expected, :env => nil)
+ expect(@provider).to receive(:shell_out!).with(expected, env: nil, timeout: 900)
@provider.run_action(:install)
expect(@new_resource).to be_updated_by_last_action
end
@@ -572,7 +538,7 @@ describe Chef::Provider::Package::Rubygems do
it "installs the gem by shelling out when options are provided but no version is given" do
@new_resource.options('-i /alt/install/location')
expected ="gem install rspec-core -q --no-rdoc --no-ri -v \"#{@provider.candidate_version}\" -i /alt/install/location"
- expect(@provider).to receive(:shell_out!).with(expected, :env => nil)
+ expect(@provider).to receive(:shell_out!).with(expected, env: nil, timeout: 900)
@provider.run_action(:install)
expect(@new_resource).to be_updated_by_last_action
end
@@ -618,7 +584,7 @@ describe Chef::Provider::Package::Rubygems do
describe "in an alternate gem environment" do
it "installs the gem by shelling out to gem install" do
@new_resource.gem_binary('/usr/weird/bin/gem')
- expect(@provider).to receive(:shell_out!).with("/usr/weird/bin/gem install rspec-core -q --no-rdoc --no-ri -v \"#{@spec_version}\"", :env=>nil)
+ expect(@provider).to receive(:shell_out!).with("/usr/weird/bin/gem install rspec-core -q --no-rdoc --no-ri -v \"#{@spec_version}\"", env: nil, timeout: 900)
@provider.run_action(:install)
expect(@new_resource).to be_updated_by_last_action
end
@@ -627,7 +593,7 @@ describe Chef::Provider::Package::Rubygems do
@new_resource.gem_binary('/usr/weird/bin/gem')
@new_resource.source(CHEF_SPEC_DATA + '/gems/chef-integration-test-0.1.0.gem')
@new_resource.version('>= 0')
- expect(@provider).to receive(:shell_out!).with("/usr/weird/bin/gem install #{CHEF_SPEC_DATA}/gems/chef-integration-test-0.1.0.gem -q --no-rdoc --no-ri -v \">= 0\"", :env=>nil)
+ expect(@provider).to receive(:shell_out!).with("/usr/weird/bin/gem install #{CHEF_SPEC_DATA}/gems/chef-integration-test-0.1.0.gem -q --no-rdoc --no-ri -v \">= 0\"", env: nil, timeout: 900)
@provider.run_action(:install)
expect(@new_resource).to be_updated_by_last_action
end
@@ -639,7 +605,7 @@ describe Chef::Provider::Package::Rubygems do
@new_resource.gem_binary('/usr/weird/bin/gem')
@new_resource.version('>= 0')
expect(@new_resource.source).to eq(CHEF_SPEC_DATA + '/gems/chef-integration-test-0.1.0.gem')
- expect(@provider).to receive(:shell_out!).with("/usr/weird/bin/gem install #{CHEF_SPEC_DATA}/gems/chef-integration-test-0.1.0.gem -q --no-rdoc --no-ri -v \">= 0\"", :env=>nil)
+ expect(@provider).to receive(:shell_out!).with("/usr/weird/bin/gem install #{CHEF_SPEC_DATA}/gems/chef-integration-test-0.1.0.gem -q --no-rdoc --no-ri -v \">= 0\"", env: nil, timeout: 900)
@provider.run_action(:install)
expect(@new_resource).to be_updated_by_last_action
end
@@ -678,7 +644,7 @@ describe Chef::Provider::Package::Rubygems do
it "uninstalls via the gem command when options are given as a String" do
@new_resource.options('-i /alt/install/location')
- expect(@provider).to receive(:shell_out!).with("gem uninstall rspec -q -x -I -a -i /alt/install/location", :env=>nil)
+ expect(@provider).to receive(:shell_out!).with("gem uninstall rspec -q -x -I -a -i /alt/install/location", env: nil, timeout: 900)
@provider.action_remove
end
@@ -692,7 +658,7 @@ describe Chef::Provider::Package::Rubygems do
describe "in an alternate gem environment" do
it "uninstalls via the gem command" do
@new_resource.gem_binary('/usr/weird/bin/gem')
- expect(@provider).to receive(:shell_out!).with("/usr/weird/bin/gem uninstall rspec -q -x -I -a", :env=>nil)
+ expect(@provider).to receive(:shell_out!).with("/usr/weird/bin/gem uninstall rspec -q -x -I -a", env: nil, timeout: 900)
@provider.action_remove
end
end
diff --git a/spec/unit/provider/package/smartos_spec.rb b/spec/unit/provider/package/smartos_spec.rb
index db39589b85..8f2d2bb8ea 100644
--- a/spec/unit/provider/package/smartos_spec.rb
+++ b/spec/unit/provider/package/smartos_spec.rb
@@ -29,45 +29,45 @@ describe Chef::Provider::Package::SmartOS, "load_current_resource" do
@current_resource = Chef::Resource::Package.new("varnish")
- @status = double("Status", :exitstatus => 0)
- @provider = Chef::Provider::Package::SmartOS.new(@new_resource, @run_context)
- allow(Chef::Resource::Package).to receive(:new).and_return(@current_resource)
- @stdin = StringIO.new
- @stdout = "varnish-2.1.5nb2\n"
- @stderr = StringIO.new
- @pid = 10
- @shell_out = OpenStruct.new(:stdout => @stdout, :stdin => @stdin, :stderr => @stderr, :status => @status, :exitstatus => 0)
+ @status = double("Status", :exitstatus => 0)
+ @provider = Chef::Provider::Package::SmartOS.new(@new_resource, @run_context)
+ allow(Chef::Resource::Package).to receive(:new).and_return(@current_resource)
+ @stdin = StringIO.new
+ @stdout = "varnish-2.1.5nb2\n"
+ @stderr = StringIO.new
+ @pid = 10
+ @shell_out = OpenStruct.new(:stdout => @stdout, :stdin => @stdin, :stderr => @stderr, :status => @status, :exitstatus => 0)
end
- describe "when loading current resource" do
+ describe "when loading current resource" do
it "should create a current resource with the name of the new_resource" do
- expect(@provider).to receive(:shell_out!).and_return(@shell_out)
- expect(Chef::Resource::Package).to receive(:new).and_return(@current_resource)
- @provider.load_current_resource
+ expect(@provider).to receive(:shell_out!).and_return(@shell_out)
+ expect(Chef::Resource::Package).to receive(:new).and_return(@current_resource)
+ @provider.load_current_resource
end
- it "should set the current resource package name" do
- expect(@provider).to receive(:shell_out!).and_return(@shell_out)
- expect(@current_resource).to receive(:package_name).with(@new_resource.package_name)
- @provider.load_current_resource
- end
+ it "should set the current resource package name" do
+ expect(@provider).to receive(:shell_out!).and_return(@shell_out)
+ expect(@current_resource).to receive(:package_name).with(@new_resource.package_name)
+ @provider.load_current_resource
+ end
- it "should set the installed version if it is installed" do
- expect(@provider).to receive(:shell_out!).and_return(@shell_out)
- @provider.load_current_resource
- expect(@current_resource.version).to eq("2.1.5nb2")
- end
+ it "should set the installed version if it is installed" do
+ expect(@provider).to receive(:shell_out!).and_return(@shell_out)
+ @provider.load_current_resource
+ expect(@current_resource.version).to eq("2.1.5nb2")
+ end
- it "should set the installed version to nil if it's not installed" do
- out = OpenStruct.new(:stdout => nil)
- expect(@provider).to receive(:shell_out!).and_return(out)
- @provider.load_current_resource
- expect(@current_resource.version).to eq(nil)
- end
+ it "should set the installed version to nil if it's not installed" do
+ out = OpenStruct.new(:stdout => nil)
+ expect(@provider).to receive(:shell_out!).and_return(out)
+ @provider.load_current_resource
+ expect(@current_resource.version).to eq(nil)
+ end
- end
+ end
describe "candidate_version" do
it "should return the candidate_version variable if already setup" do
@@ -76,27 +76,37 @@ describe Chef::Provider::Package::SmartOS, "load_current_resource" do
@provider.candidate_version
end
- it "should lookup the candidate_version if the variable is not already set" do
+ it "should lookup the candidate_version if the variable is not already set (pkgin separated by spaces)" do
search = double()
expect(search).to receive(:each_line).
- and_yield("something-varnish-1.1.1 something varnish like\n").
- and_yield("varnish-2.3.4 actual varnish\n")
+ and_yield("something-varnish-1.1.1 something varnish like\n").
+ and_yield("varnish-2.3.4 actual varnish\n")
@shell_out = double('shell_out!', :stdout => search)
- expect(@provider).to receive(:shell_out!).with('/opt/local/bin/pkgin se varnish', :env => nil, :returns => [0,1]).and_return(@shell_out)
+ expect(@provider).to receive(:shell_out!).with('/opt/local/bin/pkgin', 'se', 'varnish', :env => nil, :returns => [0,1], :timeout=>900).and_return(@shell_out)
+ expect(@provider.candidate_version).to eq("2.3.4")
+ end
+
+ it "should lookup the candidate_version if the variable is not already set (pkgin separated by semicolons)" do
+ search = double()
+ expect(search).to receive(:each_line).
+ and_yield("something-varnish-1.1.1;;something varnish like\n").
+ and_yield("varnish-2.3.4;;actual varnish\n")
+ @shell_out = double('shell_out!', :stdout => search)
+ expect(@provider).to receive(:shell_out!).with('/opt/local/bin/pkgin', 'se', 'varnish', :env => nil, :returns => [0,1], :timeout=>900).and_return(@shell_out)
expect(@provider.candidate_version).to eq("2.3.4")
end
end
- describe "when manipulating a resource" do
+ describe "when manipulating a resource" do
- it "run pkgin and install the package" do
- out = OpenStruct.new(:stdout => nil)
- expect(@provider).to receive(:shell_out!).with("/opt/local/sbin/pkg_info -E \"varnish*\"", {:env => nil, :returns=>[0,1]}).and_return(@shell_out)
- expect(@provider).to receive(:shell_out!).with("/opt/local/bin/pkgin -y install varnish-2.1.5nb2", {:env=>nil}).and_return(out)
+ it "run pkgin and install the package" do
+ out = OpenStruct.new(:stdout => nil)
+ expect(@provider).to receive(:shell_out!).with("/opt/local/sbin/pkg_info", "-E", "varnish*", {:env => nil, :returns=>[0,1], :timeout=>900}).and_return(@shell_out)
+ expect(@provider).to receive(:shell_out!).with("/opt/local/bin/pkgin", "-y", "install", "varnish-2.1.5nb2", {:env=>nil, :timeout=>900}).and_return(out)
@provider.load_current_resource
@provider.install_package("varnish", "2.1.5nb2")
- end
+ end
- end
+ end
end
diff --git a/spec/unit/provider/package/solaris_spec.rb b/spec/unit/provider/package/solaris_spec.rb
index c348d665e8..ae6c96da00 100644
--- a/spec/unit/provider/package/solaris_spec.rb
+++ b/spec/unit/provider/package/solaris_spec.rb
@@ -71,8 +71,8 @@ PKGINFO
it "should get the source package version from pkginfo if provided" do
status = double(:stdout => @pkginfo, :exitstatus => 0)
- expect(@provider).to receive(:shell_out).with("pkginfo -l -d /tmp/bash.pkg SUNWbash").and_return(status)
- expect(@provider).to receive(:shell_out).with("pkginfo -l SUNWbash").and_return(@status)
+ expect(@provider).to receive(:shell_out).with("pkginfo -l -d /tmp/bash.pkg SUNWbash", { timeout: 900 }).and_return(status)
+ expect(@provider).to receive(:shell_out).with("pkginfo -l SUNWbash", { timeout: 900 }).and_return(@status)
@provider.load_current_resource
expect(@provider.current_resource.package_name).to eq("SUNWbash")
@@ -81,8 +81,8 @@ PKGINFO
it "should return the current version installed if found by pkginfo" do
status = double(:stdout => @pkginfo, :exitstatus => 0)
- expect(@provider).to receive(:shell_out).with("pkginfo -l -d /tmp/bash.pkg SUNWbash").and_return(@status)
- expect(@provider).to receive(:shell_out).with("pkginfo -l SUNWbash").and_return(status)
+ expect(@provider).to receive(:shell_out).with("pkginfo -l -d /tmp/bash.pkg SUNWbash", { timeout: 900 }).and_return(@status)
+ expect(@provider).to receive(:shell_out).with("pkginfo -l SUNWbash", { timeout: 900 }).and_return(status)
@provider.load_current_resource
expect(@provider.current_resource.version).to eq("11.10.0,REV=2005.01.08.05.16")
end
@@ -101,8 +101,8 @@ PKGINFO
end
it "should return a current resource with a nil version if the package is not found" do
- expect(@provider).to receive(:shell_out).with("pkginfo -l -d /tmp/bash.pkg SUNWbash").and_return(@status)
- expect(@provider).to receive(:shell_out).with("pkginfo -l SUNWbash").and_return(@status)
+ expect(@provider).to receive(:shell_out).with("pkginfo -l -d /tmp/bash.pkg SUNWbash", { timeout: 900 }).and_return(@status)
+ expect(@provider).to receive(:shell_out).with("pkginfo -l SUNWbash", { timeout: 900 }).and_return(@status)
@provider.load_current_resource
expect(@provider.current_resource.version).to be_nil
end
@@ -132,7 +132,7 @@ PKGINFO
describe "install and upgrade" do
it "should run pkgadd -n -d with the package source to install" do
- expect(@provider).to receive(:shell_out!).with("pkgadd -n -d /tmp/bash.pkg all")
+ expect(@provider).to receive(:shell_out!).with("pkgadd -n -d /tmp/bash.pkg all", { timeout: 900 })
@provider.install_package("SUNWbash", "11.10.0,REV=2005.01.08.05.16")
end
@@ -140,26 +140,26 @@ PKGINFO
@new_resource = Chef::Resource::Package.new("/tmp/bash.pkg")
@provider = Chef::Provider::Package::Solaris.new(@new_resource, @run_context)
expect(@new_resource.source).to eq("/tmp/bash.pkg")
- expect(@provider).to receive(:shell_out!).with("pkgadd -n -d /tmp/bash.pkg all")
+ expect(@provider).to receive(:shell_out!).with("pkgadd -n -d /tmp/bash.pkg all", { timeout: 900 })
@provider.install_package("/tmp/bash.pkg", "11.10.0,REV=2005.01.08.05.16")
end
it "should run pkgadd -n -a /tmp/myadmin -d with the package options -a /tmp/myadmin" do
allow(@new_resource).to receive(:options).and_return("-a /tmp/myadmin")
- expect(@provider).to receive(:shell_out!).with("pkgadd -n -a /tmp/myadmin -d /tmp/bash.pkg all")
+ expect(@provider).to receive(:shell_out!).with("pkgadd -n -a /tmp/myadmin -d /tmp/bash.pkg all", { timeout: 900 })
@provider.install_package("SUNWbash", "11.10.0,REV=2005.01.08.05.16")
end
end
describe "remove" do
it "should run pkgrm -n to remove the package" do
- expect(@provider).to receive(:shell_out!).with("pkgrm -n SUNWbash")
+ expect(@provider).to receive(:shell_out!).with("pkgrm -n SUNWbash", { timeout: 900 })
@provider.remove_package("SUNWbash", "11.10.0,REV=2005.01.08.05.16")
end
it "should run pkgrm -n -a /tmp/myadmin with options -a /tmp/myadmin" do
allow(@new_resource).to receive(:options).and_return("-a /tmp/myadmin")
- expect(@provider).to receive(:shell_out!).with("pkgrm -n -a /tmp/myadmin SUNWbash")
+ expect(@provider).to receive(:shell_out!).with("pkgrm -n -a /tmp/myadmin SUNWbash", { timeout: 900 })
@provider.remove_package("SUNWbash", "11.10.0,REV=2005.01.08.05.16")
end
diff --git a/spec/unit/provider/package/windows_spec.rb b/spec/unit/provider/package/windows_spec.rb
index d402113d72..e5acc87694 100644
--- a/spec/unit/provider/package/windows_spec.rb
+++ b/spec/unit/provider/package/windows_spec.rb
@@ -19,50 +19,129 @@
require 'spec_helper'
describe Chef::Provider::Package::Windows, :windows_only do
+ before(:each) do
+ allow(Chef::Util::PathHelper).to receive(:windows?).and_return(true)
+ allow(Chef::FileCache).to receive(:create_cache_path).with("package/").and_return(cache_path)
+ end
+
let(:node) { double('Chef::Node') }
let(:events) { double('Chef::Events').as_null_object } # mock all the methods
let(:run_context) { double('Chef::RunContext', :node => node, :events => events) }
- let(:new_resource) { Chef::Resource::WindowsPackage.new("calculator.msi") }
+ let(:resource_source) { 'calculator.msi' }
+ let(:new_resource) { Chef::Resource::WindowsPackage.new(resource_source) }
let(:provider) { Chef::Provider::Package::Windows.new(new_resource, run_context) }
+ let(:cache_path) { 'c:\\cache\\' }
describe "load_current_resource" do
- before(:each) do
- allow(Chef::Util::PathHelper).to receive(:validate_path)
- allow(provider).to receive(:package_provider).and_return(double('package_provider',
+ shared_examples "a local file" do
+ before(:each) do
+ allow(Chef::Util::PathHelper).to receive(:validate_path)
+ allow(provider).to receive(:package_provider).and_return(double('package_provider',
:installed_version => "1.0", :package_version => "2.0"))
- end
+ end
- it "creates a current resource with the name of the new resource" do
- provider.load_current_resource
- expect(provider.current_resource).to be_a(Chef::Resource::WindowsPackage)
- expect(provider.current_resource.name).to eql("calculator.msi")
- end
+ it "creates a current resource with the name of the new resource" do
+ provider.load_current_resource
+ expect(provider.current_resource).to be_a(Chef::Resource::WindowsPackage)
+ expect(provider.current_resource.name).to eql(resource_source)
+ end
+
+ it "sets the current version if the package is installed" do
+ provider.load_current_resource
+ expect(provider.current_resource.version).to eql("1.0")
+ end
- it "sets the current version if the package is installed" do
- provider.load_current_resource
- expect(provider.current_resource.version).to eql("1.0")
+ it "sets the version to be installed" do
+ provider.load_current_resource
+ expect(provider.new_resource.version).to eql("2.0")
+ end
end
- it "sets the version to be installed" do
- provider.load_current_resource
- expect(provider.new_resource.version).to eql("2.0")
+ context "when the source is a uri" do
+ let(:resource_source) { 'https://foo.bar/calculator.msi' }
+
+ context "when the source has not been downloaded" do
+ before(:each) do
+ allow(provider).to receive(:downloadable_file_missing?).and_return(true)
+ end
+ it "sets the current version to unknown" do
+ provider.load_current_resource
+ expect(provider.current_resource.version).to eql("unknown")
+ end
+ end
+
+ context "when the source has been downloaded" do
+ before(:each) do
+ allow(provider).to receive(:downloadable_file_missing?).and_return(false)
+ end
+ it_behaves_like "a local file"
+ end
+
+ context "when remote_file_attributes are provided" do
+ let (:remote_file_attributes) { {:path => 'C:\\foobar.msi'} }
+ before(:each) do
+ new_resource.remote_file_attributes(remote_file_attributes)
+ end
+
+ it 'should override the attributes of the remote file resource used' do
+ expect(::File).to receive(:exists?).with(remote_file_attributes[:path])
+ provider.load_current_resource
+ end
+
+ end
end
- it "checks that the source path is valid" do
- expect(Chef::Util::PathHelper).to receive(:validate_path)
- provider.load_current_resource
+ context "when source is a local file" do
+ it_behaves_like "a local file"
end
end
describe "package_provider" do
- it "sets the package provider to MSI if the the installer type is :msi" do
- allow(provider).to receive(:installer_type).and_return(:msi)
- expect(provider.package_provider).to be_a(Chef::Provider::Package::Windows::MSI)
+ shared_examples "a local file" do
+ it "checks that the source path is valid" do
+ expect(Chef::Util::PathHelper).to receive(:validate_path)
+ provider.package_provider
+ end
+
+ it "sets the package provider to MSI if the the installer type is :msi" do
+ allow(provider).to receive(:installer_type).and_return(:msi)
+ expect(provider.package_provider).to be_a(Chef::Provider::Package::Windows::MSI)
+ end
+
+ it "raises an error if the installer_type is unknown" do
+ allow(provider).to receive(:installer_type).and_return(:apt_for_windows)
+ expect { provider.package_provider }.to raise_error
+ end
+ end
+
+ context "when the source is a uri" do
+ let(:resource_source) { 'https://foo.bar/calculator.msi' }
+
+ context "when the source has not been downloaded" do
+ before(:each) do
+ allow(provider).to receive(:should_download?).and_return(true)
+ end
+
+ it "should create a package provider with source pointing at the local file" do
+ expect(Chef::Provider::Package::Windows::MSI).to receive(:new) do |r|
+ expect(r.source).to eq("#{cache_path}#{::File.basename(resource_source)}")
+ end
+ provider.package_provider
+ end
+
+ it_behaves_like "a local file"
+ end
+
+ context "when the source has been downloaded" do
+ before(:each) do
+ allow(provider).to receive(:should_download?).and_return(false)
+ end
+ it_behaves_like "a local file"
+ end
end
- it "raises an error if the installer_type is unknown" do
- allow(provider).to receive(:installer_type).and_return(:apt_for_windows)
- expect { provider.package_provider }.to raise_error
+ context "when source is a local file" do
+ it_behaves_like "a local file"
end
end
diff --git a/spec/unit/provider/package/yum_spec.rb b/spec/unit/provider/package/yum_spec.rb
index 865dce23fa..e878b92621 100644
--- a/spec/unit/provider/package/yum_spec.rb
+++ b/spec/unit/provider/package/yum_spec.rb
@@ -17,6 +17,7 @@
#
require 'spec_helper'
+require 'securerandom'
describe Chef::Provider::Package::Yum do
before(:each) do
@@ -122,6 +123,26 @@ describe Chef::Provider::Package::Yum do
expect(@provider.arch).to eq("noarch")
end
+ describe "when version constraint in package_name" do
+ it "should set package_version if no existing package_name is found and new_package_name is available" do
+ @new_resource = Chef::Resource::Package.new('cups = 1.2.4-11.18.el5_2.3')
+ @provider = Chef::Provider::Package::Yum.new(@new_resource, @run_context)
+ allow(@yum_cache).to receive(:package_available?) { |pkg| pkg == 'cups' ? true : false }
+ allow(@yum_cache).to receive(:packages_from_require) do |pkg|
+ [Chef::Provider::Package::Yum::RPMDbPackage.new("cups", "1.2.4-11.18.el5_2.3", "noarch", [], false, true, "base"),
+ Chef::Provider::Package::Yum::RPMDbPackage.new("cups", "1.2.4-11.18.el5_2.2", "noarch", [], false, true, "base"),]
+ end
+ expect(Chef::Log).to receive(:debug).exactly(1).times.with(%r{checking yum info})
+ expect(Chef::Log).to receive(:debug).exactly(1).times.with(%r{installed version})
+ expect(Chef::Log).to receive(:debug).exactly(1).times.with(%r{matched 2 packages,})
+ @provider.load_current_resource
+ expect(@provider.new_resource.package_name).to eq("cups")
+ expect(@provider.new_resource.version).to eq("1.2.4-11.18.el5_2.3")
+ expect(@provider.send(:new_version_array)).to eq(["1.2.4-11.18.el5_2.3"])
+ expect(@provider.send(:package_name_array)).to eq(["cups"])
+ end
+ end
+
it "should not set the arch when an existing package_name is found" do
@new_resource = Chef::Resource::YumPackage.new('testing.beta3')
@yum_cache = double(
@@ -1659,6 +1680,14 @@ describe Chef::Provider::Package::Yum::YumCache do
end
end
+ let(:yum_exe) {
+ StringIO.new("#!/usr/bin/python\n\naldsjfa\ldsajflkdsjf\lajsdfj")
+ }
+
+ let(:bin_exe) {
+ StringIO.new(SecureRandom.random_bytes)
+ }
+
before(:each) do
@stdin = double("STDIN", :nil_object => true)
@stdout = double("STDOUT", :nil_object => true)
@@ -1704,12 +1733,19 @@ file: file://///etc/yum.repos.d/CentOS-Base.repo, line: 12
'qeqwewe\n'
EOF
@status = double("Status", :exitstatus => 0, :stdin => @stdin, :stdout => @stdout_good, :stderr => @stderr)
-
# new singleton each time
Chef::Provider::Package::Yum::YumCache.reset_instance
@yc = Chef::Provider::Package::Yum::YumCache.instance
# load valid data
allow(@yc).to receive(:shell_out!).and_return(@status)
+ allow_any_instance_of(described_class).to receive(:which).with("yum").and_return("/usr/bin/yum")
+ allow(::File).to receive(:open).with("/usr/bin/yum", "r") do |&block|
+ res = block.call(yum_exe)
+ # a bit of a hack. rewind this since it seem that no matter what
+ # I do, we get the same StringIO objects on multiple calls to
+ # ::File.open
+ yum_exe.rewind; res
+ end
end
describe "initialize" do
@@ -1726,6 +1762,24 @@ EOF
end
end
+ describe "python_bin" do
+ it "should return the default python if an error occurs" do
+ allow(::File).to receive(:open).with("/usr/bin/yum", "r").and_raise(StandardError)
+ expect(@yc.python_bin).to eq("/usr/bin/python")
+ end
+
+ it "should return the default python if the yum-executable doesn't start with #!" do
+ allow(::File).to receive(:open).with("/usr/bin/yum", "r") { |&b| r = b.call(bin_exe); bin_exe.rewind; r}
+ expect(@yc.python_bin).to eq("/usr/bin/python")
+ end
+
+ it "should return the interpreter for yum" do
+ other = StringIO.new("#!/usr/bin/super_python\n\nlasjdfdsaljf\nlasdjfs")
+ allow(::File).to receive(:open).with("/usr/bin/yum", "r") { |&b| r = b.call(other); other.rewind; r}
+ expect(@yc.python_bin).to eq("/usr/bin/super_python")
+ end
+ end
+
describe "refresh" do
it "should implicitly call yum-dump.py only once by default after being instantiated" do
expect(@yc).to receive(:shell_out!).once
@@ -2041,6 +2095,36 @@ describe "Chef::Provider::Package::Yum - Multi" do
it "should return the current resouce" do
expect(@provider.load_current_resource).to eql(@provider.current_resource)
end
+
+ describe "when version constraint in package_name" do
+ it "should set package_version if no existing package_name is found and new_package_name is available" do
+ @new_resource = Chef::Resource::Package.new(['cups = 1.2.4-11.18.el5_2.3', 'emacs = 24.4'])
+ @provider = Chef::Provider::Package::Yum.new(@new_resource, @run_context)
+ allow(@yum_cache).to receive(:package_available?) { |pkg| %w(cups emacs).include?(pkg) ? true : false }
+ allow(@yum_cache).to receive(:candidate_version) do |pkg|
+ if pkg == 'cups'
+ "1.2.4-11.18.el5_2.3"
+ elsif pkg == 'emacs'
+ "24.4"
+ end
+ end
+ allow(@yum_cache).to receive(:packages_from_require) do |pkg|
+ if pkg.name == 'cups'
+ [Chef::Provider::Package::Yum::RPMDbPackage.new("cups", "1.2.4-11.18.el5_2.3", "noarch", [], false, true, "base")]
+ elsif pkg.name == 'emacs'
+ [Chef::Provider::Package::Yum::RPMDbPackage.new("emacs", "24.4", "noarch", [], false, true, "base")]
+ end
+ end
+ expect(Chef::Log).to receive(:debug).exactly(2).times.with(%r{matched 1 package,})
+ expect(Chef::Log).to receive(:debug).exactly(1).times.with(%r{candidate version: \["1.2.4-11.18.el5_2.3", "24.4"\]})
+ expect(Chef::Log).to receive(:debug).at_least(2).times.with(%r{checking yum info})
+ @provider.load_current_resource
+ expect(@provider.new_resource.package_name).to eq(["cups", "emacs"])
+ expect(@provider.new_resource.version).to eq(["1.2.4-11.18.el5_2.3", "24.4"])
+ expect(@provider.send(:package_name_array)).to eq(["cups", "emacs"])
+ expect(@provider.send(:new_version_array)).to eq(["1.2.4-11.18.el5_2.3", "24.4"])
+ end
+ end
end
describe "when installing a package" do
@@ -2076,5 +2160,31 @@ describe "Chef::Provider::Package::Yum - Multi" do
allow(@new_resource).to receive(:options).and_return("--disablerepo epmd")
@provider.install_package(["cups", "vim"], ["1.2.4-11.19.el5", '1.0'])
end
+
+ it "should run yum install with the package name and version when name has arch" do
+ @new_resource = Chef::Resource::Package.new(['cups.x86_64', 'vim'])
+ @provider = Chef::Provider::Package::Yum.new(@new_resource, @run_context)
+ allow(Chef::Provider::Package::Yum::RPMUtils).to receive(:rpmvercmp).and_return(-1)
+
+ # Inside of load_current_resource() we'll call parse_arch for cups,
+ # and we need to craft the right response. The default mock setup above
+ # will just return valid versions all the time which won't work for this
+ # test.
+ allow(@yum_cache).to receive(:installed_version).with('cups', 'x86_64').and_return('XXXX')
+ allow(@yum_cache).to receive(:candidate_version).with('cups', 'x86_64').and_return('1.2.4-11.18.el5')
+ allow(@yum_cache).to receive(:installed_version).with('cups.x86_64').and_return(nil)
+ allow(@yum_cache).to receive(:candidate_version).with('cups.x86_64').and_return(nil)
+
+ # Normal mock's for the idempotency check
+ allow(@yum_cache).to receive(:installed_version).with('cups', nil).and_return('1.2.4-11.18.el5')
+ allow(@yum_cache).to receive(:installed_version).with('vim', nil).and_return('0.9')
+
+ @provider.load_current_resource
+ expect(@provider).to receive(:yum_command).with(
+ "yum -d0 -e0 -y install cups-1.2.4-11.19.el5.x86_64 vim-1.0"
+ )
+ @provider.install_package(["cups", "vim"], ["1.2.4-11.19.el5", '1.0'])
+ end
+
end
end
diff --git a/spec/unit/provider/package/zypper_spec.rb b/spec/unit/provider/package/zypper_spec.rb
index 706ad722dd..18ff739bc6 100644
--- a/spec/unit/provider/package/zypper_spec.rb
+++ b/spec/unit/provider/package/zypper_spec.rb
@@ -19,126 +19,150 @@
require 'spec_helper'
describe Chef::Provider::Package::Zypper do
+ let!(:new_resource) { Chef::Resource::ZypperPackage.new("cups") }
+
+ let!(:current_resource) { Chef::Resource::ZypperPackage.new("cups") }
+
+ let(:provider) do
+ node = Chef::Node.new
+ events = Chef::EventDispatch::Dispatcher.new
+ run_context = Chef::RunContext.new(node, {}, events)
+ Chef::Provider::Package::Zypper.new(new_resource, run_context)
+ end
+
+ let(:status) { double(:stdout => "\n", :exitstatus => 0) }
+
before(:each) do
- @node = Chef::Node.new
- @events = Chef::EventDispatch::Dispatcher.new
- @run_context = Chef::RunContext.new(@node, {}, @events)
- @new_resource = Chef::Resource::Package.new("cups")
-
- @current_resource = Chef::Resource::Package.new("cups")
-
- @provider = Chef::Provider::Package::Zypper.new(@new_resource, @run_context)
- allow(Chef::Resource::Package).to receive(:new).and_return(@current_resource)
- @status = double(:stdout => "\n", :exitstatus => 0)
- allow(@provider).to receive(:shell_out).and_return(@status)
- allow(@provider).to receive(:`).and_return("2.0")
+ allow(Chef::Resource::Package).to receive(:new).and_return(current_resource)
+ allow(provider).to receive(:shell_out).and_return(status)
+ allow(provider).to receive(:`).and_return("2.0")
+ end
+
+ def shell_out_expectation(command, options=nil)
+ options ||= { timeout: 900 }
+ expect(provider).to receive(:shell_out).with(command, options)
+ end
+
+ def shell_out_expectation!(command, options=nil)
+ options ||= { timeout: 900 }
+ expect(provider).to receive(:shell_out!).with(command, options)
end
describe "when loading the current package state" do
it "should create a current resource with the name of the new_resource" do
- expect(Chef::Resource::Package).to receive(:new).and_return(@current_resource)
- @provider.load_current_resource
+ expect(Chef::Resource::Package).to receive(:new).with(new_resource.name).and_return(current_resource)
+ provider.load_current_resource
end
it "should set the current resources package name to the new resources package name" do
- expect(@current_resource).to receive(:package_name).with(@new_resource.package_name)
- @provider.load_current_resource
+ expect(current_resource).to receive(:package_name).with(new_resource.package_name)
+ provider.load_current_resource
end
it "should run zypper info with the package name" do
- expect(@provider).to receive(:shell_out).with("zypper --non-interactive info #{@new_resource.package_name}").and_return(@status)
- @provider.load_current_resource
+ shell_out_expectation(
+ "zypper --non-interactive info #{new_resource.package_name}"
+ ).and_return(status)
+ provider.load_current_resource
end
it "should set the installed version to nil on the current resource if zypper info installed version is (none)" do
- allow(@provider).to receive(:shell_out).and_return(@status)
- expect(@current_resource).to receive(:version).with(nil).and_return(true)
- @provider.load_current_resource
+ allow(provider).to receive(:shell_out).and_return(status)
+ expect(current_resource).to receive(:version).with(nil).and_return(true)
+ provider.load_current_resource
end
it "should set the installed version if zypper info has one" do
status = double(:stdout => "Version: 1.0\nInstalled: Yes\n", :exitstatus => 0)
- allow(@provider).to receive(:shell_out).and_return(status)
- expect(@current_resource).to receive(:version).with("1.0").and_return(true)
- @provider.load_current_resource
+ allow(provider).to receive(:shell_out).and_return(status)
+ expect(current_resource).to receive(:version).with("1.0").and_return(true)
+ provider.load_current_resource
end
it "should set the candidate version if zypper info has one" do
status = double(:stdout => "Version: 1.0\nInstalled: No\nStatus: out-of-date (version 0.9 installed)", :exitstatus => 0)
- allow(@provider).to receive(:shell_out).and_return(status)
- @provider.load_current_resource
- expect(@provider.candidate_version).to eql("1.0")
+ allow(provider).to receive(:shell_out).and_return(status)
+ provider.load_current_resource
+ expect(provider.candidate_version).to eql("1.0")
end
it "should raise an exception if zypper info fails" do
- expect(@status).to receive(:exitstatus).and_return(1)
- expect { @provider.load_current_resource }.to raise_error(Chef::Exceptions::Package)
+ expect(status).to receive(:exitstatus).and_return(1)
+ expect { provider.load_current_resource }.to raise_error(Chef::Exceptions::Package)
end
it "should not raise an exception if zypper info succeeds" do
- expect(@status).to receive(:exitstatus).and_return(0)
- expect { @provider.load_current_resource }.not_to raise_error
+ expect(status).to receive(:exitstatus).and_return(0)
+ expect { provider.load_current_resource }.not_to raise_error
end
it "should return the current resouce" do
- expect(@provider.load_current_resource).to eql(@current_resource)
+ expect(provider.load_current_resource).to eql(current_resource)
end
end
describe "install_package" do
it "should run zypper install with the package name and version" do
allow(Chef::Config).to receive(:[]).with(:zypper_check_gpg).and_return(true)
- expect(@provider).to receive(:shell_out!).with(
- "zypper --non-interactive install --auto-agree-with-licenses emacs=1.0")
- @provider.install_package("emacs", "1.0")
+ shell_out_expectation!(
+ "zypper --non-interactive install --auto-agree-with-licenses emacs=1.0"
+ )
+ provider.install_package("emacs", "1.0")
end
it "should run zypper install without gpg checks" do
allow(Chef::Config).to receive(:[]).with(:zypper_check_gpg).and_return(false)
- expect(@provider).to receive(:shell_out!).with(
+ shell_out_expectation!(
"zypper --non-interactive --no-gpg-checks install "+
- "--auto-agree-with-licenses emacs=1.0")
- @provider.install_package("emacs", "1.0")
+ "--auto-agree-with-licenses emacs=1.0"
+ )
+ provider.install_package("emacs", "1.0")
end
it "should warn about gpg checks on zypper install" do
expect(Chef::Log).to receive(:warn).with(
- /All packages will be installed without gpg signature checks/)
- expect(@provider).to receive(:shell_out!).with(
+ /All packages will be installed without gpg signature checks/
+ )
+ shell_out_expectation!(
"zypper --non-interactive --no-gpg-checks install "+
- "--auto-agree-with-licenses emacs=1.0")
- @provider.install_package("emacs", "1.0")
+ "--auto-agree-with-licenses emacs=1.0"
+ )
+ provider.install_package("emacs", "1.0")
end
end
describe "upgrade_package" do
it "should run zypper update with the package name and version" do
allow(Chef::Config).to receive(:[]).with(:zypper_check_gpg).and_return(true)
- expect(@provider).to receive(:shell_out!).with(
- "zypper --non-interactive install --auto-agree-with-licenses emacs=1.0")
- @provider.upgrade_package("emacs", "1.0")
+ shell_out_expectation!(
+ "zypper --non-interactive install --auto-agree-with-licenses emacs=1.0"
+ )
+ provider.upgrade_package("emacs", "1.0")
end
it "should run zypper update without gpg checks" do
allow(Chef::Config).to receive(:[]).with(:zypper_check_gpg).and_return(false)
- expect(@provider).to receive(:shell_out!).with(
+ shell_out_expectation!(
"zypper --non-interactive --no-gpg-checks install "+
- "--auto-agree-with-licenses emacs=1.0")
- @provider.upgrade_package("emacs", "1.0")
+ "--auto-agree-with-licenses emacs=1.0"
+ )
+ provider.upgrade_package("emacs", "1.0")
end
it "should warn about gpg checks on zypper upgrade" do
expect(Chef::Log).to receive(:warn).with(
- /All packages will be installed without gpg signature checks/)
- expect(@provider).to receive(:shell_out!).with(
+ /All packages will be installed without gpg signature checks/
+ )
+ shell_out_expectation!(
"zypper --non-interactive --no-gpg-checks install "+
- "--auto-agree-with-licenses emacs=1.0")
- @provider.upgrade_package("emacs", "1.0")
+ "--auto-agree-with-licenses emacs=1.0"
+ )
+ provider.upgrade_package("emacs", "1.0")
end
it "should run zypper upgrade without gpg checks" do
- expect(@provider).to receive(:shell_out!).with(
+ shell_out_expectation!(
"zypper --non-interactive --no-gpg-checks install "+
- "--auto-agree-with-licenses emacs=1.0")
-
- @provider.upgrade_package("emacs", "1.0")
+ "--auto-agree-with-licenses emacs=1.0"
+ )
+ provider.upgrade_package("emacs", "1.0")
end
end
@@ -147,83 +171,94 @@ describe Chef::Provider::Package::Zypper do
context "when package version is not explicitly specified" do
it "should run zypper remove with the package name" do
allow(Chef::Config).to receive(:[]).with(:zypper_check_gpg).and_return(true)
- expect(@provider).to receive(:shell_out!).with(
- "zypper --non-interactive remove emacs")
- @provider.remove_package("emacs", nil)
+ shell_out_expectation!(
+ "zypper --non-interactive remove emacs"
+ )
+ provider.remove_package("emacs", nil)
end
end
context "when package version is explicitly specified" do
it "should run zypper remove with the package name" do
allow(Chef::Config).to receive(:[]).with(:zypper_check_gpg).and_return(true)
- expect(@provider).to receive(:shell_out!).with(
- "zypper --non-interactive remove emacs=1.0")
- @provider.remove_package("emacs", "1.0")
+ shell_out_expectation!(
+ "zypper --non-interactive remove emacs=1.0"
+ )
+ provider.remove_package("emacs", "1.0")
end
it "should run zypper remove without gpg checks" do
allow(Chef::Config).to receive(:[]).with(:zypper_check_gpg).and_return(false)
- expect(@provider).to receive(:shell_out!).with(
- "zypper --non-interactive --no-gpg-checks remove emacs=1.0")
- @provider.remove_package("emacs", "1.0")
+ shell_out_expectation!(
+ "zypper --non-interactive --no-gpg-checks remove emacs=1.0"
+ )
+ provider.remove_package("emacs", "1.0")
end
it "should warn about gpg checks on zypper remove" do
expect(Chef::Log).to receive(:warn).with(
- /All packages will be installed without gpg signature checks/)
- expect(@provider).to receive(:shell_out!).with(
- "zypper --non-interactive --no-gpg-checks remove emacs=1.0")
-
- @provider.remove_package("emacs", "1.0")
+ /All packages will be installed without gpg signature checks/
+ )
+ shell_out_expectation!(
+ "zypper --non-interactive --no-gpg-checks remove emacs=1.0"
+ )
+ provider.remove_package("emacs", "1.0")
end
end
end
describe "purge_package" do
it "should run remove_package with the name and version" do
- expect(@provider).to receive(:shell_out!).with(
- "zypper --non-interactive --no-gpg-checks remove --clean-deps emacs=1.0")
- @provider.purge_package("emacs", "1.0")
+ shell_out_expectation!(
+ "zypper --non-interactive --no-gpg-checks remove --clean-deps emacs=1.0"
+ )
+ provider.purge_package("emacs", "1.0")
end
it "should run zypper purge without gpg checks" do
allow(Chef::Config).to receive(:[]).with(:zypper_check_gpg).and_return(false)
- expect(@provider).to receive(:shell_out!).with(
- "zypper --non-interactive --no-gpg-checks remove --clean-deps emacs=1.0")
- @provider.purge_package("emacs", "1.0")
+ shell_out_expectation!(
+ "zypper --non-interactive --no-gpg-checks remove --clean-deps emacs=1.0"
+ )
+ provider.purge_package("emacs", "1.0")
end
it "should warn about gpg checks on zypper purge" do
expect(Chef::Log).to receive(:warn).with(
- /All packages will be installed without gpg signature checks/)
- expect(@provider).to receive(:shell_out!).with(
- "zypper --non-interactive --no-gpg-checks remove --clean-deps emacs=1.0")
- @provider.purge_package("emacs", "1.0")
+ /All packages will be installed without gpg signature checks/
+ )
+ shell_out_expectation!(
+ "zypper --non-interactive --no-gpg-checks remove --clean-deps emacs=1.0"
+ )
+ provider.purge_package("emacs", "1.0")
end
end
describe "on an older zypper" do
before(:each) do
- allow(@provider).to receive(:`).and_return("0.11.6")
+ allow(provider).to receive(:`).and_return("0.11.6")
end
describe "install_package" do
it "should run zypper install with the package name and version" do
- expect(@provider).to receive(:shell_out!).with(
- "zypper --no-gpg-checks install --auto-agree-with-licenses -y emacs")
- @provider.install_package("emacs", "1.0")
+ shell_out_expectation!(
+ "zypper --no-gpg-checks install --auto-agree-with-licenses -y emacs"
+ )
+ provider.install_package("emacs", "1.0")
end
end
describe "upgrade_package" do
it "should run zypper update with the package name and version" do
- expect(@provider).to receive(:shell_out!).with(
- "zypper --no-gpg-checks install --auto-agree-with-licenses -y emacs")
- @provider.upgrade_package("emacs", "1.0")
+ shell_out_expectation!(
+ "zypper --no-gpg-checks install --auto-agree-with-licenses -y emacs"
+ )
+ provider.upgrade_package("emacs", "1.0")
end
end
describe "remove_package" do
it "should run zypper remove with the package name" do
- expect(@provider).to receive(:shell_out!).with(
- "zypper --no-gpg-checks remove -y emacs")
- @provider.remove_package("emacs", "1.0")
+ shell_out_expectation!(
+ "zypper --no-gpg-checks remove -y emacs"
+ )
+ provider.remove_package("emacs", "1.0")
end
end
end
diff --git a/spec/unit/provider/package_spec.rb b/spec/unit/provider/package_spec.rb
index 1633d18f9d..432d968906 100644
--- a/spec/unit/provider/package_spec.rb
+++ b/spec/unit/provider/package_spec.rb
@@ -37,6 +37,12 @@ describe Chef::Provider::Package do
allow(@provider).to receive(:install_package).and_return(true)
end
+ it "raises a Chef::Exceptions::InvalidResourceSpecification if both multipackage and source are provided" do
+ @new_resource.package_name(['a', 'b'])
+ @new_resource.source('foo')
+ expect { @provider.run_action(:install) }.to raise_error(Chef::Exceptions::InvalidResourceSpecification)
+ end
+
it "should raise a Chef::Exceptions::Package if no version is specified, and no candidate is available" do
@provider.candidate_version = nil
expect { @provider.run_action(:install) }.to raise_error(Chef::Exceptions::Package)
@@ -698,4 +704,38 @@ describe "Chef::Provider::Package - Multi" do
expect(@new_resource).not_to be_updated_by_last_action
end
end
+
+ describe "shell_out helpers" do
+ [ :shell_out_with_timeout, :shell_out_with_timeout! ].each do |method|
+ stubbed_method = method == :shell_out_with_timeout! ? :shell_out! : :shell_out
+ [ %w{command arg1 arg2}, "command arg1 arg2" ].each do |command|
+ it "#{method} defaults to 900 seconds" do
+ expect(@provider).to receive(stubbed_method).with(*command, timeout: 900)
+ @provider.send(method, *command)
+ end
+ it "#{method} overrides the default timeout with its options" do
+ expect(@provider).to receive(stubbed_method).with(*command, timeout: 1)
+ @provider.send(method, *command, timeout: 1)
+ end
+ it "#{method} overrides both timeouts with the new_resource.timeout" do
+ @new_resource.timeout(99)
+ expect(@provider).to receive(stubbed_method).with(*command, timeout: 99)
+ @provider.send(method, *command, timeout: 1)
+ end
+ it "#{method} defaults to 900 seconds and preserves options" do
+ expect(@provider).to receive(stubbed_method).with(*command, env: nil, timeout: 900)
+ @provider.send(method, *command, env: nil)
+ end
+ it "#{method} overrides the default timeout with its options and preserves options" do
+ expect(@provider).to receive(stubbed_method).with(*command, timeout: 1, env: nil)
+ @provider.send(method, *command, timeout: 1, env: nil)
+ end
+ it "#{method} overrides both timeouts with the new_resource.timeout and preseves options" do
+ @new_resource.timeout(99)
+ expect(@provider).to receive(stubbed_method).with(*command, timeout: 99, env: nil)
+ @provider.send(method, *command, timeout: 1, env: nil)
+ end
+ end
+ end
+ end
end
diff --git a/spec/unit/provider/powershell_spec.rb b/spec/unit/provider/powershell_spec.rb
index 60dbcf80b0..855c18af9b 100644
--- a/spec/unit/provider/powershell_spec.rb
+++ b/spec/unit/provider/powershell_spec.rb
@@ -19,20 +19,62 @@
require 'spec_helper'
describe Chef::Provider::PowershellScript, "action_run" do
- before(:each) do
- @node = Chef::Node.new
+ let(:powershell_version) { nil }
+ let(:node) {
+ node = Chef::Node.new
+ node.default["kernel"] = Hash.new
+ node.default["kernel"][:machine] = :x86_64.to_s
+ if ! powershell_version.nil?
+ node.default[:languages] = { :powershell => { :version => powershell_version } }
+ end
+ node
+ }
- @node.default["kernel"] = Hash.new
- @node.default["kernel"][:machine] = :x86_64.to_s
+ let(:provider) {
+ empty_events = Chef::EventDispatch::Dispatcher.new
+ run_context = Chef::RunContext.new(node, {}, empty_events)
+ new_resource = Chef::Resource::PowershellScript.new('run some powershell code', run_context)
+ Chef::Provider::PowershellScript.new(new_resource, run_context)
+ }
- @run_context = Chef::RunContext.new(@node, {}, @events)
- @new_resource = Chef::Resource::PowershellScript.new('run some powershell code', @run_context)
+ context 'when setting interpreter flags' do
+ it "should set the -File flag as the last flag" do
+ expect(provider.flags.split(' ').pop).to eq("-File")
+ end
- @provider = Chef::Provider::PowershellScript.new(@new_resource, @run_context)
- end
+ let(:execution_policy_flag) do
+ execution_policy_index = 0
+ provider_flags = provider.flags.split(' ')
+ execution_policy_specified = false
- it "should set the -File flag as the last flag" do
- expect(@provider.flags.split(' ').pop).to eq("-File")
- end
+ provider_flags.find do | value |
+ execution_policy_index += 1
+ execution_policy_specified = value.downcase == '-ExecutionPolicy'.downcase
+ end
+
+ execution_policy = execution_policy_specified ? provider_flags[execution_policy_index] : nil
+ end
+ context 'when running with an unspecified PowerShell version' do
+ let(:powershell_version) { nil }
+ it "should set the -ExecutionPolicy flag to 'Unrestricted' by default" do
+ expect(execution_policy_flag.downcase).to eq('unrestricted'.downcase)
+ end
+ end
+
+ { '2.0' => 'Unrestricted',
+ '2.5' => 'Unrestricted',
+ '3.0' => 'Bypass',
+ '3.6' => 'Bypass',
+ '4.0' => 'Bypass',
+ '5.0' => 'Bypass' }.each do | version_policy |
+ let(:powershell_version) { version_policy[0].to_f }
+ context "when running PowerShell version #{version_policy[0]}" do
+ let(:powershell_version) { version_policy[0].to_f }
+ it "should set the -ExecutionPolicy flag to '#{version_policy[1]}'" do
+ expect(execution_policy_flag.downcase).to eq(version_policy[1].downcase)
+ end
+ end
+ end
+ end
end
diff --git a/spec/unit/provider/remote_directory_spec.rb b/spec/unit/provider/remote_directory_spec.rb
index 4434714ebc..99e2fe285c 100644
--- a/spec/unit/provider/remote_directory_spec.rb
+++ b/spec/unit/provider/remote_directory_spec.rb
@@ -194,8 +194,8 @@ describe Chef::Provider::RemoteDirectory do
expect(::File.exist?(symlinked_dir_path)).to be_falsey
expect(::File.exist?(tmp_dir)).to be_truthy
- rescue Chef::Exceptions::Win32APIError => e
- pending "This must be run as an Administrator to create symlinks"
+ rescue Chef::Exceptions::Win32APIError
+ skip "This must be run as an Administrator to create symlinks"
end
end
end
diff --git a/spec/unit/provider/remote_file/fetcher_spec.rb b/spec/unit/provider/remote_file/fetcher_spec.rb
index c049848fbf..8bd3b7c625 100644
--- a/spec/unit/provider/remote_file/fetcher_spec.rb
+++ b/spec/unit/provider/remote_file/fetcher_spec.rb
@@ -24,6 +24,26 @@ describe Chef::Provider::RemoteFile::Fetcher do
let(:new_resource) { double("new resource") }
let(:fetcher_instance) { double("fetcher") }
+ describe "when passed a network share" do
+ before do
+ expect(Chef::Provider::RemoteFile::NetworkFile).to receive(:new).and_return(fetcher_instance)
+ end
+
+ context "when host is a name" do
+ let(:source) { "\\\\foohost\\fooshare\\Foo.tar.gz" }
+ it "returns a network file fetcher" do
+ expect(described_class.for_resource(source, new_resource, current_resource)).to eq(fetcher_instance)
+ end
+ end
+
+ context "when host is an ip" do
+ let(:source) { "\\\\127.0.0.1\\fooshare\\Foo.tar.gz" }
+ it "returns a network file fetcher" do
+ expect(described_class.for_resource(source, new_resource, current_resource)).to eq(fetcher_instance)
+ end
+ end
+ end
+
describe "when passed an http url" do
let(:uri) { double("uri", :scheme => "http" ) }
before do
@@ -72,4 +92,3 @@ describe Chef::Provider::RemoteFile::Fetcher do
end
end
-
diff --git a/spec/unit/provider/remote_file/local_file_spec.rb b/spec/unit/provider/remote_file/local_file_spec.rb
index b33d82f624..575996a540 100644
--- a/spec/unit/provider/remote_file/local_file_spec.rb
+++ b/spec/unit/provider/remote_file/local_file_spec.rb
@@ -25,26 +25,45 @@ describe Chef::Provider::RemoteFile::LocalFile do
let(:new_resource) { Chef::Resource::RemoteFile.new("local file backend test (new_resource)") }
let(:current_resource) { Chef::Resource::RemoteFile.new("local file backend test (current_resource)") }
subject(:fetcher) { Chef::Provider::RemoteFile::LocalFile.new(uri, new_resource, current_resource) }
-
- context "when parsing source path" do
+
+ context "when parsing source path on windows" do
+
+ before do
+ allow(Chef::Platform).to receive(:windows?).and_return(true)
+ end
+
describe "when given local unix path" do
let(:uri) { URI.parse("file:///nyan_cat.png") }
it "returns a correct unix path" do
- expect(fetcher.fix_windows_path(uri.path)).to eq("/nyan_cat.png")
+ expect(fetcher.source_path).to eq("/nyan_cat.png")
end
end
describe "when given local windows path" do
let(:uri) { URI.parse("file:///z:/windows/path/file.txt") }
it "returns a valid windows local path" do
- expect(fetcher.fix_windows_path(uri.path)).to eq("z:/windows/path/file.txt")
+ expect(fetcher.source_path).to eq("z:/windows/path/file.txt")
+ end
+ end
+
+ describe "when given local windows path with spaces" do
+ let(:uri) { URI.parse(URI.escape("file:///z:/windows/path/foo & bar.txt")) }
+ it "returns a valid windows local path" do
+ expect(fetcher.source_path).to eq("z:/windows/path/foo & bar.txt")
end
end
describe "when given unc windows path" do
let(:uri) { URI.parse("file:////server/share/windows/path/file.txt") }
it "returns a valid windows unc path" do
- expect(fetcher.fix_windows_path(uri.path)).to eq("//server/share/windows/path/file.txt")
+ expect(fetcher.source_path).to eq("//server/share/windows/path/file.txt")
+ end
+ end
+
+ describe "when given unc windows path with spaces" do
+ let(:uri) { URI.parse(URI.escape("file:////server/share/windows/path/foo & bar.txt")) }
+ it "returns a valid windows unc path" do
+ expect(fetcher.source_path).to eq("//server/share/windows/path/foo & bar.txt")
end
end
end
@@ -73,7 +92,7 @@ describe Chef::Provider::RemoteFile::LocalFile do
it "stages the local file to a temporary file" do
expect(Chef::FileContentManagement::Tempfile).to receive(:new).with(new_resource).and_return(chef_tempfile)
expect(::FileUtils).to receive(:cp).with(uri.path, tempfile.path)
- expect(tempfile).to receive(:close)
+ expect(tempfile).to receive(:close)
result = fetcher.fetch
expect(result).to eq(tempfile)
diff --git a/spec/unit/provider/remote_file/network_file_spec.rb b/spec/unit/provider/remote_file/network_file_spec.rb
new file mode 100644
index 0000000000..3666a47468
--- /dev/null
+++ b/spec/unit/provider/remote_file/network_file_spec.rb
@@ -0,0 +1,45 @@
+#
+# Author:: Jay Mundrawala (<jdm@chef.io>)
+# Copyright:: Copyright (c) 2015 Chef Software
+# 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'
+
+describe Chef::Provider::RemoteFile::NetworkFile do
+
+ let(:source) { "\\\\foohost\\fooshare\\Foo.tar.gz" }
+
+ let(:new_resource) { Chef::Resource::RemoteFile.new("network file (new_resource)") }
+ let(:current_resource) { Chef::Resource::RemoteFile.new("network file (current_resource)") }
+ subject(:fetcher) { Chef::Provider::RemoteFile::NetworkFile.new(source, new_resource, current_resource) }
+
+ describe "when fetching the object" do
+
+ let(:tempfile) { double("Tempfile", :path => "/tmp/foo/bar/Foo.tar.gz", :close => nil) }
+ let(:chef_tempfile) { double("Chef::FileContentManagement::Tempfile", :tempfile => tempfile) }
+
+ it "stages the local file to a temporary file" do
+ expect(Chef::FileContentManagement::Tempfile).to receive(:new).with(new_resource).and_return(chef_tempfile)
+ expect(::FileUtils).to receive(:cp).with(source, tempfile.path)
+ expect(tempfile).to receive(:close)
+
+ result = fetcher.fetch
+ expect(result).to eq(tempfile)
+ end
+
+ end
+
+end
diff --git a/spec/unit/provider/service/aix_service_spec.rb b/spec/unit/provider/service/aix_service_spec.rb
index 796661145b..a0c8bb3407 100644
--- a/spec/unit/provider/service/aix_service_spec.rb
+++ b/spec/unit/provider/service/aix_service_spec.rb
@@ -51,22 +51,35 @@ describe Chef::Provider::Service::Aix do
end
it "current resource is running" do
- expect(@provider).to receive(:shell_out!).with("lssrc -a | grep -w chef").and_return(@status)
- expect(@provider).to receive(:is_resource_group?).with(["chef chef 12345 active"])
+ expect(@provider).to receive(:shell_out!).with("lssrc -s chef").and_return(@status)
+ expect(@provider).to receive(:is_resource_group?).and_return false
@provider.load_current_resource
expect(@current_resource.running).to be_truthy
end
end
- context "when the service is inoprative" do
+ context "when the service is inoperative" do
before do
@status = double("Status", :exitstatus => 0, :stdout => "chef chef inoperative\n")
end
it "current resource is not running" do
- expect(@provider).to receive(:shell_out!).with("lssrc -a | grep -w chef").and_return(@status)
- expect(@provider).to receive(:is_resource_group?).with(["chef chef inoperative"])
+ expect(@provider).to receive(:shell_out!).with("lssrc -s chef").and_return(@status)
+ expect(@provider).to receive(:is_resource_group?).and_return false
+
+ @provider.load_current_resource
+ expect(@current_resource.running).to be_falsey
+ end
+ end
+
+ context "when there is no such service" do
+ before do
+ @status = double("Status", :exitstatus => 1, :stdout => "0513-085 The chef Subsystem is not on file.\n")
+ end
+ it "current resource is not running" do
+ expect(@provider).to receive(:shell_out!).with("lssrc -s chef").and_return(@status)
+ expect(@provider).to receive(:is_resource_group?).and_return false
@provider.load_current_resource
expect(@current_resource.running).to be_falsey
@@ -75,13 +88,13 @@ describe Chef::Provider::Service::Aix do
end
describe "is resource group" do
- context "when there are mutiple subsystems associated with group" do
+ context "when there are multiple subsystems associated with group" do
before do
@status = double("Status", :exitstatus => 0, :stdout => "chef1 chef 12345 active\nchef2 chef 12334 active\nchef3 chef inoperative")
end
it "service is a group" do
- expect(@provider).to receive(:shell_out!).with("lssrc -a | grep -w chef").and_return(@status)
+ expect(@provider).to receive(:shell_out!).with("lssrc -g chef").and_return(@status)
@provider.load_current_resource
expect(@provider.instance_eval("@is_resource_group")).to be_truthy
end
@@ -93,19 +106,21 @@ describe Chef::Provider::Service::Aix do
end
it "service is a group" do
- expect(@provider).to receive(:shell_out!).with("lssrc -a | grep -w chef").and_return(@status)
+ expect(@provider).to receive(:shell_out!).with("lssrc -g chef").and_return(@status)
@provider.load_current_resource
expect(@provider.instance_eval("@is_resource_group")).to be_truthy
end
end
- context "when there service is a subsytem" do
+ context "when the service is a subsystem" do
before do
- @status = double("Status", :exitstatus => 0, :stdout => "chef chef123 inoperative\n")
+ @group_status = double("Status", :exitstatus => 1, :stdout => "0513-086 The chef Group is not on file.\n")
+ @service_status = double("Status", :exitstatus => 0, :stdout => "chef chef inoperative\n")
end
it "service is a subsystem" do
- expect(@provider).to receive(:shell_out!).with("lssrc -a | grep -w chef").and_return(@status)
+ expect(@provider).to receive(:shell_out!).with("lssrc -g chef").and_return(@group_status)
+ expect(@provider).to receive(:shell_out!).with("lssrc -s chef").and_return(@service_status)
@provider.load_current_resource
expect(@provider.instance_eval("@is_resource_group")).to be_falsey
end
diff --git a/spec/unit/provider/service/freebsd_service_spec.rb b/spec/unit/provider/service/freebsd_service_spec.rb
index 5a55425d87..cfc28c94d5 100644
--- a/spec/unit/provider/service/freebsd_service_spec.rb
+++ b/spec/unit/provider/service/freebsd_service_spec.rb
@@ -189,18 +189,6 @@ PS_SAMPLE
expect(provider.status_load_success).to be_nil
end
- context "when ps command is nil" do
- before do
- node.automatic_attrs[:command] = {:ps => nil}
- end
-
- it "should set running to nil" do
- pending "superclass raises no conversion of nil to string which seems broken"
- provider.determine_current_status!
- expect(current_resource.running).to be_nil
- end
- end
-
context "when ps is empty string" do
before do
node.automatic_attrs[:command] = {:ps => ""}
diff --git a/spec/unit/provider/user/dscl_spec.rb b/spec/unit/provider/user/dscl_spec.rb
index 5ea037d944..32d0812d8c 100644
--- a/spec/unit/provider/user/dscl_spec.rb
+++ b/spec/unit/provider/user/dscl_spec.rb
@@ -24,7 +24,7 @@ require 'mixlib/shellout'
describe Chef::Provider::User::Dscl do
before do
- allow(Chef::Platform).to receive(:windows?) { false }
+ allow(ChefConfig).to receive(:windows?) { false }
end
let(:node) {
node = Chef::Node.new
diff --git a/spec/unit/provider/user_spec.rb b/spec/unit/provider/user_spec.rb
index 381168647b..2345ce18fb 100644
--- a/spec/unit/provider/user_spec.rb
+++ b/spec/unit/provider/user_spec.rb
@@ -143,8 +143,8 @@ describe Chef::Provider::User do
begin
require 'rubygems'
require 'shadow'
- rescue LoadError => e
- pending "ruby-shadow gem not installed for dynamic load test"
+ rescue LoadError
+ skip "ruby-shadow gem not installed for dynamic load test"
true
else
false
@@ -161,7 +161,7 @@ describe Chef::Provider::User do
unless shadow_lib_unavail?
context "and we have the ruby-shadow gem" do
- pending "and we are not root (rerun this again as root)", :requires_unprivileged_user => true
+ skip "and we are not root (rerun this again as root)", :requires_unprivileged_user => true
context "and we are root", :requires_root => true do
it "should pass assertions when ruby-shadow can be loaded" do
diff --git a/spec/unit/provider_resolver_spec.rb b/spec/unit/provider_resolver_spec.rb
index 718eebfdf4..e18d69bc19 100644
--- a/spec/unit/provider_resolver_spec.rb
+++ b/spec/unit/provider_resolver_spec.rb
@@ -19,9 +19,13 @@
require 'spec_helper'
require 'chef/mixin/convert_to_class_name'
require 'chef/provider_resolver'
+require 'chef/platform/service_helpers'
include Chef::Mixin::ConvertToClassName
+# Open up Provider so we can write things down easier in here
+#module Chef::Provider
+
describe Chef::ProviderResolver do
let(:node) do
@@ -46,6 +50,55 @@ describe Chef::ProviderResolver do
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)
+ end
+
+ def self.on_platform(platform, *tags,
+ platform_version: '11.0.1',
+ platform_family: nil,
+ os: nil,
+ &block)
+ Array(platform).each do |platform|
+ Array(platform_version).each do |platform_version|
+ on_one_platform(platform, platform_version, platform_family || platform, os || platform_family || platform, *tags, &block)
+ end
+ end
+ end
+
+ def self.on_one_platform(platform, platform_version, platform_family, os, *tags, &block)
+ describe "on #{platform} #{platform_version}, platform_family: #{platform_family}, os: #{os}", *tags do
+ let(:os) { os }
+ let(:platform) { platform }
+ let(:platform_family) { platform_family }
+ let(:platform_version) { platform_version }
+
+ define_singleton_method(:os) { os }
+ define_singleton_method(:platform) { platform }
+ define_singleton_method(:platform_family) { platform_family }
+ define_singleton_method(:platform_version) { platform_version }
+
+ instance_eval(&block)
+ end
+ end
+
+ def self.expect_providers(**providers)
+ providers.each do |name, provider|
+ describe name.to_s do
+ let(:resource_name) { name }
+ if provider
+ it "resolves to a #{provider}" do
+ expect(resolved_provider).to eql(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/
+ end
+ end
+ end
+ end
+ end
+
describe "resolving service resource" do
def stub_service_providers(*services)
services ||= []
@@ -60,7 +113,6 @@ describe Chef::ProviderResolver do
end
before do
- expect(provider_resolver).not_to receive(:maybe_chef_platform_lookup)
allow(resource).to receive(:service_name).and_return("ntp")
end
@@ -297,389 +349,477 @@ describe Chef::ProviderResolver do
end
end
- describe "on Ubuntu 14.10" do
- let(:os) { "linux" }
- let(:platform) { "ubuntu" }
- let(:platform_family) { "debian" }
- let(:platform_version) { "14.04" }
-
+ on_platform "ubuntu", platform_version: "14.10", platform_family: "debian", os: "linux" do
it_behaves_like "an ubuntu platform with upstart, update-rc.d and systemd"
end
- describe "on Ubuntu 14.04" do
- let(:os) { "linux" }
- let(:platform) { "ubuntu" }
- let(:platform_family) { "debian" }
- let(:platform_version) { "14.04" }
-
+ on_platform "ubuntu", platform_version: "14.04", platform_family: "debian", os: "linux" do
it_behaves_like "an ubuntu platform with upstart and update-rc.d"
end
- describe "on Ubuntu 10.04" do
- let(:os) { "linux" }
- let(:platform) { "ubuntu" }
- let(:platform_family) { "debian" }
- let(:platform_version) { "10.04" }
-
+ on_platform "ubuntu", platform_version: "10.04", platform_family: "debian", os: "linux" do
it_behaves_like "an ubuntu platform with upstart and update-rc.d"
end
# old debian uses the Debian provider (does not have insserv or upstart, or update-rc.d???)
- describe "on Debian 4.0" do
- let(:os) { "linux" }
- let(:platform) { "debian" }
- let(:platform_family) { "debian" }
- let(:platform_version) { "4.0" }
-
+ on_platform "debian", platform_version: "4.0", os: "linux" do
#it_behaves_like "a debian platform using the debian provider"
end
# Debian replaced the debian provider with insserv in the FIXME:VERSION distro
- describe "on Debian 7.0" do
- let(:os) { "linux" }
- let(:platform) { "debian" }
- let(:platform_family) { "debian" }
- let(:platform_version) { "7.0" }
-
+ on_platform "debian", platform_version: "7.0", os: "linux" do
it_behaves_like "a debian platform using the insserv provider"
end
- %w{solaris2 openindiana opensolaris nexentacore omnios smartos}.each do |platform|
- describe "on #{platform}" do
- let(:os) { "solaris2" }
- let(:platform) { platform }
- let(:platform_family) { platform }
- let(:platform_version) { "5.11" }
-
- it "returns a Solaris provider" do
- stub_service_providers
- stub_service_configs
- expect(resolved_provider).to eql(Chef::Provider::Service::Solaris)
- end
+ on_platform %w{solaris2 openindiana opensolaris nexentacore omnios smartos}, os: "solaris2", platform_version: "5.11" do
+ it "returns a Solaris provider" do
+ stub_service_providers
+ stub_service_configs
+ expect(resolved_provider).to eql(Chef::Provider::Service::Solaris)
+ end
- it "always returns a Solaris provider" do
- # no matter what we stub on the next two lines we should get a Solaris provider
- stub_service_providers(:debian, :invokercd, :insserv, :upstart, :redhat, :systemd)
- stub_service_configs(:initd, :upstart, :xinetd, :user_local_etc_rcd, :systemd)
- expect(resolved_provider).to eql(Chef::Provider::Service::Solaris)
- end
+ it "always returns a Solaris provider" do
+ # no matter what we stub on the next two lines we should get a Solaris provider
+ stub_service_providers(:debian, :invokercd, :insserv, :upstart, :redhat, :systemd)
+ stub_service_configs(:initd, :upstart, :xinetd, :user_local_etc_rcd, :systemd)
+ expect(resolved_provider).to eql(Chef::Provider::Service::Solaris)
end
end
- %w{mswin mingw32 windows}.each do |platform|
- describe "on #{platform}" do
- let(:os) { "windows" }
- let(:platform) { platform }
- let(:platform_family) { "windows" }
- let(:platform_version) { "5.11" }
-
- it "returns a Windows provider" do
- stub_service_providers
- stub_service_configs
- expect(resolved_provider).to eql(Chef::Provider::Service::Windows)
- end
+ on_platform %w{mswin mingw32 windows}, platform_family: "windows", platform_version: "5.11" do
+ it "returns a Windows provider" do
+ stub_service_providers
+ stub_service_configs
+ expect(resolved_provider).to eql(Chef::Provider::Service::Windows)
+ end
- it "always returns a Windows provider" do
- # no matter what we stub on the next two lines we should get a Windows provider
- stub_service_providers(:debian, :invokercd, :insserv, :upstart, :redhat, :systemd)
- stub_service_configs(:initd, :upstart, :xinetd, :user_local_etc_rcd, :systemd)
- expect(resolved_provider).to eql(Chef::Provider::Service::Windows)
- end
+ it "always returns a Windows provider" do
+ # no matter what we stub on the next two lines we should get a Windows provider
+ stub_service_providers(:debian, :invokercd, :insserv, :upstart, :redhat, :systemd)
+ stub_service_configs(:initd, :upstart, :xinetd, :user_local_etc_rcd, :systemd)
+ expect(resolved_provider).to eql(Chef::Provider::Service::Windows)
end
end
- %w{mac_os_x mac_os_x_server}.each do |platform|
- describe "on #{platform}" do
- let(:os) { "darwin" }
- let(:platform) { platform }
- let(:platform_family) { "mac_os_x" }
- let(:platform_version) { "10.9.2" }
-
- it "returns a Macosx provider" do
- stub_service_providers
- stub_service_configs
- expect(resolved_provider).to eql(Chef::Provider::Service::Macosx)
- end
+ on_platform %w{mac_os_x mac_os_x_server}, os: "darwin", platform_family: "mac_os_x", platform_version: "10.9.2" do
+ it "returns a Macosx provider" do
+ stub_service_providers
+ stub_service_configs
+ expect(resolved_provider).to eql(Chef::Provider::Service::Macosx)
+ end
- it "always returns a Macosx provider" do
- # no matter what we stub on the next two lines we should get a Macosx provider
- stub_service_providers(:debian, :invokercd, :insserv, :upstart, :redhat, :systemd)
- stub_service_configs(:initd, :upstart, :xinetd, :user_local_etc_rcd, :systemd)
- expect(resolved_provider).to eql(Chef::Provider::Service::Macosx)
- end
+ it "always returns a Macosx provider" do
+ # no matter what we stub on the next two lines we should get a Macosx provider
+ stub_service_providers(:debian, :invokercd, :insserv, :upstart, :redhat, :systemd)
+ stub_service_configs(:initd, :upstart, :xinetd, :user_local_etc_rcd, :systemd)
+ expect(resolved_provider).to eql(Chef::Provider::Service::Macosx)
end
end
- %w{freebsd netbsd}.each do |platform|
- describe "on #{platform}" do
- let(:os) { platform }
- let(:platform) { platform }
- let(:platform_family) { platform }
- let(:platform_version) { "10.0-RELEASE" }
-
- it "returns a Freebsd provider if it finds the /usr/local/etc/rc.d initscript" do
- stub_service_providers
- stub_service_configs(:usr_local_etc_rcd)
- expect(resolved_provider).to eql(Chef::Provider::Service::Freebsd)
- end
+ on_platform %w(freebsd netbsd), platform_version: '3.1.4' do
+ it "returns a Freebsd provider if it finds the /usr/local/etc/rc.d initscript" do
+ stub_service_providers
+ stub_service_configs(:usr_local_etc_rcd)
+ expect(resolved_provider).to eql(Chef::Provider::Service::Freebsd)
+ end
- it "returns a Freebsd provider if it finds the /etc/rc.d initscript" do
- stub_service_providers
- stub_service_configs(:etc_rcd)
- expect(resolved_provider).to eql(Chef::Provider::Service::Freebsd)
- end
+ it "returns a Freebsd provider if it finds the /etc/rc.d initscript" do
+ stub_service_providers
+ stub_service_configs(:etc_rcd)
+ expect(resolved_provider).to eql(Chef::Provider::Service::Freebsd)
+ end
- it "always returns a Freebsd provider if it finds the /usr/local/etc/rc.d initscript" do
- # should only care about :usr_local_etc_rcd stub in the service configs
- stub_service_providers(:debian, :invokercd, :insserv, :upstart, :redhat, :systemd)
- stub_service_configs(:usr_local_etc_rcd, :initd, :upstart, :xinetd, :systemd)
- expect(resolved_provider).to eql(Chef::Provider::Service::Freebsd)
- end
+ it "always returns a Freebsd provider if it finds the /usr/local/etc/rc.d initscript" do
+ # should only care about :usr_local_etc_rcd stub in the service configs
+ stub_service_providers(:debian, :invokercd, :insserv, :upstart, :redhat, :systemd)
+ stub_service_configs(:usr_local_etc_rcd, :initd, :upstart, :xinetd, :systemd)
+ expect(resolved_provider).to eql(Chef::Provider::Service::Freebsd)
+ end
- it "always returns a Freebsd provider if it finds the /usr/local/etc/rc.d initscript" do
- # should only care about :etc_rcd stub in the service configs
- stub_service_providers(:debian, :invokercd, :insserv, :upstart, :redhat, :systemd)
- stub_service_configs(:etc_rcd, :initd, :upstart, :xinetd, :systemd)
- expect(resolved_provider).to eql(Chef::Provider::Service::Freebsd)
- end
+ it "always returns a Freebsd provider if it finds the /usr/local/etc/rc.d initscript" do
+ # should only care about :etc_rcd stub in the service configs
+ stub_service_providers(:debian, :invokercd, :insserv, :upstart, :redhat, :systemd)
+ stub_service_configs(:etc_rcd, :initd, :upstart, :xinetd, :systemd)
+ expect(resolved_provider).to eql(Chef::Provider::Service::Freebsd)
+ end
- it "foo" do
- stub_service_providers
- stub_service_configs
- expect(resolved_provider).to eql(Chef::Provider::Service::Freebsd)
- end
+ it "foo" do
+ stub_service_providers
+ stub_service_configs
+ expect(resolved_provider).to eql(Chef::Provider::Service::Freebsd)
end
end
end
- describe "for the package provider" do
- let(:resource_name) { :package }
-
- before do
- expect(provider_resolver).not_to receive(:maybe_chef_platform_lookup)
- end
-
- %w{mac_os_x mac_os_x_server}.each do |platform|
- describe "on #{platform}" do
- let(:os) { "darwin" }
- let(:platform) { platform }
- let(:platform_family) { "mac_os_x" }
- let(:platform_version) { "10.9.2" }
-
-
- it "returns a Chef::Provider::Package::Homebrew provider" do
- expect(resolved_provider).to eql(Chef::Provider::Package::Homebrew)
- end
- end
- end
- end
+ 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,
+ rpm_package: Chef::Provider::Package::Rpm,
+ 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,
+
+ # We want to check that these are unsupported:
+ apt_package: nil,
+ bff_package: nil,
+ dsc_script: nil,
+ dpkg_package: nil,
+ ips_package: nil,
+ pacman_package: nil,
+ paludis_package: nil,
+ rpm_package: nil,
+ smartos_package: nil,
+ solaris_package: nil,
+ yum_package: nil,
+ windows_package: nil,
+ 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,
+
+ "debian" => {
+ ifconfig: Chef::Provider::Ifconfig::Debian,
+ package: Chef::Provider::Package::Apt,
+# service: Chef::Provider::Service::Debian,
+
+ "debian" => {
+ "7.0" => {
+ },
+ "6.0" => {
+ ifconfig: Chef::Provider::Ifconfig,
+# service: Chef::Provider::Service::Insserv,
+ },
+ "5.0" => {
+ ifconfig: Chef::Provider::Ifconfig,
+ },
+ },
+ "gcel" => {
+ "3.1.4" => {
+ ifconfig: Chef::Provider::Ifconfig,
+ },
+ },
+ "linaro" => {
+ "3.1.4" => {
+ ifconfig: Chef::Provider::Ifconfig,
+ },
+ },
+ "linuxmint" => {
+ "3.1.4" => {
+ ifconfig: Chef::Provider::Ifconfig,
+# service: Chef::Provider::Service::Upstart,
+ },
+ },
+ "raspbian" => {
+ "3.1.4" => {
+ ifconfig: Chef::Provider::Ifconfig,
+ },
+ },
+ "ubuntu" => {
+ "11.10" => {
+ },
+ "10.04" => {
+ ifconfig: Chef::Provider::Ifconfig,
+ },
+ },
+ },
+
+ "arch" => {
+ package: Chef::Provider::Package::Pacman,
+
+ "arch" => {
+ "3.1.4" => {
+ }
+ },
+ },
+
+ "freebsd" => {
+ group: Chef::Provider::Group::Pw,
+ user: Chef::Provider::User::Pw,
+
+ "freebsd" => {
+ "3.1.4" => {
+ },
+ },
+ },
+ "suse" => {
+ group: Chef::Provider::Group::Gpasswd,
+ "suse" => {
+ "12.0" => {
+ },
+ %w(11.1 11.2 11.3) => {
+ group: Chef::Provider::Group::Suse,
+ },
+ },
+ "opensuse" => {
+# service: Chef::Provider::Service::Redhat,
+ package: Chef::Provider::Package::Zypper,
+ group: Chef::Provider::Group::Usermod,
+ "12.3" => {
+ },
+ "12.2" => {
+ group: Chef::Provider::Group::Suse,
+ },
+ },
+ },
+
+ "gentoo" => {
+ package: Chef::Provider::Package::Portage,
+ portage_package: Chef::Provider::Package::Portage,
+# service: Chef::Provider::Service::Gentoo,
+
+ "gentoo" => {
+ "3.1.4" => {
+ },
+ },
+ },
+
+ "rhel" => {
+# service: Chef::Provider::Service::Systemd,
+ package: Chef::Provider::Package::Yum,
+ ifconfig: Chef::Provider::Ifconfig::Redhat,
+
+ %w(amazon xcp xenserver ibm_powerkvm cloudlinux parallels) => {
+ "3.1.4" => {
+# service: Chef::Provider::Service::Redhat,
+ },
+ },
+ %w(redhat centos scientific oracle) => {
+ "7.0" => {
+ },
+ "6.0" => {
+# service: Chef::Provider::Service::Redhat,
+ },
+ },
+ "fedora" => {
+ "15.0" => {
+ },
+ "14.0" => {
+# service: Chef::Provider::Service::Redhat,
+ },
+ },
+ },
- provider_mapping = {
- "mac_os_x" => {
- :package => Chef::Provider::Package::Homebrew,
- :user => Chef::Provider::User::Dscl,
- :group => Chef::Provider::Group::Dscl,
- },
- "mac_os_x_server" => {
- :package => Chef::Provider::Package::Homebrew,
- :user => Chef::Provider::User::Dscl,
- :group => Chef::Provider::Group::Dscl,
- },
- "mswin" => {
- :env => Chef::Provider::Env::Windows,
- :user => Chef::Provider::User::Windows,
- :group => Chef::Provider::Group::Windows,
- :mount => Chef::Provider::Mount::Windows,
- :batch => Chef::Provider::Batch,
- :powershell_script => Chef::Provider::PowershellScript,
},
- "mingw32" => {
- :env => Chef::Provider::Env::Windows,
- :user => Chef::Provider::User::Windows,
- :group => Chef::Provider::Group::Windows,
- :mount => Chef::Provider::Mount::Windows,
- :batch => Chef::Provider::Batch,
- :powershell_script => Chef::Provider::PowershellScript,
+
+ "darwin" => {
+ %w(mac_os_x mac_os_x_server) => {
+ group: Chef::Provider::Group::Dscl,
+ package: Chef::Provider::Package::Homebrew,
+ user: Chef::Provider::User::Dscl,
+
+ "mac_os_x" => {
+ "10.9.2" => {
+ },
+ },
+ },
},
+
"windows" => {
- :env => Chef::Provider::Env::Windows,
- :user => Chef::Provider::User::Windows,
- :group => Chef::Provider::Group::Windows,
- :mount => Chef::Provider::Mount::Windows,
- :batch => Chef::Provider::Batch,
- :powershell_script => Chef::Provider::PowershellScript,
+ 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,
+
+ "windows" => {
+ %w(mswin mingw32 windows) => {
+ "10.9.2" => {
+ },
+ },
+ },
},
+
"aix" => {
- :cron => Chef::Provider::Cron::Aix,
- },
- "netbsd"=> {
- :group => Chef::Provider::Group::Groupmod,
- },
- "openbsd" => {
- :group => Chef::Provider::Group::Usermod,
- :package => Chef::Provider::Package::Openbsd,
+ 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,
+
+ "aix" => {
+ "aix" => {
+ "5.6" => {
+ },
+ },
+ },
},
- }
-
- def self.do_platform(platform_hash)
- platform_hash.each do |resource, provider|
- describe "for #{resource}" do
- let(:resource_name) { resource }
-
- it "resolves to a #{provider}" do
- expect(resolved_provider).to eql(provider)
- end
- end
- end
- end
-
- describe "individual platform mappings" do
- let(:resource_name) { :user }
-
- before do
- expect(provider_resolver).not_to receive(:maybe_chef_platform_lookup)
- end
-
- %w{mac_os_x mac_os_x_server}.each do |platform|
- describe "on #{platform}" do
- let(:os) { "darwin" }
- let(:platform) { platform }
- let(:platform_family) { "mac_os_x" }
- let(:platform_version) { "10.9.2" }
- do_platform(provider_mapping[platform])
- end
- end
-
- %w{mswin mingw32 windows}.each do |platform|
- describe "on #{platform}" do
- let(:os) { "windows" }
- let(:platform) { platform }
- let(:platform_family) { "windows" }
- let(:platform_version) { "10.9.2" }
+ "hpux" => {
+ "hpux" => {
+ "hpux" => {
+ "3.1.4" => {
+ group: Chef::Provider::Group::Usermod
+ }
+ }
+ }
+ },
- do_platform(provider_mapping[platform])
- end
- end
+ "netbsd" => {
+ "netbsd" => {
+ "netbsd" => {
+ "3.1.4" => {
+ group: Chef::Provider::Group::Groupmod,
+ },
+ },
+ },
+ },
- describe "on AIX" do
- let(:os) { "aix" }
- let(:platform) { "aix" }
- let(:platform_family) { "aix" }
- let(:platform_version) { "6.2" }
+ "openbsd" => {
+ group: Chef::Provider::Group::Usermod,
+ package: Chef::Provider::Package::Openbsd,
+
+ "openbsd" => {
+ "openbsd" => {
+ "3.1.4" => {
+ },
+ },
+ },
+ },
- do_platform(provider_mapping['aix'])
- end
+ "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,
+
+ "smartos" => {
+ smartos_package: Chef::Provider::Package::SmartOS,
+ package: Chef::Provider::Package::SmartOS,
+
+ "smartos" => {
+ "3.1.4" => {
+ },
+ },
+ },
+
+ "solaris2" => {
+ "nexentacore" => {
+ "3.1.4" => {
+ package: Chef::Provider::Package::Solaris,
+ },
+ },
+ "omnios" => {
+ "3.1.4" => {
+ user: Chef::Provider::User::Solaris,
+ }
+ },
+ "openindiana" => {
+ "3.1.4" => {
+ },
+ },
+ "opensolaris" => {
+ "3.1.4" => {
+ },
+ },
+ "solaris2" => {
+ user: Chef::Provider::User::Solaris,
+ "5.11" => {
+ },
+ "5.9" => {
+ package: Chef::Provider::Package::Solaris,
+ },
+ },
+ },
- %w{netbsd openbsd}.each do |platform|
- describe "on #{platform}" do
- let(:os) { platform }
- let(:platform) { platform }
- let(:platform_family) { platform }
- let(:platform_version) { "10.0-RELEASE" }
+ },
- do_platform(provider_mapping[platform])
- end
- end
- end
+ "solaris" => {
+ "solaris" => {
+ "solaris" => {
+ "3.1.4" => {
+ },
+ },
+ },
+ },
- describe "resolving static providers" do
- def resource_class(resource)
- Chef::Resource.const_get(convert_to_class_name(resource.to_s))
- end
- static_mapping = {
- apt_package: Chef::Provider::Package::Apt,
- bash: Chef::Provider::Script,
- bff_package: Chef::Provider::Package::Aix,
- 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,
- dpkg_package: Chef::Provider::Package::Dpkg,
- dsc_script: Chef::Provider::DscScript,
- 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,
- homebrew_package: Chef::Provider::Package::Homebrew,
- http_request: Chef::Provider::HttpRequest,
- ips_package: Chef::Provider::Package::Ips,
- link: Chef::Provider::Link,
- log: Chef::Provider::Log::ChefLog,
- macports_package: Chef::Provider::Package::Macports,
- mdadm: Chef::Provider::Mdadm,
- pacman_package: Chef::Provider::Package::Pacman,
- paludis_package: Chef::Provider::Package::Paludis,
- perl: Chef::Provider::Script,
- portage_package: Chef::Provider::Package::Portage,
- python: Chef::Provider::Script,
- remote_directory: Chef::Provider::RemoteDirectory,
- route: Chef::Provider::Route,
- rpm_package: Chef::Provider::Package::Rpm,
- ruby: Chef::Provider::Script,
- ruby_block: Chef::Provider::RubyBlock,
- script: Chef::Provider::Script,
- smartos_package: Chef::Provider::Package::SmartOS,
- solaris_package: Chef::Provider::Package::Solaris,
- subversion: Chef::Provider::Subversion,
- template: Chef::Provider::Template,
- timestamped_deploy: Chef::Provider::Deploy::Timestamped,
- whyrun_safe_ruby_block: Chef::Provider::WhyrunSafeRubyBlock,
- windows_package: Chef::Provider::Package::Windows,
- windows_service: Chef::Provider::Service::Windows,
- yum_package: Chef::Provider::Package::Yum,
+ "exherbo" => {
+ "exherbo" => {
+ "exherbo" => {
+ "3.1.4" => {
+ package: Chef::Provider::Package::Paludis
+ }
+ }
}
+ }
+ }
- describe "on Ubuntu 14.04" do
- let(:os) { "linux" }
- let(:platform) { "ubuntu" }
- let(:platform_family) { "debian" }
- let(:platform_version) { "14.04" }
-
- supported_providers = [
- :apt_package, :bash, :breakpoint, :chef_gem, :cookbook_file, :csh, :deploy,
- :deploy_revision, :directory, :dpkg_package, :easy_install_package, :erl_call,
- :execute, :file, :gem_package, :git, :homebrew_package, :http_request, :link,
- :log, :macports_package, :pacman_package, :paludis_package, :perl, :python,
- :remote_directory, :route, :rpm_package, :ruby, :ruby_block, :script, :subversion,
- :template, :timestamped_deploy, :whyrun_safe_ruby_block, :yum_package,
- ]
-
- supported_providers.each do |static_resource|
- static_provider = static_mapping[static_resource]
- context "when the resource is a #{static_resource}" do
- let(:resource) { double(Chef::Resource, provider: nil, resource_name: static_resource) }
- let(:action) { :start } # in reality this doesn't matter much
- it "should resolve to a #{static_provider} provider" do
- expect(provider_resolver).not_to receive(:maybe_chef_platform_lookup)
- expect(resolved_provider).to eql(static_provider)
+ def self.create_provider_tests(providers, test, expected, filter)
+ expected = expected.merge(providers.select { |key, value| key.is_a?(Symbol) })
+ providers.each do |key, value|
+ if !key.is_a?(Symbol)
+ next_test = test.merge({ filter => key })
+ next_filter =
+ case filter
+ when :os
+ :platform_family
+ when :platform_family
+ :platform
+ when :platform
+ :platform_version
+ when :platform_version
+ nil
+ else
+ raise "Hash too deep; only os, platform_family, platform and platform_version supported"
end
- end
+ create_provider_tests(value, next_test, expected, next_filter)
end
-
- unsupported_providers = [
- :bff_package, :dsc_script, :ips_package, :smartos_package,
- :solaris_package, :windows_package, :windows_service,
- ]
-
- unsupported_providers.each do |static_resource|
- static_provider = static_mapping[static_resource]
- context "when the resource is a #{static_resource}" do
- let(:resource) { double(Chef::Resource, provider: nil, resource_name: static_resource) }
- let(:action) { :start } # in reality this doesn't matter much
- it "should fall back into the old provider mapper code and hooks" do
- retval = Object.new
- expect(provider_resolver).to receive(:maybe_chef_platform_lookup).and_return(retval)
- expect(resolved_provider).to equal(retval)
- end
- end
+ end
+ # If there is no filter, we're as deep as we need to go
+ if !filter
+ on_platform test.delete(:platform), test do
+ expect_providers(expected)
end
end
end
+
+ create_provider_tests(PROVIDERS, {}, {}, :os)
end
diff --git a/spec/unit/provider_spec.rb b/spec/unit/provider_spec.rb
index 5a21b094d0..d7a34bc21b 100644
--- a/spec/unit/provider_spec.rb
+++ b/spec/unit/provider_spec.rb
@@ -49,6 +49,13 @@ class ConvergeActionDemonstrator < Chef::Provider
end
end
+class CheckResourceSemanticsDemonstrator < ConvergeActionDemonstrator
+ def check_resource_semantics!
+ raise Chef::Exceptions::InvalidResourceSpecification.new("check_resource_semantics!")
+ end
+end
+
+
describe Chef::Provider do
before(:each) do
@cookbook_collection = Chef::CookbookCollection.new([])
@@ -89,6 +96,10 @@ describe Chef::Provider do
expect(@provider.send(:whyrun_supported?)).to eql(false)
end
+ it "should do nothing for check_resource_semantics! by default" do
+ expect { @provider.check_resource_semantics! }.not_to raise_error
+ end
+
it "should return true for action_nothing" do
expect(@provider.action_nothing).to eql(true)
end
@@ -176,6 +187,15 @@ describe Chef::Provider do
expect(@resource).not_to be_updated_by_last_action
end
end
+
+ describe "and the resource is invalid" do
+ let(:provider) { CheckResourceSemanticsDemonstrator.new(@resource, @run_context) }
+
+ it "fails with InvalidResourceSpecification when run" do
+ expect { provider.run_action(:foo) }.to raise_error(Chef::Exceptions::InvalidResourceSpecification)
+ end
+
+ end
end
end
diff --git a/spec/unit/recipe_spec.rb b/spec/unit/recipe_spec.rb
index 7442f4477e..ee98e63c1f 100644
--- a/spec/unit/recipe_spec.rb
+++ b/spec/unit/recipe_spec.rb
@@ -83,7 +83,7 @@ describe Chef::Recipe do
it "should require a name argument" do
expect {
recipe.cat
- }.to raise_error(ArgumentError, "You must supply a name when declaring a cat resource")
+ }.to raise_error(ArgumentError)
end
it "should allow regular errors (not NameErrors) to pass unchanged" do
@@ -121,7 +121,7 @@ describe Chef::Recipe do
it "locate resource for particular platform" do
ShaunTheSheep = Class.new(Chef::Resource)
- ShaunTheSheep.provides :laughter, :on_platforms => ["television"]
+ ShaunTheSheep.provides :laughter, :platform => ["television"]
node.automatic[:platform] = "television"
node.automatic[:platform_version] = "123"
res = recipe.laughter "timmy"
@@ -141,9 +141,7 @@ describe Chef::Recipe do
before do
node.automatic[:platform] = "nbc_sports"
Sounders = Class.new(Chef::Resource)
- Sounders.provides :football, platform: "nbc_sports"
TottenhamHotspur = Class.new(Chef::Resource)
- TottenhamHotspur.provides :football, platform: "nbc_sports"
end
after do
@@ -151,16 +149,12 @@ describe Chef::Recipe do
Object.send(:remove_const, :TottenhamHotspur)
end
- it "warns if resolution of the two resources is ambiguous" do
- expect(Chef::Log).to receive(:warn).at_least(:once).with(/Ambiguous resource precedence/)
- res1 = recipe.football "club world cup"
- expect(res1.name).to eql("club world cup")
- # the class of res1 is not defined.
- end
-
- it "selects one if it is given priority" do
+ it "selects one if it is the last declared" do
expect(Chef::Log).not_to receive(:warn)
- Chef::Platform::ResourcePriorityMap.instance.send(:priority, :football, TottenhamHotspur, platform: "nbc_sports")
+
+ Sounders.provides :football, platform: "nbc_sports"
+ TottenhamHotspur.provides :football, platform: "nbc_sports"
+
res1 = recipe.football "club world cup"
expect(res1.name).to eql("club world cup")
expect(res1).to be_a_kind_of(TottenhamHotspur)
@@ -168,7 +162,10 @@ describe Chef::Recipe do
it "selects the other one if it is given priority" do
expect(Chef::Log).not_to receive(:warn)
- Chef::Platform::ResourcePriorityMap.instance.send(:priority, :football, Sounders, platform: "nbc_sports")
+
+ TottenhamHotspur.provides :football, platform: "nbc_sports"
+ Sounders.provides :football, platform: "nbc_sports"
+
res1 = recipe.football "club world cup"
expect(res1.name).to eql("club world cup")
expect(res1).to be_a_kind_of(Sounders)
@@ -408,7 +405,7 @@ describe Chef::Recipe do
end
it "does not copy the action from the first resource" do
- expect(original_resource.action).to eq([:score])
+ expect(original_resource.action).to eq(:score)
expect(duplicated_resource.action).to eq(:nothing)
end
@@ -504,7 +501,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)
@@ -577,6 +574,36 @@ describe Chef::Recipe do
expect(cookbook_collection[:openldap]).not_to receive(:load_recipe).with("default", run_context)
openldap_recipe.include_recipe "::default"
end
+
+ it "will not load a recipe twice when called first from an LWRP provider" do
+ openldap_recipe = Chef::Recipe.new("openldap", "test", run_context)
+ expect(node).to receive(:loaded_recipe).with(:openldap, "default").exactly(:once)
+ allow(run_context).to receive(:unreachable_cookbook?).with(:openldap).and_return(false)
+ expect(cookbook_collection[:openldap]).to receive(:load_recipe).with("default", run_context)
+ openldap_recipe.include_recipe "::default"
+ expect(cookbook_collection[:openldap]).not_to receive(:load_recipe).with("default", run_context)
+ openldap_recipe.openldap_includer("do it").run_action(:run)
+ end
+
+ it "will not load a recipe twice when called last from an LWRP provider" do
+ openldap_recipe = Chef::Recipe.new("openldap", "test", run_context)
+ expect(node).to receive(:loaded_recipe).with(:openldap, "default").exactly(:once)
+ allow(run_context).to receive(:unreachable_cookbook?).with(:openldap).and_return(false)
+ expect(cookbook_collection[:openldap]).to receive(:load_recipe).with("default", run_context)
+ openldap_recipe.openldap_includer("do it").run_action(:run)
+ expect(cookbook_collection[:openldap]).not_to receive(:load_recipe).with("default", run_context)
+ openldap_recipe.include_recipe "::default"
+ end
+
+ it "will not load a recipe twice when called both times from an LWRP provider" do
+ openldap_recipe = Chef::Recipe.new("openldap", "test", run_context)
+ expect(node).to receive(:loaded_recipe).with(:openldap, "default").exactly(:once)
+ allow(run_context).to receive(:unreachable_cookbook?).with(:openldap).and_return(false)
+ expect(cookbook_collection[:openldap]).to receive(:load_recipe).with("default", run_context)
+ openldap_recipe.openldap_includer("do it").run_action(:run)
+ expect(cookbook_collection[:openldap]).not_to receive(:load_recipe).with("default", run_context)
+ openldap_recipe.openldap_includer("do it").run_action(:run)
+ end
end
describe "tags" do
diff --git a/spec/unit/resource/batch_spec.rb b/spec/unit/resource/batch_spec.rb
index 4a056b8735..b8c2897f42 100644
--- a/spec/unit/resource/batch_spec.rb
+++ b/spec/unit/resource/batch_spec.rb
@@ -25,6 +25,7 @@ describe Chef::Resource::Batch do
node.default["kernel"] = Hash.new
node.default["kernel"][:machine] = :x86_64.to_s
+ node.automatic[:os] = 'windows'
run_context = Chef::RunContext.new(node, nil, nil)
diff --git a/spec/unit/resource/breakpoint_spec.rb b/spec/unit/resource/breakpoint_spec.rb
index ed1f3ebcd5..9c867ebcc7 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/erl_call_spec.rb b/spec/unit/resource/erl_call_spec.rb
index 8ec182665f..008d27372a 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 db52e35004..dd20f5f03a 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/ifconfig_spec.rb b/spec/unit/resource/ifconfig_spec.rb
index ea5282acd5..e3e1f6daa2 100644
--- a/spec/unit/resource/ifconfig_spec.rb
+++ b/spec/unit/resource/ifconfig_spec.rb
@@ -47,21 +47,23 @@ describe Chef::Resource::Ifconfig do
end
end
- shared_examples "being a platform using the default ifconfig provider" do |platform, version|
+ shared_examples "being a platform based on an old Debian" do |platform, version|
before do
+ @node.automatic_attrs[:os] = 'linux'
+ @node.automatic_attrs[:platform_family] = 'debian'
@node.automatic_attrs[:platform] = platform
@node.automatic_attrs[:platform_version] = version
end
it "should use an ordinary Provider::Ifconfig as a provider for #{platform} #{version}" do
- expect(@resource.provider_for_action(:add)).to be_a_kind_of(Chef::Provider::Ifconfig)
- expect(@resource.provider_for_action(:add)).not_to be_a_kind_of(Chef::Provider::Ifconfig::Debian)
- expect(@resource.provider_for_action(:add)).not_to be_a_kind_of(Chef::Provider::Ifconfig::Redhat)
+ expect(@resource.provider_for_action(:add).class).to eq(Chef::Provider::Ifconfig)
end
end
shared_examples "being a platform based on RedHat" do |platform, version|
before do
+ @node.automatic_attrs[:os] = 'linux'
+ @node.automatic_attrs[:platform_family] = 'rhel'
@node.automatic_attrs[:platform] = platform
@node.automatic_attrs[:platform_version] = version
end
@@ -73,6 +75,8 @@ describe Chef::Resource::Ifconfig do
shared_examples "being a platform based on a recent Debian" do |platform, version|
before do
+ @node.automatic_attrs[:os] = 'linux'
+ @node.automatic_attrs[:platform_family] = 'debian'
@node.automatic_attrs[:platform] = platform
@node.automatic_attrs[:platform_version] = version
end
@@ -87,7 +91,7 @@ describe Chef::Resource::Ifconfig do
end
describe "when it is an old Debian platform" do
- it_should_behave_like "being a platform using the default ifconfig provider", "debian", "6.0"
+ it_should_behave_like "being a platform based on an old Debian", "debian", "6.0"
end
describe "when it is a new Debian platform" do
@@ -95,7 +99,7 @@ describe Chef::Resource::Ifconfig do
end
describe "when it is an old Ubuntu platform" do
- it_should_behave_like "being a platform using the default ifconfig provider", "ubuntu", "11.04"
+ it_should_behave_like "being a platform based on an old Debian", "ubuntu", "11.04"
end
describe "when it is a new Ubuntu platform" do
diff --git a/spec/unit/resource/powershell_spec.rb b/spec/unit/resource/powershell_spec.rb
index c263172ae6..2505c4a3d7 100644
--- a/spec/unit/resource/powershell_spec.rb
+++ b/spec/unit/resource/powershell_spec.rb
@@ -25,6 +25,7 @@ describe Chef::Resource::PowershellScript do
node.default["kernel"] = Hash.new
node.default["kernel"][:machine] = :x86_64.to_s
+ node.automatic[:os] = 'windows'
run_context = Chef::RunContext.new(node, nil, nil)
diff --git a/spec/unit/resource/remote_file_spec.rb b/spec/unit/resource/remote_file_spec.rb
index 3731d1aee2..0a379ff574 100644
--- a/spec/unit/resource/remote_file_spec.rb
+++ b/spec/unit/resource/remote_file_spec.rb
@@ -39,6 +39,11 @@ describe Chef::Resource::RemoteFile do
expect(Chef::Platform.find_provider(:noplatform, 'noversion', @resource)).to eq(Chef::Provider::RemoteFile)
end
+ it "says its provider is RemoteFile when the source is a network share" do
+ @resource.source("\\\\fakey\\fakerton\\fake.txt")
+ expect(@resource.provider).to eq(Chef::Provider::RemoteFile)
+ expect(Chef::Platform.find_provider(:noplatform, 'noversion', @resource)).to eq(Chef::Provider::RemoteFile)
+ end
describe "source" do
it "does not have a default value for 'source'" do
@@ -50,6 +55,16 @@ describe Chef::Resource::RemoteFile do
expect(@resource.source).to eql([ "http://opscode.com/" ])
end
+ it "should accept a windows network share source" do
+ @resource.source "\\\\fakey\\fakerton\\fake.txt"
+ expect(@resource.source).to eql([ "\\\\fakey\\fakerton\\fake.txt" ])
+ end
+
+ it 'should accept file URIs with spaces' do
+ @resource.source("file:///C:/foo bar")
+ expect(@resource.source).to eql(["file:///C:/foo bar"])
+ end
+
it "should accept a delayed evalutator (string) for the remote file source" do
@resource.source Chef::DelayedEvaluator.new {"http://opscode.com/"}
expect(@resource.source).to eql([ "http://opscode.com/" ])
diff --git a/spec/unit/resource/route_spec.rb b/spec/unit/resource/route_spec.rb
index ec1d369932..ffb9304511 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 9f19fecd4f..5d83f7e367 100644
--- a/spec/unit/resource/ruby_block_spec.rb
+++ b/spec/unit/resource/ruby_block_spec.rb
@@ -31,7 +31,7 @@ describe Chef::Resource::RubyBlock do
end
it "should have a default action of 'create'" do
- expect(@resource.action).to eql("run")
+ 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/template_spec.rb b/spec/unit/resource/template_spec.rb
index df5ca94b8a..2fd951b72d 100644
--- a/spec/unit/resource/template_spec.rb
+++ b/spec/unit/resource/template_spec.rb
@@ -98,7 +98,7 @@ describe Chef::Resource::Template do
context "on windows", :windows_only do
# according to Chef::Resource::File, windows state attributes are rights + deny_rights
- pending "it describes its state"
+ skip "it describes its state"
end
it "returns the file path as its identity" do
diff --git a/spec/unit/resource/timestamped_deploy_spec.rb b/spec/unit/resource/timestamped_deploy_spec.rb
index eca6c570d4..4ebfdaf059 100644
--- a/spec/unit/resource/timestamped_deploy_spec.rb
+++ b/spec/unit/resource/timestamped_deploy_spec.rb
@@ -23,11 +23,10 @@ describe Chef::Resource::TimestampedDeploy, "initialize" do
static_provider_resolution(
resource: Chef::Resource::TimestampedDeploy,
provider: Chef::Provider::Deploy::Timestamped,
- name: :deploy,
+ name: :timestamped_deploy,
action: :deploy,
os: 'linux',
platform_family: 'rhel',
)
end
-
diff --git a/spec/unit/resource/windows_package_spec.rb b/spec/unit/resource/windows_package_spec.rb
index 1e02f2449b..6aa5d357ea 100644
--- a/spec/unit/resource/windows_package_spec.rb
+++ b/spec/unit/resource/windows_package_spec.rb
@@ -63,9 +63,9 @@ describe Chef::Resource::WindowsPackage, "initialize" do
end
it "coverts a source to an absolute path" do
- allow(::File).to receive(:absolute_path).and_return("c:\\Files\\frost.msi")
+ allow(::File).to receive(:absolute_path).and_return("c:\\files\\frost.msi")
resource.source("frost.msi")
- expect(resource.source).to eql "c:\\Files\\frost.msi"
+ expect(resource.source).to eql "c:\\files\\frost.msi"
end
it "converts slashes to backslashes in the source path" do
@@ -78,4 +78,18 @@ describe Chef::Resource::WindowsPackage, "initialize" do
# it's a little late to stub out File.absolute_path
expect(resource.source).to include("solitaire.msi")
end
+
+ it "supports the checksum attribute" do
+ resource.checksum('somechecksum')
+ expect(resource.checksum).to eq('somechecksum')
+ end
+
+ context 'when a URL is used' do
+ let(:resource_source) { 'https://foo.bar/solitare.msi' }
+ let(:resource) { Chef::Resource::WindowsPackage.new(resource_source) }
+
+ it "should return the source unmodified" do
+ expect(resource.source).to eq(resource_source)
+ end
+ end
end
diff --git a/spec/unit/resource/windows_service_spec.rb b/spec/unit/resource/windows_service_spec.rb
index 45a295c24e..8866cad1bf 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_spec.rb b/spec/unit/resource_spec.rb
index 6b2d6c89d3..8ba45d9350 100644
--- a/spec/unit/resource_spec.rb
+++ b/spec/unit/resource_spec.rb
@@ -21,10 +21,6 @@
require 'spec_helper'
-class ResourceTestHarness < Chef::Resource
- provider_base Chef::Provider::Package
-end
-
describe Chef::Resource do
before(:each) do
@cookbook_repo_path = File.join(CHEF_SPEC_DATA, 'cookbooks')
@@ -35,6 +31,18 @@ describe Chef::Resource do
@resource = Chef::Resource.new("funk", @run_context)
end
+ it "should mixin shell_out" do
+ expect(@resource.respond_to?(:shell_out)).to be true
+ end
+
+ it "should mixin shell_out!" do
+ expect(@resource.respond_to?(:shell_out!)).to be true
+ end
+
+ it "should mixin shell_out_with_systems_locale" do
+ expect(@resource.respond_to?(:shell_out_with_systems_locale)).to be true
+ end
+
describe "when inherited" do
it "adds an entry to a list of subclasses" do
@@ -324,6 +332,71 @@ describe Chef::Resource do
end
end
+ describe "self.resource_name" do
+ context "When resource_name is not set" do
+ it "and there are no provides lines, resource_name is nil" do
+ c = Class.new(Chef::Resource) do
+ end
+
+ r = c.new('hi')
+ r.declared_type = :d
+ expect(c.resource_name).to be_nil
+ expect(r.resource_name).to be_nil
+ expect(r.declared_type).to eq :d
+ end
+ it "and there are no provides lines, @resource_name is used" do
+ c = Class.new(Chef::Resource) do
+ def initialize(*args, &block)
+ @resource_name = :blah
+ super
+ end
+ end
+
+ r = c.new('hi')
+ r.declared_type = :d
+ expect(c.resource_name).to be_nil
+ expect(r.resource_name).to eq :blah
+ expect(r.declared_type).to eq :d
+ end
+ end
+
+ it "resource_name without provides is honored" do
+ c = Class.new(Chef::Resource) do
+ resource_name 'blah'
+ end
+
+ r = c.new('hi')
+ r.declared_type = :d
+ expect(c.resource_name).to eq :blah
+ expect(r.resource_name).to eq :blah
+ expect(r.declared_type).to eq :d
+ end
+ it "setting class.resource_name with 'resource_name = blah' overrides declared_type" do
+ c = Class.new(Chef::Resource) do
+ provides :self_resource_name_test_2
+ end
+ c.resource_name = :blah
+
+ r = c.new('hi')
+ r.declared_type = :d
+ expect(c.resource_name).to eq :blah
+ expect(r.resource_name).to eq :blah
+ expect(r.declared_type).to eq :d
+ end
+ it "setting class.resource_name with 'resource_name blah' overrides declared_type" do
+ c = Class.new(Chef::Resource) do
+ resource_name :blah
+ provides :self_resource_name_test_3
+ end
+
+ r = c.new('hi')
+ r.declared_type = :d
+ expect(c.resource_name).to eq :blah
+ expect(r.resource_name).to eq :blah
+ expect(r.declared_type).to eq :d
+ end
+ end
+
describe "is" do
it "should return the arguments passed with 'is'" do
zm = Chef::Resource::ZenMaster.new("coffee")
@@ -447,8 +520,21 @@ describe Chef::Resource do
expect(Chef::Resource.provider_base).to eq(Chef::Provider)
end
- it "allows the base provider to be overriden by a " do
- expect(ResourceTestHarness.provider_base).to eq(Chef::Provider::Package)
+ it "allows the base provider to be overridden" do
+ Chef::Config.treat_deprecation_warnings_as_errors(false)
+ class OverrideProviderBaseTest < Chef::Resource
+ provider_base Chef::Provider::Package
+ end
+
+ expect(OverrideProviderBaseTest.provider_base).to eq(Chef::Provider::Package)
+ end
+
+ it "warns when setting provider_base" do
+ expect {
+ class OverrideProviderBaseTest2 < Chef::Resource
+ provider_base Chef::Provider::Package
+ end
+ }.to raise_error(Chef::Exceptions::DeprecatedFeatureError)
end
end
@@ -709,57 +795,73 @@ describe Chef::Resource do
end
it 'adds mappings for a single platform' do
- expect(Chef::Resource::Klz.node_map).to receive(:set).with(
- :dinobot, true, { platform: ['autobots'] }
+ expect(Chef).to receive(:set_resource_priority_array).with(
+ :dinobot, Chef::Resource::Klz, { platform: ['autobots'] }
)
klz.provides :dinobot, platform: ['autobots']
end
it 'adds mappings for multiple platforms' do
- expect(Chef::Resource::Klz.node_map).to receive(:set).with(
- :energy, true, { platform: ['autobots', 'decepticons']}
+ expect(Chef).to receive(:set_resource_priority_array).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::Klz.node_map).to receive(:set).with(
- :tape_deck, true, {}
+ expect(Chef).to receive(:set_resource_priority_array).with(
+ :tape_deck, Chef::Resource::Klz, {}
)
klz.provides :tape_deck
end
end
- describe "lookups from the platform map" do
- let(:klz1) { Class.new(Chef::Resource) }
- let(:klz2) { Class.new(Chef::Resource) }
+ describe "resource_for_node" do
+ describe "lookups from the platform map" do
+ let(:klz1) { Class.new(Chef::Resource) }
+
+ before(:each) do
+ Chef::Resource::Klz1 = klz1
+ @node = Chef::Node.new
+ @node.name("bumblebee")
+ @node.automatic[:platform] = "autobots"
+ @node.automatic[:platform_version] = "6.1"
+ Object.const_set('Soundwave', klz1)
+ klz1.provides :soundwave
+ end
- before(:each) do
- Chef::Resource::Klz1 = klz1
- Chef::Resource::Klz2 = klz2
- @node = Chef::Node.new
- @node.name("bumblebee")
- @node.automatic[:platform] = "autobots"
- @node.automatic[:platform_version] = "6.1"
- Object.const_set('Soundwave', klz1)
- klz2.provides :dinobot, :on_platforms => ['autobots']
- Object.const_set('Grimlock', klz2)
- end
+ after(:each) do
+ Object.send(:remove_const, :Soundwave)
+ Chef::Resource.send(:remove_const, :Klz1)
+ end
- after(:each) do
- Object.send(:remove_const, :Soundwave)
- Object.send(:remove_const, :Grimlock)
- Chef::Resource.send(:remove_const, :Klz1)
- Chef::Resource.send(:remove_const, :Klz2)
+ it "returns a resource by short_name if nothing else matches" do
+ expect(Chef::Resource.resource_for_node(:soundwave, @node)).to eql(klz1)
+ end
end
- describe "resource_for_node" do
- it "returns a resource by short_name and node" do
- expect(Chef::Resource.resource_for_node(:dinobot, @node)).to eql(Grimlock)
+ describe "lookups from the platform map" do
+ let(:klz2) { Class.new(Chef::Resource) }
+
+ before(:each) do
+ Chef::Resource::Klz2 = klz2
+ @node = Chef::Node.new
+ @node.name("bumblebee")
+ @node.automatic[:platform] = "autobots"
+ @node.automatic[:platform_version] = "6.1"
+ klz2.provides :dinobot, :platform => ['autobots']
+ Object.const_set('Grimlock', klz2)
+ klz2.provides :grimlock
end
- it "returns a resource by short_name if nothing else matches" do
- expect(Chef::Resource.resource_for_node(:soundwave, @node)).to eql(Soundwave)
+
+ after(:each) do
+ Object.send(:remove_const, :Grimlock)
+ Chef::Resource.send(:remove_const, :Klz2)
+ end
+
+ it "returns a resource by short_name and node" do
+ expect(Chef::Resource.resource_for_node(:dinobot, @node)).to eql(klz2)
end
end
diff --git a/spec/unit/rest_spec.rb b/spec/unit/rest_spec.rb
index 85c9e3df8f..3b04981610 100644
--- a/spec/unit/rest_spec.rb
+++ b/spec/unit/rest_spec.rb
@@ -69,8 +69,8 @@ describe Chef::REST do
rest
end
- let(:standard_read_headers) {{"Accept"=>"application/json", "Accept"=>"application/json", "Accept-Encoding"=>"gzip;q=1.0,deflate;q=0.6,identity;q=0.3", "X-REMOTE-REQUEST-ID"=>request_id}}
- let(:standard_write_headers) {{"Accept"=>"application/json", "Content-Type"=>"application/json", "Accept"=>"application/json", "Accept-Encoding"=>"gzip;q=1.0,deflate;q=0.6,identity;q=0.3", "X-REMOTE-REQUEST-ID"=>request_id}}
+ let(:standard_read_headers) {{"Accept"=>"application/json", "Accept"=>"application/json", "Accept-Encoding"=>"gzip;q=1.0,deflate;q=0.6,identity;q=0.3", "X-REMOTE-REQUEST-ID"=>request_id, 'X-Ops-Server-API-Version' => Chef::HTTP::Authenticator::DEFAULT_SERVER_API_VERSION}}
+ let(:standard_write_headers) {{"Accept"=>"application/json", "Content-Type"=>"application/json", "Accept"=>"application/json", "Accept-Encoding"=>"gzip;q=1.0,deflate;q=0.6,identity;q=0.3", "X-REMOTE-REQUEST-ID"=>request_id, 'X-Ops-Server-API-Version' => Chef::HTTP::Authenticator::DEFAULT_SERVER_API_VERSION}}
before(:each) do
Chef::Log.init(log_stringio)
@@ -277,19 +277,6 @@ describe Chef::REST do
rest
end
- let(:base_headers) do
- {
- 'Accept' => 'application/json',
- 'X-Chef-Version' => Chef::VERSION,
- 'Accept-Encoding' => Chef::REST::RESTRequest::ENCODING_GZIP_DEFLATE,
- 'X-REMOTE-REQUEST-ID' => request_id
- }
- end
-
- let (:req_with_body_headers) do
- base_headers.merge("Content-Type" => "application/json", "Content-Length" => '13')
- end
-
before(:each) do
Chef::Config[:ssl_client_cert] = nil
Chef::Config[:ssl_client_key] = nil
@@ -304,7 +291,8 @@ describe Chef::REST do
'X-Chef-Version' => Chef::VERSION,
'Accept-Encoding' => Chef::REST::RESTRequest::ENCODING_GZIP_DEFLATE,
'Host' => host_header,
- 'X-REMOTE-REQUEST-ID' => request_id
+ 'X-REMOTE-REQUEST-ID' => request_id,
+ 'X-Ops-Server-API-Version' => Chef::HTTP::Authenticator::DEFAULT_SERVER_API_VERSION
}
end
@@ -548,7 +536,7 @@ describe Chef::REST do
end
end
end
- end
+ end # as JSON API requests
context "when streaming downloads to a tempfile" do
let!(:tempfile) { Tempfile.open("chef-rspec-rest_spec-line-@{__LINE__}--") }
@@ -586,7 +574,8 @@ describe Chef::REST do
'X-Chef-Version' => Chef::VERSION,
'Accept-Encoding' => Chef::REST::RESTRequest::ENCODING_GZIP_DEFLATE,
'Host' => host_header,
- 'X-REMOTE-REQUEST-ID'=> request_id
+ 'X-REMOTE-REQUEST-ID'=> request_id,
+ 'X-Ops-Server-API-Version' => Chef::HTTP::Authenticator::DEFAULT_SERVER_API_VERSION
}
expect(Net::HTTP::Get).to receive(:new).with("/?foo=bar", expected_headers).and_return(request_mock)
rest.streaming_request(url, {})
@@ -597,7 +586,8 @@ describe Chef::REST do
'X-Chef-Version' => Chef::VERSION,
'Accept-Encoding' => Chef::REST::RESTRequest::ENCODING_GZIP_DEFLATE,
'Host' => host_header,
- 'X-REMOTE-REQUEST-ID'=> request_id
+ 'X-REMOTE-REQUEST-ID'=> request_id,
+ 'X-Ops-Server-API-Version' => Chef::HTTP::Authenticator::DEFAULT_SERVER_API_VERSION
}
expect(Net::HTTP::Get).to receive(:new).with("/?foo=bar", expected_headers).and_return(request_mock)
rest.streaming_request(url, {})
@@ -695,7 +685,7 @@ describe Chef::REST do
expect(block_called).to be_truthy
end
end
- end
+ end # when making REST requests
context "when following redirects" do
let(:rest) do
diff --git a/spec/unit/role_spec.rb b/spec/unit/role_spec.rb
index 5421b5a7b3..f120ca6da6 100644
--- a/spec/unit/role_spec.rb
+++ b/spec/unit/role_spec.rb
@@ -21,7 +21,7 @@ require 'chef/role'
describe Chef::Role do
before(:each) do
- allow(Chef::Platform).to receive(:windows?) { false }
+ allow(ChefConfig).to receive(:windows?) { false }
@role = Chef::Role.new
@role.name("ops_master")
end
diff --git a/spec/unit/run_context_spec.rb b/spec/unit/run_context_spec.rb
index d656111a7d..e20ba63b72 100644
--- a/spec/unit/run_context_spec.rb
+++ b/spec/unit/run_context_spec.rb
@@ -53,6 +53,37 @@ describe Chef::RunContext do
expect(run_context.node).to eq(node)
end
+ it "loads up node[:cookbooks]" do
+ expect(run_context.node[:cookbooks]).to eql(
+ {
+ "circular-dep1" => {
+ "version" => "0.0.0",
+ },
+ "circular-dep2" => {
+ "version" => "0.0.0",
+ },
+ "dependency1" => {
+ "version" => "0.0.0",
+ },
+ "dependency2" => {
+ "version" => "0.0.0",
+ },
+ "no-default-attr" => {
+ "version" => "0.0.0",
+ },
+ "test" => {
+ "version" => "0.0.0",
+ },
+ "test-with-circular-deps" => {
+ "version" => "0.0.0",
+ },
+ "test-with-deps" => {
+ "version" => "0.0.0",
+ },
+ }
+ )
+ end
+
describe "loading cookbooks for a run list" do
before do
@@ -159,4 +190,45 @@ describe Chef::RunContext do
expect(run_context.reboot_requested?).to be_falsey
end
end
+
+ describe "notifications" do
+ let(:notification) { Chef::Resource::Notification.new(nil, nil, notifying_resource) }
+
+ shared_context "notifying resource is a Chef::Resource" do
+ let(:notifying_resource) { Chef::Resource.new("gerbil") }
+
+ it "should be keyed off the resource name" do
+ run_context.send(setter, notification)
+ expect(run_context.send(getter, notifying_resource)).to eq([notification])
+ end
+ end
+
+ shared_context "notifying resource is a subclass of Chef::Resource" do
+ let(:declared_type) { :alpaca }
+ let(:notifying_resource) {
+ r = Class.new(Chef::Resource).new("guinea pig")
+ r.declared_type = declared_type
+ r
+ }
+
+ it "should be keyed off the resource declared key" do
+ run_context.send(setter, notification)
+ expect(run_context.send(getter, notifying_resource)).to eq([notification])
+ end
+ end
+
+ describe "of the immediate kind" do
+ let(:setter) { :notifies_immediately }
+ let(:getter) { :immediate_notifications }
+ include_context "notifying resource is a Chef::Resource"
+ include_context "notifying resource is a subclass of Chef::Resource"
+ end
+
+ describe "of the delayed kind" do
+ let(:setter) { :notifies_delayed }
+ let(:getter) { :delayed_notifications }
+ include_context "notifying resource is a Chef::Resource"
+ include_context "notifying resource is a subclass of Chef::Resource"
+ end
+ end
end
diff --git a/spec/unit/runner_spec.rb b/spec/unit/runner_spec.rb
index b30f818da1..82e57e068c 100644
--- a/spec/unit/runner_spec.rb
+++ b/spec/unit/runner_spec.rb
@@ -273,8 +273,8 @@ describe Chef::Runner do
expected_message =<<-E
Multiple failures occurred:
-* FailureProvider::ChefClientFail occurred in delayed notification: [explode] (dynamically defined) had an error: FailureProvider::ChefClientFail: chef had an error of some sort
-* FailureProvider::ChefClientFail occurred in delayed notification: [explode again] (dynamically defined) had an error: FailureProvider::ChefClientFail: chef had an error of some sort
+* FailureProvider::ChefClientFail occurred in delayed notification: failure_resource[explode] (dynamically defined) had an error: FailureProvider::ChefClientFail: chef had an error of some sort
+* FailureProvider::ChefClientFail occurred in delayed notification: failure_resource[explode again] (dynamically defined) had an error: FailureProvider::ChefClientFail: chef had an error of some sort
E
expect(exception.message).to eq(expected_message)
diff --git a/spec/unit/shell_spec.rb b/spec/unit/shell_spec.rb
index acbb1891e7..379043a017 100644
--- a/spec/unit/shell_spec.rb
+++ b/spec/unit/shell_spec.rb
@@ -43,7 +43,7 @@ describe Shell do
before do
Shell.irb_conf = {}
allow(Shell::ShellSession.instance).to receive(:reset!)
- allow(Chef::Platform).to receive(:windows?).and_return(false)
+ allow(ChefConfig).to receive(:windows?).and_return(false)
allow(Chef::Util::PathHelper).to receive(:home).and_return('/home/foo')
end
@@ -71,7 +71,7 @@ describe Shell do
Shell.irb_conf[:IRB_RC].call(conf)
expect(conf.prompt_c).to eq("chef > ")
expect(conf.return_format).to eq(" => %s \n")
- expect(conf.prompt_i).to eq("chef > ")
+ expect(conf.prompt_i).to eq("chef (#{Chef::VERSION})> ")
expect(conf.prompt_n).to eq("chef ?> ")
expect(conf.prompt_s).to eq("chef%l> ")
expect(conf.use_tracer).to eq(false)
@@ -85,7 +85,7 @@ describe Shell do
conf.main = Chef::Recipe.new(nil,nil,Chef::RunContext.new(Chef::Node.new, {}, events))
Shell.irb_conf[:IRB_RC].call(conf)
expect(conf.prompt_c).to eq("chef:recipe > ")
- expect(conf.prompt_i).to eq("chef:recipe > ")
+ expect(conf.prompt_i).to eq("chef:recipe (#{Chef::VERSION})> ")
expect(conf.prompt_n).to eq("chef:recipe ?> ")
expect(conf.prompt_s).to eq("chef:recipe%l> ")
end
@@ -97,7 +97,7 @@ describe Shell do
conf.main = Chef::Node.new
Shell.irb_conf[:IRB_RC].call(conf)
expect(conf.prompt_c).to eq("chef:attributes > ")
- expect(conf.prompt_i).to eq("chef:attributes > ")
+ expect(conf.prompt_i).to eq("chef:attributes (#{Chef::VERSION})> ")
expect(conf.prompt_n).to eq("chef:attributes ?> ")
expect(conf.prompt_s).to eq("chef:attributes%l> ")
end
diff --git a/spec/unit/user_spec.rb b/spec/unit/user_spec.rb
index d451531b16..57822df7e3 100644
--- a/spec/unit/user_spec.rb
+++ b/spec/unit/user_spec.rb
@@ -26,98 +26,141 @@ 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 "name" do
- it "should let you set the name to a string" do
- expect(@user.name("ops_master")).to eq("ops_master")
+ 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 name" do
- @user.name "ops_master"
- expect(@user.name).to eq("ops_master")
+ 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.name "Bar" }.to raise_error(ArgumentError)
+ expect { @user.username "Bar" }.to raise_error(ArgumentError)
# slashes
- expect { @user.name "foo/bar" }.to raise_error(ArgumentError)
+ expect { @user.username "foo/bar" }.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)
+ expect { @user.username "foo&" }.to raise_error(ArgumentError)
end
it "should not accept spaces" do
- expect { @user.name "ops master" }.to raise_error(ArgumentError)
+ 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.name Hash.new }.to raise_error(ArgumentError)
+ expect { @user.username 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)
+ 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
- it "should default to false" do
- expect(@user.admin).to eq(false)
+ describe "string fields" do
+ describe "public_key" do
+ it_should_behave_like "string fields with no contraints" do
+ let(:method) { :public_key }
+ end
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)
+ describe "private_key" do
+ it_should_behave_like "string fields with no contraints" do
+ let(:method) { :private_key }
+ end
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")
+ describe "display_name" do
+ it_should_behave_like "string fields with no contraints" do
+ let(:method) { :display_name }
+ end
end
- it "should return the current public key" do
- @user.public_key("super public")
- expect(@user.public_key).to eq("super public")
+ describe "first_name" do
+ it_should_behave_like "string fields with no contraints" do
+ let(:method) { :first_name }
+ end
end
- it "should throw an ArgumentError if you feed it something lame" do
- expect { @user.public_key Hash.new }.to raise_error(ArgumentError)
+ describe "middle_name" do
+ it_should_behave_like "string fields with no contraints" do
+ let(:method) { :middle_name }
+ end
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")
+ describe "last_name" do
+ it_should_behave_like "string fields with no contraints" do
+ let(:method) { :last_name }
+ end
end
- it "should return the private key" do
- @user.private_key("super private")
- expect(@user.private_key).to eq("super private")
+ describe "email" do
+ it_should_behave_like "string fields with no contraints" do
+ let(:method) { :email }
+ end
end
- it "should throw an ArgumentError if you feed it something lame" do
- expect { @user.private_key Hash.new }.to raise_error(ArgumentError)
+ 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.name("black")
- @user.public_key("crowes")
+ @user.username("black")
@json = @user.to_json
end
@@ -125,16 +168,62 @@ describe Chef::User do
expect(@json).to match(/^\{.+\}$/)
end
- it "includes the name value" do
- expect(@json).to include(%q{"name":"black"})
+ 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 public key value" do
- expect(@json).to include(%{"public_key":"crowes"})
+ it "includes the first name when present" do
+ @user.first_name("char")
+ expect(@user.to_json).to include(%{"first_name":"char"})
end
- it "includes the 'admin' flag" do
- expect(@json).to include(%q{"admin":false})
+ 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
@@ -162,11 +251,18 @@ describe Chef::User do
describe "when deserializing from JSON" do
before(:each) do
- user = { "name" => "mr_spinks",
+ 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",
- "password" => "password",
- "admin" => true }
+ "create_key" => false
+ }
@user = Chef::User.from_json(Chef::JSONCompat.to_json(user))
end
@@ -174,32 +270,275 @@ describe Chef::User do
expect(@user).to be_a_kind_of(Chef::User)
end
- it "preserves the name" do
- expect(@user.name).to eq("mr_spinks")
+ it "preserves the username" do
+ expect(@user.username).to eq("mr_spinks")
end
- it "preserves the public key" do
- expect(@user.public_key).to eq("turtles")
+ it "preserves the display name if present" do
+ expect(@user.display_name).to eq("displayed")
end
- it "preserves the admin status" do
- expect(@user.admin).to be_truthy
+ it "preserves the first name if present" do
+ expect(@user.first_name).to eq("char")
end
- it "includes the private key if present" do
- expect(@user.private_key).to eq("pandas")
+ 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::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.name "foobar"
+ @user.username "foobar"
@http_client = double("Chef::REST mock")
allow(Chef::REST).to receive(:new).and_return(@http_client)
end
@@ -213,57 +552,31 @@ 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_rest).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_rest).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_rest).with("users").and_return(@ohc_response)
+ allow(@http_client).to receive(:get).with("users").and_return(@ohc_response)
# We expect that Chef::User.list will give a consistent response
# so OHC API responses should be transformed to OSC-style output.
expect(Chef::User.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)
+ allow(@http_client).to receive(:get).with("users").and_return(@ohc_response)
expect(Chef::User.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"})
+ expect(@http_client).to receive(:get).with("users/foobar").and_return({"username" => "foobar", "admin" => true, "public_key" => "pubkey"})
user = Chef::User.load("foobar")
- expect(user.name).to eq("foobar")
- expect(user.admin).to eq(true)
+ expect(user.username).to eq("foobar")
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")
+ expect(@http_client).to receive(:delete).with("users/foobar")
@user.destroy
end
end
diff --git a/spec/unit/util/path_helper_spec.rb b/spec/unit/util/path_helper_spec.rb
deleted file mode 100644
index 23db9587a6..0000000000
--- a/spec/unit/util/path_helper_spec.rb
+++ /dev/null
@@ -1,255 +0,0 @@
-#
-# Author:: Bryan McLellan <btm@loftninjas.org>
-# Copyright:: Copyright (c) 2014 Chef Software, 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 'chef/util/path_helper'
-require 'spec_helper'
-
-describe Chef::Util::PathHelper do
- PathHelper = Chef::Util::PathHelper
-
- [ false, true ].each do |is_windows|
- context "on #{is_windows ? "windows" : "unix"}" do
- before(:each) do
- allow(Chef::Platform).to receive(:windows?).and_return(is_windows)
- end
-
- describe "join" do
- it "joins components when some end with separators" do
- expected = PathHelper.cleanpath("/foo/bar/baz")
- expected = "C:#{expected}" if is_windows
- expect(PathHelper.join(is_windows ? 'C:\\foo\\' : "/foo/", "bar", "baz")).to eq(expected)
- end
-
- it "joins components when some end and start with separators" do
- expected = PathHelper.cleanpath("/foo/bar/baz")
- expected = "C:#{expected}" if is_windows
- expect(PathHelper.join(is_windows ? 'C:\\foo\\' : "/foo/", "bar/", "/baz")).to eq(expected)
- end
-
- it "joins components that don't end in separators" do
- expected = PathHelper.cleanpath("/foo/bar/baz")
- expected = "C:#{expected}" if is_windows
- expect(PathHelper.join(is_windows ? 'C:\\foo' : "/foo", "bar", "baz")).to eq(expected)
- end
-
- it "joins starting with '' resolve to absolute paths" do
- expect(PathHelper.join('', 'a', 'b')).to eq("#{PathHelper.path_separator}a#{PathHelper.path_separator}b")
- end
-
- it "joins ending with '' add a / to the end" do
- expect(PathHelper.join('a', 'b', '')).to eq("a#{PathHelper.path_separator}b#{PathHelper.path_separator}")
- end
-
- if is_windows
- it "joins components on Windows when some end with unix separators" do
- expect(PathHelper.join('C:\\foo/', "bar", "baz")).to eq('C:\\foo\\bar\\baz')
- end
- end
- end
-
- if is_windows
- it "path_separator is \\" do
- expect(PathHelper.path_separator).to eq('\\')
- end
- else
- it "path_separator is /" do
- expect(PathHelper.path_separator).to eq('/')
- end
- end
-
- if is_windows
- it "cleanpath changes slashes into backslashes and leaves backslashes alone" do
- expect(PathHelper.cleanpath('/a/b\\c/d/')).to eq('\\a\\b\\c\\d')
- end
- it "cleanpath does not remove leading double backslash" do
- expect(PathHelper.cleanpath('\\\\a/b\\c/d/')).to eq('\\\\a\\b\\c\\d')
- end
- else
- it "cleanpath removes extra slashes alone" do
- expect(PathHelper.cleanpath('/a///b/c/d/')).to eq('/a/b/c/d')
- end
- end
-
- describe "dirname" do
- it "dirname('abc') is '.'" do
- expect(PathHelper.dirname('abc')).to eq('.')
- end
- it "dirname('/') is '/'" do
- expect(PathHelper.dirname(PathHelper.path_separator)).to eq(PathHelper.path_separator)
- end
- it "dirname('a/b/c') is 'a/b'" do
- expect(PathHelper.dirname(PathHelper.join('a', 'b', 'c'))).to eq(PathHelper.join('a', 'b'))
- end
- it "dirname('a/b/c/') is 'a/b'" do
- expect(PathHelper.dirname(PathHelper.join('a', 'b', 'c', ''))).to eq(PathHelper.join('a', 'b'))
- end
- it "dirname('/a/b/c') is '/a/b'" do
- expect(PathHelper.dirname(PathHelper.join('', 'a', 'b', 'c'))).to eq(PathHelper.join('', 'a', 'b'))
- end
- end
- end
- end
-
- describe "validate_path" do
- context "on windows" do
- before(:each) do
- # pass by default
- allow(Chef::Platform).to receive(:windows?).and_return(true)
- allow(PathHelper).to receive(:printable?).and_return(true)
- allow(PathHelper).to receive(:windows_max_length_exceeded?).and_return(false)
- end
-
- it "returns the path if the path passes the tests" do
- expect(PathHelper.validate_path("C:\\ThisIsRigged")).to eql("C:\\ThisIsRigged")
- end
-
- it "does not raise an error if everything looks great" do
- expect { PathHelper.validate_path("C:\\cool path\\dude.exe") }.not_to raise_error
- end
-
- it "raises an error if the path has invalid characters" do
- allow(PathHelper).to receive(:printable?).and_return(false)
- expect { PathHelper.validate_path("Newline!\n") }.to raise_error(Chef::Exceptions::ValidationFailed)
- end
-
- it "Adds the \\\\?\\ prefix if the path exceeds MAX_LENGTH and does not have it" do
- long_path = "C:\\" + "a" * 250 + "\\" + "b" * 250
- prefixed_long_path = "\\\\?\\" + long_path
- allow(PathHelper).to receive(:windows_max_length_exceeded?).and_return(true)
- expect(PathHelper.validate_path(long_path)).to eql(prefixed_long_path)
- end
- end
- end
-
- describe "windows_max_length_exceeded?" do
- it "returns true if the path is too long (259 + NUL) for the API" do
- expect(PathHelper.windows_max_length_exceeded?("C:\\" + "a" * 250 + "\\" + "b" * 6)).to be_truthy
- end
-
- it "returns false if the path is not too long (259 + NUL) for the standard API" do
- expect(PathHelper.windows_max_length_exceeded?("C:\\" + "a" * 250 + "\\" + "b" * 5)).to be_falsey
- end
-
- it "returns false if the path is over 259 characters but uses the \\\\?\\ prefix" do
- expect(PathHelper.windows_max_length_exceeded?("\\\\?\\C:\\" + "a" * 250 + "\\" + "b" * 250)).to be_falsey
- end
- end
-
- describe "printable?" do
- it "returns true if the string contains no non-printable characters" do
- expect(PathHelper.printable?("C:\\Program Files (x86)\\Microsoft Office\\Files.lst")).to be_truthy
- end
-
- it "returns true when given 'abc' in unicode" do
- expect(PathHelper.printable?("\u0061\u0062\u0063")).to be_truthy
- end
-
- it "returns true when given japanese unicode" do
- expect(PathHelper.printable?("\uff86\uff87\uff88")).to be_truthy
- end
-
- it "returns false if the string contains a non-printable character" do
- expect(PathHelper.printable?("\my files\work\notes.txt")).to be_falsey
- end
-
- # This isn't necessarily a requirement, but here to be explicit about functionality.
- it "returns false if the string contains a newline or tab" do
- expect(PathHelper.printable?("\tThere's no way,\n\t *no* way,\n\t that you came from my loins.\n")).to be_falsey
- end
- end
-
- describe "canonical_path" do
- context "on windows", :windows_only do
- it "returns an absolute path with backslashes instead of slashes" do
- expect(PathHelper.canonical_path("\\\\?\\C:/windows/win.ini")).to eq("\\\\?\\c:\\windows\\win.ini")
- end
-
- it "adds the \\\\?\\ prefix if it is missing" do
- expect(PathHelper.canonical_path("C:/windows/win.ini")).to eq("\\\\?\\c:\\windows\\win.ini")
- end
-
- it "returns a lowercase path" do
- expect(PathHelper.canonical_path("\\\\?\\C:\\CASE\\INSENSITIVE")).to eq("\\\\?\\c:\\case\\insensitive")
- end
- end
-
- context "not on windows", :unix_only do
- it "returns a canonical path" do
- expect(PathHelper.canonical_path("/etc//apache.d/sites-enabled/../sites-available/default")).to eq("/etc/apache.d/sites-available/default")
- end
- end
- end
-
- describe "paths_eql?" do
- it "returns true if the paths are the same" do
- allow(PathHelper).to receive(:canonical_path).with("bandit").and_return("c:/bandit/bandit")
- allow(PathHelper).to receive(:canonical_path).with("../bandit/bandit").and_return("c:/bandit/bandit")
- expect(PathHelper.paths_eql?("bandit", "../bandit/bandit")).to be_truthy
- end
-
- it "returns false if the paths are different" do
- allow(PathHelper).to receive(:canonical_path).with("bandit").and_return("c:/Bo/Bandit")
- allow(PathHelper).to receive(:canonical_path).with("../bandit/bandit").and_return("c:/bandit/bandit")
- expect(PathHelper.paths_eql?("bandit", "../bandit/bandit")).to be_falsey
- end
- end
-
- describe "escape_glob" do
- it "escapes characters reserved by glob" do
- path = "C:\\this\\*path\\[needs]\\escaping?"
- escaped_path = "C:\\\\this\\\\\\*path\\\\\\[needs\\]\\\\escaping\\?"
- expect(PathHelper.escape_glob(path)).to eq(escaped_path)
- end
-
- context "when given more than one argument" do
- it "joins, cleanpaths, and escapes characters reserved by glob" do
- args = ["this/*path", "[needs]", "escaping?"]
- escaped_path = if windows?
- "this\\\\\\*path\\\\\\[needs\\]\\\\escaping\\?"
- else
- "this/\\*path/\\[needs\\]/escaping\\?"
- end
- expect(PathHelper).to receive(:join).with(*args).and_call_original
- expect(PathHelper).to receive(:cleanpath).and_call_original
- expect(PathHelper.escape_glob(*args)).to eq(escaped_path)
- end
- end
- end
-
- describe "all_homes" do
- before do
- stub_const('ENV', env)
- allow(Chef::Platform).to receive(:windows?).and_return(is_windows)
- end
-
- context "on windows" do
- let (:is_windows) { true }
- end
-
- context "on unix" do
- let (:is_windows) { false }
-
- context "when HOME is not set" do
- let (:env) { {} }
- it "returns an empty array" do
- expect(PathHelper.all_homes).to eq([])
- end
- end
- end
- end
-end