[Pkg-puppet-devel] [facter] 169/352: (FACT-65) Extract Resolvable and Suitable mixins
Stig Sandbeck Mathisen
ssm at debian.org
Sun Apr 6 22:21:42 UTC 2014
This is an automated email from the git hooks/post-receive script.
ssm pushed a commit to branch master
in repository facter.
commit 8f45e7193ba4231f54e112c8bc9ae111e700c2be
Author: Adrien Thebo <git at somethingsinistral.net>
Date: Tue Jan 7 13:59:20 2014 -0800
(FACT-65) Extract Resolvable and Suitable mixins
The Facter::Util::Resolution class contained behavior for determining if
a resolution was suitable, the precedence of the resolution, code for
safely resolving values, and code for actually resolving information.
This commit breaks up the Resolution class into a Suitable mixin for
determining if a resolution can run and the precedence of that
resolution, and a Resolvable mixin for handling behavior around the
resolution of a given fact.
---
lib/facter/core/resolvable.rb | 96 ++++++++++++++++++
lib/facter/core/suitable.rb | 80 +++++++++++++++
lib/facter/util/resolution.rb | 178 ++++-----------------------------
spec/unit/core/resolvable_spec.rb | 116 ++++++++++++++++++++++
spec/unit/core/suitable_spec.rb | 70 +++++++++++++
spec/unit/util/resolution_spec.rb | 202 +-------------------------------------
6 files changed, 384 insertions(+), 358 deletions(-)
diff --git a/lib/facter/core/resolvable.rb b/lib/facter/core/resolvable.rb
new file mode 100644
index 0000000..420e0ab
--- /dev/null
+++ b/lib/facter/core/resolvable.rb
@@ -0,0 +1,96 @@
+require 'timeout'
+
+# The resolvable mixin defines behavior for evaluating and returning fact
+# resolutions.
+#
+# Classes including this mixin should implement at #name method describing
+# the value being resolved and a #resolve_value that actually executes the code
+# to resolve the value.
+module Facter::Core::Resolvable
+
+ # The timeout, in seconds, for evaluating this resolution.
+ # @return [Integer]
+ # @api public
+ attr_accessor :timeout
+
+ # Return the timeout period for resolving a value.
+ # (see #timeout)
+ # @return [Numeric]
+ # @comment requiring 'timeout' stdlib class causes Object#timeout to be
+ # defined which delegates to Timeout.timeout. This method may potentially
+ # overwrite the #timeout attr_reader on this class, so we define #limit to
+ # avoid conflicts.
+ def limit
+ @timeout || 0
+ end
+
+ ##
+ # on_flush accepts a block and executes the block when the resolution's value
+ # is flushed. This makes it possible to model a single, expensive system
+ # call inside of a Ruby object and then define multiple dynamic facts which
+ # resolve by sending messages to the model instance. If one of the dynamic
+ # facts is flushed then it can, in turn, flush the data stored in the model
+ # instance to keep all of the dynamic facts in sync without making multiple,
+ # expensive, system calls.
+ #
+ # Please see the Solaris zones fact for an example of how this feature may be
+ # used.
+ #
+ # @see Facter::Util::Fact#flush
+ # @see Facter::Util::Resolution#flush
+ #
+ # @api public
+ def on_flush(&block)
+ @on_flush_block = block
+ end
+
+ ##
+ # flush executes the block, if any, stored by the {on_flush} method
+ #
+ # @see Facter::Util::Fact#flush
+ # @see Facter::Util::Resolution#on_flush
+ #
+ # @api private
+ def flush
+ @on_flush_block.call if @on_flush_block
+ end
+
+ def value
+ result = nil
+
+ with_timing do
+ Timeout.timeout(limit) do
+ result = resolve_value
+ end
+ end
+
+ Facter::Util::Normalization.normalize(result)
+
+ rescue Timeout::Error => detail
+ Facter.warn "Timed out seeking value for #{self.name}"
+
+ # This call avoids zombies -- basically, create a thread that will
+ # dezombify all of the child processes that we're ignoring because
+ # of the timeout.
+ Thread.new { Process.waitall }
+ return nil
+ rescue Facter::Util::Normalization::NormalizationError => e
+ Facter.warn "Fact resolution #{self.name} resolved to an invalid value: #{e.message}"
+ return nil
+ rescue => details
+ Facter.warn "Could not retrieve #{self.name}: #{details.message}"
+ return nil
+ end
+
+ private
+
+ def with_timing
+ starttime = Time.now.to_f
+
+ yield
+
+ finishtime = Time.now.to_f
+ ms = (finishtime - starttime) * 1000
+ Facter.show_time "#{self.name}: #{"%.2f" % ms}ms"
+ end
+end
diff --git a/lib/facter/core/suitable.rb b/lib/facter/core/suitable.rb
new file mode 100644
index 0000000..3f4a7bc
--- /dev/null
+++ b/lib/facter/core/suitable.rb
@@ -0,0 +1,80 @@
+require 'facter'
+
+# The Suitable mixin provides mechanisms for confining objects to run on
+# certain platforms and determining the run precedence of these objects.
+#
+# Classes that include the Suitable mixin should define a `#confines` method
+# that returns an Array of zero or more Facter::Util::Confine objects.
+module Facter::Core::Suitable
+
+ attr_writer :weight
+
+ # Sets the weight of this resolution. If multiple suitable resolutions
+ # are found, the one with the highest weight will be used. If weight
+ # is not given, the number of confines set on a resolution will be
+ # used as its weight (so that the most specific resolution is used).
+ #
+ # @param weight [Integer] the weight of this resolution
+ #
+ # @return [void]
+ #
+ # @api public
+ def has_weight(weight)
+ @weight = weight
+ end
+
+ # Sets the conditions for this resolution to be used. This takes a
+ # hash of fact names and values. Every fact must match the values
+ # given for that fact, otherwise this resolution will not be
+ # considered suitable. The values given for a fact can be an array, in
+ # which case the value of the fact must be in the array for it to
+ # match.
+ #
+ # @param confines [Hash{String => Object}] a hash of facts and the
+ # values they should have in order for this resolution to be
+ # used
+ #
+ # @example Confining to Linux
+ # Facter.add(:powerstates) do
+ # # This resolution only makes sense on linux systems
+ # confine :kernel => "Linux"
+ # setcode do
+ # Facter::Util::Resolution.exec('cat /sys/power/states')
+ # end
+ # end
+ #
+ # @return [void]
+ #
+ # @api public
+ def confine(confines)
+ confines.each do |fact, values|
+ @confines.push Facter::Util::Confine.new(fact, *values)
+ end
+ end
+
+ # Returns the importance of this resolution. If the weight was not
+ # given, the number of confines is used instead (so that a more
+ # specific resolution wins over a less specific one).
+ #
+ # @return [Integer] the weight of this resolution
+ #
+ # @api private
+ def weight
+ if @weight
+ @weight
+ else
+ @confines.length
+ end
+ end
+
+ # Is this resolution mechanism suitable on the system in question?
+ #
+ # @api private
+ def suitable?
+ unless defined? @suitable
+ @suitable = ! @confines.detect { |confine| ! confine.true? }
+ end
+
+ return @suitable
+ end
+end
diff --git a/lib/facter/util/resolution.rb b/lib/facter/util/resolution.rb
index 4129309..6bb4842 100644
--- a/lib/facter/util/resolution.rb
+++ b/lib/facter/util/resolution.rb
@@ -2,8 +2,8 @@ require 'facter/util/confine'
require 'facter/util/config'
require 'facter/util/normalization'
require 'facter/core/execution'
-
-require 'timeout'
+require 'facter/core/resolvable'
+require 'facter/core/suitable'
# This represents a fact resolution. A resolution is a concrete
# implementation of a fact. A single fact can have many resolutions and
@@ -17,23 +17,9 @@ require 'timeout'
#
# @api public
class Facter::Util::Resolution
- # The timeout, in seconds, for evaluating this resolution. The default
- # is 0 which is equivalent to no timeout. This can be set using the
- # options hash argument to {Facter.add}.
- # @return [Integer]
- # @api public
- attr_accessor :timeout
-
- # @!attribute [rw] name
- # The name of this resolution. The resolution name should be unique with
- # respect to the given fact.
- # @return [String]
- # @api public
- attr_accessor :name
-
# @api private
attr_accessor :code
- attr_writer :value, :weight
+ attr_writer :value
INTERPRETER = Facter::Util::Config.is_windows? ? "cmd.exe" : "/bin/sh"
@@ -48,48 +34,15 @@ class Facter::Util::Resolution
public :search_paths, :which, :absolute_path?, :expand_command, :with_env, :exec
end
- # Sets the conditions for this resolution to be used. This takes a
- # hash of fact names and values. Every fact must match the values
- # given for that fact, otherwise this resolution will not be
- # considered suitable. The values given for a fact can be an array, in
- # which case the value of the fact must be in the array for it to
- # match.
- #
- # @param confines [Hash{String => Object}] a hash of facts and the
- # values they should have in order for this resolution to be
- # used
- #
- # @example Confining to Linux
- # Facter.add(:powerstates) do
- # # This resolution only makes sense on linux systems
- # confine :kernel => "Linux"
- # setcode do
- # Facter::Util::Resolution.exec('cat /sys/power/states')
- # end
- # end
- #
- # @return [void]
- #
- # @api public
- def confine(confines)
- confines.each do |fact, values|
- @confines.push Facter::Util::Confine.new(fact, *values)
- end
- end
+ include Facter::Core::Resolvable
+ include Facter::Core::Suitable
- # Sets the weight of this resolution. If multiple suitable resolutions
- # are found, the one with the highest weight will be used. If weight
- # is not given, the number of confines set on a resolution will be
- # used as its weight (so that the most specific resolution is used).
- #
- # @param weight [Integer] the weight of this resolution
- #
- # @return [void]
- #
+ # @!attribute [rw] name
+ # The name of this resolution. The resolution name should be unique with
+ # respect to the given fact.
+ # @return [String]
# @api public
- def has_weight(weight)
- @weight = weight
- end
+ attr_accessor :name
# Create a new resolution mechanism.
#
@@ -127,30 +80,6 @@ class Facter::Util::Resolution
end
end
- # Returns the importance of this resolution. If the weight was not
- # given, the number of confines is used instead (so that a more
- # specific resolution wins over a less specific one).
- #
- # @return [Integer] the weight of this resolution
- #
- # @api private
- def weight
- if @weight
- @weight
- else
- @confines.length
- end
- end
-
- # (see #timeout)
- # This is another name for {#timeout}.
- # @comment We need this as a getter for 'timeout', because some versions
- # of ruby seem to already have a 'timeout' method and we can't
- # seem to override the instance methods, somehow.
- def limit
- @timeout
- end
-
# Sets the code block or external program that will be evaluated to
# get the value of the fact.
#
@@ -181,37 +110,6 @@ class Facter::Util::Resolution
end
end
- ##
- # on_flush accepts a block and executes the block when the resolution's value
- # is flushed. This makes it possible to model a single, expensive system
- # call inside of a Ruby object and then define multiple dynamic facts which
- # resolve by sending messages to the model instance. If one of the dynamic
- # facts is flushed then it can, in turn, flush the data stored in the model
- # instance to keep all of the dynamic facts in sync without making multiple,
- # expensive, system calls.
- #
- # Please see the Solaris zones fact for an example of how this feature may be
- # used.
- #
- # @see Facter::Util::Fact#flush
- # @see Facter::Util::Resolution#flush
- #
- # @api public
- def on_flush(&block)
- @on_flush_block = block
- end
-
- ##
- # flush executes the block, if any, stored by the {on_flush} method
- #
- # @see Facter::Util::Fact#flush
- # @see Facter::Util::Resolution#on_flush
- #
- # @api private
- def flush
- @on_flush_block.call if @on_flush_block
- end
-
# @deprecated
def interpreter
Facter.warnonce "The 'Facter::Util::Resolution.interpreter' method is deprecated and will be removed in a future version."
@@ -224,62 +122,22 @@ class Facter::Util::Resolution
@interpreter = interp
end
- # Is this resolution mechanism suitable on the system in question?
- #
- # @api private
- def suitable?
- if @suitable.nil?
- @suitable = @confines.all? { |confine| confine.true? }
- end
-
- return @suitable
- end
-
# (see value)
# @deprecated
def to_s
return self.value()
end
- # Evaluates the code block or external program to get the value of the
- # fact.
- #
- # @api private
- def value
- return @value if @value
- result = nil
- return result if @code == nil
-
- starttime = Time.now.to_f
+ private
- begin
- Timeout.timeout(limit) do
- if @code.is_a?(Proc)
- result = @code.call()
- else
- result = Facter::Util::Resolution.exec(@code)
- end
- end
- rescue Timeout::Error => detail
- Facter.warn "Timed out seeking value for %s" % self.name
+ def resolve_value
+ return @value if @value
+ return nil if @code.nil?
- # This call avoids zombies -- basically, create a thread that will
- # dezombify all of the child processes that we're ignoring because
- # of the timeout.
- Thread.new { Process.waitall }
- return nil
- rescue => details
- Facter.warn "Could not retrieve %s: %s" % [self.name, details]
- return nil
+ if @code.is_a? Proc
+ @code.call()
+ else
+ Facter::Util::Resolution.exec(@code)
end
-
- finishtime = Time.now.to_f
- ms = (finishtime - starttime) * 1000
- Facter.show_time "#{self.name}: #{"%.2f" % ms}ms"
-
- Facter::Util::Normalization.normalize(result)
- rescue Facter::Util::Normalization::NormalizationError => e
- Facter.warn "Fact resolution #{self.name} resolved to an invalid value: #{e.message}"
- nil
end
end
diff --git a/spec/unit/core/resolvable_spec.rb b/spec/unit/core/resolvable_spec.rb
new file mode 100644
index 0000000..69d9c33
--- /dev/null
+++ b/spec/unit/core/resolvable_spec.rb
@@ -0,0 +1,116 @@
+require 'spec_helper'
+require 'facter/core/resolvable'
+
+describe Facter::Core::Resolvable do
+
+ class ResolvableClass
+ def initialize(name)
+ @name = name
+ end
+ attr_accessor :name, :resolve_value
+ include Facter::Core::Resolvable
+ end
+
+ subject { ResolvableClass.new('resolvable') }
+
+ it "has a default timeout of 0 seconds" do
+ expect(subject.limit).to eq 0
+ end
+
+ it "can specify a custom timeout" do
+ subject.timeout = 10
+ expect(subject.limit).to eq 10
+ end
+
+ describe "generating a value" do
+ let(:fact_value) { "" }
+
+ let(:utf16_string) do
+ if String.method_defined?(:encode) && defined?(::Encoding)
+ fact_value.encode(Encoding::UTF_16LE).freeze
+ else
+ [0x00, 0x00].pack('C*').freeze
+ end
+ end
+
+ let(:expected_value) do
+ if String.method_defined?(:encode) && defined?(::Encoding)
+ fact_value.encode(Encoding::UTF_8).freeze
+ else
+ [0x00, 0x00].pack('C*').freeze
+ end
+ end
+
+ it "returns the results of #resolve_value" do
+ subject.resolve_value = 'stuff'
+ expect(subject.value).to eq 'stuff'
+ end
+
+ it "normalizes the resolved value" do
+ subject.resolve_value = fact_value
+ expect(subject.value).to eq(expected_value)
+ end
+
+ it "returns nil if an exception was raised" do
+ subject.expects(:resolve_value).raises RuntimeError, "kaboom!"
+ expect(subject.value).to eq nil
+ end
+
+ it "logs a warning if an exception was raised" do
+ subject.expects(:resolve_value).raises RuntimeError, "kaboom!"
+ Facter.expects(:warn).with('Could not retrieve resolvable: kaboom!')
+ expect(subject.value).to eq nil
+ end
+ end
+
+ describe "timing out" do
+ it "uses #limit instead of #timeout to determine the timeout period" do
+ subject.expects(:timeout).never
+ subject.expects(:limit).returns 25
+
+ Timeout.expects(:timeout).with(25)
+ subject.value
+ end
+
+ it "times out after the provided timeout" do
+ def subject.resolve_value
+ sleep 2
+ end
+ subject.timeout = 0.1
+ subject.value
+ end
+
+ it "returns nil if the timeout was reached" do
+ Timeout.expects(:timeout).raises Timeout::Error
+
+ expect(subject.value).to be_nil
+ end
+
+
+ it "starts a thread to wait on all child processes if the timeout was reached" do
+ Thread.expects(:new).yields
+ Process.expects(:waitall)
+
+ Timeout.expects(:timeout).raises Timeout::Error
+
+ subject.value
+ end
+ end
+
+ describe 'callbacks when flushing facts' do
+ class FlushFakeError < StandardError; end
+
+ context '#on_flush' do
+ it 'accepts a block with on_flush' do
+ subject.on_flush() { raise NotImplementedError }
+ end
+ end
+
+ context '#flush' do
+ it 'calls the block passed to on_flush' do
+ subject.on_flush() { raise FlushFakeError }
+ expect { subject.flush }.to raise_error FlushFakeError
+ end
+ end
+ end
+end
diff --git a/spec/unit/core/suitable_spec.rb b/spec/unit/core/suitable_spec.rb
new file mode 100644
index 0000000..feadb41
--- /dev/null
+++ b/spec/unit/core/suitable_spec.rb
@@ -0,0 +1,70 @@
+require 'spec_helper'
+require 'facter/core/suitable'
+
+describe Facter::Core::Suitable do
+
+ class SuitableClass
+ def initialize
+ @confines = []
+ end
+ attr_reader :confines
+ include Facter::Core::Suitable
+ end
+
+ subject { SuitableClass.new }
+
+ it "can add confines" do
+ subject.confine :kernel => 'Linux'
+ end
+
+ it "creates a Facter::Util::Confine object for the confine call" do
+ subject.confine :kernel => 'Linux'
+ conf = subject.confines.first
+ expect(conf).to be_a_kind_of Facter::Util::Confine
+ expect(conf.fact).to eq :kernel
+ expect(conf.values).to eq ['Linux']
+ end
+
+ describe "determining weight" do
+ it "is zero if no confines are set" do
+ expect(subject.weight).to eq 0
+ end
+
+ it "defaults to the number of confines" do
+ subject.confine :kernel => 'Linux'
+ expect(subject.weight).to eq 1
+ end
+
+ it "can be explicitly set" do
+ subject.has_weight 10
+ expect(subject.weight).to eq 10
+ end
+
+ it "prefers an explicit weight over the number of confines" do
+ subject.confine :kernel => 'Linux'
+ subject.has_weight 11
+ expect(subject.weight).to eq 11
+ end
+ end
+
+ describe "determining suitability" do
+ it "is true if all confines for the object evaluate to true" do
+ subject.confine :kernel => 'Linux'
+ subject.confine :operatingsystem => 'Redhat'
+
+ subject.confines.each { |confine| confine.stubs(:true?).returns true }
+
+ expect(subject).to be_suitable
+ end
+
+ it "is false if any confines for the object evaluate to false" do
+ subject.confine :kernel => 'Linux'
+ subject.confine :operatingsystem => 'Redhat'
+
+ subject.confines.first.stubs(:true?).returns true
+ subject.confines.first.stubs(:true?).returns false
+
+ expect(subject).to_not be_suitable
+ end
+ end
+end
diff --git a/spec/unit/util/resolution_spec.rb b/spec/unit/util/resolution_spec.rb
index a6b954e..4e4b3f9 100755
--- a/spec/unit/util/resolution_spec.rb
+++ b/spec/unit/util/resolution_spec.rb
@@ -6,11 +6,11 @@ require 'facter/util/resolution'
describe Facter::Util::Resolution do
include FacterSpec::ConfigHelper
- it "should require a name" do
- lambda { Facter::Util::Resolution.new }.should raise_error(ArgumentError)
+ it "requires a name" do
+ expect { Facter::Util::Resolution.new }.to raise_error(ArgumentError)
end
- it "should have a name" do
+ it "can return its name" do
Facter::Util::Resolution.new("yay").name.should == "yay"
end
@@ -20,22 +20,6 @@ describe Facter::Util::Resolution do
resolve.value.should == "foo"
end
- it "should have a method for setting the weight" do
- Facter::Util::Resolution.new("yay").should respond_to(:has_weight)
- end
-
- it "should have a method for setting the code" do
- Facter::Util::Resolution.new("yay").should respond_to(:setcode)
- end
-
- it "should support a timeout value" do
- Facter::Util::Resolution.new("yay").should respond_to(:timeout=)
- end
-
- it "should default to a timeout of 0 seconds" do
- Facter::Util::Resolution.new("yay").limit.should == 0
- end
-
it "should default to nil for code" do
Facter::Util::Resolution.new("yay").code.should be_nil
end
@@ -45,12 +29,6 @@ describe Facter::Util::Resolution do
Facter::Util::Resolution.new("yay").interpreter.should be_nil
end
- it "should provide a 'limit' method that returns the timeout" do
- res = Facter::Util::Resolution.new("yay")
- res.timeout = "testing"
- res.limit.should == "testing"
- end
-
describe "when setting the code" do
before do
Facter.stubs(:warnonce)
@@ -91,54 +69,11 @@ describe Facter::Util::Resolution do
end
it "should fail if neither a string nor block has been provided" do
- lambda { @resolve.setcode }.should raise_error(ArgumentError)
- end
- end
-
- describe 'callbacks when flushing facts' do
- class FlushFakeError < StandardError; end
-
- subject do
- Facter::Util::Resolution.new("jeff")
- end
-
- context '#on_flush' do
- it 'accepts a block with on_flush' do
- subject.on_flush() { raise NotImplementedError }
- end
- end
-
- context '#flush' do
- it 'calls the block passed to on_flush' do
- subject.on_flush() { raise FlushFakeError }
- expect { subject.flush }.to raise_error FlushFakeError
- end
+ expect { @resolve.setcode }.to raise_error(ArgumentError)
end
end
- it "should be able to return a value" do
- Facter::Util::Resolution.new("yay").should respond_to(:value)
- end
-
describe "when returning the value" do
- let(:fact_value) { "" }
-
- let(:utf16_string) do
- if String.method_defined?(:encode) && defined?(::Encoding)
- fact_value.encode(Encoding::UTF_16LE).freeze
- else
- [0x00, 0x00].pack('C*').freeze
- end
- end
-
- let(:expected_value) do
- if String.method_defined?(:encode) && defined?(::Encoding)
- fact_value.encode(Encoding::UTF_8).freeze
- else
- [0x00, 0x00].pack('C*').freeze
- end
- end
-
before do
@resolve = Facter::Util::Resolution.new("yay")
end
@@ -167,14 +102,6 @@ describe Facter::Util::Resolution do
@resolve.value.should == "yup"
end
-
- it "it normalizes the resolved value" do
- @resolve.setcode "/bin/foo"
-
- Facter::Util::Resolution.expects(:exec).once.returns(utf16_string)
-
- expect(@resolve.value).to eq(expected_value)
- end
end
describe "on non-windows systems" do
@@ -188,14 +115,6 @@ describe Facter::Util::Resolution do
@resolve.value.should == "yup"
end
-
- it "it normalizes the resolved value" do
- @resolve.setcode "/bin/foo"
-
- Facter::Util::Resolution.expects(:exec).once.returns(utf16_string)
-
- expect(@resolve.value).to eq(expected_value)
- end
end
end
@@ -210,41 +129,6 @@ describe Facter::Util::Resolution do
@resolve.setcode { "yayness" }
@resolve.value.should == "yayness"
end
-
- it "it normalizes the resolved value" do
- @resolve.setcode { utf16_string }
-
- expect(@resolve.value).to eq(expected_value)
- end
-
- it "should use its limit method to determine the timeout, to avoid conflict when a 'timeout' method exists for some other reason" do
- @resolve.expects(:timeout).never
- @resolve.expects(:limit).returns "foo"
- Timeout.expects(:timeout).with("foo")
-
- @resolve.setcode { sleep 2; "raise This is a test"}
- @resolve.value
- end
-
- it "should timeout after the provided timeout" do
- Facter.expects(:warn)
- @resolve.timeout = 0.1
- @resolve.setcode { sleep 2; raise "This is a test" }
- Thread.expects(:new).yields
-
- @resolve.value.should be_nil
- end
-
- it "should waitall to avoid zombies if the timeout is exceeded" do
- Facter.stubs(:warn)
- @resolve.timeout = 0.1
- @resolve.setcode { sleep 2; raise "This is a test" }
-
- Thread.expects(:new).yields
- Process.expects(:waitall)
-
- @resolve.value
- end
end
end
@@ -254,84 +138,6 @@ describe Facter::Util::Resolution do
@resolve.to_s.should == "myval"
end
- it "should allow the adding of confines" do
- Facter::Util::Resolution.new("yay").should respond_to(:confine)
- end
-
- it "should provide a method for returning the number of confines" do
- @resolve = Facter::Util::Resolution.new("yay")
- @resolve.confine "one" => "foo", "two" => "fee"
- @resolve.weight.should == 2
- end
-
- it "should return 0 confines when no confines have been added" do
- Facter::Util::Resolution.new("yay").weight.should == 0
- end
-
- it "should provide a way to set the weight" do
- @resolve = Facter::Util::Resolution.new("yay")
- @resolve.has_weight(45)
- @resolve.weight.should == 45
- end
-
- it "should allow the weight to override the number of confines" do
- @resolve = Facter::Util::Resolution.new("yay")
- @resolve.confine "one" => "foo", "two" => "fee"
- @resolve.weight.should == 2
- @resolve.has_weight(45)
- @resolve.weight.should == 45
- end
-
- it "should have a method for determining if it is suitable" do
- Facter::Util::Resolution.new("yay").should respond_to(:suitable?)
- end
-
- describe "when adding confines" do
- before do
- @resolve = Facter::Util::Resolution.new("yay")
- end
-
- it "should accept a hash of fact names and values" do
- lambda { @resolve.confine :one => "two" }.should_not raise_error
- end
-
- it "should create a Util::Confine instance for every argument in the provided hash" do
- Facter::Util::Confine.expects(:new).with("one", "foo")
- Facter::Util::Confine.expects(:new).with("two", "fee")
-
- @resolve.confine "one" => "foo", "two" => "fee"
- end
-
- end
-
- describe "when determining suitability" do
- before do
- @resolve = Facter::Util::Resolution.new("yay")
- end
-
- it "should always be suitable if no confines have been added" do
- @resolve.should be_suitable
- end
-
- it "should be unsuitable if any provided confines return false" do
- confine1 = mock 'confine1', :true? => true
- confine2 = mock 'confine2', :true? => false
- Facter::Util::Confine.expects(:new).times(2).returns(confine1).then.returns(confine2)
- @resolve.confine :one => :two, :three => :four
-
- @resolve.should_not be_suitable
- end
-
- it "should be suitable if all provided confines return true" do
- confine1 = mock 'confine1', :true? => true
- confine2 = mock 'confine2', :true? => true
- Facter::Util::Confine.expects(:new).times(2).returns(confine1).then.returns(confine2)
- @resolve.confine :one => :two, :three => :four
-
- @resolve.should be_suitable
- end
- end
-
describe "setting options" do
subject(:resolution) { described_class.new(:foo) }
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-puppet/facter.git
More information about the Pkg-puppet-devel
mailing list