summaryrefslogtreecommitdiff
path: root/spec/unit
diff options
context:
space:
mode:
Diffstat (limited to 'spec/unit')
-rw-r--r--spec/unit/application/client_spec.rb18
-rw-r--r--spec/unit/audit/audit_reporter_spec.rb2
-rw-r--r--spec/unit/client_spec.rb104
-rw-r--r--spec/unit/config_spec.rb10
-rw-r--r--spec/unit/cookbook/file_vendor_spec.rb36
-rw-r--r--spec/unit/cookbook_manifest_spec.rb21
-rw-r--r--spec/unit/cookbook_uploader_spec.rb8
-rw-r--r--spec/unit/http/socketless_chef_zero_client_spec.rb174
-rw-r--r--spec/unit/http_spec.rb14
-rw-r--r--spec/unit/knife/bootstrap_spec.rb28
-rw-r--r--spec/unit/knife/core/subcommand_loader_spec.rb58
-rw-r--r--spec/unit/knife/ssh_spec.rb18
-rw-r--r--spec/unit/knife/status_spec.rb72
-rw-r--r--spec/unit/knife_spec.rb5
-rw-r--r--spec/unit/mixin/params_validate_spec.rb136
-rw-r--r--spec/unit/mixin/powershell_type_coercions_spec.rb72
-rw-r--r--spec/unit/platform/query_helpers_spec.rb22
-rw-r--r--spec/unit/policy_builder/policyfile_spec.rb61
-rw-r--r--spec/unit/provider/dsc_resource_spec.rb84
-rw-r--r--spec/unit/provider/package/openbsd_spec.rb122
-rw-r--r--spec/unit/provider/package/rubygems_spec.rb19
-rw-r--r--spec/unit/provider/package/yum_spec.rb14
-rw-r--r--spec/unit/provider/service/macosx_spec.rb6
-rw-r--r--spec/unit/recipe_spec.rb13
-rw-r--r--spec/unit/resource/deploy_spec.rb27
-rw-r--r--spec/unit/resource/dsc_resource_spec.rb85
-rw-r--r--spec/unit/resource/link_spec.rb15
-rw-r--r--spec/unit/rest_spec.rb9
-rw-r--r--spec/unit/shell_spec.rb2
-rw-r--r--spec/unit/util/dsc/resource_store.rb76
-rw-r--r--spec/unit/util/path_helper_spec.rb22
-rw-r--r--spec/unit/util/powershell/ps_credential_spec.rb37
-rw-r--r--spec/unit/workstation_config_loader_spec.rb2
33 files changed, 1170 insertions, 222 deletions
diff --git a/spec/unit/application/client_spec.rb b/spec/unit/application/client_spec.rb
index ea2ad473e5..c753ca0ab8 100644
--- a/spec/unit/application/client_spec.rb
+++ b/spec/unit/application/client_spec.rb
@@ -131,6 +131,16 @@ Enable chef-client interval runs by setting `:client_fork = true` in your config
end
+ describe "when --no-listen is set" do
+
+ it "configures listen = false" do
+ app.config[:listen] = false
+ app.reconfigure
+ expect(Chef::Config[:listen]).to eq(false)
+ end
+
+ end
+
describe "when the json_attribs configuration option is specified" do
let(:json_attribs) { {"a" => "b"} }
@@ -305,7 +315,7 @@ describe Chef::Application::Client, "run_application", :unix_only do
allow(Chef::Daemon).to receive(:daemonize).and_return(true)
end
- it "should exit hard with exitstatus 3" do
+ it "should exit hard with exitstatus 3", :volatile do
pid = fork do
@app.run_application
end
@@ -320,9 +330,9 @@ describe Chef::Application::Client, "run_application", :unix_only do
end
expect(@pipe[0].gets).to eq("started\n")
Process.kill("TERM", pid)
- Process.wait
- sleep 1 # Make sure we give the converging child process enough time to finish
- expect(IO.select([@pipe[0]], nil, nil, 0)).not_to be_nil
+ Process.wait(pid)
+ # The timeout value needs to be large enough for the child process to finish
+ expect(IO.select([@pipe[0]], nil, nil, 15)).not_to be_nil
expect(@pipe[0].gets).to eq("finished\n")
end
end
diff --git a/spec/unit/audit/audit_reporter_spec.rb b/spec/unit/audit/audit_reporter_spec.rb
index 84d7ea82f0..4bf889510a 100644
--- a/spec/unit/audit/audit_reporter_spec.rb
+++ b/spec/unit/audit/audit_reporter_spec.rb
@@ -203,7 +203,7 @@ describe Chef::Audit::AuditReporter do
it "doesn't send reports" do
expect(reporter).to receive(:auditing_enabled?).and_return(true)
expect(reporter).to receive(:run_status).and_return(nil)
- expect(Chef::Log).to receive(:debug).with("Run failed before audits were initialized, not sending audit report to server")
+ expect(Chef::Log).to receive(:debug).with("Run failed before audit mode was initialized, not sending audit report to server")
reporter.run_completed(node)
end
diff --git a/spec/unit/client_spec.rb b/spec/unit/client_spec.rb
index 2ec32b32ac..fa8317744c 100644
--- a/spec/unit/client_spec.rb
+++ b/spec/unit/client_spec.rb
@@ -24,6 +24,9 @@ require 'chef/run_context'
require 'chef/rest'
require 'rbconfig'
+class FooError < RuntimeError
+end
+
describe Chef::Client do
let(:hostname) { "hostname" }
@@ -75,6 +78,19 @@ describe Chef::Client do
allow(Ohai::System).to receive(:new).and_return(ohai_system)
end
+ context "when minimal ohai is configured" do
+ before do
+ Chef::Config[:minimal_ohai] = true
+ end
+
+ it "runs ohai with only the minimum required plugins" do
+ expected_filter = %w[fqdn machinename hostname platform platform_version os os_version]
+ expect(ohai_system).to receive(:all_plugins).with(expected_filter)
+ client.run_ohai
+ end
+
+ end
+
describe "authentication protocol selection" do
after do
Chef::Config[:authentication_protocol_version] = "1.0"
@@ -428,34 +444,80 @@ describe Chef::Client do
describe "when the audit phase fails" do
context "with an exception" 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)
+ 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
- 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)
+ 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
- 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)
+ 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
diff --git a/spec/unit/config_spec.rb b/spec/unit/config_spec.rb
index 06178f7733..6ea67246b5 100644
--- a/spec/unit/config_spec.rb
+++ b/spec/unit/config_spec.rb
@@ -360,18 +360,12 @@ describe Chef::Config do
describe "Chef::Config[:user_home]" do
it "should set when HOME is provided" do
expected = to_platform("/home/kitten")
- allow(Chef::Config).to receive(:env).and_return({ 'HOME' => expected })
- expect(Chef::Config[:user_home]).to eq(expected)
- end
-
- it "should be set when only USERPROFILE is provided" do
- expected = to_platform("/users/kitten")
- allow(Chef::Config).to receive(:env).and_return({ 'USERPROFILE' => expected })
+ 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::Config).to receive(:env).and_return({})
+ allow(Chef::Util::PathHelper).to receive(:home).and_return(nil)
expect(Chef::Config[:user_home]).to eq(Dir.pwd)
end
end
diff --git a/spec/unit/cookbook/file_vendor_spec.rb b/spec/unit/cookbook/file_vendor_spec.rb
index 4fad7d5808..145541a63f 100644
--- a/spec/unit/cookbook/file_vendor_spec.rb
+++ b/spec/unit/cookbook/file_vendor_spec.rb
@@ -21,9 +21,6 @@ describe Chef::Cookbook::FileVendor do
let(:file_vendor_class) { Class.new(described_class) }
- # A manifest is a Hash of the format defined by Chef::CookbookVersion#manifest
- let(:manifest) { {:cookbook_name => "bob"} }
-
context "when configured to fetch files over http" do
let(:http) { double("Chef::REST") }
@@ -40,19 +37,42 @@ describe Chef::Cookbook::FileVendor do
expect(file_vendor_class.initialization_options).to eq(http)
end
- it "creates a RemoteFileVendor for a given manifest" do
- file_vendor = file_vendor_class.create_from_manifest(manifest)
- expect(file_vendor).to be_a_kind_of(Chef::Cookbook::RemoteFileVendor)
- expect(file_vendor.rest).to eq(http)
- expect(file_vendor.cookbook_name).to eq("bob")
+ context "with a manifest from a cookbook version" do
+
+ # A manifest is a Hash of the format defined by Chef::CookbookVersion#manifest
+ let(:manifest) { {:cookbook_name => "bob", :name => "bob-1.2.3"} }
+
+ it "creates a RemoteFileVendor for a given manifest" do
+ file_vendor = file_vendor_class.create_from_manifest(manifest)
+ expect(file_vendor).to be_a_kind_of(Chef::Cookbook::RemoteFileVendor)
+ expect(file_vendor.rest).to eq(http)
+ expect(file_vendor.cookbook_name).to eq("bob")
+ end
+
end
+ context "with a manifest from a cookbook artifact" do
+
+ # A manifest is a Hash of the format defined by Chef::CookbookVersion#manifest
+ let(:manifest) { {:name => "bob"} }
+
+ it "creates a RemoteFileVendor for a given manifest" do
+ file_vendor = file_vendor_class.create_from_manifest(manifest)
+ expect(file_vendor).to be_a_kind_of(Chef::Cookbook::RemoteFileVendor)
+ expect(file_vendor.rest).to eq(http)
+ expect(file_vendor.cookbook_name).to eq("bob")
+ end
+
+ end
end
context "when configured to load files from disk" do
let(:cookbook_path) { %w[/var/chef/cookbooks /var/chef/other_cookbooks] }
+ # A manifest is a Hash of the format defined by Chef::CookbookVersion#manifest
+ let(:manifest) { {:cookbook_name => "bob"} }
+
before do
file_vendor_class.fetch_from_disk(cookbook_path)
end
diff --git a/spec/unit/cookbook_manifest_spec.rb b/spec/unit/cookbook_manifest_spec.rb
index 938f72c743..f985942e09 100644
--- a/spec/unit/cookbook_manifest_spec.rb
+++ b/spec/unit/cookbook_manifest_spec.rb
@@ -24,6 +24,8 @@ describe Chef::CookbookManifest do
let(:version) { "1.2.3" }
+ let(:identifier) { "9e10455ce2b4a4e29424b7064b1d67a1a25c9d3b" }
+
let(:metadata) do
Chef::Cookbook::Metadata.new.tap do |m|
m.version(version)
@@ -35,6 +37,7 @@ describe Chef::CookbookManifest do
let(:cookbook_version) do
Chef::CookbookVersion.new("tatft", cookbook_root).tap do |c|
c.metadata = metadata
+ c.identifier = identifier
end
end
@@ -212,12 +215,26 @@ describe Chef::CookbookManifest do
let(:policy_mode) { true }
+ let(:cookbook_manifest_hash) { cookbook_manifest.to_hash }
+
+ it "sets the identifier in the manifest data" do
+ expect(cookbook_manifest_hash["identifier"]).to eq("9e10455ce2b4a4e29424b7064b1d67a1a25c9d3b")
+ end
+
+ it "sets the name to just the name" do
+ expect(cookbook_manifest_hash["name"]).to eq("tatft")
+ end
+
+ it "does not set a 'cookbook_name' field" do
+ expect(cookbook_manifest_hash).to_not have_key("cookbook_name")
+ end
+
it "gives the save URL" do
- expect(cookbook_manifest.save_url).to eq("cookbook_artifacts/tatft/1.2.3")
+ expect(cookbook_manifest.save_url).to eq("cookbook_artifacts/tatft/9e10455ce2b4a4e29424b7064b1d67a1a25c9d3b")
end
it "gives the force save URL" do
- expect(cookbook_manifest.force_save_url).to eq("cookbook_artifacts/tatft/1.2.3?force=true")
+ expect(cookbook_manifest.force_save_url).to eq("cookbook_artifacts/tatft/9e10455ce2b4a4e29424b7064b1d67a1a25c9d3b?force=true")
end
end
diff --git a/spec/unit/cookbook_uploader_spec.rb b/spec/unit/cookbook_uploader_spec.rb
index 152e5373f0..76727c18e2 100644
--- a/spec/unit/cookbook_uploader_spec.rb
+++ b/spec/unit/cookbook_uploader_spec.rb
@@ -25,11 +25,17 @@ describe Chef::CookbookUploader do
let(:cookbook_loader) do
loader = Chef::CookbookLoader.new(File.join(CHEF_SPEC_DATA, "cookbooks"))
loader.load_cookbooks
+ loader.cookbooks_by_name["apache2"].identifier = apache2_identifier
+ loader.cookbooks_by_name["java"].identifier = java_identifier
loader
end
+ let(:apache2_identifier) { "6644e6cb2ade90b8aff2ebb44728958fbc939ebf" }
+
let(:apache2_cookbook) { cookbook_loader.cookbooks_by_name["apache2"] }
+ let(:java_identifier) { "edd40c30c4e0ebb3658abde4620597597d2e9c17" }
+
let(:java_cookbook) { cookbook_loader.cookbooks_by_name["java"] }
let(:cookbooks_to_upload) { [apache2_cookbook, java_cookbook] }
@@ -175,7 +181,7 @@ describe Chef::CookbookUploader do
let(:policy_mode) { true }
def expected_save_url(cookbook)
- "cookbook_artifacts/#{cookbook.name}/#{cookbook.version}"
+ "cookbook_artifacts/#{cookbook.name}/#{cookbook.identifier}"
end
it "uploads all files in a sandbox transaction, then creates cookbooks on the server using cookbook_artifacts API" do
diff --git a/spec/unit/http/socketless_chef_zero_client_spec.rb b/spec/unit/http/socketless_chef_zero_client_spec.rb
new file mode 100644
index 0000000000..963cc9e8c4
--- /dev/null
+++ b/spec/unit/http/socketless_chef_zero_client_spec.rb
@@ -0,0 +1,174 @@
+#--
+# 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 'chef/http/socketless_chef_zero_client'
+
+describe Chef::HTTP::SocketlessChefZeroClient do
+
+ let(:relative_url) { "" }
+ let(:uri_str) { "chefzero://localhost:1/#{relative_url}" }
+ let(:uri) { URI(uri_str) }
+
+ subject(:zero_client) { Chef::HTTP::SocketlessChefZeroClient.new(uri) }
+
+ it "has a host" do
+ expect(zero_client.host).to eq("localhost")
+ end
+
+ it "has a port" do
+ expect(zero_client.port).to eq(1)
+ end
+
+ describe "converting requests to rack format" do
+
+ let(:expected_rack_req) do
+ {
+ "SCRIPT_NAME" => "",
+ "SERVER_NAME" => "localhost",
+ "REQUEST_METHOD" => method.to_s.upcase,
+ "PATH_INFO" => uri.path,
+ "QUERY_STRING" => uri.query,
+ "SERVER_PORT" => uri.port,
+ "HTTP_HOST" => "localhost:#{uri.port}",
+ "rack.url_scheme" => "chefzero",
+ }
+ end
+
+ context "when the request has no body" do
+
+ let(:method) { :GET }
+ let(:relative_url) { "clients" }
+ let(:headers) { { "Accept" => "application/json" } }
+ let(:body) { false }
+ let(:expected_body_str) { "" }
+
+ let(:rack_req) { zero_client.req_to_rack(method, uri, body, headers) }
+
+ it "creates a rack request env" do
+ # StringIO doesn't implement == in a way that we can compare, so we
+ # check rack.input individually and then iterate over everything else
+ expect(rack_req["rack.input"].string).to eq(expected_body_str)
+ expected_rack_req.each do |key, value|
+ expect(rack_req[key]).to eq(value)
+ end
+ end
+
+ end
+
+ context "when the request has a body" do
+
+ let(:method) { :PUT }
+ let(:relative_url) { "clients/foo" }
+ let(:headers) { { "Accept" => "application/json" } }
+ let(:body) { "bunch o' JSON" }
+ let(:expected_body_str) { "bunch o' JSON" }
+
+ let(:rack_req) { zero_client.req_to_rack(method, uri, body, headers) }
+
+ it "creates a rack request env" do
+ # StringIO doesn't implement == in a way that we can compare, so we
+ # check rack.input individually and then iterate over everything else
+ expect(rack_req["rack.input"].string).to eq(expected_body_str)
+ expected_rack_req.each do |key, value|
+ expect(rack_req[key]).to eq(value)
+ end
+ end
+
+ end
+
+ end
+
+ describe "converting responses to Net::HTTP objects" do
+
+ let(:net_http_response) { zero_client.to_net_http(code, headers, body) }
+
+ context "when the request was successful (2XX)" do
+
+ let(:code) { 200 }
+ let(:headers) { { "Content-Type" => "Application/JSON" } }
+ let(:body) { [ "bunch o' JSON" ] }
+
+ it "creates a Net::HTTP success response object" do
+ expect(net_http_response).to be_a_kind_of(Net::HTTPOK)
+ expect(net_http_response.read_body).to eq("bunch o' JSON")
+ expect(net_http_response["content-type"]).to eq("Application/JSON")
+ end
+
+ it "does not fail when calling read_body with a block" do
+ expect(net_http_response.read_body {|chunk| chunk }).to eq("bunch o' JSON")
+ end
+
+ end
+
+ context "when the requested object doesn't exist (404)" do
+
+ let(:code) { 404 }
+ let(:headers) { { "Content-Type" => "Application/JSON" } }
+ let(:body) { [ "nope" ] }
+
+ it "creates a Net::HTTPNotFound response object" do
+ expect(net_http_response).to be_a_kind_of(Net::HTTPNotFound)
+ end
+ end
+
+ end
+
+ describe "request-response round trip" do
+
+ let(:method) { :GET }
+ let(:relative_url) { "clients" }
+ let(:headers) { { "Accept" => "application/json" } }
+ let(:body) { false }
+
+ let(:expected_rack_req) do
+ {
+ "SCRIPT_NAME" => "",
+ "SERVER_NAME" => "localhost",
+ "REQUEST_METHOD" => method.to_s.upcase,
+ "PATH_INFO" => uri.path,
+ "QUERY_STRING" => uri.query,
+ "SERVER_PORT" => uri.port,
+ "HTTP_HOST" => "localhost:#{uri.port}",
+ "rack.url_scheme" => "chefzero",
+ "rack.input" => an_instance_of(StringIO),
+ }
+ end
+
+
+ let(:response_code) { 200 }
+ let(:response_headers) { { "Content-Type" => "Application/JSON" } }
+ let(:response_body) { [ "bunch o' JSON" ] }
+
+ let(:rack_response) { [ response_code, response_headers, response_body ] }
+
+ let(:response) { zero_client.request(method, uri, body, headers) }
+
+ before do
+ expect(ChefZero::SocketlessServerMap).to receive(:request).with(1, expected_rack_req).and_return(rack_response)
+ end
+
+ it "makes a rack request to Chef Zero and returns the response as a Net::HTTP object" do
+ _client, net_http_response = response
+ expect(net_http_response).to be_a_kind_of(Net::HTTPOK)
+ expect(net_http_response.code).to eq("200")
+ expect(net_http_response.body).to eq("bunch o' JSON")
+ end
+
+ end
+
+end
diff --git a/spec/unit/http_spec.rb b/spec/unit/http_spec.rb
index ddfc56583d..4d851df951 100644
--- a/spec/unit/http_spec.rb
+++ b/spec/unit/http_spec.rb
@@ -20,6 +20,7 @@ require 'spec_helper'
require 'chef/http'
require 'chef/http/basic_client'
+require 'chef/http/socketless_chef_zero_client'
class Chef::HTTP
public :create_url
@@ -27,6 +28,19 @@ end
describe Chef::HTTP do
+ context "when given a chefzero:// URL" do
+
+ let(:uri) { URI("chefzero://localhost:1") }
+
+ subject(:http) { Chef::HTTP.new(uri) }
+
+ it "uses the SocketlessChefZeroClient to handle requests" do
+ expect(http.http_client).to be_a_kind_of(Chef::HTTP::SocketlessChefZeroClient)
+ expect(http.http_client.url).to eq(uri)
+ end
+
+ end
+
describe "create_url" do
it 'should return a correctly formatted url 1/3 CHEF-5261' do
diff --git a/spec/unit/knife/bootstrap_spec.rb b/spec/unit/knife/bootstrap_spec.rb
index 848af11db5..f1ca510ed3 100644
--- a/spec/unit/knife/bootstrap_spec.rb
+++ b/spec/unit/knife/bootstrap_spec.rb
@@ -115,7 +115,7 @@ describe Chef::Knife::Bootstrap do
end
def configure_env_home
- ENV['HOME'] = "/env/home"
+ allow(Chef::Util::PathHelper).to receive(:home).with(".chef", "bootstrap", "example.erb").and_yield(env_home_template_path)
end
def configure_gem_files
@@ -123,15 +123,9 @@ describe Chef::Knife::Bootstrap do
end
before(:each) do
- @original_home = ENV['HOME']
- ENV['HOME'] = nil
expect(File).to receive(:exists?).with(bootstrap_template).and_return(false)
end
- after(:each) do
- ENV['HOME'] = @original_home
- end
-
context "when file is available everywhere" do
before do
configure_chef_config_dir
@@ -161,7 +155,7 @@ describe Chef::Knife::Bootstrap do
end
end
- context "when file is available in ENV['HOME']" do
+ context "when file is available in home directory" do
before do
configure_chef_config_dir
configure_env_home
@@ -180,7 +174,25 @@ describe Chef::Knife::Bootstrap do
context "when file is available in Gem files" do
before do
configure_chef_config_dir
+ configure_env_home
+ configure_gem_files
+
+ expect(File).to receive(:exists?).with(builtin_template_path).and_return(false)
+ expect(File).to receive(:exists?).with(chef_config_dir_template_path).and_return(false)
+ expect(File).to receive(:exists?).with(env_home_template_path).and_return(false)
+ expect(File).to receive(:exists?).with(gem_files_template_path).and_return(true)
+ end
+
+ it "should load the template from Gem files" do
+ expect(knife.find_template).to eq(gem_files_template_path)
+ end
+ end
+
+ context "when file is available in Gem files and home dir doesn't exist" do
+ before do
+ configure_chef_config_dir
configure_gem_files
+ allow(Chef::Util::PathHelper).to receive(:home).with(".chef", "bootstrap", "example.erb").and_return(nil)
expect(File).to receive(:exists?).with(builtin_template_path).and_return(false)
expect(File).to receive(:exists?).with(chef_config_dir_template_path).and_return(false)
diff --git a/spec/unit/knife/core/subcommand_loader_spec.rb b/spec/unit/knife/core/subcommand_loader_spec.rb
index df42cff2ea..7f9308b28a 100644
--- a/spec/unit/knife/core/subcommand_loader_spec.rb
+++ b/spec/unit/knife/core/subcommand_loader_spec.rb
@@ -19,23 +19,29 @@
require 'spec_helper'
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 }
- @home = File.join(CHEF_SPEC_DATA, 'knife-home')
- @env = {'HOME' => @home}
- @loader = Chef::Knife::SubcommandLoader.new(File.join(CHEF_SPEC_DATA, 'knife-site-subcommands'), @env)
+ Chef::Util::PathHelper.class_variable_set(:@@home_dir, home)
+ end
+
+ after do
+ Chef::Util::PathHelper.class_variable_set(:@@home_dir, nil)
end
it "builds a list of the core subcommand file require paths" do
- expect(@loader.subcommand_files).not_to be_empty
- @loader.subcommand_files.each do |require_path|
+ expect(loader.subcommand_files).not_to be_empty
+ loader.subcommand_files.each do |require_path|
expect(require_path).to match(/chef\/knife\/.*|plugins\/knife\/.*/)
end
end
it "finds files installed via rubygems" do
- expect(@loader.find_subcommands_via_rubygems).to include('chef/knife/node_create')
- @loader.find_subcommands_via_rubygems.each {|rel_path, abs_path| expect(abs_path).to match(%r[chef/knife/.+])}
+ expect(loader.find_subcommands_via_rubygems).to include('chef/knife/node_create')
+ loader.find_subcommands_via_rubygems.each {|rel_path, abs_path| expect(abs_path).to match(%r[chef/knife/.+])}
end
it "finds files from latest version of installed gems" do
@@ -54,23 +60,23 @@ describe Chef::Knife::SubcommandLoader do
expect(gems[0]).to receive(:full_gem_path).and_return('/usr/lib/ruby/gems/knife-ec2-0.5.12')
expect(Dir).to receive(:[]).with('/usr/lib/ruby/gems/knife-ec2-0.5.12/lib/chef/knife/*.rb').and_return(gem_files)
end
- expect(@loader).to receive(:find_subcommands_via_dirglob).and_return({})
- expect(@loader.find_subcommands_via_rubygems.values.select { |file| file =~ /knife-ec2/ }.sort).to eq(gem_files)
+ expect(loader).to receive(:find_subcommands_via_dirglob).and_return({})
+ expect(loader.find_subcommands_via_rubygems.values.select { |file| file =~ /knife-ec2/ }.sort).to eq(gem_files)
end
it "finds files using a dirglob when rubygems is not available" do
- expect(@loader.find_subcommands_via_dirglob).to include('chef/knife/node_create')
- @loader.find_subcommands_via_dirglob.each {|rel_path, abs_path| expect(abs_path).to match(%r[chef/knife/.+])}
+ expect(loader.find_subcommands_via_dirglob).to include('chef/knife/node_create')
+ loader.find_subcommands_via_dirglob.each {|rel_path, abs_path| expect(abs_path).to match(%r[chef/knife/.+])}
end
it "finds user-specific subcommands in the user's ~/.chef directory" do
- expected_command = File.join(@home, '.chef', 'plugins', 'knife', 'example_home_subcommand.rb')
- expect(@loader.site_subcommands).to include(expected_command)
+ expected_command = File.join(home, '.chef', 'plugins', 'knife', 'example_home_subcommand.rb')
+ expect(loader.site_subcommands).to include(expected_command)
end
it "finds repo specific subcommands by searching for a .chef directory" do
expected_command = File.join(CHEF_SPEC_DATA, 'knife-site-subcommands', 'plugins', 'knife', 'example_subcommand.rb')
- expect(@loader.site_subcommands).to include(expected_command)
+ expect(loader.site_subcommands).to include(expected_command)
end
# https://github.com/opscode/chef-dk/issues/227
@@ -137,25 +143,19 @@ describe Chef::Knife::SubcommandLoader do
end
before do
- expect(@loader).to receive(:find_files_latest_gems).with("chef/knife/*.rb").and_return(all_found_commands)
- expect(@loader).to receive(:find_subcommands_via_dirglob).and_return({})
+ expect(loader).to receive(:find_files_latest_gems).with("chef/knife/*.rb").and_return(all_found_commands)
+ expect(loader).to receive(:find_subcommands_via_dirglob).and_return({})
end
it "ignores commands from the non-matching gem install" do
- expect(@loader.find_subcommands_via_rubygems.values).to eq(expected_valid_commands)
+ expect(loader.find_subcommands_via_rubygems.values).to eq(expected_valid_commands)
end
end
describe "finding 3rd party plugins" do
- let(:env_home) { "/home/alice" }
- let(:manifest_path) { env_home + "/.chef/plugin_manifest.json" }
-
- before do
- env_dup = ENV.to_hash
- allow(ENV).to receive(:[]) { |key| env_dup[key] }
- allow(ENV).to receive(:[]).with("HOME").and_return(env_home)
- end
+ let(:home) { "/home/alice" }
+ let(:manifest_path) { home + "/.chef/plugin_manifest.json" }
context "when there is not a ~/.chef/plugin_manifest.json file" do
before do
@@ -168,14 +168,14 @@ describe Chef::Knife::SubcommandLoader do
else
expect(Gem.source_index).to receive(:latest_specs).and_call_original
end
- @loader.subcommand_files.each do |require_path|
+ loader.subcommand_files.each do |require_path|
expect(require_path).to match(/chef\/knife\/.*|plugins\/knife\/.*/)
end
end
context "and HOME environment variable is not set" do
before do
- allow(ENV).to receive(:[]).with("HOME").and_return(nil)
+ allow(Chef::Util::PathHelper).to receive(:home).and_return(nil)
end
it "searches rubygems for plugins" do
@@ -184,7 +184,7 @@ describe Chef::Knife::SubcommandLoader do
else
expect(Gem.source_index).to receive(:latest_specs).and_call_original
end
- @loader.subcommand_files.each do |require_path|
+ loader.subcommand_files.each do |require_path|
expect(require_path).to match(/chef\/knife\/.*|plugins\/knife\/.*/)
end
end
@@ -215,7 +215,7 @@ describe Chef::Knife::SubcommandLoader do
it "uses paths from the manifest instead of searching gems" do
expect(Gem::Specification).not_to receive(:latest_specs).and_call_original
- expect(@loader.subcommand_files).to include(ec2_server_create_plugin)
+ expect(loader.subcommand_files).to include(ec2_server_create_plugin)
end
end
diff --git a/spec/unit/knife/ssh_spec.rb b/spec/unit/knife/ssh_spec.rb
index 501b02c933..a838a21edc 100644
--- a/spec/unit/knife/ssh_spec.rb
+++ b/spec/unit/knife/ssh_spec.rb
@@ -96,6 +96,24 @@ describe Chef::Knife::Ssh do
should_return_specified_attributes
end
+ context "when cloud hostnames are available but empty" do
+ before do
+ @node_foo.automatic_attrs[:cloud][:public_hostname] = ''
+ @node_bar.automatic_attrs[:cloud][:public_hostname] = ''
+ end
+
+ it "returns an array of fqdns" do
+ configure_query([@node_foo, @node_bar])
+ expect(@knife).to receive(:session_from_list).with([
+ ['foo.example.org', nil],
+ ['bar.example.org', nil]
+ ])
+ @knife.configure_session
+ end
+
+ should_return_specified_attributes
+ end
+
it "should raise an error if no host are found" do
configure_query([ ])
expect(@knife.ui).to receive(:fatal)
diff --git a/spec/unit/knife/status_spec.rb b/spec/unit/knife/status_spec.rb
index 2522bc61b1..ee44f3b3fd 100644
--- a/spec/unit/knife/status_spec.rb
+++ b/spec/unit/knife/status_spec.rb
@@ -24,15 +24,81 @@ describe Chef::Knife::Status do
n.automatic_attrs["fqdn"] = "foobar"
n.automatic_attrs["ohai_time"] = 1343845969
end
- query = double("Chef::Search::Query")
- allow(query).to receive(:search).and_yield(node)
- allow(Chef::Search::Query).to receive(:new).and_return(query)
+ allow(Time).to receive(:now).and_return(Time.at(1428573420))
+ @query = double("Chef::Search::Query")
+ allow(@query).to receive(:search).and_yield(node)
+ allow(Chef::Search::Query).to receive(:new).and_return(@query)
@knife = Chef::Knife::Status.new
@stdout = StringIO.new
allow(@knife.ui).to receive(:stdout).and_return(@stdout)
end
describe "run" do
+ let(:opts) {{filter_result:
+ { name: ["name"], ipaddress: ["ipaddress"], ohai_time: ["ohai_time"],
+ ec2: ["ec2"], run_list: ["run_list"], platform: ["platform"],
+ platform_version: ["platform_version"], chef_environment: ["chef_environment"]}}}
+
+ it "should default to searching for everything" do
+ expect(@query).to receive(:search).with(:node, "*:*", opts)
+ @knife.run
+ end
+
+ it "should filter healthy nodes" do
+ @knife.config[:hide_healthy] = true
+ expect(@query).to receive(:search).with(:node, "NOT ohai_time:[1428569820 TO 1428573420]", opts)
+ @knife.run
+ end
+
+ it "should filter by environment" do
+ @knife.config[:environment] = "production"
+ expect(@query).to receive(:search).with(:node, "chef_environment:production", opts)
+ @knife.run
+ end
+
+ it "should filter by environment and health" do
+ @knife.config[:environment] = "production"
+ @knife.config[:hide_healthy] = true
+ expect(@query).to receive(:search).with(:node, "chef_environment:production NOT ohai_time:[1428569820 TO 1428573420]", opts)
+ @knife.run
+ end
+
+ it "should not use partial search with long output" do
+ @knife.config[:long_output] = true
+ expect(@query).to receive(:search).with(:node, "*:*", {})
+ @knife.run
+ end
+
+ context "with a custom query" do
+ before :each do
+ @knife.instance_variable_set(:@name_args, ["name:my_custom_name"])
+ end
+
+ it "should allow a custom query to be specified" do
+ expect(@query).to receive(:search).with(:node, "name:my_custom_name", opts)
+ @knife.run
+ end
+
+ it "should filter healthy nodes" do
+ @knife.config[:hide_healthy] = true
+ expect(@query).to receive(:search).with(:node, "name:my_custom_name NOT ohai_time:[1428569820 TO 1428573420]", opts)
+ @knife.run
+ end
+
+ it "should filter by environment" do
+ @knife.config[:environment] = "production"
+ expect(@query).to receive(:search).with(:node, "name:my_custom_name AND chef_environment:production", opts)
+ @knife.run
+ end
+
+ it "should filter by environment and health" do
+ @knife.config[:environment] = "production"
+ @knife.config[:hide_healthy] = true
+ expect(@query).to receive(:search).with(:node, "name:my_custom_name AND chef_environment:production NOT ohai_time:[1428569820 TO 1428573420]", opts)
+ @knife.run
+ end
+ end
+
it "should not colorize output unless it's writing to a tty" do
@knife.run
expect(@stdout.string.match(/foobar/)).not_to be_nil
diff --git a/spec/unit/knife_spec.rb b/spec/unit/knife_spec.rb
index 2ccf8493ad..b748232081 100644
--- a/spec/unit/knife_spec.rb
+++ b/spec/unit/knife_spec.rb
@@ -271,6 +271,11 @@ describe Chef::Knife do
expect(knife_command.config[:opt_with_default]).to eq("from-cli")
end
+ it "merges `listen` config to Chef::Config" do
+ Chef::Knife.run(%w[test yourself --no-listen], Chef::Application::Knife.options)
+ expect(Chef::Config[:listen]).to be(false)
+ end
+
context "verbosity is greater than zero" do
let(:fake_config) { "/does/not/exist/knife.rb" }
diff --git a/spec/unit/mixin/params_validate_spec.rb b/spec/unit/mixin/params_validate_spec.rb
index 1b61f9b238..85e1c1abab 100644
--- a/spec/unit/mixin/params_validate_spec.rb
+++ b/spec/unit/mixin/params_validate_spec.rb
@@ -339,83 +339,69 @@ describe Chef::Mixin::ParamsValidate do
end.to raise_error(Chef::Exceptions::ValidationFailed)
end
- def self.test_set_or_return_method(method)
- # caller is responsible for passing in the right arg to get 'return' behavior
- return_arg = method == :nillable_set_or_return ? TinyClass::NULL_ARG : nil
-
- it "#{method} should set and return a value, then return the same value" do
- value = "meow"
- expect(@vo.send(method,:test, value, {}).object_id).to eq(value.object_id)
- expect(@vo.send(method,:test, return_arg, {}).object_id).to eq(value.object_id)
- end
-
- it "#{method} should set and return a default value when the argument is nil, then return the same value" do
- value = "meow"
- expect(@vo.send(method,:test, return_arg, { :default => value }).object_id).to eq(value.object_id)
- expect(@vo.send(method,:test, return_arg, {}).object_id).to eq(value.object_id)
- end
-
- it "#{method} should raise an ArgumentError when argument is nil and required is true" do
- expect {
- @vo.send(method,:test, return_arg, { :required => true })
- }.to raise_error(ArgumentError)
- end
-
- it "#{method} should not raise an error when argument is nil and required is false" do
- expect {
- @vo.send(method,:test, return_arg, { :required => false })
- }.not_to raise_error
- end
-
- it "#{method} should set and return @name, then return @name for foo when argument is nil" do
- value = "meow"
- expect(@vo.send(method,:name, value, { }).object_id).to eq(value.object_id)
- expect(@vo.send(method,:foo, return_arg, { :name_attribute => true }).object_id).to eq(value.object_id)
- end
-
- it "#{method} should allow DelayedEvaluator instance to be set for value regardless of restriction" do
- value = Chef::DelayedEvaluator.new{ 'test' }
- @vo.send(method,:test, value, {:kind_of => Numeric})
- end
-
- it "#{method} should raise an error when delayed evaluated attribute is not valid" do
- value = Chef::DelayedEvaluator.new{ 'test' }
- @vo.send(method,:test, value, {:kind_of => Numeric})
- expect do
- @vo.send(method,:test, return_arg, {:kind_of => Numeric})
- end.to raise_error(Chef::Exceptions::ValidationFailed)
- end
-
- it "#{method} should create DelayedEvaluator instance when #lazy is used" do
- @vo.send(method,:delayed, @vo.lazy{ 'test' }, {})
- expect(@vo.instance_variable_get(:@delayed)).to be_a(Chef::DelayedEvaluator)
- end
-
- it "#{method} should execute block on each call when DelayedEvaluator" do
- value = 'fubar'
- @vo.send(method,:test, @vo.lazy{ value }, {})
- expect(@vo.send(method,:test, return_arg, {})).to eq('fubar')
- value = 'foobar'
- expect(@vo.send(method,:test, return_arg, {})).to eq('foobar')
- value = 'fauxbar'
- expect(@vo.send(method,:test, return_arg, {})).to eq('fauxbar')
- end
-
- it "#{method} should not evaluate non DelayedEvaluator instances" do
- value = lambda{ 'test' }
- @vo.send(method,:test, value, {})
- expect(@vo.send(method,:test, return_arg, {}).object_id).to eq(value.object_id)
- expect(@vo.send(method,:test, return_arg, {})).to be_a(Proc)
- end
+ it "should set and return a value, then return the same value" do
+ value = "meow"
+ expect(@vo.set_or_return(:test, value, {}).object_id).to eq(value.object_id)
+ expect(@vo.set_or_return(:test, nil, {}).object_id).to eq(value.object_id)
end
- test_set_or_return_method(:set_or_return)
- test_set_or_return_method(:nillable_set_or_return)
+ it "should set and return a default value when the argument is nil, then return the same value" do
+ value = "meow"
+ expect(@vo.set_or_return(:test, nil, { :default => value }).object_id).to eq(value.object_id)
+ expect(@vo.set_or_return(:test, nil, {}).object_id).to eq(value.object_id)
+ end
+
+ it "should raise an ArgumentError when argument is nil and required is true" do
+ expect {
+ @vo.set_or_return(:test, nil, { :required => true })
+ }.to raise_error(ArgumentError)
+ end
+
+ it "should not raise an error when argument is nil and required is false" do
+ expect {
+ @vo.set_or_return(:test, nil, { :required => false })
+ }.not_to raise_error
+ end
+
+ it "should set and return @name, then return @name for foo when argument is nil" do
+ value = "meow"
+ expect(@vo.set_or_return(:name, value, { }).object_id).to eq(value.object_id)
+ expect(@vo.set_or_return(:foo, nil, { :name_attribute => true }).object_id).to eq(value.object_id)
+ end
- it "nillable_set_or_return supports nilling values" do
- expect(@vo.nillable_set_or_return(:test, "meow", {})).to eq("meow")
- expect(@vo.nillable_set_or_return(:test, TinyClass::NULL_ARG, {})).to eq("meow")
- expect(@vo.nillable_set_or_return(:test, nil, {})).to be_nil
- expect(@vo.nillable_set_or_return(:test, TinyClass::NULL_ARG, {})).to be_nil
+ it "should allow DelayedEvaluator instance to be set for value regardless of restriction" do
+ value = Chef::DelayedEvaluator.new{ 'test' }
+ @vo.set_or_return(:test, value, {:kind_of => Numeric})
end
+
+ it "should raise an error when delayed evaluated attribute is not valid" do
+ value = Chef::DelayedEvaluator.new{ 'test' }
+ @vo.set_or_return(:test, value, {:kind_of => Numeric})
+ expect do
+ @vo.set_or_return(:test, nil, {:kind_of => Numeric})
+ end.to raise_error(Chef::Exceptions::ValidationFailed)
+ end
+
+ it "should create DelayedEvaluator instance when #lazy is used" do
+ @vo.set_or_return(:delayed, @vo.lazy{ 'test' }, {})
+ expect(@vo.instance_variable_get(:@delayed)).to be_a(Chef::DelayedEvaluator)
+ end
+
+ it "should execute block on each call when DelayedEvaluator" do
+ value = 'fubar'
+ @vo.set_or_return(:test, @vo.lazy{ value }, {})
+ expect(@vo.set_or_return(:test, nil, {})).to eq('fubar')
+ value = 'foobar'
+ expect(@vo.set_or_return(:test, nil, {})).to eq('foobar')
+ value = 'fauxbar'
+ expect(@vo.set_or_return(:test, nil, {})).to eq('fauxbar')
+ end
+
+ it "should not evaluate non DelayedEvaluator instances" do
+ value = lambda{ 'test' }
+ @vo.set_or_return(:test, value, {})
+ expect(@vo.set_or_return(:test, nil, {}).object_id).to eq(value.object_id)
+ expect(@vo.set_or_return(:test, nil, {})).to be_a(Proc)
+ end
+
end
diff --git a/spec/unit/mixin/powershell_type_coercions_spec.rb b/spec/unit/mixin/powershell_type_coercions_spec.rb
new file mode 100644
index 0000000000..988c3926c1
--- /dev/null
+++ b/spec/unit/mixin/powershell_type_coercions_spec.rb
@@ -0,0 +1,72 @@
+#
+# 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/powershell_type_coercions'
+require 'base64'
+
+class Chef::PSTypeTester
+ include Chef::Mixin::PowershellTypeCoercions
+end
+
+describe Chef::Mixin::PowershellTypeCoercions do
+ let (:test_class) { Chef::PSTypeTester.new }
+
+ describe '#translate_type' do
+ it 'should single quote a string' do
+ expect(test_class.translate_type('foo')).to eq("'foo'")
+ end
+
+ ["'", '"', '#', '`'].each do |c|
+ it "should base64 encode a string that contains #{c}" do
+ expect(test_class.translate_type("#{c}")).to match(Base64.strict_encode64(c))
+ end
+ end
+
+ it 'should not quote an integer' do
+ expect(test_class.translate_type(123)).to eq('123')
+ end
+
+ it 'should not quote a floating point number' do
+ expect(test_class.translate_type(123.4)).to eq('123.4')
+ end
+
+ it 'should return $false when an instance of FalseClass is provided' do
+ expect(test_class.translate_type(false)).to eq('$false')
+ end
+
+ it 'should return $true when an instance of TrueClass is provided' do
+ expect(test_class.translate_type(true)).to eq('$true')
+ end
+
+ it 'should translate all members of a hash and wrap them in @{} separated by ;' do
+ expect(test_class.translate_type({"a" => 1, "b" => 1.2, "c" => false, "d" => true
+ })).to eq("@{a=1;b=1.2;c=$false;d=$true}")
+ end
+
+ it 'should translat all members of an array and them by a ,' do
+ expect(test_class.translate_type([true, false])).to eq('@($true,$false)')
+ end
+
+ it 'should fall back :to_psobject if we have not defined at explicit rule' do
+ ps_obj = double("PSObject")
+ expect(ps_obj).to receive(:to_psobject).and_return('$true')
+ expect(test_class.translate_type(ps_obj)).to eq('($true)')
+ end
+ end
+end
diff --git a/spec/unit/platform/query_helpers_spec.rb b/spec/unit/platform/query_helpers_spec.rb
index 7aafc287ea..1dbd07a021 100644
--- a/spec/unit/platform/query_helpers_spec.rb
+++ b/spec/unit/platform/query_helpers_spec.rb
@@ -53,3 +53,25 @@ describe 'Chef::Platform#supports_dsc?' do
end
end
end
+
+describe 'Chef::Platform#supports_dsc_invoke_resource?' do
+ it 'returns false if powershell is not present' do
+ node = Chef::Node.new
+ expect(Chef::Platform.supports_dsc_invoke_resource?(node)).to be_falsey
+ end
+
+ ['1.0', '2.0', '3.0', '4.0', '5.0.10017.9'].each do |version|
+ it "returns false for Powershell #{version}" do
+ node = Chef::Node.new
+ node.automatic[:languages][:powershell][:version] = version
+ expect(Chef::Platform.supports_dsc_invoke_resource?(node)).to be_falsey
+ end
+ end
+
+ it "returns true for Powershell 5.0.10018.0" do
+ node = Chef::Node.new
+ node.automatic[:languages][:powershell][:version] = "5.0.10018.0"
+ expect(Chef::Platform.supports_dsc_invoke_resource?(node)).to be_truthy
+ end
+end
+
diff --git a/spec/unit/policy_builder/policyfile_spec.rb b/spec/unit/policy_builder/policyfile_spec.rb
index 8b6e928a46..e4f7388a1c 100644
--- a/spec/unit/policy_builder/policyfile_spec.rb
+++ b/spec/unit/policy_builder/policyfile_spec.rb
@@ -256,7 +256,7 @@ describe Chef::PolicyBuilder::Policyfile do
context "and policy_name and policy_group are configured" do
- let(:policy_relative_url) { "policies/policy-stage/example" }
+ let(:policy_relative_url) { "policy_groups/policy-stage/policies/example" }
before do
expect(http_api).to receive(:get).with(policy_relative_url).and_return(parsed_policyfile_json)
@@ -386,6 +386,9 @@ describe Chef::PolicyBuilder::Policyfile do
describe "fetching the desired cookbook set" 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") }
@@ -396,9 +399,12 @@ describe Chef::PolicyBuilder::Policyfile do
let(:example1_xyz_version) { example1_lock_data["dotted_decimal_identifier"] }
let(:example2_xyz_version) { example2_lock_data["dotted_decimal_identifier"] }
+ let(:example1_identifier) { example1_lock_data["identifier"] }
+ let(:example2_identifier) { example2_lock_data["identifier"] }
+
let(:cookbook_synchronizer) { double("Chef::CookbookSynchronizer") }
- shared_examples_for "fetching cookbooks" do
+ shared_examples "fetching cookbooks when they don't exist" do
context "and a cookbook is missing" do
let(:error404) { Net::HTTPServerException.new("404 message", :body) }
@@ -418,7 +424,9 @@ describe Chef::PolicyBuilder::Policyfile do
end
end
+ end
+ shared_examples_for "fetching cookbooks when they exist" do
context "and the cookbooks can be fetched" do
before do
expect(Chef::Node).to receive(:find_or_create).with(node_name).and_return(node)
@@ -426,11 +434,6 @@ describe Chef::PolicyBuilder::Policyfile do
policy_builder.load_node
policy_builder.build_node
- expect(http_api).to receive(:get).with(cookbook1_url).
- and_return(example1_cookbook_object)
- expect(http_api).to receive(:get).with(cookbook2_url).
- and_return(example2_cookbook_object)
-
allow(Chef::CookbookSynchronizer).to receive(:new).
with(expected_cookbook_hash, events).
and_return(cookbook_synchronizer)
@@ -457,11 +460,23 @@ describe Chef::PolicyBuilder::Policyfile do
end # shared_examples_for "fetching cookbooks"
context "when using compatibility mode (policy_document_native_api == false)" do
- include_examples "fetching cookbooks" do
+ let(:cookbook1_url) { "cookbooks/example1/#{example1_xyz_version}" }
+ let(:cookbook2_url) { "cookbooks/example2/#{example2_xyz_version}" }
- let(:cookbook1_url) { "cookbooks/example1/#{example1_xyz_version}" }
- let(:cookbook2_url) { "cookbooks/example2/#{example2_xyz_version}" }
+ context "when the cookbooks don't exist on the server" do
+ include_examples "fetching cookbooks when they don't exist"
+ end
+
+ context "when the cookbooks exist on the server" do
+
+ before do
+ expect(http_api).to receive(:get).with(cookbook1_url).
+ and_return(example1_cookbook_object)
+ expect(http_api).to receive(:get).with(cookbook2_url).
+ and_return(example2_cookbook_object)
+ end
+ include_examples "fetching cookbooks when they exist"
end
end
@@ -474,13 +489,33 @@ describe Chef::PolicyBuilder::Policyfile do
Chef::Config[:policy_name] = "example"
end
- include_examples "fetching cookbooks" do
+ let(:cookbook1_url) { "cookbook_artifacts/example1/#{example1_identifier}" }
+ let(:cookbook2_url) { "cookbook_artifacts/example2/#{example2_identifier}" }
+
+ context "when the cookbooks don't exist on the server" do
+ include_examples "fetching cookbooks when they don't exist"
+ end
+
- let(:cookbook1_url) { "cookbook_artifacts/example1/#{example1_xyz_version}" }
- let(:cookbook2_url) { "cookbook_artifacts/example2/#{example2_xyz_version}" }
+ context "when the cookbooks exist on the server" do
+
+ before do
+ expect(http_api).to receive(:get).with(cookbook1_url).
+ and_return(example1_cookbook_data)
+ expect(http_api).to receive(:get).with(cookbook2_url).
+ and_return(example2_cookbook_data)
+
+ expect(Chef::CookbookVersion).to receive(:from_cb_artifact_data).with(example1_cookbook_data).
+ and_return(example1_cookbook_object)
+ expect(Chef::CookbookVersion).to receive(:from_cb_artifact_data).with(example2_cookbook_data).
+ and_return(example2_cookbook_object)
+ end
+
+ include_examples "fetching cookbooks when they exist"
end
+
end
end
diff --git a/spec/unit/provider/dsc_resource_spec.rb b/spec/unit/provider/dsc_resource_spec.rb
new file mode 100644
index 0000000000..0a6c22bdcf
--- /dev/null
+++ b/spec/unit/provider/dsc_resource_spec.rb
@@ -0,0 +1,84 @@
+#
+# Author:: Jay Mundrawala (<jdm@chef.io>)
+#
+# 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'
+require 'spec_helper'
+
+describe Chef::Provider::DscResource do
+ let (:events) { Chef::EventDispatch::Dispatcher.new }
+ let (:run_context) { Chef::RunContext.new(node, {}, events) }
+ let (:resource) { Chef::Resource::DscResource.new("dscresource", run_context) }
+ let (:provider) do
+ Chef::Provider::DscResource.new(resource, run_context)
+ end
+
+ context 'when Powershell does not support Invoke-DscResource' do
+ let (:node) {
+ node = Chef::Node.new
+ node.automatic[:languages][:powershell][:version] = '4.0'
+ node
+ }
+
+ it 'raises a NoProviderAvailable exception' do
+ expect(provider).not_to receive(:meta_configuration)
+ expect{provider.run_action(:run)}.to raise_error(
+ Chef::Exceptions::NoProviderAvailable, /5\.0\.10018\.0/)
+ end
+ end
+
+ context 'when Powershell supports Invoke-DscResource' do
+ let (:node) {
+ node = Chef::Node.new
+ node.automatic[:languages][:powershell][:version] = '5.0.10018.0'
+ node
+ }
+
+ context 'when RefreshMode is not set to Disabled' do
+ let (:meta_configuration) { {'RefreshMode' => 'AnythingElse'}}
+
+ it 'raises an exception' do
+ expect(provider).to receive(:meta_configuration).and_return(
+ meta_configuration)
+ expect { provider.run_action(:run) }.to raise_error(
+ Chef::Exceptions::NoProviderAvailable, /Disabled/)
+ end
+ end
+
+ context 'when RefreshMode is set to Disabled' do
+ let (:meta_configuration) { {'RefreshMode' => 'Disabled'}}
+
+ it 'does not update the resource if it is up to date' do
+ expect(provider).to receive(:meta_configuration).and_return(
+ meta_configuration)
+ expect(provider).to receive(:test_resource).and_return(true)
+ provider.run_action(:run)
+ expect(resource).not_to be_updated
+ end
+
+ it 'converges the resource if it is not up to date' do
+ expect(provider).to receive(:meta_configuration).and_return(
+ meta_configuration)
+ expect(provider).to receive(:test_resource).and_return(false)
+ expect(provider).to receive(:set_resource)
+ provider.run_action(:run)
+ expect(resource).to be_updated
+ end
+ end
+ end
+end
diff --git a/spec/unit/provider/package/openbsd_spec.rb b/spec/unit/provider/package/openbsd_spec.rb
index ee9c9e89fb..b0cdb9969d 100644
--- a/spec/unit/provider/package/openbsd_spec.rb
+++ b/spec/unit/provider/package/openbsd_spec.rb
@@ -21,28 +21,116 @@ require 'ostruct'
describe Chef::Provider::Package::Openbsd do
+ let(:node) do
+ node = Chef::Node.new
+ node.default['kernel'] = {'name' => 'OpenBSD', 'release' => '5.5', 'machine' => 'amd64'}
+ node
+ end
+
+ let (:provider) do
+ events = Chef::EventDispatch::Dispatcher.new
+ run_context = Chef::RunContext.new(node, {}, events)
+ Chef::Provider::Package::Openbsd.new(new_resource, run_context)
+ end
+
+ let(:new_resource) { Chef::Resource::Package.new(name)}
+
before(:each) do
- @node = Chef::Node.new
- @node.default['kernel'] = {'name' => 'OpenBSD', 'release' => '5.5', 'machine' => 'amd64'}
- @events = Chef::EventDispatch::Dispatcher.new
- @run_context = Chef::RunContext.new(@node, {}, @events)
ENV['PKG_PATH'] = nil
end
describe "install a package" do
- before do
- @name = 'ihavetoes'
- @new_resource = Chef::Resource::Package.new(@name)
- @current_resource = Chef::Resource::Package.new(@name)
- @provider = Chef::Provider::Package::Openbsd.new(@new_resource, @run_context)
- @provider.current_resource = @current_resource
- end
- it "should run the installation command" do
- expect(@provider).to receive(:shell_out!).with(
- "pkg_add -r #{@name}",
- {:env => {"PKG_PATH" => "http://ftp.OpenBSD.org/pub/OpenBSD/5.5/packages/amd64/"}}
- ) {OpenStruct.new :status => true}
- @provider.install_package(@name, nil)
+ let(:name) { 'ihavetoes' }
+ let(:version) {'0.0'}
+
+ context 'when not already installed' do
+ before do
+ allow(provider).to receive(:shell_out!).with("pkg_info -e \"#{name}->0\"", anything()).and_return(instance_double('shellout', :stdout => ''))
+ end
+
+ 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/"}}
+ ) {OpenStruct.new :status => true}
+ provider.run_action(:install)
+ end
+ end
+ end
+
+ context 'when there are multiple candidates' do
+ let(:flavor_a) { 'flavora' }
+ let(:flavor_b) { 'flavorb' }
+
+ context 'if no version is specified' do
+ it 'should raise an exception' do
+ expect(provider).to receive(:shell_out!).with("pkg_info -I \"#{name}\"", anything()).and_return(
+ instance_double('shellout', :stdout => "#{name}-#{version}-#{flavor_a}\n#{name}-#{version}-#{flavor_b}\n"))
+ expect { provider.run_action(:install) }.to raise_error(Chef::Exceptions::Package, /multiple matching candidates/)
+ end
+ end
+
+ context 'if a flavor is specified' do
+
+ let(:flavor) { 'flavora' }
+ let(:package_name) {'ihavetoes' }
+ let(:name) { "#{package_name}--#{flavor}" }
+
+ context 'if no version is specified' do
+ it 'should run the installation command' do
+ expect(provider).to receive(:shell_out!).with("pkg_info -e \"#{package_name}->0\"", anything()).and_return(instance_double('shellout', :stdout => ''))
+ expect(provider).to receive(:shell_out!).with("pkg_info -I \"#{name}\"", anything()).and_return(
+ 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/"}}
+ ) {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
+ it 'should use the flavor from the version' do
+ expect(provider).to receive(:shell_out!).with("pkg_info -I \"#{name}-#{version}-#{flavor_b}\"", anything()).and_return(
+ instance_double('shellout', :stdout => "#{name}-#{version}-#{flavor_a}\n"))
+
+ 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/"}}
+ ) {OpenStruct.new :status => true}
+ provider.run_action(:install)
+ end
+ end
+ end
end
end
diff --git a/spec/unit/provider/package/rubygems_spec.rb b/spec/unit/provider/package/rubygems_spec.rb
index b17c216ddd..380572499c 100644
--- a/spec/unit/provider/package/rubygems_spec.rb
+++ b/spec/unit/provider/package/rubygems_spec.rb
@@ -547,6 +547,25 @@ describe Chef::Provider::Package::Rubygems do
expect(@new_resource).to be_updated_by_last_action
end
+ it "installs the gem with rubygems.org as an added source" 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)
+ @provider.run_action(:install)
+ expect(@new_resource).to be_updated_by_last_action
+ end
+
+ it "installs the gem with cleared sources and explict source when specified" do
+ @new_resource.gem_binary('/foo/bar')
+ @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)
+ @provider.run_action(:install)
+ expect(@new_resource).to be_updated_by_last_action
+ end
+
context "when no version is given" do
let(:target_version) { nil }
diff --git a/spec/unit/provider/package/yum_spec.rb b/spec/unit/provider/package/yum_spec.rb
index cd2b3decf4..865dce23fa 100644
--- a/spec/unit/provider/package/yum_spec.rb
+++ b/spec/unit/provider/package/yum_spec.rb
@@ -73,6 +73,20 @@ describe Chef::Provider::Package::Yum do
expect(@provider.load_current_resource).to eql(@provider.current_resource)
end
+ describe "when source is provided" do
+ it "should set the candidate version" do
+ @new_resource = Chef::Resource::YumPackage.new('testing.source')
+ @new_resource.source "chef-server-core-12.0.5-1.rpm"
+ @provider = Chef::Provider::Package::Yum.new(@new_resource, @run_context)
+ allow(File).to receive(:exists?).with(@new_resource.source).and_return(true)
+ allow(@yum_cache).to receive(:installed_version).and_return(nil)
+ shellout_double = double(:stdout => 'chef-server-core 12.0.5-1')
+ allow(@provider).to receive(:shell_out!).and_return(shellout_double)
+ @provider.load_current_resource
+ expect(@provider.candidate_version).to eql('12.0.5-1')
+ end
+ end
+
describe "when arch in package_name" do
it "should set the arch if no existing package_name is found and new_package_name+new_arch is available" do
@new_resource = Chef::Resource::YumPackage.new('testing.noarch')
diff --git a/spec/unit/provider/service/macosx_spec.rb b/spec/unit/provider/service/macosx_spec.rb
index 42d45f09e0..597845a558 100644
--- a/spec/unit/provider/service/macosx_spec.rb
+++ b/spec/unit/provider/service/macosx_spec.rb
@@ -22,17 +22,17 @@ describe Chef::Provider::Service::Macosx do
describe ".gather_plist_dirs" do
context "when HOME directory is set" do
before do
- allow(ENV).to receive(:[]).with('HOME').and_return("/User/someuser")
+ allow(Chef::Util::PathHelper).to receive(:home).with('Library', 'LaunchAgents').and_yield('/Users/someuser/Library/LaunchAgents')
end
it "includes users's LaunchAgents folder" do
- expect(described_class.gather_plist_dirs).to include("#{ENV['HOME']}/Library/LaunchAgents")
+ expect(described_class.gather_plist_dirs).to include("/Users/someuser/Library/LaunchAgents")
end
end
context "when HOME directory is not set" do
before do
- allow(ENV).to receive(:[]).with('HOME').and_return(nil)
+ allow(Chef::Util::PathHelper).to receive(:home).with('Library', 'LaunchAgents').and_return(nil)
end
it "doesn't include user's LaunchAgents folder" do
diff --git a/spec/unit/recipe_spec.rb b/spec/unit/recipe_spec.rb
index 8d0b1bcfd2..b370e12732 100644
--- a/spec/unit/recipe_spec.rb
+++ b/spec/unit/recipe_spec.rb
@@ -237,8 +237,17 @@ describe Chef::Recipe do
action :nothing
end
end
+
+ it "validating resources via build_resource" do
+ expect {recipe.build_resource(:remote_file, "klopp") do
+ source Chef::DelayedEvaluator.new {"http://chef.io"}
+ end}.to_not raise_error
+ end
+
end
+
+
describe "creating resources via declare_resource" do
let(:zm_resource) do
recipe.declare_resource(:zen_master, "klopp") do
@@ -593,5 +602,9 @@ describe Chef::Recipe do
expect(recipe.singleton_class.included_modules).to include(Chef::DSL::Audit)
expect(recipe.respond_to?(:control_group)).to be true
end
+
+ it "should respond to :ps_credential from Chef::DSL::Powershell" do
+ expect(recipe.respond_to?(:ps_credential)).to be true
+ end
end
end
diff --git a/spec/unit/resource/deploy_spec.rb b/spec/unit/resource/deploy_spec.rb
index 07f5f973c0..0403a7ba6b 100644
--- a/spec/unit/resource/deploy_spec.rb
+++ b/spec/unit/resource/deploy_spec.rb
@@ -30,35 +30,12 @@ describe Chef::Resource::Deploy do
class << self
-
- def resource_has_a_hash_attribute(attr_name)
- it "has a Hash attribute for #{attr_name.to_s}" do
- @resource.send(attr_name, {foo: "bar"})
- expect(@resource.send(attr_name)).to eql({foo: "bar"})
- expect {@resource.send(attr_name, 8675309)}.to raise_error(ArgumentError)
- end
-
- it "the Hash attribute for #{attr_name.to_s} is nillable" do
- @resource.send(attr_name, {foo: "bar"})
- expect(@resource.send(attr_name)).to eql({foo: "bar"})
- @resource.send(attr_name, nil)
- expect(@resource.send(attr_name)).to eql(nil)
- end
- end
-
def resource_has_a_string_attribute(attr_name)
it "has a String attribute for #{attr_name.to_s}" do
@resource.send(attr_name, "this is a string")
expect(@resource.send(attr_name)).to eql("this is a string")
expect {@resource.send(attr_name, 8675309)}.to raise_error(ArgumentError)
end
-
- it "the String attribute for #{attr_name.to_s} is nillable" do
- @resource.send(attr_name, "this is a string")
- expect(@resource.send(attr_name)).to eql("this is a string")
- @resource.send(attr_name, nil)
- expect(@resource.send(attr_name)).to eql(nil)
- end
end
def resource_has_a_boolean_attribute(attr_name, opts={:defaults_to=>false})
@@ -212,10 +189,6 @@ describe Chef::Resource::Deploy do
expect(@resource.symlink_before_migrate).to eq({"wtf?" => "wtf is going on"})
end
- resource_has_a_hash_attribute :symlink_before_migrate
- resource_has_a_hash_attribute :symlinks
- resource_has_a_hash_attribute :additional_remotes
-
resource_has_a_callback_attribute :before_migrate
resource_has_a_callback_attribute :before_symlink
resource_has_a_callback_attribute :before_restart
diff --git a/spec/unit/resource/dsc_resource_spec.rb b/spec/unit/resource/dsc_resource_spec.rb
new file mode 100644
index 0000000000..ae15f56eaf
--- /dev/null
+++ b/spec/unit/resource/dsc_resource_spec.rb
@@ -0,0 +1,85 @@
+#
+# Author:: Adam Edwards (<adamed@getchef.com>)
+# 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::Resource::DscResource do
+ let(:dsc_test_resource_name) { 'DSCTest' }
+ let(:dsc_test_property_name) { :DSCTestProperty }
+ let(:dsc_test_property_value) { 'DSCTestValue' }
+
+ context 'when Powershell supports Dsc' do
+ let(:dsc_test_run_context) {
+ node = Chef::Node.new
+ node.automatic[:languages][:powershell][:version] = '5.0.10018.0'
+ empty_events = Chef::EventDispatch::Dispatcher.new
+ Chef::RunContext.new(node, {}, empty_events)
+ }
+ let(:dsc_test_resource) {
+ Chef::Resource::DscResource.new(dsc_test_resource_name, dsc_test_run_context)
+ }
+
+ it "has a default action of `:run`" do
+ expect(dsc_test_resource.action).to eq(:run)
+ end
+
+ it "has an allowed_actions attribute with only the `:run` and `:nothing` attributes" do
+ expect(dsc_test_resource.allowed_actions.to_set).to eq([:run,:nothing].to_set)
+ end
+
+ it "allows the resource attribute to be set" do
+ dsc_test_resource.resource(dsc_test_resource_name)
+ expect(dsc_test_resource.resource).to eq(dsc_test_resource_name)
+ end
+
+ it "allows the module_name attribute to be set" do
+ dsc_test_resource.module_name(dsc_test_resource_name)
+ expect(dsc_test_resource.module_name).to eq(dsc_test_resource_name)
+ end
+
+ context "when setting a dsc property" do
+ it "allows setting a dsc property with a property name of type Symbol" do
+ dsc_test_resource.property(dsc_test_property_name, dsc_test_property_value)
+ expect(dsc_test_resource.property(dsc_test_property_name)).to eq(dsc_test_property_value)
+ expect(dsc_test_resource.properties[dsc_test_property_name]).to eq(dsc_test_property_value)
+ end
+
+ it "raises a TypeError if property_name is not a symbol" do
+ expect{
+ dsc_test_resource.property('Foo', dsc_test_property_value)
+ }.to raise_error(TypeError)
+ end
+
+ context "when using DelayedEvaluators" do
+ it "allows setting a dsc property with a property name of type Symbol" do
+ dsc_test_resource.property(dsc_test_property_name, Chef::DelayedEvaluator.new {
+ dsc_test_property_value
+ })
+ expect(dsc_test_resource.property(dsc_test_property_name)).to eq(dsc_test_property_value)
+ expect(dsc_test_resource.properties[dsc_test_property_name]).to eq(dsc_test_property_value)
+ end
+ end
+ end
+
+ context 'Powershell DSL methods' do
+ it "responds to :ps_credential" do
+ expect(dsc_test_resource.respond_to?(:ps_credential)).to be true
+ end
+ end
+ end
+end
diff --git a/spec/unit/resource/link_spec.rb b/spec/unit/resource/link_spec.rb
index 3573a15f31..51221e0472 100644
--- a/spec/unit/resource/link_spec.rb
+++ b/spec/unit/resource/link_spec.rb
@@ -53,6 +53,21 @@ describe Chef::Resource::Link do
expect(@resource.target_file).to eql("fakey_fakerton")
end
+ it "should accept a delayed evaluator as the target path" do
+ @resource.target_file Chef::DelayedEvaluator.new { "my_lazy_name" }
+ expect(@resource.target_file).to eql("my_lazy_name")
+ end
+
+ it "should accept a delayed evaluator when accessing via 'path'" do
+ @resource.target_file Chef::DelayedEvaluator.new { "my_lazy_name" }
+ expect(@resource.path).to eql("my_lazy_name")
+ end
+
+ it "should accept a delayed evaluator via 'to'" do
+ @resource.to Chef::DelayedEvaluator.new { "my_lazy_name" }
+ expect(@resource.to).to eql("my_lazy_name")
+ end
+
it "should accept a string as the link source via 'to'" do
expect { @resource.to "/tmp" }.not_to raise_error
end
diff --git a/spec/unit/rest_spec.rb b/spec/unit/rest_spec.rb
index 1aa7ac84ee..85c9e3df8f 100644
--- a/spec/unit/rest_spec.rb
+++ b/spec/unit/rest_spec.rb
@@ -92,6 +92,15 @@ describe Chef::REST do
Chef::REST.new(base_url, nil, nil, options)
end
+ context 'when created with a chef zero URL' do
+
+ let(:url) { "chefzero://localhost:1" }
+
+ it "does not load the signing key" do
+ expect { Chef::REST.new(url) }.to_not raise_error
+ end
+ end
+
describe "calling an HTTP verb on a path or absolute URL" do
it "adds a relative URL to the base url it was initialized with" do
expect(rest.create_url("foo/bar/baz")).to eq(URI.parse(base_url + "/foo/bar/baz"))
diff --git a/spec/unit/shell_spec.rb b/spec/unit/shell_spec.rb
index 0e028f4359..617abcfde2 100644
--- a/spec/unit/shell_spec.rb
+++ b/spec/unit/shell_spec.rb
@@ -56,7 +56,7 @@ describe Shell do
describe "configuring IRB" do
it "configures irb history" do
Shell.configure_irb
- expect(Shell.irb_conf[:HISTORY_FILE]).to eq("~/.chef/chef_shell_history")
+ expect(Shell.irb_conf[:HISTORY_FILE]).to eq("#{ENV['HOME']}/.chef/chef_shell_history")
expect(Shell.irb_conf[:SAVE_HISTORY]).to eq(1000)
end
diff --git a/spec/unit/util/dsc/resource_store.rb b/spec/unit/util/dsc/resource_store.rb
new file mode 100644
index 0000000000..a89e73fcaa
--- /dev/null
+++ b/spec/unit/util/dsc/resource_store.rb
@@ -0,0 +1,76 @@
+#
+# 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 'chef'
+require 'chef/util/dsc/resource_store'
+
+describe Chef::Util::DSC::ResourceStore do
+ let(:resource_store) { Chef::Util::DSC::ResourceStore.new }
+ let(:resource_a) { {
+ 'ResourceType' => 'AFoo',
+ 'Name' => 'Foo',
+ 'Module' => {'Name' => 'ModuleA'}
+ }
+ }
+
+ let(:resource_b) { {
+ 'ResourceType' => 'BFoo',
+ 'Name' => 'Foo',
+ 'Module' => {'Name' => 'ModuleB'}
+ }
+ }
+
+ context 'when resources are not cached' do
+ context 'when calling #resources' do
+ it 'returns an empty array' do
+ expect(resource_store.resources).to eql([])
+ end
+ end
+
+ context 'when calling #find' do
+ it 'returns an empty list if it cannot find any matching resources' do
+ expect(resource_store).to receive(:query_resource).and_return([])
+ expect(resource_store.find('foo')).to eql([])
+ end
+
+ it 'returns the resource if it is found (comparisons are case insensitive)' do
+ expect(resource_store).to receive(:query_resource).and_return([resource_a])
+ expect(resource_store.find('foo')).to eql([resource_a])
+ end
+
+ it 'returns multiple resoures if they are found' do
+ expect(resource_store).to receive(:query_resource).and_return([resource_a, resource_b])
+ expect(resource_store.find('foo')).to include(resource_a, resource_b)
+ end
+
+ it 'deduplicates resources by ResourceName' do
+ expect(resource_store).to receive(:query_resource).and_return([resource_a, resource_a])
+ resource_store.find('foo')
+ expect(resource_store.resources).to eq([resource_a])
+ end
+ end
+ end
+
+ context 'when resources are cached' do
+ it 'recalls resources from the cache if present' do
+ expect(resource_store).not_to receive(:query_resource)
+ expect(resource_store).to receive(:resources).and_return([resource_a])
+ resource_store.find('foo')
+ end
+ end
+end
diff --git a/spec/unit/util/path_helper_spec.rb b/spec/unit/util/path_helper_spec.rb
index 5756c29b90..23db9587a6 100644
--- a/spec/unit/util/path_helper_spec.rb
+++ b/spec/unit/util/path_helper_spec.rb
@@ -230,4 +230,26 @@ describe Chef::Util::PathHelper do
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
diff --git a/spec/unit/util/powershell/ps_credential_spec.rb b/spec/unit/util/powershell/ps_credential_spec.rb
new file mode 100644
index 0000000000..bac58b02e5
--- /dev/null
+++ b/spec/unit/util/powershell/ps_credential_spec.rb
@@ -0,0 +1,37 @@
+#
+# 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 'chef'
+require 'chef/util/powershell/ps_credential'
+
+describe Chef::Util::Powershell::PSCredential do
+ let (:username) { 'foo' }
+ let (:password) { 'password' }
+
+ context 'when username and password are provided' do
+ let(:ps_credential) { Chef::Util::Powershell::PSCredential.new(username, password)}
+ context 'when calling to_psobject' do
+ it 'should create the script to create a PSCredential when calling' do
+ allow(ps_credential).to receive(:encrypt).with(password).and_return('encrypted')
+ expect(ps_credential.to_psobject).to eq(
+ "New-Object System.Management.Automation.PSCredential("\
+ "'#{username}',('encrypted' | ConvertTo-SecureString))")
+ end
+ end
+ end
+end
diff --git a/spec/unit/workstation_config_loader_spec.rb b/spec/unit/workstation_config_loader_spec.rb
index a865103188..72631f3dfa 100644
--- a/spec/unit/workstation_config_loader_spec.rb
+++ b/spec/unit/workstation_config_loader_spec.rb
@@ -65,7 +65,7 @@ describe Chef::WorkstationConfigLoader do
let(:home) { "/Users/example.user" }
before do
- env["HOME"] = home
+ allow(Chef::Util::PathHelper).to receive(:home).with('.chef').and_yield(File.join(home, '.chef'))
allow(config_loader).to receive(:path_exists?).with("#{home}/.chef/knife.rb").and_return(true)
end