diff options
| author | Daniel Pittman <daniel@puppetlabs.com> | 2011-05-06 11:08:35 -0700 |
|---|---|---|
| committer | Daniel Pittman <daniel@puppetlabs.com> | 2011-05-06 11:08:35 -0700 |
| commit | f80afbe72b848fe4ed81d8116d4eeb494aa6f61e (patch) | |
| tree | 73c7f27f2ea2fb1668f7067ce05638f5064f540d /spec | |
| parent | 1b12b55b6a2d3581f9643bf09d55727ba1213580 (diff) | |
| parent | b983386ece1b9816e6d3d59a316ad589e35773df (diff) | |
| download | puppet-f80afbe72b848fe4ed81d8116d4eeb494aa6f61e.tar.gz puppet-f80afbe72b848fe4ed81d8116d4eeb494aa6f61e.tar.xz puppet-f80afbe72b848fe4ed81d8116d4eeb494aa6f61e.zip | |
Merge branch '2.7.x' into 2.7.next
Conflicts:
* spec/unit/node/facts_spec.rb
Updates:
* spec/unit/interface/action{,_builder}_spec.rb
=> update for 'when_invoked' block being required.
Diffstat (limited to 'spec')
64 files changed, 1199 insertions, 655 deletions
diff --git a/spec/fixtures/faulty_face/puppet/face/syntax.rb b/spec/fixtures/faulty_face/puppet/face/syntax.rb new file mode 100644 index 000000000..3b1e36c3f --- /dev/null +++ b/spec/fixtures/faulty_face/puppet/face/syntax.rb @@ -0,0 +1,8 @@ +Puppet::Face.define(:syntax, '1.0.0') do + action :foo do + when_invoked do |whom| + "hello, #{whom}" + end + # This 'end' is deliberately omitted, to induce a syntax error. + # Please don't fix that, as it is used for testing. --daniel 2011-05-02 +end diff --git a/spec/integration/application/doc_spec.rb b/spec/integration/application/doc_spec.rb index df9b91608..c1e463033 100755 --- a/spec/integration/application/doc_spec.rb +++ b/spec/integration/application/doc_spec.rb @@ -36,8 +36,8 @@ describe Puppet::Application::Doc do Puppet[:modulepath] = modules_dir Puppet[:manifest] = site_file puppet.options[:mode] = :rdoc - puppet.expects(:exit).with(0) - puppet.run_command + + expect { puppet.run_command }.to exit_with 0 File.should be_exist('doc') ensure diff --git a/spec/integration/faces/documentation_spec.rb b/spec/integration/faces/documentation_spec.rb new file mode 100755 index 000000000..9ddf2f1b3 --- /dev/null +++ b/spec/integration/faces/documentation_spec.rb @@ -0,0 +1,55 @@ +#!/usr/bin/env rspec +require 'spec_helper' +require 'puppet/face' + +describe "documentation of faces" do + it "should generate global help" do + help = nil + expect { help = Puppet::Face[:help, :current].help }.not_to raise_error + help.should be_an_instance_of String + help.length.should be > 200 + end + + ######################################################################## + # Can we actually generate documentation for the face, and the actions it + # has? This avoids situations where the ERB template turns out to have a + # bug in it, triggered in something the user might do. + Puppet::Face.faces.sort.each do |face_name| + # REVISIT: We should walk all versions of the face here... + let :help do Puppet::Face[:help, :current] end + + context "generating help" do + it "for #{face_name}" do + expect { + text = help.help(face_name) + text.should be_an_instance_of String + text.length.should be > 100 + }.not_to raise_error + end + + Puppet::Face[face_name, :current].actions.sort.each do |action_name| + it "for #{face_name}.#{action_name}" do + expect { + text = help.help(face_name, action_name) + text.should be_an_instance_of String + text.length.should be > 100 + }.not_to raise_error + end + end + end + + ######################################################################## + # Ensure that we have authorship and copyright information in *our* faces; + # if you apply this to third party faces you might well be disappointed. + context "licensing of Puppet Labs face '#{face_name}'" do + subject { Puppet::Face[face_name, :current] } + its :license do should =~ /Apache\s*2/ end + its :copyright do should =~ /Puppet Labs/ end + + # REVISIT: This is less that ideal, I think, but right now I am more + # comfortable watching us ship with some copyright than without any; we + # can redress that when it becomes appropriate. --daniel 2011-04-27 + its :copyright do should =~ /2011/ end + end + end +end diff --git a/spec/integration/transaction_spec.rb b/spec/integration/transaction_spec.rb index 78d62fc51..0ff50f47c 100755 --- a/spec/integration/transaction_spec.rb +++ b/spec/integration/transaction_spec.rb @@ -275,7 +275,7 @@ describe Puppet::Transaction do it "should not attempt to evaluate resources with failed dependencies" do exec = Puppet::Type.type(:exec).new( - :command => "/bin/mkdir /this/path/cannot/possibly/exit", + :command => "/bin/mkdir /this/path/cannot/possibly/exist", :title => "mkdir" ) @@ -309,7 +309,7 @@ describe Puppet::Transaction do ) exec = Puppet::Type.type(:exec).new( - :command => "/bin/mkdir /this/path/cannot/possibly/exit", + :command => "/bin/mkdir /this/path/cannot/possibly/exist", :title => "mkdir", :notify => create_file1 ) diff --git a/spec/lib/puppet/face/basetest.rb b/spec/lib/puppet/face/basetest.rb index e935161ae..9398f5b2d 100755 --- a/spec/lib/puppet/face/basetest.rb +++ b/spec/lib/puppet/face/basetest.rb @@ -1,2 +1,41 @@ require 'puppet/face' -Puppet::Face.define(:basetest, '0.0.1') + +Puppet::Face.define(:basetest, '0.0.1') do + copyright "Puppet Labs", 2011 + license "Apache 2 license; see COPYING" + summary "This is just so tests don't fail" + + option "--[no-]boolean" + option "--mandatory ARGUMENT" + + action :foo do + option("--action") + when_invoked do |*args| args.length end + end + + action :return_true do + summary "just returns true" + when_invoked do |options| true end + end + + action :return_false do + summary "just returns false" + when_invoked do |options| false end + end + + action :return_nil do + summary "just returns nil" + when_invoked do |options| nil end + end + + action :raise do + summary "just raises an exception" + when_invoked do |options| raise ArgumentError, "your failure" end + end + + action :with_s_rendering_hook do + summary "has a rendering hook for 's'" + when_invoked do |options| "this is not the hook you are looking for" end + when_rendering :s do |value| "you invoked the 's' rendering hook" end + end +end diff --git a/spec/lib/puppet/face/huzzah.rb b/spec/lib/puppet/face/huzzah.rb index 3428c6816..6593d358a 100755 --- a/spec/lib/puppet/face/huzzah.rb +++ b/spec/lib/puppet/face/huzzah.rb @@ -1,5 +1,7 @@ require 'puppet/face' Puppet::Face.define(:huzzah, '2.0.1') do + copyright "Puppet Labs", 2011 + license "Apache 2 license; see COPYING" summary "life is a thing for celebration" - action :bar do "is where beer comes from" end + script :bar do "is where beer comes from" end end diff --git a/spec/lib/puppet/face/version_matching.rb b/spec/lib/puppet/face/version_matching.rb index bfd0013f7..52bc71dbd 100644 --- a/spec/lib/puppet/face/version_matching.rb +++ b/spec/lib/puppet/face/version_matching.rb @@ -4,6 +4,8 @@ require 'puppet/face' # change this you need to ensure that is still correct. --daniel 2011-04-21 ['1.0.0', '1.0.1', '1.1.0', '1.1.1', '2.0.0'].each do |version| Puppet::Face.define(:version_matching, version) do + copyright "Puppet Labs", 2011 + license "Apache 2 license; see COPYING" summary "version matching face #{version}" script :version do version end end diff --git a/spec/lib/puppet_spec/matchers.rb b/spec/lib/puppet_spec/matchers.rb new file mode 100644 index 000000000..77f580330 --- /dev/null +++ b/spec/lib/puppet_spec/matchers.rb @@ -0,0 +1,87 @@ +require 'stringio' + +######################################################################## +# Backward compatibility for Jenkins outdated environment. +module RSpec + module Matchers + module BlockAliases + alias_method :to, :should unless method_defined? :to + alias_method :to_not, :should_not unless method_defined? :to_not + alias_method :not_to, :should_not unless method_defined? :not_to + end + end +end + + +######################################################################## +# Custom matchers... +RSpec::Matchers.define :have_matching_element do |expected| + match do |actual| + actual.any? { |item| item =~ expected } + end +end + + +RSpec::Matchers.define :exit_with do |expected| + actual = nil + match do |block| + begin + block.call + rescue SystemExit => e + actual = e.status + end + actual and actual == expected + end + failure_message_for_should do |block| + "expected exit with code #{expected} but " + + (actual.nil? ? " exit was not called" : "we exited with #{actual} instead") + end + failure_message_for_should_not do |block| + "expected that exit would not be called with #{expected}" + end + description do + "expect exit with #{expected}" + end +end + + +RSpec::Matchers.define :have_printed do |expected| + match do |block| + $stderr = $stdout = StringIO.new + + begin + block.call + ensure + $stdout.rewind + @actual = $stdout.read + + $stdout = STDOUT + $stderr = STDERR + end + + if @actual then + case expected + when String + @actual.include? expected + when Regexp + expected.match @actual + else + raise ArgumentError, "No idea how to match a #{@actual.class.name}" + end + end + end + + failure_message_for_should do |actual| + if actual.nil? then + "expected #{expected.inspect}, but nothing was printed" + else + "expected #{expected.inspect} to be printed; got:\n#{actual}" + end + end + + description do + "expect #{expected.inspect} to be printed" + end + + diffable +end diff --git a/spec/shared_behaviours/an_indirector_face.rb b/spec/shared_behaviours/an_indirector_face.rb new file mode 100644 index 000000000..cba74b696 --- /dev/null +++ b/spec/shared_behaviours/an_indirector_face.rb @@ -0,0 +1,6 @@ +shared_examples_for "an indirector face" do + [:find, :search, :save, :destroy, :info].each do |action| + it { should be_action action } + it { should respond_to action } + end +end diff --git a/spec/shared_behaviours/documentation_on_faces.rb b/spec/shared_behaviours/documentation_on_faces.rb index 41b4015c9..3cfb178f7 100644 --- a/spec/shared_behaviours/documentation_on_faces.rb +++ b/spec/shared_behaviours/documentation_on_faces.rb @@ -1,34 +1,255 @@ # encoding: UTF-8 shared_examples_for "documentation on faces" do - context "description" do - describe "#summary" do - it "should accept a summary" do - text = "this is my summary" - expect { subject.summary = text }.to_not raise_error - subject.summary.should == text + defined?(Attrs) or + Attrs = [:summary, :description, :examples, :short_description, :notes, :author] + + defined?(SingleLineAttrs) or + SingleLineAttrs = [:summary, :author] + + # Simple, procedural tests that apply to a bunch of methods. + Attrs.each do |attr| + it "should accept a #{attr}" do + expect { subject.send("#{attr}=", "hello") }.not_to raise_error + subject.send(attr).should == "hello" + end + + it "should accept a long (single line) value for #{attr}" do + text = "I never know when to stop with the word banana" + ("na" * 1000) + expect { subject.send("#{attr}=", text) }.to_not raise_error + subject.send(attr).should == text + end + end + + Attrs.each do |getter| + setter = "#{getter}=".to_sym + context "#{getter}" do + it "should strip leading whitespace on a single line" do + subject.send(setter, " death to whitespace") + subject.send(getter).should == "death to whitespace" + end + + it "should strip trailing whitespace on a single line" do + subject.send(setter, "death to whitespace ") + subject.send(getter).should == "death to whitespace" + end + + it "should strip whitespace at both ends at once" do + subject.send(setter, " death to whitespace ") + subject.send(getter).should == "death to whitespace" + end + + multiline_text = "with\nnewlines" + if SingleLineAttrs.include? getter then + it "should not accept multiline values" do + expect { subject.send(setter, multiline_text) }. + to raise_error ArgumentError, /#{getter} should be a single line/ + subject.send(getter).should be_nil + end + else + it "should accept multiline values" do + expect { subject.send(setter, multiline_text) }.not_to raise_error + subject.send(getter).should == multiline_text + end + + [1, 2, 4, 7, 25].each do |length| + context "#{length} chars indent" do + indent = ' ' * length + + it "should strip leading whitespace on multiple lines" do + text = "this\nis\the\final\outcome" + subject.send(setter, text.gsub(/^/, indent)) + subject.send(getter).should == text + end + + it "should not remove formatting whitespace, only global indent" do + text = "this\n is\n the\n ultimate\ntest\n" + subject.send(setter, text.gsub(/^/, indent)) + subject.send(getter).should == text + end + end + end + + it "should strip whitespace with a blank line" do + subject.send(setter, " this\n\n should outdent\n") + subject.send(getter).should == "this\n\nshould outdent\n" + end + end + end + end + + describe "#short_description" do + it "should return the set value if set after description" do + subject.description = "hello\ngoodbye" + subject.short_description = "whatever" + subject.short_description.should == "whatever" + end + + it "should return the set value if set before description" do + subject.short_description = "whatever" + subject.description = "hello\ngoodbye" + subject.short_description.should == "whatever" + end + + it "should return nothing if not set and no description" do + subject.short_description.should be_nil + end + + it "should return the first paragraph of description if not set (where it is one line long)" do + subject.description = "hello" + subject.short_description.should == subject.description + end + + it "should return the first paragraph of description if not set (where there is no paragraph break)" do + subject.description = "hello\ngoodbye" + subject.short_description.should == subject.description + end + + it "should return the first paragraph of description if not set (where there is a paragraph break)" do + subject.description = "hello\ngoodbye\n\nmore\ntext\nhere\n\nfinal\nparagraph" + subject.short_description.should == "hello\ngoodbye" + end + + it "should trim a very, very long first paragraph" do + line = "this is a very, very, very long long line full of text\n" + subject.description = line * 20 + "\n\nwhatever, dude." + + subject.short_description.should == (line * 5).chomp + end + end + + describe "multiple authors" do + authors = %w{John Paul George Ringo} + + context "in the DSL" do + it "should support multiple authors" do + + authors.each {|name| subject.author name } + subject.authors.should =~ authors + + subject.author.should == authors.join("\n") + end + + it "should reject author as an array" do + expect { subject.author ["Foo", "Bar"] }. + to raise_error ArgumentError, /author must be a string/ + end + end + + context "#author=" do + it "should accept a single name" do + subject.author = "Fred" + subject.author.should == "Fred" + end + + it "should accept an array of names" do + subject.author = authors + subject.authors.should =~ authors + subject.author.should == authors.join("\n") end - it "should accept a long, long, long summary" do - text = "I never know when to stop with the word banana" + ("na" * 1000) - expect { subject.summary = text }.to_not raise_error - subject.summary.should == text + it "should not append when set multiple times" do + subject.author = "Fred" + subject.author = "John" + subject.author.should == "John" end - it "should reject a summary with a newline" do - expect { subject.summary = "with\nnewlines" }. - to raise_error ArgumentError, /summary should be a single line/ + it "should reject arrays with embedded newlines" do + expect { subject.author = ["Fred\nJohn"] }. + to raise_error ArgumentError, /author should be a single line/ end end + end + + describe "#license" do + it "should default to reserving rights" do + subject.license.should =~ /All Rights Reserved/ + end + + it "should accept an arbitrary license string on the object" do + subject.license = "foo" + subject.license.should == "foo" + end + + it "should accept symbols to specify existing licenses..." + end + + describe "#copyright" do + it "should fail with just a name" do + expect { subject.copyright("invalid") }. + to raise_error ArgumentError, /copyright takes the owners names, then the years covered/ + end + + [1997, "1997"].each do |year| + it "should accept an entity name and a #{year.class.name} year" do + subject.copyright("me", year) + subject.copyright.should =~ /\bme\b/ + subject.copyright.should =~ /#{year}/ + end + + it "should accept multiple entity names and a #{year.class.name} year" do + subject.copyright ["me", "you"], year + subject.copyright.should =~ /\bme\b/ + subject.copyright.should =~ /\byou\b/ + subject.copyright.should =~ /#{year}/ + end + end + + ["1997-2003", "1997 - 2003", 1997..2003].each do |range| + it "should accept a #{range.class.name} range of years" do + subject.copyright("me", range) + subject.copyright.should =~ /\bme\b/ + subject.copyright.should =~ /1997-2003/ + end + + it "should accept a #{range.class.name} range of years" do + subject.copyright ["me", "you"], range + subject.copyright.should =~ /\bme\b/ + subject.copyright.should =~ /\byou\b/ + subject.copyright.should =~ /1997-2003/ + end + end + + [[1997, 2003], ["1997", 2003], ["1997", "2003"]].each do |input| + it "should accept the set of years #{input.inspect} in an array" do + subject.copyright "me", input + subject.copyright.should =~ /\bme\b/ + subject.copyright.should =~ /1997, 2003/ + end + + it "should accept the set of years #{input.inspect} in an array" do + subject.copyright ["me", "you"], input + subject.copyright.should =~ /\bme\b/ + subject.copyright.should =~ /\byou\b/ + subject.copyright.should =~ /1997, 2003/ + end + end + + it "should warn if someone does math accidentally on the range of years" do + expect { subject.copyright "me", 1997-2003 }. + to raise_error ArgumentError, /copyright with a year before 1970 is very strange; did you accidentally add or subtract two years\?/ + end + + it "should accept complex copyright years" do + years = [1997, 1999, 2000..2002, 2005].reverse + subject.copyright "me", years + subject.copyright.should =~ /\bme\b/ + subject.copyright.should =~ /1997, 1999, 2000-2002, 2005/ + end + end + + # Things that are automatically generated. + [:name, :options, :synopsis].each do |attr| + describe "##{attr}" do + it "should not allow you to set #{attr}" do + subject.should_not respond_to :"#{attr}=" + end - describe "#description" do - it "should accept a description" do - subject.description = "hello" - subject.description.should == "hello" + it "should have a #{attr}" do + subject.send(attr).should_not be_nil end - it "should accept a description with a newline" do - subject.description = "hello \n my \n fine \n friend" - subject.description.should == "hello \n my \n fine \n friend" + it "'s #{attr} should not be empty..." do + subject.send(attr).should_not == '' end end end diff --git a/spec/shared_behaviours/things_that_declare_options.rb b/spec/shared_behaviours/things_that_declare_options.rb index 5300a159a..6e7056157 100755 --- a/spec/shared_behaviours/things_that_declare_options.rb +++ b/spec/shared_behaviours/things_that_declare_options.rb @@ -28,6 +28,8 @@ shared_examples_for "things that declare options" do thing = add_options_to do option "--foo" do desc text + description text + summary text end end @@ -37,9 +39,12 @@ shared_examples_for "things that declare options" do it "should list all the options" do thing = add_options_to do option "--foo" - option "--bar" + option "--bar", '-b' + option "-q", "--quux" + option "-f" + option "--baz" end - thing.options.should =~ [:foo, :bar] + thing.options.should == [:foo, :bar, :b, :q, :quux, :f, :baz] end it "should detect conflicts in long options" do diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 01ffabc48..6b6b1c2fb 100755 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -17,9 +17,10 @@ end require 'pathname' require 'tmpdir' -require 'lib/puppet_spec/verbose' -require 'lib/puppet_spec/files' -require 'lib/puppet_spec/fixtures' +require 'puppet_spec/verbose' +require 'puppet_spec/files' +require 'puppet_spec/fixtures' +require 'puppet_spec/matchers' require 'monkey_patches/alias_should_to_must' require 'monkey_patches/publicize_methods' require 'monkey_patches/disable_signal_trap' @@ -74,9 +75,3 @@ RSpec.configure do |config| GC.enable end end - -RSpec::Matchers.define :have_matching_element do |expected| - match do |actual| - actual.any? { |item| item =~ expected } - end -end diff --git a/spec/unit/application/agent_spec.rb b/spec/unit/application/agent_spec.rb index b30a8cc6c..2e946e6bb 100755 --- a/spec/unit/application/agent_spec.rb +++ b/spec/unit/application/agent_spec.rb @@ -253,19 +253,16 @@ describe Puppet::Application::Agent do end it "should print puppet config if asked to in Puppet config" do - @puppetd.stubs(:exit) Puppet[:configprint] = "pluginsync" - - Puppet.settings.expects(:print_configs) - - @puppetd.setup + Puppet.settings.expects(:print_configs).returns true + expect { @puppetd.setup }.to exit_with 0 end it "should exit after printing puppet config if asked to in Puppet config" do Puppet[:modulepath] = '/my/path' Puppet[:configprint] = "modulepath" Puppet::Util::Settings.any_instance.expects(:puts).with('/my/path') - lambda { @puppetd.setup }.should raise_error(SystemExit) + expect { @puppetd.setup }.to exit_with 0 end it "should set a central log destination with --centrallogs" do @@ -346,17 +343,14 @@ describe Puppet::Application::Agent do describe "when enabling or disabling agent" do [:enable, :disable].each do |action| it "should call client.#{action}" do - @puppetd.stubs(:exit) @puppetd.options.stubs(:[]).with(action).returns(true) - @agent.expects(action) - - @puppetd.enable_disable_client(@agent) + expect { @puppetd.enable_disable_client(@agent) }.to exit_with 0 end end it "should finally exit" do - lambda { @puppetd.enable_disable_client(@agent) }.should raise_error(SystemExit) + expect { @puppetd.enable_disable_client(@agent) }.to exit_with 0 end end @@ -410,7 +404,6 @@ describe Puppet::Application::Agent do FileTest.stubs(:exists?).with('auth').returns(true) File.stubs(:exist?).returns(true) @puppetd.options.stubs(:[]).with(:serve).returns([]) - @puppetd.stubs(:exit) @server = stub_everything 'server' Puppet::Network::Server.stubs(:new).returns(@server) end @@ -419,10 +412,7 @@ describe Puppet::Application::Agent do it "should exit if no authorization file" do Puppet.stubs(:err) FileTest.stubs(:exists?).with(Puppet[:authconfig]).returns(false) - - @puppetd.expects(:exit) - - @puppetd.setup_listen + expect { @puppetd.setup_listen }.to exit_with 14 end it "should create a server to listen on at least the Runner handler" do @@ -483,35 +473,27 @@ describe Puppet::Application::Agent do @agent.stubs(:run).returns(:report) @puppetd.options.stubs(:[]).with(:client).returns(:client) @puppetd.options.stubs(:[]).with(:detailed_exitcodes).returns(false) - @puppetd.stubs(:exit).with(0) Puppet.stubs(:newservice) end it "should exit if no defined --client" do $stderr.stubs(:puts) @puppetd.options.stubs(:[]).with(:client).returns(nil) - - @puppetd.expects(:exit).with(43) - - @puppetd.onetime + expect { @puppetd.onetime }.to exit_with 43 end it "should setup traps" do @daemon.expects(:set_signal_traps) - - @puppetd.onetime + expect { @puppetd.onetime }.to exit_with 0 end it "should let the agent run" do @agent.expects(:run).returns(:report) - - @puppetd.onetime + expect { @puppetd.onetime }.to exit_with 0 end it "should finish by exiting with 0 error code" do - @puppetd.expects(:exit).with(0) - - @puppetd.onetime + expect { @puppetd.onetime }.to exit_with 0 end describe "and --detailed-exitcodes" do @@ -523,18 +505,16 @@ describe Puppet::Application::Agent do Puppet[:noop] = false report = stub 'report', :exit_status => 666 @agent.stubs(:run).returns(report) - @puppetd.expects(:exit).with(666) - @puppetd.onetime + expect { @puppetd.onetime }.to exit_with 666 end it "should exit with the report's computer exit status, even if --noop is set." do Puppet[:noop] = true report = stub 'report', :exit_status => 666 @agent.stubs(:run).returns(report) - @puppetd.expects(:exit).with(666) - @puppetd.onetime + expect { @puppetd.onetime }.to exit_with 666 end end end diff --git a/spec/unit/application/apply_spec.rb b/spec/unit/application/apply_spec.rb index ec3f083db..74c883a3e 100755 --- a/spec/unit/application/apply_spec.rb +++ b/spec/unit/application/apply_spec.rb @@ -93,18 +93,14 @@ describe Puppet::Application::Apply do end it "should print puppet config if asked to in Puppet config" do - @apply.stubs(:exit) - Puppet.settings.stubs(:print_configs?).returns(true) - - Puppet.settings.expects(:print_configs) - - @apply.setup + Puppet.settings.stubs(:print_configs?).returns true + Puppet.settings.expects(:print_configs).returns true + expect { @apply.setup }.to exit_with 0 end it "should exit after printing puppet config if asked to in Puppet config" do Puppet.settings.stubs(:print_configs?).returns(true) - - lambda { @apply.setup }.should raise_error(SystemExit) + expect { @apply.setup }.to exit_with 1 end it "should tell the report handler to cache locally as yaml" do @@ -155,8 +151,6 @@ describe Puppet::Application::Apply do @transaction = stub_everything 'transaction' @catalog.stubs(:apply).returns(@transaction) - @apply.stubs(:exit) - Puppet::Util::Storage.stubs(:load) Puppet::Configurer.any_instance.stubs(:save_last_run_summary) # to prevent it from trying to write files end @@ -165,7 +159,7 @@ describe Puppet::Application::Apply do @apply.options.stubs(:[]).with(:code).returns("code to run") Puppet.expects(:[]=).with(:code,"code to run") - @apply.main + expect { @apply.main }.to exit_with 0 end it "should set the code to run from STDIN if no arguments" do @@ -174,7 +168,7 @@ describe Puppet::Application::Apply do Puppet.expects(:[]=).with(:code,"code to run") - @apply.main + expect { @apply.main }.to exit_with 0 end it "should set the manifest if a file is passed on command line and the file exists" do @@ -183,7 +177,7 @@ describe Puppet::Application::Apply do Puppet.expects(:[]=).with(:manifest,"site.pp") - @apply.main + expect { @apply.main }.to exit_with 0 end it "should raise an error if a file is passed on command line and the file does not exist" do @@ -200,13 +194,13 @@ describe Puppet::Application::Apply do Puppet.expects(:[]=).with(:manifest,"starwarsIV") Puppet.expects(:warning).with('Only one file can be applied per run. Skipping starwarsI, starwarsII') - @apply.main + expect { @apply.main }.to exit_with 0 end it "should collect the node facts" do Puppet::Node::Facts.indirection.expects(:find).returns(@facts) - @apply.main + expect { @apply.main }.to exit_with 0 end it "should raise an error if we can't find the node" do @@ -218,7 +212,7 @@ describe Puppet::Application::Apply do it "should look for the node" do Puppet::Node.indirection.expects(:find).returns(@node) - @apply.main + expect { @apply.main }.to exit_with 0 end it "should raise an error if we can't find the node" do @@ -232,7 +226,7 @@ describe Puppet::Application::Apply do @node.expects(:merge).with("values") - @apply.main + expect { @apply.main }.to exit_with 0 end it "should load custom classes if loadclasses" do @@ -244,39 +238,39 @@ describe Puppet::Application::Apply do @node.expects(:classes=) - @apply.main + expect { @apply.main }.to exit_with 0 end it "should compile the catalog" do Puppet::Resource::Catalog.indirection.expects(:find).returns(@catalog) - @apply.main + expect { @apply.main }.to exit_with 0 end it "should transform the catalog to ral" do @catalog.expects(:to_ral).returns(@catalog) - @apply.main + expect { @apply.main }.to exit_with 0 end it "should finalize the catalog" do @catalog.expects(:finalize) - @apply.main + expect { @apply.main }.to exit_with 0 end it "should call the prerun and postrun commands on a Configurer instance" do Puppet::Configurer.any_instance.expects(:execute_prerun_command) Puppet::Configurer.any_instance.expects(:execute_postrun_command) - @apply.main + expect { @apply.main }.to exit_with 0 end it "should apply the catalog" do @catalog.expects(:apply).returns(stub_everything('transaction')) - @apply.main + expect { @apply.main }.to exit_with 0 end it "should save the last run summary" do @@ -285,7 +279,7 @@ describe Puppet::Application::Apply do Puppet::Transaction::Report.stubs(:new).returns(report) Puppet::Configurer.any_instance.expects(:save_last_run_summary).with(report) - @apply.main + expect { @apply.main }.to exit_with 0 end describe "with detailed_exitcodes" do @@ -293,18 +287,16 @@ describe Puppet::Application::Apply do Puppet.stubs(:[]).with(:noop).returns(false) @apply.options.stubs(:[]).with(:detailed_exitcodes).returns(true) Puppet::Transaction::Report.any_instance.stubs(:exit_status).returns(666) - @apply.expects(:exit).with(666) - @apply.main + expect { @apply.main }.to exit_with 666 end it "should exit with report's computed exit status, even if --noop is set" do Puppet.stubs(:[]).with(:noop).returns(true) @apply.options.stubs(:[]).with(:detailed_exitcodes).returns(true) Puppet::Transaction::Report.any_instance.stubs(:exit_status).returns(666) - @apply.expects(:exit).with(666) - @apply.main + expect { @apply.main }.to exit_with 666 end it "should always exit with 0 if option is disabled" do @@ -312,9 +304,8 @@ describe Puppet::Application::Apply do @apply.options.stubs(:[]).with(:detailed_exitcodes).returns(false) report = stub 'report', :exit_status => 666 @transaction.stubs(:report).returns(report) - @apply.expects(:exit).with(0) - @apply.main + expect { @apply.main }.to exit_with 0 end it "should always exit with 0 if --noop" do @@ -322,9 +313,8 @@ describe Puppet::Application::Apply do @apply.options.stubs(:[]).with(:detailed_exitcodes).returns(true) report = stub 'report', :exit_status => 666 @transaction.stubs(:report).returns(report) - @apply.expects(:exit).with(0) - @apply.main + expect { @apply.main }.to exit_with 0 end end end diff --git a/spec/unit/application/cert_spec.rb b/spec/unit/application/cert_spec.rb index 4a91c1e6c..1b1c61ab4 100755 --- a/spec/unit/application/cert_spec.rb +++ b/spec/unit/application/cert_spec.rb @@ -79,18 +79,14 @@ describe Puppet::Application::Cert do end it "should print puppet config if asked to in Puppet config" do - @cert_app.stubs(:exit) Puppet.settings.stubs(:print_configs?).returns(true) - - Puppet.settings.expects(:print_configs) - - @cert_app.setup + Puppet.settings.expects(:print_configs).returns true + expect { @cert_app.setup }.to exit_with 0 end it "should exit after printing puppet config if asked to in Puppet config" do Puppet.settings.stubs(:print_configs?).returns(true) - - lambda { @cert_app.setup }.should raise_error(SystemExit) + expect { @cert_app.setup }.to exit_with 1 end it "should set the CA location to 'only'" do diff --git a/spec/unit/application/device_spec.rb b/spec/unit/application/device_spec.rb index 832b7e55b..df8cd3eaf 100755 --- a/spec/unit/application/device_spec.rb +++ b/spec/unit/application/device_spec.rb @@ -260,8 +260,7 @@ describe Puppet::Application::Device do end it "should exit if the device list is empty" do - @device.expects(:exit).with(1) - @device.main + expect { @device.main }.to exit_with 1 end describe "for each device" do diff --git a/spec/unit/application/doc_spec.rb b/spec/unit/application/doc_spec.rb index 43a4b9849..971378cd4 100755 --- a/spec/unit/application/doc_spec.rb +++ b/spec/unit/application/doc_spec.rb @@ -106,9 +106,8 @@ describe Puppet::Application::Doc do Puppet::Util::Reference.expects(:reference).with(reference).returns(ref) ref.expects(:doc) - @doc.expects(:exit) - @doc.handle_list(nil) + expect { @doc.handle_list(nil) }.to exit_with 0 end it "should add reference to references list with --reference" do @@ -279,7 +278,6 @@ describe Puppet::Application::Doc do Puppet.settings.stubs(:[]=).with(:document_all, false) Puppet.settings.stubs(:setdefaults) Puppet::Util::RDoc.stubs(:rdoc) - @doc.stubs(:exit) File.stubs(:expand_path).with('modules').returns('modules') File.stubs(:expand_path).with('manifests').returns('manifests') @doc.command_line.stubs(:args).returns([]) @@ -289,30 +287,30 @@ describe Puppet::Application::Doc do @doc.options.expects(:[]).with(:all).returns(true) Puppet.settings.expects(:[]=).with(:document_all, true) - @doc.rdoc + expect { @doc.rdoc }.to exit_with 0 end it "should call Puppet::Util::RDoc.rdoc in full mode" do Puppet::Util::RDoc.expects(:rdoc).with('doc', ['modules','manifests'], nil) - @doc.rdoc + expect { @doc.rdoc }.to exit_with 0 end it "should call Puppet::Util::RDoc.rdoc with a charset if --charset has been provided" do @doc.options.expects(:[]).with(:charset).returns("utf-8") Puppet::Util::RDoc.expects(:rdoc).with('doc', ['modules','manifests'], "utf-8") - @doc.rdoc + expect { @doc.rdoc }.to exit_with 0 end it "should call Puppet::Util::RDoc.rdoc in full mode with outputdir set to doc if no --outputdir" do @doc.options.expects(:[]).with(:outputdir).returns(false) Puppet::Util::RDoc.expects(:rdoc).with('doc', ['modules','manifests'], nil) - @doc.rdoc + expect { @doc.rdoc }.to exit_with 0 end it "should call Puppet::Util::RDoc.manifestdoc in manifest mode" do @doc.manifest = true Puppet::Util::RDoc.expects(:manifestdoc) - @doc.rdoc + expect { @doc.rdoc }.to exit_with 0 end it "should get modulepath and manifestdir values from the environment" do @@ -321,7 +319,7 @@ describe Puppet::Application::Doc do Puppet::Util::RDoc.expects(:rdoc).with('doc', ['envmodules1','envmodules2','envmanifests'], nil) - @doc.rdoc + expect { @doc.rdoc }.to exit_with 0 end end diff --git a/spec/unit/application/face_base_spec.rb b/spec/unit/application/face_base_spec.rb index f7c55c556..2a9a22356 100755 --- a/spec/unit/application/face_base_spec.rb +++ b/spec/unit/application/face_base_spec.rb @@ -7,18 +7,6 @@ class Puppet::Application::FaceBase::Basetest < Puppet::Application::FaceBase end describe Puppet::Application::FaceBase do - before :all do - Puppet::Face.define(:basetest, '0.0.1') do - option("--[no-]boolean") - option("--mandatory MANDATORY") - - action :foo do - option("--action") - when_invoked { |*args| args.length } - end - end - end - let :app do app = Puppet::Application::FaceBase::Basetest.new app.command_line.stubs(:subcommand_name).returns('subcommand') @@ -66,7 +54,7 @@ describe Puppet::Application::FaceBase do it "should use the default action if not given any arguments" do app.command_line.stubs(:args).returns [] - action = stub(:options => []) + action = stub(:options => [], :render_as => nil) Puppet::Face[:basetest, '0.0.1'].expects(:get_default_action).returns(action) app.stubs(:main) app.run @@ -76,7 +64,7 @@ describe Puppet::Application::FaceBase do it "should use the default action if not given a valid one" do app.command_line.stubs(:args).returns %w{bar} - action = stub(:options => []) + action = stub(:options => [], :render_as => nil) Puppet::Face[:basetest, '0.0.1'].expects(:get_default_action).returns(action) app.stubs(:main) app.run @@ -88,9 +76,8 @@ describe Puppet::Application::FaceBase do app.command_line.stubs(:args).returns %w{bar} Puppet::Face[:basetest, '0.0.1'].expects(:get_default_action).returns(nil) app.stubs(:main) - app.run - app.action.should be_nil - app.arguments.should == [ 'bar', { } ] + expect { app.run }.to exit_with 1 + @logs.first.message.should =~ /does not have a default action/ end it "should report a sensible error when options with = fail" do @@ -162,7 +149,7 @@ describe Puppet::Application::FaceBase do end it "should handle application-level options" do - app.command_line.stubs(:args).returns %w{help --verbose help} + app.command_line.stubs(:args).returns %w{basetest --verbose return_true} app.preinit app.parse_options app.face.name.should == :basetest @@ -189,7 +176,7 @@ describe Puppet::Application::FaceBase do describe "#main" do before :each do - app.expects(:exit).with(0) + app.stubs(:puts) # don't dump text to screen. app.face = Puppet::Face[:basetest, '0.0.1'] app.action = app.face.get_action(:foo) @@ -198,69 +185,101 @@ describe Puppet::Application::FaceBase do it "should send the specified verb and name to the face" do app.face.expects(:foo).with(*app.arguments) - app.main + expect { app.main }.to exit_with 0 end it "should lookup help when it cannot do anything else" do app.action = nil - Puppet::Face[:help, :current].expects(:help).with(:basetest, *app.arguments) - app.stubs(:puts) # meh. Don't print nil, thanks. --daniel 2011-04-12 - app.main + Puppet::Face[:help, :current].expects(:help).with(:basetest) + expect { app.main }.to exit_with 1 end it "should use its render method to render any result" do app.expects(:render).with(app.arguments.length + 1) - app.stubs(:puts) # meh. Don't print nil, thanks. --daniel 2011-04-12 - app.main + expect { app.main }.to exit_with 0 end end - describe "#render" do + describe "error reporting" do before :each do - app.face = Puppet::Face[:basetest, '0.0.1'] - app.action = app.face.get_action(:foo) + app.stubs(:puts) # don't dump text to screen. + + app.render_as = :json + app.face = Puppet::Face[:basetest, '0.0.1'] + app.arguments = [{}] # we always have options in there... end - ["hello", 1, 1.0].each do |input| - it "should just return a #{input.class.name}" do - app.render(input).should == input - end + it "should exit 0 when the action returns true" do + app.action = app.face.get_action :return_true + expect { app.main }.to exit_with 0 end - [[1, 2], ["one"], [{ 1 => 1 }]].each do |input| - it "should render #{input.class} using the 'pp' library" do - app.render(input).should == input.pretty_inspect - end + it "should exit 0 when the action returns false" do + app.action = app.face.get_action :return_false + expect { app.main }.to exit_with 0 + end + + it "should exit 0 when the action returns nil" do + app.action = app.face.get_action :return_nil + expect { app.main }.to exit_with 0 + end + + it "should exit non-0 when the action raises" do + app.action = app.face.get_action :return_raise + expect { app.main }.not_to exit_with 0 end + end - it "should render a non-trivially-keyed Hash with the 'pp' library" do - hash = { [1,2] => 3, [2,3] => 5, [3,4] => 7 } - app.render(hash).should == hash.pretty_inspect + describe "#render" do + before :each do + app.face = Puppet::Face[:basetest, '0.0.1'] + app.action = app.face.get_action(:foo) end - it "should render a {String,Numeric}-keyed Hash into a table" do - object = Object.new - hash = { "one" => 1, "two" => [], "three" => {}, "four" => object, - 5 => 5, 6.0 => 6 } + context "default rendering" do + before :each do app.setup end - # Gotta love ASCII-betical sort order. Hope your objects are better - # structured for display than my test one is. --daniel 2011-04-18 - app.render(hash).should == <<EOT + ["hello", 1, 1.0].each do |input| + it "should just return a #{input.class.name}" do + app.render(input).should == input + end + end + + [[1, 2], ["one"], [{ 1 => 1 }]].each do |input| + it "should render #{input.class} using JSON" do + app.render(input).should == input.to_pson.chomp + end + end + + it "should render a non-trivially-keyed Hash with using JSON" do + hash = { [1,2] => 3, [2,3] => 5, [3,4] => 7 } + app.render(hash).should == hash.to_pson.chomp + end + + it "should render a {String,Numeric}-keyed Hash into a table" do + object = Object.new + hash = { "one" => 1, "two" => [], "three" => {}, "four" => object, + 5 => 5, 6.0 => 6 } + + # Gotta love ASCII-betical sort order. Hope your objects are better + # structured for display than my test one is. --daniel 2011-04-18 + app.render(hash).should == <<EOT 5 5 6.0 6 -four #{object.pretty_inspect.chomp} +four #{object.to_pson.chomp} one 1 three {} two [] EOT - end + end - it "should render a hash nicely with a multi-line value" do - hash = { - "number" => { "1" => '1' * 40, "2" => '2' * 40, '3' => '3' * 40 }, - "text" => { "a" => 'a' * 40, 'b' => 'b' * 40, 'c' => 'c' * 40 } - } - app.render(hash).should == <<EOT + it "should render a hash nicely with a multi-line value" do + pending "Moving to PSON rather than PP makes this unsupportable." + hash = { + "number" => { "1" => '1' * 40, "2" => '2' * 40, '3' => '3' * 40 }, + "text" => { "a" => 'a' * 40, 'b' => 'b' * 40, 'c' => 'c' * 40 } + } + app.render(hash).should == <<EOT number {"1"=>"1111111111111111111111111111111111111111", "2"=>"2222222222222222222222222222222222222222", "3"=>"3333333333333333333333333333333333333333"} @@ -268,12 +287,46 @@ text {"a"=>"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "b"=>"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", "c"=>"cccccccccccccccccccccccccccccccccccccccc"} EOT + end + + it "should invoke the action rendering hook while rendering" do + app.action.set_rendering_method_for(:console, proc { |value| "bi-winning!" }) + app.render("bi-polar?").should == "bi-winning!" + end + + it "should render JSON when asked for json" do + app.render_as = :json + json = app.render({ :one => 1, :two => 2 }) + json.should =~ /"one":\s*1\b/ + json.should =~ /"two":\s*2\b/ + PSON.parse(json).should == { "one" => 1, "two" => 2 } + end + end + + it "should fail early if asked to render an invalid format" do + app.command_line.stubs(:args).returns %w{--render-as interpretive-dance help help} + # We shouldn't get here, thanks to the exception, and our expectation on + # it, but this helps us fail if that slips up and all. --daniel 2011-04-27 + Puppet::Face[:help, :current].expects(:help).never + + expect { + expect { app.run }.to exit_with 1 + }.to have_printed(/I don't know how to render 'interpretive-dance'/) + end + + it "should work if asked to render a NetworkHandler format" do + app.command_line.stubs(:args).returns %w{dummy find dummy --render-as yaml} + expect { + expect { app.run }.to exit_with 0 + }.to have_printed(/--- 3/) end - it "should invoke the action rendering hook while rendering" do - app.action.set_rendering_method_for(:for_humans, proc { |value| "bi-winning!" }) - app.action.render_as = :for_humans - app.render("bi-polar?").should == "bi-winning!" + it "should invoke when_rendering hook 's' when asked to render-as 's'" do + app.command_line.stubs(:args).returns %w{with_s_rendering_hook --render-as s} + app.action = app.face.get_action(:with_s_rendering_hook) + expect { + expect { app.run }.to exit_with 0 + }.to have_printed(/you invoked the 's' rendering hook/) end end end diff --git a/spec/unit/application/facts_spec.rb b/spec/unit/application/facts_spec.rb new file mode 100755 index 000000000..2981dc805 --- /dev/null +++ b/spec/unit/application/facts_spec.rb @@ -0,0 +1,27 @@ +#!/usr/bin/env rspec +require 'spec_helper' +require 'puppet/application/facts' + +describe Puppet::Application::Facts do + before :each do + subject.command_line.stubs(:subcommand_name).returns 'facts' + end + + it "should fail if no key is given to find" do + subject.command_line.stubs(:args).returns %w{find} + expect { + expect { subject.run }.to exit_with 1 + }.to have_printed /err: puppet facts find takes 1 argument, but you gave 0/ + @logs.first.to_s.should =~ /puppet facts find takes 1 argument, but you gave 0/ + end + + it "should return facts if a key is given to find" do + subject.command_line.stubs(:args).returns %w{find whatever --render-as yaml} + + expect { + expect { subject.run }.to exit_with 0 + }.should have_printed(/object:Puppet::Node::Facts/) + + @logs.should be_empty + end +end diff --git a/spec/unit/application/filebucket_spec.rb b/spec/unit/application/filebucket_spec.rb index 92bc0410a..ee30e7d12 100755 --- a/spec/unit/application/filebucket_spec.rb +++ b/spec/unit/application/filebucket_spec.rb @@ -78,18 +78,14 @@ describe Puppet::Application::Filebucket do end it "should print puppet config if asked to in Puppet config" do - @filebucket.stubs(:exit) Puppet.settings.stubs(:print_configs?).returns(true) - - Puppet.settings.expects(:print_configs) - - @filebucket.setup + Puppet.settings.expects(:print_configs).returns(true) + expect { @filebucket.setup }.to exit_with 0 end it "should exit after printing puppet config if asked to in Puppet config" do Puppet.settings.stubs(:print_configs?).returns(true) - - lambda { @filebucket.setup }.should raise_error(SystemExit) + expect { @filebucket.setup }.to exit_with 1 end describe "with local bucket" do diff --git a/spec/unit/application/indirection_base_spec.rb b/spec/unit/application/indirection_base_spec.rb index 57740384a..910774c14 100755 --- a/spec/unit/application/indirection_base_spec.rb +++ b/spec/unit/application/indirection_base_spec.rb @@ -1,14 +1,15 @@ #!/usr/bin/env rspec require 'spec_helper' require 'puppet/application/indirection_base' -require 'puppet/face/indirector' +require 'puppet/indirector/face' ######################################################################## # Stub for testing; the names are critical, sadly. --daniel 2011-03-30 class Puppet::Application::TestIndirection < Puppet::Application::IndirectionBase end -face = Puppet::Face::Indirector.define(:testindirection, '0.0.1') do +face = Puppet::Indirector::Face.define(:testindirection, '0.0.1') do + summary "fake summary" end # REVISIT: This horror is required because we don't allow anything to be # :current except for if it lives on, and is loaded from, disk. --daniel 2011-03-29 @@ -27,11 +28,12 @@ describe Puppet::Application::IndirectionBase do Puppet::Indirector::Indirection.expects(:instance). with(:testindirection).returns(terminus) - subject.command_line.instance_variable_set('@args', %w{--terminus foo save}) + subject.command_line.instance_variable_set('@args', %w{--terminus foo save bar}) # Not a very nice thing. :( $stderr.stubs(:puts) + Puppet.stubs(:err) - expect { subject.run }.should raise_error SystemExit + expect { subject.run }.to exit_with 0 end end diff --git a/spec/unit/application/inspect_spec.rb b/spec/unit/application/inspect_spec.rb index fda61c6e4..571683f37 100755 --- a/spec/unit/application/inspect_spec.rb +++ b/spec/unit/application/inspect_spec.rb @@ -19,7 +19,7 @@ describe Puppet::Application::Inspect do Puppet[:configprint] = "all" Puppet.settings.expects(:print_configs).returns(true) - lambda { @inspect.setup }.should raise_error(SystemExit) + expect { @inspect.setup }.to exit_with 0 end it "should fail if reporting is turned off" do diff --git a/spec/unit/application/kick_spec.rb b/spec/unit/application/kick_spec.rb index 742c0fff6..b24e78452 100755 --- a/spec/unit/application/kick_spec.rb +++ b/spec/unit/application/kick_spec.rb @@ -184,9 +184,7 @@ describe Puppet::Application::Kick, :if => Puppet.features.posix? do $stderr.stubs(:puts) @kick.classes = ['class'] - @kick.expects(:exit).with(24) - - @kick.setup + expect { @kick.setup }.to exit_with 24 end end end @@ -212,9 +210,7 @@ describe Puppet::Application::Kick, :if => Puppet.features.posix? do describe "the test command" do it "should exit with exit code 0 " do - @kick.expects(:exit).with(0) - - @kick.test + expect { @kick.test }.to exit_with 0 end end @@ -226,7 +222,6 @@ describe Puppet::Application::Kick, :if => Puppet.features.posix? do @kick.options.stubs(:[]).with(:foreground).returns(false) @kick.options.stubs(:[]).with(:debug).returns(false) @kick.stubs(:print) - @kick.stubs(:exit) @kick.preinit @kick.stubs(:parse_options) @kick.setup @@ -236,17 +231,15 @@ describe Puppet::Application::Kick, :if => Puppet.features.posix? do it "should create as much childs as --parallel" do @kick.options.stubs(:[]).with(:parallel).returns(3) @kick.hosts = ['host1', 'host2', 'host3'] - @kick.stubs(:exit).raises(SystemExit) Process.stubs(:wait).returns(1).then.returns(2).then.returns(3).then.raises(Errno::ECHILD) @kick.expects(:fork).times(3).returns(1).then.returns(2).then.returns(3) - lambda { @kick.main }.should raise_error + expect { @kick.main }.to raise_error SystemExit end it "should delegate to run_for_host per host" do @kick.hosts = ['host1', 'host2'] - @kick.stubs(:exit).raises(SystemExit) @kick.stubs(:fork).returns(1).yields Process.stubs(:wait).returns(1).then.raises(Errno::ECHILD) @@ -272,31 +265,22 @@ describe Puppet::Application::Kick, :if => Puppet.features.posix? do it "should call run on a Puppet::Run for the given host" do Puppet::Run.indirection.expects(:save).with(@agent_run, 'https://host:8139/production/run/host').returns(@agent_run) - @kick.run_for_host('host') + expect { @kick.run_for_host('host') }.to exit_with 0 end it "should exit the child with 0 on success" do @agent_run.stubs(:status).returns("success") - - @kick.expects(:exit).with(0) - - @kick.run_for_host('host') + expect { @kick.run_for_host('host') }.to exit_with 0 end it "should exit the child with 3 on running" do @agent_run.stubs(:status).returns("running") - - @kick.expects(:exit).with(3) - - @kick.run_for_host('host') + expect { @kick.run_for_host('host') }.to exit_with 3 end it "should exit the child with 12 on unknown answer" do @agent_run.stubs(:status).returns("whatever") - - @kick.expects(:exit).with(12) - - @kick.run_for_host('host') + expect { @kick.run_for_host('host') }.to exit_with 12 end end end diff --git a/spec/unit/application/master_spec.rb b/spec/unit/application/master_spec.rb index 2a24086f3..2f6a328e2 100755 --- a/spec/unit/application/master_spec.rb +++ b/spec/unit/application/master_spec.rb @@ -152,18 +152,14 @@ describe Puppet::Application::Master do end it "should print puppet config if asked to in Puppet config" do - @master.stubs(:exit) Puppet.settings.stubs(:print_configs?).returns(true) - - Puppet.settings.expects(:print_configs) - - @master.setup + Puppet.settings.expects(:print_configs).returns(true) + expect { @master.setup }.to exit_with 0 end it "should exit after printing puppet config if asked to in Puppet config" do Puppet.settings.stubs(:print_configs?).returns(true) - - lambda { @master.setup }.should raise_error(SystemExit) + expect { @master.setup }.to exit_with 1 end it "should tell Puppet.settings to use :main,:ssl,:master and :metrics category" do @@ -241,7 +237,6 @@ describe Puppet::Application::Master do Puppet.stubs(:[]).with(:manifest).returns("site.pp") Puppet.stubs(:err) @master.stubs(:jj) - @master.stubs(:exit) Puppet.features.stubs(:pson?).returns true end @@ -255,7 +250,7 @@ describe Puppet::Application::Master do Puppet::Resource::Catalog.indirection.expects(:find).with("foo").returns Puppet::Resource::Catalog.new $stdout.stubs(:puts) - @master.compile + expect { @master.compile }.to exit_with 0 end it "should convert the catalog to a pure-resource catalog and use 'jj' to pretty-print the catalog" do @@ -267,25 +262,21 @@ describe Puppet::Application::Master do @master.options[:node] = "foo" @master.expects(:jj).with("rescat") - @master.compile + expect { @master.compile }.to exit_with 0 end it "should exit with error code 30 if no catalog can be found" do @master.options[:node] = "foo" Puppet::Resource::Catalog.indirection.expects(:find).returns nil - @master.expects(:exit).with(30) $stderr.expects(:puts) - - @master.compile + expect { @master.compile }.to exit_with 30 end it "should exit with error code 30 if there's a failure" do @master.options[:node] = "foo" Puppet::Resource::Catalog.indirection.expects(:find).raises ArgumentError - @master.expects(:exit).with(30) $stderr.expects(:puts) - - @master.compile + expect { @master.compile }.to exit_with 30 end end diff --git a/spec/unit/application/queue_spec.rb b/spec/unit/application/queue_spec.rb index d71c879a9..15e3927a1 100755 --- a/spec/unit/application/queue_spec.rb +++ b/spec/unit/application/queue_spec.rb @@ -86,18 +86,14 @@ describe Puppet::Application::Queue do end it "should print puppet config if asked to in Puppet config" do - @queue.stubs(:exit) Puppet.settings.stubs(:print_configs?).returns(true) - - Puppet.settings.expects(:print_configs) - - @queue.setup + Puppet.settings.expects(:print_configs).returns(true) + expect { @queue.setup }.to exit_with 0 end it "should exit after printing puppet config if asked to in Puppet config" do Puppet.settings.stubs(:print_configs?).returns(true) - - lambda { @queue.setup }.should raise_error(SystemExit) + expect { @queue.setup }.to exit_with 1 end it "should call setup_logs" do diff --git a/spec/unit/application/resource_spec.rb b/spec/unit/application/resource_spec.rb index af60f12c1..9ee6dd71b 100755 --- a/spec/unit/application/resource_spec.rb +++ b/spec/unit/application/resource_spec.rb @@ -77,10 +77,8 @@ describe Puppet::Application::Resource do type2 = stub_everything 'type2', :name => :type2 Puppet::Type.stubs(:loadall) Puppet::Type.stubs(:eachtype).multiple_yields(type1,type2) - @resource.stubs(:exit) - @resource.expects(:puts).with(['type1','type2']) - @resource.handle_types(nil) + expect { @resource.handle_types(nil) }.to exit_with 0 end it "should add param to extra_params list" do diff --git a/spec/unit/application/configurer_spec.rb b/spec/unit/application/secret_agent_spec.rb index 791a367ea..eba936447 100755 --- a/spec/unit/application/configurer_spec.rb +++ b/spec/unit/application/secret_agent_spec.rb @@ -1,11 +1,11 @@ #!/usr/bin/env rspec require 'spec_helper' -require 'puppet/application/configurer' +require 'puppet/application/secret_agent' require 'puppet/indirector/catalog/rest' require 'puppet/indirector/report/rest' require 'tempfile' -describe "Puppet::Application::Configurer" do +describe "Puppet::Application::Secret_agent" do it "should retrieve and apply a catalog and submit a report" do pending "REVISIT: 2.7 changes broke this, and we want the merge published" @@ -25,7 +25,7 @@ describe "Puppet::Application::Configurer" do Puppet::Util::Log.stubs(:newdestination) - Puppet::Application::Configurer.new.run + Puppet::Application::Secret_agent.new.run @report.status.should == "changed" end diff --git a/spec/unit/application_spec.rb b/spec/unit/application_spec.rb index de1ca1257..fc1bbceb6 100755 --- a/spec/unit/application_spec.rb +++ b/spec/unit/application_spec.rb @@ -27,11 +27,11 @@ describe Puppet::Application do end it "should not find classes outside the namespace" do - lambda { @klass.find("String") }.should raise_error(SystemExit) + expect { @klass.find("String") }.to exit_with 1 end it "should exit if it can't find a class" do - lambda { @klass.find("ThisShallNeverEverEverExistAsdf") }.should raise_error(SystemExit) + expect { @klass.find("ThisShallNeverEverEverExist") }.to exit_with 1 end end @@ -286,10 +286,8 @@ describe Puppet::Application do describe "when using --help" do it "should call exit" do - @app.expects(:exit) @app.stubs(:puts) - - @app.handle_help(nil) + expect { @app.handle_help(nil) }.to exit_with 0 end end @@ -301,8 +299,7 @@ describe Puppet::Application do it "should exit after printing the version" do @app.stubs(:puts) - - lambda { @app.handle_version(nil) }.should raise_error(SystemExit) + expect { @app.handle_version(nil) }.to exit_with 0 end end @@ -505,22 +502,19 @@ describe Puppet::Application do it "should warn and exit if no command can be called" do $stderr.expects(:puts) - @app.expects(:exit).with(1) - @app.run + expect { @app.run }.to exit_with 1 end it "should raise an error if dispatch returns no command" do @app.stubs(:get_command).returns(nil) $stderr.expects(:puts) - @app.expects(:exit).with(1) - @app.run + expect { @app.run }.to exit_with 1 end it "should raise an error if dispatch returns an invalid command" do @app.stubs(:get_command).returns(:this_function_doesnt_exist) $stderr.expects(:puts) - @app.expects(:exit).with(1) - @app.run + expect { @app.run }.to exit_with 1 end end diff --git a/spec/unit/daemon_spec.rb b/spec/unit/daemon_spec.rb index ed8dec2a3..e2679a966 100755 --- a/spec/unit/daemon_spec.rb +++ b/spec/unit/daemon_spec.rb @@ -86,7 +86,6 @@ describe Puppet::Daemon do describe "when stopping" do before do @daemon.stubs(:remove_pidfile) - @daemon.stubs(:exit) Puppet::Util::Log.stubs(:close_all) # to make the global safe to mock, set it to a subclass of itself, # then restore it in an after pass @@ -102,34 +101,29 @@ describe Puppet::Daemon do server = mock 'server' server.expects(:stop) @daemon.stubs(:server).returns server - - @daemon.stop + expect { @daemon.stop }.to exit_with 0 end it 'should request a stop from Puppet::Application' do Puppet::Application.expects(:stop!) - @daemon.stop + expect { @daemon.stop }.to exit_with 0 end it "should remove its pidfile" do @daemon.expects(:remove_pidfile) - - @daemon.stop + expect { @daemon.stop }.to exit_with 0 end it "should close all logs" do Puppet::Util::Log.expects(:close_all) - - @daemon.stop + expect { @daemon.stop }.to exit_with 0 end it "should exit unless called with ':exit => false'" do - @daemon.expects(:exit) - @daemon.stop + expect { @daemon.stop }.to exit_with 0 end it "should not exit if called with ':exit => false'" do - @daemon.expects(:exit).never @daemon.stop :exit => false end end diff --git a/spec/unit/face/catalog_spec.rb b/spec/unit/face/catalog_spec.rb index 28c2aa9be..c77a9d153 100755 --- a/spec/unit/face/catalog_spec.rb +++ b/spec/unit/face/catalog_spec.rb @@ -1,4 +1,7 @@ +#!/usr/bin/env rspec +require 'spec_helper' require 'puppet/face' + describe Puppet::Face[:catalog, '0.0.1'] do it "should actually have some testing..." end diff --git a/spec/unit/face/certificate_request_spec.rb b/spec/unit/face/certificate_request_spec.rb index a83a92df8..e237800ff 100755 --- a/spec/unit/face/certificate_request_spec.rb +++ b/spec/unit/face/certificate_request_spec.rb @@ -1,3 +1,7 @@ +#!/usr/bin/env rspec +require 'spec_helper' +require 'puppet/face' + describe Puppet::Face[:certificate_request, '0.0.1'] do it "should actually have some tests..." end diff --git a/spec/unit/face/certificate_revocation_list_spec.rb b/spec/unit/face/certificate_revocation_list_spec.rb index 22c0fa2bf..1033df7ff 100755 --- a/spec/unit/face/certificate_revocation_list_spec.rb +++ b/spec/unit/face/certificate_revocation_list_spec.rb @@ -1,3 +1,7 @@ +#!/usr/bin/env rspec +require 'spec_helper' +require 'puppet/face' + describe Puppet::Face[:certificate_revocation_list, '0.0.1'] do it "should actually have some tests..." end diff --git a/spec/unit/face/certificate_spec.rb b/spec/unit/face/certificate_spec.rb index b0bbf1af6..0cb905b75 100755 --- a/spec/unit/face/certificate_spec.rb +++ b/spec/unit/face/certificate_spec.rb @@ -1,3 +1,7 @@ +#!/usr/bin/env rspec +require 'spec_helper' +require 'puppet/face' + require 'puppet/ssl/host' describe Puppet::Face[:certificate, '0.0.1'] do diff --git a/spec/unit/face/config_spec.rb b/spec/unit/face/config_spec.rb index 6004d700f..0c762f2aa 100755 --- a/spec/unit/face/config_spec.rb +++ b/spec/unit/face/config_spec.rb @@ -1,5 +1,6 @@ #!/usr/bin/env rspec require 'spec_helper' +require 'puppet/face' describe Puppet::Face[:config, '0.0.1'] do it "should use Settings#print_config_options when asked to print" do diff --git a/spec/unit/face/facts_spec.rb b/spec/unit/face/facts_spec.rb index 6ab6ad5be..27b5b9e3d 100755 --- a/spec/unit/face/facts_spec.rb +++ b/spec/unit/face/facts_spec.rb @@ -1,5 +1,6 @@ #!/usr/bin/env rspec require 'spec_helper' +require 'puppet/face' describe Puppet::Face[:facts, '0.0.1'] do it "should define an 'upload' action" do @@ -8,9 +9,15 @@ describe Puppet::Face[:facts, '0.0.1'] do describe "when uploading" do it "should set the terminus_class to :facter" + it "should set the cache_class to :rest" + it "should find the current certname" + end - it "should set the cach_eclass to :rest" + describe "#find" do + it { should be_action :find } - it "should find the current certname" + it "should fail without a key" do + expect { subject.find }.to raise_error ArgumentError, /wrong number of arguments/ + end end end diff --git a/spec/unit/face/file_spec.rb b/spec/unit/face/file_spec.rb index 97e8bcc08..c3f05720f 100755 --- a/spec/unit/face/file_spec.rb +++ b/spec/unit/face/file_spec.rb @@ -1,3 +1,12 @@ +#!/usr/bin/env rspec +require 'spec_helper' +require 'puppet/face' + describe Puppet::Face[:file, '0.0.1'] do - it "should actually have some tests..." + it_should_behave_like "an indirector face" + + [:download, :store].each do |action| + it { should be_action action } + it { should respond_to action } + end end diff --git a/spec/unit/face/help_spec.rb b/spec/unit/face/help_spec.rb index faa5f9617..ef66660ff 100755 --- a/spec/unit/face/help_spec.rb +++ b/spec/unit/face/help_spec.rb @@ -1,5 +1,6 @@ +#!/usr/bin/env rspec require 'spec_helper' -require 'puppet/face/help' +require 'puppet/face' describe Puppet::Face[:help, '0.0.1'] do it "should have a help action" do @@ -46,6 +47,12 @@ describe Puppet::Face[:help, '0.0.1'] do context "when listing subcommands" do subject { Puppet::Face[:help, :current].help } + RSpec::Matchers.define :have_a_summary do + match do |instance| + instance.summary.is_a?(String) + end + end + # Check a precondition for the next block; if this fails you have # something odd in your set of face, and we skip testing things that # matter. --daniel 2011-04-10 @@ -65,6 +72,12 @@ describe Puppet::Face[:help, '0.0.1'] do end end + Puppet::Face.faces.each do |name| + it "should have a summary for #{name}" do + Puppet::Face[name, :current].should have_a_summary + end + end + it "should list all legacy applications" do Puppet::Face[:help, :current].legacy_applications.each do |appname| subject.should =~ %r{ #{appname} } diff --git a/spec/unit/face/key_spec.rb b/spec/unit/face/key_spec.rb index 10d664790..7de4c6e76 100755 --- a/spec/unit/face/key_spec.rb +++ b/spec/unit/face/key_spec.rb @@ -1,3 +1,7 @@ +#!/usr/bin/env rspec +require 'spec_helper' +require 'puppet/face' + describe Puppet::Face[:key, '0.0.1'] do it "should actually have some tests..." end diff --git a/spec/unit/face/node_spec.rb b/spec/unit/face/node_spec.rb index d19312c58..027a4cce0 100755 --- a/spec/unit/face/node_spec.rb +++ b/spec/unit/face/node_spec.rb @@ -1,5 +1,6 @@ #!/usr/bin/env rspec require 'spec_helper' +require 'puppet/face' describe Puppet::Face[:node, '0.0.1'] do it "REVISIT: really should have some tests" diff --git a/spec/unit/face/plugin_spec.rb b/spec/unit/face/plugin_spec.rb new file mode 100755 index 000000000..383aaa3d3 --- /dev/null +++ b/spec/unit/face/plugin_spec.rb @@ -0,0 +1,10 @@ +#!/usr/bin/env rspec +require 'spec_helper' +require 'puppet/face' + +describe Puppet::Face[:plugin, '0.0.1'] do + [:download].each do |action| + it { should be_action action } + it { should respond_to action } + end +end diff --git a/spec/unit/face/report_spec.rb b/spec/unit/face/report_spec.rb index b1b28167e..befc4e496 100755 --- a/spec/unit/face/report_spec.rb +++ b/spec/unit/face/report_spec.rb @@ -1,3 +1,7 @@ +#!/usr/bin/env rspec +require 'spec_helper' +require 'puppet/face' + describe Puppet::Face[:report, '0.0.1'] do it "should actually have some tests..." end diff --git a/spec/unit/face/resource_spec.rb b/spec/unit/face/resource_spec.rb index 084e2a6a9..0671af4c2 100755 --- a/spec/unit/face/resource_spec.rb +++ b/spec/unit/face/resource_spec.rb @@ -1,3 +1,7 @@ +#!/usr/bin/env rspec +require 'spec_helper' +require 'puppet/face' + describe Puppet::Face[:resource, '0.0.1'] do it "should actually have some tests..." end diff --git a/spec/unit/face/resource_type_spec.rb b/spec/unit/face/resource_type_spec.rb index 2adaedca1..30a1adfcb 100755 --- a/spec/unit/face/resource_type_spec.rb +++ b/spec/unit/face/resource_type_spec.rb @@ -1,3 +1,7 @@ +#!/usr/bin/env rspec +require 'spec_helper' +require 'puppet/face' + describe Puppet::Face[:resource_type, '0.0.1'] do it "should actually have some tests..." end diff --git a/spec/unit/face/configurer_spec.rb b/spec/unit/face/secret_agent_spec.rb index 56b45031f..a5ec01f27 100755 --- a/spec/unit/face/configurer_spec.rb +++ b/spec/unit/face/secret_agent_spec.rb @@ -1,13 +1,13 @@ #!/usr/bin/env rspec require 'spec_helper' +require 'puppet/face' require 'puppet/indirector/catalog/rest' require 'tempfile' -describe Puppet::Face[:configurer, '0.0.1'] do +describe Puppet::Face[:secret_agent, '0.0.1'] do describe "#synchronize" do it "should retrieve and apply a catalog and return a report" do - pending "REVISIT: 2.7 changes broke this, and we want the merge published" - + pending "This test doesn't work, but the code actually does - tested by LAK" dirname = Dir.mktmpdir("puppetdir") Puppet[:vardir] = dirname Puppet[:confdir] = dirname @@ -16,7 +16,7 @@ describe Puppet::Face[:configurer, '0.0.1'] do @catalog.add_resource(@file) Puppet::Resource::Catalog::Rest.any_instance.stubs(:find).returns(@catalog) - report = subject.synchronize("foo") + report = subject.synchronize report.kind.should == "apply" report.status.should == "changed" diff --git a/spec/unit/file_serving/fileset_spec.rb b/spec/unit/file_serving/fileset_spec.rb index a369ad39c..41810650a 100755 --- a/spec/unit/file_serving/fileset_spec.rb +++ b/spec/unit/file_serving/fileset_spec.rb @@ -20,6 +20,13 @@ describe Puppet::FileServing::Fileset, " when initializing" do fileset.path.should == path end + it "should not fail if the path is just the file separator" do + path = File::SEPARATOR + File.stubs(:lstat).with(path).returns stub('stat') + fileset = Puppet::FileServing::Fileset.new(path) + fileset.path.should == path + end + it "should fail if its path does not exist" do File.expects(:lstat).with("/some/file").returns nil proc { Puppet::FileServing::Fileset.new("/some/file") }.should raise_error(ArgumentError) diff --git a/spec/unit/face/indirector_spec.rb b/spec/unit/indirector/face_spec.rb index bb06fcfe2..1530f7270 100755 --- a/spec/unit/face/indirector_spec.rb +++ b/spec/unit/indirector/face_spec.rb @@ -1,10 +1,10 @@ #!/usr/bin/env rspec require 'spec_helper' -require 'puppet/face/indirector' +require 'puppet/indirector/face' -describe Puppet::Face::Indirector do +describe Puppet::Indirector::Face do subject do - instance = Puppet::Face::Indirector.new(:test, '0.0.1') + instance = Puppet::Indirector::Face.new(:test, '0.0.1') indirection = stub('indirection', :name => :stub_indirection, :reset_terminus_class => nil) @@ -13,33 +13,33 @@ describe Puppet::Face::Indirector do end it "should be able to return a list of indirections" do - Puppet::Face::Indirector.indirections.should be_include("catalog") + Puppet::Indirector::Face.indirections.should be_include("catalog") end it "should be able to return a list of terminuses for a given indirection" do - Puppet::Face::Indirector.terminus_classes(:catalog).should be_include("compiler") + Puppet::Indirector::Face.terminus_classes(:catalog).should be_include("compiler") end describe "as an instance" do it "should be able to determine its indirection" do # Loading actions here an get, um, complicated Puppet::Face.stubs(:load_actions) - Puppet::Face::Indirector.new(:catalog, '0.0.1').indirection.should equal(Puppet::Resource::Catalog.indirection) + Puppet::Indirector::Face.new(:catalog, '0.0.1').indirection.should equal(Puppet::Resource::Catalog.indirection) end end [:find, :search, :save, :destroy].each do |method| it "should define a '#{method}' action" do - Puppet::Face::Indirector.should be_action(method) + Puppet::Indirector::Face.should be_action(method) end it "should call the indirection method with options when the '#{method}' action is invoked" do - subject.indirection.expects(method).with(:test, "myargs", {}) - subject.send(method, :test, "myargs") + subject.indirection.expects(method).with(:test, {}) + subject.send(method, :test) end it "should forward passed options" do - subject.indirection.expects(method).with(:test, "action", {'one'=>'1'}) - subject.send(method, :test, 'action', {'one'=>'1'}) + subject.indirection.expects(method).with(:test, {'one'=>'1'}) + subject.send(method, :test, {'one'=>'1'}) end end @@ -54,6 +54,6 @@ describe Puppet::Face::Indirector do end it "should define a class-level 'info' action" do - Puppet::Face::Indirector.should be_action(:info) + Puppet::Indirector::Face.should be_action(:info) end end diff --git a/spec/unit/indirector/request_spec.rb b/spec/unit/indirector/request_spec.rb index ba7dc815e..87b9af438 100755 --- a/spec/unit/indirector/request_spec.rb +++ b/spec/unit/indirector/request_spec.rb @@ -301,99 +301,4 @@ describe Puppet::Indirector::Request do lambda { @request.query_string }.should raise_error(ArgumentError) end end - - describe "when converting to json" do - before do - @request = Puppet::Indirector::Request.new(:facts, :find, "foo") - end - - it "should produce a hash with the document_type set to 'request'" do - @request.should set_json_document_type_to("Puppet::Indirector::Request") - end - - it "should set the 'key'" do - @request.should set_json_attribute("key").to("foo") - end - - it "should include an attribute for its indirection name" do - @request.should set_json_attribute("type").to("facts") - end - - it "should include a 'method' attribute set to its method" do - @request.should set_json_attribute("method").to("find") - end - - it "should add all attributes under the 'attributes' attribute" do - @request.ip = "127.0.0.1" - @request.should set_json_attribute("attributes", "ip").to("127.0.0.1") - end - - it "should add all options under the 'attributes' attribute" do - @request.options["opt"] = "value" - PSON.parse(@request.to_pson)["data"]['attributes']['opt'].should == "value" - end - - it "should include the instance if provided" do - facts = Puppet::Node::Facts.new("foo") - @request.instance = facts - PSON.parse(@request.to_pson)["data"]['instance'].should be_instance_of(Puppet::Node::Facts) - end - end - - describe "when converting from json" do - before do - @request = Puppet::Indirector::Request.new(:facts, :find, "foo") - @klass = Puppet::Indirector::Request - @format = Puppet::Network::FormatHandler.format('pson') - end - - def from_json(json) - @format.intern(Puppet::Indirector::Request, json) - end - - it "should set the 'key'" do - from_json(@request.to_pson).key.should == "foo" - end - - it "should fail if no key is provided" do - json = PSON.parse(@request.to_pson) - json['data'].delete("key") - lambda { from_json(json.to_pson) }.should raise_error(ArgumentError) - end - - it "should set its indirector name" do - from_json(@request.to_pson).indirection_name.should == :facts - end - - it "should fail if no type is provided" do - json = PSON.parse(@request.to_pson) - json['data'].delete("type") - lambda { from_json(json.to_pson) }.should raise_error(ArgumentError) - end - - it "should set its method" do - from_json(@request.to_pson).method.should == "find" - end - - it "should fail if no method is provided" do - json = PSON.parse(@request.to_pson) - json['data'].delete("method") - lambda { from_json(json.to_pson) }.should raise_error(ArgumentError) - end - - it "should initialize with all attributes and options" do - @request.ip = "127.0.0.1" - @request.options["opt"] = "value" - result = from_json(@request.to_pson) - result.options[:opt].should == "value" - result.ip.should == "127.0.0.1" - end - - it "should set its instance as an instance if one is provided" do - facts = Puppet::Node::Facts.new("foo") - @request.instance = facts - result = from_json(@request.to_pson) - result.instance.should be_instance_of(Puppet::Node::Facts) - end - end end diff --git a/spec/unit/interface/action_builder_spec.rb b/spec/unit/interface/action_builder_spec.rb index 6f36d2b44..e9f10a1a6 100755 --- a/spec/unit/interface/action_builder_spec.rb +++ b/spec/unit/interface/action_builder_spec.rb @@ -7,7 +7,8 @@ describe Puppet::Interface::ActionBuilder do let :face do Puppet::Interface.new(:puppet_interface_actionbuilder, '0.0.1') end it "should build an action" do - action = Puppet::Interface::ActionBuilder.build(nil, :foo) do + action = Puppet::Interface::ActionBuilder.build(face, :foo) do + when_invoked do true end end action.should be_a(Puppet::Interface::Action) action.name.should == :foo @@ -26,17 +27,25 @@ describe Puppet::Interface::ActionBuilder do should raise_error("Action :foo must specify a block") end + it "should require an invocation block" do + expect { + Puppet::Interface::ActionBuilder.build(face, :foo) {} + }.to raise_error(/actions need to know what to do when_invoked; please add the block/) + end + describe "when handling options" do it "should have a #option DSL function" do method = nil Puppet::Interface::ActionBuilder.build(face, :foo) do + when_invoked do true end method = self.method(:option) end - method.should be + method.should be_an_instance_of Method end it "should define an option without a block" do action = Puppet::Interface::ActionBuilder.build(face, :foo) do + when_invoked do true end option "--bar" end action.should be_option :bar @@ -44,6 +53,7 @@ describe Puppet::Interface::ActionBuilder do it "should accept an empty block" do action = Puppet::Interface::ActionBuilder.build(face, :foo) do + when_invoked do true end option "--bar" do # This space left deliberately blank. end @@ -58,15 +68,18 @@ describe Puppet::Interface::ActionBuilder do option '-w' action(:foo) do + when_invoked do true end option '-x', '--ex' option '-y', '--why' end action(:bar) do + when_invoked do true end option '-z', '--zee' end action(:baz) do + when_invoked do true end option '-z', '--zed' end end @@ -75,6 +88,7 @@ describe Puppet::Interface::ActionBuilder do it 'should add the options from the specified action' do foo = face.get_action(:foo) action = Puppet::Interface::ActionBuilder.build(face, :inherit_options) do + when_invoked do true end inherit_options_from foo end action.options.should == foo.options @@ -84,15 +98,17 @@ describe Puppet::Interface::ActionBuilder do foo = face.get_action(:foo) bar = face.get_action(:bar) action = Puppet::Interface::ActionBuilder.build(face, :inherit_options) do + when_invoked do true end inherit_options_from foo inherit_options_from bar end - action.options.should == (foo.options + bar.options).uniq.sort + action.options.should == (foo.options + bar.options).uniq end it 'should permit symbolic names for actions in the same face' do foo = face.get_action(:foo) action = Puppet::Interface::ActionBuilder.build(face, :inherit_options) do + when_invoked do true end inherit_options_from :foo end action.options.should == foo.options @@ -101,6 +117,7 @@ describe Puppet::Interface::ActionBuilder do it 'should raise a useful error if you supply a bad action name' do expect do Puppet::Interface::ActionBuilder.build(face, :inherit_options) do + when_invoked do true end inherit_options_from :nowhere end end.to raise_error /nowhere/ @@ -110,6 +127,7 @@ describe Puppet::Interface::ActionBuilder do context "inline documentation" do it "should set the summary" do action = Puppet::Interface::ActionBuilder.build(face, :foo) do + when_invoked do true end summary "this is some text" end action.summary.should == "this is some text" @@ -119,13 +137,16 @@ describe Puppet::Interface::ActionBuilder do context "action defaulting" do it "should set the default to true" do action = Puppet::Interface::ActionBuilder.build(face, :foo) do + when_invoked do true end default end action.default.should be_true end it "should not be default by, er, default. *cough*" do - action = Puppet::Interface::ActionBuilder.build(face, :foo) do end + action = Puppet::Interface::ActionBuilder.build(face, :foo) do + when_invoked do true end + end action.default.should be_false end end @@ -134,6 +155,7 @@ describe Puppet::Interface::ActionBuilder do it "should fail if no rendering format is given" do expect { Puppet::Interface::ActionBuilder.build(face, :foo) do + when_invoked do true end when_rendering do true end end }.to raise_error ArgumentError, /must give a rendering format to when_rendering/ @@ -142,6 +164,7 @@ describe Puppet::Interface::ActionBuilder do it "should fail if no block is given" do expect { Puppet::Interface::ActionBuilder.build(face, :foo) do + when_invoked do true end when_rendering :json end }.to raise_error ArgumentError, /must give a block to when_rendering/ @@ -150,6 +173,7 @@ describe Puppet::Interface::ActionBuilder do it "should fail if the block takes no arguments" do expect { Puppet::Interface::ActionBuilder.build(face, :foo) do + when_invoked do true end when_rendering :json do true end end }.to raise_error ArgumentError, /when_rendering methods take one argument, the result, not/ @@ -158,6 +182,7 @@ describe Puppet::Interface::ActionBuilder do it "should fail if the block takes more than one argument" do expect { Puppet::Interface::ActionBuilder.build(face, :foo) do + when_invoked do true end when_rendering :json do |a, b, c| true end end }.to raise_error ArgumentError, /when_rendering methods take one argument, the result, not/ @@ -166,6 +191,7 @@ describe Puppet::Interface::ActionBuilder do it "should fail if the block takes a variable number of arguments" do expect { Puppet::Interface::ActionBuilder.build(face, :foo) do + when_invoked do true end when_rendering :json do |*args| true end end }.to raise_error(ArgumentError, @@ -174,6 +200,7 @@ describe Puppet::Interface::ActionBuilder do it "should stash a rendering block" do action = Puppet::Interface::ActionBuilder.build(face, :foo) do + when_invoked do true end when_rendering :json do |a| true end end action.when_rendering(:json).should be_an_instance_of Method @@ -182,6 +209,7 @@ describe Puppet::Interface::ActionBuilder do it "should fail if you try to set the same rendering twice" do expect { Puppet::Interface::ActionBuilder.build(face, :foo) do + when_invoked do true end when_rendering :json do |a| true end when_rendering :json do |a| true end end @@ -190,6 +218,7 @@ describe Puppet::Interface::ActionBuilder do it "should work if you set two different renderings" do action = Puppet::Interface::ActionBuilder.build(face, :foo) do + when_invoked do true end when_rendering :json do |a| true end when_rendering :yaml do |a| true end end @@ -199,6 +228,7 @@ describe Puppet::Interface::ActionBuilder do it "should be bound to the face when called" do action = Puppet::Interface::ActionBuilder.build(face, :foo) do + when_invoked do true end when_rendering :json do |a| self end end action.when_rendering(:json).call(true).should == face @@ -207,13 +237,16 @@ describe Puppet::Interface::ActionBuilder do context "#render_as" do it "should default to nil (eg: based on context)" do - action = Puppet::Interface::ActionBuilder.build(face, :foo) do end + action = Puppet::Interface::ActionBuilder.build(face, :foo) do + when_invoked do true end + end action.render_as.should be_nil end it "should fail if not rendering format is given" do expect { Puppet::Interface::ActionBuilder.build(face, :foo) do + when_invoked do true end render_as end }.to raise_error ArgumentError, /must give a rendering format to render_as/ @@ -222,23 +255,18 @@ describe Puppet::Interface::ActionBuilder do Puppet::Network::FormatHandler.formats.each do |name| it "should accept #{name.inspect} format" do action = Puppet::Interface::ActionBuilder.build(face, :foo) do + when_invoked do true end render_as name end action.render_as.should == name end end - it "should accept :for_humans format" do - action = Puppet::Interface::ActionBuilder.build(face, :foo) do - render_as :for_humans - end - action.render_as.should == :for_humans - end - [:if_you_define_this_format_you_frighten_me, "json", 12].each do |input| it "should fail if given #{input.inspect}" do expect { Puppet::Interface::ActionBuilder.build(face, :foo) do + when_invoked do true end render_as input end }.to raise_error ArgumentError, /#{input.inspect} is not a valid rendering format/ diff --git a/spec/unit/interface/action_manager_spec.rb b/spec/unit/interface/action_manager_spec.rb index 07d517c18..5a479ad5c 100755 --- a/spec/unit/interface/action_manager_spec.rb +++ b/spec/unit/interface/action_manager_spec.rb @@ -94,7 +94,7 @@ describe Puppet::Interface::ActionManager do end it "should be able to indicate when an action is defined" do - subject.action(:foo) { "something" } + subject.action(:foo) { when_invoked do true end } subject.should be_action(:foo) end end @@ -218,25 +218,29 @@ describe Puppet::Interface::ActionManager do describe "#action" do it 'should add an action' do - subject.action(:foo) { } + subject.action(:foo) { when_invoked do true end } subject.get_action(:foo).should be_a Puppet::Interface::Action end it 'should support default actions' do - subject.action(:foo) { default } + subject.action(:foo) { when_invoked do true end; default } subject.get_default_action.should == subject.get_action(:foo) end it 'should not support more than one default action' do - subject.action(:foo) { default } - expect { subject.action(:bar) { default } }.should raise_error + subject.action(:foo) { when_invoked do true end; default } + expect { subject.action(:bar) { + when_invoked do true end + default + } + }.should raise_error /cannot both be default/ end end describe "#get_action" do let :parent_class do parent_class = Class.new(Puppet::Interface) - parent_class.action(:foo) {} + parent_class.action(:foo) { when_invoked do true end } parent_class end diff --git a/spec/unit/interface/action_spec.rb b/spec/unit/interface/action_spec.rb index 735fbcb72..f43968709 100755 --- a/spec/unit/interface/action_spec.rb +++ b/spec/unit/interface/action_spec.rb @@ -74,25 +74,29 @@ describe Puppet::Interface::Action do option '-w' action(:foo) do + when_invoked do true end option '-x', '--ex' option '-y', '--why' end action(:bar) do + when_invoked do true end option '-z', '--zee' end action(:baz) do + when_invoked do true end option '-z', '--zed' end action(:noopts) do # no options declared + when_invoked do true end end end end - subject { action = face.action(:new_action) { } } + subject { action = face.action(:new_action) { when_invoked do true end } } it 'should add the options from the specified action' do subject.inherit_options_from(foo = face.get_action(:foo)) @@ -108,7 +112,7 @@ describe Puppet::Interface::Action do it 'should add the options from multiple actions' do subject.inherit_options_from(foo = face.get_action(:foo)) subject.inherit_options_from(bar = face.get_action(:bar)) - subject.options.should == (foo.options + bar.options).uniq.sort + subject.options.should == (foo.options + bar.options).uniq end it 'should not inherit face options' do @@ -205,6 +209,7 @@ describe Puppet::Interface::Action do it "should support options with an empty block" do face = Puppet::Interface.new(:action_level_options, '0.0.1') do action :foo do + when_invoked do true end option "--bar" do # this line left deliberately blank end @@ -217,7 +222,10 @@ describe Puppet::Interface::Action do it "should return only action level options when there are no face options" do face = Puppet::Interface.new(:action_level_options, '0.0.1') do - action :foo do option "--bar" end + action :foo do + when_invoked do true end + option "--bar" + end end face.get_action(:foo).options.should =~ [:bar] @@ -226,8 +234,8 @@ describe Puppet::Interface::Action do describe "with both face and action options" do let :face do Puppet::Interface.new(:action_level_options, '0.0.1') do - action :foo do option "--bar" end - action :baz do option "--bim" end + action :foo do when_invoked do true end ; option "--bar" end + action :baz do when_invoked do true end ; option "--bim" end option "--quux" end end @@ -241,7 +249,10 @@ describe Puppet::Interface::Action do parent.option "--foo" child = parent.new(:inherited_options, '0.0.1') do option "--bar" - action :action do option "--baz" end + action :action do + when_invoked do true end + option "--baz" + end end action = child.get_action(:action) @@ -270,7 +281,10 @@ describe Puppet::Interface::Action do it_should_behave_like "things that declare options" do def add_options_to(&block) face = Puppet::Interface.new(:with_options, '0.0.1') do - action(:foo, &block) + action(:foo) do + when_invoked do true end + self.instance_eval &block + end end face.get_action(:foo) end @@ -292,7 +306,7 @@ describe Puppet::Interface::Action do when_invoked { } end end - expect { face.bar }.to raise_error ArgumentError, /missing required options \(foo\)/ + expect { face.bar }.to raise_error ArgumentError, /The following options are required: foo/ end it "should fail when a required face option is not provided" do @@ -300,184 +314,251 @@ describe Puppet::Interface::Action do option('--foo') { required } action(:bar) { when_invoked { } } end - expect { face.bar }.to raise_error ArgumentError, /missing required options \(foo\)/ + expect { face.bar }.to raise_error ArgumentError, /The following options are required: foo/ end end - context "with action decorators" do - context "local only" do + context "with decorators" do + context "declared locally" do let :face do Puppet::Interface.new(:action_decorators, '0.0.1') do action :bar do when_invoked do true end end - def report(arg) end + def reported; @reported; end + def report(arg) + (@reported ||= []) << arg + end end end - it "should call action before decorators" do - face.action(:baz) do - option "--baz" do - before_action do |action, args, options| - report(:action_option) - end - end - when_invoked do true end + it "should execute before advice on action options in declaration order" do + face.action(:boo) do + option("--foo") { before_action { |_,_,_| report :foo } } + option("--bar", '-b') { before_action { |_,_,_| report :bar } } + option("-q", "--quux") { before_action { |_,_,_| report :quux } } + option("-f") { before_action { |_,_,_| report :f } } + option("--baz") { before_action { |_,_,_| report :baz } } + when_invoked { } end - face.expects(:report).with(:action_option) - face.baz :baz => true + face.boo :foo => 1, :bar => 1, :quux => 1, :f => 1, :baz => 1 + face.reported.should == [ :foo, :bar, :quux, :f, :baz ] end - it "should call action after decorators" do - face.action(:baz) do - option "--baz" do - after_action do |action, args, options| - report(:action_option) - end - end - when_invoked do true end + it "should execute after advice on action options in declaration order" do + face.action(:boo) do + option("--foo") { after_action { |_,_,_| report :foo } } + option("--bar", '-b') { after_action { |_,_,_| report :bar } } + option("-q", "--quux") { after_action { |_,_,_| report :quux } } + option("-f") { after_action { |_,_,_| report :f } } + option("--baz") { after_action { |_,_,_| report :baz } } + when_invoked { } end - face.expects(:report).with(:action_option) - face.baz :baz => true + face.boo :foo => 1, :bar => 1, :quux => 1, :f => 1, :baz => 1 + face.reported.should == [ :foo, :bar, :quux, :f, :baz ].reverse end - it "should call local before decorators" do - face.option "--foo FOO" do - before_action do |action, args, options| - report(:before) - end + it "should execute before advice on face options in declaration order" do + face.instance_eval do + option("--foo") { before_action { |_,_,_| report :foo } } + option("--bar", '-b') { before_action { |_,_,_| report :bar } } + option("-q", "--quux") { before_action { |_,_,_| report :quux } } + option("-f") { before_action { |_,_,_| report :f } } + option("--baz") { before_action { |_,_,_| report :baz } } end - face.expects(:report).with(:before) - face.bar({:foo => 12}) + face.script(:boo) { } + + face.boo :foo => 1, :bar => 1, :quux => 1, :f => 1, :baz => 1 + face.reported.should == [ :foo, :bar, :quux, :f, :baz ] end - it "should call local after decorators" do - face.option "--foo FOO" do - after_action do |action, args, options| report(:after) end + it "should execute after advice on face options in declaration order" do + face.instance_eval do + option("--foo") { after_action { |_,_,_| report :foo } } + option("--bar", '-b') { after_action { |_,_,_| report :bar } } + option("-q", "--quux") { after_action { |_,_,_| report :quux } } + option("-f") { after_action { |_,_,_| report :f } } + option("--baz") { after_action { |_,_,_| report :baz } } end - face.expects(:report).with(:after) - face.bar({:foo => 12}) + face.script(:boo) { } + + face.boo :foo => 1, :bar => 1, :quux => 1, :f => 1, :baz => 1 + face.reported.should == [ :foo, :bar, :quux, :f, :baz ].reverse end - context "with inactive decorators" do - it "should not invoke a decorator if the options are empty" do - face.option "--foo FOO" do - before_action do |action, args, options| - report :before_action - end + it "should execute before advice on face options before action options" do + face.instance_eval do + option("--face-foo") { before_action { |_,_,_| report :face_foo } } + option("--face-bar", '-r') { before_action { |_,_,_| report :face_bar } } + action(:boo) do + option("--action-foo") { before_action { |_,_,_| report :action_foo } } + option("--action-bar", '-b') { before_action { |_,_,_| report :action_bar } } + option("-q", "--action-quux") { before_action { |_,_,_| report :action_quux } } + option("-a") { before_action { |_,_,_| report :a } } + option("--action-baz") { before_action { |_,_,_| report :action_baz } } + when_invoked { } end - face.expects(:report).never # I am testing the negative. - face.bar + option("-u", "--face-quux") { before_action { |_,_,_| report :face_quux } } + option("-f") { before_action { |_,_,_| report :f } } + option("--face-baz") { before_action { |_,_,_| report :face_baz } } + end + + expected_calls = [ :face_foo, :face_bar, :face_quux, :f, :face_baz, + :action_foo, :action_bar, :action_quux, :a, :action_baz ] + face.boo Hash[ *expected_calls.zip([]).flatten ] + face.reported.should == expected_calls + end + + it "should execute after advice on face options in declaration order" do + face.instance_eval do + option("--face-foo") { after_action { |_,_,_| report :face_foo } } + option("--face-bar", '-r') { after_action { |_,_,_| report :face_bar } } + action(:boo) do + option("--action-foo") { after_action { |_,_,_| report :action_foo } } + option("--action-bar", '-b') { after_action { |_,_,_| report :action_bar } } + option("-q", "--action-quux") { after_action { |_,_,_| report :action_quux } } + option("-a") { after_action { |_,_,_| report :a } } + option("--action-baz") { after_action { |_,_,_| report :action_baz } } + when_invoked { } + end + option("-u", "--face-quux") { after_action { |_,_,_| report :face_quux } } + option("-f") { after_action { |_,_,_| report :f } } + option("--face-baz") { after_action { |_,_,_| report :face_baz } } end - context "with some decorators only" do - before :each do - face.option "--foo" do - before_action do |action, args, options| report :foo end - end - face.option "--bar" do - before_action do |action, args, options| report :bar end - end - end + expected_calls = [ :face_foo, :face_bar, :face_quux, :f, :face_baz, + :action_foo, :action_bar, :action_quux, :a, :action_baz ] + face.boo Hash[ *expected_calls.zip([]).flatten ] + face.reported.should == expected_calls.reverse + end - it "should work with the foo option" do - face.expects(:report).with(:foo) - face.bar(:foo => true) - end + it "should not invoke a decorator if the options are empty" do + face.option("--foo FOO") { before_action { |_,_,_| report :before_action } } + face.expects(:report).never + face.bar + end - it "should work with the bar option" do - face.expects(:report).with(:bar) - face.bar(:bar => true) - end + context "passing a subset of the options" do + before :each do + face.option("--foo") { before_action { |_,_,_| report :foo } } + face.option("--bar") { before_action { |_,_,_| report :bar } } + end - it "should work with both options" do - face.expects(:report).with(:foo) - face.expects(:report).with(:bar) - face.bar(:foo => true, :bar => true) - end + it "should invoke only foo's advice when passed only 'foo'" do + face.bar(:foo => true) + face.reported.should == [ :foo ] + end + + it "should invoke only bar's advice when passed only 'bar'" do + face.bar(:bar => true) + face.reported.should == [ :bar ] + end + + it "should invoke advice for all passed options" do + face.bar(:foo => true, :bar => true) + face.reported.should == [ :foo, :bar ] end end end - context "with inherited decorators" do + context "and inheritance" do let :parent do - parent = Class.new(Puppet::Interface) - parent.script :on_parent do :on_parent end - parent.define_method :report do |arg| arg end - parent + Class.new(Puppet::Interface) do + script(:on_parent) { :on_parent } + + def reported; @reported; end + def report(arg) + (@reported ||= []) << arg + end + end end let :child do - child = parent.new(:inherited_decorators, '0.0.1') do - script :on_child do :on_child end + parent.new(:inherited_decorators, '0.0.1') do + script(:on_child) { :on_child } end end - context "with a child decorator" do + context "locally declared face options" do subject do - child.option "--foo FOO" do - before_action do |action, args, options| - report(:child_before) - end - end - child.expects(:report).with(:child_before) + child.option("--foo=") { before_action { |_,_,_| report :child_before } } child end - it "child actions should invoke the decorator" do - subject.on_child({:foo => true, :bar => true}).should == :on_child + it "should be invoked when calling a child action" do + subject.on_child(:foo => true, :bar => true).should == :on_child + subject.reported.should == [ :child_before ] end - it "parent actions should invoke the decorator" do - subject.on_parent({:foo => true, :bar => true}).should == :on_parent + it "should be invoked when calling a parent action" do + subject.on_parent(:foo => true, :bar => true).should == :on_parent + subject.reported.should == [ :child_before ] end end - context "with a parent decorator" do + context "inherited face option decorators" do subject do - parent.option "--foo FOO" do - before_action do |action, args, options| - report(:parent_before) - end - end - child.expects(:report).with(:parent_before) + parent.option("--foo=") { before_action { |_,_,_| report :parent_before } } child end - it "child actions should invoke the decorator" do - subject.on_child({:foo => true, :bar => true}).should == :on_child + it "should be invoked when calling a child action" do + subject.on_child(:foo => true, :bar => true).should == :on_child + subject.reported.should == [ :parent_before ] end - it "parent actions should invoke the decorator" do - subject.on_parent({:foo => true, :bar => true}).should == :on_parent + it "should be invoked when calling a parent action" do + subject.on_parent(:foo => true, :bar => true).should == :on_parent + subject.reported.should == [ :parent_before ] end end - context "with child and parent decorators" do + context "with both inherited and local face options" do + # Decorations should be invoked in declaration order, according to + # inheritance (e.g. parent class options should be handled before + # subclass options). subject do - parent.option "--foo FOO" do - before_action { |action, args, options| report(:parent_before) } - after_action { |action, args, options| report(:parent_after) } + child.option "-c" do + before_action { |action, args, options| report :c_before } + after_action { |action, args, options| report :c_after } end - child.option "--bar BAR" do - before_action { |action, args, options| report(:child_before) } - after_action { |action, args, options| report(:child_after) } + + parent.option "-a" do + before_action { |action, args, options| report :a_before } + after_action { |action, args, options| report :a_after } end - child.expects(:report).with(:child_before) - child.expects(:report).with(:parent_before) - child.expects(:report).with(:parent_after) - child.expects(:report).with(:child_after) + child.option "-d" do + before_action { |action, args, options| report :d_before } + after_action { |action, args, options| report :d_after } + end + + parent.option "-b" do + before_action { |action, args, options| report :b_before } + after_action { |action, args, options| report :b_after } + end + + child.script(:decorations) { report :invoked } child end - it "child actions should invoke all the decorator" do - subject.on_child({:foo => true, :bar => true}).should == :on_child + it "should invoke all decorations when calling a child action" do + subject.decorations(:a => 1, :b => 1, :c => 1, :d => 1) + subject.reported.should == [ + :a_before, :b_before, :c_before, :d_before, + :invoked, + :d_after, :c_after, :b_after, :a_after + ] end - it "parent actions should invoke all the decorator" do - subject.on_parent({:foo => true, :bar => true}).should == :on_parent + it "should invoke all decorations when calling a parent action" do + subject.decorations(:a => 1, :b => 1, :c => 1, :d => 1) + subject.reported.should == [ + :a_before, :b_before, :c_before, :d_before, + :invoked, + :d_after, :c_after, :b_after, :a_after + ] end end end @@ -486,7 +567,9 @@ describe Puppet::Interface::Action do it_should_behave_like "documentation on faces" do subject do face = Puppet::Interface.new(:action_documentation, '0.0.1') do - action :documentation do end + action :documentation do + when_invoked do true end + end end face.get_action(:documentation) end @@ -500,4 +583,23 @@ describe Puppet::Interface::Action do it "should fail if a second block is given for the same type" it "should return the block if asked" end + + context "#validate_args" do + subject do + Puppet::Interface.new(:validate_args, '1.0.0') do + script :test do true end + end + end + + it "should fail if a required option is not passed" do + subject.option "--foo" do required end + expect { subject.test }.to raise_error ArgumentError, /options are required/ + end + + it "should fail if two aliases to one option are passed" do + subject.option "--foo", "-f" + expect { subject.test :foo => true, :f => true }. + to raise_error ArgumentError, /Multiple aliases for the same option/ + end + end end diff --git a/spec/unit/interface/face_collection_spec.rb b/spec/unit/interface/face_collection_spec.rb index 890e06a9e..4ad8787c5 100755 --- a/spec/unit/interface/face_collection_spec.rb +++ b/spec/unit/interface/face_collection_spec.rb @@ -16,12 +16,13 @@ describe Puppet::Interface::FaceCollection do @original_faces = subject.instance_variable_get("@faces").dup @original_required = $".dup $".delete_if do |path| path =~ %r{/face/.*\.rb$} end - subject.instance_variable_get("@faces").clear + subject.instance_variable_get(:@faces).clear + subject.instance_variable_set(:@loaded, false) end after :each do - subject.instance_variable_set("@faces", @original_faces) - $".clear ; @original_required.each do |item| $" << item end + subject.instance_variable_set(:@faces, @original_faces) + @original_required.each {|f| $".push f unless $".include? f } end describe "::prefix_match?" do @@ -159,4 +160,21 @@ describe Puppet::Interface::FaceCollection do end end end + + context "faulty faces" do + before :each do + $:.unshift "#{PuppetSpec::FIXTURE_DIR}/faulty_face" + end + + after :each do + $:.delete_if {|x| x == "#{PuppetSpec::FIXTURE_DIR}/faulty_face"} + end + + it "should not die if a face has a syntax error" do + subject.faces.should be_include :help + subject.faces.should_not be_include :syntax + @logs.should_not be_empty + @logs.first.message.should =~ /syntax error/ + end + end end diff --git a/spec/unit/interface/option_builder_spec.rb b/spec/unit/interface/option_builder_spec.rb index e9346852c..3e91c683b 100755 --- a/spec/unit/interface/option_builder_spec.rb +++ b/spec/unit/interface/option_builder_spec.rb @@ -16,13 +16,15 @@ describe Puppet::Interface::OptionBuilder do option.should be_an_instance_of Puppet::Interface::Option end - it "should support documentation declarations" do - text = "this is the description" - option = Puppet::Interface::OptionBuilder.build(face, "--foo") do - desc text + [:description, :summary].each do |doc| + it "should support #{doc} declarations" do + text = "this is the #{doc}" + option = Puppet::Interface::OptionBuilder.build(face, "--foo") do + self.send doc, text + end + option.should be_an_instance_of Puppet::Interface::Option + option.send(doc).should == text end - option.should be_an_instance_of Puppet::Interface::Option - option.desc.should == text end context "before_action hook" do diff --git a/spec/unit/interface_spec.rb b/spec/unit/interface_spec.rb index a1d70cf64..e28e55aac 100755 --- a/spec/unit/interface_spec.rb +++ b/spec/unit/interface_spec.rb @@ -76,7 +76,11 @@ describe Puppet::Interface do # Required documentation methods... { :summary => "summary", - :description => "This is the description of the stuff\n\nWhee" + :description => "This is the description of the stuff\n\nWhee", + :examples => "This is my example", + :short_description => "This is my custom short description", + :notes => "These are my notes...", + :author => "This is my authorship data", }.each do |attr, value| it "should support #{attr} in the builder" do face = subject.new(:builder, '1.0.0') do @@ -142,6 +146,7 @@ describe Puppet::Interface do option "--foo" option "--bar" action :baz do + when_invoked { true } option "--quux" end end @@ -151,7 +156,10 @@ describe Puppet::Interface do it "should fail when a face option duplicates an action option" do expect { subject.new(:action_level_options, '0.0.1') do - action :bar do option "--foo" end + action :bar do + when_invoked { true } + option "--foo" + end option "--foo" end }.should raise_error ArgumentError, /Option foo conflicts with existing option foo on/i @@ -159,8 +167,8 @@ describe Puppet::Interface do it "should work when two actions have the same option" do face = subject.new(:with_options, '0.0.1') do - action :foo do option "--quux" end - action :bar do option "--quux" end + action :foo do when_invoked { true } ; option "--quux" end + action :bar do when_invoked { true } ; option "--quux" end end face.get_action(:foo).options.should =~ [:quux] @@ -172,14 +180,14 @@ describe Puppet::Interface do let :parent do parent = Class.new(subject) parent.option("--inherited") - parent.action(:parent_action) do end + parent.action(:parent_action) do when_invoked { true } end parent end let :face do face = parent.new(:example, '0.2.1') face.option("--local") - face.action(:face_action) do end + face.action(:face_action) do when_invoked { true } end face end diff --git a/spec/unit/network/formats_spec.rb b/spec/unit/network/formats_spec.rb index 72d355192..62c2dbb9d 100755 --- a/spec/unit/network/formats_spec.rb +++ b/spec/unit/network/formats_spec.rb @@ -330,4 +330,66 @@ describe "Puppet Network Format" do end end end + + describe ":console format" do + subject { Puppet::Network::FormatHandler.format(:console) } + it { should be_an_instance_of Puppet::Network::Format } + let :json do Puppet::Network::FormatHandler.format(:pson) end + + [:intern, :intern_multiple].each do |method| + it "should not implement #{method}" do + expect { subject.send(method, String, 'blah') }.to raise_error NotImplementedError + end + end + + ["hello", 1, 1.0].each do |input| + it "should just return a #{input.inspect}" do + subject.render(input).should == input + end + end + + [[1, 2], ["one"], [{ 1 => 1 }]].each do |input| + it "should render #{input.inspect} as JSON" do + subject.render(input).should == json.render(input).chomp + end + end + + it "should render a non-trivially-keyed Hash as JSON" do + hash = { [1,2] => 3, [2,3] => 5, [3,4] => 7 } + subject.render(hash).should == json.render(hash).chomp + end + + it "should render a {String,Numeric}-keyed Hash into a table" do + object = Object.new + hash = { "one" => 1, "two" => [], "three" => {}, "four" => object, + 5 => 5, 6.0 => 6 } + + # Gotta love ASCII-betical sort order. Hope your objects are better + # structured for display than my test one is. --daniel 2011-04-18 + subject.render(hash).should == <<EOT +5 5 +6.0 6 +four #{json.render(object).chomp} +one 1 +three {} +two [] +EOT + end + + it "should render a hash nicely with a multi-line value" do + pending "Moving to PSON rather than PP makes this unsupportable." + hash = { + "number" => { "1" => '1' * 40, "2" => '2' * 40, '3' => '3' * 40 }, + "text" => { "a" => 'a' * 40, 'b' => 'b' * 40, 'c' => 'c' * 40 } + } + subject.render(hash).should == <<EOT +number {"1"=>"1111111111111111111111111111111111111111", + "2"=>"2222222222222222222222222222222222222222", + "3"=>"3333333333333333333333333333333333333333"} +text {"a"=>"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "b"=>"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "c"=>"cccccccccccccccccccccccccccccccccccccccc"} +EOT + end + end end diff --git a/spec/unit/network/http/api/v1_spec.rb b/spec/unit/network/http/api/v1_spec.rb index bd95071c1..a952f24e2 100755 --- a/spec/unit/network/http/api/v1_spec.rb +++ b/spec/unit/network/http/api/v1_spec.rb @@ -31,7 +31,7 @@ describe Puppet::Network::HTTP::API::V1 do end it "should use the first field of the URI as the environment" do - @tester.uri2indirection("GET", "/env/foo/bar", {})[3][:environment].should == "env" + @tester.uri2indirection("GET", "/env/foo/bar", {})[3][:environment].to_s.should == "env" end it "should fail if the environment is not alphanumeric" do @@ -39,7 +39,11 @@ describe Puppet::Network::HTTP::API::V1 do end it "should use the environment from the URI even if one is specified in the parameters" do - @tester.uri2indirection("GET", "/env/foo/bar", {:environment => "otherenv"})[3][:environment].should == "env" + @tester.uri2indirection("GET", "/env/foo/bar", {:environment => "otherenv"})[3][:environment].to_s.should == "env" + end + + it "should return the environment as a Puppet::Node::Environment" do + @tester.uri2indirection("GET", "/env/foo/bar", {})[3][:environment].should be_a Puppet::Node::Environment end it "should use the second field of the URI as the indirection name" do diff --git a/spec/unit/network/rest_authconfig_spec.rb b/spec/unit/network/rest_authconfig_spec.rb index 499a14b78..e1403997f 100755 --- a/spec/unit/network/rest_authconfig_spec.rb +++ b/spec/unit/network/rest_authconfig_spec.rb @@ -5,18 +5,7 @@ require 'puppet/network/rest_authconfig' describe Puppet::Network::RestAuthConfig do - DEFAULT_ACL = [ - { :acl => "~ ^\/catalog\/([^\/]+)$", :method => :find, :allow => '$1', :authenticated => true }, - # this one will allow all file access, and thus delegate - # to fileserver.conf - { :acl => "/file" }, - { :acl => "/certificate_revocation_list/ca", :method => :find, :authenticated => true }, - { :acl => "/report", :method => :save, :authenticated => true }, - { :acl => "/certificate/ca", :method => :find, :authenticated => false }, - { :acl => "/certificate/", :method => :find, :authenticated => false }, - { :acl => "/certificate_request", :method => [:find, :save], :authenticated => false }, - { :acl => "/status", :method => [:find], :authenticated => true }, - ] + DEFAULT_ACL = Puppet::Network::RestAuthConfig::DEFAULT_ACL before :each do FileTest.stubs(:exists?).returns(true) diff --git a/spec/unit/node/facts_spec.rb b/spec/unit/node/facts_spec.rb index 07f5f7e1b..efaa76e12 100755 --- a/spec/unit/node/facts_spec.rb +++ b/spec/unit/node/facts_spec.rb @@ -110,11 +110,7 @@ describe Puppet::Node::Facts, "when indirecting" do end it "should accept properly formatted pson" do - facts = Puppet::Node::Facts.new("foo") - facts.values = {"a" => "1", "b" => "2", "c" => "3"} - facts.expiration = Time.now - #pson = %Q({"document_type": "Puppet::Node::Facts", "data: {"name": "foo", "expiration": "#{@expiration}", "timestamp": "#{@timestamp}", "values": {"a": "1", "b": "2", "c": "3"}}}) - pson = %Q({"data": {"name":"foo", "expiration":"#{@expiration}", "timestamp": "#{@timestamp}", "values":{"a":"1","b":"2","c":"3"}}, "document_type":"Puppet::Node::Facts"}) + pson = %Q({"name": "foo", "expiration": "#{@expiration}", "timestamp": "#{@timestamp}", "values": {"a": "1", "b": "2", "c": "3"}}) format = Puppet::Network::FormatHandler.format('pson') facts = format.intern(Puppet::Node::Facts,pson) facts.name.should == 'foo' @@ -127,29 +123,10 @@ describe Puppet::Node::Facts, "when indirecting" do facts = Puppet::Node::Facts.new("foo", {'a' => 1, 'b' => 2, 'c' => 3}) facts.expiration = @expiration result = PSON.parse(facts.to_pson) - result.name.should == facts.name - result.values.should == facts.values - result.timestamp.should == facts.timestamp - result.expiration.should == facts.expiration - result.type.should == Puppet::Node::Facts - end - - it "should not include nil values" do - facts = Puppet::Node::Facts.new("foo", {'a' => 1, 'b' => 2, 'c' => 3}) - - # XXX:LAK For some reason this is resurrection the full instance, instead - # of just returning the hash. This code works, but I can't figure out what's - # going on. - newfacts = PSON.parse(facts.to_pson) - newfacts.expiration.should be_nil - end - - it "should be able to handle nil values" do - pson = %Q({"name": "foo", "values": {"a": "1", "b": "2", "c": "3"}}) - format = Puppet::Network::FormatHandler.format('pson') - facts = format.intern(Puppet::Node::Facts,pson) - facts.name.should == 'foo' - facts.expiration.should be_nil + result['name'].should == facts.name + result['values'].should == facts.values.reject { |key, value| key.to_s =~ /_/ } + result['timestamp'].should == facts.timestamp.to_s + result['expiration'].should == facts.expiration.to_s end end end diff --git a/spec/unit/node_spec.rb b/spec/unit/node_spec.rb index e8f826dca..169a9cdcf 100755 --- a/spec/unit/node_spec.rb +++ b/spec/unit/node_spec.rb @@ -36,69 +36,6 @@ describe Puppet::Node do node.environment.name.should == :bar end end - - describe "when converting to json" do - before do - @node = Puppet::Node.new("mynode") - end - - it "should provide its name" do - @node.should set_json_attribute('name').to("mynode") - end - - it "should include the classes if set" do - @node.classes = %w{a b c} - @node.should set_json_attribute("classes").to(%w{a b c}) - end - - it "should not include the classes if there are none" do - @node.should_not set_json_attribute('classes') - end - - it "should include parameters if set" do - @node.parameters = {"a" => "b", "c" => "d"} - @node.should set_json_attribute('parameters').to({"a" => "b", "c" => "d"}) - end - - it "should not include the parameters if there are none" do - @node.should_not set_json_attribute('parameters') - end - - it "should include the environment" do - @node.environment = "production" - @node.should set_json_attribute('environment').to('production') - end - end - - describe "when converting from json" do - before do - @node = Puppet::Node.new("mynode") - @format = Puppet::Network::FormatHandler.format('pson') - end - - def from_json(json) - @format.intern(Puppet::Node, json) - end - - it "should set its name" do - Puppet::Node.should read_json_attribute('name').from(@node.to_pson).as("mynode") - end - - it "should include the classes if set" do - @node.classes = %w{a b c} - Puppet::Node.should read_json_attribute('classes').from(@node.to_pson).as(%w{a b c}) - end - - it "should include parameters if set" do - @node.parameters = {"a" => "b", "c" => "d"} - Puppet::Node.should read_json_attribute('parameters').from(@node.to_pson).as({"a" => "b", "c" => "d"}) - end - - it "should include the environment" do - @node.environment = "production" - Puppet::Node.should read_json_attribute('environment').from(@node.to_pson).as(Puppet::Node::Environment.new(:production)) - end - end end describe Puppet::Node, "when initializing" do diff --git a/spec/unit/parser/compiler_spec.rb b/spec/unit/parser/compiler_spec.rb index 48aeb98dd..88f7167f3 100755 --- a/spec/unit/parser/compiler_spec.rb +++ b/spec/unit/parser/compiler_spec.rb @@ -48,6 +48,13 @@ describe Puppet::Parser::Compiler do end before :each do + # Push me faster, I wanna go back in time! (Specifically, freeze time + # across the test since we have a bunch of version == timestamp code + # hidden away in the implementation and we keep losing the race.) + # --daniel 2011-04-21 + now = Time.now + Time.stubs(:now).returns(now) + @node = Puppet::Node.new "testnode" @known_resource_types = Puppet::Resource::TypeCollection.new "development" @compiler = Puppet::Parser::Compiler.new(@node) diff --git a/spec/unit/simple_graph_spec.rb b/spec/unit/simple_graph_spec.rb index c8fea3b58..472ebbd36 100755 --- a/spec/unit/simple_graph_spec.rb +++ b/spec/unit/simple_graph_spec.rb @@ -525,6 +525,10 @@ describe Puppet::SimpleGraph do def to_s @name end + + def ref + "Container[#{self}]" + end end require "puppet/resource/catalog" @@ -536,7 +540,7 @@ describe Puppet::SimpleGraph do @middle = Container.new("middle", ["e", "f", @two]) @top = Container.new("top", ["g", "h", @middle, @one, @three]) @empty = Container.new("empty", []) - + @whit = Puppet::Type.type(:whit) @stage = Puppet::Type.type(:stage).new(:name => "foo") @@ -574,7 +578,7 @@ describe Puppet::SimpleGraph do end def whit_called(name) - x = @depgraph.vertices.find { |v| v.is_a?(@whit) && v.name =~ /#{name}/ } + x = @depgraph.vertices.find { |v| v.is_a?(@whit) && v.name =~ /#{Regexp.escape(name)}/ } x.should_not be_nil def x.to_s "Whit[#{name}]" @@ -586,11 +590,11 @@ describe Puppet::SimpleGraph do end def admissible_sentinal_of(x) - @depgraph.vertex?(x) ? x : whit_called("admissible_#{x.name}") + @depgraph.vertex?(x) ? x : whit_called("admissible_#{x.ref}") end def completed_sentinal_of(x) - @depgraph.vertex?(x) ? x : whit_called("completed_#{x.name}") + @depgraph.vertex?(x) ? x : whit_called("completed_#{x.ref}") end before do @@ -618,7 +622,7 @@ describe Puppet::SimpleGraph do # 0) completed_X depends on admissible_X # it "every container's completed sentinal should depend on its admissible sentinal" do - containers.each { |container| + containers.each { |container| @depgraph.path_between(admissible_sentinal_of(container),completed_sentinal_of(container)).should be } end @@ -626,7 +630,7 @@ describe Puppet::SimpleGraph do # 1) contents of X each depend on admissible_X # it "all contained objects should depend on their container's admissible sentinal" do - containers.each { |container| + containers.each { |container| contents_of(container).each { |leaf| @depgraph.should be_edge(admissible_sentinal_of(container),admissible_sentinal_of(leaf)) } @@ -636,7 +640,7 @@ describe Puppet::SimpleGraph do # 2) completed_X depends on each on the contents of X # it "completed sentinals should depend on their container's contents" do - containers.each { |container| + containers.each { |container| contents_of(container).each { |leaf| @depgraph.should be_edge(completed_sentinal_of(leaf),completed_sentinal_of(container)) } diff --git a/spec/unit/ssl/host_spec.rb b/spec/unit/ssl/host_spec.rb index 2624c2234..d14da538e 100755 --- a/spec/unit/ssl/host_spec.rb +++ b/spec/unit/ssl/host_spec.rb @@ -681,16 +681,14 @@ describe Puppet::SSL::Host do @host.expects(:certificate).returns(nil) @host.expects(:generate).raises(RuntimeError) @host.expects(:puts) - @host.expects(:exit).with(1).raises(SystemExit) - lambda { @host.wait_for_cert(0) }.should raise_error(SystemExit) + expect { @host.wait_for_cert(0) }.to exit_with 1 end it "should exit if the wait time is 0 and it can neither find nor retrieve a certificate" do @host.stubs(:certificate).returns nil @host.expects(:generate) @host.expects(:puts) - @host.expects(:exit).with(1).raises(SystemExit) - lambda { @host.wait_for_cert(0) }.should raise_error(SystemExit) + expect { @host.wait_for_cert(0) }.to exit_with 1 end it "should sleep for the specified amount of time if no certificate is found after generating its certificate request" do diff --git a/spec/unit/status_spec.rb b/spec/unit/status_spec.rb index 820807638..0c572fd95 100755 --- a/spec/unit/status_spec.rb +++ b/spec/unit/status_spec.rb @@ -15,6 +15,10 @@ describe Puppet::Status do Puppet::Status.new.status.to_pson.should == '{"is_alive":true}' end + it "should render to a pson hash" do + PSON::pretty_generate(Puppet::Status.new).should =~ /"is_alive":\s*true/ + end + it "should accept a hash from pson" do status = Puppet::Status.new( { "is_alive" => false } ) status.status.should == { "is_alive" => false } diff --git a/spec/unit/type/whit_spec.rb b/spec/unit/type/whit_spec.rb index 4d0949900..9a076d1f1 100755 --- a/spec/unit/type/whit_spec.rb +++ b/spec/unit/type/whit_spec.rb @@ -5,6 +5,6 @@ whit = Puppet::Type.type(:whit).new(:name => "Foo::Bar") describe whit do it "should stringify in a way that users will regognise" do - whit.to_s.should == "(Foo::Bar)" + whit.to_s.should == "Foo::Bar" end end diff --git a/spec/unit/util/command_line_spec.rb b/spec/unit/util/command_line_spec.rb index 81612ee5c..d60bbb198 100755 --- a/spec/unit/util/command_line_spec.rb +++ b/spec/unit/util/command_line_spec.rb @@ -1,7 +1,7 @@ #!/usr/bin/env rspec require 'spec_helper' - +require 'puppet/face' require 'puppet/util/command_line' describe Puppet::Util::CommandLine do @@ -98,11 +98,9 @@ describe Puppet::Util::CommandLine do Puppet::Util.expects(:which).with('puppet-whatever').returns(nil) commandline.expects(:system).never - text = Puppet::Face[:help, :current].help - commandline.expects(:puts).with { |x| x =~ /Unknown Puppet subcommand/ } - commandline.expects(:puts).with text - - commandline.execute + expect { + commandline.execute + }.to have_printed(/Unknown Puppet subcommand 'whatever'/) end end end |
