summaryrefslogtreecommitdiff
path: root/spec
diff options
context:
space:
mode:
Diffstat (limited to 'spec')
-rw-r--r--spec/data/run_context/cookbooks/dependency1/attributes/unparsed_file1
-rw-r--r--spec/data/run_context/cookbooks/dependency1/definitions/unparsed_file1
-rw-r--r--spec/data/run_context/cookbooks/dependency1/libraries/unparsed_file1
-rw-r--r--spec/data/run_context/cookbooks/dependency1/providers/unparsed_file1
-rw-r--r--spec/data/run_context/cookbooks/dependency1/recipes/unparsed_file1
-rw-r--r--spec/data/run_context/cookbooks/dependency1/resources/unparsed_file1
-rw-r--r--spec/functional/resource/link_spec.rb4
-rw-r--r--spec/functional/resource/windows_task_spec.rb76
-rw-r--r--spec/functional/shell_spec.rb5
-rw-r--r--spec/functional/version_spec.rb4
-rw-r--r--spec/integration/client/client_spec.rb22
-rw-r--r--spec/integration/client/exit_code_spec.rb2
-rw-r--r--spec/integration/client/ipv6_spec.rb4
-rw-r--r--spec/integration/recipes/accumulator_spec.rb2
-rw-r--r--spec/integration/recipes/lwrp_inline_resources_spec.rb2
-rw-r--r--spec/integration/recipes/lwrp_spec.rb2
-rw-r--r--spec/integration/recipes/notifies_spec.rb2
-rw-r--r--spec/integration/recipes/notifying_block_spec.rb4
-rw-r--r--spec/integration/recipes/remote_directory.rb2
-rw-r--r--spec/integration/solo/solo_spec.rb8
-rw-r--r--spec/support/shared/functional/directory_resource.rb22
-rw-r--r--spec/support/shared/functional/file_resource.rb4
-rw-r--r--spec/support/shared/functional/securable_resource.rb173
-rw-r--r--spec/support/shared/integration/integration_helper.rb1
-rw-r--r--spec/support/shared/unit/provider/file.rb1
-rw-r--r--spec/unit/application/client_spec.rb2
-rw-r--r--spec/unit/application/exit_code_spec.rb2
-rw-r--r--spec/unit/application/knife_spec.rb6
-rw-r--r--spec/unit/application/solo_spec.rb2
-rw-r--r--spec/unit/application_spec.rb7
-rw-r--r--spec/unit/knife/bootstrap/train_connector_spec.rb216
-rw-r--r--spec/unit/knife/bootstrap_spec.rb132
-rw-r--r--spec/unit/knife/client_create_spec.rb19
-rw-r--r--spec/unit/knife/core/bootstrap_context_spec.rb55
-rw-r--r--spec/unit/knife/core/windows_bootstrap_context_spec.rb39
-rw-r--r--spec/unit/knife_spec.rb31
-rw-r--r--spec/unit/node_map_spec.rb40
-rw-r--r--spec/unit/provider/cron_spec.rb143
-rw-r--r--spec/unit/resource/windows_task_spec.rb4
-rw-r--r--spec/unit/run_context/cookbook_compiler_spec.rb10
-rw-r--r--spec/unit/train_transport_spec.rb79
41 files changed, 830 insertions, 303 deletions
diff --git a/spec/data/run_context/cookbooks/dependency1/attributes/unparsed_file b/spec/data/run_context/cookbooks/dependency1/attributes/unparsed_file
new file mode 100644
index 0000000000..60fee07cc6
--- /dev/null
+++ b/spec/data/run_context/cookbooks/dependency1/attributes/unparsed_file
@@ -0,0 +1 @@
+raise "this should not be parsed by the loader"
diff --git a/spec/data/run_context/cookbooks/dependency1/definitions/unparsed_file b/spec/data/run_context/cookbooks/dependency1/definitions/unparsed_file
new file mode 100644
index 0000000000..60fee07cc6
--- /dev/null
+++ b/spec/data/run_context/cookbooks/dependency1/definitions/unparsed_file
@@ -0,0 +1 @@
+raise "this should not be parsed by the loader"
diff --git a/spec/data/run_context/cookbooks/dependency1/libraries/unparsed_file b/spec/data/run_context/cookbooks/dependency1/libraries/unparsed_file
new file mode 100644
index 0000000000..60fee07cc6
--- /dev/null
+++ b/spec/data/run_context/cookbooks/dependency1/libraries/unparsed_file
@@ -0,0 +1 @@
+raise "this should not be parsed by the loader"
diff --git a/spec/data/run_context/cookbooks/dependency1/providers/unparsed_file b/spec/data/run_context/cookbooks/dependency1/providers/unparsed_file
new file mode 100644
index 0000000000..60fee07cc6
--- /dev/null
+++ b/spec/data/run_context/cookbooks/dependency1/providers/unparsed_file
@@ -0,0 +1 @@
+raise "this should not be parsed by the loader"
diff --git a/spec/data/run_context/cookbooks/dependency1/recipes/unparsed_file b/spec/data/run_context/cookbooks/dependency1/recipes/unparsed_file
new file mode 100644
index 0000000000..60fee07cc6
--- /dev/null
+++ b/spec/data/run_context/cookbooks/dependency1/recipes/unparsed_file
@@ -0,0 +1 @@
+raise "this should not be parsed by the loader"
diff --git a/spec/data/run_context/cookbooks/dependency1/resources/unparsed_file b/spec/data/run_context/cookbooks/dependency1/resources/unparsed_file
new file mode 100644
index 0000000000..60fee07cc6
--- /dev/null
+++ b/spec/data/run_context/cookbooks/dependency1/resources/unparsed_file
@@ -0,0 +1 @@
+raise "this should not be parsed by the loader"
diff --git a/spec/functional/resource/link_spec.rb b/spec/functional/resource/link_spec.rb
index 4464b6ed69..d86a904098 100644
--- a/spec/functional/resource/link_spec.rb
+++ b/spec/functional/resource/link_spec.rb
@@ -417,11 +417,11 @@ describe Chef::Resource::Link do
it_behaves_like "a securable resource without existing target" do
let(:path) { target_file }
- def allowed_acl(sid, expected_perms)
+ def allowed_acl(sid, expected_perms, _flags = 0)
[ ACE.access_allowed(sid, expected_perms[:specific]) ]
end
- def denied_acl(sid, expected_perms)
+ def denied_acl(sid, expected_perms, _flags = 0)
[ ACE.access_denied(sid, expected_perms[:specific]) ]
end
diff --git a/spec/functional/resource/windows_task_spec.rb b/spec/functional/resource/windows_task_spec.rb
index b0c6998d77..fa51ad3f8a 100644
--- a/spec/functional/resource/windows_task_spec.rb
+++ b/spec/functional/resource/windows_task_spec.rb
@@ -18,6 +18,7 @@
require "spec_helper"
require "chef/provider/windows_task"
+require "chef/dist"
describe Chef::Resource::WindowsTask, :windows_only do
# resource.task.application_name will default to task_name unless resource.command is set
@@ -45,37 +46,37 @@ describe Chef::Resource::WindowsTask, :windows_only do
context "With Arguments" do
it "creates scheduled task and sets command arguments" do
- subject.command "chef-client -W"
+ subject.command "#{Chef::Dist::CLIENT} -W"
call_for_create_action
# loading current resource again to check new task is creted and it matches task parameters
current_resource = call_for_load_current_resource
expect(current_resource.exists).to eq(true)
- expect(current_resource.task.application_name).to eq("chef-client")
+ expect(current_resource.task.application_name).to eq(Chef::Dist::CLIENT)
expect(current_resource.task.parameters).to eq("-W")
end
it "does not converge the resource if it is already converged" do
- subject.command "chef-client -W"
+ subject.command "#{Chef::Dist::CLIENT} -W"
subject.run_action(:create)
- subject.command "chef-client -W"
+ subject.command "#{Chef::Dist::CLIENT} -W"
subject.run_action(:create)
expect(subject).not_to be_updated_by_last_action
end
it "creates scheduled task and sets command arguments when arguments inclusive single quotes" do
- subject.command "chef-client -W -L 'C:\\chef\\chef-ad-join.log'"
+ subject.command "#{Chef::Dist::CLIENT} -W -L 'C:\\chef\\chef-ad-join.log'"
call_for_create_action
# loading current resource again to check new task is creted and it matches task parameters
current_resource = call_for_load_current_resource
expect(current_resource.exists).to eq(true)
- expect(current_resource.task.application_name).to eq("chef-client")
+ expect(current_resource.task.application_name).to eq(Chef::Dist::CLIENT)
expect(current_resource.task.parameters).to eq("-W -L 'C:\\chef\\chef-ad-join.log'")
end
it "does not converge the resource if it is already converged" do
- subject.command "chef-client -W -L 'C:\\chef\\chef-ad-join.log'"
+ subject.command "#{Chef::Dist::CLIENT} -W -L 'C:\\chef\\chef-ad-join.log'"
subject.run_action(:create)
- subject.command "chef-client -W -L 'C:\\chef\\chef-ad-join.log'"
+ subject.command "#{Chef::Dist::CLIENT} -W -L 'C:\\chef\\chef-ad-join.log'"
subject.run_action(:create)
expect(subject).not_to be_updated_by_last_action
end
@@ -135,19 +136,19 @@ describe Chef::Resource::WindowsTask, :windows_only do
context "Without Arguments" do
it "creates scheduled task and sets command arguments" do
- subject.command "chef-client"
+ subject.command Chef::Dist::CLIENT
call_for_create_action
# loading current resource again to check new task is creted and it matches task parameters
current_resource = call_for_load_current_resource
expect(current_resource.exists).to eq(true)
- expect(current_resource.task.application_name).to eq("chef-client")
+ expect(current_resource.task.application_name).to eq(Chef::Dist::CLIENT)
expect(current_resource.task.parameters).to be_empty
end
it "does not converge the resource if it is already converged" do
- subject.command "chef-client"
+ subject.command Chef::Dist::CLIENT
subject.run_action(:create)
- subject.command "chef-client"
+ subject.command Chef::Dist::CLIENT
subject.run_action(:create)
expect(subject).not_to be_updated_by_last_action
end
@@ -1283,6 +1284,57 @@ describe Chef::Resource::WindowsTask, :windows_only do
expect(subject).not_to be_updated_by_last_action
end
end
+
+ context "when start_when_available is passed" do
+ subject do
+ new_resource = Chef::Resource::WindowsTask.new(task_name, run_context)
+ new_resource.command task_name
+ new_resource.run_level :highest
+ new_resource.execution_time_limit = 259200 / 60 # converting "PT72H" into minutes and passing here since win32-taskscheduler accespts this
+ new_resource
+ end
+
+ it "sets start_when_available to true" do
+ subject.frequency :minute
+ subject.start_when_available true
+ call_for_create_action
+ # loading current resource again to check new task is creted and it matches task parameters
+ current_resource = call_for_load_current_resource
+ expect(current_resource.exists).to eq(true)
+ expect(current_resource.task.settings[:start_when_available]).to eql(true)
+ end
+
+ it "sets start_when_available to false" do
+ subject.frequency :minute
+ subject.start_when_available false
+ call_for_create_action
+ # loading current resource again to check new task is created and it matches task parameters
+ current_resource = call_for_load_current_resource
+ expect(current_resource.exists).to eq(true)
+ expect(current_resource.task.settings[:start_when_available]).to eql(false)
+ end
+
+ it "sets the default if start_when_available is nil" do
+ subject.frequency :minute
+ subject.start_when_available nil
+ call_for_create_action
+ # loading current resource again to check new task is created and it matches task parameters
+ current_resource = call_for_load_current_resource
+ expect(current_resource.exists).to eq(true)
+ expect(current_resource.task.settings[:start_when_available]).to eql(false)
+ end
+
+ it "does not converge the resource if it is already converged" do
+ subject.frequency :minute
+ subject.start_when_available true
+ subject.run_action(:create)
+ subject.frequency :minute
+ subject.start_when_available true
+ subject.disallow_start_if_on_batteries false
+ subject.run_action(:create)
+ expect(subject).not_to be_updated_by_last_action
+ end
+ end
end
context "task_name with parent folder" do
diff --git a/spec/functional/shell_spec.rb b/spec/functional/shell_spec.rb
index 3990f1afe0..dd0455fc9e 100644
--- a/spec/functional/shell_spec.rb
+++ b/spec/functional/shell_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Daniel DeLeo (<dan@chef.io>)
-# Copyright:: Copyright 2012-2017, Chef Software Inc.
+# Copyright:: Copyright 2012-2019, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -82,8 +82,7 @@ describe Shell do
require "pty"
config = File.expand_path("shef-config.rb", CHEF_SPEC_DATA)
- path_to_chef_shell = File.expand_path("../../../bin/chef-shell", __FILE__)
- reader, writer, pid = PTY.spawn("#{path_to_chef_shell} -c #{config} #{options}")
+ reader, writer, pid = PTY.spawn("bundle exec chef-shell -c #{config} #{options}")
read_until(reader, "chef (#{Chef::VERSION})>")
yield reader, writer if block_given?
writer.puts('"done"')
diff --git a/spec/functional/version_spec.rb b/spec/functional/version_spec.rb
index d968c36e8c..b12d235405 100644
--- a/spec/functional/version_spec.rb
+++ b/spec/functional/version_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Serdar Sutay (<dan@chef.io>)
-# Copyright:: Copyright 2013-2016, Chef Software Inc.
+# Copyright:: Copyright 2013-2019, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -28,7 +28,7 @@ describe "Chef Versions" do
binaries.each do |binary|
it "#{binary} version should be sane" do
- expect(shell_out!("ruby #{File.join("bin", binary)} -v", cwd: chef_dir).stdout.chomp).to match(/.*: #{Chef::VERSION}/)
+ expect(shell_out!("bundle exec #{binary} -v", cwd: chef_dir).stdout.chomp).to match(/.*: #{Chef::VERSION}/)
end
end
diff --git a/spec/integration/client/client_spec.rb b/spec/integration/client/client_spec.rb
index 006839be3f..cde25662c1 100644
--- a/spec/integration/client/client_spec.rb
+++ b/spec/integration/client/client_spec.rb
@@ -45,10 +45,8 @@ describe "chef-client" do
# machine that has omnibus chef installed. In that case we need to ensure
# we're running `chef-client` from the source tree and not the external one.
# cf. CHEF-4914
- let(:chef_client) { "ruby '#{chef_dir}/chef-client' --minimal-ohai" }
- let(:chef_solo) { "ruby '#{chef_dir}/chef-solo' --legacy-mode --minimal-ohai" }
-
- let(:critical_env_vars) { %w{_ORIGINAL_GEM_PATH GEM_PATH GEM_HOME GEM_ROOT BUNDLE_BIN_PATH BUNDLE_GEMFILE RUBYLIB RUBYOPT RUBY_ENGINE RUBY_ROOT RUBY_VERSION PATH}.map { |o| "#{o}=#{ENV[o]}" } .join(" ") }
+ let(:chef_client) { "bundle exec chef-client --minimal-ohai" }
+ let(:chef_solo) { "bundle exec chef-solo --legacy-mode --minimal-ohai" }
when_the_repository "has a cookbook with a no-op recipe" do
before { file "cookbooks/x/recipes/default.rb", "" }
@@ -62,22 +60,6 @@ describe "chef-client" do
shell_out!("#{chef_client} -c \"#{path_to('config/client.rb')}\" -o 'x::default'", cwd: chef_dir)
end
- it "should complete successfully with no other environment variables", skip: (Chef::Platform.windows?) do
- file "config/client.rb", <<~EOM
- local_mode true
- cookbook_path "#{path_to('cookbooks')}"
- EOM
-
- begin
- result = shell_out("env -i #{critical_env_vars} #{chef_client} -c \"#{path_to('config/client.rb')}\" -o 'x::default'", cwd: chef_dir)
- result.error!
- rescue
- Chef::Log.info "Bare invocation will have the following load-path."
- Chef::Log.info shell_out!("env -i #{critical_env_vars} ruby -e 'puts $:'").stdout
- raise
- end
- end
-
it "should complete successfully with --no-listen" do
file "config/client.rb", <<~EOM
local_mode true
diff --git a/spec/integration/client/exit_code_spec.rb b/spec/integration/client/exit_code_spec.rb
index 2e29502070..6600a65c9f 100644
--- a/spec/integration/client/exit_code_spec.rb
+++ b/spec/integration/client/exit_code_spec.rb
@@ -21,7 +21,7 @@ describe "chef-client" do
# machine that has omnibus chef installed. In that case we need to ensure
# we're running `chef-client` from the source tree and not the external one.
# cf. CHEF-4914
- let(:chef_client) { "ruby '#{chef_dir}/chef-client' --no-fork --minimal-ohai" }
+ let(:chef_client) { "bundle exec chef-client --no-fork --minimal-ohai" }
let(:critical_env_vars) { %w{PATH RUBYOPT BUNDLE_GEMFILE GEM_PATH}.map { |o| "#{o}=#{ENV[o]}" } .join(" ") }
diff --git a/spec/integration/client/ipv6_spec.rb b/spec/integration/client/ipv6_spec.rb
index 04154c296f..b97eb4e8b4 100644
--- a/spec/integration/client/ipv6_spec.rb
+++ b/spec/integration/client/ipv6_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Daniel DeLeo (<dan@chef.io>)
-# Copyright:: Copyright 2013-2016, Chef Software Inc.
+# Copyright:: Copyright 2013-2019, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -75,7 +75,7 @@ describe "chef-client" do
let(:chef_dir) { File.join(File.dirname(__FILE__), "..", "..", "..", "bin") }
- let(:chef_client_cmd) { %Q{ruby '#{chef_dir}/chef-client' --minimal-ohai -c "#{path_to('config/client.rb')}" -lwarn} }
+ let(:chef_client_cmd) { %Q{bundle exec chef-client --minimal-ohai -c "#{path_to('config/client.rb')}" -lwarn} }
after do
FileUtils.rm_rf(cache_path)
diff --git a/spec/integration/recipes/accumulator_spec.rb b/spec/integration/recipes/accumulator_spec.rb
index 65a05fcdc5..d19d8637bb 100644
--- a/spec/integration/recipes/accumulator_spec.rb
+++ b/spec/integration/recipes/accumulator_spec.rb
@@ -16,7 +16,7 @@ describe "Accumulators" do
# machine that has omnibus chef installed. In that case we need to ensure
# we're running `chef-client` from the source tree and not the external one.
# cf. CHEF-4914
- let(:chef_client) { "ruby '#{chef_dir}/chef-client' --minimal-ohai" }
+ let(:chef_client) { "bundle exec chef-client --minimal-ohai" }
let(:aliases_temppath) do
t = Tempfile.new("chef_accumulator_test")
diff --git a/spec/integration/recipes/lwrp_inline_resources_spec.rb b/spec/integration/recipes/lwrp_inline_resources_spec.rb
index 2f4ef92f31..6bc857df48 100644
--- a/spec/integration/recipes/lwrp_inline_resources_spec.rb
+++ b/spec/integration/recipes/lwrp_inline_resources_spec.rb
@@ -16,7 +16,7 @@ describe "LWRPs with inline resources" do
# machine that has omnibus chef installed. In that case we need to ensure
# we're running `chef-client` from the source tree and not the external one.
# cf. CHEF-4914
- let(:chef_client) { "ruby '#{chef_dir}/chef-client' --minimal-ohai" }
+ let(:chef_client) { "bundle exec chef-client --minimal-ohai" }
context "with a use_inline_resources provider with 'def action_a' instead of action :a" do
class LwrpInlineResourcesTest < Chef::Resource
diff --git a/spec/integration/recipes/lwrp_spec.rb b/spec/integration/recipes/lwrp_spec.rb
index b5af6978ac..ce2861d43b 100644
--- a/spec/integration/recipes/lwrp_spec.rb
+++ b/spec/integration/recipes/lwrp_spec.rb
@@ -16,7 +16,7 @@ describe "LWRPs" do
# machine that has omnibus chef installed. In that case we need to ensure
# we're running `chef-client` from the source tree and not the external one.
# cf. CHEF-4914
- let(:chef_client) { "ruby '#{chef_dir}/chef-client' --minimal-ohai" }
+ let(:chef_client) { "bundle exec chef-client --minimal-ohai" }
when_the_repository "has a cookbook named l-w-r-p" do
before do
diff --git a/spec/integration/recipes/notifies_spec.rb b/spec/integration/recipes/notifies_spec.rb
index 0df7aa311f..860a109e4d 100644
--- a/spec/integration/recipes/notifies_spec.rb
+++ b/spec/integration/recipes/notifies_spec.rb
@@ -6,7 +6,7 @@ describe "notifications" do
include Chef::Mixin::ShellOut
let(:chef_dir) { File.expand_path("../../../../bin", __FILE__) }
- let(:chef_client) { "ruby '#{chef_dir}/chef-client' --minimal-ohai" }
+ let(:chef_client) { "bundle exec chef-client --minimal-ohai" }
when_the_repository "notifies a nameless resource" do
before do
diff --git a/spec/integration/recipes/notifying_block_spec.rb b/spec/integration/recipes/notifying_block_spec.rb
index 6c50854038..753e81dadb 100644
--- a/spec/integration/recipes/notifying_block_spec.rb
+++ b/spec/integration/recipes/notifying_block_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: John Keiser (<jkeiser@chef.io>)
-# Copyright:: Copyright 2013-2016, Chef Software Inc.
+# Copyright:: Copyright 2013-2019, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -23,7 +23,7 @@ describe "notifying_block" do
include Chef::Mixin::ShellOut
let(:chef_dir) { File.expand_path("../../../../bin", __FILE__) }
- let(:chef_client) { "ruby '#{chef_dir}/chef-client' --minimal-ohai" }
+ let(:chef_client) { "bundle exec chef-client --minimal-ohai" }
when_the_repository "notifying_block test one" do
before do
diff --git a/spec/integration/recipes/remote_directory.rb b/spec/integration/recipes/remote_directory.rb
index a0e3e23ef3..6f67a38fc8 100644
--- a/spec/integration/recipes/remote_directory.rb
+++ b/spec/integration/recipes/remote_directory.rb
@@ -16,7 +16,7 @@ describe Chef::Resource::RemoteDirectory do
# machine that has omnibus chef installed. In that case we need to ensure
# we're running `chef-client` from the source tree and not the external one.
# cf. CHEF-4914
- let(:chef_client) { "ruby '#{chef_dir}/chef-client' --minimal-ohai" }
+ let(:chef_client) { "bundle exec chef-client --minimal-ohai" }
when_the_repository "has a cookbook with a source_dir with two subdirectories, each with one file and subdir in a different alphabetical order" do
before do
diff --git a/spec/integration/solo/solo_spec.rb b/spec/integration/solo/solo_spec.rb
index efd889c5d0..3d2efe703c 100644
--- a/spec/integration/solo/solo_spec.rb
+++ b/spec/integration/solo/solo_spec.rb
@@ -16,7 +16,7 @@ describe "chef-solo" do
let(:cookbook_ancient_100_metadata_rb) { cb_metadata("ancient", "1.0.0") }
- let(:chef_solo) { "ruby bin/chef-solo --legacy-mode --minimal-ohai" }
+ let(:chef_solo) { "bundle exec chef-solo --legacy-mode --minimal-ohai" }
when_the_repository "creates nodes" do
let(:nodes_dir) { File.join(@repository_dir, "nodes") }
@@ -26,7 +26,7 @@ describe "chef-solo" do
file "config/solo.rb", <<~EOM
chef_repo_path "#{@repository_dir}"
EOM
- result = shell_out("ruby bin/chef-solo -c \"#{path_to('config/solo.rb')}\" -l debug", cwd: chef_dir)
+ result = shell_out("bundle exec chef-solo -c \"#{path_to('config/solo.rb')}\" -l debug", cwd: chef_dir)
result.error!
end
@@ -163,7 +163,7 @@ describe "chef-solo" do
ruby_block "sleeping" do
block do
retries = 200
- while IO.read(Chef::Config[:log_location]) !~ /.* client .* is running, will wait for it to finish and then run./
+ while IO.read(Chef::Config[:log_location]) !~ /.* is running, will wait for it to finish and then run./
sleep 0.1
raise "we ran out of retries" if ( retries -= 1 ) <= 0
end
@@ -207,7 +207,7 @@ describe "chef-solo" do
run_log = File.read(path_to("logs/runs.log"))
# second run should have a message which indicates it's waiting for the first run
- expect(run_log).to match(/.* client .* is running, will wait for it to finish and then run./)
+ expect(run_log).to match(/.* is running, will wait for it to finish and then run./)
# both of the runs should succeed
expect(run_log.lines.reject { |l| !l.include? "Run complete in" }.length).to eq(2)
diff --git a/spec/support/shared/functional/directory_resource.rb b/spec/support/shared/functional/directory_resource.rb
index 5e5e2bb360..4fb08479e6 100644
--- a/spec/support/shared/functional/directory_resource.rb
+++ b/spec/support/shared/functional/directory_resource.rb
@@ -65,18 +65,20 @@ shared_examples_for "a directory resource" do
end
# Set up the context for security tests
- def allowed_acl(sid, expected_perms)
- [
- ACE.access_allowed(sid, expected_perms[:specific]),
- ACE.access_allowed(sid, expected_perms[:generic], (Chef::ReservedNames::Win32::API::Security::INHERIT_ONLY_ACE | Chef::ReservedNames::Win32::API::Security::CONTAINER_INHERIT_ACE | Chef::ReservedNames::Win32::API::Security::OBJECT_INHERIT_ACE)),
- ]
+ def allowed_acl(sid, expected_perms, flags = 0)
+ acl = [ ACE.access_allowed(sid, expected_perms[:specific], flags) ]
+ if expected_perms[:generic]
+ acl << ACE.access_allowed(sid, expected_perms[:generic], (Chef::ReservedNames::Win32::API::Security::SUBFOLDERS_AND_FILES_ONLY))
+ end
+ acl
end
- def denied_acl(sid, expected_perms)
- [
- ACE.access_denied(sid, expected_perms[:specific]),
- ACE.access_denied(sid, expected_perms[:generic], (Chef::ReservedNames::Win32::API::Security::INHERIT_ONLY_ACE | Chef::ReservedNames::Win32::API::Security::CONTAINER_INHERIT_ACE | Chef::ReservedNames::Win32::API::Security::OBJECT_INHERIT_ACE)),
- ]
+ def denied_acl(sid, expected_perms, flags = 0)
+ acl = [ ACE.access_denied(sid, expected_perms[:specific], flags) ]
+ if expected_perms[:generic]
+ acl << ACE.access_denied(sid, expected_perms[:generic], (Chef::ReservedNames::Win32::API::Security::SUBFOLDERS_AND_FILES_ONLY))
+ end
+ acl
end
def parent_inheritable_acls
diff --git a/spec/support/shared/functional/file_resource.rb b/spec/support/shared/functional/file_resource.rb
index 8ae5db6a57..db947614b3 100644
--- a/spec/support/shared/functional/file_resource.rb
+++ b/spec/support/shared/functional/file_resource.rb
@@ -899,11 +899,11 @@ shared_examples_for "a configured file resource" do
end
# Set up the context for security tests
- def allowed_acl(sid, expected_perms)
+ def allowed_acl(sid, expected_perms, _flags = 0)
[ ACE.access_allowed(sid, expected_perms[:specific]) ]
end
- def denied_acl(sid, expected_perms)
+ def denied_acl(sid, expected_perms, _flags = 0)
[ ACE.access_denied(sid, expected_perms[:specific]) ]
end
diff --git a/spec/support/shared/functional/securable_resource.rb b/spec/support/shared/functional/securable_resource.rb
index 2abae030c2..18e7243453 100644
--- a/spec/support/shared/functional/securable_resource.rb
+++ b/spec/support/shared/functional/securable_resource.rb
@@ -117,8 +117,7 @@ shared_context "use Windows permissions", :windows_only do
let(:expected_write_perms) do
{
- generic: Chef::ReservedNames::Win32::API::Security::GENERIC_WRITE,
- specific: Chef::ReservedNames::Win32::API::Security::FILE_GENERIC_WRITE,
+ specific: Chef::ReservedNames::Win32::API::Security::WRITE,
}
end
@@ -136,6 +135,8 @@ shared_context "use Windows permissions", :windows_only do
}
end
+ let (:write_flag) { 3 }
+
RSpec::Matchers.define :have_expected_properties do |mask, type, flags|
match do |ace|
ace.mask == mask &&
@@ -363,78 +364,108 @@ shared_examples_for "a securable resource without existing target" do
expect(descriptor.group).to eq(arbitrary_non_default_group)
end
- describe "with rights and deny_rights attributes" do
-
- it "correctly sets :read rights" do
- resource.rights(:read, "Guest")
- resource.run_action(:create)
- expect(explicit_aces).to eq(allowed_acl(SID.Guest, expected_read_perms))
+ describe "#allowed_acl" do
+ context "correctly sets" do
+
+ it ":read rights" do
+ resource.rights(:read, "Guest")
+ resource.run_action(:create)
+ expect(explicit_aces).to eq(allowed_acl(SID.Guest, expected_read_perms))
+ end
+
+ it ":read_execute rights" do
+ resource.rights(:read_execute, "Guest")
+ resource.run_action(:create)
+ expect(explicit_aces).to eq(allowed_acl(SID.Guest, expected_read_execute_perms))
+ end
+
+ it ":write rights" do
+ resource.rights(:write, "Guest")
+ resource.run_action(:create)
+ expect(explicit_aces).to eq(allowed_acl(SID.Guest, expected_write_perms, write_flag))
+ end
+
+ it ":modify rights" do
+ resource.rights(:modify, "Guest")
+ resource.run_action(:create)
+ expect(explicit_aces).to eq(allowed_acl(SID.Guest, expected_modify_perms))
+ end
+
+ it ":full_control rights" do
+ resource.rights(:full_control, "Guest")
+ resource.run_action(:create)
+ expect(explicit_aces).to eq(allowed_acl(SID.Guest, expected_full_control_perms))
+ end
+
+ it "multiple rights" do
+ resource.rights(:read, "Everyone")
+ resource.rights(:modify, "Guest")
+ resource.run_action(:create)
+
+ expect(explicit_aces).to eq(
+ allowed_acl(SID.Everyone, expected_read_perms) +
+ allowed_acl(SID.Guest, expected_modify_perms)
+ )
+ end
end
+ end
- it "correctly sets :read_execute rights" do
- resource.rights(:read_execute, "Guest")
- resource.run_action(:create)
- expect(explicit_aces).to eq(allowed_acl(SID.Guest, expected_read_execute_perms))
- end
-
- it "correctly sets :write rights" do
- resource.rights(:write, "Guest")
- resource.run_action(:create)
- expect(explicit_aces).to eq(allowed_acl(SID.Guest, expected_write_perms))
- end
-
- it "correctly sets :modify rights" do
- resource.rights(:modify, "Guest")
- resource.run_action(:create)
- expect(explicit_aces).to eq(allowed_acl(SID.Guest, expected_modify_perms))
- end
-
- it "correctly sets :full_control rights" do
- resource.rights(:full_control, "Guest")
- resource.run_action(:create)
- expect(explicit_aces).to eq(allowed_acl(SID.Guest, expected_full_control_perms))
- end
-
- it "correctly sets deny_rights" do
- # deny is an ACE with full rights, but is a deny type ace, not an allow type
- resource.deny_rights(:full_control, "Guest")
- resource.run_action(:create)
- expect(explicit_aces).to eq(denied_acl(SID.Guest, expected_full_control_perms))
- end
-
- it "Sets multiple rights" do
- resource.rights(:read, "Everyone")
- resource.rights(:modify, "Guest")
- resource.run_action(:create)
-
- expect(explicit_aces).to eq(
- allowed_acl(SID.Everyone, expected_read_perms) +
- allowed_acl(SID.Guest, expected_modify_perms)
- )
- end
-
- it "Sets deny_rights ahead of rights" do
- resource.rights(:read, "Everyone")
- resource.deny_rights(:modify, "Guest")
- resource.run_action(:create)
-
- expect(explicit_aces).to eq(
- denied_acl(SID.Guest, expected_modify_perms) +
- allowed_acl(SID.Everyone, expected_read_perms)
- )
- end
-
- it "Sets deny_rights ahead of rights when specified in reverse order" do
- resource.deny_rights(:modify, "Guest")
- resource.rights(:read, "Everyone")
- resource.run_action(:create)
-
- expect(explicit_aces).to eq(
- denied_acl(SID.Guest, expected_modify_perms) +
- allowed_acl(SID.Everyone, expected_read_perms)
- )
+ describe "#denied_acl" do
+ context "correctly sets" do
+
+ it ":read rights" do
+ resource.deny_rights(:read, "Guest")
+ resource.run_action(:create)
+ expect(explicit_aces).to eq(denied_acl(SID.Guest, expected_read_perms))
+ end
+
+ it ":read_execute rights" do
+ resource.deny_rights(:read_execute, "Guest")
+ resource.run_action(:create)
+ expect(explicit_aces).to eq(denied_acl(SID.Guest, expected_read_execute_perms))
+ end
+
+ it ":write rights" do
+ resource.deny_rights(:write, "Guest")
+ resource.run_action(:create)
+ expect(explicit_aces).to eq(denied_acl(SID.Guest, expected_write_perms, write_flag))
+ end
+
+ it ":modify rights" do
+ resource.deny_rights(:modify, "Guest")
+ resource.run_action(:create)
+ expect(explicit_aces).to eq(denied_acl(SID.Guest, expected_modify_perms))
+ end
+
+ it ":full_control rights" do
+ # deny is an ACE with full rights, but is a deny type ace, not an allow type
+ resource.deny_rights(:full_control, "Guest")
+ resource.run_action(:create)
+ expect(explicit_aces).to eq(denied_acl(SID.Guest, expected_full_control_perms))
+ end
+
+ it "deny_rights ahead of rights" do
+ resource.rights(:read, "Everyone")
+ resource.deny_rights(:modify, "Guest")
+ resource.run_action(:create)
+
+ expect(explicit_aces).to eq(
+ denied_acl(SID.Guest, expected_modify_perms) +
+ allowed_acl(SID.Everyone, expected_read_perms)
+ )
+ end
+
+ it "deny_rights ahead of rights when specified in reverse order" do
+ resource.deny_rights(:modify, "Guest")
+ resource.rights(:read, "Everyone")
+ resource.run_action(:create)
+
+ expect(explicit_aces).to eq(
+ denied_acl(SID.Guest, expected_modify_perms) +
+ allowed_acl(SID.Everyone, expected_read_perms)
+ )
+ end
end
-
end
context "with a mode attribute" do
diff --git a/spec/support/shared/integration/integration_helper.rb b/spec/support/shared/integration/integration_helper.rb
index b6851f2d0e..5fc9de4de7 100644
--- a/spec/support/shared/integration/integration_helper.rb
+++ b/spec/support/shared/integration/integration_helper.rb
@@ -19,7 +19,6 @@
require "tmpdir"
require "fileutils"
-require "chef_core/text"
require "chef/config"
require "chef/json_compat"
require "chef/server_api"
diff --git a/spec/support/shared/unit/provider/file.rb b/spec/support/shared/unit/provider/file.rb
index a7c7af92f6..b3039f9be4 100644
--- a/spec/support/shared/unit/provider/file.rb
+++ b/spec/support/shared/unit/provider/file.rb
@@ -76,6 +76,7 @@ def setup_symlink
allow(File).to receive(:directory?).with(path).and_return(false)
allow(File).to receive(:writable?).with(path).and_return(true)
allow(file_symlink_class).to receive(:symlink?).with(path).and_return(true)
+ allow(file_symlink_class).to receive(:realpath).with(path).and_return(path)
end
allow(File).to receive(:directory?).with(enclosing_directory).and_return(true)
end
diff --git a/spec/unit/application/client_spec.rb b/spec/unit/application/client_spec.rb
index 8daba1d660..df1b6c99e2 100644
--- a/spec/unit/application/client_spec.rb
+++ b/spec/unit/application/client_spec.rb
@@ -326,7 +326,7 @@ describe Chef::Application::Client, "reconfigure" do
Chef::Config[:interval] = 600
allow(ChefConfig).to receive(:windows?).and_return(false)
expect(Chef::Application).to receive(:fatal!).with(
- /Unforked .* interval runs are disabled in .* 12\.
+ /Unforked .* interval runs are disabled by default\.
Configuration settings:
interval = 600 seconds
Enable .* interval runs by setting `:client_fork = true` in your config file or adding `--fork` to your command line options\./
diff --git a/spec/unit/application/exit_code_spec.rb b/spec/unit/application/exit_code_spec.rb
index e8a0072ff3..6800ad0de5 100644
--- a/spec/unit/application/exit_code_spec.rb
+++ b/spec/unit/application/exit_code_spec.rb
@@ -70,7 +70,7 @@ describe Chef::Application::ExitCode do
it "does write a warning on non-standard exit codes" do
expect(Chef::Log).to receive(:warn).with(
- /^Chef attempted to exit with a non-standard exit code of 151/)
+ /attempted to exit with a non-standard exit code of 151/)
expect(exit_codes.normalize_exit_code(151)).to eq(1)
end
diff --git a/spec/unit/application/knife_spec.rb b/spec/unit/application/knife_spec.rb
index 8a574b4d0f..f8f5560597 100644
--- a/spec/unit/application/knife_spec.rb
+++ b/spec/unit/application/knife_spec.rb
@@ -75,11 +75,7 @@ describe Chef::Application::Knife do
expect(@knife).to receive(:exit).with(0)
@knife.run
end
- if windows?
- expect(Chef::Config[:color]).to be_truthy
- else
- expect(Chef::Config[:color]).to be_truthy
- end
+ expect(Chef::Config[:color]).to be_truthy
end
context "when given fips flags" do
diff --git a/spec/unit/application/solo_spec.rb b/spec/unit/application/solo_spec.rb
index 1a4961f025..74f71a9115 100644
--- a/spec/unit/application/solo_spec.rb
+++ b/spec/unit/application/solo_spec.rb
@@ -64,7 +64,7 @@ describe Chef::Application::Solo do
it "should terminate with message" do
expect(Chef::Application).to receive(:fatal!).with(
- /Unforked .* interval runs are disabled in .* 12\.
+ /Unforked .* interval runs are disabled by default\.
Configuration settings:
interval = 600 seconds
Enable .* interval runs by setting `:client_fork = true` in your config file or adding `--fork` to your command line options\./
diff --git a/spec/unit/application_spec.rb b/spec/unit/application_spec.rb
index e76e21bddc..10dff0e250 100644
--- a/spec/unit/application_spec.rb
+++ b/spec/unit/application_spec.rb
@@ -87,6 +87,13 @@ describe Chef::Application do
@app.run
end
+ describe "when enforce_license is set to true" do
+ it "should check the license acceptance" do
+ expect(@app).to receive(:check_license_acceptance)
+ @app.run(enforce_license: true)
+ end
+ end
+
it "should run the actual application" do
expect(@app).to receive(:run_application).and_return(true)
@app.run
diff --git a/spec/unit/knife/bootstrap/train_connector_spec.rb b/spec/unit/knife/bootstrap/train_connector_spec.rb
new file mode 100644
index 0000000000..385a192648
--- /dev/null
+++ b/spec/unit/knife/bootstrap/train_connector_spec.rb
@@ -0,0 +1,216 @@
+#
+# Copyright:: Copyright (c) 2019 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 "ostruct"
+require "chef/knife/bootstrap/train_connector"
+
+describe Chef::Knife::Bootstrap::TrainConnector do
+ let(:protocol) { "mock" }
+ let(:family) { "unknown" }
+ let(:release) { "unknown" } # version
+ let(:name) { "unknown" }
+ let(:arch) { "x86_64" }
+ let(:connection_opts) { {} } # connection opts
+ let(:host_url) { "mock://user1@example.com" }
+ let(:mock_connection) { true }
+
+ subject do
+ # Example groups can still override by setting explicitly it in 'connection_opts'
+ tc = Chef::Knife::Bootstrap::TrainConnector.new(host_url, protocol, connection_opts)
+ tc
+ end
+
+ before(:each) do
+ if mock_connection
+ subject.connect!
+ subject.connection.mock_os(
+ family: family,
+ name: name,
+ release: release,
+ arch: arch
+ )
+ end
+ end
+
+ describe "platform helpers" do
+ context "on linux" do
+ let(:family) { "debian" }
+ let(:name) { "ubuntu" }
+ it "reports that it is linux and unix, because that is how train classifies it" do
+ expect(subject.unix?).to eq true
+ expect(subject.linux?).to eq true
+ expect(subject.windows?).to eq false
+ end
+ end
+ context "on unix" do
+ let(:family) { "os" }
+ let(:name) { "mac_os_x" }
+ it "reports only a unix OS" do
+ expect(subject.unix?).to eq true
+ expect(subject.linux?).to eq false
+ expect(subject.windows?).to eq false
+ end
+ end
+ context "on windows" do
+ let(:family) { "windows" }
+ let(:name) { "windows" }
+ it "reports only a windows OS" do
+ expect(subject.unix?).to eq false
+ expect(subject.linux?).to eq false
+ expect(subject.windows?).to eq true
+ end
+ end
+ end
+
+ describe "#connect!" do
+ it "establishes the connection to the remote host by waiting for it" do
+ expect(subject.connection).to receive(:wait_until_ready)
+ subject.connect!
+ end
+ end
+
+ describe "#initialize" do
+ let(:mock_connection) { false }
+
+ context "when provided target is a proper URL" do
+ let(:protocol) { "ssh" }
+ let(:host_url) { "mock://user1@localhost:2200" }
+ it "correctly configures the instance from the URL" do
+ expect(subject.config[:backend]).to eq "mock"
+ expect(subject.config[:port]).to eq 2200
+ expect(subject.config[:host]).to eq "localhost"
+ expect(subject.config[:user]).to eq "user1"
+ end
+
+ context "and conflicting options are given" do
+ let(:connection_opts) { { user: "user2", host: "example.com", port: 15 } }
+ it "resolves them from the URI" do
+ expect(subject.config[:backend]).to eq "mock"
+ expect(subject.config[:port]).to eq 2200
+ expect(subject.config[:host]).to eq "localhost"
+ expect(subject.config[:user]).to eq "user1"
+ end
+ end
+ end
+
+ context "when provided target is just a hostname" do
+ let(:host_url) { "localhost" }
+ let(:protocol) { "mock" }
+ it "correctly sets backend protocol from the default" do
+ expect(subject.config[:backend]).to eq "mock"
+ end
+
+ context "and options have been provided that are supported by the transport" do
+ let(:protocol) { "ssh" }
+ let(:connection_opts) { { port: 15, user: "user2" } }
+
+ it "sets hostname and transport from arguments and provided fields from options" do
+ expect(subject.config[:backend]).to eq "ssh"
+ expect(subject.config[:host]).to eq "localhost"
+ expect(subject.config[:user]).to eq "user2"
+ expect(subject.config[:port]).to eq 15
+ end
+
+ end
+
+ end
+
+ context "when provided target is just a an IP address" do
+ let(:host_url) { "127.0.0.1" }
+ let(:protocol) { "mock" }
+ it "correctly sets backend protocol from the default" do
+ expect(subject.config[:backend]).to eq "mock"
+ end
+ end
+ end
+
+ describe "#temp_dir" do
+ context "under windows" do
+ let(:family) { "windows" }
+ let(:name) { "windows" }
+
+ it "uses the windows command to create the temp dir" do
+ expected_command = Chef::Knife::Bootstrap::TrainConnector::MKTEMP_WIN_COMMAND
+ expect(subject).to receive(:run_command!).with(expected_command)
+ .and_return double("result", stdout: "C:/a/path")
+ expect(subject.temp_dir).to eq "C:/a/path"
+ end
+
+ end
+ context "under linux and unix-like" do
+ let(:family) { "debian" }
+ let(:name) { "ubuntu" }
+ it "uses the *nix command to create the temp dir and sets ownership to logged-in user" do
+ expected_command = Chef::Knife::Bootstrap::TrainConnector::MKTEMP_NIX_COMMAND
+ expect(subject).to receive(:run_command!).with(expected_command)
+ .and_return double("result", stdout: "/a/path")
+ expect(subject).to receive(:run_command!).with("chown user1 '/a/path'")
+ expect(subject.temp_dir).to eq "/a/path"
+ end
+
+ end
+ end
+ context "#upload_file_content!" do
+ it "creates a local file with expected content and uploads it" do
+ expect(subject).to receive(:upload_file!) do |local_path, remote_path|
+ expect(File.read(local_path)).to eq "test data"
+ expect(remote_path).to eq "/target/path"
+ end
+ subject.upload_file_content!("test data", "/target/path")
+ end
+ end
+
+ context "del_file" do
+ context "on windows" do
+ let(:family) { "windows" }
+ let(:name) { "windows" }
+ it "deletes the file with a windows command" do
+ expect(subject).to receive(:run_command!) do |cmd, &_handler|
+ expect(cmd).to match(/Test-Path "deleteme\.txt".*/)
+ end
+ subject.del_file!("deleteme.txt")
+ end
+ end
+ context "on unix-like" do
+ let(:family) { "debian" }
+ let(:name) { "ubuntu" }
+ it "deletes the file with a windows command" do
+ expect(subject).to receive(:run_command!) do |cmd, &_handler|
+ expect(cmd).to match(/rm -f "deleteme\.txt".*/)
+ end
+ subject.del_file!("deleteme.txt")
+ end
+ end
+ end
+
+ context "#run_command!" do
+ it "raises a RemoteExecutionFailed when the remote execution failed" do
+ command_result = double("results", stdout: "", stderr: "failed", exit_status: 1)
+ expect(subject).to receive(:run_command).and_return command_result
+
+ expect { subject.run_command!("test") }.to raise_error do |e|
+ expect(e.hostname).to eq subject.hostname
+ expect(e.class).to eq Chef::Knife::Bootstrap::RemoteExecutionFailed
+ expect(e.stderr).to eq "failed"
+ expect(e.stdout).to eq ""
+ expect(e.exit_status).to eq 1
+ end
+ end
+ end
+
+end
diff --git a/spec/unit/knife/bootstrap_spec.rb b/spec/unit/knife/bootstrap_spec.rb
index f54c8ac1d6..b8141d496f 100644
--- a/spec/unit/knife/bootstrap_spec.rb
+++ b/spec/unit/knife/bootstrap_spec.rb
@@ -25,23 +25,34 @@ describe Chef::Knife::Bootstrap do
let(:bootstrap_template) { nil }
let(:stderr) { StringIO.new }
let(:bootstrap_cli_options) { [ ] }
- let(:base_os) { :linux }
- let(:target_host) { double("TargetHost") }
+ let(:linux_test) { true }
+ let(:windows_test) { false }
+ let(:linux_test) { false }
+ let(:unix_test) { false }
+ let(:ssh_test) { false }
+
+ let(:connection) do
+ double("TrainConnector",
+ windows?: windows_test,
+ linux?: linux_test,
+ unix?: unix_test) end
let(:knife) do
Chef::Log.logger = Logger.new(StringIO.new)
Chef::Config[:knife][:bootstrap_template] = bootstrap_template unless bootstrap_template.nil?
+ expect(LicenseAcceptance::Acceptor).to receive(:check_and_persist!)
k = Chef::Knife::Bootstrap.new(bootstrap_cli_options)
allow(k.ui).to receive(:stderr).and_return(stderr)
allow(k).to receive(:encryption_secret_provided_ignore_encrypt_flag?).and_return(false)
- allow(k).to receive(:target_host).and_return target_host
+ allow(k).to receive(:connection).and_return connection
k.merge_configs
k
end
- before do
- allow(target_host).to receive(:base_os).and_return base_os
+ it "fails when LicenseAcceptance fails" do
+ expect(LicenseAcceptance::Acceptor).to receive(:check_and_persist!).and_raise("foo")
+ expect { k = Chef::Knife::Bootstrap.new(bootstrap_cli_options) }.to raise_error("foo")
end
context "#bootstrap_template" do
@@ -318,9 +329,10 @@ describe Chef::Knife::Bootstrap do
describe "specifying no_proxy with various entries" do
subject(:knife) do
+ expect(LicenseAcceptance::Acceptor).to receive(:check_and_persist!)
k = described_class.new
Chef::Config[:knife][:bootstrap_template] = template_file
- allow(k).to receive(:target_host).and_return target_host
+ allow(k).to receive(:connection).and_return connection
k.parse_options(options)
k.merge_configs
k
@@ -956,6 +968,7 @@ describe Chef::Knife::Bootstrap do
sudo: false,
verify_host_key: false,
port: 9999,
+ non_interactive: true,
}
end
@@ -1007,6 +1020,7 @@ describe Chef::Knife::Bootstrap do
sudo: true, # ccli
verify_host_key: false, # Config
port: 12, # cli
+ non_interactive: true,
}
end
@@ -1055,6 +1069,7 @@ describe Chef::Knife::Bootstrap do
sudo_options: "-H",
sudo_password: "blah",
verify_host_key: true,
+ non_interactive: true,
}
end
it "generates a config hash using the CLI options and pulling nothing from Chef::Config" do
@@ -1074,6 +1089,7 @@ describe Chef::Knife::Bootstrap do
keys_only: false,
sudo: false,
verify_host_key: true,
+ non_interactive: true,
}
end
it "populates appropriate defaults" do
@@ -1425,13 +1441,13 @@ describe Chef::Knife::Bootstrap do
before do
knife.config[:ssh_forward_agent] = true
end
- it "returns a configuration hash with forward_agent set to true" do
- expect(knife.ssh_opts).to eq({ forward_agent: true })
+ it "returns a configuration hash with forward_agent set to true. non-interactive is always true" do
+ expect(knife.ssh_opts).to eq({ forward_agent: true, non_interactive: true })
end
end
context "when ssh_forward_agent is not set" do
- it "returns a configuration hash with forward_agent set to false" do
- expect(knife.ssh_opts).to eq({ forward_agent: false })
+ it "returns a configuration hash with forward_agent set to false. non-interactive is always true" do
+ expect(knife.ssh_opts).to eq({ forward_agent: false, non_interactive: true })
end
end
end
@@ -1566,7 +1582,7 @@ describe Chef::Knife::Bootstrap do
end
it "performs the steps we expect to run a bootstrap" do
- expect(knife).to receive(:warn_and_map_deprecated_flags).ordered
+ expect(knife).to receive(:verify_deprecated_flags!).ordered
expect(knife).to receive(:validate_name_args!).ordered
expect(knife).to receive(:validate_protocol!).ordered
expect(knife).to receive(:validate_first_boot_attributes!).ordered
@@ -1578,7 +1594,7 @@ describe Chef::Knife::Bootstrap do
expect(knife).to receive(:render_template).and_return "content"
expect(knife).to receive(:upload_bootstrap).with("content").and_return "/remote/path.sh"
expect(knife).to receive(:perform_bootstrap).with("/remote/path.sh")
- expect(target_host).to receive(:del_file) # Make sure cleanup happens
+ expect(connection).to receive(:del_file!) # Make sure cleanup happens
knife.run
@@ -1588,33 +1604,35 @@ describe Chef::Knife::Bootstrap do
end
end
- describe "#warn_and_map_deprecated_flags" do
+ describe "#verify_deprecated_flags!" do
before do
Chef::Config[:silence_deprecation_warnings] = false
end
context "when a deprecated CLI flag is given on the CLI" do
- before do
- knife.config[:ssh_user] = "sshuser"
- knife.merge_configs
- end
+ let(:bootstrap_cli_options) { %w{--ssh-user sshuser} }
it "maps the key value to the new key and points the human to the new flag" do
- expect(knife.ui).to receive(:warn).with(/--ssh-user USER is deprecated. Use --connection-user USERNAME instead./)
- knife.warn_and_map_deprecated_flags
+ expect(knife.ui).to receive(:warn).with(/You provided --ssh-user. This flag is deprecated. Please use '--connection-user USERNAME' instead./)
+ knife.verify_deprecated_flags!
expect(knife.config[:connection_user]).to eq "sshuser"
end
end
context "when a deprecated CLI flag is given on the CLI, along with its replacement" do
- before do
- knife.config[:ssh_user] = "sshuser"
- knife.config[:connection_user] = "real-user"
- knife.merge_configs
+ let(:bootstrap_cli_options) { %w{--connection-user a --ssh-user b} }
+
+ it "informs the human that both are provided and exits" do
+ expect(knife.ui).to receive(:error).with(/You provided both --connection-user and --ssh-user.*Please use.*/m)
+ expect { knife.verify_deprecated_flags! }.to raise_error SystemExit
end
- it "warns that both are provided and takes the non-deprecated value" do
- expect(knife.ui).to receive(:warn).with(/You provided both --connection-user and --ssh-user.*'--connection-user real-user'/m)
- knife.warn_and_map_deprecated_flags
- expect(knife.config[:connection_user]).to eq "real-user"
+ end
+
+ context "when a deprecated boolean CLI flag is given on the CLI, and its non-boolean replacement is used" do
+ let(:bootstrap_cli_options) { %w{--prerelease} }
+ it "correctly maps the old boolean value to the new value" do
+ expect(knife.ui).to receive(:warn)
+ knife.verify_deprecated_flags!
+ expect(knife.config[:channel]).to eq "current"
end
end
end
@@ -1687,14 +1705,14 @@ describe Chef::Knife::Bootstrap do
let(:result_mock) { double("result", exit_status: exit_status, stderr: "A message") }
before do
- allow(target_host).to receive(:hostname).and_return "testhost"
+ allow(connection).to receive(:hostname).and_return "testhost"
end
it "runs the remote script and logs the output" do
expect(knife.ui).to receive(:info).with(/Bootstrapping.*/)
expect(knife).to receive(:bootstrap_command)
.with("/path.sh")
.and_return("sh /path.sh")
- expect(target_host)
+ expect(connection)
.to receive(:run_command)
.with("sh /path.sh")
.and_yield("output here")
@@ -1710,7 +1728,7 @@ describe Chef::Knife::Bootstrap do
expect(knife).to receive(:bootstrap_command)
.with("/path.sh")
.and_return("sh /path.sh")
- expect(target_host).to receive(:run_command).with("sh /path.sh").and_return result_mock
+ expect(connection).to receive(:run_command).with("sh /path.sh").and_return result_mock
expect { knife.perform_bootstrap("/path.sh") }.to raise_error(SystemExit)
end
end
@@ -1738,13 +1756,11 @@ describe Chef::Knife::Bootstrap do
context "when an auth failure occurs" do
let(:expected_error) do
- # TODO This is awkward and ugly. Requires some refactor of chef_core/error
- # to make it not so. See comment in rescue block of connect! for details.
- e = RuntimeError.new
- interim = RuntimeError.new
+ e = Train::Error.new
actual = Net::SSH::AuthenticationFailed.new
- allow(interim).to receive(:cause).and_return(actual)
- allow(e).to receive(:cause).and_return(interim)
+ # Simulate train's nested error - they wrap
+ # ssh/network errors in a TrainError.
+ allow(e).to receive(:cause).and_return(actual)
e
end
@@ -1754,7 +1770,7 @@ describe Chef::Knife::Bootstrap do
context "and password auth was used" do
before do
- knife.config[:connection_password] = "tryme"
+ allow(connection).to receive(:password_auth?).and_return true
end
it "re-raises the error so as not to resubmit the same failing password" do
@@ -1765,8 +1781,8 @@ describe Chef::Knife::Bootstrap do
context "and password auth was not used" do
before do
- knife.config.delete :connection_password
- allow(target_host).to receive(:user).and_return "testuser"
+ allow(connection).to receive(:password_auth?).and_return false
+ allow(connection).to receive(:user).and_return "testuser"
end
it "warns, prompts for password, then reconnects with a password-enabled configuration using the new password" do
@@ -1793,7 +1809,7 @@ describe Chef::Knife::Bootstrap do
describe "#bootstrap_context" do
context "under Windows" do
- let(:base_os) { :windows }
+ let(:windows_test) { true }
it "creates a WindowsBootstrapContext" do
require "chef/knife/core/windows_bootstrap_context"
expect(knife.bootstrap_context.class).to eq Chef::Knife::Core::WindowsBootstrapContext
@@ -1801,7 +1817,7 @@ describe Chef::Knife::Bootstrap do
end
context "under linux" do
- let(:base_os) { :linux }
+ let(:linux_test) { true }
it "creates a BootstrapContext" do
require "chef/knife/core/bootstrap_context"
expect(knife.bootstrap_context.class).to eq Chef::Knife::Core::BootstrapContext
@@ -1841,25 +1857,25 @@ describe Chef::Knife::Bootstrap do
describe "#upload_bootstrap" do
before do
- allow(target_host).to receive(:temp_dir).and_return(temp_dir)
- allow(target_host).to receive(:normalize_path) { |a| a }
+ allow(connection).to receive(:temp_dir).and_return(temp_dir)
+ allow(connection).to receive(:normalize_path) { |a| a }
end
let(:content) { "bootstrap script content" }
context "under Windows" do
- let(:base_os) { :windows }
+ let(:windows_test) { true }
let(:temp_dir) { "C:/Temp/bootstrap" }
- it "creates a bat file in the temp dir provided by target_host, using given content" do
- expect(target_host).to receive(:save_as_remote_file).with(content, "C:/Temp/bootstrap/bootstrap.bat")
+ it "creates a bat file in the temp dir provided by connection, using given content" do
+ expect(connection).to receive(:upload_file_content!).with(content, "C:/Temp/bootstrap/bootstrap.bat")
expect(knife.upload_bootstrap(content)).to eq "C:/Temp/bootstrap/bootstrap.bat"
end
end
context "under Linux" do
- let(:base_os) { :linux }
+ let(:linux_test) { true }
let(:temp_dir) { "/tmp/bootstrap" }
- it "creates a 'sh file in the temp dir provided by target_host, using given content" do
- expect(target_host).to receive(:save_as_remote_file).with(content, "/tmp/bootstrap/bootstrap.sh")
+ it "creates a 'sh file in the temp dir provided by connection, using given content" do
+ expect(connection).to receive(:upload_file_content!).with(content, "/tmp/bootstrap/bootstrap.sh")
expect(knife.upload_bootstrap(content)).to eq "/tmp/bootstrap/bootstrap.sh"
end
end
@@ -1867,14 +1883,14 @@ describe Chef::Knife::Bootstrap do
describe "#bootstrap_command" do
context "under Windows" do
- let(:base_os) { :windows }
+ let(:windows_test) { true }
it "prefixes the command to run under cmd.exe" do
expect(knife.bootstrap_command("autoexec.bat")).to eq "cmd.exe /C autoexec.bat"
end
end
context "under Linux" do
- let(:base_os) { :linux }
+ let(:linux_test) { true }
it "prefixes the command to run under sh" do
expect(knife.bootstrap_command("bootstrap")).to eq "sh bootstrap"
end
@@ -1883,14 +1899,14 @@ describe Chef::Knife::Bootstrap do
describe "#default_bootstrap_template" do
context "under Windows" do
- let(:base_os) { :windows }
+ let(:windows_test) { true }
it "is windows-chef-client-msi" do
expect(knife.default_bootstrap_template).to eq "windows-chef-client-msi"
end
end
context "under Linux" do
- let(:base_os) { :linux }
+ let(:linux_test) { true }
it "is chef-full" do
expect(knife.default_bootstrap_template).to eq "chef-full"
end
@@ -1899,15 +1915,15 @@ describe Chef::Knife::Bootstrap do
describe "#do_connect" do
let(:host_descriptor) { "example.com" }
- let(:target_host) { double("TargetHost") }
- let(:resolver_mock) { double("TargetResolver", targets: [ target_host ]) }
+ let(:connection) { double("TrainConnector") }
+ let(:connector_mock) { double("TargetResolver", targets: [ connection ]) }
before do
allow(knife).to receive(:host_descriptor).and_return host_descriptor
end
- it "resolves the target and connects it" do
- expect(ChefCore::TargetResolver).to receive(:new).and_return resolver_mock
- expect(target_host).to receive(:connect!)
+ it "creates a TrainConnector and connects it" do
+ expect(Chef::Knife::Bootstrap::TrainConnector).to receive(:new).and_return connection
+ expect(connection).to receive(:connect!)
knife.do_connect({})
end
end
diff --git a/spec/unit/knife/client_create_spec.rb b/spec/unit/knife/client_create_spec.rb
index 17d18d084e..fe25dccfbf 100644
--- a/spec/unit/knife/client_create_spec.rb
+++ b/spec/unit/knife/client_create_spec.rb
@@ -28,7 +28,6 @@ describe Chef::Knife::ClientCreate do
{
"name" => "adam",
"validator" => false,
- "admin" => false,
}
end
@@ -102,14 +101,9 @@ describe Chef::Knife::ClientCreate do
expect(client.name).to eq("adam")
end
- it "by default it is not an admin" do
- knife.run
- expect(client.admin).to be_falsey
- end
-
it "by default it is not a validator" do
knife.run
- expect(client.admin).to be_falsey
+ expect(client.validator).to be_falsey
end
it "by default it should set create_key to true" do
@@ -136,17 +130,6 @@ describe Chef::Knife::ClientCreate do
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"
diff --git a/spec/unit/knife/core/bootstrap_context_spec.rb b/spec/unit/knife/core/bootstrap_context_spec.rb
index 7b12177ab9..d57e254793 100644
--- a/spec/unit/knife/core/bootstrap_context_spec.rb
+++ b/spec/unit/knife/core/bootstrap_context_spec.rb
@@ -46,21 +46,21 @@ describe Chef::Knife::Core::BootstrapContext do
expect { described_class.new(config, run_list, chef_config) }.not_to raise_error
end
- it "runs chef with the first-boot.json with no environment specified" do
- expect(bootstrap_context.start_chef).to eq "chef-client -j /etc/chef/first-boot.json"
+ it "runs chef with the first-boot.json with no environment other than chef-license acceptance specified" do
+ expect(bootstrap_context.start_chef).to eq "CHEF_LICENSE=accept chef-client -j /etc/chef/first-boot.json"
end
describe "when in verbosity mode" do
let(:config) { { verbosity: 2, color: true } }
it "adds '-l debug' when verbosity is >= 2" do
- expect(bootstrap_context.start_chef).to eq "chef-client -j /etc/chef/first-boot.json -l debug"
+ expect(bootstrap_context.start_chef).to eq "CHEF_LICENSE=accept chef-client -j /etc/chef/first-boot.json -l debug"
end
end
describe "when no color value has been set in config" do
let(:config) { { color: false } }
it "adds '--no-color' when color is false" do
- expect(bootstrap_context.start_chef).to eq "chef-client -j /etc/chef/first-boot.json --no-color"
+ expect(bootstrap_context.start_chef).to eq "CHEF_LICENSE=accept chef-client -j /etc/chef/first-boot.json --no-color"
end
end
@@ -82,7 +82,7 @@ describe Chef::Knife::Core::BootstrapContext do
describe "alternate chef-client path" do
let(:chef_config) { { chef_client_path: "/usr/local/bin/chef-client" } }
it "runs chef-client from another path when specified" do
- expect(bootstrap_context.start_chef).to eq "/usr/local/bin/chef-client -j /etc/chef/first-boot.json"
+ expect(bootstrap_context.start_chef).to eq "CHEF_LICENSE=accept /usr/local/bin/chef-client -j /etc/chef/first-boot.json"
end
end
@@ -105,7 +105,7 @@ describe Chef::Knife::Core::BootstrapContext do
describe "when bootstrapping into a specific environment" do
let(:config) { { environment: "prodtastic", color: true } }
it "starts chef in the configured environment" do
- expect(bootstrap_context.start_chef).to eq("chef-client -j /etc/chef/first-boot.json -E prodtastic")
+ expect(bootstrap_context.start_chef).to eq("CHEF_LICENSE=accept chef-client -j /etc/chef/first-boot.json -E prodtastic")
end
end
@@ -156,25 +156,6 @@ describe Chef::Knife::Core::BootstrapContext do
end
end
- describe "when a bootstrap_version is specified" do
- let(:chef_config) do
- {
- knife: { bootstrap_version: "11.12.4" },
- }
- end
-
- it "should send the full version to the installer" do
- expect(bootstrap_context.latest_current_chef_version_string).to eq("-v 11.12.4")
- end
- end
-
- describe "when a bootstrap_version is not specified" do
- it "should send the latest current to the installer" do
- # Intentionally hard coded in order not to replicate the logic.
- expect(bootstrap_context.latest_current_chef_version_string).to eq("-v #{Chef::VERSION.to_i}")
- end
- end
-
describe "ssl_verify_mode" do
it "isn't set in the config_content by default" do
expect(bootstrap_context.config_content).not_to include("ssl_verify_mode")
@@ -292,4 +273,28 @@ describe Chef::Knife::Core::BootstrapContext do
end
end
+
+ describe "#version_to_install" do
+ context "when bootstrap_version is provided" do
+ let(:chef_config) { { knife: { bootstrap_version: "awesome" } } }
+
+ it "returns bootstrap_version" do
+ expect(bootstrap_context.version_to_install).to eq "awesome"
+ end
+ end
+
+ context "when bootstrap_version is not provided" do
+ let(:config) { { channel: "stable" } }
+ it "returns the currently running major version out of Chef::VERSION" do
+ expect(bootstrap_context.version_to_install).to eq Chef::VERSION.split(".").first
+ end
+ end
+
+ context "and channel is other than stable" do
+ let(:config) { { channel: "unstable" } }
+ it "returns the version string 'latest'" do
+ expect(bootstrap_context.version_to_install).to eq "latest"
+ end
+ end
+ end
end
diff --git a/spec/unit/knife/core/windows_bootstrap_context_spec.rb b/spec/unit/knife/core/windows_bootstrap_context_spec.rb
index 3ab173f316..561e43eefc 100644
--- a/spec/unit/knife/core/windows_bootstrap_context_spec.rb
+++ b/spec/unit/knife/core/windows_bootstrap_context_spec.rb
@@ -176,29 +176,30 @@ describe Chef::Knife::Core::WindowsBootstrapContext do
end
end
- describe "latest_current_windows_chef_version_query" do
- it "returns the major version of the current version of Chef" do
- stub_const("Chef::VERSION", "15.1.2")
- expect(bootstrap_context.latest_current_windows_chef_version_query).to eq("&v=15")
- end
-
- end
-
describe "msi_url" do
- context "when config option is not set" do
+ context "when msi_url config option is not set" do
+ let(:config) { { channel: "stable" } }
before do
- expect(bootstrap_context).to receive(:latest_current_windows_chef_version_query).and_return("&v=something")
+ expect(bootstrap_context).to receive(:version_to_install).and_return("something")
end
it "returns a chef.io msi url with minimal url parameters" do
- reference_url = "https://www.chef.io/chef/download?p=windows&v=something"
+ reference_url = "https://www.chef.io/chef/download?p=windows&channel=stable&v=something"
expect(bootstrap_context.msi_url).to eq(reference_url)
end
it "returns a chef.io msi url with provided url parameters substituted" do
- reference_url = "https://www.chef.io/chef/download?p=windows&pv=machine&m=arch&DownloadContext=ctx&v=something"
+ reference_url = "https://www.chef.io/chef/download?p=windows&pv=machine&m=arch&DownloadContext=ctx&channel=stable&v=something"
expect(bootstrap_context.msi_url("machine", "arch", "ctx")).to eq(reference_url)
end
+
+ context "when a channel is provided in config" do
+ let(:config) { { channel: "current" } }
+ it "returns a chef.io msi url with the requested channel" do
+ reference_url = "https://www.chef.io/chef/download?p=windows&channel=current&v=something"
+ expect(bootstrap_context.msi_url).to eq(reference_url)
+ end
+ end
end
context "when msi_url config option is set" do
@@ -220,6 +221,8 @@ describe Chef::Knife::Core::WindowsBootstrapContext do
let(:bootstrap) { Chef::Knife::Bootstrap.new(["--bootstrap-install-command", "chef-client"]) }
before do
bootstrap.config[:bootstrap_install_command] = "chef-client"
+ @old_env = ENV["CHEF_LICENSE"]
+ ENV["CHEF_LICENSE"] = "accept"
end
it "sets the bootstrap_install_command option under Chef::Config::Knife object" do
@@ -229,6 +232,7 @@ describe Chef::Knife::Core::WindowsBootstrapContext do
after do
bootstrap.config.delete(:bootstrap_install_command)
Chef::Config[:knife].delete(:bootstrap_install_command)
+ ENV["CHEF_LICENSE"] = @old_env
end
end
@@ -245,6 +249,8 @@ describe Chef::Knife::Core::WindowsBootstrapContext do
let(:bootstrap) { Chef::Knife::Bootstrap.new(["--bootstrap-install-command", "chef-client"]) }
before do
bootstrap.config[:bootstrap_install_command] = "chef-client"
+ @old_env = ENV["CHEF_LICENSE"]
+ ENV["CHEF_LICENSE"] = "accept"
end
it "sets the bootstrap_install_command option under Chef::Config::Knife object" do
@@ -254,6 +260,7 @@ describe Chef::Knife::Core::WindowsBootstrapContext do
after do
bootstrap.config.delete(:bootstrap_install_command)
Chef::Config[:knife].delete(:bootstrap_install_command)
+ ENV["CHEF_LICENSE"] = @old_env
end
end
@@ -264,4 +271,12 @@ describe Chef::Knife::Core::WindowsBootstrapContext do
end
end
end
+
+ describe "#start_chef" do
+ it "the command includes the license acceptance environment variable" do
+ expect(bootstrap_context.start_chef).to match(/SET "CHEF_LICENSE=accept"\n/m)
+ end
+
+ end
+
end
diff --git a/spec/unit/knife_spec.rb b/spec/unit/knife_spec.rb
index f48ab4019c..6fcb831531 100644
--- a/spec/unit/knife_spec.rb
+++ b/spec/unit/knife_spec.rb
@@ -299,37 +299,26 @@ describe Chef::Knife do
expect(Chef::Config[:log_level]).to eql(:warn)
end
- it "prefers the default value if no config or command line value is present and reports the source as default" do
+ it "prefers the default value from option definition if no config or command line value is present and reports the source as default" do
knife_command = KnifeSpecs::TestYourself.new([]) # empty argv
knife_command.configure_chef
expect(knife_command.config[:opt_with_default]).to eq("default-value")
+ expect(knife_command.config_source(:opt_with_default)).to eq(:cli_default)
end
- it "prefers a value in Chef::Config[:knife] to the default" do
+ it "prefers a value in Chef::Config[:knife] to the default and reports the source as config" do
Chef::Config[:knife][:opt_with_default] = "from-knife-config"
knife_command = KnifeSpecs::TestYourself.new([]) # empty argv
knife_command.configure_chef
expect(knife_command.config[:opt_with_default]).to eq("from-knife-config")
- expect(knife_command.config_source(:opt_with_default)).to eq (:config)
- end
-
- it "correctly reports Chef::Config as the source when a a config entry comes from there" do
- Chef::Config[:knife][:opt_with_default] = "from-knife-config"
- knife_command = KnifeSpecs::TestYourself.new([]) # empty argv
- knife_command.configure_chef
- expect(knife_command.config_source(:opt_with_default)).to eq (:config)
+ expect(knife_command.config_source(:opt_with_default)).to eq(:config)
end
it "prefers a value from command line over Chef::Config and the default and reports the source as CLI" do
knife_command = KnifeSpecs::TestYourself.new(["-D", "from-cli"])
knife_command.configure_chef
expect(knife_command.config[:opt_with_default]).to eq("from-cli")
- expect(knife_command.config_source(:opt_with_default)).to eq (:cli)
- end
- it "correctly reports CLI as the source when a config entry comes from the CLI" do
- knife_command = KnifeSpecs::TestYourself.new(["-D", "from-cli"])
- knife_command.configure_chef
- expect(knife_command.config_source(:opt_with_default)).to eq (:cli)
+ expect(knife_command.config_source(:opt_with_default)).to eq(:cli)
end
it "merges `listen` config to Chef::Config" do
@@ -472,7 +461,7 @@ describe Chef::Knife do
allow(knife).to receive(:username).and_return("sadpanda")
knife.run_with_pretty_exceptions
expect(stderr.string).to match(%r{ERROR: You authenticated successfully to http.+ as sadpanda but you are not authorized for this action})
- expect(stderr.string).to match(%r{ERROR: There are proxy servers configured, your .* server may need to be added to NO_PROXY.})
+ expect(stderr.string).to match(%r{ERROR: There are proxy servers configured, your server url may need to be added to NO_PROXY.})
expect(stderr.string).to match(%r{Response: y u no administrator})
end
end
@@ -508,9 +497,9 @@ describe Chef::Knife do
allow(knife).to receive(:run).and_raise(Net::HTTPClientException.new("406 Not Acceptable", response))
knife.run_with_pretty_exceptions
- expect(stderr.string).to match(/The request that .* sent was using API version 10000000/)
- expect(stderr.string).to match(/The .* server you sent the request to supports a min API verson of 0 and a max API version of 1/)
- expect(stderr.string).to match(/Please either update your .* client or server to be a compatible set/)
+ expect(stderr.string).to match(/The request that .* sent was using API version 10000000./)
+ expect(stderr.string).to match(/The server you sent the request to supports a min API verson of 0 and a max API version of 1./)
+ expect(stderr.string).to match(/Please either update your .* or the server to be a compatible set./)
end
it "formats 500s nicely" do
@@ -588,7 +577,7 @@ describe Chef::Knife do
expected_message = <<~MSG
ERROR: Could not establish a secure connection to the server.
Use `.* ssl check` to troubleshoot your SSL configuration.
- If your .* Server uses a self-signed certificate, you can use
+ If your server uses a self-signed certificate, you can use
`.* ssl fetch` to make .* trust the server's certificates.
MSG
expect(stderr.string).to match(expected_message)
diff --git a/spec/unit/node_map_spec.rb b/spec/unit/node_map_spec.rb
index 9c161f3893..7c867857dc 100644
--- a/spec/unit/node_map_spec.rb
+++ b/spec/unit/node_map_spec.rb
@@ -145,14 +145,14 @@ describe Chef::NodeMap do
describe "deleting classes" do
it "deletes a class and removes the mapping completely" do
node_map.set(:thing, Bar)
- expect( node_map.delete_class(Bar) ).to include({ thing: [{ klass: Bar, cookbook_override: false, core_override: false }] })
+ expect( node_map.delete_class(Bar) ).to include({ thing: [{ klass: Bar, cookbook_override: false, core_override: false, target_mode: nil }] })
expect( node_map.get(node, :thing) ).to eql(nil)
end
it "deletes a class and leaves the mapping that still has an entry" do
node_map.set(:thing, Bar)
node_map.set(:thing, Foo)
- expect( node_map.delete_class(Bar) ).to eql({ thing: [{ klass: Bar, cookbook_override: false, core_override: false }] })
+ expect( node_map.delete_class(Bar) ).to eql({ thing: [{ klass: Bar, cookbook_override: false, core_override: false, target_mode: nil }] })
expect( node_map.get(node, :thing) ).to eql(Foo)
end
@@ -160,7 +160,7 @@ describe Chef::NodeMap do
node_map.set(:thing1, Bar)
node_map.set(:thing2, Bar)
node_map.set(:thing2, Foo)
- expect( node_map.delete_class(Bar) ).to eql({ thing1: [{ klass: Bar, cookbook_override: false, core_override: false }], thing2: [{ klass: Bar, cookbook_override: false, core_override: false }] })
+ expect( node_map.delete_class(Bar) ).to eql({ thing1: [{ klass: Bar, cookbook_override: false, core_override: false, target_mode: nil }], thing2: [{ klass: Bar, cookbook_override: false, core_override: false, target_mode: nil }] })
expect( node_map.get(node, :thing1) ).to eql(nil)
expect( node_map.get(node, :thing2) ).to eql(Foo)
end
@@ -210,6 +210,40 @@ describe Chef::NodeMap do
end
end
+ # When in target mode, only match when target_mode is explicitly supported
+ context "when target mode is enabled" do
+ before do
+ allow(Chef::Config).to receive(:target_mode?).and_return(true)
+ end
+
+ it "returns the value when target_mode matches" do
+ node_map.set(:something, :network, target_mode: true)
+ expect(node_map.get(node, :something)).to eql(:network)
+ end
+
+ it "returns nil when target_mode does not match" do
+ node_map.set(:something, :local, target_mode: false)
+ expect(node_map.get(node, :something)).to eql(nil)
+ end
+ end
+
+ # When not in target mode, match regardless of target_mode filter
+ context "when target mode is not enabled" do
+ before do
+ allow(Chef::Config).to receive(:target_mode?).and_return(false)
+ end
+
+ it "returns the value if target_mode matches" do
+ node_map.set(:something, :local, target_mode: true)
+ expect(node_map.get(node, :something)).to eql(:local)
+ end
+
+ it "returns the value if target_mode does not match" do
+ node_map.set(:something, :local, target_mode: false)
+ expect(node_map.get(node, :something)).to eql(:local)
+ end
+ end
+
describe "locked mode" do
context "while unlocked" do
it "allows setting the same key twice" do
diff --git a/spec/unit/provider/cron_spec.rb b/spec/unit/provider/cron_spec.rb
index 98c525762b..6bfc18c359 100644
--- a/spec/unit/provider/cron_spec.rb
+++ b/spec/unit/provider/cron_spec.rb
@@ -690,33 +690,136 @@ describe Chef::Provider::Cron do
end
context "when there is a crontab with a matching and identical section" do
- before :each do
- @provider.cron_exists = true
- allow(@provider).to receive(:cron_different?).and_return(false)
- allow(@provider).to receive(:read_crontab).and_return(<<~CRONTAB)
- 0 2 * * * /some/other/command
+ context "when environment variable is not used" do
+ before :each do
+ @provider.cron_exists = true
+ allow(@provider).to receive(:cron_different?).and_return(false)
+ allow(@provider).to receive(:read_crontab).and_return(<<~CRONTAB)
+ 0 2 * * * /some/other/command
- # Chef Name: cronhole some stuff
- * 5 * * * /bin/true
+ # Chef Name: cronhole some stuff
+ SHELL=/bash
+ * 5 * * * /bin/true
- # Another comment
- CRONTAB
- end
+ # Another comment
+ CRONTAB
+ end
- it "should not update the crontab" do
- expect(@provider).not_to receive(:write_crontab)
- @provider.run_action(:create)
+ it "should not update the crontab" do
+ expect(@provider).not_to receive(:write_crontab)
+ @provider.run_action(:create)
+ end
+
+ it "should not mark the resource as updated" do
+ @provider.run_action(:create)
+ expect(@new_resource).not_to be_updated_by_last_action
+ end
+
+ it "should log nothing changed" do
+ expect(logger).to receive(:trace).with("Found cron '#{@new_resource.name}'")
+ expect(logger).to receive(:trace).with("Skipping existing cron entry '#{@new_resource.name}'")
+ @provider.run_action(:create)
+ end
end
- it "should not mark the resource as updated" do
- @provider.run_action(:create)
- expect(@new_resource).not_to be_updated_by_last_action
+ context "when environment variable is used" do
+ before :each do
+ @provider.cron_exists = true
+ allow(@provider).to receive(:read_crontab).and_return(<<~CRONTAB)
+ 0 2 * * * /some/other/command
+
+ # Chef Name: cronhole some stuff
+ SHELL=/bash
+ ENV=environment
+ 30 * * * * /bin/true
+
+ # Another comment
+ CRONTAB
+ end
+ context "contains an entry that can also be specified as a `property`" do
+ before :each do
+ @new_resource.environment = { "SHELL" => "/bash", "ENV" => "environment" }
+ end
+
+ it "should raise a warning for idempotency" do
+ expect(logger).to receive(:warn).with("cronhole some stuff: the environment property contains the 'SHELL' variable, which should be set separately as a property.")
+ @provider.run_action(:create)
+ end
+
+ it "should not update the crontab" do
+ expect(@provider).not_to receive(:write_crontab)
+ @provider.run_action(:create)
+ end
+
+ it "should not mark the resource as updated" do
+ expect(@new_resource).not_to be_updated_by_last_action
+ @provider.run_action(:create)
+ end
+ end
+
+ context "contains an entry that cannot be specified as a `property`" do
+ before :each do
+ @new_resource.environment = { "ENV" => "environment" }
+ @new_resource.shell "/bash"
+ end
+
+ it "should not raise a warning for idempotency" do
+ expect(logger).not_to receive(:warn).with("cronhole some stuff: the environment property contains the 'SHELL' variable, which should be set separately as a property.")
+ @provider.run_action(:create)
+ end
+
+ it "should not update the crontab" do
+ expect(@provider).not_to receive(:write_crontab)
+ @provider.run_action(:create)
+ end
+
+ it "should not mark the resource as updated" do
+ @provider.run_action(:create)
+ expect(@new_resource).not_to be_updated_by_last_action
+ end
+ end
end
- it "should log nothing changed" do
- expect(logger).to receive(:trace).with("Found cron '#{@new_resource.name}'")
- expect(logger).to receive(:trace).with("Skipping existing cron entry '#{@new_resource.name}'")
- @provider.run_action(:create)
+ context "when environment variable is used with property" do
+ before :each do
+ @provider.cron_exists = true
+ allow(@provider).to receive(:read_crontab).and_return(<<~CRONTAB)
+ 0 2 * * * /some/other/command
+
+ # Chef Name: cronhole some stuff
+ SHELL=/bash
+ ENV=environment
+ 30 * * * * /bin/true
+
+ # Another comment
+ CRONTAB
+ end
+
+ context "when environment variable is same as property" do
+ it "should throw an error" do
+ @new_resource.shell "/bash"
+ @new_resource.environment "SHELL" => "/bash"
+ expect do
+ @provider.run_action(:create)
+ end.to raise_error(Chef::Exceptions::Cron, /cronhole some stuff: the 'SHELL' property is set and environment property also contains the 'SHELL' variable. Remove the variable from the environment property./)
+ end
+ end
+
+ context "when environment variable is different from property" do
+ it "should not update the crontab" do
+ @new_resource.shell "/bash"
+ @new_resource.environment "ENV" => "environment"
+ expect(@provider).not_to receive(:write_crontab)
+ @provider.run_action(:create)
+ end
+
+ it "should not mark the resource as updated" do
+ @new_resource.shell "/bash"
+ @new_resource.environment "ENV" => "environment"
+ @provider.run_action(:create)
+ expect(@new_resource).not_to be_updated_by_last_action
+ end
+ end
end
end
end
diff --git a/spec/unit/resource/windows_task_spec.rb b/spec/unit/resource/windows_task_spec.rb
index 96482d3d56..b152d879f6 100644
--- a/spec/unit/resource/windows_task_spec.rb
+++ b/spec/unit/resource/windows_task_spec.rb
@@ -61,6 +61,10 @@ describe Chef::Resource::WindowsTask, :windows_only do
expect(resource.stop_if_going_on_batteries).to eql(false)
end
+ it "sets the default value for start_when_available as false" do
+ expect(resource.start_when_available).to eql(false)
+ end
+
context "when frequency is not provided" do
it "raises ArgumentError to provide frequency" do
expect { resource.after_created }.to raise_error(ArgumentError, "Frequency needs to be provided. Valid frequencies are :minute, :hourly, :daily, :weekly, :monthly, :once, :on_logon, :onstart, :on_idle, :none." )
diff --git a/spec/unit/run_context/cookbook_compiler_spec.rb b/spec/unit/run_context/cookbook_compiler_spec.rb
index c3a4c1b98f..3c585cf444 100644
--- a/spec/unit/run_context/cookbook_compiler_spec.rb
+++ b/spec/unit/run_context/cookbook_compiler_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Daniel DeLeo (<dan@chef.io>)
-# Copyright:: Copyright 2012-2018, Chef Software Inc.
+# Copyright:: Copyright 2012-2019, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -51,6 +51,14 @@ describe Chef::RunContext::CookbookCompiler do
Chef::RunContext::CookbookCompiler.new(run_context, run_list_expansion, events)
end
+ describe "loading a cookbook fully" do
+ it "does not error" do
+ run_context.instance_variable_set(:@cookbook_compiler, compiler)
+ node.run_list("dependency1::default")
+ compiler.compile
+ end
+ end
+
describe "loading attribute files" do
# Attribute files in the fixture data will append their
diff --git a/spec/unit/train_transport_spec.rb b/spec/unit/train_transport_spec.rb
new file mode 100644
index 0000000000..b56c7e1104
--- /dev/null
+++ b/spec/unit/train_transport_spec.rb
@@ -0,0 +1,79 @@
+#
+# Author:: Bryan McLellan (<btm@loftninjas.org>)
+# Copyright:: Copyright 2019, 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::TrainTransport do
+ describe "load_credentials" do
+ let(:transport) { Chef::TrainTransport.new }
+ let(:good_credentials) { { "switch.cisco.com" => { "user" => "cisco", "password" => "cisco", "enable_password" => "secret" } } }
+
+ before do
+ allow(Chef::TrainTransport).to receive(:parse_credentials_file).and_return(good_credentials)
+ end
+
+ it "matches credentials when they exist" do
+ expect(Chef::TrainTransport.load_credentials("switch.cisco.com")[:user]).to eq("cisco")
+ expect(Chef::TrainTransport.load_credentials("switch.cisco.com")[:password]).to eq("cisco")
+ expect(Chef::TrainTransport.load_credentials("switch.cisco.com")[:enable_password]).to eq("secret")
+ end
+
+ it "returns nil if there is no match" do
+ expect(Chef::TrainTransport.load_credentials("router.unicorns.com")).to be_nil
+ end
+
+ # [foo.example.org] => {"foo"=>{"example"=>{"org"=>{}}}}
+ # ['foo.example.org'] => {"foo.example.org"=>{}}
+ it "warns if the host has been split by toml" do
+ allow(Chef::TrainTransport).to receive(:parse_credentials_file).and_return({ "foo" => { "example" => { "org" => {} } } })
+ expect(Chef::Log).to receive(:warn).with(/as a Hash/)
+ expect(Chef::Log).to receive(:warn).with(/Hostnames must be surrounded by single quotes/)
+ expect(Chef::TrainTransport.load_credentials("foo.example.org")).to be_nil
+ end
+ end
+
+ describe "credentials_file_path" do
+
+ context "when a file path is specified by a config" do
+ let(:cred_file_path) { "/somewhere/credentials" }
+
+ before do
+ tm_config = double("Config Context", host: "foo.example.org", credentials_file: cred_file_path)
+ allow(Chef::Config).to receive(:target_mode).and_return(tm_config)
+ end
+
+ it "returns the path if it exists" do
+ allow(File).to receive(:exists?).with(cred_file_path).and_return(true)
+ expect(Chef::TrainTransport.credentials_file_path).to eq(cred_file_path)
+ end
+
+ it "raises an error if it does not exist" do
+ allow(File).to receive(:exists?).with(cred_file_path).and_return(false)
+ expect { Chef::TrainTransport.credentials_file_path }.to raise_error(ArgumentError, /does not exist/)
+ end
+ end
+
+ it "returns the path to the default config file if it exists" do
+ cred_file_path = Chef::Config.platform_specific_path("/etc/chef/foo.example.org/credentials")
+ tm_config = double("Config Context", host: "foo.example.org", credentials_file: nil)
+ allow(Chef::Config).to receive(:target_mode).and_return(tm_config)
+ allow(File).to receive(:exists?).with(cred_file_path).and_return(true)
+ expect(Chef::TrainTransport.credentials_file_path).to eq(cred_file_path)
+ end
+ end
+end