1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
|
require "support/shared/integration/integration_helper"
require "chef/mixin/shell_out"
require "tiny_server"
require "tmpdir"
require "chef/platform"
describe "chef-client" do
include IntegrationSupport
include Chef::Mixin::ShellOut
let(:chef_dir) { File.join(File.dirname(__FILE__), "..", "..", "..", "bin") }
# Invoke `chef-client` as `ruby PATH/TO/chef-client`. This ensures the
# following constraints are satisfied:
# * Windows: windows can only run batch scripts as bare executables. Rubygems
# creates batch wrappers for installed gems, but we don't have batch wrappers
# in the source tree.
# * Other `chef-client` in PATH: A common case is running the tests on a
# 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(:critical_env_vars) { %w{PATH RUBYOPT BUNDLE_GEMFILE GEM_PATH}.map { |o| "#{o}=#{ENV[o]}" } .join(" ") }
when_the_repository "uses RFC 062 defined exit codes" do
def setup_client_rb
file "config/client.rb", <<~EOM
local_mode true
cookbook_path "#{path_to('cookbooks')}"
EOM
end
def setup_client_rb_with_audit_mode
file "config/client.rb", <<~EOM
local_mode true
cookbook_path "#{path_to('cookbooks')}"
audit_mode :audit_only
EOM
end
def run_chef_client_and_expect_exit_code(exit_code)
shell_out!("#{chef_client} -c \"#{path_to('config/client.rb')}\" -o 'x::default'",
cwd: chef_dir,
returns: [exit_code])
end
context "has a cookbook" do
context "with a library" do
context "which cannot be loaded" do
before do
file "cookbooks/x/recipes/default.rb", ""
file "cookbooks/x/libraries/error.rb", "require 'does/not/exist'"
end
it "exits with GENERIC_FAILURE, 1" do
setup_client_rb
run_chef_client_and_expect_exit_code 1
end
end
end
context "with an audit recipe" do
context "which fails" do
before do
file "cookbooks/x/recipes/default.rb", <<~RECIPE
control_group "control group without top level control" do
it "should fail" do
expect(4 - 4).to eq(1)
end
end
RECIPE
end
it "exits with AUDIT_MODE_FAILURE, 42" do
setup_client_rb_with_audit_mode
run_chef_client_and_expect_exit_code 42
end
end
end
context "with a recipe" do
context "which throws an error" do
before { file "cookbooks/x/recipes/default.rb", "raise 'BOOM'" }
it "exits with GENERIC_FAILURE, 1" do
setup_client_rb
run_chef_client_and_expect_exit_code 1
end
end
context "with a recipe which calls Chef::Application.fatal with a non-RFC exit code" do
before { file "cookbooks/x/recipes/default.rb", "Chef::Application.fatal!('BOOM', 123)" }
it "exits with the GENERIC_FAILURE exit code, 1" do
setup_client_rb
run_chef_client_and_expect_exit_code 1
end
end
context "with a recipe which calls Chef::Application.exit with a non-RFC exit code" do
before { file "cookbooks/x/recipes/default.rb", "Chef::Application.exit!('BOOM', 231)" }
it "exits with the GENERIC_FAILURE exit code, 1" do
setup_client_rb
run_chef_client_and_expect_exit_code 1
end
end
context "when a reboot exception is raised (like from the reboot resource)" do
before do
file "cookbooks/x/recipes/default.rb", <<~EOM
raise Chef::Exceptions::Reboot.new
EOM
end
it "exits with REBOOT_SCHEDULED, 35" do
setup_client_rb
run_chef_client_and_expect_exit_code 35
end
end
context "when an attempt to reboot fails (like from the reboot resource)" do
before do
file "cookbooks/x/recipes/default.rb", <<~EOM
raise Chef::Exceptions::RebootFailed.new
EOM
end
it "exits with REBOOT_FAILED, 41" do
setup_client_rb
run_chef_client_and_expect_exit_code 41
end
end
end
end
end
end
|