summaryrefslogtreecommitdiff
path: root/spec/unit/formatters
diff options
context:
space:
mode:
Diffstat (limited to 'spec/unit/formatters')
-rw-r--r--spec/unit/formatters/error_inspectors/compile_error_inspector_spec.rb202
-rw-r--r--spec/unit/formatters/error_inspectors/cookbook_resolve_error_inspector_spec.rb93
-rw-r--r--spec/unit/formatters/error_inspectors/cookbook_sync_error_inspector_spec.rb43
-rw-r--r--spec/unit/formatters/error_inspectors/node_load_error_inspector_spec.rb27
-rw-r--r--spec/unit/formatters/error_inspectors/registration_error_inspector_spec.rb27
-rw-r--r--spec/unit/formatters/error_inspectors/resource_failure_inspector_spec.rb162
-rw-r--r--spec/unit/formatters/error_inspectors/run_list_expansion_error_inspector_spec.rb93
7 files changed, 647 insertions, 0 deletions
diff --git a/spec/unit/formatters/error_inspectors/compile_error_inspector_spec.rb b/spec/unit/formatters/error_inspectors/compile_error_inspector_spec.rb
new file mode 100644
index 0000000000..e1f8f28bb9
--- /dev/null
+++ b/spec/unit/formatters/error_inspectors/compile_error_inspector_spec.rb
@@ -0,0 +1,202 @@
+#
+# Author:: Daniel DeLeo (<dan@opscode.com>)
+# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require 'spec_helper'
+
+BAD_RECIPE=<<-E
+#
+# Cookbook Name:: syntax-err
+# Recipe:: default
+#
+# Copyright 2012, YOUR_COMPANY_NAME
+#
+# All rights reserved - Do Not Redistribute
+#
+
+
+file "/tmp/explode-me" do
+ mode 0655
+ owner "root"
+ this_is_not_a_valid_method
+end
+E
+
+describe Chef::Formatters::ErrorInspectors::CompileErrorInspector do
+ before do
+ @node_name = "test-node.example.com"
+ @description = Chef::Formatters::ErrorDescription.new("Error Evaluating File:")
+ @exception = NoMethodError.new("undefined method `this_is_not_a_valid_method' for Chef::Resource::File")
+
+ @outputter = Chef::Formatters::Outputter.new(StringIO.new, STDERR)
+ #@outputter = Chef::Formatters::Outputter.new(STDOUT, STDERR)
+ end
+
+ describe "when scrubbing backtraces" do
+ it "shows backtrace lines from cookbook files" do
+ # Error inspector originally used file_cache_path which is incorrect on
+ # chef-solo. Using cookbook_path should do the right thing for client and
+ # solo.
+ Chef::Config.stub!(:cookbook_path).and_return([ "/home/someuser/dev-laptop/cookbooks" ])
+ @trace = [
+ "/home/someuser/dev-laptop/cookbooks/syntax-err/recipes/default.rb:14:in `from_file'",
+ "/home/someuser/dev-laptop/cookbooks/syntax-err/recipes/default.rb:11:in `from_file'",
+ "/home/someuser/.multiruby/gems/chef/lib/chef/client.rb:123:in `run'"
+ ]
+ @exception.set_backtrace(@trace)
+ @path = "/var/chef/cache/cookbooks/syntax-err/recipes/default.rb"
+ @inspector = described_class.new(@path, @exception)
+
+ @expected_filtered_trace = [
+ "/home/someuser/dev-laptop/cookbooks/syntax-err/recipes/default.rb:14:in `from_file'",
+ "/home/someuser/dev-laptop/cookbooks/syntax-err/recipes/default.rb:11:in `from_file'",
+ ]
+ @inspector.filtered_bt.should == @expected_filtered_trace
+ end
+ end
+
+ describe "when explaining an error in the compile phase" do
+ before do
+ Chef::Config.stub!(:cookbook_path).and_return([ "/var/chef/cache/cookbooks" ])
+ recipe_lines = BAD_RECIPE.split("\n").map {|l| l << "\n" }
+ IO.should_receive(:readlines).with("/var/chef/cache/cookbooks/syntax-err/recipes/default.rb").and_return(recipe_lines)
+ @trace = [
+ "/var/chef/cache/cookbooks/syntax-err/recipes/default.rb:14:in `from_file'",
+ "/var/chef/cache/cookbooks/syntax-err/recipes/default.rb:11:in `from_file'",
+ "/usr/local/lib/ruby/gems/chef/lib/chef/client.rb:123:in `run'" # should not display
+ ]
+ @exception.set_backtrace(@trace)
+ @path = "/var/chef/cache/cookbooks/syntax-err/recipes/default.rb"
+ @inspector = described_class.new(@path, @exception)
+ @inspector.add_explanation(@description)
+ end
+
+ it "finds the line number of the error from the stacktrace" do
+ @inspector.culprit_line.should == 14
+ end
+
+ it "prints a pretty message" do
+ @description.display(@outputter)
+ end
+ end
+
+ describe "when explaining an error on windows" do
+ before do
+ Chef::Config.stub!(:cookbook_path).and_return([ "C:/opscode/chef/var/cache/cookbooks" ])
+ recipe_lines = BAD_RECIPE.split("\n").map {|l| l << "\n" }
+ IO.should_receive(:readlines).at_least(1).times.with(/:\/opscode\/chef\/var\/cache\/cookbooks\/foo\/recipes\/default.rb/).and_return(recipe_lines)
+ @trace = [
+ "C:/opscode/chef/var/cache/cookbooks/foo/recipes/default.rb:14 in `from_file'",
+ "C:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/run_context.rb:144:in `rescue in block in load_libraries'",
+ "C:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/run_context.rb:138:in `block in load_libraries'",
+ "C:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/run_context.rb:230:in `call'",
+ "C:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/run_context.rb:230:in `block (2 levels) in foreach_cookbook_load_segment'",
+ "C:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/run_context.rb:229:in `each'",
+ "C:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/run_context.rb:229:in `block in foreach_cookbook_load_segment'",
+ "C:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/run_context.rb:227:in `each'",
+ "C:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/run_context.rb:227:in `foreach_cookbook_load_segment'",
+ "C:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/run_context.rb:137:in `load_libraries'",
+ "C:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/run_context.rb:62:in `load'",
+ "C:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/client.rb:198:in `setup_run_context'",
+ "C:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/client.rb:418:in `do_run'",
+ "C:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/client.rb:176:in `run'",
+ "C:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/application/client.rb:283:in `block in run_application'",
+ "C:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/application/client.rb:270:in `loop'",
+ "C:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/application/client.rb:270:in `run_application'",
+ "C:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/application.rb:70:in `run'",
+ "C:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/bin/chef-client:26:in `<top (required)>'",
+ "C:/opscode/chef/bin/chef-client:19:in `load'",
+ "C:/opscode/chef/bin/chef-client:19:in `<main>'"
+ ]
+ @exception.set_backtrace(@trace)
+ @path = "/var/chef/cache/cookbooks/syntax-err/recipes/default.rb"
+ @inspector = described_class.new(@path, @exception)
+ @inspector.add_explanation(@description)
+ end
+
+
+ describe "and examining the stack trace for a recipe" do
+ it "find the culprit recipe name when the drive letter is upper case" do
+ @inspector.culprit_file.should == "C:/opscode/chef/var/cache/cookbooks/foo/recipes/default.rb"
+ end
+
+ it "find the culprit recipe name when the drive letter is lower case" do
+ @trace.each { |line| line.gsub!(/^C:/, "c:") }
+ @exception.set_backtrace(@trace)
+ @inspector = described_class.new(@path, @exception)
+ @inspector.add_explanation(@description)
+ @inspector.culprit_file.should == "c:/opscode/chef/var/cache/cookbooks/foo/recipes/default.rb"
+ end
+ end
+
+ it "finds the line number of the error from the stack trace" do
+ @inspector.culprit_line.should == 14
+ end
+
+ it "prints a pretty message" do
+ @description.display(@outputter)
+ end
+ end
+
+ describe "when explaining an error on windows, and the backtrace lowercases the drive letter" do
+ before do
+ Chef::Config.stub!(:cookbook_path).and_return([ "C:/opscode/chef/var/cache/cookbooks" ])
+ recipe_lines = BAD_RECIPE.split("\n").map {|l| l << "\n" }
+ IO.should_receive(:readlines).with("c:/opscode/chef/var/cache/cookbooks/foo/recipes/default.rb").and_return(recipe_lines)
+ @trace = [
+ "c:/opscode/chef/var/cache/cookbooks/foo/recipes/default.rb:14 in `from_file'",
+ "c:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/run_context.rb:144:in `rescue in block in load_libraries'",
+ "c:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/run_context.rb:138:in `block in load_libraries'",
+ "c:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/run_context.rb:230:in `call'",
+ "c:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/run_context.rb:230:in `block (2 levels) in foreach_cookbook_load_segment'",
+ "c:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/run_context.rb:229:in `each'",
+ "c:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/run_context.rb:229:in `block in foreach_cookbook_load_segment'",
+ "c:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/run_context.rb:227:in `each'",
+ "c:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/run_context.rb:227:in `foreach_cookbook_load_segment'",
+ "c:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/run_context.rb:137:in `load_libraries'",
+ "c:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/run_context.rb:62:in `load'",
+ "c:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/client.rb:198:in `setup_run_context'",
+ "c:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/client.rb:418:in `do_run'",
+ "c:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/client.rb:176:in `run'",
+ "c:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/application/client.rb:283:in `block in run_application'",
+ "c:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/application/client.rb:270:in `loop'",
+ "c:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/application/client.rb:270:in `run_application'",
+ "c:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/application.rb:70:in `run'",
+ "c:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/bin/chef-client:26:in `<top (required)>'",
+ "c:/opscode/chef/bin/chef-client:19:in `load'",
+ "c:/opscode/chef/bin/chef-client:19:in `<main>'"
+ ]
+ @exception.set_backtrace(@trace)
+ @path = "/var/chef/cache/cookbooks/syntax-err/recipes/default.rb"
+ @inspector = described_class.new(@path, @exception)
+ @inspector.add_explanation(@description)
+ end
+
+ it "finds the culprit recipe name from the stacktrace" do
+ @inspector.culprit_file.should == "c:/opscode/chef/var/cache/cookbooks/foo/recipes/default.rb"
+ end
+
+ it "finds the line number of the error from the stack trace" do
+ @inspector.culprit_line.should == 14
+ end
+
+ it "prints a pretty message" do
+ @description.display(@outputter)
+ end
+ end
+
+end
diff --git a/spec/unit/formatters/error_inspectors/cookbook_resolve_error_inspector_spec.rb b/spec/unit/formatters/error_inspectors/cookbook_resolve_error_inspector_spec.rb
new file mode 100644
index 0000000000..bb694f8e5c
--- /dev/null
+++ b/spec/unit/formatters/error_inspectors/cookbook_resolve_error_inspector_spec.rb
@@ -0,0 +1,93 @@
+#--
+# Author:: Daniel DeLeo (<dan@opscode.com>)
+# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require 'spec_helper'
+
+describe Chef::Formatters::ErrorInspectors::CookbookResolveErrorInspector do
+
+ before do
+ @expanded_run_list = Chef::RunList.new("recipe[annoyances]", "recipe[apache2]", "recipe[users]", "recipe[chef::client]")
+
+ @description = Chef::Formatters::ErrorDescription.new("Error Resolving Cookbooks for Run List:")
+ @outputter = Chef::Formatters::Outputter.new(StringIO.new, STDERR)
+ #@outputter = Chef::Formatters::Outputter.new(STDOUT, STDERR)
+ end
+
+ describe "when explaining a 403 error" do
+ before do
+
+ @response_body = %Q({"error": [{"message": "gtfo"}])
+ @response = Net::HTTPForbidden.new("1.1", "403", "(response) forbidden")
+ @response.stub!(:body).and_return(@response_body)
+ @exception = Net::HTTPServerException.new("(exception) forbidden", @response)
+
+ @inspector = Chef::Formatters::ErrorInspectors::CookbookResolveErrorInspector.new(@expanded_run_list, @exception)
+ @inspector.add_explanation(@description)
+ end
+
+ it "prints a nice message" do
+ lambda { @description.display(@outputter) }.should_not raise_error
+ end
+
+ end
+
+ describe "when explaining a PreconditionFailed (412) error with current error message style" do
+ # Chef currently returns error messages with some fields as JSON strings,
+ # which must be re-parsed to get the actual data.
+
+ before do
+
+ @response_body = "{\"error\":[\"{\\\"non_existent_cookbooks\\\":[\\\"apache2\\\"],\\\"cookbooks_with_no_versions\\\":[\\\"users\\\"],\\\"message\\\":\\\"Run list contains invalid items: no such cookbook nope.\\\"}\"]}"
+ @response = Net::HTTPPreconditionFailed.new("1.1", "412", "(response) unauthorized")
+ @response.stub!(:body).and_return(@response_body)
+ @exception = Net::HTTPServerException.new("(exception) precondition failed", @response)
+
+ @inspector = Chef::Formatters::ErrorInspectors::CookbookResolveErrorInspector.new(@expanded_run_list, @exception)
+ @inspector.add_explanation(@description)
+ end
+
+ it "prints a pretty message" do
+ @description.display(@outputter)
+ end
+
+ end
+
+ describe "when explaining a PreconditionFailed (412) error with single encoded JSON" do
+ # Chef currently returns error messages with some fields as JSON strings,
+ # which must be re-parsed to get the actual data.
+
+ before do
+
+ @response_body = "{\"error\":[{\"non_existent_cookbooks\":[\"apache2\"],\"cookbooks_with_no_versions\":[\"users\"],\"message\":\"Run list contains invalid items: no such cookbook nope.\"}]}"
+ @response = Net::HTTPPreconditionFailed.new("1.1", "412", "(response) unauthorized")
+ @response.stub!(:body).and_return(@response_body)
+ @exception = Net::HTTPServerException.new("(exception) precondition failed", @response)
+
+ @inspector = Chef::Formatters::ErrorInspectors::CookbookResolveErrorInspector.new(@expanded_run_list, @exception)
+ @inspector.add_explanation(@description)
+ end
+
+ it "prints a pretty message" do
+ @description.display(@outputter)
+ end
+
+ end
+end
+
+
+
diff --git a/spec/unit/formatters/error_inspectors/cookbook_sync_error_inspector_spec.rb b/spec/unit/formatters/error_inspectors/cookbook_sync_error_inspector_spec.rb
new file mode 100644
index 0000000000..6db7aaaa0d
--- /dev/null
+++ b/spec/unit/formatters/error_inspectors/cookbook_sync_error_inspector_spec.rb
@@ -0,0 +1,43 @@
+#--
+# Author:: Daniel DeLeo (<dan@opscode.com>)
+# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require 'spec_helper'
+
+describe Chef::Formatters::ErrorInspectors::CookbookSyncErrorInspector do
+ before do
+ @description = Chef::Formatters::ErrorDescription.new("Error Expanding RunList:")
+ @outputter = Chef::Formatters::Outputter.new(StringIO.new, STDERR)
+ #@outputter = Chef::Formatters::Outputter.new(STDOUT, STDERR)
+ end
+
+ describe "when explaining a 502 error" do
+ before do
+ @response_body = "sad trombone orchestra"
+ @response = Net::HTTPBadGateway.new("1.1", "502", "(response) bad gateway")
+ @response.stub!(:body).and_return(@response_body)
+ @exception = Net::HTTPFatalError.new("(exception) bad gateway", @response)
+ @inspector = described_class.new({}, @exception)
+ @inspector.add_explanation(@description)
+ end
+
+ it "prints a nice message" do
+ @description.display(@outputter)
+ end
+
+ end
+end
diff --git a/spec/unit/formatters/error_inspectors/node_load_error_inspector_spec.rb b/spec/unit/formatters/error_inspectors/node_load_error_inspector_spec.rb
new file mode 100644
index 0000000000..bd3cc6b764
--- /dev/null
+++ b/spec/unit/formatters/error_inspectors/node_load_error_inspector_spec.rb
@@ -0,0 +1,27 @@
+#
+# Author:: Daniel DeLeo (<dan@opscode.com>)
+# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require 'spec_helper'
+
+# spec_helper loads the shared examples already.
+#require 'support/shared/unit/api_error_inspector_spec'
+
+
+describe Chef::Formatters::ErrorInspectors::NodeLoadErrorInspector do
+ it_behaves_like "an api error inspector"
+end
diff --git a/spec/unit/formatters/error_inspectors/registration_error_inspector_spec.rb b/spec/unit/formatters/error_inspectors/registration_error_inspector_spec.rb
new file mode 100644
index 0000000000..4fcf034d80
--- /dev/null
+++ b/spec/unit/formatters/error_inspectors/registration_error_inspector_spec.rb
@@ -0,0 +1,27 @@
+#
+# Author:: Daniel DeLeo (<dan@opscode.com>)
+# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require 'spec_helper'
+
+# spec_helper loads the shared examples already.
+#require 'support/shared/unit/api_error_inspector_spec'
+
+
+describe Chef::Formatters::ErrorInspectors::RegistrationErrorInspector do
+ it_behaves_like "an api error inspector"
+end
diff --git a/spec/unit/formatters/error_inspectors/resource_failure_inspector_spec.rb b/spec/unit/formatters/error_inspectors/resource_failure_inspector_spec.rb
new file mode 100644
index 0000000000..52c719d2fb
--- /dev/null
+++ b/spec/unit/formatters/error_inspectors/resource_failure_inspector_spec.rb
@@ -0,0 +1,162 @@
+#
+# Author:: Daniel DeLeo (<dan@opscode.com>)
+# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require 'spec_helper'
+
+describe Chef::Formatters::ErrorInspectors::ResourceFailureInspector do
+ include Chef::DSL::Recipe
+
+ def run_context
+ node = Chef::Node.new
+ node.automatic_attrs[:platform] = "ubuntu"
+ node.automatic_attrs[:platform_version] = "10.04"
+ Chef::RunContext.new(node, {}, nil)
+ end
+
+ def cookbook_name
+ "rspec-example"
+ end
+
+ before do
+ @description = Chef::Formatters::ErrorDescription.new("Error Converging Resource:")
+ @stdout = StringIO.new
+ @outputter = Chef::Formatters::Outputter.new(@stdout, STDERR)
+ #@outputter = Chef::Formatters::Outputter.new(STDOUT, STDERR)
+
+ Chef::Config.stub!(:cookbook_path).and_return([ "/var/chef/cache" ])
+ end
+
+ describe "when explaining an error converging a resource" do
+ before do
+ source_line = caller(0)[0]
+ @resource = package("non-existing-package") do
+
+ only_if do
+ true
+ end
+
+ not_if("/bin/false")
+ action :upgrade
+ end
+
+ @trace = [
+ "/var/chef/cache/cookbooks/syntax-err/recipes/default.rb:14:in `from_file'",
+ "/var/chef/cache/cookbooks/syntax-err/recipes/default.rb:11:in `from_file'",
+ "/usr/local/lib/ruby/gems/chef/lib/chef/client.rb:123:in `run'" # should not display
+ ]
+ @exception = Chef::Exceptions::Package.new("No such package 'non-existing-package'")
+ @exception.set_backtrace(@trace)
+ @inspector = Chef::Formatters::ErrorInspectors::ResourceFailureInspector.new(@resource, :create, @exception)
+ @inspector.add_explanation(@description)
+ end
+
+ it "filters chef core code from the backtrace" do
+ @expected_filtered_trace = [
+ "/var/chef/cache/cookbooks/syntax-err/recipes/default.rb:14:in `from_file'",
+ "/var/chef/cache/cookbooks/syntax-err/recipes/default.rb:11:in `from_file'",
+ ]
+
+ @inspector.filtered_bt.should == @expected_filtered_trace
+ end
+
+ it "prints a pretty message" do
+ @description.display(@outputter)
+ end
+
+ describe "and the error is a template error" do
+ before do
+ @description = Chef::Formatters::ErrorDescription.new("Error Converging Resource:")
+ @template_class = Class.new { include Chef::Mixin::Template }
+ @template = @template_class.new
+ @context = {:chef => "cool"}
+
+ @resource = template("/tmp/foo.txt") do
+ mode "0644"
+ end
+
+ @error = begin
+ @template.render_template("foo\nbar\nbaz\n<%= this_is_not_defined %>\nquin\nqunx\ndunno", @context) {|r| r}
+ rescue Chef::Mixin::Template::TemplateError => e
+ e
+ end
+
+ @inspector = Chef::Formatters::ErrorInspectors::ResourceFailureInspector.new(@resource, :create, @error)
+ @inspector.add_explanation(@description)
+ end
+
+ it "includes contextual info from the template error in the output" do
+ @description.display(@outputter)
+ @stdout.string.should include(@error.source_listing)
+ end
+
+
+ end
+
+ describe "recipe_snippet" do
+ before do
+ # fake code to run through #recipe_snippet
+ source_file = [ "if true", "var = non_existant", "end" ]
+ IO.stub!(:readlines).and_return(source_file)
+ end
+
+ it "parses a Windows path" do
+ source_line = "C:/Users/btm/chef/chef/spec/unit/fake_file.rb:2: undefined local variable or method `non_existant' for main:Object (NameError)"
+ @resource.source_line = source_line
+ @inspector = Chef::Formatters::ErrorInspectors::ResourceFailureInspector.new(@resource, :create, @exception)
+ @inspector.recipe_snippet.should match(/^# In C:\/Users\/btm/)
+ end
+
+ it "parses a unix path" do
+ source_line = "/home/btm/src/chef/chef/spec/unit/fake_file.rb:2: undefined local variable or method `non_existant' for main:Object (NameError)"
+ @resource.source_line = source_line
+ @inspector = Chef::Formatters::ErrorInspectors::ResourceFailureInspector.new(@resource, :create, @exception)
+ @inspector.recipe_snippet.should match(/^# In \/home\/btm/)
+ end
+ end
+
+ describe "when examining a resource that confuses the parser" do
+ before do
+ angry_bash_recipe = File.expand_path("cookbooks/angrybash/recipes/default.rb", CHEF_SPEC_DATA)
+ source_line = "#{angry_bash_recipe}:1:in `<main>'"
+
+ # source_line = caller(0)[0]; @resource = bash "go off the rails" do
+ # code <<-END
+ # for i in localhost 127.0.0.1 #{Socket.gethostname()}
+ # do
+ # echo "grant all on *.* to root@'$i' identified by 'a_password'; flush privileges;" | mysql -u root -h 127.0.0.1
+ # done
+ # END
+ # end
+ @resource = eval(IO.read(angry_bash_recipe))
+ @resource.source_line = source_line
+ @inspector = Chef::Formatters::ErrorInspectors::ResourceFailureInspector.new(@resource, :create, @exception)
+
+ @exception.set_backtrace(@trace)
+ @inspector = Chef::Formatters::ErrorInspectors::ResourceFailureInspector.new(@resource, :create, @exception)
+ end
+
+ it "does not generate an error" do
+ lambda { @inspector.add_explanation(@description) }.should_not raise_error(TypeError)
+ @description.display(@outputter)
+ end
+ end
+
+ end
+
+
+end
diff --git a/spec/unit/formatters/error_inspectors/run_list_expansion_error_inspector_spec.rb b/spec/unit/formatters/error_inspectors/run_list_expansion_error_inspector_spec.rb
new file mode 100644
index 0000000000..4b6751a120
--- /dev/null
+++ b/spec/unit/formatters/error_inspectors/run_list_expansion_error_inspector_spec.rb
@@ -0,0 +1,93 @@
+#--
+# Author:: Daniel DeLeo (<dan@opscode.com>)
+# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require 'spec_helper'
+
+describe Chef::Formatters::ErrorInspectors::RunListExpansionErrorInspector do
+ before do
+ @node = Chef::Node.new.tap do |n|
+ n.name("unit-test.example.com")
+ n.run_list("role[base]")
+ end
+
+ @description = Chef::Formatters::ErrorDescription.new("Error Expanding RunList:")
+ @outputter = Chef::Formatters::Outputter.new(StringIO.new, STDERR)
+ #@outputter = Chef::Formatters::Outputter.new(STDOUT, STDERR)
+ end
+
+ describe "when explaining a missing role error" do
+
+ before do
+ @run_list_expansion = Chef::RunList::RunListExpansion.new("_default", @node.run_list)
+ @run_list_expansion.missing_roles_with_including_role << [ "role[missing-role]", "role[base]" ]
+ @run_list_expansion.missing_roles_with_including_role << [ "role[another-missing-role]", "role[base]" ]
+
+ @exception = Chef::Exceptions::MissingRole.new(@run_list_expansion)
+
+
+ @inspector = Chef::Formatters::ErrorInspectors::RunListExpansionErrorInspector.new(@node, @exception)
+ @inspector.add_explanation(@description)
+ end
+
+ it "prints a pretty message" do
+ @description.display(@outputter)
+ end
+
+ end
+
+ describe "when explaining an HTTP 403 error" do
+ before do
+
+ @response_body = "forbidden"
+ @response = Net::HTTPForbidden.new("1.1", "403", "(response) forbidden")
+ @response.stub!(:body).and_return(@response_body)
+ @exception = Net::HTTPServerException.new("(exception) forbidden", @response)
+ @inspector = Chef::Formatters::ErrorInspectors::RunListExpansionErrorInspector.new(@node, @exception)
+ @inspector.stub!(:config).and_return(:node_name => "unit-test.example.com")
+
+ @inspector.add_explanation(@description)
+ end
+
+ it "prints a pretty message" do
+ @description.display(@outputter)
+ end
+
+ end
+
+ describe "when explaining an HTTP 401 error" do
+ before do
+ @response_body = "check your key and node name"
+ @response = Net::HTTPUnauthorized.new("1.1", "401", "(response) unauthorized")
+ @response.stub!(:body).and_return(@response_body)
+ @exception = Net::HTTPServerException.new("(exception) unauthorized", @response)
+
+ @inspector = Chef::Formatters::ErrorInspectors::RunListExpansionErrorInspector.new(@node, @exception)
+ @inspector.stub!(:config).and_return(:node_name => "unit-test.example.com",
+ :client_key => "/etc/chef/client.pem",
+ :chef_server_url => "http://chef.example.com")
+
+ @inspector.add_explanation(@description)
+ end
+
+ it "prints a pretty message" do
+ @description.display(@outputter)
+ end
+ end
+
+end
+