chef-apply 0.4.6 → 0.4.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Gemfile +1 -7
- data/chef-apply.gemspec +3 -3
- data/lib/chef_apply/version.rb +1 -1
- metadata +3 -38
- data/README.md +0 -62
- data/spec/fixtures/custom_config.toml +0 -2
- data/spec/integration/chef-run_spec.rb +0 -41
- data/spec/integration/fixtures/chef_help.out +0 -70
- data/spec/integration/fixtures/chef_version.out +0 -1
- data/spec/integration/spec_helper.rb +0 -55
- data/spec/spec_helper.rb +0 -154
- data/spec/support/matchers/output_to_terminal.rb +0 -36
- data/spec/unit/action/base_spec.rb +0 -60
- data/spec/unit/action/converge_target/ccr_failure_mapper_spec.rb +0 -106
- data/spec/unit/action/converge_target_spec.rb +0 -400
- data/spec/unit/action/generate_local_policy_spec.rb +0 -114
- data/spec/unit/action/generate_temp_cookbook/recipe_lookup_spec.rb +0 -122
- data/spec/unit/action/generate_temp_cookbook/temp_cookbook_spec.rb +0 -198
- data/spec/unit/action/generate_temp_cookbook_spec.rb +0 -73
- data/spec/unit/action/install_chef/minimum_chef_version_spec.rb +0 -90
- data/spec/unit/action/install_chef_spec.rb +0 -164
- data/spec/unit/cli/options_spec.rb +0 -75
- data/spec/unit/cli/validation_spec.rb +0 -81
- data/spec/unit/cli_spec.rb +0 -475
- data/spec/unit/config_spec.rb +0 -70
- data/spec/unit/file_fetcher_spec.rb +0 -40
- data/spec/unit/fixtures/multi-error.out +0 -2
- data/spec/unit/log_spec.rb +0 -37
- data/spec/unit/startup_spec.rb +0 -323
- data/spec/unit/target_host/linux_spec.rb +0 -57
- data/spec/unit/target_host/windows_spec.rb +0 -43
- data/spec/unit/target_host_spec.rb +0 -297
- data/spec/unit/target_resolver_spec.rb +0 -380
- data/spec/unit/telemeter/sender_spec.rb +0 -140
- data/spec/unit/telemeter_spec.rb +0 -191
- data/spec/unit/text/error_translation_spec.rb +0 -109
- data/spec/unit/ui/error_printer_spec.rb +0 -196
- data/spec/unit/ui/terminal_spec.rb +0 -119
- data/spec/unit/version_spec.rb +0 -31
@@ -1,140 +0,0 @@
|
|
1
|
-
#
|
2
|
-
# Copyright:: Copyright (c) 2018 Chef Software Inc.
|
3
|
-
# License:: Apache License, Version 2.0
|
4
|
-
#
|
5
|
-
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
-
# you may not use this file except in compliance with the License.
|
7
|
-
# You may obtain a copy of the License at
|
8
|
-
#
|
9
|
-
# http://www.apache.org/licenses/LICENSE-2.0
|
10
|
-
#
|
11
|
-
# Unless required by applicable law or agreed to in writing, software
|
12
|
-
# distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
-
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
-
# See the License for the specific language governing permissions and
|
15
|
-
# limitations under the License.
|
16
|
-
#
|
17
|
-
|
18
|
-
require "spec_helper"
|
19
|
-
require "chef_apply/telemeter/sender"
|
20
|
-
require "chef_apply/config"
|
21
|
-
|
22
|
-
RSpec.describe ChefApply::Telemeter::Sender do
|
23
|
-
let(:session_files) { %w{file1 file2} }
|
24
|
-
let(:enabled_flag) { true }
|
25
|
-
let(:dev_mode) { false }
|
26
|
-
let(:config) { double("config") }
|
27
|
-
|
28
|
-
let(:subject) { ChefApply::Telemeter::Sender.new(session_files) }
|
29
|
-
|
30
|
-
before do
|
31
|
-
allow(config).to receive(:dev).and_return dev_mode
|
32
|
-
allow(ChefApply::Config).to receive(:telemetry).and_return config
|
33
|
-
allow(ChefApply::Telemeter).to receive(:enabled?).and_return enabled_flag
|
34
|
-
# Ensure this is not set for each test:
|
35
|
-
ENV.delete("CHEF_TELEMETRY_ENDPOINT")
|
36
|
-
end
|
37
|
-
|
38
|
-
describe "::start_upload_thread" do
|
39
|
-
let(:sender_mock) { instance_double(ChefApply::Telemeter::Sender) }
|
40
|
-
it "spawns a thread to run the send" do
|
41
|
-
expect(ChefApply::Telemeter::Sender).to receive(:find_session_files).and_return session_files
|
42
|
-
expect(ChefApply::Telemeter::Sender).to receive(:new).with(session_files).and_return sender_mock
|
43
|
-
expect(sender_mock).to receive(:run)
|
44
|
-
expect(::Thread).to receive(:new).and_yield
|
45
|
-
ChefApply::Telemeter::Sender.start_upload_thread
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
describe "#run" do
|
50
|
-
before do
|
51
|
-
expect(subject).to receive(:session_files).and_return session_files
|
52
|
-
end
|
53
|
-
|
54
|
-
context "when telemetry is disabled" do
|
55
|
-
let(:enabled_flag) { false }
|
56
|
-
it "deletes session files without sending" do
|
57
|
-
expect(FileUtils).to receive(:rm_rf).with("file1")
|
58
|
-
expect(FileUtils).to receive(:rm_rf).with("file2")
|
59
|
-
expect(FileUtils).to receive(:rm_rf).with(ChefApply::Config.telemetry_session_file)
|
60
|
-
expect(subject).to_not receive(:process_session)
|
61
|
-
subject.run
|
62
|
-
end
|
63
|
-
end
|
64
|
-
|
65
|
-
context "when telemetry is enabled" do
|
66
|
-
context "and telemetry dev mode is true" do
|
67
|
-
let(:dev_mode) { true }
|
68
|
-
let(:session_files) { [] } # Ensure we don't send anything without mocking :allthecalls:
|
69
|
-
context "and a custom telemetry endpoint is not set" do
|
70
|
-
it "configures the environment to submit to the Acceptance telemetry endpoint" do
|
71
|
-
subject.run
|
72
|
-
expect(ENV["CHEF_TELEMETRY_ENDPOINT"]).to eq "https://telemetry-acceptance.chef.io"
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
|
-
context "and a custom telemetry endpoint is already set" do
|
77
|
-
before do
|
78
|
-
ENV["CHEF_TELEMETRY_ENDPOINT"] = "https://localhost"
|
79
|
-
end
|
80
|
-
it "should not overwrite the custom value" do
|
81
|
-
subject.run
|
82
|
-
expect(ENV["CHEF_TELEMETRY_ENDPOINT"]).to eq "https://localhost"
|
83
|
-
end
|
84
|
-
end
|
85
|
-
end
|
86
|
-
|
87
|
-
it "submits the session capture for each session file found" do
|
88
|
-
expect(subject).to receive(:process_session).with("file1")
|
89
|
-
expect(subject).to receive(:process_session).with("file2")
|
90
|
-
expect(FileUtils).to receive(:rm_rf).with(ChefApply::Config.telemetry_session_file)
|
91
|
-
subject.run
|
92
|
-
end
|
93
|
-
end
|
94
|
-
|
95
|
-
context "when an error occurrs" do
|
96
|
-
it "logs it" do
|
97
|
-
allow(config).to receive(:enabled?).and_raise("Failed")
|
98
|
-
expect(ChefApply::Log).to receive(:fatal)
|
99
|
-
subject.run
|
100
|
-
end
|
101
|
-
end
|
102
|
-
end
|
103
|
-
|
104
|
-
describe "::find_session_files" do
|
105
|
-
it "finds all telemetry-payload-*.yml files in the telemetry directory" do
|
106
|
-
expect(ChefApply::Config).to receive(:telemetry_path).and_return("/tmp")
|
107
|
-
expect(Dir).to receive(:glob).with("/tmp/telemetry-payload-*.yml").and_return []
|
108
|
-
ChefApply::Telemeter::Sender.find_session_files
|
109
|
-
end
|
110
|
-
end
|
111
|
-
|
112
|
-
describe "process_session" do
|
113
|
-
it "loads the sesion and submits it" do
|
114
|
-
expect(subject).to receive(:load_and_clear_session).with("file1").and_return({ "version" => "1.0.0", "entries" => [] })
|
115
|
-
expect(subject).to receive(:submit_session).with({ "version" => "1.0.0", "entries" => [] })
|
116
|
-
subject.process_session("file1")
|
117
|
-
end
|
118
|
-
end
|
119
|
-
|
120
|
-
describe "submit_session" do
|
121
|
-
let(:telemetry) { instance_double("telemetry") }
|
122
|
-
it "removes the telemetry session file and starts a new session, then submits each entry in the session" do
|
123
|
-
expect(ChefApply::Config).to receive(:telemetry_session_file).and_return("/tmp/SESSION_ID")
|
124
|
-
expect(FileUtils).to receive(:rm_rf).with("/tmp/SESSION_ID")
|
125
|
-
expect(Telemetry).to receive(:new).and_return telemetry
|
126
|
-
expect(subject).to receive(:submit_entry).with(telemetry, { "event" => "action1" }, 1, 2)
|
127
|
-
expect(subject).to receive(:submit_entry).with(telemetry, { "event" => "action2" }, 2, 2)
|
128
|
-
subject.submit_session( { "version" => "1.0.0",
|
129
|
-
"entries" => [ { "event" => "action1" }, { "event" => "action2" } ] } )
|
130
|
-
end
|
131
|
-
end
|
132
|
-
|
133
|
-
describe "submit_entry" do
|
134
|
-
let(:telemetry) { instance_double("telemetry") }
|
135
|
-
it "submits the entry to telemetry" do
|
136
|
-
expect(telemetry).to receive(:deliver).with("test" => "this")
|
137
|
-
subject.submit_entry(telemetry, { "test" => "this" }, 1, 1)
|
138
|
-
end
|
139
|
-
end
|
140
|
-
end
|
data/spec/unit/telemeter_spec.rb
DELETED
@@ -1,191 +0,0 @@
|
|
1
|
-
#
|
2
|
-
# Copyright:: Copyright (c) 2018 Chef Software Inc.
|
3
|
-
# License:: Apache License, Version 2.0
|
4
|
-
#
|
5
|
-
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
-
# you may not use this file except in compliance with the License.
|
7
|
-
# You may obtain a copy of the License at
|
8
|
-
#
|
9
|
-
# http://www.apache.org/licenses/LICENSE-2.0
|
10
|
-
#
|
11
|
-
# Unless required by applicable law or agreed to in writing, software
|
12
|
-
# distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
-
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
-
# See the License for the specific language governing permissions and
|
15
|
-
# limitations under the License.
|
16
|
-
#
|
17
|
-
|
18
|
-
require "spec_helper"
|
19
|
-
require "chef_apply/telemeter"
|
20
|
-
|
21
|
-
RSpec.describe ChefApply::Telemeter do
|
22
|
-
subject { ChefApply::Telemeter.instance }
|
23
|
-
let(:host_platform) { "linux" }
|
24
|
-
|
25
|
-
before do
|
26
|
-
allow(subject).to receive(:host_platform).and_return host_platform
|
27
|
-
end
|
28
|
-
|
29
|
-
context "#commit" do
|
30
|
-
context "when telemetry is enabled" do
|
31
|
-
before do
|
32
|
-
allow(subject).to receive(:enabled?).and_return true
|
33
|
-
end
|
34
|
-
|
35
|
-
it "writes events out and clears the queue" do
|
36
|
-
subject.capture(:test)
|
37
|
-
expect(subject.pending_event_count).to eq 1
|
38
|
-
expect(subject).to receive(:convert_events_to_session)
|
39
|
-
expect(subject).to receive(:write_session)
|
40
|
-
|
41
|
-
subject.commit
|
42
|
-
expect(subject.pending_event_count).to eq 0
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
|
-
context "when telemetry is disabled" do
|
47
|
-
before do
|
48
|
-
allow(subject).to receive(:enabled?).and_return false
|
49
|
-
end
|
50
|
-
it "does not write any events and clears the queue" do
|
51
|
-
subject.capture(:test)
|
52
|
-
expect(subject.pending_event_count).to eq 1
|
53
|
-
expect(subject).to_not receive(:convert_events_to_session)
|
54
|
-
|
55
|
-
subject.commit
|
56
|
-
expect(subject.pending_event_count).to eq 0
|
57
|
-
end
|
58
|
-
end
|
59
|
-
end
|
60
|
-
|
61
|
-
context "#timed_action_capture" do
|
62
|
-
context "when a valid target_host is present" do
|
63
|
-
it "invokes timed_capture with action and valid target data" do
|
64
|
-
target = instance_double("TargetHost",
|
65
|
-
base_os: "windows",
|
66
|
-
version: "10.0.0",
|
67
|
-
architecture: "x86_64",
|
68
|
-
hostname: "My_Host",
|
69
|
-
transport_type: "winrm")
|
70
|
-
action = instance_double("Action::Base", name: "test_action",
|
71
|
-
target_host: target)
|
72
|
-
expected_data = {
|
73
|
-
action: "test_action",
|
74
|
-
target: {
|
75
|
-
platform: {
|
76
|
-
name: "windows",
|
77
|
-
version: "10.0.0",
|
78
|
-
architecture: "x86_64",
|
79
|
-
},
|
80
|
-
hostname_sha1: Digest::SHA1.hexdigest("my_host"),
|
81
|
-
transport_type: "winrm",
|
82
|
-
},
|
83
|
-
}
|
84
|
-
expect(subject).to receive(:timed_capture).with(:action, expected_data)
|
85
|
-
subject.timed_action_capture(action) { :ok }
|
86
|
-
end
|
87
|
-
|
88
|
-
context "when a valid target_host is not present" do
|
89
|
-
it "invokes timed_capture with empty target values" do
|
90
|
-
expected_data = { action: "Base", target: { platform: {},
|
91
|
-
hostname_sha1: nil,
|
92
|
-
transport_type: nil } }
|
93
|
-
expect(subject).to receive(:timed_capture)
|
94
|
-
.with(:action, expected_data)
|
95
|
-
subject.timed_action_capture(
|
96
|
-
ChefApply::Action::Base.new(target_host: nil)
|
97
|
-
) { :ok }
|
98
|
-
end
|
99
|
-
end
|
100
|
-
end
|
101
|
-
end
|
102
|
-
|
103
|
-
context "::enabled?" do
|
104
|
-
let(:enabled_flag) { false }
|
105
|
-
let(:config) { double("config") }
|
106
|
-
before do
|
107
|
-
allow(ChefApply::Config).to receive(:telemetry).and_return(config)
|
108
|
-
allow(config).to receive(:enable).and_return(enabled_flag)
|
109
|
-
end
|
110
|
-
|
111
|
-
context "when config value is enabled" do
|
112
|
-
let(:enabled_flag) { true }
|
113
|
-
context "and CHEF_TELEMETRY_OPT_OUT is not present in env vars" do
|
114
|
-
it "returns false" do
|
115
|
-
ENV.delete("CHEF_TELEMETRY_OPT_OUT")
|
116
|
-
expect(subject.enabled?).to eq true
|
117
|
-
end
|
118
|
-
end
|
119
|
-
context "and CHEF_TELEMETRY_OPT_OUT is present in env vars" do
|
120
|
-
it "returns false" do
|
121
|
-
ENV["CHEF_TELEMETRY_OPT_OUT"] = ""
|
122
|
-
expect(subject.enabled?).to eq false
|
123
|
-
end
|
124
|
-
end
|
125
|
-
end
|
126
|
-
|
127
|
-
context "when config value is disabled" do
|
128
|
-
let(:enabled_flag) { false }
|
129
|
-
it "returns false" do
|
130
|
-
expect(subject.enabled?).to eq false
|
131
|
-
end
|
132
|
-
end
|
133
|
-
end
|
134
|
-
|
135
|
-
context "#timed_run_capture" do
|
136
|
-
it "invokes timed_capture with run data" do
|
137
|
-
expected_data = { arguments: [ "arg1" ] }
|
138
|
-
expect(subject).to receive(:timed_capture)
|
139
|
-
.with(:run, expected_data)
|
140
|
-
subject.timed_run_capture(["arg1"])
|
141
|
-
end
|
142
|
-
end
|
143
|
-
|
144
|
-
context "#timed_capture" do
|
145
|
-
let(:runner) { double("capture_test") }
|
146
|
-
before do
|
147
|
-
expect(subject.pending_event_count).to eq 0
|
148
|
-
end
|
149
|
-
|
150
|
-
it "runs the requested thing and invokes #capture with duration" do
|
151
|
-
expect(runner).to receive(:do_it)
|
152
|
-
expect(subject).to receive(:capture) do |name, data|
|
153
|
-
expect(name).to eq(:do_it_test)
|
154
|
-
expect(data[:duration]).to be > 0.0
|
155
|
-
end
|
156
|
-
subject.timed_capture(:do_it_test) do
|
157
|
-
runner.do_it
|
158
|
-
end
|
159
|
-
end
|
160
|
-
end
|
161
|
-
|
162
|
-
context "#capture" do
|
163
|
-
before do
|
164
|
-
expect(subject.pending_event_count).to eq 0
|
165
|
-
end
|
166
|
-
it "adds the captured event to the session" do
|
167
|
-
subject.capture(:test, {})
|
168
|
-
expect(subject.pending_event_count) == 1
|
169
|
-
end
|
170
|
-
end
|
171
|
-
|
172
|
-
context "#make_event_payload" do
|
173
|
-
before do
|
174
|
-
allow(subject).to receive(:installation_id).and_return "0000"
|
175
|
-
end
|
176
|
-
|
177
|
-
it "adds expected properties" do
|
178
|
-
payload = subject.make_event_payload(:run, { hello: "world" })
|
179
|
-
expected_payload = {
|
180
|
-
event: :run,
|
181
|
-
properties: {
|
182
|
-
installation_id: "0000",
|
183
|
-
run_timestamp: subject.run_timestamp,
|
184
|
-
host_platform: host_platform,
|
185
|
-
event_data: { hello: "world" },
|
186
|
-
},
|
187
|
-
}
|
188
|
-
expect(payload).to eq expected_payload
|
189
|
-
end
|
190
|
-
end
|
191
|
-
end
|
@@ -1,109 +0,0 @@
|
|
1
|
-
#
|
2
|
-
# Copyright:: Copyright (c) 2017 Chef Software Inc.
|
3
|
-
# License:: Apache License, Version 2.0
|
4
|
-
#
|
5
|
-
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
-
# you may not use this file except in compliance with the License.
|
7
|
-
# You may obtain a copy of the License at
|
8
|
-
#
|
9
|
-
# http://www.apache.org/licenses/LICENSE-2.0
|
10
|
-
#
|
11
|
-
# Unless required by applicable law or agreed to in writing, software
|
12
|
-
# distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
-
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
-
# See the License for the specific language governing permissions and
|
15
|
-
# limitations under the License.
|
16
|
-
#
|
17
|
-
|
18
|
-
require "spec_helper"
|
19
|
-
require "chef_apply/text"
|
20
|
-
|
21
|
-
RSpec.describe ChefApply::Text::ErrorTranslation do
|
22
|
-
|
23
|
-
let(:display_defaults) do
|
24
|
-
{
|
25
|
-
decorations: true,
|
26
|
-
header: true,
|
27
|
-
footer: true,
|
28
|
-
stack: false,
|
29
|
-
log: false }
|
30
|
-
end
|
31
|
-
|
32
|
-
let(:error_table) do
|
33
|
-
{ display_defaults: display_defaults,
|
34
|
-
TESTERROR: test_error }
|
35
|
-
end
|
36
|
-
|
37
|
-
let(:test_error_text) { "This is a test error" }
|
38
|
-
let(:test_error) { {} }
|
39
|
-
|
40
|
-
subject { ChefApply::Text::ErrorTranslation }
|
41
|
-
let(:error_mock) do
|
42
|
-
double("R18n::Translated",
|
43
|
-
text: test_error_text )
|
44
|
-
end
|
45
|
-
let(:translation_mock) do
|
46
|
-
double("R18n::Translated",
|
47
|
-
TESTERROR: error_mock,
|
48
|
-
text: test_error_text )
|
49
|
-
end
|
50
|
-
before do
|
51
|
-
# Mock out the R18n portion - our methods care only that the key exists, and
|
52
|
-
# the test focus is on the display metadata.
|
53
|
-
allow(ChefApply::Text).to receive(:errors).and_return translation_mock
|
54
|
-
allow(ChefApply::Text).to receive(:_error_table).and_return(error_table)
|
55
|
-
end
|
56
|
-
|
57
|
-
context "when some display attributes are specified" do
|
58
|
-
let(:test_error) { { display: { stack: true, log: true } } }
|
59
|
-
it "sets display attributes to specified values and defaults remaining" do
|
60
|
-
translation = subject.new("TESTERROR")
|
61
|
-
expect(translation.decorations).to be true
|
62
|
-
expect(translation.header).to be true
|
63
|
-
expect(translation.footer).to be true
|
64
|
-
expect(translation.stack).to be true
|
65
|
-
expect(translation.log).to be true
|
66
|
-
expect(translation.message).to eq test_error_text
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
context "when all display attributes are specified" do
|
71
|
-
let(:test_error) do
|
72
|
-
{ display: { decorations: false, header: false,
|
73
|
-
footer: false, stack: true, log: true } }
|
74
|
-
end
|
75
|
-
it "sets display attributes to specified values with no defaults" do
|
76
|
-
translation = subject.new("TESTERROR")
|
77
|
-
expect(translation.decorations).to be false
|
78
|
-
expect(translation.header).to be false
|
79
|
-
expect(translation.footer).to be false
|
80
|
-
expect(translation.stack).to be true
|
81
|
-
expect(translation.log).to be true
|
82
|
-
expect(translation.message).to eq test_error_text
|
83
|
-
end
|
84
|
-
end
|
85
|
-
|
86
|
-
context "when no attributes for an error are specified" do
|
87
|
-
let(:test_error) { {} }
|
88
|
-
it "sets display attribute to default values and references the correct message" do
|
89
|
-
translation = subject.new("TESTERROR")
|
90
|
-
expect(translation.decorations).to be true
|
91
|
-
expect(translation.header).to be true
|
92
|
-
expect(translation.footer).to be true
|
93
|
-
expect(translation.stack).to be false
|
94
|
-
expect(translation.log).to be false
|
95
|
-
expect(translation.message).to eq test_error_text
|
96
|
-
end
|
97
|
-
end
|
98
|
-
|
99
|
-
context "when invalid attributes for an error are specified" do
|
100
|
-
let(:test_error) { { display: { bad_value: true } } }
|
101
|
-
it "raises InvalidDisplayAttributes when invalid attributes are specified" do
|
102
|
-
expect { subject.new("TESTERROR") }
|
103
|
-
.to raise_error(ChefApply::Text::ErrorTranslation::InvalidDisplayAttributes) do |e|
|
104
|
-
expect(e.invalid_attrs).to eq({ bad_value: true })
|
105
|
-
end
|
106
|
-
|
107
|
-
end
|
108
|
-
end
|
109
|
-
end
|
@@ -1,196 +0,0 @@
|
|
1
|
-
#
|
2
|
-
# Copyright:: Copyright (c) 2018 Chef Software Inc.
|
3
|
-
# License:: Apache License, Version 2.0
|
4
|
-
#
|
5
|
-
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
-
# you may not use this file except in compliance with the License.
|
7
|
-
# You may obtain a copy of the License at
|
8
|
-
#
|
9
|
-
# http://www.apache.org/licenses/LICENSE-2.0
|
10
|
-
#
|
11
|
-
# Unless required by applicable law or agreed to in writing, software
|
12
|
-
# distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
-
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
-
# See the License for the specific language governing permissions and
|
15
|
-
# limitations under the License.
|
16
|
-
#
|
17
|
-
|
18
|
-
require "spec_helper"
|
19
|
-
require "chef_apply/ui/error_printer"
|
20
|
-
require "chef_apply/text/error_translation"
|
21
|
-
require "chef_apply/errors/standard_error_resolver"
|
22
|
-
require "chef_apply/target_host"
|
23
|
-
|
24
|
-
RSpec.describe ChefApply::UI::ErrorPrinter do
|
25
|
-
|
26
|
-
let(:orig_exception) { StandardError.new("test") }
|
27
|
-
let(:target_host) { ChefApply::TargetHost.mock_instance("mock://localhost") }
|
28
|
-
let(:wrapped_exception) { ChefApply::WrappedError.new(orig_exception, target_host) }
|
29
|
-
|
30
|
-
let(:show_footer) { true }
|
31
|
-
let(:show_log) { true }
|
32
|
-
let(:show_stack) { true }
|
33
|
-
let(:has_decorations) { true }
|
34
|
-
let(:show_header) { true }
|
35
|
-
let(:translation_mock) do
|
36
|
-
instance_double("ChefApply::Errors::ErrorTranslation",
|
37
|
-
footer: show_footer,
|
38
|
-
log: show_log,
|
39
|
-
stack: show_stack,
|
40
|
-
header: show_header,
|
41
|
-
decorations: has_decorations)
|
42
|
-
end
|
43
|
-
subject { ChefApply::UI::ErrorPrinter.new(wrapped_exception, nil) }
|
44
|
-
|
45
|
-
before do
|
46
|
-
allow(ChefApply::Text::ErrorTranslation).to receive(:new).and_return translation_mock
|
47
|
-
end
|
48
|
-
|
49
|
-
context "#format_error" do
|
50
|
-
|
51
|
-
context "and the message has decorations" do
|
52
|
-
let(:has_decorations) { true }
|
53
|
-
it "formats the message using the correct method" do
|
54
|
-
expect(subject).to receive(:format_decorated).and_return "decorated"
|
55
|
-
subject.format_error
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
|
-
context "and the message does not have decorations" do
|
60
|
-
let(:has_decorations) { false }
|
61
|
-
it "formats the message using the correct method" do
|
62
|
-
expect(subject).to receive(:format_undecorated).and_return "undecorated"
|
63
|
-
subject.format_error
|
64
|
-
end
|
65
|
-
end
|
66
|
-
end
|
67
|
-
|
68
|
-
context "#format_body" do
|
69
|
-
RC = ChefApply::TargetHost
|
70
|
-
context "when exception is a ChefApply::Error" do
|
71
|
-
let(:result) { RemoteExecResult.new(1, "", "failed") }
|
72
|
-
let(:orig_exception) { RC::RemoteExecutionFailed.new("localhost", "test", result) }
|
73
|
-
it "invokes the right handler" do
|
74
|
-
expect(subject).to receive(:format_workstation_exception)
|
75
|
-
subject.format_body
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
context "when exception is a Train::Error" do
|
80
|
-
# These may expand as we find error-specific messaging we can provide to customers
|
81
|
-
# for more specific train exceptions
|
82
|
-
let(:orig_exception) { Train::Error.new("test") }
|
83
|
-
it "invokes the right handler" do
|
84
|
-
expect(subject).to receive(:format_train_exception)
|
85
|
-
subject.format_body
|
86
|
-
end
|
87
|
-
end
|
88
|
-
|
89
|
-
context "when exception is something else" do
|
90
|
-
# These may expand as we find error-specific messaging we can provide to customers
|
91
|
-
# for more specific general exceptions
|
92
|
-
it "invokes the right handler" do
|
93
|
-
expect(subject).to receive(:format_other_exception)
|
94
|
-
subject.format_body
|
95
|
-
end
|
96
|
-
end
|
97
|
-
end
|
98
|
-
|
99
|
-
context ".show_error" do
|
100
|
-
subject { ChefApply::UI::ErrorPrinter }
|
101
|
-
context "when handling a MultiJobFailure" do
|
102
|
-
it "recognizes it and invokes capture_multiple_failures" do
|
103
|
-
underlying_error = ChefApply::MultiJobFailure.new([])
|
104
|
-
error_to_process = ChefApply::Errors::StandardErrorResolver.wrap_exception(underlying_error)
|
105
|
-
expect(subject).to receive(:capture_multiple_failures).with(underlying_error)
|
106
|
-
subject.show_error(error_to_process)
|
107
|
-
|
108
|
-
end
|
109
|
-
end
|
110
|
-
|
111
|
-
context "when an error occurs in error handling" do
|
112
|
-
it "processes the new failure with dump_unexpected_error" do
|
113
|
-
error_to_raise = StandardError.new("this will be raised")
|
114
|
-
error_to_process = ChefApply::Errors::StandardErrorResolver.wrap_exception(StandardError.new("this is being shown"))
|
115
|
-
# Intercept a known call to raise an error
|
116
|
-
expect(ChefApply::UI::Terminal).to receive(:output).and_raise error_to_raise
|
117
|
-
expect(subject).to receive(:dump_unexpected_error).with(error_to_raise)
|
118
|
-
subject.show_error(error_to_process)
|
119
|
-
end
|
120
|
-
end
|
121
|
-
|
122
|
-
end
|
123
|
-
|
124
|
-
context ".capture_multiple_failures" do
|
125
|
-
subject { ChefApply::UI::ErrorPrinter }
|
126
|
-
let(:file_content_capture) { StringIO.new }
|
127
|
-
before do
|
128
|
-
allow(ChefApply::Config).to receive(:error_output_path).and_return "/dev/null"
|
129
|
-
allow(File).to receive(:open).with("/dev/null", "w").and_yield(file_content_capture)
|
130
|
-
end
|
131
|
-
|
132
|
-
it "should write a properly formatted error file" do
|
133
|
-
# TODO - add support for test-only i18n content, so that we don't have
|
134
|
-
# to rely on specific known error IDs that may change or be removed,
|
135
|
-
# and arent' directly relevant to the test at hand.
|
136
|
-
job1 = double("Job", target_host: double("TargetHost", hostname: "host1"),
|
137
|
-
exception: ChefApply::Error.new("CHEFUPL005"))
|
138
|
-
job2 = double("Job", target_host: double("TargetHost", hostname: "host2"),
|
139
|
-
exception: StandardError.new("Hello World"))
|
140
|
-
|
141
|
-
expected_content = File.read("spec/unit/fixtures/multi-error.out")
|
142
|
-
multifailure = ChefApply::MultiJobFailure.new([job1, job2] )
|
143
|
-
subject.capture_multiple_failures(multifailure)
|
144
|
-
expect(file_content_capture.string).to eq expected_content
|
145
|
-
end
|
146
|
-
end
|
147
|
-
|
148
|
-
context "#format_footer" do
|
149
|
-
let(:formatter) do
|
150
|
-
ChefApply::UI::ErrorPrinter.new(wrapped_exception, nil)
|
151
|
-
end
|
152
|
-
|
153
|
-
subject do
|
154
|
-
lambda { formatter.format_footer }
|
155
|
-
end
|
156
|
-
|
157
|
-
context "when both log and stack wanted" do
|
158
|
-
let(:show_log) { true }
|
159
|
-
let(:show_stack) { true }
|
160
|
-
assert_string_lookup("errors.footer.both")
|
161
|
-
end
|
162
|
-
|
163
|
-
context "when only log is wanted" do
|
164
|
-
let(:show_log) { true }
|
165
|
-
let(:show_stack) { false }
|
166
|
-
assert_string_lookup("errors.footer.log_only")
|
167
|
-
end
|
168
|
-
|
169
|
-
context "when only stack is wanted" do
|
170
|
-
let(:show_log) { false }
|
171
|
-
let(:show_stack) { true }
|
172
|
-
assert_string_lookup("errors.footer.stack_only")
|
173
|
-
end
|
174
|
-
|
175
|
-
context "when neither log nor stack wanted" do
|
176
|
-
let(:show_log) { false }
|
177
|
-
let(:show_stack) { false }
|
178
|
-
assert_string_lookup("errors.footer.neither")
|
179
|
-
end
|
180
|
-
end
|
181
|
-
|
182
|
-
context ".write_backtrace" do
|
183
|
-
let(:inst) { double(ChefApply::UI::ErrorPrinter) }
|
184
|
-
before do
|
185
|
-
allow(ChefApply::UI::ErrorPrinter).to receive(:new).and_return inst
|
186
|
-
end
|
187
|
-
|
188
|
-
let(:orig_args) { %w{test} }
|
189
|
-
it "formats and saves the backtrace" do
|
190
|
-
expect(inst).to receive(:add_backtrace_header).with(anything, orig_args)
|
191
|
-
expect(inst).to receive(:add_formatted_backtrace)
|
192
|
-
expect(inst).to receive(:save_backtrace)
|
193
|
-
ChefApply::UI::ErrorPrinter.write_backtrace(wrapped_exception, orig_args)
|
194
|
-
end
|
195
|
-
end
|
196
|
-
end
|