diff options
-rw-r--r-- | lib/puppet/parser/functions/fqdn_rotate.rb | 46 | ||||
-rw-r--r-- | spec/spec_helper.rb | 73 | ||||
-rw-r--r-- | spec/unit/puppet/parser/functions/fqdn_rotate_spec.rb | 40 |
3 files changed, 91 insertions, 68 deletions
diff --git a/lib/puppet/parser/functions/fqdn_rotate.rb b/lib/puppet/parser/functions/fqdn_rotate.rb new file mode 100644 index 0000000..6558206 --- /dev/null +++ b/lib/puppet/parser/functions/fqdn_rotate.rb @@ -0,0 +1,46 @@ +# +# fqdn_rotate.rb +# + +module Puppet::Parser::Functions + newfunction(:fqdn_rotate, :type => :rvalue, :doc => <<-EOS +Rotates an array a random number of times based on a nodes fqdn. + EOS + ) do |arguments| + + raise(Puppet::ParseError, "fqdn_rotate(): Wrong number of arguments " + + "given (#{arguments.size} for 1)") if arguments.size < 1 + + value = arguments[0] + klass = value.class + require 'digest/md5' + + unless [Array, String].include?(klass) + raise(Puppet::ParseError, 'fqdn_rotate(): Requires either ' + + 'array or string to work with') + end + + result = value.clone + + string = value.is_a?(String) ? true : false + + # Check whether it makes sense to rotate ... + return result if result.size <= 1 + + # We turn any string value into an array to be able to rotate ... + result = string ? result.split('') : result + + elements = result.size + + srand(Digest::MD5.hexdigest([lookupvar('::fqdn'),arguments].join(':')).hex) + rand(elements).times { + result.push result.shift + } + + result = string ? result.join : result + + return result + end +end + +# vim: set ts=2 sw=2 et : diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 0f3248b..f64fcba 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -10,90 +10,27 @@ require 'mocha' gem 'rspec', '>=2.0.0' require 'rspec/expectations' + # So everyone else doesn't have to include this base constant. module PuppetSpec FIXTURE_DIR = File.join(dir = File.expand_path(File.dirname(__FILE__)), "fixtures") unless defined?(FIXTURE_DIR) end -require 'pathname' -require 'tmpdir' - -require 'puppet_spec/verbose' +# TODO: ultimately would like to move these requires into the puppet_spec_helper.rb file, but the namespaces +# are not currently the same between the two, so tests would need to be modified. Not ready to undertake that +# just yet. require 'puppet_spec/files' -require 'puppet_spec/fixtures' -require 'puppet_spec/matchers' -require 'monkey_patches/alias_should_to_must' -require 'monkey_patches/publicize_methods' - -# JJM Hack to make the stdlib tests run in Puppet 2.6 (See puppet commit cf183534) -if not Puppet.constants.include? "Test" then - module Puppet::Test - class LogCollector - def initialize(logs) - @logs = logs - end - - def <<(value) - @logs << value - end - end - end - Puppet::Util::Log.newdesttype :log_collector do - match "Puppet::Test::LogCollector" - def initialize(messages) - @messages = messages - end +require 'puppet_spec_helper' - def handle(msg) - @messages << msg - end - end -end - -Pathname.glob("#{dir}/shared_behaviours/**/*.rb") do |behaviour| - require behaviour.relative_path_from(Pathname.new(dir)) -end RSpec.configure do |config| - include PuppetSpec::Fixtures - - config.mock_with :mocha config.before :each do GC.disable - - - # REVISIT: I think this conceals other bad tests, but I don't have time to - # fully diagnose those right now. When you read this, please come tell me - # I suck for letting this float. --daniel 2011-04-21 - Signal.stubs(:trap) - - # We're using send because this is a private method to communicate it - # should only be used for tests. Puppet 2.6.x does not have the method. - Puppet.settings.send(:initialize_everything_for_tests) unless Puppet.version =~ /^2\.6/ - - - @logs = [] - Puppet::Util::Log.newdestination(Puppet::Test::LogCollector.new(@logs)) - - @log_level = Puppet::Util::Log.level end config.after :each do - # We're using send because this is a private method to communicate it - # should only be used for tests. Puppet 2.6.x does not have the method. - Puppet.settings.send(:clear_everything_for_tests) unless Puppet.version =~ /^2\.6/ - Puppet::Node::Environment.clear - Puppet::Util::Storage.clear - Puppet::Util::ExecutionStub.reset if Puppet::Util.constants.include? "ExecutionStub" - - PuppetSpec::Files.cleanup - - @logs.clear - Puppet::Util::Log.close_all - Puppet::Util::Log.level = @log_level - GC.enable end end diff --git a/spec/unit/puppet/parser/functions/fqdn_rotate_spec.rb b/spec/unit/puppet/parser/functions/fqdn_rotate_spec.rb new file mode 100644 index 0000000..dd1c3f3 --- /dev/null +++ b/spec/unit/puppet/parser/functions/fqdn_rotate_spec.rb @@ -0,0 +1,40 @@ +#!/usr/bin/env rspec +require 'spec_helper' + +describe "the fqdn_rotate function" do + before :all do + Puppet::Parser::Functions.autoloader.loadall + end + + before :each do + @scope = Puppet::Parser::Scope.new + end + + it "should exist" do + Puppet::Parser::Functions.function("fqdn_rotate").should == "function_fqdn_rotate" + end + + it "should raise a ParseError if there is less than 1 arguments" do + lambda { @scope.function_fqdn_rotate([]) }.should( raise_error(Puppet::ParseError)) + end + + it "should rotate a string and the result should be the same size" do + @scope.expects(:lookupvar).with("::fqdn").returns("127.0.0.1") + result = @scope.function_fqdn_rotate(["asdf"]) + result.size.should(eq(4)) + end + + it "should rotate a string to give the same results for one host" do + @scope.expects(:lookupvar).with("::fqdn").returns("127.0.0.1").twice + @scope.function_fqdn_rotate(["abcdefg"]).should eql(@scope.function_fqdn_rotate(["abcdefg"])) + end + + it "should rotate a string to give different values on different hosts" do + @scope.expects(:lookupvar).with("::fqdn").returns("127.0.0.1") + val1 = @scope.function_fqdn_rotate(["abcdefghijklmnopqrstuvwxyz01234567890987654321"]) + @scope.expects(:lookupvar).with("::fqdn").returns("127.0.0.2") + val2 = @scope.function_fqdn_rotate(["abcdefghijklmnopqrstuvwxyz01234567890987654321"]) + val1.should_not eql(val2) + end + +end |