summaryrefslogtreecommitdiffstats
path: root/spec
diff options
context:
space:
mode:
authorJosh Cooper <josh@puppetlabs.com>2011-04-21 14:37:50 -0700
committerJosh Cooper <josh@puppetlabs.com>2011-04-21 14:37:50 -0700
commit01f610bb223b435dc52f491260af3ea002930102 (patch)
tree93565136d5ef2b4156fdd64476792e441bcfbb4e /spec
parentac428b9557e2da251e4b51e48de844833ca0aa2a (diff)
parentfc66e98b84b9a16728af054485883334a5887cca (diff)
Merge branch 'next'
Diffstat (limited to 'spec')
-rwxr-xr-xspec/integration/indirector/catalog/queue_spec.rb4
-rwxr-xr-xspec/integration/transaction_spec.rb56
-rw-r--r--spec/lib/matchers/json.rb111
-rwxr-xr-xspec/lib/puppet/face/basetest.rb1
-rw-r--r--spec/shared_behaviours/documentation_on_faces.rb35
-rwxr-xr-xspec/shared_behaviours/things_that_declare_options.rb54
-rw-r--r--spec/unit/application/device_spec.rb349
-rwxr-xr-xspec/unit/application/face_base_spec.rb105
-rwxr-xr-xspec/unit/application/indirection_base_spec.rb7
-rwxr-xr-xspec/unit/face/certificate_spec.rb9
-rwxr-xr-xspec/unit/face/facts_spec.rb6
-rwxr-xr-xspec/unit/face/help_spec.rb24
-rwxr-xr-xspec/unit/face/node_spec.rb4
-rw-r--r--spec/unit/indirector/facts/network_device_spec.rb89
-rwxr-xr-xspec/unit/indirector/queue_spec.rb8
-rwxr-xr-xspec/unit/indirector/request_spec.rb96
-rwxr-xr-xspec/unit/indirector/rest_spec.rb5
-rwxr-xr-xspec/unit/interface/action_builder_spec.rb194
-rwxr-xr-xspec/unit/interface/action_manager_spec.rb20
-rwxr-xr-xspec/unit/interface/action_spec.rb226
-rwxr-xr-xspec/unit/interface/face_collection_spec.rb4
-rwxr-xr-xspec/unit/interface/option_builder_spec.rb66
-rwxr-xr-xspec/unit/interface/option_spec.rb25
-rwxr-xr-xspec/unit/interface_spec.rb42
-rwxr-xr-xspec/unit/network/http/handler_spec.rb18
-rwxr-xr-xspec/unit/node/facts_spec.rb34
-rwxr-xr-xspec/unit/node_spec.rb64
-rwxr-xr-xspec/unit/parser/compiler_spec.rb54
-rwxr-xr-xspec/unit/parser/resource_spec.rb64
-rwxr-xr-xspec/unit/parser/scope_spec.rb6
-rw-r--r--spec/unit/provider/cisco_spec.rb16
-rwxr-xr-xspec/unit/provider/interface/cisco_spec.rb20
-rwxr-xr-xspec/unit/provider/network_device_spec.rb21
-rwxr-xr-xspec/unit/provider/package/pkgutil_spec.rb182
-rwxr-xr-xspec/unit/provider/vlan/cisco_spec.rb20
-rwxr-xr-xspec/unit/resource/catalog_spec.rb1
-rwxr-xr-xspec/unit/transaction_spec.rb18
-rwxr-xr-xspec/unit/type/interface_spec.rb5
-rwxr-xr-xspec/unit/type/schedule_spec.rb8
-rwxr-xr-xspec/unit/type/vlan_spec.rb5
-rwxr-xr-xspec/unit/util/network_device/cisco/device_spec.rb137
-rw-r--r--spec/unit/util/network_device/cisco/facts_spec.rb63
-rw-r--r--spec/unit/util/network_device/config_spec.rb102
-rwxr-xr-xspec/unit/util/network_device/transport/ssh_spec.rb8
-rw-r--r--spec/unit/util/network_device_spec.rb50
-rwxr-xr-xspec/unit/util/queue/stomp_spec.rb20
-rwxr-xr-xspec/watchr.rb6
47 files changed, 2085 insertions, 377 deletions
diff --git a/spec/integration/indirector/catalog/queue_spec.rb b/spec/integration/indirector/catalog/queue_spec.rb
index 569f096bf..940c8bab8 100755
--- a/spec/integration/indirector/catalog/queue_spec.rb
+++ b/spec/integration/indirector/catalog/queue_spec.rb
@@ -19,13 +19,13 @@ describe "Puppet::Resource::Catalog::Queue", :if => Puppet.features.pson? do
after { Puppet.settings.clear }
- it "should render catalogs to pson and send them via the queue client when catalogs are saved" do
+ it "should render catalogs to pson and publish them via the queue client when catalogs are saved" do
terminus = Puppet::Resource::Catalog.indirection.terminus(:queue)
client = mock 'client'
terminus.stubs(:client).returns client
- client.expects(:send_message).with(:catalog, @catalog.to_pson)
+ client.expects(:publish_message).with(:catalog, @catalog.to_pson)
request = Puppet::Indirector::Request.new(:catalog, :save, "foo", :instance => @catalog)
diff --git a/spec/integration/transaction_spec.rb b/spec/integration/transaction_spec.rb
index 41a1ebac3..78d62fc51 100755
--- a/spec/integration/transaction_spec.rb
+++ b/spec/integration/transaction_spec.rb
@@ -75,6 +75,62 @@ describe Puppet::Transaction do
transaction.evaluate
end
+ it "should not apply device resources on normal host" do
+ catalog = Puppet::Resource::Catalog.new
+ resource = Puppet::Type.type(:interface).new :name => "FastEthernet 0/1"
+ catalog.add_resource resource
+
+ transaction = Puppet::Transaction.new(catalog)
+ transaction.for_network_device = false
+
+ transaction.expects(:apply).never.with(resource, nil)
+
+ transaction.evaluate
+ transaction.resource_status(resource).should be_skipped
+ end
+
+ it "should not apply host resources on device" do
+ catalog = Puppet::Resource::Catalog.new
+ resource = Puppet::Type.type(:file).new :path => "/foo/bar", :backup => false
+ catalog.add_resource resource
+
+ transaction = Puppet::Transaction.new(catalog)
+ transaction.for_network_device = true
+
+ transaction.expects(:apply).never.with(resource, nil)
+
+ transaction.evaluate
+ transaction.resource_status(resource).should be_skipped
+ end
+
+ it "should apply device resources on device" do
+ catalog = Puppet::Resource::Catalog.new
+ resource = Puppet::Type.type(:interface).new :name => "FastEthernet 0/1"
+ catalog.add_resource resource
+
+ transaction = Puppet::Transaction.new(catalog)
+ transaction.for_network_device = true
+
+ transaction.expects(:apply).with(resource, nil)
+
+ transaction.evaluate
+ transaction.resource_status(resource).should_not be_skipped
+ end
+
+ it "should apply resources appliable on host and device on a device" do
+ catalog = Puppet::Resource::Catalog.new
+ resource = Puppet::Type.type(:schedule).new :name => "test"
+ catalog.add_resource resource
+
+ transaction = Puppet::Transaction.new(catalog)
+ transaction.for_network_device = true
+
+ transaction.expects(:apply).with(resource, nil)
+
+ transaction.evaluate
+ transaction.resource_status(resource).should_not be_skipped
+ end
+
# Verify that one component requiring another causes the contained
# resources in the requiring component to get refreshed.
it "should propagate events from a contained resource through its container to its dependent container's contained resources" do
diff --git a/spec/lib/matchers/json.rb b/spec/lib/matchers/json.rb
new file mode 100644
index 000000000..798e4cd21
--- /dev/null
+++ b/spec/lib/matchers/json.rb
@@ -0,0 +1,111 @@
+RSpec::Matchers.define :set_json_attribute do |*attributes|
+ def format
+ @format ||= Puppet::Network::FormatHandler.format('pson')
+ end
+
+ chain :to do |value|
+ @value = value
+ end
+
+ def json(instance)
+ PSON.parse(instance.to_pson)
+ end
+
+ def attr_value(attrs, instance)
+ attrs = attrs.dup
+ hash = json(instance)['data']
+ while attrs.length > 0
+ name = attrs.shift
+ hash = hash[name]
+ end
+ hash
+ end
+
+ match do |instance|
+ result = attr_value(attributes, instance)
+ if @value
+ result == @value
+ else
+ ! result.nil?
+ end
+ end
+
+ failure_message_for_should do |instance|
+ if @value
+ "expected #{instance.inspect} to set #{attributes.inspect} to #{@value.inspect}; got #{attr_value(attributes, instance).inspect}"
+ else
+ "expected #{instance.inspect} to set #{attributes.inspect} but was nil"
+ end
+ end
+
+ failure_message_for_should_not do |instance|
+ if @value
+ "expected #{instance.inspect} not to set #{attributes.inspect} to #{@value.inspect}"
+ else
+ "expected #{instance.inspect} not to set #{attributes.inspect} to nil"
+ end
+ end
+end
+
+RSpec::Matchers.define :set_json_document_type_to do |type|
+ def format
+ @format ||= Puppet::Network::FormatHandler.format('pson')
+ end
+
+ match do |instance|
+ json(instance)['document_type'] == type
+ end
+
+ def json(instance)
+ PSON.parse(instance.to_pson)
+ end
+
+ failure_message_for_should do |instance|
+ "expected #{instance.inspect} to set document_type to #{type.inspect}; got #{json(instance)['document_type'].inspect}"
+ end
+
+ failure_message_for_should_not do |instance|
+ "expected #{instance.inspect} not to set document_type to #{type.inspect}"
+ end
+end
+
+RSpec::Matchers.define :read_json_attribute do |attribute|
+ def format
+ @format ||= Puppet::Network::FormatHandler.format('pson')
+ end
+
+ chain :from do |value|
+ @json = value
+ end
+
+ chain :as do |as|
+ @value = as
+ end
+
+ match do |klass|
+ raise "Must specify json with 'from'" unless @json
+
+ @instance = format.intern(klass, @json)
+ if @value
+ @instance.send(attribute) == @value
+ else
+ ! @instance.send(attribute).nil?
+ end
+ end
+
+ failure_message_for_should do |klass|
+ if @value
+ "expected #{klass} to read #{attribute} from #{@json} as #{@value.inspect}; got #{@instance.send(attribute).inspect}"
+ else
+ "expected #{klass} to read #{attribute} from #{@json} but was nil"
+ end
+ end
+
+ failure_message_for_should_not do |klass|
+ if @value
+ "expected #{klass} not to set #{attribute} to #{@value}"
+ else
+ "expected #{klass} not to set #{attribute} to nil"
+ end
+ end
+end
diff --git a/spec/lib/puppet/face/basetest.rb b/spec/lib/puppet/face/basetest.rb
index 00616f74f..e935161ae 100755
--- a/spec/lib/puppet/face/basetest.rb
+++ b/spec/lib/puppet/face/basetest.rb
@@ -1 +1,2 @@
+require 'puppet/face'
Puppet::Face.define(:basetest, '0.0.1')
diff --git a/spec/shared_behaviours/documentation_on_faces.rb b/spec/shared_behaviours/documentation_on_faces.rb
new file mode 100644
index 000000000..41b4015c9
--- /dev/null
+++ b/spec/shared_behaviours/documentation_on_faces.rb
@@ -0,0 +1,35 @@
+# 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
+ 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
+ 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/
+ end
+ end
+
+ describe "#description" do
+ it "should accept a description" do
+ subject.description = "hello"
+ subject.description.should == "hello"
+ 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"
+ end
+ end
+ end
+end
diff --git a/spec/shared_behaviours/things_that_declare_options.rb b/spec/shared_behaviours/things_that_declare_options.rb
index ac358eacd..5300a159a 100755
--- a/spec/shared_behaviours/things_that_declare_options.rb
+++ b/spec/shared_behaviours/things_that_declare_options.rb
@@ -1,45 +1,45 @@
# encoding: UTF-8
shared_examples_for "things that declare options" do
it "should support options without arguments" do
- subject = add_options_to { option "--bar" }
- subject.should be_option :bar
+ thing = add_options_to { option "--bar" }
+ thing.should be_option :bar
end
it "should support options with an empty block" do
- subject = add_options_to do
+ thing = add_options_to do
option "--foo" do
# this section deliberately left blank
end
end
- subject.should be
- subject.should be_option :foo
+ thing.should be
+ thing.should be_option :foo
end
{ "--foo=" => :foo }.each do |input, option|
it "should accept #{name.inspect}" do
- subject = add_options_to { option input }
- subject.should be_option option
+ thing = add_options_to { option input }
+ thing.should be_option option
end
end
it "should support option documentation" do
text = "Sturm und Drang (German pronunciation: [ˈʃtʊʁm ʊnt ˈdʁaŋ]) …"
- subject = add_options_to do
+ thing = add_options_to do
option "--foo" do
desc text
end
end
- subject.get_option(:foo).desc.should == text
+ thing.get_option(:foo).desc.should == text
end
it "should list all the options" do
- subject = add_options_to do
+ thing = add_options_to do
option "--foo"
option "--bar"
end
- subject.options.should =~ [:foo, :bar]
+ thing.options.should =~ [:foo, :bar]
end
it "should detect conflicts in long options" do
@@ -95,22 +95,24 @@ shared_examples_for "things that declare options" do
should raise_error ArgumentError, /inconsistent about taking an argument/
end
- it "should accept optional arguments" do
- subject = add_options_to do option "--foo=[baz]", "--bar=[baz]" end
- [:foo, :bar].each do |name|
- subject.should be_option name
- end
+ it "should not accept optional arguments" do
+ expect do
+ thing = add_options_to do option "--foo=[baz]", "--bar=[baz]" end
+ [:foo, :bar].each do |name|
+ thing.should be_option name
+ end
+ end.to raise_error(ArgumentError, /optional arguments are not supported/)
end
describe "#takes_argument?" do
it "should detect an argument being absent" do
- subject = add_options_to do option "--foo" end
- subject.get_option(:foo).should_not be_takes_argument
+ thing = add_options_to do option "--foo" end
+ thing.get_option(:foo).should_not be_takes_argument
end
- ["=FOO", " FOO", "=[FOO]", " [FOO]"].each do |input|
+ ["=FOO", " FOO"].each do |input|
it "should detect an argument given #{input.inspect}" do
- subject = add_options_to do option "--foo#{input}" end
- subject.get_option(:foo).should be_takes_argument
+ thing = add_options_to do option "--foo#{input}" end
+ thing.get_option(:foo).should be_takes_argument
end
end
end
@@ -131,10 +133,12 @@ shared_examples_for "things that declare options" do
end
["=[FOO]", " [FOO]"].each do |input|
- it "should be true if the argument is optional (like #{input.inspect})" do
- option = add_options_to do option "--foo#{input}" end.get_option(:foo)
- option.should be_takes_argument
- option.should be_optional_argument
+ it "should fail if the argument is optional (like #{input.inspect})" do
+ expect do
+ option = add_options_to do option "--foo#{input}" end.get_option(:foo)
+ option.should be_takes_argument
+ option.should be_optional_argument
+ end.to raise_error(ArgumentError, /optional arguments are not supported/)
end
end
end
diff --git a/spec/unit/application/device_spec.rb b/spec/unit/application/device_spec.rb
new file mode 100644
index 000000000..086e321e9
--- /dev/null
+++ b/spec/unit/application/device_spec.rb
@@ -0,0 +1,349 @@
+#!/usr/bin/env ruby
+
+require File.dirname(__FILE__) + '/../../spec_helper'
+
+require 'puppet/application/device'
+require 'puppet/util/network_device/config'
+require 'ostruct'
+require 'puppet/configurer'
+
+describe Puppet::Application::Device do
+ before :each do
+ @device = Puppet::Application[:device]
+# @device.stubs(:puts)
+ @device.preinit
+ Puppet::Util::Log.stubs(:newdestination)
+ Puppet::Util::Log.stubs(:level=)
+
+ Puppet::Node.indirection.stubs(:terminus_class=)
+ Puppet::Node.indirection.stubs(:cache_class=)
+ Puppet::Node::Facts.indirection.stubs(:terminus_class=)
+ end
+
+ it "should operate in agent run_mode" do
+ @device.class.run_mode.name.should == :agent
+ end
+
+ it "should ask Puppet::Application to parse Puppet configuration file" do
+ @device.should_parse_config?.should be_true
+ end
+
+ it "should declare a main command" do
+ @device.should respond_to(:main)
+ end
+
+ it "should declare a preinit block" do
+ @device.should respond_to(:preinit)
+ end
+
+ describe "in preinit" do
+ before :each do
+ @device.stubs(:trap)
+ end
+
+ it "should catch INT" do
+ @device.expects(:trap).with { |arg,block| arg == :INT }
+
+ @device.preinit
+ end
+ end
+
+ describe "when handling options" do
+ before do
+ @device.command_line.stubs(:args).returns([])
+ end
+
+ [:centrallogging, :debug, :verbose,].each do |option|
+ it "should declare handle_#{option} method" do
+ @device.should respond_to("handle_#{option}".to_sym)
+ end
+
+ it "should store argument value when calling handle_#{option}" do
+ @device.options.expects(:[]=).with(option, 'arg')
+ @device.send("handle_#{option}".to_sym, 'arg')
+ end
+ end
+
+ it "should set waitforcert to 0 with --onetime and if --waitforcert wasn't given" do
+ Puppet[:onetime] = true
+ Puppet::SSL::Host.any_instance.expects(:wait_for_cert).with(0)
+ @device.setup_host
+ end
+
+ it "should use supplied waitforcert when --onetime is specified" do
+ Puppet[:onetime] = true
+ @device.handle_waitforcert(60)
+ Puppet::SSL::Host.any_instance.expects(:wait_for_cert).with(60)
+ @device.setup_host
+ end
+
+ it "should use a default value for waitforcert when --onetime and --waitforcert are not specified" do
+ Puppet::SSL::Host.any_instance.expects(:wait_for_cert).with(120)
+ @device.setup_host
+ end
+
+ it "should set the log destination with --logdest" do
+ @device.options.stubs(:[]=).with { |opt,val| opt == :setdest }
+ Puppet::Log.expects(:newdestination).with("console")
+
+ @device.handle_logdest("console")
+ end
+
+ it "should put the setdest options to true" do
+ @device.options.expects(:[]=).with(:setdest,true)
+
+ @device.handle_logdest("console")
+ end
+
+ it "should parse the log destination from the command line" do
+ @device.command_line.stubs(:args).returns(%w{--logdest /my/file})
+
+ Puppet::Util::Log.expects(:newdestination).with("/my/file")
+
+ @device.parse_options
+ end
+
+ it "should store the waitforcert options with --waitforcert" do
+ @device.options.expects(:[]=).with(:waitforcert,42)
+
+ @device.handle_waitforcert("42")
+ end
+
+ it "should set args[:Port] with --port" do
+ @device.handle_port("42")
+ @device.args[:Port].should == "42"
+ end
+
+ end
+
+ describe "during setup" do
+ before :each do
+ @device.options.stubs(:[])
+ Puppet.stubs(:info)
+ FileTest.stubs(:exists?).returns(true)
+ Puppet[:libdir] = "/dev/null/lib"
+ Puppet::SSL::Host.stubs(:ca_location=)
+ Puppet::Transaction::Report.indirection.stubs(:terminus_class=)
+ Puppet::Resource::Catalog.indirection.stubs(:terminus_class=)
+ Puppet::Resource::Catalog.indirection.stubs(:cache_class=)
+ Puppet::Node::Facts.indirection.stubs(:terminus_class=)
+ @host = stub_everything 'host'
+ Puppet::SSL::Host.stubs(:new).returns(@host)
+ Puppet.stubs(:settraps)
+ end
+
+ it "should call setup_logs" do
+ @device.expects(:setup_logs)
+ @device.setup
+ end
+
+ describe "when setting up logs" do
+ before :each do
+ Puppet::Util::Log.stubs(:newdestination)
+ end
+
+ it "should set log level to debug if --debug was passed" do
+ @device.options.stubs(:[]).with(:debug).returns(true)
+
+ Puppet::Util::Log.expects(:level=).with(:debug)
+
+ @device.setup_logs
+ end
+
+ it "should set log level to info if --verbose was passed" do
+ @device.options.stubs(:[]).with(:verbose).returns(true)
+
+ Puppet::Util::Log.expects(:level=).with(:info)
+
+ @device.setup_logs
+ end
+
+ [:verbose, :debug].each do |level|
+ it "should set console as the log destination with level #{level}" do
+ @device.options.stubs(:[]).with(level).returns(true)
+
+ Puppet::Util::Log.expects(:newdestination).with(:console)
+
+ @device.setup_logs
+ end
+ end
+
+ it "should set syslog as the log destination if no --logdest" do
+ @device.options.stubs(:[]).with(:setdest).returns(false)
+
+ Puppet::Util::Log.expects(:newdestination).with(:syslog)
+
+ @device.setup_logs
+ end
+
+ end
+
+ it "should set a central log destination with --centrallogs" do
+ @device.options.stubs(:[]).with(:centrallogs).returns(true)
+ Puppet[:server] = "puppet.reductivelabs.com"
+ Puppet::Util::Log.stubs(:newdestination).with(:syslog)
+
+ Puppet::Util::Log.expects(:newdestination).with("puppet.reductivelabs.com")
+
+ @device.setup
+ end
+
+ it "should use :main, :agent, :device and :ssl config" do
+ Puppet.settings.expects(:use).with(:main, :agent, :device, :ssl)
+
+ @device.setup
+ end
+
+ it "should install a remote ca location" do
+ Puppet::SSL::Host.expects(:ca_location=).with(:remote)
+
+ @device.setup
+ end
+
+ it "should tell the report handler to use REST" do
+ Puppet::Transaction::Report.indirection.expects(:terminus_class=).with(:rest)
+
+ @device.setup
+ end
+
+ it "should change the catalog_terminus setting to 'rest'" do
+ Puppet[:catalog_terminus] = :foo
+ @device.setup
+ Puppet[:catalog_terminus].should == :rest
+ end
+
+ it "should tell the catalog handler to use cache" do
+ Puppet::Resource::Catalog.indirection.expects(:cache_class=).with(:yaml)
+
+ @device.setup
+ end
+
+ it "should change the facts_terminus setting to 'network_device'" do
+ Puppet[:facts_terminus] = :foo
+
+ @device.setup
+ Puppet[:facts_terminus].should == :network_device
+ end
+ end
+
+ describe "when initializing each devices SSL" do
+ before(:each) do
+ @host = stub_everything 'host'
+ Puppet::SSL::Host.stubs(:new).returns(@host)
+ end
+
+ it "should create a new ssl host" do
+ Puppet::SSL::Host.expects(:new).returns(@host)
+ @device.setup_host
+ end
+
+ it "should wait for a certificate" do
+ @device.options.stubs(:[]).with(:waitforcert).returns(123)
+ @host.expects(:wait_for_cert).with(123)
+
+ @device.setup_host
+ end
+ end
+
+
+ describe "when running" do
+ before :each do
+ @device.options.stubs(:[]).with(:fingerprint).returns(false)
+ Puppet.stubs(:notice)
+ @device.options.stubs(:[]).with(:client)
+ Puppet::Util::NetworkDevice::Config.stubs(:devices).returns({})
+ end
+
+ it "should dispatch to main" do
+ @device.stubs(:main)
+ @device.run_command
+ end
+
+ it "should get the device list" do
+ device_hash = stub_everything 'device hash'
+ Puppet::Util::NetworkDevice::Config.expects(:devices).returns(device_hash)
+ @device.main
+ end
+
+ it "should exit if the device list is empty" do
+ @device.expects(:exit).with(1)
+ @device.main
+ end
+
+ describe "for each device" do
+ before(:each) do
+ Puppet[:vardir] = "/dummy"
+ Puppet[:confdir] = "/dummy"
+ Puppet[:certname] = "certname"
+ @device_hash = {
+ "device1" => OpenStruct.new(:name => "device1", :url => "url", :provider => "cisco"),
+ "device2" => OpenStruct.new(:name => "device2", :url => "url", :provider => "cisco"),
+ }
+ Puppet::Util::NetworkDevice::Config.stubs(:devices).returns(@device_hash)
+ Puppet.settings.stubs(:set_value)
+ Puppet.settings.stubs(:use)
+ @device.stubs(:setup_host)
+ Puppet::Util::NetworkDevice.stubs(:init)
+ @configurer = stub_everything 'configurer'
+ Puppet::Configurer.stubs(:new).returns(@configurer)
+ end
+
+ it "should set vardir to the device vardir" do
+ Puppet.settings.expects(:set_value).with(:vardir, "/dummy/devices/device1", :cli)
+ @device.main
+ end
+
+ it "should set confdir to the device confdir" do
+ Puppet.settings.expects(:set_value).with(:confdir, "/dummy/devices/device1", :cli)
+ @device.main
+ end
+
+ it "should set certname to the device certname" do
+ Puppet.settings.expects(:set_value).with(:certname, "device1", :cli)
+ Puppet.settings.expects(:set_value).with(:certname, "device2", :cli)
+ @device.main
+ end
+
+ it "should make sure all the required folders and files are created" do
+ Puppet.settings.expects(:use).with(:main, :agent, :ssl).twice
+ @device.main
+ end
+
+ it "should initialize the device singleton" do
+ Puppet::Util::NetworkDevice.expects(:init).with(@device_hash["device1"]).then.with(@device_hash["device2"])
+ @device.main
+ end
+
+ it "should setup the SSL context" do
+ @device.expects(:setup_host).twice
+ @device.main
+ end
+
+ it "should launch a configurer for this device" do
+ @configurer.expects(:run).twice
+ @device.main
+ end
+
+ [:vardir, :confdir].each do |setting|
+ it "should cleanup the #{setting} setting after the run" do
+ configurer = states('configurer').starts_as('notrun')
+ Puppet.settings.expects(:set_value).with(setting, "/dummy/devices/device1", :cli).when(configurer.is('notrun'))
+ @configurer.expects(:run).twice.then(configurer.is('run'))
+ Puppet.settings.expects(:set_value).with(setting, "/dummy", :cli).when(configurer.is('run'))
+
+ @device.main
+ end
+ end
+
+ it "should cleanup the certname setting after the run" do
+ configurer = states('configurer').starts_as('notrun')
+ Puppet.settings.expects(:set_value).with(:certname, "device1", :cli).when(configurer.is('notrun'))
+ @configurer.expects(:run).twice.then(configurer.is('run'))
+ Puppet.settings.expects(:set_value).with(:certname, "certname", :cli).when(configurer.is('run'))
+
+ @device.main
+ end
+
+ end
+ end
+end
diff --git a/spec/unit/application/face_base_spec.rb b/spec/unit/application/face_base_spec.rb
index 939712ef8..5403608cf 100755
--- a/spec/unit/application/face_base_spec.rb
+++ b/spec/unit/application/face_base_spec.rb
@@ -11,7 +11,6 @@ describe Puppet::Application::FaceBase do
Puppet::Face.define(:basetest, '0.0.1') do
option("--[no-]boolean")
option("--mandatory MANDATORY")
- option("--optional [OPTIONAL]")
action :foo do
option("--action")
@@ -60,19 +59,39 @@ describe Puppet::Application::FaceBase do
app.face.name.should == :basetest
end
- it "should set the format based on the face default" do
- app.format.should == :pson
- end
-
it "should find the action" do
app.action.should be
app.action.name.should == :foo
end
end
- it "should fail if no action is given" do
- expect { app.preinit; app.parse_options }.
- to raise_error OptionParser::MissingArgument, /No action given/
+ it "should use the default action if not given any arguments" do
+ app.command_line.stubs(:args).returns []
+ action = stub(:options => [])
+ Puppet::Face[:basetest, '0.0.1'].expects(:get_default_action).returns(action)
+ app.stubs(:main)
+ app.run
+ app.action.should == action
+ app.arguments.should == [ { } ]
+ end
+
+ it "should use the default action if not given a valid one" do
+ app.command_line.stubs(:args).returns %w{bar}
+ action = stub(:options => [])
+ Puppet::Face[:basetest, '0.0.1'].expects(:get_default_action).returns(action)
+ app.stubs(:main)
+ app.run
+ app.action.should == action
+ app.arguments.should == [ 'bar', { } ]
+ end
+
+ it "should have no action if not given a valid one and there is no default action" 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', { } ]
end
it "should report a sensible error when options with = fail" do
@@ -169,7 +188,6 @@ describe Puppet::Application::FaceBase do
app.face = Puppet::Face[:basetest, '0.0.1']
app.action = app.face.get_action(:foo)
- app.format = :pson
app.arguments = ["myname", "myarg"]
end
@@ -178,10 +196,79 @@ describe Puppet::Application::FaceBase do
app.main
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
+ 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
end
end
+
+ describe "#render" do
+ before :each do
+ app.face = Puppet::Face[:basetest, '0.0.1']
+ app.action = app.face.get_action(:foo)
+ end
+
+ ["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 the 'pp' library" do
+ app.render(input).should == input.pretty_inspect
+ 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
+ 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}
+one 1
+three {}
+two []
+EOT
+ 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
+number {"1"=>"1111111111111111111111111111111111111111",
+ "2"=>"2222222222222222222222222222222222222222",
+ "3"=>"3333333333333333333333333333333333333333"}
+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(:for_humans, proc { |value| "bi-winning!" })
+ app.action.render_as = :for_humans
+ app.render("bi-polar?").should == "bi-winning!"
+ end
+ end
end
diff --git a/spec/unit/application/indirection_base_spec.rb b/spec/unit/application/indirection_base_spec.rb
index 63ab11eed..57740384a 100755
--- a/spec/unit/application/indirection_base_spec.rb
+++ b/spec/unit/application/indirection_base_spec.rb
@@ -23,12 +23,11 @@ describe Puppet::Application::IndirectionBase do
it "should accept a terminus command line option" do
# It would be nice not to have to stub this, but whatever... writing an
# entire indirection stack would cause us more grief. --daniel 2011-03-31
- terminus = mock("test indirection terminus")
+ terminus = stub_everything("test indirection terminus")
Puppet::Indirector::Indirection.expects(:instance).
- with(:testindirection).twice.returns()
+ 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})
# Not a very nice thing. :(
$stderr.stubs(:puts)
diff --git a/spec/unit/face/certificate_spec.rb b/spec/unit/face/certificate_spec.rb
index dbcc888ad..b0bbf1af6 100755
--- a/spec/unit/face/certificate_spec.rb
+++ b/spec/unit/face/certificate_spec.rb
@@ -6,9 +6,14 @@ describe Puppet::Face[:certificate, '0.0.1'] do
end
it "should set the ca location when invoked" do
- pending "#6983: This is broken in the actual face..."
Puppet::SSL::Host.expects(:ca_location=).with(:foo)
Puppet::SSL::Host.indirection.expects(:save)
- subject.sign :ca_location => :foo
+ subject.sign "hello, friend", :ca_location => :foo
+ end
+
+ it "(#7059) should set the ca location when an inherited action is invoked" do
+ Puppet::SSL::Host.expects(:ca_location=).with(:foo)
+ subject.indirection.expects(:find)
+ subject.find "hello, friend", :ca_location => :foo
end
end
diff --git a/spec/unit/face/facts_spec.rb b/spec/unit/face/facts_spec.rb
index e6411f836..6ab6ad5be 100755
--- a/spec/unit/face/facts_spec.rb
+++ b/spec/unit/face/facts_spec.rb
@@ -2,14 +2,10 @@
require 'spec_helper'
describe Puppet::Face[:facts, '0.0.1'] do
- it "should define an 'upload' fact" do
+ it "should define an 'upload' action" do
subject.should be_action(:upload)
end
- it "should set its default format to :yaml" do
- subject.default_format.should == :yaml
- end
-
describe "when uploading" do
it "should set the terminus_class to :facter"
diff --git a/spec/unit/face/help_spec.rb b/spec/unit/face/help_spec.rb
index e67f29e07..faa5f9617 100755
--- a/spec/unit/face/help_spec.rb
+++ b/spec/unit/face/help_spec.rb
@@ -7,7 +7,7 @@ describe Puppet::Face[:help, '0.0.1'] do
end
it "should have a default action of help" do
- pending "REVISIT: we don't support default actions yet"
+ subject.get_action('help').should be_default
end
it "should accept a call with no arguments" do
@@ -55,19 +55,23 @@ describe Puppet::Face[:help, '0.0.1'] do
end
end
- Puppet::Face.faces.each do |name|
- face = Puppet::Face[name, :current]
- summary = face.summary
+ it "should list all faces" do
+ Puppet::Face.faces.each do |name|
+ face = Puppet::Face[name, :current]
+ summary = face.summary
- it { should =~ %r{ #{name} } }
- it { should =~ %r{ #{name} +#{summary}} } if summary
+ subject.should =~ %r{ #{name} }
+ summary and subject.should =~ %r{ #{name} +#{summary}}
+ end
end
- Puppet::Face[:help, :current].legacy_applications.each do |appname|
- it { should =~ %r{ #{appname} } }
+ it "should list all legacy applications" do
+ Puppet::Face[:help, :current].legacy_applications.each do |appname|
+ subject.should =~ %r{ #{appname} }
- summary = Puppet::Face[:help, :current].horribly_extract_summary_from(appname)
- summary and it { should =~ %r{ #{summary}\b} }
+ summary = Puppet::Face[:help, :current].horribly_extract_summary_from(appname)
+ summary and subject.should =~ %r{ #{summary}\b}
+ end
end
end
diff --git a/spec/unit/face/node_spec.rb b/spec/unit/face/node_spec.rb
index 90d258db9..d19312c58 100755
--- a/spec/unit/face/node_spec.rb
+++ b/spec/unit/face/node_spec.rb
@@ -2,7 +2,5 @@
require 'spec_helper'
describe Puppet::Face[:node, '0.0.1'] do
- it "should set its default format to :yaml" do
- subject.default_format.should == :yaml
- end
+ it "REVISIT: really should have some tests"
end
diff --git a/spec/unit/indirector/facts/network_device_spec.rb b/spec/unit/indirector/facts/network_device_spec.rb
new file mode 100644
index 000000000..302a810e8
--- /dev/null
+++ b/spec/unit/indirector/facts/network_device_spec.rb
@@ -0,0 +1,89 @@
+#!/usr/bin/env ruby
+#
+# Created by Luke Kanies on 2007-9-23.
+# Copyright (c) 2007. All rights reserved.
+
+require File.dirname(__FILE__) + '/../../../spec_helper'
+
+require 'puppet/indirector/facts/network_device'
+
+describe Puppet::Node::Facts::NetworkDevice do
+ it "should be a subclass of the Code terminus" do
+ Puppet::Node::Facts::NetworkDevice.superclass.should equal(Puppet::Indirector::Code)
+ end
+
+ it "should have documentation" do
+ Puppet::Node::Facts::NetworkDevice.doc.should_not be_nil
+ end
+
+ it "should be registered with the configuration store indirection" do
+ indirection = Puppet::Indirector::Indirection.instance(:facts)
+ Puppet::Node::Facts::NetworkDevice.indirection.should equal(indirection)
+ end
+
+ it "should have its name set to :facter" do
+ Puppet::Node::Facts::NetworkDevice.name.should == :network_device
+ end
+end
+
+describe Puppet::Node::Facts::NetworkDevice do
+ before :each do
+ @remote_device = stub 'remote_device', :facts => {}
+ Puppet::Util::NetworkDevice.stubs(:current).returns(@remote_device)
+ @device = Puppet::Node::Facts::NetworkDevice.new
+ @name = "me"
+ @request = stub 'request', :key => @name
+ end
+
+ describe Puppet::Node::Facts::NetworkDevice, " when finding facts" do
+ it "should return a Facts instance" do
+ @device.find(@request).should be_instance_of(Puppet::Node::Facts)
+ end
+
+ it "should return a Facts instance with the provided key as the name" do
+ @device.find(@request).name.should == @name
+ end
+
+ it "should return the device facts as the values in the Facts instance" do
+ @remote_device.expects(:facts).returns("one" => "two")
+ facts = @device.find(@request)
+ facts.values["one"].should == "two"
+ end
+
+ it "should add local facts" do
+ facts = Puppet::Node::Facts.new("foo")
+ Puppet::Node::Facts.expects(:new).returns facts
+ facts.expects(:add_local_facts)
+
+ @device.find(@request)
+ end
+
+ it "should convert all facts into strings" do
+ facts = Puppet::Node::Facts.new("foo")
+ Puppet::Node::Facts.expects(:new).returns facts
+ facts.expects(:stringify)
+
+ @device.find(@request)
+ end
+
+ it "should call the downcase hook" do
+ facts = Puppet::Node::Facts.new("foo")
+ Puppet::Node::Facts.expects(:new).returns facts
+ facts.expects(:downcase_if_necessary)
+
+ @device.find(@request)
+ end
+ end
+
+ describe Puppet::Node::Facts::NetworkDevice, " when saving facts" do
+ it "should fail" do
+ proc { @device.save(@facts) }.should raise_error(Puppet::DevError)
+ end
+ end
+
+ describe Puppet::Node::Facts::NetworkDevice, " when destroying facts" do
+ it "should fail" do
+ proc { @device.destroy(@facts) }.should raise_error(Puppet::DevError)
+ end
+ end
+end
diff --git a/spec/unit/indirector/queue_spec.rb b/spec/unit/indirector/queue_spec.rb
index b84ed2aea..eba136bbc 100755
--- a/spec/unit/indirector/queue_spec.rb
+++ b/spec/unit/indirector/queue_spec.rb
@@ -60,20 +60,20 @@ describe Puppet::Indirector::Queue, :if => Puppet.features.pson? do
describe "when saving" do
it 'should render the instance using pson' do
@subject.expects(:render).with(:pson)
- @store.client.stubs(:send_message)
+ @store.client.stubs(:publish_message)
@store.save(@request)
end
- it "should send the rendered message to the appropriate queue on the client" do
+ it "should publish the rendered message to the appropriate queue on the client" do
@subject.expects(:render).returns "mypson"
- @store.client.expects(:send_message).with(:my_queue, "mypson")
+ @store.client.expects(:publish_message).with(:my_queue, "mypson")
@store.save(@request)
end
it "should catch any exceptions raised" do
- @store.client.expects(:send_message).raises ArgumentError
+ @store.client.expects(:publish_message).raises ArgumentError
lambda { @store.save(@request) }.should raise_error(Puppet::Error)
end
diff --git a/spec/unit/indirector/request_spec.rb b/spec/unit/indirector/request_spec.rb
index 965d54188..ba7dc815e 100755
--- a/spec/unit/indirector/request_spec.rb
+++ b/spec/unit/indirector/request_spec.rb
@@ -1,5 +1,6 @@
#!/usr/bin/env rspec
require 'spec_helper'
+require 'matchers/json'
require 'puppet/indirector/request'
describe Puppet::Indirector::Request do
@@ -300,4 +301,99 @@ 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/indirector/rest_spec.rb b/spec/unit/indirector/rest_spec.rb
index 513eb8352..5637080e8 100755
--- a/spec/unit/indirector/rest_spec.rb
+++ b/spec/unit/indirector/rest_spec.rb
@@ -233,6 +233,11 @@ describe Puppet::Indirector::REST do
params[s] = 'foo'
end
+ # The request special-cases this parameter, and it
+ # won't be passed on to the server, so we remove it here
+ # to avoid a failure.
+ params.delete('ip')
+
@request = Puppet::Indirector::Request.new(:foo, :find, "foo bar", params.merge(:environment => "myenv"))
@connection.expects(:post).with do |uri, body|
diff --git a/spec/unit/interface/action_builder_spec.rb b/spec/unit/interface/action_builder_spec.rb
index 5b04df900..bf7afa74e 100755
--- a/spec/unit/interface/action_builder_spec.rb
+++ b/spec/unit/interface/action_builder_spec.rb
@@ -1,68 +1,192 @@
#!/usr/bin/env rspec
require 'spec_helper'
require 'puppet/interface/action_builder'
+require 'puppet/network/format_handler'
describe Puppet::Interface::ActionBuilder do
- describe "::build" do
- it "should build an action" do
- action = Puppet::Interface::ActionBuilder.build(nil, :foo) 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
+ end
+ action.should be_a(Puppet::Interface::Action)
+ action.name.should == :foo
+ end
+
+ it "should define a method on the face which invokes the action" do
+ face = Puppet::Interface.new(:action_builder_test_interface, '0.0.1') do
+ action(:foo) { when_invoked { "invoked the method" } }
+ end
+
+ face.foo.should == "invoked the method"
+ end
+
+ it "should require a block" do
+ expect { Puppet::Interface::ActionBuilder.build(nil, :foo) }.
+ should raise_error("Action :foo must specify a block")
+ end
+
+ describe "when handling options" do
+ it "should have a #option DSL function" do
+ method = nil
+ Puppet::Interface::ActionBuilder.build(face, :foo) do
+ method = self.method(:option)
+ end
+ method.should be
+ end
+
+ it "should define an option without a block" do
+ action = Puppet::Interface::ActionBuilder.build(face, :foo) do
+ option "--bar"
end
- action.should be_a(Puppet::Interface::Action)
- action.name.should == :foo
+ action.should be_option :bar
end
- it "should define a method on the face which invokes the action" do
- face = Puppet::Interface.new(:action_builder_test_interface, '0.0.1')
+ it "should accept an empty block" do
action = Puppet::Interface::ActionBuilder.build(face, :foo) do
- when_invoked do
- "invoked the method"
+ option "--bar" do
+ # This space left deliberately blank.
end
end
+ action.should be_option :bar
+ end
+ end
+
+ context "inline documentation" do
+ it "should set the summary" do
+ action = Puppet::Interface::ActionBuilder.build(face, :foo) do
+ summary "this is some text"
+ end
+ action.summary.should == "this is some text"
+ end
+ end
- face.foo.should == "invoked the method"
+ context "action defaulting" do
+ it "should set the default to true" do
+ action = Puppet::Interface::ActionBuilder.build(face, :foo) do
+ default
+ end
+ action.default.should be_true
end
- it "should require a block" do
- expect { Puppet::Interface::ActionBuilder.build(nil, :foo) }.
- should raise_error("Action :foo must specify a block")
+ it "should not be default by, er, default. *cough*" do
+ action = Puppet::Interface::ActionBuilder.build(face, :foo) do end
+ action.default.should be_false
end
+ end
- describe "when handling options" do
- let :face do Puppet::Interface.new(:option_handling, '0.0.1') end
+ context "#when_rendering" do
+ it "should fail if no rendering format is given" do
+ expect {
+ Puppet::Interface::ActionBuilder.build(face, :foo) do
+ when_rendering do true end
+ end
+ }.to raise_error ArgumentError, /must give a rendering format to when_rendering/
+ end
- it "should have a #option DSL function" do
- method = nil
+ it "should fail if no block is given" do
+ expect {
Puppet::Interface::ActionBuilder.build(face, :foo) do
- method = self.method(:option)
+ when_rendering :json
end
- method.should be
- end
+ }.to raise_error ArgumentError, /must give a block to when_rendering/
+ end
- it "should define an option without a block" do
- action = Puppet::Interface::ActionBuilder.build(face, :foo) do
- option "--bar"
+ it "should fail if the block takes no arguments" do
+ expect {
+ Puppet::Interface::ActionBuilder.build(face, :foo) do
+ when_rendering :json do true end
end
- action.should be_option :bar
+ }.to raise_error ArgumentError, /when_rendering methods take one argument, the result, not/
+ end
+
+ it "should fail if the block takes more than one argument" do
+ expect {
+ Puppet::Interface::ActionBuilder.build(face, :foo) do
+ when_rendering :json do |a, b, c| true end
+ end
+ }.to raise_error ArgumentError, /when_rendering methods take one argument, the result, not/
+ end
+
+ it "should fail if the block takes a variable number of arguments" do
+ expect {
+ Puppet::Interface::ActionBuilder.build(face, :foo) do
+ when_rendering :json do |*args| true end
+ end
+ }.to raise_error(ArgumentError,
+ /when_rendering methods take one argument, the result, not/)
+ end
+
+ it "should stash a rendering block" do
+ action = Puppet::Interface::ActionBuilder.build(face, :foo) do
+ when_rendering :json do |a| true end
end
+ action.when_rendering(:json).should be_an_instance_of Method
+ end
- it "should accept an empty block" do
- action = Puppet::Interface::ActionBuilder.build(face, :foo) do
- option "--bar" do
- # This space left deliberately blank.
- end
+ it "should fail if you try to set the same rendering twice" do
+ expect {
+ Puppet::Interface::ActionBuilder.build(face, :foo) do
+ when_rendering :json do |a| true end
+ when_rendering :json do |a| true end
end
- action.should be_option :bar
+ }.to raise_error ArgumentError, /You can't define a rendering method for json twice/
+ end
+
+ it "should work if you set two different renderings" do
+ action = Puppet::Interface::ActionBuilder.build(face, :foo) do
+ when_rendering :json do |a| true end
+ when_rendering :yaml do |a| true end
end
+ action.when_rendering(:json).should be_an_instance_of Method
+ action.when_rendering(:yaml).should be_an_instance_of Method
end
- context "inline documentation" do
- let :face do Puppet::Interface.new(:inline_action_docs, '0.0.1') end
+ it "should be bound to the face when called" do
+ action = Puppet::Interface::ActionBuilder.build(face, :foo) do
+ when_rendering :json do |a| self end
+ end
+ action.when_rendering(:json).call(true).should == face
+ end
+ end
+
+ context "#render_as" do
+ it "should default to nil (eg: based on context)" do
+ action = Puppet::Interface::ActionBuilder.build(face, :foo) do 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
+ render_as
+ end
+ }.to raise_error ArgumentError, /must give a rendering format to render_as/
+ end
- it "should set the summary" do
+ Puppet::Network::FormatHandler.formats.each do |name|
+ it "should accept #{name.inspect} format" do
action = Puppet::Interface::ActionBuilder.build(face, :foo) do
- summary "this is some text"
+ render_as name
end
- action.summary.should == "this is some text"
+ 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
+ render_as input
+ end
+ }.to raise_error ArgumentError, /#{input.inspect} is not a valid rendering format/
end
end
end
diff --git a/spec/unit/interface/action_manager_spec.rb b/spec/unit/interface/action_manager_spec.rb
index c4b21eaac..07d517c18 100755
--- a/spec/unit/interface/action_manager_spec.rb
+++ b/spec/unit/interface/action_manager_spec.rb
@@ -3,6 +3,7 @@ require 'spec_helper'
# This is entirely an internal class for Interface, so we have to load it instead of our class.
require 'puppet/interface'
+require 'puppet/face'
class ActionManagerTester
include Puppet::Interface::ActionManager
@@ -103,6 +104,8 @@ describe Puppet::Interface::ActionManager do
@klass = Class.new do
include Puppet::Interface::ActionManager
extend Puppet::Interface::ActionManager
+ def __invoke_decorations(*args) true end
+ def options() [] end
end
@instance = @klass.new
end
@@ -213,6 +216,23 @@ describe Puppet::Interface::ActionManager do
end
end
+ describe "#action" do
+ it 'should add an action' do
+ subject.action(:foo) { }
+ subject.get_action(:foo).should be_a Puppet::Interface::Action
+ end
+
+ it 'should support default actions' do
+ subject.action(:foo) { 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
+ end
+ end
+
describe "#get_action" do
let :parent_class do
parent_class = Class.new(Puppet::Interface)
diff --git a/spec/unit/interface/action_spec.rb b/spec/unit/interface/action_spec.rb
index 8c6782976..0eb450ee2 100755
--- a/spec/unit/interface/action_spec.rb
+++ b/spec/unit/interface/action_spec.rb
@@ -66,8 +66,8 @@ describe Puppet::Interface::Action do
let :face do
Puppet::Interface.new(:ruby_api, '1.0.0') do
action :bar do
- when_invoked do |options|
- options
+ when_invoked do |*args|
+ args.last
end
end
end
@@ -79,9 +79,14 @@ describe Puppet::Interface::Action do
end
it "should work when options are supplied" do
- options = face.bar :bar => "beer"
+ options = face.bar(:bar => "beer")
options.should == { :bar => "beer" }
end
+
+ it "should call #validate_args on the action when invoked" do
+ face.get_action(:bar).expects(:validate_args).with([1, :two, 'three', {}])
+ face.bar 1, :two, 'three'
+ end
end
end
@@ -168,5 +173,220 @@ describe Puppet::Interface::Action do
end
}.should raise_error ArgumentError, /Option foo conflicts with existing option foo/i
end
+
+ it "should fail when a required action option is not provided" do
+ face = Puppet::Interface.new(:required_action_option, '0.0.1') do
+ action(:bar) do
+ option('--foo') { required }
+ when_invoked { }
+ end
+ end
+ expect { face.bar }.to raise_error ArgumentError, /missing required options \(foo\)/
+ end
+
+ it "should fail when a required face option is not provided" do
+ face = Puppet::Interface.new(:required_face_option, '0.0.1') do
+ option('--foo') { required }
+ action(:bar) { when_invoked { } }
+ end
+ expect { face.bar }.to raise_error ArgumentError, /missing required options \(foo\)/
+ end
+ end
+
+ context "with action decorators" do
+ context "local only" 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
+ 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
+ end
+
+ face.expects(:report).with(:action_option)
+ face.baz :baz => true
+ 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
+ end
+
+ face.expects(:report).with(:action_option)
+ face.baz :baz => true
+ end
+
+ it "should call local before decorators" do
+ face.option "--foo FOO" do
+ before_action do |action, args, options|
+ report(:before)
+ end
+ end
+ face.expects(:report).with(:before)
+ face.bar({:foo => 12})
+ end
+
+ it "should call local after decorators" do
+ face.option "--foo FOO" do
+ after_action do |action, args, options| report(:after) end
+ end
+ face.expects(:report).with(:after)
+ face.bar({:foo => 12})
+ 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
+ end
+ face.expects(:report).never # I am testing the negative.
+ face.bar
+ 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
+
+ it "should work with the foo option" do
+ face.expects(:report).with(:foo)
+ face.bar(:foo => true)
+ end
+
+ it "should work with the bar option" do
+ face.expects(:report).with(:bar)
+ face.bar(:bar => true)
+ 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
+ end
+ end
+ end
+
+ context "with inherited decorators" 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
+ end
+
+ let :child do
+ child = parent.new(:inherited_decorators, '0.0.1') do
+ script :on_child do :on_child end
+ end
+ end
+
+ context "with a child decorator" 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
+ end
+
+ it "child actions should invoke the decorator" do
+ subject.on_child({:foo => true, :bar => true}).should == :on_child
+ end
+
+ it "parent actions should invoke the decorator" do
+ subject.on_parent({:foo => true, :bar => true}).should == :on_parent
+ end
+ end
+
+ context "with a parent decorator" 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)
+ child
+ end
+
+ it "child actions should invoke the decorator" do
+ subject.on_child({:foo => true, :bar => true}).should == :on_child
+ end
+
+ it "parent actions should invoke the decorator" do
+ subject.on_parent({:foo => true, :bar => true}).should == :on_parent
+ end
+ end
+
+ context "with child and parent decorators" do
+ subject do
+ parent.option "--foo FOO" do
+ before_action { |action, args, options| report(:parent_before) }
+ after_action { |action, args, options| report(:parent_after) }
+ end
+ child.option "--bar BAR" do
+ before_action { |action, args, options| report(:child_before) }
+ after_action { |action, args, options| report(:child_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
+ end
+
+ it "child actions should invoke all the decorator" do
+ subject.on_child({:foo => true, :bar => true}).should == :on_child
+ end
+
+ it "parent actions should invoke all the decorator" do
+ subject.on_parent({:foo => true, :bar => true}).should == :on_parent
+ end
+ end
+ end
+ end
+
+ it_should_behave_like "documentation on faces" do
+ subject do
+ face = Puppet::Interface.new(:action_documentation, '0.0.1') do
+ action :documentation do end
+ end
+ face.get_action(:documentation)
+ end
+ end
+
+ context "#when_rendering" do
+ it "should fail if no type is given when_rendering"
+ it "should accept a when_rendering block"
+ it "should accept multiple when_rendering blocks"
+ it "should fail if when_rendering gets a non-symbol identifier"
+ it "should fail if a second block is given for the same type"
+ it "should return the block if asked"
end
end
diff --git a/spec/unit/interface/face_collection_spec.rb b/spec/unit/interface/face_collection_spec.rb
index d1114dde7..f9498cbb8 100755
--- a/spec/unit/interface/face_collection_spec.rb
+++ b/spec/unit/interface/face_collection_spec.rb
@@ -24,10 +24,6 @@ describe Puppet::Interface::FaceCollection do
$".clear ; @original_required.each do |item| $" << item end
end
- describe "::faces" do
- it "REVISIT: should have some tests here, if we describe it"
- end
-
describe "::validate_version" do
it 'should permit three number versions' do
subject.validate_version('10.10.10').should == true
diff --git a/spec/unit/interface/option_builder_spec.rb b/spec/unit/interface/option_builder_spec.rb
index fae48324e..e9346852c 100755
--- a/spec/unit/interface/option_builder_spec.rb
+++ b/spec/unit/interface/option_builder_spec.rb
@@ -8,22 +8,68 @@ describe Puppet::Interface::OptionBuilder do
should be_an_instance_of Puppet::Interface::Option
end
- describe "when using the DSL block" do
- it "should work with an empty block" do
+ it "should work with an empty block" do
+ option = Puppet::Interface::OptionBuilder.build(face, "--foo") do
+ # This block deliberately left blank.
+ end
+
+ 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
+ end
+ option.should be_an_instance_of Puppet::Interface::Option
+ option.desc.should == text
+ end
+
+ context "before_action hook" do
+ it "should support a before_action hook" do
option = Puppet::Interface::OptionBuilder.build(face, "--foo") do
- # This block deliberately left blank.
+ before_action do |a,b,c| :whatever end
end
+ option.before_action.should be_an_instance_of UnboundMethod
+ end
- option.should be_an_instance_of Puppet::Interface::Option
+ it "should fail if the hook block takes too few arguments" do
+ expect do
+ Puppet::Interface::OptionBuilder.build(face, "--foo") do
+ before_action do |one, two| true end
+ end
+ end.to raise_error ArgumentError, /takes three arguments/
end
- it "should support documentation declarations" do
- text = "this is the description"
- option = Puppet::Interface::OptionBuilder.build(face, "--foo") do
- desc text
+ it "should fail if the hook block takes too many arguments" do
+ expect do
+ Puppet::Interface::OptionBuilder.build(face, "--foo") do
+ before_action do |one, two, three, four| true end
+ end
+ end.to raise_error ArgumentError, /takes three arguments/
+ end
+
+ it "should fail if the hook block takes a variable number of arguments" do
+ expect do
+ Puppet::Interface::OptionBuilder.build(face, "--foo") do
+ before_action do |*blah| true end
+ end
+ end.to raise_error ArgumentError, /takes three arguments/
+ end
+
+ it "should support simple required declarations" do
+ opt = Puppet::Interface::OptionBuilder.build(face, "--foo") do
+ required
end
- option.should be_an_instance_of Puppet::Interface::Option
- option.desc.should == text
+ opt.should be_required
end
+
+ it "should support arguments to the required property" do
+ opt = Puppet::Interface::OptionBuilder.build(face, "--foo") do
+ required(false)
+ end
+ opt.should_not be_required
+ end
+
end
end
diff --git a/spec/unit/interface/option_spec.rb b/spec/unit/interface/option_spec.rb
index 3bcd121e2..e77b46e79 100755
--- a/spec/unit/interface/option_spec.rb
+++ b/spec/unit/interface/option_spec.rb
@@ -1,3 +1,4 @@
+require 'puppet/interface'
require 'puppet/interface/option'
describe Puppet::Interface::Option do
@@ -72,4 +73,28 @@ describe Puppet::Interface::Option do
option.to_s.should == "foo-bar"
end
end
+
+ %w{before after}.each do |side|
+ describe "#{side} hooks" do
+ subject { Puppet::Interface::Option.new(face, "--foo") }
+ let :proc do Proc.new do :from_proc end end
+
+ it { should respond_to "#{side}_action" }
+ it { should respond_to "#{side}_action=" }
+
+ it "should set the #{side}_action hook" do
+ subject.send("#{side}_action").should be_nil
+ subject.send("#{side}_action=", proc)
+ subject.send("#{side}_action").should be_an_instance_of UnboundMethod
+ end
+
+ data = [1, "foo", :foo, Object.new, method(:hash), method(:hash).unbind]
+ data.each do |input|
+ it "should fail if a #{input.class} is added to the #{side} hooks" do
+ expect { subject.send("#{side}_action=", input) }.
+ to raise_error ArgumentError, /not a proc/
+ end
+ end
+ end
+ end
end
diff --git a/spec/unit/interface_spec.rb b/spec/unit/interface_spec.rb
index e52b45d8a..b4fef0307 100755
--- a/spec/unit/interface_spec.rb
+++ b/spec/unit/interface_spec.rb
@@ -33,7 +33,7 @@ describe Puppet::Interface do
describe "#define" do
it "should register the face" do
- face = subject.define(:face_test_register, '0.0.1')
+ face = subject.define(:face_test_register, '0.0.1')
face.should == subject[:face_test_register, '0.0.1']
end
@@ -51,22 +51,16 @@ describe Puppet::Interface do
subject.new(:foo, '1.0.0').should respond_to(:summary=).with(1).arguments
end
- it "should set the summary text" do
- text = "hello, freddy, my little pal"
- subject.define(:face_test_summary, '1.0.0') do
- summary text
- end
- subject[:face_test_summary, '1.0.0'].summary.should == text
- end
-
- it "should support mutating the summary" do
- text = "hello, freddy, my little pal"
- subject.define(:face_test_summary, '1.0.0') do
- summary text
+ # Required documentation methods...
+ { :summary => "summary",
+ :description => "This is the description of the stuff\n\nWhee"
+ }.each do |attr, value|
+ it "should support #{attr} in the builder" do
+ face = subject.new(:builder, '1.0.0') do
+ self.send(attr, value)
+ end
+ face.send(attr).should == value
end
- subject[:face_test_summary, '1.0.0'].summary.should == text
- subject[:face_test_summary, '1.0.0'].summary = text + text
- subject[:face_test_summary, '1.0.0'].summary.should == text + text
end
end
@@ -99,16 +93,6 @@ describe Puppet::Interface do
subject.new(:me, '0.0.1').to_s.should =~ /\bme\b/
end
- it "should allow overriding of the default format" do
- face = subject.new(:me, '0.0.1')
- face.set_default_format :foo
- face.default_format.should == :foo
- end
-
- it "should default to :pson for its format" do
- subject.new(:me, '0.0.1').default_format.should == :pson
- end
-
# Why?
it "should create a class-level autoloader" do
subject.autoloader.should be_instance_of(Puppet::Util::Autoload)
@@ -204,4 +188,10 @@ describe Puppet::Interface do
end
end
end
+
+ it_should_behave_like "documentation on faces" do
+ subject do
+ Puppet::Interface.new(:face_documentation, '0.0.1')
+ end
+ end
end
diff --git a/spec/unit/network/http/handler_spec.rb b/spec/unit/network/http/handler_spec.rb
index 83969c504..c709d82fe 100755
--- a/spec/unit/network/http/handler_spec.rb
+++ b/spec/unit/network/http/handler_spec.rb
@@ -240,34 +240,30 @@ describe Puppet::Network::HTTP::Handler do
describe "when performing head operation" do
before do
- @irequest = stub 'indirection_request', :method => :head, :indirection_name => "my_handler", :to_hash => {}, :key => "my_result", :model => @model_class
+ @handler.stubs(:model).with("my_handler").returns(stub 'model', :indirection => @model_class)
+ @handler.stubs(:http_method).with(@request).returns("HEAD")
+ @handler.stubs(:path).with(@request).returns("/production/my_handler/my_result")
+ @handler.stubs(:params).with(@request).returns({})
@model_class.stubs(:head).returns true
end
- it "should use the indirection request to find the model class" do
- @irequest.expects(:model).returns @model_class
-
- @handler.do_head(@irequest, @request, @response)
- end
-
it "should use the escaped request key" do
@model_class.expects(:head).with do |key, args|
key == "my_result"
end.returns true
- @handler.do_head(@irequest, @request, @response)
+ @handler.process(@request, @response)
end
it "should not generate a response when a model head call succeeds" do
@handler.expects(:set_response).never
- @handler.do_head(@irequest, @request, @response)
+ @handler.process(@request, @response)
end
it "should return a 404 when the model head call returns false" do
- @model_class.stubs(:name).returns "my name"
@handler.expects(:set_response).with { |response, body, status| status == 404 }
@model_class.stubs(:head).returns(false)
- @handler.do_head(@irequest, @request, @response)
+ @handler.process(@request, @response)
end
end
diff --git a/spec/unit/node/facts_spec.rb b/spec/unit/node/facts_spec.rb
index a130ae3f8..07f5f7e1b 100755
--- a/spec/unit/node/facts_spec.rb
+++ b/spec/unit/node/facts_spec.rb
@@ -1,6 +1,6 @@
#!/usr/bin/env rspec
require 'spec_helper'
-
+require 'matchers/json'
require 'puppet/node/facts'
describe Puppet::Node::Facts, "when indirecting" do
@@ -110,7 +110,11 @@ describe Puppet::Node::Facts, "when indirecting" do
end
it "should accept properly formatted pson" do
- pson = %Q({"name": "foo", "expiration": "#{@expiration}", "timestamp": "#{@timestamp}", "values": {"a": "1", "b": "2", "c": "3"}})
+ 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"})
format = Puppet::Network::FormatHandler.format('pson')
facts = format.intern(Puppet::Node::Facts,pson)
facts.name.should == 'foo'
@@ -122,8 +126,30 @@ describe Puppet::Node::Facts, "when indirecting" do
Time.stubs(:now).returns(@timestamp)
facts = Puppet::Node::Facts.new("foo", {'a' => 1, 'b' => 2, 'c' => 3})
facts.expiration = @expiration
- pson = PSON.parse(facts.to_pson)
- pson.should == {"name"=>"foo", "timestamp"=>@timestamp.to_s, "expiration"=>@expiration.to_s, "values"=>{"a"=>1, "b"=>2, "c"=>3}}
+ 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
end
end
end
diff --git a/spec/unit/node_spec.rb b/spec/unit/node_spec.rb
index 7d813ba30..e8f826dca 100755
--- a/spec/unit/node_spec.rb
+++ b/spec/unit/node_spec.rb
@@ -1,5 +1,6 @@
#!/usr/bin/env rspec
require 'spec_helper'
+require 'matchers/json'
describe Puppet::Node do
describe "when managing its environment" do
@@ -35,6 +36,69 @@ 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 ced760b76..48aeb98dd 100755
--- a/spec/unit/parser/compiler_spec.rb
+++ b/spec/unit/parser/compiler_spec.rb
@@ -32,6 +32,14 @@ class CompilerTestResource
def evaluate
end
+
+ def file
+ "/fake/file/goes/here"
+ end
+
+ def line
+ "42"
+ end
end
describe Puppet::Parser::Compiler do
@@ -413,52 +421,6 @@ describe Puppet::Parser::Compiler do
@compiler.catalog.should be_edge(@scope.resource, resource)
end
- it "should add an edge to any specified stage for class resources" do
- other_stage = resource(:stage, "other")
- @compiler.add_resource(@scope, other_stage)
- resource = resource(:class, "foo")
- resource[:stage] = 'other'
-
- @compiler.add_resource(@scope, resource)
-
- @compiler.catalog.edge?(other_stage, resource).should be_true
- end
-
- it "should fail if a non-class resource attempts to set a stage" do
- other_stage = resource(:stage, "other")
- @compiler.add_resource(@scope, other_stage)
- resource = resource(:file, "foo")
- resource[:stage] = 'other'
-
- lambda { @compiler.add_resource(@scope, resource) }.should raise_error(ArgumentError)
- end
-
- it "should fail if an unknown stage is specified" do
- resource = resource(:class, "foo")
- resource[:stage] = 'other'
-
- lambda { @compiler.add_resource(@scope, resource) }.should raise_error(ArgumentError)
- end
-
- it "should add edges from the class resources to the parent's stage if no stage is specified" do
- main = @compiler.catalog.resource(:stage, :main)
- foo_stage = resource(:stage, :foo_stage)
- @compiler.add_resource(@scope, foo_stage)
- resource = resource(:class, "foo")
- @scope.stubs(:resource).returns(:stage => :foo_stage)
- @compiler.add_resource(@scope, resource)
-
- @compiler.catalog.should be_edge(foo_stage, resource)
- end
-
- it "should add edges from top-level class resources to the main stage if no stage is specified" do
- main = @compiler.catalog.resource(:stage, :main)
- resource = resource(:class, "foo")
- @compiler.add_resource(@scope, resource)
-
- @compiler.catalog.should be_edge(main, resource)
- end
-
it "should not add non-class resources that don't specify a stage to the 'main' stage" do
main = @compiler.catalog.resource(:stage, :main)
resource = resource(:file, "foo")
diff --git a/spec/unit/parser/resource_spec.rb b/spec/unit/parser/resource_spec.rb
index b03c18e5f..0d9cba60b 100755
--- a/spec/unit/parser/resource_spec.rb
+++ b/spec/unit/parser/resource_spec.rb
@@ -131,9 +131,19 @@ describe Puppet::Parser::Resource do
end
describe "when evaluating" do
+ before do
+ @node = Puppet::Node.new "test-node"
+ @compiler = Puppet::Parser::Compiler.new @node
+ @catalog = Puppet::Resource::Catalog.new
+ source = stub('source')
+ source.stubs(:module_name)
+ @scope = Puppet::Parser::Scope.new(:compiler => @compiler, :source => source)
+ @catalog.add_resource(Puppet::Parser::Resource.new("stage", :main, :scope => @scope))
+ end
+
it "should evaluate the associated AST definition" do
definition = newdefine "mydefine"
- res = Puppet::Parser::Resource.new("mydefine", "whatever", :scope => @scope, :source => @source)
+ res = Puppet::Parser::Resource.new("mydefine", "whatever", :scope => @scope, :source => @source, :catalog => @catalog)
definition.expects(:evaluate_code).with(res)
res.evaluate
@@ -141,17 +151,65 @@ describe Puppet::Parser::Resource do
it "should evaluate the associated AST class" do
@class = newclass "myclass"
- res = Puppet::Parser::Resource.new("class", "myclass", :scope => @scope, :source => @source)
+ res = Puppet::Parser::Resource.new("class", "myclass", :scope => @scope, :source => @source, :catalog => @catalog)
@class.expects(:evaluate_code).with(res)
res.evaluate
end
it "should evaluate the associated AST node" do
nodedef = newnode("mynode")
- res = Puppet::Parser::Resource.new("node", "mynode", :scope => @scope, :source => @source)
+ res = Puppet::Parser::Resource.new("node", "mynode", :scope => @scope, :source => @source, :catalog => @catalog)
nodedef.expects(:evaluate_code).with(res)
res.evaluate
end
+
+ it "should add an edge to any specified stage for class resources" do
+ @compiler.known_resource_types.add Puppet::Resource::Type.new(:hostclass, "foo", '')
+
+ other_stage = Puppet::Parser::Resource.new(:stage, "other", :scope => @scope, :catalog => @catalog)
+ @compiler.add_resource(@scope, other_stage)
+ resource = Puppet::Parser::Resource.new(:class, "foo", :scope => @scope, :catalog => @catalog)
+ resource[:stage] = 'other'
+ @compiler.add_resource(@scope, resource)
+
+ resource.evaluate
+
+ @compiler.catalog.edge?(other_stage, resource).should be_true
+ end
+
+ it "should fail if an unknown stage is specified" do
+ @compiler.known_resource_types.add Puppet::Resource::Type.new(:hostclass, "foo", '')
+
+ resource = Puppet::Parser::Resource.new(:class, "foo", :scope => @scope, :catalog => @catalog)
+ resource[:stage] = 'other'
+
+ lambda { resource.evaluate }.should raise_error(ArgumentError, /Could not find stage other specified by/)
+ end
+
+ it "should add edges from the class resources to the parent's stage if no stage is specified" do
+ main = @compiler.catalog.resource(:stage, :main)
+ foo_stage = Puppet::Parser::Resource.new(:stage, :foo_stage, :scope => @scope, :catalog => @catalog)
+ @compiler.add_resource(@scope, foo_stage)
+ @compiler.known_resource_types.add Puppet::Resource::Type.new(:hostclass, "foo", '')
+ resource = Puppet::Parser::Resource.new(:class, "foo", :scope => @scope, :catalog => @catalog)
+ resource[:stage] = 'foo_stage'
+ @compiler.add_resource(@scope, resource)
+
+ resource.evaluate
+
+ @compiler.catalog.should be_edge(foo_stage, resource)
+ end
+
+ it "should add edges from top-level class resources to the main stage if no stage is specified" do
+ main = @compiler.catalog.resource(:stage, :main)
+ @compiler.known_resource_types.add Puppet::Resource::Type.new(:hostclass, "foo", '')
+ resource = Puppet::Parser::Resource.new(:class, "foo", :scope => @scope, :catalog => @catalog)
+ @compiler.add_resource(@scope, resource)
+
+ resource.evaluate
+
+ @compiler.catalog.should be_edge(main, resource)
+ end
end
describe "when finishing" do
diff --git a/spec/unit/parser/scope_spec.rb b/spec/unit/parser/scope_spec.rb
index bf4d1e29e..5308856ed 100755
--- a/spec/unit/parser/scope_spec.rb
+++ b/spec/unit/parser/scope_spec.rb
@@ -121,7 +121,11 @@ describe Puppet::Parser::Scope do
def create_class_scope(name)
klass = newclass(name)
- Puppet::Parser::Resource.new("class", name, :scope => @scope, :source => mock('source')).evaluate
+
+ catalog = Puppet::Resource::Catalog.new
+ catalog.add_resource(Puppet::Parser::Resource.new("stage", :main, :scope => Puppet::Parser::Scope.new))
+
+ Puppet::Parser::Resource.new("class", name, :scope => @scope, :source => mock('source'), :catalog => catalog).evaluate
@scope.class_scope(klass)
end
diff --git a/spec/unit/provider/cisco_spec.rb b/spec/unit/provider/cisco_spec.rb
new file mode 100644
index 000000000..08320731c
--- /dev/null
+++ b/spec/unit/provider/cisco_spec.rb
@@ -0,0 +1,16 @@
+#!/usr/bin/env ruby
+
+require File.dirname(__FILE__) + '/../../spec_helper'
+
+require 'puppet/provider/cisco'
+
+describe Puppet::Provider::Cisco do
+ it "should implement a device class method" do
+ Puppet::Provider::Cisco.should respond_to(:device)
+ end
+
+ it "should create a cisco device instance" do
+ Puppet::Util::NetworkDevice::Cisco::Device.expects(:new).returns :device
+ Puppet::Provider::Cisco.device(:url).should == :device
+ end
+end \ No newline at end of file
diff --git a/spec/unit/provider/interface/cisco_spec.rb b/spec/unit/provider/interface/cisco_spec.rb
index d1f70609f..c18f87cf8 100755
--- a/spec/unit/provider/interface/cisco_spec.rb
+++ b/spec/unit/provider/interface/cisco_spec.rb
@@ -8,12 +8,13 @@ provider_class = Puppet::Type.type(:interface).provider(:cisco)
describe provider_class do
before do
+ @device = stub_everything 'device'
@resource = stub("resource", :name => "Fa0/1")
- @provider = provider_class.new(@resource)
+ @provider = provider_class.new(@device, @resource)
end
- it "should have a parent of Puppet::Provider::NetworkDevice" do
- provider_class.should < Puppet::Provider::NetworkDevice
+ it "should have a parent of Puppet::Provider::Cisco" do
+ provider_class.should < Puppet::Provider::Cisco
end
it "should have an instances method" do
@@ -22,31 +23,24 @@ describe provider_class do
describe "when looking up instances at prefetch" do
before do
- @device = stub_everything 'device'
- Puppet::Util::NetworkDevice::Cisco::Device.stubs(:new).returns(@device)
@device.stubs(:command).yields(@device)
end
- it "should initialize the network device with the given url" do
- Puppet::Util::NetworkDevice::Cisco::Device.expects(:new).with(:url).returns(@device)
- provider_class.lookup(:url, "Fa0/1")
- end
-
it "should delegate to the device interface fetcher" do
@device.expects(:interface)
- provider_class.lookup("", "Fa0/1")
+ provider_class.lookup(@device, "Fa0/1")
end
it "should return the given interface data" do
@device.expects(:interface).returns({ :description => "thisone", :mode => :access})
- provider_class.lookup("", "Fa0").should == {:description => "thisone", :mode => :access }
+ provider_class.lookup(@device, "Fa0").should == {:description => "thisone", :mode => :access }
end
end
describe "when an instance is being flushed" do
it "should call the device interface update method with current and past properties" do
- @instance = provider_class.new(:ensure => :present, :name => "Fa0/1", :description => "myinterface")
+ @instance = provider_class.new(@device, :ensure => :present, :name => "Fa0/1", :description => "myinterface")
@instance.description = "newdesc"
@instance.resource = @resource
@resource.stubs(:[]).with(:name).returns("Fa0/1")
diff --git a/spec/unit/provider/network_device_spec.rb b/spec/unit/provider/network_device_spec.rb
index 83d2bdc01..e2a87cf4e 100755
--- a/spec/unit/provider/network_device_spec.rb
+++ b/spec/unit/provider/network_device_spec.rb
@@ -3,10 +3,15 @@
require File.dirname(__FILE__) + '/../../spec_helper'
require 'puppet/provider/network_device'
+require 'ostruct'
Puppet::Type.type(:vlan).provide :test, :parent => Puppet::Provider::NetworkDevice do
mk_resource_methods
- def self.lookup(device_url, name)
+ def self.lookup(device, name)
+ end
+
+ def self.device(url)
+ :device
end
end
@@ -34,7 +39,7 @@ describe provider_class do
end
it "should lookup an entry for each passed resource" do
- provider_class.expects(:lookup).with(nil, "200").returns nil
+ provider_class.expects(:lookup).with{ |device,value| value == "200" }.returns nil
provider_class.stubs(:new)
@resource.stubs(:provider=)
@@ -44,7 +49,7 @@ describe provider_class do
describe "resources that do not exist" do
it "should create a provider with :ensure => :absent" do
provider_class.stubs(:lookup).returns(nil)
- provider_class.expects(:new).with(:ensure => :absent).returns "myprovider"
+ provider_class.expects(:new).with(:device, :ensure => :absent).returns "myprovider"
@resource.expects(:provider=).with("myprovider")
provider_class.prefetch(@resources)
end
@@ -54,7 +59,7 @@ describe provider_class do
it "should create a provider with the results of the find and ensure at present" do
provider_class.stubs(:lookup).returns({ :name => "200", :description => "myvlan"})
- provider_class.expects(:new).with(:name => "200", :description => "myvlan", :ensure => :present).returns "myprovider"
+ provider_class.expects(:new).with(:device, :name => "200", :description => "myvlan", :ensure => :present).returns "myprovider"
@resource.expects(:provider=).with("myprovider")
provider_class.prefetch(@resources)
@@ -74,7 +79,7 @@ describe provider_class do
end
it "should store a copy of the hash as its vlan_properties" do
- instance = provider_class.new(:one => :two)
+ instance = provider_class.new(:device, :one => :two)
instance.former_properties.should == {:one => :two}
end
end
@@ -82,7 +87,7 @@ describe provider_class do
describe "when an instance" do
before do
- @instance = provider_class.new
+ @instance = provider_class.new(:device)
@property_class = stub 'property_class', :array_matching => :all, :superclass => Puppet::Property
@resource_class = stub 'resource_class', :attrclass => @property_class, :valid_parameter? => true, :validproperties => [:description]
@@ -98,12 +103,12 @@ describe provider_class do
end
it "should indicate when the instance already exists" do
- @instance = provider_class.new(:ensure => :present)
+ @instance = provider_class.new(:device, :ensure => :present)
@instance.exists?.should be_true
end
it "should indicate when the instance does not exist" do
- @instance = provider_class.new(:ensure => :absent)
+ @instance = provider_class.new(:device, :ensure => :absent)
@instance.exists?.should be_false
end
diff --git a/spec/unit/provider/package/pkgutil_spec.rb b/spec/unit/provider/package/pkgutil_spec.rb
new file mode 100755
index 000000000..5549b3f6d
--- /dev/null
+++ b/spec/unit/provider/package/pkgutil_spec.rb
@@ -0,0 +1,182 @@
+#!/usr/bin/env ruby
+
+require File.dirname(__FILE__) + '/../../../spec_helper'
+
+provider = Puppet::Type.type(:package).provider(:pkgutil)
+
+describe provider do
+ before(:each) do
+ @resource = Puppet::Type.type(:package).new(
+ :name => "TESTpkg",
+ :ensure => :present,
+ :provider => :pkgutil
+ )
+ @provider = provider.new(@resource)
+
+ # Stub all file and config tests
+ provider.stubs(:healthcheck)
+ end
+
+ it "should have an install method" do
+ @provider.should respond_to(:install)
+ end
+
+ it "should have a latest method" do
+ @provider.should respond_to(:uninstall)
+ end
+
+ it "should have an update method" do
+ @provider.should respond_to(:update)
+ end
+
+ it "should have a latest method" do
+ @provider.should respond_to(:latest)
+ end
+
+ describe "when installing" do
+ it "should use a command without versioned package" do
+ @resource[:ensure] = :latest
+ @provider.expects(:pkguti).with('-y', '-i', 'TESTpkg')
+ @provider.install
+ end
+ end
+
+ describe "when updating" do
+ it "should use a command without versioned package" do
+ @provider.expects(:pkguti).with('-y', '-u', 'TESTpkg')
+ @provider.update
+ end
+ end
+
+ describe "when uninstalling" do
+ it "should call the remove operation" do
+ @provider.expects(:pkguti).with('-y', '-r', 'TESTpkg')
+ @provider.uninstall
+ end
+ end
+
+ describe "when getting latest version" do
+ it "should return TESTpkg's version string" do
+ fake_data = "
+noisy output here
+TESTpkg 1.4.5,REV=2007.11.18 1.4.5,REV=2007.11.20"
+ provider.expects(:pkguti).with(['-c', '--single', 'TESTpkg']).returns fake_data
+ @provider.latest.should == "1.4.5,REV=2007.11.20"
+ end
+
+ it "should handle TESTpkg's 'SAME' version string" do
+ fake_data = "
+noisy output here
+TESTpkg 1.4.5,REV=2007.11.18 SAME"
+ provider.expects(:pkguti).with(['-c', '--single', 'TESTpkg']).returns fake_data
+ @provider.latest.should == "1.4.5,REV=2007.11.18"
+ end
+
+ it "should handle a non-existent package" do
+ fake_data = "noisy output here
+Not in catalog"
+ provider.expects(:pkguti).with(['-c', '--single', 'TESTpkg']).returns fake_data
+ @provider.latest.should == nil
+ end
+
+ it "should warn on unknown pkgutil noise" do
+ provider.expects(:pkguti).with(['-c', '--single', 'TESTpkg']).returns("testingnoise")
+ @provider.latest.should == nil
+ end
+
+ it "should ignore pkgutil noise/headers to find TESTpkg" do
+ fake_data = "# stuff
+=> Fetching new catalog and descriptions (http://mirror.opencsw.org/opencsw/unstable/i386/5.11) if available ...
+2011-02-19 23:05:46 URL:http://mirror.opencsw.org/opencsw/unstable/i386/5.11/catalog [534635/534635] -> \"/var/opt/csw/pkgutil/catalog.mirror.opencsw.org_opencsw_unstable_i386_5.11.tmp\" [1]
+Checking integrity of /var/opt/csw/pkgutil/catalog.mirror.opencsw.org_opencsw_unstable_i386_5.11 with gpg.
+gpg: Signature made February 17, 2011 05:27:53 PM GMT using DSA key ID E12E9D2F
+gpg: Good signature from \"Distribution Manager <dm@blastwave.org>\"
+==> 2770 packages loaded from /var/opt/csw/pkgutil/catalog.mirror.opencsw.org_opencsw_unstable_i386_5.11
+package installed catalog
+TESTpkg 1.4.5,REV=2007.11.18 1.4.5,REV=2007.11.20"
+ provider.expects(:pkguti).with(['-c', '--single', 'TESTpkg']).returns fake_data
+ @provider.latest.should == "1.4.5,REV=2007.11.20"
+ end
+
+ it "should find REALpkg via an alias (TESTpkg)" do
+ fake_data = "
+noisy output here
+REALpkg 1.4.5,REV=2007.11.18 1.4.5,REV=2007.11.20"
+ provider.expects(:pkguti).with(['-c', '--single', 'TESTpkg']).returns fake_data
+ @provider.query[:name].should == "TESTpkg"
+ end
+ end
+
+ describe "when querying current version" do
+ it "should return TESTpkg's version string" do
+ fake_data = "TESTpkg 1.4.5,REV=2007.11.18 1.4.5,REV=2007.11.20"
+ provider.expects(:pkguti).with(['-c', '--single', 'TESTpkg']).returns fake_data
+ @provider.query[:ensure].should == "1.4.5,REV=2007.11.18"
+ end
+
+ it "should handle a package that isn't installed" do
+ fake_data = "TESTpkg notinst 1.4.5,REV=2007.11.20"
+ provider.expects(:pkguti).with(['-c', '--single', 'TESTpkg']).returns fake_data
+ @provider.query[:ensure].should == :absent
+ end
+
+ it "should handle a non-existent package" do
+ fake_data = "noisy output here
+Not in catalog"
+ provider.expects(:pkguti).with(['-c', '--single', 'TESTpkg']).returns fake_data
+ @provider.query[:ensure].should == :absent
+ end
+ end
+
+ describe "when querying current instances" do
+ it "should warn on unknown pkgutil noise" do
+ provider.expects(:pkguti).with(['-a']).returns("testingnoise")
+ provider.expects(:pkguti).with(['-c']).returns("testingnoise")
+ Puppet.expects(:warning).times(2)
+ provider.expects(:new).never
+ provider.instances.should == []
+ end
+
+ it "should return TESTpkg's version string" do
+ fake_data = "TESTpkg TESTpkg 1.4.5,REV=2007.11.20"
+ provider.expects(:pkguti).with(['-a']).returns fake_data
+
+ fake_data = "TESTpkg 1.4.5,REV=2007.11.18 1.4.5,REV=2007.11.20"
+ provider.expects(:pkguti).with(['-c']).returns fake_data
+
+ testpkg = mock 'pkg1'
+ provider.expects(:new).with(:ensure => "1.4.5,REV=2007.11.18", :name => "TESTpkg", :provider => :pkgutil).returns testpkg
+ provider.instances.should == [testpkg]
+ end
+
+ it "should also return both TESTpkg and mypkg alias instances" do
+ fake_data = "mypkg TESTpkg 1.4.5,REV=2007.11.20"
+ provider.expects(:pkguti).with(['-a']).returns fake_data
+
+ fake_data = "TESTpkg 1.4.5,REV=2007.11.18 1.4.5,REV=2007.11.20"
+ provider.expects(:pkguti).with(['-c']).returns fake_data
+
+ testpkg = mock 'pkg1'
+ provider.expects(:new).with(:ensure => "1.4.5,REV=2007.11.18", :name => "TESTpkg", :provider => :pkgutil).returns testpkg
+
+ aliaspkg = mock 'pkg2'
+ provider.expects(:new).with(:ensure => "1.4.5,REV=2007.11.18", :name => "mypkg", :provider => :pkgutil).returns aliaspkg
+
+ provider.instances.should == [testpkg,aliaspkg]
+ end
+
+ it "shouldn't mind noise in the -a output" do
+ fake_data = "noisy output here"
+ provider.expects(:pkguti).with(['-a']).returns fake_data
+
+ fake_data = "TESTpkg 1.4.5,REV=2007.11.18 1.4.5,REV=2007.11.20"
+ provider.expects(:pkguti).with(['-c']).returns fake_data
+
+ testpkg = mock 'pkg1'
+ provider.expects(:new).with(:ensure => "1.4.5,REV=2007.11.18", :name => "TESTpkg", :provider => :pkgutil).returns testpkg
+
+ provider.instances.should == [testpkg]
+ end
+ end
+
+end
diff --git a/spec/unit/provider/vlan/cisco_spec.rb b/spec/unit/provider/vlan/cisco_spec.rb
index bb243a75e..a67290eb4 100755
--- a/spec/unit/provider/vlan/cisco_spec.rb
+++ b/spec/unit/provider/vlan/cisco_spec.rb
@@ -8,12 +8,13 @@ provider_class = Puppet::Type.type(:vlan).provider(:cisco)
describe provider_class do
before do
+ @device = stub_everything 'device'
@resource = stub("resource", :name => "200")
- @provider = provider_class.new(@resource)
+ @provider = provider_class.new(@device, @resource)
end
- it "should have a parent of Puppet::Provider::NetworkDevice" do
- provider_class.should < Puppet::Provider::NetworkDevice
+ it "should have a parent of Puppet::Provider::Cisco" do
+ provider_class.should < Puppet::Provider::Cisco
end
it "should have an instances method" do
@@ -22,31 +23,24 @@ describe provider_class do
describe "when looking up instances at prefetch" do
before do
- @device = stub_everything 'device'
- Puppet::Util::NetworkDevice::Cisco::Device.stubs(:new).returns(@device)
@device.stubs(:command).yields(@device)
end
- it "should initialize the network device with the given url" do
- Puppet::Util::NetworkDevice::Cisco::Device.expects(:new).with(:url).returns(@device)
- provider_class.lookup(:url, "200")
- end
-
it "should delegate to the device vlans" do
@device.expects(:parse_vlans)
- provider_class.lookup("", "200")
+ provider_class.lookup(@device, "200")
end
it "should return only the given vlan" do
@device.expects(:parse_vlans).returns({"200" => { :description => "thisone" }, "1" => { :description => "nothisone" }})
- provider_class.lookup("", "200").should == {:description => "thisone" }
+ provider_class.lookup(@device, "200").should == {:description => "thisone" }
end
end
describe "when an instance is being flushed" do
it "should call the device update_vlan method with its vlan id, current attributes, and desired attributes" do
- @instance = provider_class.new(:ensure => :present, :name => "200", :description => "myvlan")
+ @instance = provider_class.new(@device, :ensure => :present, :name => "200", :description => "myvlan")
@instance.description = "myvlan2"
@instance.resource = @resource
@resource.stubs(:[]).with(:name).returns("200")
diff --git a/spec/unit/resource/catalog_spec.rb b/spec/unit/resource/catalog_spec.rb
index ae65aa91a..ebf523eab 100755
--- a/spec/unit/resource/catalog_spec.rb
+++ b/spec/unit/resource/catalog_spec.rb
@@ -592,6 +592,7 @@ describe Puppet::Resource::Catalog, "when compiling" do
Puppet::Transaction.stubs(:new).returns(@transaction)
@transaction.stubs(:evaluate)
@transaction.stubs(:add_times)
+ @transaction.stubs(:for_network_device=)
Puppet.settings.stubs(:use)
end
diff --git a/spec/unit/transaction_spec.rb b/spec/unit/transaction_spec.rb
index 4157e58ac..d7788c06c 100755
--- a/spec/unit/transaction_spec.rb
+++ b/spec/unit/transaction_spec.rb
@@ -270,6 +270,24 @@ describe Puppet::Transaction do
@resource.stubs(:virtual?).returns true
@transaction.should be_skip(@resource)
end
+
+ it "should skip device only resouce on normal host" do
+ @resource.stubs(:appliable_to_device?).returns true
+ @transaction.for_network_device = false
+ @transaction.should be_skip(@resource)
+ end
+
+ it "should not skip device only resouce on remote device" do
+ @resource.stubs(:appliable_to_device?).returns true
+ @transaction.for_network_device = true
+ @transaction.should_not be_skip(@resource)
+ end
+
+ it "should skip host resouce on device" do
+ @resource.stubs(:appliable_to_device?).returns false
+ @transaction.for_network_device = true
+ @transaction.should be_skip(@resource)
+ end
end
describe "when determining if tags are missing" do
diff --git a/spec/unit/type/interface_spec.rb b/spec/unit/type/interface_spec.rb
index 68f4c765f..12ba225d9 100755
--- a/spec/unit/type/interface_spec.rb
+++ b/spec/unit/type/interface_spec.rb
@@ -3,6 +3,7 @@
require File.dirname(__FILE__) + '/../../spec_helper'
describe Puppet::Type.type(:interface) do
+
it "should have a 'name' parameter'" do
Puppet::Type.type(:interface).new(:name => "FastEthernet 0/1")[:name].should == "FastEthernet 0/1"
end
@@ -15,6 +16,10 @@ describe Puppet::Type.type(:interface) do
Puppet::Type.type(:interface).attrtype(:ensure).should == :property
end
+ it "should be applied on device" do
+ Puppet::Type.type(:interface).new(:name => "FastEthernet 0/1").should be_appliable_to_device
+ end
+
[:description, :speed, :duplex, :native_vlan, :encapsulation, :mode, :allowed_trunk_vlans, :etherchannel, :ipaddress].each do |p|
it "should have a #{p} property" do
Puppet::Type.type(:interface).attrtype(p).should == :property
diff --git a/spec/unit/type/schedule_spec.rb b/spec/unit/type/schedule_spec.rb
index 7599411e4..33064ca6f 100755
--- a/spec/unit/type/schedule_spec.rb
+++ b/spec/unit/type/schedule_spec.rb
@@ -36,6 +36,14 @@ describe Puppet::Type.type(:schedule) do
describe Puppet::Type.type(:schedule) do
include ScheduleTesting
+ it "should apply to device" do
+ @schedule.should be_appliable_to_device
+ end
+
+ it "should apply to host" do
+ @schedule.should be_appliable_to_host
+ end
+
it "should default to :distance for period-matching" do
@schedule[:periodmatch].should == :distance
end
diff --git a/spec/unit/type/vlan_spec.rb b/spec/unit/type/vlan_spec.rb
index 2983a58e9..3bee14bbd 100755
--- a/spec/unit/type/vlan_spec.rb
+++ b/spec/unit/type/vlan_spec.rb
@@ -3,6 +3,7 @@
require File.dirname(__FILE__) + '/../../spec_helper'
describe Puppet::Type.type(:vlan) do
+
it "should have a 'name' parameter'" do
Puppet::Type.type(:vlan).new(:name => "200")[:name].should == "200"
end
@@ -11,6 +12,10 @@ describe Puppet::Type.type(:vlan) do
Puppet::Type.type(:vlan).new(:name => "200", :device_url => :device)[:device_url].should == :device
end
+ it "should be applied on device" do
+ Puppet::Type.type(:vlan).new(:name => "200").should be_appliable_to_device
+ end
+
it "should have an ensure property" do
Puppet::Type.type(:vlan).attrtype(:ensure).should == :property
end
diff --git a/spec/unit/util/network_device/cisco/device_spec.rb b/spec/unit/util/network_device/cisco/device_spec.rb
index 82b0666e6..33242a1ab 100755
--- a/spec/unit/util/network_device/cisco/device_spec.rb
+++ b/spec/unit/util/network_device/cisco/device_spec.rb
@@ -392,130 +392,17 @@ eos
@cisco.parse_interface_config("Gi0/17").should == {:etherchannel=>"1"}
end
end
+
+ describe "when finding device facts" do
+ it "should delegate to the cisco facts entity" do
+ facts = stub 'facts'
+ Puppet::Util::NetworkDevice::Cisco::Facts.expects(:new).returns(facts)
+
+ facts.expects(:retrieve).returns(:facts)
+
+ @cisco.facts.should == :facts
+ end
+ end
+
end
-# static access
-# Switch#sh interfaces FastEthernet 0/1 switchport
-# Name: Fa0/1
-# Switchport: Enabled
-# Administrative mode: static access
-# Operational Mode: static access
-# Administrative Trunking Encapsulation: isl
-# Operational Trunking Encapsulation: isl
-# Negotiation of Trunking: Disabled
-# Access Mode VLAN: 100 (SHDSL)
-# Trunking Native Mode VLAN: 1 (default)
-# Trunking VLANs Enabled: NONE
-# Pruning VLANs Enabled: NONE
-#
-# Priority for untagged frames: 0
-# Override vlan tag priority: FALSE
-# Voice VLAN: none
-# Appliance trust: none
-# Self Loopback: No
-# Switch#
-
-# c2960#sh interfaces GigabitEthernet 0/1 switchport
-# Name: Gi0/1
-# Switchport: Enabled
-# Administrative Mode: trunk
-# Operational Mode: trunk
-# Administrative Trunking Encapsulation: dot1q
-# Operational Trunking Encapsulation: dot1q
-# Negotiation of Trunking: On
-# Access Mode VLAN: 1 (default)
-# Trunking Native Mode VLAN: 1 (default)
-# Administrative Native VLAN tagging: enabled
-# Voice VLAN: none
-# Administrative private-vlan host-association: none
-# Administrative private-vlan mapping: none
-# Administrative private-vlan trunk native VLAN: none
-# Administrative private-vlan trunk Native VLAN tagging: enabled
-# Administrative private-vlan trunk encapsulation: dot1q
-# Administrative private-vlan trunk normal VLANs: none
-# Administrative private-vlan trunk associations: none
-# Administrative private-vlan trunk mappings: none
-# Operational private-vlan: none
-# Trunking VLANs Enabled: 1,99
-# Pruning VLANs Enabled: 2-1001
-# Capture Mode Disabled
-# Capture VLANs Allowed: ALL
-#
-# Protected: false
-# Unknown unicast blocked: disabled
-# Unknown multicast blocked: disabled
-# Appliance trust: none
-# c2960#
-
-# c2960#sh interfaces GigabitEthernet 0/2 switchport
-# Name: Gi0/2
-# Switchport: Enabled
-# Administrative Mode: static access
-# Operational Mode: static access
-# Administrative Trunking Encapsulation: dot1q
-# Operational Trunking Encapsulation: native
-# Negotiation of Trunking: Off
-# Access Mode VLAN: 99 (MGMT)
-# Trunking Native Mode VLAN: 1 (default)
-# Administrative Native VLAN tagging: enabled
-# Voice VLAN: none
-# Administrative private-vlan host-association: none
-# Administrative private-vlan mapping: none
-# Administrative private-vlan trunk native VLAN: none
-# Administrative private-vlan trunk Native VLAN tagging: enabled
-# Administrative private-vlan trunk encapsulation: dot1q
-# Administrative private-vlan trunk normal VLANs: none
-# Administrative private-vlan trunk associations: none
-# Administrative private-vlan trunk mappings: none
-# Operational private-vlan: none
-# Trunking VLANs Enabled: ALL
-# Pruning VLANs Enabled: 2-1001
-# Capture Mode Disabled
-# Capture VLANs Allowed: ALL
-#
-# Protected: false
-# Unknown unicast blocked: disabled
-# Unknown multicast blocked: disabled
-# Appliance trust: none
-# c2960#
-
-# c877#sh interfaces FastEthernet 1 switchport
-# Name: Fa1
-# Switchport: Enabled
-# Administrative Mode: trunk
-# Operational Mode: trunk
-# Administrative Trunking Encapsulation: dot1q
-# Operational Trunking Encapsulation: dot1q
-# Negotiation of Trunking: Disabled
-# Access Mode VLAN: 0 ((Inactive))
-# Trunking Native Mode VLAN: 1 (default)
-# Trunking VLANs Enabled: ALL
-# Trunking VLANs Active: 1
-# Protected: false
-# Priority for untagged frames: 0
-# Override vlan tag priority: FALSE
-# Voice VLAN: none
-# Appliance trust: none
-
-
-# c2960#sh etherchannel summary
-# Flags: D - down P - bundled in port-channel
-# I - stand-alone s - suspended
-# H - Hot-standby (LACP only)
-# R - Layer3 S - Layer2
-# U - in use f - failed to allocate aggregator
-#
-# M - not in use, minimum links not met
-# u - unsuitable for bundling
-# w - waiting to be aggregated
-# d - default port
-#
-#
-# Number of channel-groups in use: 1
-# Number of aggregators: 1
-#
-# Group Port-channel Protocol Ports
-# ------+-------------+-----------+-----------------------------------------------
-# 1 Po1(SU) LACP Gi0/17(P) Gi0/18(P)
-#
-# c2960#
diff --git a/spec/unit/util/network_device/cisco/facts_spec.rb b/spec/unit/util/network_device/cisco/facts_spec.rb
new file mode 100644
index 000000000..bb29ac292
--- /dev/null
+++ b/spec/unit/util/network_device/cisco/facts_spec.rb
@@ -0,0 +1,63 @@
+#!/usr/bin/env ruby
+
+require File.dirname(__FILE__) + '/../../../../spec_helper'
+
+require 'puppet/util/network_device'
+require 'puppet/util/network_device/cisco/facts'
+
+describe Puppet::Util::NetworkDevice::Cisco::Facts do
+ before(:each) do
+ @transport = stub_everything 'transport'
+ @facts = Puppet::Util::NetworkDevice::Cisco::Facts.new(@transport)
+ end
+
+ {
+ "cisco WS-C2924C-XL (PowerPC403GA) processor (revision 0x11) with 8192K/1024K bytes of memory." => {:hardwaremodel => "WS-C2924C-XL", :memorysize => "8192K", :processor => "PowerPC403GA", :hardwarerevision => "0x11" },
+ "Cisco 1841 (revision 5.0) with 355328K/37888K bytes of memory." => {:hardwaremodel=>"1841", :memorysize => "355328K", :hardwarerevision => "5.0" },
+ "Cisco 877 (MPC8272) processor (revision 0x200) with 118784K/12288K bytes of memory." => {:hardwaremodel=>"877", :memorysize => "118784K", :processor => "MPC8272", :hardwarerevision => "0x200" },
+ "cisco WS-C2960G-48TC-L (PowerPC405) processor (revision C0) with 61440K/4088K bytes of memory." => {:hardwaremodel=>"WS-C2960G-48TC-L", :memorysize => "61440K", :processor => "PowerPC405", :hardwarerevision => "C0" },
+ "cisco WS-C2950T-24 (RC32300) processor (revision R0) with 19959K bytes of memory." => {:hardwaremodel=>"WS-C2950T-24", :memorysize => "19959K", :processor => "RC32300", :hardwarerevision => "R0" }
+ }.each do |ver, expected|
+ it "should parse show ver output for hardware device facts" do
+ @transport.stubs(:command).with("sh ver").returns(<<eos)
+Switch>sh ver
+#{ver}
+Switch>
+eos
+ @facts.parse_show_ver.should == expected
+ end
+ end
+
+ {
+"Switch uptime is 1 year, 12 weeks, 6 days, 22 hours, 32 minutes" => { :hostname => "Switch", :uptime => "1 year, 12 weeks, 6 days, 22 hours, 32 minutes", :uptime_seconds => 39393120, :uptime_days => 455 },
+"c2950 uptime is 3 weeks, 1 day, 23 hours, 36 minutes" => { :hostname => "c2950", :uptime => "3 weeks, 1 day, 23 hours, 36 minutes", :uptime_days => 22, :uptime_seconds => 1985760},
+"router uptime is 5 weeks, 1 day, 3 hours, 30 minutes" => { :hostname => "router", :uptime => "5 weeks, 1 day, 3 hours, 30 minutes", :uptime_days => 36, :uptime_seconds => 3123000 },
+"c2950 uptime is 1 minute" => { :hostname => "c2950", :uptime => "1 minute", :uptime_days => 0, :uptime_seconds => 60 }
+ }.each do |ver, expected|
+ it "should parse show ver output for device uptime facts" do
+ @transport.stubs(:command).with("sh ver").returns(<<eos)
+Switch>sh ver
+#{ver}
+Switch>
+eos
+ @facts.parse_show_ver.should == expected
+ end
+ end
+
+ {
+"IOS (tm) C2900XL Software (C2900XL-C3H2S-M), Version 12.0(5)WC10, RELEASE SOFTWARE (fc1)"=> { :operatingsystem => "IOS", :operatingsystemrelease => "12.0(5)WC10", :operatingsystemmajrelease => "12.0WC", :operatingsystemfeature => "C3H2S"},
+"IOS (tm) C2950 Software (C2950-I6K2L2Q4-M), Version 12.1(22)EA8a, RELEASE SOFTWARE (fc1)"=> { :operatingsystem => "IOS", :operatingsystemrelease => "12.1(22)EA8a", :operatingsystemmajrelease => "12.1EA", :operatingsystemfeature => "I6K2L2Q4"},
+"Cisco IOS Software, C2960 Software (C2960-LANBASEK9-M), Version 12.2(44)SE, RELEASE SOFTWARE (fc1)"=>{ :operatingsystem => "IOS", :operatingsystemrelease => "12.2(44)SE", :operatingsystemmajrelease => "12.2SE", :operatingsystemfeature => "LANBASEK9"},
+"Cisco IOS Software, C870 Software (C870-ADVIPSERVICESK9-M), Version 12.4(11)XJ4, RELEASE SOFTWARE (fc2)"=>{ :operatingsystem => "IOS", :operatingsystemrelease => "12.4(11)XJ4", :operatingsystemmajrelease => "12.4XJ", :operatingsystemfeature => "ADVIPSERVICESK9"},
+"Cisco IOS Software, 1841 Software (C1841-ADVSECURITYK9-M), Version 12.4(24)T4, RELEASE SOFTWARE (fc2)" =>{ :operatingsystem => "IOS", :operatingsystemrelease => "12.4(24)T4", :operatingsystemmajrelease => "12.4T", :operatingsystemfeature => "ADVSECURITYK9"},
+ }.each do |ver, expected|
+ it "should parse show ver output for device software version facts" do
+ @transport.stubs(:command).with("sh ver").returns(<<eos)
+Switch>sh ver
+#{ver}
+Switch>
+eos
+ @facts.parse_show_ver.should == expected
+ end
+ end
+end
diff --git a/spec/unit/util/network_device/config_spec.rb b/spec/unit/util/network_device/config_spec.rb
new file mode 100644
index 000000000..52796f30b
--- /dev/null
+++ b/spec/unit/util/network_device/config_spec.rb
@@ -0,0 +1,102 @@
+#!/usr/bin/env ruby
+
+require File.dirname(__FILE__) + '/../../../spec_helper'
+
+require 'puppet/util/network_device/config'
+
+describe Puppet::Util::NetworkDevice::Config do
+ before(:each) do
+ Puppet[:deviceconfig] = "/dummy"
+ FileTest.stubs(:exists?).with("/dummy").returns(true)
+ end
+
+ describe "when initializing" do
+ before :each do
+ Puppet::Util::NetworkDevice::Config.any_instance.stubs(:read)
+ end
+
+ it "should use the deviceconfig setting as pathname" do
+ Puppet.expects(:[]).with(:deviceconfig).returns("/dummy")
+
+ Puppet::Util::NetworkDevice::Config.new
+ end
+
+ it "should raise an error if no file is defined finally" do
+ Puppet.expects(:[]).with(:deviceconfig).returns(nil)
+
+ lambda { Puppet::Util::NetworkDevice::Config.new }.should raise_error(Puppet::DevError)
+ end
+
+ it "should read and parse the file" do
+ Puppet::Util::NetworkDevice::Config.any_instance.expects(:read)
+
+ Puppet::Util::NetworkDevice::Config.new
+ end
+ end
+
+ describe "when parsing device" do
+ before :each do
+ @config = Puppet::Util::NetworkDevice::Config.new
+ @config.stubs(:changed?).returns(true)
+ @fd = stub 'fd'
+ File.stubs(:open).yields(@fd)
+ end
+
+ it "should skip comments" do
+ @fd.stubs(:each).yields(' # comment')
+
+ OpenStruct.expects(:new).never
+
+ @config.read
+ end
+
+ it "should increment line number even on commented lines" do
+ @fd.stubs(:each).multiple_yields(' # comment','[router.puppetlabs.com]')
+
+ @config.read
+ @config.devices.should be_include('router.puppetlabs.com')
+ end
+
+ it "should skip blank lines" do
+ @fd.stubs(:each).yields(' ')
+
+ @config.read
+ @config.devices.should be_empty
+ end
+
+ it "should produce the correct line number" do
+ @fd.stubs(:each).multiple_yields(' ', '[router.puppetlabs.com]')
+
+ @config.read
+ @config.devices['router.puppetlabs.com'].line.should == 2
+ end
+
+ it "should throw an error if the current device already exists" do
+ @fd.stubs(:each).multiple_yields('[router.puppetlabs.com]', '[router.puppetlabs.com]')
+
+ lambda { @config.read }.should raise_error
+ end
+
+ it "should create a new device for each found device line" do
+ @fd.stubs(:each).multiple_yields('[router.puppetlabs.com]', '[swith.puppetlabs.com]')
+
+ @config.read
+ @config.devices.size.should == 2
+ end
+
+ it "should parse the device type" do
+ @fd.stubs(:each).multiple_yields('[router.puppetlabs.com]', 'type cisco')
+
+ @config.read
+ @config.devices['router.puppetlabs.com'].provider.should == 'cisco'
+ end
+
+ it "should parse the device url" do
+ @fd.stubs(:each).multiple_yields('[router.puppetlabs.com]', 'type cisco', 'url ssh://test/')
+
+ @config.read
+ @config.devices['router.puppetlabs.com'].url.should == 'ssh://test/'
+ end
+ end
+
+end \ No newline at end of file
diff --git a/spec/unit/util/network_device/transport/ssh_spec.rb b/spec/unit/util/network_device/transport/ssh_spec.rb
index 0e91ed9f9..18d22a953 100755
--- a/spec/unit/util/network_device/transport/ssh_spec.rb
+++ b/spec/unit/util/network_device/transport/ssh_spec.rb
@@ -30,6 +30,14 @@ describe Puppet::Util::NetworkDevice::Transport::Ssh, :if => Puppet.features.ssh
@transport.connect
end
+ it "should raise a Puppet::Error when encountering an authentication failure" do
+ Net::SSH.expects(:start).raises Net::SSH::AuthenticationFailed
+ @transport.host = "localhost"
+ @transport.user = "user"
+
+ lambda { @transport.connect }.should raise_error Puppet::Error
+ end
+
describe "when connected" do
before(:each) do
@ssh = stub_everything 'ssh'
diff --git a/spec/unit/util/network_device_spec.rb b/spec/unit/util/network_device_spec.rb
new file mode 100644
index 000000000..0f7c6036b
--- /dev/null
+++ b/spec/unit/util/network_device_spec.rb
@@ -0,0 +1,50 @@
+#!/usr/bin/env rspec
+require 'spec_helper'
+
+require 'ostruct'
+require 'puppet/util/network_device'
+
+describe Puppet::Util::NetworkDevice do
+
+ before(:each) do
+ @device = OpenStruct.new(:name => "name", :provider => "test")
+ end
+
+ after(:each) do
+ Puppet::Util::NetworkDevice.teardown
+ end
+
+ class Puppet::Util::NetworkDevice::Test
+ class Device
+ def initialize(device)
+ end
+ end
+ end
+
+ describe "when initializing the remote network device singleton" do
+ it "should load the network device code" do
+ Puppet::Util::NetworkDevice.expects(:require)
+ Puppet::Util::NetworkDevice.init(@device)
+ end
+
+ it "should create a network device instance" do
+ Puppet::Util::NetworkDevice.stubs(:require)
+ Puppet::Util::NetworkDevice::Test::Device.expects(:new)
+ Puppet::Util::NetworkDevice.init(@device)
+ end
+
+ it "should raise an error if the remote device instance can't be created" do
+ Puppet::Util::NetworkDevice.stubs(:require).raises("error")
+ lambda { Puppet::Util::NetworkDevice.init(@device) }.should raise_error
+ end
+
+ it "should let caller to access the singleton device" do
+ device = stub 'device'
+ Puppet::Util::NetworkDevice.stubs(:require)
+ Puppet::Util::NetworkDevice::Test::Device.expects(:new).returns(device)
+ Puppet::Util::NetworkDevice.init(@device)
+
+ Puppet::Util::NetworkDevice.current.should == device
+ end
+ end
+end
diff --git a/spec/unit/util/queue/stomp_spec.rb b/spec/unit/util/queue/stomp_spec.rb
index f67189cf5..99c77d0b4 100755
--- a/spec/unit/util/queue/stomp_spec.rb
+++ b/spec/unit/util/queue/stomp_spec.rb
@@ -63,26 +63,26 @@ describe 'Puppet::Util::Queue::Stomp', :if => Puppet.features.stomp? do
end
end
- describe "when sending a message" do
+ describe "when publishing a message" do
before do
@client = stub 'client'
Stomp::Client.stubs(:new).returns @client
@queue = Puppet::Util::Queue::Stomp.new
end
- it "should send it to the queue client instance" do
- @client.expects(:send).with { |queue, msg, options| msg == "Smite!" }
- @queue.send_message('fooqueue', 'Smite!')
+ it "should publish it to the queue client instance" do
+ @client.expects(:publish).with { |queue, msg, options| msg == "Smite!" }
+ @queue.publish_message('fooqueue', 'Smite!')
end
- it "should send it to the transformed queue name" do
- @client.expects(:send).with { |queue, msg, options| queue == "/queue/fooqueue" }
- @queue.send_message('fooqueue', 'Smite!')
+ it "should publish it to the transformed queue name" do
+ @client.expects(:publish).with { |queue, msg, options| queue == "/queue/fooqueue" }
+ @queue.publish_message('fooqueue', 'Smite!')
end
- it "should send it as a persistent message" do
- @client.expects(:send).with { |queue, msg, options| options[:persistent] == true }
- @queue.send_message('fooqueue', 'Smite!')
+ it "should publish it as a persistent message" do
+ @client.expects(:publish).with { |queue, msg, options| options[:persistent] == true }
+ @queue.publish_message('fooqueue', 'Smite!')
end
end
diff --git a/spec/watchr.rb b/spec/watchr.rb
index 26919d1a1..c0f1d0257 100755
--- a/spec/watchr.rb
+++ b/spec/watchr.rb
@@ -85,7 +85,11 @@ def run_spec_files(files)
else
opts = File.readlines('spec/spec.opts').collect { |l| l.chomp }.join(" ")
end
- run_spec("rspec #{opts} --tty #{files.join(' ')}")
+ begin
+ run_spec("rspec #{opts} --tty #{files.join(' ')}")
+ rescue => detail
+ puts "Failed to load #{files}: #{detail}"
+ end
end
def run_all_tests